clapton 0.0.13 → 0.0.14

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