DokuWiki

It's better when it's simple

User Tools

Site Tools


tips:rowspansfix

Yet another way to make rowspan possible

I tried to emprove syntax for tables in such a way. Besides the common syntax you may use cells with colspan and rowspan parameters implictly set. You can see it in work at the page http://nvcamc.ipsys.net/doku.php?id=playground:playground FIXME To make this possible you must open table cell. Then without any spaces you must put colspan and rowspan parameters, separated by comma and a closing tag (like the opening cell). For example:

|2,2| A 2x2 cell A11,A12,A21,A22|  A13  |
|                                  A23  |
|      A31      |      A32      |  A33  |

The same syntax I made for header cells. The closing tag must repeat the opening tag. The example, where spanned cell is a header style cell is shown below

^2,2^ A 2x2 cell A11,A12,A21,A22|  A13  |
|                                  A23  |
|      A31      |      A32      |  A33  |

The same way you can force cells to have any rowspan and colspan values. For this I had to emprove parser, handler and renderer I show only differencies between current version (2006.11.06). The same thing I made on version 2006.03.09

So here are parser changes in inc/parser/parser.inc:

class Doku_Parser_Mode_table extends Doku_Parser_Mode {
  function Doku_Parser_Mode_table() {
      global $PARSER_MODES;
      $this->allowedModes = array_merge (
              $PARSER_MODES['formatting'],
              $PARSER_MODES['substition'],
              $PARSER_MODES['disabled'],
              $PARSER_MODES['protected']
          );
  }
  function connectTo($mode) {
 +    $this->Lexer->addEntryPattern('\n\^[0-9]{1,},[0-9]{1,}\^',$mode,'table');
 +    $this->Lexer->addEntryPattern('\n\|[0-9]{1,},[0-9]{1,}\|',$mode,'table');
      $this->Lexer->addEntryPattern('\n\^',$mode,'table');
      $this->Lexer->addEntryPattern('\n\|',$mode,'table');
  }
  function postConnect() {
 +    $this->Lexer->addPattern('\n\^[0-9]{1,},[0-9]{1,}\^','table');
 +    $this->Lexer->addPattern('\n\|[0-9]{1,},[0-9]{1,}\|','table');
      $this->Lexer->addPattern('\n\^','table');
      $this->Lexer->addPattern('\n\|','table');
      #$this->Lexer->addPattern(' {2,}','table');
      $this->Lexer->addPattern('[\t ]+','table');
 +    $this->Lexer->addPattern('\^[0-9]{1,},[0-9]{1,}\^','table');
 +    $this->Lexer->addPattern('\|[0-9]{1,},[0-9]{1,}\|','table');
      $this->Lexer->addPattern('\^','table');
      $this->Lexer->addPattern('\|','table');
      $this->Lexer->addExitPattern('\n','table');
  }
  function getSort() {
      return 60;
  }
}

Handler changes in inc/parser/handler.inc:

function table($match, $state, $pos) {
    switch ( $state ) {
        case DOKU_LEXER_ENTER:
            $ReWriter = & new Doku_Handler_Table($this->CallWriter);
            $this->CallWriter = & $ReWriter;
            $this->_addCall('table_start', array(), $pos);
            //$this->_addCall('table_row', array(), $pos);
+	if ( preg_match('/\n\^[0-9]{1,},[0-9]{1,}\^/',$match) ) {
+		list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 2, -1), 2);
+		$this->_addCall('tableheader',array($colspan, $rowspan), $pos);	//DEBUG
+	}else if ( preg_match('/\n\|[0-9]{1,},[0-9]{1,}\|/',$match) ) {
+		list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 2, -1), 2);
+		$this->_addCall('tablecell',array($colspan, $rowspan), $pos);	//DEBUG
*	}else if ( trim($match) == '^' ) {
		$this->_addCall('tableheader', array(), $pos);
	}else{
		$this->_addCall('tablecell', array(), $pos);
            }
        break;
        case DOKU_LEXER_EXIT:
            $this->_addCall('table_end', array(), $pos);
            $this->CallWriter->process();
            $ReWriter = & $this->CallWriter;
            $this->CallWriter = & $ReWriter->CallWriter;
        break;
        case DOKU_LEXER_UNMATCHED:
            if ( trim($match) != '' ) {
                $this->_addCall('cdata',array($match), $pos);
            }
        break;
        case DOKU_LEXER_MATCHED:
            if ( $match == ' ' ){
                $this->_addCall('cdata', array($match), $pos);
            } else if ( preg_match('/\t+/',$match) ) {
                $this->_addCall('table_align', array($match), $pos);
            } else if ( preg_match('/ {2,}/',$match) ) {
                $this->_addCall('table_align', array($match), $pos);
+           } else if ( preg_match('/\n\|[0-9]{1,},[0-9]{1,}\|/',$match) ) {
+               $this->_addCall('table_row', array(), $pos);
+			list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 2, -1), 2);
+			$this->_addCall('tablecell',array($colspan, $rowspan), $pos);	//DEBUG
            } else if ( $match == "\n|" ) {
                $this->_addCall('table_row', array(), $pos);
                $this->_addCall('tablecell', array(), $pos);
+           } else if ( preg_match('/\n\^[0-9]{1,},[0-9]{1,}\^/',$match) ) {
+               $this->_addCall('table_row', array(), $pos);
+			list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 2, -1), 2);
+			$this->_addCall('tableheader',array($colspan, $rowspan), $pos);	//DEBUG
            } else if ( $match == "\n^" ) {
                $this->_addCall('table_row', array(), $pos);
                $this->_addCall('tableheader', array(), $pos);
+           } else if ( preg_match('/\|[0-9]{1,},[0-9]{1,}\|/',$match) ) {
+			list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 1, -1), 2);
+			$this->_addCall('tablecell',array($colspan, $rowspan), $pos);	//DEBUG
            } else if ( $match == '|' ) {
                $this->_addCall('tablecell', array(), $pos);
    +       } else if ( preg_match('/\^[0-9]{1,},[0-9]{1,}\^/',$match) ) {
+			list($colspan,$rowspan) = preg_split("/\,/u", substr($match, 1, -1), 2);
+			$this->_addCall('tableheader',array($colspan, $rowspan), $pos);	//DEBUG
            } else if ( $match == '^' ) {
                $this->_addCall('tableheader', array(), $pos);
            }
        break;
    }
    return TRUE;
}

AND

function tableCell($call) {
    if ( !$this->firstCell ) {
        // Increase the span
        $lastCall = end($this->tableCalls);
        // A cell call which follows an open cell means an empty cell so span
        if ( $lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open' ) {
             $this->tableCalls[] = array('colspan',array(),$call[2]);
        }
        $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]);
 *      $this->tableCalls[] = array($call[0].'_open',array($call[1][0],$call[1][1],NULL),$call[2]);
        $this->lastCellType = $call[0];
    } else {
 *      $this->tableCalls[] = array($call[0].'_open',array($call[1][0],$call[1][1],NULL),$call[2]);
        $this->lastCellType = $call[0];
        $this->firstCell = FALSE;
    }
    $this->currentCols++;
}
function tableDefault($call) {
    $this->tableCalls[] = $call;
}
function finalizeTable() {
    // Add the max cols and rows to the table opening
    if ( $this->tableCalls[0][0] == 'table_open' ) {
        // Adjust to num cols not num col delimeters
        $this->tableCalls[0][1][] = $this->maxCols - 1;
        $this->tableCalls[0][1][] = $this->maxRows;
    } else {
        trigger_error('First element in table call list is not table_open');
    }
    $lastRow = 0;
    $lastCell = 0;
    $toDelete = array();
    // Look for the colspan elements and increment the colspan on the
    // previous non-empty opening cell. Once done, delete all the cells
    // that contain colspans
    foreach ( $this->tableCalls as $key => $call ) {
        if ( $call[0] == 'tablerow_open' ) {
            $lastRow = $key;
        } else if ( $call[0] == 'tablecell_open' || $call[0] == 'tableheader_open' ) {
            $lastCell = $key;
        } else if ( $call[0] == 'table_align' ) {
            // If the previous element was a cell open, align right
            if ( $this->tableCalls[$key-1][0] == 'tablecell_open' || $this->tableCalls[$key-1][0] == 'tableheader_open' ) {
*               $this->tableCalls[$key-1][1][2] = 'right';
            // If the next element if the close of an element, align either center or left
            } else if ( $this->tableCalls[$key+1][0] == 'tablecell_close' || $this->tableCalls[$key+1][0] == 'tableheader_close' ) {
*               if ( $this->tableCalls[$lastCell][1][2] == 'right' ) {
*                   $this->tableCalls[$lastCell][1][2] = 'center';
                } else {
*                   $this->tableCalls[$lastCell][1][2] = 'left';
                }
            }
            // Now convert the whitespace back to cdata
            $this->tableCalls[$key][0] = 'cdata';
        } else if ( $call[0] == 'colspan' ) {
            $this->tableCalls[$key-1][1][0] = FALSE;
            for($i = $key-2; $i > $lastRow; $i--) {
                if ( $this->tableCalls[$i][0] == 'tablecell_open' || $this->tableCalls[$i][0] == 'tableheader_open' ) {
                    if ( FALSE !== $this->tableCalls[$i][1][0] ) {
                        $this->tableCalls[$i][1][0]++;
                        break;
                    }
                }
            }
            $toDelete[] = $key-1;
            $toDelete[] = $key;
            $toDelete[] = $key+1;
        }
    }

renderer changes in inc/parser/renderer.inc and renderer changes in inc/parser/wiki.inc

  function table_open($maxcols = NULL, $numrows = NULL){}
  function table_close(){}
  function tablerow_open(){}
  function tablerow_close(){}
* function tableheader_open($colspan = 1, $rowspan = 1, $align = NULL){}
  function tableheader_close(){}
* function tablecell_open($colspan = 1, $rowspan = 1, $align = NULL){}
  function tablecell_close(){}

and renderer changes in inc/parser/xhtml.inc

function tableheader_open($colspan = 1, $rowspan = 1, $align = NULL){
     $this->doc .= '<th';
     if ( !is_null($align) ) {
         $this->doc .= ' class="'.$align.'align"';
     }
*    if ( $rowspan > 1 ) {
*        $this->doc .= ' rowspan="'.$rowspan.'"';
*    }
     if ( $colspan > 1 ) {
         $this->doc .= ' colspan="'.$colspan.'"';
     }
     $this->doc .= '>';
 }
 function tableheader_close(){
     $this->doc .= '</th>';
 }
*function tablecell_open($colspan = 1, $rowspan = 1, $align = NULL){
     $this->doc .= '<td';
     if ( !is_null($align) ) {
         $this->doc .= ' class="'.$align.'align"';
     }
*    if ( $rowspan > 1 ) {
*        $this->doc .= ' rowspan="'.$rowspan.'"';
*    }
     if ( $colspan > 1 ) {
         $this->doc .= ' colspan="'.$colspan.'"';
     }
     $this->doc .= '>';
}

and renderer changes in inc/parser/metadata.inc

  function table_open($maxcols = NULL, $numrows = NULL){}
  function table_close(){}
  function tablerow_open(){}
  function tablerow_close(){}
* function tableheader_open($colspan = 1, $rowspan = 1, $align = NULL){}
  function tableheader_close(){}
* function tablecell_open($colspan = 1, $rowspan = 1, $align = NULL){}
  function tablecell_close(){}
2,2 A 2×2 cell A11,A12,A21,A22 A13
A23
A31 A32 A33
2,2 A 2×2 cell A11,A12,A21,A22 A13
A23
A31 A32 A33

Sergiy Stetsuk 2007-10-25 00:04

tips/rowspansfix.txt · Last modified: 2015-10-13 15:36 by 195.233.26.84

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki