diff --git a/src/app/editor/ckeditorgithubeditor.js b/src/app/editor/ckeditorgithubeditor.js index 759206e..062fa34 100644 --- a/src/app/editor/ckeditorgithubeditor.js +++ b/src/app/editor/ckeditorgithubeditor.js @@ -8,6 +8,7 @@ import GFMDataProcessor from '@ckeditor/ckeditor5-markdown-gfm/src/gfmdataproces import CKEditorInspector from '@ckeditor/ckeditor5-inspector'; import AttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement'; +import PendingActions from '@ckeditor/ckeditor5-core/src/pendingactions'; import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import Enter from '../plugins/enter'; @@ -118,5 +119,6 @@ CKEditorGitHubEditor.builtinPlugins = [ QuoteSelection, SavedReplies, Messenger, EditorExtras, ControlClick, SmartCaret, CodeBlockLanguageSelector, LiveModelData, - Mermaid + Mermaid, + PendingActions ]; diff --git a/src/app/editor/setupmixin.js b/src/app/editor/setupmixin.js index ff13991..3e8aa42 100644 --- a/src/app/editor/setupmixin.js +++ b/src/app/editor/setupmixin.js @@ -141,6 +141,14 @@ const SetupMixin = { // Reset the rte editor on form reset (e.g. after a new comment is added). { this.domManipulator.addEventListener( form, 'reset', () => { + if ( this.ckeditor.plugins.has( 'PendingActions' ) ) { + const pendingActions = ckeditor.plugins.get( 'PendingActions' ); + + // Remove submit pending action to undisable actual submit button + if ( pendingActions.hasAny ) { + pendingActions.fire( 'change:removeAction', 'submit' ); + } + } // We actually want it 'after-reset', so form elements are clean, thus setTimeout. setTimeout( () => { this.setCKEditorData( this.dom.textarea.defaultValue ); @@ -171,6 +179,18 @@ const SetupMixin = { ev.preventDefault(); ev.stopImmediatePropagation(); } + + if ( this.ckeditor.plugins.has( 'PendingActions' ) ) { + const pendingActions = ckeditor.plugins.get( 'PendingActions' ); + + // Add submit pending action to disable actual submit button for preventing possibility + // clicking on that more than one time. + if ( !this.ckeditor.plugins.get( 'PendingActions' ).hasAny ) { + setTimeout( () => { + pendingActions.fire( 'change:addAction', 'submit' ); + } ); + } + } } } ); } @@ -333,10 +353,28 @@ const SetupMixin = { _setupPendingActions() { if ( this.ckeditor.plugins.has( 'PendingActions' ) ) { const pendingActions = this.ckeditor.plugins.get( 'PendingActions' ); + const actions = new Map(); pendingActions.on( 'change:hasAny', () => { this._setSubmitStatus(); } ); + + // Add to PendingActions collection new action. + pendingActions.on( 'change:addAction', ( _, name ) => { + const action = pendingActions.add( name ); + + actions.set( name, action ); + } ); + + // Remove action from PendingActions collection. + pendingActions.on( 'change:removeAction', ( _, name ) => { + const action = actions.get( name ); + + if ( action ) { + pendingActions.remove( action ); + actions.delete( name ); + } + } ); } } }; diff --git a/tests/unit/editor/setupmixin.js b/tests/unit/editor/setupmixin.js index 45fe39b..9bdf78e 100644 --- a/tests/unit/editor/setupmixin.js +++ b/tests/unit/editor/setupmixin.js @@ -631,6 +631,143 @@ describe( 'Editor', () => { expect( editor ).to.be.an.instanceOf( Editor ); } ); } ); + + it( 'should call "change:addAction" event', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + + const editor = new Editor( GitHubPage.appendRoot( ) ); + + return editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( pendingActions, 'add' ); + + pendingActions.fire( 'change:addAction', 'submit' ); + + expect( spy.callCount ).to.equals( 1 ); + } ); + } ); + + it( 'should call "change:removeAction" event', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + + const editor = new Editor( GitHubPage.appendRoot( ) ); + + return editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( pendingActions, 'remove' ); + + pendingActions.fire( 'change:addAction', 'submit' ); + + pendingActions.fire( 'change:removeAction', 'submit' ); + + expect( spy.callCount ).to.equals( 1 ); + } ); + } ); + + it( 'should not call "change:removeAction" event if the are no pending action', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + + const editor = new Editor( GitHubPage.appendRoot( ) ); + + return editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( pendingActions, 'remove' ); + + pendingActions.fire( 'change:removeAction', 'submit' ); + + expect( spy.callCount ).to.equals( 0 ); + } ); + } ); + + it( 'should not remove pending action', done => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + const editor = new Editor( GitHubPage.appendRoot() ); + editor.dom.root.querySelector( 'textarea' ).defaultValue = 'Test'; + + editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( pendingActions, 'remove' ); + + editor.setData( 'Changed data' ); + editor.dom.textarea.form.dispatchEvent( new Event( 'reset' ) ); + + setTimeout( () => { + expect( spy.callCount ).to.equals( 0 ); + done(); + }, 1 ); + } ); + } ); + + it( 'should remove pending action', done => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + const editor = new Editor( GitHubPage.appendRoot() ); + editor.dom.root.querySelector( 'textarea' ).defaultValue = 'Test'; + + editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( pendingActions, 'remove' ); + + pendingActions.fire( 'change:addAction', 'submit' ); + editor.setData( 'Changed data' ); + editor.dom.textarea.form.dispatchEvent( new Event( 'reset' ) ); + + setTimeout( () => { + expect( spy.callCount ).to.equals( 1 ); + done(); + }, 1 ); + } ); + } ); + + it( 'should sync editors on submit.click', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + const editor = new Editor( GitHubPage.appendRoot() ); + + return editor.create() + .then( () => { + const spy = sinon.spy( editor, 'syncData' ); + editor.dom.getSubmitBtn().dispatchEvent( new Event( 'click' ) ); + + expect( spy.callCount ).to.equals( 1 ); + } ); + } ); + + it( 'should add new pending action', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + const editor = new Editor( GitHubPage.appendRoot() ); + + return editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + const spy = sinon.spy( editor, 'syncData' ); + + pendingActions.fire( 'change:addAction', 'submit' ); + editor.dom.getSubmitBtn().dispatchEvent( new Event( 'click' ) ); + + expect( spy.callCount ).to.equals( 1 ); + } ); + } ); + + it( 'should not add new pending action if any action exist', () => { + CKEditorConfig.get.returns( { plugins: [ QuoteSelection, PendingActions ] } ); + const editor = new Editor( GitHubPage.appendRoot() ); + + return editor.create() + .then( () => { + const pendingActions = editor.ckeditor.plugins.get( 'PendingActions' ); + pendingActions.fire( 'change:addAction', 'submit' ); + + const spy = sinon.spy( pendingActions, 'add' ); + + editor.dom.getSubmitBtn().dispatchEvent( new Event( 'click' ) ); + + expect( spy.callCount ).to.equals( 0 ); + } ); + } ); } ); } ); } );