1<?php 2 3/** 4 * Plugin RefNotes: Note renderer 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Mykola Ostrovskyy <dwpforge@gmail.com> 8 */ 9 10require_once(DOKU_PLUGIN . 'refnotes/core.php'); 11 12class syntax_plugin_refnotes_notes extends DokuWiki_Syntax_Plugin { 13 14 private $mode; 15 16 /** 17 * Constructor 18 */ 19 public function __construct() { 20 $this->mode = substr(get_class($this), 7); 21 } 22 23 /** 24 * What kind of syntax are we? 25 */ 26 public function getType() { 27 return 'substition'; 28 } 29 30 public function getPType() { 31 return 'block'; 32 } 33 34 /** 35 * Where to sort in? 36 */ 37 public function getSort() { 38 return 150; 39 } 40 41 public function connectTo($mode) { 42 $this->Lexer->addSpecialPattern('~~REFNOTES.*?~~', $mode, $this->mode); 43 $this->Lexer->addSpecialPattern('<refnotes[^>]*?\/>', $mode, $this->mode); 44 $this->Lexer->addSpecialPattern('<refnotes(?:[^>]*?[^/>])?>.*?<\/refnotes>', $mode, $this->mode); 45 } 46 47 /** 48 * Handle the match 49 */ 50 public function handle($match, $state, $pos, Doku_Handler $handler) { 51 switch ($match[0]) { 52 case '~': 53 return $this->handleBasic($match); 54 55 case '<': 56 return $this->handleExtended($match); 57 } 58 59 return false; 60 } 61 62 /** 63 * Create output 64 */ 65 public function render($mode, Doku_Renderer $renderer, $data) { 66 try { 67 if($mode == 'xhtml') { 68 switch ($data[0]) { 69 case 'style': 70 refnotes_renderer_core::getInstance()->styleNamespace($data[1]['ns'], $data[2]); 71 break; 72 73 case 'map': 74 refnotes_renderer_core::getInstance()->setNamespaceMapping($data[1]['ns'], $data[2]); 75 break; 76 77 case 'render': 78 $this->renderNotes($mode, $renderer, $data[1]); 79 break; 80 81 case 'block': 82 refnotes_renderer_core::getInstance()->updateRenderingBlocks($data[1]); 83 break; 84 } 85 86 return true; 87 } 88 elseif ($mode == 'odt') { 89 switch ($data[0]) { 90 case 'render': 91 $this->renderNotes($mode, $renderer, $data[1]); 92 break; 93 } 94 95 return true; 96 } 97 } 98 catch (Exception $error) { 99 msg($error->getMessage(), -1); 100 } 101 102 return false; 103 } 104 105 /** 106 * 107 */ 108 private function handleBasic($syntax) { 109 preg_match('/~~REFNOTES(.*?)~~/', $syntax, $match); 110 111 return array('render', $this->parseAttributes($match[1])); 112 } 113 114 /** 115 * 116 */ 117 private function handleExtended($syntax) { 118 preg_match('/<refnotes(.*?)(?:\/>|>(.*?)<\/refnotes>)/s', $syntax, $match); 119 $attribute = $this->parseAttributes($match[1]); 120 $style = array(); 121 122 if ($match[2] != '') { 123 $style = $this->parseStyles($match[2]); 124 } 125 126 if (count($style) > 0) { 127 return array('split', $attribute, $style); 128 } 129 else { 130 return array('render', $attribute); 131 } 132 } 133 134 /** 135 * 136 */ 137 private function parseAttributes($syntax) { 138 $propertyMatch = array( 139 'ns' => '/^' . refnotes_namespace::getNamePattern('required') . '$/', 140 'limit' => '/^\/?\d+$/' 141 ); 142 143 $attribute = array(); 144 $token = preg_split('/\s+/', $syntax, -1, PREG_SPLIT_NO_EMPTY); 145 foreach ($token as $t) { 146 foreach ($propertyMatch as $name => $pattern) { 147 if (preg_match($pattern, $t) == 1) { 148 $attribute[$name][] = $t; 149 break; 150 } 151 } 152 } 153 154 if (array_key_exists('ns', $attribute)) { 155 /* Ensure that namespaces are in canonic form */ 156 $attribute['ns'] = array_map('refnotes_namespace::canonizeName', $attribute['ns']); 157 158 if (count($attribute['ns']) > 1) { 159 $attribute['map'] = array_slice($attribute['ns'], 1); 160 } 161 162 $attribute['ns'] = $attribute['ns'][0]; 163 } 164 else { 165 $attribute['ns'] = ':'; 166 } 167 168 if (array_key_exists('limit', $attribute)) { 169 $attribute['limit'] = end($attribute['limit']); 170 } 171 172 return $attribute; 173 } 174 175 /** 176 * 177 */ 178 private function parseStyles($syntax) { 179 $style = array(); 180 preg_match_all('/([-\w]+)\s*:[ \t]*([^\s\n;].*?)[ \t]*?(?:[\n;]|$)/', $syntax, $match, PREG_SET_ORDER); 181 foreach ($match as $m) { 182 $style[$m[1]] = $m[2]; 183 } 184 185 /* Validate direct-to-html styles */ 186 if (array_key_exists('notes-separator', $style)) { 187 if (preg_match('/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/', $style['notes-separator'], $match) == 1) { 188 $style['notes-separator'] = $match[0]; 189 } 190 else { 191 $style['notes-separator'] = ''; 192 } 193 } 194 195 /* Ensure that namespaces are in canonic form */ 196 if (array_key_exists('inherit', $style)) { 197 $style['inherit'] = refnotes_namespace::canonizeName($style['inherit']); 198 } 199 200 return $style; 201 } 202 203 /** 204 * 205 */ 206 private function renderNotes($mode, $renderer, $attribute) { 207 $limit = array_key_exists('limit', $attribute) ? $attribute['limit'] : ''; 208 $doc = refnotes_renderer_core::getInstance()->renderNotes($mode, $attribute['ns'], $limit); 209 210 if ($doc != '') { 211 if ($mode == 'xhtml') { 212 $open = '<div class="refnotes">' . DOKU_LF; 213 $close = '</div>' . DOKU_LF; 214 } 215 else { 216 $open = ''; 217 $close = ''; 218 } 219 220 $renderer->doc .= $open; 221 $renderer->doc .= $doc; 222 $renderer->doc .= $close; 223 } 224 } 225} 226