diff --git a/package-lock.json b/package-lock.json
index db34633e8..32bd26997 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -47,6 +47,7 @@
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"moment": "^2.30.1",
+ "morphdom": "^2.7.4",
"multer": "^1.4.5-lts.1",
"node-fetch": "^3.3.2",
"node-persist": "^4.0.1",
@@ -5784,6 +5785,12 @@
"node": "*"
}
},
+ "node_modules/morphdom": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz",
+ "integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
diff --git a/package.json b/package.json
index 7c4afac75..43ae658bc 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"lodash": "^4.17.21",
"mime-types": "^2.1.35",
"moment": "^2.30.1",
+ "morphdom": "^2.7.4",
"multer": "^1.4.5-lts.1",
"node-fetch": "^3.3.2",
"node-persist": "^4.0.1",
diff --git a/public/lib.js b/public/lib.js
index 73d81b109..7c6f6e11d 100644
--- a/public/lib.js
+++ b/public/lib.js
@@ -20,6 +20,7 @@ import moment from 'moment';
import seedrandom from 'seedrandom';
import * as Popper from '@popperjs/core';
import droll from 'droll';
+import morphdom from 'morphdom';
/**
* Expose the libraries to the 'window' object.
@@ -96,6 +97,7 @@ export default {
seedrandom,
Popper,
droll,
+ morphdom,
};
export {
@@ -118,4 +120,5 @@ export {
seedrandom,
Popper,
droll,
+ morphdom,
};
diff --git a/public/scripts/extensions/quick-reply/lib/morphdom-esm.js b/public/scripts/extensions/quick-reply/lib/morphdom-esm.js
deleted file mode 100644
index 7a13a27fc..000000000
--- a/public/scripts/extensions/quick-reply/lib/morphdom-esm.js
+++ /dev/null
@@ -1,769 +0,0 @@
-var DOCUMENT_FRAGMENT_NODE = 11;
-
-function morphAttrs(fromNode, toNode) {
- var toNodeAttrs = toNode.attributes;
- var attr;
- var attrName;
- var attrNamespaceURI;
- var attrValue;
- var fromValue;
-
- // document-fragments dont have attributes so lets not do anything
- if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
- return;
- }
-
- // update attributes on original DOM element
- for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
- attr = toNodeAttrs[i];
- attrName = attr.name;
- attrNamespaceURI = attr.namespaceURI;
- attrValue = attr.value;
-
- if (attrNamespaceURI) {
- attrName = attr.localName || attrName;
- fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
-
- if (fromValue !== attrValue) {
- if (attr.prefix === 'xmlns'){
- attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix
- }
- fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
- }
- } else {
- fromValue = fromNode.getAttribute(attrName);
-
- if (fromValue !== attrValue) {
- fromNode.setAttribute(attrName, attrValue);
- }
- }
- }
-
- // Remove any extra attributes found on the original DOM element that
- // weren't found on the target element.
- var fromNodeAttrs = fromNode.attributes;
-
- for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
- attr = fromNodeAttrs[d];
- attrName = attr.name;
- attrNamespaceURI = attr.namespaceURI;
-
- if (attrNamespaceURI) {
- attrName = attr.localName || attrName;
-
- if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
- fromNode.removeAttributeNS(attrNamespaceURI, attrName);
- }
- } else {
- if (!toNode.hasAttribute(attrName)) {
- fromNode.removeAttribute(attrName);
- }
- }
- }
-}
-
-var range; // Create a range object for efficently rendering strings to elements.
-var NS_XHTML = 'http://www.w3.org/1999/xhtml';
-
-var doc = typeof document === 'undefined' ? undefined : document;
-var HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');
-var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();
-
-function createFragmentFromTemplate(str) {
- var template = doc.createElement('template');
- template.innerHTML = str;
- return template.content.childNodes[0];
-}
-
-function createFragmentFromRange(str) {
- if (!range) {
- range = doc.createRange();
- range.selectNode(doc.body);
- }
-
- var fragment = range.createContextualFragment(str);
- return fragment.childNodes[0];
-}
-
-function createFragmentFromWrap(str) {
- var fragment = doc.createElement('body');
- fragment.innerHTML = str;
- return fragment.childNodes[0];
-}
-
-/**
- * This is about the same
- * var html = new DOMParser().parseFromString(str, 'text/html');
- * return html.body.firstChild;
- *
- * @method toElement
- * @param {String} str
- */
-function toElement(str) {
- str = str.trim();
- if (HAS_TEMPLATE_SUPPORT) {
- // avoid restrictions on content for things like `
Hi
` which
- // createContextualFragment doesn't support
- // support not available in IE
- return createFragmentFromTemplate(str);
- } else if (HAS_RANGE_SUPPORT) {
- return createFragmentFromRange(str);
- }
-
- return createFragmentFromWrap(str);
-}
-
-/**
- * Returns true if two node's names are the same.
- *
- * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same
- * nodeName and different namespace URIs.
- *
- * @param {Element} a
- * @param {Element} b The target element
- * @return {boolean}
- */
-function compareNodeNames(fromEl, toEl) {
- var fromNodeName = fromEl.nodeName;
- var toNodeName = toEl.nodeName;
- var fromCodeStart, toCodeStart;
-
- if (fromNodeName === toNodeName) {
- return true;
- }
-
- fromCodeStart = fromNodeName.charCodeAt(0);
- toCodeStart = toNodeName.charCodeAt(0);
-
- // If the target element is a virtual DOM node or SVG node then we may
- // need to normalize the tag name before comparing. Normal HTML elements that are
- // in the "http://www.w3.org/1999/xhtml"
- // are converted to upper case
- if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower
- return fromNodeName === toNodeName.toUpperCase();
- } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower
- return toNodeName === fromNodeName.toUpperCase();
- } else {
- return false;
- }
-}
-
-/**
- * Create an element, optionally with a known namespace URI.
- *
- * @param {string} name the element name, e.g. 'div' or 'svg'
- * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of
- * its `xmlns` attribute or its inferred namespace.
- *
- * @return {Element}
- */
-function createElementNS(name, namespaceURI) {
- return !namespaceURI || namespaceURI === NS_XHTML ?
- doc.createElement(name) :
- doc.createElementNS(namespaceURI, name);
-}
-
-/**
- * Copies the children of one DOM element to another DOM element
- */
-function moveChildren(fromEl, toEl) {
- var curChild = fromEl.firstChild;
- while (curChild) {
- var nextChild = curChild.nextSibling;
- toEl.appendChild(curChild);
- curChild = nextChild;
- }
- return toEl;
-}
-
-function syncBooleanAttrProp(fromEl, toEl, name) {
- if (fromEl[name] !== toEl[name]) {
- fromEl[name] = toEl[name];
- if (fromEl[name]) {
- fromEl.setAttribute(name, '');
- } else {
- fromEl.removeAttribute(name);
- }
- }
-}
-
-var specialElHandlers = {
- OPTION: function(fromEl, toEl) {
- var parentNode = fromEl.parentNode;
- if (parentNode) {
- var parentName = parentNode.nodeName.toUpperCase();
- if (parentName === 'OPTGROUP') {
- parentNode = parentNode.parentNode;
- parentName = parentNode && parentNode.nodeName.toUpperCase();
- }
- if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {
- if (fromEl.hasAttribute('selected') && !toEl.selected) {
- // Workaround for MS Edge bug where the 'selected' attribute can only be
- // removed if set to a non-empty value:
- // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/
- fromEl.setAttribute('selected', 'selected');
- fromEl.removeAttribute('selected');
- }
- // We have to reset select element's selectedIndex to -1, otherwise setting
- // fromEl.selected using the syncBooleanAttrProp below has no effect.
- // The correct selectedIndex will be set in the SELECT special handler below.
- parentNode.selectedIndex = -1;
- }
- }
- syncBooleanAttrProp(fromEl, toEl, 'selected');
- },
- /**
- * The "value" attribute is special for the element since it sets
- * the initial value. Changing the "value" attribute without changing the
- * "value" property will have no effect since it is only used to the set the
- * initial value. Similar for the "checked" attribute, and "disabled".
- */
- INPUT: function(fromEl, toEl) {
- syncBooleanAttrProp(fromEl, toEl, 'checked');
- syncBooleanAttrProp(fromEl, toEl, 'disabled');
-
- if (fromEl.value !== toEl.value) {
- fromEl.value = toEl.value;
- }
-
- if (!toEl.hasAttribute('value')) {
- fromEl.removeAttribute('value');
- }
- },
-
- TEXTAREA: function(fromEl, toEl) {
- var newValue = toEl.value;
- if (fromEl.value !== newValue) {
- fromEl.value = newValue;
- }
-
- var firstChild = fromEl.firstChild;
- if (firstChild) {
- // Needed for IE. Apparently IE sets the placeholder as the
- // node value and vise versa. This ignores an empty update.
- var oldValue = firstChild.nodeValue;
-
- if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {
- return;
- }
-
- firstChild.nodeValue = newValue;
- }
- },
- SELECT: function(fromEl, toEl) {
- if (!toEl.hasAttribute('multiple')) {
- var selectedIndex = -1;
- var i = 0;
- // We have to loop through children of fromEl, not toEl since nodes can be moved
- // from toEl to fromEl directly when morphing.
- // At the time this special handler is invoked, all children have already been morphed
- // and appended to / removed from fromEl, so using fromEl here is safe and correct.
- var curChild = fromEl.firstChild;
- var optgroup;
- var nodeName;
- while(curChild) {
- nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
- if (nodeName === 'OPTGROUP') {
- optgroup = curChild;
- curChild = optgroup.firstChild;
- } else {
- if (nodeName === 'OPTION') {
- if (curChild.hasAttribute('selected')) {
- selectedIndex = i;
- break;
- }
- i++;
- }
- curChild = curChild.nextSibling;
- if (!curChild && optgroup) {
- curChild = optgroup.nextSibling;
- optgroup = null;
- }
- }
- }
-
- fromEl.selectedIndex = selectedIndex;
- }
- }
-};
-
-var ELEMENT_NODE = 1;
-var DOCUMENT_FRAGMENT_NODE$1 = 11;
-var TEXT_NODE = 3;
-var COMMENT_NODE = 8;
-
-function noop() {}
-
-function defaultGetNodeKey(node) {
- if (node) {
- return (node.getAttribute && node.getAttribute('id')) || node.id;
- }
-}
-
-function morphdomFactory(morphAttrs) {
-
- return function morphdom(fromNode, toNode, options) {
- if (!options) {
- options = {};
- }
-
- if (typeof toNode === 'string') {
- if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {
- var toNodeHtml = toNode;
- toNode = doc.createElement('html');
- toNode.innerHTML = toNodeHtml;
- } else {
- toNode = toElement(toNode);
- }
- } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
- toNode = toNode.firstElementChild;
- }
-
- var getNodeKey = options.getNodeKey || defaultGetNodeKey;
- var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
- var onNodeAdded = options.onNodeAdded || noop;
- var onBeforeElUpdated = options.onBeforeElUpdated || noop;
- var onElUpdated = options.onElUpdated || noop;
- var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
- var onNodeDiscarded = options.onNodeDiscarded || noop;
- var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
- var skipFromChildren = options.skipFromChildren || noop;
- var addChild = options.addChild || function(parent, child){ return parent.appendChild(child); };
- var childrenOnly = options.childrenOnly === true;
-
- // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.
- var fromNodesLookup = Object.create(null);
- var keyedRemovalList = [];
-
- function addKeyedRemoval(key) {
- keyedRemovalList.push(key);
- }
-
- function walkDiscardedChildNodes(node, skipKeyedNodes) {
- if (node.nodeType === ELEMENT_NODE) {
- var curChild = node.firstChild;
- while (curChild) {
-
- var key = undefined;
-
- if (skipKeyedNodes && (key = getNodeKey(curChild))) {
- // If we are skipping keyed nodes then we add the key
- // to a list so that it can be handled at the very end.
- addKeyedRemoval(key);
- } else {
- // Only report the node as discarded if it is not keyed. We do this because
- // at the end we loop through all keyed elements that were unmatched
- // and then discard them in one final pass.
- onNodeDiscarded(curChild);
- if (curChild.firstChild) {
- walkDiscardedChildNodes(curChild, skipKeyedNodes);
- }
- }
-
- curChild = curChild.nextSibling;
- }
- }
- }
-
- /**
- * Removes a DOM node out of the original DOM
- *
- * @param {Node} node The node to remove
- * @param {Node} parentNode The nodes parent
- * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.
- * @return {undefined}
- */
- function removeNode(node, parentNode, skipKeyedNodes) {
- if (onBeforeNodeDiscarded(node) === false) {
- return;
- }
-
- if (parentNode) {
- parentNode.removeChild(node);
- }
-
- onNodeDiscarded(node);
- walkDiscardedChildNodes(node, skipKeyedNodes);
- }
-
- // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future
- // function indexTree(root) {
- // var treeWalker = document.createTreeWalker(
- // root,
- // NodeFilter.SHOW_ELEMENT);
- //
- // var el;
- // while((el = treeWalker.nextNode())) {
- // var key = getNodeKey(el);
- // if (key) {
- // fromNodesLookup[key] = el;
- // }
- // }
- // }
-
- // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future
- //
- // function indexTree(node) {
- // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);
- // var el;
- // while((el = nodeIterator.nextNode())) {
- // var key = getNodeKey(el);
- // if (key) {
- // fromNodesLookup[key] = el;
- // }
- // }
- // }
-
- function indexTree(node) {
- if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
- var curChild = node.firstChild;
- while (curChild) {
- var key = getNodeKey(curChild);
- if (key) {
- fromNodesLookup[key] = curChild;
- }
-
- // Walk recursively
- indexTree(curChild);
-
- curChild = curChild.nextSibling;
- }
- }
- }
-
- indexTree(fromNode);
-
- function handleNodeAdded(el) {
- onNodeAdded(el);
-
- var curChild = el.firstChild;
- while (curChild) {
- var nextSibling = curChild.nextSibling;
-
- var key = getNodeKey(curChild);
- if (key) {
- var unmatchedFromEl = fromNodesLookup[key];
- // if we find a duplicate #id node in cache, replace `el` with cache value
- // and morph it to the child node.
- if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
- curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
- morphEl(unmatchedFromEl, curChild);
- } else {
- handleNodeAdded(curChild);
- }
- } else {
- // recursively call for curChild and it's children to see if we find something in
- // fromNodesLookup
- handleNodeAdded(curChild);
- }
-
- curChild = nextSibling;
- }
- }
-
- function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
- // We have processed all of the "to nodes". If curFromNodeChild is
- // non-null then we still have some from nodes left over that need
- // to be removed
- while (curFromNodeChild) {
- var fromNextSibling = curFromNodeChild.nextSibling;
- if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {
- // Since the node is keyed it might be matched up later so we defer
- // the actual removal to later
- addKeyedRemoval(curFromNodeKey);
- } else {
- // NOTE: we skip nested keyed nodes from being removed since there is
- // still a chance they will be matched up later
- removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
- }
- curFromNodeChild = fromNextSibling;
- }
- }
-
- function morphEl(fromEl, toEl, childrenOnly) {
- var toElKey = getNodeKey(toEl);
-
- if (toElKey) {
- // If an element with an ID is being morphed then it will be in the final
- // DOM so clear it out of the saved elements collection
- delete fromNodesLookup[toElKey];
- }
-
- if (!childrenOnly) {
- // optional
- var beforeUpdateResult = onBeforeElUpdated(fromEl, toEl);
- if (beforeUpdateResult === false) {
- return;
- } else if (beforeUpdateResult instanceof HTMLElement) {
- fromEl = beforeUpdateResult;
- // reindex the new fromEl in case it's not in the same
- // tree as the original fromEl
- // (Phoenix LiveView sometimes returns a cloned tree,
- // but keyed lookups would still point to the original tree)
- indexTree(fromEl);
- }
-
- // update attributes on original DOM element first
- morphAttrs(fromEl, toEl);
- // optional
- onElUpdated(fromEl);
-
- if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
- return;
- }
- }
-
- if (fromEl.nodeName !== 'TEXTAREA') {
- morphChildren(fromEl, toEl);
- } else {
- specialElHandlers.TEXTAREA(fromEl, toEl);
- }
- }
-
- function morphChildren(fromEl, toEl) {
- var skipFrom = skipFromChildren(fromEl, toEl);
- var curToNodeChild = toEl.firstChild;
- var curFromNodeChild = fromEl.firstChild;
- var curToNodeKey;
- var curFromNodeKey;
-
- var fromNextSibling;
- var toNextSibling;
- var matchingFromEl;
-
- // walk the children
- outer: while (curToNodeChild) {
- toNextSibling = curToNodeChild.nextSibling;
- curToNodeKey = getNodeKey(curToNodeChild);
-
- // walk the fromNode children all the way through
- while (!skipFrom && curFromNodeChild) {
- fromNextSibling = curFromNodeChild.nextSibling;
-
- if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
- curToNodeChild = toNextSibling;
- curFromNodeChild = fromNextSibling;
- continue outer;
- }
-
- curFromNodeKey = getNodeKey(curFromNodeChild);
-
- var curFromNodeType = curFromNodeChild.nodeType;
-
- // this means if the curFromNodeChild doesnt have a match with the curToNodeChild
- var isCompatible = undefined;
-
- if (curFromNodeType === curToNodeChild.nodeType) {
- if (curFromNodeType === ELEMENT_NODE) {
- // Both nodes being compared are Element nodes
-
- if (curToNodeKey) {
- // The target node has a key so we want to match it up with the correct element
- // in the original DOM tree
- if (curToNodeKey !== curFromNodeKey) {
- // The current element in the original DOM tree does not have a matching key so
- // let's check our lookup to see if there is a matching element in the original
- // DOM tree
- if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {
- if (fromNextSibling === matchingFromEl) {
- // Special case for single element removals. To avoid removing the original
- // DOM node out of the tree (since that can break CSS transitions, etc.),
- // we will instead discard the current node and wait until the next
- // iteration to properly match up the keyed target element with its matching
- // element in the original tree
- isCompatible = false;
- } else {
- // We found a matching keyed element somewhere in the original DOM tree.
- // Let's move the original DOM node into the current position and morph
- // it.
-
- // NOTE: We use insertBefore instead of replaceChild because we want to go through
- // the `removeNode()` function for the node that is being discarded so that
- // all lifecycle hooks are correctly invoked
- fromEl.insertBefore(matchingFromEl, curFromNodeChild);
-
- // fromNextSibling = curFromNodeChild.nextSibling;
-
- if (curFromNodeKey) {
- // Since the node is keyed it might be matched up later so we defer
- // the actual removal to later
- addKeyedRemoval(curFromNodeKey);
- } else {
- // NOTE: we skip nested keyed nodes from being removed since there is
- // still a chance they will be matched up later
- removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
- }
-
- curFromNodeChild = matchingFromEl;
- curFromNodeKey = getNodeKey(curFromNodeChild);
- }
- } else {
- // The nodes are not compatible since the "to" node has a key and there
- // is no matching keyed node in the source tree
- isCompatible = false;
- }
- }
- } else if (curFromNodeKey) {
- // The original has a key
- isCompatible = false;
- }
-
- isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
- if (isCompatible) {
- // We found compatible DOM elements so transform
- // the current "from" node to match the current
- // target DOM node.
- // MORPH
- morphEl(curFromNodeChild, curToNodeChild);
- }
-
- } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
- // Both nodes being compared are Text or Comment nodes
- isCompatible = true;
- // Simply update nodeValue on the original node to
- // change the text value
- if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
- curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
- }
-
- }
- }
-
- if (isCompatible) {
- // Advance both the "to" child and the "from" child since we found a match
- // Nothing else to do as we already recursively called morphChildren above
- curToNodeChild = toNextSibling;
- curFromNodeChild = fromNextSibling;
- continue outer;
- }
-
- // No compatible match so remove the old node from the DOM and continue trying to find a
- // match in the original DOM. However, we only do this if the from node is not keyed
- // since it is possible that a keyed node might match up with a node somewhere else in the
- // target tree and we don't want to discard it just yet since it still might find a
- // home in the final DOM tree. After everything is done we will remove any keyed nodes
- // that didn't find a home
- if (curFromNodeKey) {
- // Since the node is keyed it might be matched up later so we defer
- // the actual removal to later
- addKeyedRemoval(curFromNodeKey);
- } else {
- // NOTE: we skip nested keyed nodes from being removed since there is
- // still a chance they will be matched up later
- removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
- }
-
- curFromNodeChild = fromNextSibling;
- } // END: while(curFromNodeChild) {}
-
- // If we got this far then we did not find a candidate match for
- // our "to node" and we exhausted all of the children "from"
- // nodes. Therefore, we will just append the current "to" node
- // to the end
- if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
- // MORPH
- if(!skipFrom){ addChild(fromEl, matchingFromEl); }
- morphEl(matchingFromEl, curToNodeChild);
- } else {
- var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
- if (onBeforeNodeAddedResult !== false) {
- if (onBeforeNodeAddedResult) {
- curToNodeChild = onBeforeNodeAddedResult;
- }
-
- if (curToNodeChild.actualize) {
- curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
- }
- addChild(fromEl, curToNodeChild);
- handleNodeAdded(curToNodeChild);
- }
- }
-
- curToNodeChild = toNextSibling;
- curFromNodeChild = fromNextSibling;
- }
-
- cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
-
- var specialElHandler = specialElHandlers[fromEl.nodeName];
- if (specialElHandler) {
- specialElHandler(fromEl, toEl);
- }
- } // END: morphChildren(...)
-
- var morphedNode = fromNode;
- var morphedNodeType = morphedNode.nodeType;
- var toNodeType = toNode.nodeType;
-
- if (!childrenOnly) {
- // Handle the case where we are given two DOM nodes that are not
- // compatible (e.g.
--> or
--> TEXT)
- if (morphedNodeType === ELEMENT_NODE) {
- if (toNodeType === ELEMENT_NODE) {
- if (!compareNodeNames(fromNode, toNode)) {
- onNodeDiscarded(fromNode);
- morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
- }
- } else {
- // Going from an element node to a text node
- morphedNode = toNode;
- }
- } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node
- if (toNodeType === morphedNodeType) {
- if (morphedNode.nodeValue !== toNode.nodeValue) {
- morphedNode.nodeValue = toNode.nodeValue;
- }
-
- return morphedNode;
- } else {
- // Text node to something else
- morphedNode = toNode;
- }
- }
- }
-
- if (morphedNode === toNode) {
- // The "to node" was not compatible with the "from node" so we had to
- // toss out the "from node" and use the "to node"
- onNodeDiscarded(fromNode);
- } else {
- if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
- return;
- }
-
- morphEl(morphedNode, toNode, childrenOnly);
-
- // We now need to loop over any keyed nodes that might need to be
- // removed. We only do the removal if we know that the keyed node
- // never found a match. When a keyed node is matched up we remove
- // it out of fromNodesLookup and we use fromNodesLookup to determine
- // if a keyed node has been matched up or not
- if (keyedRemovalList) {
- for (var i=0, len=keyedRemovalList.length; i (psteeleidem.com)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
\ No newline at end of file
diff --git a/public/scripts/extensions/quick-reply/src/QuickReply.js b/public/scripts/extensions/quick-reply/src/QuickReply.js
index b3fff3781..ff7d5121f 100644
--- a/public/scripts/extensions/quick-reply/src/QuickReply.js
+++ b/public/scripts/extensions/quick-reply/src/QuickReply.js
@@ -1,4 +1,4 @@
-import { hljs } from '../../../../lib.js';
+import { hljs, morphdom } from '../../../../lib.js';
import { POPUP_RESULT, POPUP_TYPE, Popup } from '../../../popup.js';
import { setSlashCommandAutoComplete } from '../../../slash-commands.js';
import { SlashCommandAbortController } from '../../../slash-commands/SlashCommandAbortController.js';
@@ -12,7 +12,6 @@ import { SlashCommandParserError } from '../../../slash-commands/SlashCommandPar
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
import { debounce, delay, getSortableDelay, showFontAwesomePicker } from '../../../utils.js';
import { log, quickReplyApi, warn } from '../index.js';
-import morphdom from '../lib/morphdom-esm.js';
import { QuickReplyContextLink } from './QuickReplyContextLink.js';
import { QuickReplySet } from './QuickReplySet.js';
import { ContextMenu } from './ui/ctx/ContextMenu.js';