xref: /plugin/combo/ComboStrap/XmlTagProcessing.php (revision 04fd306c7c155fa133ebb3669986875d65988276)
1<?php
2
3namespace ComboStrap;
4
5
6use ComboStrap\Tag\AdTag;
7use ComboStrap\Tag\BackgroundTag;
8use ComboStrap\Tag\BarTag;
9use ComboStrap\Tag\BoxTag;
10use ComboStrap\Tag\FollowTag;
11use ComboStrap\Tag\MermaidTag;
12use ComboStrap\Tag\RelatedTag;
13use ComboStrap\Tag\ShareTag;
14use ComboStrap\Tag\SubscribeTag;
15use ComboStrap\Tag\TableTag;
16use ComboStrap\Tag\WebCodeTag;
17use ComboStrap\TagAttribute\Hero;
18use Doku_Handler;
19use Doku_Renderer;
20use Doku_Renderer_metadata;
21use Doku_Renderer_xhtml;
22use DokuWiki_Syntax_Plugin;
23use Mpdf\Tag\Sub;
24use renderer_plugin_combo_analytics;
25use renderer_plugin_combo_xml;
26use syntax_plugin_combo_code;
27
28
29class XmlTagProcessing
30{
31
32
33    /**
34     * The start tag pattern does not allow > or /
35     * in the data to not compete with the empty tag pattern (ie <empty/>
36     */
37    public const START_TAG_PATTERN = '<[\w-]+[^/>]*>';
38
39
40    public static function renderStaticExitXhtml(TagAttributes $tagAttributes, Doku_Renderer_xhtml $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
41    {
42        $logicalTag = $tagAttributes->getLogicalTag();
43        switch ($logicalTag) {
44            case BlockquoteTag::TAG:
45                BlockquoteTag::renderExitXhtml($tagAttributes, $renderer, $data);
46                return true;
47            case BoxTag::TAG:
48                $renderer->doc .= BoxTag::renderExitXhtml($tagAttributes);
49                return true;
50            case ButtonTag::LOGICAL_TAG:
51                $renderer->doc .= ButtonTag::renderExitXhtml($data);
52                return true;
53            case CardTag::LOGICAL_TAG:
54                CardTag::handleExitXhtml($data, $renderer);
55                return true;
56            case BarTag::LOGICAL_TAG:
57                $renderer->doc .= BarTag::renderExitXhtml($data);
58                return true;
59            case CarrouselTag::TAG:
60                $renderer->doc .= CarrouselTag::renderExitXhtml();
61                return true;
62            case PrismTags::CONSOLE_TAG:
63            case PrismTags::FILE_TAG:
64                PrismTags::processExitXhtml($tagAttributes, $renderer);
65                return true;
66            case ContainerTag::TAG:
67                $renderer->doc .= ContainerTag::renderExitXhtml();
68                return true;
69            case GridTag::LOGICAL_TAG:
70                $renderer->doc .= GridTag::renderExitXhtml($tagAttributes);
71                return true;
72            case PipelineTag::TAG:
73            case DateTag::TAG:
74            case PageExplorerTag::LOGICAL_TAG:
75            case PermalinkTag::TAG:
76            case IconTag::TAG:
77            case MermaidTag::LOGICAL_TAG:
78                return true;
79            case DropDownTag::TAG:
80                $renderer->doc .= DropDownTag::renderExitXhtml();
81                return true;
82            case HeadingTag::LOGICAL_TAG:
83                $context = $data[PluginUtility::CONTEXT];
84                $renderer->doc .= HeadingTag::renderClosingTag($tagAttributes, $context);
85                return true;
86            case NoteTag::TAG_INOTE:
87                $renderer->doc .= NoteTag::renderClosingInlineNote();
88                return true;
89            case JumbotronTag::TAG:
90                $renderer->doc .= JumbotronTag::renderExitHtml();
91                return true;
92            case MasonryTag::LOGICAL_TAG:
93                $renderer->doc .= MasonryTag::renderExitHtml();
94                return true;
95            case SectionTag::TAG:
96                $renderer->doc .= SectionTag::renderExitXhtml();
97                return true;
98            case TabsTag::TAG:
99                $renderer->doc .= TabsTag::renderExitXhtml($tagAttributes, $data);
100                return true;
101            case PanelTag::PANEL_LOGICAL_MARKUP:
102                $renderer->doc .= PanelTag::renderExitXhtml($data);
103                return true;
104            case BackgroundTag::LOGICAL_TAG:
105                $renderer->doc .= BackgroundTag::renderExitSpecialHtml($data);
106                return true;
107            case WebCodeTag::TAG:
108                $renderer->doc .= WebCodeTag::renderExit($tagAttributes, $data);
109                return true;
110            case ShareTag::MARKUP:
111                $renderer->doc .= ShareTag::renderExit();
112                return true;
113            case FollowTag::MARKUP:
114                $renderer->doc .= FollowTag::renderExit();
115                return true;
116            default:
117                LogUtility::warning("The exit tag (" . $logicalTag . ") was not processed.");
118                return false;
119        }
120
121    }
122
123    /**
124     * Static because it handle inline and block tag
125     * @param string $match
126     * @param int $state
127     * @param int $pos
128     * @param Doku_Handler $handler
129     * @param DokuWiki_Syntax_Plugin $plugin
130     * @return array
131     */
132    public static function handleStatic(string $match, int $state, int $pos, Doku_Handler $handler, DokuWiki_Syntax_Plugin $plugin): array
133    {
134        /**
135         * Logical Tag Building
136         */
137        switch ($state) {
138
139            case DOKU_LEXER_ENTER:
140
141                return self::handleStaticEnter($match, $pos, $handler, $plugin);
142
143            case DOKU_LEXER_UNMATCHED :
144
145                $data = PluginUtility::handleAndReturnUnmatchedData(null, $match, $handler);
146                /**
147                 * Attribute of parent are send for context
148                 * (example `display = none`)
149                 */
150                $callStack = CallStack::createFromHandler($handler);
151                $parentTag = $callStack->moveToParent();
152                if ($parentTag !== false) {
153                    $tagAttributes = $parentTag->getAttributes();
154                    $data[PluginUtility::ATTRIBUTES] = $tagAttributes;
155                }
156                return $data;
157
158            case DOKU_LEXER_EXIT :
159
160                return self::handleStaticExit($match, $pos, $handler, $plugin);
161
162
163            default:
164                throw new ExceptionRuntimeInternal("Should not happen");
165        }
166    }
167
168    public static function renderStaticEnterXhtml(TagAttributes $tagAttributes, Doku_Renderer_xhtml $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
169    {
170
171        $context = $data[PluginUtility::CONTEXT];
172        $pos = $data[PluginUtility::POSITION];
173        $logicalTag = $tagAttributes->getLogicalTag();
174        switch ($logicalTag) {
175            case BlockquoteTag::TAG:
176                $renderer->doc .= BlockquoteTag::renderEnterXhtml($tagAttributes, $data, $renderer);
177                return true;
178            case BoxTag::TAG:
179                $renderer->doc .= BoxTag::renderEnterXhtml($tagAttributes);
180                return true;
181            case ButtonTag::LOGICAL_TAG:
182                $renderer->doc .= ButtonTag::renderEnterXhtml($tagAttributes, $plugin, $data);
183                return true;
184            case CardTag::LOGICAL_TAG:
185                $renderer->doc .= CardTag::renderEnterXhtml($tagAttributes, $renderer, $data);
186                return true;
187            case BarTag::LOGICAL_TAG:
188                $renderer->doc .= BarTag::renderEnterXhtml($tagAttributes, $data);
189                return true;
190            case CarrouselTag::TAG:
191                $renderer->doc .= CarrouselTag::renderEnterXhtml($tagAttributes, $data);
192                return true;
193            case PrismTags::CONSOLE_TAG:
194            case PrismTags::FILE_TAG:
195                PrismTags::processEnterXhtml($tagAttributes, $plugin, $renderer);
196                return true;
197            case ContainerTag::TAG:
198                $renderer->doc .= ContainerTag::renderEnterXhtml($tagAttributes);
199                return true;
200            case GridTag::LOGICAL_TAG:
201                $renderer->doc .= GridTag::renderEnterXhtml($tagAttributes);
202                return true;
203            case PipelineTag::TAG:
204                $renderer->doc .= PipelineTag::renderEnterXhtml($tagAttributes);
205                return true;
206            case DateTag::TAG:
207                $renderer->doc .= DateTag::renderHtml($tagAttributes);
208                return true;
209            case DropDownTag::TAG:
210                $renderer->doc .= DropDownTag::renderEnterXhtml($tagAttributes);
211                return true;
212            case HeadingTag::LOGICAL_TAG:
213                HeadingTag::processRenderEnterXhtml($context, $tagAttributes, $renderer, $pos);
214                return true;
215            case NoteTag::TAG_INOTE:
216                $renderer->doc .= NoteTag::renderEnterInlineNote($tagAttributes);
217                return true;
218            case JumbotronTag::TAG:
219                $renderer->doc .= JumbotronTag::renderEnterXhtml($tagAttributes);
220                return true;
221            case MasonryTag::LOGICAL_TAG:
222                $renderer->doc .= MasonryTag::renderEnterTag();
223                return true;
224            case PageExplorerTag::LOGICAL_TAG:
225                $renderer->doc .= PageExplorerTag::renderEnterTag($tagAttributes, $data);
226                return true;
227            case SectionTag::TAG:
228                $renderer->doc .= SectionTag::renderEnterXhtml($tagAttributes);
229                return true;
230            case TabsTag::TAG:
231                $renderer->doc .= TabsTag::renderEnterXhtml($tagAttributes, $data);
232                return true;
233            case PanelTag::PANEL_LOGICAL_MARKUP:
234                $renderer->doc .= PanelTag::renderEnterXhtml($tagAttributes, $data);
235                return true;
236            case PermalinkTag::TAG:
237                $renderer->doc .= PermalinkTag::renderEnterSpecialXhtml($data);
238                return true;
239            case HrTag::TAG:
240                $renderer->doc .= HrTag::render($tagAttributes);
241                return true;
242            case IconTag::TAG:
243                $renderer->doc .= IconTag::renderEnterTag($tagAttributes);
244                return true;
245            case BackgroundTag::LOGICAL_TAG:
246                $renderer->doc .= BackgroundTag::renderEnterTag();
247                return true;
248            case MermaidTag::LOGICAL_TAG:
249                $renderer->doc .= MermaidTag::renderEnter($tagAttributes);
250                return true;
251            case WebCodeTag::TAG:
252                return true;
253            case ShareTag::MARKUP:
254                $renderer->doc .= ShareTag::renderSpecialEnter($tagAttributes, DOKU_LEXER_ENTER);
255                return true;
256            case FollowTag::MARKUP:
257                $renderer->doc .= FollowTag::renderSpecialEnterNode($tagAttributes, DOKU_LEXER_ENTER);
258                return true;
259            case TableTag::TAG:
260                TableTag::renderEnterXhtml($tagAttributes, $renderer);
261                return true;
262            case RelatedTag::TAG:
263                LogUtility::warning("The related tag should be closed. You should write <related/> and not <related>.");
264                $renderer->doc .= RelatedTag::render($tagAttributes);
265                return true;
266            default:
267                LogUtility::warning("The enter tag (" . $logicalTag . ") was not processed.");
268                return false;
269        }
270    }
271
272    public static function handleStaticEnter(string $match, int $pos, Doku_Handler $handler, DokuWiki_Syntax_Plugin $plugin): array
273    {
274        // context data
275        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
276
277        // Normalize Trim and delete eol to start clean
278        $match = trim($match);
279        $match = str_replace("\n"," ",$match);
280
281        // Markup
282        $markupTag = PluginUtility::getMarkupTag($match);
283        $logicalTag = $markupTag;
284        $defaultAttributes = [];
285        $knownTypes = [];
286        $allowAnyFirstBooleanAttributesAsType = false;
287
288        // code block allow a second attribute value as file name
289        $hasTwoBooleanAttribute = false;
290        $secondBooleanAttribute = null;
291
292        switch ($markupTag) {
293            case BlockquoteTag::TAG:
294                // Suppress the component name
295                $defaultAttributes = array("type" => BlockquoteTag::CARD_TYPE);
296                $knownTypes = [BlockquoteTag::TYPO_TYPE, BlockquoteTag::CARD_TYPE];;
297                break;
298            case BoxTag::TAG:
299                $defaultAttributes[BoxTag::HTML_TAG_ATTRIBUTE] = BoxTag::DEFAULT_HTML_TAG;
300                $defaultAttributes[BoxTag::LOGICAL_TAG_ATTRIBUTE] = BoxTag::LOGICAL_TAG_DEFAUT;
301                break;
302            case ButtonTag::MARKUP_SHORT:
303            case ButtonTag::MARKUP_LONG:
304                $logicalTag = ButtonTag::LOGICAL_TAG;
305                $knownTypes = ButtonTag::TYPES;
306                $defaultAttributes = array(
307                    Skin::SKIN_ATTRIBUTE => Skin::FILLED_VALUE,
308                    TagAttributes::TYPE_KEY => ColorRgb::PRIMARY_VALUE
309                );
310                break;
311            case CardTag::CARD_TAG:
312            case CardTag::TEASER_TAG:
313                $logicalTag = CardTag::LOGICAL_TAG;
314                break;
315            case BarTag::BAR_TAG:
316            case BarTag::SLIDE_TAG:
317                $logicalTag = BarTag::LOGICAL_TAG;
318                $defaultAttributes[Hero::ATTRIBUTE] = "sm";
319                break;
320            case PrismTags::CONSOLE_TAG:
321            case PrismTags::FILE_TAG:
322                $hasTwoBooleanAttribute = true;
323                $secondBooleanAttribute = syntax_plugin_combo_code::FILE_PATH_KEY;
324                $allowAnyFirstBooleanAttributesAsType = true;
325                break;
326            case ContainerTag::TAG:
327                $knownTypes = ContainerTag::CONTAINER_VALUES;
328                $defaultAttributes[TagAttributes::TYPE_KEY] = $executionContext->getConfig()->getValue(ContainerTag::DEFAULT_LAYOUT_CONTAINER_CONF, ContainerTag::DEFAULT_LAYOUT_CONTAINER_DEFAULT_VALUE);
329                break;
330            case GridTag::ROW_TAG:
331            case GridTag::GRID_TAG:
332                $logicalTag = GridTag::LOGICAL_TAG;
333                $knownTypes = GridTag::KNOWN_TYPES;
334                break;
335            case HeadingTag::HEADING_TAG:
336            case HeadingTag::TITLE_TAG:
337                $logicalTag = HeadingTag::LOGICAL_TAG;
338                $knownTypes = HeadingTag::getAllTypes();
339                break;
340            case NoteTag::TAG_INOTE:
341                $defaultConfValue = $plugin->getConf(NoteTag::INOTE_CONF_DEFAULT_ATTRIBUTES_KEY);
342                $defaultAttributes = PluginUtility::parseAttributes($defaultConfValue);
343                if (!isset($defaultAttributes[TagAttributes::TYPE_KEY])) {
344                    $defaultAttributes[TagAttributes::TYPE_KEY] = "info";
345                }
346                $knownTypes = NoteTag::KNOWN_TYPES;
347                break;
348            case JumbotronTag::TAG:
349                $defaultAttributes = JumbotronTag::getDefault();
350                break;
351            case MasonryTag::CARD_COLUMNS_TAG:
352            case MasonryTag::TEASER_COLUMNS_TAG:
353            case MasonryTag::MASONRY_TAG:
354                $logicalTag = MasonryTag::LOGICAL_TAG;
355                break;
356            case PageExplorerTag::NTOC_MARKUP:
357            case PageExplorerTag::PAGE_EXPLORER_MARKUP:
358                $logicalTag = PageExplorerTag::LOGICAL_TAG;
359                $defaultAttributes = [TagAttributes::TYPE_KEY => PageExplorerTag::LIST_TYPE];
360                $knownTypes = [PageExplorerTag::TYPE_TREE, PageExplorerTag::LIST_TYPE];
361                break;
362            case PageExplorerTag::INDEX_HOME_TAG:
363            case PageExplorerTag::INDEX_TAG:
364                $logicalTag = PageExplorerTag::LOGICAL_INDEX_TAG;
365                break;
366            case PageExplorerTag::NAMESPACE_ITEM_TAG:
367            case PageExplorerTag::NAMESPACE_LONG_TAG:
368            case PageExplorerTag::NAMESPACE_SHORT_TAG:
369                $logicalTag = PageExplorerTag::NAMESPACE_LOGICAL_TAG;
370                break;
371            case PageExplorerTag::PAGE_ITEM_TAG:
372            case PageExplorerTag::PAGE_TAG:
373                $logicalTag = PageExplorerTag::PAGE_LOGICAL_TAG;
374                break;
375            case TabsTag::TAG:
376                $knownTypes = [TabsTag::ENCLOSED_PILLS_TYPE, TabsTag::ENCLOSED_TABS_TYPE, TabsTag::PILLS_TYPE, TabsTag::TABS_TYPE];
377                break;
378            case PanelTag::PANEL_MARKUP:
379            case PanelTag::TAB_PANEL_MARKUP:
380                $logicalTag = PanelTag::PANEL_LOGICAL_MARKUP;
381                break;
382            case PermalinkTag::TAG:
383                $knownTypes = PermalinkTag::getKnownTypes();
384                $defaultAttributes = [TagAttributes::TYPE_KEY => PermalinkTag::GENERATED_TYPE];
385                break;
386            case BackgroundTag::MARKUP_LONG:
387            case BackgroundTag::MARKUP_SHORT:
388                $logicalTag = BackgroundTag::LOGICAL_TAG;
389                break;
390            case MermaidTag::MARKUP_MERMAID:
391            case WebCodeTag::TAG:
392                $logicalTag = Tag\WebCodeTag::TAG;
393                $defaultAttributes = WebCodeTag::getDefaultAttributes();
394                break;
395            case MermaidTag::MARKUP_SEQUENCE_DIAGRAM:
396            case MermaidTag::MARKUP_CLASS_DIAGRAM:
397            case MermaidTag::MARKUP_FLOWCHART:
398            case MermaidTag::MARKUP_GANTT:
399            case MermaidTag::MARKUP_ERD:
400            case MermaidTag::MARKUP_JOURNEY:
401            case MermaidTag::MARKUP_PIECHART:
402            case MermaidTag::MARKUP_STATE_DIAGRAM:
403                $logicalTag = MermaidTag::LOGICAL_TAG;
404                break;
405            case ShareTag::MARKUP:
406                $knownTypes = ShareTag::getKnownTypes();
407                break;
408            case FollowTag::MARKUP:
409                $knownTypes = FollowTag::getKnownTypes();
410                break;
411        }
412
413        /**
414         * Build tag Attributes
415         */
416        if (!$hasTwoBooleanAttribute) {
417            $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, $knownTypes, $allowAnyFirstBooleanAttributesAsType);
418        } else {
419            $tagAttributes = TagAttributes::createEmpty();
420            $attributesArray = PluginUtility::getQualifiedTagAttributes($match, true, $secondBooleanAttribute, $knownTypes, $allowAnyFirstBooleanAttributesAsType);
421            foreach ($attributesArray as $key => $value) {
422                $tagAttributes->addComponentAttributeValue($key, $value);
423            }
424        }
425        $tagAttributes->setLogicalTag($logicalTag);
426
427        /**
428         * Calculate extra returned key in the table
429         */
430        $returnedArray = [];
431        switch ($logicalTag) {
432            case BlockquoteTag::TAG:
433                $returnedArray = BlockquoteTag::handleEnter($handler);
434                break;
435            case BoxTag::TAG:
436                BoxTag::handleEnter($tagAttributes);
437                break;
438            case ButtonTag::LOGICAL_TAG:
439                $returnedArray = ButtonTag::handleEnter($tagAttributes, $handler);
440                break;
441            case CardTag::CARD_TAG:
442                $returnedArray = CardTag::handleEnter($tagAttributes, $handler);
443                break;
444            case BarTag::LOGICAL_TAG:
445                $returnedArray = BarTag::handleEnter($tagAttributes);
446                break;
447            case CarrouselTag::TAG:
448                $returnedArray = CarrouselTag::handleEnter($handler);
449                break;
450            case GridTag::LOGICAL_TAG:
451                GridTag::processEnter($tagAttributes, $handler, $match);
452                break;
453            case DateTag::TAG:
454                DateTag::handleEnterAndSpecial();
455                break;
456            case HeadingTag::LOGICAL_TAG:
457                $returnedArray = HeadingTag::handleEnter($handler, $tagAttributes, $markupTag);
458                break;
459            case PanelTag::PANEL_LOGICAL_MARKUP:
460                $returnedArray = PanelTag::handleEnter($tagAttributes, $handler, $markupTag);
461                break;
462            case PermalinkTag::TAG:
463                $returnedArray = PermalinkTag::handleEnterSpecial($tagAttributes, DOKU_LEXER_ENTER, $handler);
464                break;
465            case IconTag::TAG:
466                $returnedArray = IconTag::handleEnter($tagAttributes, $handler);
467                break;
468            case BackgroundTag::LOGICAL_TAG:
469                BackgroundTag::handleEnterAndSpecial($tagAttributes);
470                break;
471        }
472
473        /**
474         * Common default
475         */
476        $defaultReturnedArray[PluginUtility::STATE] = DOKU_LEXER_ENTER;
477        $defaultReturnedArray[PluginUtility::TAG] = $logicalTag;
478        $defaultReturnedArray[PluginUtility::MARKUP_TAG] = $markupTag;
479        $defaultReturnedArray[PluginUtility::POSITION] = $pos;
480        $defaultReturnedArray[PluginUtility::ATTRIBUTES] = $tagAttributes->toCallStackArray();
481
482        return array_merge($defaultReturnedArray, $returnedArray);
483
484    }
485
486    public static function renderStatic(string $format, Doku_Renderer $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
487    {
488        $logicalTag = $data[PluginUtility::TAG];
489        $attributes = $data[PluginUtility::ATTRIBUTES];
490        $context = $data[PluginUtility::CONTEXT];
491        $state = $data[PluginUtility::STATE];
492        $pos = $data[PluginUtility::POSITION];
493        $tagAttributes = TagAttributes::createFromCallStackArray($attributes)->setLogicalTag($logicalTag);
494        switch ($format) {
495            case "xhtml":
496                /** @var Doku_Renderer_xhtml $renderer */
497                switch ($state) {
498                    case DOKU_LEXER_ENTER:
499                        return self::renderStaticEnterXhtml($tagAttributes, $renderer, $data, $plugin);
500                    case DOKU_LEXER_UNMATCHED:
501
502                        $renderer->doc .= PluginUtility::renderUnmatched($data);
503                        return true;
504
505                    case DOKU_LEXER_EXIT:
506
507                        return XmlTagProcessing::renderStaticExitXhtml($tagAttributes, $renderer, $data, $plugin);
508                }
509                break;
510            case 'metadata':
511                /** @var Doku_Renderer_metadata $renderer */
512                if (!in_array($state, [DOKU_LEXER_ENTER, DOKU_LEXER_SPECIAL])) {
513                    return true;
514                }
515                return XmlTagProcessing::renderStaticEnterSpecialMetadata($tagAttributes, $renderer, $data, $plugin);
516            case 'xml':
517                /** @var renderer_plugin_combo_xml $renderer */
518                switch ($state) {
519                    case DOKU_LEXER_ENTER:
520                        switch ($logicalTag) {
521                            default:
522                            case BarTag::LOGICAL_TAG:
523                                $renderer->doc .= "<$logicalTag>";
524                                return true;
525                        }
526                    case DOKU_LEXER_UNMATCHED :
527                        $renderer->doc .= PluginUtility::renderUnmatched($data);
528                        break;
529                    case DOKU_LEXER_EXIT :
530                        switch ($logicalTag) {
531                            default:
532                            case BarTag::LOGICAL_TAG:
533                                $renderer->doc .= "</$logicalTag>";
534                                return true;
535                        }
536                }
537                return false;
538            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
539                /**
540                 * @var renderer_plugin_combo_analytics $renderer
541                 */
542                switch ($logicalTag) {
543                    default:
544                    case HeadingTag::LOGICAL_TAG:
545                        HeadingTag::processMetadataAnalytics($data, $renderer);
546                        return true;
547                }
548
549        }
550
551        // unsupported $mode
552        return false;
553    }
554
555    public static function handleStaticExit(string $match, int $pos, Doku_Handler $handler, DokuWiki_Syntax_Plugin $plugin): array
556    {
557        $markupTag = PluginUtility::getMarkupTag($match);
558        $logicalTag = $markupTag;
559        $returnedArray = [];
560        switch ($markupTag) {
561            case BlockquoteTag::TAG:
562                $returnedArray = BlockquoteTag::handleExit($handler);
563                break;
564            case BoxTag::TAG:
565                $returnedArray = BoxTag::handleExit($handler);
566                break;
567            case ButtonTag::MARKUP_SHORT:
568            case ButtonTag::MARKUP_LONG:
569                $logicalTag = ButtonTag::LOGICAL_TAG;
570                $returnedArray = ButtonTag::handleExit($handler);
571                break;
572            case CardTag::CARD_TAG:
573            case CardTag::TEASER_TAG:
574                $logicalTag = CardTag::LOGICAL_TAG;
575                $returnedArray = CardTag::handleExit($handler, $pos, $match);
576                break;
577            case BarTag::BAR_TAG:
578            case BarTag::SLIDE_TAG:
579                $logicalTag = BarTag::LOGICAL_TAG;
580                $returnedArray = BarTag::handleExit($handler, $pos, $match);
581                break;
582            case CarrouselTag::TAG:
583                $returnedArray = CarrouselTag::handleExit($handler);
584                break;
585            case PrismTags::CONSOLE_TAG:
586            case PrismTags::FILE_TAG:
587                $returnedArray = PrismTags::handleExit($handler);
588                break;
589            case PipelineTag::TAG:
590                PipelineTag::processExit($handler);
591                break;
592            case GridTag::GRID_TAG:
593            case GridTag::ROW_TAG:
594                $logicalTag = GridTag::LOGICAL_TAG;
595                $returnedArray = GridTag::handleExit($handler);
596                break;
597            case DateTag::TAG:
598                DateTag::handleExit($handler);
599                break;
600            case HeadingTag::TITLE_TAG:
601            case HeadingTag::HEADING_TAG:
602                $logicalTag = HeadingTag::LOGICAL_TAG;
603                $returnedArray = HeadingTag::handleExit($handler);
604                break;
605            case MasonryTag::CARD_COLUMNS_TAG:
606            case MasonryTag::TEASER_COLUMNS_TAG:
607            case MasonryTag::MASONRY_TAG:
608                $logicalTag = MasonryTag::LOGICAL_TAG;
609                MasonryTag::handleExit($handler);
610                break;
611            case PageExplorerTag::NTOC_MARKUP:
612            case PageExplorerTag::PAGE_EXPLORER_MARKUP:
613                $logicalTag = PageExplorerTag::LOGICAL_TAG;
614                PageExplorerTag::handleExit($handler);
615                break;
616            case PageExplorerTag::INDEX_HOME_TAG:
617            case PageExplorerTag::INDEX_TAG:
618                $logicalTag = PageExplorerTag::LOGICAL_INDEX_TAG;
619                break;
620            case PageExplorerTag::NAMESPACE_ITEM_TAG:
621            case PageExplorerTag::NAMESPACE_LONG_TAG:
622            case PageExplorerTag::NAMESPACE_SHORT_TAG:
623                $logicalTag = PageExplorerTag::NAMESPACE_LOGICAL_TAG;
624                break;
625            case PageExplorerTag::PAGE_ITEM_TAG:
626            case PageExplorerTag::PAGE_TAG:
627                $logicalTag = PageExplorerTag::PAGE_LOGICAL_TAG;
628                break;
629            case PageExplorerTag::PARENT_TAG:
630                // nothing as the content is captured and deleted by page-explorer
631                break;
632            case TabsTag::TAG:
633                $returnedArray = TabsTag::handleExit($handler);
634                break;
635            case PanelTag::PANEL_MARKUP:
636            case PanelTag::TAB_PANEL_MARKUP:
637                $logicalTag = PanelTag::PANEL_LOGICAL_MARKUP;
638                $returnedArray = PanelTag::handleExit($handler, $pos, $markupTag, $match);
639                break;
640            case PermalinkTag::TAG:
641                PermalinkTag::handeExit($handler);
642                break;
643            case IconTag::TAG:
644                $returnedArray = IconTag::handleExit($handler);
645                break;
646            case BackgroundTag::MARKUP_SHORT:
647            case BackgroundTag::MARKUP_LONG:
648                $logicalTag = BackgroundTag::LOGICAL_TAG;
649                $returnedArray = BackgroundTag::handleExit($handler);
650                break;
651            case MermaidTag::MARKUP_SEQUENCE_DIAGRAM:
652            case MermaidTag::MARKUP_CLASS_DIAGRAM:
653            case MermaidTag::MARKUP_FLOWCHART:
654            case MermaidTag::MARKUP_GANTT:
655            case MermaidTag::MARKUP_ERD:
656            case MermaidTag::MARKUP_JOURNEY:
657            case MermaidTag::MARKUP_PIECHART:
658            case MermaidTag::MARKUP_STATE_DIAGRAM:
659                $logicalTag = MermaidTag::LOGICAL_TAG;
660                MermaidTag::handleExit($handler);
661                break;
662            case MermaidTag::MARKUP_MERMAID: // bug
663            case WebCodeTag::TAG:
664                $logicalTag = WebCodeTag::TAG;
665                $returnedArray = WebCodeTag::handleExit($handler);
666                break;
667        }
668        /**
669         * Common exit attributes
670         */
671        $defaultReturnedArray[PluginUtility::STATE] = DOKU_LEXER_EXIT;
672        $defaultReturnedArray[PluginUtility::TAG] = $logicalTag;
673        $defaultReturnedArray[PluginUtility::MARKUP_TAG] = $markupTag;
674        return array_merge($defaultReturnedArray, $returnedArray);
675    }
676
677    /**
678     * @param $tag
679     * @return string
680     *
681     * Create a lookahead pattern for a container tag used to enter in a mode
682     */
683    public static function getContainerTagPattern($tag): string
684    {
685        // this pattern ensure that the tag
686        // `accordion` will not intercept also the tag `accordionitem`
687        // where:
688        // ?: means non capturing group (to not capture the last >)
689        // (\s.*?): is a capturing group that starts with a space
690        $pattern = "(?:\s.*?>|>)";
691        return '<' . $tag . $pattern . '(?=.*?<\/' . $tag . '>)';
692    }
693
694    public static function handleStaticEmptyTag(string $match, int $state, int $pos, Doku_Handler $handler, DokuWiki_Syntax_Plugin $plugin): array
695    {
696        /**
697         * Logical Tag Building
698         */
699        $logicalTag = PluginUtility::getMarkupTag($match);
700        $defaultAttributes = [];
701        $knownTypes = [];
702        $allowAnyFirstBooleanAttributesAsType = false;
703        switch ($logicalTag) {
704            case SearchTag::TAG:
705                $defaultAttributes = array(
706                    'ajax' => true,
707                    'autocomplete' => false
708                );
709                break;
710            case PageImageTag::MARKUP:
711                $knownTypes = PageImageTag::TYPES;
712                $defaultAttributes = PageImageTag::getDefaultAttributes();
713                break;
714            case ShareTag::MARKUP:
715                $knownTypes = ShareTag::getKnownTypes();
716                break;
717            case FollowTag::MARKUP:
718                $knownTypes = FollowTag::getKnownTypes();
719                break;
720            case BrandListTag::MARKUP:
721                $knownTypes = BrandButton::TYPE_BUTTONS;
722                $defaultAttributes = [TagAttributes::TYPE_KEY => BrandButton::TYPE_BUTTON_BRAND];
723                break;
724            case BrandTag::MARKUP:
725                $defaultAttributes = [TagAttributes::TYPE_KEY => Brand::CURRENT_BRAND];
726                $allowAnyFirstBooleanAttributesAsType = true;
727                break;
728            case PermalinkTag::TAG:
729                $knownTypes = PermalinkTag::getKnownTypes();
730                $defaultAttributes = [TagAttributes::TYPE_KEY => PermalinkTag::GENERATED_TYPE];
731                break;
732            case BreadcrumbTag::MARKUP_BLOCK:
733                $logicalTag = BreadcrumbTag::LOGICAL_TAG;
734                $knownTypes = BreadcrumbTag::TYPES;
735                $defaultAttributes = BreadcrumbTag::getDefaultBlockAttributes();
736                break;
737        }
738        $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, $knownTypes, $allowAnyFirstBooleanAttributesAsType)
739            ->setLogicalTag($logicalTag);
740
741        /**
742         * Calculate extra returned key in the table
743         */
744        $returnedArray = [];
745        switch ($logicalTag) {
746            case IconTag::TAG:
747                $returnedArray = IconTag::handleSpecial($tagAttributes, $handler);
748                break;
749            case PageImageTag::MARKUP:
750                $returnedArray = PageImageTag::handle($tagAttributes, $handler);
751                break;
752            case BrandTag::MARKUP:
753                $returnedArray = BrandTag::handleSpecialEnter($tagAttributes, $handler);
754                break;
755            case CacheTag::MARKUP:
756                $returnedArray = CacheTag::handle($tagAttributes);
757                break;
758            case BackgroundTag::MARKUP_SHORT:
759            case BackgroundTag::MARKUP_LONG:
760                BackgroundTag::handleEnterAndSpecial($tagAttributes);
761                $callStack = CallStack::createFromHandler($handler);
762                $returnedArray = BackgroundTag::setAttributesToParentAndReturnData($callStack, $tagAttributes, $state);
763                break;
764            case DateTag::TAG:
765                DateTag::handleEnterAndSpecial();
766                break;
767            case PermalinkTag::TAG:
768                $returnedArray = PermalinkTag::handleEnterSpecial($tagAttributes, $state, $handler);
769                break;
770            case BreadcrumbTag::MARKUP_BLOCK:
771                $returnedArray = BreadcrumbTag::handleEnter($tagAttributes);
772                break;
773            case HrTag::TAG:
774                /**
775                 * Block tag
776                 */
777                $returnedArray = [PluginUtility::DISPLAY => HrTag::getDisplay()];
778                break;
779        }
780
781        /**
782         * Common default
783         * {@link PluginUtility::DISPLAY} should be set on handle
784         */
785        $defaultReturnedArray[PluginUtility::STATE] = $state;
786        $defaultReturnedArray[PluginUtility::TAG] = $logicalTag;
787        $defaultReturnedArray[PluginUtility::ATTRIBUTES] = $tagAttributes->toCallStackArray();
788
789        return array_merge($defaultReturnedArray, $returnedArray);
790    }
791
792    public static function renderStaticEmptyTag(string $format, Doku_Renderer $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
793    {
794
795        $tag = $data[PluginUtility::TAG];
796        $attributes = $data[PluginUtility::ATTRIBUTES];
797        $state = DOKU_LEXER_SPECIAL;
798        $tagAttributes = TagAttributes::createFromCallStackArray($attributes)->setLogicalTag($tag);
799        switch ($format) {
800            case "xhtml":
801                /** @var Doku_Renderer_xhtml $renderer */
802                switch ($tag) {
803                    case HrTag::TAG:
804                        $renderer->doc .= HrTag::render($tagAttributes);
805                        break;
806                    case SearchTag::TAG:
807                        $renderer->doc .= SearchTag::render($tagAttributes);
808                        break;
809                    case IconTag::TAG:
810                        $renderer->doc .= IconTag::renderEmptyTag($tagAttributes);
811                        break;
812                    case BreadcrumbTag::LOGICAL_TAG:
813                        $renderer->doc .= BreadcrumbTag::render($tagAttributes);
814                        break;
815                    case PageImageTag::MARKUP:
816                        $renderer->doc .= PageImageTag::render($tagAttributes, $data);
817                        break;
818                    case ShareTag::MARKUP:
819                        $renderer->doc .= ShareTag::renderSpecialEnter($tagAttributes, $state);
820                        break;
821                    case BrandListTag::MARKUP:
822                        $renderer->doc .= BrandListTag::render($tagAttributes);
823                        break;
824                    case BrandTag::MARKUP:
825                        $renderer->doc .= BrandTag::render($tagAttributes, $state, $data);
826                        break;
827                    case CacheTag::MARKUP:
828                        $renderer->doc .= CacheTag::renderXhtml($data);
829                        break;
830                    case BackgroundTag::MARKUP_LONG:
831                    case BackgroundTag::MARKUP_SHORT:
832                        $renderer->doc .= BackgroundTag::renderExitSpecialHtml($data);
833                        break;
834                    case DateTag::TAG:
835                        $renderer->doc .= DateTag::renderHtml($tagAttributes);
836                        return true;
837                    case PermalinkTag::TAG:
838                        $renderer->doc .= PermalinkTag::renderEnterSpecialXhtml($data);
839                        return true;
840                    case QualityTag::MARKUP_TAG:
841                        $renderer->doc .= QualityTag::renderXhtml($tagAttributes);
842                        return true;
843                    case FollowTag::MARKUP:
844                        $renderer->doc .= FollowTag::renderSpecialEnterNode($tagAttributes, DOKU_LEXER_SPECIAL);
845                        return true;
846                    case MediaMarkup::TAG:
847                        $renderer->doc .= MediaMarkup::renderSpecial($data, $renderer);
848                        return true;
849                    case SubscribeTag::LOGICAL_TAG:
850                        $renderer->doc .= SubscribeTag::renderEnterXhtml($tagAttributes);
851                        return true;
852                    case AdTag::MARKUP:
853                        $renderer->doc .= AdTag::render($tagAttributes);
854                        return true;
855                    case RelatedTag::TAG:
856                        $renderer->doc .= RelatedTag::render($tagAttributes);
857                        return true;
858                    default:
859                        LogUtility::errorIfDevOrTest("The empty tag (" . $tag . ") was not processed.");
860                }
861                break;
862            case 'metadata':
863                /** @var Doku_Renderer_metadata $renderer */
864                switch ($tag) {
865                    case IconTag::TAG:
866                        IconTag::metadata($renderer, $tagAttributes);
867                        return true;
868                    case CacheTag::MARKUP:
869                        CacheTag::metadata($data);
870                        return true;
871                    case MediaMarkup::TAG:
872                        MediaMarkup::metadata($data, $renderer);
873                        return true;
874                }
875                break;
876            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
877
878        }
879        // unsupported $mode
880        return false;
881    }
882
883    private static function renderStaticEnterSpecialMetadata(TagAttributes $tagAttributes, Doku_Renderer_metadata $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
884    {
885        $logicalTag = $tagAttributes->getLogicalTag();
886        switch ($logicalTag) {
887            case HeadingTag::LOGICAL_TAG:
888                HeadingTag::processHeadingEnterMetadata($data, $renderer);
889                return true;
890            case IconTag::TAG:
891                IconTag::metadata($renderer, $tagAttributes);
892                return true;
893            case BackgroundTag::LOGICAL_TAG:
894                BackgroundTag::renderMeta($data, $renderer);
895                return true;
896        }
897        return false;
898    }
899}
900
901