*
* 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;
}
}