<?php if (!defined('PmWiki')) exit(); /* This file is AdvancedTableDirectives.php; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation http://www.fsf.org either version 2 of the License, or (at your option) any later version. Copyright 2007 GNUZoo (guru@gnuzoo.org) http://www.pmwiki.org/wiki/Profiles/GNUZoo Please donate to the author: http://gnuzoo.org/GNUZooPayPal/ ---- To add actions set variable $RecipeRunAction before including this file: $RecipeRunAction['AdvancedTableDirectives'][] = 'pdf'; $RecipeRunAction['AdvancedTableDirectives'][] = 'whatever'; include_once("$FarmD/cookbook/AdvancedTableDirectives.php"); */ $RecipeName = 'AdvancedTableDirectives'; $RecipeVersion = '3.2'; $RecipeInfo[$RecipeName]['Version'] = $RecipeVersion; #---------------------------------------- # Add actions to array to run this recipe $RecipeRunAction[$RecipeName][]='browse'; $RecipeRunAction[$RecipeName][]='preview'; $RecipeRunAction[$RecipeName][]='print'; #---------------------------------------- $UserAction = ($action === 'edit' && isset($_POST['preview']) && (boolean)$_POST["preview"]) ? 'preview' : $action; if (! in_array($UserAction, $RecipeRunAction[$RecipeName])) return; #------------------------------------------------------------ #recipe runs below this line #------------------------------------------------------------ Markup('AdvancedTableDirectives', '<table', '/^\\(:(table(?:end)?|caption|row#|row(?:end)?|cell(?:[cri])?#|celli#(?:[\d])?|celli[cr]#|cell(?:nr)?|head(?:nr)?)(\\s.*?)?:\\)/ie', "AdvancedTableDirectives(strtolower('$1'),PQA(PSS('$2')))"); #------------------------------------------------------------ SDV($TableCellIndexMax, 1); #------------------------------------------------------------ $ATDTableNumber = 0; $ATDLastElementOpen = array(); # boolean $ATDLastElementCloseText = array(); # string to close element #------------------------------------------------------------ function MergeClassAndAppendAttributes($AttributeString1, $AttributeString2){ # if either is empty if ($AttributeString1 === '' | $AttributeString1 === NULL) return $AttributeString2; if ($AttributeString2 === '' | $AttributeString2 === NULL) return $AttributeString1; # if either has no class attribute if (strpos($AttributeString1, 'class=') === false || strpos($AttributeString2, 'class=') === false) return $AttributeString1 . ' ' . $AttributeString2; # below here we know that both have the class attribute # quote unquoted $AttributeString1 = preg_replace('/\\bclass=([^\'\\"].*?)\\b/', 'class=\'$1\'', $AttributeString1); $AttributeString2 = preg_replace('/\\bclass=([^\'\\"].*?)\\b/', 'class=\'$1\'', $AttributeString2); # get the stuff inside the quotes preg_match('/(?:class=)(?:\'|\\")(.*?)(?:\'|\\")/', $AttributeString1, $matches); $AttributeStringValue1 = $matches[1]; preg_match('/(?:class=)(?:\'|\\")(.*?)(?:\'|\\")/', $AttributeString2, $matches); $AttributeStringValue2 = $matches[1]; # get string of all classes $ClassValues = array_unique(array_merge(explode(' ', $AttributeStringValue1), explode(' ', $AttributeStringValue2))); $ClassValues = implode(' ', $ClassValues); # replace stuff in quotes in 1st attribute string with all classes $AttributeString1 = preg_replace('/\\bclass=(\'|\\")(.*?)(\1)/', 'class=$1' . $ClassValues . '$1', $AttributeString1); # remove class information from the 2nd attribute string $AttributeString2 = preg_replace('/\\bclass=(\'|\\")(.*?)(\1)/', '', $AttributeString2); return $AttributeString1 . ' ' . $AttributeString2; } #------------------------------------------------------------ # ElementType 0=cell,head,caption 1=row, 2=table function SetupCloseLastElement($sometext, $ElementType = 0) { global $ATDTableNumber, $ATDLastElementOpen, $ATDLastElementCloseText; $ATDLastElementCloseText[$ATDTableNumber][$ElementType] = $sometext; $ATDLastElementOpen[$ATDTableNumber][$ElementType] = true; } #------------------------------------------------------------ # ElementType 0=cell,head,caption 1=row, 2=table function CloseLastElement($ElementType = 0) { global $ATDTableNumber, $ATDLastElementOpen, $ATDLastElementCloseText; $ATDLastElementOpen[$ATDTableNumber][$ElementType] = false; return $ATDLastElementCloseText[$ATDTableNumber][$ElementType]; } #------------------------------------------------------------ function AdvancedTableDirectives($name,$attr) { global $TableCellAttrFmt, $TableRowAttrFmt, $TableCellIndexMax, $TableRowIndexMax, $FmtV; global $ATDTableNumber, $ATDLastElementOpen; static $TableRowNumber = array(); # actual table row number static $TableColumnNumber = array(); # actual table column number static $IncrementingColumn = array(); # incermenting column number static $IncrementingRow = array(); # incrementing row number static $LastIncrementingTableRow = array(); # last actual table row number when an incrementing row number is used static $Incrementor = array(); # incrementing number $IncSub = 0; # designates which incrementor to use $out = ''; # output buffer static $RowCounter = array(); # incrementing row number - used only by case 'row#' $n = substr($name, 0, 4); if ($n === 'cell' || $n === 'head') { if ($name === 'cellnr' || $name == 'headnr') $out .= AdvancedTableDirectives('row', ''); # If not already set, PMWiki will automatically include the # attribute valign='top' with all (:cell:) and (:cellnr:). # PM said "Table Directives were created for layout purposes # and in that case it makes the most sense for each cell (column) # to have its content at the top of the row. The attribute is # placed in each cell and not in the row because certain browsers # didn't recognize valign='top' in the row tag. $attr .= (strpos(strtolower($attr), 'valign=') !== false) ? '' : ' valign=\'top\''; if ($ATDLastElementOpen[$ATDTableNumber][0]) $out .= CloseLastElement(); if (!$ATDLastElementOpen[$ATDTableNumber][1]) $out .= AdvancedTableDirectives('newrow', ''); $FmtV['$TableCellIndex'] = ($TableColumnNumber[$ATDTableNumber] % $TableCellIndexMax) + 1; $FmtV['$TableCellCount'] = ++$TableColumnNumber[$ATDTableNumber]; $attr = MergeClassAndAppendAttributes($attr, FmtPageName(@$TableCellAttrFmt, '')); if ($n === 'head') { SetupCloseLastElement('</th>'); return $out . '<th ' . $attr . '>'; } $out .= '<td ' . $attr . '>'; switch($name) { case 'cell': case 'cellnr': SetupCloseLastElement('</td>'); return $out; case 'celli#9': if ($IncSub === 0) $IncSub = 9; case 'celli#8': if ($IncSub === 0) $IncSub = 8; case 'celli#7': if ($IncSub === 0) $IncSub = 7; case 'celli#6': if ($IncSub === 0) $IncSub = 6; case 'celli#5': if ($IncSub === 0) $IncSub = 5; case 'celli#4': if ($IncSub === 0) $IncSub = 4; case 'celli#3': if ($IncSub === 0) $IncSub = 3; case 'celli#2': if ($IncSub === 0) $IncSub = 2; case 'celli#1': if ($IncSub === 0) $IncSub = 1; case 'celli#' : return $out . ++$Incrementor[$ATDTableNumber][$IncSub] . '</td>'; case 'cellr#' : return $out . $TableRowNumber[$ATDTableNumber] . '</td>'; case 'cellc#' : case 'cell#' : return $out . $TableColumnNumber[$ATDTableNumber] . '</td>'; case 'cellic#': return $out . ++$IncrementingColumn[$ATDTableNumber] . '</td>'; case 'cellir#': # only increment if in a new row if ($LastIncrementingTableRow[$ATDTableNumber] !== $TableRowNumber[$ATDTableNumber]) { $LastIncrementingTableRow[$ATDTableNumber] = $TableRowNumber[$ATDTableNumber]; $IncrementingRow[$ATDTableNumber] ++; } return $out . $IncrementingRow[$ATDTableNumber] . '</td>'; } } switch ($name) { case 'row': # THIS DIRECTIVE CAN ALSO BE CALLED THROUGH RECURSION if ($ATDLastElementOpen[$ATDTableNumber][0]) $out .= CloseLastElement(); # FALL THROUGH TO NEXT CASE case 'newrow': # ONLY CALLED THROUGH RECURSION AND FALL THROUGH if ($ATDLastElementOpen[$ATDTableNumber][1]) $out .= CloseLastElement(1); $TableColumnNumber[$ATDTableNumber] = 0; $IncrementingColumn[$ATDTableNumber] = 0; $FmtV['$TableCellCount'] = 0; $FmtV['$TableRowIndex' ] = ($TableRowNumber[$ATDTableNumber] % $TableRowIndexMax) + 1; $FmtV['$TableRowCount' ] = ++$TableRowNumber[$ATDTableNumber]; $attr = MergeClassAndAppendAttributes($attr, FmtPageName(@$TableRowAttrFmt, '')); SetupCloseLastElement('</tr>', 1); return $out . '<tr ' . $attr . '>'; case 'caption': # valign does not belong on caption attribute SetupCloseLastElement('</caption>'); # pmwiki does not recognize caption as a block markup return '<:block><caption ' . $attr . '>'; case 'table': $ATDTableNumber ++; $TableRowNumber [$ATDTableNumber] = 0; $RowCounter [$ATDTableNumber] = 0; $IncrementingColumn[$ATDTableNumber] = 0; $IncrementingRow [$ATDTableNumber] = 0; $Incrementor[$ATDTableNumber][0] = 0; $Incrementor[$ATDTableNumber][1] = 0; $Incrementor[$ATDTableNumber][2] = 0; $Incrementor[$ATDTableNumber][3] = 0; $Incrementor[$ATDTableNumber][4] = 0; $Incrementor[$ATDTableNumber][5] = 0; $Incrementor[$ATDTableNumber][6] = 0; $Incrementor[$ATDTableNumber][7] = 0; $Incrementor[$ATDTableNumber][8] = 0; $Incrementor[$ATDTableNumber][9] = 0; CloseLastElement($ATDTableNumber); CloseLastElement($ATDTableNumber, 1); SetupCloseLastElement('</table>', 2); # PM said to put <:block> here. return '<:block><table ' . $attr . '>'; case 'tableend': if ($ATDLastElementOpen[$ATDTableNumber][0]) $out .= CloseLastElement(); if ($ATDLastElementOpen[$ATDTableNumber][1]) $out .= CloseLastElement(1); if ($ATDLastElementOpen[$ATDTableNumber][2]) $out .= CloseLastElement(2); $ATDTableNumber --; return $out; case 'row#': # deprecated - kept for backward compatibility $out .= AdvancedTableDirectives('row', $attr); $RowCounter[$ATDTableNumber]++; $FmtV['$TableCellCount'] = $RowCounter[$ATDTableNumber]; $attr = MergeClassAndAppendAttributes($attr, FmtPageName(@$TableCellAttrFmt, '')); return $out . '<td ' . $attr . '>' . $RowCounter[$ATDTableNumber] . '</td>'; } }