1<?php
2
3
4// must be run within Dokuwiki
5use ComboStrap\CallStack;
6use ComboStrap\Dimension;
7use ComboStrap\PluginUtility;
8use ComboStrap\TagAttributes;
9use ComboStrap\XmlTagProcessing;
10
11require_once(__DIR__ . '/../vendor/autoload.php');
12
13/**
14 * Class syntax_plugin_combo_text
15 * A text block that permits to style
16 * paragraph at once
17 *
18 * The output will be a series of {@link syntax_plugin_combo_para paragraph}
19 * with the same properties
20 *
21 * It permits to have several paragraph
22 */
23class syntax_plugin_combo_text extends DokuWiki_Syntax_Plugin
24{
25
26    const TAG = "text";
27    const TAGS = ["typo", self::TAG];
28
29    /**
30     * Syntax Type.
31     *
32     * Needs to return one of the mode types defined in {@link $PARSER_MODES} in parser.php
33     * @see DokuWiki_Syntax_Plugin::getType()
34     */
35    function getType(): string
36    {
37        return 'paragraphs';
38    }
39
40    /**
41     * How Dokuwiki will add P element
42     *
43     *  * 'normal' - The plugin can be used inside paragraphs
44     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
45     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
46     *
47     * @see DokuWiki_Syntax_Plugin::getPType()
48     */
49    function getPType(): string
50    {
51        return 'stack';
52    }
53
54    /**
55     * @return array
56     * Allow which kind of plugin inside
57     *
58     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
59     * because we manage self the content and we call self the parser
60     *
61     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
62     */
63    function getAllowedTypes(): array
64    {
65        return array('formatting', 'substition', 'paragraphs');
66    }
67
68    public function accepts($mode): bool
69    {
70
71        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
72
73    }
74
75
76    function getSort(): int
77    {
78        /**
79         * Less than {@link syntax_plugin_typography_base}
80         */
81        return 65;
82    }
83
84
85    function connectTo($mode)
86    {
87
88        foreach (self::TAGS as $tag) {
89            $pattern = XmlTagProcessing::getContainerTagPattern($tag);
90            $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
91        }
92    }
93
94
95    function postConnect()
96    {
97        foreach (self::TAGS as $tag) {
98            $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
99        }
100
101    }
102
103    function handle($match, $state, $pos, Doku_Handler $handler)
104    {
105
106        switch ($state) {
107
108            case DOKU_LEXER_ENTER :
109
110                $attributes = TagAttributes::createFromTagMatch($match,[],[],true);
111                $callStackArray = $attributes->toCallStackArray();
112
113                return array(
114                    PluginUtility::STATE => $state,
115                    PluginUtility::ATTRIBUTES => $callStackArray
116                );
117
118            case DOKU_LEXER_UNMATCHED :
119                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
120
121            case DOKU_LEXER_EXIT :
122                /**
123                 * Transform all paragraphs
124                 * with the type as class
125                 */
126                $callStack = CallStack::createFromHandler($handler);
127                $openingCall = $callStack->moveToPreviousCorrespondingOpeningCall();
128                $attributes = $openingCall->getAttributes();
129                // if there is no EOL, we add one to create at minimal a paragraph
130                $callStack->insertEolIfNextCallIsNotEolOrBlock();
131                $callStack->processEolToEndStack($attributes);
132
133                /**
134                 * Check and add a scroll toggle if the
135                 * text is constrained by height
136                 */
137                Dimension::addScrollToggleOnClickIfNoControl($callStack);
138
139                return array(PluginUtility::STATE => $state);
140
141
142        }
143        return array();
144
145    }
146
147    /**
148     * Render the output
149     * @param string $format
150     * @param Doku_Renderer $renderer
151     * @param array $data - what the function handle() return'ed
152     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
153     * @see DokuWiki_Syntax_Plugin::render()
154     *
155     *
156     */
157    function render($format, Doku_Renderer $renderer, $data): bool
158    {
159        if ($format == 'xhtml') {
160
161            /** @var Doku_Renderer_xhtml $renderer */
162            $state = $data[PluginUtility::STATE];
163            switch ($state) {
164                case DOKU_LEXER_EXIT :
165                case DOKU_LEXER_ENTER :
166                    /**
167                     * The {@link DOKU_LEXER_EXIT} of the {@link syntax_plugin_combo_text::handle()}
168                     * has already created in the callstack the {@link syntax_plugin_combo_para} call
169                     */
170                    $renderer->doc .= "";
171                    break;
172                case DOKU_LEXER_UNMATCHED :
173                    $renderer->doc .= PluginUtility::renderUnmatched($data);
174                    break;
175            }
176            return true;
177        }
178
179        // unsupported $mode
180        return false;
181    }
182
183
184}
185
186