@@ -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 }
0 commit comments