xref: /plugin/combo/ComboStrap/BrandButton.php (revision 8b8569b7384a60bf4f631e3aa3bd7f9aab461558)
14cadd4f8SNickeau<?php
24cadd4f8SNickeau
34cadd4f8SNickeau
44cadd4f8SNickeaunamespace ComboStrap;
54cadd4f8SNickeau
64cadd4f8SNickeau
74cadd4f8SNickeauuse action_plugin_combo_metatwitter;
804fd306cSNickeauuse 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    /**
8804fd306cSNickeau     * @throws ExceptionCompile
894cadd4f8SNickeau     */
9004fd306cSNickeau    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)) {
9704fd306cSNickeau            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                }
11504fd306cSNickeau                $variants[] = [BrandTag::ICON_ATTRIBUTE => $typeIcon, TagAttributes::TYPE_KEY => $widget];
1164cadd4f8SNickeau            }
1174cadd4f8SNickeau        }
1184cadd4f8SNickeau        return $variants;
1194cadd4f8SNickeau    }
1204cadd4f8SNickeau
1214cadd4f8SNickeau    /**
12204fd306cSNickeau     * @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    /**
13104fd306cSNickeau     * @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)) {
14104fd306cSNickeau            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    /**
14704fd306cSNickeau     * @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)) {
15704fd306cSNickeau            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    /**
17504fd306cSNickeau     * @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    /**
19004fd306cSNickeau     * @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    /**
20704fd306cSNickeau     *
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
21204fd306cSNickeau     * @throws ExceptionBadArgument
2134cadd4f8SNickeau     */
21404fd306cSNickeau    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) {
22204fd306cSNickeau            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) {
22804fd306cSNickeau                    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();
23304fd306cSNickeau
23404fd306cSNickeau                try {
23504fd306cSNickeau                    $templateData["description"] = $requestedPage->getDescription();
23604fd306cSNickeau                } catch (ExceptionNotFound $e) {
23704fd306cSNickeau                    $templateData["description"] = "";
2384cadd4f8SNickeau                }
23904fd306cSNickeau
2404cadd4f8SNickeau                $templateData["text"] = $this->getTextForPage($requestedPage);
24104fd306cSNickeau
2424cadd4f8SNickeau                $via = null;
24304fd306cSNickeau                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
25304fd306cSNickeau                return Template::create($urlTemplate)->setProperties($templateData)->render();
2544cadd4f8SNickeau
2554cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
2564cadd4f8SNickeau                if ($this->handle === null) {
2574cadd4f8SNickeau                    return $urlTemplate;
2584cadd4f8SNickeau                }
25904fd306cSNickeau                $templateData[Tag\FollowTag::HANDLE_ATTRIBUTE] = $this->handle;
26004fd306cSNickeau                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
27604fd306cSNickeau    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    /**
30004fd306cSNickeau     * @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
39604fd306cSNickeau     * 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    {
41104fd306cSNickeau        return StyleAttribute::addComboStrapSuffix($this->getStyleScriptIdentifier());
4124cadd4f8SNickeau    }
4134cadd4f8SNickeau
4144cadd4f8SNickeau    /**
41504fd306cSNickeau     * @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)) {
42704fd306cSNickeau                throw new ExceptionNotFound("No {$this->iconType} icon could be found for the known brand ($this)");
4284cadd4f8SNickeau            }
4294cadd4f8SNickeau        }
43004fd306cSNickeau        $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    {
46104fd306cSNickeau        /**
46204fd306cSNickeau         * The btn bootstrap class:
46304fd306cSNickeau         * * makes a link a button
46404fd306cSNickeau         * * and normalize the button styling
46504fd306cSNickeau         */
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        }
50804fd306cSNickeau
5094cadd4f8SNickeau        if ($this->brand->getIconName($this->iconType) !== null) {
5104cadd4f8SNickeau            return true;
5114cadd4f8SNickeau        }
51204fd306cSNickeau
5134cadd4f8SNickeau        if (!FileSystems::exists($this->getResourceIconFile())) {
5144cadd4f8SNickeau            return false;
5154cadd4f8SNickeau        }
5164cadd4f8SNickeau        return true;
5174cadd4f8SNickeau    }
5184cadd4f8SNickeau
51904fd306cSNickeau
52004fd306cSNickeau    /**
52104fd306cSNickeau     */
5224cadd4f8SNickeau    public
52304fd306cSNickeau    function getTextForPage(MarkupPath $requestedPage): string
5244cadd4f8SNickeau    {
52504fd306cSNickeau
52604fd306cSNickeau        try {
52704fd306cSNickeau            return "{$requestedPage->getTitleOrDefault()} > {$requestedPage->getDescription()}";
52804fd306cSNickeau        } catch (ExceptionNotFound $e) {
52904fd306cSNickeau            // no description, may be ?
53004fd306cSNickeau            return $requestedPage->getTitleOrDefault();
5314cadd4f8SNickeau        }
5324cadd4f8SNickeau
5334cadd4f8SNickeau    }
5344cadd4f8SNickeau
5354cadd4f8SNickeau    public
53604fd306cSNickeau    function getSharedUrlForPage(MarkupPath $requestedPage): string
5374cadd4f8SNickeau    {
53804fd306cSNickeau        return $requestedPage->getCanonicalUrl()->toAbsoluteUrlString();
5394cadd4f8SNickeau    }
5404cadd4f8SNickeau
5414cadd4f8SNickeau    /**
54204fd306cSNickeau     * Return the button HTML attributes
54304fd306cSNickeau     * @throws ExceptionCompile
5444cadd4f8SNickeau     */
5454cadd4f8SNickeau    public
54604fd306cSNickeau    function getHtmlAttributes(MarkupPath $requestedPage = null): TagAttributes
5474cadd4f8SNickeau    {
5484cadd4f8SNickeau
5494cadd4f8SNickeau
5504cadd4f8SNickeau        $logicalTag = $this->type;
55104fd306cSNickeau        $buttonAttributes = TagAttributes::createEmpty($logicalTag);
55204fd306cSNickeau        $buttonAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, $logicalTag);
55304fd306cSNickeau        $buttonAttributes->addClassName("{$this->getWidgetClass()} {$this->getIdentifierClass()}");
55404fd306cSNickeau        $label = $this->getLabel();
5554cadd4f8SNickeau        switch ($this->type) {
5564cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
5574cadd4f8SNickeau
5584cadd4f8SNickeau                if ($requestedPage === null) {
55904fd306cSNickeau                    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                         */
56804fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("target", "_blank");
56904fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("href", $this->getBrandEndpointForPage($requestedPage));
570*8b8569b7Sgerardnico                        $buttonAttributes->addOutputAttributeValue("title", $label);
5714cadd4f8SNickeau                        break;
5724cadd4f8SNickeau                    default:
5734cadd4f8SNickeau                        /**
5744cadd4f8SNickeau                         * Sharer
5754cadd4f8SNickeau                         * https://ellisonleao.github.io/sharer.js/
5764cadd4f8SNickeau                         */
5774cadd4f8SNickeau                        /**
5784cadd4f8SNickeau                         * Opens in a popup
5794cadd4f8SNickeau                         */
58004fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("rel", "noopener");
5814cadd4f8SNickeau
58204fd306cSNickeau                        PluginUtility::getSnippetManager()->attachRemoteJavascriptLibrary(
5834cadd4f8SNickeau                            "sharer",
5844cadd4f8SNickeau                            "https://cdn.jsdelivr.net/npm/sharer.js@0.5.0/sharer.min.js",
5854cadd4f8SNickeau                            "sha256-AqqY/JJCWPQwZFY/mAhlvxjC5/880Q331aOmargQVLU="
5864cadd4f8SNickeau                        );
58704fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("aria-label", $label);
58804fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-sharer", $this->getBrand()); // the id
58904fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-link", "false");
59004fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-title", $this->getTextForPage($requestedPage));
5914cadd4f8SNickeau                        $urlToShare = $this->getSharedUrlForPage($requestedPage);
59204fd306cSNickeau                        $buttonAttributes->addOutputAttributeValue("data-url", $urlToShare);
5934cadd4f8SNickeau                        //$linkAttributes->addComponentAttributeValue("href", "#"); // with # we style navigate to the top
59404fd306cSNickeau                        $buttonAttributes->addStyleDeclarationIfNotSet("cursor", "pointer"); // show a pointer (without href, there is none)
5954cadd4f8SNickeau                }
59604fd306cSNickeau                return $buttonAttributes;
5974cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
5984cadd4f8SNickeau
59904fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("title", $label);
60004fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("target", "_blank");
60104fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("rel", "nofollow");
6024cadd4f8SNickeau                $href = $this->getBrandEndpointForPage();
6034cadd4f8SNickeau                if ($href !== null) {
60404fd306cSNickeau                    $buttonAttributes->addOutputAttributeValue("href", $href);
6054cadd4f8SNickeau                }
60604fd306cSNickeau                return $buttonAttributes;
6074cadd4f8SNickeau            case self::TYPE_BUTTON_BRAND:
6084cadd4f8SNickeau                if ($this->brand->getBrandUrl() !== null) {
60904fd306cSNickeau                    $buttonAttributes->addOutputAttributeValue("href", $this->brand->getBrandUrl());
6104cadd4f8SNickeau                }
61104fd306cSNickeau                $buttonAttributes->addOutputAttributeValue("title", $label);
61204fd306cSNickeau                return $buttonAttributes;
6134cadd4f8SNickeau            default:
61404fd306cSNickeau                return $buttonAttributes;
6154cadd4f8SNickeau
6164cadd4f8SNickeau        }
6174cadd4f8SNickeau
6184cadd4f8SNickeau
6194cadd4f8SNickeau    }
6204cadd4f8SNickeau
6214cadd4f8SNickeau
62204fd306cSNickeau    public
6234cadd4f8SNickeau    function getType(): string
6244cadd4f8SNickeau    {
6254cadd4f8SNickeau        return $this->type;
6264cadd4f8SNickeau    }
6274cadd4f8SNickeau
6284cadd4f8SNickeau    public function setHandle(string $handle): BrandButton
6294cadd4f8SNickeau    {
6304cadd4f8SNickeau        $this->handle = $handle;
6314cadd4f8SNickeau        return $this;
6324cadd4f8SNickeau    }
6334cadd4f8SNickeau
6344cadd4f8SNickeau    public function setLinkTitle(string $title): BrandButton
6354cadd4f8SNickeau    {
6364cadd4f8SNickeau        $this->title = $title;
6374cadd4f8SNickeau        return $this;
6384cadd4f8SNickeau    }
6394cadd4f8SNickeau
6404cadd4f8SNickeau    public function setPrimaryColor(string $color): BrandButton
6414cadd4f8SNickeau    {
6424cadd4f8SNickeau        $this->primaryColor = $color;
6434cadd4f8SNickeau        return $this;
6444cadd4f8SNickeau    }
6454cadd4f8SNickeau
64604fd306cSNickeau    private function getResourceIconFile(): WikiPath
6474cadd4f8SNickeau    {
6484cadd4f8SNickeau        $iconName = $this->getResourceIconName();
64904fd306cSNickeau        $iconPath = str_replace(IconDownloader::COMBO, "", $iconName) . ".svg";
65004fd306cSNickeau        return WikiPath::createComboResource($iconPath);
6514cadd4f8SNickeau    }
6524cadd4f8SNickeau
6534cadd4f8SNickeau    public function setSecondaryColor(string $secondaryColor): BrandButton
6544cadd4f8SNickeau    {
6554cadd4f8SNickeau        $this->secondaryColor = $secondaryColor;
6564cadd4f8SNickeau        return $this;
6574cadd4f8SNickeau    }
6584cadd4f8SNickeau
6594cadd4f8SNickeau    private function getResourceIconName(): string
6604cadd4f8SNickeau    {
66104fd306cSNickeau        $comboLibrary = IconDownloader::COMBO;
66204fd306cSNickeau        return "$comboLibrary:brand:{$this->getBrand()->getName()}:{$this->iconType}";
6634cadd4f8SNickeau    }
6644cadd4f8SNickeau
6654cadd4f8SNickeau
6664cadd4f8SNickeau    private function getPrimaryColor(): ?string
6674cadd4f8SNickeau    {
6684cadd4f8SNickeau        if ($this->primaryColor !== null) {
6694cadd4f8SNickeau            return $this->primaryColor;
6704cadd4f8SNickeau        }
6714cadd4f8SNickeau        return $this->brand->getPrimaryColor();
6724cadd4f8SNickeau    }
6734cadd4f8SNickeau
6744cadd4f8SNickeau    private function getSecondaryColor(): ?string
6754cadd4f8SNickeau    {
6764cadd4f8SNickeau        if ($this->secondaryColor !== null) {
6774cadd4f8SNickeau            return $this->secondaryColor;
6784cadd4f8SNickeau        }
6794cadd4f8SNickeau        return $this->brand->getSecondaryColor();
6804cadd4f8SNickeau    }
6814cadd4f8SNickeau
68204fd306cSNickeau    /**
68304fd306cSNickeau     * The button is sometimes:
68404fd306cSNickeau     * * a HTML button
68504fd306cSNickeau     * * and other times a HTML link
68604fd306cSNickeau     *
68704fd306cSNickeau     * It seems that the button is mostly for data-sharer (share button)
68804fd306cSNickeau     *
68904fd306cSNickeau     * A Link should have an href otherwise the SEO scan will not be happy
69004fd306cSNickeau     * A button should have a aria-label
69104fd306cSNickeau     *
69204fd306cSNickeau     * @param $tagAttributes
69304fd306cSNickeau     * @return string
69404fd306cSNickeau     */
69504fd306cSNickeau    public function getHtmlElement($tagAttributes): string
69604fd306cSNickeau    {
69704fd306cSNickeau        if ($tagAttributes->hasAttribute("href")) {
69804fd306cSNickeau            return "a";
69904fd306cSNickeau        } else {
70004fd306cSNickeau            return "button";
70104fd306cSNickeau        }
70204fd306cSNickeau    }
70304fd306cSNickeau
7044cadd4f8SNickeau
7054cadd4f8SNickeau}
706