Translations of this page?:

Extended Table Syntax 2 Plugin

exttab2 plugin by disorder Chang
Another Mediawiki style tables inside DokuWiki

Last updated on 2007-11-06. Provides Syntax.
Compatible with DokuWiki 2007-06-26b.

Similar to exttab1, truetable.

Tagged with mediawiki, tables.

The following security issue was reported for this plugin:

XSS vulnerability allows arbitrary JavaScript insertion. Author informed on 2008-02-07.

It is not recommended to use this plugin until this issue was fixed. Plugin authors should read the plugin security guidelines.

About

I like the exttab1 plugin, which can handle Wikimedia way of table syntax. But exttab1 does not parse some dokuwiki syntax correctly, eg. footnote, image link, etc. So I decided to write a new one.

This plugin is still in its early stages, please feel free to modify the code.

Installation

  • create the folder lib/plugins/exttab2
  • and copy the source code to lib/plugins/exttab2/syntax.php

Usage

Unlike exttab1 plugin, you don't need to put any markup to enclose the syntax, just draw table as mediawiki do.

markup summary

* means that the markup must be on a new line

* {| start table
* {| para start table with parameters
* |+ caption table caption; only one per table and between table start and first row1)
* |+ para | caption table caption with parameters
* |- table row
* |- para table row with parameters
* ! header table header cell
* ! para | header table header cell with parameters
!! header consecutive table headers
!! para | header consecutive table headers with parameters
* | cell table data cell; Cell content may follow on same line or on following lines
* | para | cell table data cell with parameters
|| cell consecutive table data cell
|| para | cell consecutive table data cell with parameters
* |} end table; please add an additional empty line to end the whole table2)

please see http://meta.wikimedia.org/wiki/Help:Table for more detail.

Examples

Simple table

{| 
|+ caption
! header 1
! header 2
|- 
| cell A
| 
cell B
|}
{| 
|+ caption
! header 1 !! header 2
|- 
| cell A || cell B 
|}

Table with parameter and wiki markups (formatting, linking, etc.)

{| border="1" style="width:300px"
|+ style="color:red"| //caption//
|- style="background:green;height:50px"
! style="color:white" |header 1
! header 2 !! style="color:yellow" | header 3
|- 
| style="text-align:right" | **bold**, //italic//, ((footnote))
| [[link|a link]] || style="color:yellow" | {{pdf.pdf}} 
|-
| text with  \\ new line OK\\ [[http://www.google.com|google]] good\\
| colspan="2" | but ====Headline==== not working!
|}

Table with complex wiki markups (listblock, hr, preformatted, code, etc.)

{| border="1"
|- 
| 
  * add an additional 
    * blank line 
  * after the last list

| as
many lines
as you like 
but don't add any empty line
|-
| 
  add an additional blank line
  after the preformatted text

| hr fine
----
|-
|
> quoting must 
>> add a blank line too

|
<file>
file or code
goes 
here
</file>
|}

Nested tables

{| border="1"
| you
| can use
{| border="2" style="background:#CCC;"
| nested
|-
| table
|}
now
| .
|}

Limits

I use the source of http://meta.wikimedia.org/wiki/Help:Table to test this plugin. It works fine, except:

Column headings with double bar

The following syntax will render heading 2 as normal cell

! Column heading 1 || Column heading 2 

Revision History

  • 2006-11-06 0.2.0 support nested table and many more…
  • 2006-10-04 0.1.0 Initial release

Sources

 
<?php
//ini_set("display_errors", "On"); // for debuging
/**
 * exttab2-Plugin: Parses extended tables (like MediaWiki) 
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     disorde chang <disorder.chang@gmail.com>
 * @date       2007-10-04
 */
 
// 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');
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_exttab2 extends DokuWiki_Syntax_Plugin {
 
  var $stack = array();
 
  function syntax_plugin_exttab2(){
    define("EXTTAB2_TABLE", 0);
    define("EXTTAB2_CAPTION", 1);
    define("EXTTAB2_TR", 2);
    define("EXTTAB2_TD", 3);
    define("EXTTAB2_TH", 4);
    $this->tagsmap = array(
                  EXTTAB2_TABLE=>   array("table", "", "\n" ),
                  EXTTAB2_CAPTION=> array("caption", "\t", "\n" ),
                  EXTTAB2_TR=>      array("tr", "\t", "\n" ),
                  EXTTAB2_TD=>      array("td", "\t"."\t", "\n" ),
                  EXTTAB2_TH=>      array("th", "\t"."\t", "\n" ),
 
/* // DOKU constant not work when preview
                  EXTTAB2_TABLE=>   array("table", "", DOKU_LF ),
                  EXTTAB2_CAPTION=> array("caption", DOKU_TAB, DOKU_LF ),
                  EXTTAB2_TR=>      array("tr", DOKU_TAB, DOKU_LF ),
                  EXTTAB2_TD=>      array("td", DOKU_TAB.DOKU_TAB, DOKU_LF ),
                  EXTTAB2_TH=>      array("th", DOKU_TAB.DOKU_TAB, DOKU_LF ),
*/                  );
  }
 
  function getInfo(){
    return array(
          'author' => 'Disorder Chang',
          'email'  => 'disorder.chang@gmail.com',
          'date'   => '2007-11-06',
          'name'   => 'exttab2 Plugin',
          'desc'   => 'parses MediaWiki-like tables',
          'url'    => 'http://www.dokuwiki.org/plugin:exttab2',
    );
  }
 
  function getType(){
    return 'container';
  }
 
  function getPType(){
    return 'block';
  }
 
  function getAllowedTypes() { 
    return array('container', 'formatting', 'substition', 'disabled', 'protected'); 
  }
 
  function getSort(){ 
    return 50; 
  }
 
  function connectTo($mode) { 
     $this->Lexer->addEntryPattern('\n\{\|[^\n]*',$mode,'plugin_exttab2'); 
  }
 
  function postConnect() { 
    $para = "[^\|\n\[\{\!]+"; // parametes
 
    // caption: |+ params | caption
    $this->Lexer->addPattern("\n\|\+(?:$para\|(?!\|))?",'plugin_exttab2');
 
    // row: |- params
    $this->Lexer->addPattern('\n\|\-[^\n]*','plugin_exttab2');
 
    // table open
    $this->Lexer->addPattern('\n\{\|[^\n]*','plugin_exttab2');
 
    // table close
    $this->Lexer->addPattern('\n\|\}','plugin_exttab2');
 
    // header
    $this->Lexer->addPattern("(?:\n|\!)\!(?:$para\|(?!\|))?",'plugin_exttab2');
 
    //cell
    $this->Lexer->addPattern("(?:\n|\|)\|(?:$para\|(?!\|))?",'plugin_exttab2');
 
    //end
//    $this->Lexer->addExitPattern('\n','plugin_exttab2'); 
//    $this->Lexer->addExitPattern("(?<!\|)\n",'plugin_exttab2'); // not work
    $this->Lexer->addExitPattern("\n(?=\n)",'plugin_exttab2'); 
  }
 
  /**
   * Handle the match
   */
  function handle($match, $state, $pos, &$handler){
    if($state == DOKU_LEXER_EXIT) {
      return array($state, "end");
    }
    else if($state == DOKU_LEXER_UNMATCHED){
      return array($state, "", $match);
    }
    else{
      $para = "[^\|\n]+"; // parametes
      if(preg_match ( '/\{\|([^\n]*)/', $match, $m)){ // table open
        $func = "table_open";
        $params = $m[1];
        return array($state, $func, $params);
      }
      else if($match == "\n|}"){ // table close
        $func = "table_close";
        $params = "";
        return array($state, $func, $params);
      }
      else if(preg_match ("/^\n\|\+(?:(?:($para)\|)?)$/", $match, $m)){ // caption
        $func = "caption";
        $params = $m[1];
        return array($state, $func, $params);
      }
      else if(preg_match ( '/\|-([^\n]*)/', $match, $m)){ // row
        $func = "row";
        $params = $m[1];
        return array($state, $func, $params);
      }
      else if(preg_match("/^(?:\n|\!)\!(?:(?:([^\|\n\!]+)\|)?)$/", $match, $m)){ // header
        $func = "header";
        $params = $m[1];
        return array($state, $func, $params);
      }
      else if(preg_match("/^(?:\n|\|)\|(?:(?:($para)\|)?)$/", $match, $m)){ // cell
        $func = "cell";
        $params = $m[1];
        return array($state, $func, $params);
      }
      else{
        die("what? ".$match);  // for debugging
      }
    }
  }
 
  /**
   * Create output
   */
 
  function render($mode, &$renderer, $data) {
 
    if($mode == 'xhtml'){
      list($state, $func, $params) = $data;
 
      switch ($state) {
        case DOKU_LEXER_UNMATCHED :  
          $r = $renderer->_xmlEntities($params); 
          $renderer->doc .= $r; 
          break;
        case DOKU_LEXER_ENTER :
        case DOKU_LEXER_MATCHED:
          $r = $this->$func($params);
          $renderer->doc .= $r;
          break;
        case DOKU_LEXER_EXIT :       
          $r = $this->$func($params);
          $renderer->doc .= $r; 
          break;
      }
      return true;
 
    }
    return false;
  }
 
 
  function _attrString($attr="", $before=" "){
    if(is_null($attr) || trim($attr)=="") $attr = "";
    else $attr = $before.trim($attr);
    return $attr;
  }
 
  var $tagsmap = array();
 
  function _starttag($tag, $params=NULL, $before="", $after=""){
    $tagstr = $this->tagsmap[$tag][0];
    $before = $this->tagsmap[$tag][1].$before;
    $after = $this->tagsmap[$tag][2].$after;
    $r = $before."<".$tagstr.$this->_attrString($params).">". $after;
    return $r;
  }
 
  function _endtag($tag, $before="", $after=""){
    $tagstr = $this->tagsmap[$tag][0];
    $before = $this->tagsmap[$tag][1].$before;
    $after = $this->tagsmap[$tag][2].$after;
 
    $r = $before."</".$tagstr.">". $after;
    return $r;
  }
 
  function table_open($params=NULL){
    $r .= $this->_closetags(EXTTAB2_TABLE);
    $r .= $this->_starttag(EXTTAB2_TABLE, $params);
    $this->stack[] = EXTTAB2_TABLE;
    return $r;
  }
 
  function table_close($params=NULL){
    $t = end($this->stack);
    switch($t){
      case EXTTAB2_TABLE:
        array_push($this->stack, EXTTAB2_TR, EXTTAB2_TD);
        $r .= $this->_starttag(EXTTAB2_TR, $params);
        $r .= $this->_starttag(EXTTAB2_TD, $params);
        break;
      case EXTTAB2_CAPTION:
        $r .= $this->_endtag(EXTTAB2_CAPTION);
        array_pop($this->stack);
        array_push($this->stack, EXTTAB2_TR, EXTTAB2_TD);
        $r .= $this->_starttag(EXTTAB2_TR, $params);
        $r .= $this->_starttag(EXTTAB2_TD, $params);
        break;
      case EXTTAB2_TR:
        array_push($this->stack, EXTTAB2_TD);
        $r = $this->_starttag(EXTTAB2_TD, $params);
        break;
      case EXTTAB2_TD:
      case EXTTAB2_TH:
        break;
    }
 
    while(($t = end($this->stack)) != EXTTAB2_TABLE){
      $r .= $this->_endtag($t);
      array_pop($this->stack);
    }
    array_pop($this->stack);
    $r .= $this->_endtag(EXTTAB2_TABLE);
    return $r;   
 
  }
 
  function end($params=NULL){
    while(!empty($this->stack)){
      $r .= $this->table_close();
    }
    return $r;
  }
 
  function caption($params=NULL){
    if(($r = $this->_closetags(EXTTAB2_CAPTION)) === FALSE){
      return ""; 
    }
    $r .= $this->_starttag(EXTTAB2_CAPTION, $params);
    $this->stack[] = EXTTAB2_CAPTION;
    return $r;
  }
 
  function row($params=NULL){
    $r .= $this->_closetags(EXTTAB2_TR);
    $r .= $this->_starttag(EXTTAB2_TR, $params);
     $this->stack[] = EXTTAB2_TR;
    return $r;
  }
 
  function header($params=NULL){
    $r .= $this->_closetags(EXTTAB2_TH);
    $r .= $this->_starttag(EXTTAB2_TH, $params);
    $this->stack[] = EXTTAB2_TH;
    return $r;
  }
 
  function cell($params=NULL){
    $r .= $this->_closetags(EXTTAB2_TD);
    $r .= $this->_starttag(EXTTAB2_TD, $params);
    $this->stack[] = EXTTAB2_TD;
    return $r;
  }
 
  function _closetags($tag){
    $r = "";
    switch($tag){
      case EXTTAB2_TD:
      case EXTTAB2_TH:
        $t = end($this->stack);
 
        switch($t){
          case EXTTAB2_TABLE:
            array_push($this->stack, EXTTAB2_TR);
            $r .= $this->_starttag(EXTTAB2_TR, $params);
            break;
          case EXTTAB2_CAPTION:
            $r .= $this->_endtag(EXTTAB2_CAPTION);
            array_pop($this->stack);
            array_push($this->stack, EXTTAB2_TR);
            $r .= $this->_starttag(EXTTAB2_TR, $params);
            break;
          case EXTTAB2_TR:
            break;
          case EXTTAB2_TD:
          case EXTTAB2_TH:
            $r .= $this->_endtag($t);
            array_pop($this->stack);
            break;
        }
        break;
      case EXTTAB2_TR:
        $t = end($this->stack);
 
        switch($t){
          case EXTTAB2_TABLE:
            break;
          case EXTTAB2_CAPTION:
            $r .= $this->_endtag(EXTTAB2_CAPTION);
            array_pop($this->stack);
            break;
          case EXTTAB2_TR:
            $r .= $this->_starttag(EXTTAB2_TD);
            $r .= $this->_endtag(EXTTAB2_TD);
            $r .= $this->_endtag(EXTTAB2_TR);
            array_pop($this->stack);
            break;
          case EXTTAB2_TD:
          case EXTTAB2_TH:
            $r .= $this->_endtag($t);
            $r .= $this->_endtag(EXTTAB2_TR);
            array_pop($this->stack);
            array_pop($this->stack);
            break;
        }
        break;        
      case EXTTAB2_TABLE:
        $t = end($this->stack);
        if($t === FALSE) break;
        switch($t){
          case EXTTAB2_TABLE:
            array_push($this->stack, EXTTAB2_TR, EXTTAB2_TD);
            $r .= $this->_starttag(EXTTAB2_TR, $params);
            $r .= $this->_starttag(EXTTAB2_TD, $params);
            break;
          case EXTTAB2_CAPTION:
            $r .= $this->_endtag(EXTTAB2_CAPTION);
            array_pop($this->stack);
            array_push($this->stack, EXTTAB2_TR, EXTTAB2_TD);
            $r .= $this->_starttag(EXTTAB2_TR, $params);
            $r .= $this->_starttag(EXTTAB2_TD, $params);
            break;
          case EXTTAB2_TR:
            array_push($this->stack, EXTTAB2_TD);
            $r = $this->_starttag(EXTTAB2_TD, $params);
            break;
          case EXTTAB2_TD:
          case EXTTAB2_TH:
            break;
        }
        break;
      case EXTTAB2_CAPTION:
        $t = end($this->stack);
        if($t==EXTTAB2_TABLE){
        }
        else{
          return false ; // ignore this, or should echo error?
        }
        break;
    }
    return $r;
  } 
}
 
?>

Discussion

Yup this is an awesome plug in I love it. One question. I tried using the sorting feature but was unable to. Any hopes of getting this to work? –lenehey [Nov. 27, 2007]

Another question. Any hopes of doing Ettab3 where Ettab3 is Ettab2 + sorting table and a finished plugin á non-programmer can use ?. Philip Hettel [feb. 17, 2008]

Found a bug which prevents you from coloring a cell anything brighter than #999999. For some reason if you include a letter such as ”#AA88BB” in the hex-color, it won't parse.

1) caption appears in other place will be echo out directly
2) no need for nested table
 
plugin/exttab2.txt · Last modified: 2008/03/21 21:55 by lenehey
 
Imprint Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
WikiForumIRCBugsTranslate