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