[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 namespace dokuwiki\Parsing\Handler; 4 5 /** 6 * Handler for paragraphs 7 * 8 * @author Harry Fuecks <hfuecks@gmail.com> 9 */ 10 class Block 11 { 12 protected $calls = array(); 13 protected $skipEol = false; 14 protected $inParagraph = false; 15 16 // Blocks these should not be inside paragraphs 17 protected $blockOpen = array( 18 'header', 19 'listu_open','listo_open','listitem_open','listcontent_open', 20 'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open', 21 'quote_open', 22 'code','file','hr','preformatted','rss', 23 'htmlblock','phpblock', 24 'footnote_open', 25 ); 26 27 protected $blockClose = array( 28 'header', 29 'listu_close','listo_close','listitem_close','listcontent_close', 30 'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close', 31 'quote_close', 32 'code','file','hr','preformatted','rss', 33 'htmlblock','phpblock', 34 'footnote_close', 35 ); 36 37 // Stacks can contain paragraphs 38 protected $stackOpen = array( 39 'section_open', 40 ); 41 42 protected $stackClose = array( 43 'section_close', 44 ); 45 46 47 /** 48 * Constructor. Adds loaded syntax plugins to the block and stack 49 * arrays 50 * 51 * @author Andreas Gohr <andi@splitbrain.org> 52 */ 53 public function __construct() 54 { 55 global $DOKU_PLUGINS; 56 //check if syntax plugins were loaded 57 if (empty($DOKU_PLUGINS['syntax'])) return; 58 foreach ($DOKU_PLUGINS['syntax'] as $n => $p) { 59 $ptype = $p->getPType(); 60 if ($ptype == 'block') { 61 $this->blockOpen[] = 'plugin_'.$n; 62 $this->blockClose[] = 'plugin_'.$n; 63 } elseif ($ptype == 'stack') { 64 $this->stackOpen[] = 'plugin_'.$n; 65 $this->stackClose[] = 'plugin_'.$n; 66 } 67 } 68 } 69 70 protected function openParagraph($pos) 71 { 72 if ($this->inParagraph) return; 73 $this->calls[] = array('p_open',array(), $pos); 74 $this->inParagraph = true; 75 $this->skipEol = true; 76 } 77 78 /** 79 * Close a paragraph if needed 80 * 81 * This function makes sure there are no empty paragraphs on the stack 82 * 83 * @author Andreas Gohr <andi@splitbrain.org> 84 * 85 * @param string|integer $pos 86 */ 87 protected function closeParagraph($pos) 88 { 89 if (!$this->inParagraph) return; 90 // look back if there was any content - we don't want empty paragraphs 91 $content = ''; 92 $ccount = count($this->calls); 93 for ($i=$ccount-1; $i>=0; $i--) { 94 if ($this->calls[$i][0] == 'p_open') { 95 break; 96 } elseif ($this->calls[$i][0] == 'cdata') { 97 $content .= $this->calls[$i][1][0]; 98 } else { 99 $content = 'found markup'; 100 break; 101 } 102 } 103 104 if (trim($content)=='') { 105 //remove the whole paragraph 106 //array_splice($this->calls,$i); // <- this is much slower than the loop below 107 for ($x=$ccount; $x>$i; 108 $x--) array_pop($this->calls); 109 } else { 110 // remove ending linebreaks in the paragraph 111 $i=count($this->calls)-1; 112 if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0], "\n"); 113 $this->calls[] = array('p_close',array(), $pos); 114 } 115 116 $this->inParagraph = false; 117 $this->skipEol = true; 118 } 119 120 protected function addCall($call) 121 { 122 $key = count($this->calls); 123 if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) { 124 $this->calls[$key-1][1][0] .= $call[1][0]; 125 } else { 126 $this->calls[] = $call; 127 } 128 } 129 130 // simple version of addCall, without checking cdata 131 protected function storeCall($call) 132 { 133 $this->calls[] = $call; 134 } 135 136 /** 137 * Processes the whole instruction stack to open and close paragraphs 138 * 139 * @author Harry Fuecks <hfuecks@gmail.com> 140 * @author Andreas Gohr <andi@splitbrain.org> 141 * 142 * @param array $calls 143 * 144 * @return array 145 */ 146 public function process($calls) 147 { 148 // open first paragraph 149 $this->openParagraph(0); 150 foreach ($calls as $key => $call) { 151 $cname = $call[0]; 152 if ($cname == 'plugin') { 153 $cname='plugin_'.$call[1][0]; 154 $plugin = true; 155 $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL)); 156 $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL)); 157 } else { 158 $plugin = false; 159 } 160 /* stack */ 161 if (in_array($cname, $this->stackClose) && (!$plugin || $plugin_close)) { 162 $this->closeParagraph($call[2]); 163 $this->storeCall($call); 164 $this->openParagraph($call[2]); 165 continue; 166 } 167 if (in_array($cname, $this->stackOpen) && (!$plugin || $plugin_open)) { 168 $this->closeParagraph($call[2]); 169 $this->storeCall($call); 170 $this->openParagraph($call[2]); 171 continue; 172 } 173 /* block */ 174 // If it's a substition it opens and closes at the same call. 175 // To make sure next paragraph is correctly started, let close go first. 176 if (in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) { 177 $this->closeParagraph($call[2]); 178 $this->storeCall($call); 179 $this->openParagraph($call[2]); 180 continue; 181 } 182 if (in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) { 183 $this->closeParagraph($call[2]); 184 $this->storeCall($call); 185 continue; 186 } 187 /* eol */ 188 if ($cname == 'eol') { 189 // Check this isn't an eol instruction to skip... 190 if (!$this->skipEol) { 191 // Next is EOL => double eol => mark as paragraph 192 if (isset($calls[$key+1]) && $calls[$key+1][0] == 'eol') { 193 $this->closeParagraph($call[2]); 194 $this->openParagraph($call[2]); 195 } else { 196 //if this is just a single eol make a space from it 197 $this->addCall(array('cdata',array("\n"), $call[2])); 198 } 199 } 200 continue; 201 } 202 /* normal */ 203 $this->addCall($call); 204 $this->skipEol = false; 205 } 206 // close last paragraph 207 $call = end($this->calls); 208 $this->closeParagraph($call[2]); 209 return $this->calls; 210 } 211 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body