mirror of
https://github.com/processwire/processwire.git
synced 2025-08-14 10:45:54 +02:00
Add simple string diff markup generator to WireTextTools class, via diffMarkup() method
This commit is contained in:
@@ -854,6 +854,117 @@ class WireTextTools extends Wire {
|
|||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given two arrays, return array of the changes with 'ins' and 'del' keys
|
||||||
|
*
|
||||||
|
* Based upon Paul Butler’s Simple Diff Algorithm v0.1 © 2007 (zlib/libpng) https://paulbutler.org
|
||||||
|
*
|
||||||
|
* @param array $oldArray
|
||||||
|
* @param array $newArray
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function diffArray(array $oldArray, array $newArray) {
|
||||||
|
|
||||||
|
$matrix = array();
|
||||||
|
$maxLen = 0;
|
||||||
|
$oldMax = 0;
|
||||||
|
$newMax = 0;
|
||||||
|
|
||||||
|
foreach($oldArray as $oldKey => $oldValue){
|
||||||
|
|
||||||
|
$newKeys = array_keys($newArray, $oldValue);
|
||||||
|
|
||||||
|
foreach($newKeys as $newKey) {
|
||||||
|
$len = 1;
|
||||||
|
if(isset($matrix[$oldKey - 1][$newKey - 1])) {
|
||||||
|
$len = $matrix[$oldKey - 1][$newKey - 1] + 1;
|
||||||
|
}
|
||||||
|
$matrix[$oldKey][$newKey] = $len;
|
||||||
|
|
||||||
|
if($len > $maxLen) {
|
||||||
|
$maxLen = $len;
|
||||||
|
$oldMax = $oldKey + 1 - $maxLen;
|
||||||
|
$newMax = $newKey + 1 - $maxLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($maxLen == 0) {
|
||||||
|
$result = array(
|
||||||
|
array('del' => $oldArray, 'ins' => $newArray)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$result = array_merge(
|
||||||
|
$this->diffArray(
|
||||||
|
array_slice($oldArray, 0, $oldMax),
|
||||||
|
array_slice($newArray, 0, $newMax)
|
||||||
|
),
|
||||||
|
array_slice($newArray, $newMax, $maxLen),
|
||||||
|
$this->diffArray(
|
||||||
|
array_slice($oldArray, $oldMax + $maxLen),
|
||||||
|
array_slice($newArray, $newMax + $maxLen)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given two strings ($old and $new) return a diff string in HTML markup
|
||||||
|
*
|
||||||
|
* @param string $old Old string value
|
||||||
|
* @param string $new New string value
|
||||||
|
* @param array $options Options to modify behavior:
|
||||||
|
* - `ins` (string) Markup to use for diff insertions (default: `<ins>{out}</ins>`)
|
||||||
|
* - `del` (string) Markup to use for diff deletions (default: `<del>{out}</del>`)
|
||||||
|
* - `entityEncode` (bool): Entity encode values, other than added ins/del tags? (default=true)
|
||||||
|
* - `split` (string): Regex used to split strings for parts to diff (default=`\s+`)
|
||||||
|
* @return string
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function diffMarkup($old, $new, array $options = array()) {
|
||||||
|
|
||||||
|
$defaults = array(
|
||||||
|
'ins' => "<ins>{out}</ins>",
|
||||||
|
'del' => "<del>{out}</del>",
|
||||||
|
'entityEncode' => true,
|
||||||
|
'split' => '\s+',
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var Sanitizer $sanitizer */
|
||||||
|
$sanitizer = $this->wire('sanitizer');
|
||||||
|
list($old, $new) = array("$old", "$new"); // enforce as string
|
||||||
|
$options = array_merge($defaults, $options);
|
||||||
|
$oldArray = preg_split("!($options[split])!", $old, 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
$newArray = preg_split("!($options[split])!", $new, 0, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
$diffArray = $this->diffArray($oldArray, $newArray);
|
||||||
|
list(,$delClose) = explode('{out}', $options['del'], 2);
|
||||||
|
list($insOpen,) = explode('{out}', $options['ins'], 2);
|
||||||
|
$out = '';
|
||||||
|
|
||||||
|
foreach($diffArray as $diff) {
|
||||||
|
if(is_array($diff)) {
|
||||||
|
foreach(array('del', 'ins') as $key) {
|
||||||
|
if(empty($diff[$key])) continue;
|
||||||
|
$diffStr = implode('', $diff[$key]);
|
||||||
|
if($options['entityEncode']) $diffStr = $sanitizer->entities1($diffStr);
|
||||||
|
$out .= str_replace('{out}', $diffStr, $options[$key]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$out .= ($options['entityEncode'] ? $sanitizer->entities1($diff) : $diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($out, "$delClose$insOpen")) {
|
||||||
|
// put a space between '</del><ins>' so that it is '</del> <ins>'
|
||||||
|
$out = str_replace("$delClose$insOpen", "$delClose $insOpen", $out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************
|
/***********************************************************************************************************
|
||||||
* MULTIBYTE PHP STRING FUNCTIONS THAT FALLBACK WHEN MBSTRING NOT AVAILABLE
|
* MULTIBYTE PHP STRING FUNCTIONS THAT FALLBACK WHEN MBSTRING NOT AVAILABLE
|
||||||
|
Reference in New Issue
Block a user