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