xref: /plugin/combo/syntax/iterator.php (revision 37748cd8654635afbeca80942126742f0f4cc346)
1*37748cd8SNickeau<?php
2*37748cd8SNickeau
3*37748cd8SNickeau
4*37748cd8SNickeauuse ComboStrap\CallStack;
5*37748cd8SNickeauuse ComboStrap\PluginUtility;
6*37748cd8SNickeauuse ComboStrap\TagAttributes;
7*37748cd8SNickeau
8*37748cd8SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
9*37748cd8SNickeau
10*37748cd8SNickeau
11*37748cd8SNickeau/**
12*37748cd8SNickeau *
13*37748cd8SNickeau * An iterator to iterate over templates.
14*37748cd8SNickeau *
15*37748cd8SNickeau * *******************
16*37748cd8SNickeau * Iteration driver
17*37748cd8SNickeau * *******************
18*37748cd8SNickeau * The end tag of the template node is driving the iteration.
19*37748cd8SNickeau * This way, the tags just after the template
20*37748cd8SNickeau * sees them in the {@link CallStack} and can change their context
21*37748cd8SNickeau *
22*37748cd8SNickeau * For instance, a {@link syntax_plugin_combo_masonry}
23*37748cd8SNickeau * component will change the context of all card inside it.
24*37748cd8SNickeau *
25*37748cd8SNickeau * ********************
26*37748cd8SNickeau * Header and footer delimitation
27*37748cd8SNickeau * ********************
28*37748cd8SNickeau * The iterator delimits also the header and footer.
29*37748cd8SNickeau * Some component needs the header to be generate completely.
30*37748cd8SNickeau * This is the case of a complex markup such as a table
31*37748cd8SNickeau *
32*37748cd8SNickeau * ******************************
33*37748cd8SNickeau * Delete if no data
34*37748cd8SNickeau * ******************************
35*37748cd8SNickeau * It gives also the possibility to {@link syntax_plugin_combo_iterator::EMPTY_ROWS_COUNT_ATTRIBUTE
36*37748cd8SNickeau * delete the whole block}
37*37748cd8SNickeau * (header and footer also) if there is no data
38*37748cd8SNickeau *
39*37748cd8SNickeau * *****************************
40*37748cd8SNickeau * Always Contextual
41*37748cd8SNickeau * *****************************
42*37748cd8SNickeau * We don't capture the text markup such as in a {@link syntax_plugin_combo_code}
43*37748cd8SNickeau * in order to loop because you can't pass the actual handler (ie callstack)
44*37748cd8SNickeau * when you {@link p_get_instructions() parse again} a markup.
45*37748cd8SNickeau *
46*37748cd8SNickeau * The markup is then seen as a new single page without any context.
47*37748cd8SNickeau * That may lead to problems.
48*37748cd8SNickeau * Example: `heading` may then think that they are `outline heading` ...
49*37748cd8SNickeau *
50*37748cd8SNickeau */
51*37748cd8SNickeauclass syntax_plugin_combo_iterator extends DokuWiki_Syntax_Plugin
52*37748cd8SNickeau{
53*37748cd8SNickeau
54*37748cd8SNickeau    /**
55*37748cd8SNickeau     * Tag in Dokuwiki cannot have a `-`
56*37748cd8SNickeau     * This is the last part of the class
57*37748cd8SNickeau     */
58*37748cd8SNickeau    const TAG = "iterator";
59*37748cd8SNickeau
60*37748cd8SNickeau    /**
61*37748cd8SNickeau     * Page canonical and tag pattern
62*37748cd8SNickeau     */
63*37748cd8SNickeau    const CANONICAL = "iterator";
64*37748cd8SNickeau
65*37748cd8SNickeau    /**
66*37748cd8SNickeau     * An attribute that is set back
67*37748cd8SNickeau     * by the {@link DOKU_LEXER_EXIT} state in {@link syntax_plugin_combo_template::handle()}
68*37748cd8SNickeau     * in order to delete the whole iterator content (ie header, footer)
69*37748cd8SNickeau     * at the {@link DOKU_LEXER_EXIT} state of {@link syntax_plugin_combo_iterator::handle()}
70*37748cd8SNickeau     * if there is no rows to iterate
71*37748cd8SNickeau     */
72*37748cd8SNickeau    const EMPTY_ROWS_COUNT_ATTRIBUTE = "emptyRowCount";
73*37748cd8SNickeau
74*37748cd8SNickeau
75*37748cd8SNickeau    /**
76*37748cd8SNickeau     * Syntax Type.
77*37748cd8SNickeau     *
78*37748cd8SNickeau     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
79*37748cd8SNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
80*37748cd8SNickeau     * @see DokuWiki_Syntax_Plugin::getType()
81*37748cd8SNickeau     */
82*37748cd8SNickeau    function getType()
83*37748cd8SNickeau    {
84*37748cd8SNickeau        return 'container';
85*37748cd8SNickeau    }
86*37748cd8SNickeau
87*37748cd8SNickeau    /**
88*37748cd8SNickeau     * How Dokuwiki will add P element
89*37748cd8SNickeau     *
90*37748cd8SNickeau     *  * 'normal' - The plugin can be used inside paragraphs (inline or inside)
91*37748cd8SNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output (box) - block should not be inside paragraphs
92*37748cd8SNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
93*37748cd8SNickeau     *
94*37748cd8SNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
95*37748cd8SNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#ptype
96*37748cd8SNickeau     */
97*37748cd8SNickeau    function getPType()
98*37748cd8SNickeau    {
99*37748cd8SNickeau        return 'block';
100*37748cd8SNickeau    }
101*37748cd8SNickeau
102*37748cd8SNickeau    /**
103*37748cd8SNickeau     * @return array
104*37748cd8SNickeau     * Allow which kind of plugin inside
105*37748cd8SNickeau     *
106*37748cd8SNickeau     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
107*37748cd8SNickeau     * because we manage self the content and we call self the parser
108*37748cd8SNickeau     *
109*37748cd8SNickeau     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
110*37748cd8SNickeau     */
111*37748cd8SNickeau    function getAllowedTypes()
112*37748cd8SNickeau    {
113*37748cd8SNickeau        return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
114*37748cd8SNickeau    }
115*37748cd8SNickeau
116*37748cd8SNickeau    function getSort()
117*37748cd8SNickeau    {
118*37748cd8SNickeau        return 201;
119*37748cd8SNickeau    }
120*37748cd8SNickeau
121*37748cd8SNickeau    public function accepts($mode)
122*37748cd8SNickeau    {
123*37748cd8SNickeau        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
124*37748cd8SNickeau    }
125*37748cd8SNickeau
126*37748cd8SNickeau
127*37748cd8SNickeau    function connectTo($mode)
128*37748cd8SNickeau    {
129*37748cd8SNickeau
130*37748cd8SNickeau
131*37748cd8SNickeau        $pattern = PluginUtility::getContainerTagPattern(self::TAG);
132*37748cd8SNickeau        $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
133*37748cd8SNickeau
134*37748cd8SNickeau
135*37748cd8SNickeau    }
136*37748cd8SNickeau
137*37748cd8SNickeau
138*37748cd8SNickeau    public function postConnect()
139*37748cd8SNickeau    {
140*37748cd8SNickeau
141*37748cd8SNickeau        $this->Lexer->addExitPattern('</' . self::TAG . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
142*37748cd8SNickeau
143*37748cd8SNickeau
144*37748cd8SNickeau    }
145*37748cd8SNickeau
146*37748cd8SNickeau
147*37748cd8SNickeau    /**
148*37748cd8SNickeau     *
149*37748cd8SNickeau     * The handle function goal is to parse the matched syntax through the pattern function
150*37748cd8SNickeau     * and to return the result for use in the renderer
151*37748cd8SNickeau     * This result is always cached until the page is modified.
152*37748cd8SNickeau     * @param string $match
153*37748cd8SNickeau     * @param int $state
154*37748cd8SNickeau     * @param int $pos - byte position in the original source file
155*37748cd8SNickeau     * @param Doku_Handler $handler
156*37748cd8SNickeau     * @return array|bool
157*37748cd8SNickeau     * @throws Exception
158*37748cd8SNickeau     * @see DokuWiki_Syntax_Plugin::handle()
159*37748cd8SNickeau     *
160*37748cd8SNickeau     */
161*37748cd8SNickeau    function handle($match, $state, $pos, Doku_Handler $handler)
162*37748cd8SNickeau    {
163*37748cd8SNickeau
164*37748cd8SNickeau        switch ($state) {
165*37748cd8SNickeau
166*37748cd8SNickeau            case DOKU_LEXER_ENTER :
167*37748cd8SNickeau
168*37748cd8SNickeau                $tagAttributes = TagAttributes::createFromTagMatch($match);
169*37748cd8SNickeau                $callStackArray = $tagAttributes->toCallStackArray();
170*37748cd8SNickeau                return array(
171*37748cd8SNickeau                    PluginUtility::STATE => $state,
172*37748cd8SNickeau                    PluginUtility::ATTRIBUTES => $callStackArray
173*37748cd8SNickeau                );
174*37748cd8SNickeau
175*37748cd8SNickeau            case DOKU_LEXER_UNMATCHED :
176*37748cd8SNickeau
177*37748cd8SNickeau                // We should not ever come here but a user does not not known that
178*37748cd8SNickeau                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
179*37748cd8SNickeau
180*37748cd8SNickeau
181*37748cd8SNickeau            case DOKU_LEXER_EXIT :
182*37748cd8SNickeau
183*37748cd8SNickeau                return array(PluginUtility::STATE => $state);
184*37748cd8SNickeau
185*37748cd8SNickeau        }
186*37748cd8SNickeau        return array();
187*37748cd8SNickeau
188*37748cd8SNickeau    }
189*37748cd8SNickeau
190*37748cd8SNickeau    /**
191*37748cd8SNickeau     * Render the output
192*37748cd8SNickeau     * @param string $format
193*37748cd8SNickeau     * @param Doku_Renderer $renderer
194*37748cd8SNickeau     * @param array $data - what the function handle() return'ed
195*37748cd8SNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
196*37748cd8SNickeau     * @see DokuWiki_Syntax_Plugin::render()
197*37748cd8SNickeau     *
198*37748cd8SNickeau     *
199*37748cd8SNickeau     */
200*37748cd8SNickeau    function render($format, Doku_Renderer $renderer, $data)
201*37748cd8SNickeau    {
202*37748cd8SNickeau        // unsupported $mode
203*37748cd8SNickeau        return false;
204*37748cd8SNickeau    }
205*37748cd8SNickeau
206*37748cd8SNickeau
207*37748cd8SNickeau}
208*37748cd8SNickeau
209