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