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