Home Reference Source

src/Bindings/DomBinding/applyChangesFromDom.js

import YXmlHook from '../../YXml/YXmlHook.js'
import {
  iterateUntilUndeleted,
  removeAssociation,
  insertNodeHelper } from './util.js'

/*
 * 1. Check if any of the nodes was deleted
 * 2. Iterate over the children.
 *    2.1 If a node exists without _yxml property, insert a new node
 *    2.2 If _contents.length < dom.childNodes.length, fill the
 *        rest of _content with childNodes
 *    2.3 If a node was moved, delete it and
 *       recreate a new yxml element that is bound to that node.
 *       You can detect that a node was moved because expectedId
 *       !== actualId in the list
 */
export default function applyChangesFromDom (dom, yxml) {
  if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
    return
  }
  const y = yxml._y
  const knownChildren = new Set()
  for (let child in dom.childNodes) {
    const type = knownChildren.get(child)
    if (type !== undefined && type !== false) {
      knownChildren.add(type)
    }
  }
  // 1. Check if any of the nodes was deleted
  yxml.forEach(function (childType) {
    if (knownChildren.has(childType) === false) {
      childType._delete(y)
    }
  })
  // 2. iterate
  const childNodes = dom.childNodes
  const len = childNodes.length
  let prevExpectedType = null
  let expectedType = iterateUntilUndeleted(yxml._start)
  for (let domCnt = 0; domCnt < len; domCnt++) {
    const childNode = childNodes[domCnt]
    const childType = this.domToYXml.get(childNode)
    if (childType != null) {
      if (childType === false) {
        // should be ignored or is going to be deleted
        continue
      }
      if (expectedType !== null) {
        if (expectedType !== childType) {
          // 2.3 Not expected node
          if (childType._parent !== yxml) {
            // child was moved from another parent
            // childType is going to be deleted by its previous parent
            removeAssociation(this, childNode, this.domToYXml(childNode))
          } else {
            // child was moved to a different position.
            childType._delete(y)
          }
          prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
        } else {
          // Found expected node
          prevExpectedType = expectedType
          expectedType = iterateUntilUndeleted(expectedType._right)
        }
      } else {
        // 2.2 Fill _content with child nodes
        prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
      }
    } else {
      // 2.1 A new node was found
      prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
    }
  }
}