From 964dcd80281b1448d29e5d4a86b1169487fb6955 Mon Sep 17 00:00:00 2001 From: Patrick Steele-Idem Date: Wed, 10 Aug 2016 15:07:03 -0600 Subject: [PATCH] Updated dist files --- dist/morphdom-umd.js | 84 ++++++++++++++++++++++++++++++++-------- dist/morphdom-umd.min.js | 2 +- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/dist/morphdom-umd.js b/dist/morphdom-umd.js index 5c6363b..1d4a446 100644 --- a/dist/morphdom-umd.js +++ b/dist/morphdom-umd.js @@ -238,18 +238,34 @@ function morphdom(fromNode, toNode, options) { // This object is used as a lookup to quickly find all keyed elements in the original DOM tree. var fromNodesLookup = {}; + var keyedRemovalList; - function walkDiscardedChildNodes(node) { + function addKeyedRemoval(key) { + if (keyedRemovalList) { + keyedRemovalList.push(key); + } else { + keyedRemovalList = [key]; + } + } + + function walkDiscardedChildNodes(node, skipKeyedNodes) { if (node.nodeType === ELEMENT_NODE) { var curChild = node.firstChild; while (curChild) { - if (!getNodeKey(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); + walkDiscardedChildNodes(curChild, skipKeyedNodes); } } @@ -258,7 +274,15 @@ function morphdom(fromNode, toNode, options) { } } - function removeNode(node, parentNode) { + /** + * 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; } @@ -268,7 +292,7 @@ function morphdom(fromNode, toNode, options) { } onNodeDiscarded(node); - walkDiscardedChildNodes(node); + walkDiscardedChildNodes(node, skipKeyedNodes); } // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future @@ -341,6 +365,8 @@ function morphdom(fromNode, toNode, options) { function morphEl(fromEl, toEl, childrenOnly) { var toElKey = getNodeKey(toEl); + var curFromNodeKey; + if (toElKey) { // If an element with an ID is being morphed then it is will be in the final // DOM so clear it out of the saved elements collection @@ -374,7 +400,7 @@ function morphdom(fromNode, toNode, options) { curToNodeKey = getNodeKey(curToNodeChild); while (curFromNodeChild) { - var curFromNodeKey = getNodeKey(curFromNodeChild); + curFromNodeKey = getNodeKey(curFromNodeChild); fromNextSibling = curFromNodeChild.nextSibling; var curFromNodeType = curFromNodeChild.nodeType; @@ -410,8 +436,15 @@ function morphdom(fromNode, toNode, options) { // all lifecycle hooks are correctly invoked fromEl.insertBefore(matchingFromEl, curFromNodeChild); - if (!curFromNodeKey) { - removeNode(curFromNodeChild, fromEl); + 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 */); + } fromNextSibling = curFromNodeChild.nextSibling; curFromNodeChild = matchingFromEl; @@ -457,8 +490,14 @@ function morphdom(fromNode, toNode, options) { // 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) { - removeNode(curFromNodeChild, fromEl); + 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; @@ -487,8 +526,14 @@ function morphdom(fromNode, toNode, options) { // to be removed while (curFromNodeChild) { fromNextSibling = curFromNodeChild.nextSibling; - if (!getNodeKey(curFromNodeChild)) { - removeNode(curFromNodeChild, fromEl); + 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; } @@ -535,10 +580,17 @@ function morphdom(fromNode, toNode, options) { } else { morphEl(morphedNode, toNode, childrenOnly); - for (var k in fromNodesLookup) { - if (fromNodesLookup.hasOwnProperty(k)) { - var elToRemove = fromNodesLookup[k]; - removeNode(elToRemove, elToRemove.parentNode); + // 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=0;--i){attr=attrs[i];attrName=attr.name;attrNamespaceURI=attr.namespaceURI;attrValue=attr.value;if(attrNamespaceURI){attrName=attr.localName||attrName;fromValue=fromNode.getAttributeNS(attrNamespaceURI,attrName);if(fromValue!==attrValue){fromNode.setAttributeNS(attrNamespaceURI,attrName,attrValue)}}else{fromValue=fromNode.getAttribute(attrName);if(fromValue!==attrValue){fromNode.setAttribute(attrName,attrValue)}}}attrs=fromNode.attributes;for(i=attrs.length-1;i>=0;--i){attr=attrs[i];if(attr.specified!==false){attrName=attr.name;attrNamespaceURI=attr.namespaceURI;if(attrNamespaceURI){attrName=attrName=attr.localName||attrName;if(!hasAttributeNS(toNode,attrNamespaceURI,attrName)){fromNode.removeAttributeNS(attrNamespaceURI,attr.localName)}}else{if(!hasAttributeNS(toNode,null,attrName)){fromNode.removeAttribute(attrName)}}}}}function moveChildren(fromEl,toEl){var curChild=fromEl.firstChild;while(curChild){var nextChild=curChild.nextSibling;toEl.appendChild(curChild);curChild=nextChild}return toEl}function defaultGetNodeKey(node){return node.id}function morphdom(fromNode,toNode,options){if(!options){options={}}if(typeof toNode==="string"){if(fromNode.nodeName==="#document"||fromNode.nodeName==="HTML"){var toNodeHtml=toNode;toNode=document.createElement("html");toNode.innerHTML=toNodeHtml}else{toNode=toElement(toNode)}}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 childrenOnly=options.childrenOnly===true;var fromNodesLookup={};function walkDiscardedChildNodes(node){if(node.nodeType===ELEMENT_NODE){var curChild=node.firstChild;while(curChild){if(!getNodeKey(curChild)){onNodeDiscarded(curChild);if(curChild.firstChild){walkDiscardedChildNodes(curChild)}}curChild=curChild.nextSibling}}}function removeNode(node,parentNode){if(onBeforeNodeDiscarded(node)===false){return}if(parentNode){parentNode.removeChild(node)}onNodeDiscarded(node);walkDiscardedChildNodes(node)}function indexTree(node){if(node.nodeType===ELEMENT_NODE){var curChild=node.firstChild;while(curChild){var key=getNodeKey(curChild);if(key){fromNodesLookup[key]=curChild}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(unmatchedFromEl&&compareNodeNames(curChild,unmatchedFromEl)){curChild.parentNode.replaceChild(unmatchedFromEl,curChild);morphEl(unmatchedFromEl,curChild)}}handleNodeAdded(curChild);curChild=nextSibling}}function morphEl(fromEl,toEl,childrenOnly){var toElKey=getNodeKey(toEl);if(toElKey){delete fromNodesLookup[toElKey]}if(!childrenOnly){if(onBeforeElUpdated(fromEl,toEl)===false){return}morphAttrs(fromEl,toEl);onElUpdated(fromEl);if(onBeforeElChildrenUpdated(fromEl,toEl)===false){return}}if(fromEl.nodeName!=="TEXTAREA"){var curToNodeChild=toEl.firstChild;var curFromNodeChild=fromEl.firstChild;var curToNodeKey;var fromNextSibling;var toNextSibling;var matchingFromEl;outer:while(curToNodeChild){toNextSibling=curToNodeChild.nextSibling;curToNodeKey=getNodeKey(curToNodeChild);while(curFromNodeChild){var curFromNodeKey=getNodeKey(curFromNodeChild);fromNextSibling=curFromNodeChild.nextSibling;var curFromNodeType=curFromNodeChild.nodeType;var isCompatible=undefined;if(curFromNodeType===curToNodeChild.nodeType){if(curFromNodeType===ELEMENT_NODE){if(curToNodeKey){if(curToNodeKey!==curFromNodeKey){if(matchingFromEl=fromNodesLookup[curToNodeKey]){if(curFromNodeChild.nextSibling===matchingFromEl){isCompatible=false}else{fromEl.insertBefore(matchingFromEl,curFromNodeChild);if(!curFromNodeKey){removeNode(curFromNodeChild,fromEl)}fromNextSibling=curFromNodeChild.nextSibling;curFromNodeChild=matchingFromEl}}else{isCompatible=false}}}else if(curFromNodeKey){isCompatible=false}isCompatible=isCompatible!==false&&compareNodeNames(curFromNodeChild,curToNodeChild);if(isCompatible){morphEl(curFromNodeChild,curToNodeChild)}}else if(curFromNodeType===TEXT_NODE||curFromNodeType==COMMENT_NODE){isCompatible=true;curFromNodeChild.nodeValue=curToNodeChild.nodeValue}}if(isCompatible){curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling;continue outer}if(!curFromNodeKey){removeNode(curFromNodeChild,fromEl)}curFromNodeChild=fromNextSibling}if(curToNodeKey&&(matchingFromEl=fromNodesLookup[curToNodeKey])&&compareNodeNames(matchingFromEl,curToNodeChild)){fromEl.appendChild(matchingFromEl);morphEl(matchingFromEl,curToNodeChild)}else{if(onBeforeNodeAdded(curToNodeChild)!==false){fromEl.appendChild(curToNodeChild);handleNodeAdded(curToNodeChild)}}curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling}while(curFromNodeChild){fromNextSibling=curFromNodeChild.nextSibling;if(!getNodeKey(curFromNodeChild)){removeNode(curFromNodeChild,fromEl)}curFromNodeChild=fromNextSibling}}var specialElHandler=specialElHandlers[fromEl.nodeName];if(specialElHandler){specialElHandler(fromEl,toEl)}}var morphedNode=fromNode;var morphedNodeType=morphedNode.nodeType;var toNodeType=toNode.nodeType;if(!childrenOnly){if(morphedNodeType===ELEMENT_NODE){if(toNodeType===ELEMENT_NODE){if(!compareNodeNames(fromNode,toNode)){onNodeDiscarded(fromNode);morphedNode=moveChildren(fromNode,createElementNS(toNode.nodeName,toNode.namespaceURI))}}else{morphedNode=toNode}}else if(morphedNodeType===TEXT_NODE||morphedNodeType===COMMENT_NODE){if(toNodeType===morphedNodeType){morphedNode.nodeValue=toNode.nodeValue;return morphedNode}else{morphedNode=toNode}}}if(morphedNode===toNode){onNodeDiscarded(fromNode)}else{morphEl(morphedNode,toNode,childrenOnly);for(var k in fromNodesLookup){if(fromNodesLookup.hasOwnProperty(k)){var elToRemove=fromNodesLookup[k];removeNode(elToRemove,elToRemove.parentNode)}}}if(!childrenOnly&&morphedNode!==fromNode&&fromNode.parentNode){fromNode.parentNode.replaceChild(morphedNode,fromNode)}return morphedNode}module.exports=morphdom;return module.exports}); \ No newline at end of file +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.morphdom=f()}})(function(){var define,module,exports;module={exports:exports={}};"use strict";var range;var testEl=typeof document!=="undefined"?document.body||document.createElement("div"):{};var XHTML="http://www.w3.org/1999/xhtml";var ELEMENT_NODE=1;var TEXT_NODE=3;var COMMENT_NODE=8;var hasAttributeNS;if(testEl.hasAttributeNS){hasAttributeNS=function(el,namespaceURI,name){return el.hasAttributeNS(namespaceURI,name)}}else if(testEl.hasAttribute){hasAttributeNS=function(el,namespaceURI,name){return el.hasAttribute(name)}}else{hasAttributeNS=function(el,namespaceURI,name){return!!el.getAttributeNode(name)}}function toElement(str){if(!range&&document.createRange){range=document.createRange();range.selectNode(document.body)}var fragment;if(range&&range.createContextualFragment){fragment=range.createContextualFragment(str)}else{fragment=document.createElement("body");fragment.innerHTML=str}return fragment.childNodes[0]}var specialElHandlers={OPTION:function(fromEl,toEl){fromEl.selected=toEl.selected;if(fromEl.selected){fromEl.setAttribute("selected","")}else{fromEl.removeAttribute("selected","")}},INPUT:function(fromEl,toEl){fromEl.checked=toEl.checked;if(fromEl.checked){fromEl.setAttribute("checked","")}else{fromEl.removeAttribute("checked")}if(fromEl.value!==toEl.value){fromEl.value=toEl.value}if(!hasAttributeNS(toEl,null,"value")){fromEl.removeAttribute("value")}fromEl.disabled=toEl.disabled;if(fromEl.disabled){fromEl.setAttribute("disabled","")}else{fromEl.removeAttribute("disabled")}},TEXTAREA:function(fromEl,toEl){var newValue=toEl.value;if(fromEl.value!==newValue){fromEl.value=newValue}if(fromEl.firstChild){fromEl.firstChild.nodeValue=newValue}}};function noop(){}var compareNodeNames=function(a,b){return a.nodeName===b.nodeName&&a.namespaceURI===b.namespaceURI};function createElementNS(name,namespaceURI){return!namespaceURI||namespaceURI===XHTML?document.createElement(name):document.createElementNS(namespaceURI,name)}function morphAttrs(fromNode,toNode){var attrs=toNode.attributes;var i;var attr;var attrName;var attrNamespaceURI;var attrValue;var fromValue;for(i=attrs.length-1;i>=0;--i){attr=attrs[i];attrName=attr.name;attrNamespaceURI=attr.namespaceURI;attrValue=attr.value;if(attrNamespaceURI){attrName=attr.localName||attrName;fromValue=fromNode.getAttributeNS(attrNamespaceURI,attrName);if(fromValue!==attrValue){fromNode.setAttributeNS(attrNamespaceURI,attrName,attrValue)}}else{fromValue=fromNode.getAttribute(attrName);if(fromValue!==attrValue){fromNode.setAttribute(attrName,attrValue)}}}attrs=fromNode.attributes;for(i=attrs.length-1;i>=0;--i){attr=attrs[i];if(attr.specified!==false){attrName=attr.name;attrNamespaceURI=attr.namespaceURI;if(attrNamespaceURI){attrName=attrName=attr.localName||attrName;if(!hasAttributeNS(toNode,attrNamespaceURI,attrName)){fromNode.removeAttributeNS(attrNamespaceURI,attr.localName)}}else{if(!hasAttributeNS(toNode,null,attrName)){fromNode.removeAttribute(attrName)}}}}}function moveChildren(fromEl,toEl){var curChild=fromEl.firstChild;while(curChild){var nextChild=curChild.nextSibling;toEl.appendChild(curChild);curChild=nextChild}return toEl}function defaultGetNodeKey(node){return node.id}function morphdom(fromNode,toNode,options){if(!options){options={}}if(typeof toNode==="string"){if(fromNode.nodeName==="#document"||fromNode.nodeName==="HTML"){var toNodeHtml=toNode;toNode=document.createElement("html");toNode.innerHTML=toNodeHtml}else{toNode=toElement(toNode)}}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 childrenOnly=options.childrenOnly===true;var fromNodesLookup={};var keyedRemovalList;function addKeyedRemoval(key){if(keyedRemovalList){keyedRemovalList.push(key)}else{keyedRemovalList=[key]}}function walkDiscardedChildNodes(node,skipKeyedNodes){if(node.nodeType===ELEMENT_NODE){var curChild=node.firstChild;while(curChild){var key=undefined;if(skipKeyedNodes&&(key=getNodeKey(curChild))){addKeyedRemoval(key)}else{onNodeDiscarded(curChild);if(curChild.firstChild){walkDiscardedChildNodes(curChild,skipKeyedNodes)}}curChild=curChild.nextSibling}}}function removeNode(node,parentNode,skipKeyedNodes){if(onBeforeNodeDiscarded(node)===false){return}if(parentNode){parentNode.removeChild(node)}onNodeDiscarded(node);walkDiscardedChildNodes(node,skipKeyedNodes)}function indexTree(node){if(node.nodeType===ELEMENT_NODE){var curChild=node.firstChild;while(curChild){var key=getNodeKey(curChild);if(key){fromNodesLookup[key]=curChild}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(unmatchedFromEl&&compareNodeNames(curChild,unmatchedFromEl)){curChild.parentNode.replaceChild(unmatchedFromEl,curChild);morphEl(unmatchedFromEl,curChild)}}handleNodeAdded(curChild);curChild=nextSibling}}function morphEl(fromEl,toEl,childrenOnly){var toElKey=getNodeKey(toEl);var curFromNodeKey;if(toElKey){delete fromNodesLookup[toElKey]}if(!childrenOnly){if(onBeforeElUpdated(fromEl,toEl)===false){return}morphAttrs(fromEl,toEl);onElUpdated(fromEl);if(onBeforeElChildrenUpdated(fromEl,toEl)===false){return}}if(fromEl.nodeName!=="TEXTAREA"){var curToNodeChild=toEl.firstChild;var curFromNodeChild=fromEl.firstChild;var curToNodeKey;var fromNextSibling;var toNextSibling;var matchingFromEl;outer:while(curToNodeChild){toNextSibling=curToNodeChild.nextSibling;curToNodeKey=getNodeKey(curToNodeChild);while(curFromNodeChild){curFromNodeKey=getNodeKey(curFromNodeChild);fromNextSibling=curFromNodeChild.nextSibling;var curFromNodeType=curFromNodeChild.nodeType;var isCompatible=undefined;if(curFromNodeType===curToNodeChild.nodeType){if(curFromNodeType===ELEMENT_NODE){if(curToNodeKey){if(curToNodeKey!==curFromNodeKey){if(matchingFromEl=fromNodesLookup[curToNodeKey]){if(curFromNodeChild.nextSibling===matchingFromEl){isCompatible=false}else{fromEl.insertBefore(matchingFromEl,curFromNodeChild);if(curFromNodeKey){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}fromNextSibling=curFromNodeChild.nextSibling;curFromNodeChild=matchingFromEl}}else{isCompatible=false}}}else if(curFromNodeKey){isCompatible=false}isCompatible=isCompatible!==false&&compareNodeNames(curFromNodeChild,curToNodeChild);if(isCompatible){morphEl(curFromNodeChild,curToNodeChild)}}else if(curFromNodeType===TEXT_NODE||curFromNodeType==COMMENT_NODE){isCompatible=true;curFromNodeChild.nodeValue=curToNodeChild.nodeValue}}if(isCompatible){curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling;continue outer}if(curFromNodeKey){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}curFromNodeChild=fromNextSibling}if(curToNodeKey&&(matchingFromEl=fromNodesLookup[curToNodeKey])&&compareNodeNames(matchingFromEl,curToNodeChild)){fromEl.appendChild(matchingFromEl);morphEl(matchingFromEl,curToNodeChild)}else{if(onBeforeNodeAdded(curToNodeChild)!==false){fromEl.appendChild(curToNodeChild);handleNodeAdded(curToNodeChild)}}curToNodeChild=toNextSibling;curFromNodeChild=fromNextSibling}while(curFromNodeChild){fromNextSibling=curFromNodeChild.nextSibling;if(curFromNodeKey=getNodeKey(curFromNodeChild)){addKeyedRemoval(curFromNodeKey)}else{removeNode(curFromNodeChild,fromEl,true)}curFromNodeChild=fromNextSibling}}var specialElHandler=specialElHandlers[fromEl.nodeName];if(specialElHandler){specialElHandler(fromEl,toEl)}}var morphedNode=fromNode;var morphedNodeType=morphedNode.nodeType;var toNodeType=toNode.nodeType;if(!childrenOnly){if(morphedNodeType===ELEMENT_NODE){if(toNodeType===ELEMENT_NODE){if(!compareNodeNames(fromNode,toNode)){onNodeDiscarded(fromNode);morphedNode=moveChildren(fromNode,createElementNS(toNode.nodeName,toNode.namespaceURI))}}else{morphedNode=toNode}}else if(morphedNodeType===TEXT_NODE||morphedNodeType===COMMENT_NODE){if(toNodeType===morphedNodeType){morphedNode.nodeValue=toNode.nodeValue;return morphedNode}else{morphedNode=toNode}}}if(morphedNode===toNode){onNodeDiscarded(fromNode)}else{morphEl(morphedNode,toNode,childrenOnly);if(keyedRemovalList){for(var i=0,len=keyedRemovalList.length;i