1<?php 2 3require_once(__DIR__ . "/../ComboStrap/PluginUtility.php"); 4 5use ComboStrap\BrandButton; 6use ComboStrap\CacheManager; 7use ComboStrap\CacheDependencies; 8use ComboStrap\Call; 9use ComboStrap\CallStack; 10use ComboStrap\ExceptionCombo; 11use ComboStrap\Icon; 12use ComboStrap\LogUtility; 13use ComboStrap\Page; 14use ComboStrap\CacheRuntimeDependencies2; 15use ComboStrap\PluginUtility; 16use ComboStrap\TagAttributes; 17 18 19/** 20 * 21 * See also: 22 * Mobile sharing: https://web.dev/web-share/ 23 * https://twitter.com/addyosmani/status/1490055796704497665?s=21 24 */ 25class syntax_plugin_combo_share extends DokuWiki_Syntax_Plugin 26{ 27 28 29 const TAG = "share"; 30 const CANONICAL = self::TAG; 31 32 33 function getType(): string 34 { 35 return 'substition'; 36 } 37 38 /** 39 * How Dokuwiki will add P element 40 * 41 * * 'normal' - The plugin can be used inside paragraphs (inline) 42 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 43 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 44 * 45 * @see DokuWiki_Syntax_Plugin::getPType() 46 */ 47 function getPType(): string 48 { 49 return 'normal'; 50 } 51 52 /** 53 * @return array 54 * Allow which kind of plugin inside 55 * 56 * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 57 * because we manage self the content and we call self the parser 58 */ 59 function getAllowedTypes(): array 60 { 61 return array('substition', 'formatting', 'disabled'); 62 } 63 64 function getSort(): int 65 { 66 return 201; 67 } 68 69 70 function connectTo($mode) 71 { 72 73 /** 74 * The empty tag pattern should be before the container pattern 75 */ 76 $this->Lexer->addSpecialPattern(PluginUtility::getEmptyTagPattern(self::TAG), $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 77 78 /** 79 * Container 80 */ 81 $entryPattern = PluginUtility::getContainerTagPattern(self::TAG); 82 $this->Lexer->addEntryPattern($entryPattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 83 84 85 } 86 87 public function postConnect() 88 { 89 90 $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent())); 91 92 } 93 94 function handle($match, $state, $pos, Doku_Handler $handler): array 95 { 96 97 $returnArray = array( 98 PluginUtility::STATE => $state, 99 ); 100 switch ($state) { 101 102 case DOKU_LEXER_ENTER: 103 case DOKU_LEXER_SPECIAL: 104 105 $defaultAttributes = []; 106 $types = null; 107 $shareAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, $types) 108 ->setLogicalTag(self::TAG); 109 110 111 /** 112 * Return the data to add the snippet style in rendering 113 */ 114 $returnArray[PluginUtility::ATTRIBUTES] = $shareAttributes->toCallStackArray(); 115 return $returnArray; 116 117 118 case DOKU_LEXER_EXIT: 119 120 return $returnArray; 121 122 case DOKU_LEXER_UNMATCHED: 123 124 return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 125 126 127 } 128 return $returnArray; 129 130 } 131 132 /** 133 * Render the output 134 * @param string $format 135 * @param Doku_Renderer $renderer 136 * @param array $data - what the function handle() return'ed 137 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 138 * @see DokuWiki_Syntax_Plugin::render() 139 * 140 * 141 */ 142 function render($format, Doku_Renderer $renderer, $data): bool 143 { 144 if ($format === "xhtml") { 145 $state = $data[PluginUtility::STATE]; 146 switch ($state) { 147 case DOKU_LEXER_SPECIAL: 148 case DOKU_LEXER_ENTER: 149 150 $shareAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 151 152 /** 153 * The channel 154 */ 155 try { 156 $brandButton = syntax_plugin_combo_brand::createButtonFromAttributes($shareAttributes, BrandButton::TYPE_BUTTON_SHARE); 157 } catch (ExceptionCombo $e) { 158 $renderer->doc .= LogUtility::wrapInRedForHtml("The brand creation returns an error ({$e->getMessage()}"); 159 return false; 160 } 161 162 163 /** 164 * Standard link attribute 165 * and Runtime Cache key dependencies 166 */ 167 CacheManager::getOrCreate()->addDependencyForCurrentSlot(CacheDependencies::REQUESTED_PAGE_DEPENDENCY); 168 try { 169 $requestedPage = Page::createPageFromRequestedPage(); 170 } catch (ExceptionCombo $e) { 171 $renderer->doc .= LogUtility::wrapInRedForHtml("The requested page could not be determined. Error: ({$e->getMessage()}"); 172 return false; 173 } 174 try { 175 $linkAttributes = $brandButton->getLinkAttributes($requestedPage) 176 ->setType($shareAttributes->getType()) 177 ->setLogicalTag(self::TAG); 178 } catch (ExceptionCombo $e) { 179 $renderer->doc .= LogUtility::wrapInRedForHtml("The social channel creation returns an error when creating the link ({$e->getMessage()}"); 180 return false; 181 } 182 183 /** 184 * Add the link 185 */ 186 $renderer->doc .= $linkAttributes->toHtmlEnterTag("a"); 187 188 /** 189 * Icon 190 */ 191 if ($brandButton->hasIcon()) { 192 try { 193 $iconAttributes = $brandButton->getIconAttributes(); 194 $name = $iconAttributes[\syntax_plugin_combo_icon::ICON_NAME_ATTRIBUTE]; 195 unset($iconAttributes[\syntax_plugin_combo_icon::ICON_NAME_ATTRIBUTE]); 196 $iconAttributes = TagAttributes::createFromCallStackArray($iconAttributes); 197 $renderer->doc .= Icon::create($name, $iconAttributes) 198 ->render(); 199 } catch (ExceptionCombo $e) { 200 $renderer->doc .= LogUtility::wrapInRedForHtml("Getting the icon for the social channel ($brandButton) returns an error ({$e->getMessage()}"); 201 // don't return because the anchor link is open 202 } 203 } 204 205 206 if ($state === DOKU_LEXER_SPECIAL) { 207 $renderer->doc .= "</a>"; 208 } 209 210 211 try { 212 $style = $brandButton->getStyle(); 213 } catch (ExceptionCombo $e) { 214 $renderer->doc .= LogUtility::wrapInRedForHtml("The style of the share button ($brandButton) could not be determined. Error: {$e->getMessage()}"); 215 return false; 216 } 217 $snippetId = $brandButton->getStyleScriptIdentifier(); 218 PluginUtility::getSnippetManager()->attachCssInternalStyleSheetForSlot($snippetId, $style); 219 break; 220 case DOKU_LEXER_EXIT: 221 $renderer->doc .= "</a>"; 222 break; 223 case DOKU_LEXER_UNMATCHED: 224 $renderer->doc .= PluginUtility::renderUnmatched($data); 225 break; 226 default: 227 228 } 229 return true; 230 } 231 232 // unsupported $mode 233 return false; 234 } 235 236 237 private function closeLinkInCallStack(CallStack $callStack) 238 { 239 $callStack->appendCallAtTheEnd( 240 Call::createComboCall( 241 syntax_plugin_combo_link::TAG, 242 DOKU_LEXER_EXIT 243 )); 244 } 245 246 247} 248 249