OSDN Git Service

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