3 namespace RemexHtml\TreeBuilder;
4 use RemexHtml\Tokenizer\Attributes;
7 * This is a debugging helper class which calls the supplied callback function
8 * each time there is a TreeHandler event, giving a descriptive message. It
9 * then forwards the event through to the supplied handler.
11 class TreeMutationTracer implements TreeHandler {
16 * @param TreeHandler $handler The next pipeline stage
17 * @param callable $callback The message output function
18 * @param integer $verbosity Set to non-zero to call dump() on the handler
19 * before and after each event.
21 public function __construct( TreeHandler $handler, callable $callback, $verbosity = 0 ) {
22 $this->handler = $handler;
23 $this->callback = $callback;
24 $this->verbosity = $verbosity;
30 private function trace( $msg ) {
31 call_user_func( $this->callback, "[Tree] $msg" );
35 * Get a debug tag for an element or null
37 * @param Element|null $element
39 private function getDebugTag( $element ) {
40 return $element ? $element->getDebugTag() : '';
44 * Get a short excerpt of some text
49 private function excerpt( $text ) {
50 if ( strlen( $text ) > 20 ) {
51 $text = substr( $text, 0, 20 ) . '...';
53 return str_replace( "\n", "\\n", $text );
57 * Get a readable version of the TreeBuilder preposition constants
59 private function getPrepositionName( $prep ) {
61 TreeBuilder::BEFORE => 'before',
62 TreeBuilder::UNDER => 'under',
63 TreeBuilder::ROOT => 'under root'
65 return isset( $names[$prep] ) ? $names[$prep] : '???';
69 * A helper called before the underlying handler is called.
71 private function before() {
72 if ( $this->verbosity > 0 ) {
73 $this->trace( "Before: " . $this->handler->dump() . "\n" );
78 * A helper called after the underlying handler is called.
80 private function after() {
81 if ( $this->verbosity > 0 ) {
82 $this->trace( "After: " . $this->handler->dump() . "\n" );
86 public function startDocument( $fns, $fn ) {
87 $this->trace( "startDocument" );
88 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
91 public function endDocument( $pos ) {
92 $this->trace( "endDocument $pos" );
93 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
96 public function characters( $preposition, $refNode, $text, $start, $length,
97 $sourceStart, $sourceLength
99 $excerpt = $this->excerpt( substr( $text, $start, $length ) );
100 $prepName = $this->getPrepositionName( $preposition );
101 $refTag = $this->getDebugTag( $refNode );
103 $this->trace( "characters \"$excerpt\", $prepName $refTag, start=$sourceStart" );
105 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
109 public function insertElement( $preposition, $refNode, Element $element, $void,
110 $sourceStart, $sourceLength
112 $prepName = $this->getPrepositionName( $preposition );
113 $refTag = $this->getDebugTag( $refNode );
114 $elementTag = $this->getDebugTag( $element );
115 $voidMsg = $void ? 'void' : '';
116 $this->trace( "insert $elementTag $voidMsg, $prepName $refTag, start=$sourceStart" );
118 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
122 public function endTag( Element $element, $sourceStart, $sourceLength ) {
123 $elementTag = $this->getDebugTag( $element );
124 $this->trace( "end $elementTag, start=$sourceStart" );
126 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
130 public function doctype( $name, $public, $system, $quirks, $sourceStart, $sourceLength ) {
132 TreeBuilder::QUIRKS => 'quirks',
133 TreeBuilder::NO_QUIRKS => 'no-quirks',
134 TreeBuilder::LIMITED_QUIRKS => 'limited-quirks'
136 $quirksMsg = $quirksTypes[$quirks];
137 $this->trace( "doctype $name, public=\"$public\", system=\"$system\", " .
138 "$quirksMsg, start=$sourceStart" );
140 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
144 public function comment( $preposition, $refNode, $text, $sourceStart, $sourceLength ) {
145 $prepName = $this->getPrepositionName( $preposition );
146 $refTag = $this->getDebugTag( $refNode );
147 $excerpt = $this->excerpt( $text );
149 $this->trace( "comment \"$excerpt\", $prepName $refTag, start=$sourceStart" );
151 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
155 public function error( $text, $pos ) {
156 $this->trace( "error \"$text\", start=$pos" );
157 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
160 public function mergeAttributes( Element $element, Attributes $attrs, $sourceStart ) {
161 $elementTag = $this->getDebugTag( $element );
162 $this->trace( "merge $elementTag, start=$sourceStart" );
164 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
167 public function removeNode( Element $element, $sourceStart ) {
168 $elementTag = $this->getDebugTag( $element );
169 $this->trace( "remove $elementTag, start=$sourceStart" );
171 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );
175 public function reparentChildren( Element $element, Element $newParent, $sourceStart ) {
176 $elementTag = $this->getDebugTag( $element );
177 $newParentTag = $this->getDebugTag( $newParent );
178 $this->trace( "reparent children of $elementTag under $newParentTag, start=$sourceStart" );
180 call_user_func_array( [ $this->handler, __FUNCTION__ ], func_get_args() );