2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
5 // $Id: convert_html.php,v 1.1 2003/01/27 05:44:11 panda Exp $
8 function convert_html($string)
10 global $script,$vars,$digest;
11 static $contents_id = 0;
13 $contents = new Contents(++$contents_id);
15 $string = rtrim($string);
16 $string = preg_replace("/^#freeze\n/","","$string\n"); // Åà·ë»Ø¼¨»Ò½üµî
17 $string = preg_replace("/\n\/\/[^\n]*/","", "\n$string"); // ¥³¥á¥ó¥È½üµî
18 $string = preg_replace("/\n\n+/","\n\n\n", $string); // ¶õ¹Ô¤ÎÄ´À°
19 $string = preg_replace("/(?<=[\r\n])(?!\s)([^\n]*~)\n/", "$1\r", "\n$string");
21 $lines = split("\n", $string);
23 $digest = md5(@join('',get_source($vars['page'])));
26 $last =& $body->insert(new Paragraph(''));
28 foreach ($lines as $line) {
29 if (substr($line,0,2) == '//') { //¥³¥á¥ó¥È¤Ï½èÍý¤·¤Ê¤¤
34 if (preg_match('/^(LEFT|CENTER|RIGHT):(.*)$/',$line,$matches)) {
35 $last =& $last->add(new Align(strtolower($matches[1]))); // <div style="text-align:...">
36 if ($matches[2] == '') {
43 $head = substr($line,0,1);
44 if ($line == '') { $last =& $body; } // ¶õ¹Ô
45 else if (rtrim($line) == '----') {
46 $last =& $body->insert(new HRule()); } // HRule
47 else if ($head == '*') {
48 $last =& $body->insert(new Heading($line, $contents)); } // Heading
49 else if ($head == '-') { $last =& $last->add(new UList($line)); } // UList
50 else if ($head == '+') { $last =& $last->add(new OList($line)); } // OList
51 else if ($head == ':') { $last =& $last->add(new DList($line)); } // DList
52 else if ($head == '|') { $last =& $last->add(new Table($line)); } // Table
53 else if ($head == ',') { $last =& $last->add(new YTable($line)); } // Table(YukiWiki¸ß´¹)
54 else if ($head == ' ' or $head == "\t")
55 { $last =& $last->add(new Pre($line)); } // Pre
56 else if ($head == '>') { $last =& $last->add(new BQuote($line)); } // BrockQuote
57 else if ($head == '<') { $last =& bq_end($last, $line); } // BlockQuote end
58 else if ($head == '#') { $last =& $last->add(new Div($line)); } // Div
59 else { $last =& $last->add(new Inline($line)); } // ÃÊÍî
61 $ret = $body->toArray();
62 // $ret = inline2($ret);
63 $ret = $contents->replaceContents($ret);
65 return join("\n",$ret);
73 function setParent(&$parent)
75 $this->parent =& $parent;
79 class Inline extends Element
83 function Inline($text)
85 if (substr($text,0,1) == '~') { // ¹ÔƬ~¡£¥Ñ¥é¥°¥é¥Õ³«»Ï
86 $parent =& $this->parent;
87 $this = new Paragraph(" ".substr($text,1));
88 $this->setParent($parent);
91 $this->text = trim((preg_match("/^\n/", $text)) ? $text : inline($text));
96 return $this->insert($obj);
98 function &insert(&$obj)
100 return $this->parent->add($obj);
104 return ($this->text == '') ? array() : array(inline2($this->text));
106 function toPara($class = '')
108 $obj = new Paragraph('',$class);
110 $this->setParent($obj);
114 class Block extends Element
116 var $elements; // Í×ÁǤÎÇÛÎó
119 $this->elements = array();
122 function &add(&$obj) // ¥¨¥ì¥á¥ó¥È¤òÄɲÃ
124 if ($this->canContain($obj)) {
125 return $this->insert($obj);
127 return $this->parent->add($obj);
129 function &insert(&$obj)
131 $obj->setParent($this);
132 $this->elements[] =& $obj;
133 if (isset($obj->last) and is_object($obj->last)) {
138 function canContain($obj)
145 if (isset($this->elements) and count($this->elements) > 0) {
146 foreach ($this->elements as $obj) {
147 array_splice($arr, count($arr), 0, $obj->toArray());
152 function wrap($arr, $tag, $param = '')
154 if (count($arr) > 0) {
155 array_unshift($arr,"<$tag$param>");
156 array_push($arr,"</$tag>");
161 class Body extends Block
164 function &insert(&$obj)
166 if (is_a($obj,'Inline')) {
167 $obj =& $obj->toPara();
169 return parent::insert($obj);
172 class Paragraph extends Block
176 function Paragraph($text, $class = '')
179 $this->class = $class;
183 if (substr($text,0,1) == '~') {
184 $text = substr($text,1);
186 $this->elements[] =& new Inline($text);
188 function canContain($obj)
190 return is_a($obj,'Inline');
194 return $this->wrap(parent::toArray(), 'p', $this->class);
198 class Heading extends Block
200 function Heading($text, &$contents)
203 preg_match("/^(\*{1,3})\s*(.*)$/",$text,$out) or die("Heading");
204 $this->level = strlen($out[1]) + 1;
205 list($this->text,$this->contents_str) = $contents->getAnchor($out[2], $this->level);
207 function canContain(&$obj)
213 return $this->wrap(array($this->text),'h'.$this->level, $this->contents_str);
216 class HRule extends Block
218 function canContain(&$obj)
229 class _List extends Block
232 var $step, $margin, $left_margin;
234 function _List($tag, $tag2, $level, $text)
238 $var_margin = "_{$tag}_margin";
239 $var_left_margin = "_{$tag}_left_margin";
240 global $$var_margin, $$var_left_margin;
241 $this->margin = $$var_margin;
242 $this->left_margin = $$var_left_margin;
247 $this->level = $level;
250 $this->insert(new Inline($text));
254 function canContain(&$obj)
256 return is_a($obj, '_List') ? ($this->tag == $obj->tag and $this->level == $obj->level) : TRUE;
258 function setParent(&$parent)
260 parent::setParent($parent);
261 $this->step = $this->level;
262 if (isset($parent->parent) and is_a($parent->parent,'_List')) {
263 $this->step -= $parent->parent->level;
266 function &insert(&$obj)
268 if (is_a($obj, get_class($this))) {
269 for ($n = 0; $n < count($obj->elements); $n++) {
270 $this->last =& parent::insert($obj->elements[$n]);
275 $obj =& new ListElement($obj, $this->level, $this->tag2); // wrap
278 return parent::insert($obj);
280 function toArray($param='')
282 global $_list_left_margin, $_list_margin, $_list_pad_str;
284 $margin = $_list_margin * $this->step;
285 if ($this->level == $this->step) {
286 $margin += $_list_left_margin;
288 $style = sprintf($_list_pad_str,$this->level,$margin,$margin);
289 return $this->wrap(Block::toArray(),$this->tag,$style.$param);
292 class ListElement extends Block
294 function ListElement($obj,$level,$head)
297 $this->level = $level;
301 function canContain(&$obj)
303 return !(is_a($obj, '_List') and ($obj->level <= $this->level));
307 return $this->wrap(parent::toArray(), $this->head);
310 class UList extends _List
312 function UList($text)
314 preg_match("/^(\-{1,3})([\n]?.*)$/",$text,$out) or die("UList $text");
315 parent::_List('ul', 'li', strlen($out[1]), $out[2]);
318 class OList extends _List
320 function OList($text)
322 preg_match("/^(\+{1,3})(.*)$/",$text,$out) or die("OList");
323 parent::_List('ol', 'li', strlen($out[1]), $out[2]);
326 class DList extends _List
328 function DList($text)
330 if (!preg_match("/^(:{1,3})(.*)\|(.*)$/",$text,$out)) {
331 $this = new Inline($text);
334 parent::_List('dl', 'dd', strlen($out[1]), $out[3]);
336 array_unshift($this->elements,new Inline("\n".'<dt>'.inline($out[2]).'</dt>'));
340 class BQuote extends Block
342 function BQuote($text)
345 preg_match("/^(\>{1,3})(.*)$/",$text,$out) or die("BQuote");
346 $this->level = strlen($out[1]);
347 $this->text = $out[2];
348 $this->insert(new Paragraph($this->text, ' class="quotation"'));
350 function canContain(&$obj)
352 if (!is_a($obj, get_class($this))) {
355 return ($this->level <= $obj->level);
357 function &insert(&$obj)
359 if (is_a($obj, 'BQuote') and $obj->level == $this->level) {
360 $obj =& $obj->elements[0];
362 else if (is_a($obj,'Inline')) {
363 $obj = $obj->toPara('quotation');
366 return parent::insert($obj);
370 return $this->wrap(parent::toArray(),'blockquote');
373 function &bq_end(&$last, $text)
375 preg_match("/^(\<{1,3})(.*)$/",$text,$out) or die("bq_end");
376 $level = strlen($out[1]);
378 while (is_object($parent)) {
379 if (is_a($parent,'BQuote') and $parent->level == $level) {
380 return $parent->parent->insert(new Inline($out[2]));
382 $parent =& $parent->parent;
384 return $last->insert(new Inline($text));
386 class Table extends Block
390 function Table($text)
393 if (!preg_match("/^\|(.+)\|([hHfFcC]?)$/",$text,$out)) {
394 $this = new Inline($text);
397 $this->elements = array();
398 $cells = explode('|',$out[1]);
399 $this->level = count($cells);
400 $char = strtolower($out[2]);
402 $this->col =& new Col($cells);
405 $this->insert(new Row($cells,($char == 'h' ? 0 : ($char == 'f' ? 1 : 2))));
408 function canContain(&$obj)
410 return is_a($obj, 'Table') and $obj->level == $this->level;
412 function &insert(&$obj)
414 if (is_a($obj, 'Table')) {
415 if (isset($obj->col) and is_object($obj->col)) {
416 $this->col = $obj->col;
419 $obj =& $obj->elements[0];
420 $last = count($this->elements) - 1;
421 for ($n = 0; $n < count($obj->elements); $n++) {
422 if ($obj->elements[$n] != '~') {
425 $obj->type = $this->elements[$last]->type;
426 for ($m = $last; $m >= 0; $m--) {
427 if ($this->elements[$m]->elements[$n] == '~') {
430 $this->elements[$m]->row[$n]++;
435 $this->elements[] = $obj;
441 if (isset($this->col) and is_object($this->col)) {
444 $arr = $col ? $this->col->toArray() : array();
445 $part = array(0=>'thead',1=>'tfoot',2=>'tbody');
446 foreach ($part as $type=>$str) {
448 foreach ($this->elements as $row) {
449 if ($row->type != $type) {
452 $tmp = array_merge($tmp,$row->toArray($col));
454 if (count($tmp) > 0) {
455 $arr = array_merge($arr,$this->wrap($tmp,$str));
458 if (count($arr) > 0) {
459 array_unshift($arr, '<div class="ie5">','<table class="style_table" cellspacing="1" border="0">');
460 array_push($arr,'</table>','</div>');
465 class Row extends Block
469 function Row($cells,$type='')
472 $this->elements = $cells;
475 for ($n = 0; $n < count($cells); $n++) {
477 if ($cells[$n] == '>') {
482 $this->col[$n] = $span;
487 function toArray($obj)
490 for ($n = 0; $n < count($this->elements); $n++) {
491 $cell = $this->elements[$n];
492 if ($cell == '>' or $cell == '~') {
496 if ($this->row[$n] > 1) {
497 $row = " rowspan=\"{$this->row[$n]}\"";
499 if ($this->col[$n] > 1) {
500 $col = " colspan=\"{$this->col[$n]}\"";
502 $align = $width = '';
503 if (is_object($obj)) {
504 $align = $obj->align[$n];
505 if ($this->col[$n] == 1) {
506 $width = $obj->width[$n];
509 if (preg_match("/^(LEFT|CENTER|RIGHT):(.*)$/",$cell,$out)) {
510 $align = strtolower($out[1]);
513 if (preg_match('/^~(.+)$/',$cell,$matches)) {
514 $tag = 'th'; $cell = $matches[1];
519 $style = $width == '' ? '' : 'width:'.$width.'px;';
520 $style.= $align == '' ? '' : 'text-align:'.$align.';';
521 $style = $style == '' ? '' : ' style="'.$style.'"';
522 $cells[] = "<$tag class=\"style_$tag\"$style$row$col>".inline2(inline($cell))."</$tag>";
524 return $this->wrap($cells,'tr');
527 class Col extends Row
534 $align = $width = '';
535 for ($n = count($this->elements) - 1; $n >= 0; $n--) {
536 if ($cells[$n] == '') {
537 $align = $width = '';
539 else if ($cells[$n] != '>') {
540 if (preg_match("/^(LEFT|CENTER|RIGHT):(.*)$/",$cells[$n],$out)) {
541 $align = strtolower($out[1]);
544 $width = htmlspecialchars($cell);
546 $this->align[$n] = $align;
547 $this->width[$n] = $width;
553 for ($n = 0; $n < count($this->elements); $n++) {
554 $cell = $this->elements[$n];
558 $span = " span=\"{$this->col[$n]}\"";
559 $align = $this->align[$n] == '' ? '' : ' align="'.$this->align[$n].'"';
560 $width = $this->width[$n] == '' ? '' : ' width="'.$this->width[$n].'"';
561 $cells[] = "<colgroup$span$align$width></colgroup>";
566 class YTable extends Block
570 function YTable($text)
573 if (!preg_match_all('/("[^"]*(?:""[^"]*)*"|[^,]*),/',"$text,",$out)) {
574 $this = new Inline($text);
577 array_shift($out[1]);
579 foreach ($out[1] as $val) {
580 $_value[] = preg_match('/^"(.*)"$/',$val,$matches) ? str_replace('""','"',$matches[1]) : $val;
584 foreach($_value as $val) {
585 if (preg_match('/^(\s+)?(.+?)(\s+)?$/',$val,$matches)) {
586 $align[] =($matches[1] != '') ?
587 ((array_key_exists(3,$matches) and $matches[3] != '') ? ' style="text-align:center"' : ' style="text-align:right"') : '';
588 $value[] = $matches[2];
595 $this->col = count($value);
597 foreach ($value as $val) {
598 $colspan[] = ($val == '==') ? 0 : 1;
601 for ($i = 0; $i < count($value); $i++) {
603 while ($i + $colspan[$i] < count($value) and $value[$i + $colspan[$i]] == '==') {
606 $colspan[$i] = ($colspan[$i] > 1) ? " colspan=\"{$colspan[$i]}\"" : '';
607 $str .= "<td class=\"style_td\"{$align[$i]}{$colspan[$i]}>".inline2(inline($value[$i])).'</td>';
610 $this->elements[] = $str;
612 function canContain(&$obj)
614 return is_a($obj, 'YTable') and $obj->col == $this->col;
616 function &insert(&$obj)
618 $this->elements[] = $obj->elements[0];
624 foreach ($this->elements as $str) {
625 $arr[] = '<tr class="style_tr">';
629 array_unshift($arr, '<div class="ie5">','<table class="style_table" cellspacing="1" border="0">');
630 array_push($arr,'</table>','</div>');
634 class Pre extends Block
641 while (preg_match('/^([^\t]*)(\t+)(.+)$/',$text,$m)) {
642 $text = $m[1].str_repeat(' ',strlen($m[2]) * $tab - strlen($m[1]) % $tab).$m[3];
644 $this->elements[] = htmlspecialchars($text,ENT_NOQUOTES);
646 function canContain(&$obj)
648 return is_a($obj, 'Pre');
650 function &insert(&$obj)
652 $this->elements[] = $obj->elements[0];
657 return $this->wrap($this->elements,'pre');
660 class Div extends Block
669 function canContain(&$obj)
675 if (preg_match("/^\#([^\(]+)(.*)$/",$this->text,$out) and exist_plugin_convert($out[1])) {
677 $_plugin = preg_replace("/^\#([^\(]+)\((.*)\)$/ex","do_plugin_convert('$1','$2')",$this->text);
680 $_plugin = preg_replace("/^\#([^\(]+)$/ex","do_plugin_convert('$1','$2')",$this->text);
682 $text = "\t$_plugin";
685 $text = '<p>'.htmlspecialchars($this->text).'</p>';
690 class Align extends Body
691 { // LEFT:/CENTER:/RIGHT:
694 function Align($align)
696 $this->align = $align;
700 $arr = parent::toArray();
702 if (preg_match('/^(.+)style="(.+)$/',$arr[0],$matches)) {
703 $arr[0] = $matches[1].'style="text-align:'.$this->align.'; '.$matches[2];
706 $arr[0] = preg_replace('/(<[a-z]+)/', '$1 style="text-align:'.$this->align.';"',$arr[0]);
715 var $id,$count,$top,$contents,$last;
716 function Contents($id)
721 $this->top = "<a href=\"#contents_$id\">$top</a>";
722 $this->contents =& new Block();
723 $this->last =& $this->contents;
725 function getAnchor($text,$level)
727 $content_str = "content_{$this->id}_{$this->count}";
728 $this->last =& $this->last->add(new Contents_UList($text,$this->id,$level,$content_str));
730 return array(inline2(inline($text)).$this->top," id=\"{$content_str}\"");
732 function replaceContents($text)
734 global $strip_link_wall;
736 $contents = "<a id=\"contents_{$this->id}\"></a>";
737 $contents .= join("\n",$this->contents->toArray());
738 if($strip_link_wall) {
739 $contents = preg_replace("/\[\[([^\]]+)\]\]/","$1",$contents);
741 return preg_replace("/^<p>#contents<\/p>/",$contents,$text);
744 class Contents_UList extends _List
746 function Contents_UList($text,$id,$level,$content_str)
749 // ¥Æ¥¥¹¥È¤Î¥ê¥Õ¥©¡¼¥à
750 $text = "\n<a href=\"#{$content_str}\">".
751 strip_htmltag(make_user_rules(inline($text,TRUE))).'</a>';
752 parent::_List('ul', 'li', --$level, $text);