mirror of
https://github.com/yjs/yjs.git
synced 2026-02-24 04:01:14 +01:00
190 lines
5.8 KiB
JavaScript
190 lines
5.8 KiB
JavaScript
import {
|
|
diffIdSet,
|
|
mergeIdSets,
|
|
noAttributionsManager,
|
|
YType, Doc, AbstractAttributionManager, Item, Transaction, AbstractStruct, // eslint-disable-line
|
|
createAbsolutePositionFromRelativePosition,
|
|
createRelativePosition
|
|
} from '../internals.js'
|
|
|
|
import * as map from 'lib0/map'
|
|
import * as delta from 'lib0/delta' // eslint-disable-line
|
|
import * as set from 'lib0/set'
|
|
|
|
/**
|
|
* @template {delta.DeltaConf} DConf
|
|
* YEvent describes the changes on a YType.
|
|
*/
|
|
export class YEvent {
|
|
/**
|
|
* @param {YType<DConf>} target The changed type.
|
|
* @param {Transaction} transaction
|
|
* @param {Set<any>?} subs The keys that changed
|
|
*/
|
|
constructor (target, transaction, subs) {
|
|
/**
|
|
* The type on which this event was created on.
|
|
* @type {YType<DConf>}
|
|
*/
|
|
this.target = target
|
|
/**
|
|
* The current target on which the observe callback is called.
|
|
* @type {YType<any>}
|
|
*/
|
|
this.currentTarget = target
|
|
/**
|
|
* The transaction that triggered this event.
|
|
* @type {Transaction}
|
|
*/
|
|
this.transaction = transaction
|
|
/**
|
|
* @type {delta.Delta<import('../ytype.js').DeltaConfDeltaToYType<DConf>>|null}
|
|
*/
|
|
this._delta = null
|
|
/**
|
|
* @type {delta.Delta<DConf>|null}
|
|
*/
|
|
this._deltaDeep = null
|
|
/**
|
|
* Whether the children changed.
|
|
* @type {Boolean}
|
|
* @private
|
|
*/
|
|
this.childListChanged = false
|
|
/**
|
|
* Set of all changed attributes.
|
|
* @type {Set<string>}
|
|
*/
|
|
this.keysChanged = new Set()
|
|
subs?.forEach((sub) => {
|
|
if (sub === null) {
|
|
this.childListChanged = true
|
|
} else {
|
|
this.keysChanged.add(sub)
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Check if a struct is deleted by this event.
|
|
*
|
|
* In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
|
|
*
|
|
* @param {AbstractStruct} struct
|
|
* @return {boolean}
|
|
*/
|
|
deletes (struct) {
|
|
return this.transaction.deleteSet.hasId(struct.id)
|
|
}
|
|
|
|
/**
|
|
* Check if a struct is added by this event.
|
|
*
|
|
* In contrast to change.deleted, this method also returns true if the struct was added and then deleted.
|
|
*
|
|
* @param {AbstractStruct} struct
|
|
* @return {boolean}
|
|
*/
|
|
adds (struct) {
|
|
return this.transaction.insertSet.hasId(struct.id)
|
|
}
|
|
|
|
/**
|
|
* @template {boolean} [Deep=false]
|
|
* @param {AbstractAttributionManager} am
|
|
* @param {object} [opts]
|
|
* @param {Deep} [opts.deep]
|
|
* @return {Deep extends true ? delta.Delta<DConf> : delta.Delta<import('../internals.js').DeltaConfDeltaToYType<DConf>>} The Delta representation of this type.
|
|
*
|
|
* @public
|
|
*/
|
|
getDelta (am = noAttributionsManager, { deep } = {}) {
|
|
const itemsToRender = mergeIdSets([diffIdSet(this.transaction.insertSet, this.transaction.deleteSet), diffIdSet(this.transaction.deleteSet, this.transaction.insertSet)])
|
|
/**
|
|
* @todo this should be done only one in the transaction step
|
|
*
|
|
* @type {Map<YType,Set<string|null>>|null}
|
|
*/
|
|
let modified = this.transaction.changed
|
|
if (deep) {
|
|
// need to add deep changes to copy of modified
|
|
const dchanged = new Map()
|
|
modified.forEach((attrs, type) => {
|
|
dchanged.set(type, new Set(attrs))
|
|
})
|
|
for (let m of modified.keys()) {
|
|
while (m._item != null) {
|
|
const item = m._item
|
|
const ms = map.setIfUndefined(dchanged, item?.parent, set.create)
|
|
if (item && !ms.has(item.parentSub)) {
|
|
ms.add(item.parentSub)
|
|
m = /** @type {any} */ (item.parent)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
modified = dchanged
|
|
}
|
|
return /** @type {any} */ (this.target.toDelta(am, { itemsToRender, retainDeletes: true, deletedItems: this.transaction.deleteSet, deep: !!deep, modified }))
|
|
}
|
|
|
|
/**
|
|
* Compute the changes in the delta format.
|
|
* A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
|
|
*
|
|
* @type {delta.Delta<import('../internals.js').DeltaConfDeltaToYType<DConf>>} The Delta representation of this type.
|
|
* @public
|
|
*/
|
|
get delta () {
|
|
return /** @type {any} */ (this._delta ?? (this._delta = this.getDelta().done()))
|
|
}
|
|
|
|
/**
|
|
* Compute the changes in the delta format.
|
|
* A {@link https://quilljs.com/docs/delta/|Quill Delta}) that represents the changes on the document.
|
|
*
|
|
* @type {delta.Delta<DConf>} The Delta representation of this type.
|
|
* @public
|
|
*/
|
|
get deltaDeep () {
|
|
return /** @type {any} */ (this._deltaDeep ?? (this._deltaDeep = /** @type {any} */ (this.getDelta(noAttributionsManager, { deep: true }))))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compute the path from this type to the specified target.
|
|
*
|
|
* @example
|
|
* // `child` should be accessible via `type.get(path[0]).get(path[1])..`
|
|
* const path = type.getPathTo(child)
|
|
* // assuming `type instanceof YArray`
|
|
* console.log(path) // might look like => [2, 'key1']
|
|
* child === type.get(path[0]).get(path[1])
|
|
*
|
|
* @param {YType} parent
|
|
* @param {YType} child target
|
|
* @param {AbstractAttributionManager} am
|
|
* @return {Array<string|number>} Path to the target
|
|
*
|
|
* @private
|
|
* @function
|
|
*/
|
|
export const getPathTo = (parent, child, am = noAttributionsManager) => {
|
|
const path = []
|
|
const doc = /** @type {Doc} */ (parent.doc)
|
|
while (child._item !== null && child !== parent) {
|
|
if (child._item.parentSub !== null) {
|
|
// parent is map-ish
|
|
path.unshift(child._item.parentSub)
|
|
} else {
|
|
const parent = /** @type {import('../ytype.js').YType} */ (child._item.parent)
|
|
// parent is array-ish
|
|
const apos = /** @type {import('../utils/RelativePosition.js').AbsolutePosition} */ (createAbsolutePositionFromRelativePosition(createRelativePosition(parent, child._item.id), doc, false, am))
|
|
path.unshift(apos.index)
|
|
}
|
|
child = /** @type {YType} */ (child._item.parent)
|
|
}
|
|
return path
|
|
}
|