1
+ − 1
<?php
+ − 2
// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+ − 3
/**
+ − 4
* Mediawiki: Parses for tables.
+ − 5
*
+ − 6
* This class implements a Text_Wiki_Rule to find tables in pipe syntax
+ − 7
* {| ... |- ... | ... |}
+ − 8
* On parsing, the text itself is left in place, but the starting and ending
+ − 9
* tags for table, rows and cells are replaced with tokens. (nested tables enabled)
+ − 10
*
+ − 11
* PHP versions 4 and 5
+ − 12
*
+ − 13
* @category Text
+ − 14
* @package Text_Wiki
+ − 15
* @author Bertrand Gugger <bertrand@toggg.com>
+ − 16
* @copyright 2005 bertrand Gugger
+ − 17
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
+ − 18
* @version CVS: $Id: Table.php,v 1.7 2005/12/06 15:54:56 ritzmo Exp $
+ − 19
* @link http://pear.php.net/package/Text_Wiki
+ − 20
*/
+ − 21
+ − 22
/**
+ − 23
* Table rule parser class for Mediawiki.
+ − 24
*
+ − 25
* @category Text
+ − 26
* @package Text_Wiki
+ − 27
* @author Bertrand Gugger <bertrand@toggg.com>
+ − 28
* @copyright 2005 bertrand Gugger
+ − 29
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
+ − 30
* @version Release: @package_version@
+ − 31
* @link http://pear.php.net/package/Text_Wiki
+ − 32
* @see Text_Wiki_Parse::Text_Wiki_Parse()
+ − 33
*/
+ − 34
class Text_Wiki_Parse_Table extends Text_Wiki_Parse {
+ − 35
+ − 36
/**
+ − 37
* The regular expression used to parse the source text and find
+ − 38
* matches conforming to this rule. Used by the parse() method.
+ − 39
*
+ − 40
* @access public
+ − 41
* @var string
+ − 42
* @see parse()
+ − 43
*/
+ − 44
var $regex = '#^\{\|(.*?)(?:^\|\+(.*?))?(^(?:((?R))|.)*?)^\|}#msi';
+ − 45
+ − 46
/**
+ − 47
* The regular expression used in second stage to find table's rows
+ − 48
* used by process() to call back processRows()
+ − 49
*
+ − 50
* @access public
+ − 51
* @var string
+ − 52
* @see process()
+ − 53
* @see processRows()
+ − 54
*/
+ − 55
var $regexRows = '#(?:^(\||!)-|\G)(.*?)^(.*?)(?=^(?:\|-|!-|\z))#msi';
+ − 56
+ − 57
/**
+ − 58
* The regular expression used in third stage to find rows's cells
+ − 59
* used by processRows() to call back processCells()
+ − 60
*
+ − 61
* @access public
+ − 62
* @var string
+ − 63
* @see process()
+ − 64
* @see processCells()
+ − 65
*/
+ − 66
var $regexCells =
+ − 67
'#((?:^\||^!|\|\||!!|\G))(?:([^|\n]*?) \|(?!\|))?(.+?)(?=^\||^!|\|\||!!|\z)#msi';
+ − 68
+ − 69
/**
+ − 70
* The current table nesting depth, starts by zero
+ − 71
*
+ − 72
* @access private
+ − 73
* @var int
+ − 74
*/
+ − 75
var $_level = 0;
+ − 76
+ − 77
/**
+ − 78
* The count of rows for this level
+ − 79
*
+ − 80
* @access private
+ − 81
* @var array of int
+ − 82
*/
+ − 83
var $_countRows = array();
+ − 84
+ − 85
/**
+ − 86
* The max count of cells for this level
+ − 87
*
+ − 88
* @access private
+ − 89
* @var array of int
+ − 90
*/
+ − 91
var $_maxCells = array();
+ − 92
+ − 93
/**
+ − 94
* The count of cells for each row
+ − 95
*
+ − 96
* @access private
+ − 97
* @var array of int
+ − 98
*/
+ − 99
var $_countCells = array();
+ − 100
+ − 101
/**
+ − 102
* The count of spanned cells from previous rowspans for each column
+ − 103
*
+ − 104
* @access private
+ − 105
* @var array of int
+ − 106
*/
+ − 107
var $_spanCells = array();
+ − 108
+ − 109
/**
+ − 110
* Generates a replacement for the matched text. Returned token options are:
+ − 111
* 'type' =>
+ − 112
* 'table_start' : the start of a bullet list
+ − 113
* 'table_end' : the end of a bullet list
+ − 114
* 'row_start' : the start of a number list
+ − 115
* 'row_end' : the end of a number list
+ − 116
* 'cell_start' : the start of item text (bullet or number)
+ − 117
* 'cell_end' : the end of item text (bullet or number)
+ − 118
* 'caption_start' : the start of associated caption
+ − 119
* 'caption_end' : the end of associated caption
+ − 120
*
+ − 121
* 'level' => the table nesting level (starting zero) ('table_start')
+ − 122
*
+ − 123
* 'rows' => the number of rows in the table ('table_start')
+ − 124
*
+ − 125
* 'cols' => the number of columns in the table or rows
+ − 126
* ('table_start' and 'row_start')
+ − 127
*
+ − 128
* 'span' => column span ('cell_start')
+ − 129
*
+ − 130
* 'row_span' => row span ('cell_start')
+ − 131
*
+ − 132
* 'attr' => header optional attribute flag ('row_start' or 'cell_start')
+ − 133
*
+ − 134
* 'format' => table, row or cell optional styling ('xxx_start')
+ − 135
*
+ − 136
* @param array &$matches The array of matches from parse().
+ − 137
* @return string the original text with tags replaced by delimited tokens
+ − 138
* which point to the the token array containing their type and definition
+ − 139
* @access public
+ − 140
*/
+ − 141
function process(&$matches)
+ − 142
{
+ − 143
if (array_key_exists(4, $matches)) {
+ − 144
$this->_level++;
+ − 145
$expsub = preg_replace_callback(
+ − 146
$this->regex,
+ − 147
array(&$this, 'process'),
+ − 148
$matches[3]
+ − 149
);
+ − 150
$this->_level--;
+ − 151
} else {
+ − 152
$expsub = $matches[3];
+ − 153
}
+ − 154
$this->_countRows[$this->_level] = $this->_maxCells[$this->_level] = 0;
+ − 155
$this->_countCells[$this->_level] = $this->_spanCells[$this->_level] = array();
+ − 156
$sub = preg_replace_callback(
+ − 157
$this->regexRows,
+ − 158
array(&$this, 'processRows'),
+ − 159
$expsub
+ − 160
);
+ − 161
$param = array(
+ − 162
'type' => 'table_start',
+ − 163
'level' => $this->_level,
+ − 164
'rows' => $this->_countRows[$this->_level],
+ − 165
'cols' => $this->_maxCells[$this->_level]
+ − 166
);
+ − 167
if ($format = trim($matches[1])) {
+ − 168
$param['format'] = $format;
+ − 169
}
+ − 170
$ret = $this->wiki->addToken($this->rule, $param );
+ − 171
if ($matches[2]) {
+ − 172
$ret .= $this->wiki->addToken($this->rule, array(
+ − 173
'type' => 'caption_start',
+ − 174
'level' => $this->_level ) ) . $matches[2] .
+ − 175
$this->wiki->addToken($this->rule, array(
+ − 176
'type' => 'caption_end',
+ − 177
'level' => $this->_level ) );
+ − 178
}
+ − 179
$param['type'] = 'table_end';
+ − 180
return $ret . $sub . $this->wiki->addToken($this->rule, $param );
+ − 181
}
+ − 182
+ − 183
/**
+ − 184
* Generates a replacement for the matched rows. Token options are:
+ − 185
* 'type' =>
+ − 186
* 'row_start' : the start of a row
+ − 187
* 'row_end' : the end of a row
+ − 188
*
+ − 189
* 'order' => the row order in the table
+ − 190
*
+ − 191
* 'cols' => the count of cells in the row
+ − 192
*
+ − 193
* 'attr' => header optional attribute flag
+ − 194
*
+ − 195
* 'format' => row optional styling
+ − 196
*
+ − 197
* @param array &$matches The array of matches from process() callback.
+ − 198
* @return string 2 delimited tokens pointing the row params
+ − 199
* and containing the cells-parsed block of text between the tags
+ − 200
* @access public
+ − 201
*/
+ − 202
function processRows(&$matches)
+ − 203
{
+ − 204
$this->_countCells[$this->_level][$this->_countRows[$this->_level]] = 0;
+ − 205
$sub = preg_replace_callback(
+ − 206
$this->regexCells,
+ − 207
array(&$this, 'processCells'),
+ − 208
$matches[3]
+ − 209
);
+ − 210
$param = array(
+ − 211
'type' => 'row_start',
+ − 212
'order' => $this->_countRows[$this->_level],
+ − 213
'cols' => $this->_countCells[$this->_level][$this->_countRows[$this->_level]++]
+ − 214
);
+ − 215
if ($matches[1] == '!') {
+ − 216
$param['attr'] = 'header';
+ − 217
}
+ − 218
if ($format = trim($matches[2])) {
+ − 219
$param['format'] = $format;
+ − 220
}
+ − 221
if ($this->_maxCells[$this->_level] < $param['cols']) {
+ − 222
$this->_maxCells[$this->_level] = $param['cols'];
+ − 223
}
+ − 224
$ret = $this->wiki->addToken($this->rule, $param );
+ − 225
$param['type'] = 'row_end';
+ − 226
return $ret . $sub . $this->wiki->addToken($this->rule, $param );
+ − 227
}
+ − 228
+ − 229
/**
+ − 230
* Generates a replacement for the matched cells. Token options are:
+ − 231
* 'type' =>
+ − 232
* 'cell_start' : the start of a row
+ − 233
* 'cell_end' : the end of a row
+ − 234
*
+ − 235
* 'order' => the cell order in the row
+ − 236
*
+ − 237
* 'cols' => the count of cells in the row
+ − 238
*
+ − 239
* 'span' => column span
+ − 240
*
+ − 241
* 'row_span' => row span
+ − 242
*
+ − 243
* 'attr' => header optional attribute flag
+ − 244
*
+ − 245
* 'format' => cell optional styling
+ − 246
*
+ − 247
* @param array &$matches The array of matches from processRows() callback.
+ − 248
* @return string 2 delimited tokens pointing the cell params
+ − 249
* and containing the block of text between the tags
+ − 250
* @access public
+ − 251
*/
+ − 252
function processCells(&$matches)
+ − 253
{
+ − 254
$order = & $this->_countCells[$this->_level][$this->_countRows[$this->_level]];
+ − 255
while (isset($this->_spanCells[$this->_level][$order])) {
+ − 256
if (--$this->_spanCells[$this->_level][$order] < 2) {
+ − 257
unset($this->_spanCells[$this->_level][$order]);
+ − 258
}
+ − 259
$order++;
+ − 260
}
+ − 261
$param = array(
+ − 262
'type' => 'cell_start',
+ − 263
'attr' => $matches[1] && ($matches[1]{0} == '!') ? 'header': null,
+ − 264
'span' => 1,
+ − 265
'rowspan' => 1,
+ − 266
'order' => $order
+ − 267
);
+ − 268
if ($format = trim($matches[2])) {
+ − 269
if (preg_match('#(.*)colspan=("|\')?(\d+)(?(2)\2)(.*)#i', $format, $pieces)) {
+ − 270
$param['span'] = (int)$pieces[3];
+ − 271
$format = $pieces[1] . $pieces[4];
+ − 272
}
+ − 273
if (preg_match('#(.*)rowspan=("|\')?(\d+)(?(2)\2)(.*)#i', $format, $pieces)) {
+ − 274
$this->_spanCells[$this->_level][$order] =
+ − 275
$param['rowspan'] = (int)$pieces[3];
+ − 276
$format = $pieces[1] . $pieces[4];
+ − 277
}
+ − 278
$param['format'] = $format;
+ − 279
}
+ − 280
$this->_countCells[$this->_level][$this->_countRows[$this->_level]] += $param['span'];
+ − 281
$ret = $this->wiki->addToken($this->rule, $param);
+ − 282
$param['type'] = 'cell_end';
+ − 283
return $ret . $matches[3] . $this->wiki->addToken($this->rule, $param );
+ − 284
}
+ − 285
}
+ − 286
?>