@matrixreq/htmldiff 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +76 -8
  2. package/js/constants.d.ts +3 -0
  3. package/js/constants.js +6 -0
  4. package/js/core/atomicTags.d.ts +10 -0
  5. package/js/core/atomicTags.js +28 -0
  6. package/js/core/diff.d.ts +2 -0
  7. package/js/core/diff.js +15 -0
  8. package/js/core/matching.d.ts +27 -0
  9. package/js/core/matching.js +207 -0
  10. package/js/core/operations.d.ts +10 -0
  11. package/js/core/operations.js +76 -0
  12. package/js/core/rendering.d.ts +25 -0
  13. package/js/core/rendering.js +212 -0
  14. package/js/core/tokens.d.ts +11 -0
  15. package/js/core/tokens.js +256 -0
  16. package/js/htmldiff.d.ts +0 -15
  17. package/js/htmldiff.js +14 -1343
  18. package/js/tables/Cell.d.ts +24 -0
  19. package/js/tables/Cell.js +115 -0
  20. package/js/tables/ColumnAligner.d.ts +11 -0
  21. package/js/tables/ColumnAligner.js +83 -0
  22. package/js/tables/MergedCells.d.ts +11 -0
  23. package/js/tables/MergedCells.js +171 -0
  24. package/js/tables/Row.d.ts +22 -0
  25. package/js/tables/Row.js +49 -0
  26. package/js/tables/RowAligner.d.ts +12 -0
  27. package/js/tables/RowAligner.js +107 -0
  28. package/js/tables/SequenceAligner.d.ts +47 -0
  29. package/js/tables/SequenceAligner.js +125 -0
  30. package/js/tables/Table.d.ts +27 -0
  31. package/js/tables/Table.js +166 -0
  32. package/js/tables/TableAligner.d.ts +9 -0
  33. package/js/tables/TableAligner.js +69 -0
  34. package/js/tables/TableMerger.d.ts +16 -0
  35. package/js/tables/TableMerger.js +216 -0
  36. package/js/tables/TableRedlining.d.ts +10 -0
  37. package/js/tables/TableRedlining.js +65 -0
  38. package/js/tables/TableVersion.d.ts +32 -0
  39. package/js/tables/TableVersion.js +128 -0
  40. package/js/tables/constants.d.ts +6 -0
  41. package/js/tables/constants.js +8 -0
  42. package/js/tables/helpers.d.ts +4 -0
  43. package/js/tables/helpers.js +23 -0
  44. package/js/tables/html.d.ts +32 -0
  45. package/js/tables/html.js +107 -0
  46. package/js/tables/index.d.ts +2 -0
  47. package/js/tables/index.js +5 -0
  48. package/js/tables/similarity.d.ts +10 -0
  49. package/js/tables/similarity.js +107 -0
  50. package/package.json +21 -14
  51. package/test/calculate_operations.spec.js +0 -278
  52. package/test/config.js +0 -2
  53. package/test/diff.spec.js +0 -318
  54. package/test/edge_cases.spec.js +0 -41
  55. package/test/find_matching_blocks.spec.js +0 -168
  56. package/test/from_port_source.spec.js +0 -30
  57. package/test/html_to_tokens.spec.js +0 -238
  58. package/test/inner_diff.spec.js +0 -333
  59. package/test/mocha.opts +0 -3
  60. package/test/module.spec.js +0 -11
  61. package/test/pain_games.spec.js +0 -18
  62. package/test/render_operations.spec.js +0 -178
@@ -1,333 +0,0 @@
1
- describe('Recursive inner diff (data-htmldiff-inner-diff)', function(){
2
- var cut;
3
-
4
- beforeEach(function(){
5
- cut = require('../js/htmldiff');
6
- });
7
-
8
- function tocEntry(href, name){
9
- return '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
10
- '<a href="' + href + '">' + name + '</a></div>';
11
- }
12
-
13
- describe('when an opted-in element is renamed in place', function(){
14
- it('renders inline ins/del inside the single emitted element', function(){
15
- var res = cut(tocEntry('#123', '1. Old name'), tocEntry('#123', '1. New name'));
16
- expect(res).to.equal(
17
- '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
18
- '<a href="#123">1. <del data-operation-index="1">Old</del>' +
19
- '<ins data-operation-index="1">New</ins> name</a></div>');
20
- });
21
-
22
- it('passes className and dataPrefix through to the inner ins/del tags', function(){
23
- var res = cut(tocEntry('#123', 'Old'), tocEntry('#123', 'New'), 'diff-cls', 'pre');
24
- expect(res).to.equal(
25
- '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
26
- '<a href="#123"><del data-pre-operation-index="1" class="diff-cls">Old</del>' +
27
- '<ins data-pre-operation-index="1" class="diff-cls">New</ins></a></div>');
28
- });
29
-
30
- it('keeps diffing the rest of the document with the outer atomic tag list', function(){
31
- // The <a> outside the opted-in element must stay atomic after the inner diff ran.
32
- var res = cut(
33
- tocEntry('#123', 'Old name') + '<a href="x.html">same link</a>',
34
- tocEntry('#123', 'New name') + '<a href="y.html">same link</a>');
35
- expect(res).to.equal(
36
- '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
37
- '<a href="#123"><del data-operation-index="1">Old</del>' +
38
- '<ins data-operation-index="1">New</ins> name</a></div>' +
39
- '<del data-operation-index="1"><a href="x.html">same link</a></del>' +
40
- '<ins data-operation-index="1"><a href="y.html">same link</a></ins>');
41
- });
42
- }); // describe('when an opted-in element is renamed in place')
43
-
44
- describe('anchors inside the recursive diff', function(){
45
- it('do not treat <a> as atomic, so href-only changes produce no diff markup', function(){
46
- var res = cut(tocEntry('#18036', '1. Same name'), tocEntry('#18037', '1. Same name'));
47
- expect(res).to.equal(tocEntry('#18037', '1. Same name'));
48
- });
49
-
50
- it('diffs the link text inline when the href changed', function(){
51
- var res = cut(tocEntry('#18036', '1. Old name'), tocEntry('#18037', '1. New name'));
52
- expect(res).to.equal(
53
- '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
54
- '<a href="#18037">1. <del data-operation-index="1">Old</del>' +
55
- '<ins data-operation-index="1">New</ins> name</a></div>');
56
- });
57
- }); // describe('anchors inside the recursive diff')
58
-
59
- describe('atomic tags inside the recursive diff', function(){
60
- function el(extraAttrs, inner){
61
- return '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"' + extraAttrs +
62
- '>' + inner + '</div>';
63
- }
64
-
65
- it('keeps the default atomic tags (without a) inside the recursion', function(){
66
- // Embedded content like svg stays atomic by default: a changed svg is replaced
67
- // as a whole, not word-diffed.
68
- var res = cut(
69
- el('', '<svg viewBox="0 0 1 1"><text>old</text></svg>'),
70
- el('', '<svg viewBox="0 0 1 1"><text>new</text></svg>'));
71
- expect(res).to.equal(
72
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
73
- '<del data-operation-index="0">' +
74
- '<svg viewBox="0 0 1 1"><text>old</text></svg></del>' +
75
- '<ins data-operation-index="0">' +
76
- '<svg viewBox="0 0 1 1"><text>new</text></svg></ins>' +
77
- '</div>');
78
- });
79
-
80
- it('replaces the default list with data-htmldiff-inner-diff-atomic-tags', function(){
81
- // The override lists only em, so svg is no longer atomic and gets word-diffed.
82
- var attrs = ' data-htmldiff-inner-diff-atomic-tags="em"';
83
- var res = cut(
84
- el(attrs, '<svg viewBox="0 0 1 1"><text>old</text></svg>'),
85
- el(attrs, '<svg viewBox="0 0 1 1"><text>new</text></svg>'));
86
- expect(res).to.equal(
87
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"' + attrs + '>' +
88
- '<svg viewBox="0 0 1 1"><text>' +
89
- '<del data-operation-index="1">old</del>' +
90
- '<ins data-operation-index="1">new</ins>' +
91
- '</text></svg></div>');
92
- });
93
-
94
- it('restores atomic anchors (href comparison) when the override lists a', function(){
95
- var attrs = ' data-htmldiff-inner-diff-atomic-tags="a"';
96
- var res = cut(
97
- el(attrs, '<a href="#1">Name</a>'),
98
- el(attrs, '<a href="#2">Name</a>'));
99
- expect(res).to.equal(
100
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"' + attrs + '>' +
101
- '<del data-operation-index="0"><a href="#1">Name</a></del>' +
102
- '<ins data-operation-index="0"><a href="#2">Name</a></ins>' +
103
- '</div>');
104
- });
105
-
106
- it('treats no tag name as atomic when the override value is empty', function(){
107
- var attrs = ' data-htmldiff-inner-diff-atomic-tags=""';
108
- var res = cut(
109
- el(attrs, '<svg viewBox="0 0 1 1"><text>old</text></svg>'),
110
- el(attrs, '<svg viewBox="0 0 1 1"><text>new</text></svg>'));
111
- expect(res).to.equal(
112
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"' + attrs + '>' +
113
- '<svg viewBox="0 0 1 1"><text>' +
114
- '<del data-operation-index="1">old</del>' +
115
- '<ins data-operation-index="1">new</ins>' +
116
- '</text></svg></div>');
117
- });
118
- }); // describe('atomic tags inside the recursive diff')
119
-
120
- describe('opt-in attribute values', function(){
121
- function entry(value, name){
122
- return '<div data-htmldiff-id="123" data-htmldiff-inner-diff=' + value + '>' +
123
- name + '</div>';
124
- }
125
-
126
- it('treats a double-quoted "false" value as opted out', function(){
127
- var res = cut(entry('"false"', 'old'), entry('"false"', 'new'));
128
- expect(res).to.equal(entry('"false"', 'new'));
129
- });
130
-
131
- it('treats a single-quoted \'false\' value as opted out', function(){
132
- var res = cut(entry("'false'", 'old'), entry("'false'", 'new'));
133
- expect(res).to.equal(entry("'false'", 'new'));
134
- });
135
-
136
- it('treats an unquoted false value as opted out', function(){
137
- var res = cut(entry('false', 'old'), entry('false', 'new'));
138
- expect(res).to.equal(entry('false', 'new'));
139
- });
140
-
141
- it('treats a bare attribute without a value as opted in', function(){
142
- var res = cut(
143
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff>old</div>',
144
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff>new</div>');
145
- expect(res).to.equal(
146
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff>' +
147
- '<del data-operation-index="0">old</del>' +
148
- '<ins data-operation-index="0">new</ins></div>');
149
- });
150
-
151
- it('only matches exact attribute name', function(){
152
- var res = cut(
153
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff-extra="true">old</div>',
154
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff-extra="true">new</div>');
155
- expect(res).to.equal(
156
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff-extra="true">new</div>');
157
- });
158
-
159
- it('recognizes the attribute regardless of its position', function(){
160
- var res = cut(
161
- '<div data-htmldiff-inner-diff="true" data-htmldiff-id="123">old</div>',
162
- '<div data-htmldiff-inner-diff="true" data-htmldiff-id="123">new</div>');
163
- expect(res).to.equal(
164
- '<div data-htmldiff-inner-diff="true" data-htmldiff-id="123">' +
165
- '<del data-operation-index="0">old</del>' +
166
- '<ins data-operation-index="0">new</ins></div>');
167
- });
168
- }); // describe('opt-in attribute values')
169
-
170
- describe('edge cases', function(){
171
- it('ignores the attribute on non-atomic elements (no data-htmldiff-id)', function(){
172
- // Without data-htmldiff-id the div is not atomic, so this is a plain word diff.
173
- var res = cut(
174
- '<div data-htmldiff-inner-diff="true">old text</div>',
175
- '<div data-htmldiff-inner-diff="true">new text</div>');
176
- expect(res).to.equal(
177
- '<div data-htmldiff-inner-diff="true">' +
178
- '<del data-operation-index="1">old</del>' +
179
- '<ins data-operation-index="1">new</ins> text</div>');
180
- });
181
-
182
- it('diffs text following a self-closing opted-in element normally', function(){
183
- var res = cut(
184
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>x old',
185
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>x new');
186
- expect(res).to.equal(
187
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>x ' +
188
- '<del data-operation-index="1">old</del>' +
189
- '<ins data-operation-index="1">new</ins>');
190
- });
191
-
192
- it('marks the content as inserted when the before element was self-closing', function(){
193
- // A self-closing element has empty inner content, so the new content is a
194
- // pure insertion.
195
- var res = cut(
196
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>',
197
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">new</div>');
198
- expect(res).to.equal(
199
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
200
- '<ins data-operation-index="0">new</ins></div>');
201
- });
202
-
203
- it('marks the content as deleted when the after element became self-closing', function(){
204
- // The after element has no content anymore, so the deleted content is
205
- // rendered right after the self-closing tag.
206
- var res = cut(
207
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">old</div>',
208
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>');
209
- expect(res).to.equal(
210
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true"/>' +
211
- '<del data-operation-index="0">old</del>');
212
- });
213
-
214
- it('is not confused by ">" inside attribute values', function(){
215
- var res = cut(
216
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true" title="a > b">' +
217
- 'old</div>',
218
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true" title="a > c">' +
219
- 'new</div>');
220
- expect(res).to.equal(
221
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true" title="a > c">' +
222
- '<del data-operation-index="0">old</del>' +
223
- '<ins data-operation-index="0">new</ins></div>');
224
- });
225
-
226
- it('is not confused by ">" inside single-quoted attribute values', function(){
227
- var res = cut(
228
- "<div data-htmldiff-id='123' data-htmldiff-inner-diff title='a > b'>old</div>",
229
- "<div data-htmldiff-id='123' data-htmldiff-inner-diff title='a > b'>new</div>");
230
- expect(res).to.equal(
231
- "<div data-htmldiff-id='123' data-htmldiff-inner-diff title='a > b'>" +
232
- '<del data-operation-index="0">old</del>' +
233
- '<ins data-operation-index="0">new</ins></div>');
234
- });
235
-
236
- it('falls back to the after version when a token cannot be split', function(){
237
- // An unterminated atomic tag swallows the rest of the input and has no closing
238
- // tag to split on; the inner diff falls back instead of producing broken markup.
239
- var after = '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">new';
240
- var res = cut(
241
- '<div data-htmldiff-id="123" data-htmldiff-inner-diff="true">old',
242
- after);
243
- expect(res).to.equal(after);
244
- });
245
-
246
- it('renders pure insertions when the before content is empty', function(){
247
- var res = cut(tocEntry('#1', ''), tocEntry('#1', 'New name'));
248
- expect(res).to.equal(
249
- '<div class="toc-entry" data-htmldiff-id="123" data-htmldiff-inner-diff="true">' +
250
- '<a href="#1"><ins data-operation-index="1">New name</ins></a></div>');
251
- });
252
-
253
- it('do not diffs inner html for moved opted-in elements', function(){
254
- function entry(id, name){
255
- return '<div data-htmldiff-id="' + id + '" data-htmldiff-inner-diff="true">' +
256
- name + '</div>';
257
- }
258
- var res = cut(entry('a', 'First') + entry('b', 'Second'),
259
- entry('b', 'Second') + entry('a', 'First'));
260
- expect(res).to.equal(
261
- '<ins data-operation-index="0">' + entry('b', 'Second') + '</ins>' +
262
- entry('a', 'First') +
263
- '<del data-operation-index="2">' + entry('b', 'Second') + '</del>');
264
- });
265
- }); // describe('edge cases')
266
-
267
- describe('when the element did not opt in', function(){
268
- it('should render the after version as is when keys match but content differs', function(){
269
- var before = '<div data-htmldiff-id="chart-1"><svg viewBox="0 0 1 1">' +
270
- '<rect width="5"/></svg></div>';
271
- var after = '<div data-htmldiff-id="chart-1"><svg viewBox="0 0 2 2">' +
272
- '<rect width="9"/></svg></div>';
273
- expect(cut(before, after)).to.equal(after);
274
- });
275
- }); // describe('when the element did not opt in')
276
-
277
- describe('when key and content are both equal', function(){
278
- it('should render the element unchanged', function(){
279
- var before = 'x ' + tocEntry('#123', '1. Same name') + ' y';
280
- var after = 'x ' + tocEntry('#123', '1. Same name') + ' z';
281
- expect(cut(before, after)).to.equal(
282
- 'x ' + tocEntry('#123', '1. Same name') + ' ' +
283
- '<del data-operation-index="1">y</del><ins data-operation-index="1">z</ins>');
284
- });
285
- }); // describe('when key and content are both equal')
286
-
287
- describe('when opted-in elements are nested', function(){
288
- function nest(depth, content){
289
- var html = content;
290
- for (var i = depth; i >= 1; i--){
291
- html = '<div data-htmldiff-id="d' + i + '" data-htmldiff-inner-diff="true">' +
292
- html + '</div>';
293
- }
294
- return html;
295
- }
296
-
297
- it('diffs nested elements', function(){
298
- var res = cut(
299
- '<div data-htmldiff-id="outer" data-htmldiff-inner-diff="true">x ' +
300
- '<span data-htmldiff-id="inner" data-htmldiff-inner-diff="true">old</span></div>',
301
- '<div data-htmldiff-id="outer" data-htmldiff-inner-diff="true">x ' +
302
- '<span data-htmldiff-id="inner" data-htmldiff-inner-diff="true">new</span></div>');
303
- expect(res).to.equal(
304
- '<div data-htmldiff-id="outer" data-htmldiff-inner-diff="true">x ' +
305
- '<span data-htmldiff-id="inner" data-htmldiff-inner-diff="true">' +
306
- '<del data-operation-index="0">old</del>' +
307
- '<ins data-operation-index="0">new</ins></span></div>');
308
- });
309
-
310
- it('do not diffs nested element that do not opt-in', function(){
311
- var after = '<div data-htmldiff-id="outer" data-htmldiff-inner-diff="true">t ' +
312
- '<span data-htmldiff-id="inner">new</span></div>';
313
- var res = cut(
314
- '<div data-htmldiff-id="outer" data-htmldiff-inner-diff="true">t ' +
315
- '<span data-htmldiff-id="inner">old</span></div>',
316
- after);
317
- expect(res).to.equal(after);
318
- });
319
-
320
- it('diffs all levels up to the depth cap of 10', function(){
321
- var res = cut(nest(10, 'old'), nest(10, 'new'));
322
- expect(res).to.equal(nest(10,
323
- '<del data-operation-index="0">old</del>' +
324
- '<ins data-operation-index="0">new</ins>'));
325
- });
326
-
327
- it('renders the after version as is beyond the depth cap', function(){
328
- var res = cut(nest(11, 'old'), nest(11, 'new'));
329
- expect(res).to.equal(nest(11, 'new'));
330
- });
331
- }); // describe('when opted-in elements are nested')
332
-
333
- }); // describe('Recursive inner diff (data-htmldiff-inner-diff)')
package/test/mocha.opts DELETED
@@ -1,3 +0,0 @@
1
- --require test/config.js
2
- --ui bdd
3
- --reporter spec
@@ -1,11 +0,0 @@
1
- describe('The module', function(){
2
- var cut;
3
-
4
- beforeEach(function(){
5
- cut = require('../js/htmldiff');
6
- });
7
-
8
- it('should return a function', function(){
9
- expect(cut).is.a('function');
10
- });
11
- });
@@ -1,18 +0,0 @@
1
- describe('Pain Games', function(){
2
- var cut, res;
3
-
4
- beforeEach(function(){
5
- cut = require('../js/htmldiff');
6
- });
7
-
8
- describe('When an entire sentence is replaced', function(){
9
- beforeEach(function(){
10
- res = cut('this is what I had', 'and now we have a new one');
11
- });
12
-
13
- it('should replace the whole chunk', function(){
14
- expect(res).to.equal('<del data-operation-index="0">this is what I had</del>' +
15
- '<ins data-operation-index="0">and now we have a new one</ins>');
16
- });
17
- });
18
- });
@@ -1,178 +0,0 @@
1
- describe('renderOperations', function(){
2
- var cut, res, createToken, tokenize;
3
-
4
- beforeEach(function(){
5
- var diff = require('../js/htmldiff');
6
- createToken = diff.findMatchingBlocks.createToken;
7
-
8
- tokenize = function(tokens){
9
- return tokens.map(function(token){
10
- return createToken(token);
11
- });
12
- };
13
-
14
- cut = function(before, after){
15
- var ops = diff.calculateOperations(before, after);
16
- return diff.renderOperations(before, after, ops);
17
- };
18
- });
19
-
20
- it('should be a function', function(){
21
- expect(cut).is.a('function');
22
- });
23
-
24
- describe('equal', function(){
25
- beforeEach(function(){
26
- var before = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'test']);
27
- res = cut(before, before);
28
- });
29
-
30
- it('should output the text', function(){
31
- expect(res).equal('this is a test');
32
- });
33
- });
34
-
35
- describe('insert', function(){
36
- beforeEach(function(){
37
- before = tokenize(['this', ' ', 'is']);
38
- after = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'test']);
39
- res = cut(before, after);
40
- });
41
-
42
- it('should wrap in an <ins>', function(){
43
- expect(res).equal('this is<ins data-operation-index="1"> a test</ins>');
44
- });
45
- });
46
-
47
- describe('delete', function(){
48
- beforeEach(function(){
49
- var before = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'test',
50
- ' ', 'of', ' ', 'stuff']);
51
- var after = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'test']);
52
- res = cut(before, after);
53
- });
54
-
55
- it('should wrap in a <del>', function(){
56
- expect(res).to.equal('this is a test<del data-operation-index="1"> of stuff</del>');
57
- });
58
- });
59
-
60
- describe('replace', function(){
61
- beforeEach(function(){
62
- var before = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'break']);
63
- var after = tokenize(['this', ' ', 'is', ' ', 'a', ' ', 'test']);
64
- res = cut(before, after);
65
- });
66
-
67
- it('should wrap in both <ins> and <del>', function(){
68
- expect(res).to.equal('this is a <del data-operation-index="1">break</del>' +
69
- '<ins data-operation-index="1">test</ins>');
70
- });
71
- });
72
-
73
- describe('Dealing with tags', function(){
74
- var before, after;
75
-
76
- beforeEach(function(){
77
- before = tokenize(['<p>', 'a', '</p>']);
78
- after = tokenize(['<p>', 'a', ' ', 'b', '</p>', '<p>', 'c', '</p>']);
79
- res = cut(before, after);
80
- });
81
-
82
- it('should identify contained inserted tags', function(){
83
- expect(res).to.equal('<p>a<ins data-operation-index="1"> b</ins></p>' +
84
- '<p data-diff-node="ins" data-operation-index="3">' +
85
- '<ins data-operation-index="3">c</ins></p>');
86
- });
87
-
88
- it('should identify contained deleted tags', function(){
89
- res = cut(after, before);
90
-
91
- expect(res).to.equal('<p>a<del data-operation-index="1"> b</del></p>' +
92
- '<p data-diff-node="del" data-operation-index="3">' +
93
- '<del data-operation-index="3">c</del></p>');
94
- });
95
-
96
- it('should not identify partial tags', function(){
97
- var before = tokenize(['test', '</b>', 'non-bold']);
98
- var after = tokenize(['test!', '</b>', 'non-bold', '<b>', 'bold']);
99
- res = cut(before, after);
100
-
101
- expect(res).to.equal('<del data-operation-index="0">test</del>' +
102
- '<ins data-operation-index="0">test!</ins></b>non-bold<b>' +
103
- '<ins data-operation-index="2">bold</ins>');
104
- });
105
-
106
- describe('When there is a change at the beginning, in a <p>', function(){
107
- beforeEach(function(){
108
- var before = tokenize(['<p>', 'this', ' ', 'is', ' ', 'awesome', '</p>']);
109
- var after = tokenize(['<p>', 'I', ' ', 'is', ' ', 'awesome', '</p>']);
110
- res = cut(before, after);
111
- });
112
-
113
- it('should keep the change inside the <p>', function(){
114
- expect(res).to.equal('<p><del data-operation-index="1">this</del>' +
115
- '<ins data-operation-index="1">I</ins> is awesome</p>');
116
- });
117
- });
118
- });
119
-
120
- describe('empty tokens', function(){
121
- it('should not be wrapped', function(){
122
- var before = tokenize(['text']);
123
- var after = tokenize(['text', ' ']);
124
-
125
- res = cut(before, after);
126
-
127
- expect(res).to.equal('text');
128
- });
129
- });
130
-
131
- describe('tags with attributes', function(){
132
- it('should treat attribute changes as equal and output the after tag', function(){
133
- var before = tokenize(['<p>', 'this', ' ', 'is', ' ', 'awesome', '</p>']);
134
- var after = tokenize(['<p style="margin: 2px;" class="after">', 'this', ' ', 'is', ' ',
135
- 'awesome', '</p>']);
136
-
137
- res = cut(before, after);
138
-
139
- expect(res).to.equal('<p style="margin: 2px;" class="after">this is awesome</p>');
140
- });
141
-
142
- it('should show changes within tags with different attributes', function(){
143
- var before = tokenize(['<p>', 'this', ' ', 'is', ' ', 'awesome', '</p>']);
144
- var after = tokenize(['<p style="margin: 2px;" class="after">', 'that', ' ', 'is', ' ',
145
- 'awesome', '</p>']);
146
-
147
- res = cut(before, after);
148
-
149
- expect(res).to.equal('<p style="margin: 2px;" class="after">' +
150
- '<del data-operation-index="1">this</del><ins data-operation-index="1">' +
151
- 'that</ins> is awesome</p>');
152
- });
153
- });
154
-
155
- describe('wrappable tags', function(){
156
- it('should wrap void tags', function(){
157
- var before = tokenize(['old', ' ', 'text']);
158
- var after = tokenize(['new', '<br/>', ' ', 'text']);
159
-
160
- res = cut(before, after);
161
-
162
- expect(res).to.equal('<del data-operation-index="0">old</del>' +
163
- '<ins data-operation-index="0">new<br/></ins> text');
164
- });
165
-
166
- it('should wrap atomic tags independently', function(){
167
- var before = tokenize(['old', '<iframe src="source.html"></iframe>', ' ', 'text']);
168
- var after = tokenize(['new', ' ', 'text']);
169
-
170
- res = cut(before, after);
171
-
172
- expect(res).to.equal(
173
- '<del data-operation-index="0">old</del>' +
174
- '<del data-operation-index="0"><iframe src="source.html"></iframe></del>' +
175
- '<ins data-operation-index="0">new</ins> text');
176
- });
177
- });
178
- });