diff --git a/src/types/YText.js b/src/types/YText.js index a38dc867..93537c7b 100644 --- a/src/types/YText.js +++ b/src/types/YText.js @@ -502,14 +502,6 @@ const deleteText = (transaction, currPos, length) => { * @typedef {Object} TextAttributes */ -/** - * @typedef {Object} DeltaItem - * @property {number|undefined} DeltaItem.delete - * @property {number|undefined} DeltaItem.retain - * @property {string|undefined} DeltaItem.insert - * @property {Object} DeltaItem.attributes - */ - /** * Event that describes the changes on a YText type. */ @@ -521,10 +513,6 @@ export class YTextEvent extends YEvent { */ constructor (ytext, transaction, subs) { super(ytext, transaction) - /** - * @type {Array|null} - */ - this._delta = null /** * Whether the children changed. * @type {Boolean} @@ -545,20 +533,41 @@ export class YTextEvent extends YEvent { }) } + /** + * @type {{added:Set,deleted:Set,keys:Map,delta:Array<{insert?:Array|string, delete?:number, retain?:number}>}} + */ + get changes () { + if (this._changes === null) { + /** + * @type {{added:Set,deleted:Set,keys:Map,delta:Array<{insert?:Array|string, delete?:number, retain?:number}>}} + */ + const changes = { + keys: this.keys, + delta: this.delta, + added: new Set(), + deleted: new Set() + } + this._changes = changes + } + return /** @type {any} */ (this._changes) + } + /** * Compute the changes in the delta format. * A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document. * - * @type {Array} + * @type {Array<{insert?:string, delete?:number, retain?:number, attributes?: Object}>} * * @public */ get delta () { if (this._delta === null) { const y = /** @type {Doc} */ (this.target.doc) - this._delta = [] + /** + * @type {Array<{insert?:string, delete?:number, retain?:number, attributes?: Object}>} + */ + const delta = [] transact(y, transaction => { - const delta = /** @type {Array} */ (this._delta) const currentAttributes = new Map() // saves all current attributes for insert const oldAttributes = new Map() let item = this.target._start @@ -728,8 +737,9 @@ export class YTextEvent extends YEvent { } } }) + this._delta = delta } - return this._delta + return /** @type {any} */ (this._delta) } } diff --git a/src/utils/YEvent.js b/src/utils/YEvent.js index ff4e7339..cfbb9123 100644 --- a/src/utils/YEvent.js +++ b/src/utils/YEvent.js @@ -35,6 +35,14 @@ export class YEvent { * @type {Object|null} */ this._changes = null + /** + * @type {null | Map} + */ + this._keys = null + /** + * @type {null | Array<{ insert?: string | Array, retain?: number, delete?: number, attributes?: Object }>} + */ + this._delta = null } /** @@ -67,6 +75,66 @@ export class YEvent { return isDeleted(this.transaction.deleteSet, struct.id) } + /** + * @type {Map} + */ + get keys () { + if (this._keys === null) { + const keys = new Map() + const target = this.target + const changed = /** @type Set */ (this.transaction.changed.get(target)) + changed.forEach(key => { + if (key !== null) { + const item = /** @type {Item} */ (target._map.get(key)) + /** + * @type {'delete' | 'add' | 'update'} + */ + let action + let oldValue + if (this.adds(item)) { + let prev = item.left + while (prev !== null && this.adds(prev)) { + prev = prev.left + } + if (this.deletes(item)) { + if (prev !== null && this.deletes(prev)) { + action = 'delete' + oldValue = array.last(prev.content.getContent()) + } else { + return + } + } else { + if (prev !== null && this.deletes(prev)) { + action = 'update' + oldValue = array.last(prev.content.getContent()) + } else { + action = 'add' + oldValue = undefined + } + } + } else { + if (this.deletes(item)) { + action = 'delete' + oldValue = array.last(/** @type {Item} */ item.content.getContent()) + } else { + return // nop + } + } + keys.set(key, { action, oldValue }) + } + }) + this._keys = keys + } + return this._keys + } + + /** + * @type {Array<{insert?: string | Array, retain?: number, delete?: number, attributes?: Object}>} + */ + get delta () { + return this.changes.delta + } + /** * Check if a struct is added by this event. * @@ -80,7 +148,7 @@ export class YEvent { } /** - * @return {{added:Set,deleted:Set,keys:Map,delta:Array<{insert:Array}|{delete:number}|{retain:number}>}} + * @type {{added:Set,deleted:Set,keys:Map,delta:Array<{insert?:Array|string, delete?:number, retain?:number}>}} */ get changes () { let changes = this._changes @@ -92,12 +160,11 @@ export class YEvent { * @type {Array<{insert:Array}|{delete:number}|{retain:number}>} */ const delta = [] - /** - * @type {Map} - */ - const keys = new Map() changes = { - added, deleted, delta, keys + added, + deleted, + delta, + keys: this.keys } const changed = /** @type Set */ (this.transaction.changed.get(target)) if (changed.has(null)) { @@ -141,46 +208,6 @@ export class YEvent { packOp() } } - changed.forEach(key => { - if (key !== null) { - const item = /** @type {Item} */ (target._map.get(key)) - /** - * @type {'delete' | 'add' | 'update'} - */ - let action - let oldValue - if (this.adds(item)) { - let prev = item.left - while (prev !== null && this.adds(prev)) { - prev = prev.left - } - if (this.deletes(item)) { - if (prev !== null && this.deletes(prev)) { - action = 'delete' - oldValue = array.last(prev.content.getContent()) - } else { - return - } - } else { - if (prev !== null && this.deletes(prev)) { - action = 'update' - oldValue = array.last(prev.content.getContent()) - } else { - action = 'add' - oldValue = undefined - } - } - } else { - if (this.deletes(item)) { - action = 'delete' - oldValue = array.last(/** @type {Item} */ item.content.getContent()) - } else { - return // nop - } - } - keys.set(key, { action, oldValue }) - } - }) this._changes = changes } return /** @type {any} */ (changes)