[UndoManager] support global undo
This commit is contained in:
parent
cc9a857441
commit
69d4a5c821
@ -39,7 +39,7 @@ export class StackItem {
|
|||||||
*/
|
*/
|
||||||
const clearUndoManagerStackItem = (tr, um, stackItem) => {
|
const clearUndoManagerStackItem = (tr, um, stackItem) => {
|
||||||
iterateDeletedStructs(tr, stackItem.deletions, item => {
|
iterateDeletedStructs(tr, stackItem.deletions, item => {
|
||||||
if (item instanceof Item && um.scope.some(type => isParentOf(type, item))) {
|
if (item instanceof Item && um.scope.some(type => type === tr.doc || isParentOf(/** @type {AbstractType<any>} */ (type), item))) {
|
||||||
keepItem(item, false)
|
keepItem(item, false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -81,7 +81,7 @@ const popStackItem = (undoManager, stack, eventType) => {
|
|||||||
}
|
}
|
||||||
struct = item
|
struct = item
|
||||||
}
|
}
|
||||||
if (!struct.deleted && scope.some(type => isParentOf(type, /** @type {Item} */ (struct)))) {
|
if (!struct.deleted && scope.some(type => type === transaction.doc || isParentOf(/** @type {AbstractType<any>} */ (type), /** @type {Item} */ (struct)))) {
|
||||||
itemsToDelete.push(struct)
|
itemsToDelete.push(struct)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ const popStackItem = (undoManager, stack, eventType) => {
|
|||||||
iterateDeletedStructs(transaction, stackItem.deletions, struct => {
|
iterateDeletedStructs(transaction, stackItem.deletions, struct => {
|
||||||
if (
|
if (
|
||||||
struct instanceof Item &&
|
struct instanceof Item &&
|
||||||
scope.some(type => isParentOf(type, struct)) &&
|
scope.some(type => type === transaction.doc || isParentOf(/** @type {AbstractType<any>} */ (type), struct)) &&
|
||||||
// Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
|
// Never redo structs in stackItem.insertions because they were created and deleted in the same capture interval.
|
||||||
!isDeleted(stackItem.insertions, struct.id)
|
!isDeleted(stackItem.insertions, struct.id)
|
||||||
) {
|
) {
|
||||||
@ -159,7 +159,7 @@ const popStackItem = (undoManager, stack, eventType) => {
|
|||||||
*/
|
*/
|
||||||
export class UndoManager extends ObservableV2 {
|
export class UndoManager extends ObservableV2 {
|
||||||
/**
|
/**
|
||||||
* @param {AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
|
* @param {Doc|AbstractType<any>|Array<AbstractType<any>>} typeScope Accepts either a single type, or an array of types
|
||||||
* @param {UndoManagerOptions} options
|
* @param {UndoManagerOptions} options
|
||||||
*/
|
*/
|
||||||
constructor (typeScope, {
|
constructor (typeScope, {
|
||||||
@ -168,11 +168,11 @@ export class UndoManager extends ObservableV2 {
|
|||||||
deleteFilter = () => true,
|
deleteFilter = () => true,
|
||||||
trackedOrigins = new Set([null]),
|
trackedOrigins = new Set([null]),
|
||||||
ignoreRemoteMapChanges = false,
|
ignoreRemoteMapChanges = false,
|
||||||
doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope.doc)
|
doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope instanceof Doc ? typeScope : typeScope.doc)
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super()
|
super()
|
||||||
/**
|
/**
|
||||||
* @type {Array<AbstractType<any>>}
|
* @type {Array<AbstractType<any> | Doc>}
|
||||||
*/
|
*/
|
||||||
this.scope = []
|
this.scope = []
|
||||||
this.doc = doc
|
this.doc = doc
|
||||||
@ -212,7 +212,7 @@ export class UndoManager extends ObservableV2 {
|
|||||||
// Only track certain transactions
|
// Only track certain transactions
|
||||||
if (
|
if (
|
||||||
!this.captureTransaction(transaction) ||
|
!this.captureTransaction(transaction) ||
|
||||||
!this.scope.some(type => transaction.changedParentTypes.has(type)) ||
|
!this.scope.some(type => transaction.changedParentTypes.has(/** @type {AbstractType<any>} */ (type)) || type === this.doc) ||
|
||||||
(!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor)))
|
(!this.trackedOrigins.has(transaction.origin) && (!transaction.origin || !this.trackedOrigins.has(transaction.origin.constructor)))
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
@ -251,7 +251,7 @@ export class UndoManager extends ObservableV2 {
|
|||||||
}
|
}
|
||||||
// make sure that deleted structs are not gc'd
|
// make sure that deleted structs are not gc'd
|
||||||
iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => {
|
iterateDeletedStructs(transaction, transaction.deleteSet, /** @param {Item|GC} item */ item => {
|
||||||
if (item instanceof Item && this.scope.some(type => isParentOf(type, item))) {
|
if (item instanceof Item && this.scope.some(type => type === transaction.doc || isParentOf(/** @type {AbstractType<any>} */ (type), item))) {
|
||||||
keepItem(item, true)
|
keepItem(item, true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -272,13 +272,15 @@ export class UndoManager extends ObservableV2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Array<AbstractType<any>> | AbstractType<any>} ytypes
|
* @param {Array<AbstractType<any> | Doc> | AbstractType<any> | Doc} ytypes
|
||||||
*/
|
*/
|
||||||
addToScope (ytypes) {
|
addToScope (ytypes) {
|
||||||
|
const tmpSet = new Set(this.scope)
|
||||||
ytypes = array.isArray(ytypes) ? ytypes : [ytypes]
|
ytypes = array.isArray(ytypes) ? ytypes : [ytypes]
|
||||||
ytypes.forEach(ytype => {
|
ytypes.forEach(ytype => {
|
||||||
if (this.scope.every(yt => yt !== ytype)) {
|
if (!tmpSet.has(ytype)) {
|
||||||
if (ytype.doc !== this.doc) logging.warn('[yjs#509] Not same Y.Doc') // use MultiDocUndoManager instead. also see https://github.com/yjs/yjs/issues/509
|
tmpSet.add(ytype)
|
||||||
|
if (ytype instanceof AbstractType ? ytype.doc !== this.doc : ytype !== this.doc) logging.warn('[yjs#509] Not same Y.Doc') // use MultiDocUndoManager instead. also see https://github.com/yjs/yjs/issues/509
|
||||||
this.scope.push(ytype)
|
this.scope.push(ytype)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -116,6 +116,19 @@ export const testEmptyTypeScope = _tc => {
|
|||||||
t.assert(yarray.length === 0)
|
t.assert(yarray.length === 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case to fix #241
|
||||||
|
* @param {t.TestCase} _tc
|
||||||
|
*/
|
||||||
|
export const testGlobalScope = _tc => {
|
||||||
|
const ydoc = new Y.Doc()
|
||||||
|
const um = new Y.UndoManager(ydoc)
|
||||||
|
const yarray = ydoc.getArray()
|
||||||
|
yarray.insert(0, [1])
|
||||||
|
um.undo()
|
||||||
|
t.assert(yarray.length === 0)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test case to fix #241
|
* Test case to fix #241
|
||||||
* @param {t.TestCase} _tc
|
* @param {t.TestCase} _tc
|
||||||
|
Loading…
x
Reference in New Issue
Block a user