1<?php 2/** 3 * Plugin itemtable: Renders tables in DokuWiki format by using itemlists instead of the Wiki syntax (very helpful for big tables with a lot of text) 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Olaf Trieschmann <trieschmann@otri.de> 7 * 8 * Thanks to Stephen C's plugin "dbtables", which was used as a starting point! 9 */ 10 11// must be run within DokuWiki 12if(!defined('DOKU_INC')) die(); 13 14if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 15require_once DOKU_PLUGIN.'syntax.php'; 16require_once DOKU_INC.'inc/parser/parser.php'; 17require_once DOKU_INC . 'inc/parser/xhtml.php'; 18 19/** 20 * All DokuWiki plugins to extend the parser/rendering mechanism 21 * need to inherit from this class 22 */ 23class syntax_plugin_itemtable extends DokuWiki_Syntax_Plugin { 24 25 // $options is used for rendering options 26 public $options=array(); 27 28 function getInfo() { 29 return array('author' => 'Olaf Trieschmann', 30 'email' => 'develop@otri.de', 31 'date' => '2010-11-06', 32 'name' => 'Item Table', 33 'desc' => 'Renders tables in DokuWiki format by using itemlists instead of the Wiki syntax', 34 'url' => 'https://github.com/otriesch/itemtable/raw/master/itemtable.zip'); 35 } 36 function getType() { return 'substition'; } 37 function getSort() { return 32; } 38 39 function connectTo($mode) { 40 $this->Lexer->addEntryPattern('<itemtable *[^>]*>',$mode,'plugin_itemtable'); 41 } 42 43 function postConnect() { 44 $this->Lexer->addExitPattern('</itemtable>','plugin_itemtable'); 45 } 46 47 /** 48 * Handle the match 49 */ 50 function handle($match, $state, $pos, &$handler){ 51 switch ($state) { 52 case DOKU_LEXER_ENTER : 53 return array($state, substr($match, 10, -1) ); 54 break; 55 case DOKU_LEXER_MATCHED : 56 return array($state,$match); 57 break; 58 case DOKU_LEXER_UNMATCHED : 59 return array($state, $match); 60 break; 61 case DOKU_LEXER_EXIT : 62 return array($state, ''); 63 break; 64 } 65 return array(); 66 } 67 68 function render_tables($match,$mode,$data) { 69 // $match is the full text we're to consider 70 $raw=explode("\n",$match); 71 72// $TableData.=$this->options["test"]; 73// foreach($this->options as $option) { 74// $TableData.=$option." "; 75// } 76// $TableData.="\n\n\n"; 77 78 // Yes, so draw the heading 79 if (trim($this->options["header"])!=""){ 80 // Draw the Dokuwiki table heading 81 $TableData.="^".$this->options["header"].substr("^^^^^^^^^^",0,$this->options["cols"]+1)."\n"; 82 } else { 83 $TableData.=""; 84 } 85 86 // Draw the descriptors of each field 87 $TableData.="^ "; 88 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) 89 $TableData.="^".$this->options["__col"][$ColPos]." "; 90 $TableData.="^\n"; 91 92 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { 93 $RowElements["__col"][$ColPos]=" "; 94 } 95 $RowCount=0; 96 $CellActive=0; 97 98 // Run through each line and decide how to render the text 99 foreach($raw as $rawline) { 100 //In case we have to read a multiline input for one cell 101 if ($CellActive) { 102 if (strstr($rawline,$this->options["cell_off"])) { 103 $RowElements["__col"][$CellActive-1].=" ".substr($rawline,0,strpos($rawline,$this->options["cell_off"])); 104 $CellActive=0; 105 } else { 106 $RowElements["__col"][$CellActive-1].=" ".$rawline; 107 } 108 } else { 109 $CurrentLine=trim($rawline); 110 if ($CurrentLine!=""){ 111 // Is this row the name of a row? 112 if (substr($rawline,0,1)==$this->options["thead"]) { 113 if ($RowCount!=0) { 114 // Go through each entity and output it 115 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { 116 $TableData.="|".$RowElements["__col"][$ColPos]." "; 117 } 118 // SHIP IT! 119 $TableData.="|\n"; 120 } 121 // Remember the current row name 122 $TableData.="|".substr($rawline,1)." "; 123 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { 124 $RowElements["__col"][$ColPos]=" "; 125 } 126 $RowCount++; 127 } else { 128 // Split the fields up. 129 $RowInfo=explode($this->options["fdelim"],$rawline); 130 if (count($RowInfo)>=2) { 131 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { 132 if ($RowInfo[0]==$this->options["__col"][$ColPos]) { 133 $r=substr($rawline,strlen($RowInfo[0])+1); 134 if (strstr($r,$this->options["cell_on"])) { 135 $r=substr(strstr($r,$this->options["cell_on"]),strlen($this->options["cell_on"])); 136 if (strstr($r,$this->options["cell_off"])) { 137 $r=substr($r,0,strpos($r,$this->options["cell_off"])); 138 } else { 139 $CellActive=$ColPos+1; 140 } 141 } 142 $RowElements["__col"][$ColPos]=$r; 143 } 144 } 145 } 146 } 147 } 148 } 149 } 150 // Go through each entity and output it 151 for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { 152 $TableData.="|".$RowElements["__col"][$ColPos]." "; 153 } 154 // SHIP IT! 155 $TableData.="|\n"; 156 // Start the HTML table rendering 157 $res="</p><table"; 158 if ($this->options["twidth"]!="") 159 $res.=" width='".$this->options["twidth"]."'>"; 160 else 161 $res.=">"; 162 163 // Prepare the table information 164 // The option to not render from Dokuwiki to HTML is available 165 if ($this->options["norender"]=="") 166 $td="<td class='dbtables-td_0'>".p_render($mode,p_get_instructions($TableData),$data)."</td>"; 167 else 168 $td="<td><pre>".$TableData."</pre></td>"; 169 170 // Draw the table row 171 $res.="\n<tr class='dbtables-tr_0' valign='top'>\n"; 172 // Write out the table data 173 $res.=$td."\n"; 174 $CurTablePos=$CurTablePos+1; 175 // Close off the HTML-Table 176 $res.="</tr></table><p>"; 177 return $res; 178 } 179 180 function render($mode, &$renderer, $data) { 181 // This will only render in xhtml 182 if($mode == 'xhtml'){ 183 list($state, $match) = $data; 184 switch ($state) { 185 // This happens when we first find the <itemtable> 186 case DOKU_LEXER_ENTER : 187 $parmsexp=explode(';',$match); 188 // Set the relevant default values 189 $this->options["fdelim"]="="; // The character used to delimit what goes between fields 190 $this->options["header"]=""; // 191 $this->options["__col"]=array(); 192 $this->options["cell_on"]="<tablecell>"; 193 $this->options["cell_off"]="</tablecell>"; 194 $this->options["thead"]="_"; // The character used to indicate the table name 195 // $this->options["twidth"] // Default HTML table width in HTML specifications (IE: 95% - 960px) 196 // $this->options["norender"] -> Assign a value to NOT render from Dokuwiki to HTML 197 198 // Prepare each option 199// $this->options["test"]=""; 200 $this->options["cols"]=0; 201 foreach($parmsexp as $pexp) { 202 $p=explode("=",$pexp); 203 $p[0]=trim($p[0]); 204 if (substr($p[0],0,1)=="c") { 205 $pp=explode(",",$p[1]); 206// $this->options["test"].=" p[0]=".$p[0]." p[1]=".$p[1]." pp[0]=".$pp[0]." pp[1]=".$pp[1]."\\ \n"; 207 $this->options["__col"]=array_merge ($this->options["__col"],$pp); 208 foreach($pp as $ppexp) { 209 $this->options["cols"]++; 210 } 211 } else { 212 $this->options[$p[0]]=$p[1]; 213 } 214 } 215 break; 216 // This happens each line between <dbtables> and </dbtables> 217 case DOKU_LEXER_UNMATCHED : 218 // Send to the rendering function 219 $renderer->doc.=$this->render_tables($match,$mode,$data); 220 //$renderer->doc .= $renderer->_xmlEntities($match); 221 break; 222 } 223 return true; 224 } 225 return false; 226 } 227}