xref: /plugin/combo/ComboStrap/XmlTagProcessing.php (revision 8b8569b7384a60bf4f631e3aa3bd7f9aab461558)
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($tagAttributes);
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            case ShareTag::MARKUP:
668                $returnedArray = ShareTag::handleExit($handler);
669
670                break;
671
672        }
673        /**
674         * Common exit attributes
675         */
676        $defaultReturnedArray[PluginUtility::STATE] = DOKU_LEXER_EXIT;
677        $defaultReturnedArray[PluginUtility::TAG] = $logicalTag;
678        $defaultReturnedArray[PluginUtility::MARKUP_TAG] = $markupTag;
679        return array_merge($defaultReturnedArray, $returnedArray);
680    }
681
682    /**
683     * @param $tag
684     * @return string
685     *
686     * Create a lookahead pattern for a container tag used to enter in a mode
687     */
688    public static function getContainerTagPattern($tag): string
689    {
690        // this pattern ensure that the tag
691        // `accordion` will not intercept also the tag `accordionitem`
692        // where:
693        // ?: means non capturing group (to not capture the last >)
694        // (\s.*?): is a capturing group that starts with a space
695        $pattern = "(?:\s.*?>|>)";
696        return '<' . $tag . $pattern . '(?=.*?<\/' . $tag . '>)';
697    }
698
699    public static function handleStaticEmptyTag(string $match, int $state, int $pos, Doku_Handler $handler, DokuWiki_Syntax_Plugin $plugin): array
700    {
701        /**
702         * Logical Tag Building
703         */
704        $logicalTag = PluginUtility::getMarkupTag($match);
705        $defaultAttributes = [];
706        $knownTypes = [];
707        $allowAnyFirstBooleanAttributesAsType = false;
708        switch ($logicalTag) {
709            case SearchTag::TAG:
710                $defaultAttributes = array(
711                    'ajax' => true,
712                    'autocomplete' => false
713                );
714                break;
715            case PageImageTag::MARKUP:
716                $knownTypes = PageImageTag::TYPES;
717                $defaultAttributes = PageImageTag::getDefaultAttributes();
718                break;
719            case ShareTag::MARKUP:
720                $knownTypes = ShareTag::getKnownTypes();
721                break;
722            case FollowTag::MARKUP:
723                $knownTypes = FollowTag::getKnownTypes();
724                break;
725            case BrandListTag::MARKUP:
726                $knownTypes = BrandButton::TYPE_BUTTONS;
727                $defaultAttributes = [TagAttributes::TYPE_KEY => BrandButton::TYPE_BUTTON_BRAND];
728                break;
729            case BrandTag::MARKUP:
730                $defaultAttributes = [TagAttributes::TYPE_KEY => Brand::CURRENT_BRAND];
731                $allowAnyFirstBooleanAttributesAsType = true;
732                break;
733            case PermalinkTag::TAG:
734                $knownTypes = PermalinkTag::getKnownTypes();
735                $defaultAttributes = [TagAttributes::TYPE_KEY => PermalinkTag::GENERATED_TYPE];
736                break;
737            case BreadcrumbTag::MARKUP_BLOCK:
738                $logicalTag = BreadcrumbTag::LOGICAL_TAG;
739                $knownTypes = BreadcrumbTag::TYPES;
740                $defaultAttributes = BreadcrumbTag::getDefaultBlockAttributes();
741                break;
742        }
743        $tagAttributes = TagAttributes::createFromTagMatch($match, $defaultAttributes, $knownTypes, $allowAnyFirstBooleanAttributesAsType)
744            ->setLogicalTag($logicalTag);
745
746        /**
747         * Calculate extra returned key in the table
748         */
749        $returnedArray = [];
750        switch ($logicalTag) {
751            case IconTag::TAG:
752                $returnedArray = IconTag::handleSpecial($tagAttributes, $handler);
753                break;
754            case PageImageTag::MARKUP:
755                $returnedArray = PageImageTag::handle($tagAttributes, $handler);
756                break;
757            case BrandTag::MARKUP:
758                $returnedArray = BrandTag::handleSpecialEnter($tagAttributes, $handler);
759                break;
760            case CacheTag::MARKUP:
761                $returnedArray = CacheTag::handle($tagAttributes);
762                break;
763            case BackgroundTag::MARKUP_SHORT:
764            case BackgroundTag::MARKUP_LONG:
765                BackgroundTag::handleEnterAndSpecial($tagAttributes);
766                $callStack = CallStack::createFromHandler($handler);
767                $returnedArray = BackgroundTag::setAttributesToParentAndReturnData($callStack, $tagAttributes, $state);
768                break;
769            case DateTag::TAG:
770                DateTag::handleEnterAndSpecial();
771                break;
772            case PermalinkTag::TAG:
773                $returnedArray = PermalinkTag::handleEnterSpecial($tagAttributes, $state, $handler);
774                break;
775            case BreadcrumbTag::MARKUP_BLOCK:
776                $returnedArray = BreadcrumbTag::handleEnter($tagAttributes);
777                break;
778            case HrTag::TAG:
779                /**
780                 * Block tag
781                 */
782                $returnedArray = [PluginUtility::DISPLAY => HrTag::getDisplay()];
783                break;
784        }
785
786        /**
787         * Common default
788         * {@link PluginUtility::DISPLAY} should be set on handle
789         */
790        $defaultReturnedArray[PluginUtility::STATE] = $state;
791        $defaultReturnedArray[PluginUtility::TAG] = $logicalTag;
792        $defaultReturnedArray[PluginUtility::ATTRIBUTES] = $tagAttributes->toCallStackArray();
793
794        return array_merge($defaultReturnedArray, $returnedArray);
795    }
796
797    public static function renderStaticEmptyTag(string $format, Doku_Renderer $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
798    {
799
800        $tag = $data[PluginUtility::TAG];
801        $attributes = $data[PluginUtility::ATTRIBUTES];
802        $state = DOKU_LEXER_SPECIAL;
803        $tagAttributes = TagAttributes::createFromCallStackArray($attributes)->setLogicalTag($tag);
804        switch ($format) {
805            case "xhtml":
806                /** @var Doku_Renderer_xhtml $renderer */
807                switch ($tag) {
808                    case HrTag::TAG:
809                        $renderer->doc .= HrTag::render($tagAttributes);
810                        break;
811                    case SearchTag::TAG:
812                        $renderer->doc .= SearchTag::render($tagAttributes);
813                        break;
814                    case IconTag::TAG:
815                        $renderer->doc .= IconTag::renderEmptyTag($tagAttributes);
816                        break;
817                    case BreadcrumbTag::LOGICAL_TAG:
818                        $renderer->doc .= BreadcrumbTag::render($tagAttributes);
819                        break;
820                    case PageImageTag::MARKUP:
821                        $renderer->doc .= PageImageTag::render($tagAttributes, $data);
822                        break;
823                    case ShareTag::MARKUP:
824                        $renderer->doc .= ShareTag::renderSpecialEnter($tagAttributes, $state);
825                        break;
826                    case BrandListTag::MARKUP:
827                        $renderer->doc .= BrandListTag::render($tagAttributes);
828                        break;
829                    case BrandTag::MARKUP:
830                        $renderer->doc .= BrandTag::render($tagAttributes, $state, $data);
831                        break;
832                    case CacheTag::MARKUP:
833                        $renderer->doc .= CacheTag::renderXhtml($data);
834                        break;
835                    case BackgroundTag::MARKUP_LONG:
836                    case BackgroundTag::MARKUP_SHORT:
837                        $renderer->doc .= BackgroundTag::renderExitSpecialHtml($data);
838                        break;
839                    case DateTag::TAG:
840                        $renderer->doc .= DateTag::renderHtml($tagAttributes);
841                        return true;
842                    case PermalinkTag::TAG:
843                        $renderer->doc .= PermalinkTag::renderEnterSpecialXhtml($data);
844                        return true;
845                    case QualityTag::MARKUP_TAG:
846                        $renderer->doc .= QualityTag::renderXhtml($tagAttributes);
847                        return true;
848                    case FollowTag::MARKUP:
849                        $renderer->doc .= FollowTag::renderSpecialEnterNode($tagAttributes, DOKU_LEXER_SPECIAL);
850                        return true;
851                    case MediaMarkup::TAG:
852                        $renderer->doc .= MediaMarkup::renderSpecial($data, $renderer);
853                        return true;
854                    case SubscribeTag::LOGICAL_TAG:
855                        $renderer->doc .= SubscribeTag::renderEnterXhtml($tagAttributes);
856                        return true;
857                    case AdTag::MARKUP:
858                        $renderer->doc .= AdTag::render($tagAttributes);
859                        return true;
860                    case RelatedTag::TAG:
861                        $renderer->doc .= RelatedTag::render($tagAttributes);
862                        return true;
863                    default:
864                        LogUtility::errorIfDevOrTest("The empty tag (" . $tag . ") was not processed.");
865                }
866                break;
867            case 'metadata':
868                /** @var Doku_Renderer_metadata $renderer */
869                switch ($tag) {
870                    case IconTag::TAG:
871                        IconTag::metadata($renderer, $tagAttributes);
872                        return true;
873                    case CacheTag::MARKUP:
874                        CacheTag::metadata($data);
875                        return true;
876                    case MediaMarkup::TAG:
877                        MediaMarkup::metadata($data, $renderer);
878                        return true;
879                }
880                break;
881            case renderer_plugin_combo_analytics::RENDERER_FORMAT:
882
883        }
884        // unsupported $mode
885        return false;
886    }
887
888    private static function renderStaticEnterSpecialMetadata(TagAttributes $tagAttributes, Doku_Renderer_metadata $renderer, array $data, DokuWiki_Syntax_Plugin $plugin): bool
889    {
890        $logicalTag = $tagAttributes->getLogicalTag();
891        switch ($logicalTag) {
892            case HeadingTag::LOGICAL_TAG:
893                HeadingTag::processHeadingEnterMetadata($data, $renderer);
894                return true;
895            case IconTag::TAG:
896                IconTag::metadata($renderer, $tagAttributes);
897                return true;
898            case BackgroundTag::LOGICAL_TAG:
899                BackgroundTag::renderMeta($data, $renderer);
900                return true;
901        }
902        return false;
903    }
904}
905
906