16a458d92SdWiGhT<?php 26a458d92SdWiGhT/** 36a458d92SdWiGhT * DokuWiki Plugin pagecss 46a458d92SdWiGhT * 5*f2a25b8dSdwightmulcahy * This file defines the syntax component of the 'pagecss' DokuWiki plugin. 6*f2a25b8dSdwightmulcahy * It is responsible for recognizing and parsing custom CSS blocks embedded 7*f2a25b8dSdwightmulcahy * directly within DokuWiki pages using the `<pagecss>...</pagecss>` tags. 8*f2a25b8dSdwightmulcahy * 9*f2a25b8dSdwightmulcahy * While this syntax plugin captures the CSS content, it does NOT directly 10*f2a25b8dSdwightmulcahy * output it to the HTML. The actual injection of this CSS into the 11*f2a25b8dSdwightmulcahy * `<head>` section of the DokuWiki page is handled by the `action.php` 12*f2a25b8dSdwightmulcahy * component of this plugin (specifically, `action_plugin_pagecss`). 13*f2a25b8dSdwightmulcahy * 146a458d92SdWiGhT * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 156a458d92SdWiGhT * @author dWiGhT Mulcahy <dWiGhT.Codes@gmail.com> 166a458d92SdWiGhT */ 176a458d92SdWiGhT 186a458d92SdWiGhT// Ensure DokuWiki is loaded and prevent direct access to the plugin file. 196a458d92SdWiGhT// DOKU_INC is a constant defined by DokuWiki, representing its installation directory. 20*f2a25b8dSdwightmulcahy// If DOKU_INC is not defined, it means the script is being accessed directly, 21*f2a25b8dSdwightmulcahy// which is not allowed for DokuWiki plugins. 226a458d92SdWiGhTif (!defined('DOKU_INC')) { 236a458d92SdWiGhT die(); 246a458d92SdWiGhT} 256a458d92SdWiGhT 266a458d92SdWiGhT/** 276a458d92SdWiGhT * Class syntax_plugin_pagecss 286a458d92SdWiGhT * 29*f2a25b8dSdwightmulcahy * This class extends DokuWiki_Syntax_Plugin, providing the necessary 30*f2a25b8dSdwightmulcahy * methods to define a custom syntax for embedding CSS within DokuWiki pages. 31*f2a25b8dSdwightmulcahy * It's responsible for: 32*f2a25b8dSdwightmulcahy * 1. Defining the type of syntax (container). 33*f2a25b8dSdwightmulcahy * 2. Specifying the block-level nature of the syntax. 34*f2a25b8dSdwightmulcahy * 3. Setting its processing priority. 35*f2a25b8dSdwightmulcahy * 4. Connecting its entry and exit patterns to the DokuWiki lexer. 36*f2a25b8dSdwightmulcahy * 5. Handling the data parsed by the lexer (capturing the CSS content). 37*f2a25b8dSdwightmulcahy * 6. (Optionally) Rendering output, though for this plugin, rendering is minimal 38*f2a25b8dSdwightmulcahy * as the CSS is passed to an action plugin for actual injection. 396a458d92SdWiGhT */ 406a458d92SdWiGhTclass syntax_plugin_pagecss extends DokuWiki_Syntax_Plugin { 416a458d92SdWiGhT 426a458d92SdWiGhT /** 436a458d92SdWiGhT * Defines the type of syntax plugin. 446a458d92SdWiGhT * 45*f2a25b8dSdwightmulcahy * 'container' means this plugin has distinct opening and closing tags, 46*f2a25b8dSdwightmulcahy * and it encapsulates content between them (e.g., `<pagecss>...</pagecss>`). 47*f2a25b8dSdwightmulcahy * Other common types include 'substition' (self-closing tags), 'protected' 48*f2a25b8dSdwightmulcahy * (content not parsed by DokuWiki), 'formatting' (inline text formatting), etc. 496a458d92SdWiGhT * 506a458d92SdWiGhT * @return string 'container' 516a458d92SdWiGhT */ 526a458d92SdWiGhT public function getType() { 536a458d92SdWiGhT return 'container'; 546a458d92SdWiGhT } 556a458d92SdWiGhT 566a458d92SdWiGhT /** 576a458d92SdWiGhT * Defines the paragraph type. 586a458d92SdWiGhT * 59*f2a25b8dSdwightmulcahy * 'block' indicates that this syntax element creates a block-level element. 60*f2a25b8dSdwightmulcahy * This means it cannot be part of an existing paragraph and will typically 61*f2a25b8dSdwightmulcahy * force a new line before and after its content in the parsed output. 62*f2a25b8dSdwightmulcahy * This is appropriate for CSS blocks which are not meant to be inline text. 636a458d92SdWiGhT * 646a458d92SdWiGhT * @return string 'block' 656a458d92SdWiGhT */ 666a458d92SdWiGhT public function getPType() { 676a458d92SdWiGhT return 'block'; 686a458d92SdWiGhT } 696a458d92SdWiGhT 706a458d92SdWiGhT /** 71*f2a25b8dSdwightmulcahy * Defines the sort order (priority) for syntax plugins. 726a458d92SdWiGhT * 73*f2a25b8dSdwightmulcahy * DokuWiki processes syntax plugins in ascending order of their sort value. 74*f2a25b8dSdwightmulcahy * A higher number means the plugin is processed later. This plugin is given 75*f2a25b8dSdwightmulcahy * a relatively high number (199). This ensures that it runs after most 76*f2a25b8dSdwightmulcahy * other common DokuWiki syntax elements have been processed, allowing it 77*f2a25b8dSdwightmulcahy * to capture raw text that might otherwise be interpreted by other plugins. 786a458d92SdWiGhT * 79*f2a25b8dSdwightmulcahy * @return int The sort order value (e.g., 199). 806a458d92SdWiGhT */ 816a458d92SdWiGhT public function getSort() { 826a458d92SdWiGhT return 199; 836a458d92SdWiGhT } 846a458d92SdWiGhT 856a458d92SdWiGhT /** 866a458d92SdWiGhT * Connects the plugin's syntax patterns to the DokuWiki lexer. 876a458d92SdWiGhT * 88*f2a25b8dSdwightmulcahy * This method is crucial for telling DokuWiki how to identify the start 89*f2a25b8dSdwightmulcahy * of this plugin's custom syntax within the wiki text. 906a458d92SdWiGhT * 916a458d92SdWiGhT * @param string $mode The current DokuWiki lexer mode (e.g., 'base', 'p_wiki'). 92*f2a25b8dSdwightmulcahy * Plugins often connect to 'base' mode to be available everywhere. 936a458d92SdWiGhT */ 946a458d92SdWiGhT public function connectTo($mode) { 95*f2a25b8dSdwightmulcahy // Adds an entry pattern for the '<pagecss>' opening tag. 96*f2a25b8dSdwightmulcahy // The regular expression '<pagecss>(?=.*?</pagecss>)' is used: 976a458d92SdWiGhT // - '<pagecss>': Matches the literal string "<pagecss>". 986a458d92SdWiGhT // - (?=.*?</pagecss>): This is a positive lookahead assertion. 99*f2a25b8dSdwightmulcahy // - `(?=...)`: Asserts that the characters immediately following the current position 100*f2a25b8dSdwightmulcahy // match the pattern inside the lookahead, but these characters are NOT 101*f2a25b8dSdwightmulcahy // consumed by this match. This means the lexer won't advance past `<pagecss>` 102*f2a25b8dSdwightmulcahy // based on the lookahead part. 103*f2a25b8dSdwightmulcahy // - `.*?`: Matches any character (`.`) zero or more times (`*`) in a non-greedy way (`?`). 104*f2a25b8dSdwightmulcahy // This ensures it matches the shortest possible string until the next part. 105*f2a25b8dSdwightmulcahy // - `</pagecss>`: Matches the literal closing tag. 106*f2a25b8dSdwightmulcahy // This lookahead ensures that the '<pagecss>' tag is only recognized as a valid entry 107*f2a25b8dSdwightmulcahy // pattern if it is eventually followed by a matching closing '</pagecss>' tag. 108*f2a25b8dSdwightmulcahy // 'plugin_pagecss' is the name of the new lexer state (or mode) that DokuWiki enters 109*f2a25b8dSdwightmulcahy // when this pattern is matched. All content until the exit pattern will be processed 110*f2a25b8dSdwightmulcahy // within this 'plugin_pagecss' state. 1116a458d92SdWiGhT $this->Lexer->addEntryPattern('<pagecss>(?=.*?</pagecss>)',$mode,'plugin_pagecss'); 1126a458d92SdWiGhT } 1136a458d92SdWiGhT 1146a458d92SdWiGhT /** 1156a458d92SdWiGhT * Defines how the plugin's syntax pattern exits the current state. 1166a458d92SdWiGhT * 117*f2a25b8dSdwightmulcahy * This method specifies the closing tag for this 'container' type plugin. 118*f2a25b8dSdwightmulcahy * When the lexer is in the 'plugin_pagecss' state and encounters this pattern, 119*f2a25b8dSdwightmulcahy * it will exit that state and return to the previous lexer mode. 1206a458d92SdWiGhT */ 1216a458d92SdWiGhT public function postConnect() { 1226a458d92SdWiGhT // Adds an exit pattern for '</pagecss>'. 123*f2a25b8dSdwightmulcahy // When this pattern is encountered while the lexer is in the 'plugin_pagecss' state, 124*f2a25b8dSdwightmulcahy // it signifies the end of the custom CSS block. 1256a458d92SdWiGhT $this->Lexer->addExitPattern('</pagecss>', 'plugin_pagecss'); 1266a458d92SdWiGhT } 1276a458d92SdWiGhT 1286a458d92SdWiGhT /** 1296a458d92SdWiGhT * Handles the matched syntax. 1306a458d92SdWiGhT * 131*f2a25b8dSdwightmulcahy * This method is called by the DokuWiki parser when the lexer identifies 132*f2a25b8dSdwightmulcahy * content related to this plugin's defined syntax patterns. Its primary 133*f2a25b8dSdwightmulcahy * role is to process the raw matched text and transform it into a 134*f2a25b8dSdwightmulcahy * structured data representation that can be used by the renderer or other 135*f2a25b8dSdwightmulcahy * parts of the plugin (like the action plugin). 1366a458d92SdWiGhT * 137*f2a25b8dSdwightmulcahy * @param string $match The raw text that was matched by the lexer (e.g., "<pagecss>", "body { color: red; }", "</pagecss>"). 138*f2a25b8dSdwightmulcahy * @param int $state The current state of the lexer when the match occurred. 139*f2a25b8dSdwightmulcahy * Possible states include: 140*f2a25b8dSdwightmulcahy * - DOKU_LEXER_ENTER: The opening tag was matched (e.g., '<pagecss>'). 141*f2a25b8dSdwightmulcahy * - DOKU_LEXER_UNMATCHED: Content between the entry and exit patterns (the actual CSS). 142*f2a25b8dSdwightmulcahy * - DOKU_LEXER_EXIT: The closing tag was matched (e.g., '</pagecss>'). 1436a458d92SdWiGhT * @param int $pos The byte position of the match within the original text. 144*f2a25b8dSdwightmulcahy * @param Doku_Handler $handler The DokuWiki handler object. This object is used to 145*f2a25b8dSdwightmulcahy * manipulate the parser's instruction stream (e.g., adding instructions). 146*f2a25b8dSdwightmulcahy * @return array|bool Returns an array containing the captured CSS content if the state is 147*f2a25b8dSdwightmulcahy * DOKU_LEXER_UNMATCHED, otherwise returns true to indicate successful handling 148*f2a25b8dSdwightmulcahy * of the enter/exit states (no specific data needed for those). 1496a458d92SdWiGhT */ 1506a458d92SdWiGhT public function handle($match, $state, $pos, Doku_Handler $handler){ 151*f2a25b8dSdwightmulcahy // This condition checks if the lexer is processing the actual content 152*f2a25b8dSdwightmulcahy // *between* the opening and closing tags. This is where the user's CSS code resides. 1536a458d92SdWiGhT if ($state === DOKU_LEXER_UNMATCHED) { 154*f2a25b8dSdwightmulcahy // Return an associative array where the key 'css' holds the matched content. 155*f2a25b8dSdwightmulcahy // This data will then be passed to the `render` method of this plugin. 1566a458d92SdWiGhT return ['css' => $match]; 1576a458d92SdWiGhT } 158*f2a25b8dSdwightmulcahy // For the DOKU_LEXER_ENTER (opening tag) and DOKU_LEXER_EXIT (closing tag) states, 159*f2a25b8dSdwightmulcahy // no specific data needs to be captured by the syntax plugin itself, 160*f2a25b8dSdwightmulcahy // so we simply return `true` to acknowledge that the state transition was handled. 1616a458d92SdWiGhT return true; 1626a458d92SdWiGhT } 1636a458d92SdWiGhT 1646a458d92SdWiGhT /** 1656a458d92SdWiGhT * Renders the handled data into the DokuWiki output. 1666a458d92SdWiGhT * 167*f2a25b8dSdwightmulcahy * This method is called by the DokuWiki renderer to generate the final HTML 168*f2a25b8dSdwightmulcahy * or other output format (e.g., XHTML, ODT). 169*f2a25b8dSdwightmulcahy * 170*f2a25b8dSdwightmulcahy * For the 'pagecss' plugin, this `render` method primarily serves for 171*f2a25b8dSdwightmulcahy * debugging purposes. The actual injection of the CSS into the page's 172*f2a25b8dSdwightmulcahy * `<head>` section is NOT done here. Instead, the CSS is captured by 173*f2a25b8dSdwightmulcahy * the `handle()` method and then typically retrieved and processed by an 174*f2a25b8dSdwightmulcahy * accompanying action plugin (defined in `action.php`) which listens to 175*f2a25b8dSdwightmulcahy * DokuWiki events (e.g., `TPL_METAHEADER_OUTPUT`) to insert the CSS 176*f2a25b8dSdwightmulcahy * at the correct location in the HTML document. 1776a458d92SdWiGhT * 1786a458d92SdWiGhT * @param string $mode The rendering mode (e.g., 'xhtml', 'odt'). 179*f2a25b8dSdwightmulcahy * @param Doku_Renderer $renderer The DokuWiki renderer object, used to output HTML, etc. 180*f2a25b8dSdwightmulcahy * @param mixed $data The data returned by the `handle()` method. For this plugin, 181*f2a25b8dSdwightmulcahy * it's an array like `['css' => '...']` when processing the CSS content. 182*f2a25b8dSdwightmulcahy * @return bool Always returns true, indicating that the rendering process for this 183*f2a25b8dSdwightmulcahy * syntax element has completed successfully, even if no visible output is produced. 1846a458d92SdWiGhT */ 1856a458d92SdWiGhT public function render($mode, Doku_Renderer $renderer, $data) { 186*f2a25b8dSdwightmulcahy // Check if the received data is an array, which signifies that it contains 187*f2a25b8dSdwightmulcahy // the CSS content captured during the DOKU_LEXER_UNMATCHED state in `handle()`. 1886a458d92SdWiGhT if (is_array($data)) { 189*f2a25b8dSdwightmulcahy // Log the captured CSS content to the DokuWiki debug log. 190*f2a25b8dSdwightmulcahy // This is useful for verifying that the plugin correctly extracts the CSS. 191*f2a25b8dSdwightmulcahy // `substr($data['css'], 0, 200)` truncates the CSS string to the first 192*f2a25b8dSdwightmulcahy // 200 characters to prevent excessively long entries in the debug log. 193*f2a25b8dSdwightmulcahy dbglog("pagecss plugin: Captured CSS (first 200 chars): " . substr($data['css'], 0, 200)); 1946a458d92SdWiGhT 195*f2a25b8dSdwightmulcahy // IMPORTANT NOTE: This `render` method DOES NOT output the CSS directly 196*f2a25b8dSdwightmulcahy // to the HTML page's `<body>`. If it did, the CSS would not be applied 197*f2a25b8dSdwightmulcahy // correctly and would likely be visible as text on the page. 198*f2a25b8dSdwightmulcahy // The sole purpose of this `syntax.php` file is to identify, parse, 199*f2a25b8dSdwightmulcahy // and capture the CSS content. The `action.php` file (the action plugin) 200*f2a25b8dSdwightmulcahy // is responsible for retrieving this captured CSS and injecting it into 201*f2a25b8dSdwightmulcahy // the `<head>` section of the HTML. 2026a458d92SdWiGhT } 203*f2a25b8dSdwightmulcahy // Always return true to signal that the rendering process for this syntax element 204*f2a25b8dSdwightmulcahy // has finished successfully. 2056a458d92SdWiGhT return true; 2066a458d92SdWiGhT } 2076a458d92SdWiGhT} 208