.
$el = $this->stack->cnt() % 2 == 0 ? 'dl' : 'dd';
$retvar .= "<$el>";
$this->stack->push($el);
}
$retvar .= StartTag($tag, $args) . "\n";
$this->stack->push($tag);
}
}
return $this->token($retvar);
}
/**
* Start new list item element.
*
* This closes any currently open list items at the specified level or deeper,
* then opens a new list item element.
*
* @param $list_type string Type of list element to open. This should
* be one of 'dl', 'ol', or 'ul'.
*
* @param $level integer Nesting depth for list item. Should be a positive integer.
*
* @param $defn_term string Definition term. Specifies the contents for the
* <dt> element. Only used if $list_type is 'dl'.
*
* @return string HTML
*/
function ListItem($list_type, $level, $defn_term = '')
{
$level = min($level, 10);
$retval = $this->SetHTMLMode($list_type, 2 * $level - 1);
if ($list_type == 'dl') {
$retval .= Element('dt', $defn_term);
$retval .= $this->SetHTMLMode('dd', 2 * $level);
}
else {
$retval .= $this->SetHTMLMode('li', 2 * $level);
}
return $retval;
}
/** Work horse and main loop.
*
* This function does the transform from wiki markup to HTML.
*
* Contains main-loop and calls transformer functions.
*
* @param $html string HTML header (if needed, otherwise '')
* (This string is prepended to the return value.)
*
* @param $content array Wiki markup as array of lines
*
* @return string HTML
*/
function do_transform($html, $content)
{
global $FieldSeparator;
$this->content = $content;
$this->replacements = array();
$this->user_data = array();
// Loop over all lines of the page and apply transformation rules
$numlines = count($this->content);
for ($lnum = 0; $lnum < $numlines; $lnum++)
{
$this->linenumber = $lnum;
$line = $this->content[$lnum];
// blank lines clear the current mode (to force new paragraph)
if (!strlen($line) || $line == "\r") {
$html .= $this->SetHTMLMode('', 0);
continue;
}
$this->mode_set = 0;
// main loop applying all registered functions
// tokenizers, markup, html mode, ...
// functions are executed in order of registering
for (reset($this->trfrm_func);
list($flags, $func, $regexp) = current($this->trfrm_func);
next($this->trfrm_func)) {
// if HTMLmode is already set then skip all following
// WT_MODE_MARKUP functions
if ($this->mode_set && ($flags & WT_MODE_MARKUP) != 0)
continue;
if (!empty($regexp) && !preg_match("/$regexp/", $line))
continue;
// call registered function
if (($flags & WT_TOKENIZER) != 0)
$line = $this->tokenize($line, $regexp, $func);
else
$line = $func($line, $this);
}
$html .= $line . "\n";
}
// close all tags
$html .= $this->SetHTMLMode('', 0);
return $this->untokenize($html);
}
// end do_transfrom()
// Register a new token.
function token($repl) {
global $FieldSeparator;
$tok = $FieldSeparator . sizeof($this->replacements) . $FieldSeparator;
$this->replacements[] = $repl;
return $tok;
}
// helper function which does actual tokenizing
function tokenize($str, $pattern, $func) {
// Find any strings in $str that match $pattern and
// store them in $orig, replacing them with tokens
// starting at number $ntokens - returns tokenized string
$new = '';
while (preg_match("/^(.*?)($pattern)/", $str, $matches)) {
$str = substr($str, strlen($matches[0]));
$new .= $matches[1] . $this->token($func($matches[2], $this));
}
return $new . $str;
}
function untokenize($line) {
global $FieldSeparator;
$chunks = explode ($FieldSeparator, "$line ");
$line = $chunks[0];
for ($i = 1; $i < count($chunks); $i += 2)
{
$tok = $chunks[$i];
$line .= $this->replacements[$tok] . $chunks[$i + 1];
}
return $line;
}
}
// end class WikiTransform
//////////////////////////////////////////////////////////
class WikiPageTransform
extends WikiTransform {
function WikiPageTransform() {
global $WikiNameRegexp, $AllowedProtocols, $InterWikiLinkRegexp;
$this->WikiTransform();
// register functions
// functions are applied in order of registering
$this->register(WT_SIMPLE_MARKUP, 'wtm_plugin_link');
$this->register(WT_MODE_MARKUP, 'wtm_plugin');
$this->register(WT_TOKENIZER, 'wtt_doublebrackets', '\[\[');
$this->register(WT_TOKENIZER, 'wtt_footnotes', '^\[\d+\]');
$this->register(WT_TOKENIZER, 'wtt_footnoterefs', '\[\d+\]');
$this->register(WT_TOKENIZER, 'wtt_bracketlinks', '\[.+?\]');
$this->register(WT_TOKENIZER, 'wtt_urls',
"!?\b($AllowedProtocols):[^\s<>\[\]\"'()]*[^\s<>\[\]\"'(),.?]");
if (function_exists('wtt_interwikilinks')) {
$this->register(WT_TOKENIZER, 'wtt_interwikilinks',
pcre_fix_posix_classes("!?(?register(WT_TOKENIZER, 'wtt_bumpylinks', "!?$WikiNameRegexp");
if (function_exists('wtm_table')) {
$this->register(WT_MODE_MARKUP, 'wtm_table', '^\|');
}
$this->register(WT_SIMPLE_MARKUP, 'wtm_htmlchars');
$this->register(WT_SIMPLE_MARKUP, 'wtm_linebreak');
$this->register(WT_SIMPLE_MARKUP, 'wtm_bold_italics');
$this->register(WT_MODE_MARKUP, 'wtm_list_ul');
$this->register(WT_MODE_MARKUP, 'wtm_list_ol');
$this->register(WT_MODE_MARKUP, 'wtm_list_dl');
$this->register(WT_MODE_MARKUP, 'wtm_preformatted');
$this->register(WT_MODE_MARKUP, 'wtm_headings');
$this->register(WT_MODE_MARKUP, 'wtm_hr');
$this->register(WT_MODE_MARKUP, 'wtm_paragraph');
}
};
function do_transform ($lines, $class = 'WikiPageTransform') {
if (is_string($lines))
$lines = preg_split('/[ \t\r]*\n/', trim($lines));
$trfm = new $class;
return $trfm->do_transform('', $lines);
}
class LinkTransform
extends WikiTransform {
function LinkTransform() {
global $WikiNameRegexp, $AllowedProtocols, $InterWikiLinkRegexp;
$this->WikiTransform();
// register functions
// functions are applied in order of registering
$this->register(WT_TOKENIZER, 'wtt_doublebrackets', '\[\[');
$this->register(WT_TOKENIZER, 'wtt_quotetoken', '\[\d+\]');
$this->register(WT_TOKENIZER, 'wtt_bracketlinks', '\[.+?\]');
$this->register(WT_TOKENIZER, 'wtt_urls',
"!?\b($AllowedProtocols):[^\s<>\[\]\"'()]*[^\s<>\[\]\"'(),.?]");
if (function_exists('wtt_interwikilinks')) {
$this->register(WT_TOKENIZER, 'wtt_interwikilinks',
pcre_fix_posix_classes("!?(?register(WT_TOKENIZER, 'wtt_bumpylinks', "!?$WikiNameRegexp");
$this->register(WT_SIMPLE_MARKUP, 'wtm_htmlchars');
}
};
/*
Requirements for functions registered to WikiTransform:
Signature: function wtm_xxxx($line, &$transform)
$line ... current line containing wiki markup
(Note: it may already contain HTML from other transform functions)
&$transform ... WikiTransform object -- public variables of this
object and their use see above.
Functions have to return $line (doesn't matter if modified or not)
All conversion should take place inside $line.
Tokenizer functions should use $transform->replacements to store
the replacement strings. Also, they have to keep track of
$transform->tokencounter. See functions below. Back substitution
of tokenized strings is done by do_transform().
*/
//////////////////////////////////////////////////////////
// Tokenizer functions
function wtt_doublebrackets($match, &$trfrm)
{
return '[';
}
function wtt_footnotes($match, &$trfrm)
{
// FIXME: should this set HTML mode?
$ftnt = trim(substr($match,1,-1)) + 0;
$fntext = "[$ftnt]";
$html = Element('br');
$fnlist = $trfrm->user_data['footnotes'][$ftnt];
if (!is_array($fnlist))
return $html . $fntext;
$trfrm->user_data['footnotes'][$ftnt] = 'footnote_seen';
while (list($k, $anchor) = each($fnlist))
{
$html .= Element("a", array("name" => "footnote-$ftnt",
"href" => "#$anchor",
"class" => "footnote-rev"),
$fntext);
$fntext = '+';
}
return $html;
}
function wtt_footnoterefs($match, &$trfrm)
{
$ftnt = trim(substr($match,1,-1)) + 0;
$footnote_definition_seen = false;
if (empty($trfrm->user_data['footnotes']))
$trfrm->user_data['footnotes'] = array();
if (empty($trfrm->user_data['footnotes'][$ftnt]))
$trfrm->user_data['footnotes'][$ftnt] = array();
else if (!is_array($trfrm->user_data['footnotes'][$ftnt]))
$footnote_definition_seen = true;
$args['href'] = "#footnote-$ftnt";
if (!$footnote_definition_seen)
{
$args['name'] = "footrev-$ftnt-" .
count($trfrm->user_data['footnotes'][$ftnt]);
$trfrm->user_data['footnotes'][$ftnt][] = $args['name'];
}
return Element('sup', array('class' => 'footnote'),
QElement("a", $args, "[$ftnt]"));
}
function wtt_bracketlinks($match, &$trfrm)
{
if (preg_match('/^\[\s*\]$/', $match)) {
return htmlspecialchars($match);
}
$link = ParseAndLink($match);
if (strstr($link['link'], "")) {
// FIXME: BIG HACK: see note in wtm_plugin.
return "" . $link['link'] . "";
}
return $link["link"];
}
// replace all URL's with tokens, so we don't confuse them
// with Wiki words later. Wiki words in URL's break things.
// URLs preceeded by a '!' are not linked
function wtt_urls($match, &$trfrm)
{
if ($match[0] == "!")
return htmlspecialchars(substr($match,1));
return LinkURL($match);
}
// Link Wiki words (BumpyText)
// Wikiwords preceeded by a '!' are not linked
function wtt_bumpylinks($match, &$trfrm)
{
global $dbi;
if ($match[0] == "!")
return htmlspecialchars(substr($match,1));
return LinkWikiWord($match);
}
// Just quote the token.
function wtt_quotetoken($match, &$trfrm)
{
return htmlspecialchars($match);
}
// end of tokenizer functions
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// basic simple markup functions
// escape HTML metachars
function wtm_htmlchars($line, &$transformer)
{
$line = str_replace('&', '&', $line);
$line = str_replace('>', '>', $line);
$line = str_replace('<', '<', $line);
return($line);
}
// %%% are linebreaks
function wtm_linebreak($line, &$transformer) {
return str_replace('%%%', Element('br'), $line);
}
// bold and italics
function wtm_bold_italics($line, &$transformer) {
$line = preg_replace('|(__)(.*?)(__)|', '\2', $line);
$line = preg_replace("|('')(.*?)('')|", '\2', $line);
return $line;
}
//////////////////////////////////////////////////////////
// some tokens to be replaced by (dynamic) content
// FIXME: some plugins are in-line (maybe?) and some are block level.
// Here we treat them all as inline, which will probably
// generate some minorly invalid HTML in some cases.
//
function wtm_plugin_link($line, &$transformer) {
// FIXME: is this good syntax?
global $dbi, $request; // FIXME: make these non-global?
if (preg_match('/^(.*?)(<\?plugin-link\s+.*?\?>)(.*)$/', $line, $m)) {
list(, $prematch, $plugin_pi, $postmatch) = $m;
$loader = new WikiPluginLoader;
$html = $loader->expandPI($plugin_pi, $dbi, $request);
$line = $prematch . $transformer->token($html) . $postmatch;
}
return $line;
}
function wtm_plugin($line, &$transformer) {
// FIXME: is this good syntax?
global $dbi, $request; // FIXME: make these non-global?
if (preg_match('/^<\?plugin(-form)?\s.*\?>\s*$/', $line)) {
$loader = new WikiPluginLoader;
$html = $loader->expandPI($line, $dbi, $request);
$line = $transformer->SetHTMLMode('', 0) . $transformer->token($html);
}
return $line;
}
//////////////////////////////////////////////////////////
// mode markup functions
// tabless markup for unordered, ordered, and dictionary lists
// ul/ol list types can be mixed, so we only look at the last
// character. Changes e.g. from "**#*" to "###*" go unnoticed.
// and wouldn't make a difference to the HTML layout anyway.
// unordered lists
: "*"
// has to be registereed before list OL
function wtm_list_ul($line, &$trfrm) {
if (preg_match("/^([#*;]*\*)[^#]/", $line, $matches)) {
$numtabs = strlen($matches[1]);
$line = preg_replace("/^([#*]*\*)/", '', $line);
$line = $trfrm->ListItem('ul', $numtabs) . $line;
}
return $line;
}
// ordered lists : "#"
function wtm_list_ol($line, &$trfrm) {
if (preg_match("/^([#*;]*\#)/", $line, $matches)) {
$numtabs = strlen($matches[1]);
$line = preg_replace("/^([#*]*\#)/", "", $line);
$line = $trfrm->ListItem('ol', $numtabs) . $line;
}
return $line;
}
// definition lists : ";text:text"
function wtm_list_dl($line, &$trfrm) {
if (preg_match("/^([#*;]*;)(.*?):(.*$)/", $line, $matches)) {
$numtabs = strlen($matches[1]);
$line = $trfrm->ListItem('dl', $numtabs, $matches[2]) . $matches[3];
}
return $line;
}
// mode: preformatted text, i.e.
function wtm_preformatted($line, &$trfrm) {
if (preg_match("/^\s+/", $line)) {
$line = $trfrm->SetHTMLMode('pre') . $line;
}
return $line;
}
// mode: headings, i.e. , ,
// lines starting with !,!!,!!! are headings
// Patch from steph/tara :
// use , , since is page title.
function wtm_headings($line, &$trfrm) {
if (preg_match("/^(!{1,3})[^!]/", $line, $whichheading)) {
if($whichheading[1] == '!') $heading = 'h4';
elseif($whichheading[1] == '!!') $heading = 'h3';
elseif($whichheading[1] == '!!!') $heading = 'h2';
$line = preg_replace("/^!+/", '', $line);
$line = $trfrm->SetHTMLMode($heading) . $line;
}
return $line;
}
// markup for tables
function wtm_table($line, &$trfrm)
{
$row = '';
while (preg_match('/^(\|+)(v*)([<>^]?)([^|]*)/', $line, $m))
{
$line = substr($line, strlen($m[0]));
$td = array();
if (strlen($m[1]) > 1)
$td['colspan'] = strlen($m[1]);
if (strlen($m[2]) > 0)
$td['rowspan'] = strlen($m[2]) + 1;
if ($m[3] == '^')
$td['align'] = 'center';
else if ($m[3] == '>')
$td['align'] = 'right';
else
$td['align'] = 'left';
$row .= $trfrm->token(StartTag('td', $td) . " ");
$row .= trim($m[4]);
$row .= $trfrm->token(" ");
}
assert(empty($line));
$row = $trfrm->token("") . $row . $trfrm->token("
");
return $trfrm->SetHTMLMode(array('table',
array(//'align' => 'left',
'cellpadding' => 1,
'cellspacing' => 1,
'border' => 1))) .
$row;
}
// four or more dashes to
// Note this is of type WT_MODE_MARKUP becuase
's aren't
// allowed within
's. (e.g. "
" is not valid HTML.)
function wtm_hr($line, &$trfrm) {
if (preg_match('/^-{4,}(.*)$/', $line, $m)) {
$line = $trfrm->SetHTMLMode('', 0) . Element('hr');
if ($m[1])
$line .= $trfrm->SetHTMLMode('p') . $m[1];
}
return $line;
}
// default mode: simple text paragraph
function wtm_paragraph($line, &$trfrm) {
$line = $trfrm->SetHTMLMode('p') . $line;
return $line;
}
// (c-file-style: "gnu")
// Local Variables:
// mode: php
// tab-width: 8
// c-basic-offset: 4
// c-hanging-comment-ender-p: nil
// indent-tabs-mode: nil
// End:
?>