<?php
// PukiWiki - Yet another WikiWikiWeb clone
-// $Id: convert_html.php,v 1.6 2005/01/16 12:20:57 henoheno Exp $
+// convert_html.php
+// Copyright
+// 2002-2016 PukiWiki Development Team
+// 2001-2002 Originally written by yu-ji
+// License: GPL v2 or (at your option) any later version
//
// function 'convert_html()', wiki text parser
// and related classes-and-functions
if (! is_array($lines)) $lines = explode("\n", $lines);
- $body = & new Body(++$contents_id);
+ $body = new Body(++$contents_id);
$body->parse($lines);
return $body->toString();
}
-// ¥Ö¥í¥Ã¥¯Í×ÁÇ
+// Block elements
class Element
{
- var $parent; // ¿ÆÍ×ÁÇ
- var $last; // ¼¡¤ËÍ×ÁǤòÁÞÆþ¤¹¤ëÀè
- var $elements; // Í×ÁǤÎÇÛÎó
+ var $parent;
+ var $elements; // References of childs
+ var $last; // Insert new one at the back of the $last
function Element()
{
+ $this->__construct();
+ }
+ function __construct()
+ {
$this->elements = array();
$this->last = & $this;
}
}
}
+// Returns inline-related object
function & Factory_Inline($text)
{
+ // Check the first letter of the line
if (substr($text, 0, 1) == '~') {
- // ¹ÔƬ '~' ¡£¥Ñ¥é¥°¥é¥Õ³«»Ï
return new Paragraph(' ' . substr($text, 1));
} else {
return new Inline($text);
function & Factory_Div(& $root, $text)
{
- if (! preg_match('/^\#([^\(]+)(?:\((.*)\))?/', $text, $out) ||
- ! exist_plugin_convert($out[1])) {
- return new Paragraph($text);
+ $matches = array();
+
+ // Seems block plugin?
+ if (PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK) {
+ // Usual code
+ if (preg_match('/^\#([^\(]+)(?:\((.*)\))?/', $text, $matches) &&
+ exist_plugin_convert($matches[1])) {
+ return new Div($matches);
+ }
} else {
- return new Div($out);
+ // Hack code
+ if(preg_match('/^#([^\(\{]+)(?:\(([^\r]*)\))?(\{*)/', $text, $matches) &&
+ exist_plugin_convert($matches[1])) {
+ $len = strlen($matches[3]);
+ $body = array();
+ if ($len == 0) {
+ return new Div($matches); // Seems legacy block plugin
+ } else if (preg_match('/\{{' . $len . '}\s*\r(.*)\r\}{' . $len . '}/', $text, $body)) {
+ $matches[2] .= "\r" . $body[1] . "\r";
+ return new Div($matches); // Seems multiline-enabled block plugin
+ }
+ }
}
+
+ return new Paragraph($text);
}
-// ¥¤¥ó¥é¥¤¥óÍ×ÁÇ
+// Inline elements
class Inline extends Element
{
function Inline($text)
{
- parent::Element();
+ $this->__construct($text);
+ }
+ function __construct($text)
+ {
+ parent::__construct();
$this->elements[] = trim((substr($text, 0, 1) == "\n") ?
$text : make_link($text));
}
function & toPara($class = '')
{
- $obj = & new Paragraph('', $class);
+ $obj = new Paragraph('', $class);
$obj->insert($this);
return $obj;
}
function Paragraph($text, $param = '')
{
- parent::Element();
+ $this->__construct($text, $param);
+ }
+ function __construct($text, $param = '')
+ {
+ parent::__construct();
$this->param = $param;
if ($text == '') return;
function Heading(& $root, $text)
{
- parent::Element();
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
+ parent::__construct();
$this->level = min(3, strspn($text, '*'));
list($text, $this->msg_top, $this->id) = $root->getAnchor($text, $this->level);
{
function HRule(& $root, $text)
{
- parent::Element();
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
+ parent::__construct();
}
function canContain(& $obj)
}
}
+// Lists (UL, OL, DL)
class ListContainer extends Element
{
var $tag;
var $tag2;
var $level;
var $style;
- var $margin;
- var $left_margin;
function ListContainer($tag, $tag2, $head, $text)
{
- parent::Element();
-
- //¥Þ¡¼¥¸¥ó¤ò¼èÆÀ
- $var_margin = '_' . $tag . '_margin';
- $var_left_margin = '_' . $tag . '_left_margin';
-
- global $$var_margin, $$var_left_margin;
-
- $this->margin = $$var_margin;
- $this->left_margin = $$var_left_margin;
+ $this->__construct($tag, $tag2, $head, $text);
+ }
+ function __construct($tag, $tag2, $head, $text)
+ {
+ parent::__construct();
- //½é´ü²½
$this->tag = $tag;
$this->tag2 = $tag2;
$this->level = min(3, strspn($text, $head));
function setParent(& $parent)
{
- global $_list_pad_str;
-
parent::setParent($parent);
$step = $this->level;
if (isset($parent->parent) && is_a($parent->parent, 'ListContainer'))
$step -= $parent->parent->level;
- $margin = $this->margin * $step;
- if ($step == $this->level)
- $margin += $this->left_margin;
-
- $this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
+ $this->style = sprintf(pkwk_list_attrs_template(), $this->level, $step);
}
function & insert(& $obj)
if (! is_a($obj, get_class($this)))
return $this->last = & $this->last->insert($obj);
- // ¹ÔƬʸ»ú¤Î¤ß¤Î»ØÄê»þ¤ÏUL/OL¥Ö¥í¥Ã¥¯¤òæ½Ð
- // BugTrack/524
+ // Break if no elements found (BugTrack/524)
if (count($obj->elements) == 1 && empty($obj->elements[0]->elements))
- return $this->last->parent; // up to ListElement.
+ return $this->last->parent; // up to ListElement
- // Move elements.
+ // Move elements
foreach(array_keys($obj->elements) as $key)
parent::insert($obj->elements[$key]);
{
function ListElement($level, $head)
{
- parent::Element();
+ $this->__construct($level, $head);
+ }
+ function __construct($level, $head)
+ {
+ parent::__construct();
$this->level = $level;
$this->head = $head;
}
{
function UList(& $root, $text)
{
- parent::ListContainer('ul', 'li', '-', $text);
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
+ parent::__construct('ul', 'li', '-', $text);
}
}
{
function OList(& $root, $text)
{
- parent::ListContainer('ol', 'li', '+', $text);
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
+ parent::__construct('ol', 'li', '+', $text);
}
}
{
function DList($out)
{
- parent::ListContainer('dl', 'dt', ':', $out[0]);
+ $this->__construct($out);
+ }
+ function __construct($out)
+ {
+ parent::__construct('dl', 'dt', ':', $out[0]);
$this->last = & Element::insert(new ListElement($this->level, 'dd'));
if ($out[1] != '')
$this->last = & $this->last->insert(Factory_Inline($out[1]));
function BQuote(& $root, $text)
{
- parent::Element();
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
+ parent::__construct();
$head = substr($text, 0, 1);
$this->level = min(3, strspn($text, $head));
function TableCell($text, $is_template = FALSE)
{
- parent::Element();
+ $this->__construct($text, $is_template);
+ }
+ function __construct($text, $is_template = FALSE)
+ {
+ parent::__construct();
$this->style = $matches = array();
while (preg_match('/^(?:(LEFT|CENTER|RIGHT)|(BG)?COLOR\(([#\w]+)\)|SIZE\((\d+)\)):(.*)$/',
$text = $matches[5];
} else if ($matches[3]) {
$name = $matches[2] ? 'background-color' : 'color';
- $this->style[$name] = $name . ':' . htmlspecialchars($matches[3]) . ';';
+ $this->style[$name] = $name . ':' . htmlsc($matches[3]) . ';';
$text = $matches[5];
} else if ($matches[4]) {
- $this->style['size'] = 'font-size:' . htmlspecialchars($matches[4]) . 'px;';
+ $this->style['size'] = 'font-size:' . htmlsc($matches[4]) . 'px;';
$text = $matches[5];
}
}
}
if ($text != '' && $text{0} == '#') {
- // ¥»¥ëÆâÍƤ¬'#'¤Ç»Ï¤Þ¤ë¤È¤¤ÏDiv¥¯¥é¥¹¤òÄ̤·¤Æ¤ß¤ë
+ // Try using Div class for this $text
$obj = & Factory_Div($this, $text);
if (is_a($obj, 'Paragraph'))
$obj = & $obj->elements[0];
function Table($out)
{
- parent::Element();
+ $this->__construct($out);
+ }
+ function __construct($out)
+ {
+ parent::__construct();
$cells = explode('|', $out[1]);
$this->col = count($cells);
$is_template = ($this->type == 'c');
$row = array();
foreach ($cells as $cell)
- $row[] = & new TableCell($cell, $is_template);
+ $row[] = new TableCell($cell, $is_template);
$this->elements[] = $row;
}
{
static $parts = array('h'=>'thead', 'f'=>'tfoot', ''=>'tbody');
- // rowspan¤òÀßÄê(²¼¤«¤é¾å¤Ø)
+ // Set rowspan (from bottom, to top)
for ($ncol = 0; $ncol < $this->col; $ncol++) {
$rowspan = 1;
foreach (array_reverse(array_keys($this->elements)) as $nrow) {
continue;
}
$row[$ncol]->rowspan = $rowspan;
- while (--$rowspan) // ¹Ô¼ïÊ̤ò·Ñ¾µ¤¹¤ë
+ // Inherits row type
+ while (--$rowspan)
$this->types[$nrow + $rowspan] = $this->types[$nrow];
$rowspan = 1;
}
}
- // colspan,style¤òÀßÄê
+ // Set colspan and style
$stylerow = NULL;
foreach (array_keys($this->elements) as $nrow) {
$row = & $this->elements[$nrow];
$row[$ncol]->colspan = $colspan;
if ($stylerow !== NULL) {
$row[$ncol]->setStyle($stylerow[$ncol]->style);
- while (--$colspan) // Îó¥¹¥¿¥¤¥ë¤ò·Ñ¾µ¤¹¤ë
+ // Inherits column style
+ while (--$colspan)
$row[$ncol - $colspan]->setStyle($stylerow[$ncol]->style);
}
$colspan = 1;
}
}
- // ¥Æ¥¥¹¥È²½
+ // toString
$string = '';
foreach ($parts as $type => $part)
{
$row_string = '';
foreach (array_keys($row) as $ncol)
$row_string .= $row[$ncol]->toString();
- $part_string .= $this->wrap($row_string, 'tr');
+ $part_string .= $this->wrap($row_string, 'tr') . "\n";
}
$string .= $this->wrap($part_string, $part);
}
}
}
-// , title1 , title2 , title3
-// , cell1 , cell2 , cell3
-// , cell4 , cell5 , cell6
+// , cell1 , cell2 , cell3
+// , cell4 , cell5 , cell6
+// , cell7 , right,==
+// ,left ,==, cell8
class YTable extends Element
{
- var $col;
-
- function YTable($_value)
- {
- parent::Element();
-
- $align = $value = $matches = array();
- foreach($_value as $val) {
- if (preg_match('/^(\s+)?(.+?)(\s+)?$/', $val, $matches)) {
- $align[] =($matches[1] != '') ?
- ((isset($matches[3]) && $matches[3] != '') ?
- ' style="text-align:center"' :
- ' style="text-align:right"'
- ) : '';
- $value[] = $matches[2];
+ var $col; // Number of columns
+
+ function YTable($row = array('cell1 ', ' cell2 ', ' cell3'))
+ {
+ $this->__construct($row);
+ }
+ // TODO: Seems unable to show literal '==' without tricks.
+ // But it will be imcompatible.
+ // TODO: Why toString() or toXHTML() here
+ function __construct($row = array('cell1 ', ' cell2 ', ' cell3'))
+ {
+ parent::__construct();
+
+ $str = array();
+ $col = count($row);
+
+ $matches = $_value = $_align = array();
+ foreach($row as $cell) {
+ if (preg_match('/^(\s+)?(.+?)(\s+)?$/', $cell, $matches)) {
+ if ($matches[2] == '==') {
+ // Colspan
+ $_value[] = FALSE;
+ $_align[] = FALSE;
+ } else {
+ $_value[] = $matches[2];
+ if ($matches[1] == '') {
+ $_align[] = ''; // left
+ } else if (isset($matches[3])) {
+ $_align[] = 'center';
+ } else {
+ $_align[] = 'right';
+ }
+ }
} else {
- $align[] = '';
- $value[] = $val;
+ $_value[] = $cell;
+ $_align[] = '';
}
}
- $this->col = count($value);
- $colspan = array();
- foreach ($value as $val)
- $colspan[] = ($val == '==') ? 0 : 1;
- $str = '';
- $count = count($value);
- for ($i = 0; $i < $count; $i++) {
- if ($colspan[$i]) {
- while ($i + $colspan[$i] < $count && $value[$i + $colspan[$i]] == '==')
- $colspan[$i]++;
- $colspan[$i] = ($colspan[$i] > 1) ? ' colspan="' . $colspan[$i] . '"' : '';
- $str .= '<td class="style_td"' . $align[$i] . $colspan[$i] . '>' . make_link($value[$i]) . '</td>';
- }
+
+ for ($i = 0; $i < $col; $i++) {
+ if ($_value[$i] === FALSE) continue;
+ $colspan = 1;
+ while (isset($_value[$i + $colspan]) && $_value[$i + $colspan] === FALSE) ++$colspan;
+ $colspan = ($colspan > 1) ? ' colspan="' . $colspan . '"' : '';
+ $align = $_align[$i] ? ' style="text-align:' . $_align[$i] . '"' : '';
+ $str[] = '<td class="style_td"' . $align . $colspan . '>';
+ $str[] = make_link($_value[$i]);
+ $str[] = '</td>';
+ unset($_value[$i], $_align[$i]);
}
- $this->elements[] = $str;
+
+ $this->col = $col;
+ $this->elements[] = implode('', $str);
}
function canContain(& $obj)
function toString()
{
$rows = '';
- foreach ($this->elements as $str)
+ foreach ($this->elements as $str) {
$rows .= "\n" . '<tr class="style_tr">' . $str . '</tr>' . "\n";
+ }
$rows = $this->wrap($rows, 'table', ' class="style_table" cellspacing="1" border="0"');
return $this->wrap($rows, 'div', ' class="ie5"');
}
{
function Pre(& $root, $text)
{
+ $this->__construct($root, $text);
+ }
+ function __construct(& $root, $text)
+ {
global $preformat_ltrim;
- parent::Element();
- $this->elements[] = htmlspecialchars(
+ parent::__construct();
+ $this->elements[] = htmlsc(
(! $preformat_ltrim || $text == '' || $text{0} != ' ') ? $text : substr($text, 1));
}
}
}
-// #someting(started with '#')
+// Block plugin: #something (started with '#')
class Div extends Element
{
var $name;
function Div($out)
{
- parent::Element();
+ $this->__construct($out);
+ }
+ function __construct($out)
+ {
+ parent::__construct();
list(, $this->name, $this->param) = array_pad($out, 3, '');
}
function toString()
{
+ // Call #plugin
return do_plugin_convert($this->name, $this->param);
}
}
function Align($align)
{
- parent::Element();
+ $this->__construct($align);
+ }
+ function __construct($align)
+ {
+ parent::__construct();
$this->align = $align;
}
function Body($id)
{
+ $this->__construct($id);
+ }
+ function __construct($id)
+ {
$this->id = $id;
- $this->contents = & new Element();
+ $this->contents = new Element();
$this->contents_last = & $this->contents;
- parent::Element();
+ parent::__construct();
}
function parse(& $lines)
$line = $matches[2];
}
- $line = preg_replace("/[\r\n]*$/", '', $line);
+ $line = rtrim($line, "\r\n");
// Empty
if ($line == '') {
continue;
}
+ // Multiline-enabled block plugin
+ if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK &&
+ preg_match('/^#[^{]+(\{\{+)\s*$/', $line, $matches)) {
+ $len = strlen($matches[1]);
+ $line .= "\r"; // Delimiter
+ while (! empty($lines)) {
+ $next_line = preg_replace("/[\r\n]*$/", '', array_shift($lines));
+ if (preg_match('/\}{' . $len . '}/', $next_line)) {
+ $line .= $next_line;
+ break;
+ } else {
+ $line .= $next_line .= "\r"; // Delimiter
+ }
+ }
+ }
+
// The first character
$head = $line{0};
{
global $top, $_symbol_anchor;
+ // Heading id (auto-generated)
+ $autoid = 'content_' . $this->id . '_' . $this->count;
+ $this->count++;
+
+ // Heading id (specified by users)
$id = make_heading($text, FALSE); // Cut fixed-anchor from $text
- $anchor = ($id == '') ? '' : ' &aname(' . $id . ',super,full){' . $_symbol_anchor . '};';
+ if ($id == '') {
+ // Not specified
+ $id = & $autoid;
+ $anchor = '';
+ } else {
+ $anchor = ' &aname(' . $id . ',super,full){' . $_symbol_anchor . '};';
+ }
$text = ' ' . $text;
- $id = 'content_' . $this->id . '_' . $this->count;
- $this->count++;
+
+ // Add 'page contents' link to its heading
$this->contents_last = & $this->contents_last->add(new Contents_UList($text, $level, $id));
- return array($text . $anchor, $this->count > 1 ? "\n" . $top : '', $id);
+ // Add heding
+ return array($text . $anchor, $this->count > 1 ? "\n" . $top : '', $autoid);
}
function & insert(& $obj)
$text = parent::toString();
// #contents
- $text = preg_replace_callback('/(<p[^>]*>)<del>#contents<\/del>(\s*)(<\/p>)/',
+ $text = preg_replace_callback('/<#_contents_>/',
array(& $this, 'replace_contents'), $text);
- // ´ØÏ¢¤¹¤ë¥Ú¡¼¥¸
- // <p>¤Î¤È¤¤Ï¹ÔƬ¤«¤é¡¢<del>¤Î¤È¤¤Ï¾¤ÎÍ×ÁǤλÒÍ×ÁǤȤ·¤Æ¸ºß
- $text = preg_replace_callback('/(<p[^>]*>)<del>#related<\/del>(\s*)(<\/p>)/',
- array(& $this, 'replace_related'), $text);
- $text = preg_replace('/<del>#related<\/del>/', make_related($vars['page'], 'del'), $text);
return $text . "\n";
}
'<a id="contents_' . $this->id . '"></a>' . "\n" .
$this->contents->toString() . "\n" .
'</div>' . "\n";
- array_shift($arr);
- return ($arr[1] != '') ? $contents . join('', $arr) : $contents;
- }
-
- function replace_related($arr)
- {
- global $vars;
- static $related = NULL;
-
- if (is_null($related)) $related = make_related($vars['page'], 'p');
- array_shift($arr);
- return ($arr[1] != '') ? $related . join('', $arr) : $related;
+ return $contents;
}
}
{
function Contents_UList($text, $level, $id)
{
- // ¥Æ¥¥¹¥È¤Î¥ê¥Õ¥©¡¼¥à
- // ¹ÔƬ\n¤ÇÀ°·ÁºÑ¤ß¤òɽ¤¹ ... X(
+ $this->__construct($text, $level, $id);
+ }
+ function __construct($text, $level, $id)
+ {
+ // Reformatting $text
+ // A line started with "\n" means "preformatted" ... X(
make_heading($text);
$text = "\n" . '<a href="#' . $id . '">' . $text . '</a>' . "\n";
- parent::ListContainer('ul', 'li', '-', str_repeat('-', $level));
+ parent::__construct('ul', 'li', '-', str_repeat('-', $level));
$this->insert(Factory_Inline($text));
}
function setParent(& $parent)
{
- global $_list_pad_str;
-
parent::setParent($parent);
$step = $this->level;
- $margin = $this->left_margin;
if (isset($parent->parent) && is_a($parent->parent, 'ListContainer')) {
$step -= $parent->parent->level;
- $margin = 0;
}
- $margin += $this->margin * ($step == $this->level ? 1 : $step);
- $this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
+ $indent_level = ($step == $this->level ? 1 : $step);
+ $this->style = sprintf(pkwk_list_attrs_template(), $this->level, $indent_level);
}
}
-?>