From d227190ece960077718553f350cd6500cbc32469 Mon Sep 17 00:00:00 2001 From: Blake Thomson Date: Mon, 13 Jul 2015 17:48:03 -0400 Subject: [PATCH 1/4] Transform the undo/redo stacks against non-user initiated changes --- src/modules/undo-manager.coffee | 16 +++++++++++++-- test/unit/modules/undo-manager.coffee | 28 +++++++++++++++++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/modules/undo-manager.coffee b/src/modules/undo-manager.coffee index e2a7f59064..3a996d60f1 100644 --- a/src/modules/undo-manager.coffee +++ b/src/modules/undo-manager.coffee @@ -33,7 +33,10 @@ class UndoManager ) @quill.on(@quill.constructor.events.TEXT_CHANGE, (delta, origin) => return if @ignoreChange - this.record(delta, @oldDelta) + if origin == 'user' + this.record(delta, @oldDelta) + else + this._transform(delta) @oldDelta = @quill.getContents() ) @@ -90,13 +93,22 @@ class UndoManager change = @stack[source].pop() @lastRecorded = 0 @ignoreChange = true - @quill.updateContents(change[source], 'user') + @quill.updateContents(change[source], Quill.sources.USER) @ignoreChange = false index = this._getLastChangeIndex(change[source]) @quill.setSelection(index, index) @oldDelta = @quill.getContents() @stack[dest].push(change) + _transform: (delta) -> + @oldDelta = delta.transform(@oldDelta, true) + for change in @stack.undo + change.undo = delta.transform(change.undo, true) + change.redo = delta.transform(change.redo, true) + for change in @stack.redo + change.undo = delta.transform(change.undo, true) + change.redo = delta.transform(change.redo, true) + Quill.registerModule('undo-manager', UndoManager) module.exports = UndoManager diff --git a/test/unit/modules/undo-manager.coffee b/test/unit/modules/undo-manager.coffee index 800a9a0328..61c11c87fd 100644 --- a/test/unit/modules/undo-manager.coffee +++ b/test/unit/modules/undo-manager.coffee @@ -42,7 +42,7 @@ describe('UndoManager', -> describe('undo/redo', -> _.each(tests, (test, name) -> it(name, -> - @quill.updateContents(test.delta) + @quill.updateContents(test.delta, Quill.sources.USER) changed = @quill.getContents() expect(changed).not.toEqualDelta(@original) @undoManager.undo() @@ -65,9 +65,9 @@ describe('UndoManager', -> it('merge changes', -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e')) + @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) expect(@undoManager.stack.undo.length).toEqual(1) - @quill.updateContents(new Quill.Delta().retain(13).insert('s')) + @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) expect(@undoManager.stack.undo.length).toEqual(1) @undoManager.undo() expect(@quill.getContents()).toEqual(@original) @@ -76,10 +76,10 @@ describe('UndoManager', -> it('dont merge changes', (done) -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e')) + @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) expect(@undoManager.stack.undo.length).toEqual(1) setTimeout( => - @quill.updateContents(new Quill.Delta().retain(13).insert('s')) + @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) expect(@undoManager.stack.undo.length).toEqual(2) done() , @undoManager.options.delay * 1.25) @@ -87,10 +87,10 @@ describe('UndoManager', -> it('multiple undos', (done) -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e')) + @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) contents = @quill.getContents() setTimeout( => - @quill.updateContents(new Quill.Delta().retain(13).insert('s')) + @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) @undoManager.undo() expect(@quill.getContents()).toEqual(contents) @undoManager.undo() @@ -100,7 +100,7 @@ describe('UndoManager', -> ) it('hotkeys', -> - @quill.updateContents(new Quill.Delta().insert('A')) + @quill.updateContents(new Quill.Delta().insert('A'), Quill.sources.USER) changed = @quill.getContents() expect(changed).not.toEqualDelta(@original) dom(@quill.root).trigger('keydown', Quill.Module.UndoManager.hotkeys.UNDO) @@ -108,5 +108,17 @@ describe('UndoManager', -> dom(@quill.root).trigger('keydown', Quill.Module.UndoManager.hotkeys.REDO) expect(@quill.getContents()).toEqualDelta(changed) ) + + it('api change transform', -> + @quill.updateContents(new Quill.Delta().retain(12).insert('es'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(4).delete(5), Quill.sources.API) + @quill.updateContents(new Quill.Delta().retain(9).insert('!'), Quill.sources.USER) + expect(@undoManager.stack.undo.length).toEqual(1) + expect(@quill.getContents()).toEqual(new Quill.Delta().insert('The foxes!\n')) + @undoManager.undo() + expect(@quill.getContents()).toEqual(new Quill.Delta().insert('The fox\n')) + @undoManager.redo() + expect(@quill.getContents()).toEqual(new Quill.Delta().insert('The foxes!\n')) + ) ) ) From c1e2b6806a1502c32999d3b0e88be5ffd3d0661a Mon Sep 17 00:00:00 2001 From: Blake Thomson Date: Wed, 15 Jul 2015 10:14:18 -0400 Subject: [PATCH 2/4] Clean up some style --- src/modules/undo-manager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/undo-manager.coffee b/src/modules/undo-manager.coffee index 3a996d60f1..1774bb4c45 100644 --- a/src/modules/undo-manager.coffee +++ b/src/modules/undo-manager.coffee @@ -31,9 +31,9 @@ class UndoManager return false ) ) - @quill.on(@quill.constructor.events.TEXT_CHANGE, (delta, origin) => + @quill.on(@quill.constructor.events.TEXT_CHANGE, (delta, source) => return if @ignoreChange - if origin == 'user' + if source == Quill.sources.USER this.record(delta, @oldDelta) else this._transform(delta) From f4e3c69af1202e4d1532da956a4ced7196baa79a Mon Sep 17 00:00:00 2001 From: Blake Thomson Date: Wed, 15 Jul 2015 14:59:52 -0400 Subject: [PATCH 3/4] Pass {userOnly:true} to tell the undo-manager to transform non-user deltas --- src/modules/undo-manager.coffee | 3 ++- test/unit/modules/undo-manager.coffee | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/undo-manager.coffee b/src/modules/undo-manager.coffee index 1774bb4c45..b829984f62 100644 --- a/src/modules/undo-manager.coffee +++ b/src/modules/undo-manager.coffee @@ -7,6 +7,7 @@ class UndoManager @DEFAULTS: delay: 1000 maxStack: 100 + userOnly: false @hotkeys: UNDO: { key: 'Z', metaKey: true } @@ -33,7 +34,7 @@ class UndoManager ) @quill.on(@quill.constructor.events.TEXT_CHANGE, (delta, source) => return if @ignoreChange - if source == Quill.sources.USER + if !@options.userOnly or source == Quill.sources.USER this.record(delta, @oldDelta) else this._transform(delta) diff --git a/test/unit/modules/undo-manager.coffee b/test/unit/modules/undo-manager.coffee index 61c11c87fd..48981e81f9 100644 --- a/test/unit/modules/undo-manager.coffee +++ b/test/unit/modules/undo-manager.coffee @@ -9,7 +9,7 @@ describe('UndoManager', -> ' @quill = new Quill(@container.firstChild, { modules: { - 'undo-manager': { delay: 400 } + 'undo-manager': { delay: 400, userOnly: true } } }) @undoManager = @quill.getModule('undo-manager') From 06a44b74812d73660404be8e6e1e4fcffdb9a2f4 Mon Sep 17 00:00:00 2001 From: Blake Thomson Date: Fri, 17 Jul 2015 12:41:02 -0400 Subject: [PATCH 4/4] Update the undo-manager test to only use the userOnly option for the applicable test --- test/unit/modules/undo-manager.coffee | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/unit/modules/undo-manager.coffee b/test/unit/modules/undo-manager.coffee index 48981e81f9..46b83f1660 100644 --- a/test/unit/modules/undo-manager.coffee +++ b/test/unit/modules/undo-manager.coffee @@ -9,7 +9,7 @@ describe('UndoManager', -> ' @quill = new Quill(@container.firstChild, { modules: { - 'undo-manager': { delay: 400, userOnly: true } + 'undo-manager': { delay: 400 } } }) @undoManager = @quill.getModule('undo-manager') @@ -42,7 +42,7 @@ describe('UndoManager', -> describe('undo/redo', -> _.each(tests, (test, name) -> it(name, -> - @quill.updateContents(test.delta, Quill.sources.USER) + @quill.updateContents(test.delta) changed = @quill.getContents() expect(changed).not.toEqualDelta(@original) @undoManager.undo() @@ -65,9 +65,9 @@ describe('UndoManager', -> it('merge changes', -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(12).insert('e')) expect(@undoManager.stack.undo.length).toEqual(1) - @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(13).insert('s')) expect(@undoManager.stack.undo.length).toEqual(1) @undoManager.undo() expect(@quill.getContents()).toEqual(@original) @@ -76,10 +76,10 @@ describe('UndoManager', -> it('dont merge changes', (done) -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(12).insert('e')) expect(@undoManager.stack.undo.length).toEqual(1) setTimeout( => - @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(13).insert('s')) expect(@undoManager.stack.undo.length).toEqual(2) done() , @undoManager.options.delay * 1.25) @@ -87,10 +87,10 @@ describe('UndoManager', -> it('multiple undos', (done) -> expect(@undoManager.stack.undo.length).toEqual(0) - @quill.updateContents(new Quill.Delta().retain(12).insert('e'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(12).insert('e')) contents = @quill.getContents() setTimeout( => - @quill.updateContents(new Quill.Delta().retain(13).insert('s'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().retain(13).insert('s')) @undoManager.undo() expect(@quill.getContents()).toEqual(contents) @undoManager.undo() @@ -100,7 +100,7 @@ describe('UndoManager', -> ) it('hotkeys', -> - @quill.updateContents(new Quill.Delta().insert('A'), Quill.sources.USER) + @quill.updateContents(new Quill.Delta().insert('A')) changed = @quill.getContents() expect(changed).not.toEqualDelta(@original) dom(@quill.root).trigger('keydown', Quill.Module.UndoManager.hotkeys.UNDO) @@ -110,6 +110,7 @@ describe('UndoManager', -> ) it('api change transform', -> + @quill.getModule('undo-manager').options.userOnly = true @quill.updateContents(new Quill.Delta().retain(12).insert('es'), Quill.sources.USER) @quill.updateContents(new Quill.Delta().retain(4).delete(5), Quill.sources.API) @quill.updateContents(new Quill.Delta().retain(9).insert('!'), Quill.sources.USER)