restructure EventHandler

This commit is contained in:
Kevin Jahns 2019-04-04 13:50:00 +02:00
parent 6578727c9c
commit 8dbd2c4696
11 changed files with 187 additions and 179 deletions

View File

@ -33,7 +33,7 @@ export class ItemFormat extends AbstractItem {
* @param {ID} id * @param {ID} id
* @param {AbstractItem | null} left * @param {AbstractItem | null} left
* @param {AbstractItem | null} right * @param {AbstractItem | null} right
* @param {AbstractType<any> parent * @param {AbstractType<any>} parent
* @param {string | null} parentSub * @param {string | null} parentSub
*/ */
copy (id, left, right, parent, parentSub) { copy (id, left, right, parent, parentSub) {

View File

@ -34,7 +34,7 @@ export class ItemJSON extends AbstractItem {
* @param {ID} id * @param {ID} id
* @param {AbstractItem | null} left * @param {AbstractItem | null} left
* @param {AbstractItem | null} right * @param {AbstractItem | null} right
* @param {AbstractType<any> parent * @param {AbstractType<any>} parent
* @param {string | null} parentSub * @param {string | null} parentSub
*/ */
copy (id, left, right, parent, parentSub) { copy (id, left, right, parent, parentSub) {

View File

@ -33,7 +33,7 @@ export class ItemString extends AbstractItem {
* @param {ID} id * @param {ID} id
* @param {AbstractItem | null} left * @param {AbstractItem | null} left
* @param {AbstractItem | null} right * @param {AbstractItem | null} right
* @param {AbstractType<any> parent * @param {AbstractType<any>} parent
* @param {string | null} parentSub * @param {string | null} parentSub
*/ */
copy (id, left, right, parent, parentSub) { copy (id, left, right, parent, parentSub) {

View File

@ -67,7 +67,7 @@ export class ItemType extends AbstractItem {
* @param {ID} id * @param {ID} id
* @param {AbstractItem | null} left * @param {AbstractItem | null} left
* @param {AbstractItem | null} right * @param {AbstractItem | null} right
* @param {AbstractType<any> parent * @param {AbstractType<any>} parent
* @param {string | null} parentSub * @param {string | null} parentSub
* @return {AbstractItem} TODO, returns itemtype * @return {AbstractItem} TODO, returns itemtype
*/ */
@ -150,7 +150,7 @@ export class ItemTypeRef extends AbstractItemRef {
super(decoder, id, info) super(decoder, id, info)
const typeRef = decoding.readVarUint(decoder) const typeRef = decoding.readVarUint(decoder)
/** /**
* @type {AbstractType<any> * @type {AbstractType<any>}
*/ */
this.type = typeRefs[typeRef](decoder) this.type = typeRefs[typeRef](decoder)
} }

View File

@ -3,8 +3,8 @@
*/ */
import { Y } from '../utils/Y.js' // eslint-disable-line import { Y } from '../utils/Y.js' // eslint-disable-line
import { EventHandler } from '../utils/EventHandler.js' import * as eventHandler from '../utils/EventHandler.js'
import { YEvent } from '../utils/YEvent.js' import { YEvent } from '../utils/YEvent.js' // eslint-disable-line
import { AbstractItem } from '../structs/AbstractItem.js' // eslint-disable-line import { AbstractItem } from '../structs/AbstractItem.js' // eslint-disable-line
import { ItemType } from '../structs/ItemType.js' // eslint-disable-line import { ItemType } from '../structs/ItemType.js' // eslint-disable-line
import { Encoder } from 'lib0/encoding.js' // eslint-disable-line import { Encoder } from 'lib0/encoding.js' // eslint-disable-line
@ -16,6 +16,7 @@ import { ItemBinary } from '../structs/ItemBinary.js'
import { ID, createID } from '../utils/ID.js' // eslint-disable-line import { ID, createID } from '../utils/ID.js' // eslint-disable-line
import { getItemCleanStart, getItemCleanEnd } from '../utils/StructStore.js' import { getItemCleanStart, getItemCleanEnd } from '../utils/StructStore.js'
import * as iterator from 'lib0/iterator.js' import * as iterator from 'lib0/iterator.js'
import * as error from 'lib0/error.js'
/** /**
* @template EventType * @template EventType
@ -43,8 +44,16 @@ export class AbstractType {
*/ */
this._y = null this._y = null
this._length = 0 this._length = 0
this._eventHandler = new EventHandler() /**
this._deepEventHandler = new EventHandler() * Event handlers
* @type {eventHandler.EventHandler<EventType,Transaction>}
*/
this._eH = eventHandler.create()
/**
* Deep event handlers
* @type {eventHandler.EventHandler<Array<YEvent>,Transaction>}
*/
this._dEH = eventHandler.create()
} }
/** /**
@ -89,14 +98,16 @@ export class AbstractType {
} }
/** /**
* Creates YEvent and calls observers. * Creates YEvent and calls _callEventHandler.
* Must be implemented by each type.
* @todo Rename to _createEvent
* @private * @private
* *
* @param {Transaction} transaction * @param {Transaction} transaction
* @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified. * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
*/ */
_callObserver (transaction, parentSubs) { _callObserver (transaction, parentSubs) {
this._callEventHandler(transaction, new YEvent(this, transaction)) throw error.methodUnimplemented()
} }
/** /**
@ -108,8 +119,8 @@ export class AbstractType {
* @param {any} event * @param {any} event
*/ */
_callEventHandler (transaction, event) { _callEventHandler (transaction, event) {
eventHandler.callEventListeners(this._eH, [event, transaction])
const changedParentTypes = transaction.changedParentTypes const changedParentTypes = transaction.changedParentTypes
this._eventHandler.callEventListeners(transaction, event)
/** /**
* @type {AbstractType<EventType>} * @type {AbstractType<EventType>}
*/ */
@ -127,37 +138,37 @@ export class AbstractType {
/** /**
* Observe all events that are created on this type. * Observe all events that are created on this type.
* *
* @param {function(EventType):void} f Observer function * @param {function(EventType, Transaction):void} f Observer function
*/ */
observe (f) { observe (f) {
this._eventHandler.addEventListener(f) eventHandler.addEventListener(this._eH, f)
} }
/** /**
* Observe all events that are created by this type and its children. * Observe all events that are created by this type and its children.
* *
* @param {function(Array<YEvent>):void} f Observer function * @param {function(Array<YEvent>,Transaction):void} f Observer function
*/ */
observeDeep (f) { observeDeep (f) {
this._deepEventHandler.addEventListener(f) eventHandler.addEventListener(this._dEH, f)
} }
/** /**
* Unregister an observer function. * Unregister an observer function.
* *
* @param {Function} f Observer function * @param {function(EventType,Transaction):void} f Observer function
*/ */
unobserve (f) { unobserve (f) {
this._eventHandler.removeEventListener(f) eventHandler.removeEventListener(this._eH, f)
} }
/** /**
* Unregister an observer function. * Unregister an observer function.
* *
* @param {Function} f Observer function * @param {function(Array<YEvent>,Transaction):void} f Observer function
*/ */
unobserveDeep (f) { unobserveDeep (f) {
this._deepEventHandler.removeEventListener(f) eventHandler.removeEventListener(this._dEH, f)
} }
/** /**

View File

@ -9,7 +9,7 @@ import * as decoding from 'lib0/decoding.js'
/** /**
* You can manage binding to a custom type with YXmlHook. * You can manage binding to a custom type with YXmlHook.
* *
* @public * @extends {YMap<any>}
*/ */
export class YXmlHook extends YMap { export class YXmlHook extends YMap {
/** /**

View File

@ -1,70 +1,66 @@
/** import { Transaction } from './Transaction.js' // eslint-disable-line
* @module utils import { YEvent } from './YEvent.js' // eslint-disable-line
*/ import * as f from 'lib0/function.js'
/** /**
* General event handler implementation. * General event handler implementation.
*
* @template ARG0, ARG1
*/ */
export class EventHandler { export class EventHandler {
constructor () { constructor () {
this.eventListeners = [] /**
* @type {Array<function(ARG0, ARG1):void>}
*/
this.l = []
}
} }
/** /**
* To prevent memory leaks, call this method when the eventListeners won't be * @template ARG0,ARG1
* used anymore. * @returns {EventHandler<ARG0,ARG1>}
*/ */
destroy () { export const create = () => new EventHandler()
this.eventListeners = null
}
/** /**
* Adds an event listener that is called when * Adds an event listener that is called when
* {@link EventHandler#callEventListeners} is called. * {@link EventHandler#callEventListeners} is called.
* *
* @param {Function} f The event handler. * @template ARG0,ARG1
* @param {EventHandler<ARG0,ARG1>} eventHandler
* @param {function(ARG0,ARG1):void} f The event handler.
*/ */
addEventListener (f) { export const addEventListener = (eventHandler, f) =>
this.eventListeners.push(f) eventHandler.l.push(f)
}
/** /**
* Removes an event listener. * Removes an event listener.
* *
* @param {Function} f The event handler that was added with * @template ARG0,ARG1
* @param {EventHandler<ARG0,ARG1>} eventHandler
* @param {function(ARG0,ARG1):void} f The event handler that was added with
* {@link EventHandler#addEventListener} * {@link EventHandler#addEventListener}
*/ */
removeEventListener (f) { export const removeEventListener = (eventHandler, f) => {
this.eventListeners = this.eventListeners.filter(g => f !== g) eventHandler.l = eventHandler.l.filter(g => f !== g)
} }
/** /**
* Removes all event listeners. * Removes all event listeners.
* @template ARG0,ARG1
* @param {EventHandler<ARG0,ARG1>} eventHandler
*/ */
removeAllEventListeners () { export const removeAllEventListeners = eventHandler => {
this.eventListeners = [] eventHandler.l.length = 0
} }
/** /**
* Call all event listeners that were added via * Call all event listeners that were added via
* {@link EventHandler#addEventListener}. * {@link EventHandler#addEventListener}.
* *
* @param {Transaction} transaction The transaction object * @template ARG0,ARG1
* @param {YEvent} event An event object that describes the change on a type. * @param {EventHandler<ARG0,ARG1>} eventHandler
* @param {[ARG0,ARG1]} args
*/ */
callEventListeners (transaction, event) { export const callEventListeners = (eventHandler, args) =>
for (var i = 0; i < this.eventListeners.length; i++) { f.callAll(eventHandler.l, args)
try {
const f = this.eventListeners[i]
f(event, transaction)
} catch (e) {
/*
Your observer threw an error. This error was caught so that Yjs
can ensure data consistency! In order to debug this error you
have to check "Pause On Caught Exceptions" in developer tools.
*/
console.error(e)
}
}
}
}

View File

@ -1,3 +1,4 @@
// @ts-nocheck
import * as ID from './ID.js' import * as ID from './ID.js'
import { isParentOf } from './isParentOf.js' import { isParentOf } from './isParentOf.js'

View File

@ -15,6 +15,7 @@ import { YText } from '../types/YText.js'
import { YMap } from '../types/YMap.js' import { YMap } from '../types/YMap.js'
import { YXmlFragment } from '../types/YXmlElement.js' import { YXmlFragment } from '../types/YXmlElement.js'
import { YEvent } from './YEvent.js' // eslint-disable-line import { YEvent } from './YEvent.js' // eslint-disable-line
import * as eventHandler from './EventHandler.js'
/** /**
* A Yjs instance handles the state of shared data. * A Yjs instance handles the state of shared data.
@ -74,9 +75,7 @@ export class Y extends Observable {
} }
try { try {
f(this._transaction) f(this._transaction)
} catch (e) { } finally {
console.error(e)
}
if (initialCall) { if (initialCall) {
const transaction = this._transaction const transaction = this._transaction
this._transaction = null this._transaction = null
@ -97,9 +96,9 @@ export class Y extends Observable {
.forEach(event => { .forEach(event => {
event.currentTarget = type event.currentTarget = type
}) })
// we don't have to check for events.length // we don't need to check for events.length
// because there is no way events is empty.. // because we know it has at least one element
type._deepEventHandler.callEventListeners(transaction, events) eventHandler.callEventListeners(type._dEH, [events, transaction])
}) })
// when all changes & events are processed, emit afterTransaction event // when all changes & events are processed, emit afterTransaction event
this.emit('afterTransaction', [this, transaction]) this.emit('afterTransaction', [this, transaction])
@ -179,6 +178,7 @@ export class Y extends Observable {
} }
} }
} }
}
/** /**
* Define a shared data type. * Define a shared data type.
* *

View File

@ -81,7 +81,7 @@ export class YEvent {
* console.log(path) // might look like => [2, 'key1'] * console.log(path) // might look like => [2, 'key1']
* child === type.get(path[0]).get(path[1]) * child === type.get(path[0]).get(path[1])
* *
* @param {AbstractType<any> parent * @param {AbstractType<any>} parent
* @param {AbstractItem} child target * @param {AbstractItem} child target
* @return {Array<string|number>} Path to the target * @return {Array<string|number>} Path to the target
*/ */

View File

@ -76,13 +76,13 @@ export class AbsolutePosition {
} }
/** /**
* @param {AbstractType<any> type * @param {AbstractType<any>} type
* @param {number} offset * @param {number} offset
*/ */
export const createAbsolutePosition = (type, offset) => new AbsolutePosition(type, offset) export const createAbsolutePosition = (type, offset) => new AbsolutePosition(type, offset)
/** /**
* @param {AbstractType<any> type * @param {AbstractType<any>} type
* @param {ID.ID|null} item * @param {ID.ID|null} item
*/ */
export const createRelativePosition = (type, item) => { export const createRelativePosition = (type, item) => {
@ -99,7 +99,7 @@ export const createRelativePosition = (type, item) => {
/** /**
* Create a relativePosition based on a absolute position. * Create a relativePosition based on a absolute position.
* *
* @param {AbstractType<any> type The base type (e.g. YText or YArray). * @param {AbstractType<any>} type The base type (e.g. YText or YArray).
* @param {number} offset The absolute position. * @param {number} offset The absolute position.
* @return {RelativePosition} * @return {RelativePosition}
*/ */