UNPKG

patience-diff

Version:
82 lines (70 loc) 3.13 kB
// var diffSwap = require('patience-diff-swap') var remove = require('remove-array-items') var diff = require('patience-diff') var assert = require('assert') var morphNode = require('./lib/morph') function Morph () { this.results = [] this.swaps = [] this.from = [] this.to = [] this.index = -1 } Morph.prototype.morph = function (from, to) { assert.equal(typeof from, 'object', 'nanomorph: from should be an object') assert.equal(typeof to, 'object', 'nanomorph: to should be an object') this._morph(from, to) } // Look at a single node, and figure out what to do. Morph.prototype._morph = function (from, to) { if (!from) return to // {from} does not exist, return {to}. else if (!to) return null // {to} does not exist, return null. else if (to.isSameNode && to.isSameNode(from)) return from // if .isSameNode() checks out, return {from}. else if (to.tagName !== from.tagName) return to // {from, to} are different DOM types, return {to}. else return morphNode(from, to) && this._children(from, to) && from // {from, to} are same DOM types, copy over attributes. } Morph.prototype._children = function (from, to) { if (!from.firstChild && to.firstChild) { while (to.firstChild) to.removeChild(to.lastChild) // {from} has no childNodes, delete all {to} childNodes. } else if (!to.firstChild && from.firstChild) { while (from.firstChild) to.appendChild(from.firstChild) // {to} has no childNodes, copy over all {from} childNodes. } else { this._morphChildNodes(to, from) // {from, to} have childNodes, apply Myers diff reorder. } } Morph.prototype._morphChildNodes = function (from, to) { this.results.length = 0 this.swaps.length = 0 this.from.length = 0 this.to.length = 0 this.index = -1 var fromNode, toNode, fromPosition, toPosition var fromTmpId = 0 var toTmpId = 0 // Walk over the elements in the array, and write their id to the array // if a new child element is encountered, increment a tmp id. var max = Math.max(this.from.length, this.to.length) for (var i = 0; i < max; i++) { fromNode = from.childNodes[i] if (fromNode) this.from.push(fromNode.id || fromTmpId++) toNode = to.childNodes[i] if (toNode) this.to.push(toNode.id || toTmpId++) } // Calculate the shortest diff, and mark all points where we can swap instead. diff(this.from, this.to, this.result) // diffSwap(this.results, this.swaps) if (this.swaps.length > 0) this.index = this.swaps[0] // Apply the diffs generated from the previous step. for (var j = 0, len = this.results.length; j < len; j += 2) { fromPosition = this.results[j] toPosition = this.results[j + 1] if (fromPosition === -1) { remove(this.from, toPosition, 1) } else if (fromPosition === toPosition) { this._morph(this.from[fromPosition], this.to[toPosition]) } else { this.to[toPosition].insertBefore(this.from[fromPosition]) } } }