xref: /plugin/combo/syntax/contentlist.php (revision 9337a630db122fdba0294f47d72bdf5433c2bf10)
1<?php
2
3
4use ComboStrap\Call;
5use ComboStrap\CallStack;
6use ComboStrap\PluginUtility;
7use ComboStrap\StyleUtility;
8use ComboStrap\TagAttributes;
9
10require_once(__DIR__ . '/../class/StyleUtility.php');
11require_once(__DIR__ . '/../class/SnippetManager.php');
12
13
14/**
15 * Class syntax_plugin_combo_list
16 * Implementation of a list
17 *
18 * Content list is a list implementation that permits to
19 * create simple and complex list such as media list
20 *
21 * https://getbootstrap.com/docs/4.0/layout/media-object/#media-list - Bootstrap media list
22 * https://getbootstrap.com/docs/5.0/utilities/flex/#media-object
23 * https://github.com/material-components/material-components-web/tree/master/packages/mdc-list - mdc list
24 *
25 * It's implemented on the basis of:
26 *   * bootstrap list-group
27 *   * flex utility on the list-group-item
28 *   * with the row/cell (grid) adjusted in order to add automatically a space between col (cell)
29 *
30 * Note:
31 *   * The cell inside a row are centered vertically automatically
32 *   * The illustrative image does not get any [[ui:image#link|link]]
33 *
34 * Documentation:
35 * https://getbootstrap.com/docs/4.1/components/list-group/
36 * https://getbootstrap.com/docs/5.0/components/list-group/
37 *
38 * https://getbootstrap.com/docs/5.0/utilities/flex/
39 * https://getbootstrap.com/docs/5.0/utilities/flex/#media-object
40 *
41 */
42class syntax_plugin_combo_contentlist extends DokuWiki_Syntax_Plugin
43{
44
45    const DOKU_TAG = "contentlist";
46
47    /**
48     * To allow a minus
49     */
50    const MARKI_TAG = "content-list";
51    const COMBO_TAG_OLD = "list";
52    const COMBO_TAGS = [self::MARKI_TAG, self::COMBO_TAG_OLD];
53
54
55    /**
56     * Syntax Type.
57     *
58     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
59     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
60     * @see DokuWiki_Syntax_Plugin::getType()
61     */
62    function getType()
63    {
64        return 'container';
65    }
66
67    /**
68     * How Dokuwiki will add P element
69     *
70     *  * 'normal' - The plugin can be used inside paragraphs (inline or inside)
71     *  * 'block'  - Open paragraphs need to be closed before plugin output (box) - block should not be inside paragraphs
72     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
73     *
74     * @see DokuWiki_Syntax_Plugin::getPType()
75     * @see https://www.dokuwiki.org/devel:syntax_plugins#ptype
76     */
77    function getPType()
78    {
79        return 'block';
80    }
81
82    /**
83     * @return array
84     * Allow which kind of plugin inside
85     *
86     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
87     * because we manage self the content and we call self the parser
88     *
89     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
90     */
91    function getAllowedTypes()
92    {
93        return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs');
94    }
95
96    public function accepts($mode)
97    {
98
99        return syntax_plugin_combo_preformatted::disablePreformatted($mode);
100
101    }
102
103
104    function getSort()
105    {
106        return 15;
107    }
108
109
110    function connectTo($mode)
111    {
112
113        foreach (self::COMBO_TAGS as $tag) {
114            $pattern = PluginUtility::getContainerTagPattern($tag);
115            $this->Lexer->addEntryPattern($pattern, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
116        }
117
118    }
119
120    public function postConnect()
121    {
122        foreach (self::COMBO_TAGS as $tag) {
123            $this->Lexer->addExitPattern('</' . $tag . '>', PluginUtility::getModeFromTag($this->getPluginComponent()));
124        }
125
126    }
127
128
129    /**
130     *
131     * The handle function goal is to parse the matched syntax through the pattern function
132     * and to return the result for use in the renderer
133     * This result is always cached until the page is modified.
134     * @param string $match
135     * @param int $state
136     * @param int $pos - byte position in the original source file
137     * @param Doku_Handler $handler
138     * @return array|bool
139     * @see DokuWiki_Syntax_Plugin::handle()
140     *
141     */
142    function handle($match, $state, $pos, Doku_Handler $handler)
143    {
144
145        switch ($state) {
146
147            case DOKU_LEXER_ENTER :
148
149                $attributes = TagAttributes::createFromTagMatch($match);
150
151                if ($attributes->hasComponentAttribute(TagAttributes::TYPE_KEY)) {
152                    $type = trim(strtolower($attributes->getType()));
153                    if ($type == "flush") {
154                        // https://getbootstrap.com/docs/5.0/components/list-group/#flush
155                        // https://getbootstrap.com/docs/4.1/components/list-group/#flush
156                        $attributes->addClassName("list-group-flush");
157                    }
158                }
159                return array(
160                    PluginUtility::STATE => $state,
161                    PluginUtility::ATTRIBUTES => $attributes->toCallStackArray()
162                );
163
164            case DOKU_LEXER_UNMATCHED :
165
166                return PluginUtility::handleAndReturnUnmatchedData(self::MARKI_TAG, $match, $handler);
167
168            case DOKU_LEXER_EXIT :
169
170                /**
171                 * Add to all row the list-group-item
172                 */
173                $callStack = CallStack::createFromHandler($handler);
174                $callStack->moveToPreviousCorrespondingOpeningCall();
175                while ($actualCall = $callStack->next()) {
176                    if($actualCall->getTagName()==syntax_plugin_combo_contentlistitem::DOKU_TAG){
177                        // List item were added by the user
178                        break;
179                    }
180                    if ($actualCall->getTagName() == syntax_plugin_combo_row::TAG) {
181                        $actualState = $actualCall->getState();
182                        switch ($actualState) {
183                            case DOKU_LEXER_ENTER:
184                                $callStack->insertBefore(Call::createComboCall(
185                                    syntax_plugin_combo_contentlistitem::DOKU_TAG,
186                                    DOKU_LEXER_ENTER
187                                ));
188                                break;
189                            case DOKU_LEXER_EXIT:
190                                $callStack->insertAfter(Call::createComboCall(
191                                    syntax_plugin_combo_contentlistitem::DOKU_TAG,
192                                    DOKU_LEXER_EXIT
193                                ));
194                                $callStack->next();
195                                break;
196                        }
197
198                    }
199                }
200
201
202                return array(PluginUtility::STATE => $state);
203
204
205        }
206        return array();
207
208    }
209
210    /**
211     * Render the output
212     * @param string $format
213     * @param Doku_Renderer $renderer
214     * @param array $data - what the function handle() return'ed
215     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
216     * @see DokuWiki_Syntax_Plugin::render()
217     *
218     *
219     */
220    function render($format, Doku_Renderer $renderer, $data)
221    {
222        if ($format == 'xhtml') {
223
224            /** @var Doku_Renderer_xhtml $renderer */
225            $state = $data[PluginUtility::STATE];
226            switch ($state) {
227                case DOKU_LEXER_ENTER :
228
229                    PluginUtility::getSnippetManager()->attachCssSnippetForBar(self::MARKI_TAG);
230                    $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES], self::MARKI_TAG);
231                    $tagAttributes->addClassName("list-group");
232                    $renderer->doc .= $tagAttributes->toHtmlEnterTag("ul") . DOKU_LF;
233
234                    break;
235                case DOKU_LEXER_EXIT :
236                    $renderer->doc .= "</ul>" . DOKU_LF;
237                    break;
238                case DOKU_LEXER_UNMATCHED :
239                    $renderer->doc .= PluginUtility::renderUnmatched($data);
240                    break;
241            }
242            return true;
243        }
244
245        // unsupported $mode
246        return false;
247    }
248
249
250}
251
252