2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
5 // $Id: convert_html.php,v 1.5 2003/01/31 05:16:43 panda Exp $
8 function &convert_html(&$lines)
10 global $script,$vars,$digest;
11 static $contents_id = 0;
13 $digest = md5(join('',get_source($vars['page'])));
15 $contents = new Contents(++$contents_id);
20 foreach ($lines as $line) {
21 if (substr($line,0,2) == '//') { //¥³¥á¥ó¥È¤Ï½èÍý¤·¤Ê¤¤
28 if (preg_match('/^(LEFT|CENTER|RIGHT):(.*)$/',$line,$matches)) {
29 $last =& $last->add(new Align(strtolower($matches[1]))); // <div style="text-align:...">
30 if ($matches[2] == '') {
37 $head = substr($line,0,1);
39 if ($line == '') { // ¶õ¹Ô
42 else if (substr($line,0,4) == '----') { // HRule
43 $last =& $body->insert(new HRule());
45 else if ($head == ' ' or $head == "\t") { // Pre
46 $last =& $last->add(new Pre($line));
48 else if ($head == '*') { // Heading
49 $last =& $body->insert(new Heading($line, $contents));
52 if (substr($line,-1) == '~') {
55 if ($head == '-') { // UList
56 $last =& $last->add(new UList($line));
58 else if ($head == '+') { // OList
59 $last =& $last->add(new OList($line));
61 else if ($head == ':') { // DList
62 $last =& $last->add(new DList($line));
64 else if ($head == '|') { // Table
65 $last =& $last->add(new Table($line));
67 else if ($head == ',') { // Table(YukiWiki¸ß´¹)
68 $last =& $last->add(new YTable($line));
70 else if ($head == '>') { // BrockQuote
71 $last =& $last->add(new BQuote($line));
73 else if ($head == '<') { // BlockQuote end
74 $last =& bq_end($last, $line);
76 else if ($head == '#') { // Div
77 $last =& $last->add(new Div($line));
80 $last =& $last->add(new Inline($line));
84 $ret = $body->toString();
87 $ret = preg_replace("/<p>#contents<\/p>/",$contents->getContents(),$ret);
90 $ret = preg_replace('/#related/e','make_related($vars[\'page\'],TRUE)',$ret);
99 function setParent(&$parent)
101 $this->parent =& $parent;
105 class Inline extends Element
109 function Inline($text)
111 if (substr($text,0,1) == '~') { // ¹ÔƬ~¡£¥Ñ¥é¥°¥é¥Õ³«»Ï
112 $parent =& $this->parent;
113 $this = new Paragraph(substr($text,1));
114 $this->setParent($parent);
117 $this->text = (substr($text,0,1) == "\n") ? $text : inline2(inline($text)));
122 return $this->insert($obj);
124 function &insert(&$obj)
126 return $this->parent->add($obj);
132 function toPara($class = '')
134 $obj = new Paragraph('',$class);
136 $this->setParent($obj);
140 class Block extends Element
142 var $elements; // Í×ÁǤÎÇÛÎó
145 $this->elements = array();
148 function &add(&$obj) // ¥¨¥ì¥á¥ó¥È¤òÄɲÃ
150 if ($this->canContain($obj)) {
151 return $this->insert($obj);
153 return $this->parent->add($obj);
155 function &insert(&$obj)
157 $obj->setParent($this);
158 $this->elements[] =& $obj;
159 if (isset($obj->last) and is_object($obj->last)) {
164 function canContain($obj)
171 if (isset($this->elements) and count($this->elements) > 0) {
172 foreach ($this->elements as $obj) {
173 $ret .= $obj->toString();
178 function wrap($string, $tag, $param = '')
180 return ($string == '') ? '' : "\n<$tag$param>$string</$tag>\n";
183 class Body extends Block
186 function &insert(&$obj)
188 if (is_a($obj,'Inline')) {
189 $obj =& $obj->toPara();
191 return parent::insert($obj);
194 class Paragraph extends Block
198 function Paragraph($text, $class = '')
201 $this->class = $class;
205 if (substr($text,0,1) == '~') {
206 $text = substr($text,1);
208 $this->elements[] =& new Inline($text);
210 function canContain($obj)
212 return is_a($obj,'Inline');
216 return $this->wrap(parent::toString(), 'p', $this->class);
220 class Heading extends Block
223 function Heading($text, &$contents)
226 preg_match("/^(\*{1,3})\s*(.*)$/",$text,$out) or die("Heading");
227 $this->level = strlen($out[1]) + 1;
228 list($this->text,$this->contents_str) = $contents->getAnchor($out[2], $this->level);
230 function canContain(&$obj)
236 return $this->wrap($this->text,'h'.$this->level, $this->contents_str);
239 class HRule extends Block
241 function canContain(&$obj)
252 class _List extends Block
255 var $step, $margin, $left_margin;
257 function _List($tag, $tag2, $level, $text)
261 $var_margin = "_{$tag}_margin";
262 $var_left_margin = "_{$tag}_left_margin";
263 global $$var_margin, $$var_left_margin;
264 $this->margin = $$var_margin;
265 $this->left_margin = $$var_left_margin;
270 $this->level = $level;
273 $this->insert(new Inline($text));
277 function canContain(&$obj)
279 return is_a($obj, '_List') ? ($this->tag == $obj->tag and $this->level == $obj->level) : TRUE;
281 function setParent(&$parent)
283 parent::setParent($parent);
284 $this->step = $this->level;
285 if (isset($parent->parent) and is_a($parent->parent,'_List')) {
286 $this->step -= $parent->parent->level;
289 function &insert(&$obj)
291 if (is_a($obj, get_class($this))) {
292 for ($n = 0; $n < count($obj->elements); $n++) {
293 $this->last =& parent::insert($obj->elements[$n]);
297 $obj =& new ListElement($obj, $this->level, $this->tag2); // wrap
299 return parent::insert($obj);
301 function toString($param='')
303 global $_list_left_margin, $_list_margin, $_list_pad_str;
305 $margin = $_list_margin * $this->step;
306 if ($this->level == $this->step) {
307 $margin += $_list_left_margin;
309 $style = sprintf($_list_pad_str,$this->level,$margin,$margin);
310 return $this->wrap(Block::toString(),$this->tag,$style.$param);
313 class ListElement extends Block
315 function ListElement($obj,$level,$head)
318 $this->level = $level;
322 function canContain(&$obj)
324 return !(is_a($obj, '_List') and ($obj->level <= $this->level));
328 return $this->wrap(parent::toString(), $this->head);
331 class UList extends _List
333 function UList($text)
335 preg_match("/^(\-{1,3})([\n]?.*)$/",$text,$out) or die("UList $text");
336 parent::_List('ul', 'li', strlen($out[1]), $out[2]);
339 class OList extends _List
341 function OList($text)
343 preg_match("/^(\+{1,3})(.*)$/",$text,$out) or die("OList");
344 parent::_List('ol', 'li', strlen($out[1]), $out[2]);
347 class DList extends _List
349 function DList($text)
351 if (!preg_match("/^(:{1,3})(.*)\|(.*)$/",$text,$out)) {
352 $this = new Inline($text);
355 parent::_List('dl', 'dd', strlen($out[1]), $out[3]);
357 array_unshift($this->elements,new Inline("\n<dt>".inline2(inline($out[2]))."</dt>\n"));
361 class BQuote extends Block
365 function BQuote($text)
368 preg_match("/^(\>{1,3})(.*)$/",$text,$out) or die("BQuote");
369 $this->level = strlen($out[1]);
370 $this->text = $out[2];
371 $this->last =& $this->insert(new Paragraph($this->text, ' class="quotation"'));
373 function canContain(&$obj)
375 if (!is_a($obj, get_class($this))) {
378 return ($this->level <= $obj->level);
380 function &insert(&$obj)
382 if (is_a($obj, 'BQuote') and $obj->level == $this->level) {
383 if (is_a($this->last,'Paragraph')) {
384 $this->last->insert($obj->elements[0]->elements[0]);
386 $this->last =& $this->insert($obj->elements[0]);
391 return parent::insert($obj);
395 return $this->wrap(parent::toString(),'blockquote');
398 function &bq_end(&$last, $text)
400 preg_match("/^(\<{1,3})(.*)$/",$text,$out) or die("bq_end");
401 $level = strlen($out[1]);
403 while (is_object($parent)) {
404 if (is_a($parent,'BQuote') and $parent->level == $level) {
405 return $parent->parent->insert(new Inline($out[2]));
407 $parent =& $parent->parent;
409 return $last->insert(new Inline($text));
411 class Table extends Block
413 var $col,$head,$foot;
416 function Table($text)
419 if (!preg_match("/^\|(.+)\|([hHfFcC]?)$/",$text,$out)) {
420 $this = new Inline($text);
423 $this->elements = array();
424 $cells = explode('|',$out[1]);
425 $this->level = count($cells);
426 $char = strtolower($out[2]);
428 $this->col =& new Col($cells);
431 $this->insert(new Row($cells,($char == 'h' ? 0 : ($char == 'f' ? 1 : 2))));
434 function canContain(&$obj)
436 return is_a($obj, 'Table') and $obj->level == $this->level;
438 function &insert(&$obj)
440 if (is_a($obj, 'Table')) {
441 if (isset($obj->col) and is_object($obj->col)) {
442 $this->col = $obj->col;
445 $obj =& $obj->elements[0];
446 $last = count($this->elements) - 1;
447 for ($n = 0; $n < count($obj->elements); $n++) {
448 if ($obj->elements[$n] != '~') {
451 $obj->type = $this->elements[$last]->type;
452 for ($m = $last; $m >= 0; $m--) {
453 if ($this->elements[$m]->elements[$n] == '~') {
456 $this->elements[$m]->row[$n]++;
461 $this->elements[] = $obj;
467 if (isset($this->col) and is_object($this->col)) {
470 $string = $col ? $this->col->toString() : '';
471 $part = array(0=>'thead',1=>'tfoot',2=>'tbody');
472 foreach ($part as $type=>$str) {
474 foreach ($this->elements as $row) {
475 if ($row->type != $type) {
478 $tmp .= $row->toString($col);
481 $string .= $this->wrap($tmp,$str);
488 <table class="style_table" cellspacing="1" border="0">
497 class Row extends Block
501 function Row($cells,$type='')
504 $this->elements = $cells;
507 for ($n = 0; $n < count($cells); $n++) {
509 if ($cells[$n] == '>') {
514 $this->col[$n] = $span;
519 function toString($obj)
522 for ($n = 0; $n < count($this->elements); $n++) {
523 $cell = $this->elements[$n];
524 if ($cell == '>' or $cell == '~') {
528 if ($this->row[$n] > 1) {
529 $row = " rowspan=\"{$this->row[$n]}\"";
531 if ($this->col[$n] > 1) {
532 $col = " colspan=\"{$this->col[$n]}\"";
534 $align = $width = '';
535 if (is_object($obj)) {
536 $align = $obj->align[$n];
537 if ($this->col[$n] == 1) {
538 $width = $obj->width[$n];
541 if (preg_match("/^(LEFT|CENTER|RIGHT):(.*)$/",$cell,$out)) {
542 $align = strtolower($out[1]);
545 if (preg_match('/^~(.+)$/',$cell,$matches)) {
546 $tag = 'th'; $cell = $matches[1];
551 $style = $width == '' ? '' : 'width:'.$width.'px;';
552 $style.= $align == '' ? '' : 'text-align:'.$align.';';
553 $style = $style == '' ? '' : ' style="'.$style.'"';
554 $cells .= "\n<$tag class=\"style_$tag\"$style$row$col>".inline2(inline($cell))."</$tag>\n";
556 return $this->wrap($cells,'tr');
559 class Col extends Row
566 $align = $width = '';
567 for ($n = count($this->elements) - 1; $n >= 0; $n--) {
568 if ($cells[$n] == '') {
569 $align = $width = '';
571 else if ($cells[$n] != '>') {
572 if (preg_match("/^(LEFT|CENTER|RIGHT):(.*)$/",$cells[$n],$out)) {
573 $align = strtolower($out[1]);
574 $width = htmlspecialchars($out[2]);
577 $this->align[$n] = $align;
578 $this->width[$n] = $width;
584 for ($n = 0; $n < count($this->elements); $n++) {
585 $cell = $this->elements[$n];
589 $span = " span=\"{$this->col[$n]}\"";
590 $align = $this->align[$n] == '' ? '' : ' align="'.$this->align[$n].'"';
591 $width = $this->width[$n] == '' ? '' : ' width="'.$this->width[$n].'"';
592 $cells .= "\n<colgroup$span$align$width></colgroup>\n";
597 class YTable extends Block
601 function YTable($text)
604 if (!preg_match_all('/("[^"]*(?:""[^"]*)*"|[^,]*),/',"$text,",$out)) {
605 $this = new Inline($text);
608 array_shift($out[1]);
610 foreach ($out[1] as $val) {
611 $_value[] = preg_match('/^"(.*)"$/',$val,$matches) ? str_replace('""','"',$matches[1]) : $val;
615 foreach($_value as $val) {
616 if (preg_match('/^(\s+)?(.+?)(\s+)?$/',$val,$matches)) {
617 $align[] =($matches[1] != '') ?
618 ((array_key_exists(3,$matches) and $matches[3] != '') ? ' style="text-align:center"' : ' style="text-align:right"') : '';
619 $value[] = $matches[2];
626 $this->col = count($value);
628 foreach ($value as $val) {
629 $colspan[] = ($val == '==') ? 0 : 1;
632 for ($i = 0; $i < count($value); $i++) {
634 while ($i + $colspan[$i] < count($value) and $value[$i + $colspan[$i]] == '==') {
637 $colspan[$i] = ($colspan[$i] > 1) ? " colspan=\"{$colspan[$i]}\"" : '';
638 $str .= "<td class=\"style_td\"{$align[$i]}{$colspan[$i]}>".inline2(inline($value[$i])).'</td>';
641 $this->elements[] = $str;
643 function canContain(&$obj)
645 return is_a($obj, 'YTable') and $obj->col == $this->col;
647 function &insert(&$obj)
649 $this->elements[] = $obj->elements[0];
655 foreach ($this->elements as $str) {
656 $rows .= "\n<tr class=\"style_tr\">$str</tr>\n";
661 <table class="style_table" cellspacing="1" border="0">
670 class Pre extends Block
677 while (preg_match('/^([^\t]*)(\t+)(.+)$/',$text,$m)) {
678 $text = $m[1].str_repeat(' ',strlen($m[2]) * $tab - strlen($m[1]) % $tab).$m[3];
680 $this->elements[] = htmlspecialchars($text,ENT_NOQUOTES);
682 function canContain(&$obj)
684 return is_a($obj, 'Pre');
686 function &insert(&$obj)
688 $this->elements[] = $obj->elements[0];
693 return $this->wrap(join("\n",$this->elements),'pre');
696 class Div extends Block
705 function canContain(&$obj)
711 if (preg_match("/^\#([^\(]+)(.*)$/",$this->text,$out) and exist_plugin_convert($out[1])) {
713 $_plugin = preg_replace("/^\#([^\(]+)\((.*)\)$/ex","do_plugin_convert('$1','$2')",$this->text);
716 $_plugin = preg_replace("/^\#([^\(]+)$/ex","do_plugin_convert('$1','$2')",$this->text);
718 $text = "\t$_plugin";
721 $text = "\n<p>".htmlspecialchars($this->text)."</p>\n";
726 class Align extends Body
727 { // LEFT:/CENTER:/RIGHT:
730 function Align($align)
732 $this->align = $align;
736 $string = parent::toString();
738 if (preg_match('/^(\s*<[^>]+style=")([^"]+)"/',$string,$matches)) {
739 $string = $matches[1]."text-align:{$this->align};".$matches[2];
742 $string = preg_replace('/^(\s*<[a-z]+)/', '$1 style="text-align:'.$this->align.';"',$string);
751 var $id,$count,$top,$contents,$last;
753 function Contents($id)
759 $this->top = "<a href=\"#contents_$id\">$top</a>";
760 $this->contents =& new Block();
761 $this->last =& $this->contents;
763 function getAnchor($text,$level)
765 $content_str = "content_{$this->id}_{$this->count}";
766 $this->last =& $this->last->add(new Contents_UList($text,$this->id,$level,$content_str));
768 return array(inline2(inline($text)).$this->top," id=\"{$content_str}\"");
770 function getContents()
772 global $strip_link_wall;
774 $contents = "<a id=\"contents_{$this->id}\"></a>";
775 $contents .= $this->contents->toString();
776 if ($strip_link_wall) {
777 $contents = preg_replace("/\[\[([^\]]+)\]\]/","$1",$contents);
782 class Contents_UList extends _List
786 function Contents_UList($text,$id,$level,$content_str)
789 // ¥Æ¥¥¹¥È¤Î¥ê¥Õ¥©¡¼¥à
790 // ¹ÔƬ\n¤ÇÀ°·ÁºÑ¤ß¤òɽ¤¹ ... X(
791 $text = "\n<a href=\"#{$content_str}\">".
792 strip_htmltag(inline2(inline($text,TRUE))).
794 parent::_List('ul', 'li', --$level, $text);