[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