async-debug 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/lib/async/debug.rb +90 -0
  3. data/lib/async/debug/reactor_view.rb +101 -0
  4. data/lib/async/debug/version.rb +27 -0
  5. data/pages/_heading.xnode +2 -0
  6. data/pages/_page.xnode +42 -0
  7. data/pages/controller.rb +21 -0
  8. data/pages/errors/exception.xnode +5 -0
  9. data/pages/errors/file-not-found.xnode +5 -0
  10. data/pages/index.xnode +3 -0
  11. data/pages/links.yaml +4 -0
  12. data/public/_components/@socketry/live/live.js +157 -0
  13. data/public/_components/@socketry/live/live.min.js +1 -0
  14. data/public/_components/jquery-syntax/base/jquery.syntax.brush.apache.css +12 -0
  15. data/public/_components/jquery-syntax/base/jquery.syntax.brush.applescript.css +5 -0
  16. data/public/_components/jquery-syntax/base/jquery.syntax.brush.assembly.css +8 -0
  17. data/public/_components/jquery-syntax/base/jquery.syntax.brush.bash-script.css +4 -0
  18. data/public/_components/jquery-syntax/base/jquery.syntax.brush.bash.css +2 -0
  19. data/public/_components/jquery-syntax/base/jquery.syntax.brush.clang.css +6 -0
  20. data/public/_components/jquery-syntax/base/jquery.syntax.brush.css.css +14 -0
  21. data/public/_components/jquery-syntax/base/jquery.syntax.brush.diff.css +16 -0
  22. data/public/_components/jquery-syntax/base/jquery.syntax.brush.html.css +5 -0
  23. data/public/_components/jquery-syntax/base/jquery.syntax.brush.ocaml.css +3 -0
  24. data/public/_components/jquery-syntax/base/jquery.syntax.brush.protobuf.css +2 -0
  25. data/public/_components/jquery-syntax/base/jquery.syntax.brush.python.css +6 -0
  26. data/public/_components/jquery-syntax/base/jquery.syntax.brush.ruby.css +2 -0
  27. data/public/_components/jquery-syntax/base/jquery.syntax.brush.xml.css +35 -0
  28. data/public/_components/jquery-syntax/base/jquery.syntax.core.css +58 -0
  29. data/public/_components/jquery-syntax/base/jquery.syntax.editor.css +6 -0
  30. data/public/_components/jquery-syntax/base/theme.js +1 -0
  31. data/public/_components/jquery-syntax/bright/jquery.syntax.core.css +27 -0
  32. data/public/_components/jquery-syntax/bright/theme.js +1 -0
  33. data/public/_components/jquery-syntax/jquery.syntax.brush.apache.js +3 -0
  34. data/public/_components/jquery-syntax/jquery.syntax.brush.applescript.js +5 -0
  35. data/public/_components/jquery-syntax/jquery.syntax.brush.assembly.js +3 -0
  36. data/public/_components/jquery-syntax/jquery.syntax.brush.bash-script.js +4 -0
  37. data/public/_components/jquery-syntax/jquery.syntax.brush.bash.js +2 -0
  38. data/public/_components/jquery-syntax/jquery.syntax.brush.basic.js +5 -0
  39. data/public/_components/jquery-syntax/jquery.syntax.brush.clang.js +5 -0
  40. data/public/_components/jquery-syntax/jquery.syntax.brush.csharp.js +4 -0
  41. data/public/_components/jquery-syntax/jquery.syntax.brush.css.js +5 -0
  42. data/public/_components/jquery-syntax/jquery.syntax.brush.diff.js +2 -0
  43. data/public/_components/jquery-syntax/jquery.syntax.brush.go.js +3 -0
  44. data/public/_components/jquery-syntax/jquery.syntax.brush.haskell.js +3 -0
  45. data/public/_components/jquery-syntax/jquery.syntax.brush.html.js +4 -0
  46. data/public/_components/jquery-syntax/jquery.syntax.brush.io.js +3 -0
  47. data/public/_components/jquery-syntax/jquery.syntax.brush.java.js +4 -0
  48. data/public/_components/jquery-syntax/jquery.syntax.brush.javascript.js +3 -0
  49. data/public/_components/jquery-syntax/jquery.syntax.brush.kai.js +2 -0
  50. data/public/_components/jquery-syntax/jquery.syntax.brush.lisp.js +2 -0
  51. data/public/_components/jquery-syntax/jquery.syntax.brush.lua.js +3 -0
  52. data/public/_components/jquery-syntax/jquery.syntax.brush.nginx.js +2 -0
  53. data/public/_components/jquery-syntax/jquery.syntax.brush.ocaml.js +4 -0
  54. data/public/_components/jquery-syntax/jquery.syntax.brush.ooc.js +4 -0
  55. data/public/_components/jquery-syntax/jquery.syntax.brush.pascal.js +4 -0
  56. data/public/_components/jquery-syntax/jquery.syntax.brush.perl5.js +3 -0
  57. data/public/_components/jquery-syntax/jquery.syntax.brush.php-script.js +4 -0
  58. data/public/_components/jquery-syntax/jquery.syntax.brush.php.js +2 -0
  59. data/public/_components/jquery-syntax/jquery.syntax.brush.plain.js +2 -0
  60. data/public/_components/jquery-syntax/jquery.syntax.brush.protobuf.js +3 -0
  61. data/public/_components/jquery-syntax/jquery.syntax.brush.python.js +5 -0
  62. data/public/_components/jquery-syntax/jquery.syntax.brush.ruby.js +5 -0
  63. data/public/_components/jquery-syntax/jquery.syntax.brush.scala.js +4 -0
  64. data/public/_components/jquery-syntax/jquery.syntax.brush.smalltalk.js +2 -0
  65. data/public/_components/jquery-syntax/jquery.syntax.brush.sql.js +4 -0
  66. data/public/_components/jquery-syntax/jquery.syntax.brush.super-collider.js +3 -0
  67. data/public/_components/jquery-syntax/jquery.syntax.brush.swift.js +3 -0
  68. data/public/_components/jquery-syntax/jquery.syntax.brush.trenni.js +2 -0
  69. data/public/_components/jquery-syntax/jquery.syntax.brush.xml.js +4 -0
  70. data/public/_components/jquery-syntax/jquery.syntax.brush.yaml.js +2 -0
  71. data/public/_components/jquery-syntax/jquery.syntax.cache.js +7 -0
  72. data/public/_components/jquery-syntax/jquery.syntax.core.js +34 -0
  73. data/public/_components/jquery-syntax/jquery.syntax.editor.js +11 -0
  74. data/public/_components/jquery-syntax/jquery.syntax.js +8 -0
  75. data/public/_components/jquery-syntax/jquery.syntax.min.js +13 -0
  76. data/public/_components/jquery-syntax/paper/jquery.syntax.core.css +31 -0
  77. data/public/_components/jquery-syntax/paper/theme.js +1 -0
  78. data/public/_components/jquery/jquery.js +10872 -0
  79. data/public/_components/jquery/jquery.min.js +2 -0
  80. data/public/_components/jquery/jquery.min.map +1 -0
  81. data/public/_components/jquery/jquery.slim.js +8777 -0
  82. data/public/_components/jquery/jquery.slim.min.js +2 -0
  83. data/public/_components/jquery/jquery.slim.min.map +1 -0
  84. data/public/_components/morphdom/morphdom-esm.js +755 -0
  85. data/public/_components/morphdom/morphdom-factory.js +691 -0
  86. data/public/_components/morphdom/morphdom-umd.js +763 -0
  87. data/public/_components/morphdom/morphdom-umd.min.js +1 -0
  88. data/public/_components/morphdom/morphdom.js +757 -0
  89. data/public/_static/icon.png +0 -0
  90. data/public/_static/links.js +21 -0
  91. data/public/_static/site.css +332 -0
  92. metadata +244 -0
@@ -0,0 +1,691 @@
1
+ 'use strict';
2
+
3
+ var range; // Create a range object for efficently rendering strings to elements.
4
+ var NS_XHTML = 'http://www.w3.org/1999/xhtml';
5
+
6
+ var doc = typeof document === 'undefined' ? undefined : document;
7
+ var HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');
8
+ var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();
9
+
10
+ function createFragmentFromTemplate(str) {
11
+ var template = doc.createElement('template');
12
+ template.innerHTML = str;
13
+ return template.content.childNodes[0];
14
+ }
15
+
16
+ function createFragmentFromRange(str) {
17
+ if (!range) {
18
+ range = doc.createRange();
19
+ range.selectNode(doc.body);
20
+ }
21
+
22
+ var fragment = range.createContextualFragment(str);
23
+ return fragment.childNodes[0];
24
+ }
25
+
26
+ function createFragmentFromWrap(str) {
27
+ var fragment = doc.createElement('body');
28
+ fragment.innerHTML = str;
29
+ return fragment.childNodes[0];
30
+ }
31
+
32
+ /**
33
+ * This is about the same
34
+ * var html = new DOMParser().parseFromString(str, 'text/html');
35
+ * return html.body.firstChild;
36
+ *
37
+ * @method toElement
38
+ * @param {String} str
39
+ */
40
+ function toElement(str) {
41
+ str = str.trim();
42
+ if (HAS_TEMPLATE_SUPPORT) {
43
+ // avoid restrictions on content for things like `<tr><th>Hi</th></tr>` which
44
+ // createContextualFragment doesn't support
45
+ // <template> support not available in IE
46
+ return createFragmentFromTemplate(str);
47
+ } else if (HAS_RANGE_SUPPORT) {
48
+ return createFragmentFromRange(str);
49
+ }
50
+
51
+ return createFragmentFromWrap(str);
52
+ }
53
+
54
+ /**
55
+ * Returns true if two node's names are the same.
56
+ *
57
+ * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same
58
+ * nodeName and different namespace URIs.
59
+ *
60
+ * @param {Element} a
61
+ * @param {Element} b The target element
62
+ * @return {boolean}
63
+ */
64
+ function compareNodeNames(fromEl, toEl) {
65
+ var fromNodeName = fromEl.nodeName;
66
+ var toNodeName = toEl.nodeName;
67
+ var fromCodeStart, toCodeStart;
68
+
69
+ if (fromNodeName === toNodeName) {
70
+ return true;
71
+ }
72
+
73
+ fromCodeStart = fromNodeName.charCodeAt(0);
74
+ toCodeStart = toNodeName.charCodeAt(0);
75
+
76
+ // If the target element is a virtual DOM node or SVG node then we may
77
+ // need to normalize the tag name before comparing. Normal HTML elements that are
78
+ // in the "http://www.w3.org/1999/xhtml"
79
+ // are converted to upper case
80
+ if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower
81
+ return fromNodeName === toNodeName.toUpperCase();
82
+ } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower
83
+ return toNodeName === fromNodeName.toUpperCase();
84
+ } else {
85
+ return false;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Create an element, optionally with a known namespace URI.
91
+ *
92
+ * @param {string} name the element name, e.g. 'div' or 'svg'
93
+ * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of
94
+ * its `xmlns` attribute or its inferred namespace.
95
+ *
96
+ * @return {Element}
97
+ */
98
+ function createElementNS(name, namespaceURI) {
99
+ return !namespaceURI || namespaceURI === NS_XHTML ?
100
+ doc.createElement(name) :
101
+ doc.createElementNS(namespaceURI, name);
102
+ }
103
+
104
+ /**
105
+ * Copies the children of one DOM element to another DOM element
106
+ */
107
+ function moveChildren(fromEl, toEl) {
108
+ var curChild = fromEl.firstChild;
109
+ while (curChild) {
110
+ var nextChild = curChild.nextSibling;
111
+ toEl.appendChild(curChild);
112
+ curChild = nextChild;
113
+ }
114
+ return toEl;
115
+ }
116
+
117
+ function syncBooleanAttrProp(fromEl, toEl, name) {
118
+ if (fromEl[name] !== toEl[name]) {
119
+ fromEl[name] = toEl[name];
120
+ if (fromEl[name]) {
121
+ fromEl.setAttribute(name, '');
122
+ } else {
123
+ fromEl.removeAttribute(name);
124
+ }
125
+ }
126
+ }
127
+
128
+ var specialElHandlers = {
129
+ OPTION: function(fromEl, toEl) {
130
+ var parentNode = fromEl.parentNode;
131
+ if (parentNode) {
132
+ var parentName = parentNode.nodeName.toUpperCase();
133
+ if (parentName === 'OPTGROUP') {
134
+ parentNode = parentNode.parentNode;
135
+ parentName = parentNode && parentNode.nodeName.toUpperCase();
136
+ }
137
+ if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {
138
+ if (fromEl.hasAttribute('selected') && !toEl.selected) {
139
+ // Workaround for MS Edge bug where the 'selected' attribute can only be
140
+ // removed if set to a non-empty value:
141
+ // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/
142
+ fromEl.setAttribute('selected', 'selected');
143
+ fromEl.removeAttribute('selected');
144
+ }
145
+ // We have to reset select element's selectedIndex to -1, otherwise setting
146
+ // fromEl.selected using the syncBooleanAttrProp below has no effect.
147
+ // The correct selectedIndex will be set in the SELECT special handler below.
148
+ parentNode.selectedIndex = -1;
149
+ }
150
+ }
151
+ syncBooleanAttrProp(fromEl, toEl, 'selected');
152
+ },
153
+ /**
154
+ * The "value" attribute is special for the <input> element since it sets
155
+ * the initial value. Changing the "value" attribute without changing the
156
+ * "value" property will have no effect since it is only used to the set the
157
+ * initial value. Similar for the "checked" attribute, and "disabled".
158
+ */
159
+ INPUT: function(fromEl, toEl) {
160
+ syncBooleanAttrProp(fromEl, toEl, 'checked');
161
+ syncBooleanAttrProp(fromEl, toEl, 'disabled');
162
+
163
+ if (fromEl.value !== toEl.value) {
164
+ fromEl.value = toEl.value;
165
+ }
166
+
167
+ if (!toEl.hasAttribute('value')) {
168
+ fromEl.removeAttribute('value');
169
+ }
170
+ },
171
+
172
+ TEXTAREA: function(fromEl, toEl) {
173
+ var newValue = toEl.value;
174
+ if (fromEl.value !== newValue) {
175
+ fromEl.value = newValue;
176
+ }
177
+
178
+ var firstChild = fromEl.firstChild;
179
+ if (firstChild) {
180
+ // Needed for IE. Apparently IE sets the placeholder as the
181
+ // node value and vise versa. This ignores an empty update.
182
+ var oldValue = firstChild.nodeValue;
183
+
184
+ if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {
185
+ return;
186
+ }
187
+
188
+ firstChild.nodeValue = newValue;
189
+ }
190
+ },
191
+ SELECT: function(fromEl, toEl) {
192
+ if (!toEl.hasAttribute('multiple')) {
193
+ var selectedIndex = -1;
194
+ var i = 0;
195
+ // We have to loop through children of fromEl, not toEl since nodes can be moved
196
+ // from toEl to fromEl directly when morphing.
197
+ // At the time this special handler is invoked, all children have already been morphed
198
+ // and appended to / removed from fromEl, so using fromEl here is safe and correct.
199
+ var curChild = fromEl.firstChild;
200
+ var optgroup;
201
+ var nodeName;
202
+ while(curChild) {
203
+ nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
204
+ if (nodeName === 'OPTGROUP') {
205
+ optgroup = curChild;
206
+ curChild = optgroup.firstChild;
207
+ } else {
208
+ if (nodeName === 'OPTION') {
209
+ if (curChild.hasAttribute('selected')) {
210
+ selectedIndex = i;
211
+ break;
212
+ }
213
+ i++;
214
+ }
215
+ curChild = curChild.nextSibling;
216
+ if (!curChild && optgroup) {
217
+ curChild = optgroup.nextSibling;
218
+ optgroup = null;
219
+ }
220
+ }
221
+ }
222
+
223
+ fromEl.selectedIndex = selectedIndex;
224
+ }
225
+ }
226
+ };
227
+
228
+ var ELEMENT_NODE = 1;
229
+ var DOCUMENT_FRAGMENT_NODE = 11;
230
+ var TEXT_NODE = 3;
231
+ var COMMENT_NODE = 8;
232
+
233
+ function noop() {}
234
+
235
+ function defaultGetNodeKey(node) {
236
+ if (node) {
237
+ return (node.getAttribute && node.getAttribute('id')) || node.id;
238
+ }
239
+ }
240
+
241
+ function morphdomFactory(morphAttrs) {
242
+
243
+ return function morphdom(fromNode, toNode, options) {
244
+ if (!options) {
245
+ options = {};
246
+ }
247
+
248
+ if (typeof toNode === 'string') {
249
+ if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {
250
+ var toNodeHtml = toNode;
251
+ toNode = doc.createElement('html');
252
+ toNode.innerHTML = toNodeHtml;
253
+ } else {
254
+ toNode = toElement(toNode);
255
+ }
256
+ }
257
+
258
+ var getNodeKey = options.getNodeKey || defaultGetNodeKey;
259
+ var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
260
+ var onNodeAdded = options.onNodeAdded || noop;
261
+ var onBeforeElUpdated = options.onBeforeElUpdated || noop;
262
+ var onElUpdated = options.onElUpdated || noop;
263
+ var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
264
+ var onNodeDiscarded = options.onNodeDiscarded || noop;
265
+ var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
266
+ var childrenOnly = options.childrenOnly === true;
267
+
268
+ // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.
269
+ var fromNodesLookup = Object.create(null);
270
+ var keyedRemovalList = [];
271
+
272
+ function addKeyedRemoval(key) {
273
+ keyedRemovalList.push(key);
274
+ }
275
+
276
+ function walkDiscardedChildNodes(node, skipKeyedNodes) {
277
+ if (node.nodeType === ELEMENT_NODE) {
278
+ var curChild = node.firstChild;
279
+ while (curChild) {
280
+
281
+ var key = undefined;
282
+
283
+ if (skipKeyedNodes && (key = getNodeKey(curChild))) {
284
+ // If we are skipping keyed nodes then we add the key
285
+ // to a list so that it can be handled at the very end.
286
+ addKeyedRemoval(key);
287
+ } else {
288
+ // Only report the node as discarded if it is not keyed. We do this because
289
+ // at the end we loop through all keyed elements that were unmatched
290
+ // and then discard them in one final pass.
291
+ onNodeDiscarded(curChild);
292
+ if (curChild.firstChild) {
293
+ walkDiscardedChildNodes(curChild, skipKeyedNodes);
294
+ }
295
+ }
296
+
297
+ curChild = curChild.nextSibling;
298
+ }
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Removes a DOM node out of the original DOM
304
+ *
305
+ * @param {Node} node The node to remove
306
+ * @param {Node} parentNode The nodes parent
307
+ * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.
308
+ * @return {undefined}
309
+ */
310
+ function removeNode(node, parentNode, skipKeyedNodes) {
311
+ if (onBeforeNodeDiscarded(node) === false) {
312
+ return;
313
+ }
314
+
315
+ if (parentNode) {
316
+ parentNode.removeChild(node);
317
+ }
318
+
319
+ onNodeDiscarded(node);
320
+ walkDiscardedChildNodes(node, skipKeyedNodes);
321
+ }
322
+
323
+ // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future
324
+ // function indexTree(root) {
325
+ // var treeWalker = document.createTreeWalker(
326
+ // root,
327
+ // NodeFilter.SHOW_ELEMENT);
328
+ //
329
+ // var el;
330
+ // while((el = treeWalker.nextNode())) {
331
+ // var key = getNodeKey(el);
332
+ // if (key) {
333
+ // fromNodesLookup[key] = el;
334
+ // }
335
+ // }
336
+ // }
337
+
338
+ // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future
339
+ //
340
+ // function indexTree(node) {
341
+ // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);
342
+ // var el;
343
+ // while((el = nodeIterator.nextNode())) {
344
+ // var key = getNodeKey(el);
345
+ // if (key) {
346
+ // fromNodesLookup[key] = el;
347
+ // }
348
+ // }
349
+ // }
350
+
351
+ function indexTree(node) {
352
+ if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE) {
353
+ var curChild = node.firstChild;
354
+ while (curChild) {
355
+ var key = getNodeKey(curChild);
356
+ if (key) {
357
+ fromNodesLookup[key] = curChild;
358
+ }
359
+
360
+ // Walk recursively
361
+ indexTree(curChild);
362
+
363
+ curChild = curChild.nextSibling;
364
+ }
365
+ }
366
+ }
367
+
368
+ indexTree(fromNode);
369
+
370
+ function handleNodeAdded(el) {
371
+ onNodeAdded(el);
372
+
373
+ var curChild = el.firstChild;
374
+ while (curChild) {
375
+ var nextSibling = curChild.nextSibling;
376
+
377
+ var key = getNodeKey(curChild);
378
+ if (key) {
379
+ var unmatchedFromEl = fromNodesLookup[key];
380
+ // if we find a duplicate #id node in cache, replace `el` with cache value
381
+ // and morph it to the child node.
382
+ if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
383
+ curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
384
+ morphEl(unmatchedFromEl, curChild);
385
+ } else {
386
+ handleNodeAdded(curChild);
387
+ }
388
+ } else {
389
+ // recursively call for curChild and it's children to see if we find something in
390
+ // fromNodesLookup
391
+ handleNodeAdded(curChild);
392
+ }
393
+
394
+ curChild = nextSibling;
395
+ }
396
+ }
397
+
398
+ function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
399
+ // We have processed all of the "to nodes". If curFromNodeChild is
400
+ // non-null then we still have some from nodes left over that need
401
+ // to be removed
402
+ while (curFromNodeChild) {
403
+ var fromNextSibling = curFromNodeChild.nextSibling;
404
+ if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {
405
+ // Since the node is keyed it might be matched up later so we defer
406
+ // the actual removal to later
407
+ addKeyedRemoval(curFromNodeKey);
408
+ } else {
409
+ // NOTE: we skip nested keyed nodes from being removed since there is
410
+ // still a chance they will be matched up later
411
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
412
+ }
413
+ curFromNodeChild = fromNextSibling;
414
+ }
415
+ }
416
+
417
+ function morphEl(fromEl, toEl, childrenOnly) {
418
+ var toElKey = getNodeKey(toEl);
419
+
420
+ if (toElKey) {
421
+ // If an element with an ID is being morphed then it will be in the final
422
+ // DOM so clear it out of the saved elements collection
423
+ delete fromNodesLookup[toElKey];
424
+ }
425
+
426
+ if (!childrenOnly) {
427
+ // optional
428
+ if (onBeforeElUpdated(fromEl, toEl) === false) {
429
+ return;
430
+ }
431
+
432
+ // update attributes on original DOM element first
433
+ morphAttrs(fromEl, toEl);
434
+ // optional
435
+ onElUpdated(fromEl);
436
+
437
+ if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
438
+ return;
439
+ }
440
+ }
441
+
442
+ if (fromEl.nodeName !== 'TEXTAREA') {
443
+ morphChildren(fromEl, toEl);
444
+ } else {
445
+ specialElHandlers.TEXTAREA(fromEl, toEl);
446
+ }
447
+ }
448
+
449
+ function morphChildren(fromEl, toEl) {
450
+ var curToNodeChild = toEl.firstChild;
451
+ var curFromNodeChild = fromEl.firstChild;
452
+ var curToNodeKey;
453
+ var curFromNodeKey;
454
+
455
+ var fromNextSibling;
456
+ var toNextSibling;
457
+ var matchingFromEl;
458
+
459
+ // walk the children
460
+ outer: while (curToNodeChild) {
461
+ toNextSibling = curToNodeChild.nextSibling;
462
+ curToNodeKey = getNodeKey(curToNodeChild);
463
+
464
+ // walk the fromNode children all the way through
465
+ while (curFromNodeChild) {
466
+ fromNextSibling = curFromNodeChild.nextSibling;
467
+
468
+ if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
469
+ curToNodeChild = toNextSibling;
470
+ curFromNodeChild = fromNextSibling;
471
+ continue outer;
472
+ }
473
+
474
+ curFromNodeKey = getNodeKey(curFromNodeChild);
475
+
476
+ var curFromNodeType = curFromNodeChild.nodeType;
477
+
478
+ // this means if the curFromNodeChild doesnt have a match with the curToNodeChild
479
+ var isCompatible = undefined;
480
+
481
+ if (curFromNodeType === curToNodeChild.nodeType) {
482
+ if (curFromNodeType === ELEMENT_NODE) {
483
+ // Both nodes being compared are Element nodes
484
+
485
+ if (curToNodeKey) {
486
+ // The target node has a key so we want to match it up with the correct element
487
+ // in the original DOM tree
488
+ if (curToNodeKey !== curFromNodeKey) {
489
+ // The current element in the original DOM tree does not have a matching key so
490
+ // let's check our lookup to see if there is a matching element in the original
491
+ // DOM tree
492
+ if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {
493
+ if (fromNextSibling === matchingFromEl) {
494
+ // Special case for single element removals. To avoid removing the original
495
+ // DOM node out of the tree (since that can break CSS transitions, etc.),
496
+ // we will instead discard the current node and wait until the next
497
+ // iteration to properly match up the keyed target element with its matching
498
+ // element in the original tree
499
+ isCompatible = false;
500
+ } else {
501
+ // We found a matching keyed element somewhere in the original DOM tree.
502
+ // Let's move the original DOM node into the current position and morph
503
+ // it.
504
+
505
+ // NOTE: We use insertBefore instead of replaceChild because we want to go through
506
+ // the `removeNode()` function for the node that is being discarded so that
507
+ // all lifecycle hooks are correctly invoked
508
+ fromEl.insertBefore(matchingFromEl, curFromNodeChild);
509
+
510
+ // fromNextSibling = curFromNodeChild.nextSibling;
511
+
512
+ if (curFromNodeKey) {
513
+ // Since the node is keyed it might be matched up later so we defer
514
+ // the actual removal to later
515
+ addKeyedRemoval(curFromNodeKey);
516
+ } else {
517
+ // NOTE: we skip nested keyed nodes from being removed since there is
518
+ // still a chance they will be matched up later
519
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
520
+ }
521
+
522
+ curFromNodeChild = matchingFromEl;
523
+ }
524
+ } else {
525
+ // The nodes are not compatible since the "to" node has a key and there
526
+ // is no matching keyed node in the source tree
527
+ isCompatible = false;
528
+ }
529
+ }
530
+ } else if (curFromNodeKey) {
531
+ // The original has a key
532
+ isCompatible = false;
533
+ }
534
+
535
+ isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
536
+ if (isCompatible) {
537
+ // We found compatible DOM elements so transform
538
+ // the current "from" node to match the current
539
+ // target DOM node.
540
+ // MORPH
541
+ morphEl(curFromNodeChild, curToNodeChild);
542
+ }
543
+
544
+ } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
545
+ // Both nodes being compared are Text or Comment nodes
546
+ isCompatible = true;
547
+ // Simply update nodeValue on the original node to
548
+ // change the text value
549
+ if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
550
+ curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
551
+ }
552
+
553
+ }
554
+ }
555
+
556
+ if (isCompatible) {
557
+ // Advance both the "to" child and the "from" child since we found a match
558
+ // Nothing else to do as we already recursively called morphChildren above
559
+ curToNodeChild = toNextSibling;
560
+ curFromNodeChild = fromNextSibling;
561
+ continue outer;
562
+ }
563
+
564
+ // No compatible match so remove the old node from the DOM and continue trying to find a
565
+ // match in the original DOM. However, we only do this if the from node is not keyed
566
+ // since it is possible that a keyed node might match up with a node somewhere else in the
567
+ // target tree and we don't want to discard it just yet since it still might find a
568
+ // home in the final DOM tree. After everything is done we will remove any keyed nodes
569
+ // that didn't find a home
570
+ if (curFromNodeKey) {
571
+ // Since the node is keyed it might be matched up later so we defer
572
+ // the actual removal to later
573
+ addKeyedRemoval(curFromNodeKey);
574
+ } else {
575
+ // NOTE: we skip nested keyed nodes from being removed since there is
576
+ // still a chance they will be matched up later
577
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
578
+ }
579
+
580
+ curFromNodeChild = fromNextSibling;
581
+ } // END: while(curFromNodeChild) {}
582
+
583
+ // If we got this far then we did not find a candidate match for
584
+ // our "to node" and we exhausted all of the children "from"
585
+ // nodes. Therefore, we will just append the current "to" node
586
+ // to the end
587
+ if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
588
+ fromEl.appendChild(matchingFromEl);
589
+ // MORPH
590
+ morphEl(matchingFromEl, curToNodeChild);
591
+ } else {
592
+ var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
593
+ if (onBeforeNodeAddedResult !== false) {
594
+ if (onBeforeNodeAddedResult) {
595
+ curToNodeChild = onBeforeNodeAddedResult;
596
+ }
597
+
598
+ if (curToNodeChild.actualize) {
599
+ curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
600
+ }
601
+ fromEl.appendChild(curToNodeChild);
602
+ handleNodeAdded(curToNodeChild);
603
+ }
604
+ }
605
+
606
+ curToNodeChild = toNextSibling;
607
+ curFromNodeChild = fromNextSibling;
608
+ }
609
+
610
+ cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
611
+
612
+ var specialElHandler = specialElHandlers[fromEl.nodeName];
613
+ if (specialElHandler) {
614
+ specialElHandler(fromEl, toEl);
615
+ }
616
+ } // END: morphChildren(...)
617
+
618
+ var morphedNode = fromNode;
619
+ var morphedNodeType = morphedNode.nodeType;
620
+ var toNodeType = toNode.nodeType;
621
+
622
+ if (!childrenOnly) {
623
+ // Handle the case where we are given two DOM nodes that are not
624
+ // compatible (e.g. <div> --> <span> or <div> --> TEXT)
625
+ if (morphedNodeType === ELEMENT_NODE) {
626
+ if (toNodeType === ELEMENT_NODE) {
627
+ if (!compareNodeNames(fromNode, toNode)) {
628
+ onNodeDiscarded(fromNode);
629
+ morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
630
+ }
631
+ } else {
632
+ // Going from an element node to a text node
633
+ morphedNode = toNode;
634
+ }
635
+ } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node
636
+ if (toNodeType === morphedNodeType) {
637
+ if (morphedNode.nodeValue !== toNode.nodeValue) {
638
+ morphedNode.nodeValue = toNode.nodeValue;
639
+ }
640
+
641
+ return morphedNode;
642
+ } else {
643
+ // Text node to something else
644
+ morphedNode = toNode;
645
+ }
646
+ }
647
+ }
648
+
649
+ if (morphedNode === toNode) {
650
+ // The "to node" was not compatible with the "from node" so we had to
651
+ // toss out the "from node" and use the "to node"
652
+ onNodeDiscarded(fromNode);
653
+ } else {
654
+ if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
655
+ return;
656
+ }
657
+
658
+ morphEl(morphedNode, toNode, childrenOnly);
659
+
660
+ // We now need to loop over any keyed nodes that might need to be
661
+ // removed. We only do the removal if we know that the keyed node
662
+ // never found a match. When a keyed node is matched up we remove
663
+ // it out of fromNodesLookup and we use fromNodesLookup to determine
664
+ // if a keyed node has been matched up or not
665
+ if (keyedRemovalList) {
666
+ for (var i=0, len=keyedRemovalList.length; i<len; i++) {
667
+ var elToRemove = fromNodesLookup[keyedRemovalList[i]];
668
+ if (elToRemove) {
669
+ removeNode(elToRemove, elToRemove.parentNode, false);
670
+ }
671
+ }
672
+ }
673
+ }
674
+
675
+ if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
676
+ if (morphedNode.actualize) {
677
+ morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
678
+ }
679
+ // If we had to swap out the from node with a new node because the old
680
+ // node was not compatible with the target node then we need to
681
+ // replace the old DOM node in the original DOM tree. This is only
682
+ // possible if the original DOM node was part of a DOM tree which
683
+ // we know is the case if it has a parent node.
684
+ fromNode.parentNode.replaceChild(morphedNode, fromNode);
685
+ }
686
+
687
+ return morphedNode;
688
+ };
689
+ }
690
+
691
+ module.exports = morphdomFactory;