xref: /plugin/pagecss/syntax.php (revision 6a458d926978e44b3364ae61e8e8373d66dd839f)
1<?php
2/**
3 * DokuWiki Plugin pagecss
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  dWiGhT Mulcahy <dWiGhT.Codes@gmail.com>
7 */
8
9// Ensure DokuWiki is loaded and prevent direct access to the plugin file.
10// DOKU_INC is a constant defined by DokuWiki, representing its installation directory.
11if (!defined('DOKU_INC')) {
12    die();
13}
14
15/**
16 * Class syntax_plugin_pagecss
17 *
18 * This class defines the syntax for the 'pagecss' DokuWiki plugin.
19 * It allows users to embed custom CSS directly within a DokuWiki page
20 * using <pagecss> tags. The plugin captures the content within these
21 * tags but doesn't directly render it into the HTML output in the 'render' method.
22 * Instead, it's expected that another part of the plugin (e.g., an event handler)
23 * would retrieve and process this captured CSS to inject it into the page's
24 * <head> section or similar.
25 */
26class syntax_plugin_pagecss extends DokuWiki_Syntax_Plugin {
27
28    /**
29     * Defines the type of syntax plugin.
30     *
31     * 'container' means this plugin has opening and closing tags (e.g., <pagecss>...</pagecss>).
32     * Other common types include 'substition' (self-closing tags), 'protected' (content not parsed), etc.
33     *
34     * @return string 'container'
35     */
36    public function getType() {
37        return 'container';
38    }
39
40    /**
41     * Defines the paragraph type.
42     *
43     * 'block' indicates that this syntax element creates a block-level element,
44     * meaning it cannot be part of an existing paragraph and will typically start
45     * on a new line.
46     *
47     * @return string 'block'
48     */
49    public function getPType() {
50        return 'block';
51    }
52
53    /**
54     * Defines the sort order for syntax plugins.
55     *
56     * Plugins are processed in ascending order of their sort value.
57     * A higher number means it's processed later. This plugin is given
58     * a relatively high number (199), suggesting it should be processed
59     * after many other common DokuWiki syntax elements.
60     *
61     * @return int The sort order.
62     */
63    public function getSort() {
64        return 199;
65    }
66
67    /**
68     * Connects the plugin's syntax patterns to the DokuWiki lexer.
69     *
70     * This method defines how the DokuWiki parser identifies the start of
71     * this plugin's syntax.
72     *
73     * @param string $mode The current DokuWiki lexer mode (e.g., 'base', 'p_wiki').
74     */
75    public function connectTo($mode) {
76        // Adds an entry pattern for '<pagecss>' tag.
77        // '<pagecss>(?=.*?</pagecss>)' is a regular expression:
78        // - '<pagecss>': Matches the literal string "<pagecss>".
79        // - (?=.*?</pagecss>): This is a positive lookahead assertion.
80        //   - (?=...): Asserts that the following characters match the pattern inside, but
81        //              do not consume them.
82        //   - .*: Matches any character (except newline) zero or more times.
83        //   - ?: Makes the `.*` non-greedy, so it matches the shortest possible string.
84        //   - </pagecss>: Matches the literal closing tag.
85        // This ensures that the '<pagecss>' tag is only recognized as an entry pattern
86        // if it is followed by a closing '</pagecss>' tag somewhere later in the text,
87        // making it a valid container.
88        // 'plugin_pagecss' is the name of the state (or mode) that the lexer enters
89        // when this pattern is matched.
90        $this->Lexer->addEntryPattern('<pagecss>(?=.*?</pagecss>)',$mode,'plugin_pagecss');
91    }
92
93    /**
94     * Defines how the plugin's syntax pattern exits the current state.
95     *
96     * This method specifies the closing tag for the 'container' type plugin.
97     */
98    public function postConnect() {
99        // Adds an exit pattern for '</pagecss>'.
100        // When this pattern is encountered while in the 'plugin_pagecss' state,
101        // the lexer exits that state.
102        $this->Lexer->addExitPattern('</pagecss>', 'plugin_pagecss');
103    }
104
105    /**
106     * Handles the matched syntax.
107     *
108     * This method is called by the DokuWiki parser when the lexer encounters
109     * content related to this plugin's syntax. It processes the raw matched
110     * text and returns a structured data representation.
111     *
112     * @param string        $match   The text that was matched by the lexer.
113     * @param int           $state   The current state of the lexer (e.g., DOKU_LEXER_UNMATCHED,
114     *                               DOKU_LEXER_ENTER, DOKU_LEXER_MATCHED, DOKU_LEXER_EXIT).
115     * @param int           $pos     The byte position of the match within the original text.
116     * @param Doku_Handler  $handler The DokuWiki handler object, used to pass data through the parser.
117     * @return array|bool   Returns an array containing the captured CSS if the state is DOKU_LEXER_UNMATCHED,
118     *                      otherwise returns true to indicate successful handling of enter/exit states.
119     */
120    public function handle($match, $state, $pos, Doku_Handler $handler){
121        // DOKU_LEXER_UNMATCHED state indicates that the content *between* the
122        // entry and exit patterns is being processed. This is where the actual
123        // CSS code is captured.
124        if ($state === DOKU_LEXER_UNMATCHED) {
125            // Return an associative array with the key 'css' holding the matched CSS content.
126            return ['css' => $match];
127        }
128        // For DOKU_LEXER_ENTER and DOKU_LEXER_EXIT states, we just return true
129        // as no specific data needs to be captured for these states beyond marking
130        // the start/end of the container.
131        return true;
132    }
133
134    /**
135     * Renders the handled data into the DokuWiki output.
136     *
137     * This method is called by the DokuWiki renderer to generate the final HTML.
138     * For this plugin, the 'render' method primarily serves for debugging.
139     * The actual injection of CSS into the page is typically handled by an
140     * action plugin that listens to DokuWiki events (e.g., 'TPL_METAHEADERS').
141     *
142     * @param string        $mode     The rendering mode (e.g., 'xhtml', 'odt').
143     * @param Doku_Renderer $renderer The DokuWiki renderer object.
144     * @param mixed         $data     The data returned by the `handle()` method.
145     * @return bool     Always returns true, indicating that the rendering process for this element is complete.
146     */
147    public function render($mode, Doku_Renderer $renderer, $data) {
148        // Check if the data received is an array, which means it contains the
149        // CSS content captured in the `handle` method (state DOKU_LEXER_UNMATCHED).
150        if (is_array($data)) {
151            // Log the captured CSS to the DokuWiki debug log.
152            // substr($data['css'], 0, 200) truncates the CSS string to the first 200 characters
153            // for brevity in the log, preventing very long log entries.
154            dbglog("Captured CSS: " . substr($data['css'], 0, 200));
155
156            // It's important to note that this `render` method *does not* output
157            // the CSS directly to the HTML. If it did, the CSS would appear
158            // in the page body, which is not the desired behavior for CSS.
159            // The purpose of this plugin is to *capture* the CSS, and then a
160            // separate part of the plugin (likely an `action.php` file
161            // listening to `TPL_METAHEADERS` or similar events) would
162            // retrieve this captured CSS from a global variable or cache
163            // and insert it into the appropriate section of the HTML <head>.
164        }
165        // Always return true to indicate successful rendering (even if nothing is output).
166        return true;
167    }
168}
169