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 {AbstractItem | null} left
* @param {AbstractItem | null} right
* @param {AbstractType<any> parent
* @param {AbstractType<any>} parent
* @param {string | null} parentSub
*/
copy (id, left, right, parent, parentSub) {

View File

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

View File

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

View File

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

View File

@ -3,8 +3,8 @@
*/
import { Y } from '../utils/Y.js' // eslint-disable-line
import { EventHandler } from '../utils/EventHandler.js'
import { YEvent } from '../utils/YEvent.js'
import * as eventHandler from '../utils/EventHandler.js'
import { YEvent } from '../utils/YEvent.js' // eslint-disable-line
import { AbstractItem } from '../structs/AbstractItem.js' // eslint-disable-line
import { ItemType } from '../structs/ItemType.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 { getItemCleanStart, getItemCleanEnd } from '../utils/StructStore.js'
import * as iterator from 'lib0/iterator.js'
import * as error from 'lib0/error.js'
/**
* @template EventType
@ -43,8 +44,16 @@ export class AbstractType {
*/
this._y = null
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
*
* @param {Transaction} transaction
* @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
*/
_callObserver (transaction, parentSubs) {
this._callEventHandler(transaction, new YEvent(this, transaction))
throw error.methodUnimplemented()
}
/**
@ -108,8 +119,8 @@ export class AbstractType {
* @param {any} event
*/
_callEventHandler (transaction, event) {
eventHandler.callEventListeners(this._eH, [event, transaction])
const changedParentTypes = transaction.changedParentTypes
this._eventHandler.callEventListeners(transaction, event)
/**
* @type {AbstractType<EventType>}
*/
@ -127,37 +138,37 @@ export class AbstractType {
/**
* 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) {
this._eventHandler.addEventListener(f)
eventHandler.addEventListener(this._eH, f)
}
/**
* 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) {
this._deepEventHandler.addEventListener(f)
eventHandler.addEventListener(this._dEH, f)
}
/**
* Unregister an observer function.
*
* @param {Function} f Observer function
* @param {function(EventType,Transaction):void} f Observer function
*/
unobserve (f) {
this._eventHandler.removeEventListener(f)
eventHandler.removeEventListener(this._eH, f)
}
/**
* Unregister an observer function.
*
* @param {Function} f Observer function
* @param {function(Array<YEvent>,Transaction):void} f Observer function
*/
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.
*
* @public
* @extends {YMap<any>}
*/
export class YXmlHook extends YMap {
/**

View File

@ -1,70 +1,66 @@
/**
* @module utils
*/
import { Transaction } from './Transaction.js' // eslint-disable-line
import { YEvent } from './YEvent.js' // eslint-disable-line
import * as f from 'lib0/function.js'
/**
* General event handler implementation.
*
* @template ARG0, ARG1
*/
export class EventHandler {
constructor () {
this.eventListeners = []
/**
* @type {Array<function(ARG0, ARG1):void>}
*/
this.l = []
}
}
/**
* To prevent memory leaks, call this method when the eventListeners won't be
* used anymore.
* @template ARG0,ARG1
* @returns {EventHandler<ARG0,ARG1>}
*/
destroy () {
this.eventListeners = null
}
export const create = () => new EventHandler()
/**
* Adds an event listener that is called when
* {@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) {
this.eventListeners.push(f)
}
export const addEventListener = (eventHandler, f) =>
eventHandler.l.push(f)
/**
* 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}
*/
removeEventListener (f) {
this.eventListeners = this.eventListeners.filter(g => f !== g)
export const removeEventListener = (eventHandler, f) => {
eventHandler.l = eventHandler.l.filter(g => f !== g)
}
/**
* Removes all event listeners.
* @template ARG0,ARG1
* @param {EventHandler<ARG0,ARG1>} eventHandler
*/
removeAllEventListeners () {
this.eventListeners = []
export const removeAllEventListeners = eventHandler => {
eventHandler.l.length = 0
}
/**
* Call all event listeners that were added via
* {@link EventHandler#addEventListener}.
*
* @param {Transaction} transaction The transaction object
* @param {YEvent} event An event object that describes the change on a type.
* @template ARG0,ARG1
* @param {EventHandler<ARG0,ARG1>} eventHandler
* @param {[ARG0,ARG1]} args
*/
callEventListeners (transaction, event) {
for (var i = 0; i < this.eventListeners.length; i++) {
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)
}
}
}
}
export const callEventListeners = (eventHandler, args) =>
f.callAll(eventHandler.l, args)

View File

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

View File

@ -81,7 +81,7 @@ export class YEvent {
* console.log(path) // might look like => [2, 'key1']
* child === type.get(path[0]).get(path[1])
*
* @param {AbstractType<any> parent
* @param {AbstractType<any>} parent
* @param {AbstractItem} child 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
*/
export const createAbsolutePosition = (type, offset) => new AbsolutePosition(type, offset)
/**
* @param {AbstractType<any> type
* @param {AbstractType<any>} type
* @param {ID.ID|null} item
*/
export const createRelativePosition = (type, item) => {
@ -99,7 +99,7 @@ export const createRelativePosition = (type, item) => {
/**
* 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.
* @return {RelativePosition}
*/