Skip to content

Commit 334d1b4

Browse files
committed
Add support for diffing img elements
1 parent 65b1794 commit 334d1b4

File tree

4 files changed

+85
-32
lines changed

4 files changed

+85
-32
lines changed

demo/codes.css

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1-
/*
2-
Document : codes
3-
Created on : Sep 23, 2013, 4:41:58 PM
4-
Author : mgersten
5-
Description: CSS related to I-code specific display
6-
*/
1+
del.diffimg.diffsrc {
2+
display: inline-block;
3+
position: relative;
4+
}
5+
6+
del.diffimg.diffsrc:before {
7+
position: absolute;
8+
content: "";
9+
left: 0;
10+
top: 0;
11+
width: 100%;
12+
height: 100%;
13+
background: repeating-linear-gradient(
14+
to left top,
15+
rgba(255, 0, 0, 0),
16+
rgba(255, 0, 0, 0) 49.5%,
17+
rgba(255, 0, 0, 1) 49.5%,
18+
rgba(255, 0, 0, 1) 50.5%
19+
), repeating-linear-gradient(
20+
to left bottom,
21+
rgba(255, 0, 0, 0),
22+
rgba(255, 0, 0, 0) 49.5%,
23+
rgba(255, 0, 0, 1) 49.5%,
24+
rgba(255, 0, 0, 1) 50.5%
25+
);
26+
}
27+
728
.diff-list > li.normal,
829
.diff-list > li.removed,
930
.diff-list > li.replacement{

demo/demos.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

lib/Caxy/HtmlDiff/HtmlDiff.php

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -142,28 +142,39 @@ protected function replaceIsolatedDiffTags()
142142
protected function createIsolatedDiffTagPlaceholders(&$words)
143143
{
144144
$openIsolatedDiffTags = 0;
145-
$isolatedDiffTagIndicies = array();
145+
$isolatedDiffTagIndices = array();
146146
$isolatedDiffTagStart = 0;
147147
$currentIsolatedDiffTag = null;
148148
foreach ($words as $index => $word) {
149149
$openIsolatedDiffTag = $this->isOpeningIsolatedDiffTag($word, $currentIsolatedDiffTag);
150150
if ($openIsolatedDiffTag) {
151-
if ($openIsolatedDiffTags === 0) {
152-
$isolatedDiffTagStart = $index;
151+
if ($this->isSelfClosingTag($word) || stripos($word, '<img') !== false) {
152+
if ($openIsolatedDiffTags === 0) {
153+
$isolatedDiffTagIndices[] = array(
154+
'start' => $index,
155+
'length' => 1,
156+
'tagType' => $openIsolatedDiffTag,
157+
);
158+
$currentIsolatedDiffTag = null;
159+
}
160+
} else {
161+
if ($openIsolatedDiffTags === 0) {
162+
$isolatedDiffTagStart = $index;
163+
}
164+
$openIsolatedDiffTags++;
165+
$currentIsolatedDiffTag = $openIsolatedDiffTag;
153166
}
154-
$openIsolatedDiffTags++;
155-
$currentIsolatedDiffTag = $openIsolatedDiffTag;
156167
} elseif ($openIsolatedDiffTags > 0 && $this->isClosingIsolatedDiffTag($word, $currentIsolatedDiffTag)) {
157168
$openIsolatedDiffTags--;
158169
if ($openIsolatedDiffTags == 0) {
159-
$isolatedDiffTagIndicies[] = array ('start' => $isolatedDiffTagStart, 'length' => $index - $isolatedDiffTagStart + 1, 'tagType' => $currentIsolatedDiffTag);
170+
$isolatedDiffTagIndices[] = array ('start' => $isolatedDiffTagStart, 'length' => $index - $isolatedDiffTagStart + 1, 'tagType' => $currentIsolatedDiffTag);
160171
$currentIsolatedDiffTag = null;
161172
}
162173
}
163174
}
164175
$isolatedDiffTagScript = array();
165176
$offset = 0;
166-
foreach ($isolatedDiffTagIndicies as $isolatedDiffTagIndex) {
177+
foreach ($isolatedDiffTagIndices as $isolatedDiffTagIndex) {
167178
$start = $isolatedDiffTagIndex['start'] - $offset;
168179
$placeholderString = $this->config->getIsolatedDiffTagPlaceholder($isolatedDiffTagIndex['tagType']);
169180
$isolatedDiffTagScript[$start] = array_splice($words, $start, $isolatedDiffTagIndex['length'], $placeholderString);
@@ -185,15 +196,21 @@ protected function isOpeningIsolatedDiffTag($item, $currentIsolatedDiffTag = nul
185196
$tagsToMatch = $currentIsolatedDiffTag !== null
186197
? array($currentIsolatedDiffTag => $this->config->getIsolatedDiffTagPlaceholder($currentIsolatedDiffTag))
187198
: $this->config->getIsolatedDiffTags();
199+
$pattern = '#<%s(\s+[^>]*)?>#iU';
188200
foreach ($tagsToMatch as $key => $value) {
189-
if (preg_match("#<".$key."[^>]*>\\s*#iU", $item)) {
201+
if (preg_match(sprintf($pattern, $key), $item)) {
190202
return $key;
191203
}
192204
}
193205

194206
return false;
195207
}
196208

209+
protected function isSelfClosingTag($text)
210+
{
211+
return (bool) preg_match('/<[^>]+\/\s*>/', $text);
212+
}
213+
197214
/**
198215
* @param string $item
199216
* @param null|string $currentIsolatedDiffTag
@@ -205,8 +222,9 @@ protected function isClosingIsolatedDiffTag($item, $currentIsolatedDiffTag = nul
205222
$tagsToMatch = $currentIsolatedDiffTag !== null
206223
? array($currentIsolatedDiffTag => $this->config->getIsolatedDiffTagPlaceholder($currentIsolatedDiffTag))
207224
: $this->config->getIsolatedDiffTags();
225+
$pattern = '#</%s(\s+[^>]*)?>#iU';
208226
foreach ($tagsToMatch as $key => $value) {
209-
if (preg_match("#</".$key."[^>]*>\\s*#iU", $item)) {
227+
if (preg_match(sprintf($pattern, $key), $item)) {
210228
return $key;
211229
}
212230
}
@@ -306,7 +324,9 @@ protected function diffIsolatedPlaceholder($operation, $pos, $placeholder, $stri
306324
} elseif ($this->config->isUseTableDiffing() && $this->isTablePlaceholder($placeholder)) {
307325
return $this->diffTables($oldText, $newText);
308326
} elseif ($this->isLinkPlaceholder($placeholder)) {
309-
return $this->diffLinks($oldText, $newText);
327+
return $this->diffElementsByAttribute($oldText, $newText, 'href', 'a');
328+
} elseif ($this->isImagePlaceholder($placeholder)) {
329+
return $this->diffElementsByAttribute($oldText, $newText, 'src', 'img');
310330
}
311331

312332
return $this->diffElements($oldText, $newText, $stripWrappingTags);
@@ -367,22 +387,18 @@ protected function diffTables($oldText, $newText)
367387
return $diff->build();
368388
}
369389

370-
/**
371-
* @param string $oldText
372-
* @param string $newText
373-
*
374-
* @return string
375-
*/
376-
protected function diffLinks($oldText, $newText)
390+
protected function diffElementsByAttribute($oldText, $newText, $attribute, $element)
377391
{
378-
$oldHref = $this->getAttributeFromTag($oldText, 'href');
379-
$newHref = $this->getAttributeFromTag($newText, 'href');
392+
$oldAttribute = $this->getAttributeFromTag($oldText, $attribute);
393+
$newAttribute = $this->getAttributeFromTag($newText, $attribute);
394+
395+
if ($oldAttribute !== $newAttribute) {
396+
$diffClass = sprintf('diffmod diff%s diff%s', $element, $attribute);
380397

381-
if ($oldHref != $newHref) {
382398
return sprintf(
383399
'%s%s',
384-
$this->wrapText($oldText, 'del', 'diffmod diff-href'),
385-
$this->wrapText($newText, 'ins', 'diffmod diff-href')
400+
$this->wrapText($oldText, 'del', $diffClass),
401+
$this->wrapText($newText, 'ins', $diffClass)
386402
);
387403
}
388404

@@ -418,8 +434,8 @@ protected function processEqualOperation($operation)
418434
protected function getAttributeFromTag($text, $attribute)
419435
{
420436
$matches = array();
421-
if (preg_match(sprintf('/<a\s+[^>]*%s=([\'"])(.*)\1[^>]*>/i', $attribute), $text, $matches)) {
422-
return $matches[2];
437+
if (preg_match(sprintf('/<[^>]*\b%s\s*=\s*([\'"])(.*)\1[^>]*>/i', $attribute), $text, $matches)) {
438+
return htmlspecialchars_decode($matches[2]);
423439
}
424440

425441
return null;
@@ -445,6 +461,16 @@ public function isLinkPlaceholder($text)
445461
return $this->isPlaceholderType($text, 'a');
446462
}
447463

464+
/**
465+
* @param string $text
466+
*
467+
* @return bool
468+
*/
469+
public function isImagePlaceholder($text)
470+
{
471+
return $this->isPlaceholderType($text, 'img');
472+
}
473+
448474
/**
449475
* @param string $text
450476
* @param array|string $types
@@ -549,7 +575,12 @@ protected function insertTag($tag, $cssClass, &$words)
549575
$workTag[ 0 ] = str_replace( ">", ' class="diffmod">', $workTag[ 0 ] );
550576
}
551577
}
552-
$this->content .= implode( "", $workTag ) . $specialCaseTagInjection;
578+
579+
$appendContent = implode( "", $workTag ) . $specialCaseTagInjection;
580+
if (isset($workTag[0]) && false !== stripos($workTag[0], '<img')) {
581+
$appendContent = $this->wrapText($appendContent, $tag, $cssClass);
582+
}
583+
$this->content .= $appendContent;
553584
}
554585
}
555586
}

lib/Caxy/HtmlDiff/HtmlDiffConfig.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class HtmlDiffConfig
4848
'em' => '[[REPLACE_EM]]',
4949
'i' => '[[REPLACE_I]]',
5050
'a' => '[[REPLACE_A]]',
51+
'img' => '[[REPLACE_IMG]]',
5152
);
5253

5354
/**

0 commit comments

Comments
 (0)