From 82db5a024fcadc624ffd3cf6874168dc27f060ad Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Thu, 4 Jul 2019 11:50:32 +0200 Subject: [PATCH] Feature: Implemented CKEditorInspector#attachToAll(). Closes #56. --- src/ckeditorinspector.js | 35 +++++++++++++ tests/inspector/ckeditorinspector.js | 73 ++++++++++++++++++++++++++++ tests/utils/testeditor.js | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/ckeditorinspector.js b/src/ckeditorinspector.js index 1598a21..9f7751f 100644 --- a/src/ckeditorinspector.js +++ b/src/ckeditorinspector.js @@ -77,6 +77,37 @@ export default class CKEditorInspector { return Object.keys( editors ); } + /** + * Attaches the inspector to all CKEditor instances discovered in DOM. + * + * Editor instances are named `editor-1`, `editor-2`, etc.. + * + * **Note:** This method requires CKEditor 12.3.0 or later. + * + * **Note:** You can pass global configuration options when attaching: + * + * CKEditorInspector.attachToAll( { option: 'value', ... } ); + * + * @param {CKEditorInspectorConfig} [options] An object of global configuration options controlling the + * behavior of the inspector. + * @returns {Array.} Names of the editors the inspector attached to. Useful when using `CKEditorInspector.detach()` + * with generated editor names. + */ + static attachToAll( options ) { + const domEditables = document.querySelectorAll( '.ck.ck-content.ck-editor__editable' ); + const attachedEditorNames = []; + + for ( const domEditable of domEditables ) { + const editor = domEditable.ckeditorInstance; + + if ( editor && !CKEditorInspector._isAttachedTo( editor ) ) { + attachedEditorNames.push( ...CKEditorInspector.attach( editor, options ) ); + } + } + + return attachedEditorNames; + } + /** * Detaches the inspector from an editor instance. * @@ -138,6 +169,10 @@ export default class CKEditorInspector { static get _isMounted() { return !!CKEditorInspector._inspectorRef.current; } + + static _isAttachedTo( editor ) { + return [ ...CKEditorInspector._editors.values() ].indexOf( editor ) > -1; + } } CKEditorInspector._editors = new Map(); diff --git a/tests/inspector/ckeditorinspector.js b/tests/inspector/ckeditorinspector.js index caea26d..36b419a 100644 --- a/tests/inspector/ckeditorinspector.js +++ b/tests/inspector/ckeditorinspector.js @@ -178,6 +178,79 @@ describe( 'CKEditorInspector', () => { } ); } ); + describe( '#attachToAll()', () => { + it( 'attaches to all editors', () => { + return TestEditor.create( element ) + .then( anotherEditor => { + document.body.appendChild( editor.ui.view.element ); + document.body.appendChild( anotherEditor.ui.view.element ); + + const editorNames = CKEditorInspector.attachToAll(); + + inspectorRef = CKEditorInspector._inspectorRef.current; + + expect( inspectorRef.state.editors.size ).to.equal( 2 ); + expect( inspectorRef.state.editors.get( 'editor-5' ) ).to.equal( editor ); + expect( inspectorRef.state.editors.get( 'editor-6' ) ).to.equal( anotherEditor ); + expect( editorNames ).to.have.members( [ 'editor-5', 'editor-6' ] ); + + return anotherEditor.destroy(); + } ) + .catch( err => { + throw err; + } ); + } ); + + it( 'detects and prevents duplicates', () => { + return TestEditor.create( element ) + .then( anotherEditor => { + document.body.appendChild( editor.ui.view.element ); + document.body.appendChild( anotherEditor.ui.view.element ); + + CKEditorInspector.attachToAll(); + + inspectorRef = CKEditorInspector._inspectorRef.current; + + expect( inspectorRef.state.editors.size ).to.equal( 2 ); + expect( inspectorRef.state.editors.get( 'editor-7' ) ).to.equal( editor ); + expect( inspectorRef.state.editors.get( 'editor-8' ) ).to.equal( anotherEditor ); + + CKEditorInspector.attachToAll(); + + inspectorRef = CKEditorInspector._inspectorRef.current; + + expect( inspectorRef.state.editors.size ).to.equal( 2 ); + + return anotherEditor.destroy(); + } ) + .catch( err => { + throw err; + } ); + } ); + + it( 'passes options to #attach()', () => { + return TestEditor.create( element ) + .then( anotherEditor => { + document.body.appendChild( editor.ui.view.element ); + document.body.appendChild( anotherEditor.ui.view.element ); + + const spy = sinon.spy( CKEditorInspector, 'attach' ); + const options = { foo: true }; + CKEditorInspector.attachToAll( options ); + + sinon.assert.calledWithExactly( spy.firstCall, editor, options ); + sinon.assert.calledWithExactly( spy.secondCall, anotherEditor, options ); + + spy.restore(); + + return anotherEditor.destroy(); + } ) + .catch( err => { + throw err; + } ); + } ); + } ); + describe( '#detach()', () => { it( 'detaches an editor', () => { CKEditorInspector.attach( { foo: editor } ); diff --git a/tests/utils/testeditor.js b/tests/utils/testeditor.js index 1a69367..b994624 100644 --- a/tests/utils/testeditor.js +++ b/tests/utils/testeditor.js @@ -74,7 +74,7 @@ class ClassicTestEditorUI extends EditorUI { view.render(); view.main.add( view.editable ); - this._editableElements.set( 'main', view.editable.element ); + this.setEditableElement( 'main', view.editable.element ); this._elementReplacer.replace( element, view.element ); this.editor.commands.add( 'foo', new FooCommand( this.editor ) );