OSDN Git Service

Merged from r1_4_4 to branch_r1_4_4_php5_end
[pukiwiki/pukiwiki.git] / lib / convert_html.php
1 <?php
2 /////////////////////////////////////////////////
3 // PukiWiki - Yet another WikiWikiWeb clone.
4 //
5 // $Id: convert_html.php,v 1.2 2004/09/19 14:05:30 henoheno Exp $
6 //
7
8 function convert_html($lines)
9 {
10         global $vars, $digest;
11         static $contents_id = 0;
12
13         if (!is_array($lines))
14         {
15                 $lines = explode("\n", $lines);
16         }
17
18         $digest = md5(join('', get_source($vars['page'])));
19
20         $body = &new Body(++$contents_id);
21         $body->parse($lines);
22         $ret = $body->toString();
23
24         return $ret;
25 }
26
27 class Element
28 { // ¥Ö¥í¥Ã¥¯Í×ÁÇ
29         var $parent;   // ¿ÆÍ×ÁÇ
30         var $last;     // ¼¡¤ËÍ×ÁǤòÁÞÆþ¤¹¤ëÀè
31         var $elements; // Í×ÁǤÎÇÛÎó
32
33         function Element()
34         {
35                 $this->elements = array();
36                 $this->last = &$this;
37         }
38
39         function setParent(&$parent)
40         {
41                 $this->parent = &$parent;
42         }
43
44         function &add(&$obj)
45         {
46                 if ($this->canContain($obj))
47                 {
48                         return $this->insert($obj);
49                 }
50
51                 return $this->parent->add($obj);
52         }
53
54         function &insert(&$obj)
55         {
56                 $obj->setParent($this);
57                 $this->elements[] = &$obj;
58
59                 return $this->last = &$obj->last;
60         }
61         function canContain($obj)
62         {
63                 return TRUE;
64         }
65
66         function wrap($string, $tag, $param = '', $canomit = TRUE)
67         {
68                 return ($canomit and $string == '') ? '' : "<$tag$param>$string</$tag>";
69         }
70
71         function toString()
72         {
73                 $ret = array();
74                 foreach (array_keys($this->elements) as $key)
75                 {
76                         $ret[] = $this->elements[$key]->toString();
77                 }
78
79                 return join("\n",$ret);
80         }
81
82         function dump($indent = 0)
83         {
84                 $ret = str_repeat(' ', $indent).get_class($this)."\n";
85
86                 $indent += 2;
87
88                 foreach (array_keys($this->elements) as $key)
89                 {
90                         $ret .= is_object($this->elements[$key]) ?
91                                 $this->elements[$key]->dump($indent) : '';
92                                 //str_repeat(' ',$indent).$this->elements[$key];
93                 }
94
95                 return $ret;
96         }
97 }
98
99   // PHP5 mod: $this cannot be reassigned
100 function &Factory_Inline($text)
101 {
102         if (substr($text,0,1) == '~') { // ¹ÔƬ~¡£¥Ñ¥é¥°¥é¥Õ³«»Ï
103                 return new Paragraph(' '.substr($text,1));
104         }
105         return new Inline($text);
106 }
107
108   // PHP5 mod: $this cannot be reassigned
109 function &Factory_DList(&$root, $text)
110 {
111         $out = explode('|', ltrim($text), 2);
112         if (count($out) < 2) {
113                 return Factory_Inline($text);
114         }
115
116         return new DList($out);
117 }
118
119   // PHP5 mod: $this cannot be reassigned
120 function &Factory_Table(&$root, $text)
121 {
122         if (!preg_match("/^\|(.+)\|([hHfFcC]?)$/",$text,$out)) {
123                 return Factory_Inline($text);
124         }
125         return new Table($out);
126 }
127
128   // PHP5 mod: $this cannot be reassigned
129 function &Factory_YTable(&$root,$text)
130 {
131         $_value = csv_explode(',', substr($text,1));
132         if (count($_value) == 0) {
133                 return Factory_Inline($text);
134         }
135         return new YTable($_value);
136 }
137
138   // PHP5 mod: $this cannot be reassigned
139 function &Factory_Div(&$root,$text)
140 {
141         if (!preg_match("/^\#([^\(]+)(?:\((.*)\))?/", $text, $out) or !exist_plugin_convert($out[1])) {
142                 return new Paragraph($text);
143         }
144         return new Div($out);
145 }
146
147 class Inline extends Element
148 { // ¥¤¥ó¥é¥¤¥óÍ×ÁÇ
149
150         function Inline($text)
151         {
152                 parent::Element();
153
154                 $this->elements[] = trim((substr($text, 0, 1) == "\n") ? $text : make_link($text));
155         }
156
157         function &insert(&$obj)
158         {
159                 $this->elements[] = $obj->elements[0];
160
161                 return $this;
162         }
163
164         function canContain($obj)
165         {
166                 return is_a($obj,'Inline');
167         }
168
169         function toString()
170         {
171                 global $line_break;
172
173                 return join($line_break ? "<br />\n" : "\n",$this->elements);
174         }
175
176         function &toPara($class = '')
177         {
178                 $obj = &new Paragraph('', $class);
179                 $obj->insert($this);
180                 return $obj;
181         }
182 }
183
184 class Paragraph extends Element
185 { // ÃÊÍî
186         var $param;
187
188         function Paragraph($text, $param = '')
189         {
190                 parent::Element();
191
192                 $this->param = $param;
193                 if ($text == '')
194                 {
195                         return;
196                 }
197                 if (substr($text,0,1) == '~')
198                 {
199                         $text = ' '.substr($text, 1);
200                 }
201                 $this->insert(Factory_Inline($text));
202         }
203
204         function canContain($obj)
205         {
206                 return is_a($obj,'Inline');
207         }
208
209         function toString()
210         {
211                 return $this->wrap(parent::toString(), 'p', $this->param);
212         }
213 }
214
215 class Heading extends Element
216 { // *
217         var $level;
218         var $id;
219         var $msg_top;
220
221         function Heading(&$root, $text)
222         {
223                 parent::Element();
224
225                 $this->level = min(3, strspn($text, '*'));
226                 list($text, $this->msg_top, $this->id) = $root->getAnchor($text, $this->level);
227                 $this->insert(Factory_Inline($text));
228                 $this->level++; // h2,h3,h4
229         }
230
231         function &insert(&$obj)
232         {
233                 parent::insert($obj);
234                 return $this->last = &$this;
235         }
236
237         function canContain(&$obj)
238         {
239                 return FALSE;
240         }
241
242         function toString()
243         {
244                 return $this->msg_top.$this->wrap(parent::toString(), 'h'.$this->level, " id=\"{$this->id}\"");
245         }
246 }
247
248 class HRule extends Element
249 { // ----
250
251         function HRule(&$root, $text)
252         {
253                 parent::Element();
254         }
255
256         function canContain(&$obj)
257         {
258                 return FALSE;
259         }
260
261         function toString()
262         {
263                 global $hr;
264
265                 return $hr;
266         }
267 }
268
269 class ListContainer extends Element
270 {
271         var $tag;
272         var $tag2;
273         var $level;
274         var $style;
275         var $margin;
276         var $left_margin;
277
278         function ListContainer($tag, $tag2, $head, $text)
279         {
280                 parent::Element();
281
282                 //¥Þ¡¼¥¸¥ó¤ò¼èÆÀ
283                 $var_margin = "_{$tag}_margin";
284                 $var_left_margin = "_{$tag}_left_margin";
285                 global $$var_margin, $$var_left_margin;
286                 $this->margin = $$var_margin;
287                 $this->left_margin = $$var_left_margin;
288
289                 //½é´ü²½
290                 $this->tag = $tag;
291                 $this->tag2 = $tag2;
292                 $this->level = min(3, strspn($text, $head));
293                 $text = ltrim(substr($text, $this->level));
294
295                 parent::insert(new ListElement($this->level, $tag2));
296                 if ($text != '')
297                 {
298                         $this->last = &$this->last->insert(Factory_Inline($text));
299                 }
300         }
301
302         function canContain(&$obj)
303         {
304                 return (!is_a($obj, 'ListContainer')
305                         or ($this->tag == $obj->tag and $this->level == $obj->level));
306         }
307
308         function setParent(&$parent)
309         {
310                 global $_list_pad_str;
311
312                 parent::setParent($parent);
313
314                 $step = $this->level;
315                 if (isset($parent->parent) and is_a($parent->parent, 'ListContainer'))
316                 {
317                         $step -= $parent->parent->level;
318                 }
319                 $margin = $this->margin * $step;
320                 if ($step == $this->level)
321                 {
322                         $margin += $this->left_margin;
323                 }
324                 $this->style = sprintf($_list_pad_str, $this->level, $margin, $margin);
325         }
326
327         function &insert(&$obj)
328         {
329                 if (!is_a($obj, get_class($this)))
330                 {
331                         return $this->last = &$this->last->insert($obj);
332                 }
333         // ¹ÔƬʸ»ú¤Î¤ß¤Î»ØÄê»þ¤ÏUL/OL¥Ö¥í¥Ã¥¯¤òæ½Ð
334         // BugTrack/524
335                 if (count($obj->elements) == 1 && count($obj->elements[0]->elements) == 0)
336                 {
337                         return $this->last->parent; // up to ListElement.
338                 }
339                 // move elements.
340                 foreach(array_keys($obj->elements) as $key)
341                 {
342                         parent::insert($obj->elements[$key]);
343                 }
344
345                 return $this->last;
346         }
347
348         function toString()
349         {
350                 return $this->wrap(parent::toString(), $this->tag, $this->style);
351         }
352 }
353
354 class ListElement extends Element
355 {
356         function ListElement($level, $head)
357         {
358                 parent::Element();
359                 $this->level = $level;
360                 $this->head = $head;
361         }
362
363         function canContain(&$obj)
364         {
365                 return (!is_a($obj, 'ListContainer') or ($obj->level > $this->level));
366         }
367
368         function toString()
369         {
370                 return $this->wrap(parent::toString(), $this->head);
371         }
372 }
373
374 class UList extends ListContainer
375 { // -
376         function UList(&$root, $text)
377         {
378                 parent::ListContainer('ul', 'li', '-', $text);
379         }
380 }
381
382 class OList extends ListContainer
383 { // +
384         function OList(&$root, $text)
385         {
386                 parent::ListContainer('ol', 'li', '+', $text);
387         }
388 }
389
390 class DList extends ListContainer
391 { // :
392         function DList($out)
393         {
394                 parent::ListContainer('dl', 'dt', ':', $out[0]);
395
396                 $this->last = &Element::insert(new ListElement($this->level, 'dd'));
397                 if ($out[1] != '')
398                 {
399                         $this->last = &$this->last->insert(Factory_Inline($out[1]));
400                 }
401         }
402 }
403
404 class BQuote extends Element
405 { // >
406         var $level;
407
408         function BQuote(&$root, $text)
409         {
410                 parent::Element();
411
412                 $head = substr($text, 0, 1);
413                 $this->level = min(3, strspn($text, $head));
414                 $text = ltrim(substr($text, $this->level));
415
416                 if ($head == '<') //blockquote close
417                 {
418                         $level = $this->level;
419                         $this->level = 0;
420                         $this->last = &$this->end($root, $level);
421                         if ($text != '')
422                         {
423                                 $this->last = &$this->last->insert(Factory_Inline($text));
424                         }
425                 }
426                 else
427                 {
428                         $this->insert(Factory_Inline($text));
429                 }
430         }
431
432         function canContain(&$obj)
433         {
434                 return (!is_a($obj, get_class($this)) or $obj->level >= $this->level);
435         }
436
437         function &insert(&$obj)
438         {
439         // BugTrack/521, BugTrack/545
440                 if (is_a($obj, 'inline')) {
441                 return parent::insert($obj->toPara(' class="quotation"'));
442         }
443                 if (is_a($obj, 'BQuote') and $obj->level == $this->level and count($obj->elements))
444                 {
445                         $obj = &$obj->elements[0];
446                         if (is_a($this->last,'Paragraph') and count($obj->elements))
447                         {
448                                 $obj = &$obj->elements[0];
449                         }
450                 }
451                 return parent::insert($obj);
452         }
453
454         function toString()
455         {
456                 return $this->wrap(parent::toString(), 'blockquote');
457         }
458
459         function &end(&$root, $level)
460         {
461                 $parent = &$root->last;
462
463                 while (is_object($parent))
464                 {
465                         if (is_a($parent,'BQuote') and $parent->level == $level)
466                         {
467                                 return $parent->parent;
468                         }
469                         $parent = &$parent->parent;
470                 }
471                 return $this;
472         }
473 }
474
475 class TableCell extends Element
476 {
477         var $tag = 'td'; // {td|th}
478         var $colspan = 1;
479         var $rowspan = 1;
480         var $style; // is array('width'=>, 'align'=>...);
481
482         function TableCell($text, $is_template = FALSE)
483         {
484                 parent::Element();
485                 $this->style = $matches = array();
486
487                 while (preg_match('/^(?:(LEFT|CENTER|RIGHT)|(BG)?COLOR\(([#\w]+)\)|SIZE\((\d+)\)):(.*)$/',$text,$matches))
488                 {
489                         if ($matches[1])
490                         {
491                                 $this->style['align'] = 'text-align:'.strtolower($matches[1]).';';
492                                 $text = $matches[5];
493                         }
494                         else if ($matches[3])
495                         {
496                                 $name = $matches[2] ? 'background-color' : 'color';
497                                 $this->style[$name] = $name.':'.htmlspecialchars($matches[3]).';';
498                                 $text = $matches[5];
499                         }
500                         else if ($matches[4])
501                         {
502                                 $this->style['size'] = 'font-size:'.htmlspecialchars($matches[4]).'px;';
503                                 $text = $matches[5];
504                         }
505                 }
506                 if ($is_template and is_numeric($text))
507                 {
508                         $this->style['width'] = "width:{$text}px;";
509                 }
510                 if ($text == '>')
511                 {
512                         $this->colspan = 0;
513                 }
514                 else if ($text == '~')
515                 {
516                         $this->rowspan = 0;
517                 }
518                 else if (substr($text, 0, 1) == '~')
519                 {
520                         $this->tag = 'th';
521                         $text = substr($text, 1);
522                 }
523                 if ($text != '' and $text{0} == '#')
524                 {
525                         // ¥»¥ëÆâÍƤ¬'#'¤Ç»Ï¤Þ¤ë¤È¤­¤ÏDiv¥¯¥é¥¹¤òÄ̤·¤Æ¤ß¤ë
526                         $obj = &Factory_Div($this, $text);
527                         if (is_a($obj, 'Paragraph'))
528                         {
529                                 $obj = &$obj->elements[0];
530                         }
531                 }
532                 else
533                 {
534                         $obj = &Factory_Inline($text);
535                 }
536                 $this->insert($obj);
537         }
538
539         function setStyle(&$style)
540         {
541                 foreach ($style as $key=>$value)
542                 {
543                         if (!array_key_exists($key, $this->style))
544                         {
545                                 $this->style[$key] = $value;
546                         }
547                 }
548         }
549
550         function toString()
551         {
552                 if ($this->rowspan == 0 or $this->colspan == 0)
553                 {
554                         return '';
555                 }
556                 $param = " class=\"style_{$this->tag}\"";
557                 if ($this->rowspan > 1)
558                 {
559                         $param .= " rowspan=\"{$this->rowspan}\"";
560                 }
561                 if ($this->colspan > 1)
562                 {
563                         $param .= " colspan=\"{$this->colspan}\"";
564                         unset($this->style['width']);
565                 }
566                 if (count($this->style))
567                 {
568                         $param .= ' style="'.join(' ', $this->style).'"';
569                 }
570
571                 return $this->wrap(parent::toString(), $this->tag, $param, FALSE);
572         }
573 }
574
575 class Table extends Element
576 { // |
577         var $type;
578         var $types;
579         var $col; // number of column
580
581         function Table($out)
582         {
583                 parent::Element();
584
585                 $cells = explode('|', $out[1]);
586                 $this->col = count($cells);
587                 $this->type = strtolower($out[2]);
588                 $this->types = array($this->type);
589                 $is_template = ($this->type == 'c');
590                 $row = array();
591                 foreach ($cells as $cell)
592                 {
593                         $row[] = &new TableCell($cell, $is_template);
594                 }
595                 $this->elements[] = $row;
596         }
597
598         function canContain(&$obj)
599         {
600                 return is_a($obj, 'Table') and ($obj->col == $this->col);
601         }
602
603         function &insert(&$obj)
604         {
605                 $this->elements[] = $obj->elements[0];
606                 $this->types[] = $obj->type;
607
608                 return $this;
609         }
610
611         function toString()
612         {
613                 static $parts = array('h'=>'thead', 'f'=>'tfoot', ''=>'tbody');
614
615                 // rowspan¤òÀßÄê(²¼¤«¤é¾å¤Ø)
616                 for ($ncol = 0; $ncol < $this->col; $ncol++)
617                 {
618                         $rowspan = 1;
619                         foreach (array_reverse(array_keys($this->elements)) as $nrow)
620                         {
621                                 $row = &$this->elements[$nrow];
622                                 if ($row[$ncol]->rowspan == 0)
623                                 {
624                                         $rowspan++;
625                                         continue;
626                                 }
627                                 $row[$ncol]->rowspan = $rowspan;
628                                 while (--$rowspan) // ¹Ô¼ïÊ̤ò·Ñ¾µ¤¹¤ë
629                                 {
630                                         $this->types[$nrow + $rowspan] = $this->types[$nrow];
631                                 }
632                                 $rowspan = 1;
633                         }
634                 }
635                 // colspan,style¤òÀßÄê
636                 $stylerow = NULL;
637                 foreach (array_keys($this->elements) as $nrow)
638                 {
639                         $row = &$this->elements[$nrow];
640                         if ($this->types[$nrow] == 'c')
641                         {
642                                 $stylerow = &$row;
643                         }
644                         $colspan = 1;
645                         foreach (array_keys($row) as $ncol)
646                         {
647                                 if ($row[$ncol]->colspan == 0)
648                                 {
649                                         $colspan++;
650                                         continue;
651                                 }
652                                 $row[$ncol]->colspan = $colspan;
653                                 if ($stylerow !== NULL)
654                                 {
655                                         $row[$ncol]->setStyle($stylerow[$ncol]->style);
656                                         while (--$colspan) // Îó¥¹¥¿¥¤¥ë¤ò·Ñ¾µ¤¹¤ë
657                                         {
658                                                 $row[$ncol - $colspan]->setStyle($stylerow[$ncol]->style);
659                                         }
660                                 }
661                                 $colspan = 1;
662                         }
663                 }
664                 // ¥Æ¥­¥¹¥È²½
665                 $string = '';
666                 foreach ($parts as $type => $part)
667                 {
668                         $part_string = '';
669                         foreach (array_keys($this->elements) as $nrow)
670                         {
671                                 if ($this->types[$nrow] != $type)
672                                 {
673                                         continue;
674                                 }
675                                 $row = &$this->elements[$nrow];
676                                 $row_string = '';
677                                 foreach (array_keys($row) as $ncol)
678                                 {
679                                         $row_string .= $row[$ncol]->toString();
680                                 }
681                                 $part_string .= $this->wrap($row_string, 'tr');
682                         }
683                         $string .= $this->wrap($part_string, $part);
684                 }
685                 $string = $this->wrap($string, 'table', ' class="style_table" cellspacing="1" border="0"');
686                 return $this->wrap($string, 'div', ' class="ie5"');
687         }
688 }
689
690 class YTable extends Element
691 { // ,
692         var $col;
693
694         function YTable($_value)
695         {
696                 parent::Element();
697
698                 $align = $value = $matches = array();
699                 foreach($_value as $val)
700                 {
701                         if (preg_match('/^(\s+)?(.+?)(\s+)?$/', $val, $matches))
702                         {
703                                 $align[] =($matches[1] != '') ?
704                                         ((array_key_exists(3,$matches) and $matches[3] != '') ?
705                                                 ' style="text-align:center"' : ' style="text-align:right"'
706                                         ) : '';
707                                 $value[] = $matches[2];
708                         }
709                         else
710                         {
711                                 $align[] = '';
712                                 $value[] = $val;
713                         }
714                 }
715                 $this->col = count($value);
716                 $colspan = array();
717                 foreach ($value as $val)
718                 {
719                         $colspan[] = ($val == '==') ? 0 : 1;
720                 }
721                 $str = '';
722                 for ($i = 0; $i < count($value); $i++)
723                 {
724                         if ($colspan[$i])
725                         {
726                                 while ($i + $colspan[$i] < count($value) and $value[$i + $colspan[$i]] == '==')
727                                 {
728                                         $colspan[$i]++;
729                                 }
730                                 $colspan[$i] = ($colspan[$i] > 1) ? " colspan=\"{$colspan[$i]}\"" : '';
731                                 $str .= "<td class=\"style_td\"{$align[$i]}{$colspan[$i]}>".make_link($value[$i]).'</td>';
732                         }
733                 }
734                 $this->elements[] = $str;
735         }
736
737         function canContain(&$obj)
738         {
739                 return is_a($obj, 'YTable') and ($obj->col == $this->col);
740         }
741
742         function &insert(&$obj)
743         {
744                 $this->elements[] = $obj->elements[0];
745
746                 return $this;
747         }
748
749         function toString()
750         {
751                 $rows = '';
752                 foreach ($this->elements as $str)
753                 {
754                         $rows .= "\n<tr class=\"style_tr\">$str</tr>\n";
755                 }
756                 $rows = $this->wrap($rows, 'table', ' class="style_table" cellspacing="1" border="0"');
757                 return $this->wrap($rows, 'div', ' class="ie5"');
758         }
759 }
760
761 class Pre extends Element
762 { // ' '
763         function Pre(&$root,$text)
764         {
765                 global $preformat_ltrim;
766
767                 parent::Element();
768                 $this->elements[] = htmlspecialchars(
769                         (!$preformat_ltrim or $text == '' or $text{0} != ' ') ? $text : substr($text, 1)
770                 );
771         }
772
773         function canContain(&$obj)
774         {
775                 return is_a($obj, 'Pre');
776         }
777
778         function &insert(&$obj)
779         {
780                 $this->elements[] = $obj->elements[0];
781
782                 return $this;
783         }
784
785         function toString()
786         {
787                 return $this->wrap(join("\n", $this->elements), 'pre');
788         }
789 }
790
791 class Div extends Element
792 { // #
793         var $name;
794         var $param;
795
796         function Div($out)
797         {
798                 parent::Element();
799
800                 list(, $this->name, $this->param) = array_pad($out,3,'');
801         }
802
803         function canContain(&$obj)
804         {
805                 return FALSE;
806         }
807
808         function toString()
809         {
810                 return do_plugin_convert($this->name,$this->param);
811         }
812 }
813
814 class Align extends Element
815 { // LEFT:/CENTER:/RIGHT:
816         var $align;
817
818         function Align($align)
819         {
820                 parent::Element();
821
822                 $this->align = $align;
823         }
824
825         function canContain(&$obj)
826         {
827                 return is_a($obj, 'Inline');
828         }
829
830         function toString()
831         {
832                 return $this->wrap(parent::toString(), 'div', ' style="text-align:'.$this->align.'"');
833         }
834 }
835
836 class Body extends Element
837 { // Body
838         var $id;
839         var $count = 0;
840         var $contents;
841         var $contents_last;
842         var $classes = array(
843                 '-' => 'UList',
844                 '+' => 'OList',
845                 '>' => 'BQuote',
846                 '<' => 'BQuote'
847         );
848         var $factories = array(
849                 ':' => 'DList',
850                 '|' => 'Table',
851                 ',' => 'YTable',
852                 '#' => 'Div'
853         );
854
855         function Body($id)
856         {
857                 $this->id = $id;
858                 $this->contents = &new Element();
859                 $this->contents_last = &$this->contents;
860                 parent::Element();
861         }
862
863         function parse(&$lines)
864         {
865                 $this->last = &$this;
866
867                 while (count($lines))
868                 {
869                         $line = array_shift($lines);
870
871                         if (substr($line,0,2) == '//') //¥³¥á¥ó¥È¤Ï½èÍý¤·¤Ê¤¤
872                         {
873                                 continue;
874                         }
875
876                         if (preg_match('/^(LEFT|CENTER|RIGHT):(.*)$/',$line,$matches))
877                         {
878                                 $this->last = &$this->last->add(new Align(strtolower($matches[1]))); // <div style="text-align:...">
879                                 if ($matches[2] == '')
880                                 {
881                                         continue;
882                                 }
883                                 $line = $matches[2];
884                         }
885
886                         $line = preg_replace("/[\r\n]*$/",'',$line);
887
888                         // Empty
889                         if ($line == '')
890                         {
891                                 $this->last = &$this;
892                                 continue;
893                         }
894                         // Horizontal Rule
895                         if (substr($line,0,4) == '----')
896                         {
897                                 $this->insert(new HRule($this,$line));
898                                 continue;
899                         }
900                         // ¹ÔƬʸ»ú
901                         $head = $line{0};
902
903                         // Heading
904                         if ($head == '*')
905                         {
906                                 $this->insert(new Heading($this,$line));
907                                 continue;
908                         }
909                         // Pre
910                         if ($head == ' ' or $head == "\t")
911                         {
912                                 $this->last = &$this->last->add(new Pre($this,$line));
913                                 continue;
914                         }
915                         // Line Break
916                         if (substr($line,-1) == '~')
917                         {
918                                 $line = substr($line,0,-1)."\r";
919                         }
920                         // Other Character
921                         if (array_key_exists($head, $this->classes))
922                         {
923                                 $classname = $this->classes[$head];
924                                 $this->last = &$this->last->add(new $classname($this,$line));
925                                 continue;
926                         }
927                         // Other Character
928                         if (array_key_exists($head, $this->factories))
929                         {
930                                 $factoryname = 'Factory_'. $this->factories[$head];
931                                 $this->last = &$this->last->add($factoryname($this,$line));
932                                 continue;
933                         }
934
935                         // Default
936                         $this->last = &$this->last->add(Factory_Inline($line));
937                 }
938         }
939
940         function getAnchor($text,$level)
941         {
942                 global $top,$_symbol_anchor;
943
944                 $anchor = (($id = make_heading($text,FALSE)) == '') ?
945                         '' : " &aname($id,super,full)\{$_symbol_anchor};";
946                 $text = ' '.$text;
947                 $id = "content_{$this->id}_{$this->count}";
948                 $this->count++;
949                 $this->contents_last = &$this->contents_last->add(new Contents_UList($text,$level,$id));
950
951                 return array($text. $anchor, $this->count > 1 ? "\n$top" : '', $id);
952         }
953
954         function &insert(&$obj)
955         {
956                 if (is_a($obj, 'Inline'))
957                 {
958                         $obj = &$obj->toPara();
959                 }
960                 return parent::insert($obj);
961         }
962
963         function toString()
964         {
965                 global $vars;
966
967                 $text = parent::toString();
968
969                 // #contents
970                 $text = preg_replace_callback('/(<p[^>]*>)<del>#contents<\/del>(\s*)(<\/p>)/', array(&$this,'replace_contents'),$text);
971
972                 // ´ØÏ¢¤¹¤ë¥Ú¡¼¥¸
973                 // <p>¤Î¤È¤­¤Ï¹ÔƬ¤«¤é¡¢<del>¤Î¤È¤­¤Ï¾¤ÎÍ×ÁǤλÒÍ×ÁǤȤ·¤Æ¸ºß
974                 $text = preg_replace_callback('/(<p[^>]*>)<del>#related<\/del>(\s*)(<\/p>)/', array(&$this, 'replace_related'), $text);
975                 $text = preg_replace('/<del>#related<\/del>/',make_related($vars['page'],'del'),$text);
976                 return "$text\n";
977         }
978
979         function replace_contents($arr)
980         {
981                 $contents  = "<div class=\"contents\">\n";
982                 $contents .= "<a id=\"contents_{$this->id}\"></a>";
983                 $contents .= $this->contents->toString();
984                 $contents .= "</div>\n";
985                 array_shift($arr);
986
987                 return ($arr[1] != '') ? $contents.join('',$arr) : $contents;
988         }
989
990         function replace_related($arr)
991         {
992                 global $vars;
993                 static $related = NULL;
994
995                 if (is_null($related))
996                 {
997                         $related = make_related($vars['page'],'p');
998                 }
999                 array_shift($arr);
1000
1001                 return ($arr[1] != '') ? $related.join('',$arr) : $related;
1002         }
1003 }
1004
1005 class Contents_UList extends ListContainer
1006 {
1007         function Contents_UList($text,$level,$id)
1008         {
1009                 // ¥Æ¥­¥¹¥È¤Î¥ê¥Õ¥©¡¼¥à
1010                 // ¹ÔƬ\n¤ÇÀ°·ÁºÑ¤ß¤òɽ¤¹ ... X(
1011                 make_heading($text);
1012                 $text = "\n<a href=\"#$id\">$text</a>\n";
1013                 parent::ListContainer('ul', 'li', '-', str_repeat('-',$level));
1014                 $this->insert(Factory_Inline($text));
1015         }
1016
1017         function setParent(&$parent)
1018         {
1019                 global $_list_pad_str;
1020
1021                 parent::setParent($parent);
1022                 $step = $this->level;
1023                 $margin = $this->left_margin;
1024                 if (isset($parent->parent) and is_a($parent->parent,'ListContainer'))
1025                 {
1026                         $step -= $parent->parent->level;
1027                         $margin = 0;
1028                 }
1029                 $margin += $this->margin * ($step == $this->level ? 1 : $step);
1030                 $this->style = sprintf($_list_pad_str,$this->level,$margin,$margin);
1031         }
1032 }
1033 ?>