1be906b56SAndreas Gohr<?php 2be906b56SAndreas Gohr 3be906b56SAndreas Gohrnamespace dokuwiki\Parsing\Handler; 4be906b56SAndreas Gohr 5*533aca44SAndreas Gohrclass Lists extends AbstractRewriter 6be906b56SAndreas Gohr{ 7be906b56SAndreas Gohr protected $listCalls = array(); 8be906b56SAndreas Gohr protected $listStack = array(); 9be906b56SAndreas Gohr 10be906b56SAndreas Gohr protected $initialDepth = 0; 11be906b56SAndreas Gohr 12be906b56SAndreas Gohr const NODE = 1; 13be906b56SAndreas Gohr 14be906b56SAndreas Gohr /** @inheritdoc */ 15be906b56SAndreas Gohr public function finalise() 16be906b56SAndreas Gohr { 17be906b56SAndreas Gohr $last_call = end($this->calls); 18be906b56SAndreas Gohr $this->writeCall(array('list_close',array(), $last_call[2])); 19be906b56SAndreas Gohr 20be906b56SAndreas Gohr $this->process(); 21be906b56SAndreas Gohr $this->callWriter->finalise(); 22be906b56SAndreas Gohr unset($this->callWriter); 23be906b56SAndreas Gohr } 24be906b56SAndreas Gohr 25be906b56SAndreas Gohr /** @inheritdoc */ 26be906b56SAndreas Gohr public function process() 27be906b56SAndreas Gohr { 28be906b56SAndreas Gohr 29be906b56SAndreas Gohr foreach ($this->calls as $call) { 30be906b56SAndreas Gohr switch ($call[0]) { 31be906b56SAndreas Gohr case 'list_item': 32be906b56SAndreas Gohr $this->listOpen($call); 33be906b56SAndreas Gohr break; 34be906b56SAndreas Gohr case 'list_open': 35be906b56SAndreas Gohr $this->listStart($call); 36be906b56SAndreas Gohr break; 37be906b56SAndreas Gohr case 'list_close': 38be906b56SAndreas Gohr $this->listEnd($call); 39be906b56SAndreas Gohr break; 40be906b56SAndreas Gohr default: 41be906b56SAndreas Gohr $this->listContent($call); 42be906b56SAndreas Gohr break; 43be906b56SAndreas Gohr } 44be906b56SAndreas Gohr } 45be906b56SAndreas Gohr 46be906b56SAndreas Gohr $this->callWriter->writeCalls($this->listCalls); 47be906b56SAndreas Gohr return $this->callWriter; 48be906b56SAndreas Gohr } 49be906b56SAndreas Gohr 50be906b56SAndreas Gohr protected function listStart($call) 51be906b56SAndreas Gohr { 52be906b56SAndreas Gohr $depth = $this->interpretSyntax($call[1][0], $listType); 53be906b56SAndreas Gohr 54be906b56SAndreas Gohr $this->initialDepth = $depth; 55be906b56SAndreas Gohr // array(list type, current depth, index of current listitem_open) 56be906b56SAndreas Gohr $this->listStack[] = array($listType, $depth, 1); 57be906b56SAndreas Gohr 58be906b56SAndreas Gohr $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]); 59be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open',array(1),$call[2]); 60be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 61be906b56SAndreas Gohr } 62be906b56SAndreas Gohr 63be906b56SAndreas Gohr 64be906b56SAndreas Gohr protected function listEnd($call) 65be906b56SAndreas Gohr { 66be906b56SAndreas Gohr $closeContent = true; 67be906b56SAndreas Gohr 68be906b56SAndreas Gohr while ($list = array_pop($this->listStack)) { 69be906b56SAndreas Gohr if ($closeContent) { 70be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_close',array(),$call[2]); 71be906b56SAndreas Gohr $closeContent = false; 72be906b56SAndreas Gohr } 73be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 74be906b56SAndreas Gohr $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]); 75be906b56SAndreas Gohr } 76be906b56SAndreas Gohr } 77be906b56SAndreas Gohr 78be906b56SAndreas Gohr protected function listOpen($call) 79be906b56SAndreas Gohr { 80be906b56SAndreas Gohr $depth = $this->interpretSyntax($call[1][0], $listType); 81be906b56SAndreas Gohr $end = end($this->listStack); 82be906b56SAndreas Gohr $key = key($this->listStack); 83be906b56SAndreas Gohr 84be906b56SAndreas Gohr // Not allowed to be shallower than initialDepth 85be906b56SAndreas Gohr if ($depth < $this->initialDepth) { 86be906b56SAndreas Gohr $depth = $this->initialDepth; 87be906b56SAndreas Gohr } 88be906b56SAndreas Gohr 89be906b56SAndreas Gohr if ($depth == $end[1]) { 90be906b56SAndreas Gohr // Just another item in the list... 91be906b56SAndreas Gohr if ($listType == $end[0]) { 92be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_close',array(),$call[2]); 93be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 94be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]); 95be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 96be906b56SAndreas Gohr 97be906b56SAndreas Gohr // new list item, update list stack's index into current listitem_open 98be906b56SAndreas Gohr $this->listStack[$key][2] = count($this->listCalls) - 2; 99be906b56SAndreas Gohr 100be906b56SAndreas Gohr // Switched list type... 101be906b56SAndreas Gohr } else { 102be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_close',array(),$call[2]); 103be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 104be906b56SAndreas Gohr $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]); 105be906b56SAndreas Gohr $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); 106be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); 107be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 108be906b56SAndreas Gohr 109be906b56SAndreas Gohr array_pop($this->listStack); 110be906b56SAndreas Gohr $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); 111be906b56SAndreas Gohr } 112be906b56SAndreas Gohr } elseif ($depth > $end[1]) { // Getting deeper... 113be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_close',array(),$call[2]); 114be906b56SAndreas Gohr $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); 115be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); 116be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 117be906b56SAndreas Gohr 118be906b56SAndreas Gohr // set the node/leaf state of this item's parent listitem_open to NODE 119be906b56SAndreas Gohr $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE; 120be906b56SAndreas Gohr 121be906b56SAndreas Gohr $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); 122be906b56SAndreas Gohr } else { // Getting shallower ( $depth < $end[1] ) 123be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_close',array(),$call[2]); 124be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 125be906b56SAndreas Gohr $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]); 126be906b56SAndreas Gohr 127be906b56SAndreas Gohr // Throw away the end - done 128be906b56SAndreas Gohr array_pop($this->listStack); 129be906b56SAndreas Gohr 130be906b56SAndreas Gohr while (1) { 131be906b56SAndreas Gohr $end = end($this->listStack); 132be906b56SAndreas Gohr $key = key($this->listStack); 133be906b56SAndreas Gohr 134be906b56SAndreas Gohr if ($end[1] <= $depth) { 135be906b56SAndreas Gohr // Normalize depths 136be906b56SAndreas Gohr $depth = $end[1]; 137be906b56SAndreas Gohr 138be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 139be906b56SAndreas Gohr 140be906b56SAndreas Gohr if ($end[0] == $listType) { 141be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]); 142be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 143be906b56SAndreas Gohr 144be906b56SAndreas Gohr // new list item, update list stack's index into current listitem_open 145be906b56SAndreas Gohr $this->listStack[$key][2] = count($this->listCalls) - 2; 146be906b56SAndreas Gohr } else { 147be906b56SAndreas Gohr // Switching list type... 148be906b56SAndreas Gohr $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]); 149be906b56SAndreas Gohr $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]); 150be906b56SAndreas Gohr $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]); 151be906b56SAndreas Gohr $this->listCalls[] = array('listcontent_open',array(),$call[2]); 152be906b56SAndreas Gohr 153be906b56SAndreas Gohr array_pop($this->listStack); 154be906b56SAndreas Gohr $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2); 155be906b56SAndreas Gohr } 156be906b56SAndreas Gohr 157be906b56SAndreas Gohr break; 158be906b56SAndreas Gohr 159be906b56SAndreas Gohr // Haven't dropped down far enough yet.... ( $end[1] > $depth ) 160be906b56SAndreas Gohr } else { 161be906b56SAndreas Gohr $this->listCalls[] = array('listitem_close',array(),$call[2]); 162be906b56SAndreas Gohr $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]); 163be906b56SAndreas Gohr 164be906b56SAndreas Gohr array_pop($this->listStack); 165be906b56SAndreas Gohr } 166be906b56SAndreas Gohr } 167be906b56SAndreas Gohr } 168be906b56SAndreas Gohr } 169be906b56SAndreas Gohr 170be906b56SAndreas Gohr protected function listContent($call) 171be906b56SAndreas Gohr { 172be906b56SAndreas Gohr $this->listCalls[] = $call; 173be906b56SAndreas Gohr } 174be906b56SAndreas Gohr 175be906b56SAndreas Gohr protected function interpretSyntax($match, & $type) 176be906b56SAndreas Gohr { 177be906b56SAndreas Gohr if (substr($match, -1) == '*') { 178be906b56SAndreas Gohr $type = 'u'; 179be906b56SAndreas Gohr } else { 180be906b56SAndreas Gohr $type = 'o'; 181be906b56SAndreas Gohr } 182be906b56SAndreas Gohr // Is the +1 needed? It used to be count(explode(...)) 183be906b56SAndreas Gohr // but I don't think the number is seen outside this handler 184be906b56SAndreas Gohr return substr_count(str_replace("\t", ' ', $match), ' ') + 1; 185be906b56SAndreas Gohr } 186be906b56SAndreas Gohr} 187