1
+ − 1
<?php
+ − 2
// vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
+ − 3
/**
+ − 4
*
+ − 5
* Mediawiki: Parse for definition lists.
+ − 6
*
+ − 7
* @category Text
+ − 8
* @package Text_Wiki
+ − 9
* @author Justin Patrin <papercrane@reversefold.com>
+ − 10
* @author Paul M. Jones <pmjones@php.net>
+ − 11
* @author Moritz Venn <ritzmo@php.net>
+ − 12
* @license LGPL
+ − 13
* @version $Id: Deflist.php,v 1.1 2006/03/29 18:41:43 ritzmo Exp $
+ − 14
*
+ − 15
*/
+ − 16
+ − 17
/**
+ − 18
*
+ − 19
* Parses for definition lists.
+ − 20
*
+ − 21
* This class implements a Text_Wiki_Parse to find source text marked as a
+ − 22
* definition list.
+ − 23
* If a line starts with ';' or ':' it is considered a part of a definition
+ − 24
* list. ';' indicates the term to be defined and ':' indicates its definition.
+ − 25
* As in Mediawiki we also allow definition lists to only consist of one
+ − 26
* item-type.
+ − 27
*
+ − 28
* @category Text
+ − 29
* @package Text_Wiki
+ − 30
*
+ − 31
* @author Justin Patrin <papercrane@reversefold.com>
+ − 32
* @author Paul M. Jones <pmjones@php.net>
+ − 33
* @author Moritz Venn <ritzmo@php.net>
+ − 34
*
+ − 35
*/
+ − 36
+ − 37
class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse {
+ − 38
+ − 39
+ − 40
/**
+ − 41
*
+ − 42
* The regular expression used to parse the source text and find
+ − 43
* matches conforming to this rule. Used by the parse() method.
+ − 44
*
+ − 45
* @access public
+ − 46
*
+ − 47
* @var string
+ − 48
*
+ − 49
* @see parse()
+ − 50
*
+ − 51
*/
+ − 52
+ − 53
var $regex = '/\n((?:\;|\:)+.*?\n(?!(?:\;|\:)+))/s';
+ − 54
+ − 55
/**
+ − 56
*
+ − 57
* Generates a replacement for the matched text. Token options are:
+ − 58
*
+ − 59
* 'type' =>
+ − 60
* 'list_start' : the start of a definition list
+ − 61
* 'list_end' : the end of a definition list
+ − 62
* 'term_start' : the start of a definition term
+ − 63
* 'term_end' : the end of a definition term
+ − 64
* 'narr_start' : the start of definition narrative
+ − 65
* 'narr_end' : the end of definition narrative
+ − 66
* 'unknown' : unknown type of definition portion
+ − 67
*
+ − 68
* 'level' => the indent level (0 for the first level, 1 for the
+ − 69
* second, etc)
+ − 70
*
+ − 71
* 'count' => the list item number at this level. not needed for
+ − 72
* xhtml, but very useful for PDF and RTF.
+ − 73
*
+ − 74
* @access public
+ − 75
*
+ − 76
* @param array &$matches The array of matches from parse().
+ − 77
*
+ − 78
* @return A series of text and delimited tokens marking the different
+ − 79
* list text and list elements.
+ − 80
*
+ − 81
*/
+ − 82
function process(&$matches)
+ − 83
{
+ − 84
// the replacement text we will return
+ − 85
$return = '';
+ − 86
+ − 87
// the list of post-processing matches
+ − 88
$list = array();
+ − 89
+ − 90
// a stack of list-start and list-end types; we keep this
+ − 91
// so that we know what kind of list we're working with
+ − 92
// (bullet or number) and what indent level we're at.
+ − 93
$stack = array();
+ − 94
+ − 95
// the item count is the number of list items for any
+ − 96
// given list-type on the stack
+ − 97
$itemcount = array();
+ − 98
+ − 99
// have we processed the very first list item?
+ − 100
$pastFirst = false;
+ − 101
+ − 102
// populate $list with this set of matches. $matches[1] is the
+ − 103
// text matched as a list set by parse().
+ − 104
preg_match_all(
+ − 105
'/^((;|:)+)(.*?)$/ms',
+ − 106
$matches[1],
+ − 107
$list,
+ − 108
PREG_SET_ORDER
+ − 109
);
+ − 110
+ − 111
// loop through each list-item element.
+ − 112
foreach ($list as $key => $val) {
+ − 113
// $val[0] is the full matched list-item line
+ − 114
// $val[1] is the type (* or #)
+ − 115
// $val[2] is the level (number)
+ − 116
// $val[3] is the list item text
+ − 117
+ − 118
// how many levels are we indented? (1 means the "root"
+ − 119
// list level, no indenting.)
+ − 120
$level = strlen($val[1]);
+ − 121
+ − 122
// get the list item type
+ − 123
if ($val[2] == ';') {
+ − 124
$type = 'term';
+ − 125
} elseif ($val[2] == ':') {
+ − 126
$type = 'narr';
+ − 127
} else {
+ − 128
$type = 'unknown';
+ − 129
}
+ − 130
+ − 131
// get the text of the list item
+ − 132
$text = $val[3];
+ − 133
+ − 134
// add a level to the list?
+ − 135
if ($level > count($stack)) {
+ − 136
+ − 137
// the current indent level is greater than the
+ − 138
// number of stack elements, so we must be starting
+ − 139
// a new list. push the new list type onto the
+ − 140
// stack...
+ − 141
array_push($stack, $type);
+ − 142
+ − 143
// The new list has to be opened in an item (use current type)
+ − 144
if ($level > 1) {
+ − 145
$return .= $this->wiki->addToken(
+ − 146
$this->rule,
+ − 147
array(
+ − 148
'type' => $type . '_start',
+ − 149
'level' => $level - 1
+ − 150
)
+ − 151
);
+ − 152
}
+ − 153
// ...and add a list-start token to the return.
+ − 154
$return .= $this->wiki->addToken(
+ − 155
$this->rule,
+ − 156
array(
+ − 157
'type' => 'list_start',
+ − 158
'level' => $level - 1
+ − 159
)
+ − 160
);
+ − 161
}
+ − 162
+ − 163
// remove a level from the list?
+ − 164
while (count($stack) > $level) {
+ − 165
// so we don't keep counting the stack, we set up a temp
+ − 166
// var for the count. -1 becuase we're going to pop the
+ − 167
// stack in the next command. $tmp will then equal the
+ − 168
// current level of indent.
+ − 169
$tmp = count($stack) - 1;
+ − 170
+ − 171
// as long as the stack count is greater than the
+ − 172
// current indent level, we need to end list types.
+ − 173
// continue adding end-list tokens until the stack count
+ − 174
// and the indent level are the same.
+ − 175
$return .= $this->wiki->addToken(
+ − 176
$this->rule,
+ − 177
array (
+ − 178
'type' => 'list_end',
+ − 179
'level' => $tmp
+ − 180
)
+ − 181
);
+ − 182
+ − 183
array_pop($stack);
+ − 184
+ − 185
// reset to the current (previous) list type so that
+ − 186
// the new list item matches the proper list type.
+ − 187
$type = $stack[$tmp - 1];
+ − 188
+ − 189
// Close the previously opened List item
+ − 190
$return .= $this->wiki->addToken(
+ − 191
$this->rule,
+ − 192
array (
+ − 193
'type' => $type . '_end',
+ − 194
'level' => $tmp
+ − 195
)
+ − 196
);
+ − 197
+ − 198
// reset the item count for the popped indent level
+ − 199
unset($itemcount[$tmp + 1]);
+ − 200
}
+ − 201
+ − 202
// add to the item count for this list (taking into account
+ − 203
// which level we are at).
+ − 204
if (! isset($itemcount[$level])) {
+ − 205
// first count
+ − 206
$itemcount[$level] = 0;
+ − 207
} else {
+ − 208
// increment count
+ − 209
$itemcount[$level]++;
+ − 210
}
+ − 211
+ − 212
// is this the very first item in the list?
+ − 213
if (! $pastFirst) {
+ − 214
$first = true;
+ − 215
$pastFirst = true;
+ − 216
} else {
+ − 217
$first = false;
+ − 218
}
+ − 219
+ − 220
// create a list-item starting token.
+ − 221
$start = $this->wiki->addToken(
+ − 222
$this->rule,
+ − 223
array(
+ − 224
'type' => $type . '_start',
+ − 225
'level' => $level,
+ − 226
'count' => $itemcount[$level],
+ − 227
'first' => $first
+ − 228
)
+ − 229
);
+ − 230
+ − 231
// create a list-item ending token.
+ − 232
$end = $this->wiki->addToken(
+ − 233
$this->rule,
+ − 234
array(
+ − 235
'type' => $type . '_end',
+ − 236
'level' => $level,
+ − 237
'count' => $itemcount[$level]
+ − 238
)
+ − 239
);
+ − 240
+ − 241
// add the starting token, list-item text, and ending token
+ − 242
// to the return.
+ − 243
$return .= $start . $text . $end;
+ − 244
}
+ − 245
+ − 246
// the last list-item may have been indented. go through the
+ − 247
// list-type stack and create end-list tokens until the stack
+ − 248
// is empty.
+ − 249
$level = count($stack);
+ − 250
while ($level > 0) {
+ − 251
array_pop($stack);
+ − 252
$return .= $this->wiki->addToken(
+ − 253
$this->rule,
+ − 254
array (
+ − 255
'type' => 'list_end',
+ − 256
'level' => $level - 1
+ − 257
)
+ − 258
);
+ − 259
+ − 260
// if we are higher than level 1 we need to close fake items
+ − 261
if ($level > 1) {
+ − 262
$return .= $this->wiki->addToken(
+ − 263
$this->rule,
+ − 264
array (
+ − 265
'type' => $stack[$level - 2] . '_end',
+ − 266
'level' => $level - 2
+ − 267
)
+ − 268
);
+ − 269
}
+ − 270
$level = count($stack);
+ − 271
}
+ − 272
+ − 273
// we're done! send back the replacement text.
+ − 274
return "\n" . $return . "\n\n";
+ − 275
}
+ − 276
}
+ − 277
?>