all files / src/updateChildren/ updateChildren.ts

100% Statements 64/64
96.15% Branches 25/26
100% Functions 2/2
100% Lines 63/63
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                    62× 62× 62× 62×     62× 62× 62× 62×     62×   62× 192× 23×   169×   160× 72× 72× 72×     88× 15× 15× 15×     73× 19× 19× 19× 19×     54× 16× 16× 16× 16×       38×     38×   38×       33×   33×     33×   33×   33×           62× 51×   51×           11× 11×             10× 10× 10×   10× 84×   84× 78×     10×    
import { ElementVNode } from '../'
import { ModuleCallbacks } from '../modules/ModuleCallbacks'
import { addVNodes } from '../addVNodes'
import { createElement } from '../createElement'
import { patchVNode } from '../patchVNode'
import { removeVNodes } from '../removeVNodes'
import { vNodesAreEqual } from '../helpers'
 
export function updateChildren(
  parentElement: Element,
  formerChildren: Array<ElementVNode>,
  children: Array<ElementVNode>,
  moduleCallbacks: ModuleCallbacks,
  insertedVNodeQueue: Array<ElementVNode>)
{
  // indexes
  let formerStartIndex = 0
  let startIndex = 0
  let formerEndIndex = formerChildren.length - 1
  let endIndex = children.length - 1
 
  // VNodes
  let formerStartVNode = formerChildren[formerStartIndex]
  let startVNode = children[startIndex]
  let formerEndVNode = formerChildren[formerEndIndex]
  let endVNode = children[endIndex]
 
  // an object mapping keys to indexes in formerChildren array
  let mappedKeyToFormerIndex: any
 
  while (formerStartIndex <= formerEndIndex && startIndex <= endIndex) {
    if (!formerStartVNode)
      formerStartVNode = formerChildren[++formerStartIndex]
 
    else if (!formerEndVNode)
      formerEndVNode = formerChildren[--formerEndIndex]
 
    else if (vNodesAreEqual(formerStartVNode, startVNode)) {
      patchVNode(formerStartVNode, startVNode, moduleCallbacks, insertedVNodeQueue)
      formerStartVNode = formerChildren[++formerStartIndex]
      startVNode = children[++startIndex]
    }
 
    else if (vNodesAreEqual(formerEndVNode, endVNode)) {
      patchVNode(formerEndVNode, endVNode, moduleCallbacks, insertedVNodeQueue)
      formerEndVNode = formerChildren[--formerEndIndex]
      endVNode = children[--endIndex]
    }
 
    else if (vNodesAreEqual(formerStartVNode, endVNode)) {
      patchVNode(formerStartVNode, endVNode, moduleCallbacks, insertedVNodeQueue)
      parentElement.insertBefore(formerStartVNode.element, formerEndVNode.element.nextSibling)
      formerStartVNode = formerChildren[++formerStartIndex]
      endVNode = children[--endIndex]
    }
 
    else if (vNodesAreEqual(formerEndVNode, startVNode)) {
      patchVNode(formerEndVNode, startVNode, moduleCallbacks, insertedVNodeQueue)
      parentElement.insertBefore(formerEndVNode.element, formerStartVNode.element)
      formerEndVNode = formerChildren[--formerEndIndex]
      startVNode = children[++startIndex]
    }
 
    else {
      if (!mappedKeyToFormerIndex) mappedKeyToFormerIndex =
        mapKeyToFormerIndex(formerChildren, formerStartIndex, formerEndIndex)
 
      const formerIndexKey = mappedKeyToFormerIndex[startVNode.key as string | number]
 
      if (!formerIndexKey) { // new element
        const element = createElement(startVNode, moduleCallbacks, insertedVNodeQueue).element
        parentElement.insertBefore(element, formerStartVNode.element)
        startVNode = children[++startIndex]
      }
 
      else {
        const reorderableVNode = formerChildren[formerIndexKey]
 
        patchVNode(reorderableVNode, startVNode, moduleCallbacks, insertedVNodeQueue)
 
        // WARNING: hack for performance optimization
        formerChildren[formerIndexKey] = void 0 as any
 
        parentElement.insertBefore(reorderableVNode.element, formerStartVNode.element)
 
        startVNode = children[++startIndex]
      }
 
    }
  }
 
  if (formerStartIndex > formerEndIndex) {
    const referenceNode = children[endIndex + 1] ? children[endIndex + 1].element : null
 
    addVNodes(
      parentElement, referenceNode,
      children, startIndex, endIndex,
      moduleCallbacks, insertedVNodeQueue,
    )
  }
  else Eif (startIndex > endIndex)
    removeVNodes(parentElement, formerChildren, formerStartIndex, formerEndIndex, moduleCallbacks)
}
 
function mapKeyToFormerIndex(
  children: Array<ElementVNode>,
  startIndex: number,
  endIndex: number): any
{
  let index: number = startIndex
  const map: any = {}
  let key: any
 
  for (; index <= endIndex; ++index) {
    key = children[index].key
 
    if (key)
      map[key] = index
  }
 
  return map
}