| 1 |
<?php
|
| 2 |
// $Id: wiki.module,v 1.3 2005/12/30 15:57:22 alaa Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Handle filtering of Wiki Text
|
| 7 |
*/
|
| 8 |
|
| 9 |
define('WIKI_FILTER_HTML_ENABLE', 1);
|
| 10 |
define('WIKI_FILTER_HTML_DISABLE', 2);
|
| 11 |
|
| 12 |
/**
|
| 13 |
* Implementation of hook_help().
|
| 14 |
*/
|
| 15 |
function wiki_help($section) {
|
| 16 |
switch ($section) {
|
| 17 |
case 'admin/modules#description':
|
| 18 |
return t('Enables users to use simple WikiText markup to format content.');
|
| 19 |
}
|
| 20 |
}
|
| 21 |
|
| 22 |
/**
|
| 23 |
* @name WikiText filters
|
| 24 |
* @{
|
| 25 |
* Filters implemented by the filter.module.
|
| 26 |
*/
|
| 27 |
|
| 28 |
/**
|
| 29 |
* Implementation of hook_filter(). Contains a basic set of essential filters.
|
| 30 |
* - WikiText filter:
|
| 31 |
* Processes wiki text and convert to HTML
|
| 32 |
*/
|
| 33 |
function wiki_filter($op, $delta = 0, $format = -1, $text = '') {
|
| 34 |
switch ($op) {
|
| 35 |
case 'list':
|
| 36 |
return array(t('WikiText filter'));
|
| 37 |
|
| 38 |
case 'description':
|
| 39 |
return t('Converts WikiText to HTML.');
|
| 40 |
|
| 41 |
case 'process':
|
| 42 |
return _wiki_filter($text);
|
| 43 |
|
| 44 |
default:
|
| 45 |
return $text;
|
| 46 |
}
|
| 47 |
}
|
| 48 |
|
| 49 |
/**
|
| 50 |
* Implementation of hook_menu()
|
| 51 |
* /wiki/goto/title redirects to a node or edit form based on title
|
| 52 |
*/
|
| 53 |
function wiki_menu($may_cache) {
|
| 54 |
$items = array();
|
| 55 |
|
| 56 |
if ($may_cache) {
|
| 57 |
$items[] = array('path' => 'wiki/goto', 'title' => t('wiki goto'), 'type' => MENU_CALLBACK,
|
| 58 |
'callback' => 'wiki_goto', 'access' => user_access('access content'));
|
| 59 |
}
|
| 60 |
|
| 61 |
return $items;
|
| 62 |
}
|
| 63 |
|
| 64 |
|
| 65 |
define("WIKI_ZERO_LEVEL", 0);
|
| 66 |
define("WIKI_NESTED_LEVEL", 1);
|
| 67 |
define("WIKI_FIELD_SEPARATOR", "\263");
|
| 68 |
|
| 69 |
// allowed protocols for links - be careful not to allow "javascript:"
|
| 70 |
// within a named link [name|uri] one more protocol is defined: phpwiki
|
| 71 |
//define("WIKI_ALLOWED_PROTOCOLS", "http|https|mailto|ftp|news|gopher");
|
| 72 |
define("WIKI_ALLOWED_PROTOCOLS", "http|https|javascript|mailto|ftp|news|gopher");
|
| 73 |
|
| 74 |
// URLs ending with the following extension should be inlined as images
|
| 75 |
define("WIKI_INLINE_IMAGES", "png|jpg|gif");
|
| 76 |
|
| 77 |
class _wiki_stack {
|
| 78 |
var $items = array();
|
| 79 |
var $size = 0;
|
| 80 |
|
| 81 |
function push($item) {
|
| 82 |
$this->items[$this->size] = $item;
|
| 83 |
$this->size++;
|
| 84 |
return true;
|
| 85 |
}
|
| 86 |
|
| 87 |
function pop() {
|
| 88 |
if ($this->size == 0) {
|
| 89 |
return false; // stack is empty
|
| 90 |
}
|
| 91 |
$this->size--;
|
| 92 |
return $this->items[$this->size];
|
| 93 |
}
|
| 94 |
|
| 95 |
function cnt() {
|
| 96 |
return $this->size;
|
| 97 |
}
|
| 98 |
|
| 99 |
function top() {
|
| 100 |
if ($this->size) {
|
| 101 |
return $this->items[$this->size - 1];
|
| 102 |
} else {
|
| 103 |
return '';
|
| 104 |
}
|
| 105 |
}
|
| 106 |
} // end class definition
|
| 107 |
|
| 108 |
/**
|
| 109 |
* Find any strings in $str that match $pattern and
|
| 110 |
* store them in $orig, replacing them with tokens
|
| 111 |
* starting at number $ntokens - returns tokenized string
|
| 112 |
*/
|
| 113 |
function _wiki_tokenize($str, $pattern, &$orig, &$ntokens) {
|
| 114 |
$new = '';
|
| 115 |
while (preg_match("/^(.*?)($pattern)/", $str, $matches)) {
|
| 116 |
$linktoken = WIKI_FIELD_SEPARATOR . WIKI_FIELD_SEPARATOR . ($ntokens++) . WIKI_FIELD_SEPARATOR;
|
| 117 |
$new .= $matches[1] . $linktoken;
|
| 118 |
$orig[] = $matches[2];
|
| 119 |
$str = substr($str, strlen($matches[0]));
|
| 120 |
}
|
| 121 |
$new .= $str;
|
| 122 |
return $new;
|
| 123 |
}
|
| 124 |
|
| 125 |
function _wiki_find_node($title) {
|
| 126 |
// I'm surprised there's no Drupal API for finding a node (the do_search
|
| 127 |
// function is way too process intensive for our needs here
|
| 128 |
// As for node security we don't need to worry here. At the time of viewing
|
| 129 |
// the node security will be checked.
|
| 130 |
return db_fetch_object(db_query("SELECT nid FROM {node} WHERE title = '%s' AND status = 1 ORDER BY created DESC", $title));
|
| 131 |
}
|
| 132 |
|
| 133 |
function _wiki_link_URL($url, $linktext='') {
|
| 134 |
if (ereg("[<>\"]", $url)) {
|
| 135 |
return '<b><u>BAD URL -- remove all of <, >, "</u></b>';
|
| 136 |
}
|
| 137 |
if (empty($linktext)) {
|
| 138 |
$linktext = htmlspecialchars($url);
|
| 139 |
}
|
| 140 |
return "<a href=\"$url\">$linktext</a>";
|
| 141 |
}
|
| 142 |
|
| 143 |
function _wiki_link_image($url, $alt='[Image]') {
|
| 144 |
if (ereg('[<>"]', $url)) {
|
| 145 |
return "<b><u>BAD URL -- remove all of <, >, "</u></b>";
|
| 146 |
}
|
| 147 |
return theme("image", $url, $alt, $title = '', $attr = '', $getsize = false);
|
| 148 |
}
|
| 149 |
|
| 150 |
function _wiki_link_node($title, $linktext='') {
|
| 151 |
if (empty($linktext)) {
|
| 152 |
$linktext = htmlspecialchars($title);
|
| 153 |
}
|
| 154 |
return l($linktext, 'wiki/'. liquid_encode($title));
|
| 155 |
}
|
| 156 |
|
| 157 |
function wiki_goto() {
|
| 158 |
$dest_raw = arg(2);
|
| 159 |
$dest = rawurldecode($dest_raw);
|
| 160 |
if ($node = _wiki_find_node($dest)) {
|
| 161 |
drupal_goto('node/'. $node->nid);
|
| 162 |
}
|
| 163 |
else {
|
| 164 |
// We need a node type to link to if we're going to do this.
|
| 165 |
// So I picked story, the most basic type of node.
|
| 166 |
drupal_goto('node/add/book', 'edit[title]='. $dest_raw);
|
| 167 |
}
|
| 168 |
}
|
| 169 |
|
| 170 |
/**
|
| 171 |
* $bracketlink will start and end with brackets; in between
|
| 172 |
* will be either a page name, a URL or both separated by a pipe.
|
| 173 |
*/
|
| 174 |
function _wiki_parse_and_link($bracketlink) {
|
| 175 |
// strip brackets and leading space
|
| 176 |
preg_match("/(\[\s*)(.+?)(\s*\])/", $bracketlink, $match);
|
| 177 |
// match the contents
|
| 178 |
preg_match("/([^|]+)(\|)?([^|]+)?/", $match[2], $matches);
|
| 179 |
|
| 180 |
if (isset($matches[3])) {
|
| 181 |
// named link of the form "[some link name | http://blippy.com/]"
|
| 182 |
$URL = trim($matches[3]);
|
| 183 |
$linkname = htmlspecialchars(trim($matches[1]));
|
| 184 |
$linktype = 'named';
|
| 185 |
}
|
| 186 |
else {
|
| 187 |
// unnamed link of the form "[http://blippy.com/] or [wiki page]"
|
| 188 |
$URL = trim($matches[1]);
|
| 189 |
$linkname = '';
|
| 190 |
$linktype = 'simple';
|
| 191 |
}
|
| 192 |
|
| 193 |
if (preg_match("/\.".WIKI_INLINE_IMAGES."$/i", $URL)) {
|
| 194 |
// if it's an image, embed it; otherwise, it's a regular link
|
| 195 |
$link = array('type' => "image-$linktype", 'link' => _wiki_link_image($URL, $linkname));
|
| 196 |
}
|
| 197 |
elseif (preg_match("#^".WIKI_ALLOWED_PROTOCOLS.":#", $URL)) {
|
| 198 |
$link = array('type' => "url-$linktype", 'link' => _wiki_link_URL($URL, $linkname));
|
| 199 |
}
|
| 200 |
elseif (preg_match("#^phpwiki:(.*)#", $URL, $match)) {
|
| 201 |
if (empty($linkname)) {
|
| 202 |
$linkname = htmlspecialchars($URL);
|
| 203 |
}
|
| 204 |
$link = array('type' => "url-wiki-$linktype", 'link' => "<a href=\"/SCRIPT/$match[1]\">$linkname</a>");
|
| 205 |
}
|
| 206 |
elseif (preg_match("#^\d+$#", $URL)) {
|
| 207 |
$link = array('type' => "reference-$linktype", 'link' => $URL);
|
| 208 |
}
|
| 209 |
else {
|
| 210 |
$link = array('type' => "wiki-$linktype", 'link' => _wiki_link_node($URL, $linkname));
|
| 211 |
}
|
| 212 |
|
| 213 |
return $link;
|
| 214 |
}
|
| 215 |
|
| 216 |
|
| 217 |
/**
|
| 218 |
* Wiki HTML output can, at any given time, be in only one mode.
|
| 219 |
* It will be something like Unordered List, Preformatted Text,
|
| 220 |
* plain text etc. When we change modes we have to issue close tags
|
| 221 |
* for one mode and start tags for another.
|
| 222 |
*
|
| 223 |
* @param $tag HTML tag to insert
|
| 224 |
* @param $tagtype WIKI_ZERO_LEVEL - close all open tags before inserting $tag
|
| 225 |
* WIKI_NESTED_LEVEL - close tags until depths match
|
| 226 |
* @param $level nesting level (depth) of $tag
|
| 227 |
* nesting is arbitrary limited to 10 levels
|
| 228 |
*/
|
| 229 |
function _wiki_set_output_mode($tag, $tagtype, $level) {
|
| 230 |
static $stack;
|
| 231 |
|
| 232 |
if (!$stack) {
|
| 233 |
$stack = new _wiki_stack;
|
| 234 |
}
|
| 235 |
$retvar = '';
|
| 236 |
|
| 237 |
if ($level > 10) {
|
| 238 |
/*
|
| 239 |
* arbitrarily limit tag nesting
|
| 240 |
* We just clamp the the maximum depth.
|
| 241 |
*/
|
| 242 |
$level = 10;
|
| 243 |
}
|
| 244 |
|
| 245 |
if ($tagtype == WIKI_ZERO_LEVEL) {
|
| 246 |
// empty the stack until $level == 0;
|
| 247 |
if ($tag == $stack->top()) {
|
| 248 |
return; // same tag? -> nothing to do
|
| 249 |
}
|
| 250 |
while ($stack->cnt() > 0) {
|
| 251 |
$closetag = $stack->pop();
|
| 252 |
$retvar .= "</$closetag>\n";
|
| 253 |
}
|
| 254 |
|
| 255 |
if ($tag) {
|
| 256 |
$retvar .= "<$tag>\n";
|
| 257 |
$stack->push($tag);
|
| 258 |
}
|
| 259 |
|
| 260 |
}
|
| 261 |
elseif ($tagtype == WIKI_NESTED_LEVEL) {
|
| 262 |
if ($level < $stack->cnt()) {
|
| 263 |
// $tag has fewer nestings (old: tabs) than stack,
|
| 264 |
// reduce stack to that tab count
|
| 265 |
while ($stack->cnt() > $level) {
|
| 266 |
$closetag = $stack->pop();
|
| 267 |
if ($closetag == FALSE) {
|
| 268 |
//echo "bounds error in tag stack";
|
| 269 |
break;
|
| 270 |
}
|
| 271 |
$retvar .= "</$closetag>\n";
|
| 272 |
}
|
| 273 |
|
| 274 |
// if list type isn't the same,
|
| 275 |
// back up one more and push new tag
|
| 276 |
if ($tag != $stack->top()) {
|
| 277 |
$closetag = $stack->pop();
|
| 278 |
$retvar .= "</$closetag><$tag>\n";
|
| 279 |
$stack->push($tag);
|
| 280 |
}
|
| 281 |
|
| 282 |
}
|
| 283 |
elseif ($level > $stack->cnt()) {
|
| 284 |
// Test for and close top level elements which are not allowed to contain
|
| 285 |
// other block-level elements.
|
| 286 |
if ($stack->cnt() == 1 and preg_match('/^(p|pre|h\d)$/i', $stack->top())) {
|
| 287 |
$closetag = $stack->pop();
|
| 288 |
$retvar .= "</$closetag>";
|
| 289 |
}
|
| 290 |
|
| 291 |
// we add the diff to the stack
|
| 292 |
// stack might be zero
|
| 293 |
if ($stack->cnt() < $level) {
|
| 294 |
while ($stack->cnt() < $level - 1) {
|
| 295 |
/*
|
| 296 |
* This is a bit of a hack:
|
| 297 |
*
|
| 298 |
* We're not nested deep enough, and have to make up
|
| 299 |
* some kind of block element to nest within.
|
| 300 |
*
|
| 301 |
* Currently, this can only happen for nested list
|
| 302 |
* element (either <ul> <ol> or <dl>). What we used
|
| 303 |
* to do here is to open extra lists of whatever
|
| 304 |
* type was requested. This would result in invalid
|
| 305 |
* HTML, since and list is not allowed to contain
|
| 306 |
* another list without first containing a list
|
| 307 |
* item. ("<ul><ul><li>Item</ul></ul>" is invalid.)
|
| 308 |
*
|
| 309 |
* So now, when we need extra list elements, we use
|
| 310 |
* a <dl>, and open it with an empty <dd>.
|
| 311 |
*/
|
| 312 |
|
| 313 |
$retvar .= "<dl><dd>";
|
| 314 |
$stack->push('dl');
|
| 315 |
}
|
| 316 |
|
| 317 |
$retvar .= "<$tag>\n";
|
| 318 |
$stack->push($tag);
|
| 319 |
}
|
| 320 |
}
|
| 321 |
else {
|
| 322 |
if ($tag == $stack->top()) {
|
| 323 |
return; // same tag? -> nothing to do
|
| 324 |
}
|
| 325 |
else {
|
| 326 |
// different tag - close old one, add new one
|
| 327 |
$closetag = $stack->pop();
|
| 328 |
$retvar .= "</$closetag>\n";
|
| 329 |
$retvar .= "<$tag>\n";
|
| 330 |
$stack->push($tag);
|
| 331 |
}
|
| 332 |
}
|
| 333 |
}
|
| 334 |
else { // unknown $tagtype
|
| 335 |
ExitWiki ("Passed bad tag type value in _wiki_set_output_mode");
|
| 336 |
}
|
| 337 |
return $retvar;
|
| 338 |
} // end _wiki_set_output_mode()
|
| 339 |
|
| 340 |
|
| 341 |
/**
|
| 342 |
* WikiText filter. Provides filtering of input into accepted HTML.
|
| 343 |
*/
|
| 344 |
function _wiki_filter($text) {
|
| 345 |
$html = '';
|
| 346 |
$isprotect = FALSE; // whether we're within a {{{ }}} protection block
|
| 347 |
$istable = FALSE; // whether we're currently in a table
|
| 348 |
|
| 349 |
$ishtml = 0;
|
| 350 |
$tag = "";
|
| 351 |
$closeflag = FALSE;
|
| 352 |
// process text line by line
|
| 353 |
$lines = preg_split('/\n/', $text);
|
| 354 |
$numlines = count($lines);
|
| 355 |
|
| 356 |
for ($index = 0; $index < $numlines; $index++) {
|
| 357 |
unset($tokens);
|
| 358 |
unset($replacements);
|
| 359 |
$ntokens = 0;
|
| 360 |
$replacements = array();
|
| 361 |
|
| 362 |
$tmpline = $lines[$index];
|
| 363 |
|
| 364 |
// protect everthing within "{{{" and "}}}" as is
|
| 365 |
// multi line case:
|
| 366 |
if (preg_match("/^{{{(.*)/", $tmpline, $matches) && !preg_match("/}}}/", $tmpline, $matches)) {
|
| 367 |
$isprotect = TRUE;
|
| 368 |
$html .= _wiki_set_output_mode("pre", WIKI_ZERO_LEVEL, 0);
|
| 369 |
$html .= htmlspecialchars($matches[1]). "\n";
|
| 370 |
continue;
|
| 371 |
}
|
| 372 |
elseif ($isprotect) {
|
| 373 |
if (preg_match("/^}}}/", $tmpline, $matches)) {
|
| 374 |
$isprotect = FALSE;
|
| 375 |
$html .= _wiki_set_output_mode("", WIKI_ZERO_LEVEL, 0);
|
| 376 |
}
|
| 377 |
else {
|
| 378 |
$html .= htmlspecialchars($tmpline). "\n";
|
| 379 |
}
|
| 380 |
continue;
|
| 381 |
}
|
| 382 |
|
| 383 |
// single line case:
|
| 384 |
$oldn = $ntokens;
|
| 385 |
$tmpline = _wiki_tokenize($tmpline, '{{{.+}}}', $replacements, $ntokens);
|
| 386 |
while ($oldn < $ntokens) {
|
| 387 |
if (preg_match("/{{{(.+)}}}/", $replacements[$oldn], $matches)) {
|
| 388 |
// this, of course, goes through, but we want the matched piece
|
| 389 |
$matches[1] = str_replace('\\\\', '<br\>', htmlspecialchars($matches[1]));
|
| 390 |
$replacements[$oldn] = preg_replace("{{{.+}}}", "<pre>$matches[1]</pre>", $replacements[$oldn]);
|
| 391 |
}
|
| 392 |
$oldn++;
|
| 393 |
}
|
| 394 |
|
| 395 |
if (!strlen($tmpline) || $tmpline == "\r" || preg_match('#^\s*$#',
|
| 396 |
$tmpline)) {
|
| 397 |
// this is a blank line, send <p>
|
| 398 |
$html .= _wiki_set_output_mode('', WIKI_ZERO_LEVEL, 0);
|
| 399 |
continue;
|
| 400 |
}
|
| 401 |
elseif (variable_get("wiki_filter_html", WIKI_FILTER_HTML_DISABLE) == WIKI_FILTER_HTML_ENABLE) {
|
| 402 |
// We protect HTML by having lines start with |> php-wiki way is just |
|
| 403 |
// this change is to prevent wiki table from being skipped
|
| 404 |
if (preg_match("/(^\|>)(.*)/", $tmpline, $matches)) {
|
| 405 |
// HTML mode
|
| 406 |
$html .= _wiki_set_output_mode("", WIKI_ZERO_LEVEL, 0);
|
| 407 |
$html .= $matches[2];
|
| 408 |
continue;
|
| 409 |
}
|
| 410 |
}
|
| 411 |
|
| 412 |
//ho2a
|
| 413 |
|
| 414 |
|
| 415 |
if (preg_match("#<\s*(ol|ul|dl|div|pre|p|blockquote|code|h[1-6]).*>#Ui", $tmpline, $matches)) {
|
| 416 |
++$ishtml;
|
| 417 |
$tag = $matches[1];
|
| 418 |
// _wiki_set_output_mode("$tag", WIKI_ZERO_LEVEL, 0);
|
| 419 |
}
|
| 420 |
if (preg_match("#<\s*/\s*$tag\s*>#Ui", $tmpline)) {
|
| 421 |
$closeflag = TRUE;
|
| 422 |
}
|
| 423 |
//ho2a
|
| 424 |
|
| 425 |
// This would keep HTML at this point as-is
|
| 426 |
$tmpline = _wiki_tokenize($tmpline, '<[^>]+>', $replacements, $ntokens);
|
| 427 |
|
| 428 |
/*
|
| 429 |
* New linking scheme: links are in brackets. This will
|
| 430 |
* emulate typical HTML linking as well as Wiki linking.
|
| 431 |
*/
|
| 432 |
|
| 433 |
// First need to protect [[.
|
| 434 |
$oldn = $ntokens;
|
| 435 |
$tmpline = _wiki_tokenize($tmpline, '\[\[', $replacements, $ntokens);
|
| 436 |
while ($oldn < $ntokens) {
|
| 437 |
$replacements[$oldn] = '[';
|
| 438 |
$oldn++;
|
| 439 |
}
|
| 440 |
|
| 441 |
// *** Footnotes currently aren't supported, but will be added later
|
| 442 |
// Now process the [\d+] links which are numeric references
|
| 443 |
$oldn = $ntokens;
|
| 444 |
$tmpline = _wiki_tokenize($tmpline, '\[\s*\d+\s*\]', $replacements, $ntokens);
|
| 445 |
while ($oldn < $ntokens) {
|
| 446 |
$num = (int) substr($replacements[$oldn], 1);
|
| 447 |
if (! empty($embedded[$num])) {
|
| 448 |
$replacements[$oldn] = $embedded[$num];
|
| 449 |
}
|
| 450 |
$oldn++;
|
| 451 |
}
|
| 452 |
|
| 453 |
// match anything else between brackets
|
| 454 |
$oldn = $ntokens;
|
| 455 |
$tmpline = _wiki_tokenize($tmpline, '\[.+?\]', $replacements, $ntokens);
|
| 456 |
while ($oldn < $ntokens) {
|
| 457 |
$link = _wiki_parse_and_link($replacements[$oldn]);
|
| 458 |
$replacements[$oldn] = $link['link'];
|
| 459 |
$oldn++;
|
| 460 |
}
|
| 461 |
|
| 462 |
/*
|
| 463 |
* replace all URL's with tokens, so we don't confuse them
|
| 464 |
* with Wiki words later. Wiki words in URL's break things.
|
| 465 |
* URLs preceeded by a '!' are not linked
|
| 466 |
*/
|
| 467 |
|
| 468 |
$tmpline = _wiki_tokenize($tmpline, "!?\b(".WIKI_ALLOWED_PROTOCOLS."):[^\s<>\[\]\"'()]*[^\s<>\[\]\"'(),.?]", $replacements, $ntokens);
|
| 469 |
while ($oldn < $ntokens) {
|
| 470 |
if($replacements[$oldn][0] == '!') {
|
| 471 |
$replacements[$oldn] = substr($replacements[$oldn], 1);
|
| 472 |
}
|
| 473 |
else {
|
| 474 |
$replacements[$oldn] = _wiki_link_URL($replacements[$oldn]);
|
| 475 |
}
|
| 476 |
$oldn++;
|
| 477 |
}
|
| 478 |
|
| 479 |
$tmpline = htmlspecialchars($tmpline);
|
| 480 |
|
| 481 |
// %%% are linebreaks
|
| 482 |
$tmpline = str_replace('%%%', '<br />', $tmpline);
|
| 483 |
// \\ are also linebreaks
|
| 484 |
$tmpline = str_replace('\\\\', '<br />', $tmpline);
|
| 485 |
|
| 486 |
// bold italics (old way)
|
| 487 |
$tmpline = preg_replace("|(''''')(.*?)(''''')|",
|
| 488 |
"<strong><em>\\2</em></strong>", $tmpline);
|
| 489 |
|
| 490 |
// bold (old way)
|
| 491 |
$tmpline = preg_replace("|(''')(.*?)(''')|",
|
| 492 |
"<strong>\\2</strong>", $tmpline);
|
| 493 |
|
| 494 |
// bold
|
| 495 |
$tmpline = preg_replace("|(__)(.*?)(__)|",
|
| 496 |
"<strong>\\2</strong>", $tmpline);
|
| 497 |
|
| 498 |
// italics
|
| 499 |
$tmpline = preg_replace("|('')(.*?)('')|",
|
| 500 |
"<em>\\2</em>", $tmpline);
|
| 501 |
|
| 502 |
|
| 503 |
/*
|
| 504 |
* unordered, ordered, and dictionary list (using TAB)
|
| 505 |
*/
|
| 506 |
|
| 507 |
if (preg_match("/(^\t+)(.*?)(:\t)(.*$)/", $tmpline, $matches)) {
|
| 508 |
// this is a dictionary list (<dl>) item
|
| 509 |
$numtabs = strlen($matches[1]);
|
| 510 |
$html .= _wiki_set_output_mode('dl', WIKI_NESTED_LEVEL, $numtabs);
|
| 511 |
$tmpline = '';
|
| 512 |
if (trim($matches[2])) {
|
| 513 |
$tmpline = '<dt>' . $matches[2];
|
| 514 |
}
|
| 515 |
$tmpline .= '<dd>' . $matches[4];
|
| 516 |
|
| 517 |
}
|
| 518 |
else if (preg_match("/(^\t+)(\*|\d+|#)/", $tmpline, $matches)) {
|
| 519 |
// this is part of a list (<ul>, <ol>)
|
| 520 |
$numtabs = strlen($matches[1]);
|
| 521 |
if ($matches[2] == '*') {
|
| 522 |
$listtag = 'ul';
|
| 523 |
}
|
| 524 |
else {
|
| 525 |
$listtag = 'ol'; // a rather tacit assumption. oh well.
|
| 526 |
}
|
| 527 |
$tmpline = preg_replace("/^(\t+)(\*|\d+|#)/", "", $tmpline);
|
| 528 |
$html .= _wiki_set_output_mode($listtag, WIKI_NESTED_LEVEL, $numtabs);
|
| 529 |
$html .= '<li>';
|
| 530 |
|
| 531 |
/*
|
| 532 |
* tabless markup for unordered, ordered, and dictionary lists
|
| 533 |
* ul/ol list types can be mixed, so we only look at the last
|
| 534 |
* character. Changes e.g. from "**#*" to "###*" go unnoticed.
|
| 535 |
* and wouldn\'t make a difference to the HTML layout anyway.
|
| 536 |
*/
|
| 537 |
|
| 538 |
// unordered lists <UL>: "*"
|
| 539 |
}
|
| 540 |
elseif (preg_match("/^([#*]*\*)[^#]/", $tmpline, $matches)) {
|
| 541 |
// this is part of an unordered list
|
| 542 |
$numtabs = strlen($matches[1]);
|
| 543 |
$tmpline = preg_replace("/^([#*]*\*)/", '', $tmpline);
|
| 544 |
$html .= _wiki_set_output_mode('ul', WIKI_NESTED_LEVEL, $numtabs);
|
| 545 |
$html .= '<li>';
|
| 546 |
|
| 547 |
// ordered lists <OL>: "#"
|
| 548 |
}
|
| 549 |
elseif (preg_match("/^([#*]*\#)/", $tmpline, $matches)) {
|
| 550 |
// this is part of an ordered list
|
| 551 |
$numtabs = strlen($matches[1]);
|
| 552 |
$tmpline = preg_replace("/^([#*]*\#)/", "", $tmpline);
|
| 553 |
$html .= _wiki_set_output_mode('ol', WIKI_NESTED_LEVEL, $numtabs);
|
| 554 |
$html .= '<li>';
|
| 555 |
|
| 556 |
// definition lists <DL>: ";text:text"
|
| 557 |
}
|
| 558 |
elseif (preg_match("/(^;+)(.*?):(.*$)/", $tmpline, $matches)) {
|
| 559 |
// this is a dictionary list item
|
| 560 |
$numtabs = strlen($matches[1]);
|
| 561 |
$html .= _wiki_set_output_mode('dl', WIKI_NESTED_LEVEL, $numtabs);
|
| 562 |
$tmpline = '';
|
| 563 |
|
| 564 |
if (trim($matches[2])) {
|
| 565 |
$tmpline = '<dt>' . $matches[2];
|
| 566 |
}
|
| 567 |
$tmpline .= '<dd>' . $matches[3];
|
| 568 |
|
| 569 |
// remaining modes: preformatted text, headings, normal text
|
| 570 |
|
| 571 |
}
|
| 572 |
/* elseif (preg_match("/^\s+/", $tmpline)) {
|
| 573 |
// this is preformatted text, i.e. <pre>
|
| 574 |
$html .= _wiki_set_output_mode('pre', WIKI_ZERO_LEVEL, 0);
|
| 575 |
|
| 576 |
}
|
| 577 |
*/
|
| 578 |
elseif (preg_match("/^(!{1,3})[^!]/", $tmpline, $whichheading)) {
|
| 579 |
// lines starting with !,!!,!!! are headings
|
| 580 |
if ($whichheading[1] == '!') {
|
| 581 |
$heading = 'h3';
|
| 582 |
}
|
| 583 |
elseif ($whichheading[1] == '!!') {
|
| 584 |
$heading = 'h2';
|
| 585 |
}
|
| 586 |
elseif ($whichheading[1] == '!!!') {
|
| 587 |
$heading = 'h1';
|
| 588 |
}
|
| 589 |
$tmpline = preg_replace("/^!+/", '', $tmpline);
|
| 590 |
$html .= _wiki_set_output_mode($heading, WIKI_ZERO_LEVEL, 0);
|
| 591 |
}
|
| 592 |
elseif (preg_match('/^-{4,}\s*(.*?)\s*$/', $tmpline, $matches)) {
|
| 593 |
// four or more dashes to <hr>
|
| 594 |
// <hr> can not be contained in a
|
| 595 |
$html .= _wiki_set_output_mode('', WIKI_ZERO_LEVEL, 0) . "<hr>\n";
|
| 596 |
if ( ($tmpline = $matches[1]) != '' ) {
|
| 597 |
$html .= _wiki_set_output_mode('p', WIKI_ZERO_LEVEL, 0);
|
| 598 |
}
|
| 599 |
}
|
| 600 |
elseif (preg_match('/^\|/', $tmpline, $matches)) {
|
| 601 |
// table!
|
| 602 |
if (!$istable) {
|
| 603 |
$istable = TRUE;
|
| 604 |
$html .= _wiki_set_output_mode('', WIKI_ZERO_LEVEL, 0);
|
| 605 |
// unfortunately, can't use _wiki_set_output_mode due to add'l params
|
| 606 |
$html .= "<table border=2 cellpadding=2 cellspacing=1>\n";
|
| 607 |
}
|
| 608 |
if (preg_match('/^\|\|/', $tmpline, $matches)) {
|
| 609 |
// first do heading row
|
| 610 |
$tmpline = preg_replace("/^\|\|\s*/", "<th>", $tmpline);
|
| 611 |
$tmpline = preg_replace("/\s*\|\|\s*/", "</th><th>", $tmpline);
|
| 612 |
$tmpline = "<tr>" . $tmpline . "</th></tr>";
|
| 613 |
}
|
| 614 |
else {
|
| 615 |
// do normal row
|
| 616 |
$tmpline = preg_replace("/^\|\s*/", "<td>", $tmpline);
|
| 617 |
$tmpline = preg_replace("/\s*\|\s*/", "</td><td>", $tmpline);
|
| 618 |
$tmpline = "<tr>" . $tmpline . "</td></tr>";
|
| 619 |
}
|
| 620 |
}
|
| 621 |
elseif ($ishtml) {
|
| 622 |
if ($closeflag) {
|
| 623 |
--$ishtml;
|
| 624 |
$closeflag = FALSE;
|
| 625 |
}
|
| 626 |
_wiki_set_output_mode("", WIKI_ZERO_LEVEL, 0);
|
| 627 |
}
|
| 628 |
else {
|
| 629 |
// it's ordinary output if nothing else
|
| 630 |
$html .= _wiki_set_output_mode('p', WIKI_ZERO_LEVEL, 0);
|
| 631 |
}
|
| 632 |
|
| 633 |
/*
|
| 634 |
* Replace tokens
|
| 635 |
*/
|
| 636 |
for ($i = 0; $i < $ntokens; $i++) {
|
| 637 |
$tmpline = str_replace(WIKI_FIELD_SEPARATOR.WIKI_FIELD_SEPARATOR.$i.WIKI_FIELD_SEPARATOR, $replacements[$i], $tmpline);
|
| 638 |
}
|
| 639 |
$html .= $tmpline . "\n";
|
| 640 |
|
| 641 |
/* look ahead one row to determine if we should close off the table
|
| 642 |
* doing it this way prevents having to disperse table closing
|
| 643 |
* in several different parts of this function
|
| 644 |
*/
|
| 645 |
$nextindex = $index+1;
|
| 646 |
if ($istable && !preg_match('/^\|/', $lines[$nextindex], $matches)) {
|
| 647 |
// turn table off
|
| 648 |
$istable = FALSE;
|
| 649 |
$html .= "</table><br />\n";
|
| 650 |
}
|
| 651 |
}
|
| 652 |
$html .= _wiki_set_output_mode('', WIKI_ZERO_LEVEL, 0);
|
| 653 |
|
| 654 |
return $html;
|
| 655 |
}
|
| 656 |
|
| 657 |
/**
|
| 658 |
* Implementation of hook_filter_tips().
|
| 659 |
*/
|
| 660 |
function wiki_filter_tips($delta = 0, $format = -1, $long = false) {
|
| 661 |
if ($long) {
|
| 662 |
// orig. from <http://phpwiki.sourceforge.net/phpwiki/TextFormattingRules>
|
| 663 |
// but has since been enhanced with other WikiText support.
|
| 664 |
$output = t('WikiText is converted to HTML according to the following formatting guidelines:
|
| 665 |
<h4>Paragraphs</h4>
|
| 666 |
<ul>
|
| 667 |
<li>Don\'t indent paragraphs</li>
|
| 668 |
<li>Words wrap and fill as needed</li>
|
| 669 |
<li>Use blank lines as separators</li>
|
| 670 |
<li>Four or more minus signs make a horizontal rule</li>
|
| 671 |
<li><em>%%%</em> or <em>\\\\</em> makes a linebreak (in headings and lists too)</li>
|
| 672 |
</ul>
|
| 673 |
<h4>Lists</h4>
|
| 674 |
<ul>
|
| 675 |
<li>asterisk for first level</li>
|
| 676 |
<ul>
|
| 677 |
<li>asterisk-asterisk for second level, etc.</li>
|
| 678 |
</ul>
|
| 679 |
<li>Use * for bullet lists, # for numbered lists (mix at will)</li>
|
| 680 |
<li>semicolon-term-colon-definition for definition lists:</li>
|
| 681 |
<dl>
|
| 682 |
<dt>term here</dt>
|
| 683 |
<dd>definition here, as in the <DL><DT><DD> list</dd>
|
| 684 |
</dl>
|
| 685 |
<li>One line for each item</li>
|
| 686 |
<li>Other leading whitespace signals preformatted text, changes font.</li>
|
| 687 |
</ul>
|
| 688 |
<h4>Headings</h4>
|
| 689 |
<ul>
|
| 690 |
<li>! at the start of a line makes a small heading</li>
|
| 691 |
<li>!! at the start of a line makes a medium heading</li>
|
| 692 |
<li>!!! at the start of a line makes a large heading</li>
|
| 693 |
</ul>
|
| 694 |
<h4>Fonts</h4>
|
| 695 |
<ul>
|
| 696 |
<li>Indent with one or more spaces to use a monospace font;</li>
|
| 697 |
<li>Or enclose within triple braces {{{ }}}, which may cross multiple lines:</li>
|
| 698 |
</ul>
|
| 699 |
<pre>This is in monospace</pre>
|
| 700 |
<p>This is not</p>
|
| 701 |
<h4>Indented Paragraphs</h4>
|
| 702 |
<ul>
|
| 703 |
<li>semicolon-colon -- works like <BLOCKQUOTE>, but is actually implemented as <strong>Term Definition</strong> above without the <em>term</em></li>
|
| 704 |
</ul>
|
| 705 |
<p><dl>
|
| 706 |
<dt></dt><dd>this is an indented block of text</dd>
|
| 707 |
</dl></p>
|
| 708 |
<h4>Emphasis</h4>
|
| 709 |
<ul>
|
| 710 |
<li>Use doubled single-quotes (\'\') for <em>emphasis</em></li>
|
| 711 |
<li>Use doubled underscores (__) for <strong>strong emphasis</strong></li>
|
| 712 |
<li>Mix them at will: <strong><em>very strong emphasis</em></strong></li>
|
| 713 |
<li><em>Emphasis</em> can be used <em>multiple</em> times within a line, but <em>cannot</em> cross line boundaries:
|
| 714 |
<p>\'\'this<br/>
|
| 715 |
will not work\'\'</p></li>
|
| 716 |
</ul>
|
| 717 |
<h4>References</h4>
|
| 718 |
<ul>
|
| 719 |
<li>Hyperlinks to other pages within the Wiki are made by placing the page name in square brackets: [<a href="this%20is%20a%20page%20link">this is a page link</a>]</li>
|
| 720 |
<li>Hyperlinks to external pages are done like this: [<a href="http://www.example.com">http://www.example.com</a>]</li>
|
| 721 |
<li>You can name the links by providing a name, a pipe/bar (|) and then the hyperlink or pagename: <br>[PhpWiki home page | <a href="http://phpwiki.sourceforge.net/">http://phpwiki.sourceforge.net/</a>]</li>
|
| 722 |
<li>You can suppress linking to old-style references and URIs by preceding the word with a \'!\', e.g. NotLinkedAsWikiName, http://not.linked.to/</li>'.
|
| 723 |
|
| 724 |
/*
|
| 725 |
<li>You can create footnotes by using [1], [2], [3], ... like this here <sup><a href="'. $_SERVER['REQUEST_URI'] .'#footnote-1" name="footrev-1-0">[1]</a></sup>. See footnote for counterpart. (If the [ is in the first column, it is a footnote <em>definition</em> rather than a footnote <em>reference</em> <sup><a href="'. $_SERVER['REQUEST_URI'] .'#footnote-1" name="footrev-1-1">[1]</a></sup>.)</li>
|
| 726 |
*/
|
| 727 |
|
| 728 |
'<li>Also, the old way of linking URLs is still supported: precede URLs with "http:", "ftp:" or "mailto:" to create links automatically as in: <a href="http://example.com/">http://example.com/</a></li>
|
| 729 |
<li>URLs ending with .png, .gif, or .jpg are inlined if in square brackets, by themselves</li>
|
| 730 |
</ul>
|
| 731 |
<h4>HTML Mark-Up Language</h4>
|
| 732 |
<ul>
|
| 733 |
<li>HTML will display as-is</li>
|
| 734 |
<li>< and > are themselves</li>
|
| 735 |
<li>Entities (e.g. &amp;) will not convert to characters</li>');
|
| 736 |
|
| 737 |
if (variable_get("wiki_filter_html", WIKI_FILTER_HTML_DISABLE) == WIKI_FILTER_HTML_ENABLE) {
|
| 738 |
$output .= t('<li>If you really must use HTML, the system administrator has enabled this feature. Start each line with a bar-greater-than (|>).<!--Note that this feature is disabled by default.--></li>');
|
| 739 |
}
|
| 740 |
|
| 741 |
$output .= t('</ul>
|
| 742 |
<h4>Content protection</h4>
|
| 743 |
<ul>
|
| 744 |
<li>To protect content as is (i.e., in a <pre></pre> block) without interpretation, enclose within triple braces {{{ }}}, which may cross multiple lines. Note that the content within the triple braces may still be interpreted by the browser in the same way <pre></pre> enclosed content is.</li>
|
| 745 |
</ul>
|
| 746 |
<h4>Table is supported</h4>
|
| 747 |
<ul>
|
| 748 |
<li>Start the line with single-bar (|) or double-bars (||) to create a table</li>
|
| 749 |
<li>One line per row, <strong>do not</strong> insert blank line, or the table ends</li>
|
| 750 |
<li>Double-bar separates header (<th></th>) cells</li>
|
| 751 |
<li>Single-bar separates normal table (<td></td>) cells</li>
|
| 752 |
<li><strong>Don\'t</strong> end a line with single or double bar; otherwise, a blank cell results</li>
|
| 753 |
<li>Example:<br\>
|
| 754 |
<pre>|| Heading 1 || Heading 2
|
| 755 |
| Cell a1 | Cell a2
|
| 756 |
| Cell b1 | Cell b2</pre>
|
| 757 |
Result:<br/>
|
| 758 |
<table border=2 cellpadding=2 cellspacing=1>
|
| 759 |
<tr><th>Heading 1</th><th>Heading 2</th></tr>
|
| 760 |
<tr><td>Cell a1</td><td>Cell a2</td></tr>
|
| 761 |
<tr><td>Cell b1</td><td>Cell b2</td></tr>
|
| 762 |
</table></li>
|
| 763 |
</ul>');
|
| 764 |
|
| 765 |
/*
|
| 766 |
<h4>More detail than you want to know</h4>
|
| 767 |
<p>Footnotes:</p>
|
| 768 |
<p><br/><a name="footnote-1" href="'. $_SERVER['REQUEST_URI'] .'#footrev-1-0" class="footnote-rev">[1]</a><a name="footnote-1" href="'. $_SERVER['REQUEST_URI'] .'#footrev-1-1" class="footnote-rev">+</a> By using [1] a second time (in the first column) the footnote itself is <em>defined</em>. You may refer to a footnote as many times as you want, but you may only define it once on the page. Note the the [1] in the footnote links back to the first reference, if there are multiple references there will be one or more plus symbols (+) after the [1] which will link to the other references. (References which come <em>after</em> the footnote <em>definition</em> will not be linked to.)</p>';
|
| 769 |
*/
|
| 770 |
|
| 771 |
return $output;
|
| 772 |
} else {
|
| 773 |
return t('WikiText is converted to HTML (supported WikiText formatting will show in the long tip format).');
|
| 774 |
}
|
| 775 |
}
|
| 776 |
|
| 777 |
?>
|