======Tables with rowspans and vertical alignment====== ===== Introduction ===== Having examined the two current (Oct08) offerings to facilitate rowspans in a DW table (see [[tips:tableswithrowspans|Method 1]] and [[tips:tableswithrowspans2|Method 2]]), I felt that what was needed was a //simpler// way of including the necessary markup without losing the clean and elegant DW table syntax. While a syntax plugin would have been my preferred way to achieve this, I was unable, with my limited knowledge of PHP, to determine how to insert the appropriate code inside a TH or TD HTML tag. This offering therefore is based on the approach used by //jmucchiello// in [[tips:tableswithrowspans2|Method 2]] but with a more direct way of specifying the rowspan syntax. By applying the code patches listed below, it is possible to create a table with rowspans, each with their own vertical alignment. The patches do not alter the existing table syntax. To create a rowspan, the table cell starting the rowspan must include the character ":" followed by the number of rows to be spanned, followed optionally by the character "-" to indicate middle (or central) vertical alignment or the character "_" to indicate bottom vertical alignment. The absence of this optional vertical alignment character would indicate vertical alignment at the top. Using this syntax means that the number of columns in succeeding rows will be reduced, depending on how many previous rowspans affect any particular row. =====Features at a glance===== * 100% compatible with existing DokuWiki tables. * Supports bidirectional spans - column spans can be incorporated with rowspans. * Supports vertical alignment (top, middle and bottom) in each rowspan using CSS. * Supports both header and non-header spans. =====Usage===== {{ http://www.amherst.kent.sch.uk/wiki_school/data/media/wiki/table_rowspan_example.png?nolink&nocache|example table}} To generate this example table in Dokuwiki, the following syntax would be used: ^ ^col 1 ^ col 2 ^ col 3&4^^ ^row a |:2 a1-b1 | :3_ a2-c3|| a4 | ^row b&c :2- | b4| ^c1 ^ c4| ^row d |d1 | d2 | d3| d4 | This 4x4 table (plus headers) has individual cells at a4, b4, c1, c4, d1, d2, d3, and d4.\\ The top row and leftmost columns are header cells. c1 and c4 are also header cells.\\ There are 2 2-cell blocks, the one at rowb&c is aligned vertically in the middle and the one at a1-b1 is top aligned.\\ There is a 6-cell block spanning a2, a3, b2, b3, c2 and c3 which is bottom aligned vertically. Note that the order in which a cell's content and any row spanning statement are coded is not important, either may appear first. The HTML generated by the above DW table definitions would be:
col 1 col 2 col 3&4
row a a1-b1 a2-c3 a4
row b&c b4
c1 c4
row d d1 d2 d3 d4
=====Known Issues===== * The column number in the ''class='' generated statement will not be correct when any column in the row is an intermediate vertically spanned column, see the cell containing the value b4 in the example above. BTW, this column number was not computed correctly for any cells following a horizontal span (Bug#1506 in DW version 05-05-2008). The patch below corrects this oversight. * Care is needed when all columns in a row have no visible content. Some browsers will suppress the display of such a row and although there is a CSS rule {empty-cells:show} it is not supported by all browsers (eg IE). If all the columns in a row are intermediate vertically spanned columns, then there are no cells to define in the row, but an opening / closing TR tag is still required. * An update to the ''wiki:syntax'' page for table formatting using rowspan is outstanding. =====Patch Code===== The patch was introduced into the Dokuwiki release dated 2008-05-05. It has been tested and works under the current Dokuwiki release dated 2009-02-14 (//Jan/2009-03-22//). The patch involves changes to 5 code files in the ''inc/parser'' directory. They are ''parser.php'', ''handler.php'', ''metadata.php'', ''renderer.php'', and ''xhtml.php''. In addition, the CSS rules are shown for inclusion in the ''userstyle.css'' file in the ''conf'' directory. ==== parser.php ==== in the //class// **Doku_Parser_Mode_table**, find the //function// **postConnect()** which begins at LINE 453, and then incorporate the following one line addition at the position marked: $this->Lexer->addPattern('[\t ]+','table'); /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ $this->Lexer->addPattern(':(?:[2-9][0-9]?|[1][0-9])[-_]?','table'); /*** ------------------------------------------------------------ ROWSPAN: addition end */ $this->Lexer->addPattern('\^','table'); ==== handler.php ==== There are 4 separate changes to be made to this file. === Change 1 === In the //class// **Doku_Handler**, find the //function// **table($match, $state, $pos)** which begins at LINE 580 and then the //case// **DOKU_LEXER_MATCHED** which begins at LINE 610. Finally, incorporate the following two line addition at the position marked: } else if ( $match == '^' ) { $this->_addCall('tableheader', array(), $pos); /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ } else if ( substr($match,0,1) == ':') { $this->_addCall('tablevspan', array($match), $pos); /*** ------------------------------------------------------------ ROWSPAN: addition end */ } === Change 2 === In the //class// **Doku_Handler_Table** find the //function// **process()** which begins at LINE 1190 and then incorporate the following three line addition at the position marked: case 'tableheader': case 'tablecell': $this->tableCell($call); break; /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ case 'tablevspan': $this->tableVspan($call); break; /*** ------------------------------------------------------------ ROWSPAN: addition end */ case 'table_end': === Change 3 === Still in the //class// **Doku_Handler_Table** find the //function// **tableDefault($call)** which begins at LINE 1295 and then incorporate the following three line addition at the position marked: function tableDefault($call) { $this->tableCalls[] = $call; } /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ function tableVspan($call) { $this->tableCalls[] = array('rowspan',$call[1],$call[2]); } /*** ------------------------------------------------------------ ROWSPAN: addition end */ === Change 4 === And finally, still in the //class// **Doku_Handler_Table**, find the //function// **finalizeTable()** which begins at LINE 1306 and then incorporate the following fifteen line addition at the position marked: $toDelete[] = $key-1; $toDelete[] = $key; $toDelete[] = $key+1; /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ } else if ( $call[0] == 'rowspan' ) { $match = $call[1][0]; $tmpa = substr($match,1,strlen($match)-1); $valign = substr($tmpa,-1,1); if ($valign == "-") { $valign = 'mid'; $tmpa = substr($tmpa,0,strlen($tmpa)-1); } else if ($valign == "_") { $valign = 'bot'; $tmpa = substr($tmpa,0,strlen($tmpa)-1); } else $valign = 'top'; $this->tableCalls[$lastCell][1][2] = $tmpa; $this->tableCalls[$lastCell][1][3] = $valign; $toDelete[] = $key; /*** ------------------------------------------------------------ ROWSPAN: addition end */ ==== metadata.php ==== There are 2 changes to be made to this file. In the //class// **Doku_Renderer_metadata** find the //function// **tableheader_open** which begins at LINE 364 and then incorporate the following one line replacement: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: change start */ function tableheader_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){} //function tableheader_open($colspan = 1, $align = NULL){} /*** ------------------------------------------------------------ ROWSPAN: change end */ and a little further on, find the //function// **tablecell_open** and incorporate the following one line replacement: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: change start */ function tablecell_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){} //function tablecell_open($colspan = 1, $align = NULL){} /*** ------------------------------------------------------------ ROWSPAN: change end */ ==== renderer.php ==== There are 2 changes to be made to this file in a similar way to metadata.php. In the //class// **Doku_Renderer** find the //function// **tableheader_open** which begins at LINE 241 and then incorporate the following one line replacement: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: change start */ function tableheader_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){} //function tableheader_open($colspan = 1, $align = NULL){} /*** ------------------------------------------------------------ ROWSPAN: change end */ and a little further on, find the //function// **tablecell_open** and incorporate the following one line replacement: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: change start */ function tablecell_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){} //function tablecell_open($colspan = 1, $align = NULL){} /*** ------------------------------------------------------------ ROWSPAN: change end */ ==== xhtml.php ==== There are 2 changes to be made to this file. In the //class// **Doku_Renderer_xhtml** find the //function// **tableheader_open** which begins at LINE 824 and then incorporate the following replacement for this function: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: replacement start */ function tableheader_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){ $class = 'class="col' . $this->_counter['cell_counter']++; if ( !is_null($align) ) { $class .= ' '.$align.'align'; } if ( !is_null($valign) ) { $class .= ' valign'.$valign; } $class .= '"'; $this->doc .= ' 1 ) { $this->doc .= ' rowspan="'.$rowspan.'"'; } if ( $colspan > 1 ) { $this->_counter['cell_counter'] += $colspan-1; /*--- BUG FS#1506 */ $this->doc .= ' colspan="'.$colspan.'"'; } $this->doc .= '>'; } /*** ------------------------------------------------------------ ROWSPAN: replacement end */ and a little further on, find the //function// **tablecell_open** and incorporate the following replacement for this function: /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: replacement start */ function tablecell_open($colspan = 1, $align = NULL, $rowspan = 1, $valign = NULL){ $class = 'class="col' . $this->_counter['cell_counter']++; if ( !is_null($align) ) { $class .= ' '.$align.'align'; } if ( !is_null($valign) ) { $class .= ' valign'.$valign; } $class .= '"'; $this->doc .= ' 1 ) { $this->doc .= ' rowspan="'.$rowspan.'"'; } if ( $colspan > 1 ) { $this->_counter['cell_counter'] += $colspan-1; /*--- BUG FS#1506 */ $this->doc .= ' colspan="'.$colspan.'"'; } $this->doc .= '>'; } /*** ------------------------------------------------------------ ROWSPAN: replacement end */ ==== userstyle.css ==== And finally, the CSS is added to the **conf/userstyle.css**, which if it does not exist, may be created as a simple text file. /* for table cell vertical alignment */ .valigntop {vertical-align:top} .valignmid {vertical-align:middle} .valignbot {vertical-align:bottom} ===== Comments / Discussion ===== Feel free to express your opinion. --- //[[mail@weatherhead.org.uk|Jan Weatherhead]] 2008-10-14 // ---- Hi, it works very good, many thanks! PS look [[http://bertucci.org/doku.php/start#port_number_settings_in_websphere_application_server|here]] to see. Frank ---- Hi Jan, Very nice and useful patch! However, I am not sure that this way of integrating rowspan is really 100% compatible. What worries me is that the expression ://n// can occur anywhere in the cell and still means "rowspan". \\ I would prefer if rowspan functionality will be invoked only when the expression directly follows the "|" or "^" without anything in betweeen, including space. As dokuwiki is being used in technical documentations, I can easily image table uses when there is a ":" followed by a number somewhere in a table cell. My understanding of the whole parser is still not very good. \\ But the following modification to **Change 4** of **inc/parser/handler.php** seems to work for me: $toDelete[] = $key-1; $toDelete[] = $key; $toDelete[] = $key+1; /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ } else if ( $call[0] == 'rowspan' ) { // Apply only immediately after a cell open if ( $this->tableCalls[$key-1][0] == 'tablecell_open' || $this->tableCalls[$key-1][0] == 'tableheader_open' ) { $match = $call[1][0]; $tmpa = substr($match,1,strlen($match)-1); $valign = substr($tmpa,-1,1); if ($valign == "-") { $valign = 'mid'; $tmpa = substr($tmpa,0,strlen($tmpa)-1); } else if ($valign == "_") { $valign = 'bot'; $tmpa = substr($tmpa,0,strlen($tmpa)-1); } else $valign = 'top'; $this->tableCalls[$lastCell][1][2] = $tmpa; $this->tableCalls[$lastCell][1][3] = $valign; $toDelete[] = $key; } else { // Convert the false-positive back to cdata $this->tableCalls[$key][0] = 'cdata'; } /*** ------------------------------------------------------------ ROWSPAN: addition end */ Is it a good idea or a bad one? //[[astrid.hanssen@gmx.de|Astrid Hanssen]] 2008-10-25 // > Many thanks for your feedback, Astrid. I realise on reflection just how exaggerated the claim of 100% compatibility is. And I believe that fixing the position of the rowspan markup to follow immediately after the cell start markup as you suggest, is on balance a small step in the right direction towards that 100% target. > >However, implementing your changes has an immediate side-effect on the horizontal alignment of data in the rowspanned cells - they are always left aligned. To overcome this drawback and re-establish the DW rules on horizontal alignment in cells, the following additional patch is required. > >**Patch 3a** \\ >Still in the //class// **Doku_Handler_Table** find the //function// **finalizeTable()** which begins at LINE 1306 and then incorporate the following two line addition at the position marked: } 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][1] = 'right'; /*** ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ROWSPAN: addition start */ } else if ( $this->tableCalls[$key-1][0] == 'rowspan' ) { $this->tableCalls[$key-2][1][1] = 'right'; /*** ------------------------------------------------------------ ROWSPAN: addition end */ > Now the only loss of compatibility with existing DW table markup would be when ://n// data is used in a left-aligned cell. The solution here would be an enforced change to the existing DW table cell data to wrap %% around this data in order to ignore the markup. Hence I feel the best that can be said about compatibility and this modification is that it approaches 100%. \\ //Jan/2008-10-28// ---- I failed at first (probably made a copy paste error), but then tried again after restoring and it worked. I incorporated the Astrid patch as well, since I like stricter syntax and can sense data with colons and numbers coming on some day. Though I won't be using it much, I sure missed rowspans at several points in my life of using DokuWiki.\\ Thank you very much. --- //Doc/2009-09-03//