You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

280 lines
9.1 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
//this script may only be included - so its better to die if called directly.
if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) {
header("location: index.php");
exit;
}
require_once(__DIR__ . "/Diff.php");
require_once(__DIR__ . "/Renderer.php");
/* @brief modif tiki for the renderer lib */
class Tiki_Text_Diff_Renderer extends Text_Diff_Renderer
{
protected function _lines($lines, $prefix = '', $suffix = '', $type = '')
{
//ADD $suffix
foreach ($lines as $line) {
echo "$prefix$line$suffix\n";
}
}
public function render($diff, $singleEdit = false)
{
$x0 = $y0 = 0;
$xi = $yi = 1;
$block = false;
$context = [];
$nlead = $this->_leading_context_lines;
$ntrail = $this->_trailing_context_lines;
$this->_startDiff();
if (! $singleEdit) {
$diff = $diff->getDiff();
}
foreach ($diff as $edit) {
if (is_a($edit, 'Text_Diff_Op_copy')) {
if (is_array($block)) {
if (count($edit->orig) <= $nlead + $ntrail) {
$block[] = $edit;
} else {
if ($ntrail) {
$context = array_slice($edit->orig, 0, $ntrail);
$block[] = new Text_Diff_Op_copy($context);
}
$this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
$block = false;
}
}
$context = $edit->orig;
} else {
if (! is_array($block)) {
//BUG if compare on all the length: $context = array_slice($context, count($context) - $nlead);
$context = array_slice($context, -$nlead, $nlead);
$x0 = $xi - count($context);
$y0 = $yi - count($context);
$block = [];
if ($context) {
$block[] = new Text_Diff_Op_copy($context);
}
}
$block[] = $edit;
}
if ($edit->orig) {
$xi += count($edit->orig);
}
if ($edit->final) {
$yi += count($edit->final);
}
}
if (is_array($block)) {
$this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
}
return $this->_endDiff();
}
}
function diff2($page1, $page2, $type = 'sidediff')
{
global $tikilib, $prefs;
if ($type == 'htmldiff') {
//$search = "#(<[^>]+>|\s*[^\s<]+\s*|</[^>]+>)#";
$search = "#(<[^>]+>|[,\"':\s]+|[^\s,\"':<]+|</[^>]+>)#";
preg_match_all($search, $page1, $out, PREG_PATTERN_ORDER);
$page1 = $out[0];
preg_match_all($search, $page2, $out, PREG_PATTERN_ORDER);
$page2 = $out[0];
} else {
$page1 = explode("\n", $page1);
$page2 = explode("\n", $page2);
}
$z = new Text_Diff($page1, $page2);
if ($z->isEmpty()) {
$html = '';
} else {
$context = 2;
$words = 1;
if (strstr($type, "-")) {
list($type,$opt) = explode("-", $type, 2);
if (strstr($opt, "full")) {
$context = count($page1);
}
if (strstr($opt, "char")) {
$words = 0;
}
}
if ($type == 'unidiff') {
require_once('renderer_unified.php');
$renderer = new Text_Diff_Renderer_unified($context);
} elseif ($type == 'inlinediff') {
require_once('renderer_inline.php');
$renderer = new Text_Diff_Renderer_inline($context, $words);
} elseif ($type == 'sidediff') {
require_once('renderer_sidebyside.php');
$renderer = new Text_Diff_Renderer_sidebyside($context, $words);
} elseif ($type == 'bytes' && $prefs['feature_actionlog_bytes'] == 'y') {
require_once('renderer_bytes.php');
$renderer = new Text_Diff_Renderer_bytes();
} elseif ($type == 'htmldiff') {
require_once('renderer_htmldiff.php');
$renderer = new Text_Diff_Renderer_htmldiff($context, $words);
} else {
return "";
}
$html = $renderer->render($z);
}
return $html;
}
/* @brief compute the characters differences between a list of lines
* @param $orig array list lines in the original version
* @param $final array the same lines in the final version
* @param int $words
* @param string $function
* @return array
*/
function diffChar($orig, $final, $words = 0, $function = 'character')
{
$glue = strpos($function, 'inline') !== false ? "<br />" : "\n";
if ($words) {
preg_match_all("/\w+\s+(?=\w)|\w+|\W/u", implode($glue, $orig), $matches);
$line1 = $matches[0];
preg_match_all("/\w+\s+(?=\w)|\w+|\W/u", implode($glue, $final), $matches);
$line2 = $matches[0];
} else {
$line1 = preg_split('//u', implode($glue, $orig), -1, PREG_SPLIT_NO_EMPTY);
$line2 = preg_split('//u', implode($glue, $final), -1, PREG_SPLIT_NO_EMPTY);
}
$z = new Text_Diff($line1, $line2);
if ($z->isEmpty()) {
return [$orig[0], $final[0]];
}
//echo "<pre>";print_r($z);echo "</pre>";
compileRendererClass($function);
$new = "Text_Diff_Renderer_$function";
$renderer = new $new(count($line1));
return $renderer->render($z);
}
function compileRendererClass($function)
{
/*
* The various subclasses of Text_Diff_Renderer have methods whose signatures are incompatible
* with those of their parents. This raises some warnings which don't matter in production settings.
*
* But when running phpunit tests, this causes some failures, because we have configured phpunit
* to report warnings as failures.
*
* Making the methods compatible with each other would be very involved, and might introduce some
* actual bugs. So instead, temporarily disable warning reporting, just for the compilation of
* this file.
*/
global $old_error_reporting_level;
if (defined('TIKI_IN_TEST')) {
$old_error_reporting_level = error_reporting(E_ERROR | E_PARSE);
}
require_once("renderer_$function.php");
if (defined('TIKI_IN_TEST')) {
error_reporting($old_error_reporting_level);
}
}
/**
* Find mentions
*
* @param $lines
* @param $state
* @return array
*/
function findMentions($lines, $state)
{
$allMatches = [] ;
if (isset($lines) && is_array($lines)) {
foreach (array_filter($lines) as $line) {
preg_match_all("/(?:^|\s)@(\w+)/i", $line, $matches);
foreach ($matches[0] as $match) {
$allMatches[] = [
'state' => $state,
'mention' => trim($match)
];
}
}
}
return $allMatches;
}
/**
* Find mentions on change content
*
* @param $edit
* @return array
*/
function findMentionsOnChange($edit)
{
$allMatches = [];
if ((isset($edit->orig) && is_array($edit->orig)) && (isset($edit->final) && is_array($edit->final))) {
if (empty($edit->orig[0])) {
$mentions = findMentions($edit->final, 'new');
foreach ($mentions as $m) {
$allMatches[] = $m;
}
} else {
require_once('renderer_inline.php');
$renderer = new Text_Diff_Renderer_inline(1);
$html = $renderer->render([$edit], true);
// remove unnecessary content
$html = preg_replace("#<tr class=\"diffheader\">(.*?)</tr>#", "", $html);
$html = preg_replace("#<span class='diffinldel'>(.*?)</span>#", "", $html);
$html = str_replace(["<tr class='diffbody'>", "</tr>", "<td colspan='3'>", "</td>"], "", $html);
$html = str_replace(["<span class='diffadded'>", "</span>"], "<ins>", $html);
$finalContent = explode('<ins>', $html);
$index = 0;
foreach ($finalContent as $key => $value) {
if (($index % 2) == 1) {
// new mention
$charToAdd = '';
$previousMention = $finalContent[$key - 1];
if (! empty($previousMention)) {
$lastChar = substr($previousMention, -1);
if ($lastChar == '@') {
$charToAdd = '@';
}
}
$mentions = findMentions([$charToAdd . $value], 'new');
} else {
// old mention
$mentions = findMentions([$value], 'old');
}
foreach ($mentions as $m) {
$allMatches[] = $m;
}
$index++;
}
}
}
return $allMatches;
}