clapton 0.0.12 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -0
  3. data/app/helpers/clapton/clapton_helper.rb +16 -1
  4. data/lib/clapton/engine.rb +16 -10
  5. data/lib/clapton/javascripts/dist/client.js +65 -39
  6. data/lib/clapton/javascripts/dist/components-for-test.js +439 -0
  7. data/lib/clapton/javascripts/dist/components.js +357 -369
  8. data/lib/clapton/javascripts/node_modules/diff-dom/LICENSE.txt +165 -0
  9. data/lib/clapton/javascripts/node_modules/diff-dom/README.md +224 -0
  10. data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js +2 -0
  11. data/lib/clapton/javascripts/node_modules/diff-dom/browser/diffDOM.js.map +1 -0
  12. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/TraceLogger.d.ts +28 -0
  13. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/apply.d.ts +4 -0
  14. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/fromVirtual.d.ts +2 -0
  15. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/index.d.ts +2 -0
  16. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/dom/undo.d.ts +3 -0
  17. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/helpers.d.ts +11 -0
  18. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/index.d.ts +10 -0
  19. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/types.d.ts +104 -0
  20. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/apply.d.ts +3 -0
  21. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/diff.d.ts +22 -0
  22. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromDOM.d.ts +2 -0
  23. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/fromString.d.ts +2 -0
  24. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/helpers.d.ts +40 -0
  25. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/diffDOM/virtual/index.d.ts +3 -0
  26. data/lib/clapton/javascripts/node_modules/diff-dom/dist/dts/index.d.ts +2 -0
  27. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.d.ts +136 -0
  28. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js +1996 -0
  29. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.js.map +1 -0
  30. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js +2 -0
  31. data/lib/clapton/javascripts/node_modules/diff-dom/dist/index.min.js.map +1 -0
  32. data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js +1991 -0
  33. data/lib/clapton/javascripts/node_modules/diff-dom/dist/module.js.map +1 -0
  34. data/lib/clapton/javascripts/node_modules/diff-dom/index.html +62 -0
  35. data/lib/clapton/javascripts/node_modules/diff-dom/package.json +54 -0
  36. data/lib/clapton/javascripts/node_modules/diff-dom/rollup.config.mjs +67 -0
  37. data/lib/clapton/javascripts/node_modules/diff-dom/src/TraceLogger.ts +143 -0
  38. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/apply.ts +227 -0
  39. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/fromVirtual.ts +83 -0
  40. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/index.ts +2 -0
  41. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/dom/undo.ts +90 -0
  42. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/helpers.ts +40 -0
  43. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/index.ts +121 -0
  44. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/types.ts +154 -0
  45. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/apply.ts +349 -0
  46. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/diff.ts +855 -0
  47. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromDOM.ts +74 -0
  48. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/fromString.ts +239 -0
  49. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/helpers.ts +461 -0
  50. data/lib/clapton/javascripts/node_modules/diff-dom/src/diffDOM/virtual/index.ts +3 -0
  51. data/lib/clapton/javascripts/node_modules/diff-dom/src/index.ts +2 -0
  52. data/lib/clapton/javascripts/node_modules/diff-dom/tsconfig.json +103 -0
  53. data/lib/clapton/javascripts/rollup.config.mjs +17 -2
  54. data/lib/clapton/javascripts/src/actions/handle-action.ts +6 -1
  55. data/lib/clapton/javascripts/src/actions/initialize-actions.ts +11 -0
  56. data/lib/clapton/javascripts/src/channel/clapton-channel.js +8 -4
  57. data/lib/clapton/javascripts/src/client.ts +15 -18
  58. data/lib/clapton/javascripts/src/components/box.ts +5 -0
  59. data/lib/clapton/javascripts/src/components/embed.spec.ts +8 -0
  60. data/lib/clapton/javascripts/src/components/embed.ts +11 -0
  61. data/lib/clapton/javascripts/src/components-for-test.ts +29 -0
  62. data/lib/clapton/javascripts/src/components.ts +5 -1
  63. data/lib/clapton/javascripts/src/dom/update-component.ts +3 -2
  64. data/lib/clapton/javascripts/src/inputs/initialize-inputs.ts +3 -3
  65. data/lib/clapton/test_helper/base.rb +1 -1
  66. data/lib/clapton/version.rb +2 -1
  67. metadata +51 -3
  68. data/lib/clapton/javascripts/src/dom/update-component.spec.ts +0 -32
@@ -0,0 +1,1991 @@
1
+ /******************************************************************************
2
+ Copyright (c) Microsoft Corporation.
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any
5
+ purpose with or without fee is hereby granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
14
+ ***************************************************************************** */
15
+ /* global Reflect, Promise, SuppressedError, Symbol */
16
+
17
+
18
+ var __assign = function() {
19
+ __assign = Object.assign || function __assign(t) {
20
+ var arguments$1 = arguments;
21
+
22
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
23
+ s = arguments$1[i];
24
+ for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) { t[p] = s[p]; } }
25
+ }
26
+ return t;
27
+ };
28
+ return __assign.apply(this, arguments);
29
+ };
30
+
31
+ function __spreadArray(to, from, pack) {
32
+ if (pack || arguments.length === 2) { for (var i = 0, l = from.length, ar; i < l; i++) {
33
+ if (ar || !(i in from)) {
34
+ if (!ar) { ar = Array.prototype.slice.call(from, 0, i); }
35
+ ar[i] = from[i];
36
+ }
37
+ } }
38
+ return to.concat(ar || Array.prototype.slice.call(from));
39
+ }
40
+
41
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
42
+ var e = new Error(message);
43
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
44
+ };
45
+
46
+ var Diff = /** @class */ (function () {
47
+ function Diff(options) {
48
+ if (options === void 0) { options = {}; }
49
+ var _this = this;
50
+ Object.entries(options).forEach(function (_a) {
51
+ var key = _a[0], value = _a[1];
52
+ return (_this[key] = value);
53
+ });
54
+ }
55
+ Diff.prototype.toString = function () {
56
+ return JSON.stringify(this);
57
+ };
58
+ Diff.prototype.setValue = function (aKey, aValue) {
59
+ this[aKey] = aValue;
60
+ return this;
61
+ };
62
+ return Diff;
63
+ }());
64
+ function checkElementType(element) {
65
+ var arguments$1 = arguments;
66
+
67
+ var elementTypeNames = [];
68
+ for (var _i = 1; _i < arguments.length; _i++) {
69
+ elementTypeNames[_i - 1] = arguments$1[_i];
70
+ }
71
+ if (typeof element === "undefined" || element === null) {
72
+ return false;
73
+ }
74
+ return elementTypeNames.some(function (elementTypeName) {
75
+ var _a, _b;
76
+ // We need to check if the specified type is defined
77
+ // because otherwise instanceof throws an exception.
78
+ return typeof ((_b = (_a = element === null || element === void 0 ? void 0 : element.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView) === null || _b === void 0 ? void 0 : _b[elementTypeName]) ===
79
+ "function" &&
80
+ element instanceof
81
+ element.ownerDocument.defaultView[elementTypeName];
82
+ });
83
+ }
84
+
85
+ function objToNode(objNode, insideSvg, options) {
86
+ var node;
87
+ if (objNode.nodeName === "#text") {
88
+ node = options.document.createTextNode(objNode.data);
89
+ }
90
+ else if (objNode.nodeName === "#comment") {
91
+ node = options.document.createComment(objNode.data);
92
+ }
93
+ else {
94
+ if (insideSvg) {
95
+ node = options.document.createElementNS("http://www.w3.org/2000/svg", objNode.nodeName);
96
+ if (objNode.nodeName === "foreignObject") {
97
+ insideSvg = false;
98
+ }
99
+ }
100
+ else if (objNode.nodeName.toLowerCase() === "svg") {
101
+ node = options.document.createElementNS("http://www.w3.org/2000/svg", "svg");
102
+ insideSvg = true;
103
+ }
104
+ else {
105
+ node = options.document.createElement(objNode.nodeName);
106
+ }
107
+ if (objNode.attributes) {
108
+ Object.entries(objNode.attributes).forEach(function (_a) {
109
+ var key = _a[0], value = _a[1];
110
+ return node.setAttribute(key, value);
111
+ });
112
+ }
113
+ if (objNode.childNodes) {
114
+ node = node;
115
+ objNode.childNodes.forEach(function (childNode) {
116
+ return node.appendChild(objToNode(childNode, insideSvg, options));
117
+ });
118
+ }
119
+ if (options.valueDiffing) {
120
+ if (objNode.value &&
121
+ checkElementType(node, "HTMLButtonElement", "HTMLDataElement", "HTMLInputElement", "HTMLLIElement", "HTMLMeterElement", "HTMLOptionElement", "HTMLProgressElement", "HTMLParamElement")) {
122
+ node.value = objNode.value;
123
+ }
124
+ if (objNode.checked && checkElementType(node, "HTMLInputElement")) {
125
+ node.checked = objNode.checked;
126
+ }
127
+ if (objNode.selected &&
128
+ checkElementType(node, "HTMLOptionElement")) {
129
+ node.selected = objNode.selected;
130
+ }
131
+ }
132
+ }
133
+ return node;
134
+ }
135
+
136
+ // ===== Apply a diff =====
137
+ var getFromRoute = function (node, route) {
138
+ route = route.slice();
139
+ while (route.length > 0) {
140
+ var c = route.splice(0, 1)[0];
141
+ node = node.childNodes[c];
142
+ }
143
+ return node;
144
+ };
145
+ function applyDiff(tree, diff, options) {
146
+ var action = diff[options._const.action];
147
+ var route = diff[options._const.route];
148
+ var node;
149
+ if (![options._const.addElement, options._const.addTextElement].includes(action)) {
150
+ // For adding nodes, we calculate the route later on. It's different because it includes the position of the newly added item.
151
+ node = getFromRoute(tree, route);
152
+ }
153
+ var newNode;
154
+ var reference;
155
+ var nodeArray;
156
+ // pre-diff hook
157
+ var info = {
158
+ diff: diff,
159
+ node: node
160
+ };
161
+ if (options.preDiffApply(info)) {
162
+ return true;
163
+ }
164
+ switch (action) {
165
+ case options._const.addAttribute:
166
+ if (!node || !checkElementType(node, "Element")) {
167
+ return false;
168
+ }
169
+ node.setAttribute(diff[options._const.name], diff[options._const.value]);
170
+ break;
171
+ case options._const.modifyAttribute:
172
+ if (!node || !checkElementType(node, "Element")) {
173
+ return false;
174
+ }
175
+ node.setAttribute(diff[options._const.name], diff[options._const.newValue]);
176
+ if (checkElementType(node, "HTMLInputElement") &&
177
+ diff[options._const.name] === "value") {
178
+ node.value = diff[options._const.newValue];
179
+ }
180
+ break;
181
+ case options._const.removeAttribute:
182
+ if (!node || !checkElementType(node, "Element")) {
183
+ return false;
184
+ }
185
+ node.removeAttribute(diff[options._const.name]);
186
+ break;
187
+ case options._const.modifyTextElement:
188
+ if (!node || !checkElementType(node, "Text")) {
189
+ return false;
190
+ }
191
+ options.textDiff(node, node.data, diff[options._const.oldValue], diff[options._const.newValue]);
192
+ if (checkElementType(node.parentNode, "HTMLTextAreaElement")) {
193
+ node.parentNode.value = diff[options._const.newValue];
194
+ }
195
+ break;
196
+ case options._const.modifyValue:
197
+ if (!node || typeof node.value === "undefined") {
198
+ return false;
199
+ }
200
+ node.value = diff[options._const.newValue];
201
+ break;
202
+ case options._const.modifyComment:
203
+ if (!node || !checkElementType(node, "Comment")) {
204
+ return false;
205
+ }
206
+ options.textDiff(node, node.data, diff[options._const.oldValue], diff[options._const.newValue]);
207
+ break;
208
+ case options._const.modifyChecked:
209
+ if (!node || typeof node.checked === "undefined") {
210
+ return false;
211
+ }
212
+ node.checked = diff[options._const.newValue];
213
+ break;
214
+ case options._const.modifySelected:
215
+ if (!node || typeof node.selected === "undefined") {
216
+ return false;
217
+ }
218
+ node.selected = diff[options._const.newValue];
219
+ break;
220
+ case options._const.replaceElement: {
221
+ var insideSvg = diff[options._const.newValue].nodeName.toLowerCase() === "svg" ||
222
+ node.parentNode.namespaceURI === "http://www.w3.org/2000/svg";
223
+ node.parentNode.replaceChild(objToNode(diff[options._const.newValue], insideSvg, options), node);
224
+ break;
225
+ }
226
+ case options._const.relocateGroup:
227
+ nodeArray = __spreadArray([], new Array(diff[options._const.groupLength]), true).map(function () {
228
+ return node.removeChild(node.childNodes[diff[options._const.from]]);
229
+ });
230
+ nodeArray.forEach(function (childNode, index) {
231
+ if (index === 0) {
232
+ reference =
233
+ node.childNodes[diff[options._const.to]];
234
+ }
235
+ node.insertBefore(childNode, reference || null);
236
+ });
237
+ break;
238
+ case options._const.removeElement:
239
+ node.parentNode.removeChild(node);
240
+ break;
241
+ case options._const.addElement: {
242
+ var parentRoute = route.slice();
243
+ var c = parentRoute.splice(parentRoute.length - 1, 1)[0];
244
+ node = getFromRoute(tree, parentRoute);
245
+ if (!checkElementType(node, "Element")) {
246
+ return false;
247
+ }
248
+ node.insertBefore(objToNode(diff[options._const.element], node.namespaceURI === "http://www.w3.org/2000/svg", options), node.childNodes[c] || null);
249
+ break;
250
+ }
251
+ case options._const.removeTextElement: {
252
+ if (!node || node.nodeType !== 3) {
253
+ return false;
254
+ }
255
+ var parentNode = node.parentNode;
256
+ parentNode.removeChild(node);
257
+ if (checkElementType(parentNode, "HTMLTextAreaElement")) {
258
+ parentNode.value = "";
259
+ }
260
+ break;
261
+ }
262
+ case options._const.addTextElement: {
263
+ var parentRoute = route.slice();
264
+ var c = parentRoute.splice(parentRoute.length - 1, 1)[0];
265
+ newNode = options.document.createTextNode(diff[options._const.value]);
266
+ node = getFromRoute(tree, parentRoute);
267
+ if (!node.childNodes) {
268
+ return false;
269
+ }
270
+ node.insertBefore(newNode, node.childNodes[c] || null);
271
+ if (checkElementType(node.parentNode, "HTMLTextAreaElement")) {
272
+ node.parentNode.value = diff[options._const.value];
273
+ }
274
+ break;
275
+ }
276
+ default:
277
+ console.log("unknown action");
278
+ }
279
+ // if a new node was created, we might be interested in its
280
+ // post diff hook
281
+ options.postDiffApply({
282
+ diff: info.diff,
283
+ node: info.node,
284
+ newNode: newNode
285
+ });
286
+ return true;
287
+ }
288
+ function applyDOM(tree, diffs, options) {
289
+ return diffs.every(function (diff) {
290
+ return applyDiff(tree, diff, options);
291
+ });
292
+ }
293
+
294
+ // ===== Undo a diff =====
295
+ function swap(obj, p1, p2) {
296
+ var tmp = obj[p1];
297
+ obj[p1] = obj[p2];
298
+ obj[p2] = tmp;
299
+ }
300
+ function undoDiff(tree, diff, options) {
301
+ switch (diff[options._const.action]) {
302
+ case options._const.addAttribute:
303
+ diff[options._const.action] = options._const.removeAttribute;
304
+ applyDiff(tree, diff, options);
305
+ break;
306
+ case options._const.modifyAttribute:
307
+ swap(diff, options._const.oldValue, options._const.newValue);
308
+ applyDiff(tree, diff, options);
309
+ break;
310
+ case options._const.removeAttribute:
311
+ diff[options._const.action] = options._const.addAttribute;
312
+ applyDiff(tree, diff, options);
313
+ break;
314
+ case options._const.modifyTextElement:
315
+ swap(diff, options._const.oldValue, options._const.newValue);
316
+ applyDiff(tree, diff, options);
317
+ break;
318
+ case options._const.modifyValue:
319
+ swap(diff, options._const.oldValue, options._const.newValue);
320
+ applyDiff(tree, diff, options);
321
+ break;
322
+ case options._const.modifyComment:
323
+ swap(diff, options._const.oldValue, options._const.newValue);
324
+ applyDiff(tree, diff, options);
325
+ break;
326
+ case options._const.modifyChecked:
327
+ swap(diff, options._const.oldValue, options._const.newValue);
328
+ applyDiff(tree, diff, options);
329
+ break;
330
+ case options._const.modifySelected:
331
+ swap(diff, options._const.oldValue, options._const.newValue);
332
+ applyDiff(tree, diff, options);
333
+ break;
334
+ case options._const.replaceElement:
335
+ swap(diff, options._const.oldValue, options._const.newValue);
336
+ applyDiff(tree, diff, options);
337
+ break;
338
+ case options._const.relocateGroup:
339
+ swap(diff, options._const.from, options._const.to);
340
+ applyDiff(tree, diff, options);
341
+ break;
342
+ case options._const.removeElement:
343
+ diff[options._const.action] = options._const.addElement;
344
+ applyDiff(tree, diff, options);
345
+ break;
346
+ case options._const.addElement:
347
+ diff[options._const.action] = options._const.removeElement;
348
+ applyDiff(tree, diff, options);
349
+ break;
350
+ case options._const.removeTextElement:
351
+ diff[options._const.action] = options._const.addTextElement;
352
+ applyDiff(tree, diff, options);
353
+ break;
354
+ case options._const.addTextElement:
355
+ diff[options._const.action] = options._const.removeTextElement;
356
+ applyDiff(tree, diff, options);
357
+ break;
358
+ default:
359
+ console.log("unknown action");
360
+ }
361
+ }
362
+ function undoDOM(tree, diffs, options) {
363
+ diffs = diffs.slice();
364
+ diffs.reverse();
365
+ diffs.forEach(function (diff) {
366
+ undoDiff(tree, diff, options);
367
+ });
368
+ }
369
+
370
+ var elementDescriptors = function (el) {
371
+ var output = [];
372
+ output.push(el.nodeName);
373
+ if (el.nodeName !== "#text" && el.nodeName !== "#comment") {
374
+ el = el;
375
+ if (el.attributes) {
376
+ if (el.attributes["class"]) {
377
+ output.push("".concat(el.nodeName, ".").concat(el.attributes["class"].replace(/ /g, ".")));
378
+ }
379
+ if (el.attributes.id) {
380
+ output.push("".concat(el.nodeName, "#").concat(el.attributes.id));
381
+ }
382
+ }
383
+ }
384
+ return output;
385
+ };
386
+ var findUniqueDescriptors = function (li) {
387
+ var uniqueDescriptors = {};
388
+ var duplicateDescriptors = {};
389
+ li.forEach(function (node) {
390
+ elementDescriptors(node).forEach(function (descriptor) {
391
+ var inUnique = descriptor in uniqueDescriptors;
392
+ var inDupes = descriptor in duplicateDescriptors;
393
+ if (!inUnique && !inDupes) {
394
+ uniqueDescriptors[descriptor] = true;
395
+ }
396
+ else if (inUnique) {
397
+ delete uniqueDescriptors[descriptor];
398
+ duplicateDescriptors[descriptor] = true;
399
+ }
400
+ });
401
+ });
402
+ return uniqueDescriptors;
403
+ };
404
+ var uniqueInBoth = function (l1, l2) {
405
+ var l1Unique = findUniqueDescriptors(l1);
406
+ var l2Unique = findUniqueDescriptors(l2);
407
+ var inBoth = {};
408
+ Object.keys(l1Unique).forEach(function (key) {
409
+ if (l2Unique[key]) {
410
+ inBoth[key] = true;
411
+ }
412
+ });
413
+ return inBoth;
414
+ };
415
+ var removeDone = function (tree) {
416
+ delete tree.outerDone;
417
+ delete tree.innerDone;
418
+ delete tree.valueDone;
419
+ if (tree.childNodes) {
420
+ return tree.childNodes.every(removeDone);
421
+ }
422
+ else {
423
+ return true;
424
+ }
425
+ };
426
+ var cleanNode = function (diffNode) {
427
+ if (Object.prototype.hasOwnProperty.call(diffNode, "data")) {
428
+ var textNode = {
429
+ nodeName: diffNode.nodeName === "#text" ? "#text" : "#comment",
430
+ data: diffNode.data
431
+ };
432
+ return textNode;
433
+ }
434
+ else {
435
+ var elementNode = {
436
+ nodeName: diffNode.nodeName
437
+ };
438
+ diffNode = diffNode;
439
+ if (Object.prototype.hasOwnProperty.call(diffNode, "attributes")) {
440
+ elementNode.attributes = __assign({}, diffNode.attributes);
441
+ }
442
+ if (Object.prototype.hasOwnProperty.call(diffNode, "checked")) {
443
+ elementNode.checked = diffNode.checked;
444
+ }
445
+ if (Object.prototype.hasOwnProperty.call(diffNode, "value")) {
446
+ elementNode.value = diffNode.value;
447
+ }
448
+ if (Object.prototype.hasOwnProperty.call(diffNode, "selected")) {
449
+ elementNode.selected = diffNode.selected;
450
+ }
451
+ if (Object.prototype.hasOwnProperty.call(diffNode, "childNodes")) {
452
+ elementNode.childNodes = diffNode.childNodes.map(function (diffChildNode) {
453
+ return cleanNode(diffChildNode);
454
+ });
455
+ }
456
+ return elementNode;
457
+ }
458
+ };
459
+ var isEqual = function (e1, e2) {
460
+ if (!["nodeName", "value", "checked", "selected", "data"].every(function (element) {
461
+ if (e1[element] !== e2[element]) {
462
+ return false;
463
+ }
464
+ return true;
465
+ })) {
466
+ return false;
467
+ }
468
+ if (Object.prototype.hasOwnProperty.call(e1, "data")) {
469
+ // Comment or Text
470
+ return true;
471
+ }
472
+ e1 = e1;
473
+ e2 = e2;
474
+ if (Boolean(e1.attributes) !== Boolean(e2.attributes)) {
475
+ return false;
476
+ }
477
+ if (Boolean(e1.childNodes) !== Boolean(e2.childNodes)) {
478
+ return false;
479
+ }
480
+ if (e1.attributes) {
481
+ var e1Attributes = Object.keys(e1.attributes);
482
+ var e2Attributes = Object.keys(e2.attributes);
483
+ if (e1Attributes.length !== e2Attributes.length) {
484
+ return false;
485
+ }
486
+ if (!e1Attributes.every(function (attribute) {
487
+ if (e1.attributes[attribute] !==
488
+ e2.attributes[attribute]) {
489
+ return false;
490
+ }
491
+ return true;
492
+ })) {
493
+ return false;
494
+ }
495
+ }
496
+ if (e1.childNodes) {
497
+ if (e1.childNodes.length !== e2.childNodes.length) {
498
+ return false;
499
+ }
500
+ if (!e1.childNodes.every(function (childNode, index) {
501
+ return isEqual(childNode, e2.childNodes[index]);
502
+ })) {
503
+ return false;
504
+ }
505
+ }
506
+ return true;
507
+ };
508
+ var roughlyEqual = function (e1, e2, uniqueDescriptors, sameSiblings, preventRecursion) {
509
+ if (preventRecursion === void 0) { preventRecursion = false; }
510
+ if (!e1 || !e2) {
511
+ return false;
512
+ }
513
+ if (e1.nodeName !== e2.nodeName) {
514
+ return false;
515
+ }
516
+ if (["#text", "#comment"].includes(e1.nodeName)) {
517
+ // Note that we initially don't care what the text content of a node is,
518
+ // the mere fact that it's the same tag and "has text" means it's roughly
519
+ // equal, and then we can find out the true text difference later.
520
+ return preventRecursion
521
+ ? true
522
+ : e1.data === e2.data;
523
+ }
524
+ e1 = e1;
525
+ e2 = e2;
526
+ if (e1.nodeName in uniqueDescriptors) {
527
+ return true;
528
+ }
529
+ if (e1.attributes && e2.attributes) {
530
+ if (e1.attributes.id) {
531
+ if (e1.attributes.id !== e2.attributes.id) {
532
+ return false;
533
+ }
534
+ else {
535
+ var idDescriptor = "".concat(e1.nodeName, "#").concat(e1.attributes.id);
536
+ if (idDescriptor in uniqueDescriptors) {
537
+ return true;
538
+ }
539
+ }
540
+ }
541
+ if (e1.attributes["class"] &&
542
+ e1.attributes["class"] === e2.attributes["class"]) {
543
+ var classDescriptor = "".concat(e1.nodeName, ".").concat(e1.attributes["class"].replace(/ /g, "."));
544
+ if (classDescriptor in uniqueDescriptors) {
545
+ return true;
546
+ }
547
+ }
548
+ }
549
+ if (sameSiblings) {
550
+ return true;
551
+ }
552
+ var nodeList1 = e1.childNodes ? e1.childNodes.slice().reverse() : [];
553
+ var nodeList2 = e2.childNodes ? e2.childNodes.slice().reverse() : [];
554
+ if (nodeList1.length !== nodeList2.length) {
555
+ return false;
556
+ }
557
+ if (preventRecursion) {
558
+ return nodeList1.every(function (element, index) {
559
+ return element.nodeName === nodeList2[index].nodeName;
560
+ });
561
+ }
562
+ else {
563
+ // note: we only allow one level of recursion at any depth. If 'preventRecursion'
564
+ // was not set, we must explicitly force it to true for child iterations.
565
+ var childUniqueDescriptors_1 = uniqueInBoth(nodeList1, nodeList2);
566
+ return nodeList1.every(function (element, index) {
567
+ return roughlyEqual(element, nodeList2[index], childUniqueDescriptors_1, true, true);
568
+ });
569
+ }
570
+ };
571
+ /**
572
+ * based on https://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Longest_common_substring#JavaScript
573
+ */
574
+ var findCommonSubsets = function (c1, c2, marked1, marked2) {
575
+ var lcsSize = 0;
576
+ var index = [];
577
+ var c1Length = c1.length;
578
+ var c2Length = c2.length;
579
+ var // set up the matching table
580
+ matches = __spreadArray([], new Array(c1Length + 1), true).map(function () { return []; });
581
+ var uniqueDescriptors = uniqueInBoth(c1, c2);
582
+ var // If all of the elements are the same tag, id and class, then we can
583
+ // consider them roughly the same even if they have a different number of
584
+ // children. This will reduce removing and re-adding similar elements.
585
+ subsetsSame = c1Length === c2Length;
586
+ if (subsetsSame) {
587
+ c1.some(function (element, i) {
588
+ var c1Desc = elementDescriptors(element);
589
+ var c2Desc = elementDescriptors(c2[i]);
590
+ if (c1Desc.length !== c2Desc.length) {
591
+ subsetsSame = false;
592
+ return true;
593
+ }
594
+ c1Desc.some(function (description, i) {
595
+ if (description !== c2Desc[i]) {
596
+ subsetsSame = false;
597
+ return true;
598
+ }
599
+ });
600
+ if (!subsetsSame) {
601
+ return true;
602
+ }
603
+ });
604
+ }
605
+ // fill the matches with distance values
606
+ for (var c1Index = 0; c1Index < c1Length; c1Index++) {
607
+ var c1Element = c1[c1Index];
608
+ for (var c2Index = 0; c2Index < c2Length; c2Index++) {
609
+ var c2Element = c2[c2Index];
610
+ if (!marked1[c1Index] &&
611
+ !marked2[c2Index] &&
612
+ roughlyEqual(c1Element, c2Element, uniqueDescriptors, subsetsSame)) {
613
+ matches[c1Index + 1][c2Index + 1] = matches[c1Index][c2Index]
614
+ ? matches[c1Index][c2Index] + 1
615
+ : 1;
616
+ if (matches[c1Index + 1][c2Index + 1] >= lcsSize) {
617
+ lcsSize = matches[c1Index + 1][c2Index + 1];
618
+ index = [c1Index + 1, c2Index + 1];
619
+ }
620
+ }
621
+ else {
622
+ matches[c1Index + 1][c2Index + 1] = 0;
623
+ }
624
+ }
625
+ }
626
+ if (lcsSize === 0) {
627
+ return false;
628
+ }
629
+ return {
630
+ oldValue: index[0] - lcsSize,
631
+ newValue: index[1] - lcsSize,
632
+ length: lcsSize
633
+ };
634
+ };
635
+ var makeBooleanArray = function (n, v) {
636
+ return __spreadArray([], new Array(n), true).map(function () { return v; });
637
+ };
638
+ /**
639
+ * Generate arrays that indicate which node belongs to which subset,
640
+ * or whether it's actually an orphan node, existing in only one
641
+ * of the two trees, rather than somewhere in both.
642
+ *
643
+ * So if t1 = <img><canvas><br>, t2 = <canvas><br><img>.
644
+ * The longest subset is "<canvas><br>" (length 2), so it will group 0.
645
+ * The second longest is "<img>" (length 1), so it will be group 1.
646
+ * gaps1 will therefore be [1,0,0] and gaps2 [0,0,1].
647
+ *
648
+ * If an element is not part of any group, it will stay being 'true', which
649
+ * is the initial value. For example:
650
+ * t1 = <img><p></p><br><canvas>, t2 = <b></b><br><canvas><img>
651
+ *
652
+ * The "<p></p>" and "<b></b>" do only show up in one of the two and will
653
+ * therefore be marked by "true". The remaining parts are parts of the
654
+ * groups 0 and 1:
655
+ * gaps1 = [1, true, 0, 0], gaps2 = [true, 0, 0, 1]
656
+ *
657
+ */
658
+ var getGapInformation = function (t1, t2, stable) {
659
+ var gaps1 = t1.childNodes
660
+ ? makeBooleanArray(t1.childNodes.length, true)
661
+ : [];
662
+ var gaps2 = t2.childNodes
663
+ ? makeBooleanArray(t2.childNodes.length, true)
664
+ : [];
665
+ var group = 0;
666
+ // give elements from the same subset the same group number
667
+ stable.forEach(function (subset) {
668
+ var endOld = subset.oldValue + subset.length;
669
+ var endNew = subset.newValue + subset.length;
670
+ for (var j = subset.oldValue; j < endOld; j += 1) {
671
+ gaps1[j] = group;
672
+ }
673
+ for (var j = subset.newValue; j < endNew; j += 1) {
674
+ gaps2[j] = group;
675
+ }
676
+ group += 1;
677
+ });
678
+ return {
679
+ gaps1: gaps1,
680
+ gaps2: gaps2
681
+ };
682
+ };
683
+ /**
684
+ * Find all matching subsets, based on immediate child differences only.
685
+ */
686
+ var markBoth = function (marked1, marked2, subset, i) {
687
+ marked1[subset.oldValue + i] = true;
688
+ marked2[subset.newValue + i] = true;
689
+ };
690
+ var markSubTrees = function (oldTree, newTree) {
691
+ // note: the child lists are views, and so update as we update old/newTree
692
+ var oldChildren = oldTree.childNodes ? oldTree.childNodes : [];
693
+ var newChildren = newTree.childNodes ? newTree.childNodes : [];
694
+ var marked1 = makeBooleanArray(oldChildren.length, false);
695
+ var marked2 = makeBooleanArray(newChildren.length, false);
696
+ var subsets = [];
697
+ var returnIndex = function () {
698
+ return arguments[1];
699
+ };
700
+ var foundAllSubsets = false;
701
+ var _loop_1 = function () {
702
+ var subset = findCommonSubsets(oldChildren, newChildren, marked1, marked2);
703
+ if (subset) {
704
+ subsets.push(subset);
705
+ var subsetArray = __spreadArray([], new Array(subset.length), true).map(returnIndex);
706
+ subsetArray.forEach(function (item) {
707
+ return markBoth(marked1, marked2, subset, item);
708
+ });
709
+ }
710
+ else {
711
+ foundAllSubsets = true;
712
+ }
713
+ };
714
+ while (!foundAllSubsets) {
715
+ _loop_1();
716
+ }
717
+ oldTree.subsets = subsets;
718
+ oldTree.subsetsAge = 100;
719
+ return subsets;
720
+ };
721
+ var DiffTracker = /** @class */ (function () {
722
+ function DiffTracker() {
723
+ this.list = [];
724
+ }
725
+ DiffTracker.prototype.add = function (diffs) {
726
+ var _a;
727
+ (_a = this.list).push.apply(_a, diffs);
728
+ };
729
+ DiffTracker.prototype.forEach = function (fn) {
730
+ this.list.forEach(function (li) { return fn(li); });
731
+ };
732
+ return DiffTracker;
733
+ }());
734
+
735
+ // ===== Apply a virtual diff =====
736
+ function getFromVirtualRoute(tree, route) {
737
+ var node = tree;
738
+ var parentNode;
739
+ var nodeIndex;
740
+ route = route.slice();
741
+ while (route.length > 0) {
742
+ nodeIndex = route.splice(0, 1)[0];
743
+ parentNode = node;
744
+ node = node.childNodes ? node.childNodes[nodeIndex] : undefined;
745
+ }
746
+ return {
747
+ node: node,
748
+ parentNode: parentNode,
749
+ nodeIndex: nodeIndex
750
+ };
751
+ }
752
+ function applyVirtualDiff(tree, diff, options) {
753
+ var _a;
754
+ var node, parentNode, nodeIndex;
755
+ if (![options._const.addElement, options._const.addTextElement].includes(diff[options._const.action])) {
756
+ // For adding nodes, we calculate the route later on. It's different because it includes the position of the newly added item.
757
+ var routeInfo = getFromVirtualRoute(tree, diff[options._const.route]);
758
+ node = routeInfo.node;
759
+ parentNode = routeInfo.parentNode;
760
+ nodeIndex = routeInfo.nodeIndex;
761
+ }
762
+ var newSubsets = [];
763
+ // pre-diff hook
764
+ var info = {
765
+ diff: diff,
766
+ node: node
767
+ };
768
+ if (options.preVirtualDiffApply(info)) {
769
+ return true;
770
+ }
771
+ var newNode;
772
+ var nodeArray;
773
+ var route;
774
+ switch (diff[options._const.action]) {
775
+ case options._const.addAttribute:
776
+ if (!node.attributes) {
777
+ node.attributes = {};
778
+ }
779
+ node.attributes[diff[options._const.name]] =
780
+ diff[options._const.value];
781
+ if (diff[options._const.name] === "checked") {
782
+ node.checked = true;
783
+ }
784
+ else if (diff[options._const.name] === "selected") {
785
+ node.selected = true;
786
+ }
787
+ else if (node.nodeName === "INPUT" &&
788
+ diff[options._const.name] === "value") {
789
+ node.value = diff[options._const.value];
790
+ }
791
+ break;
792
+ case options._const.modifyAttribute:
793
+ node.attributes[diff[options._const.name]] =
794
+ diff[options._const.newValue];
795
+ break;
796
+ case options._const.removeAttribute:
797
+ delete node.attributes[diff[options._const.name]];
798
+ if (Object.keys(node.attributes).length === 0) {
799
+ delete node.attributes;
800
+ }
801
+ if (diff[options._const.name] === "checked") {
802
+ node.checked = false;
803
+ }
804
+ else if (diff[options._const.name] === "selected") {
805
+ delete node.selected;
806
+ }
807
+ else if (node.nodeName === "INPUT" &&
808
+ diff[options._const.name] === "value") {
809
+ delete node.value;
810
+ }
811
+ break;
812
+ case options._const.modifyTextElement:
813
+ node.data = diff[options._const.newValue];
814
+ if (parentNode.nodeName === "TEXTAREA") {
815
+ parentNode.value = diff[options._const.newValue];
816
+ }
817
+ break;
818
+ case options._const.modifyValue:
819
+ node.value = diff[options._const.newValue];
820
+ break;
821
+ case options._const.modifyComment:
822
+ node.data = diff[options._const.newValue];
823
+ break;
824
+ case options._const.modifyChecked:
825
+ node.checked = diff[options._const.newValue];
826
+ break;
827
+ case options._const.modifySelected:
828
+ node.selected = diff[options._const.newValue];
829
+ break;
830
+ case options._const.replaceElement:
831
+ newNode = cleanNode(diff[options._const.newValue]);
832
+ parentNode.childNodes[nodeIndex] = newNode;
833
+ break;
834
+ case options._const.relocateGroup:
835
+ nodeArray = node.childNodes
836
+ .splice(diff[options._const.from], diff[options._const.groupLength])
837
+ .reverse();
838
+ nodeArray.forEach(function (movedNode) {
839
+ return node.childNodes.splice(diff[options._const.to], 0, movedNode);
840
+ });
841
+ if (node.subsets) {
842
+ node.subsets.forEach(function (map) {
843
+ if (diff[options._const.from] < diff[options._const.to] &&
844
+ map.oldValue <= diff[options._const.to] &&
845
+ map.oldValue > diff[options._const.from]) {
846
+ map.oldValue -= diff[options._const.groupLength];
847
+ var splitLength = map.oldValue + map.length - diff[options._const.to];
848
+ if (splitLength > 0) {
849
+ // new insertion splits map.
850
+ newSubsets.push({
851
+ oldValue: diff[options._const.to] +
852
+ diff[options._const.groupLength],
853
+ newValue: map.newValue + map.length - splitLength,
854
+ length: splitLength
855
+ });
856
+ map.length -= splitLength;
857
+ }
858
+ }
859
+ else if (diff[options._const.from] > diff[options._const.to] &&
860
+ map.oldValue > diff[options._const.to] &&
861
+ map.oldValue < diff[options._const.from]) {
862
+ map.oldValue += diff[options._const.groupLength];
863
+ var splitLength = map.oldValue + map.length - diff[options._const.to];
864
+ if (splitLength > 0) {
865
+ // new insertion splits map.
866
+ newSubsets.push({
867
+ oldValue: diff[options._const.to] +
868
+ diff[options._const.groupLength],
869
+ newValue: map.newValue + map.length - splitLength,
870
+ length: splitLength
871
+ });
872
+ map.length -= splitLength;
873
+ }
874
+ }
875
+ else if (map.oldValue === diff[options._const.from]) {
876
+ map.oldValue = diff[options._const.to];
877
+ }
878
+ });
879
+ }
880
+ break;
881
+ case options._const.removeElement:
882
+ parentNode.childNodes.splice(nodeIndex, 1);
883
+ if (parentNode.subsets) {
884
+ parentNode.subsets.forEach(function (map) {
885
+ if (map.oldValue > nodeIndex) {
886
+ map.oldValue -= 1;
887
+ }
888
+ else if (map.oldValue === nodeIndex) {
889
+ map["delete"] = true;
890
+ }
891
+ else if (map.oldValue < nodeIndex &&
892
+ map.oldValue + map.length > nodeIndex) {
893
+ if (map.oldValue + map.length - 1 === nodeIndex) {
894
+ map.length--;
895
+ }
896
+ else {
897
+ newSubsets.push({
898
+ newValue: map.newValue + nodeIndex - map.oldValue,
899
+ oldValue: nodeIndex,
900
+ length: map.length - nodeIndex + map.oldValue - 1
901
+ });
902
+ map.length = nodeIndex - map.oldValue;
903
+ }
904
+ }
905
+ });
906
+ }
907
+ node = parentNode;
908
+ break;
909
+ case options._const.addElement: {
910
+ route = diff[options._const.route].slice();
911
+ var c_1 = route.splice(route.length - 1, 1)[0];
912
+ node = (_a = getFromVirtualRoute(tree, route)) === null || _a === void 0 ? void 0 : _a.node;
913
+ newNode = cleanNode(diff[options._const.element]);
914
+ if (!node.childNodes) {
915
+ node.childNodes = [];
916
+ }
917
+ if (c_1 >= node.childNodes.length) {
918
+ node.childNodes.push(newNode);
919
+ }
920
+ else {
921
+ node.childNodes.splice(c_1, 0, newNode);
922
+ }
923
+ if (node.subsets) {
924
+ node.subsets.forEach(function (map) {
925
+ if (map.oldValue >= c_1) {
926
+ map.oldValue += 1;
927
+ }
928
+ else if (map.oldValue < c_1 &&
929
+ map.oldValue + map.length > c_1) {
930
+ var splitLength = map.oldValue + map.length - c_1;
931
+ newSubsets.push({
932
+ newValue: map.newValue + map.length - splitLength,
933
+ oldValue: c_1 + 1,
934
+ length: splitLength
935
+ });
936
+ map.length -= splitLength;
937
+ }
938
+ });
939
+ }
940
+ break;
941
+ }
942
+ case options._const.removeTextElement:
943
+ parentNode.childNodes.splice(nodeIndex, 1);
944
+ if (parentNode.nodeName === "TEXTAREA") {
945
+ delete parentNode.value;
946
+ }
947
+ if (parentNode.subsets) {
948
+ parentNode.subsets.forEach(function (map) {
949
+ if (map.oldValue > nodeIndex) {
950
+ map.oldValue -= 1;
951
+ }
952
+ else if (map.oldValue === nodeIndex) {
953
+ map["delete"] = true;
954
+ }
955
+ else if (map.oldValue < nodeIndex &&
956
+ map.oldValue + map.length > nodeIndex) {
957
+ if (map.oldValue + map.length - 1 === nodeIndex) {
958
+ map.length--;
959
+ }
960
+ else {
961
+ newSubsets.push({
962
+ newValue: map.newValue + nodeIndex - map.oldValue,
963
+ oldValue: nodeIndex,
964
+ length: map.length - nodeIndex + map.oldValue - 1
965
+ });
966
+ map.length = nodeIndex - map.oldValue;
967
+ }
968
+ }
969
+ });
970
+ }
971
+ node = parentNode;
972
+ break;
973
+ case options._const.addTextElement: {
974
+ route = diff[options._const.route].slice();
975
+ var c_2 = route.splice(route.length - 1, 1)[0];
976
+ newNode = {
977
+ nodeName: "#text",
978
+ data: diff[options._const.value]
979
+ };
980
+ node = getFromVirtualRoute(tree, route).node;
981
+ if (!node.childNodes) {
982
+ node.childNodes = [];
983
+ }
984
+ if (c_2 >= node.childNodes.length) {
985
+ node.childNodes.push(newNode);
986
+ }
987
+ else {
988
+ node.childNodes.splice(c_2, 0, newNode);
989
+ }
990
+ if (node.nodeName === "TEXTAREA") {
991
+ node.value = diff[options._const.newValue];
992
+ }
993
+ if (node.subsets) {
994
+ node.subsets.forEach(function (map) {
995
+ if (map.oldValue >= c_2) {
996
+ map.oldValue += 1;
997
+ }
998
+ if (map.oldValue < c_2 && map.oldValue + map.length > c_2) {
999
+ var splitLength = map.oldValue + map.length - c_2;
1000
+ newSubsets.push({
1001
+ newValue: map.newValue + map.length - splitLength,
1002
+ oldValue: c_2 + 1,
1003
+ length: splitLength
1004
+ });
1005
+ map.length -= splitLength;
1006
+ }
1007
+ });
1008
+ }
1009
+ break;
1010
+ }
1011
+ default:
1012
+ console.log("unknown action");
1013
+ }
1014
+ if (node.subsets) {
1015
+ node.subsets = node.subsets.filter(function (map) { return !map["delete"] && map.oldValue !== map.newValue; });
1016
+ if (newSubsets.length) {
1017
+ node.subsets = node.subsets.concat(newSubsets);
1018
+ }
1019
+ }
1020
+ options.postVirtualDiffApply({
1021
+ node: info.node,
1022
+ diff: info.diff,
1023
+ newNode: newNode
1024
+ });
1025
+ return;
1026
+ }
1027
+ function applyVirtual(tree, diffs, options) {
1028
+ diffs.forEach(function (diff) {
1029
+ applyVirtualDiff(tree, diff, options);
1030
+ });
1031
+ return true;
1032
+ }
1033
+
1034
+ function nodeToObj(aNode, options) {
1035
+ if (options === void 0) { options = { valueDiffing: true }; }
1036
+ var objNode = {
1037
+ nodeName: aNode.nodeName
1038
+ };
1039
+ if (checkElementType(aNode, "Text", "Comment")) {
1040
+ objNode.data = aNode.data;
1041
+ }
1042
+ else {
1043
+ if (aNode.attributes && aNode.attributes.length > 0) {
1044
+ objNode.attributes = {};
1045
+ var nodeArray = Array.prototype.slice.call(aNode.attributes);
1046
+ nodeArray.forEach(function (attribute) {
1047
+ return (objNode.attributes[attribute.name] = attribute.value);
1048
+ });
1049
+ }
1050
+ if (aNode.childNodes && aNode.childNodes.length > 0) {
1051
+ objNode.childNodes = [];
1052
+ var nodeArray = Array.prototype.slice.call(aNode.childNodes);
1053
+ nodeArray.forEach(function (childNode) {
1054
+ return objNode.childNodes.push(nodeToObj(childNode, options));
1055
+ });
1056
+ }
1057
+ if (options.valueDiffing) {
1058
+ if (checkElementType(aNode, "HTMLTextAreaElement")) {
1059
+ objNode.value = aNode.value;
1060
+ }
1061
+ if (checkElementType(aNode, "HTMLInputElement") &&
1062
+ ["radio", "checkbox"].includes(aNode.type.toLowerCase()) &&
1063
+ aNode.checked !== undefined) {
1064
+ objNode.checked = aNode.checked;
1065
+ }
1066
+ else if (checkElementType(aNode, "HTMLButtonElement", "HTMLDataElement", "HTMLInputElement", "HTMLLIElement", "HTMLMeterElement", "HTMLOptionElement", "HTMLProgressElement", "HTMLParamElement")) {
1067
+ objNode.value = aNode.value;
1068
+ }
1069
+ if (checkElementType(aNode, "HTMLOptionElement")) {
1070
+ objNode.selected = aNode.selected;
1071
+ }
1072
+ }
1073
+ }
1074
+ return objNode;
1075
+ }
1076
+
1077
+ // from html-parse-stringify (MIT)
1078
+ var tagRE = /<\s*\/*[a-zA-Z:_][a-zA-Z0-9:_\-.]*\s*(?:"[^"]*"['"]*|'[^']*'['"]*|[^'"/>])*\/*\s*>|<!--(?:.|\n|\r)*?-->/g;
1079
+ var attrRE = /\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;
1080
+ function unescape(string) {
1081
+ return string
1082
+ .replace(/&lt;/g, "<")
1083
+ .replace(/&gt;/g, ">")
1084
+ .replace(/&amp;/g, "&");
1085
+ }
1086
+ // create optimized lookup object for
1087
+ // void elements as listed here:
1088
+ // https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
1089
+ var lookup = {
1090
+ area: true,
1091
+ base: true,
1092
+ br: true,
1093
+ col: true,
1094
+ embed: true,
1095
+ hr: true,
1096
+ img: true,
1097
+ input: true,
1098
+ keygen: true,
1099
+ link: true,
1100
+ menuItem: true,
1101
+ meta: true,
1102
+ param: true,
1103
+ source: true,
1104
+ track: true,
1105
+ wbr: true
1106
+ };
1107
+ var parseTag = function (tag, caseSensitive) {
1108
+ var res = {
1109
+ nodeName: "",
1110
+ attributes: {}
1111
+ };
1112
+ var voidElement = false;
1113
+ var type = "tag";
1114
+ var tagMatch = tag.match(/<\/?([^\s]+?)[/\s>]/);
1115
+ if (tagMatch) {
1116
+ res.nodeName =
1117
+ caseSensitive || tagMatch[1] === "svg"
1118
+ ? tagMatch[1]
1119
+ : tagMatch[1].toUpperCase();
1120
+ if (lookup[tagMatch[1]] || tag.charAt(tag.length - 2) === "/") {
1121
+ voidElement = true;
1122
+ }
1123
+ // handle comment tag
1124
+ if (res.nodeName.startsWith("!--")) {
1125
+ var endIndex = tag.indexOf("-->");
1126
+ return {
1127
+ type: "comment",
1128
+ node: {
1129
+ nodeName: "#comment",
1130
+ data: endIndex !== -1 ? tag.slice(4, endIndex) : ""
1131
+ },
1132
+ voidElement: voidElement
1133
+ };
1134
+ }
1135
+ }
1136
+ var reg = new RegExp(attrRE);
1137
+ var result = null;
1138
+ var done = false;
1139
+ while (!done) {
1140
+ result = reg.exec(tag);
1141
+ if (result === null) {
1142
+ done = true;
1143
+ }
1144
+ else if (result[0].trim()) {
1145
+ if (result[1]) {
1146
+ var attr = result[1].trim();
1147
+ var arr = [attr, ""];
1148
+ if (attr.indexOf("=") > -1)
1149
+ { arr = attr.split("="); }
1150
+ res.attributes[arr[0]] = arr[1];
1151
+ reg.lastIndex--;
1152
+ }
1153
+ else if (result[2])
1154
+ { res.attributes[result[2]] = result[3]
1155
+ .trim()
1156
+ .substring(1, result[3].length - 1); }
1157
+ }
1158
+ }
1159
+ return {
1160
+ type: type,
1161
+ node: res,
1162
+ voidElement: voidElement
1163
+ };
1164
+ };
1165
+ var stringToObj = function (html, options) {
1166
+ if (options === void 0) { options = {
1167
+ valueDiffing: true,
1168
+ caseSensitive: false
1169
+ }; }
1170
+ var result = [];
1171
+ var current;
1172
+ var level = -1;
1173
+ var arr = [];
1174
+ var inComponent = false, insideSvg = false;
1175
+ // handle text at top level
1176
+ if (html.indexOf("<") !== 0) {
1177
+ var end = html.indexOf("<");
1178
+ result.push({
1179
+ nodeName: "#text",
1180
+ data: end === -1 ? html : html.substring(0, end)
1181
+ });
1182
+ }
1183
+ html.replace(tagRE, function (tag, index) {
1184
+ var isOpen = tag.charAt(1) !== "/";
1185
+ var isComment = tag.startsWith("<!--");
1186
+ var start = index + tag.length;
1187
+ var nextChar = html.charAt(start);
1188
+ if (isComment) {
1189
+ var comment = parseTag(tag, options.caseSensitive).node;
1190
+ // if we're at root, push new base node
1191
+ if (level < 0) {
1192
+ result.push(comment);
1193
+ return "";
1194
+ }
1195
+ var parent_1 = arr[level];
1196
+ if (parent_1 && comment.nodeName) {
1197
+ if (!parent_1.node.childNodes) {
1198
+ parent_1.node.childNodes = [];
1199
+ }
1200
+ parent_1.node.childNodes.push(comment);
1201
+ }
1202
+ return "";
1203
+ }
1204
+ if (isOpen) {
1205
+ current = parseTag(tag, options.caseSensitive || insideSvg);
1206
+ if (current.node.nodeName === "svg") {
1207
+ insideSvg = true;
1208
+ }
1209
+ level++;
1210
+ if (!current.voidElement &&
1211
+ !inComponent &&
1212
+ nextChar &&
1213
+ nextChar !== "<") {
1214
+ if (!current.node.childNodes) {
1215
+ current.node.childNodes = [];
1216
+ }
1217
+ var data = unescape(html.slice(start, html.indexOf("<", start)));
1218
+ current.node.childNodes.push({
1219
+ nodeName: "#text",
1220
+ data: data
1221
+ });
1222
+ if (options.valueDiffing &&
1223
+ current.node.nodeName === "TEXTAREA") {
1224
+ current.node.value = data;
1225
+ }
1226
+ }
1227
+ // if we're at root, push new base node
1228
+ if (level === 0 && current.node.nodeName) {
1229
+ result.push(current.node);
1230
+ }
1231
+ var parent_2 = arr[level - 1];
1232
+ if (parent_2 && current.node.nodeName) {
1233
+ if (!parent_2.node.childNodes) {
1234
+ parent_2.node.childNodes = [];
1235
+ }
1236
+ parent_2.node.childNodes.push(current.node);
1237
+ }
1238
+ arr[level] = current;
1239
+ }
1240
+ if (!isOpen || current.voidElement) {
1241
+ if (level > -1 &&
1242
+ (current.voidElement ||
1243
+ (options.caseSensitive &&
1244
+ current.node.nodeName === tag.slice(2, -1)) ||
1245
+ (!options.caseSensitive &&
1246
+ current.node.nodeName.toUpperCase() ===
1247
+ tag.slice(2, -1).toUpperCase()))) {
1248
+ level--;
1249
+ // move current up a level to match the end tag
1250
+ if (level > -1) {
1251
+ if (current.node.nodeName === "svg") {
1252
+ insideSvg = false;
1253
+ }
1254
+ current = arr[level];
1255
+ }
1256
+ }
1257
+ if (nextChar !== "<" && nextChar) {
1258
+ // trailing text node
1259
+ // if we're at the root, push a base text node. otherwise add as
1260
+ // a child to the current node.
1261
+ var childNodes = level === -1 ? result : arr[level].node.childNodes || [];
1262
+ // calculate correct end of the data slice in case there's
1263
+ // no tag after the text node.
1264
+ var end = html.indexOf("<", start);
1265
+ var data = unescape(html.slice(start, end === -1 ? undefined : end));
1266
+ childNodes.push({
1267
+ nodeName: "#text",
1268
+ data: data
1269
+ });
1270
+ }
1271
+ }
1272
+ return "";
1273
+ });
1274
+ return result[0];
1275
+ };
1276
+
1277
+ // ===== Create a diff =====
1278
+ var DiffFinder = /** @class */ (function () {
1279
+ function DiffFinder(t1Node, t2Node, options) {
1280
+ this.options = options;
1281
+ this.t1 = (typeof Element !== "undefined" &&
1282
+ checkElementType(t1Node, "Element")
1283
+ ? nodeToObj(t1Node, this.options)
1284
+ : typeof t1Node === "string"
1285
+ ? stringToObj(t1Node, this.options)
1286
+ : JSON.parse(JSON.stringify(t1Node)));
1287
+ this.t2 = (typeof Element !== "undefined" &&
1288
+ checkElementType(t2Node, "Element")
1289
+ ? nodeToObj(t2Node, this.options)
1290
+ : typeof t2Node === "string"
1291
+ ? stringToObj(t2Node, this.options)
1292
+ : JSON.parse(JSON.stringify(t2Node)));
1293
+ this.diffcount = 0;
1294
+ this.foundAll = false;
1295
+ if (this.debug) {
1296
+ this.t1Orig =
1297
+ typeof Element !== "undefined" &&
1298
+ checkElementType(t1Node, "Element")
1299
+ ? nodeToObj(t1Node, this.options)
1300
+ : typeof t1Node === "string"
1301
+ ? stringToObj(t1Node, this.options)
1302
+ : JSON.parse(JSON.stringify(t1Node));
1303
+ this.t2Orig =
1304
+ typeof Element !== "undefined" &&
1305
+ checkElementType(t2Node, "Element")
1306
+ ? nodeToObj(t2Node, this.options)
1307
+ : typeof t2Node === "string"
1308
+ ? stringToObj(t2Node, this.options)
1309
+ : JSON.parse(JSON.stringify(t2Node));
1310
+ }
1311
+ this.tracker = new DiffTracker();
1312
+ }
1313
+ DiffFinder.prototype.init = function () {
1314
+ return this.findDiffs(this.t1, this.t2);
1315
+ };
1316
+ DiffFinder.prototype.findDiffs = function (t1, t2) {
1317
+ var diffs;
1318
+ do {
1319
+ if (this.options.debug) {
1320
+ this.diffcount += 1;
1321
+ if (this.diffcount > this.options.diffcap) {
1322
+ throw new Error("surpassed diffcap:".concat(JSON.stringify(this.t1Orig), " -> ").concat(JSON.stringify(this.t2Orig)));
1323
+ }
1324
+ }
1325
+ diffs = this.findNextDiff(t1, t2, []);
1326
+ if (diffs.length === 0) {
1327
+ // Last check if the elements really are the same now.
1328
+ // If not, remove all info about being done and start over.
1329
+ // Sometimes a node can be marked as done, but the creation of subsequent diffs means that it has to be changed again.
1330
+ if (!isEqual(t1, t2)) {
1331
+ if (this.foundAll) {
1332
+ console.error("Could not find remaining diffs!");
1333
+ }
1334
+ else {
1335
+ this.foundAll = true;
1336
+ removeDone(t1);
1337
+ diffs = this.findNextDiff(t1, t2, []);
1338
+ }
1339
+ }
1340
+ }
1341
+ if (diffs.length > 0) {
1342
+ this.foundAll = false;
1343
+ this.tracker.add(diffs);
1344
+ applyVirtual(t1, diffs, this.options);
1345
+ }
1346
+ } while (diffs.length > 0);
1347
+ return this.tracker.list;
1348
+ };
1349
+ DiffFinder.prototype.findNextDiff = function (t1, t2, route) {
1350
+ var diffs;
1351
+ var fdiffs;
1352
+ if (this.options.maxDepth && route.length > this.options.maxDepth) {
1353
+ return [];
1354
+ }
1355
+ // outer differences?
1356
+ if (!t1.outerDone) {
1357
+ diffs = this.findOuterDiff(t1, t2, route);
1358
+ if (this.options.filterOuterDiff) {
1359
+ fdiffs = this.options.filterOuterDiff(t1, t2, diffs);
1360
+ if (fdiffs)
1361
+ { diffs = fdiffs; }
1362
+ }
1363
+ if (diffs.length > 0) {
1364
+ t1.outerDone = true;
1365
+ return diffs;
1366
+ }
1367
+ else {
1368
+ t1.outerDone = true;
1369
+ }
1370
+ }
1371
+ if (Object.prototype.hasOwnProperty.call(t1, "data")) {
1372
+ // Comment or Text
1373
+ return [];
1374
+ }
1375
+ t1 = t1;
1376
+ t2 = t2;
1377
+ // inner differences?
1378
+ if (!t1.innerDone) {
1379
+ diffs = this.findInnerDiff(t1, t2, route);
1380
+ if (diffs.length > 0) {
1381
+ return diffs;
1382
+ }
1383
+ else {
1384
+ t1.innerDone = true;
1385
+ }
1386
+ }
1387
+ if (this.options.valueDiffing && !t1.valueDone) {
1388
+ // value differences?
1389
+ diffs = this.findValueDiff(t1, t2, route);
1390
+ if (diffs.length > 0) {
1391
+ t1.valueDone = true;
1392
+ return diffs;
1393
+ }
1394
+ else {
1395
+ t1.valueDone = true;
1396
+ }
1397
+ }
1398
+ // no differences
1399
+ return [];
1400
+ };
1401
+ DiffFinder.prototype.findOuterDiff = function (t1, t2, route) {
1402
+ var diffs = [];
1403
+ var attr;
1404
+ var attr1;
1405
+ var attr2;
1406
+ var attrLength;
1407
+ var pos;
1408
+ var i;
1409
+ if (t1.nodeName !== t2.nodeName) {
1410
+ if (!route.length) {
1411
+ throw new Error("Top level nodes have to be of the same kind.");
1412
+ }
1413
+ return [
1414
+ new Diff()
1415
+ .setValue(this.options._const.action, this.options._const.replaceElement)
1416
+ .setValue(this.options._const.oldValue, cleanNode(t1))
1417
+ .setValue(this.options._const.newValue, cleanNode(t2))
1418
+ .setValue(this.options._const.route, route) ];
1419
+ }
1420
+ if (route.length &&
1421
+ this.options.diffcap <
1422
+ Math.abs((t1.childNodes || []).length - (t2.childNodes || []).length)) {
1423
+ return [
1424
+ new Diff()
1425
+ .setValue(this.options._const.action, this.options._const.replaceElement)
1426
+ .setValue(this.options._const.oldValue, cleanNode(t1))
1427
+ .setValue(this.options._const.newValue, cleanNode(t2))
1428
+ .setValue(this.options._const.route, route) ];
1429
+ }
1430
+ if (Object.prototype.hasOwnProperty.call(t1, "data") &&
1431
+ t1.data !== t2.data) {
1432
+ // Comment or text node.
1433
+ if (t1.nodeName === "#text") {
1434
+ return [
1435
+ new Diff()
1436
+ .setValue(this.options._const.action, this.options._const.modifyTextElement)
1437
+ .setValue(this.options._const.route, route)
1438
+ .setValue(this.options._const.oldValue, t1.data)
1439
+ .setValue(this.options._const.newValue, t2.data) ];
1440
+ }
1441
+ else {
1442
+ return [
1443
+ new Diff()
1444
+ .setValue(this.options._const.action, this.options._const.modifyComment)
1445
+ .setValue(this.options._const.route, route)
1446
+ .setValue(this.options._const.oldValue, t1.data)
1447
+ .setValue(this.options._const.newValue, t2.data) ];
1448
+ }
1449
+ }
1450
+ t1 = t1;
1451
+ t2 = t2;
1452
+ attr1 = t1.attributes ? Object.keys(t1.attributes).sort() : [];
1453
+ attr2 = t2.attributes ? Object.keys(t2.attributes).sort() : [];
1454
+ attrLength = attr1.length;
1455
+ for (i = 0; i < attrLength; i++) {
1456
+ attr = attr1[i];
1457
+ pos = attr2.indexOf(attr);
1458
+ if (pos === -1) {
1459
+ diffs.push(new Diff()
1460
+ .setValue(this.options._const.action, this.options._const.removeAttribute)
1461
+ .setValue(this.options._const.route, route)
1462
+ .setValue(this.options._const.name, attr)
1463
+ .setValue(this.options._const.value, t1.attributes[attr]));
1464
+ }
1465
+ else {
1466
+ attr2.splice(pos, 1);
1467
+ if (t1.attributes[attr] !== t2.attributes[attr]) {
1468
+ diffs.push(new Diff()
1469
+ .setValue(this.options._const.action, this.options._const.modifyAttribute)
1470
+ .setValue(this.options._const.route, route)
1471
+ .setValue(this.options._const.name, attr)
1472
+ .setValue(this.options._const.oldValue, t1.attributes[attr])
1473
+ .setValue(this.options._const.newValue, t2.attributes[attr]));
1474
+ }
1475
+ }
1476
+ }
1477
+ attrLength = attr2.length;
1478
+ for (i = 0; i < attrLength; i++) {
1479
+ attr = attr2[i];
1480
+ diffs.push(new Diff()
1481
+ .setValue(this.options._const.action, this.options._const.addAttribute)
1482
+ .setValue(this.options._const.route, route)
1483
+ .setValue(this.options._const.name, attr)
1484
+ .setValue(this.options._const.value, t2.attributes[attr]));
1485
+ }
1486
+ return diffs;
1487
+ };
1488
+ DiffFinder.prototype.findInnerDiff = function (t1, t2, route) {
1489
+ var t1ChildNodes = t1.childNodes ? t1.childNodes.slice() : [];
1490
+ var t2ChildNodes = t2.childNodes ? t2.childNodes.slice() : [];
1491
+ var last = Math.max(t1ChildNodes.length, t2ChildNodes.length);
1492
+ var childNodesLengthDifference = Math.abs(t1ChildNodes.length - t2ChildNodes.length);
1493
+ var diffs = [];
1494
+ var index = 0;
1495
+ if (!this.options.maxChildCount || last < this.options.maxChildCount) {
1496
+ var cachedSubtrees = Boolean(t1.subsets && t1.subsetsAge--);
1497
+ var subtrees = cachedSubtrees
1498
+ ? t1.subsets
1499
+ : t1.childNodes && t2.childNodes
1500
+ ? markSubTrees(t1, t2)
1501
+ : [];
1502
+ if (subtrees.length > 0) {
1503
+ /* One or more groups have been identified among the childnodes of t1
1504
+ * and t2.
1505
+ */
1506
+ diffs = this.attemptGroupRelocation(t1, t2, subtrees, route, cachedSubtrees);
1507
+ if (diffs.length > 0) {
1508
+ return diffs;
1509
+ }
1510
+ }
1511
+ }
1512
+ /* 0 or 1 groups of similar child nodes have been found
1513
+ * for t1 and t2. 1 If there is 1, it could be a sign that the
1514
+ * contents are the same. When the number of groups is below 2,
1515
+ * t1 and t2 are made to have the same length and each of the
1516
+ * pairs of child nodes are diffed.
1517
+ */
1518
+ for (var i = 0; i < last; i += 1) {
1519
+ var e1 = t1ChildNodes[i];
1520
+ var e2 = t2ChildNodes[i];
1521
+ if (childNodesLengthDifference) {
1522
+ /* t1 and t2 have different amounts of childNodes. Add
1523
+ * and remove as necessary to obtain the same length */
1524
+ if (e1 && !e2) {
1525
+ if (e1.nodeName === "#text") {
1526
+ diffs.push(new Diff()
1527
+ .setValue(this.options._const.action, this.options._const.removeTextElement)
1528
+ .setValue(this.options._const.route, route.concat(index))
1529
+ .setValue(this.options._const.value, e1.data));
1530
+ index -= 1;
1531
+ }
1532
+ else {
1533
+ diffs.push(new Diff()
1534
+ .setValue(this.options._const.action, this.options._const.removeElement)
1535
+ .setValue(this.options._const.route, route.concat(index))
1536
+ .setValue(this.options._const.element, cleanNode(e1)));
1537
+ index -= 1;
1538
+ }
1539
+ }
1540
+ else if (e2 && !e1) {
1541
+ if (e2.nodeName === "#text") {
1542
+ diffs.push(new Diff()
1543
+ .setValue(this.options._const.action, this.options._const.addTextElement)
1544
+ .setValue(this.options._const.route, route.concat(index))
1545
+ .setValue(this.options._const.value, e2.data));
1546
+ }
1547
+ else {
1548
+ diffs.push(new Diff()
1549
+ .setValue(this.options._const.action, this.options._const.addElement)
1550
+ .setValue(this.options._const.route, route.concat(index))
1551
+ .setValue(this.options._const.element, cleanNode(e2)));
1552
+ }
1553
+ }
1554
+ }
1555
+ /* We are now guaranteed that childNodes e1 and e2 exist,
1556
+ * and that they can be diffed.
1557
+ */
1558
+ /* Diffs in child nodes should not affect the parent node,
1559
+ * so we let these diffs be submitted together with other
1560
+ * diffs.
1561
+ */
1562
+ if (e1 && e2) {
1563
+ if (!this.options.maxChildCount ||
1564
+ last < this.options.maxChildCount) {
1565
+ diffs = diffs.concat(this.findNextDiff(e1, e2, route.concat(index)));
1566
+ }
1567
+ else if (!isEqual(e1, e2)) {
1568
+ if (t1ChildNodes.length > t2ChildNodes.length) {
1569
+ if (e1.nodeName === "#text") {
1570
+ diffs.push(new Diff()
1571
+ .setValue(this.options._const.action, this.options._const.removeTextElement)
1572
+ .setValue(this.options._const.route, route.concat(index))
1573
+ .setValue(this.options._const.value, e1.data));
1574
+ }
1575
+ else {
1576
+ diffs.push(new Diff()
1577
+ .setValue(this.options._const.action, this.options._const.removeElement)
1578
+ .setValue(this.options._const.element, cleanNode(e1))
1579
+ .setValue(this.options._const.route, route.concat(index)));
1580
+ }
1581
+ t1ChildNodes.splice(i, 1);
1582
+ i -= 1;
1583
+ index -= 1;
1584
+ childNodesLengthDifference -= 1;
1585
+ }
1586
+ else if (t1ChildNodes.length < t2ChildNodes.length) {
1587
+ diffs = diffs.concat([
1588
+ new Diff()
1589
+ .setValue(this.options._const.action, this.options._const.addElement)
1590
+ .setValue(this.options._const.element, cleanNode(e2))
1591
+ .setValue(this.options._const.route, route.concat(index)) ]);
1592
+ t1ChildNodes.splice(i, 0, cleanNode(e2));
1593
+ childNodesLengthDifference -= 1;
1594
+ }
1595
+ else {
1596
+ diffs = diffs.concat([
1597
+ new Diff()
1598
+ .setValue(this.options._const.action, this.options._const.replaceElement)
1599
+ .setValue(this.options._const.oldValue, cleanNode(e1))
1600
+ .setValue(this.options._const.newValue, cleanNode(e2))
1601
+ .setValue(this.options._const.route, route.concat(index)) ]);
1602
+ }
1603
+ }
1604
+ }
1605
+ index += 1;
1606
+ }
1607
+ t1.innerDone = true;
1608
+ return diffs;
1609
+ };
1610
+ DiffFinder.prototype.attemptGroupRelocation = function (t1, t2, subtrees, route, cachedSubtrees) {
1611
+ /* Either t1.childNodes and t2.childNodes have the same length, or
1612
+ * there are at least two groups of similar elements can be found.
1613
+ * attempts are made at equalizing t1 with t2. First all initial
1614
+ * elements with no group affiliation (gaps=true) are removed (if
1615
+ * only in t1) or added (if only in t2). Then the creation of a group
1616
+ * relocation diff is attempted.
1617
+ */
1618
+ var gapInformation = getGapInformation(t1, t2, subtrees);
1619
+ var gaps1 = gapInformation.gaps1;
1620
+ var gaps2 = gapInformation.gaps2;
1621
+ var t1ChildNodes = t1.childNodes.slice();
1622
+ var t2ChildNodes = t2.childNodes.slice();
1623
+ var shortest = Math.min(gaps1.length, gaps2.length);
1624
+ var destinationDifferent;
1625
+ var toGroup;
1626
+ var group;
1627
+ var node;
1628
+ var similarNode;
1629
+ var diffs = [];
1630
+ for (var index2 = 0, index1 = 0; index2 < shortest; index1 += 1, index2 += 1) {
1631
+ if (cachedSubtrees &&
1632
+ (gaps1[index2] === true || gaps2[index2] === true)) ;
1633
+ else if (gaps1[index1] === true) {
1634
+ node = t1ChildNodes[index1];
1635
+ if (node.nodeName === "#text") {
1636
+ if (t2ChildNodes[index2].nodeName === "#text") {
1637
+ if (node.data !==
1638
+ t2ChildNodes[index2].data) {
1639
+ // Check whether a text node with the same value follows later on.
1640
+ var testI = index1;
1641
+ while (t1ChildNodes.length > testI + 1 &&
1642
+ t1ChildNodes[testI + 1].nodeName === "#text") {
1643
+ testI += 1;
1644
+ if (t2ChildNodes[index2]
1645
+ .data ===
1646
+ t1ChildNodes[testI]
1647
+ .data) {
1648
+ similarNode = true;
1649
+ break;
1650
+ }
1651
+ }
1652
+ if (!similarNode) {
1653
+ diffs.push(new Diff()
1654
+ .setValue(this.options._const.action, this.options._const
1655
+ .modifyTextElement)
1656
+ .setValue(this.options._const.route, route.concat(index1))
1657
+ .setValue(this.options._const.oldValue, node.data)
1658
+ .setValue(this.options._const.newValue, t2ChildNodes[index2].data));
1659
+ }
1660
+ }
1661
+ }
1662
+ else {
1663
+ diffs.push(new Diff()
1664
+ .setValue(this.options._const.action, this.options._const.removeTextElement)
1665
+ .setValue(this.options._const.route, route.concat(index1))
1666
+ .setValue(this.options._const.value, node.data));
1667
+ gaps1.splice(index1, 1);
1668
+ t1ChildNodes.splice(index1, 1);
1669
+ shortest = Math.min(gaps1.length, gaps2.length);
1670
+ index1 -= 1;
1671
+ index2 -= 1;
1672
+ }
1673
+ }
1674
+ else if (gaps2[index2] === true) {
1675
+ // both gaps1[index1] and gaps2[index2] are true.
1676
+ // We replace one element with another.
1677
+ diffs.push(new Diff()
1678
+ .setValue(this.options._const.action, this.options._const.replaceElement)
1679
+ .setValue(this.options._const.oldValue, cleanNode(node))
1680
+ .setValue(this.options._const.newValue, cleanNode(t2ChildNodes[index2]))
1681
+ .setValue(this.options._const.route, route.concat(index1)));
1682
+ // t1ChildNodes at position index1 is not up-to-date, but that does not matter as
1683
+ // index1 will increase +1
1684
+ }
1685
+ else {
1686
+ diffs.push(new Diff()
1687
+ .setValue(this.options._const.action, this.options._const.removeElement)
1688
+ .setValue(this.options._const.route, route.concat(index1))
1689
+ .setValue(this.options._const.element, cleanNode(node)));
1690
+ gaps1.splice(index1, 1);
1691
+ t1ChildNodes.splice(index1, 1);
1692
+ shortest = Math.min(gaps1.length, gaps2.length);
1693
+ index1 -= 1;
1694
+ index2 -= 1;
1695
+ }
1696
+ }
1697
+ else if (gaps2[index2] === true) {
1698
+ node = t2ChildNodes[index2];
1699
+ if (node.nodeName === "#text") {
1700
+ diffs.push(new Diff()
1701
+ .setValue(this.options._const.action, this.options._const.addTextElement)
1702
+ .setValue(this.options._const.route, route.concat(index1))
1703
+ .setValue(this.options._const.value, node.data));
1704
+ gaps1.splice(index1, 0, true);
1705
+ t1ChildNodes.splice(index1, 0, {
1706
+ nodeName: "#text",
1707
+ data: node.data
1708
+ });
1709
+ shortest = Math.min(gaps1.length, gaps2.length);
1710
+ //index1 += 1
1711
+ }
1712
+ else {
1713
+ diffs.push(new Diff()
1714
+ .setValue(this.options._const.action, this.options._const.addElement)
1715
+ .setValue(this.options._const.route, route.concat(index1))
1716
+ .setValue(this.options._const.element, cleanNode(node)));
1717
+ gaps1.splice(index1, 0, true);
1718
+ t1ChildNodes.splice(index1, 0, cleanNode(node));
1719
+ shortest = Math.min(gaps1.length, gaps2.length);
1720
+ //index1 += 1
1721
+ }
1722
+ }
1723
+ else if (gaps1[index1] !== gaps2[index2]) {
1724
+ if (diffs.length > 0) {
1725
+ return diffs;
1726
+ }
1727
+ // group relocation
1728
+ group = subtrees[gaps1[index1]];
1729
+ toGroup = Math.min(group.newValue, t1ChildNodes.length - group.length);
1730
+ if (toGroup !== group.oldValue && toGroup > -1) {
1731
+ // Check whether destination nodes are different than originating ones.
1732
+ destinationDifferent = false;
1733
+ for (var j = 0; j < group.length; j += 1) {
1734
+ if (!roughlyEqual(t1ChildNodes[toGroup + j], t1ChildNodes[group.oldValue + j], {}, false, true)) {
1735
+ destinationDifferent = true;
1736
+ }
1737
+ }
1738
+ if (destinationDifferent) {
1739
+ return [
1740
+ new Diff()
1741
+ .setValue(this.options._const.action, this.options._const.relocateGroup)
1742
+ .setValue(this.options._const.groupLength, group.length)
1743
+ .setValue(this.options._const.from, group.oldValue)
1744
+ .setValue(this.options._const.to, toGroup)
1745
+ .setValue(this.options._const.route, route) ];
1746
+ }
1747
+ }
1748
+ }
1749
+ }
1750
+ return diffs;
1751
+ };
1752
+ DiffFinder.prototype.findValueDiff = function (t1, t2, route) {
1753
+ // Differences of value. Only useful if the value/selection/checked value
1754
+ // differs from what is represented in the DOM. For example in the case
1755
+ // of filled out forms, etc.
1756
+ var diffs = [];
1757
+ if (t1.selected !== t2.selected) {
1758
+ diffs.push(new Diff()
1759
+ .setValue(this.options._const.action, this.options._const.modifySelected)
1760
+ .setValue(this.options._const.oldValue, t1.selected)
1761
+ .setValue(this.options._const.newValue, t2.selected)
1762
+ .setValue(this.options._const.route, route));
1763
+ }
1764
+ if ((t1.value || t2.value) &&
1765
+ t1.value !== t2.value &&
1766
+ t1.nodeName !== "OPTION") {
1767
+ diffs.push(new Diff()
1768
+ .setValue(this.options._const.action, this.options._const.modifyValue)
1769
+ .setValue(this.options._const.oldValue, t1.value || "")
1770
+ .setValue(this.options._const.newValue, t2.value || "")
1771
+ .setValue(this.options._const.route, route));
1772
+ }
1773
+ if (t1.checked !== t2.checked) {
1774
+ diffs.push(new Diff()
1775
+ .setValue(this.options._const.action, this.options._const.modifyChecked)
1776
+ .setValue(this.options._const.oldValue, t1.checked)
1777
+ .setValue(this.options._const.newValue, t2.checked)
1778
+ .setValue(this.options._const.route, route));
1779
+ }
1780
+ return diffs;
1781
+ };
1782
+ return DiffFinder;
1783
+ }());
1784
+
1785
+ var DEFAULT_OPTIONS = {
1786
+ debug: false,
1787
+ diffcap: 10,
1788
+ maxDepth: false,
1789
+ maxChildCount: 50,
1790
+ valueDiffing: true,
1791
+ // syntax: textDiff: function (node, currentValue, expectedValue, newValue)
1792
+ textDiff: function (node, currentValue, expectedValue, newValue) {
1793
+ node.data = newValue;
1794
+ return;
1795
+ },
1796
+ // empty functions were benchmarked as running faster than both
1797
+ // `f && f()` and `if (f) { f(); }`
1798
+ preVirtualDiffApply: function () { },
1799
+ postVirtualDiffApply: function () { },
1800
+ preDiffApply: function () { },
1801
+ postDiffApply: function () { },
1802
+ filterOuterDiff: null,
1803
+ compress: false,
1804
+ _const: false,
1805
+ document: typeof window !== "undefined" && window.document
1806
+ ? window.document
1807
+ : false,
1808
+ components: []
1809
+ };
1810
+ var DiffDOM = /** @class */ (function () {
1811
+ function DiffDOM(options) {
1812
+ if (options === void 0) { options = {}; }
1813
+ // IE11 doesn't have Object.assign and buble doesn't translate object spreaders
1814
+ // by default, so this is the safest way of doing it currently.
1815
+ Object.entries(DEFAULT_OPTIONS).forEach(function (_a) {
1816
+ var key = _a[0], value = _a[1];
1817
+ if (!Object.prototype.hasOwnProperty.call(options, key)) {
1818
+ options[key] = value;
1819
+ }
1820
+ });
1821
+ if (!options._const) {
1822
+ var varNames = [
1823
+ "addAttribute",
1824
+ "modifyAttribute",
1825
+ "removeAttribute",
1826
+ "modifyTextElement",
1827
+ "relocateGroup",
1828
+ "removeElement",
1829
+ "addElement",
1830
+ "removeTextElement",
1831
+ "addTextElement",
1832
+ "replaceElement",
1833
+ "modifyValue",
1834
+ "modifyChecked",
1835
+ "modifySelected",
1836
+ "modifyComment",
1837
+ "action",
1838
+ "route",
1839
+ "oldValue",
1840
+ "newValue",
1841
+ "element",
1842
+ "group",
1843
+ "groupLength",
1844
+ "from",
1845
+ "to",
1846
+ "name",
1847
+ "value",
1848
+ "data",
1849
+ "attributes",
1850
+ "nodeName",
1851
+ "childNodes",
1852
+ "checked",
1853
+ "selected" ];
1854
+ var constNames_1 = {};
1855
+ if (options.compress) {
1856
+ varNames.forEach(function (varName, index) { return (constNames_1[varName] = index); });
1857
+ }
1858
+ else {
1859
+ varNames.forEach(function (varName) { return (constNames_1[varName] = varName); });
1860
+ }
1861
+ options._const = constNames_1;
1862
+ }
1863
+ this.options = options;
1864
+ }
1865
+ DiffDOM.prototype.apply = function (tree, diffs) {
1866
+ return applyDOM(tree, diffs, this.options);
1867
+ };
1868
+ DiffDOM.prototype.undo = function (tree, diffs) {
1869
+ return undoDOM(tree, diffs, this.options);
1870
+ };
1871
+ DiffDOM.prototype.diff = function (t1Node, t2Node) {
1872
+ var finder = new DiffFinder(t1Node, t2Node, this.options);
1873
+ return finder.init();
1874
+ };
1875
+ return DiffDOM;
1876
+ }());
1877
+
1878
+ /**
1879
+ * Use TraceLogger to figure out function calls inside
1880
+ * JS objects by wrapping an object with a TraceLogger
1881
+ * instance.
1882
+ *
1883
+ * Pretty-prints the call trace (using unicode box code)
1884
+ * when tracelogger.toString() is called.
1885
+ */
1886
+ /**
1887
+ * Wrap an object by calling new TraceLogger(obj)
1888
+ *
1889
+ * If you're familiar with Python decorators, this
1890
+ * does roughly the same thing, adding pre/post
1891
+ * call hook logging calls so that you can see
1892
+ * what's going on.
1893
+ */
1894
+ var TraceLogger = /** @class */ (function () {
1895
+ function TraceLogger(obj) {
1896
+ if (obj === void 0) { obj = {}; }
1897
+ var _this = this;
1898
+ this.pad = "│ ";
1899
+ this.padding = "";
1900
+ this.tick = 1;
1901
+ this.messages = [];
1902
+ var wrapkey = function (obj, key) {
1903
+ // trace this function
1904
+ var oldfn = obj[key];
1905
+ obj[key] = function () {
1906
+ var arguments$1 = arguments;
1907
+
1908
+ var args = [];
1909
+ for (var _i = 0; _i < arguments.length; _i++) {
1910
+ args[_i] = arguments$1[_i];
1911
+ }
1912
+ _this.fin(key, Array.prototype.slice.call(args));
1913
+ var result = oldfn.apply(obj, args);
1914
+ _this.fout(key, result);
1915
+ return result;
1916
+ };
1917
+ };
1918
+ // can't use Object.keys for prototype walking
1919
+ for (var key in obj) {
1920
+ if (typeof obj[key] === "function") {
1921
+ wrapkey(obj, key);
1922
+ }
1923
+ }
1924
+ this.log("┌ TRACELOG START");
1925
+ }
1926
+ // called when entering a function
1927
+ TraceLogger.prototype.fin = function (fn, args) {
1928
+ this.padding += this.pad;
1929
+ this.log("\u251C\u2500> entering ".concat(fn), args);
1930
+ };
1931
+ // called when exiting a function
1932
+ TraceLogger.prototype.fout = function (fn, result) {
1933
+ this.log("│<──┘ generated return value", result);
1934
+ this.padding = this.padding.substring(0, this.padding.length - this.pad.length);
1935
+ };
1936
+ // log message formatting
1937
+ TraceLogger.prototype.format = function (s, tick) {
1938
+ var nf = function (t) {
1939
+ var tStr = "".concat(t);
1940
+ while (tStr.length < 4) {
1941
+ tStr = "0".concat(t);
1942
+ }
1943
+ return tStr;
1944
+ };
1945
+ return "".concat(nf(tick), "> ").concat(this.padding).concat(s);
1946
+ };
1947
+ // log a trace message
1948
+ TraceLogger.prototype.log = function () {
1949
+ var arguments$1 = arguments;
1950
+
1951
+ var args = [];
1952
+ for (var _i = 0; _i < arguments.length; _i++) {
1953
+ args[_i] = arguments$1[_i];
1954
+ }
1955
+ var stringCollapse = function (v) {
1956
+ if (!v) {
1957
+ return "<falsey>";
1958
+ }
1959
+ if (typeof v === "string") {
1960
+ return v;
1961
+ }
1962
+ if (checkElementType(v, "HTMLElement")) {
1963
+ return v.outerHTML || "<empty>";
1964
+ }
1965
+ if (v instanceof Array) {
1966
+ return "[".concat(v.map(stringCollapse).join(","), "]");
1967
+ }
1968
+ return v.toString() || v.valueOf() || "<unknown>";
1969
+ };
1970
+ var s = args.map(stringCollapse).join(", ");
1971
+ this.messages.push(this.format(s, this.tick++));
1972
+ };
1973
+ // turn the log into a structured string with
1974
+ // unicode box codes to make it a sensible trace.
1975
+ TraceLogger.prototype.toString = function () {
1976
+ var cap = "× ";
1977
+ var terminator = "└───";
1978
+ while (terminator.length <= this.padding.length + this.pad.length) {
1979
+ terminator += cap;
1980
+ }
1981
+ var _ = this.padding;
1982
+ this.padding = "";
1983
+ terminator = this.format(terminator, this.tick);
1984
+ this.padding = _;
1985
+ return "".concat(this.messages.join("\n"), "\n").concat(terminator);
1986
+ };
1987
+ return TraceLogger;
1988
+ }());
1989
+
1990
+ export { DiffDOM, TraceLogger, nodeToObj, stringToObj };
1991
+ //# sourceMappingURL=module.js.map