19 @include_once
'Text/Diff/Renderer.php';
20 include_once
'Text/Diff/Renderer/inline.php';
55 if (empty($lines))
return '';
57 if (count($lines) == 1) {
59 return $prefix.$lines[0].$suffix;
63 }
else if (count($lines) >= 2) {
65 foreach ($lines as $i => $line) {
70 if ($num_lines == count($lines))
return $this->_lines($lines,
' ', FALSE);
75 return $prefix.$this->_lines($lines,
' ', FALSE).$suffix;
78 $table_opened = FALSE;
80 $need_traversal = FALSE;
81 foreach ($lines as $i => $line) {
82 if (preg_match(
'/<table([^>]*)>/i', $line)) {
85 if (preg_match(
'/<(ul|ol|dl)([^>]*)>/i', $line)) {
88 if (preg_match(
'/<li([^>]*)>/i', $line) && !$list_opened) {
90 $need_traversal = TRUE;
93 if (preg_match(
'/<td([^>]*)>/i', $line) && !$table_opened) {
95 $need_traversal = TRUE;
100 if ($need_traversal) {
103 foreach ($lines as $i => $line) {
104 if (preg_match(
'/<(td|th|li)([^>]*)>/i', $line)) {
107 $pattern =
'/<\/td>/i';
108 if (preg_match(
'/<th([^>]*)>/i', $line)) {
109 $pattern =
'/<\/th>/i';
110 }
else if (preg_match(
'/<li([^>]*)>/i', $line)) {
111 $pattern =
'/<\/li>/i';
113 while ($end_index < count($lines)){
114 if (preg_match($pattern, $lines[$end_index])) {
123 $begin_index = $i + 1;
124 while ($this->
_isOpenTag($lines[$begin_index]) && ($begin_index < $end_index)) {
128 while ($this->
_isCloseTag($lines[$end_index]) && ($end_index > 0)) {
132 $lines[$begin_index] = $prefix.$lines[$begin_index];
133 $lines[$end_index] .= $suffix;
136 $lines[$i] .= $prefix;
143 }
else if (preg_match(
'/<\/(td|th|li)([^>]*)>/i', $line)) {
150 $lines[0] = $lines[0].$prefix;
152 $lines[0] = $prefix.$lines[0];
155 while ($this->
_isCloseTag($lines[$end_index]) && ($end_index > 0)) {
158 $lines[$end_index] .= $suffix;
167 $lines[count($lines)-2] = str_replace($prefix,
'',$lines[count($lines)-2]);
169 $lines[count($lines)-1] .= $suffix;
172 return $this->_lines($lines,
' ', FALSE);
176 $this->_removeInvalidBlockTags($lines);
180 while ($this->
_isCloseTag($lines[$begin_index]) && ($begin_index < count($lines))) {
183 $end_index = count($lines) - 1;
184 while ($this->
_isOpenTag($lines[$end_index]) && ($end_index > 0)) {
188 $lines[$begin_index] = $prefix.$lines[$begin_index];
189 $lines[$end_index] .= $suffix;
191 return $this->_lines($lines,
' ', FALSE);
205 private function _removeInvalidBlockTags(&$lines)
207 $opened_tags = Array();
208 foreach($lines as $index => $tag) {
210 $opened_tags[] = Array(
'line' => $index,
'tag' => trim(preg_replace(
'|<([^\s]+).*?>|',
'$1', $tag)));
212 if (!empty($opened_tags)) {
213 $previous_tag = $opened_tags[count($opened_tags)-1][
'tag'];
214 $current_tag = trim(preg_replace(
'|</([^>]+)>|',
'$1', $tag));
215 if ($previous_tag != $current_tag) {
219 array_pop($opened_tags);
228 foreach($opened_tags as $opened_tag) {
229 $lines[$opened_tag[
'line']] =
'';
245 return $this->
_markChanges($lines, $this->_ins_prefix, $this->_ins_suffix);
260 return $this->
_markChanges($lines, $this->_del_prefix, $this->_del_suffix);
278 if ($this->_split_level ==
'words') {
280 while ($orig[0] !== FALSE && $final[0] !== FALSE &&
281 substr($orig[0], 0, 1) ==
' ' &&
282 substr($final[0], 0, 1) ==
' ') {
283 $prefix .= substr($orig[0], 0, 1);
284 $orig[0] = substr($orig[0], 1);
285 $final[0] = substr($final[0], 1);
287 return $prefix.$this->_deleted($orig).$this->_added($final);
290 $text1 = implode(
"\n", $orig);
291 $text2 = implode(
"\n", $final);
302 $diff =
new Text_Diff($text1_words,
307 Array(
'split_level' =>
'words')));
310 return str_replace($nl,
"\n", $renderer->render($diff)).
"\n";
325 return preg_match(
'/<\/[^>]+>/i', $x);
340 if (preg_match(
'/<(br|hr|img)( ([^>]*))?>/i', $x)) {
344 if (preg_match(
'/<a[^>]+href=[^>]+>/i', $x)) {
348 return preg_match(
'/<[^\/>]+>/i', $x);
363 return preg_match(
'/<(address|blockcode|blockquote|div|h|h1|h2|h3|h4|h5|h6|hr|p|pre|section)>/i', $x);
378 return preg_match(
'/<\/(address|blockcode|blockquote|div|h|h1|h2|h3|h4|h5|h6|hr|p|pre|section)>/i', $x);
396 $string = str_replace(
"\0",
'', $string);
397 $string = str_replace(
'>',
'> ', $string);
398 $string = str_replace(
'<',
' <', $string);
400 $bits = preg_split(
'/[\s]+/', $string);
402 $total = count($bits);
403 while ($i < $total) {
404 if (isset($bits[$i])) {
405 if ($bits[$i] ===
'') {
407 }
else if ($bits[$i]{0} ==
'<') {
409 if (strpos($bits[$i],
'>') === FALSE) {
413 $bits[$i] .=
' '.$bits[$j];
416 }
while (strpos($bits[$i],
'>') === FALSE);
423 foreach ($bits as $i => $v) {
427 return array_values($bits);
443 <style type="text/css">
444 ins, ins *, ins * * {
446 text-decoration: none;
448 del, del *, del * * {
450 text-decoration: line-through;
457 $out .= @parent::render($diff);
461 $out = preg_replace(
'/<ins>(\s*)/',
' <ins>', $out);
462 $out = preg_replace(
'/<del>(\s*)/',
' <del>', $out);
463 $out = preg_replace(
'/(\s*)<\/ins>/',
'</ins> ', $out);
464 $out = preg_replace(
'/(\s*)<\/del>/',
'</del> ', $out);
467 $out = preg_replace(
'/<del>(\s*)<\/del>/',
'', $out);
468 $out = preg_replace(
'/<ins>(\s*)<\/ins>/',
'', $out);
470 return html_entity_decode($out, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
486 if ($first == $second)
return $second;
489 $first = trim(preg_replace(
'/<([^>]+)>/',
' <$1> ', $first),
' ');
490 $second = trim(preg_replace(
'/<([^>]+)>/',
' <$1> ', $second),
' ');
493 $first = preg_replace(
'/([ \t]+)/',
' ', $first);
494 $second = preg_replace(
'/([ \t]+)/',
' ', $second);
499 @include_once
'Text/Diff.php';
500 @$diff =
new Text_Diff(explode(
"\n", $first), explode(
"\n", $second));
502 return $this->
render($diff);