#topicpath

convert_html.php 1ファイルのみです

 <?php
 // PukiWiki - Yet another WikiWikiWeb clone
 // $Id: convert_html.php,v 1.16 2005/07/19 15:38:35 henoheno Exp $
 // Copyright (C)
 //   2002-2005 PukiWiki Developers 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
 
 function convert_html($lines)
 {
 	global $vars, $digest;
 	static $contents_id = 0;
 
 	// Set digest
 	$digest = md5(join('', get_source($vars['page'])));
 
 	if (! is_array($lines)) $lines = explode("\n", $lines);
 
 	$body = & new Body(++$contents_id);
 	$body->parse($lines);
 
 	return $body->toString();
 }
 
 // ブロック要素
 class Element
 {
 	var $elements = array(); // 要素の配列
 
 	function add($tree)
 	{
 		while (! empty($tree)) {
 			if ($tree[0]->canContain($this))
 				return $this->connect($tree);
 			array_shift($tree);
 		}
 		die('oops');
 	}
 
 	function connect($tree)
 	{
 		$tree[0]->elements[] = & $this;
 		return array_merge(array(& $this), $tree);
 	}
 
 	function canContain($obj)
 	{
 		return TRUE;
 	}
 
 	function wrap($string, $tag, $param = '')
 	{
 		return $string == '' ? '' :
 			'<' . $tag . $param . '>' . $string . '</' . $tag . '>';
 	}
 
 	function toString()
 	{
 		$ret = array();
 		foreach (array_keys($this->elements) as $key)
 			$ret[] = $this->elements[$key]->toString();
 		return join("\n", $ret);
 	}
 
 	function dump($indent = 0)
 	{
 		$ret = str_repeat(' ', $indent) . get_class($this) . "\n";
 		$indent += 2;
 		foreach (array_keys($this->elements) as $key) {
 			$ret .= is_object($this->elements[$key]) ?
 				$this->elements[$key]->dump($indent) : '';
 				//str_repeat(' ', $indent) . $this->elements[$key] . "\n";
 		}
 		return $ret;
 	}
 }
 
 function & Factory_Inline($text)
 {
 	if (substr($text, 0, 1) == '~') {
 		// 行頭 '~' 。パラグラフ開始
 		return new Paragraph(' ' . substr($text, 1));
 	} else {
 		return new Inline($text);
 	}
 }
 
 function Factory_DList($tree, $text)
 {
 	$out = explode('|', ltrim($text), 2);
 	if (count($out) < 2) {
 		$obj = Factory_Inline($text);
 		return $obj->add($tree);
 	} else {
 		$level = min(3, strspn($out[0], ':'));
 		$title = new DTitle($out[0], $level);
 		$data = new DData($out[1], $level);
 		return $data->add($title->add($tree));
 	}
 }
 
 // '|'-separated table
 function Factory_Table($tree, $text)
 {
 	if (! preg_match('/^\|(.+)\|([hHfFcC]?)$/', $text, $out)) {
 		$obj = Factory_Inline($text);
 	} else {
 		$obj = new Table($out);
 	}
 	return $obj->add($tree);
 }
 
 // Comma-separated table
 function Factory_YTable($tree, $text)
 {
 	if ($text == ',') {
 		$obj = Factory_Inline($text);
 	} else {
 		$obj = new YTable(csv_explode(',', substr($text, 1)));
 	}
 	return $obj->add($tree);
 }
 
 function Factory_Div($tree, $text)
 {
 	$matches = array();
 
 	// Seems block plugin?
 	if (PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK) {
 		// Usual code
 		if (preg_match('/^\#([^\(]+)(?:\((.*)\))?/', $text, $matches) &&
 		    exist_plugin_convert($matches[1])) {
 			$obj = new Div($matches);
 		} else {
 			$obj = new Paragraph($text);
 		}
 	} else {
 		// Hack code
 		if(preg_match('/^#([^\(\{]+)(?:\(([^\r]*)\))?(\{*)/', $text, $matches) &&
 		   exist_plugin_convert($matches[1])) {
 			$len  = strlen($matches[3]);
 			$body = array();
 			if ($len == 0) {
 				$obj = new Div($matches); // Seems legacy block plugin
 			} else if (preg_match('/\{{' . $len . '}\s*\r(.*)\r\}{' . $len . '}/', $text, $body)) { 
 				$matches[2] .= "\r" . $body[1] . "\r";
 				$obj = new Div($matches); // Seems multiline-enabled block plugin
 			}
 		} else {
 			$obj = new Paragraph($text);
 		}
 	}
 	return $obj->add($tree);
 }
 
 // インライン要素
 class Inline extends Element
 {
 	function Inline($text)
 	{
 		$this->elements[] = $text ? trim(make_link($text)) : '';
 	}
 
 	function connect($tree)
 	{
 		if (is_a($tree[0], 'Inline')) {
 			$tree[0]->elements[] = $this->elements[0];
 			return $tree;
 		}
 		if (is_a($tree[0], 'Body')) {
 			$obj = new Paragraph('');
 			$tree = $obj->connect($tree);
 		}
 		return parent::connect($tree);
 	}
 
 	function canContain($obj)
 	{
 		return is_a($obj, 'Inline');
 	}
 
 	function toString()
 	{
 		global $line_break;
 		return join(($line_break ? '<br />' . "\n" : "\n"), $this->elements);
 	}
 }
 
 // Paragraph: blank-line-separated sentences
 class Paragraph extends Element
 {
 	var $param;
 
 	function Paragraph($text, $param = '')
 	{
 		$this->param = $param;
 		if ($text == '') return;
 
 		if (substr($text, 0, 1) == '~')
 			$text = ' ' . substr($text, 1);
 
 		$this->elements[] = new Inline($text);
 	}
 
 	function connect($tree)
 	{
 		$tree[0]->elements[] = & $this;
 		return empty($this->elements) ?
 			array_merge(array(& $this), $tree) :
 			array_merge(array(& $this->elements[0], & $this), $tree);
 	}
 
 	function canContain($obj)
 	{
 		return is_a($obj, 'Inline');
 	}
 
 	function toString()
 	{
 		return $this->wrap(parent::toString(), 'p', $this->param);
 	}
 }
 
 // * Heading1
 // ** Heading2
 // *** Heading3
 class Heading extends Element
 {
 	var $level;
 	var $id;
 	var $msg_top;
 
 	function Heading(& $root, $text)
 	{
 		$this->level = min(3, strspn($text, '*'));
 		list($text, $this->msg_top, $this->id) = $root->getAnchor($text, $this->level);
 		$this->elements[] = new Inline($text);
 		$this->level++; // h2,h3,h4
 	}
 
 	function connect($tree)
 	{
 		$tree = array_slice($tree, -1);
 		$tree[0]->elements[] = & $this;
 		return $tree;
 	}
 
 	function canContain(& $obj)
 	{
 		return FALSE;
 	}
 
 	function toString()
 	{
 		return $this->msg_top .  $this->wrap(parent::toString(),
 			'h' . $this->level, ' id="' . $this->id . '"');
 	}
 }
 
 // ----
 // Horizontal Rule
 class HRule extends Element
 {
 	function connect($tree)
 	{
 		$tree = array_slice($tree, -1);
 		$tree[0]->elements[] = & $this;
 		return $tree;
 	}
 
 	function canContain(& $obj)
 	{
 		return FALSE;
 	}
 
 	function toString()
 	{
 		global $hr;
 		return $hr;
 	}
 }
 
 class ListContainer extends Element
 {
 	var $tag;
 	var $level;
 	var $style;
 
 	function ListContainer($tag, $level)
 	{
 		$this->tag   = $tag;
 		$this->level = $level;
 	}
 
 	function connect($tree)
 	{
 		//マージンを取得
 		$var_margin      = '_' . $this->tag . '_margin';
 		$var_left_margin = '_' . $this->tag . '_left_margin';
 
 		global $$var_margin, $$var_left_margin, $_list_pad_str;
 
 		$step = $this->level;
 		if (isset($tree[1]) && is_a($tree[1], 'ListContainer'))
 			$step -= $tree[1]->level;
 
 		$margin = $$var_margin * $step;
 		if ($step == $this->level)
 			$margin += $$var_left_margin;
 
 		$this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
 
 		return parent::connect($tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return is_a($obj, 'ListElement') && $this->tag == $obj->tag && $this->level == $obj->level;
 	}
 
 	function toString()
 	{
 		return $this->wrap(parent::toString(), $this->tag, $this->style);
 	}
 }
 
 class ListElement extends Element
 {
 	var $tag;
 	var $tag2;
 	var $level;
 
 	function ListElement($tag, $tag2, $level, $text)
 	{
 		$this->tag   = $tag;
 		$this->tag2  = $tag2;
 		$this->level = $level;
 
 		if ($text != '')
 			$this->elements[] = Factory_Inline($text);
 	}
 
 	function buildContainer($tree)
 	{
 		$obj = new ListContainer($this->tag, $this->level);
 		return $obj->connect($tree);
 	}
 
 	function connect($tree)
 	{
 		if (empty($this->elements)) {
 			if (! is_a($tree[0], 'ListContainer'))
 				return parent::connect($this->buildContainer($tree));
 			// 行頭文字のみの指定時はUL/OLブロックを脱出
 			return array_merge(array(& $tree[0]->elements[count($tree[0]->elements) - 1]), $tree);
 		}
 		if (! is_a($tree[0], 'ListContainer'))
 			$tree = $this->buildContainer($tree);
 		$tree[0]->elements[] = & $this;
 		return array_merge(array(& $this->elements[0], & $this), $tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return (! is_a($obj, 'ListElement') || ($obj->level > $this->level));
 	}
 
 	function toString()
 	{
 		return $this->wrap(parent::toString(), $this->tag2);
 	}
 }
 
 // - One
 // - Two
 // - Three
 class UList extends ListElement
 {
 	function UList($text)
 	{
 		$level = min(3, strspn($text, '-'));
 		parent::ListElement('ul', 'li', $level, substr($text, $level));
 	}
 }
 
 // + One
 // + Two
 // + Three
 class OList extends ListElement
 {
 	function OList($text)
 	{
 		$level = min(3, strspn($text, '+'));
 		parent::ListElement('ol', 'li', $level, substr($text, $level));
 	}
 }
 
 // : definition1 | description1
 // : definition2 | description2
 // : definition3 | description3
 class DTitle extends ListElement
 {
 	function DTitle($text, $level)
 	{
 		parent::ListElement('dl', 'dt', $level, substr($text, $level));
 	}
 }
 
 class DData extends ListElement
 {
 	function DData($text, $level)
 	{
 		parent::ListElement('dl', 'dd', $level, $text);
 	}
 
 	function connect($tree)
 	{
 		//	脱出処理させたくないので
 		$tree[0]->elements[] = & $this;
 		return empty($this->elements) ?
 			array_merge(array(& $this), $tree) :
 			array_merge(array(& $this->elements[0], & $this), $tree);
 	}
 }
 
 // > Someting cited
 // > like E-mail text
 class BQuote extends Element
 {
 	var $text;
 	var $level;
 	var $close;
 
 	function BQuote($text)
 	{
 		$this->text = $text;
 		$this->level = min(3, strspn($text, $text{0}));
 		$this->close = ($text{0} == '<');
 	}
 
 	function buildContainer($tree)
 	{
 		$obj = new BQuoteContainer($this->level);
 		return $obj->connect($tree);
 	}
 
 	function connect($tree)
 	{
 		if ($this->close) {
 			if (! is_a($tree[0], 'BQuoteContainer')) {
 				//	対応するコンテナが無い
 				$obj = new Inline($this->text);
 				return $obj->connect($tree);
 			}
 			if ($this->level == $tree[0]->level) {
 				array_shift($tree);
 				if ($this->level == 1) {
 					//	全て抜けた
 					$obj = Factory_Inline(substr($this->text, $this->level));
 					return $obj->connect($tree);
 				}
 				$this->text = ltrim(substr($this->text, $this->level));
 			}
 		} else {
 			$this->text = ltrim(substr($this->text, $this->level));
 			if (! is_a($tree[0], 'BQuoteContainer') || $this->level != $tree[0]->level)
 				$tree = $this->buildContainer($tree);
 		}
 
 		$obj = new Paragraph($this->text, ' class="quotation"');
 		return $obj->connect($tree);
 	}
 }
 
 class BQuoteContainer extends Element
 {
 	var $level;
 
 	function BQuoteContainer($level)
 	{
 		$this->level = $level;
 	}
 
 	function connect($tree)
 	{
 		if ($this->level != 1 &&
 			(! is_a($tree[0], 'BQuoteContainer') || $this->level != $tree[0]->level + 1)) {
 				$obj = new BQuoteContainer($this->level - 1);
 				$tree = $obj->connect($tree);
 		}
 		return parent::connect($tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return (! is_a($obj, 'BQuote') || $obj->level >= $this->level);
 	}
 
 	function toString()
 	{
 		return $this->wrap(parent::toString(), 'blockquote');
 	}
 }
 
 class TableCell extends Element
 {
 	var $tag = 'td'; // {td|th}
 	var $colspan = 1;
 	var $rowspan = 1;
 	var $style = array(); // is array('width'=>, 'align'=>...);
 
 	function TableCell($text, $is_template = FALSE)
 	{
 		$matches = array();
 
 		while (preg_match('/^(?:(LEFT|CENTER|RIGHT)|(BG)?COLOR\(([#\w]+)\)|SIZE\((\d+)\)):(.*)$/',
 		    $text, $matches)) {
 			if ($matches[1]) {
 				$this->style['align'] = 'text-align:' . strtolower($matches[1]) . ';';
 				$text = $matches[5];
 			} else if ($matches[3]) {
 				$name = $matches[2] ? 'background-color' : 'color';
 				$this->style[$name] = $name . ':' . htmlspecialchars($matches[3]) . ';';
 				$text = $matches[5];
 			} else if ($matches[4]) {
 				$this->style['size'] = 'font-size:' . htmlspecialchars($matches[4]) . 'px;';
 				$text = $matches[5];
 			}
 		}
 		if ($is_template && is_numeric($text))
 			$this->style['width'] = 'width:' . $text . 'px;';
 
 		if ($text == '>') {
 			$this->colspan = 0;
 		} else if ($text == '~') {
 			$this->rowspan = 0;
 		} else if (substr($text, 0, 1) == '~') {
 			$this->tag = 'th';
 			$text      = substr($text, 1);
 		}
 
 		if ($text != '' && $text{0} == '#') {
 			// セル内容が'#'で始まるときはDivクラスを通してみる
 			$tree = array(& $this);
 			Factory_Div($tree, $text);
 		} else {
 			$this->elements[] = Factory_Inline($text);
 		}
 	}
 
 	function setStyle($style)
 	{
 		foreach ($style as $key=>$value)
 			if (! isset($this->style[$key]))
 				$this->style[$key] = $value;
 	}
 
 	function wrap($string, $tag, $param)
 	{
 		return '<' . $tag . $param . '>' . $string . '</' . $tag . '>';
 	}
 
 	function toString()
 	{
 		if ($this->rowspan == 0 || $this->colspan == 0) return '';
 
 		$param = ' class="style_' . $this->tag . '"';
 		if ($this->rowspan > 1)
 			$param .= ' rowspan="' . $this->rowspan . '"';
 		if ($this->colspan > 1) {
 			$param .= ' colspan="' . $this->colspan . '"';
 			unset($this->style['width']);
 		}
 		if (! empty($this->style))
 			$param .= ' style="' . join(' ', $this->style) . '"';
 
 		return $this->wrap(parent::toString(), $this->tag, $param);
 	}
 }
 
 // | title1 | title2 | title3 |
 // | cell1  | cell2  | cell3  |
 // | cell4  | cell5  | cell6  |
 class Table extends Element
 {
 	var $types;
 	var $col; // number of column
 
 	function Table($out)
 	{
 		$cells = explode('|', $out[1]);
 		$type  = strtolower($out[2]);
 		$is_template = ($type == 'c');
 
 		$this->col   = count($cells);
 		$this->types = array($type);
 		$row = array();
 		foreach ($cells as $cell)
 			$row[] = new TableCell($cell, $is_template);
 		$this->elements[] = $row;
 	}
 
 	function connect($tree)
 	{
 		if (is_a($tree[0], 'Table')) {
 			$tree[0]->elements[] = $this->elements[0];
 			$tree[0]->types[]    = $this->types[0];
 			return $tree;
 		}
 		return parent::connect($tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return is_a($obj, 'Table') && ($obj->col == $this->col);
 	}
 
 	function toString()
 	{
 		static $parts = array('h'=>'thead', 'f'=>'tfoot', ''=>'tbody');
 
 		// rowspanを設定(下から上へ)
 		for ($ncol = 0; $ncol < $this->col; $ncol++) {
 			$rowspan = 1;
 			foreach (array_reverse(array_keys($this->elements)) as $nrow) {
 				$row = & $this->elements[$nrow];
 				if ($row[$ncol]->rowspan == 0) {
 					++$rowspan;
 					continue;
 				}
 				$row[$ncol]->rowspan = $rowspan;
 				while (--$rowspan) // 行種別を継承する
 					$this->types[$nrow + $rowspan] = $this->types[$nrow];
 				$rowspan = 1;
 			}
 		}
 
 		// colspan,styleを設定
 		$stylerow = NULL;
 		foreach (array_keys($this->elements) as $nrow) {
 			$row = & $this->elements[$nrow];
 			if ($this->types[$nrow] == 'c')
 				$stylerow = & $row;
 			$colspan = 1;
 			foreach (array_keys($row) as $ncol) {
 				if ($row[$ncol]->colspan == 0) {
 					++$colspan;
 					continue;
 				}
 				$row[$ncol]->colspan = $colspan;
 				if ($stylerow !== NULL) {
 					$row[$ncol]->setStyle($stylerow[$ncol]->style);
 					while (--$colspan) // 列スタイルを継承する
 						$row[$ncol - $colspan]->setStyle($stylerow[$ncol]->style);
 				}
 				$colspan = 1;
 			}
 		}
 
 		// テキスト化
 		$string = '';
 		foreach ($parts as $type => $part)
 		{
 			$part_string = '';
 			foreach (array_keys($this->elements) as $nrow) {
 				if ($this->types[$nrow] != $type)
 					continue;
 				$row        = & $this->elements[$nrow];
 				$row_string = '';
 				foreach (array_keys($row) as $ncol)
 					$row_string .= $row[$ncol]->toString();
 				$part_string .= $this->wrap($row_string, 'tr');
 			}
 			if ($part_string != '')
 				$string .= $this->wrap($part_string, $part);
 		}
 		$string = $this->wrap($string, 'table', ' class="style_table" cellspacing="1" border="0"');
 
 		return $this->wrap($string, 'div', ' class="ie5"');
 	}
 }
 
 // , title1 , title2 , title3
 // , cell1  , cell2  , cell3
 // , cell4  , cell5  , cell6
 class YTable extends Element
 {
 	var $col;
 
 	function YTable($_value)
 	{
 		$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];
 			} else {
 				$align[] = '';
 				$value[] = $val;
 			}
 		}
 		$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>';
 			}
 		}
 		$this->elements[] = $str;
 	}
 
 	function connect($tree)
 	{
 		if (is_a($tree[0], 'YTable')) {
 			$tree[0]->elements[] = $this->elements[0];
 			return $tree;
 		}
 		return parent::connect($tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return is_a($obj, 'YTable') && ($obj->col == $this->col);
 	}
 
 	function toString()
 	{
 		$rows = '';
 		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"');
 	}
 }
 
 // ' 'Space-beginning sentence
 // ' 'Space-beginning sentence
 // ' 'Space-beginning sentence
 class Pre extends Element
 {
 	function Pre($text)
 	{
 		global $preformat_ltrim;
 
 		$this->elements[] = htmlspecialchars(
 			(! $preformat_ltrim || $text == '' || $text{0} != ' ') ? $text : substr($text, 1));
 	}
 
 	function connect($tree)
 	{
 		if (is_a($tree[0], 'Pre')) {
 			$tree[0]->elements[] = $this->elements[0];
 			return $tree;
 		}
 		return parent::connect($tree);
 	}
 
 	function canContain(& $obj)
 	{
 		return is_a($obj, 'Pre');
 	}
 
 	function toString()
 	{
 		return $this->wrap(join("\n", $this->elements), 'pre');
 	}
 }
 
 // Block plugin: #something (started with '#')
 class Div extends Element
 {
 	var $name;
 	var $param;
 
 	function Div($out)
 	{
 		list(, $this->name, $this->param) = array_pad($out, 3, '');
 	}
 
 	function connect($tree)
 	{
 		$tree[0]->elements[] = & $this;
 		return $tree;
 	}
 
 	function canContain(& $obj)
 	{
 		return FALSE;
 	}
 
 	function toString()
 	{
 		// Call #plugin
 		return do_plugin_convert($this->name, $this->param);
 	}
 }
 
 // LEFT:/CENTER:/RIGHT:
 class Align extends Element
 {
 	var $align;
 
 	function Align($align)
 	{
 		$this->align = $align;
 	}
 
 	function canContain(& $obj)
 	{
 		return is_a($obj, 'Inline');
 	}
 
 	function toString()
 	{
 		return $this->wrap(parent::toString(), 'div', ' style="text-align:' . $this->align . '"');
 	}
 }
 
 // Body
 class Body extends Element
 {
 	var $id;
 	var $count = 0;
 	var $contents = array();
 
 	function Body($id)
 	{
 		$this->id = $id;
 	}
 
 	function parse($lines)
 	{
 		$classes = array(
 			'-' => 'UList',
 			'+' => 'OList',
 			'>' => 'BQuote',
 			'<' => 'BQuote'
 		);
 		$factories = array(
 			':' => 'DList',
 			'|' => 'Table',
 			',' => 'YTable',
 			'#' => 'Div'
 		);
 
 		$tree = array(& $this);
 		$matches = array();
 
 		while (! empty($lines)) {
 			$line = array_shift($lines);
 
 			// Escape comments
 			if (substr($line, 0, 2) == '//') continue;
 
 			if (preg_match('/^(LEFT|CENTER|RIGHT):(.*)$/', $line, $matches)) {
 				// <div style="text-align:...">
 				$obj = & new Align(strtolower($matches[1]));
 				$tree = $obj->add($tree);
 				if ($matches[2] == '') continue;
 				$line = $matches[2];
 			}
 
 			$line = preg_replace("/[\r\n]+$/", '', $line);
 
 			// Empty
 			if ($line == '') {
 				$tree = array(& $this);
 				continue;
 			}
 
 			// Horizontal Rule
 			if (substr($line, 0, 4) == '----') {
 				$obj = & new HRule();
 				$tree = $obj->add($tree);
 				continue;
 			}
 
 			// Multiline-enabled block plugin
 			if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK &&
 			    preg_match('/^#(?:(?!\)\{\{).)+\)([{]{2,})\s*$/', $line, $matches)) {
 				$len = strlen($matches[1]);
 				$line .= "\r"; // Delimiter
 				$index = 0;
 				while (TRUE) {
 					if ($index >= count($lines)) {
 						$line = '&#x23;' . substr($line, 1);
 						break;
 					}
 					if (preg_match('/^\}{' . $len . '}/', $lines[$index])) {
 						$plugin_body = array_splice($lines, 0, $index - 1);
 						$line .= implode("\r", preg_replace('/[\r\n]+$/', '', $plugin_body));
 						break;
 					}
 					$index++;
 				}
 			}
 
 			// The first character
 			$head = $line{0};
 
 			// Heading
 			if ($head == '*') {
 				$obj = & new Heading($this, $line);
 				$tree = $obj->add($tree);
 				continue;
 			}
 
 			// Pre
 			if ($head == ' ' || $head == "\t") {
 				$obj = & new Pre($line);
 				$tree = $obj->add($tree);
 				continue;
 			}
 
 			// Line Break
 			if (substr($line, -1) == '~')
 				$line = substr($line, 0, -1) . "\r";
 			
 			// Other Character
 			if (isset($classes[$head])) {
 				$classname  = $classes[$head];
 				$obj = & new $classname($line);
 				$tree = $obj->add($tree);
 				continue;
 			}
 
 			// Other Character
 			if (isset($factories[$head])) {
 				$factoryname = 'Factory_' . $factories[$head];
 				$tree = $factoryname($tree, $line);
 				continue;
 			}
 
 			// Default
 			$obj = & Factory_Inline($line);
 			$tree = $obj->add($tree);
 		}
 	}
 
 	function getAnchor($text, $level)
 	{
 		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
 		if ($id == '') {
 			// Not specified
 			$id     = & $autoid;
 			$anchor = '';
 		} else {
 			$anchor = ' &aname(' . $id . ',super,full){' . $_symbol_anchor . '};';
 		}
 
 		$text = ' ' . $text;
 
 		$this->contents[] = compact('level', 'text', 'id');
 
 		// Add heding
 		return array($text . $anchor, $this->count > 1 ? "\n" . $top : '', $autoid);
 	}
 
 	function toString()
 	{
 		global $vars;
 
 		$text = parent::toString();
 
 		// #contents
 		$text = preg_replace_callback('/<#_contents_>/',
 			array(& $this, 'replace_contents'), $text);
 
 		return $text . "\n";
 	}
 
 	function replace_contents($arr)
 	{
 		$Contents = & new Element();
 		$tree = array(& $Contents);
 		foreach ($this->contents as $param) {
 			$obj = & new Contents_UList($param['text'], $param['level'], $param['id']);
 			$tree = $obj->add($tree);
 		}
 		return '<div class="contents">' . "\n" .
 			'<a id="contents_' . $this->id . '"></a>' . "\n" .
 			$Contents->toString() . "\n" .
 			'</div>' . "\n";
 	}
 }
 
 class Contents_UList extends ListElement
 {
 	function Contents_UList($text, $level, $id)
 	{
 		make_heading($text);
 		$text = '[[' . $text . '>#' . $id . ']]';
 		parent::ListElement('ul', 'li', $level, $text);
 	}
 
 	function buildContainer($tree)
 	{
 		$obj = new Contents_ListContainer($this->tag, $this->level);
 		return $obj->connect($tree);
 	}
 }
 
 class Contents_ListContainer extends ListContainer
 {
 	function connect($tree)
 	{
 		$var_margin      = '_' . $this->tag . '_margin';
 		$var_left_margin = '_' . $this->tag . '_left_margin';
 
 		global $$var_margin, $$var_left_margin, $_list_pad_str;
 
 		$step = $this->level;
 		$margin = $$var_left_margin;
 		if (isset($tree[1]) && is_a($tree[1], 'ListContainer')) {
 			$step  -= $tree[1]->level;
 			$margin = 0;
 		}
 		$margin += $$var_margin * ($step == $this->level ? 1 : $step);
 
 		$this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
 
 		return parent::connect($tree);
 	}
 }
 ?>


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Site admin: PukiWiki Development Team

PukiWiki 1.5.4+ © 2001-2022 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u12. HTML convert time: 0.049 sec.

OSDN