xref: /plugin/combo/syntax/para.php (revision 21913ab3235d516e2fa19c7e3929b555b3a2bda1)
1*21913ab3SNickeau<?php
2*21913ab3SNickeau
3*21913ab3SNickeau
4*21913ab3SNickeaurequire_once(__DIR__ . "/../class/Analytics.php");
5*21913ab3SNickeaurequire_once(__DIR__ . "/../class/PluginUtility.php");
6*21913ab3SNickeaurequire_once(__DIR__ . "/../class/LinkUtility.php");
7*21913ab3SNickeaurequire_once(__DIR__ . "/../class/HtmlUtility.php");
8*21913ab3SNickeau
9*21913ab3SNickeauuse ComboStrap\Analytics;
10*21913ab3SNickeauuse ComboStrap\Call;
11*21913ab3SNickeauuse ComboStrap\LogUtility;
12*21913ab3SNickeauuse ComboStrap\PluginUtility;
13*21913ab3SNickeauuse ComboStrap\Tag;
14*21913ab3SNickeauuse ComboStrap\TagAttributes;
15*21913ab3SNickeau
16*21913ab3SNickeauif (!defined('DOKU_INC')) die();
17*21913ab3SNickeau
18*21913ab3SNickeau/**
19*21913ab3SNickeau *
20*21913ab3SNickeau * A paragraph syntax
21*21913ab3SNickeau *
22*21913ab3SNickeau * This syntax component is used dynamically while parsing (at the {@link DOKU_LEXER_END} of {@link \dokuwiki\Extension\SyntaxPlugin::handle()}
23*21913ab3SNickeau * with the function {@link \syntax_plugin_combo_para::fromEolToParagraphUntilEndOfStack()}
24*21913ab3SNickeau *
25*21913ab3SNickeau *
26*21913ab3SNickeau * !!!!!
27*21913ab3SNickeau *
28*21913ab3SNickeau * Info: The `eol` call are temporary created with {@link \dokuwiki\Parsing\ParserMode\Eol}
29*21913ab3SNickeau * and transformed to `p_open` and `p_close` via {@link \dokuwiki\Parsing\Handler\Block::process()}
30*21913ab3SNickeau *
31*21913ab3SNickeau * Note: p_open call may appears when the {@link \ComboStrap\Syntax::getPType()} is set to `block` or `stack`
32*21913ab3SNickeau * and the next call is not a block or a stack
33*21913ab3SNickeau *
34*21913ab3SNickeau * !!!!!
35*21913ab3SNickeau *
36*21913ab3SNickeau *
37*21913ab3SNickeau * Note on Typography
38*21913ab3SNickeau * TODO: https://github.com/typekit/webfontloader
39*21913ab3SNickeau * https://www.dokuwiki.org/plugin:typography
40*21913ab3SNickeau * https://stackoverflow.design/email/base/typography/
41*21913ab3SNickeau * http://kyleamathews.github.io/typography.js/
42*21913ab3SNickeau * https://docs.gitbook.com/features/advanced-branding (Roboto, Roboto Slab, Open Sans, Source Sans Pro, Lato, Ubuntu, Raleway, Merriweather)
43*21913ab3SNickeau * http://themenectar.com/docs/salient/theme-options/typography/ (Doc)
44*21913ab3SNickeau * https://www.modularscale.com/ - see the size of font
45*21913ab3SNickeau *
46*21913ab3SNickeau * See the fonts on your computer
47*21913ab3SNickeau * https://wordmark.it/
48*21913ab3SNickeau *
49*21913ab3SNickeau * What's a type ? Type terminology
50*21913ab3SNickeau * https://www.supremo.co.uk/typeterms/
51*21913ab3SNickeau *
52*21913ab3SNickeau * https://theprotoolbox.com/browse/font-tools/
53*21913ab3SNickeau */
54*21913ab3SNickeauclass syntax_plugin_combo_para extends DokuWiki_Syntax_Plugin
55*21913ab3SNickeau{
56*21913ab3SNickeau
57*21913ab3SNickeau    const TAG = 'para';
58*21913ab3SNickeau    const COMPONENT = "combo_para";
59*21913ab3SNickeau
60*21913ab3SNickeau
61*21913ab3SNickeau    /**
62*21913ab3SNickeau     * Syntax Type.
63*21913ab3SNickeau     *
64*21913ab3SNickeau     * Needs to return one of the mode types defined in $PARSER_MODES in parser.php
65*21913ab3SNickeau     * @see https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
66*21913ab3SNickeau     */
67*21913ab3SNickeau    function getType()
68*21913ab3SNickeau    {
69*21913ab3SNickeau        return 'paragraphs';
70*21913ab3SNickeau    }
71*21913ab3SNickeau
72*21913ab3SNickeau    /**
73*21913ab3SNickeau     * How Dokuwiki will add P element
74*21913ab3SNickeau     *
75*21913ab3SNickeau     *  * 'normal' - The plugin can be used inside paragraphs
76*21913ab3SNickeau     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
77*21913ab3SNickeau     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
78*21913ab3SNickeau     *
79*21913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::getPType()
80*21913ab3SNickeau     */
81*21913ab3SNickeau    function getPType()
82*21913ab3SNickeau    {
83*21913ab3SNickeau        /**
84*21913ab3SNickeau         * !important!
85*21913ab3SNickeau         * The {@link \dokuwiki\Parsing\Handler\Block::process()}
86*21913ab3SNickeau         * will then not create an extra paragraph after it encounters a block
87*21913ab3SNickeau         */
88*21913ab3SNickeau        return 'block';
89*21913ab3SNickeau    }
90*21913ab3SNickeau
91*21913ab3SNickeau    /**
92*21913ab3SNickeau     * @return array
93*21913ab3SNickeau     * Allow which kind of plugin inside
94*21913ab3SNickeau     *
95*21913ab3SNickeau     * No one of array('container', 'baseonly', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
96*21913ab3SNickeau     * because we manage self the content and we call self the parser
97*21913ab3SNickeau     */
98*21913ab3SNickeau    function getAllowedTypes()
99*21913ab3SNickeau    {
100*21913ab3SNickeau        /**
101*21913ab3SNickeau         * Not needed as we don't have any {@link syntax_plugin_combo_para::connectTo()}
102*21913ab3SNickeau         */
103*21913ab3SNickeau        return array();
104*21913ab3SNickeau    }
105*21913ab3SNickeau
106*21913ab3SNickeau
107*21913ab3SNickeau    /**
108*21913ab3SNickeau     * @see Doku_Parser_Mode::getSort()
109*21913ab3SNickeau     * The mode with the lowest sort number will win out
110*21913ab3SNickeau     *
111*21913ab3SNickeau     */
112*21913ab3SNickeau    function getSort()
113*21913ab3SNickeau    {
114*21913ab3SNickeau        /**
115*21913ab3SNickeau         * Not really needed as we don't have any {@link syntax_plugin_combo_para::connectTo()}
116*21913ab3SNickeau         *
117*21913ab3SNickeau         * Note: if we start to use it should be less than 370
118*21913ab3SNickeau         * Ie Less than {@link \dokuwiki\Parsing\ParserMode\Eol::getSort()}
119*21913ab3SNickeau         */
120*21913ab3SNickeau        return 369;
121*21913ab3SNickeau    }
122*21913ab3SNickeau
123*21913ab3SNickeau
124*21913ab3SNickeau    function connectTo($mode)
125*21913ab3SNickeau    {
126*21913ab3SNickeau
127*21913ab3SNickeau        /**
128*21913ab3SNickeau         * No need to connect
129*21913ab3SNickeau         * This syntax plugin is added dynamically with the {@link Tag::processEolToEndStack()}
130*21913ab3SNickeau         * function
131*21913ab3SNickeau         */
132*21913ab3SNickeau
133*21913ab3SNickeau    }
134*21913ab3SNickeau
135*21913ab3SNickeau
136*21913ab3SNickeau    /**
137*21913ab3SNickeau     * The handler for an internal link
138*21913ab3SNickeau     * based on `internallink` in {@link Doku_Handler}
139*21913ab3SNickeau     * The handler call the good renderer in {@link Doku_Renderer_xhtml} with
140*21913ab3SNickeau     * the parameters (ie for instance internallink)
141*21913ab3SNickeau     * @param string $match
142*21913ab3SNickeau     * @param int $state
143*21913ab3SNickeau     * @param int $pos
144*21913ab3SNickeau     * @param Doku_Handler $handler
145*21913ab3SNickeau     * @return array|bool
146*21913ab3SNickeau     */
147*21913ab3SNickeau    function handle($match, $state, $pos, Doku_Handler $handler)
148*21913ab3SNickeau    {
149*21913ab3SNickeau
150*21913ab3SNickeau        /**
151*21913ab3SNickeau         * No need to handle,
152*21913ab3SNickeau         * there is no {@link syntax_plugin_combo_para::connectTo() connection}
153*21913ab3SNickeau         */
154*21913ab3SNickeau        return true;
155*21913ab3SNickeau
156*21913ab3SNickeau
157*21913ab3SNickeau    }
158*21913ab3SNickeau
159*21913ab3SNickeau    /**
160*21913ab3SNickeau     * Render the output
161*21913ab3SNickeau     * @param string $format
162*21913ab3SNickeau     * @param Doku_Renderer $renderer
163*21913ab3SNickeau     * @param array $data - what the function handle() return'ed
164*21913ab3SNickeau     * @return boolean - rendered correctly? (however, returned value is not used at the moment)
165*21913ab3SNickeau     * @see DokuWiki_Syntax_Plugin::render()
166*21913ab3SNickeau     *
167*21913ab3SNickeau     *
168*21913ab3SNickeau     */
169*21913ab3SNickeau    function render($format, Doku_Renderer $renderer, $data)
170*21913ab3SNickeau    {
171*21913ab3SNickeau        // The data
172*21913ab3SNickeau        switch ($format) {
173*21913ab3SNickeau            case 'xhtml':
174*21913ab3SNickeau
175*21913ab3SNickeau                /** @var Doku_Renderer_xhtml $renderer */
176*21913ab3SNickeau                $state = $data[PluginUtility::STATE];
177*21913ab3SNickeau                switch ($state) {
178*21913ab3SNickeau                    case DOKU_LEXER_ENTER:
179*21913ab3SNickeau                        $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]);
180*21913ab3SNickeau                        $renderer->doc .= $tagAttributes->toHtmlEnterTag("p");
181*21913ab3SNickeau                        break;
182*21913ab3SNickeau                    case DOKU_LEXER_SPECIAL:
183*21913ab3SNickeau                        $tagAttributes = TagAttributes::createFromCallStackArray($data[PluginUtility::ATTRIBUTES]);
184*21913ab3SNickeau                        $renderer->doc .= $tagAttributes->toHtmlEnterTag("p");
185*21913ab3SNickeau                        $renderer->doc .= "</p>";
186*21913ab3SNickeau                        break;
187*21913ab3SNickeau                    case DOKU_LEXER_EXIT:
188*21913ab3SNickeau                        $renderer->doc .= "</p>";
189*21913ab3SNickeau                        break;
190*21913ab3SNickeau                }
191*21913ab3SNickeau                return true;
192*21913ab3SNickeau
193*21913ab3SNickeau            case 'metadata':
194*21913ab3SNickeau
195*21913ab3SNickeau                /** @var Doku_Renderer_metadata $renderer */
196*21913ab3SNickeau
197*21913ab3SNickeau
198*21913ab3SNickeau                return true;
199*21913ab3SNickeau
200*21913ab3SNickeau
201*21913ab3SNickeau            case Analytics::RENDERER_FORMAT:
202*21913ab3SNickeau
203*21913ab3SNickeau                /**
204*21913ab3SNickeau                 * @var renderer_plugin_combo_analytics $renderer
205*21913ab3SNickeau                 */
206*21913ab3SNickeau                return true;
207*21913ab3SNickeau
208*21913ab3SNickeau        }
209*21913ab3SNickeau        // unsupported $mode
210*21913ab3SNickeau        return false;
211*21913ab3SNickeau    }
212*21913ab3SNickeau
213*21913ab3SNickeau    /**
214*21913ab3SNickeau     *
215*21913ab3SNickeau     * Transform EOL into paragraph
216*21913ab3SNickeau     * between the {@link CallStack::getActualCall()} and the {@link CallStack::isPointerAtEnd()}
217*21913ab3SNickeau     * of the stack
218*21913ab3SNickeau     *
219*21913ab3SNickeau     * Info: Basically, you get an new paragraph with a blank line or `\\` : https://www.dokuwiki.org/faq:newlines
220*21913ab3SNickeau     *
221*21913ab3SNickeau     * It replaces the  {@link \dokuwiki\Parsing\Handler\Block::process() eol to paragraph Dokuwiki process}
222*21913ab3SNickeau     * that takes place at the end of parsing process on the whole stack
223*21913ab3SNickeau     *
224*21913ab3SNickeau     * Info: The `eol` call are temporary created with {@link \dokuwiki\Parsing\ParserMode\Eol}
225*21913ab3SNickeau     * and transformed to `p_open` and `p_close` via {@link \dokuwiki\Parsing\Handler\Block::process()}
226*21913ab3SNickeau     *
227*21913ab3SNickeau     * @param \ComboStrap\CallStack $callstack
228*21913ab3SNickeau     * @param $class
229*21913ab3SNickeau     */
230*21913ab3SNickeau    public static function fromEolToParagraphUntilEndOfStack(&$callstack, $class)
231*21913ab3SNickeau    {
232*21913ab3SNickeau        /**
233*21913ab3SNickeau         * The attributes passed to the paragraph
234*21913ab3SNickeau         */
235*21913ab3SNickeau        $attributes = array("class" => $class);
236*21913ab3SNickeau
237*21913ab3SNickeau        /**
238*21913ab3SNickeau         * The syntax plugin that implements the paragraph
239*21913ab3SNickeau         * ie {@link \syntax_plugin_combo_para}
240*21913ab3SNickeau         * We will transform the eol with a call to this syntax plugin
241*21913ab3SNickeau         * to create the paragraph
242*21913ab3SNickeau         */
243*21913ab3SNickeau        $paragraphComponent = \syntax_plugin_combo_para::COMPONENT;
244*21913ab3SNickeau
245*21913ab3SNickeau        /**
246*21913ab3SNickeau         * The running variables
247*21913ab3SNickeau         */
248*21913ab3SNickeau        $paragraphIsOpen = false; // A pointer to see if the paragraph is open
249*21913ab3SNickeau        while ($callstack->next()) {
250*21913ab3SNickeau
251*21913ab3SNickeau            $actualCall = $callstack->getActualCall();
252*21913ab3SNickeau            if ($actualCall->getTagName() === "eol") {
253*21913ab3SNickeau
254*21913ab3SNickeau                /**
255*21913ab3SNickeau                 * Next Call
256*21913ab3SNickeau                 */
257*21913ab3SNickeau                $nextCall = $callstack->next();
258*21913ab3SNickeau                $callstack->prev();
259*21913ab3SNickeau                if ($nextCall === false) {
260*21913ab3SNickeau                    $nextDisplay = "last";
261*21913ab3SNickeau                    $nextCall = null;
262*21913ab3SNickeau                } else {
263*21913ab3SNickeau                    $nextDisplay = $nextCall->getDisplay();
264*21913ab3SNickeau                }
265*21913ab3SNickeau
266*21913ab3SNickeau
267*21913ab3SNickeau                /**
268*21913ab3SNickeau                 * Processing
269*21913ab3SNickeau                 */
270*21913ab3SNickeau                if (!$paragraphIsOpen) {
271*21913ab3SNickeau
272*21913ab3SNickeau                    switch ($nextDisplay) {
273*21913ab3SNickeau                        case Call::BlOCK_DISPLAY:
274*21913ab3SNickeau                        case "last":
275*21913ab3SNickeau                            $callstack->deleteActualCallAndPrevious();
276*21913ab3SNickeau                            break;
277*21913ab3SNickeau                        case Call::INLINE_DISPLAY:
278*21913ab3SNickeau                            $paragraphIsOpen = true;
279*21913ab3SNickeau                            $actualCall->updateToPluginComponent(
280*21913ab3SNickeau                                $paragraphComponent,
281*21913ab3SNickeau                                DOKU_LEXER_ENTER,
282*21913ab3SNickeau                                $attributes
283*21913ab3SNickeau                            );
284*21913ab3SNickeau                            break;
285*21913ab3SNickeau                        case "eol":
286*21913ab3SNickeau                            /**
287*21913ab3SNickeau                             * Empty line
288*21913ab3SNickeau                             */
289*21913ab3SNickeau                            $actualCall->updateToPluginComponent(
290*21913ab3SNickeau                                $paragraphComponent,
291*21913ab3SNickeau                                DOKU_LEXER_ENTER,
292*21913ab3SNickeau                                $attributes
293*21913ab3SNickeau                            );
294*21913ab3SNickeau                            $nextCall->updateToPluginComponent(
295*21913ab3SNickeau                                $paragraphComponent,
296*21913ab3SNickeau                                DOKU_LEXER_EXIT
297*21913ab3SNickeau                            );
298*21913ab3SNickeau                            $callstack->next();
299*21913ab3SNickeau                            break;
300*21913ab3SNickeau                        default:
301*21913ab3SNickeau                            LogUtility::msg("The eol action for the combination enter / (" . $nextDisplay . ") of the call ( $nextCall ) was not implemented", LogUtility::LVL_MSG_ERROR);
302*21913ab3SNickeau                            break;
303*21913ab3SNickeau                    }
304*21913ab3SNickeau                } else {
305*21913ab3SNickeau                    /**
306*21913ab3SNickeau                     * Paragraph is open
307*21913ab3SNickeau                     */
308*21913ab3SNickeau                    switch ($nextDisplay) {
309*21913ab3SNickeau                        case "eol":
310*21913ab3SNickeau                            /**
311*21913ab3SNickeau                             * Empty line
312*21913ab3SNickeau                             */
313*21913ab3SNickeau                            $actualCall->updateToPluginComponent(
314*21913ab3SNickeau                                $paragraphComponent,
315*21913ab3SNickeau                                DOKU_LEXER_EXIT
316*21913ab3SNickeau                            );
317*21913ab3SNickeau                            $nextCall->updateToPluginComponent(
318*21913ab3SNickeau                                $paragraphComponent,
319*21913ab3SNickeau                                DOKU_LEXER_ENTER,
320*21913ab3SNickeau                                $attributes
321*21913ab3SNickeau                            );
322*21913ab3SNickeau                            $callstack->next();
323*21913ab3SNickeau                            break;
324*21913ab3SNickeau                        case Call::INLINE_DISPLAY:
325*21913ab3SNickeau                            // A space
326*21913ab3SNickeau                            $actualCall->updateEolToSpace();
327*21913ab3SNickeau                            break;
328*21913ab3SNickeau                        case Call::BlOCK_DISPLAY:
329*21913ab3SNickeau                        case "last";
330*21913ab3SNickeau                            $actualCall->updateToPluginComponent(
331*21913ab3SNickeau                                $paragraphComponent,
332*21913ab3SNickeau                                DOKU_LEXER_EXIT
333*21913ab3SNickeau                            );
334*21913ab3SNickeau                            $paragraphIsOpen = false;
335*21913ab3SNickeau                            break;
336*21913ab3SNickeau                        default:
337*21913ab3SNickeau                            LogUtility::msg("The display for a open paragraph (" . $nextDisplay . ") is not implemented", LogUtility::LVL_MSG_ERROR);
338*21913ab3SNickeau                            break;
339*21913ab3SNickeau                    }
340*21913ab3SNickeau                }
341*21913ab3SNickeau
342*21913ab3SNickeau            }
343*21913ab3SNickeau        }
344*21913ab3SNickeau
345*21913ab3SNickeau        // if the paragraph is open close it
346*21913ab3SNickeau        if ($paragraphIsOpen) {
347*21913ab3SNickeau            $callstack->insertBefore(
348*21913ab3SNickeau                Call::createComboCall(
349*21913ab3SNickeau                    \syntax_plugin_combo_para::TAG,
350*21913ab3SNickeau                    DOKU_LEXER_EXIT
351*21913ab3SNickeau                )
352*21913ab3SNickeau            );
353*21913ab3SNickeau        }
354*21913ab3SNickeau    }
355*21913ab3SNickeau
356*21913ab3SNickeau}
357*21913ab3SNickeau
358