OSDN Git Service

no output GO TO CONTENTS link when $top is blank.
[pukiwiki/pukiwiki.git] / convert_html.php
1 <?php
2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
4 //
5 // $Id: convert_html.php,v 1.21 2003/02/20 12:22:51 panda Exp $
6 //
7 function &convert_html(&$lines)
8 {
9         global $script,$vars,$digest;
10         static $contents_id = 0;
11         
12         $digest = md5(join('',get_source($vars['page'])));
13         
14         $body = new Body(++$contents_id);
15         $body->parse($lines);
16         $ret = $body->toString();
17         
18         return $ret;
19 }
20
21 class Element
22 {
23         var $parent;
24         
25         function setParent(&$parent)
26         {
27                 $this->parent =& $parent;
28         }
29         function debug($indent = 0)
30         {
31                 return str_repeat(' ',$indent).get_class($this)."({$this->text})\n";
32         }
33 }
34
35 class Inline extends Element
36 { // ¥¤¥ó¥é¥¤¥óÍ×ÁÇ
37         var $text;
38         
39         function Inline($text)
40         {
41                 if (substr($text,0,1) == '~') { // ¹ÔƬ~¡£¥Ñ¥é¥°¥é¥Õ³«»Ï
42                         $parent =& $this->parent;
43                         $this = new Paragraph(' '.substr($text,1));
44                         $this->setParent($parent);
45                 }
46                 else {
47                         $this->text = (substr($text,0,1) == "\n") ? $text : inline2(inline($text));
48                 }
49         }
50         function &add(&$obj)
51         {
52                 return $this->insert($obj);
53         }
54         function &insert(&$obj)
55         {
56                 return $this->parent->add($obj);
57         }
58         function toString()
59         {
60                 return $this->text;
61         }
62         function toPara($class = '')
63         {
64                 $obj = new Paragraph('',$class);
65                 $obj->insert($this);
66                 $this->setParent($obj);
67                 return $obj;
68         }
69 }
70 class Block extends Element
71 { // ¥Ö¥í¥Ã¥¯Í×ÁÇ
72         var $elements; // Í×ÁǤÎÇÛÎó
73         
74         function Block() {
75                 $this->elements = array();
76         }
77         
78         function &add(&$obj) // ¥¨¥ì¥á¥ó¥È¤òÄɲÃ
79         {
80                 if ($this->canContain($obj)) {
81                         return $this->insert($obj);
82                 }
83                 return $this->parent->add($obj);
84         }
85         function &insert(&$obj)
86         {
87                 $obj->setParent($this);
88                 $this->elements[] =& $obj;
89                 if (isset($obj->last) and is_object($obj->last)) {
90                         return $obj->last;
91                 }
92                 return $obj;
93         }
94         function canContain($obj)
95         {
96                 return TRUE;
97         }
98         function toString()
99         {
100                 $ret = '';
101                 if (isset($this->elements) and count($this->elements) > 0) {
102                         foreach ($this->elements as $obj) {
103                                 $ret .= $obj->toString();
104                         }
105                 }
106                 return $ret;
107         }
108         function wrap($string, $tag, $param = '')
109         {
110                 return  ($string == '') ? '' : "\n<$tag$param>$string</$tag>\n";
111         }
112         function debug($indent = 0)
113         {
114                 $ret = parent::debug($indent);
115                 foreach (array_keys($this->elements) as $key) {
116                         if (is_object($this->elements[$key]))
117                                 $ret .= $this->elements[$key]->debug($indent + 2);
118                         else
119                                 $ret .= str_repeat(' ',$indent + 2).$this->elements[$key];
120                 }
121                 return $ret;
122         }
123 }
124 class Paragraph extends Block
125 { // ÃÊÍî
126         var $class;
127         
128         function Paragraph($text,$class='')
129         {
130                 parent::Block();
131                 $this->class = $class;
132                 if ($text == '') {
133                         return;
134                 }
135                 if (substr($text,0,1) == '~') {
136                         $text = ' '.substr($text,1);
137                 }
138                 $this->elements[] =& new Inline($text);
139         }
140         function canContain($obj)
141         {
142                 return is_a($obj,'Inline');
143         }
144         function toString()
145         {
146                 return $this->wrap(parent::toString(), 'p', $this->class);
147         }
148 }
149
150 class Heading extends Block
151 { // *
152         var $level,$top,$id;
153         
154         function Heading(&$root,$text)
155         {
156                 parent::Block();
157                 if (($level = strspn($text,'*')) > 3) {
158                         $level = 3;
159                 }
160                 $text = ltrim(substr($text,$level));
161                 $this->level = ++$level;
162                 list($this->top,$this->id) = $root->getAnchor($text,$level);
163                 $this->last =& $this->insert(new Inline($text));
164         }
165         function canContain(&$obj)
166         {
167                 return FALSE;
168         }
169         function toString()
170         {
171                 return $this->wrap(parent::toString().$this->top,'h'.$this->level," id=\"{$this->id}\"");
172         }
173 }
174 class HRule extends Block
175 { // ----
176         function HRule(&$root,$text) {
177                 parent::Block();
178         }
179         function canContain(&$obj)
180         {
181                 return FALSE;
182         }
183         function toString()
184         {
185                 global $hr;
186                 
187                 return $hr;
188         }
189 }
190 class ListContainer extends Block
191 {
192         var $tag,$tag2,$level,$style;
193         
194         function ListContainer($tag,$tag2,$level,$text)
195         {
196                 parent::Block();
197                 //¥Þ¡¼¥¸¥ó¤ò¼èÆÀ
198                 $var_margin = "_{$tag}_margin";
199                 $var_left_margin = "_{$tag}_left_margin";
200                 global $$var_margin, $$var_left_margin;
201                 $this->margin = $$var_margin;
202                 $this->left_margin = $$var_left_margin;
203
204                 //½é´ü²½
205                 $this->tag = $tag;
206                 $this->tag2 = $tag2;
207                 $this->level = $level;
208                 
209                 if ($text != '') {
210                         $this->insert(new Inline($text));
211                 }
212         }
213
214         function canContain(&$obj)
215         {
216                 return is_a($obj, 'ListContainer') ? ($this->tag == $obj->tag and $this->level == $obj->level) : TRUE;
217         }
218         function setParent(&$parent)
219         {
220                 global $_list_left_margin, $_list_margin, $_list_pad_str;
221
222                 parent::setParent($parent);
223                 $step = $this->level;
224                 if (isset($parent->parent) and is_a($parent->parent,'ListContainer')) {
225                         $step -= $parent->parent->level; 
226                 }
227                 $margin = $_list_margin * $step;
228                 if ($step == $this->level) {
229                         $margin += $_list_left_margin;
230                 }
231                 $this->style = sprintf($_list_pad_str,$this->level,$margin,$margin);
232         }
233         function &insert(&$obj)
234         {
235                 if (is_a($obj, get_class($this))) {
236                         for ($n = 0; $n < count($obj->elements); $n++) {
237                                 $this->last =& parent::insert($obj->elements[$n]);
238                         }
239                         return $this->last;
240                 }
241                 $obj =& new ListElement($obj, $this->level, $this->tag2); // wrap
242                 $this->last =& $obj;
243                 return parent::insert($obj);
244         }
245         function toString($param='')
246         {
247                 return $this->wrap(parent::toString(),$this->tag,$this->style.$param);
248         }
249 }
250 class ListElement extends Block
251 {
252         function ListElement(&$obj,$level,$head)
253         {
254                 parent::Block();
255                 $this->level = $level;
256                 $this->head = $head;
257                 $this->insert($obj);
258                 $this->last = NULL;
259                 if (isset($obj->last) and is_object($obj->last)) {
260                         $this->last =& $obj->last;
261                 }
262         }
263         function canContain(&$obj)
264         {
265                 return !(is_a($obj, 'ListContainer') and ($obj->level <= $this->level));
266         }
267         function toString()
268         {
269                 return $this->wrap(parent::toString(), $this->head);
270         }
271 }
272 class UList extends ListContainer
273 { // -
274         function UList(&$root,$text)
275         {
276                 if (($level = strspn($text,'-')) > 3) {
277                         $level = 3; // limitation ;(
278                 }
279                 $text = ltrim(substr($text,$level));
280                 parent::ListContainer('ul','li',$level,$text);
281         }
282 }
283 class OList extends ListContainer
284 { // +
285         function OList(&$root,$text)
286         {
287                 if (($level = strspn($text,'+')) > 3) {
288                         $level = 3; // limitation ;(
289                 }
290                 $text = ltrim(substr($text,$level));
291                 parent::ListContainer('ol','li',$level,$text);
292         }
293 }
294 class DList extends ListContainer
295 { // :
296         function DList(&$root,$text)
297         {
298                 if (($level = strspn($text,':')) > 3) {
299                         $level = 3; // limitation ;(
300                 }
301                 $out = explode('|',ltrim(substr($text,$level)),2);
302                 if (count($out) < 2) {
303                         $this = new Inline($text);
304                         return;
305                 }
306                 parent::ListContainer('dl','dd',$level,$out[1]);
307                 if ($out[0] != '') {
308                         array_unshift($this->elements,new Inline("\n<dt>".inline2(inline($out[0]))."</dt>\n"));
309                 }
310         }
311 }
312 class BQuote extends Block
313 { // >
314         var $level;
315         
316         function BQuote(&$root,$text)
317         {
318                 parent::Block();
319                 $head = substr($text,0,1);
320                 if (($level = strspn($text,$head)) > 3) {
321                         $level = 3; // limitation ;(
322                 }
323                 $this->level = $level;
324                 $text = ltrim(substr($text,$level));
325                 if ($head == '<') { //blockquote close
326                         $this->level = 0;
327                         $this->last =& $this->end($root,$level,$text);
328                 }
329                 else {
330                         $this->last =& $this->insert(new Paragraph($text, ' class="quotation"'));
331                 }
332         }
333         function canContain(&$obj)
334         {
335                 if (!is_a($obj, get_class($this))) {
336                         return TRUE;
337                 }
338                 return ($obj->level >= $this->level);
339         }
340         function &insert(&$obj)
341         {
342                 if (is_a($obj, 'BQuote') and $obj->level == $this->level) {
343                         if (is_a($this->last,'Paragraph')
344                                 and array_key_exists(0,$obj->elements[0])
345                                 and is_object($obj->elements[0]->elements[0])) {
346                                 $this->last->insert($obj->elements[0]->elements[0]);
347                         } else {
348                                 $this->last =& $this->insert($obj->elements[0]);
349                         }
350                         return $this->last;
351                 }
352                 $this->last =& $obj;
353                 return parent::insert($obj);
354         }
355         function toString()
356         {
357                 return $this->wrap(parent::toString(),'blockquote');
358         }
359         function &end(&$root,$level,$text)
360         {
361                 $parent =& $root->last;
362                 while (is_object($parent)) {
363                         if (is_a($parent,'BQuote') and $parent->level == $level) {
364                                 return $parent->parent->insert(new Inline($text));
365                         }
366                         $parent =& $parent->parent;
367                 }
368                 return $this->insert(new Inline($text));
369         }
370 }
371 class TableCell extends Block
372 {
373         var $tag = 'td'; // {td|th}
374         var $colspan = 1;
375         var $rowspan = 1;
376         var $style; // is array('width'=>, 'align'=>...);
377         
378         function TableCell($text,$is_template=FALSE) {
379                 parent::Block();
380                 $this->style = array();
381                 
382                 if (preg_match("/^(LEFT|CENTER|RIGHT):(.*)$/",$text,$out)) {
383                         $this->style['align'] = 'text-align:'.strtolower($out[1]).';';
384                         $text = $out[2];
385                 }
386                 if ($is_template) {
387                         if (is_numeric($text)) {
388                                 $this->style['width'] = "width:{$text}px;";
389                         }
390                 }
391                 if ($text == '>') {
392                         $this->colspan = 0;
393                 }
394                 else if ($text == '~') {
395                         $this->rowspan = 0;
396                 }
397                 else if (substr($text,0,1) == '~') {
398                         $this->tag = 'th';
399                         $text = substr($text,1);
400                 }
401                 $this->last =& $this->insert(new Inline($text));
402         }
403         function setStyle(&$style) {
404                 foreach ($style as $key=>$value) {
405                         if (!array_key_exists($key,$this->style)) {
406                                 $this->style[$key] = $value;
407                         }
408                 }
409         }
410         function toString() {
411                 if ($this->rowspan == 0 or $this->colspan == 0) {
412                         return '';
413                 }
414                 $param = " class=\"style_{$this->tag}\"";
415                 if ($this->rowspan > 1) {
416                         $param .= " rowspan=\"{$this->rowspan}\"";
417                 }
418                 if ($this->colspan > 1) {
419                         $param .= " colspan=\"{$this->colspan}\"";
420                         unset($this->style['width']);
421                 }
422                 if (count($this->style)) {
423                         $param .= ' style="'.join(' ',$this->style).'"';
424                 }
425                 return "\n<{$this->tag}$param>".parent::toString()."</{$this->tag}>\n";
426         }
427 }
428 class Table extends Block
429 { // |
430         var $type,$types;
431         var $col; // number of column
432         
433         function Table(&$root,$text)
434         {
435                 if (!preg_match("/^\|(.+)\|([hHfFcC]?)$/",$text,$out)) {
436                         $this = new Inline($text);
437                         return;
438                 }
439                 parent::Block();
440                 $cells = explode('|',$out[1]);
441                 $this->col = count($cells);
442                 $this->type = strtolower($out[2]);
443                 $this->types = array($this->type);
444                 $is_template = ($this->type == 'c');
445                 $row = array();
446                 foreach ($cells as $cell) {
447                         $row[] = new TableCell($cell,$is_template);
448                 }
449                 $this->elements[] = $row;
450                 $this->last =& $this;
451         }
452         function canContain(&$obj)
453         {
454                 return is_a($obj, 'Table') and ($obj->col == $this->col);
455         }
456         function &insert(&$obj)
457         {
458                 $this->elements[] = $obj->elements[0];
459                 $this->types[] = $obj->type;
460                 return $this;
461         }
462         function toString()
463         {
464                 // rowspan¤òÀßÄê(²¼¤«¤é¾å¤Ø)
465                 for ($ncol = 0; $ncol < $this->col; $ncol++) {
466                         $rowspan = 1;
467                         foreach (array_reverse(array_keys($this->elements)) as $nrow) {
468                                 $row =& $this->elements[$nrow];
469                                 if ($row[$ncol]->rowspan == 0) {
470                                         $rowspan++;
471                                 }
472                                 else {
473                                         $row[$ncol]->rowspan = $rowspan;
474                                         while (--$rowspan) { // ¹Ô¼ïÊ̤ò·Ñ¾µ¤¹¤ë
475                                                 $this->types[$nrow + $rowspan] = $this->types[$nrow];
476                                         }
477                                         $rowspan = 1;
478                                 }
479                         }
480                 }
481                 // colspan,style¤òÀßÄê
482                 $stylerow = NULL;
483                 foreach (array_keys($this->elements) as $nrow) {
484                         $row =& $this->elements[$nrow];
485                         if ($this->types[$nrow] == 'c') {
486                                 $stylerow =& $row;
487                         }
488                         $colspan = 1;
489                         foreach (array_keys($row) as $ncol) {
490                                 if ($row[$ncol]->colspan == 0) {
491                                         $colspan++;
492                                 }
493                                 else {
494                                         $row[$ncol]->colspan = $colspan;
495                                         if ($stylerow !== NULL) {
496                                                 $row[$ncol]->setStyle($stylerow[$ncol]->style);
497                                                 while (--$colspan) { // Îó¥¹¥¿¥¤¥ë¤ò·Ñ¾µ¤¹¤ë
498                                                         $row[$ncol - $colspan]->setStyle($stylerow[$ncol]->style);
499                                                 }
500                                         }
501                                         $colspan = 1;
502                                 }
503                         }
504                 }
505                 // ¥Æ¥­¥¹¥È²½
506                 $string = '';
507                 $parts = array('h'=>'thead',''=>'tbody','f'=>'tfoot');
508                 foreach ($parts as $type=>$part) {
509                         $part_string = '';
510                         foreach (array_keys($this->elements) as $nrow) {
511                                 if ($this->types[$nrow] != $type) {
512                                         continue;
513                                 }
514                                 $row =& $this->elements[$nrow];
515                                 $row_string = '';
516                                 foreach (array_keys($row) as $ncol) {
517                                         $row_string .= $row[$ncol]->toString();
518                                 }
519                                 $part_string .= $this->wrap($row_string,'tr');
520                         }
521                         $string .= $this->wrap($part_string,$part);
522                 }
523                 return <<<EOD
524 <div class="ie5">
525  <table class="style_table" cellspacing="1" border="0">
526   $string
527  </table>
528 </div>
529 EOD;
530         }
531 }
532 class YTable extends Block
533 { // ,
534         var $col;
535         
536         function YTable(&$root,$text)
537         {
538                 parent::Block();
539                 if (!preg_match_all('/("[^"]*(?:""[^"]*)*"|[^,]*),/',"$text,",$out)) {
540                         $this = new Inline($text);
541                         return;
542                 }
543                 array_shift($out[1]);
544                 $_value = array();
545                 foreach ($out[1] as $val) {
546                         $_value[] = preg_match('/^"(.*)"$/',$val,$matches) ? str_replace('""','"',$matches[1]) : $val;
547                 }
548                 $align = array();
549                 $value = array();
550                 foreach($_value as $val) {
551                         if (preg_match('/^(\s+)?(.+?)(\s+)?$/',$val,$matches)) {
552                                 $align[] =($matches[1] != '') ?
553                                         ((array_key_exists(3,$matches) and $matches[3] != '') ? ' style="text-align:center"' : ' style="text-align:right"') : '';
554                                 $value[] = $matches[2];
555                         }
556                         else {
557                                 $align[] = '';
558                                 $value[] = $val;
559                         }
560                 }
561                 $this->col = count($value);
562                 $colspan = array();
563                 foreach ($value as $val) {
564                         $colspan[] = ($val == '==') ? 0 : 1;
565                 }
566                 $str = '';
567                 for ($i = 0; $i < count($value); $i++) {
568                         if ($colspan[$i]) {
569                                 while ($i + $colspan[$i] < count($value) and $value[$i + $colspan[$i]] == '==') {
570                                         $colspan[$i]++;
571                                 }
572                                 $colspan[$i] = ($colspan[$i] > 1) ? " colspan=\"{$colspan[$i]}\"" : '';
573                                 $str .= "<td class=\"style_td\"{$align[$i]}{$colspan[$i]}>".inline2(inline($value[$i])).'</td>';
574                         }
575                 }
576                 $this->elements[] = $str;
577         }
578         function canContain(&$obj)
579         {
580                 return is_a($obj, 'YTable') and ($obj->col == $this->col);
581         }
582         function &insert(&$obj)
583         {
584                 $this->elements[] = $obj->elements[0];
585                 return $this;
586         }
587         function toString()
588         {
589                 $rows = '';
590                 foreach ($this->elements as $str) {
591                         $rows .= "\n<tr class=\"style_tr\">$str</tr>\n";
592                 }
593                 return <<<EOD
594
595 <div class="ie5">
596  <table class="style_table" cellspacing="1" border="0">
597   $rows
598  </table>
599 </div>
600
601 EOD;
602         }
603 }
604 class Pre extends Block
605 { // ' '
606         
607         function Pre(&$root,$text)
608         {
609                 parent::Block();
610                 $this->elements[] = htmlspecialchars($text,ENT_NOQUOTES);
611         }
612         function canContain(&$obj)
613         {
614                 return is_a($obj, 'Pre');
615         }
616         function &insert(&$obj)
617         {
618                 $this->elements[] = $obj->elements[0];
619                 return $this;
620         }
621         function toString()
622         {
623                 return $this->wrap(join("\n",$this->elements),'pre');
624         }
625 }
626 class Div extends Block
627 { // #
628         var $name,$param;
629         
630         function Div(&$root,$text)
631         {
632                 if (!preg_match("/^\#([^\(]+)(?:\((.*)\))?/",$text,$out) or !exist_plugin_convert($out[1])) {
633                         $this = new Inline($text);
634                         return;
635                 }
636                 parent::Block();
637                 $this->name = $out[1];
638                 $this->param = array_key_exists(2,$out) ? $out[2] : '';
639         }
640         function canContain(&$obj)
641         {
642                 return FALSE;
643         }
644         function toString()
645         {
646                 return do_plugin_convert($this->name,$this->param);
647         }
648 }
649 class Align extends Block
650 { // LEFT:/CENTER:/RIGHT:
651         var $align;
652         
653         function Align($align)
654         {
655                 $this->align = $align;
656         }
657         function &insert(&$obj)
658         {
659                 if (is_a($obj,'Inline')) {
660                         $obj =& $obj->toPara();
661                 }
662                 return parent::insert($obj);
663         }
664         function toString()
665         {
666                 $string = parent::toString();
667                 if ($string != '') {
668                         if (preg_match('/^(\s*<[^>]+style=")(.+)$"/',$string,$matches)) {
669                                 $string = $matches[1]."text-align:{$this->align};".$matches[2];
670                         }
671                         else {
672                                 $string = preg_replace('/^(\s*<[a-z]+)/', '$1 style="text-align:'.$this->align.';"',$string);
673                         }
674                 }
675                 return $string;
676         }
677 }
678 class Body extends Block
679 { // Body
680         var $id,$count,$top,$contents,$contents_last;
681         var $classes = array('HRule','Heading','Pre','UList','OList','DList','Table','YTable','BQuote','BQuoteEnd','Div');
682
683         function Body($id)
684         {
685                 global $top;
686                 
687                 $this->id = $id;
688                 $this->count = 0;
689                 $this->top = $top ? "<a href=\"#contents_$id\">$top</a>" : '';
690                 $this->contents = new Block();
691                 $this->contents_last =& $this->contents;
692                 parent::Block();
693         }
694         function parse(&$lines)
695         {
696                 $this->last =& $this;
697                 
698                 foreach ($lines as $line) {
699                         if (substr($line,0,2) == '//') { //¥³¥á¥ó¥È¤Ï½èÍý¤·¤Ê¤¤
700                                 continue;
701                         }
702                         
703                         $align = '';
704                         if (preg_match('/^(LEFT|CENTER|RIGHT):(.*)$/',$line,$matches)) {
705                                 $this->last =& $this->last->add(new Align(strtolower($matches[1]))); // <div style="text-align:...">
706                                 if ($matches[2] == '') {
707                                         continue;
708                                 }
709                                 $line = $matches[2];
710                         }
711                         
712                         $line = preg_replace("/[\r\n]*$/",'',$line);
713                         
714                         // ¹ÔƬʸ»ú
715                         $head = substr($line,0,1);
716                         
717                         if ($line == '') { // ¶õ¹Ô
718                                 $this->last =& $this;
719                         }
720                         else if (substr($line,0,4) == '----') { // HRule
721                                 $this->last =& $this->insert(new HRule($this,$line));
722                         }
723                         else if ($head == '*') { // Heading
724                                 $this->last =& $this->insert(new Heading($this,$line));
725                         }
726                         else if ($head == ' ' or $head == "\t") { // Pre
727                                 $this->last =& $this->last->add(new Pre($this,$line));
728                         }
729                         else {
730                                 if (substr($line,-1) == '~') {
731                                         $line = substr($line,0,-1)."\r";
732                                 }
733                                 if      ($head == '-') { // UList
734                                         $this->last =& $this->last->add(new UList($this,$line)); // inline
735                                 }
736                                 else if ($head == '+') { // OList
737                                         $this->last =& $this->last->add(new OList($this,$line)); // inline
738                                 }
739                                 else if ($head == ':') { // DList
740                                         $this->last =& $this->last->add(new DList($this,$line)); // inline
741                                 }
742                                 else if ($head == '|') { // Table
743                                         $this->last =& $this->last->add(new Table($this,$line));
744                                 }
745                                 else if ($head == ',') { // Table(YukiWiki¸ß´¹)
746                                         $this->last =& $this->last->add(new YTable($this,$line));
747                                 }
748                                 else if ($head == '>' or $head == '<') { // BrockQuote
749                                         $this->last =& $this->last->add(new BQuote($this,$line));
750                                 }
751                                 else if ($head == '#') { // Div
752                                         $this->last =& $this->last->add(new Div($this,$line));
753                                 }
754                                 else { // Ä̾ïʸ»úÎó
755                                         $this->last =& $this->last->add(new Inline($line));
756                                 }
757                         }
758                 }
759         }
760         function getAnchor($text,$level)
761         {
762                 $id = "content_{$this->id}_{$this->count}";
763                 $this->count++;
764                 $this->contents_last =& $this->contents_last->add(new Contents_UList($text,$this->id,$level,$id));
765                 return array(&$this->top,$id);
766         }
767         function getContents()
768         {
769                 $contents  = "<a id=\"contents_{$this->id}\"></a>";
770                 $contents .= $this->contents->toString();
771                 return $contents;
772         }
773         function &insert(&$obj)
774         {
775                 if (is_a($obj,'Inline')) {
776                         $obj =& $obj->toPara();
777                 }
778                 return parent::insert($obj);
779         }
780         function toString()
781         {
782                 global $vars;
783                 
784                 $text = parent::toString();
785                 
786                 // #contents
787                 $text = preg_replace('/<p[^>]*>#contents<\/p>/',$this->getContents(),$text);
788                 
789                 // ´ØÏ¢¤¹¤ë¥Ú¡¼¥¸
790                 // <p>¤Î¤È¤­¤Ï¹ÔƬ¤«¤é¡¢<del>¤Î¤È¤­¤Ï¾¤ÎÍ×ÁǤλÒÍ×ÁǤȤ·¤Æ¸ºß
791                 $text = preg_replace('/<(p|del)>#related<\/\1>/e','make_related($vars[\'page\'],\'$1\')',$text);
792                 return $text;
793         }
794 }
795 class Contents_UList extends ListContainer
796 {
797         function Contents_UList($text,$id,$level,$id)
798         {
799                 // ¥Æ¥­¥¹¥È¤Î¥ê¥Õ¥©¡¼¥à
800                 // ¹ÔƬ\n¤ÇÀ°·ÁºÑ¤ß¤òɽ¤¹ ... X(
801                 $text = "\n<a href=\"#$id\">".strip_htmltag(inline2(inline($text,TRUE)))."</a>\n";
802                 parent::ListContainer('ul', 'li', --$level, $text);
803         }
804 }
805 ?>