xref: /plugin/combo/ComboStrap/BrandButton.php (revision 4cadd4f8c541149bdda95f080e38a6d4e3a640ca)
1*4cadd4f8SNickeau<?php
2*4cadd4f8SNickeau
3*4cadd4f8SNickeau
4*4cadd4f8SNickeaunamespace ComboStrap;
5*4cadd4f8SNickeau
6*4cadd4f8SNickeau
7*4cadd4f8SNickeauuse action_plugin_combo_metatwitter;
8*4cadd4f8SNickeau
9*4cadd4f8SNickeau/**
10*4cadd4f8SNickeau *
11*4cadd4f8SNickeau * Brand button
12*4cadd4f8SNickeau *   * basic
13*4cadd4f8SNickeau *   * share
14*4cadd4f8SNickeau *   * follow
15*4cadd4f8SNickeau *
16*4cadd4f8SNickeau * @package ComboStrap
17*4cadd4f8SNickeau *
18*4cadd4f8SNickeau *
19*4cadd4f8SNickeau * Share link:
20*4cadd4f8SNickeau *   * [Link](https://github.com/mxstbr/sharingbuttons.io/blob/master/js/stores/AppStore.js#L242)
21*4cadd4f8SNickeau *   * https://github.com/ellisonleao/sharer.js/blob/main/sharer.js#L72
22*4cadd4f8SNickeau * Style:
23*4cadd4f8SNickeau *   * [Style](https://github.com/mxstbr/sharingbuttons.io/blob/master/js/stores/AppStore.js#L10)
24*4cadd4f8SNickeau *
25*4cadd4f8SNickeau * Popup:
26*4cadd4f8SNickeau * https://gist.github.com/josephabrahams/9d023596b884e80e37e5
27*4cadd4f8SNickeau * https://jonsuh.com/blog/social-share-links/
28*4cadd4f8SNickeau * https://stackoverflow.com/questions/11473345/how-to-pop-up-new-window-with-tweet-button
29*4cadd4f8SNickeau *
30*4cadd4f8SNickeau * Inspired by:
31*4cadd4f8SNickeau * http://sharingbuttons.io (Specifically thanks for the data)
32*4cadd4f8SNickeau */
33*4cadd4f8SNickeauclass BrandButton
34*4cadd4f8SNickeau{
35*4cadd4f8SNickeau    public const WIDGET_BUTTON_VALUE = "button";
36*4cadd4f8SNickeau    public const WIDGET_LINK_VALUE = "link";
37*4cadd4f8SNickeau    const WIDGETS = [self::WIDGET_BUTTON_VALUE, self::WIDGET_LINK_VALUE];
38*4cadd4f8SNickeau    const ICON_SOLID_VALUE = "solid";
39*4cadd4f8SNickeau    const ICON_SOLID_CIRCLE_VALUE = "solid-circle";
40*4cadd4f8SNickeau    const ICON_OUTLINE_CIRCLE_VALUE = "outline-circle";
41*4cadd4f8SNickeau    const ICON_OUTLINE_VALUE = "outline";
42*4cadd4f8SNickeau    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];
43*4cadd4f8SNickeau    const ICON_NONE_VALUE = "none";
44*4cadd4f8SNickeau
45*4cadd4f8SNickeau    const CANONICAL = "social";
46*4cadd4f8SNickeau
47*4cadd4f8SNickeau
48*4cadd4f8SNickeau    /**
49*4cadd4f8SNickeau     * @var string
50*4cadd4f8SNickeau     */
51*4cadd4f8SNickeau    private $widget = self::WIDGET_BUTTON_VALUE;
52*4cadd4f8SNickeau    /**
53*4cadd4f8SNickeau     * @var mixed|string
54*4cadd4f8SNickeau     */
55*4cadd4f8SNickeau    private $iconType = self::ICON_SOLID_VALUE;
56*4cadd4f8SNickeau    /**
57*4cadd4f8SNickeau     * The width of the icon
58*4cadd4f8SNickeau     * @var int|null
59*4cadd4f8SNickeau     */
60*4cadd4f8SNickeau    private $width = null;
61*4cadd4f8SNickeau    /**
62*4cadd4f8SNickeau     * @var string
63*4cadd4f8SNickeau     */
64*4cadd4f8SNickeau    private $type;
65*4cadd4f8SNickeau    const TYPE_BUTTON_SHARE = "share";
66*4cadd4f8SNickeau    const TYPE_BUTTON_FOLLOW = "follow";
67*4cadd4f8SNickeau    const TYPE_BUTTON_BRAND = "brand";
68*4cadd4f8SNickeau    const TYPE_BUTTONS = [self::TYPE_BUTTON_SHARE, self::TYPE_BUTTON_FOLLOW, self::TYPE_BUTTON_BRAND];
69*4cadd4f8SNickeau
70*4cadd4f8SNickeau
71*4cadd4f8SNickeau    /**
72*4cadd4f8SNickeau     * @var string the follow handle
73*4cadd4f8SNickeau     */
74*4cadd4f8SNickeau    private $handle;
75*4cadd4f8SNickeau
76*4cadd4f8SNickeau
77*4cadd4f8SNickeau    /**
78*4cadd4f8SNickeau     * @var Brand
79*4cadd4f8SNickeau     */
80*4cadd4f8SNickeau    private $brand;
81*4cadd4f8SNickeau    private $primaryColor;
82*4cadd4f8SNickeau    private $title;
83*4cadd4f8SNickeau    private $secondaryColor;
84*4cadd4f8SNickeau
85*4cadd4f8SNickeau
86*4cadd4f8SNickeau    /**
87*4cadd4f8SNickeau     * @throws ExceptionCombo
88*4cadd4f8SNickeau     */
89*4cadd4f8SNickeau    public function __construct(
90*4cadd4f8SNickeau        string $brandName,
91*4cadd4f8SNickeau        string $typeButton)
92*4cadd4f8SNickeau    {
93*4cadd4f8SNickeau
94*4cadd4f8SNickeau        $this->brand = Brand::create($brandName);
95*4cadd4f8SNickeau
96*4cadd4f8SNickeau        $this->type = strtolower($typeButton);
97*4cadd4f8SNickeau        if (!in_array($this->type, self::TYPE_BUTTONS)) {
98*4cadd4f8SNickeau            throw new ExceptionCombo("The button type ($this->type} is unknown.");
99*4cadd4f8SNickeau        }
100*4cadd4f8SNickeau
101*4cadd4f8SNickeau
102*4cadd4f8SNickeau    }
103*4cadd4f8SNickeau
104*4cadd4f8SNickeau    /**
105*4cadd4f8SNickeau     * Return all combination of widget type and icon type
106*4cadd4f8SNickeau     * @return array
107*4cadd4f8SNickeau     */
108*4cadd4f8SNickeau    public static function getVariants(): array
109*4cadd4f8SNickeau    {
110*4cadd4f8SNickeau        $variants = [];
111*4cadd4f8SNickeau        foreach (self::WIDGETS as $widget) {
112*4cadd4f8SNickeau            foreach (self::ICON_TYPES as $typeIcon) {
113*4cadd4f8SNickeau                if ($typeIcon === self::ICON_NONE_VALUE) {
114*4cadd4f8SNickeau                    continue;
115*4cadd4f8SNickeau                }
116*4cadd4f8SNickeau                $variants[] = [\syntax_plugin_combo_brand::ICON_ATTRIBUTE => $typeIcon, TagAttributes::TYPE_KEY => $widget];
117*4cadd4f8SNickeau            }
118*4cadd4f8SNickeau        }
119*4cadd4f8SNickeau        return $variants;
120*4cadd4f8SNickeau    }
121*4cadd4f8SNickeau
122*4cadd4f8SNickeau    /**
123*4cadd4f8SNickeau     * @throws ExceptionCombo
124*4cadd4f8SNickeau     */
125*4cadd4f8SNickeau    public static function createBrandButton(string $brand): BrandButton
126*4cadd4f8SNickeau    {
127*4cadd4f8SNickeau        return new BrandButton($brand, self::TYPE_BUTTON_BRAND);
128*4cadd4f8SNickeau    }
129*4cadd4f8SNickeau
130*4cadd4f8SNickeau
131*4cadd4f8SNickeau    /**
132*4cadd4f8SNickeau     * @throws ExceptionCombo
133*4cadd4f8SNickeau     */
134*4cadd4f8SNickeau    public function setWidget($widget): BrandButton
135*4cadd4f8SNickeau    {
136*4cadd4f8SNickeau        /**
137*4cadd4f8SNickeau         * Widget validation
138*4cadd4f8SNickeau         */
139*4cadd4f8SNickeau        $this->widget = $widget;
140*4cadd4f8SNickeau        $widget = trim(strtolower($widget));
141*4cadd4f8SNickeau        if (!in_array($widget, self::WIDGETS)) {
142*4cadd4f8SNickeau            throw new ExceptionCombo("The {$this->type} widget ($widget} is unknown. The possible widgets value are " . implode(",", self::WIDGETS));
143*4cadd4f8SNickeau        }
144*4cadd4f8SNickeau        return $this;
145*4cadd4f8SNickeau    }
146*4cadd4f8SNickeau
147*4cadd4f8SNickeau    /**
148*4cadd4f8SNickeau     * @throws ExceptionCombo
149*4cadd4f8SNickeau     */
150*4cadd4f8SNickeau    public function setIconType($iconType): BrandButton
151*4cadd4f8SNickeau    {
152*4cadd4f8SNickeau        /**
153*4cadd4f8SNickeau         * Icon Validation
154*4cadd4f8SNickeau         */
155*4cadd4f8SNickeau        $this->iconType = $iconType;
156*4cadd4f8SNickeau        $iconType = trim(strtolower($iconType));
157*4cadd4f8SNickeau        if (!in_array($iconType, self::ICON_TYPES)) {
158*4cadd4f8SNickeau            throw new ExceptionCombo("The icon type ($iconType) is unknown. The possible icons value are " . implode(",", self::ICON_TYPES));
159*4cadd4f8SNickeau        }
160*4cadd4f8SNickeau        return $this;
161*4cadd4f8SNickeau    }
162*4cadd4f8SNickeau
163*4cadd4f8SNickeau    public function setWidth(?int $width): BrandButton
164*4cadd4f8SNickeau    {
165*4cadd4f8SNickeau        /**
166*4cadd4f8SNickeau         * Width
167*4cadd4f8SNickeau         */
168*4cadd4f8SNickeau        if ($width === null) {
169*4cadd4f8SNickeau            return $this;
170*4cadd4f8SNickeau        }
171*4cadd4f8SNickeau        $this->width = $width;
172*4cadd4f8SNickeau        return $this;
173*4cadd4f8SNickeau    }
174*4cadd4f8SNickeau
175*4cadd4f8SNickeau    /**
176*4cadd4f8SNickeau     * @throws ExceptionCombo
177*4cadd4f8SNickeau     */
178*4cadd4f8SNickeau    public static function createShareButton(
179*4cadd4f8SNickeau        string $brandName,
180*4cadd4f8SNickeau        string $widget = self::WIDGET_BUTTON_VALUE,
181*4cadd4f8SNickeau        string $icon = self::ICON_SOLID_VALUE,
182*4cadd4f8SNickeau        ?int $width = null): BrandButton
183*4cadd4f8SNickeau    {
184*4cadd4f8SNickeau        return (new BrandButton($brandName, self::TYPE_BUTTON_SHARE))
185*4cadd4f8SNickeau            ->setWidget($widget)
186*4cadd4f8SNickeau            ->setIconType($icon)
187*4cadd4f8SNickeau            ->setWidth($width);
188*4cadd4f8SNickeau    }
189*4cadd4f8SNickeau
190*4cadd4f8SNickeau    /**
191*4cadd4f8SNickeau     * @throws ExceptionCombo
192*4cadd4f8SNickeau     */
193*4cadd4f8SNickeau    public static function createFollowButton(
194*4cadd4f8SNickeau        string $brandName,
195*4cadd4f8SNickeau        string $handle = null,
196*4cadd4f8SNickeau        string $widget = self::WIDGET_BUTTON_VALUE,
197*4cadd4f8SNickeau        string $icon = self::ICON_SOLID_VALUE,
198*4cadd4f8SNickeau        ?int $width = null): BrandButton
199*4cadd4f8SNickeau    {
200*4cadd4f8SNickeau        return (new BrandButton($brandName, self::TYPE_BUTTON_FOLLOW))
201*4cadd4f8SNickeau            ->setHandle($handle)
202*4cadd4f8SNickeau            ->setWidget($widget)
203*4cadd4f8SNickeau            ->setIconType($icon)
204*4cadd4f8SNickeau            ->setWidth($width);
205*4cadd4f8SNickeau    }
206*4cadd4f8SNickeau
207*4cadd4f8SNickeau    /**
208*4cadd4f8SNickeau     * @throws ExceptionCombo
209*4cadd4f8SNickeau     *
210*4cadd4f8SNickeau     * Dictionary has been made with the data found here:
211*4cadd4f8SNickeau     *   * https://github.com/ellisonleao/sharer.js/blob/main/sharer.js#L72
212*4cadd4f8SNickeau     *   * and
213*4cadd4f8SNickeau     */
214*4cadd4f8SNickeau    public function getBrandEndpointForPage(Page $requestedPage = null): ?string
215*4cadd4f8SNickeau    {
216*4cadd4f8SNickeau
217*4cadd4f8SNickeau        /**
218*4cadd4f8SNickeau         * Shared/Follow Url template
219*4cadd4f8SNickeau         */
220*4cadd4f8SNickeau        $urlTemplate = $this->brand->getWebUrlTemplate($this->type);
221*4cadd4f8SNickeau        if ($urlTemplate === null) {
222*4cadd4f8SNickeau            throw new ExceptionCombo("The brand ($this) does not support the $this->type button (The $this->type URL is unknown)");
223*4cadd4f8SNickeau        }
224*4cadd4f8SNickeau        switch ($this->type) {
225*4cadd4f8SNickeau
226*4cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
227*4cadd4f8SNickeau                if ($requestedPage === null) {
228*4cadd4f8SNickeau                    throw new ExceptionCombo("The page requested should not be null for a share button when requesting the endpoint uri.");
229*4cadd4f8SNickeau                }
230*4cadd4f8SNickeau                $canonicalUrl = $this->getSharedUrlForPage($requestedPage);
231*4cadd4f8SNickeau                $templateData["url"] = $canonicalUrl;
232*4cadd4f8SNickeau                $templateData["title"] = $requestedPage->getTitleOrDefault();
233*4cadd4f8SNickeau                $description = $requestedPage->getDescription();
234*4cadd4f8SNickeau                if ($description === null) {
235*4cadd4f8SNickeau                    $description = "";
236*4cadd4f8SNickeau                }
237*4cadd4f8SNickeau                $templateData["description"] = $description;
238*4cadd4f8SNickeau                $templateData["text"] = $this->getTextForPage($requestedPage);
239*4cadd4f8SNickeau                $via = null;
240*4cadd4f8SNickeau                switch ($this->brand->getName()) {
241*4cadd4f8SNickeau                    case \action_plugin_combo_metatwitter::CANONICAL:
242*4cadd4f8SNickeau                        $via = substr(action_plugin_combo_metatwitter::COMBO_STRAP_TWITTER_HANDLE, 1);
243*4cadd4f8SNickeau                        break;
244*4cadd4f8SNickeau                }
245*4cadd4f8SNickeau                if ($via !== null && $via !== "") {
246*4cadd4f8SNickeau                    $templateData["via"] = $via;
247*4cadd4f8SNickeau                }
248*4cadd4f8SNickeau                foreach ($templateData as $key => $value) {
249*4cadd4f8SNickeau                    $templateData[$key] = urlencode($value);
250*4cadd4f8SNickeau                }
251*4cadd4f8SNickeau
252*4cadd4f8SNickeau                return TemplateUtility::renderStringTemplateFromDataArray($urlTemplate, $templateData);
253*4cadd4f8SNickeau
254*4cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
255*4cadd4f8SNickeau                if ($this->handle === null) {
256*4cadd4f8SNickeau                    return $urlTemplate;
257*4cadd4f8SNickeau                }
258*4cadd4f8SNickeau                $templateData["handle"] = $this->handle;
259*4cadd4f8SNickeau                return TemplateUtility::renderStringTemplateFromDataArray($urlTemplate, $templateData);
260*4cadd4f8SNickeau            default:
261*4cadd4f8SNickeau                // The type is mandatory and checked at creation,
262*4cadd4f8SNickeau                // it should not happen, we don't throw an error
263*4cadd4f8SNickeau                $message = "Button type ($this->type) is unknown";
264*4cadd4f8SNickeau                LogUtility::msg($message, LogUtility::LVL_MSG_ERROR, self::CANONICAL);
265*4cadd4f8SNickeau                return $message;
266*4cadd4f8SNickeau        }
267*4cadd4f8SNickeau
268*4cadd4f8SNickeau    }
269*4cadd4f8SNickeau
270*4cadd4f8SNickeau    public function __toString()
271*4cadd4f8SNickeau    {
272*4cadd4f8SNickeau        return $this->brand->__toString();
273*4cadd4f8SNickeau    }
274*4cadd4f8SNickeau
275*4cadd4f8SNickeau    public function getLinkTitle(): string
276*4cadd4f8SNickeau    {
277*4cadd4f8SNickeau        $title = $this->title;
278*4cadd4f8SNickeau        if ($title !== null && trim($title) !== "") {
279*4cadd4f8SNickeau            return $title;
280*4cadd4f8SNickeau        }
281*4cadd4f8SNickeau        $title = $this->brand->getTitle($this->iconType);
282*4cadd4f8SNickeau        if ($title !== null && trim($title) !== "") {
283*4cadd4f8SNickeau            return $title;
284*4cadd4f8SNickeau        }
285*4cadd4f8SNickeau        $name = ucfirst($this->brand->getName());
286*4cadd4f8SNickeau        switch ($this->type) {
287*4cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
288*4cadd4f8SNickeau                return "Share this page via $name";
289*4cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
290*4cadd4f8SNickeau                return "Follow us on $name";
291*4cadd4f8SNickeau            case self::TYPE_BUTTON_BRAND:
292*4cadd4f8SNickeau                return $name;
293*4cadd4f8SNickeau            default:
294*4cadd4f8SNickeau                return "Button type ($this->type) is unknown";
295*4cadd4f8SNickeau        }
296*4cadd4f8SNickeau    }
297*4cadd4f8SNickeau
298*4cadd4f8SNickeau    /**
299*4cadd4f8SNickeau     * @throws ExceptionCombo
300*4cadd4f8SNickeau     */
301*4cadd4f8SNickeau    public
302*4cadd4f8SNickeau    function getStyle(): string
303*4cadd4f8SNickeau    {
304*4cadd4f8SNickeau
305*4cadd4f8SNickeau        /**
306*4cadd4f8SNickeau         * Default colors
307*4cadd4f8SNickeau         */
308*4cadd4f8SNickeau        // make the button/link space square
309*4cadd4f8SNickeau        $properties["padding"] = "0.375rem 0.375rem";
310*4cadd4f8SNickeau        switch ($this->widget) {
311*4cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
312*4cadd4f8SNickeau                $properties["vertical-align"] = "middle";
313*4cadd4f8SNickeau                $properties["display"] = "inline-block";
314*4cadd4f8SNickeau                $primaryColor = $this->getPrimaryColor();
315*4cadd4f8SNickeau                if ($primaryColor !== null) {
316*4cadd4f8SNickeau                    // important because the nav-bar class takes over
317*4cadd4f8SNickeau                    $properties["color"] = "$primaryColor!important";
318*4cadd4f8SNickeau                }
319*4cadd4f8SNickeau                break;
320*4cadd4f8SNickeau            default:
321*4cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
322*4cadd4f8SNickeau
323*4cadd4f8SNickeau                $primary = $this->getPrimaryColor();
324*4cadd4f8SNickeau                if ($primary === null) {
325*4cadd4f8SNickeau                    // custom brand default color
326*4cadd4f8SNickeau                    $primary = ComboStrap::PRIMARY_COLOR;
327*4cadd4f8SNickeau                }
328*4cadd4f8SNickeau                $textColor = $this->getTextColor();
329*4cadd4f8SNickeau                if ($textColor === null || $textColor === "") {
330*4cadd4f8SNickeau                    $textColor = "#fff";
331*4cadd4f8SNickeau                }
332*4cadd4f8SNickeau                $properties["background-color"] = $primary;
333*4cadd4f8SNickeau                $properties["border-color"] = $primary;
334*4cadd4f8SNickeau                $properties["color"] = $textColor;
335*4cadd4f8SNickeau                break;
336*4cadd4f8SNickeau        }
337*4cadd4f8SNickeau        switch ($this->iconType) {
338*4cadd4f8SNickeau            case self::ICON_OUTLINE_VALUE:
339*4cadd4f8SNickeau                // not for outline circle, it's cut otherwise, don't know why
340*4cadd4f8SNickeau                $properties["stroke-width"] = "2px";
341*4cadd4f8SNickeau                break;
342*4cadd4f8SNickeau        }
343*4cadd4f8SNickeau
344*4cadd4f8SNickeau        $cssProperties = "\n";
345*4cadd4f8SNickeau        foreach ($properties as $key => $value) {
346*4cadd4f8SNickeau            $cssProperties .= "    $key:$value;\n";
347*4cadd4f8SNickeau        }
348*4cadd4f8SNickeau        $style = <<<EOF
349*4cadd4f8SNickeau.{$this->getIdentifierClass()} {{$cssProperties}}
350*4cadd4f8SNickeauEOF;
351*4cadd4f8SNickeau
352*4cadd4f8SNickeau        /**
353*4cadd4f8SNickeau         * Hover Style
354*4cadd4f8SNickeau         */
355*4cadd4f8SNickeau        $secondary = $this->getSecondaryColor();
356*4cadd4f8SNickeau        if ($secondary === null) {
357*4cadd4f8SNickeau            return $style;
358*4cadd4f8SNickeau        }
359*4cadd4f8SNickeau        $hoverProperties = [];
360*4cadd4f8SNickeau        switch ($this->widget) {
361*4cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
362*4cadd4f8SNickeau                $hoverProperties["color"] = $secondary;
363*4cadd4f8SNickeau                break;
364*4cadd4f8SNickeau            default:
365*4cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
366*4cadd4f8SNickeau                $textColor = $this->getTextColor();
367*4cadd4f8SNickeau                $hoverProperties["background-color"] = $secondary;
368*4cadd4f8SNickeau                $hoverProperties["border-color"] = $secondary;
369*4cadd4f8SNickeau                $hoverProperties["color"] = $textColor;
370*4cadd4f8SNickeau                break;
371*4cadd4f8SNickeau        }
372*4cadd4f8SNickeau        $hoverCssProperties = "\n";
373*4cadd4f8SNickeau        foreach ($hoverProperties as $key => $value) {
374*4cadd4f8SNickeau            $hoverCssProperties .= "    $key:$value;\n";
375*4cadd4f8SNickeau        }
376*4cadd4f8SNickeau        $hoverStyle = <<<EOF
377*4cadd4f8SNickeau.{$this->getIdentifierClass()}:hover, .{$this->getIdentifierClass()}:active {{$hoverCssProperties}}
378*4cadd4f8SNickeauEOF;
379*4cadd4f8SNickeau
380*4cadd4f8SNickeau        return <<<EOF
381*4cadd4f8SNickeau$style
382*4cadd4f8SNickeau$hoverStyle
383*4cadd4f8SNickeauEOF;
384*4cadd4f8SNickeau
385*4cadd4f8SNickeau
386*4cadd4f8SNickeau    }
387*4cadd4f8SNickeau
388*4cadd4f8SNickeau    public function getBrand(): Brand
389*4cadd4f8SNickeau    {
390*4cadd4f8SNickeau        return $this->brand;
391*4cadd4f8SNickeau    }
392*4cadd4f8SNickeau
393*4cadd4f8SNickeau    /**
394*4cadd4f8SNickeau     * The identifier of the {@link BrandButton::getStyle()} script
395*4cadd4f8SNickeau     * used as script id in the {@link SnippetManager}
396*4cadd4f8SNickeau     * @return string
397*4cadd4f8SNickeau     */
398*4cadd4f8SNickeau    public
399*4cadd4f8SNickeau    function getStyleScriptIdentifier(): string
400*4cadd4f8SNickeau    {
401*4cadd4f8SNickeau        return "{$this->getType()}-{$this->brand->getName()}-{$this->getWidget()}-{$this->getIcon()}";
402*4cadd4f8SNickeau    }
403*4cadd4f8SNickeau
404*4cadd4f8SNickeau    /**
405*4cadd4f8SNickeau     * @return string - the class identifier used in the {@link BrandButton::getStyle()} script
406*4cadd4f8SNickeau     */
407*4cadd4f8SNickeau    public
408*4cadd4f8SNickeau    function getIdentifierClass(): string
409*4cadd4f8SNickeau    {
410*4cadd4f8SNickeau        return "{$this->getStyleScriptIdentifier()}-combo";
411*4cadd4f8SNickeau    }
412*4cadd4f8SNickeau
413*4cadd4f8SNickeau    /**
414*4cadd4f8SNickeau     * @throws ExceptionCombo
415*4cadd4f8SNickeau     */
416*4cadd4f8SNickeau    public
417*4cadd4f8SNickeau    function getIconAttributes(): array
418*4cadd4f8SNickeau    {
419*4cadd4f8SNickeau
420*4cadd4f8SNickeau        $iconName = $this->getResourceIconName();
421*4cadd4f8SNickeau        $icon = $this->getResourceIconFile();
422*4cadd4f8SNickeau        if (!FileSystems::exists($icon)) {
423*4cadd4f8SNickeau            $iconName = $this->brand->getIconName($this->iconType);
424*4cadd4f8SNickeau            $brandNames = Brand::getAllKnownBrandNames();
425*4cadd4f8SNickeau            if ($iconName === null && in_array($this->getBrand(), $brandNames)) {
426*4cadd4f8SNickeau                throw new ExceptionComboNotFound("No {$this->iconType} icon could be found for the known brand ($this)");
427*4cadd4f8SNickeau            }
428*4cadd4f8SNickeau        }
429*4cadd4f8SNickeau        $attributes = [\syntax_plugin_combo_icon::ICON_NAME_ATTRIBUTE => $iconName];
430*4cadd4f8SNickeau        $textColor = $this->getTextColor();
431*4cadd4f8SNickeau        if ($textColor !== null) {
432*4cadd4f8SNickeau            $attributes[ColorRgb::COLOR] = $textColor;
433*4cadd4f8SNickeau        }
434*4cadd4f8SNickeau        $attributes[Dimension::WIDTH_KEY] = $this->getWidth();
435*4cadd4f8SNickeau
436*4cadd4f8SNickeau        return $attributes;
437*4cadd4f8SNickeau    }
438*4cadd4f8SNickeau
439*4cadd4f8SNickeau    public
440*4cadd4f8SNickeau    function getTextColor(): ?string
441*4cadd4f8SNickeau    {
442*4cadd4f8SNickeau
443*4cadd4f8SNickeau        switch ($this->widget) {
444*4cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
445*4cadd4f8SNickeau                return $this->getPrimaryColor();
446*4cadd4f8SNickeau            default:
447*4cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
448*4cadd4f8SNickeau                return "#fff";
449*4cadd4f8SNickeau        }
450*4cadd4f8SNickeau
451*4cadd4f8SNickeau    }
452*4cadd4f8SNickeau
453*4cadd4f8SNickeau    /**
454*4cadd4f8SNickeau     * Class added to the link
455*4cadd4f8SNickeau     * This is just to be boostrap conformance
456*4cadd4f8SNickeau     */
457*4cadd4f8SNickeau    public
458*4cadd4f8SNickeau    function getWidgetClass(): string
459*4cadd4f8SNickeau    {
460*4cadd4f8SNickeau        if ($this->widget === self::WIDGET_BUTTON_VALUE) {
461*4cadd4f8SNickeau            return "btn";
462*4cadd4f8SNickeau        }
463*4cadd4f8SNickeau        return "";
464*4cadd4f8SNickeau    }
465*4cadd4f8SNickeau
466*4cadd4f8SNickeau
467*4cadd4f8SNickeau    public
468*4cadd4f8SNickeau    function getWidget(): string
469*4cadd4f8SNickeau    {
470*4cadd4f8SNickeau        return $this->widget;
471*4cadd4f8SNickeau    }
472*4cadd4f8SNickeau
473*4cadd4f8SNickeau    private
474*4cadd4f8SNickeau    function getIcon()
475*4cadd4f8SNickeau    {
476*4cadd4f8SNickeau        return $this->iconType;
477*4cadd4f8SNickeau    }
478*4cadd4f8SNickeau
479*4cadd4f8SNickeau    private
480*4cadd4f8SNickeau    function getDefaultWidth(): int
481*4cadd4f8SNickeau    {
482*4cadd4f8SNickeau        switch ($this->widget) {
483*4cadd4f8SNickeau            case self::WIDGET_LINK_VALUE:
484*4cadd4f8SNickeau                return 36;
485*4cadd4f8SNickeau            case self::WIDGET_BUTTON_VALUE:
486*4cadd4f8SNickeau            default:
487*4cadd4f8SNickeau                return 24;
488*4cadd4f8SNickeau        }
489*4cadd4f8SNickeau    }
490*4cadd4f8SNickeau
491*4cadd4f8SNickeau    private
492*4cadd4f8SNickeau    function getWidth(): ?int
493*4cadd4f8SNickeau    {
494*4cadd4f8SNickeau        if ($this->width === null) {
495*4cadd4f8SNickeau            return $this->getDefaultWidth();
496*4cadd4f8SNickeau        }
497*4cadd4f8SNickeau        return $this->width;
498*4cadd4f8SNickeau    }
499*4cadd4f8SNickeau
500*4cadd4f8SNickeau    public function hasIcon(): bool
501*4cadd4f8SNickeau    {
502*4cadd4f8SNickeau        if ($this->iconType === self::ICON_NONE_VALUE) {
503*4cadd4f8SNickeau            return false;
504*4cadd4f8SNickeau        }
505*4cadd4f8SNickeau        if ($this->iconType !== null) {
506*4cadd4f8SNickeau            if ($this->brand->getIconName($this->iconType) !== null) {
507*4cadd4f8SNickeau                return true;
508*4cadd4f8SNickeau            }
509*4cadd4f8SNickeau        }
510*4cadd4f8SNickeau        if (!FileSystems::exists($this->getResourceIconFile())) {
511*4cadd4f8SNickeau            return false;
512*4cadd4f8SNickeau        }
513*4cadd4f8SNickeau        return true;
514*4cadd4f8SNickeau    }
515*4cadd4f8SNickeau
516*4cadd4f8SNickeau    public
517*4cadd4f8SNickeau    function getTextForPage(Page $requestedPage): ?string
518*4cadd4f8SNickeau    {
519*4cadd4f8SNickeau        $text = $requestedPage->getTitleOrDefault();
520*4cadd4f8SNickeau        $description = $requestedPage->getDescription();
521*4cadd4f8SNickeau        if ($description !== null) {
522*4cadd4f8SNickeau            $text .= " > $description";
523*4cadd4f8SNickeau        }
524*4cadd4f8SNickeau        return $text;
525*4cadd4f8SNickeau
526*4cadd4f8SNickeau    }
527*4cadd4f8SNickeau
528*4cadd4f8SNickeau    public
529*4cadd4f8SNickeau    function getSharedUrlForPage(Page $requestedPage): ?string
530*4cadd4f8SNickeau    {
531*4cadd4f8SNickeau        return $requestedPage->getCanonicalUrl([], true);
532*4cadd4f8SNickeau    }
533*4cadd4f8SNickeau
534*4cadd4f8SNickeau    /**
535*4cadd4f8SNickeau     * Return the link HTML attributes
536*4cadd4f8SNickeau     * @throws ExceptionCombo
537*4cadd4f8SNickeau     */
538*4cadd4f8SNickeau    public
539*4cadd4f8SNickeau    function getLinkAttributes(Page $requestedPage = null): TagAttributes
540*4cadd4f8SNickeau    {
541*4cadd4f8SNickeau
542*4cadd4f8SNickeau
543*4cadd4f8SNickeau        $logicalTag = $this->type;
544*4cadd4f8SNickeau        $linkAttributes = TagAttributes::createEmpty($logicalTag);
545*4cadd4f8SNickeau        $linkAttributes->addComponentAttributeValue(TagAttributes::TYPE_KEY, $logicalTag);
546*4cadd4f8SNickeau        $linkAttributes->addComponentAttributeValue(TagAttributes::CLASS_KEY, "{$this->getWidgetClass()} {$this->getIdentifierClass()}");
547*4cadd4f8SNickeau        $linkTitle = $this->getLinkTitle();
548*4cadd4f8SNickeau        $linkAttributes->addComponentAttributeValue("title", $linkTitle);
549*4cadd4f8SNickeau        switch ($this->type) {
550*4cadd4f8SNickeau            case self::TYPE_BUTTON_SHARE:
551*4cadd4f8SNickeau
552*4cadd4f8SNickeau                if ($requestedPage === null) {
553*4cadd4f8SNickeau                    throw new ExceptionCombo("The page requested should not be null for a share button");
554*4cadd4f8SNickeau                }
555*4cadd4f8SNickeau
556*4cadd4f8SNickeau                $ariaLabel = "Share on " . ucfirst($this->getBrand());
557*4cadd4f8SNickeau                $linkAttributes->addComponentAttributeValue("aria-label", $ariaLabel);
558*4cadd4f8SNickeau                $linkAttributes->addComponentAttributeValue("rel", "nofollow");
559*4cadd4f8SNickeau
560*4cadd4f8SNickeau                switch ($this->getBrand()) {
561*4cadd4f8SNickeau                    case "whatsapp":
562*4cadd4f8SNickeau                        /**
563*4cadd4f8SNickeau                         * Direct link
564*4cadd4f8SNickeau                         * For whatsapp, the sharer link is not the good one
565*4cadd4f8SNickeau                         */
566*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("target", "_blank");
567*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("href", $this->getBrandEndpointForPage($requestedPage));
568*4cadd4f8SNickeau                        break;
569*4cadd4f8SNickeau                    default:
570*4cadd4f8SNickeau                        /**
571*4cadd4f8SNickeau                         * Sharer
572*4cadd4f8SNickeau                         * https://ellisonleao.github.io/sharer.js/
573*4cadd4f8SNickeau                         */
574*4cadd4f8SNickeau                        /**
575*4cadd4f8SNickeau                         * Opens in a popup
576*4cadd4f8SNickeau                         */
577*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("rel", "noopener");
578*4cadd4f8SNickeau
579*4cadd4f8SNickeau                        PluginUtility::getSnippetManager()->attachJavascriptLibraryForSlot(
580*4cadd4f8SNickeau                            "sharer",
581*4cadd4f8SNickeau                            "https://cdn.jsdelivr.net/npm/sharer.js@0.5.0/sharer.min.js",
582*4cadd4f8SNickeau                            "sha256-AqqY/JJCWPQwZFY/mAhlvxjC5/880Q331aOmargQVLU="
583*4cadd4f8SNickeau                        );
584*4cadd4f8SNickeau
585*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("data-sharer", $this->getBrand()); // the id
586*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("data-link", "false");
587*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("data-title", $this->getTextForPage($requestedPage));
588*4cadd4f8SNickeau                        $urlToShare = $this->getSharedUrlForPage($requestedPage);
589*4cadd4f8SNickeau                        $linkAttributes->addComponentAttributeValue("data-url", $urlToShare);
590*4cadd4f8SNickeau                        //$linkAttributes->addComponentAttributeValue("href", "#"); // with # we style navigate to the top
591*4cadd4f8SNickeau                        $linkAttributes->addStyleDeclarationIfNotSet("cursor", "pointer"); // show a pointer (without href, there is none)
592*4cadd4f8SNickeau                }
593*4cadd4f8SNickeau                return $linkAttributes;
594*4cadd4f8SNickeau            case self::TYPE_BUTTON_FOLLOW:
595*4cadd4f8SNickeau
596*4cadd4f8SNickeau                $ariaLabel = "Follow us on " . ucfirst($this->getBrand());
597*4cadd4f8SNickeau                $linkAttributes->addComponentAttributeValue("aria-label", $ariaLabel);
598*4cadd4f8SNickeau                $linkAttributes->addComponentAttributeValue("target", "_blank");
599*4cadd4f8SNickeau                $linkAttributes->addComponentAttributeValue("rel", "nofollow");
600*4cadd4f8SNickeau                $href = $this->getBrandEndpointForPage();
601*4cadd4f8SNickeau                if ($href !== null) {
602*4cadd4f8SNickeau                    $linkAttributes->addComponentAttributeValue("href", $href);
603*4cadd4f8SNickeau                }
604*4cadd4f8SNickeau                return $linkAttributes;
605*4cadd4f8SNickeau            case self::TYPE_BUTTON_BRAND:
606*4cadd4f8SNickeau                if ($this->brand->getBrandUrl() !== null) {
607*4cadd4f8SNickeau                    $linkAttributes->addComponentAttributeValue("href", $this->brand->getBrandUrl());
608*4cadd4f8SNickeau                }
609*4cadd4f8SNickeau                return $linkAttributes;
610*4cadd4f8SNickeau            default:
611*4cadd4f8SNickeau                return $linkAttributes;
612*4cadd4f8SNickeau
613*4cadd4f8SNickeau        }
614*4cadd4f8SNickeau
615*4cadd4f8SNickeau
616*4cadd4f8SNickeau    }
617*4cadd4f8SNickeau
618*4cadd4f8SNickeau
619*4cadd4f8SNickeau    private
620*4cadd4f8SNickeau    function getType(): string
621*4cadd4f8SNickeau    {
622*4cadd4f8SNickeau        return $this->type;
623*4cadd4f8SNickeau    }
624*4cadd4f8SNickeau
625*4cadd4f8SNickeau    public function setHandle(string $handle): BrandButton
626*4cadd4f8SNickeau    {
627*4cadd4f8SNickeau        $this->handle = $handle;
628*4cadd4f8SNickeau        return $this;
629*4cadd4f8SNickeau    }
630*4cadd4f8SNickeau
631*4cadd4f8SNickeau    public function setLinkTitle(string $title): BrandButton
632*4cadd4f8SNickeau    {
633*4cadd4f8SNickeau        $this->title = $title;
634*4cadd4f8SNickeau        return $this;
635*4cadd4f8SNickeau    }
636*4cadd4f8SNickeau
637*4cadd4f8SNickeau    public function setPrimaryColor(string $color): BrandButton
638*4cadd4f8SNickeau    {
639*4cadd4f8SNickeau        $this->primaryColor = $color;
640*4cadd4f8SNickeau        return $this;
641*4cadd4f8SNickeau    }
642*4cadd4f8SNickeau
643*4cadd4f8SNickeau    private function getResourceIconFile(): DokuPath
644*4cadd4f8SNickeau    {
645*4cadd4f8SNickeau        $iconName = $this->getResourceIconName();
646*4cadd4f8SNickeau        $iconPath = str_replace(Icon::COMBO . ":", "", $iconName) . ".svg";
647*4cadd4f8SNickeau        return DokuPath::createComboResource($iconPath);
648*4cadd4f8SNickeau    }
649*4cadd4f8SNickeau
650*4cadd4f8SNickeau    public function setSecondaryColor(string $secondaryColor): BrandButton
651*4cadd4f8SNickeau    {
652*4cadd4f8SNickeau        $this->secondaryColor = $secondaryColor;
653*4cadd4f8SNickeau        return $this;
654*4cadd4f8SNickeau    }
655*4cadd4f8SNickeau
656*4cadd4f8SNickeau    private function getResourceIconName(): string
657*4cadd4f8SNickeau    {
658*4cadd4f8SNickeau        $comboLibrary = Icon::COMBO;
659*4cadd4f8SNickeau        return "$comboLibrary:brand:{$this->getBrand()}:{$this->iconType}";
660*4cadd4f8SNickeau    }
661*4cadd4f8SNickeau
662*4cadd4f8SNickeau
663*4cadd4f8SNickeau    private function getPrimaryColor(): ?string
664*4cadd4f8SNickeau    {
665*4cadd4f8SNickeau        if ($this->primaryColor !== null) {
666*4cadd4f8SNickeau            return $this->primaryColor;
667*4cadd4f8SNickeau        }
668*4cadd4f8SNickeau        return $this->brand->getPrimaryColor();
669*4cadd4f8SNickeau    }
670*4cadd4f8SNickeau
671*4cadd4f8SNickeau    private function getSecondaryColor(): ?string
672*4cadd4f8SNickeau    {
673*4cadd4f8SNickeau        if ($this->secondaryColor !== null) {
674*4cadd4f8SNickeau            return $this->secondaryColor;
675*4cadd4f8SNickeau        }
676*4cadd4f8SNickeau        return $this->brand->getSecondaryColor();
677*4cadd4f8SNickeau    }
678*4cadd4f8SNickeau
679*4cadd4f8SNickeau
680*4cadd4f8SNickeau}
681