diff --git a/js/htmldiff.js b/js/htmldiff.js index 5e0c28b..c88539c 100644 --- a/js/htmldiff.js +++ b/js/htmldiff.js @@ -59,7 +59,7 @@ * null otherwise */ function is_start_of_atomic_tag(word){ - var result = /^<(iframe|object|math|svg|script)/.exec(word); + var result = /^<(iframe|object|math|svg|script|video)/.exec(word); if (result){ result = result[1]; } @@ -99,7 +99,8 @@ * @return {boolean} True if the token can be wrapped inside a tag, false otherwise. */ function is_wrappable(token){ - return isnt_tag(token) || is_start_of_atomic_tag(token) || is_void_tag(token); + var is_img = /^]/.test(token); + return is_img|| isnt_tag(token) || is_start_of_atomic_tag(token) || is_void_tag(token); } /** @@ -250,10 +251,44 @@ * @return {string} The identifying key that should be used to match before and after tokens. */ function get_key_for_token(token){ + // If the token is an image element, grab it's src attribute to include in the key. + var img = /^$/.exec(token); + if (img) { + return ''; + } + + // If the token is an object element, grab it's data attribute to include in the key. + var object = /^'; + } + + // If it's a video, math or svg element, the entire token should be compared except the + // data-uuid. + if(/^<(svg|math|video)[\s>]/.test(token)) { + var uuid = token.indexOf('data-uuid="'); + if (uuid !== -1) { + var start = token.slice(0, uuid); + var end = token.slice(uuid + 44); + return start + end; + } else { + return token; + } + } + + // If the token is an iframe element, grab it's src attribute to include in it's key. + var iframe = /^/.exec(token); + if (iframe) { + return ''; + } + + // If token any other element, just grab the tag name. var tag_name = /<([^\s>]+)[\s>]/.exec(token); if (tag_name){ return '<' + (tag_name[1].toLowerCase()) + '>'; } + + // Otherwise, the token is text, collapse the whitespace. if (token){ return token.replace(/(\s+| | )/g, ' '); } diff --git a/test/diff.spec.js b/test/diff.spec.js index e286224..ea0fd72 100644 --- a/test/diff.spec.js +++ b/test/diff.spec.js @@ -1,8 +1,10 @@ describe('Diff', function(){ - var cut, res; + var cut, res, html_to_tokens, calculate_operations; beforeEach(function(){ cut = require('../js/htmldiff'); + html_to_tokens = cut.html_to_tokens; + calculate_operations = cut.calculate_operations; }); describe('When both inputs are the same', function(){ @@ -45,4 +47,164 @@ describe('Diff', function(){ 'input 2'); }); }); // describe('When a class name is specified') + + describe('Image Differences', function(){ + it('show two images as different if their src attributes are different', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'replace', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + + it('should show two images are the same if their src attributes are the same', function() { + var before = html_to_tokens(''); + var after = html_to_tokens('hey!'); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'equal', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + }); // describe('Image Differences') + + describe('Widget Differences', function(){ + it('show two widgets as different if their data attributes are different', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'replace', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + + it('should show two widgets are the same if their data attributes are the same', function() { + var before = html_to_tokens('yo!'); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'equal', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + }); // describe('Widget Differences') + + describe('Math Differences', function(){ + it('should show two math elements as different if their contents are different', function() { + var before = html_to_tokens('' + + 'b2'); + var after = html_to_tokens('' + + 'b5'); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'replace', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + + it('should show two math elements as the same if their contents are the same', function() { + var before = html_to_tokens('' + + 'b2'); + var after = html_to_tokens('' + + 'b2'); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'equal', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + }); // describe('Math Differences') + + describe('Video Differences', function(){ + it('show two widgets as different if their data attributes are different', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'replace', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + + }); + + it('should show two widgets are the same if their data attributes are the same', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'equal', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + }); // describe('Video Differences') + + describe('iframe Differences', function(){ + it('show two widgets as different if their data attributes are different', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'replace', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + + it('should show two widgets are the same if their data attributes are the same', function() { + var before = html_to_tokens(''); + var after = html_to_tokens(''); + var ops = calculate_operations(before, after); + expect(ops.length).to.equal(1); + expect(ops[0]).to.eql({ + action: 'equal', + start_in_before: 0, + end_in_before: 0, + start_in_after: 0, + end_in_after: 0 + }); + }); + }); // describe('iframe Differences') + }); // describe('Diff')