1<?php 2 3 4// must be run within Dokuwiki 5use ComboStrap\Brand; 6use ComboStrap\BrandButton; 7use ComboStrap\BrandTag; 8use ComboStrap\IconTag; 9use ComboStrap\MarkupCacheDependencies; 10use ComboStrap\CacheManager; 11use ComboStrap\Call; 12use ComboStrap\CallStack; 13use ComboStrap\ColorRgb; 14use ComboStrap\Dimension; 15use ComboStrap\ExceptionCompile; 16use ComboStrap\Icon; 17use ComboStrap\IconDownloader; 18use ComboStrap\LogUtility; 19use ComboStrap\MarkupPath; 20use ComboStrap\MediaMarkup; 21use ComboStrap\PluginUtility; 22use ComboStrap\Site; 23use ComboStrap\TagAttributes; 24use ComboStrap\Template; 25use ComboStrap\XmlTagProcessing; 26 27if (!defined('DOKU_INC')) die(); 28 29 30class syntax_plugin_combo_brand extends DokuWiki_Syntax_Plugin 31{ 32 33 const TAG = "brand"; 34 const CANONICAL = self::TAG; 35 36 37 public static function addOpenLinkTagInCallStack(CallStack $callStack, TagAttributes $tagAttributes) 38 { 39 $linkArrayAttributes = $tagAttributes->toCallStackArray(); 40 $linkArrayAttributes[TagAttributes::TYPE_KEY] = $tagAttributes->getLogicalTag(); 41 $linkAttributes = TagAttributes::createFromCallStackArray($linkArrayAttributes); 42 syntax_plugin_combo_link::addOpenLinkTagInCallStack($callStack, $linkAttributes); 43 } 44 45 46 /** 47 * Syntax Type. 48 * 49 * Needs to return one of the mode types defined in $PARSER_MODES in parser.php 50 * @see DokuWiki_Syntax_Plugin::getType() 51 */ 52 function getType(): string 53 { 54 return 'substition'; 55 } 56 57 /** 58 * How Dokuwiki will add P element 59 * 60 * * 'normal' - The plugin can be used inside paragraphs 61 * * 'block' - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs 62 * * 'stack' - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs 63 * 64 * @see DokuWiki_Syntax_Plugin::getPType() 65 */ 66 function getPType(): string 67 { 68 return 'normal'; 69 } 70 71 /** 72 * @return array 73 * Allow which kind of plugin inside 74 * 75 * array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs') 76 * 77 */ 78 function getAllowedTypes(): array 79 { 80 return array('baseonly', 'formatting', 'substition', 'protected', 'disabled'); 81 } 82 83 function getSort(): int 84 { 85 return 201; 86 } 87 88 public 89 function accepts($mode): bool 90 { 91 return syntax_plugin_combo_preformatted::disablePreformatted($mode); 92 } 93 94 95 /** 96 * Create a pattern that will called this plugin 97 * 98 * @param string $mode 99 * @see Doku_Parser_Mode::connectTo() 100 */ 101 function connectTo($mode) 102 { 103 104 $pattern = XmlTagProcessing::getContainerTagPattern(self::getTag()); 105 $this->Lexer->addEntryPattern($pattern, $mode, 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 106 107 /** 108 * The empty tag pattern should be after the container pattern 109 */ 110 $this->Lexer->addSpecialPattern(PluginUtility::getEmptyTagPattern(self::TAG), $mode, PluginUtility::getModeFromTag($this->getPluginComponent())); 111 112 } 113 114 function postConnect() 115 { 116 117 $this->Lexer->addExitPattern('</' . self::getTag() . '>', 'plugin_' . PluginUtility::PLUGIN_BASE_NAME . '_' . $this->getPluginComponent()); 118 119 } 120 121 function handle($match, $state, $pos, Doku_Handler $handler) 122 { 123 124 125 switch ($state) { 126 127 case DOKU_LEXER_SPECIAL : 128 case DOKU_LEXER_ENTER : 129 130 /** 131 * Tag building 132 */ 133 $defaultAttributes = [TagAttributes::TYPE_KEY => Brand::CURRENT_BRAND]; 134 $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, [], true) 135 ->setLogicalTag(BrandTag::MARKUP); 136 137 /** 138 * Extra properties 139 */ 140 $returnedArray = BrandTag::handleSpecialEnter($tagAttributes, $handler); 141 142 /** 143 * Common properties 144 */ 145 $returnedArray[PluginUtility::STATE] = $state; 146 $returnedArray[PluginUtility::ATTRIBUTES] = $tagAttributes->toCallStackArray(); 147 return $returnedArray; 148 149 case DOKU_LEXER_UNMATCHED : 150 return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler); 151 152 case DOKU_LEXER_EXIT : 153 154 $callStack = CallStack::createFromHandler($handler); 155 $openTag = $callStack->moveToPreviousCorrespondingOpeningCall(); 156 $openTagAttributes = TagAttributes::createFromCallStackArray($openTag->getAttributes()); 157 $openTagContext = $openTag->getContext(); 158 /** 159 * Old syntax 160 * An icon/image could be already inside 161 * We go from end to start to 162 * see if there is also a text, if this is the case, 163 * there is a class added on the media 164 */ 165 $markupIconImageFound = false; 166 $textFound = false; 167 $callStack->moveToEnd(); 168 while ($actualCall = $callStack->previous()) { 169 $tagName = $actualCall->getTagName(); 170 if (in_array($tagName, [IconTag::TAG, syntax_plugin_combo_media::TAG])) { 171 172 173 if ($textFound && $openTagContext === syntax_plugin_combo_menubar::TAG) { 174 // if text and icon 175 // We add it here because, if they are present, we don't add them later 176 // for all on raster image 177 $actualCall->addClassName(BrandTag::BOOTSTRAP_NAV_BAR_IMAGE_AND_TEXT_CLASS); 178 } 179 180 // is it a added call / no content 181 // or is it an icon from the markup 182 if ($actualCall->getCapturedContent() === null) { 183 184 // It's an added call 185 // No user icon, image can be found anymore 186 // exiting 187 break; 188 } 189 190 $primary = $openTagAttributes->getValue(ColorRgb::PRIMARY_VALUE); 191 if ($primary !== null && $tagName === IconTag::TAG) { 192 try { 193 $brandButton = BrandTag::createButtonFromAttributes($openTagAttributes); 194 $actualCall->addAttribute(ColorRgb::COLOR, $brandButton->getTextColor()); 195 } catch (ExceptionCompile $e) { 196 LogUtility::msg("Error while trying to set the icon color on exit. Error: {$e->getMessage()}"); 197 } 198 } 199 200 201 // no linking inside a brand 202 $actualCall->addAttribute(MediaMarkup::LINKING_KEY, MediaMarkup::LINKING_NOLINK_VALUE); 203 $markupIconImageFound = true; 204 205 } 206 if ($actualCall->getState() === DOKU_LEXER_UNMATCHED) { 207 $textFound = true; 208 } 209 } 210 $openTag->setPluginData(BrandTag::BRAND_IMAGE_FOUND_INDICATOR, $markupIconImageFound); 211 $openTag->setPluginData(BrandTag::BRAND_TEXT_FOUND_INDICATOR, $textFound); 212 213 return array( 214 PluginUtility::STATE => $state 215 ); 216 217 218 } 219 return array(); 220 221 } 222 223 /** 224 * Render the output 225 * @param string $format 226 * @param Doku_Renderer $renderer 227 * @param array $data - what the function handle() return 228 * @return boolean - rendered correctly? (however, returned value is not used at the moment) 229 * @see DokuWiki_Syntax_Plugin::render() 230 * 231 * 232 */ 233 function render($format, Doku_Renderer $renderer, $data): bool 234 { 235 236 if ($format === "xhtml") { 237 $state = $data[PluginUtility::STATE]; 238 switch ($state) { 239 case DOKU_LEXER_SPECIAL: 240 case DOKU_LEXER_ENTER: 241 $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]); 242 $renderer->doc .= BrandTag::render($tagAttributes, $state, $data);; 243 break; 244 case DOKU_LEXER_UNMATCHED: 245 $renderer->doc .= PluginUtility::renderUnmatched($data); 246 break; 247 case DOKU_LEXER_EXIT: 248 $renderer->doc .= "</a>"; 249 break; 250 251 } 252 return true; 253 } 254 255 // unsupported $mode 256 return false; 257 } 258 259 public 260 static function getTag(): string 261 { 262 return self::TAG; 263 } 264 265 /** 266 * 267 * @throws ExceptionCompile 268 */ 269 public 270 static function addIconInCallStack(CallStack $callStack, BrandButton $brandButton) 271 { 272 273 if (!$brandButton->hasIcon()) { 274 return; 275 } 276 $iconAttributes = $brandButton->getIconAttributes(); 277 278 $callStack->appendCallAtTheEnd( 279 Call::createComboCall( 280 IconTag::TAG, 281 DOKU_LEXER_SPECIAL, 282 $iconAttributes 283 )); 284 } 285 286} 287 288