1<?php 2/** 3 * fontcolor Plugin: Allows user-defined font colors 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author modified by ThorstenStratmann <thorsten.stratmann@web.de> 7 * @link https://www.dokuwiki.org/plugin:fontcolor 8 * @version 3.1 9 */ 10 11if(!defined('DOKU_INC')) die(); 12 13use LesserPHP\Lessc; 14 15/** 16 * All DokuWiki plugins to extend the parser/rendering mechanism 17 * need to inherit from this class 18 */ 19class syntax_plugin_fontcolor extends DokuWiki_Syntax_Plugin { 20 21 protected $odt_styles; 22 23 /** 24 * What kind of syntax are we? 25 * 26 * @return string 27 */ 28 public function getType() { 29 return 'formatting'; 30 } 31 32 /** 33 * What kind of syntax do we allow (optional) 34 * 35 * @return array 36 */ 37 public function getAllowedTypes() { 38 return array('formatting', 'substition', 'disabled'); 39 } 40 41 /** 42 * What about paragraphs? (optional) 43 * 44 * @return string 45 */ 46 public function getPType() { 47 return 'normal'; 48 } 49 50 /** 51 * Where to sort in? 52 * 53 * @return int 54 */ 55 public function getSort() { 56 return 90; 57 } 58 59 /** 60 * Connect pattern to lexer 61 * 62 * @param string $mode 63 */ 64 public function connectTo($mode) { 65 $this->Lexer->addEntryPattern('<fc.*?>(?=.*?</fc>)', $mode, 'plugin_fontcolor'); 66 /* $this->Lexer->addEntryPattern('<FC.*?>(?=.*?</FC>)', $mode, 'plugin_fontcolor'); */ 67 68 } 69 70 public function postConnect() { 71 $this->Lexer->addExitPattern('</fc>', 'plugin_fontcolor'); 72 //$this->Lexer->addExitPattern('</FC>', 'plugin_fontcolor'); 73 } 74 75 /** 76 * override default accepts() method to allow nesting - ie, to get the plugin accepts its own entry syntax 77 * 78 * @param string $mode 79 * @return bool 80 */ 81 public function accepts($mode) { 82 if($mode == 'plugin_fontcolor') return true; 83 return parent::accepts($mode); 84 } 85 86 /** 87 * Handle the match 88 * 89 * @param string $match The text matched by the patterns 90 * @param int $state The lexer state for the match 91 * @param int $pos The character position of the matched text 92 * @param Doku_Handler $handler The Doku_Handler object 93 * @return array Return an array with all data you want to use in render 94 */ 95 public function handle($match, $state, $pos, Doku_Handler $handler) { 96 switch($state) { 97 case DOKU_LEXER_ENTER : 98 $color = trim(substr($match, 4, -1)); // get the color 99 $color = $this->_color2hexdec($color); 100 if($color) { 101 return array($state, $color); 102 } 103 break; 104 case DOKU_LEXER_UNMATCHED : 105 $handler->_addCall('cdata', array($match), $pos); 106 return false; 107 case DOKU_LEXER_EXIT : 108 break; 109 } 110 return array($state, "#ffff00"); 111 } 112 113 /** 114 * Create output 115 * 116 * @param $mode string output format being rendered 117 * @param $renderer Doku_Renderer the current renderer object 118 * @param $data array data created by handler() 119 * @return boolean rendered correctly? 120 */ 121 public function render($mode, Doku_Renderer $renderer, $data) { 122 if($mode == 'xhtml') { 123 /** @var $renderer Doku_Renderer_xhtml */ 124 list($state, $color) = $data; 125 switch($state) { 126 case DOKU_LEXER_ENTER : 127 $renderer->doc .= "<span style=\"color: $color\">"; 128 break; 129 case DOKU_LEXER_EXIT : 130 $renderer->doc .= "</span>"; 131 break; 132 } 133 return true; 134 } 135 if($mode == 'odt') { 136 /** @var $renderer renderer_plugin_odt_page */ 137 list($state, $color) = $data; 138 switch($state) { 139 case DOKU_LEXER_ENTER : 140 $style_index = $color; 141 142 //store style 143 if(empty($this->odt_styles[$style_index])) { 144 $stylename = "ColorizedText" . count($this->odt_styles); 145 $this->odt_styles[$style_index] = $stylename; 146 147 //Attention: ODT only accepts hexidecimal colors of format #ffffff, not #fff. 148 $color = $color ? 'fo:color="' . $color . '" ' : ''; 149 $renderer->autostyles[$stylename] = ' 150 <style:style style:name="' . $stylename . '" style:family="text"> 151 <style:text-properties ' . $color . '/> 152 </style:style>'; 153 } 154 155 $renderer->doc .= '<text:span text:style-name="' . $this->odt_styles[$style_index] . '">'; 156 break; 157 case DOKU_LEXER_EXIT : 158 $renderer->doc .= "</text:span>"; 159 break; 160 } 161 return true; 162 } 163 return false; 164 } 165 166 /** 167 * Returns #hexdec color code, or false 168 * 169 * @param string $color 170 * @return bool|string 171 */ 172 protected function _color2hexdec($color) { 173 $less = new Lessc(); 174 $less->setImportDir[] = DOKU_INC; 175 176 $css = '.test { color: spin('.$color.', 0); }'; //less try to spin all colors, and output them as hexdec 177 try { 178 $parsedcss = $less->compile($css); 179 } catch(Exception $e) { 180 return false; 181 } 182 $hexdec = substr($parsedcss, 17, -4); 183 return $hexdec; 184 } 185 186 /** 187 * validate color value $c 188 * this is cut price validation - only to ensure the basic format is 189 * correct and there is nothing harmful 190 * three basic formats "colorname", "#fff[fff]", "rgb(255[%],255[%],255[%])" 191 * 192 * @param string $c 193 * @return int 194 */ 195 protected function _isValid($c) { 196 197 $c = trim($c); 198 199 $pattern = "/ 200 (^[a-zA-Z]+$)| #colorname - not verified 201 (^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$)| #colorvalue 202 (^rgb\(([0-9]{1,3}%?,){2}[0-9]{1,3}%?\)$) #rgb triplet 203 /x"; 204 205 return (preg_match($pattern, $c)); 206 } 207} 208 209//Setup VIM: ex: et ts=4 sw=4 enc=utf-8 : 210