1<?php 2 3/** 4 * Plugin RefNotes: Handling of instruction array 5 * 6 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 7 * @author Mykola Ostrovskyy <dwpforge@gmail.com> 8 */ 9 10////////////////////////////////////////////////////////////////////////////////////////////////// 11class refnotes_instruction { 12 13 protected $data; 14 15 /** 16 * Constructor 17 */ 18 public function __construct($name, $data, $offset = -1) { 19 $this->data = array($name, $data, $offset); 20 } 21 22 /** 23 * 24 */ 25 public function getData() { 26 return $this->data; 27 } 28} 29 30//////////////////////////////////////////////////////////////////////////////////////////////////// 31class refnotes_nest_instruction extends refnotes_instruction { 32 33 /** 34 * Constructor 35 */ 36 public function __construct($data) { 37 parent::__construct('nest', array($data)); 38 } 39} 40 41//////////////////////////////////////////////////////////////////////////////////////////////////// 42class refnotes_plugin_instruction extends refnotes_instruction { 43 44 /** 45 * Constructor 46 */ 47 public function __construct($name, $data, $type, $text, $offset = -1) { 48 parent::__construct('plugin', array($name, $data, $type, $text), $offset); 49 } 50} 51 52//////////////////////////////////////////////////////////////////////////////////////////////////// 53class refnotes_notes_instruction extends refnotes_plugin_instruction { 54 55 /** 56 * Constructor 57 */ 58 public function __construct($type, $attributes, $data = NULL) { 59 $pluginData[0] = $type; 60 $pluginData[1] = $attributes; 61 62 if (!empty($data)) { 63 $pluginData[2] = $data; 64 } 65 66 parent::__construct('refnotes_notes', $pluginData, DOKU_LEXER_SPECIAL, ''); 67 } 68} 69 70//////////////////////////////////////////////////////////////////////////////////////////////////// 71class refnotes_notes_style_instruction extends refnotes_notes_instruction { 72 73 /** 74 * Constructor 75 */ 76 public function __construct($namespace, $data) { 77 parent::__construct('style', array('ns' => $namespace), $data); 78 } 79} 80 81//////////////////////////////////////////////////////////////////////////////////////////////////// 82class refnotes_notes_map_instruction extends refnotes_notes_instruction { 83 84 /** 85 * Constructor 86 */ 87 public function __construct($namespace, $data) { 88 parent::__construct('map', array('ns' => $namespace), $data); 89 } 90} 91 92//////////////////////////////////////////////////////////////////////////////////////////////////// 93class refnotes_notes_render_instruction extends refnotes_notes_instruction { 94 95 /** 96 * Constructor 97 */ 98 public function __construct($namespace) { 99 parent::__construct('render', array('ns' => $namespace)); 100 } 101} 102 103//////////////////////////////////////////////////////////////////////////////////////////////////// 104class refnotes_notes_render_block_instruction extends refnotes_notes_instruction { 105 106 /** 107 * Constructor 108 */ 109 public function __construct($block) { 110 parent::__construct('block', $block); 111 } 112} 113 114//////////////////////////////////////////////////////////////////////////////////////////////////// 115class refnotes_instruction_reference { 116 117 private $list; 118 private $data; 119 private $index; 120 private $name; 121 122 /** 123 * Constructor 124 */ 125 public function __construct($list, &$data, $index) { 126 $this->list = $list; 127 $this->data =& $data; 128 $this->index = $index; 129 $this->name = ($data[0] == 'plugin') ? 'plugin_' . $data[1][0] : $data[0]; 130 } 131 132 /** 133 * 134 */ 135 public function getIndex() { 136 return $this->index; 137 } 138 139 /** 140 * 141 */ 142 public function getName() { 143 return $this->name; 144 } 145 146 /** 147 * 148 */ 149 public function getData($index) { 150 return $this->data[1][$index]; 151 } 152 153 /** 154 * 155 */ 156 public function getPluginData($index) { 157 return $this->data[1][1][$index]; 158 } 159 160 /** 161 * 162 */ 163 public function setPluginData($index, $data) { 164 $this->data[1][1][$index] = $data; 165 } 166 167 /** 168 * 169 */ 170 public function unsetPluginData($index) { 171 unset($this->data[1][1][$index]); 172 } 173 174 /** 175 * 176 */ 177 public function getRefnotesAttribute($name) { 178 return array_key_exists($name, $this->data[1][1][1]) ? $this->data[1][1][1][$name] : ''; 179 } 180 181 /** 182 * 183 */ 184 public function setRefnotesAttribute($name, $value) { 185 $this->data[1][1][1][$name] = $value; 186 } 187 188 /** 189 * 190 */ 191 public function unsetRefnotesAttribute($name) { 192 unset($this->data[1][1][1][$name]); 193 } 194 195 /** 196 * 197 */ 198 public function getPrevious() { 199 return $this->list->getAt($this->index - 1); 200 } 201 202 /** 203 * 204 */ 205 public function insertBefore($call) { 206 return $this->list->insert($this->index, $call); 207 } 208 209 /** 210 * 211 */ 212 public function insertAfter($call) { 213 return $this->list->insert($this->index + 1, $call); 214 } 215} 216 217//////////////////////////////////////////////////////////////////////////////////////////////////// 218class refnotes_instruction_list implements Iterator { 219 220 private $event; 221 private $index; 222 private $extraCalls; 223 224 /** 225 * Constructor 226 */ 227 public function __construct($event) { 228 $this->event = $event; 229 $this->index = 0; 230 $this->extraCalls = array(); 231 } 232 233 /** 234 * Implementation of Iterator interface 235 */ 236 public function rewind() { 237 $this->index = 0; 238 } 239 240 /** 241 * Implementation of Iterator interface 242 */ 243 public function current() { 244 return new refnotes_instruction_reference($this, $this->event->data->calls[$this->index], $this->index); 245 } 246 247 /** 248 * Implementation of Iterator interface 249 */ 250 public function key() { 251 return $this->index; 252 } 253 254 /** 255 * Implementation of Iterator interface 256 */ 257 public function next() { 258 ++$this->index; 259 } 260 261 /** 262 * Implementation of Iterator interface 263 */ 264 public function valid() { 265 return array_key_exists($this->index, $this->event->data->calls); 266 } 267 268 /** 269 * 270 */ 271 public function getAt($index) { 272 return new refnotes_instruction_reference($this, $this->event->data->calls[$index], $index); 273 } 274 275 /** 276 * 277 */ 278 public function insert($index, $call) { 279 $this->extraCalls[$index][] = $call; 280 } 281 282 /** 283 * 284 */ 285 public function append($call) { 286 $this->extraCalls[count($this->event->data->calls)][] = $call; 287 } 288 289 /** 290 * 291 */ 292 public function applyChanges() { 293 if (empty($this->extraCalls)) { 294 return; 295 } 296 297 ksort($this->extraCalls); 298 299 $calls = array(); 300 $prevIndex = 0; 301 302 foreach ($this->extraCalls as $index => $extraCalls) { 303 if ($prevIndex < $index) { 304 $slice = array_slice($this->event->data->calls, $prevIndex, $index - $prevIndex); 305 $calls = array_merge($calls, $slice); 306 } 307 308 foreach ($extraCalls as $call) { 309 $calls[] = $call->getData(); 310 } 311 312 $prevIndex = $index; 313 } 314 315 $callCount = count($this->event->data->calls); 316 317 if ($prevIndex < $callCount) { 318 $slice = array_slice($this->event->data->calls, $prevIndex, $callCount - $prevIndex); 319 $calls = array_merge($calls, $slice); 320 } 321 322 $offset = $this->event->data->calls[$callCount - 1][2]; 323 324 for ($i = count($calls) - 1; $i >= 0; --$i) { 325 if ($calls[$i][2] == -1) { 326 $calls[$i][2] = $offset; 327 } 328 else { 329 $offset = $calls[$i][2]; 330 } 331 } 332 333 $this->event->data->calls = $calls; 334 $this->extraCalls = array(); 335 } 336} 337