diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ff3136..1d9ecfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.1.7 (16.06.2021) + +* Set the undo/redo event listeners in the holder element instead of the whole document. + ## 0.1.6 (04.05.2021) * Read-only mode support added. diff --git a/dist/bundle.js b/dist/bundle.js index d3a471c..509b2c2 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Undo=e():t.Undo=e()}(window,(function(){return function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=0)}([function(t,e,n){"use strict";function i(t,e){for(var n=0;ne;)t.shift()}},{key:"initialize",value:function(t){var e="blocks"in t?t.blocks:t,n={index:e.length-1,state:e};this.stack[0]=n,this.initialItem=n}},{key:"clear",value:function(){this.stack=this.initialItem?[this.initialItem]:[{index:0,state:[]}],this.position=0,this.onUpdate()}},{key:"registerChange",value:function(){var t=this;this.readOnly||(this.editor&&this.editor.save&&this.shouldSaveHistory&&this.editor.save().then((function(e){t.editorDidUpdate(e.blocks)&&t.save(e.blocks)})),this.shouldSaveHistory=!0)}},{key:"editorDidUpdate",value:function(t){var e=this.stack[this.position].state;return t.length!==e.length||JSON.stringify(e)!==JSON.stringify(t)}},{key:"save",value:function(t){this.position>=this.maxLength&&this.truncate(this.stack,this.maxLength),this.position=Math.min(this.position,this.stack.length-1),this.stack=this.stack.slice(0,this.position+1);var e=this.editor.blocks.getCurrentBlockIndex();this.stack.push({index:e,state:t}),this.position+=1,this.onUpdate()}},{key:"undo",value:function(){var t=this;if(this.canUndo()){this.shouldSaveHistory=!1;var e=this.stack[this.position-=1],n=e.index,i=e.state;this.onUpdate(),this.editor.blocks.render({blocks:i}).then((function(){return t.editor.caret.setToBlock(n,"end")}))}}},{key:"redo",value:function(){var t=this;if(this.canRedo()){this.shouldSaveHistory=!1;var e=this.stack[this.position+=1],n=e.index,i=e.state;this.onUpdate(),this.editor.blocks.render({blocks:i}).then((function(){return t.editor.caret.setToBlock(n,"end")}))}}},{key:"canUndo",value:function(){return!this.readOnly&&this.position>0}},{key:"canRedo",value:function(){return!this.readOnly&&this.positione;)t.shift()}},{key:"initialize",value:function(t){var e="blocks"in t?t.blocks:t,n={index:e.length-1,state:e};this.stack[0]=n,this.initialItem=n}},{key:"clear",value:function(){this.stack=this.initialItem?[this.initialItem]:[{index:0,state:[]}],this.position=0,this.onUpdate()}},{key:"registerChange",value:function(){var t=this;this.readOnly||(this.editor&&this.editor.save&&this.shouldSaveHistory&&this.editor.save().then((function(e){t.editorDidUpdate(e.blocks)&&t.save(e.blocks)})),this.shouldSaveHistory=!0)}},{key:"editorDidUpdate",value:function(t){var e=this.stack[this.position].state;return t.length!==e.length||JSON.stringify(e)!==JSON.stringify(t)}},{key:"save",value:function(t){this.position>=this.maxLength&&this.truncate(this.stack,this.maxLength),this.position=Math.min(this.position,this.stack.length-1),this.stack=this.stack.slice(0,this.position+1);var e=this.editor.blocks.getCurrentBlockIndex();this.stack.push({index:e,state:t}),this.position+=1,this.onUpdate()}},{key:"undo",value:function(){var t=this;if(this.canUndo()){this.shouldSaveHistory=!1;var e=this.stack[this.position-=1],n=e.index,i=e.state;this.onUpdate(),this.editor.blocks.render({blocks:i}).then((function(){return t.editor.caret.setToBlock(n,"end")}))}}},{key:"redo",value:function(){var t=this;if(this.canRedo()){this.shouldSaveHistory=!1;var e=this.stack[this.position+=1],n=e.index,i=e.state;this.onUpdate(),this.editor.blocks.render({blocks:i}).then((function(){return t.editor.caret.setToBlock(n,"end")}))}}},{key:"canUndo",value:function(){return!this.readOnly&&this.position>0}},{key:"canRedo",value:function(){return!this.readOnly&&this.position { if (e[buttonKey] && e.key === 'z') { e.preventDefault(); @@ -206,12 +208,13 @@ export default class Undo { }; const handleDestroy = () => { - document.removeEventListener('keydown', handleUndo); - document.removeEventListener('keydown', handleRedo); + holder.removeEventListener('keydown', handleUndo); + holder.removeEventListener('keydown', handleRedo); }; - document.addEventListener('keydown', handleUndo); - document.addEventListener('keydown', handleRedo); - document.addEventListener('destroy', handleDestroy); + holder.addEventListener('keydown', handleUndo); + holder.addEventListener('keydown', handleRedo); + holder.addEventListener('destroy', handleDestroy); } + } diff --git a/test/fixtures/editor.js b/test/fixtures/editor.js index e8681e7..ffd5317 100644 --- a/test/fixtures/editor.js +++ b/test/fixtures/editor.js @@ -12,9 +12,7 @@ const editor = { caret: { setToBlock() {}, }, - configuration: { - holder: 'editorjs', - }, + configuration: {}, }; const readOnlyEditor = { @@ -27,7 +25,6 @@ const readOnlyEditor = { setToBlock() {}, }, configuration: { - holder: 'editorjs', readOnly: true, }, }; diff --git a/test/undo.test.js b/test/undo.test.js index ff459e0..fa42343 100644 --- a/test/undo.test.js +++ b/test/undo.test.js @@ -10,6 +10,10 @@ import { editor, readOnlyEditor } from './fixtures/editor'; describe('Undo', () => { beforeEach(() => { document.body.innerHTML = '
'; + // EditorJS uses as a holder an HTMLElement instead of a query selector. + // This has to be assigned each time that DOM is reset. + editor.configuration.holder = document.querySelector('#editorjs'); + readOnlyEditor.configuration.holder = document.querySelector('#editorjs'); }); describe('Read-only mode active', () => { @@ -119,4 +123,80 @@ describe('Undo', () => { expect(state).toEqual(newChange.blocks); }); }); + + describe('Undo/redo events fired inside and outside Editor\'s holder', () => { + let undo; + + beforeEach(() => { + undo = new Undo({ editor }); + undo.initialize(initialData.blocks); + undo.save(firstChange.blocks); + undo.save(secondChange.blocks); + }); + + it('undo event outside Editor\'s holder has not to cause changes in Undo Plugin stack', () => { + // Set metaKey and ctrlKey to true in order to work in Mac and other OSs. + const keyboardEvent = new KeyboardEvent('keydown', { + key: 'z', + metaKey: true, + ctrlKey: true, + }); + + document.dispatchEvent(keyboardEvent); + + expect(undo.count()).toEqual(2); + expect(undo.position).toEqual(2); + const { state } = undo.stack[2]; + expect(state).toEqual(secondChange.blocks); + }); + + it('undo event inside Editor\'s holder has to cause changes in Undo Plugin stack', () => { + const keyboardEvent = new KeyboardEvent('keydown', { + key: 'z', + metaKey: true, + ctrlKey: true, + }); + + editor.configuration.holder.dispatchEvent(keyboardEvent); + + expect(undo.count()).toEqual(2); + expect(undo.position).toEqual(1); + const { state } = undo.stack[1]; + expect(state).toEqual(firstChange.blocks); + }); + + it('redo event outside Editor\'s holder has not to cause changes in Undo Plugin stack', () => { + undo.undo(); + + const keyboardEvent = new KeyboardEvent('keydown', { + key: 'y', + metaKey: true, + ctrlKey: true, + }); + + document.dispatchEvent(keyboardEvent); + + expect(undo.count()).toEqual(2); + expect(undo.position).toEqual(1); + const { state } = undo.stack[1]; + expect(state).toEqual(firstChange.blocks); + }); + + it('redo event inside Editor\'s holder has to cause changes in Undo Plugin stack', () => { + undo.undo(); + + const keyboardEvent = new KeyboardEvent('keydown', { + key: 'y', + metaKey: true, + ctrlKey: true, + }); + + editor.configuration.holder.dispatchEvent(keyboardEvent); + + expect(undo.count()).toEqual(2); + expect(undo.position).toEqual(2); + const { state } = undo.stack[2]; + expect(state).toEqual(secondChange.blocks); + }); + }); });