observeDeep receives array of events

This commit is contained in:
Kevin Jahns 2017-11-07 22:44:43 -08:00
parent c453593ee7
commit e5f289506f
6 changed files with 126 additions and 91 deletions

View File

@ -40,10 +40,16 @@ export default class Type extends Item {
this._deepEventHandler = new EventHandler() this._deepEventHandler = new EventHandler()
} }
_callEventHandler (event) { _callEventHandler (event) {
const changedParentTypes = this._y._transaction.changedParentTypes
this._eventHandler.callEventListeners(event) this._eventHandler.callEventListeners(event)
let type = this let type = this
while (type !== this._y) { while (type !== this._y) {
type._deepEventHandler.callEventListeners(event) let events = changedParentTypes.get(type)
if (events === undefined) {
events = []
changedParentTypes.set(type, events)
}
events.push(event)
type = type._parent type = type._parent
} }
} }

View File

@ -9,6 +9,7 @@ export default class Transaction {
this.changedTypes = new Map() this.changedTypes = new Map()
this.deletedStructs = new Set() this.deletedStructs = new Set()
this.beforeState = new Map() this.beforeState = new Map()
this.changedParentTypes = new Map()
} }
} }

View File

@ -98,6 +98,14 @@ export default class YMap extends Type {
return v._content[v._content.length - 1] return v._content[v._content.length - 1]
} }
} }
has (key) {
let v = this._map.get(key)
if (v === undefined || v._deleted) {
return false
} else {
return true
}
}
_logString () { _logString () {
const left = this._left !== null ? this._left._lastId : null const left = this._left !== null ? this._left._lastId : null
const origin = this._origin !== null ? this._origin._lastId : null const origin = this._origin !== null ? this._origin._lastId : null

View File

@ -135,90 +135,92 @@ export function applyChangesFromDom (dom) {
} }
} }
export function reflectChangesOnDom (event) { export function reflectChangesOnDom (events) {
const yxml = event.target this._mutualExclude(() => {
const dom = yxml._dom events.forEach(event => {
if (dom != null) { const yxml = event.target
this._mutualExclude(() => { const dom = yxml._dom
// TODO: do this once before applying stuff if (dom != null) {
// let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement) // TODO: do this once before applying stuff
if (yxml.constructor === YXmlText) { // let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
yxml._dom.nodeValue = yxml.toString() if (yxml.constructor === YXmlText) {
} else { yxml._dom.nodeValue = yxml.toString()
// update attributes } else {
event.attributesChanged.forEach(attributeName => { // update attributes
const value = yxml.getAttribute(attributeName) event.attributesChanged.forEach(attributeName => {
if (value === undefined) { const value = yxml.getAttribute(attributeName)
dom.removeAttribute(attributeName) if (value === undefined) {
} else { dom.removeAttribute(attributeName)
dom.setAttribute(attributeName, value) } else {
} dom.setAttribute(attributeName, value)
}) }
if (event.childListChanged) {
// create fragment of undeleted nodes
const fragment = document.createDocumentFragment()
yxml.forEach(function (t) {
fragment.append(t.getDom())
}) })
// remove remainding nodes if (event.childListChanged) {
let lastChild = dom.lastChild // create fragment of undeleted nodes
while (lastChild !== null) { const fragment = document.createDocumentFragment()
dom.removeChild(lastChild) yxml.forEach(function (t) {
lastChild = dom.lastChild 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)
} }
// insert fragment of undeleted nodes
dom.append(fragment)
} }
} /* TODO: smartscrolling
/* TODO: smartscrolling .. else if (event.type === 'childInserted' || event.type === 'insert') {
.. else if (event.type === 'childInserted' || event.type === 'insert') { let nodes = event.values
let nodes = event.values for (let i = nodes.length - 1; i >= 0; i--) {
for (let i = nodes.length - 1; i >= 0; i--) { let node = nodes[i]
let node = nodes[i] node.setDomFilter(yxml._domFilter)
node.setDomFilter(yxml._domFilter) node.enableSmartScrolling(yxml._scrollElement)
node.enableSmartScrolling(yxml._scrollElement) let dom = node.getDom()
let dom = node.getDom() let fixPosition = null
let fixPosition = null let nextDom = null
let nextDom = null if (yxml._content.length > event.index + i + 1) {
if (yxml._content.length > event.index + i + 1) { nextDom = yxml.get(event.index + i + 1).getDom()
nextDom = yxml.get(event.index + i + 1).getDom() }
} yxml._dom.insertBefore(dom, nextDom)
yxml._dom.insertBefore(dom, nextDom) if (anchorViewPosition === null) {
if (anchorViewPosition === null) { // nop
// nop } else if (anchorViewPosition.anchor !== null) {
} else if (anchorViewPosition.anchor !== null) { // no scrolling when current selection
// no scrolling when current selection if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
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 fixPosition = anchorViewPosition
} }
} else if (getBoundingClientRect(dom).top <= 0) { fixScrollPosition(yxml._scrollElement, fixPosition)
// 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--) {
} else if (event.type === 'childRemoved' || event.type === 'delete') { let dom = event.values[i]._dom
for (let i = event.values.length - 1; i >= 0; i--) { let fixPosition = null
let dom = event.values[i]._dom if (anchorViewPosition === null) {
let fixPosition = null // nop
if (anchorViewPosition === null) { } else if (anchorViewPosition.anchor !== null) {
// nop // no scrolling when current selection
} else if (anchorViewPosition.anchor !== null) { if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
// no scrolling when current selection fixPosition = anchorViewPosition
if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) { }
} 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 fixPosition = anchorViewPosition
} }
} else if (getBoundingClientRect(dom).top <= 0) { dom.remove()
// adjust scrolling if modified element is out of view, fixScrollPosition(yxml._scrollElement, fixPosition)
// there is no anchor element, and the browser did not adjust scrollTop (this is checked later)
fixPosition = anchorViewPosition
} }
dom.remove()
fixScrollPosition(yxml._scrollElement, fixPosition)
} }
*/
} }
*/
}) })
} })
} }

View File

@ -2,26 +2,32 @@
export default class YEvent { export default class YEvent {
constructor (target) { constructor (target) {
this.target = target this.target = target
this._path = null
} }
get path () { get path () {
const path = [] if (this._path !== null) {
let type = this.target return this._path
const y = type._y } else {
while (type._parent !== y) { const path = []
let parent = type._parent let type = this.target
if (type._parentSub !== null) { const y = type._y
path.push(type._parentSub) while (type._parent !== y) {
} else { let parent = type._parent
// parent is array-ish if (type._parentSub !== null) {
for (let [i, child] of parent) { path.push(type._parentSub)
if (child === type) { } else {
path.push(i) // parent is array-ish
break for (let [i, child] of parent) {
if (child === type) {
path.push(i)
break
}
} }
} }
type = parent
} }
type = parent this._path = path
return path
} }
return path
} }
} }

View File

@ -55,7 +55,19 @@ export default class Y extends NamedEventHandler {
if (initialCall) { if (initialCall) {
// emit change events on changed types // emit change events on changed types
this._transaction.changedTypes.forEach(function (subs, type) { this._transaction.changedTypes.forEach(function (subs, type) {
type._callObserver(subs, remote) if (!type._deleted) {
type._callObserver(subs, remote)
}
})
this._transaction.changedParentTypes.forEach(function (events, type) {
if (!type._deleted) {
events = events.filter(event =>
!event.target._deleted
)
// we don't have to check for events.length
// because there is no way events is empty..
type._deepEventHandler.callEventListeners(events)
}
}) })
// when all changes & events are processed, emit afterTransaction event // when all changes & events are processed, emit afterTransaction event
this.emit('afterTransaction', this, remote) this.emit('afterTransaction', this, remote)