This commit is contained in:
Kevin Jahns
2018-04-27 18:33:28 +02:00
parent 99f92cb9a0
commit a54d826d6d
20 changed files with 82 additions and 77 deletions

View File

@@ -51,9 +51,9 @@ export default class DomBinding extends Binding {
this.filter = opts.filter || defaultFilter
// set initial value
target.innerHTML = ''
for (let child of type) {
type.forEach(child => {
target.insertBefore(child.toDom(opts.document, opts.hooks, this), null)
}
})
this._typeObserver = typeObserver.bind(this)
this._domObserver = (mutations) => {
domObserver.call(this, mutations, opts.document)

View File

@@ -1,35 +1,37 @@
import { YXmlText, YXmlElement, YXmlHook } from '../../Types/YXml/YXml.js'
import { createAssociation } from './util.js'
import { filterDomAttributes } from './filter.js'
import { createAssociation, domsToTypes } from './util.js'
import { filterDomAttributes, defaultFilter } from './filter.js'
/**
* Creates a Yjs type (YXml) based on the contents of a DOM Element.
*
* @param {Element|TextNode} element The DOM Element
* @param {?Document} _document Optional. Provide the global document object.
* @param {?DomBinding} binding This property should only be set if the type
* is going to be bound with the dom-binding.
* @param {?Document} _document Optional. Provide the global document object
* @param {Hooks} [hooks = {}] Optional. Set of Yjs Hooks
* @param {Filter} [filter=defaultFilter] Optional. Dom element filter
* @param {?DomBinding} binding Warning: This property is for internal use only!
* @return {YXmlElement | YXmlText}
*/
export default function domToType (element, _document = document, binding) {
export default function domToType (element, _document = document, hooks = {}, filter = defaultFilter, binding) {
let type
switch (element.nodeType) {
case _document.ELEMENT_NODE:
let hookName = element.dataset.yjsHook
let hookName = null
let hook
// configure `hookName !== undefined` if element is a hook.
if (hookName !== undefined) {
hook = binding.opts.hooks[hookName]
if (element.hasAttribute('data-yjs-hook')) {
hookName = element.getAttribute('data-yjs-hook')
hook = hooks[hookName]
if (hook === undefined) {
console.error(`Unknown hook "${hookName}". Deleting yjsHook dataset property.`)
delete element.dataset.yjsHook
hookName = undefined
delete element.removeAttribute('data-yjs-hook')
hookName = null
}
}
if (hookName === undefined) {
if (hookName === null) {
// Not a hook
const attrs = filterDomAttributes(element, binding.filter)
const attrs = filterDomAttributes(element, filter)
if (attrs === null) {
type = false
} else {
@@ -37,14 +39,7 @@ export default function domToType (element, _document = document, binding) {
attrs.forEach((val, key) => {
type.setAttribute(key, val)
})
const children = []
for (let elem of element.childNodes) {
const type = domToType(elem, _document, binding)
if (type !== false) {
children.push(type)
}
}
type.insert(0, children)
type.insert(0, domsToTypes(element.childNodes, document, hooks, filter, binding))
}
} else {
// Is a hook

View File

@@ -14,7 +14,7 @@ export function defaultFilter (nodeName, attrs) {
}
/**
*
*
*/
export function filterDomAttributes (dom, filter) {
const attrs = new Map()

View File

@@ -17,7 +17,10 @@ export function iterateUntilUndeleted (item) {
* Removes an association (the information that a DOM element belongs to a
* type).
*
* @private
* @param {DomBinding} domBinding The binding object
* @param {Element} dom The dom that is to be associated with type
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
*
*/
export function removeAssociation (domBinding, dom, type) {
domBinding.domToType.delete(dom)
@@ -28,7 +31,10 @@ export function removeAssociation (domBinding, dom, type) {
* Creates an association (the information that a DOM element belongs to a
* type).
*
* @private
* @param {DomBinding} domBinding The binding object
* @param {Element} dom The dom that is to be associated with type
* @param {YXmlElement|YXmlHook} type The type that is to be associated with dom
*
*/
export function createAssociation (domBinding, dom, type) {
if (domBinding !== undefined) {
@@ -37,6 +43,24 @@ export function createAssociation (domBinding, dom, type) {
}
}
/**
* If oldDom is associated with a type, associate newDom with the type and
* forget about oldDom. If oldDom is not associated with any type, nothing happens.
*
* @param {DomBinding} domBinding The binding object
* @param {Element} oldDom The existing dom
* @param {Element} newDom The new dom object
*/
export function switchAssociation (domBinding, oldDom, newDom) {
if (domBinding !== undefined) {
const type = domBinding.domToType.get(oldDom)
if (type !== undefined) {
removeAssociation(domBinding, oldDom, type)
createAssociation(domBinding, newDom, type)
}
}
}
/**
* Insert Dom Elements after one of the children of this YXmlFragment.
* The Dom elements will be bound to a new YXmlElement and inserted at the
@@ -54,14 +78,19 @@ export function createAssociation (domBinding, dom, type) {
* @private
*/
export function insertDomElementsAfter (type, prev, doms, _document, binding) {
const types = domsToTypes(doms, _document, binding.opts.hooks, binding.filter, binding)
return type.insertAfter(prev, types)
}
export function domsToTypes (doms, _document, hooks, filter, binding) {
const types = []
for (let dom of doms) {
const t = domToType(dom, _document, binding)
const t = domToType(dom, _document, hooks, filter, binding)
if (t !== false) {
types.push(t)
}
}
return type.insertAfter(prev, types)
return types
}
/**