unvendor: Replace morphdom

e03e32d66a628fbe3565720f76eb5bbe0fced667

Cohee <18619528+Cohee1207@users.noreply.github.com>

6 files changed, +12 -792Ignore whitespace
package-lock.json+7 -0
@@ -47,6 +47,7 @@
47 "lodash": "^4.17.21",47 "lodash": "^4.17.21",
48 "mime-types": "^2.1.35",48 "mime-types": "^2.1.35",
49 "moment": "^2.30.1",49 "moment": "^2.30.1",
50 "morphdom": "^2.7.4",
50 "multer": "^1.4.5-lts.1",51 "multer": "^1.4.5-lts.1",
51 "node-fetch": "^3.3.2",52 "node-fetch": "^3.3.2",
52 "node-persist": "^4.0.1",53 "node-persist": "^4.0.1",
@@ -5784,6 +5785,12 @@
5784 "node": "*"5785 "node": "*"
5785 }5786 }
5786 },5787 },
5788 "node_modules/morphdom": {
5789 "version": "2.7.4",
5790 "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz",
5791 "integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==",
5792 "license": "MIT"
5793 },
5787 "node_modules/ms": {5794 "node_modules/ms": {
5788 "version": "2.0.0",5795 "version": "2.0.0",
5789 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",5796 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
package.json+1 -0
@@ -37,6 +37,7 @@
37 "lodash": "^4.17.21",37 "lodash": "^4.17.21",
38 "mime-types": "^2.1.35",38 "mime-types": "^2.1.35",
39 "moment": "^2.30.1",39 "moment": "^2.30.1",
40 "morphdom": "^2.7.4",
40 "multer": "^1.4.5-lts.1",41 "multer": "^1.4.5-lts.1",
41 "node-fetch": "^3.3.2",42 "node-fetch": "^3.3.2",
42 "node-persist": "^4.0.1",43 "node-persist": "^4.0.1",
public/lib.js+3 -0
@@ -20,6 +20,7 @@ import moment from 'moment';
20import seedrandom from 'seedrandom';20import seedrandom from 'seedrandom';
21import * as Popper from '@popperjs/core';21import * as Popper from '@popperjs/core';
22import droll from 'droll';22import droll from 'droll';
23import morphdom from 'morphdom';
2324
24/**25/**
25 * Expose the libraries to the 'window' object.26 * Expose the libraries to the 'window' object.
@@ -96,6 +97,7 @@ export default {
96 seedrandom,97 seedrandom,
97 Popper,98 Popper,
98 droll,99 droll,
100 morphdom,
99};101};
100102
101export {103export {
@@ -118,4 +120,5 @@ export {
118 seedrandom,120 seedrandom,
119 Popper,121 Popper,
120 droll,122 droll,
123 morphdom,
121};124};
public/scripts/extensions/quick-reply/lib/morphdom-esm.js+0 -769
@@ -1,769 +0,0 @@
1var DOCUMENT_FRAGMENT_NODE = 11;
2
3function morphAttrs(fromNode, toNode) {
4 var toNodeAttrs = toNode.attributes;
5 var attr;
6 var attrName;
7 var attrNamespaceURI;
8 var attrValue;
9 var fromValue;
10
11 // document-fragments dont have attributes so lets not do anything
12 if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
13 return;
14 }
15
16 // update attributes on original DOM element
17 for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
18 attr = toNodeAttrs[i];
19 attrName = attr.name;
20 attrNamespaceURI = attr.namespaceURI;
21 attrValue = attr.value;
22
23 if (attrNamespaceURI) {
24 attrName = attr.localName || attrName;
25 fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
26
27 if (fromValue !== attrValue) {
28 if (attr.prefix === 'xmlns'){
29 attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix
30 }
31 fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
32 }
33 } else {
34 fromValue = fromNode.getAttribute(attrName);
35
36 if (fromValue !== attrValue) {
37 fromNode.setAttribute(attrName, attrValue);
38 }
39 }
40 }
41
42 // Remove any extra attributes found on the original DOM element that
43 // weren't found on the target element.
44 var fromNodeAttrs = fromNode.attributes;
45
46 for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
47 attr = fromNodeAttrs[d];
48 attrName = attr.name;
49 attrNamespaceURI = attr.namespaceURI;
50
51 if (attrNamespaceURI) {
52 attrName = attr.localName || attrName;
53
54 if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
55 fromNode.removeAttributeNS(attrNamespaceURI, attrName);
56 }
57 } else {
58 if (!toNode.hasAttribute(attrName)) {
59 fromNode.removeAttribute(attrName);
60 }
61 }
62 }
63}
64
65var range; // Create a range object for efficently rendering strings to elements.
66var NS_XHTML = 'http://www.w3.org/1999/xhtml';
67
68var doc = typeof document === 'undefined' ? undefined : document;
69var HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');
70var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();
71
72function createFragmentFromTemplate(str) {
73 var template = doc.createElement('template');
74 template.innerHTML = str;
75 return template.content.childNodes[0];
76}
77
78function createFragmentFromRange(str) {
79 if (!range) {
80 range = doc.createRange();
81 range.selectNode(doc.body);
82 }
83
84 var fragment = range.createContextualFragment(str);
85 return fragment.childNodes[0];
86}
87
88function createFragmentFromWrap(str) {
89 var fragment = doc.createElement('body');
90 fragment.innerHTML = str;
91 return fragment.childNodes[0];
92}
93
94/**
95 * This is about the same
96 * var html = new DOMParser().parseFromString(str, 'text/html');
97 * return html.body.firstChild;
98 *
99 * @method toElement
100 * @param {String} str
101 */
102function toElement(str) {
103 str = str.trim();
104 if (HAS_TEMPLATE_SUPPORT) {
105 // avoid restrictions on content for things like `<tr><th>Hi</th></tr>` which
106 // createContextualFragment doesn't support
107 // <template> support not available in IE
108 return createFragmentFromTemplate(str);
109 } else if (HAS_RANGE_SUPPORT) {
110 return createFragmentFromRange(str);
111 }
112
113 return createFragmentFromWrap(str);
114}
115
116/**
117 * Returns true if two node's names are the same.
118 *
119 * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same
120 * nodeName and different namespace URIs.
121 *
122 * @param {Element} a
123 * @param {Element} b The target element
124 * @return {boolean}
125 */
126function compareNodeNames(fromEl, toEl) {
127 var fromNodeName = fromEl.nodeName;
128 var toNodeName = toEl.nodeName;
129 var fromCodeStart, toCodeStart;
130
131 if (fromNodeName === toNodeName) {
132 return true;
133 }
134
135 fromCodeStart = fromNodeName.charCodeAt(0);
136 toCodeStart = toNodeName.charCodeAt(0);
137
138 // If the target element is a virtual DOM node or SVG node then we may
139 // need to normalize the tag name before comparing. Normal HTML elements that are
140 // in the "http://www.w3.org/1999/xhtml"
141 // are converted to upper case
142 if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower
143 return fromNodeName === toNodeName.toUpperCase();
144 } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower
145 return toNodeName === fromNodeName.toUpperCase();
146 } else {
147 return false;
148 }
149}
150
151/**
152 * Create an element, optionally with a known namespace URI.
153 *
154 * @param {string} name the element name, e.g. 'div' or 'svg'
155 * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of
156 * its `xmlns` attribute or its inferred namespace.
157 *
158 * @return {Element}
159 */
160function createElementNS(name, namespaceURI) {
161 return !namespaceURI || namespaceURI === NS_XHTML ?
162 doc.createElement(name) :
163 doc.createElementNS(namespaceURI, name);
164}
165
166/**
167 * Copies the children of one DOM element to another DOM element
168 */
169function moveChildren(fromEl, toEl) {
170 var curChild = fromEl.firstChild;
171 while (curChild) {
172 var nextChild = curChild.nextSibling;
173 toEl.appendChild(curChild);
174 curChild = nextChild;
175 }
176 return toEl;
177}
178
179function syncBooleanAttrProp(fromEl, toEl, name) {
180 if (fromEl[name] !== toEl[name]) {
181 fromEl[name] = toEl[name];
182 if (fromEl[name]) {
183 fromEl.setAttribute(name, '');
184 } else {
185 fromEl.removeAttribute(name);
186 }
187 }
188}
189
190var specialElHandlers = {
191 OPTION: function(fromEl, toEl) {
192 var parentNode = fromEl.parentNode;
193 if (parentNode) {
194 var parentName = parentNode.nodeName.toUpperCase();
195 if (parentName === 'OPTGROUP') {
196 parentNode = parentNode.parentNode;
197 parentName = parentNode && parentNode.nodeName.toUpperCase();
198 }
199 if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {
200 if (fromEl.hasAttribute('selected') && !toEl.selected) {
201 // Workaround for MS Edge bug where the 'selected' attribute can only be
202 // removed if set to a non-empty value:
203 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/
204 fromEl.setAttribute('selected', 'selected');
205 fromEl.removeAttribute('selected');
206 }
207 // We have to reset select element's selectedIndex to -1, otherwise setting
208 // fromEl.selected using the syncBooleanAttrProp below has no effect.
209 // The correct selectedIndex will be set in the SELECT special handler below.
210 parentNode.selectedIndex = -1;
211 }
212 }
213 syncBooleanAttrProp(fromEl, toEl, 'selected');
214 },
215 /**
216 * The "value" attribute is special for the <input> element since it sets
217 * the initial value. Changing the "value" attribute without changing the
218 * "value" property will have no effect since it is only used to the set the
219 * initial value. Similar for the "checked" attribute, and "disabled".
220 */
221 INPUT: function(fromEl, toEl) {
222 syncBooleanAttrProp(fromEl, toEl, 'checked');
223 syncBooleanAttrProp(fromEl, toEl, 'disabled');
224
225 if (fromEl.value !== toEl.value) {
226 fromEl.value = toEl.value;
227 }
228
229 if (!toEl.hasAttribute('value')) {
230 fromEl.removeAttribute('value');
231 }
232 },
233
234 TEXTAREA: function(fromEl, toEl) {
235 var newValue = toEl.value;
236 if (fromEl.value !== newValue) {
237 fromEl.value = newValue;
238 }
239
240 var firstChild = fromEl.firstChild;
241 if (firstChild) {
242 // Needed for IE. Apparently IE sets the placeholder as the
243 // node value and vise versa. This ignores an empty update.
244 var oldValue = firstChild.nodeValue;
245
246 if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {
247 return;
248 }
249
250 firstChild.nodeValue = newValue;
251 }
252 },
253 SELECT: function(fromEl, toEl) {
254 if (!toEl.hasAttribute('multiple')) {
255 var selectedIndex = -1;
256 var i = 0;
257 // We have to loop through children of fromEl, not toEl since nodes can be moved
258 // from toEl to fromEl directly when morphing.
259 // At the time this special handler is invoked, all children have already been morphed
260 // and appended to / removed from fromEl, so using fromEl here is safe and correct.
261 var curChild = fromEl.firstChild;
262 var optgroup;
263 var nodeName;
264 while(curChild) {
265 nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
266 if (nodeName === 'OPTGROUP') {
267 optgroup = curChild;
268 curChild = optgroup.firstChild;
269 } else {
270 if (nodeName === 'OPTION') {
271 if (curChild.hasAttribute('selected')) {
272 selectedIndex = i;
273 break;
274 }
275 i++;
276 }
277 curChild = curChild.nextSibling;
278 if (!curChild && optgroup) {
279 curChild = optgroup.nextSibling;
280 optgroup = null;
281 }
282 }
283 }
284
285 fromEl.selectedIndex = selectedIndex;
286 }
287 }
288};
289
290var ELEMENT_NODE = 1;
291var DOCUMENT_FRAGMENT_NODE$1 = 11;
292var TEXT_NODE = 3;
293var COMMENT_NODE = 8;
294
295function noop() {}
296
297function defaultGetNodeKey(node) {
298 if (node) {
299 return (node.getAttribute && node.getAttribute('id')) || node.id;
300 }
301}
302
303function morphdomFactory(morphAttrs) {
304
305 return function morphdom(fromNode, toNode, options) {
306 if (!options) {
307 options = {};
308 }
309
310 if (typeof toNode === 'string') {
311 if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {
312 var toNodeHtml = toNode;
313 toNode = doc.createElement('html');
314 toNode.innerHTML = toNodeHtml;
315 } else {
316 toNode = toElement(toNode);
317 }
318 } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
319 toNode = toNode.firstElementChild;
320 }
321
322 var getNodeKey = options.getNodeKey || defaultGetNodeKey;
323 var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
324 var onNodeAdded = options.onNodeAdded || noop;
325 var onBeforeElUpdated = options.onBeforeElUpdated || noop;
326 var onElUpdated = options.onElUpdated || noop;
327 var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
328 var onNodeDiscarded = options.onNodeDiscarded || noop;
329 var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
330 var skipFromChildren = options.skipFromChildren || noop;
331 var addChild = options.addChild || function(parent, child){ return parent.appendChild(child); };
332 var childrenOnly = options.childrenOnly === true;
333
334 // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.
335 var fromNodesLookup = Object.create(null);
336 var keyedRemovalList = [];
337
338 function addKeyedRemoval(key) {
339 keyedRemovalList.push(key);
340 }
341
342 function walkDiscardedChildNodes(node, skipKeyedNodes) {
343 if (node.nodeType === ELEMENT_NODE) {
344 var curChild = node.firstChild;
345 while (curChild) {
346
347 var key = undefined;
348
349 if (skipKeyedNodes && (key = getNodeKey(curChild))) {
350 // If we are skipping keyed nodes then we add the key
351 // to a list so that it can be handled at the very end.
352 addKeyedRemoval(key);
353 } else {
354 // Only report the node as discarded if it is not keyed. We do this because
355 // at the end we loop through all keyed elements that were unmatched
356 // and then discard them in one final pass.
357 onNodeDiscarded(curChild);
358 if (curChild.firstChild) {
359 walkDiscardedChildNodes(curChild, skipKeyedNodes);
360 }
361 }
362
363 curChild = curChild.nextSibling;
364 }
365 }
366 }
367
368 /**
369 * Removes a DOM node out of the original DOM
370 *
371 * @param {Node} node The node to remove
372 * @param {Node} parentNode The nodes parent
373 * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.
374 * @return {undefined}
375 */
376 function removeNode(node, parentNode, skipKeyedNodes) {
377 if (onBeforeNodeDiscarded(node) === false) {
378 return;
379 }
380
381 if (parentNode) {
382 parentNode.removeChild(node);
383 }
384
385 onNodeDiscarded(node);
386 walkDiscardedChildNodes(node, skipKeyedNodes);
387 }
388
389 // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future
390 // function indexTree(root) {
391 // var treeWalker = document.createTreeWalker(
392 // root,
393 // NodeFilter.SHOW_ELEMENT);
394 //
395 // var el;
396 // while((el = treeWalker.nextNode())) {
397 // var key = getNodeKey(el);
398 // if (key) {
399 // fromNodesLookup[key] = el;
400 // }
401 // }
402 // }
403
404 // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future
405 //
406 // function indexTree(node) {
407 // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);
408 // var el;
409 // while((el = nodeIterator.nextNode())) {
410 // var key = getNodeKey(el);
411 // if (key) {
412 // fromNodesLookup[key] = el;
413 // }
414 // }
415 // }
416
417 function indexTree(node) {
418 if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
419 var curChild = node.firstChild;
420 while (curChild) {
421 var key = getNodeKey(curChild);
422 if (key) {
423 fromNodesLookup[key] = curChild;
424 }
425
426 // Walk recursively
427 indexTree(curChild);
428
429 curChild = curChild.nextSibling;
430 }
431 }
432 }
433
434 indexTree(fromNode);
435
436 function handleNodeAdded(el) {
437 onNodeAdded(el);
438
439 var curChild = el.firstChild;
440 while (curChild) {
441 var nextSibling = curChild.nextSibling;
442
443 var key = getNodeKey(curChild);
444 if (key) {
445 var unmatchedFromEl = fromNodesLookup[key];
446 // if we find a duplicate #id node in cache, replace `el` with cache value
447 // and morph it to the child node.
448 if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
449 curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
450 morphEl(unmatchedFromEl, curChild);
451 } else {
452 handleNodeAdded(curChild);
453 }
454 } else {
455 // recursively call for curChild and it's children to see if we find something in
456 // fromNodesLookup
457 handleNodeAdded(curChild);
458 }
459
460 curChild = nextSibling;
461 }
462 }
463
464 function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
465 // We have processed all of the "to nodes". If curFromNodeChild is
466 // non-null then we still have some from nodes left over that need
467 // to be removed
468 while (curFromNodeChild) {
469 var fromNextSibling = curFromNodeChild.nextSibling;
470 if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {
471 // Since the node is keyed it might be matched up later so we defer
472 // the actual removal to later
473 addKeyedRemoval(curFromNodeKey);
474 } else {
475 // NOTE: we skip nested keyed nodes from being removed since there is
476 // still a chance they will be matched up later
477 removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
478 }
479 curFromNodeChild = fromNextSibling;
480 }
481 }
482
483 function morphEl(fromEl, toEl, childrenOnly) {
484 var toElKey = getNodeKey(toEl);
485
486 if (toElKey) {
487 // If an element with an ID is being morphed then it will be in the final
488 // DOM so clear it out of the saved elements collection
489 delete fromNodesLookup[toElKey];
490 }
491
492 if (!childrenOnly) {
493 // optional
494 var beforeUpdateResult = onBeforeElUpdated(fromEl, toEl);
495 if (beforeUpdateResult === false) {
496 return;
497 } else if (beforeUpdateResult instanceof HTMLElement) {
498 fromEl = beforeUpdateResult;
499 // reindex the new fromEl in case it's not in the same
500 // tree as the original fromEl
501 // (Phoenix LiveView sometimes returns a cloned tree,
502 // but keyed lookups would still point to the original tree)
503 indexTree(fromEl);
504 }
505
506 // update attributes on original DOM element first
507 morphAttrs(fromEl, toEl);
508 // optional
509 onElUpdated(fromEl);
510
511 if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
512 return;
513 }
514 }
515
516 if (fromEl.nodeName !== 'TEXTAREA') {
517 morphChildren(fromEl, toEl);
518 } else {
519 specialElHandlers.TEXTAREA(fromEl, toEl);
520 }
521 }
522
523 function morphChildren(fromEl, toEl) {
524 var skipFrom = skipFromChildren(fromEl, toEl);
525 var curToNodeChild = toEl.firstChild;
526 var curFromNodeChild = fromEl.firstChild;
527 var curToNodeKey;
528 var curFromNodeKey;
529
530 var fromNextSibling;
531 var toNextSibling;
532 var matchingFromEl;
533
534 // walk the children
535 outer: while (curToNodeChild) {
536 toNextSibling = curToNodeChild.nextSibling;
537 curToNodeKey = getNodeKey(curToNodeChild);
538
539 // walk the fromNode children all the way through
540 while (!skipFrom && curFromNodeChild) {
541 fromNextSibling = curFromNodeChild.nextSibling;
542
543 if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
544 curToNodeChild = toNextSibling;
545 curFromNodeChild = fromNextSibling;
546 continue outer;
547 }
548
549 curFromNodeKey = getNodeKey(curFromNodeChild);
550
551 var curFromNodeType = curFromNodeChild.nodeType;
552
553 // this means if the curFromNodeChild doesnt have a match with the curToNodeChild
554 var isCompatible = undefined;
555
556 if (curFromNodeType === curToNodeChild.nodeType) {
557 if (curFromNodeType === ELEMENT_NODE) {
558 // Both nodes being compared are Element nodes
559
560 if (curToNodeKey) {
561 // The target node has a key so we want to match it up with the correct element
562 // in the original DOM tree
563 if (curToNodeKey !== curFromNodeKey) {
564 // The current element in the original DOM tree does not have a matching key so
565 // let's check our lookup to see if there is a matching element in the original
566 // DOM tree
567 if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {
568 if (fromNextSibling === matchingFromEl) {
569 // Special case for single element removals. To avoid removing the original
570 // DOM node out of the tree (since that can break CSS transitions, etc.),
571 // we will instead discard the current node and wait until the next
572 // iteration to properly match up the keyed target element with its matching
573 // element in the original tree
574 isCompatible = false;
575 } else {
576 // We found a matching keyed element somewhere in the original DOM tree.
577 // Let's move the original DOM node into the current position and morph
578 // it.
579
580 // NOTE: We use insertBefore instead of replaceChild because we want to go through
581 // the `removeNode()` function for the node that is being discarded so that
582 // all lifecycle hooks are correctly invoked
583 fromEl.insertBefore(matchingFromEl, curFromNodeChild);
584
585 // fromNextSibling = curFromNodeChild.nextSibling;
586
587 if (curFromNodeKey) {
588 // Since the node is keyed it might be matched up later so we defer
589 // the actual removal to later
590 addKeyedRemoval(curFromNodeKey);
591 } else {
592 // NOTE: we skip nested keyed nodes from being removed since there is
593 // still a chance they will be matched up later
594 removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
595 }
596
597 curFromNodeChild = matchingFromEl;
598 curFromNodeKey = getNodeKey(curFromNodeChild);
599 }
600 } else {
601 // The nodes are not compatible since the "to" node has a key and there
602 // is no matching keyed node in the source tree
603 isCompatible = false;
604 }
605 }
606 } else if (curFromNodeKey) {
607 // The original has a key
608 isCompatible = false;
609 }
610
611 isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
612 if (isCompatible) {
613 // We found compatible DOM elements so transform
614 // the current "from" node to match the current
615 // target DOM node.
616 // MORPH
617 morphEl(curFromNodeChild, curToNodeChild);
618 }
619
620 } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
621 // Both nodes being compared are Text or Comment nodes
622 isCompatible = true;
623 // Simply update nodeValue on the original node to
624 // change the text value
625 if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
626 curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
627 }
628
629 }
630 }
631
632 if (isCompatible) {
633 // Advance both the "to" child and the "from" child since we found a match
634 // Nothing else to do as we already recursively called morphChildren above
635 curToNodeChild = toNextSibling;
636 curFromNodeChild = fromNextSibling;
637 continue outer;
638 }
639
640 // No compatible match so remove the old node from the DOM and continue trying to find a
641 // match in the original DOM. However, we only do this if the from node is not keyed
642 // since it is possible that a keyed node might match up with a node somewhere else in the
643 // target tree and we don't want to discard it just yet since it still might find a
644 // home in the final DOM tree. After everything is done we will remove any keyed nodes
645 // that didn't find a home
646 if (curFromNodeKey) {
647 // Since the node is keyed it might be matched up later so we defer
648 // the actual removal to later
649 addKeyedRemoval(curFromNodeKey);
650 } else {
651 // NOTE: we skip nested keyed nodes from being removed since there is
652 // still a chance they will be matched up later
653 removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
654 }
655
656 curFromNodeChild = fromNextSibling;
657 } // END: while(curFromNodeChild) {}
658
659 // If we got this far then we did not find a candidate match for
660 // our "to node" and we exhausted all of the children "from"
661 // nodes. Therefore, we will just append the current "to" node
662 // to the end
663 if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
664 // MORPH
665 if(!skipFrom){ addChild(fromEl, matchingFromEl); }
666 morphEl(matchingFromEl, curToNodeChild);
667 } else {
668 var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
669 if (onBeforeNodeAddedResult !== false) {
670 if (onBeforeNodeAddedResult) {
671 curToNodeChild = onBeforeNodeAddedResult;
672 }
673
674 if (curToNodeChild.actualize) {
675 curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
676 }
677 addChild(fromEl, curToNodeChild);
678 handleNodeAdded(curToNodeChild);
679 }
680 }
681
682 curToNodeChild = toNextSibling;
683 curFromNodeChild = fromNextSibling;
684 }
685
686 cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
687
688 var specialElHandler = specialElHandlers[fromEl.nodeName];
689 if (specialElHandler) {
690 specialElHandler(fromEl, toEl);
691 }
692 } // END: morphChildren(...)
693
694 var morphedNode = fromNode;
695 var morphedNodeType = morphedNode.nodeType;
696 var toNodeType = toNode.nodeType;
697
698 if (!childrenOnly) {
699 // Handle the case where we are given two DOM nodes that are not
700 // compatible (e.g. <div> --> <span> or <div> --> TEXT)
701 if (morphedNodeType === ELEMENT_NODE) {
702 if (toNodeType === ELEMENT_NODE) {
703 if (!compareNodeNames(fromNode, toNode)) {
704 onNodeDiscarded(fromNode);
705 morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
706 }
707 } else {
708 // Going from an element node to a text node
709 morphedNode = toNode;
710 }
711 } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node
712 if (toNodeType === morphedNodeType) {
713 if (morphedNode.nodeValue !== toNode.nodeValue) {
714 morphedNode.nodeValue = toNode.nodeValue;
715 }
716
717 return morphedNode;
718 } else {
719 // Text node to something else
720 morphedNode = toNode;
721 }
722 }
723 }
724
725 if (morphedNode === toNode) {
726 // The "to node" was not compatible with the "from node" so we had to
727 // toss out the "from node" and use the "to node"
728 onNodeDiscarded(fromNode);
729 } else {
730 if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
731 return;
732 }
733
734 morphEl(morphedNode, toNode, childrenOnly);
735
736 // We now need to loop over any keyed nodes that might need to be
737 // removed. We only do the removal if we know that the keyed node
738 // never found a match. When a keyed node is matched up we remove
739 // it out of fromNodesLookup and we use fromNodesLookup to determine
740 // if a keyed node has been matched up or not
741 if (keyedRemovalList) {
742 for (var i=0, len=keyedRemovalList.length; i<len; i++) {
743 var elToRemove = fromNodesLookup[keyedRemovalList[i]];
744 if (elToRemove) {
745 removeNode(elToRemove, elToRemove.parentNode, false);
746 }
747 }
748 }
749 }
750
751 if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
752 if (morphedNode.actualize) {
753 morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
754 }
755 // If we had to swap out the from node with a new node because the old
756 // node was not compatible with the target node then we need to
757 // replace the old DOM node in the original DOM tree. This is only
758 // possible if the original DOM node was part of a DOM tree which
759 // we know is the case if it has a parent node.
760 fromNode.parentNode.replaceChild(morphedNode, fromNode);
761 }
762
763 return morphedNode;
764 };
765}
766
767var morphdom = morphdomFactory(morphAttrs);
768
769export default morphdom;
public/scripts/extensions/quick-reply/lib/morphdom.LICENSE.txt+0 -21
@@ -1,21 +0,0 @@
1The MIT License (MIT)
2
3Copyright (c) Patrick Steele-Idem <pnidem@gmail.com> (psteeleidem.com)
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
21 \ No newline at end of file \ No newline at end of file
public/scripts/extensions/quick-reply/src/QuickReply.js+1 -2
@@ -1,4 +1,4 @@
1import { hljs } from '../../../../lib.js';1import { hljs, morphdom } from '../../../../lib.js';
2import { POPUP_RESULT, POPUP_TYPE, Popup } from '../../../popup.js';2import { POPUP_RESULT, POPUP_TYPE, Popup } from '../../../popup.js';
3import { setSlashCommandAutoComplete } from '../../../slash-commands.js';3import { setSlashCommandAutoComplete } from '../../../slash-commands.js';
4import { SlashCommandAbortController } from '../../../slash-commands/SlashCommandAbortController.js';4import { SlashCommandAbortController } from '../../../slash-commands/SlashCommandAbortController.js';
@@ -12,7 +12,6 @@ import { SlashCommandParserError } from '../../../slash-commands/SlashCommandPar
12import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';12import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
13import { debounce, delay, getSortableDelay, showFontAwesomePicker } from '../../../utils.js';13import { debounce, delay, getSortableDelay, showFontAwesomePicker } from '../../../utils.js';
14import { log, quickReplyApi, warn } from '../index.js';14import { log, quickReplyApi, warn } from '../index.js';
15import morphdom from '../lib/morphdom-esm.js';
16import { QuickReplyContextLink } from './QuickReplyContextLink.js';15import { QuickReplyContextLink } from './QuickReplyContextLink.js';
17import { QuickReplySet } from './QuickReplySet.js';16import { QuickReplySet } from './QuickReplySet.js';
18import { ContextMenu } from './ui/ctx/ContextMenu.js';17import { ContextMenu } from './ui/ctx/ContextMenu.js';