in packages/eui/scripts/jest/polyfills/mutation_observer.js [346:460]
var _findMutations = function (node, old) {
var $kids = node.childNodes;
var $oldkids = old.kids;
var klen = $kids.length;
// $oldkids will be undefined for text and comment nodes
var olen = $oldkids ? $oldkids.length : 0;
// if (!olen && !klen) return; // both empty; clearly no changes
// we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused)
// map of checked element of ids to prevent registering the same conflict twice
var map;
// array of potential conflicts (ie nodes that may have been re arranged)
var conflicts;
var id; // element id from getElementId helper
var idx; // index of a moved or inserted element
var oldstruct;
// current and old nodes
var $cur;
var $old;
// track the number of added nodes so we can resolve conflicts more accurately
var numAddedNodes = 0;
// iterate over both old and current child nodes at the same time
var i = 0;
var j = 0;
// while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;)
while (i < klen || j < olen) {
// current and old nodes at the indexs
$cur = $kids[i];
oldstruct = $oldkids[j];
$old = oldstruct && oldstruct.node;
if ($cur === $old) { // expected case - optimized for this case
// check attributes as specified by config
if (config.attr && oldstruct.attr) { /* oldstruct.attr instead of textnode check */
_this.findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter);
}
// check character data if node is a comment or textNode and it's being observed
if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) {
mutations.push(new MutationRecord({
type: 'characterData',
target: $cur
}));
}
// resolve conflicts; it will be undefined if there are no conflicts - otherwise an array
if (conflicts)
_resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes);
// recurse on next level of children. Avoids the recursive call when there are no children left to iterate
if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length))
_findMutations($cur, oldstruct);
i++;
j++;
}
else { // (uncommon case) lookahead until they are the same again or the end of children
dirty = true;
if (!map) { // delayed initalization (big perf benefit)
map = {};
conflicts = [];
}
if ($cur) {
// check id is in the location map otherwise do a indexOf search
if (!(map[id = Util.getElementId($cur)])) { // to prevent double checking
// mark id as found
map[id] = true;
// custom indexOf using comparitor checking oldkids[i].node === $cur
if ((idx = Util.indexOfCustomNode($oldkids, $cur, j)) === -1) {
if (config.kids) {
mutations.push(new MutationRecord({
type: 'childList',
target: node,
addedNodes: [$cur],
nextSibling: $cur.nextSibling,
previousSibling: $cur.previousSibling
}));
numAddedNodes++;
}
}
else {
conflicts.push({
i: i,
j: idx
});
}
}
i++;
}
if ($old &&
// special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case
$old !== $kids[i]) {
if (!(map[id = Util.getElementId($old)])) {
map[id] = true;
if ((idx = Util.indexOf($kids, $old, i)) === -1) {
if (config.kids) {
mutations.push(new MutationRecord({
type: 'childList',
target: old.node,
removedNodes: [$old],
nextSibling: $oldkids[j + 1],
previousSibling: $oldkids[j - 1]
}));
numAddedNodes--;
}
}
else {
conflicts.push({
i: idx,
j: j
});
}
}
j++;
}
} // end uncommon case
} // end loop
// resolve any remaining conflicts
if (conflicts)
_resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes);
};