Selaa lähdekoodia

Changes to EditorClassic after bringing *EditorUI back to life.

Aleksander Nowodzinski 9 vuotta sitten
vanhempi
commit
62cc41fa66

+ 4 - 7
packages/ckeditor5-editor-classic/src/classic.js

@@ -5,6 +5,7 @@
 
 import StandardEditor from '../core/editor/standardeditor.js';
 import HtmlDataProcessor from '../engine/dataprocessor/htmldataprocessor.js';
+import ClassicEditorUI from './classiceditorui.js';
 import ClassicEditorUIView from './classiceditoruiview.js';
 import ElementReplacer from '../utils/elementreplacer.js';
 
@@ -27,12 +28,8 @@ export default class ClassicEditor extends StandardEditor {
 		super( element, config );
 
 		this.document.createRoot();
-
-		this.editing.createRoot( 'div' );
-
 		this.data.processor = new HtmlDataProcessor();
-
-		this.ui = new ClassicEditorUIView( this, this.locale );
+		this.ui = new ClassicEditorUI( this, new ClassicEditorUIView( this.locale ) );
 
 		/**
 		 * The element replacer instance used to hide the editor element.
@@ -83,9 +80,9 @@ export default class ClassicEditor extends StandardEditor {
 
 			resolve(
 				editor.initPlugins()
-					.then( () => editor._elementReplacer.replace( element, editor.ui.element ) )
+					.then( () => editor._elementReplacer.replace( element, editor.ui.view.element ) )
 					.then( () => editor.ui.init() )
-					.then( () => editor.editing.view.attachDomRoot( editor.ui.editableElement ) )
+					.then( () => editor.editing.view.attachDomRoot( editor.ui.view.editableElement ) )
 					.then( () => editor.loadDataFromEditorElement() )
 					.then( () => editor )
 			);

+ 99 - 0
packages/ckeditor5-editor-classic/src/classiceditorui.js

@@ -0,0 +1,99 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import ComponentFactory from '../ui/componentfactory.js';
+import FocusTracker from '../utils/focustracker.js';
+
+/**
+ * The classic editor UI class.
+ *
+ * @memberOf editor-classic
+ */
+export default class ClassicEditorUI {
+	/**
+	 * Creates an instance of the editor UI class.
+	 *
+	 * @param {core.editor.Editor} editor The editor instance.
+	 * @param {ui.editorUI.EditorUIView} view View of the ui.
+	 */
+	constructor( editor, view ) {
+		/**
+		 * Editor that the UI belongs to.
+		 *
+		 * @readonly
+		 * @member {core.editor.Editor} editor-classic.ClssicEditorUI#editor
+		 */
+		this.editor = editor;
+
+		/**
+		 * View of the ui.
+		 *
+		 * @readonly
+		 * @member {ui.editorUI.EditorUIView} editor-classic.ClssicEditorUI#view
+		 */
+		this.view = view;
+
+		/**
+		 * Instance of the {@link ui.ComponentFactory}.
+		 *
+		 * @readonly
+		 * @member {ui.ComponentFactory} editor-classic.ClssicEditorUI#featureComponents
+		 */
+		this.featureComponents = new ComponentFactory( editor );
+
+		/**
+		 * Keeps information about editor focus.
+		 *
+		 * @member {utils.FocusTracker} editor-classic.ClssicEditorUI#focusTracker
+		 */
+		this.focusTracker = new FocusTracker();
+
+		// Set–up the view.
+		view.set( 'width', editor.config.get( 'ui.width' ) );
+		view.set( 'height', editor.config.get( 'ui.height' ) );
+
+		// Set–up the toolbar.
+		view.toolbar.bind( 'isActive' ).to( this.focusTracker, 'isFocused' );
+		view.toolbar.limiterElement = view.element;
+
+		// Setup the editable.
+		const editingRoot = editor.editing.createRoot( 'div' );
+		view.editable.bind( 'isReadOnly', 'isFocused' ).to( editingRoot );
+		view.editable.name = editingRoot.rootName;
+		this.focusTracker.add( view.editable.element );
+	}
+
+	/**
+	 * Initializes the UI.
+	 *
+	 * @returns {Promise} A Promise resolved when the initialization process is finished.
+	 */
+	init() {
+		const editor = this.editor;
+
+		return this.view.init()
+			.then( () => {
+				const toolbarConfig = editor.config.get( 'toolbar' );
+				const promises = [];
+
+				if ( toolbarConfig ) {
+					for ( let name of toolbarConfig ) {
+						promises.push( this.view.toolbar.items.add( this.featureComponents.create( name ) ) );
+					}
+				}
+
+				return Promise.all( promises );
+			} );
+	}
+
+	/**
+	 * Destroys the UI.
+	 *
+	 * @returns {Promise} A Promise resolved when the destruction process is finished.
+	 */
+	destroy() {
+		return this.view.destroy();
+	}
+}

+ 12 - 65
packages/ckeditor5-editor-classic/src/classiceditoruiview.js

@@ -16,49 +16,35 @@ import StickyToolbarView from '../ui/toolbar/sticky/stickytoolbarview.js';
  */
 export default class ClassicEditorUIView extends BoxedEditorUIView {
 	/**
-	 * Creates an instance of the classic editor UI.
+	 * Creates an instance of the classic editor UI view.
 	 *
-	 * @param {core.editor.Editor} editor
+	 * @param {utils.Locale} locale The {@link core.editor.Editor#locale} instance.
 	 */
-	constructor( editor, locale ) {
-		super( editor, locale );
+	constructor( locale ) {
+		super( locale );
 
 		/**
-		 * Toolbar view.
+		 * A sticky toolbar view instance.
 		 *
 		 * @readonly
-		 * @member {ui.toolbar.ToolbarView} editor-classic.ClassicEditorUI#toolbar
+		 * @member {ui.toolbar.sticky.StickyToolbarView} editor-classic.ClassicEditorUIView#toolbar
 		 */
-		this.toolbar = this._createToolbar();
+		this.toolbar = new StickyToolbarView( locale );
 
 		/**
 		 * Editable UI view.
 		 *
 		 * @readonly
-		 * @member {ui.editableUI.EditableUIView} editor-classic.ClassicEditorUI#editable
+		 * @member {ui.editableUI.inline.InlineEditableUIView} editor-classic.ClassicEditorUIView#editable
 		 */
-		this.editable = this._createEditableUIView( editor );
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	init() {
-		this.toolbar.limiterElement = this.element;
-
-		const toolbarConfig = this.editor.config.get( 'toolbar' );
-
-		if ( toolbarConfig ) {
-			for ( let name of toolbarConfig ) {
-				this.toolbar.items.add( this.featureComponents.create( name ) );
-			}
-		}
+		this.editable = new InlineEditableUIView( locale );
 
-		return super.init();
+		this.top.add( this.toolbar );
+		this.main.add( this.editable );
 	}
 
 	/**
-	 * The editing host element, {@link editor-classic.ClassicEditorUI#editable}.
+	 * The editing host element of {@link editor-classic.ClassicEditorUIView#editable}.
 	 *
 	 * @readonly
 	 * @type {HTMLElement}
@@ -66,43 +52,4 @@ export default class ClassicEditorUIView extends BoxedEditorUIView {
 	get editableElement() {
 		return this.editable.element;
 	}
-
-	/**
-	 * Creates the sticky toolbar view of the editor.
-	 *
-	 * @protected
-	 * @returns {ui.stickyToolbar.StickyToolbarView}
-	 */
-	_createToolbar() {
-		const editor = this.editor;
-		const toolbar = new StickyToolbarView( editor.locale );
-
-		toolbar.bind( 'isActive' ).to( editor.focusTracker, 'isFocused' );
-		this.top.add( toolbar );
-
-		return toolbar;
-	}
-
-	/**
-	 * Creates the main editable view of the editor and registers it
-	 * in {@link core.editor.Editor#focusTracker}.
-	 *
-	 * @protected
-	 * @returns {ui.editableUI.EditableUIView}
-	 */
-	_createEditableUIView() {
-		const editor = this.editor;
-		const editable = editor.editing.view.getRoot();
-		const editableUIView = new InlineEditableUIView( editor.locale );
-
-		editableUIView.bind( 'isReadOnly', 'isFocused' ).to( editable );
-		editableUIView.name = editable.rootName;
-
-		this.main.add( editableUIView );
-
-		// @TODO: Do it automatically ckeditor5-core#23
-		editor.focusTracker.add( editableUIView.element );
-
-		return editableUIView;
-	}
 }

+ 5 - 3
packages/ckeditor5-editor-classic/tests/classic.js

@@ -6,6 +6,7 @@
 /* globals document */
 /* bender-tags: editor, browser-only */
 
+import ClassicEditorUI from 'ckeditor5/editor-classic/classiceditorui.js';
 import ClassicEditorUIView from 'ckeditor5/editor-classic/classiceditoruiview.js';
 
 import HtmlDataProcessor from 'ckeditor5/engine/dataprocessor/htmldataprocessor.js';
@@ -48,7 +49,8 @@ describe( 'ClassicEditor', () => {
 		} );
 
 		it( 'creates the UI using BoxedEditorUI classes', () => {
-			expect( editor.ui ).to.be.instanceof( ClassicEditorUIView );
+			expect( editor.ui ).to.be.instanceof( ClassicEditorUI );
+			expect( editor.ui.view ).to.be.instanceof( ClassicEditorUIView );
 		} );
 
 		it( 'uses HTMLDataProcessor', () => {
@@ -71,11 +73,11 @@ describe( 'ClassicEditor', () => {
 		} );
 
 		it( 'inserts editor UI next to editor element', () => {
-			expect( editor.ui.element.previousSibling ).to.equal( editorElement );
+			expect( editor.ui.view.element.previousSibling ).to.equal( editorElement );
 		} );
 
 		it( 'attaches editable UI as view\'s DOM root', () => {
-			expect( editor.editing.view.getDomRoot() ).to.equal( editor.ui.editable.element );
+			expect( editor.editing.view.getDomRoot() ).to.equal( editor.ui.view.editable.element );
 		} );
 
 		it( 'loads data from the editor element', () => {

+ 183 - 0
packages/ckeditor5-editor-classic/tests/classiceditorui.js

@@ -0,0 +1,183 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals document, Event */
+/* bender-tags: editor, browser-only */
+
+import ComponentFactory from 'ckeditor5/ui/componentfactory.js';
+import FocusTracker from 'ckeditor5/utils/focustracker.js';
+import ClassicEditorUI from 'ckeditor5/editor-classic/classiceditorui.js';
+import ClassicEditorUIView from 'ckeditor5/editor-classic/classiceditoruiview.js';
+import ClassicTestEditor from 'tests/core/_utils/classictesteditor.js';
+import View from 'ckeditor5/ui/view.js';
+
+import testUtils from 'tests/core/_utils/utils.js';
+import utils from 'tests/utils/_utils/utils.js';
+
+testUtils.createSinonSandbox();
+
+describe( 'ClassicEditorUI', () => {
+	let editorElement, editor, editable, view, ui;
+
+	beforeEach( () => {
+		editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+
+		editor = new ClassicTestEditor( editorElement, {
+			toolbar: [ 'foo', 'bar' ],
+			ui: {
+				width: 100,
+				height: 200
+			}
+		} );
+
+		view = new ClassicEditorUIView( editor.locale );
+		ui = new ClassicEditorUI( editor, view );
+		editable = editor.editing.view.getRoot();
+
+		ui.featureComponents.add( 'foo', viewCreator( 'foo' ) );
+		ui.featureComponents.add( 'bar', viewCreator( 'bar' ) );
+	} );
+
+	describe( 'constructor()', () => {
+		it( 'sets #editor', () => {
+			expect( ui.editor ).to.equal( editor );
+		} );
+
+		it( 'sets #view', () => {
+			expect( ui.view ).to.equal( view );
+		} );
+
+		it( 'creates #featureComponents factory', () => {
+			expect( ui.featureComponents ).to.be.instanceOf( ComponentFactory );
+		} );
+
+		it( 'creates #focusTracker', () => {
+			expect( ui.focusTracker ).to.be.instanceOf( FocusTracker );
+		} );
+
+		it( 'sets view#width and view#height', () => {
+			expect( view.width ).to.equal( 100 );
+			expect( view.height ).to.equal( 200 );
+		} );
+
+		describe( 'toolbar', () => {
+			it( 'binds view.toolbar#isFocused to editor#focusTracker', () => {
+				ui.focusTracker.isFocused = false;
+				expect( view.toolbar.isActive ).to.be.false;
+
+				ui.focusTracker.isFocused = true;
+				expect( view.toolbar.isActive ).to.be.true;
+			} );
+
+			it( 'sets view.toolbar#limiterElement', () => {
+				expect( view.toolbar.limiterElement ).to.equal( view.element );
+			} );
+		} );
+
+		describe( 'editable', () => {
+			it( 'registers view.editable#element in editor focus tracker', () => {
+				ui.focusTracker.isFocused = false;
+
+				view.editable.element.dispatchEvent( new Event( 'focus' ) );
+				expect( ui.focusTracker.isFocused ).to.true;
+			} );
+
+			it( 'sets view.editable#name', () => {
+				expect( view.editable.name ).to.equal( editable.rootName );
+			} );
+
+			it( 'binds view.editable#isFocused', () => {
+				utils.assertBinding(
+					view.editable,
+					{ isFocused: false },
+					[
+						[ editable, { isFocused: true } ]
+					],
+					{ isFocused: true }
+				);
+			} );
+
+			it( 'binds view.editable#isReadOnly', () => {
+				utils.assertBinding(
+					view.editable,
+					{ isReadOnly: false },
+					[
+						[ editable, { isReadOnly: true } ]
+					],
+					{ isReadOnly: true }
+				);
+			} );
+		} );
+	} );
+
+	describe( 'init()', () => {
+		afterEach( () => {
+			return ui.destroy();
+		} );
+
+		it( 'returns a promise', () => {
+			document.body.appendChild( view.element );
+
+			const promise = ui.init().then( () => {
+				expect( promise ).to.be.instanceof( Promise );
+			} );
+
+			return promise;
+		} );
+
+		it( 'initializes the #view', () => {
+			const spy = sinon.spy( view, 'init' );
+
+			return ui.init().then( () => {
+				sinon.assert.calledOnce( spy );
+			} );
+		} );
+
+		it( 'fills view.toolbar#items with editor config', () => {
+			return ui.init().then( () => {
+				expect( view.toolbar.items ).to.have.length( 2 );
+				expect( view.toolbar.items.get( 0 ).name ).to.equal( 'foo' );
+				expect( view.toolbar.items.get( 1 ).name ).to.equal( 'bar' );
+			} );
+		} );
+	} );
+
+	describe( 'destroy()', () => {
+		beforeEach( () => {
+			document.body.appendChild( view.element );
+		} );
+
+		it( 'returns a promise', () => {
+			return ui.init().then( () => {
+				const promise = ui.destroy().then( () => {
+					expect( promise ).to.be.instanceof( Promise );
+				} );
+
+				return promise;
+			} );
+		} );
+
+		it( 'destroys the #view', () => {
+			const spy = sinon.spy( view, 'destroy' );
+
+			return ui.init()
+				.then( () => ui.destroy() )
+				.then( () => {
+					sinon.assert.calledOnce( spy );
+				} );
+		} );
+	} );
+} );
+
+function viewCreator( name ) {
+	return ( locale ) => {
+		const view = new View( locale );
+
+		view.name = name;
+
+		return view;
+	};
+}

+ 20 - 93
packages/ckeditor5-editor-classic/tests/classiceditoruiview.js

@@ -3,100 +3,48 @@
  * For licensing, see LICENSE.md.
  */
 
-/* globals document, Event */
+/* globals document */
 /* bender-tags: editor, browser-only */
 
 import ClassicEditorUIView from 'ckeditor5/editor-classic/classiceditoruiview.js';
-import ClassicTestEditor from 'tests/core/_utils/classictesteditor.js';
-
-import View from 'ckeditor5/ui/view.js';
 import StickyToolbarView from 'ckeditor5/ui/toolbar/sticky/stickytoolbarview.js';
 import InlineEditableUIView from 'ckeditor5/ui/editableui/inline/inlineeditableuiview.js';
-
-import testUtils from 'tests/utils/_utils/utils.js';
+import Locale from 'ckeditor5/utils/locale.js';
 
 describe( 'ClassicEditorUIView', () => {
-	let editorElement, editor, editable, view;
+	let locale, view;
 
 	beforeEach( () => {
-		editorElement = document.createElement( 'div' );
-		document.body.appendChild( editorElement );
-
-		editor = new ClassicTestEditor( editorElement, {
-			toolbar: [ 'foo', 'bar' ]
-		} );
-
-		editable = editor.editing.view.createRoot( document.createElement( 'div' ) );
-		editor.ui = view = new ClassicEditorUIView( editor, editor.locale );
-
-		function viewCreator( name ) {
-			return ( locale ) => {
-				const view = new View( locale );
-
-				view.name = name;
-
-				return view;
-			};
-		}
-
-		view.featureComponents.add( 'foo', viewCreator( 'foo' ) );
-		view.featureComponents.add( 'bar', viewCreator( 'bar' ) );
+		locale = new Locale( 'en' );
+		view = new ClassicEditorUIView( locale );
 	} );
 
 	describe( 'constructor()', () => {
-		describe( 'toolbar', () => {
-			it( 'creates toolbar', () => {
+		describe( '#toolbar', () => {
+			it( 'is created', () => {
 				expect( view.toolbar ).to.be.instanceof( StickyToolbarView );
 			} );
 
-			it( 'binds view.toolbar#isFocused to editor#focusTracker', () => {
-				editor.focusTracker.isFocused = false;
-				expect( view.toolbar.isActive ).to.false;
+			it( 'is given a locate object', () => {
+				expect( view.toolbar.locale ).to.equal( locale );
+			} );
 
-				editor.focusTracker.isFocused = true;
-				expect( view.toolbar.isActive ).to.true;
+			it( 'is put into the "top" collection', () => {
+				expect( view.top.get( 0 ) ).to.equal( view.toolbar );
 			} );
 		} );
 
-		describe( 'editable', () => {
-			it( 'creates view#editable', () => {
+		describe( '#editable', () => {
+			it( 'is created', () => {
 				expect( view.editable ).to.be.instanceof( InlineEditableUIView );
 			} );
 
-			it( 'registers editable#element in editor focus tracker', () => {
-				return view.init()
-					.then( () => {
-						editor.focusTracker.isFocused = false;
-
-						view.editable.element.dispatchEvent( new Event( 'focus' ) );
-						expect( editor.focusTracker.isFocused ).to.true;
-					} );
-			} );
-
-			it( 'sets view.editable#name', () => {
-				expect( view.editable.name ).to.equal( editable.rootName );
+			it( 'is given a locate object', () => {
+				expect( view.editable.locale ).to.equal( locale );
 			} );
 
-			it( 'binds view.editable#isFocused', () => {
-				testUtils.assertBinding(
-					view.editable,
-					{ isFocused: false },
-					[
-						[ editable, { isFocused: true } ]
-					],
-					{ isFocused: true }
-				);
-			} );
-
-			it( 'binds view.editable#isReadOnly', () => {
-				testUtils.assertBinding(
-					view.editable,
-					{ isReadOnly: false },
-					[
-						[ editable, { isReadOnly: true } ]
-					],
-					{ isReadOnly: true }
-				);
+			it( 'is put into the "main" collection', () => {
+				expect( view.main.get( 0 ) ).to.equal( view.editable );
 			} );
 		} );
 	} );
@@ -108,29 +56,8 @@ describe( 'ClassicEditorUIView', () => {
 			return view.init()
 				.then( () => {
 					expect( view.editableElement.getAttribute( 'contentEditable' ) ).to.equal( 'true' );
-				} );
-		} );
-	} );
-
-	describe( 'init', () => {
-		it( 'returns a promise', () => {
-			document.body.appendChild( view.element );
-
-			expect( view.init() ).to.be.instanceof( Promise );
-		} );
-
-		it( 'sets view.toolbar#limiterElement', () => {
-			return view.init().then( () => {
-				expect( view.toolbar.limiterElement ).to.equal( view.element );
-			} );
-		} );
-
-		it( 'fills view.toolbar#items with editor config', () => {
-			return view.init().then( () => {
-				expect( view.toolbar.items ).to.have.length( 2 );
-				expect( view.toolbar.items.get( 0 ).name ).to.equal( 'foo' );
-				expect( view.toolbar.items.get( 1 ).name ).to.equal( 'bar' );
-			} );
+				} )
+				.then( () => view.destroy() );
 		} );
 	} );
 } );