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