142 #==========================================================================
143 #-----------------------------[ SIMPLE WIKI ]------------------------------
144 #==========================================================================
156 protected $_allow_html = TRUE;
178 public function __construct($text = NULL)
181 $this->_parser =
new Parser($text);
183 $this->_emitter =
new Emitter();
185 $this->register_class_callbacks(
188 'subscript'=> array($this,
'callback_span_subscript'),
189 'superscript'=> array($this,
'callback_span_superscript'),
190 'footnote'=> array($this,
'callback_span_footnote'),
191 'comment'=> array($this,
'callback_span_comment')),
193 'newwin' => array($this,
'callback_link_newwin')),
195 'lframe'=> array($this,
'callback_image_frame'),
196 'rframe'=> array($this,
'callback_image_frame')),
197 'paragraph' => array(
198 'nop'=> array($this,
'callback_paragraph_nop'),
199 'div'=> array($this,
'callback_paragraph_div')),
201 'lframe'=> array($this,
'callback_blockdef_frame'),
202 'rframe'=> array($this,
'callback_blockdef_frame')),
203 'preformatted' => array(
204 'html'=> array($this,
'callback_pre_html')),
206 'html'=> array($this,
'callback_code_html'))
210 $this->register_macro_callbacks(
212 'quicktoc' => array($this,
'macro_quicktoc')
216 $this->register_symlinks(array(
'Anchor'=>
'',
'Local'=>
''));
218 public function __clone()
220 $this->_parser = clone $this->_parser;
221 $this->_emitter = clone $this->_emitter;
222 $this->_working_parser = NULL;
232 public function allow_html($bool = NULL)
235 $this->_allow_html = $bool;
236 return $this->_allow_html;
253 public function register_class_callbacks($callbacks)
255 $emitter = $this->_emitter;
256 $emitter->register_class_callouts($callbacks);
273 public function register_property_callbacks($callbacks)
275 $emitter = $this->_emitter;
276 $emitter->register_property_callouts($callbacks);
290 public function register_symlinks($symlinks)
292 $emitter = $this->_emitter;
293 $emitter->register_symlinks($symlinks);
307 public function register_symlink_handler($handler)
309 $emitter = $this->_emitter;
310 $emitter->register_symlink_handler($handler);
317 public function register_rawlink_handler($handler)
319 $emitter = $this->_emitter;
320 $emitter->register_rawlink_handler($handler);
328 public function register_charfilter_handler($handler)
330 $emitter = $this->_emitter;
331 $emitter->register_charfilter_handler($handler);
338 public function register_blockdef_handler($handler)
340 $emitter = $this->_emitter;
341 $emitter->register_blockdef_handler($handler);
354 public function register_macro_callbacks($callbacks)
356 $emitter = $this->_emitter;
357 $emitter->register_macro_callouts($callbacks);
372 public function register_events($callbacks)
374 $emitter = $this->_emitter;
375 $emitter->register_events($callbacks);
387 public function prepare($raw)
389 $this->_parser->prepare($raw);
395 public function get_html($markup = NULL)
397 if ($markup) $this->prepare($markup);
400 $profile[
'parse'][
'start'] = microtime(
true);
401 $dom = $this->_parser->parse();
402 $profile[
'parse'][
'end'] = microtime(
true);
403 $profiles[] = $profile;
405 $profile[
'emit'][
'start'] = microtime(
true);
406 $retval = $this->_emitter->emit($dom);
407 $profile[
'emit'][
'end'] = microtime(
true);
408 $profiles[] = $profile;
422 public function parser($parser = NULL)
424 if (!is_null($parser))
425 $this->_parser = $parser;
426 return $this->_parser;
434 public function emitter($emitter = NULL )
436 if (!is_null($emitter))
437 $this->_emitter = $parser;
438 return $this->_emitter;
445 public function get_metadata()
447 return $this->_parser->metadata();
453 public function get_markerdata()
455 return $this->_parser->markerdata();
461 public function get_preprocessed_markup()
463 return $this->_parser->preprocessed_markup();
467 #-----------------------------[ STANDARD CLASS CALLBACKS ]-----------------------------#
478 public function callback_paragraph_nop($node)
480 $node->opentag_head =
'';
481 $node->opentag_tail =
'';
482 $node->closetag =
'';
483 $node->decoration =
new StdClass;
490 public function callback_paragraph_div($node)
492 $node->opentag_head =
'<div';
493 $node->opentag_tail =
'>';
494 $node->closetag =
'</div>';
495 unset($node->decoration->classes[array_search(
'div',$node->decoration->classes)]);
502 public function callback_code_html($node)
504 if ($this->_allow_html)
506 $node->opentag_head =
'';
507 $node->opentag_tail =
'';
508 $node->closetag =
'';
509 $node->escapecontent = FALSE;
510 $node->decoration =
new StdClass;
518 public function callback_blockdef_frame($node)
520 if ($node->blocktag !=
'div')
return $node;
521 $node->decoration->classes[] =
'frame';
528 public function callback_image_frame($node)
530 $lframeindex = array_search(
'lframe',$node->decoration->classes);
531 $rframeindex = array_search(
'rframe',$node->decoration->classes);
532 if ($lframeindex === FALSE)
534 unset($node->decoration->classes[$rframeindex]);
535 $orientation =
'rframe';
539 unset($node->decoration->classes[$lframeindex]);
540 $orientation =
'lframe';
542 $opentag_head = $node->opentag_head;
543 $opentag_tail = $node->opentag_tail;
544 $opentag_head =
"<div class='frame $orientation'>" . $opentag_head;
545 $opentag_tail .=
"<br>{$node->caption}</div>";
546 $node->opentag_head = $opentag_head;
547 $node->opentag_tail = $opentag_tail;
554 public function callback_pre_html($node)
556 if ($this->_allow_html)
558 $node->opentag_head =
'';
559 $node->opentag_tail =
'';
560 $node->closetag =
'';
561 $node->escapecontent = FALSE;
562 $node->decoration =
new StdClass;
570 public function callback_span_comment($node)
572 $node->opentag_head =
'';
573 $node->opentag_tail =
'';
574 $node->closetag =
'';
575 $node->decoration =
new StdClass;
576 $node->elementcontent =
'';
583 public function callback_span_footnote($node)
585 $footnotes = $this->_footnotes;
586 if (empty($footnotes))
588 $footnotes =
new StdClass;
589 $footnotes->count = 0;
590 $footnotes->list = array();
591 if (empty($this->_working_parser))
592 $this->_working_parser =
new Parser(
'');
593 $this->register_events(
594 array(
'onafteremit' =>
595 array($this,
'render_footnotes')));
598 $footnote = $footnotes->list[] = $node;
599 $count = $footnote->id = ++$footnotes->count;
601 $parser = $this->_working_parser;
603 '%s superscript%[[#footnotemarker'
609 $dom = $parser->prepare($markup)->parse();
611 $span = $dom->children[0]->children[0];
612 $span->parent = $footnote->parent;
613 $footnote->parent = NULL;
614 $this->_footnotes = $footnotes;
616 $footnote->rendered = FALSE;
617 $footnotereference = @$footnote->decoration->attributes[
'footnotereference'];
618 if (!empty($footnotereference))
620 $this->_footnotereferences[$footnotereference][] = $footnote;
623 $span->elementcontent = $this->_emitter->emit_children($span);
624 $span = $this->callback_span_superscript($span);
631 public function callback_span_superscript($node)
633 $node->opentag_head =
'<sup';
634 $node->opentag_tail =
'>';
635 $node->closetag =
'</sup>';
636 unset($node->decoration->classes[array_search(
'superscript',$node->decoration->classes)]);
643 public function callback_span_subscript($node)
645 $node->opentag_head =
'<sub';
646 $node->opentag_tail =
'>';
647 $node->closetag =
'</sub>';
648 unset($node->decoration->classes[array_search(
'subscript',$node->decoration->classes)]);
655 public function callback_link_newwin($node)
657 $node->decoration->attributes[
'target'] =
'_blank';
658 $node->decoration->attributedelimiters[
'target'] =
'"';
659 unset($node->decoration->classes[array_search(
'newwin',$node->decoration->classes)]);
664 #-----------------------------[ DEFAULT MACROS ]----------------------------------#
670 public function macro_quicktoc($node)
672 $caption = $node->caption;
673 if (!$caption) $caption =
'Table of Contents';
674 # move to root of document
675 $document = $this->_parser->get_selected_ancestor($node,array(
'document'));
676 # collect all headings
678 $contents = $this->macro_quicktoc_assemble_headings($document,$contents);
679 # set data for content line items
680 $contentheadings = array();
682 foreach ($contents as $heading)
686 $sessionid =
'heading' . $count;
687 $headingid = @$heading->decoration->attributes[
'id'];
688 if (is_null($headingid))
690 $headingid = $heading->decoration->attributes[
'id'] = $sessionid;
691 $heading->decoration->attributedelimiters[
'id'] =
'"';
693 $heading->decoration->attributes[
'contentsid'] = $sessionid;
694 $heading->decoration->attributedelimiters[
'contentsid'] =
'"';
695 $contentheading =
new StdClass;
696 $contentheading->id = $headingid;
698 $contentheading->text = $this->_emitter->emit_node_text($heading);
700 $contentheading->level = $heading->level;
701 $contentheading->nesting = $heading->nesting;
702 $contentheadings[] = $contentheading;
704 # generate markup for table of contents
705 if (!empty($contentheadings))
710 $previouscontentdepth = $contentdepth;
711 $contentdepthstack = array();
713 $flooroffsetstack = array();
716 $previouslevel = $contentheadings[0]->level;
717 $previouslevelstack = array();
718 $previousnestinglevel = $contentheadings[0]->nesting;
720 foreach ($contentheadings as $contentheading)
723 $level = $contentheading->level;
724 $nestinglevel = $contentheading->nesting;
725 if ($nestinglevel > $previousnestinglevel)
727 array_push($flooroffsetstack,$flooroffset);
728 array_push($contentdepthstack,$contentdepth);
729 array_push($previouslevelstack,$previouslevel);
731 $flooroffset = $contentdepth;
733 elseif ($nestinglevel < $previousnestinglevel)
735 if (!empty($flooroffsetstack))
737 $flooroffset = array_pop($flooroffsetstack);
738 $contentdepth = array_pop($contentdepthstack);
739 $previouslevel = array_pop($previouslevelstack);
742 if ($level > $previouslevel)
744 elseif ($level < $previouslevel)
746 $contentdepth = min($level,$contentdepth);
747 $contentdepth = max($contentdepth,1);
748 $previouslevel = $level;
749 $previousnestinglevel = $nestinglevel;
750 $previouscontentdepth = $contentdepth;
753 str_repeat(
'*',$contentdepth + $flooroffset)
755 . $contentheading->id
757 . $contentheading->text
761 $caption = preg_replace(
'/\\n/',
'',$caption);
763 "(:div id=quicktoc-platform:)\n
764 (:div id=quicktoc-header:)\n
765 |:p div id=quicktoc-caption quicktoc-closed:|%c html%{{{" . $caption .
"}}}\n
767 (:div id=quicktoc-body:)\n"
771 # generate html for table of contents
773 $allowhtml = $this->allow_html();
774 $this->allow_html(TRUE);
776 $wiki->register_symlinks($this->emitter()->symlinks());
777 $wiki->register_symlink_handler($this->emitter()->symlink_handler());
778 $node->output = $wiki->get_html();
779 $this->allow_html($allowhtml);
784 protected function macro_quicktoc_assemble_headings($node,$contents)
786 static $nesting = -1;
789 if ($node->type == DocNode::HEADING)
791 $notoc = @$node->decoration->attributes[
'toc'] ==
'no';
794 unset($node->decoration->attributes[
'toc']);
799 $node->nesting = $nesting;
805 $children = $node->children;
806 if (!empty($children))
808 foreach ($children as $child)
810 $contents = $this->macro_quicktoc_assemble_headings($child,$contents);
817 #----------------------[ NATIVE EVENT CALLBACKS ]--------------------------#
819 # triggered at onafteremit event...
820 public function render_footnotes($document)
822 $footnotes = $this->_footnotes->list;
824 foreach ($footnotes as $footnote)
826 if ($footnote->rendered)
continue;
830 '* [[#footnotemarker' . $id .
'|^]][' . $id .
'][[#footnote' . $id .
']]';
831 $footnotename = @$footnote->decoration->attributes[
'footnotename'];
832 if (!empty($footnotename))
834 $references = @$this->_footnotereferences[$footnotename];
835 if (!empty($references))
837 foreach ($references as $reference)
839 $ref = $reference->id;
848 $reference->rendered=
true;
852 $elementcontent = $footnote->elementcontent;
853 $elementcontent = preg_replace(
'/\\n/',
'',$elementcontent);
861 "\n|:b divider:|\n----\n"
862 .
"(:div footnoteblock:)\n======Footnotes:======\n"
866 $allowhtml = $this->allow_html();
867 $this->allow_html(TRUE);
869 $wiki->register_symlinks($this->emitter()->symlinks());
870 $wiki->register_symlink_handler($this->emitter()->symlink_handler());
871 $document->closetag .= $wiki->get_html();
872 $this->allow_html($allowhtml);
876 public function auto_quicktoc($document)
878 $markup =
'<<quicktoc>>';
879 if (empty($this->_working_parser))
880 $this->_working_parser =
new Parser(
'');
881 $parser = $this->_working_parser;
882 $dom = $parser->prepare($markup)->parse();
883 $tocnode = $dom->children[0];
884 $tocnode->parent = $document;
885 array_unshift($document->children,$tocnode);