|
|
- /*! (c) 2018 Andrea Giammarchi (ISC) */
-
- import {
- eqeq, identity, indexOf, isReversed, next,
- append, remove,
- smartDiff
- } from './utils.js';
-
- const domdiff = (
- parentNode, // where changes happen
- currentNodes, // Array of current items/nodes
- futureNodes, // Array of future items/nodes
- options // optional object with one of the following properties
- // before: domNode
- // compare(generic, generic) => true if same generic
- // node(generic) => Node
- ) => {
- if (!options)
- options = {};
-
- const compare = options.compare || eqeq;
- const get = options.node || identity;
- const before = options.before == null ? null : get(options.before, 0);
-
- const currentLength = currentNodes.length;
- let currentEnd = currentLength;
- let currentStart = 0;
-
- let futureEnd = futureNodes.length;
- let futureStart = 0;
-
- // common prefix
- while (
- currentStart < currentEnd &&
- futureStart < futureEnd &&
- compare(currentNodes[currentStart], futureNodes[futureStart])
- ) {
- currentStart++;
- futureStart++;
- }
-
- // common suffix
- while (
- currentStart < currentEnd &&
- futureStart < futureEnd &&
- compare(currentNodes[currentEnd - 1], futureNodes[futureEnd - 1])
- ) {
- currentEnd--;
- futureEnd--;
- }
-
- const currentSame = currentStart === currentEnd;
- const futureSame = futureStart === futureEnd;
-
- // same list
- if (currentSame && futureSame)
- return futureNodes;
-
- // only stuff to add
- if (currentSame && futureStart < futureEnd) {
- append(
- get,
- parentNode,
- futureNodes,
- futureStart,
- futureEnd,
- next(get, currentNodes, currentStart, currentLength, before)
- );
- return futureNodes;
- }
-
- // only stuff to remove
- if (futureSame && currentStart < currentEnd) {
- remove(
- get,
- currentNodes,
- currentStart,
- currentEnd
- );
- return futureNodes;
- }
-
- const currentChanges = currentEnd - currentStart;
- const futureChanges = futureEnd - futureStart;
- let i = -1;
-
- // 2 simple indels: the shortest sequence is a subsequence of the longest
- if (currentChanges < futureChanges) {
- i = indexOf(
- futureNodes,
- futureStart,
- futureEnd,
- currentNodes,
- currentStart,
- currentEnd,
- compare
- );
- // inner diff
- if (-1 < i) {
- append(
- get,
- parentNode,
- futureNodes,
- futureStart,
- i,
- get(currentNodes[currentStart], 0)
- );
- append(
- get,
- parentNode,
- futureNodes,
- i + currentChanges,
- futureEnd,
- next(get, currentNodes, currentEnd, currentLength, before)
- );
- return futureNodes;
- }
- }
- /* istanbul ignore else */
- else if (futureChanges < currentChanges) {
- i = indexOf(
- currentNodes,
- currentStart,
- currentEnd,
- futureNodes,
- futureStart,
- futureEnd,
- compare
- );
- // outer diff
- if (-1 < i) {
- remove(
- get,
- currentNodes,
- currentStart,
- i
- );
- remove(
- get,
- currentNodes,
- i + futureChanges,
- currentEnd
- );
- return futureNodes;
- }
- }
-
- // common case with one replacement for many nodes
- // or many nodes replaced for a single one
- /* istanbul ignore else */
- if ((currentChanges < 2 || futureChanges < 2)) {
- append(
- get,
- parentNode,
- futureNodes,
- futureStart,
- futureEnd,
- get(currentNodes[currentStart], 0)
- );
- remove(
- get,
- currentNodes,
- currentStart,
- currentEnd
- );
- return futureNodes;
- }
-
- // the half match diff part has been skipped in petit-dom
- // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L391-L397
- // accordingly, I think it's safe to skip in here too
- // if one day it'll come out like the speediest thing ever to do
- // then I might add it in here too
-
- // Extra: before going too fancy, what about reversed lists ?
- // This should bail out pretty quickly if that's not the case.
- if (
- currentChanges === futureChanges &&
- isReversed(
- futureNodes,
- futureEnd,
- currentNodes,
- currentStart,
- currentEnd,
- compare
- )
- ) {
- append(
- get,
- parentNode,
- futureNodes,
- futureStart,
- futureEnd,
- next(get, currentNodes, currentEnd, currentLength, before)
- );
- return futureNodes;
- }
-
- // last resort through a smart diff
- smartDiff(
- get,
- parentNode,
- futureNodes,
- futureStart,
- futureEnd,
- futureChanges,
- currentNodes,
- currentStart,
- currentEnd,
- currentChanges,
- currentLength,
- compare,
- before
- );
-
- return futureNodes;
- };
-
- export default domdiff;
|