xref: /template/strap/ComboStrap/BrandButton.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
14cadd4f8SNickeau<?php
24cadd4f8SNickeau
34cadd4f8SNickeau
44cadd4f8SNickeaunamespace ComboStrap;
54cadd4f8SNickeau
64cadd4f8SNickeau
74cadd4f8SNickeauuse action_plugin_combo_metatwitter;
8*04fd306cSNickeauuse ComboStrap\TagAttribute\StyleAttribute;
94cadd4f8SNickeau
104cadd4f8SNickeau/**
114cadd4f8SNickeau *
124cadd4f8SNickeau * Brand button
134cadd4f8SNickeau *   * basic
144cadd4f8SNickeau *   * share
154cadd4f8SNickeau *   * follow
164cadd4f8SNickeau *
174cadd4f8SNickeau * @package ComboStrap
184cadd4f8SNickeau *
194cadd4f8SNickeau *
204cadd4f8SNickeau * Share link:
214cadd4f8SNickeau *   * [Link](https://github.com/mxstbr/sharingbuttons.io/blob/master/js/stores/AppStore.js#L242)
224cadd4f8SNickeau *   * https://github.com/ellisonleao/sharer.js/blob/main/sharer.js#L72
234cadd4f8SNickeau * Style:
244cadd4f8SNickeau *   * [Style](https://github.com/mxstbr/sharingbuttons.io/blob/master/js/stores/AppStore.js#L10)
254cadd4f8SNickeau *
264cadd4f8SNickeau * Popup:
274cadd4f8SNickeau * https://gist.github.com/josephabrahams/9d023596b884e80e37e5
284cadd4f8SNickeau * https://jonsuh.com/blog/social-share-links/
294cadd4f8SNickeau * https://stackoverflow.com/questions/11473345/how-to-pop-up-new-window-with-tweet-button
304cadd4f8SNickeau *
314cadd4f8SNickeau * Inspired by:
324cadd4f8SNickeau * http://sharingbuttons.io (Specifically thanks for the data)
334cadd4f8SNickeau */
344cadd4f8SNickeauclass BrandButton
354cadd4f8SNickeau{
364cadd4f8SNickeau    public const WIDGET_BUTTON_VALUE = "button";
374cadd4f8SNickeau    public const WIDGET_LINK_VALUE = "link";
384cadd4f8SNickeau    const WIDGETS = [self::WIDGET_BUTTON_VALUE, self::WIDGET_LINK_VALUE];
394cadd4f8SNickeau    const ICON_SOLID_VALUE = "solid";
404cadd4f8SNickeau    const ICON_SOLID_CIRCLE_VALUE = "solid-circle";
414cadd4f8SNickeau    const ICON_OUTLINE_CIRCLE_VALUE = "outline-circle";
424cadd4f8SNickeau    const ICON_OUTLINE_VALUE = "outline";
434cadd4f8SNickeau    const ICON_TYPES = [self::ICON_SOLID_VALUE, self::ICON_SOLID_CIRCLE_VALUE, self::ICON_OUTLINE_VALUE, self::ICON_OUTLINE_CIRCLE_VALUE, self::ICON_NONE_VALUE];
444cadd4f8SNickeau    const ICON_NONE_VALUE = "none";
454cadd4f8SNickeau
464cadd4f8SNickeau    const CANONICAL = "social";
474cadd4f8SNickeau
484cadd4f8SNickeau
494cadd4f8SNickeau    /**
504cadd4f8SNickeau     * @var string
514cadd4f8SNickeau     */
524cadd4f8SNickeau    private $widget = self::WIDGET_BUTTON_VALUE;
534cadd4f8SNickeau    /**
544cadd4f8SNickeau     * @var mixed|string
554cadd4f8SNickeau     */
564cadd4f8SNickeau    private $iconType = self::ICON_SOLID_VALUE;
574cadd4f8SNickeau    /**
584cadd4f8SNickeau     * The width of the icon
594cadd4f8SNickeau     * @var int|null
604cadd4f8SNickeau     */
614cadd4f8SNickeau    private $width = null;
624cadd4f8SNickeau    /**
634cadd4f8SNickeau     * @var string
644cadd4f8SNickeau     */
654cadd4f8SNickeau    private $type;
664cadd4f8SNickeau    const TYPE_BUTTON_SHARE = "share";
674cadd4f8SNickeau    const TYPE_BUTTON_FOLLOW = "follow";
684cadd4f8SNickeau    const TYPE_BUTTON_BRAND = "brand";
694cadd4f8SNickeau    const TYPE_BUTTONS = [self::TYPE_BUTTON_SHARE, self::TYPE_BUTTON_FOLLOW, self::TYPE_BUTTON_BRAND];
704cadd4f8SNickeau
714cadd4f8SNickeau
724cadd4f8SNickeau    /**
734cadd4f8SNickeau     * @var string the follow handle
744cadd4f8SNickeau     */
754cadd4f8SNickeau    private $handle;
764cadd4f8SNickeau
774cadd4f8SNickeau
784cadd4f8SNickeau    /**
794cadd4f8SNickeau     * @var Brand
804cadd4f8SNickeau     */
814cadd4f8SNickeau    private $brand;
824cadd4f8SNickeau    private $primaryColor;
834cadd4f8SNickeau    private $title;
844cadd4f8SNickeau    private $secondaryColor;
854cadd4f8SNickeau
864cadd4f8SNickeau
874cadd4f8SNickeau    /**
88*04fd306cSNickeau     * @throws ExceptionCompile
894cadd4f8SNickeau     */
90*04fd306cSNickeau    public function __construct(string $brandName, string $typeButton)
914cadd4f8SNickeau    {
924cadd4f8SNickeau
934cadd4f8SNickeau        $this->brand = Brand::create($brandName);
944cadd4f8SNickeau
954cadd4f8SNickeau        $this->type = strtolower($typeButton);
964cadd4f8SNickeau        if (!in_array($this->type, self::TYPE_BUTTONS)) {
97*04fd306cSNickeau            throw new ExceptionCompile("The button type ($this->type} is unknown.");
984cadd4f8SNickeau        }
994cadd4f8SNickeau
1004cadd4f8SNickeau
1014cadd4f8SNickeau    }
1024cadd4f8SNickeau
1034cadd4f8SNickeau    /**
1044cadd4f8SNickeau     * Return all combination of widget type and icon type
1054cadd4f8SNickeau     * @return array
1064cadd4f8SNickeau     */
1074cadd4f8SNickeau    public static function getVariants(): array
1084cadd4f8SNickeau    {
1094cadd4f8SNickeau        $variants = [];
1104cadd4f8SNickeau        foreach (self::WIDGETS as $widget) {
1114cadd4f8SNickeau            foreach (self::ICON_TYPES as $typeIcon) {
1124cadd4f8SNickeau                if ($typeIcon === self::ICON_NONE_VALUE) {
1134cadd4f8SNickeau                    continue;
1144cadd4f8SNickeau                }
115*04fd306cSNickeau                $variants[] = [BrandTag::ICON_ATTRIBUTE => $typeIcon, TagAttributes::TYPE_KEY => $widget];
1164cadd4f8SNickeau            }
1174cadd4f8SNickeau        }
1184cadd4f8SNickeau        return $variants;
1194cadd4f8SNickeau    }
1204cadd4f8SNickeau
1214cadd4f8SNickeau    /**
122*04fd306cSNickeau     * @throws ExceptionCompile
1234cadd4f8SNickeau     */
1244cadd4f8SNickeau    public static function createBrandButton(string $brand): BrandButton
1254cadd4f8SNickeau    {
1264cadd4f8SNickeau        return new BrandButton($brand, self::TYPE_BUTTON_BRAND);
1274cadd4f8SNickeau    }
1284cadd4f8SNickeau
1294cadd4f8SNickeau
1304cadd4f8SNickeau    /**
131*04fd306cSNickeau     * @throws ExceptionCompile
1324cadd4f8SNickeau     */
1334cadd4f8SNickeau    public function setWidget($widget): BrandButton
1344cadd4f8SNickeau    {
1354cadd4f8SNickeau        /**
1364cadd4f8SNickeau         * Widget validation
1374cadd4f8SNickeau         */
1384cadd4f8SNickeau        $this->widget = $widget;
1394cadd4f8SNickeau        $widget = trim(strtolower($widget));
1404cadd4f8SNickeau        if (!in_array($widget, self::WIDGETS)) {
141*04fd306cSNickeau            throw new ExceptionCompile("The {$this->type} widget ($widget} is unknown. The possible widgets value are " . implode(",", self::WIDGETS));
1424cadd4f8SNickeau        }
1434cadd4f8SNickeau        return $this;
1444cadd4f8SNickeau    }
1454cadd4f8SNickeau
1464cadd4f8SNickeau    /**
147*04fd306cSNickeau     * @throws ExceptionCompile
1484cadd4f8SNickeau     */
1494cadd4f8SNickeau    public function setIconType($iconType): BrandButton
1504cadd4f8SNickeau    {
1514cadd4f8SNickeau        /**
1524cadd4f8SNickeau         * Icon Validation
1534cadd4f8SNickeau         */
1544cadd4f8SNickeau        $this->iconType = $iconType;
1554cadd4f8SNickeau        $iconType = trim(strtolower($iconType));
1564cadd4f8SNickeau        if (!in_array($iconType, self::ICON_TYPES)) {
157*04fd306cSNickeau            throw new ExceptionCompile("The icon type ($iconType) is unknown. The possible icons value are " . implode(",", self::ICON_TYPES));
1584cadd4f8SNickeau        }
1594cadd4f8SNickeau        return $this;
1604cadd4f8SNickeau    }
1614cadd4f8SNickeau
1624cadd4f8SNickeau    public function setWidth(?int $width): BrandButton
1634cadd4f8SNickeau    {
1644cadd4f8SNickeau        /**
1654cadd4f8SNickeau         * Width
1664cadd4f8SNickeau         */
1674cadd4f8SNickeau        if ($width === null) {
1684cadd4f8SNickeau            return $this;
1694cadd4f8SNickeau        }
1704cadd4f8SNickeau        $this->width = $width;
1714cadd4f8SNickeau        return $this;
1724cadd4f8SNickeau    }
1734cadd4f8SNickeau
1744cadd4f8SNickeau    /**
175*04fd306cSNickeau     * @throws ExceptionCompile
1764cadd4f8SNickeau     */
1774cadd4f8SNickeau    public static function createShareButton(
1784cadd4f8SNickeau        string $brandName,
1794cadd4f8SNickeau        string $widget = self::WIDGET_BUTTON_VALUE,
1804cadd4f8SNickeau        string $icon = self::ICON_SOLID_VALUE,
1814cadd4f8SNickeau        ?int   $width = null): BrandButton
1824cadd4f8SNickeau    {
1834cadd4f8SNickeau        return (new BrandButton($brandName, self::TYPE_BUTTON_SHARE))
1844cadd4f8SNickeau            ->setWidget($widget)
1854cadd4f8SNickeau            ->setIconType($icon)
1864cadd4f8SNickeau            ->setWidth($width);
1874cadd4f8SNickeau    }
1884cadd4f8SNickeau
1894cadd4f8SNickeau    /**
190*04fd306cSNickeau     * @throws ExceptionCompile
1914cadd4f8SNickeau     */
1924cadd4f8SNickeau    public static function createFollowButton(
1934cadd4f8SNickeau        string $brandName,
1944cadd4f8SNickeau        string $handle = null,
1954cadd4f8SNickeau        string $widget = self::WIDGET_BUTTON_VALUE,
1964cadd4f8SNickeau        string $icon = self::ICON_SOLID_VALUE,
1974cadd4f8SNickeau        ?int   $width = null): BrandButton
1984cadd4f8SNickeau    {
1994cadd4f8SNickeau        return (new BrandButton($brandName, self::TYPE_BUTTON_FOLLOW))
2004cadd4f8SNickeau            ->setHandle($handle)
2014cadd4f8SNickeau            ->setWidget($widget)
2024cadd4f8SNickeau            ->setIconType($icon)
2034cadd4f8SNickeau            ->setWidth($width);
2044cadd4f8SNickeau    }
2054cadd4f8SNickeau
2064cadd4f8SNickeau    /**
207*04fd306cSNickeau     *
2084cadd4f8SNickeau     *
2094cadd4f8SNickeau     * Dictionary has been made with the data found here:
2104cadd4f8SNickeau     *   * https://github.com/ellisonleao/sharer.js/blob/main/sharer.js#L72
2114cadd4f8SNickeau     *   * and
212*04fd306cSNickeau     * @throws ExceptionBadArgument
2134cadd4f8SNickeau     */
214*04fd306cSNickeau    public function getBrandEndpointForPage(MarkupPath $requestedPage = null): ?string
2154cadd4f8SNickeau    {
2164cadd4f8SNickeau
2174cadd4f8SNickeau        /**
2184cadd4f8SNickeau         * Shared/Follow Url template
2194cadd4f8SNickeau         */
2204cadd4f8SNickeau        $urlTemplate = $this->brand->getWebUrlTemplate($this->type);
2214cadd4f8SNickeau        if ($urlTemplate === null) {
222*04fd306cSNickeau            throw new ExceptionBadArgument("The brand ($this) does not support the $this->type button (The $this->type URL is unknown)");
2234cadd4f8SNickeau        }
2244cadd4f8SNickeau        switch ($this->type) {
2254cadd4f8SNickeau
2264cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
2274cadd4f8SNickeau                if ($requestedPage === null) {
228*04fd306cSNickeau                    throw new ExceptionBadArgument("The page requested should not be null for a share button when requesting the endpoint uri.");
2294cadd4f8SNickeau                }
2304cadd4f8SNickeau                $canonicalUrl = $this->getSharedUrlForPage($requestedPage);
2314cadd4f8SNickeau                $templateData["url"] = $canonicalUrl;
2324cadd4f8SNickeau                $templateData["title"] = $requestedPage->getTitleOrDefault();
233*04fd306cSNickeau
234*04fd306cSNickeau                try {
235*04fd306cSNickeau                    $templateData["description"] = $requestedPage->getDescription();
236*04fd306cSNickeau                } catch (ExceptionNotFound $e) {
237*04fd306cSNickeau                    $templateData["description"] = "";
2384cadd4f8SNickeau                }
239*04fd306cSNickeau
2404cadd4f8SNickeau                $templateData["text"] = $this->getTextForPage($requestedPage);
241*04fd306cSNickeau
2424cadd4f8SNickeau                $via = null;
243*04fd306cSNickeau                if ($this->brand->getName() == \action_plugin_combo_metatwitter::CANONICAL) {
2444cadd4f8SNickeau                    $via = substr(action_plugin_combo_metatwitter::COMBO_STRAP_TWITTER_HANDLE, 1);
2454cadd4f8SNickeau                }
2464cadd4f8SNickeau                if ($via !== null && $via !== "") {
2474cadd4f8SNickeau                    $templateData["via"] = $via;
2484cadd4f8SNickeau                }
2494cadd4f8SNickeau                foreach ($templateData as $key => $value) {
2504cadd4f8SNickeau                    $templateData[$key] = urlencode($value);
2514cadd4f8SNickeau                }
2524cadd4f8SNickeau
253*04fd306cSNickeau                return Template::create($urlTemplate)->setProperties($templateData)->render();
2544cadd4f8SNickeau
2554cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
2564cadd4f8SNickeau                if ($this->handle === null) {
2574cadd4f8SNickeau                    return $urlTemplate;
2584cadd4f8SNickeau                }
259*04fd306cSNickeau                $templateData[Tag\FollowTag::HANDLE_ATTRIBUTE] = $this->handle;
260*04fd306cSNickeau                return Template::create($urlTemplate)->setProperties($templateData)->render();
2614cadd4f8SNickeau            default:
2624cadd4f8SNickeau                // The type is mandatory and checked at creation,
2634cadd4f8SNickeau                // it should not happen, we don't throw an error
2644cadd4f8SNickeau                $message = "Button type ($this->type) is unknown";
2654cadd4f8SNickeau                LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL);
2664cadd4f8SNickeau                return $message;
2674cadd4f8SNickeau        }
2684cadd4f8SNickeau
2694cadd4f8SNickeau    }
2704cadd4f8SNickeau
2714cadd4f8SNickeau    public function __toString()
2724cadd4f8SNickeau    {
2734cadd4f8SNickeau        return $this->brand->__toString();
2744cadd4f8SNickeau    }
2754cadd4f8SNickeau
276*04fd306cSNickeau    public function getLabel(): string
2774cadd4f8SNickeau    {
2784cadd4f8SNickeau        $title = $this->title;
2794cadd4f8SNickeau        if ($title !== null && trim($title) !== "") {
2804cadd4f8SNickeau            return $title;
2814cadd4f8SNickeau        }
2824cadd4f8SNickeau        $title = $this->brand->getTitle($this->iconType);
2834cadd4f8SNickeau        if ($title !== null && trim($title) !== "") {
2844cadd4f8SNickeau            return $title;
2854cadd4f8SNickeau        }
2864cadd4f8SNickeau        $name = ucfirst($this->brand->getName());
2874cadd4f8SNickeau        switch ($this->type) {
2884cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
2894cadd4f8SNickeau                return "Share this page via $name";
2904cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
2914cadd4f8SNickeau                return "Follow us on $name";
2924cadd4f8SNickeau            case self::TYPE_BUTTON_BRAND:
2934cadd4f8SNickeau                return $name;
2944cadd4f8SNickeau            default:
2954cadd4f8SNickeau                return "Button type ($this->type) is unknown";
2964cadd4f8SNickeau        }
2974cadd4f8SNickeau    }
2984cadd4f8SNickeau
2994cadd4f8SNickeau    /**
300*04fd306cSNickeau     * @throws ExceptionCompile
3014cadd4f8SNickeau     */
3024cadd4f8SNickeau    public
3034cadd4f8SNickeau    function getStyle(): string
3044cadd4f8SNickeau    {
3054cadd4f8SNickeau
3064cadd4f8SNickeau        /**
3074cadd4f8SNickeau         * Default colors
3084cadd4f8SNickeau         */
3094cadd4f8SNickeau        // make the button/link space square
3104cadd4f8SNickeau        $properties["padding"] = "0.375rem 0.375rem";
3114cadd4f8SNickeau        switch ($this->widget) {
3124cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
3134cadd4f8SNickeau                $properties["vertical-align"] = "middle";
3144cadd4f8SNickeau                $properties["display"] = "inline-block";
3154cadd4f8SNickeau                $primaryColor = $this->getPrimaryColor();
3164cadd4f8SNickeau                if ($primaryColor !== null) {
3174cadd4f8SNickeau                    // important because the nav-bar class takes over
3184cadd4f8SNickeau                    $properties["color"] = "$primaryColor!important";
3194cadd4f8SNickeau                }
3204cadd4f8SNickeau                break;
3214cadd4f8SNickeau            default:
3224cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
3234cadd4f8SNickeau
3244cadd4f8SNickeau                $primary = $this->getPrimaryColor();
3254cadd4f8SNickeau                if ($primary === null) {
3264cadd4f8SNickeau                    // custom brand default color
3274cadd4f8SNickeau                    $primary = ComboStrap::PRIMARY_COLOR;
3284cadd4f8SNickeau                }
3294cadd4f8SNickeau                $textColor = $this->getTextColor();
3304cadd4f8SNickeau                if ($textColor === null || $textColor === "") {
3314cadd4f8SNickeau                    $textColor = "#fff";
3324cadd4f8SNickeau                }
3334cadd4f8SNickeau                $properties["background-color"] = $primary;
3344cadd4f8SNickeau                $properties["border-color"] = $primary;
3354cadd4f8SNickeau                $properties["color"] = $textColor;
3364cadd4f8SNickeau                break;
3374cadd4f8SNickeau        }
3384cadd4f8SNickeau        switch ($this->iconType) {
3394cadd4f8SNickeau            case self::ICON_OUTLINE_VALUE:
3404cadd4f8SNickeau                // not for outline circle, it's cut otherwise, don't know why
3414cadd4f8SNickeau                $properties["stroke-width"] = "2px";
3424cadd4f8SNickeau                break;
3434cadd4f8SNickeau        }
3444cadd4f8SNickeau
3454cadd4f8SNickeau        $cssProperties = "\n";
3464cadd4f8SNickeau        foreach ($properties as $key => $value) {
3474cadd4f8SNickeau            $cssProperties .= "    $key:$value;\n";
3484cadd4f8SNickeau        }
3494cadd4f8SNickeau        $style = <<<EOF
3504cadd4f8SNickeau.{$this->getIdentifierClass()} {{$cssProperties}}
3514cadd4f8SNickeauEOF;
3524cadd4f8SNickeau
3534cadd4f8SNickeau        /**
3544cadd4f8SNickeau         * Hover Style
3554cadd4f8SNickeau         */
3564cadd4f8SNickeau        $secondary = $this->getSecondaryColor();
3574cadd4f8SNickeau        if ($secondary === null) {
3584cadd4f8SNickeau            return $style;
3594cadd4f8SNickeau        }
3604cadd4f8SNickeau        $hoverProperties = [];
3614cadd4f8SNickeau        switch ($this->widget) {
3624cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
3634cadd4f8SNickeau                $hoverProperties["color"] = $secondary;
3644cadd4f8SNickeau                break;
3654cadd4f8SNickeau            default:
3664cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
3674cadd4f8SNickeau                $textColor = $this->getTextColor();
3684cadd4f8SNickeau                $hoverProperties["background-color"] = $secondary;
3694cadd4f8SNickeau                $hoverProperties["border-color"] = $secondary;
3704cadd4f8SNickeau                $hoverProperties["color"] = $textColor;
3714cadd4f8SNickeau                break;
3724cadd4f8SNickeau        }
3734cadd4f8SNickeau        $hoverCssProperties = "\n";
3744cadd4f8SNickeau        foreach ($hoverProperties as $key => $value) {
3754cadd4f8SNickeau            $hoverCssProperties .= "    $key:$value;\n";
3764cadd4f8SNickeau        }
3774cadd4f8SNickeau        $hoverStyle = <<<EOF
3784cadd4f8SNickeau.{$this->getIdentifierClass()}:hover, .{$this->getIdentifierClass()}:active {{$hoverCssProperties}}
3794cadd4f8SNickeauEOF;
3804cadd4f8SNickeau
3814cadd4f8SNickeau        return <<<EOF
3824cadd4f8SNickeau$style
3834cadd4f8SNickeau$hoverStyle
3844cadd4f8SNickeauEOF;
3854cadd4f8SNickeau
3864cadd4f8SNickeau
3874cadd4f8SNickeau    }
3884cadd4f8SNickeau
3894cadd4f8SNickeau    public function getBrand(): Brand
3904cadd4f8SNickeau    {
3914cadd4f8SNickeau        return $this->brand;
3924cadd4f8SNickeau    }
3934cadd4f8SNickeau
3944cadd4f8SNickeau    /**
3954cadd4f8SNickeau     * The identifier of the {@link BrandButton::getStyle()} script
396*04fd306cSNickeau     * used as script id in the {@link SnippetSystem}
3974cadd4f8SNickeau     * @return string
3984cadd4f8SNickeau     */
3994cadd4f8SNickeau    public
4004cadd4f8SNickeau    function getStyleScriptIdentifier(): string
4014cadd4f8SNickeau    {
4024cadd4f8SNickeau        return "{$this->getType()}-{$this->brand->getName()}-{$this->getWidget()}-{$this->getIcon()}";
4034cadd4f8SNickeau    }
4044cadd4f8SNickeau
4054cadd4f8SNickeau    /**
4064cadd4f8SNickeau     * @return string - the class identifier used in the {@link BrandButton::getStyle()} script
4074cadd4f8SNickeau     */
4084cadd4f8SNickeau    public
4094cadd4f8SNickeau    function getIdentifierClass(): string
4104cadd4f8SNickeau    {
411*04fd306cSNickeau        return StyleAttribute::addComboStrapSuffix($this->getStyleScriptIdentifier());
4124cadd4f8SNickeau    }
4134cadd4f8SNickeau
4144cadd4f8SNickeau    /**
415*04fd306cSNickeau     * @throws ExceptionNotFound
4164cadd4f8SNickeau     */
4174cadd4f8SNickeau    public
4184cadd4f8SNickeau    function getIconAttributes(): array
4194cadd4f8SNickeau    {
4204cadd4f8SNickeau
4214cadd4f8SNickeau        $iconName = $this->getResourceIconName();
4224cadd4f8SNickeau        $icon = $this->getResourceIconFile();
4234cadd4f8SNickeau        if (!FileSystems::exists($icon)) {
4244cadd4f8SNickeau            $iconName = $this->brand->getIconName($this->iconType);
4254cadd4f8SNickeau            $brandNames = Brand::getAllKnownBrandNames();
4264cadd4f8SNickeau            if ($iconName === null && in_array($this->getBrand(), $brandNames)) {
427*04fd306cSNickeau                throw new ExceptionNotFound("No {$this->iconType} icon could be found for the known brand ($this)");
4284cadd4f8SNickeau            }
4294cadd4f8SNickeau        }
430*04fd306cSNickeau        $attributes = [FetcherSvg::NAME_ATTRIBUTE => $iconName];
4314cadd4f8SNickeau        $textColor = $this->getTextColor();
4324cadd4f8SNickeau        if ($textColor !== null) {
4334cadd4f8SNickeau            $attributes[ColorRgb::COLOR] = $textColor;
4344cadd4f8SNickeau        }
4354cadd4f8SNickeau        $attributes[Dimension::WIDTH_KEY] = $this->getWidth();
4364cadd4f8SNickeau
4374cadd4f8SNickeau        return $attributes;
4384cadd4f8SNickeau    }
4394cadd4f8SNickeau
4404cadd4f8SNickeau    public
4414cadd4f8SNickeau    function getTextColor(): ?string
4424cadd4f8SNickeau    {
4434cadd4f8SNickeau
4444cadd4f8SNickeau        switch ($this->widget) {
4454cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
4464cadd4f8SNickeau                return $this->getPrimaryColor();
4474cadd4f8SNickeau            default:
4484cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
4494cadd4f8SNickeau                return "#fff";
4504cadd4f8SNickeau        }
4514cadd4f8SNickeau
4524cadd4f8SNickeau    }
4534cadd4f8SNickeau
4544cadd4f8SNickeau    /**
4554cadd4f8SNickeau     * Class added to the link
4564cadd4f8SNickeau     * This is just to be boostrap conformance
4574cadd4f8SNickeau     */
4584cadd4f8SNickeau    public
4594cadd4f8SNickeau    function getWidgetClass(): string
4604cadd4f8SNickeau    {
461*04fd306cSNickeau        /**
462*04fd306cSNickeau         * The btn bootstrap class:
463*04fd306cSNickeau         * * makes a link a button
464*04fd306cSNickeau         * * and normalize the button styling
465*04fd306cSNickeau         */
4664cadd4f8SNickeau        return "btn";
4674cadd4f8SNickeau    }
4684cadd4f8SNickeau
4694cadd4f8SNickeau
4704cadd4f8SNickeau    public
4714cadd4f8SNickeau    function getWidget(): string
4724cadd4f8SNickeau    {
4734cadd4f8SNickeau        return $this->widget;
4744cadd4f8SNickeau    }
4754cadd4f8SNickeau
4764cadd4f8SNickeau    private
4774cadd4f8SNickeau    function getIcon()
4784cadd4f8SNickeau    {
4794cadd4f8SNickeau        return $this->iconType;
4804cadd4f8SNickeau    }
4814cadd4f8SNickeau
4824cadd4f8SNickeau    private
4834cadd4f8SNickeau    function getDefaultWidth(): int
4844cadd4f8SNickeau    {
4854cadd4f8SNickeau        switch ($this->widget) {
4864cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
4874cadd4f8SNickeau                return 36;
4884cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
4894cadd4f8SNickeau            default:
4904cadd4f8SNickeau                return 24;
4914cadd4f8SNickeau        }
4924cadd4f8SNickeau    }
4934cadd4f8SNickeau
4944cadd4f8SNickeau    private
4954cadd4f8SNickeau    function getWidth(): ?int
4964cadd4f8SNickeau    {
4974cadd4f8SNickeau        if ($this->width === null) {
4984cadd4f8SNickeau            return $this->getDefaultWidth();
4994cadd4f8SNickeau        }
5004cadd4f8SNickeau        return $this->width;
5014cadd4f8SNickeau    }
5024cadd4f8SNickeau
5034cadd4f8SNickeau    public function hasIcon(): bool
5044cadd4f8SNickeau    {
5054cadd4f8SNickeau        if ($this->iconType === self::ICON_NONE_VALUE) {
5064cadd4f8SNickeau            return false;
5074cadd4f8SNickeau        }
508*04fd306cSNickeau
5094cadd4f8SNickeau        if ($this->brand->getIconName($this->iconType) !== null) {
5104cadd4f8SNickeau            return true;
5114cadd4f8SNickeau        }
512*04fd306cSNickeau
5134cadd4f8SNickeau        if (!FileSystems::exists($this->getResourceIconFile())) {
5144cadd4f8SNickeau            return false;
5154cadd4f8SNickeau        }
5164cadd4f8SNickeau        return true;
5174cadd4f8SNickeau    }
5184cadd4f8SNickeau
519*04fd306cSNickeau
520*04fd306cSNickeau    /**
521*04fd306cSNickeau     */
5224cadd4f8SNickeau    public
523*04fd306cSNickeau    function getTextForPage(MarkupPath $requestedPage): string
5244cadd4f8SNickeau    {
525*04fd306cSNickeau
526*04fd306cSNickeau        try {
527*04fd306cSNickeau            return "{$requestedPage->getTitleOrDefault()} > {$requestedPage->getDescription()}";
528*04fd306cSNickeau        } catch (ExceptionNotFound $e) {
529*04fd306cSNickeau            // no description, may be ?
530*04fd306cSNickeau            return $requestedPage->getTitleOrDefault();
5314cadd4f8SNickeau        }
5324cadd4f8SNickeau
5334cadd4f8SNickeau    }
5344cadd4f8SNickeau
5354cadd4f8SNickeau    public
536*04fd306cSNickeau    function getSharedUrlForPage(MarkupPath $requestedPage): string
5374cadd4f8SNickeau    {
538*04fd306cSNickeau        return $requestedPage->getCanonicalUrl()->toAbsoluteUrlString();
5394cadd4f8SNickeau    }
5404cadd4f8SNickeau
5414cadd4f8SNickeau    /**
542*04fd306cSNickeau     * Return the button HTML attributes
543*04fd306cSNickeau     * @throws ExceptionCompile
5444cadd4f8SNickeau     */
5454cadd4f8SNickeau    public
546*04fd306cSNickeau    function getHtmlAttributes(MarkupPath $requestedPage = null): TagAttributes
5474cadd4f8SNickeau    {
5484cadd4f8SNickeau
5494cadd4f8SNickeau
5504cadd4f8SNickeau        $logicalTag = $this->type;
551*04fd306cSNickeau        $buttonAttributes = TagAttributes::createEmpty($logicalTag);
552*04fd306cSNickeau        $buttonAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, $logicalTag);
553*04fd306cSNickeau        $buttonAttributes->addClassName("{$this->getWidgetClass()} {$this->getIdentifierClass()}");
554*04fd306cSNickeau        $label = $this->getLabel();
5554cadd4f8SNickeau        switch ($this->type) {
5564cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
5574cadd4f8SNickeau
5584cadd4f8SNickeau                if ($requestedPage === null) {
559*04fd306cSNickeau                    throw new ExceptionCompile("The page requested should not be null for a share button");
5604cadd4f8SNickeau                }
5614cadd4f8SNickeau
5624cadd4f8SNickeau                switch ($this->getBrand()) {
5634cadd4f8SNickeau                    case "whatsapp":
5644cadd4f8SNickeau                        /**
5654cadd4f8SNickeau                         * Direct link
5664cadd4f8SNickeau                         * For whatsapp, the sharer link is not the good one
5674cadd4f8SNickeau                         */
568*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("target", "_blank");
569*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("href", $this->getBrandEndpointForPage($requestedPage));
5704cadd4f8SNickeau                        break;
5714cadd4f8SNickeau                    default:
5724cadd4f8SNickeau                        /**
5734cadd4f8SNickeau                         * Sharer
5744cadd4f8SNickeau                         * https://ellisonleao.github.io/sharer.js/
5754cadd4f8SNickeau                         */
5764cadd4f8SNickeau                        /**
5774cadd4f8SNickeau                         * Opens in a popup
5784cadd4f8SNickeau                         */
579*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("rel", "noopener");
5804cadd4f8SNickeau
581*04fd306cSNickeau                        PluginUtility::getSnippetManager()->attachRemoteJavascriptLibrary(
5824cadd4f8SNickeau                            "sharer",
5834cadd4f8SNickeau                            "https://cdn.jsdelivr.net/npm/sharer.js@0.5.0/sharer.min.js",
5844cadd4f8SNickeau                            "sha256-AqqY/JJCWPQwZFY/mAhlvxjC5/880Q331aOmargQVLU="
5854cadd4f8SNickeau                        );
586*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("aria-label", $label);
587*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-sharer", $this->getBrand()); // the id
588*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-link", "false");
589*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-title", $this->getTextForPage($requestedPage));
5904cadd4f8SNickeau                        $urlToShare = $this->getSharedUrlForPage($requestedPage);
591*04fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-url", $urlToShare);
5924cadd4f8SNickeau                        //$linkAttributes->addComponentAttributeValue("href", "#"); // with # we style navigate to the top
593*04fd306cSNickeau                        $buttonAttributes->addStyleDeclarationIfNotSet("cursor", "pointer"); // show a pointer (without href, there is none)
5944cadd4f8SNickeau                }
595*04fd306cSNickeau                return $buttonAttributes;
5964cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
5974cadd4f8SNickeau
598*04fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("title", $label);
599*04fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("target", "_blank");
600*04fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("rel", "nofollow");
6014cadd4f8SNickeau                $href = $this->getBrandEndpointForPage();
6024cadd4f8SNickeau                if ($href !== null) {
603*04fd306cSNickeau                    $buttonAttributes->addOutputAttributeValue("href", $href);
6044cadd4f8SNickeau                }
605*04fd306cSNickeau                return $buttonAttributes;
6064cadd4f8SNickeau            case self::TYPE_BUTTON_BRAND:
6074cadd4f8SNickeau                if ($this->brand->getBrandUrl() !== null) {
608*04fd306cSNickeau                    $buttonAttributes->addOutputAttributeValue("href", $this->brand->getBrandUrl());
6094cadd4f8SNickeau                }
610*04fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("title", $label);
611*04fd306cSNickeau                return $buttonAttributes;
6124cadd4f8SNickeau            default:
613*04fd306cSNickeau                return $buttonAttributes;
6144cadd4f8SNickeau
6154cadd4f8SNickeau        }
6164cadd4f8SNickeau
6174cadd4f8SNickeau
6184cadd4f8SNickeau    }
6194cadd4f8SNickeau
6204cadd4f8SNickeau
621*04fd306cSNickeau    public
6224cadd4f8SNickeau    function getType(): string
6234cadd4f8SNickeau    {
6244cadd4f8SNickeau        return $this->type;
6254cadd4f8SNickeau    }
6264cadd4f8SNickeau
6274cadd4f8SNickeau    public function setHandle(string $handle): BrandButton
6284cadd4f8SNickeau    {
6294cadd4f8SNickeau        $this->handle = $handle;
6304cadd4f8SNickeau        return $this;
6314cadd4f8SNickeau    }
6324cadd4f8SNickeau
6334cadd4f8SNickeau    public function setLinkTitle(string $title): BrandButton
6344cadd4f8SNickeau    {
6354cadd4f8SNickeau        $this->title = $title;
6364cadd4f8SNickeau        return $this;
6374cadd4f8SNickeau    }
6384cadd4f8SNickeau
6394cadd4f8SNickeau    public function setPrimaryColor(string $color): BrandButton
6404cadd4f8SNickeau    {
6414cadd4f8SNickeau        $this->primaryColor = $color;
6424cadd4f8SNickeau        return $this;
6434cadd4f8SNickeau    }
6444cadd4f8SNickeau
645*04fd306cSNickeau    private function getResourceIconFile(): WikiPath
6464cadd4f8SNickeau    {
6474cadd4f8SNickeau        $iconName = $this->getResourceIconName();
648*04fd306cSNickeau        $iconPath = str_replace(IconDownloader::COMBO, "", $iconName) . ".svg";
649*04fd306cSNickeau        return WikiPath::createComboResource($iconPath);
6504cadd4f8SNickeau    }
6514cadd4f8SNickeau
6524cadd4f8SNickeau    public function setSecondaryColor(string $secondaryColor): BrandButton
6534cadd4f8SNickeau    {
6544cadd4f8SNickeau        $this->secondaryColor = $secondaryColor;
6554cadd4f8SNickeau        return $this;
6564cadd4f8SNickeau    }
6574cadd4f8SNickeau
6584cadd4f8SNickeau    private function getResourceIconName(): string
6594cadd4f8SNickeau    {
660*04fd306cSNickeau        $comboLibrary = IconDownloader::COMBO;
661*04fd306cSNickeau        return "$comboLibrary:brand:{$this->getBrand()->getName()}:{$this->iconType}";
6624cadd4f8SNickeau    }
6634cadd4f8SNickeau
6644cadd4f8SNickeau
6654cadd4f8SNickeau    private function getPrimaryColor(): ?string
6664cadd4f8SNickeau    {
6674cadd4f8SNickeau        if ($this->primaryColor !== null) {
6684cadd4f8SNickeau            return $this->primaryColor;
6694cadd4f8SNickeau        }
6704cadd4f8SNickeau        return $this->brand->getPrimaryColor();
6714cadd4f8SNickeau    }
6724cadd4f8SNickeau
6734cadd4f8SNickeau    private function getSecondaryColor(): ?string
6744cadd4f8SNickeau    {
6754cadd4f8SNickeau        if ($this->secondaryColor !== null) {
6764cadd4f8SNickeau            return $this->secondaryColor;
6774cadd4f8SNickeau        }
6784cadd4f8SNickeau        return $this->brand->getSecondaryColor();
6794cadd4f8SNickeau    }
6804cadd4f8SNickeau
681*04fd306cSNickeau    /**
682*04fd306cSNickeau     * The button is sometimes:
683*04fd306cSNickeau     * * a HTML button
684*04fd306cSNickeau     * * and other times a HTML link
685*04fd306cSNickeau     *
686*04fd306cSNickeau     * It seems that the button is mostly for data-sharer (share button)
687*04fd306cSNickeau     *
688*04fd306cSNickeau     * A Link should have an href otherwise the SEO scan will not be happy
689*04fd306cSNickeau     * A button should have a aria-label
690*04fd306cSNickeau     *
691*04fd306cSNickeau     * @param $tagAttributes
692*04fd306cSNickeau     * @return string
693*04fd306cSNickeau     */
694*04fd306cSNickeau    public function getHtmlElement($tagAttributes): string
695*04fd306cSNickeau    {
696*04fd306cSNickeau        if ($tagAttributes->hasAttribute("href")) {
697*04fd306cSNickeau            return "a";
698*04fd306cSNickeau        } else {
699*04fd306cSNickeau            return "button";
700*04fd306cSNickeau        }
701*04fd306cSNickeau    }
702*04fd306cSNickeau
7034cadd4f8SNickeau
7044cadd4f8SNickeau}
705