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