Implement YXml element hooks (based on _yjsHook property)

This commit is contained in:
Kevin Jahns
2017-11-29 15:08:49 -08:00
parent 7808b143da
commit e70aa09f88
13 changed files with 806 additions and 28 deletions

View File

@@ -2,7 +2,7 @@
import { defaultDomFilter } from './utils.js'
import YMap from '../YMap.js'
import YXmlFragment from './YXmlFragment.js'
import { YXmlFragment } from './y-xml.js'
export default class YXmlElement extends YXmlFragment {
constructor (arg1, arg2, _document) {
@@ -61,7 +61,7 @@ export default class YXmlElement extends YXmlFragment {
if (this.nodeName === null) {
throw new Error('nodeName must be defined!')
}
if (this._domFilter === defaultDomFilter && this._parent instanceof YXmlFragment) {
if (this._domFilter === defaultDomFilter && this._parent._domFilter !== undefined) {
this._domFilter = this._parent._domFilter
}
super._integrate(y)

View File

@@ -4,8 +4,8 @@ import { defaultDomFilter, applyChangesFromDom, reflectChangesOnDom } from './ut
import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js'
import YArray from '../YArray.js'
import YXmlText from './YXmlText.js'
import YXmlEvent from './YXmlEvent.js'
import { YXmlText, YXmlHook } from './y-xml'
import { logID } from '../../MessageHandler/messageToString.js'
import diff from 'fast-diff'
@@ -17,14 +17,17 @@ function domToYXml (parent, doms, _document) {
}
if (parent._domFilter(d.nodeName, new Map()) !== null) {
let type
if (d.nodeType === d.TEXT_NODE) {
const hookName = d._yjsHook
if (hookName !== undefined) {
type = new YXmlHook(hookName, d)
} else if (d.nodeType === d.TEXT_NODE) {
type = new YXmlText(d)
} else if (d.nodeType === d.ELEMENT_NODE) {
type = new YXmlFragment._YXmlElement(d, parent._domFilter, _document)
} else {
throw new Error('Unsupported node!')
}
type.enableSmartScrolling(parent._scrollElement)
// type.enableSmartScrolling(parent._scrollElement)
types.push(type)
} else {
d._yxml = false

View File

@@ -0,0 +1,49 @@
import YMap from '../YMap.js'
import { getHook, addHook } from './hooks.js'
export default class YXmlHook extends YMap {
constructor (hookName, dom) {
super()
this._dom = null
this.hookName = null
if (hookName !== undefined) {
this.hookName = hookName
this._dom = dom
dom._yjsHook = hookName
dom._yxml = this
getHook(hookName).fillType(dom, this)
}
}
getDom (_document) {
_document = _document || document
if (this._dom === null) {
const dom = getHook(this.hookName).createDom(this)
this._dom = dom
dom._yxml = this
dom._yjsHook = this.hookName
}
return this._dom
}
_fromBinary (y, decoder) {
const missing = super._fromBinary(y, decoder)
this.hookName = decoder.readVarString()
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
encoder.writeVarString(this.hookName)
}
_integrate (y) {
if (this.hookName === null) {
throw new Error('hookName must be defined!')
}
super._integrate(y)
}
setDomFilter () {
// TODO: implement new modfilter method!
}
enableSmartScrolling () {
// TODO: implement new smartscrolling method!
}
}
YXmlHook.addHook = addHook

14
src/Type/y-xml/hooks.js Normal file
View File

@@ -0,0 +1,14 @@
const xmlHooks = {}
export function addHook (name, hook) {
xmlHooks[name] = hook
}
export function getHook (name) {
const hook = xmlHooks[name]
if (hook === undefined) {
throw new Error(`The hook "${name}" is not specified! You must not access this hook!`)
}
return hook
}

View File

@@ -1,4 +1,4 @@
import YXmlText from './YXmlText.js'
import { YXmlText, YXmlHook } from './y-xml.js'
export function defaultDomFilter (node, attributes) {
return attributes
@@ -84,6 +84,9 @@ function _insertNodeHelper (yxml, prevExpectedNode, child) {
*/
export function applyChangesFromDom (dom) {
const yxml = dom._yxml
if (yxml.constructor === YXmlHook) {
return
}
const y = yxml._y
let knownChildren =
new Set(
@@ -181,7 +184,15 @@ export function reflectChangesOnDom (events, _document) {
dom.setAttribute(attributeName, value)
}
})
if (event.childListChanged) {
/**
* TODO: instead of chard-checking the types, it would be best to
* specify the type's features. E.g.
* - _yxmlHasAttributes
* - _yxmlHasChildren
* Furthermore, the features shouldn't be encoded in the types,
* only in the attributes (above)
*/
if (event.childListChanged && yxml.constructor !== YXmlHook) {
// create fragment of undeleted nodes
const fragment = _document.createDocumentFragment()
yxml.forEach(function (t) {

View File

@@ -1,9 +1,12 @@
import YXmlFragment from './YXmlFragment.js'
import YXmlElement from './YXmlElement.js'
import YXmlHook from './YXmlHook.js'
export { default as YXmlFragment } from './YXmlFragment.js'
export { default as YXmlElement } from './YXmlElement.js'
export { default as YXmlText } from './YXmlText.js'
export { default as YXmlHook } from './YXmlHook.js'
YXmlFragment._YXmlElement = YXmlElement
YXmlFragment._YXmlHook = YXmlHook