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