123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- <?php
- namespace dokuwiki\Parsing\Handler;
- class Lists extends AbstractRewriter
- {
- protected $listCalls = array();
- protected $listStack = array();
- protected $initialDepth = 0;
- const NODE = 1;
- /** @inheritdoc */
- public function finalise()
- {
- $last_call = end($this->calls);
- $this->writeCall(array('list_close',array(), $last_call[2]));
- $this->process();
- $this->callWriter->finalise();
- unset($this->callWriter);
- }
- /** @inheritdoc */
- public function process()
- {
- foreach ($this->calls as $call) {
- switch ($call[0]) {
- case 'list_item':
- $this->listOpen($call);
- break;
- case 'list_open':
- $this->listStart($call);
- break;
- case 'list_close':
- $this->listEnd($call);
- break;
- default:
- $this->listContent($call);
- break;
- }
- }
- $this->callWriter->writeCalls($this->listCalls);
- return $this->callWriter;
- }
- protected function listStart($call)
- {
- $depth = $this->interpretSyntax($call[1][0], $listType);
- $this->initialDepth = $depth;
- // array(list type, current depth, index of current listitem_open)
- $this->listStack[] = array($listType, $depth, 1);
- $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
- $this->listCalls[] = array('listitem_open',array(1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- }
- protected function listEnd($call)
- {
- $closeContent = true;
- while ($list = array_pop($this->listStack)) {
- if ($closeContent) {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $closeContent = false;
- }
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
- }
- }
- protected function listOpen($call)
- {
- $depth = $this->interpretSyntax($call[1][0], $listType);
- $end = end($this->listStack);
- $key = key($this->listStack);
- // Not allowed to be shallower than initialDepth
- if ($depth < $this->initialDepth) {
- $depth = $this->initialDepth;
- }
- if ($depth == $end[1]) {
- // Just another item in the list...
- if ($listType == $end[0]) {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- // new list item, update list stack's index into current listitem_open
- $this->listStack[$key][2] = count($this->listCalls) - 2;
- // Switched list type...
- } else {
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- array_pop($this->listStack);
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
- }
- } elseif ($depth > $end[1]) { // Getting deeper...
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- // set the node/leaf state of this item's parent listitem_open to NODE
- $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
- } else { // Getting shallower ( $depth < $end[1] )
- $this->listCalls[] = array('listcontent_close',array(),$call[2]);
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
- // Throw away the end - done
- array_pop($this->listStack);
- while (1) {
- $end = end($this->listStack);
- $key = key($this->listStack);
- if ($end[1] <= $depth) {
- // Normalize depths
- $depth = $end[1];
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- if ($end[0] == $listType) {
- $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- // new list item, update list stack's index into current listitem_open
- $this->listStack[$key][2] = count($this->listCalls) - 2;
- } else {
- // Switching list type...
- $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
- $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
- $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
- $this->listCalls[] = array('listcontent_open',array(),$call[2]);
- array_pop($this->listStack);
- $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
- }
- break;
- // Haven't dropped down far enough yet.... ( $end[1] > $depth )
- } else {
- $this->listCalls[] = array('listitem_close',array(),$call[2]);
- $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
- array_pop($this->listStack);
- }
- }
- }
- }
- protected function listContent($call)
- {
- $this->listCalls[] = $call;
- }
- protected function interpretSyntax($match, & $type)
- {
- if (substr($match, -1) == '*') {
- $type = 'u';
- } else {
- $type = 'o';
- }
- // Is the +1 needed? It used to be count(explode(...))
- // but I don't think the number is seen outside this handler
- return substr_count(str_replace("\t", ' ', $match), ' ') + 1;
- }
- }
|