8
0
Quellcode durchsuchen

Merge pull request #77 from ckeditor/t/ckeditor5/1449

Other: Editor UI classes API refactoring.

BREAKING CHANGE: Removed `ClassicEditor#element` property. The `ClassicEditorUI#element` property should be used instead.
BREAKING CHANGE: Removed `ClassicEditorUIView#editableElement`. Instead `ClassicEditorUI#getEditableElement()` method should be used.
Piotr Jasiun vor 6 Jahren
Ursprung
Commit
be7d7100fa

+ 5 - 29
packages/ckeditor5-editor-classic/src/classiceditor.js

@@ -14,7 +14,6 @@ import attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
 import ClassicEditorUI from './classiceditorui';
 import ClassicEditorUIView from './classiceditoruiview';
-import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';
 import getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import { isElement } from 'lodash-es';
@@ -66,14 +65,6 @@ export default class ClassicEditor extends Editor {
 			this.sourceElement = sourceElementOrData;
 		}
 
-		/**
-		 * The element replacer instance used to hide the editor's source element.
-		 *
-		 * @protected
-		 * @member {module:utils/elementreplacer~ElementReplacer}
-		 */
-		this._elementReplacer = new ElementReplacer();
-
 		this.data.processor = new HtmlDataProcessor();
 
 		this.model.document.createRoot();
@@ -84,13 +75,6 @@ export default class ClassicEditor extends Editor {
 	}
 
 	/**
-	 * @inheritDoc
-	 */
-	get element() {
-		return this.ui.view.element;
-	}
-
-	/**
 	 * Destroys the editor instance, releasing all resources used by it.
 	 *
 	 * Updates the editor's source element with the data.
@@ -102,7 +86,6 @@ export default class ClassicEditor extends Editor {
 			this.updateSourceElement();
 		}
 
-		this._elementReplacer.restore();
 		this.ui.destroy();
 
 		return super.destroy();
@@ -167,15 +150,15 @@ export default class ClassicEditor extends Editor {
 	 *
 	 * If a source element is passed, then its contents will be automatically
 	 * {@link module:editor-classic/classiceditor~ClassicEditor#setData loaded} to the editor on startup
-	 * and the {@link module:core/editor/editorwithui~EditorWithUI#element editor element} will replace the passed element in the DOM
+	 * and the {@link module:core/editor/editorui~EditorUI#getEditableElement editor element} will replace the passed element in the DOM
 	 * (the original one will be hidden and the editor will be injected next to it).
 	 *
 	 * Moreover, the data will be set back to the source element once the editor is destroyed and
 	 * (if the element is a `<textarea>`) when a form in which this element is contained is submitted (which ensures
 	 * automatic integration with native web forms).
 	 *
-	 * If the data is passed, a detached editor will be created. It means that you need to insert it into the DOM manually
-	 * (by accessing the {@link module:editor-classic/classiceditor~ClassicEditor#element `editor.element`} property).
+	 * If the data is passed, a detached editor will be created. It means that you need to insert it into the DOM manually (by accessing
+	 * it via the {@link module:editor-classic/classiceditorui~ClassicEditorUI#getEditableElement `editor.ui.getEditableElement()`} method).
 	 *
 	 * See the examples above to learn more.
 	 *
@@ -189,15 +172,8 @@ export default class ClassicEditor extends Editor {
 
 			resolve(
 				editor.initPlugins()
-					.then( () => editor.ui.init() )
-					.then( () => {
-						if ( isElement( sourceElementOrData ) ) {
-							editor._elementReplacer.replace( sourceElementOrData, editor.element );
-						}
-
-						editor.fire( 'uiReady' );
-					} )
-					.then( () => editor.editing.view.attachDomRoot( editor.ui.view.editableElement ) )
+					.then( () => editor.ui.init( isElement( sourceElementOrData ) ? sourceElementOrData : null ) )
+					.then( () => editor.editing.view.attachDomRoot( editor.ui.getEditableElement() ) )
 					.then( () => {
 						const initialData = isElement( sourceElementOrData ) ?
 							getDataFromElement( sourceElementOrData ) :

+ 65 - 7
packages/ckeditor5-editor-classic/src/classiceditorui.js

@@ -10,6 +10,7 @@
 import EditorUI from '@ckeditor/ckeditor5-core/src/editor/editorui';
 import enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';
 import normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig';
+import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';
 
 /**
  * The classic editor UI class.
@@ -18,24 +19,62 @@ import normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalize
  */
 export default class ClassicEditorUI extends EditorUI {
 	/**
-	 * @inheritDoc
+	 * Creates an instance of the classic editor UI class.
+	 *
+	 * @param {module:core/editor/editor~Editor} editor The editor instance.
+	 * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.
 	 */
 	constructor( editor, view ) {
-		super( editor, view );
+		super( editor );
+
+		/**
+		 * The main (top–most) view of the editor UI.
+		 *
+		 * @private
+		 * @member {module:ui/editorui/editoruiview~EditorUIView} #_view
+		 */
+		this._view = view;
 
 		/**
 		 * A normalized `config.toolbar` object.
 		 *
-		 * @type {Object}
 		 * @private
+		 * @member {Object}
 		 */
 		this._toolbarConfig = normalizeToolbarConfig( editor.config.get( 'toolbar' ) );
+
+		/**
+		 * The element replacer instance used to hide the editor's source element.
+		 *
+		 * @protected
+		 * @member {module:utils/elementreplacer~ElementReplacer}
+		 */
+		this._elementReplacer = new ElementReplacer();
+	}
+
+	/**
+	 * The main (top–most) view of the editor UI.
+	 *
+	 * @readonly
+	 * @member {module:ui/editorui/editoruiview~EditorUIView} #view
+	 */
+	get view() {
+		return this._view;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	get element() {
+		return this.view.element;
 	}
 
 	/**
 	 * Initializes the UI.
+	 *
+	 * @param {HTMLElement|null} replacementElement The DOM element that will be the source for the created editor.
 	 */
-	init() {
+	init( replacementElement ) {
 		const editor = this.editor;
 		const view = this.view;
 
@@ -55,15 +94,34 @@ export default class ClassicEditorUI extends EditorUI {
 		view.editable.bind( 'isFocused' ).to( editor.editing.view.document );
 		view.editable.name = editingRoot.rootName;
 
-		this.focusTracker.add( this.view.editableElement );
+		this._editableElements.set( view.editable.name, view.editable.element );
 
-		this.view.toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );
+		this.focusTracker.add( view.editable.element );
+
+		view.toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );
 
 		enableToolbarKeyboardFocus( {
 			origin: editor.editing.view,
 			originFocusTracker: this.focusTracker,
 			originKeystrokeHandler: editor.keystrokes,
-			toolbar: this.view.toolbar
+			toolbar: view.toolbar
 		} );
+
+		if ( replacementElement ) {
+			this._elementReplacer.replace( replacementElement, this.element );
+		}
+
+		this.fire( 'ready' );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	destroy() {
+		this._elementReplacer.restore();
+
+		this._view.destroy();
+
+		super.destroy();
 	}
 }

+ 0 - 7
packages/ckeditor5-editor-classic/src/classiceditoruiview.js

@@ -67,11 +67,4 @@ export default class ClassicEditorUIView extends BoxedEditorUIView {
 		this.top.add( this.stickyPanel );
 		this.main.add( this.editable );
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	get editableElement() {
-		return this.editable.element;
-	}
 }

+ 8 - 18
packages/ckeditor5-editor-classic/tests/classiceditor.js

@@ -19,6 +19,8 @@ import ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementap
 import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
 
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import log from '@ckeditor/ckeditor5-utils/src/log';
+
 import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
 import { describeMemoryUsage, testMemoryUsage } from '@ckeditor/ckeditor5-core/tests/_utils/memory';
 
@@ -32,6 +34,8 @@ describe( 'ClassicEditor', () => {
 		editorElement.innerHTML = '<p><strong>foo</strong> bar</p>';
 
 		document.body.appendChild( editorElement );
+
+		testUtils.sinon.stub( log, 'warn' ).callsFake( () => {} );
 	} );
 
 	afterEach( () => {
@@ -171,20 +175,6 @@ describe( 'ClassicEditor', () => {
 			it( 'attaches editable UI as view\'s DOM root', () => {
 				expect( editor.editing.view.getDomRoot() ).to.equal( editor.ui.view.editable.element );
 			} );
-
-			it( 'editor.element points to the editor\'s UI when editor was initialized on the DOM element', () => {
-				expect( editor.element ).to.equal( editor.ui.view.element );
-			} );
-
-			it( 'editor.element points to the editor\'s UI when editor was initialized with data', () => {
-				return ClassicEditor.create( '<p>Hello world!</p>', {
-					plugins: [ Paragraph ]
-				} ).then( editor => {
-					expect( editor.element ).to.equal( editor.ui.view.element );
-
-					return editor.destroy();
-				} );
-			} );
 		} );
 	} );
 
@@ -203,7 +193,7 @@ describe( 'ClassicEditor', () => {
 			class EventWatcher extends Plugin {
 				init() {
 					this.editor.on( 'pluginsReady', spy );
-					this.editor.on( 'uiReady', spy );
+					this.editor.ui.on( 'ready', spy );
 					this.editor.on( 'dataReady', spy );
 					this.editor.on( 'ready', spy );
 				}
@@ -214,7 +204,7 @@ describe( 'ClassicEditor', () => {
 					plugins: [ EventWatcher ]
 				} )
 				.then( newEditor => {
-					expect( fired ).to.deep.equal( [ 'pluginsReady', 'uiReady', 'dataReady', 'ready' ] );
+					expect( fired ).to.deep.equal( [ 'pluginsReady', 'ready', 'dataReady', 'ready' ] );
 
 					editor = newEditor;
 				} );
@@ -242,12 +232,12 @@ describe( 'ClassicEditor', () => {
 				} );
 		} );
 
-		it( 'fires uiReady once UI is rendered', () => {
+		it( 'fires ready once UI is rendered', () => {
 			let isReady;
 
 			class EventWatcher extends Plugin {
 				init() {
-					this.editor.on( 'uiReady', () => {
+					this.editor.ui.on( 'ready', () => {
 						isReady = this.editor.ui.view.isRendered;
 					} );
 				}

+ 28 - 2
packages/ckeditor5-editor-classic/tests/classiceditorui.js

@@ -17,7 +17,7 @@ import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import utils from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
 describe( 'ClassicEditorUI', () => {
-	let editor, view, ui;
+	let editor, view, ui, viewElement;
 
 	testUtils.createSinonSandbox();
 
@@ -31,6 +31,7 @@ describe( 'ClassicEditorUI', () => {
 
 				ui = editor.ui;
 				view = ui.view;
+				viewElement = view.element;
 			} );
 	} );
 
@@ -178,6 +179,32 @@ describe( 'ClassicEditorUI', () => {
 				} );
 		} );
 	} );
+
+	describe( 'view()', () => {
+		it( 'returns view instance', () => {
+			expect( ui.view ).to.equal( view );
+		} );
+	} );
+
+	describe( 'element()', () => {
+		it( 'returns correct element instance', () => {
+			expect( ui.element ).to.equal( viewElement );
+		} );
+	} );
+
+	describe( 'getEditableElement()', () => {
+		it( 'returns editable element (default)', () => {
+			expect( ui.getEditableElement() ).to.equal( view.editable.element );
+		} );
+
+		it( 'returns editable element (root name passed)', () => {
+			expect( ui.getEditableElement( 'main' ) ).to.equal( view.editable.element );
+		} );
+
+		it( 'returns undefined if editable with the given name is absent', () => {
+			expect( ui.getEditableElement( 'absent' ) ).to.be.undefined;
+		} );
+	} );
 } );
 
 function viewCreator( name ) {
@@ -216,7 +243,6 @@ class VirtualClassicTestEditor extends VirtualTestEditor {
 				editor.initPlugins()
 					.then( () => {
 						editor.ui.init();
-						editor.fire( 'uiReady' );
 						editor.fire( 'dataReady' );
 						editor.fire( 'ready' );
 					} )

+ 4 - 15
packages/ckeditor5-editor-classic/tests/classiceditoruiview.js

@@ -3,17 +3,19 @@
  * For licensing, see LICENSE.md.
  */
 
-/* globals document */
-
 import ClassicEditorUIView from '../src/classiceditoruiview';
 import StickyPanelView from '@ckeditor/ckeditor5-ui/src/panel/sticky/stickypanelview';
 import ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';
 import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
 import Locale from '@ckeditor/ckeditor5-utils/src/locale';
 
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+
 describe( 'ClassicEditorUIView', () => {
 	let locale, view;
 
+	testUtils.createSinonSandbox();
+
 	beforeEach( () => {
 		locale = new Locale( 'en' );
 		view = new ClassicEditorUIView( locale );
@@ -67,17 +69,4 @@ describe( 'ClassicEditorUIView', () => {
 			} );
 		} );
 	} );
-
-	describe( 'editableElement', () => {
-		it( 'returns editable\'s view element', () => {
-			document.body.appendChild( view.element );
-
-			view.stickyPanel.limiterElement = view.element;
-
-			expect( view.editableElement.getAttribute( 'contentEditable' ) ).to.equal( 'true' );
-
-			view.element.remove();
-			view.destroy();
-		} );
-	} );
 } );