implemented xml type for new event system

This commit is contained in:
Kevin Jahns
2017-10-19 17:36:28 +02:00
parent 1311c7a0d8
commit 755c9eb16e
38 changed files with 1272 additions and 322 deletions

View File

@@ -2,6 +2,16 @@ import Type from '../Struct/Type.js'
import ItemJSON from '../Struct/ItemJSON.js'
export default class YArray extends Type {
_callObserver () {
this._eventHandler.callEventListeners({})
}
get (i) {
// TODO: This can be improved!
return this.toArray()[i]
}
toArray () {
return this.map(c => c)
}
toJSON () {
return this.map(c => {
if (c instanceof Type) {
@@ -11,6 +21,7 @@ export default class YArray extends Type {
return c.toString()
}
}
return c
})
}
map (f) {
@@ -25,11 +36,15 @@ export default class YArray extends Type {
let n = this._start
while (n !== null) {
if (!n._deleted) {
const content = n._content
const contentLen = content.length
for (let i = 0; i < contentLen; i++) {
pos++
f(content[i], pos, this)
if (n instanceof Type) {
f(n, pos++, this)
} else {
const content = n._content
const contentLen = content.length
for (let i = 0; i < contentLen; i++) {
pos++
f(content[i], pos, this)
}
}
}
n = n._right
@@ -42,14 +57,14 @@ export default class YArray extends Type {
if (!n._deleted) {
length += n._length
}
n = n._next
n = n._right
}
return length
}
[Symbol.iterator] () {
return {
next: function () {
while (this._item !== null && (this._item._deleted || this._item._content.length <= this._itemElement)) {
while (this._item !== null && (this._item._deleted || this._item._length <= this._itemElement)) {
// item is deleted or itemElement does not exist (is deleted)
this._item = this._item._right
this._itemElement = 0
@@ -58,11 +73,16 @@ export default class YArray extends Type {
return {
done: true
}
}
let content
if (this._item instanceof Type) {
content = this._item
} else {
return {
value: [this._count, this._item._content[this._itemElement++]],
done: false
}
content = this._item._content[this._itemElement++]
}
return {
value: [this._count, content],
done: false
}
},
_item: this._start,
@@ -71,68 +91,99 @@ export default class YArray extends Type {
}
}
delete (pos, length = 1) {
let item = this._start
let count = 0
while (item !== null && length > 0) {
if (count < pos && pos < count + item._length) {
const diffDel = pos - count
item = item
._splitAt(this._y, diffDel)
._splitAt(this._y, length)
length -= item._length
item._delete(this._y)
this._y.transact(() => {
let item = this._start
let count = 0
while (item !== null && length > 0) {
if (count <= pos && pos < count + item._length) {
const diffDel = pos - count
item = item._splitAt(this._y, diffDel)
item._splitAt(this._y, length)
length -= item._length
item._delete(this._y)
}
if (!item._deleted) {
count += item._length
}
item = item._right
}
if (!item._deleted) {
count += item._length
if (length > 0) {
throw new Error('Delete exceeds the range of the YArray')
}
})
}
insertAfter (left, content) {
const apply = () => {
let right
if (left === null) {
right = this._start
} else {
right = left._right
}
let prevJsonIns = null
for (let i = 0; i < content.length; i++) {
let c = content[i]
if (c instanceof Type) {
if (prevJsonIns !== null) {
if (this._y !== null) {
prevJsonIns._integrate(this._y)
}
left = prevJsonIns
prevJsonIns = null
}
c._origin = left
c._left = left
c._right = right
c._right_origin = right
c._parent = this
if (this._y !== null) {
c._integrate(this._y)
} else if (left === null) {
this._start = c
}
left = c
} else {
if (prevJsonIns === null) {
prevJsonIns = new ItemJSON()
prevJsonIns._origin = left
prevJsonIns._left = left
prevJsonIns._right = right
prevJsonIns._right_origin = right
prevJsonIns._parent = this
prevJsonIns._content = []
}
prevJsonIns._content.push(c)
}
}
if (prevJsonIns !== null && this._y !== null) {
prevJsonIns._integrate(this._y)
}
item = item._right
}
if (length > 0) {
throw new Error('Delete exceeds the range of the YArray')
if (this._y !== null) {
this._y.transact(apply)
} else {
apply()
}
return content
}
insert (pos, content) {
let left = this._start
let right = null
let left = null
let right = this._start
let count = 0
while (left !== null) {
if (count <= pos && pos < count + left._content.length) {
right = left._splitAt(this.y, pos - count)
while (right !== null) {
if (count <= pos && pos < count + right._length) {
right = right._splitAt(this._y, pos - count)
left = right._left
break
}
count += left._length
left = left.right
count += right._length
left = right
right = right._right
}
if (pos > count) {
throw new Error('Position exceeds array range!')
}
let prevJsonIns = null
for (let i = 0; i < content.length; i++) {
let c = content[i]
if (c instanceof Type) {
if (prevJsonIns === null) {
prevJsonIns._integrate(this._y)
prevJsonIns = null
}
c._left = left
c._origin = left
c._right = right
c._parent = this
} else {
if (prevJsonIns === null) {
prevJsonIns = new ItemJSON()
prevJsonIns._origin = left
prevJsonIns._left = left
prevJsonIns._right = right
prevJsonIns._parent = this
prevJsonIns._content = []
}
prevJsonIns._content.push(c)
}
}
if (prevJsonIns !== null) {
prevJsonIns._integrate(this._y)
}
this.insertAfter(left, content)
}
_logString () {
let s = super._logString()

View File

@@ -3,6 +3,11 @@ import Item from '../Struct/Item.js'
import ItemJSON from '../Struct/ItemJSON.js'
export default class YMap extends Type {
_callObserver (parentSub) {
this._eventHandler.callEventListeners({
name: parentSub
})
}
toJSON () {
const map = {}
for (let [key, item] of this._map) {
@@ -22,22 +27,40 @@ export default class YMap extends Type {
}
return map
}
delete (key) {
this._y.transact(() => {
let c = this._map.get(key)
if (c !== undefined) {
c._delete(this._y)
}
})
}
set (key, value) {
let old = this._map.get(key)
let v
if (value instanceof Item) {
v = value
} else {
let v = new ItemJSON()
v._content = JSON.stringify(value)
}
v._right = old
v._parent = this
v._parentSub = key
v._integrate()
this._y.transact(() => {
const old = this._map.get(key) || null
if (old !== null) {
old._delete(this._y)
}
let v
if (value instanceof Item) {
v = value
} else {
v = new ItemJSON()
v._content = [value]
}
v._right = old
v._right_origin = old
v._parent = this
v._parentSub = key
v._integrate(this._y)
})
return value
}
get (key) {
let v = this._map.get(key)
if (v === undefined || v._deleted) {
return undefined
}
if (v instanceof Type) {
return v
} else {

View File

@@ -1,4 +1,53 @@
import ItemString from '../Struct/ItemString.js'
import YArray from './YArray.js'
export default class YText extends YArray {
constructor (string) {
super()
if (typeof string === 'string') {
const start = new ItemString()
start._parent = this
start._content = string
this._start = start
}
}
toString () {
const strBuilder = []
let n = this._start
while (n !== null) {
if (!n._deleted) {
strBuilder.push(n._content)
}
n = n._right
}
return strBuilder.join('')
}
insert (pos, text) {
this._y.transact(() => {
let left = null
let right = this._start
let count = 0
while (right !== null) {
if (count <= pos && pos < count + right._length) {
right = right._splitAt(this._y, pos - count)
left = right._left
break
}
count += right._length
left = right
right = right._right
}
if (pos > count) {
throw new Error('Position exceeds array range!')
}
let item = new ItemString()
item._origin = left
item._left = left
item._right = right
item._right_origin = right
item._parent = this
item._content = text
item._integrate(this._y)
})
}
}

View File

@@ -1,10 +0,0 @@
import YArray from './YArray.js'
export default class YXml extends YArray {
setDomFilter () {
// TODO
}
toString () {
return '<nodeName></nodeName>'
}
}

View File

@@ -0,0 +1,117 @@
/* global MutationObserver */
// import diff from 'fast-diff'
import { defaultDomFilter } from './utils.js'
import YMap from '../YMap.js'
import YXmlFragment from './YXmlFragment.js'
export default class YXmlElement extends YXmlFragment {
constructor (arg1, arg2) {
super()
this.nodeName = null
this._scrollElement = null
if (typeof arg1 === 'string') {
this.nodeName = arg1.toUpperCase()
} else if (arg1 != null && arg1.nodeType != null && arg1.nodeType === document.ELEMENT_NODE) {
this.nodeName = arg1.nodeName
this._setDom(arg1)
} else {
this.nodeName = 'UNDEFINED'
}
if (typeof arg2 === 'function') {
this._domFilter = arg2
}
}
_setDom (dom) {
if (this._dom != null) {
throw new Error('Only call this method if you know what you are doing ;)')
} else if (dom.__yxml != null) { // TODO do i need to check this? - no.. but for dev purps..
throw new Error('Already bound to an YXml type')
} else {
dom.__yxml = this
// tag is already set in constructor
// set attributes
let attrNames = []
for (let i = 0; i < dom.attributes.length; i++) {
attrNames.push(dom.attributes[i].name)
}
attrNames = this._domFilter(dom, attrNames)
for (let i = 0; i < attrNames.length; i++) {
let attrName = attrNames[i]
let attrValue = dom.getAttribute(attrName)
this.setAttribute(attrName, attrValue)
}
this.insertDomElements(0, Array.prototype.slice.call(dom.childNodes))
if (MutationObserver != null) {
this._dom = this._bindToDom(dom)
}
return dom
}
}
_fromBinary (y, decoder) {
const missing = super._fromBinary(y, decoder)
this.nodeName = decoder.readVarString()
return missing
}
_toBinary (encoder) {
super._toBinary(encoder)
encoder.writeVarString(this.nodeName)
}
_integrate (y) {
if (this.nodeName === null) {
throw new Error('nodeName must be defined!')
}
if (this._domFilter === defaultDomFilter && this._parent instanceof YXmlFragment) {
this._domFilter = this._parent._domFilter
}
super._integrate(y)
}
toString () {
const attrs = this.getAttributes()
const stringBuilder = []
for (let key in attrs) {
stringBuilder.push(key + '="' + attrs[key] + '"')
}
const nodeName = this.nodeName.toLocaleLowerCase()
const attrsString = stringBuilder.length > 0 ? ' ' + stringBuilder.join(' ') : ''
return `<${nodeName}${attrsString}>${super.toString()}</${nodeName}>`
}
removeAttribute () {
return YMap.prototype.delete.apply(this, arguments)
}
setAttribute () {
return YMap.prototype.set.apply(this, arguments)
}
getAttribute () {
return YMap.prototype.get.apply(this, arguments)
}
getAttributes () {
const obj = {}
for (let [key, value] of this._map) {
obj[key] = value._content[0]
}
return obj
}
getDom () {
let dom = this._dom
if (dom == null) {
dom = document.createElement(this.nodeName)
dom.__yxml = this
let attrs = this.getAttributes()
for (let key in attrs) {
dom.setAttribute(key, attrs[key])
}
this.forEach(yxml => {
dom.appendChild(yxml.getDom())
})
if (MutationObserver !== null) {
this._dom = this._bindToDom(dom)
}
}
return dom
}
}

View File

@@ -0,0 +1,167 @@
/* global MutationObserver */
import { defaultDomFilter, applyChangesFromDom, reflectChangesOnDom } from './utils.js'
import YArray from '../YArray.js'
import YXmlText from './YXmlText.js'
function domToYXml (parent, doms) {
const types = []
doms.forEach(d => {
if (d.__yxml != null && d.__yxml !== false) {
d.__yxml._unbindFromDom()
}
if (parent._domFilter(d, []) !== null) {
let type
if (d.nodeType === document.TEXT_NODE) {
type = new YXmlText(d)
} else if (d.nodeType === document.ELEMENT_NODE) {
type = new YXmlFragment._YXmlElement(d, parent._domFilter)
} else {
throw new Error('Unsupported node!')
}
type.enableSmartScrolling(parent._scrollElement)
types.push(type)
} else {
d.__yxml = false
}
})
return types
}
export default class YXmlFragment extends YArray {
constructor () {
super()
this._dom = null
this._domFilter = defaultDomFilter
this._domObserver = null
// this function makes sure that either the
// dom event is executed, or the yjs observer is executed
var token = true
this._mutualExclude = f => {
if (token) {
token = false
try {
f()
} catch (e) {
console.error(e)
}
this._domObserver.takeRecords()
token = true
}
}
// Apply Y.Xml events to dom
this.observe(reflectChangesOnDom)
}
enableSmartScrolling (scrollElement) {
this._scrollElement = scrollElement
this.forEach(xml => {
xml.enableSmartScrolling(scrollElement)
})
}
setDomFilter (f) {
this._domFilter = f
this.forEach(xml => {
xml.setDomFilter(f)
})
}
_callObserver (parentSub) {
let event
if (parentSub !== null) {
event = {
type: 'attributeChanged',
name: parentSub,
value: this.getAttribute(parentSub),
target: this
}
} else {
event = {
type: 'contentChanged',
target: this
}
}
this._eventHandler.callEventListeners(event)
}
toString () {
return this.map(xml => xml.toString()).join('')
}
_unbindFromDom () {
if (this._domObserver != null) {
this._domObserver.disconnect()
this._domObserver = null
}
if (this._dom != null) {
this._dom.__yxml = null
this._dom = null
}
}
insertDomElementsAfter (prev, doms) {
const types = domToYXml(this, doms)
return this.insertAfter(prev, types)
}
insertDomElements (pos, doms) {
const types = domToYXml(this, doms)
this.insert(pos, types)
return types.length
}
bindToDom (dom) {
if (this._dom != null) {
this._unbindFromDom()
}
if (dom.__yxml != null) {
dom.__yxml._unbindFromDom()
}
if (MutationObserver == null) {
throw new Error('Not able to bind to a DOM element, because MutationObserver is not available!')
}
dom.innerHTML = ''
this.forEach(t => {
dom.insertBefore(t.getDom(), null)
})
this._dom = dom
dom.__yxml = this
this._bindToDom(dom)
}
// binds to a dom element
// Only call if dom and YXml are isomorph
_bindToDom (dom) {
this._domObserverListener = mutations => {
this._mutualExclude(() => {
let diffChildren = false
mutations.forEach(mutation => {
if (mutation.type === 'attributes') {
let name = mutation.attributeName
// check if filter accepts attribute
if (this._domFilter(this._dom, [name]).length > 0) {
var val = mutation.target.getAttribute(name)
if (this.getAttribute(name) !== val) {
if (val == null) {
this.removeAttribute(name)
} else {
this.setAttribute(name, val)
}
}
}
} else if (mutation.type === 'childList') {
diffChildren = true
}
})
if (diffChildren) {
applyChangesFromDom(this)
}
})
}
this._domObserver = new MutationObserver(this._domObserverListener)
const observeOptions = { childList: true }
if (this instanceof YXmlFragment._YXmlElement) {
observeOptions.attributes = true
}
this._domObserver.observe(dom, observeOptions)
return dom
}
_beforeChange () {
if (this._domObserver != null) {
this._domObserverListener(this._domObserver.takeRecords())
}
}
}

157
src/Type/y-xml/YXmlText.js Normal file
View File

@@ -0,0 +1,157 @@
/* global getSelection, MutationObserver */
import diff from 'fast-diff'
import YText from '../YText.js'
import { getAnchorViewPosition, fixScrollPosition, getBoundingClientRect } from './utils.js'
function fixPosition (event, pos) {
if (event.index <= pos) {
if (event.type === 'delete') {
return pos - Math.min(pos - event.index, event.length)
} else {
return pos + 1
}
} else {
return pos
}
}
export default class YXmlText extends YText {
constructor (arg1) {
let dom = null
let initialText = null
if (arg1 != null && arg1.nodeType === document.TEXT_NODE) {
dom = arg1
initialText = dom.nodeValue
}
super(initialText)
this._dom = null
this._domObserver = null
this._domObserverListener = null
this._scrollElement = null
if (dom !== null) {
this._setDom(arg1)
}
var token = true
this._mutualExclude = f => {
if (token) {
token = false
try {
f()
} catch (e) {
console.error(e)
}
this._domObserver.takeRecords()
token = true
}
}
this.observe(event => {
if (this._dom != null) {
const dom = this._dom
this._mutualExclude(() => {
let selection = null
let shouldUpdateSelection = false
let anchorNode = null
let anchorOffset = null
let focusNode = null
let focusOffset = null
if (typeof getSelection !== 'undefined') {
selection = getSelection()
if (selection.anchorNode === dom) {
anchorNode = selection.anchorNode
anchorOffset = fixPosition(event, selection.anchorOffset)
shouldUpdateSelection = true
}
if (selection.focusNode === dom) {
focusNode = selection.focusNode
focusOffset = fixPosition(event, selection.focusOffset)
shouldUpdateSelection = true
}
}
let anchorViewPosition = getAnchorViewPosition(this._scrollElement)
let anchorViewFix
if (anchorViewPosition !== null && (anchorViewPosition.anchor !== null || getBoundingClientRect(this._dom).top <= 0)) {
anchorViewFix = anchorViewPosition
} else {
anchorViewFix = null
}
dom.nodeValue = this.toString()
fixScrollPosition(this._scrollElement, anchorViewFix)
if (shouldUpdateSelection) {
selection.setBaseAndExtent(
anchorNode || selection.anchorNode,
anchorOffset || selection.anchorOffset,
focusNode || selection.focusNode,
focusOffset || selection.focusOffset
)
}
})
}
})
}
setDomFilter () {}
enableSmartScrolling (scrollElement) {
this._scrollElement = scrollElement
}
_setDom (dom) {
if (this._dom != null) {
this._unbindFromDom()
}
if (dom.__yxml != null) {
dom.__yxml._unbindFromDom()
}
// set marker
this._dom = dom
dom.__yxml = this
if (typeof MutationObserver === 'undefined') {
return
}
this._domObserverListener = () => {
this._mutualExclude(() => {
var diffs = diff(this.toString(), dom.nodeValue)
var pos = 0
for (var i = 0; i < diffs.length; i++) {
var d = diffs[i]
if (d[0] === 0) { // EQUAL
pos += d[1].length
} else if (d[0] === -1) { // DELETE
this.delete(pos, d[1].length)
} else { // INSERT
this.insert(pos, d[1])
pos += d[1].length
}
}
})
}
this._domObserver = new MutationObserver(this._domObserverListener)
this._domObserver.observe(this._dom, { characterData: true })
}
getDom () {
if (this._dom == null) {
const dom = document.createTextNode(this.toString())
this._setDom(dom)
return dom
}
return this._dom
}
_beforeChange () {
if (this._domObserver != null && this._y !== null) { // TODO: do I need th y condition
this._domObserverListener(this._domObserver.takeRecords())
}
}
_delete (y, createDelete) {
this._unbindFromDom()
super._delete(y, createDelete)
}
_unbindFromDom () {
if (this._domObserver != null) {
this._domObserver.disconnect()
this._domObserver = null
}
if (this._dom != null) {
this._dom.__yxml = null
this._dom = null
}
}
}

206
src/Type/y-xml/utils.js Normal file
View File

@@ -0,0 +1,206 @@
export function defaultDomFilter (node, attributes) {
return attributes
}
export function getAnchorViewPosition (scrollElement) {
if (scrollElement == null) {
return null
}
let anchor = document.getSelection().anchorNode
if (anchor != null) {
let top = getBoundingClientRect(anchor).top
if (top >= 0 && top <= document.documentElement.clientHeight) {
return {
anchor: anchor,
top: top
}
}
}
return {
anchor: null,
scrollTop: scrollElement.scrollTop,
scrollHeight: scrollElement.scrollHeight
}
}
// get BoundingClientRect that works on text nodes
export function getBoundingClientRect (element) {
if (element.getBoundingClientRect != null) {
// is element node
return element.getBoundingClientRect()
} else {
// is text node
if (element.parentNode == null) {
// range requires that text nodes have a parent
let span = document.createElement('span')
span.appendChild(element)
}
let range = document.createRange()
range.selectNode(element)
return range.getBoundingClientRect()
}
}
export function fixScrollPosition (scrollElement, fix) {
if (scrollElement !== null && fix !== null) {
if (fix.anchor === null) {
if (scrollElement.scrollTop === fix.scrollTop) {
scrollElement.scrollTop = scrollElement.scrollHeight - fix.scrollHeight
}
} else {
scrollElement.scrollTop = getBoundingClientRect(fix.anchor).top - fix.top
}
}
}
function iterateUntilUndeleted (item) {
while (item !== null && item._deleted) {
item = item._right
}
return item
}
/*
* 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 (yxml) {
const y = yxml._y
let knownChildren =
new Set(
Array.prototype.map.call(yxml._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 = yxml._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 = yxml.insertDomElementsAfter(prevExpectedNode, [child])[0]
} 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 = yxml.insertDomElementsAfter(prevExpectedNode, [child])[0]
}
} else {
// 2.1 A new node was found
prevExpectedNode = yxml.insertDomElementsAfter(prevExpectedNode, [child])[0]
}
}
}
export function reflectChangesOnDom (event) {
const yxml = event.target
const dom = yxml._dom
if (dom != null) {
yxml._mutualExclude(() => {
// TODO: do this once before applying stuff
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
if (event.type === 'attributeChanged') {
if (event.value === undefined) {
dom.removeAttribute(event.name)
} else {
dom.setAttribute(event.name, event.value)
}
} else if (event.type === 'contentChanged') {
// create fragment of undeleted nodes
const fragment = document.createDocumentFragment()
yxml.forEach(function (t) {
fragment.append(t.getDom())
})
// remove remainding nodes
let lastChild = dom.lastChild
while (lastChild !== null) {
dom.removeChild(lastChild)
lastChild = dom.lastChild
}
// insert fragment of undeleted nodes
dom.append(fragment)
}
/* TODO: smartscrolling
.. else if (event.type === 'childInserted' || event.type === 'insert') {
let nodes = event.values
for (let i = nodes.length - 1; i >= 0; i--) {
let node = nodes[i]
node.setDomFilter(yxml._domFilter)
node.enableSmartScrolling(yxml._scrollElement)
let dom = node.getDom()
let fixPosition = null
let nextDom = null
if (yxml._content.length > event.index + i + 1) {
nextDom = yxml.get(event.index + i + 1).getDom()
}
yxml._dom.insertBefore(dom, nextDom)
if (anchorViewPosition === null) {
// nop
} else if (anchorViewPosition.anchor !== null) {
// no scrolling when current selection
if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
fixPosition = anchorViewPosition
}
} else if (getBoundingClientRect(dom).top <= 0) {
// adjust scrolling if modified element is out of view,
// there is no anchor element, and the browser did not adjust scrollTop (this is checked later)
fixPosition = anchorViewPosition
}
fixScrollPosition(yxml._scrollElement, fixPosition)
}
} else if (event.type === 'childRemoved' || event.type === 'delete') {
for (let i = event.values.length - 1; i >= 0; i--) {
let dom = event.values[i]._dom
let fixPosition = null
if (anchorViewPosition === null) {
// nop
} else if (anchorViewPosition.anchor !== null) {
// no scrolling when current selection
if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
fixPosition = anchorViewPosition
}
} else if (getBoundingClientRect(dom).top <= 0) {
// adjust scrolling if modified element is out of view,
// there is no anchor element, and the browser did not adjust scrollTop (this is checked later)
fixPosition = anchorViewPosition
}
dom.remove()
fixScrollPosition(yxml._scrollElement, fixPosition)
}
}
*/
})
}
}

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

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