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