* * Thanks to Stephen C's plugin "dbtables", which was used as a starting point! */ // must be run within DokuWiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once DOKU_PLUGIN.'syntax.php'; require_once DOKU_INC.'inc/parser/parser.php'; require_once DOKU_INC . 'inc/parser/xhtml.php'; /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_itemtable extends DokuWiki_Syntax_Plugin { // $options is used for rendering options public $options=array(); function getInfo() { return array('author' => 'Olaf Trieschmann', 'email' => 'develop@otri.de', 'date' => '2010-11-06', 'name' => 'Item Table', 'desc' => 'Renders tables in DokuWiki format by using itemlists instead of the Wiki syntax', 'url' => 'https://github.com/otriesch/itemtable/raw/master/itemtable.zip'); } function getType() { return 'substition'; } function getSort() { return 32; } function connectTo($mode) { $this->Lexer->addEntryPattern(']*>',$mode,'plugin_itemtable'); } function postConnect() { $this->Lexer->addExitPattern('','plugin_itemtable'); } /** * Handle the match */ function handle($match, $state, $pos, &$handler){ switch ($state) { case DOKU_LEXER_ENTER : return array($state, substr($match, 10, -1) ); break; case DOKU_LEXER_MATCHED : return array($state,$match); break; case DOKU_LEXER_UNMATCHED : return array($state, $match); break; case DOKU_LEXER_EXIT : return array($state, ''); break; } return array(); } function render_tables($match,$mode,$data) { // $match is the full text we're to consider $raw=explode("\n",$match); // $TableData.=$this->options["test"]; // foreach($this->options as $option) { // $TableData.=$option." "; // } // $TableData.="\n\n\n"; // Yes, so draw the heading if (trim($this->options["header"])!=""){ // Draw the Dokuwiki table heading $TableData.="^".$this->options["header"].substr("^^^^^^^^^^",0,$this->options["cols"]+1)."\n"; } else { $TableData.=""; } // Draw the descriptors of each field $TableData.="^ "; for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) $TableData.="^".$this->options["__col"][$ColPos]." "; $TableData.="^\n"; for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { $RowElements["__col"][$ColPos]=" "; } $RowCount=0; $CellActive=0; // Run through each line and decide how to render the text foreach($raw as $rawline) { //In case we have to read a multiline input for one cell if ($CellActive) { if (strstr($rawline,$this->options["cell_off"])) { $RowElements["__col"][$CellActive-1].=" ".substr($rawline,0,strpos($rawline,$this->options["cell_off"])); $CellActive=0; } else { $RowElements["__col"][$CellActive-1].=" ".$rawline; } } else { $CurrentLine=trim($rawline); if ($CurrentLine!=""){ // Is this row the name of a row? if (substr($rawline,0,1)==$this->options["thead"]) { if ($RowCount!=0) { // Go through each entity and output it for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { $TableData.="|".$RowElements["__col"][$ColPos]." "; } // SHIP IT! $TableData.="|\n"; } // Remember the current row name $TableData.="|".substr($rawline,1)." "; for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { $RowElements["__col"][$ColPos]=" "; } $RowCount++; } else { // Split the fields up. $RowInfo=explode($this->options["fdelim"],$rawline); if (count($RowInfo)>=2) { for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { if ($RowInfo[0]==$this->options["__col"][$ColPos]) { $r=substr($rawline,strlen($RowInfo[0])+1); if (strstr($r,$this->options["cell_on"])) { $r=substr(strstr($r,$this->options["cell_on"]),strlen($this->options["cell_on"])); if (strstr($r,$this->options["cell_off"])) { $r=substr($r,0,strpos($r,$this->options["cell_off"])); } else { $CellActive=$ColPos+1; } } $RowElements["__col"][$ColPos]=$r; } } } } } } } // Go through each entity and output it for($ColPos=0;$ColPos<$this->options["cols"];$ColPos++) { $TableData.="|".$RowElements["__col"][$ColPos]." "; } // SHIP IT! $TableData.="|\n"; // Start the HTML table rendering $res="

options["twidth"]!="") $res.=" width='".$this->options["twidth"]."'>"; else $res.=">"; // Prepare the table information // The option to not render from Dokuwiki to HTML is available if ($this->options["norender"]=="") $td="".p_render($mode,p_get_instructions($TableData),$data).""; else $td="
".$TableData."
"; // Draw the table row $res.="\n\n"; // Write out the table data $res.=$td."\n"; $CurTablePos=$CurTablePos+1; // Close off the HTML-Table $res.="

"; return $res; } function render($mode, &$renderer, $data) { // This will only render in xhtml if($mode == 'xhtml'){ list($state, $match) = $data; switch ($state) { // This happens when we first find the case DOKU_LEXER_ENTER : $parmsexp=explode(';',$match); // Set the relevant default values $this->options["fdelim"]="="; // The character used to delimit what goes between fields $this->options["header"]=""; // $this->options["__col"]=array(); $this->options["cell_on"]=""; $this->options["cell_off"]=""; $this->options["thead"]="_"; // The character used to indicate the table name // $this->options["twidth"] // Default HTML table width in HTML specifications (IE: 95% - 960px) // $this->options["norender"] -> Assign a value to NOT render from Dokuwiki to HTML // Prepare each option // $this->options["test"]=""; $this->options["cols"]=0; foreach($parmsexp as $pexp) { $p=explode("=",$pexp); $p[0]=trim($p[0]); if (substr($p[0],0,1)=="c") { $pp=explode(",",$p[1]); // $this->options["test"].=" p[0]=".$p[0]." p[1]=".$p[1]." pp[0]=".$pp[0]." pp[1]=".$pp[1]."\\ \n"; $this->options["__col"]=array_merge ($this->options["__col"],$pp); foreach($pp as $ppexp) { $this->options["cols"]++; } } else { $this->options[$p[0]]=$p[1]; } } break; // This happens each line between and case DOKU_LEXER_UNMATCHED : // Send to the rendering function $renderer->doc.=$this->render_tables($match,$mode,$data); //$renderer->doc .= $renderer->_xmlEntities($match); break; } return true; } return false; } }