reworking bindings
This commit is contained in:
parent
814af5a3d7
commit
acf443aacb
164
src/Bindings/DomBinding/DomBinding.js
Normal file
164
src/Bindings/DomBinding/DomBinding.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/* global MutationObserver */
|
||||||
|
|
||||||
|
import Binding from './Binding.js'
|
||||||
|
import diff from '../Util/simpleDiff.js'
|
||||||
|
import YXmlFragment from '../../Type/YXml/YXmlFragment.js'
|
||||||
|
import YXmlHook from '../../Type/YXml/YXmlHook.js'
|
||||||
|
|
||||||
|
|
||||||
|
function defaultFilter (nodeName, attrs) {
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilter (target, filter, type) {
|
||||||
|
if (type._deleted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// check if type is a child of this
|
||||||
|
let isChild = false
|
||||||
|
let p = type
|
||||||
|
while (p !== undefined) {
|
||||||
|
if (p === target) {
|
||||||
|
isChild = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p = p._parent
|
||||||
|
}
|
||||||
|
if (!isChild) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// filter attributes
|
||||||
|
const attributes = new Map()
|
||||||
|
if (type.getAttributes !== undefined) {
|
||||||
|
let attrs = type.getAttributes()
|
||||||
|
for (let key in attrs) {
|
||||||
|
attributes.set(key, attrs[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let result = filter(type.nodeName, new Map(attributes))
|
||||||
|
if (result === null) {
|
||||||
|
type._delete(this._y)
|
||||||
|
} else {
|
||||||
|
attributes.forEach((value, key) => {
|
||||||
|
if (!result.has(key)) {
|
||||||
|
type.removeAttribute(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeObserver (events) {
|
||||||
|
this._mutualExclude(() => {
|
||||||
|
reflectChangesOnDom.call(this, events)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function domObserver (mutations) {
|
||||||
|
this._mutualExclude(() => {
|
||||||
|
this._y.transact(() => {
|
||||||
|
let diffChildren = new Set()
|
||||||
|
mutations.forEach(mutation => {
|
||||||
|
const dom = mutation.target
|
||||||
|
const yxml = this.domToYXml.get(dom._yxml)
|
||||||
|
if (yxml == null || yxml.constructor === YXmlHook) {
|
||||||
|
// dom element is filtered
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (mutation.type) {
|
||||||
|
case 'characterData':
|
||||||
|
var change = diff(yxml.toString(), dom.nodeValue)
|
||||||
|
yxml.delete(change.pos, change.remove)
|
||||||
|
yxml.insert(change.pos, change.insert)
|
||||||
|
break
|
||||||
|
case 'attributes':
|
||||||
|
if (yxml.constructor === YXmlFragment) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
let name = mutation.attributeName
|
||||||
|
let val = dom.getAttribute(name)
|
||||||
|
// check if filter accepts attribute
|
||||||
|
let attributes = new Map()
|
||||||
|
attributes.set(name, val)
|
||||||
|
if (this.filter(dom.nodeName, attributes).size > 0 && yxml.constructor !== YXmlFragment) {
|
||||||
|
if (yxml.getAttribute(name) !== val) {
|
||||||
|
if (val == null) {
|
||||||
|
yxml.removeAttribute(name)
|
||||||
|
} else {
|
||||||
|
yxml.setAttribute(name, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'childList':
|
||||||
|
diffChildren.add(mutation.target)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
for (let dom of diffChildren) {
|
||||||
|
if (dom.yOnChildrenChanged !== undefined) {
|
||||||
|
dom.yOnChildrenChanged()
|
||||||
|
}
|
||||||
|
const yxml = this.domToType.get(dom)
|
||||||
|
applyChangesFromDom(dom, yxml)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A binding that binds the children of a YXmlFragment to a DOM element.
|
||||||
|
*
|
||||||
|
* This binding is automatically destroyed when its parent is deleted.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const div = document.createElement('div')
|
||||||
|
* const type = y.define('xml', Y.XmlFragment)
|
||||||
|
* const binding = new Y.QuillBinding(type, div)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export default class DomBinding extends Binding {
|
||||||
|
/**
|
||||||
|
* @param {YXmlFragment} type The bind source. This is the ultimate source of
|
||||||
|
* truth.
|
||||||
|
* @param {Element} target The bind target. Mirrors the target.
|
||||||
|
*/
|
||||||
|
constructor (type, target, opts) {
|
||||||
|
// Binding handles textType as this.type and domTextarea as this.target
|
||||||
|
super(type, target)
|
||||||
|
this.domToType = new Map()
|
||||||
|
this.typeToDom = new Map()
|
||||||
|
this.filter = opts.filter || defaultFilter
|
||||||
|
// set initial value
|
||||||
|
target.innerHTML = ''
|
||||||
|
for (let child of type) {
|
||||||
|
target.insertBefore(child.toDom(this.domToType, this.typeToDom), null)
|
||||||
|
}
|
||||||
|
this._typeObserver = typeObserver.bind(this)
|
||||||
|
this._domObserver = domObserver.bind(this)
|
||||||
|
type.observe(this._typeObserver)
|
||||||
|
this._domObserver = domObserver.bind(this)
|
||||||
|
this._mutationObserver = new MutationObserver(this._domObserver())
|
||||||
|
this._mutationObserver.observe(target, {
|
||||||
|
childList: true,
|
||||||
|
attributes: true,
|
||||||
|
characterData: true,
|
||||||
|
subtree: true
|
||||||
|
})
|
||||||
|
this._beforeTransactionHandler = () => {
|
||||||
|
this._domObserverListener(this._domObserver.takeRecords())
|
||||||
|
}
|
||||||
|
this._y.on('beforeTransaction', this._beforeTransactionHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all properties that are handled by this class
|
||||||
|
*/
|
||||||
|
destroy () {
|
||||||
|
this.domToType = null
|
||||||
|
this.typeToDom = null
|
||||||
|
this.type.unobserve(this._typeObserver)
|
||||||
|
this._mutationObserver.disconnect()
|
||||||
|
this.type._y.off('beforeTransaction', this._beforeTransactionHandler)
|
||||||
|
super.destroy()
|
||||||
|
}
|
||||||
|
}
|
75
src/Bindings/DomBinding/applyChangesFromDom.js
Normal file
75
src/Bindings/DomBinding/applyChangesFromDom.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/Bindings/DomBinding/util.js
Normal file
26
src/Bindings/DomBinding/util.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
export function iterateUntilUndeleted (item) {
|
||||||
|
while (item !== null && item._deleted) {
|
||||||
|
item = item._right
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeAssociation (domBinding, dom, type) {
|
||||||
|
domBinding.domToType.delete(dom)
|
||||||
|
domBinding.typeToDom.delete(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAssociation (domBinding, dom, type) {
|
||||||
|
domBinding.domToType.set(dom, type)
|
||||||
|
domBinding.typeToDom.set(type, dom)
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertNodeHelper (yxml, prevExpectedNode, child) {
|
||||||
|
let insertedNodes = yxml.insertDomElementsAfter(prevExpectedNode, [child])
|
||||||
|
if (insertedNodes.length > 0) {
|
||||||
|
return insertedNodes[0]
|
||||||
|
} else {
|
||||||
|
return prevExpectedNode
|
||||||
|
}
|
||||||
|
}
|
@ -27,12 +27,12 @@ function domObserver () {
|
|||||||
/**
|
/**
|
||||||
* A binding that binds a YText to a dom textarea.
|
* A binding that binds a YText to a dom textarea.
|
||||||
*
|
*
|
||||||
* This binding will automatically be destroyed when it's parent is deleted
|
* This binding is automatically destroyed when its parent is deleted.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const textare = document.createElement('textarea')
|
* const textare = document.createElement('textarea')
|
||||||
* const type = y.define('textarea', Y.Text)
|
* const type = y.define('textarea', Y.Text)
|
||||||
* const binding = new Y.QuillBinding(textarea, type)
|
* const binding = new Y.QuillBinding(type, textarea)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default class TextareaBinding extends Binding {
|
export default class TextareaBinding extends Binding {
|
@ -371,42 +371,7 @@ export default class YXmlFragment extends YArray {
|
|||||||
}
|
}
|
||||||
this._y.on('beforeTransaction', beforeTransactionSelectionFixer)
|
this._y.on('beforeTransaction', beforeTransactionSelectionFixer)
|
||||||
this._y.on('afterTransaction', afterTransactionSelectionFixer)
|
this._y.on('afterTransaction', afterTransactionSelectionFixer)
|
||||||
const applyFilter = (type) => {
|
|
||||||
if (type._deleted) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// check if type is a child of this
|
|
||||||
let isChild = false
|
|
||||||
let p = type
|
|
||||||
while (p !== this._y) {
|
|
||||||
if (p === this) {
|
|
||||||
isChild = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p = p._parent
|
|
||||||
}
|
|
||||||
if (!isChild) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// filter attributes
|
|
||||||
let attributes = new Map()
|
|
||||||
if (type.getAttributes !== undefined) {
|
|
||||||
let attrs = type.getAttributes()
|
|
||||||
for (let key in attrs) {
|
|
||||||
attributes.set(key, attrs[key])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let result = this._domFilter(type.nodeName, new Map(attributes))
|
|
||||||
if (result === null) {
|
|
||||||
type._delete(this._y)
|
|
||||||
} else {
|
|
||||||
attributes.forEach((value, key) => {
|
|
||||||
if (!result.has(key)) {
|
|
||||||
type.removeAttribute(key)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._y.on('beforeObserverCalls', function (y, transaction) {
|
this._y.on('beforeObserverCalls', function (y, transaction) {
|
||||||
// apply dom filter to new and changed types
|
// apply dom filter to new and changed types
|
||||||
transaction.changedTypes.forEach(function (subs, type) {
|
transaction.changedTypes.forEach(function (subs, type) {
|
||||||
@ -417,76 +382,6 @@ export default class YXmlFragment extends YArray {
|
|||||||
})
|
})
|
||||||
transaction.newTypes.forEach(applyFilter)
|
transaction.newTypes.forEach(applyFilter)
|
||||||
})
|
})
|
||||||
// Apply Y.Xml events to dom
|
|
||||||
this.observeDeep(events => {
|
|
||||||
reflectChangesOnDom.call(this, events, _document)
|
|
||||||
})
|
|
||||||
// Apply Dom changes on Y.Xml
|
|
||||||
if (typeof MutationObserver !== 'undefined') {
|
|
||||||
this._beforeTransactionHandler = () => {
|
|
||||||
this._domObserverListener(this._domObserver.takeRecords())
|
|
||||||
}
|
|
||||||
this._y.on('beforeTransaction', this._beforeTransactionHandler)
|
|
||||||
this._domObserverListener = mutations => {
|
|
||||||
this._mutualExclude(() => {
|
|
||||||
this._y.transact(() => {
|
|
||||||
let diffChildren = new Set()
|
|
||||||
mutations.forEach(mutation => {
|
|
||||||
const dom = mutation.target
|
|
||||||
const yxml = dom._yxml
|
|
||||||
if (yxml == null || yxml.constructor === YXmlHook) {
|
|
||||||
// dom element is filtered
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch (mutation.type) {
|
|
||||||
case 'characterData':
|
|
||||||
var change = diff(yxml.toString(), dom.nodeValue)
|
|
||||||
yxml.delete(change.pos, change.remove)
|
|
||||||
yxml.insert(change.pos, change.insert)
|
|
||||||
break
|
|
||||||
case 'attributes':
|
|
||||||
if (yxml.constructor === YXmlFragment) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
let name = mutation.attributeName
|
|
||||||
let val = dom.getAttribute(name)
|
|
||||||
// check if filter accepts attribute
|
|
||||||
let attributes = new Map()
|
|
||||||
attributes.set(name, val)
|
|
||||||
if (this._domFilter(dom.nodeName, attributes).size > 0 && yxml.constructor !== YXmlFragment) {
|
|
||||||
if (yxml.getAttribute(name) !== val) {
|
|
||||||
if (val == null) {
|
|
||||||
yxml.removeAttribute(name)
|
|
||||||
} else {
|
|
||||||
yxml.setAttribute(name, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'childList':
|
|
||||||
diffChildren.add(mutation.target)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
})
|
|
||||||
for (let dom of diffChildren) {
|
|
||||||
if (dom.yOnChildrenChanged !== undefined) {
|
|
||||||
dom.yOnChildrenChanged()
|
|
||||||
}
|
|
||||||
if (dom._yxml != null && dom._yxml !== false) {
|
|
||||||
applyChangesFromDom(dom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this._domObserver = new MutationObserver(this._domObserverListener)
|
|
||||||
this._domObserver.observe(dom, {
|
|
||||||
childList: true,
|
|
||||||
attributes: true,
|
|
||||||
characterData: true,
|
|
||||||
subtree: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return dom
|
return dom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
72
src/Types/YXml/YXmlTreeWalker.js
Normal file
72
src/Types/YXml/YXmlTreeWalker.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import YXmlFragment from './YXmlFragment.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the elements to which a set of CSS queries apply.
|
||||||
|
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* query = '.classSelector'
|
||||||
|
* query = 'nodeSelector'
|
||||||
|
* query = '#idSelector'
|
||||||
|
*
|
||||||
|
* @typedef {string} CSS_Selector
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
|
||||||
|
* position within them.
|
||||||
|
*
|
||||||
|
* Can be created with {@link YXmlFragment#createTreeWalker}
|
||||||
|
*/
|
||||||
|
export default class YXmlTreeWalker {
|
||||||
|
constructor (root, f) {
|
||||||
|
this._filter = f || (() => true)
|
||||||
|
this._root = root
|
||||||
|
this._currentNode = root
|
||||||
|
this._firstCall = true
|
||||||
|
}
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the next node.
|
||||||
|
*
|
||||||
|
* @return {YXmlElement} The next node.
|
||||||
|
*/
|
||||||
|
next () {
|
||||||
|
let n = this._currentNode
|
||||||
|
if (this._firstCall) {
|
||||||
|
this._firstCall = false
|
||||||
|
if (!n._deleted && this._filter(n)) {
|
||||||
|
return { value: n, done: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if (!n._deleted && (n.constructor === YXmlFragment._YXmlElement || n.constructor === YXmlFragment) && n._start !== null) {
|
||||||
|
// walk down in the tree
|
||||||
|
n = n._start
|
||||||
|
} else {
|
||||||
|
// walk right or up in the tree
|
||||||
|
while (n !== this._root) {
|
||||||
|
if (n._right !== null) {
|
||||||
|
n = n._right
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n = n._parent
|
||||||
|
}
|
||||||
|
if (n === this._root) {
|
||||||
|
n = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n === this._root) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} while (n !== null && (n._deleted || !this._filter(n)))
|
||||||
|
this._currentNode = n
|
||||||
|
if (n === null) {
|
||||||
|
return { done: true }
|
||||||
|
} else {
|
||||||
|
return { value: n, done: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -55,88 +55,6 @@ export function fixScrollPosition (scrollElement, fix) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterateUntilUndeleted (item) {
|
|
||||||
while (item !== null && item._deleted) {
|
|
||||||
item = item._right
|
|
||||||
}
|
|
||||||
return item
|
|
||||||
}
|
|
||||||
|
|
||||||
function _insertNodeHelper (yxml, prevExpectedNode, child) {
|
|
||||||
let insertedNodes = yxml.insertDomElementsAfter(prevExpectedNode, [child])
|
|
||||||
if (insertedNodes.length > 0) {
|
|
||||||
return insertedNodes[0]
|
|
||||||
} else {
|
|
||||||
return prevExpectedNode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 function applyChangesFromDom (dom) {
|
|
||||||
const yxml = dom._yxml
|
|
||||||
if (yxml.constructor === YXmlHook) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const y = yxml._y
|
|
||||||
let knownChildren =
|
|
||||||
new Set(
|
|
||||||
Array.prototype.map.call(dom.childNodes, child => child._yxml)
|
|
||||||
.filter(id => id !== undefined)
|
|
||||||
)
|
|
||||||
// 1. Check if any of the nodes was deleted
|
|
||||||
yxml.forEach(function (childType, i) {
|
|
||||||
if (!knownChildren.has(childType)) {
|
|
||||||
childType._delete(y)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 2. iterate
|
|
||||||
let childNodes = dom.childNodes
|
|
||||||
let len = childNodes.length
|
|
||||||
let prevExpectedNode = null
|
|
||||||
let expectedNode = iterateUntilUndeleted(yxml._start)
|
|
||||||
for (let domCnt = 0; domCnt < len; domCnt++) {
|
|
||||||
const child = childNodes[domCnt]
|
|
||||||
const childYXml = child._yxml
|
|
||||||
if (childYXml != null) {
|
|
||||||
if (childYXml === false) {
|
|
||||||
// should be ignored or is going to be deleted
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if (expectedNode !== null) {
|
|
||||||
if (expectedNode !== childYXml) {
|
|
||||||
// 2.3 Not expected node
|
|
||||||
if (childYXml._parent !== this) {
|
|
||||||
// element is going to be deleted by its previous parent
|
|
||||||
child._yxml = null
|
|
||||||
} else {
|
|
||||||
childYXml._delete(y)
|
|
||||||
}
|
|
||||||
prevExpectedNode = _insertNodeHelper(yxml, prevExpectedNode, child)
|
|
||||||
} else {
|
|
||||||
prevExpectedNode = expectedNode
|
|
||||||
expectedNode = iterateUntilUndeleted(expectedNode._right)
|
|
||||||
}
|
|
||||||
// if this is the expected node id, just continue
|
|
||||||
} else {
|
|
||||||
// 2.2 fill _conten with child nodes
|
|
||||||
prevExpectedNode = _insertNodeHelper(yxml, prevExpectedNode, child)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 2.1 A new node was found
|
|
||||||
prevExpectedNode = _insertNodeHelper(yxml, prevExpectedNode, child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reflectChangesOnDom (events, _document) {
|
export function reflectChangesOnDom (events, _document) {
|
||||||
// Make sure that no filtered attributes are applied to the structure
|
// Make sure that no filtered attributes are applied to the structure
|
||||||
|
Loading…
x
Reference in New Issue
Block a user