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,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