8
0
Просмотр исходного кода

Merge pull request #14 from ckeditor/t/10

Support for multiple editables and changes in editor infrastructure changes.
Piotrek Koszuliński 9 лет назад
Родитель
Сommit
3491888fc6

+ 7 - 0
packages/ckeditor5-ui/src/controller.js

@@ -115,6 +115,7 @@ export default class Controller {
 			.then( this._initCollections.bind( this ) )
 			.then( () => {
 				this.ready = true;
+				this.fire( 'ready' );
 			} );
 	}
 
@@ -215,3 +216,9 @@ export default class Controller {
 }
 
 utils.mix( Controller, EmitterMixin );
+
+/**
+ * Fired when the controller is fully initialized.
+ *
+ * @event ui.Controller#ready
+ */

+ 46 - 0
packages/ckeditor5-ui/src/creator-utils.js

@@ -0,0 +1,46 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+/**
+ * Creates and if needed (if not yet done) binds the editable UI to the {@link ckeditor5.Editable editable instance}.
+ *
+ * @param {ckeditor5.Editor} editor The editor instance.
+ * @param {ckeditor5.Editable} editable The editable instance with which the editable UI will be bound.
+ * @param {Function} EditableUI Editable UI controller constructor.
+ * @param {Function} EditableUIView Editable UI view constructor.
+ * @returns {ui.editableui.EditableUI} Instance of the editable UI.
+ */
+export function createEditableUI( editor, editable, EditableUI, EditableUIView ) {
+	const domElement = editable.domElement;
+	const editableUI = new EditableUI( editor, editable );
+	const editableUIView = new EditableUIView( editableUI.viewModel, editor.locale, domElement );
+
+	editableUI.view = editableUIView;
+
+	// If editable.domElement is set then the editable.bindTo() must've been already called.
+	if ( !domElement ) {
+		editable.listenTo( editableUI, 'ready', () => editable.bindTo( editableUIView.editableElement ) );
+	}
+
+	return editableUI;
+}
+
+/**
+ * Creates editor UI instance.
+ *
+ * @param {ckeditor5.Editor} editor The editor instance.
+ * @param {Function} Editor UI controller constructor.
+ * @param {Function} Editor UI view constructor.
+ */
+export function createEditorUI( editor, EditorUI, EditorUIView ) {
+	const editorUI = new EditorUI( editor );
+	const editorUIView = new EditorUIView( editorUI.viewModel, editor.locale );
+
+	editorUI.view = editorUIView;
+
+	return editorUI;
+}

+ 0 - 105
packages/ckeditor5-ui/src/editable/editable.js

@@ -1,105 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Controller from '../controller.js';
-import Model from '../model.js';
-import utils from '../../utils/utils.js';
-import ObservableMixin from '../../utils/observablemixin.js';
-
-/**
- * @memberOf ui.editable
- * @extends ui.Controller
- * @mixes utils.ObservaleMixin
- */
-export default class Editable extends Controller {
-	/**
-	 * Creates a new instance of the Editable class.
-	 *
-	 * @param editor
-	 */
-	constructor( editor ) {
-		super();
-
-		this.editor = editor;
-
-		/**
-		 * Whether the editable is in read-write or read-only mode.
-		 *
-		 * @member {Boolean} ui.editable.Editable#isEditable
-		 */
-		this.set( 'isEditable', true );
-
-		/**
-		 * Whether the editable is focused.
-		 *
-		 * @readonly
-		 * @member {Boolean} ui.editable.Editable#isFocused
-		 */
-		this.set( 'isFocused', false );
-	}
-
-	/**
-	 * The model for the editable view.
-	 *
-	 * @readonly
-	 * @type {ui.Model}
-	 */
-	get viewModel() {
-		if ( this._viewModel ) {
-			return this._viewModel;
-		}
-
-		const viewModel = new Model( {
-			isFocused: this.isFocused
-		} );
-		this._viewModel = viewModel;
-
-		viewModel.bind( 'isEditable' ).to( this );
-		this.bind( 'isFocused' ).to( viewModel );
-
-		return viewModel;
-	}
-
-	/**
-	 * Temporary implementation (waiting for integration with the data model).
-	 *
-	 * @param {String} data HTML to be loaded.
-	 */
-	setData( data ) {
-		this.view.editableElement.innerHTML = data;
-	}
-
-	/**
-	 * Temporary implementation (waiting for integration with the data model).
-	 *
-	 * @returns {String} HTML string.
-	 */
-	getData() {
-		return this.view.editableElement.innerHTML;
-	}
-}
-
-utils.mix( Editable, ObservableMixin );
-
-/**
- * The editable model interface.
- *
- * @memberOf ui.editable
- * @interface EditableModel
- */
-
-/**
- * Whether the editable has focus.
- *
- * @member {Boolean} ui.editable.EditableModel#isFocused
- */
-
-/**
- * Whether the editable is not in read-only mode.
- *
- * @member {Boolean} ui.editable.EditableModel#isEditable
- */

+ 1 - 1
packages/ckeditor5-ui/src/editable.jsdoc → packages/ckeditor5-ui/src/editableui.jsdoc

@@ -4,5 +4,5 @@
  */
 
 /**
- * @namespace ui.editable
+ * @namespace ui.editableUI
  */

+ 42 - 0
packages/ckeditor5-ui/src/editableui/editableui.js

@@ -0,0 +1,42 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Controller from '../controller.js';
+import Model from '../model.js';
+
+/**
+ * @memberOf ui.editableUI
+ * @extends ui.Controller
+ */
+export default class EditableUI extends Controller {
+	/**
+	 * Creates a new instance of the Editable class.
+	 *
+	 * @param {ckeditor5.Editor} editor The editor instance.
+	 * @param {utils.Observable} editableModel The model for the editable.
+	 */
+	constructor( editor, editableModel ) {
+		super();
+
+		/**
+		 * The editor instance.
+		 *
+		 * @readonly
+		 * @member {ckeditor5.Editor} ui.editableUI.EditableUI#editor
+		 */
+		this.editor = editor;
+
+		/**
+		 * The model for the view.
+		 *
+		 * @readonly
+		 * @member {ui.Model} ui.editableUI.EditableUI#viewModel
+		 */
+		this.viewModel = new Model();
+		this.viewModel.bind( 'isEditable', 'isFocused' ).to( editableModel );
+	}
+}

+ 15 - 13
packages/ckeditor5-ui/src/editable/editableview.js → packages/ckeditor5-ui/src/editableui/editableuiview.js

@@ -9,15 +9,25 @@ import View from '../view.js';
 import CKEditorError from '../../utils/ckeditorerror.js';
 
 /**
- * @memberOf ui.editable
+ * @memberOf ui.editableUI
  * @extends ui.View
  */
-export default class EditableView extends View {
+export default class EditableUIView extends View {
+	/**
+	 * Creates an instance of the EditableUIView class.
+	 *
+	 * @method constructor
+	 * @param {ui.Model} model (View)Model of this view.
+	 * @param {utils.Locale} [locale] The {@link ckeditor5.Editor#locale editor's locale} instance.
+	 * @param {HTMLElement} [editableElement] The editable element. If not specified the editable UI view
+	 * should create it. Otherwise, the existing element should be used.
+	 */
+
 	/**
 	 * The element which is the main editable element (usually the one with `contentEditable="true"`).
 	 *
 	 * @readonly
-	 * @member {HTMLElement} ui.editable.EditableView#editableElement
+	 * @member {HTMLElement} ui.editable.EditableUIView#editableElement
 	 */
 
 	/**
@@ -37,17 +47,9 @@ export default class EditableView extends View {
 		this.editableElement = editableElement;
 
 		this.applyTemplateToElement( editableElement, {
-			on: {
-				focus: () => {
-					this.model.isFocused = true;
-				},
-				blur: () => {
-					this.model.isFocused = false;
-				}
-			},
-
 			attributes: {
-				contentEditable: bind.to( 'isEditable' )
+				contentEditable: bind.to( 'isEditable' ),
+				class: [ bind.to( 'isFocused', value => value ? 'ck-focused' : 'ck-blurred' ) ]
 			}
 		} );
 	}

+ 9 - 0
packages/ckeditor5-ui/src/editorui/editorui.js

@@ -34,6 +34,15 @@ export default class EditorUI extends Controller {
 		 */
 		this.editor = editor;
 
+		/**
+		 * Property used by the [CKEditor UI library](https://github.com/ckeditor/ckeditor5-ui) for storing
+		 * the main UI controller.
+		 *
+		 * @readonly
+		 * @member {ui.editorui.EditorUI} ckeditor5.Editor#ui
+		 */
+		editor.ui = this;
+
 		/**
 		 * @readonly
 		 * @member {ui.ComponentFactory} ui.editorUI.EditorUI#featureComponents

+ 1 - 1
packages/ckeditor5-ui/src/view.js

@@ -24,7 +24,7 @@ const bindIfSymbol = Symbol( 'bindIf' );
  */
 export default class View {
 	/**
-	 * Creates an instance of the {@link View} class.
+	 * Creates an instance of the {@link ui.View} class.
 	 *
 	 * @param {ui.Model} model (View)Model of this View.
 	 * @param {utils.Locale} [locale] The {@link ckeditor5.Editor#locale editor's locale} instance.

+ 7 - 2
packages/ckeditor5-ui/tests/controller.js

@@ -56,11 +56,16 @@ describe( 'Controller', () => {
 				} );
 		} );
 
-		it( 'should set #ready flag', () => {
+		it( 'should set #ready flag and fire #ready event', () => {
 			const controller = new Controller();
+			const spy = sinon.spy( () => {
+				expect( controller ).to.have.property( 'ready', true );
+			} );
+
+			controller.on( 'ready', spy );
 
 			return controller.init().then( () => {
-				expect( controller.ready ).to.be.true;
+				expect( spy.calledOnce ).to.be.true;
 			} );
 		} );
 

+ 126 - 0
packages/ckeditor5-ui/tests/creator-utils.js

@@ -0,0 +1,126 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: ui */
+
+'use strict';
+
+import { createEditableUI, createEditorUI } from '/ckeditor5/ui/creator-utils.js';
+import ObservableMixin from '/ckeditor5/utils/observablemixin.js';
+import utils from '/ckeditor5/utils/utils.js';
+import Editor from '/ckeditor5/editor.js';
+import Controller from '/ckeditor5/ui/controller.js';
+import View from '/ckeditor5/ui/view.js';
+import Model from '/ckeditor5/ui/model.js';
+
+describe( 'creator-utils', () => {
+	let editor;
+
+	beforeEach( () => {
+		editor = new Editor();
+	} );
+
+	describe( 'createEditableUI', () => {
+		let editable;
+
+		class Editable {}
+		utils.mix( Editable, ObservableMixin );
+
+		class TestController extends Controller {
+			constructor( editor, editable ) {
+				super();
+
+				this.editor = editor;
+				this.editable = editable;
+
+				this.viewModel = new Model();
+			}
+		}
+
+		class TestView extends View {
+			constructor( model, locale, editableElement ) {
+				super( model, locale );
+
+				this.editableElement = editableElement;
+			}
+		}
+
+		beforeEach( () => {
+			editable = new Editable();
+			editable.bindTo = sinon.spy();
+		} );
+
+		it( 'creates an instance of editable UI', () => {
+			const editableUI = createEditableUI( editor, editable, TestController, TestView );
+
+			expect( editableUI ).to.be.instanceof( TestController );
+			expect( editableUI ).to.have.property( 'editor', editor );
+			expect( editableUI ).to.have.property( 'editable', editable );
+
+			const view = editableUI.view;
+			expect( view ).to.be.instanceof( TestView );
+			expect( view.model ).to.equal( editableUI.viewModel );
+			expect( view.editableElement ).to.be.undefined;
+			expect( view.locale ).to.equal( editor.locale );
+		} );
+
+		it( 'passes the editable.domElement to the view and do not try to bind it again', () => {
+			const editableElement = document.createElement( 'div' );
+
+			editable.domElement = editableElement;
+			editable.bindTo = sinon.spy();
+
+			const editableUI = createEditableUI( editor, editable, TestController, TestView );
+
+			expect( editableUI.view.editableElement ).to.equal( editableElement );
+			expect( editable.bindTo.callCount ).to.equal( 0 );
+		} );
+
+		it( 'passes the editable.domElement to the view and do not try to bind it again', () => {
+			const editableElement = document.createElement( 'div' );
+
+			editable.domElement = editableElement;
+
+			const editableUI = createEditableUI( editor, editable, TestController, TestView );
+
+			expect( editableUI.view.editableElement ).to.equal( editableElement );
+			expect( editable.bindTo.callCount ).to.equal( 0 );
+		} );
+
+		it( 'if editable.domElement is not yet defined, tries to bind the editable element', () => {
+			const editableElement = document.createElement( 'div' );
+			const editableUI = createEditableUI( editor, editable, TestController, TestView );
+
+			editableUI.view.editableElement = editableElement;
+			editableUI.fire( 'ready' );
+
+			expect( editable.bindTo.calledWith( editableElement ) ).to.be.true;
+		} );
+	} );
+
+	describe( 'createEditorUI', () => {
+		class TestController extends Controller {
+			constructor( editor ) {
+				super();
+
+				this.editor = editor;
+				this.viewModel = new Model();
+			}
+		}
+
+		class TestView extends View {}
+
+		it( 'creates an instance of the EditorUI', () => {
+			const editorUI = createEditorUI( editor, TestController, TestView );
+
+			expect( editorUI ).to.be.instanceof( TestController );
+			expect( editorUI.editor ).to.equal( editor );
+
+			expect( editorUI.view ).to.be.instanceof( TestView );
+			expect( editorUI.view.model ).to.equal( editorUI.viewModel );
+			expect( editorUI.view.locale ).to.equal( editor.locale );
+		} );
+	} );
+} );

+ 0 - 79
packages/ckeditor5-ui/tests/editable/editable.js

@@ -1,79 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: editable */
-
-'use strict';
-
-import Editor from '/ckeditor5/editor.js';
-import Editable from '/ckeditor5/ui/editable/editable.js';
-import Model from '/ckeditor5/ui/model.js';
-import testUtils from '/tests/utils/_utils/utils.js';
-
-describe( 'Editable', () => {
-	let editable, editor;
-
-	beforeEach( () => {
-		editor = new Editor();
-		editable = new Editable( editor );
-	} );
-
-	describe( 'constructor', () => {
-		it( 'sets all the properties', () => {
-			expect( editable ).to.have.property( 'editor', editor );
-			expect( editable ).to.have.property( 'isFocused', false );
-			expect( editable ).to.have.property( 'isEditable', true );
-		} );
-	} );
-
-	describe( 'viewModel', () => {
-		it( 'returns a model instance', () => {
-			expect( editable.viewModel ).to.be.an.instanceof( Model );
-		} );
-
-		it( 'always returns the same instance', () => {
-			expect( editable.viewModel ).to.equal( editable.viewModel );
-		} );
-
-		it( 'constains editable attributes', () => {
-			expect( editable.viewModel ).to.have.property( 'isEditable', true );
-			expect( editable.viewModel ).to.have.property( 'isFocused', false );
-		} );
-
-		it( 'binds this.isFocused to editable', () => {
-			testUtils.assertBinding(
-				editable,
-				{ isFocused: false },
-				[
-					[ editable.viewModel, { isFocused: true } ]
-				],
-				{ isFocused: true }
-			);
-		} );
-
-		it( 'binds editable.isEditable to itself', () => {
-			testUtils.assertBinding(
-				editable.viewModel,
-				{ isEditable: true },
-				[
-					[ editable, { isEditable: false } ]
-				],
-				{ isEditable: false }
-			);
-		} );
-	} );
-
-	// These are temporary implementation, so tests do nothing beside ensuring 100% CC.
-	describe( 'getData() and setData()', () => {
-		it( 'exist', () => {
-			editable.view = {
-				editableElement: document.createElement( 'div' )
-			};
-
-			editable.getData();
-			editable.setData();
-		} );
-	} );
-} );

+ 60 - 0
packages/ckeditor5-ui/tests/editableui/editableui.js

@@ -0,0 +1,60 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: editable */
+
+'use strict';
+
+import Editor from '/ckeditor5/editor.js';
+import Editable from '/ckeditor5/editable.js';
+import EditableUI from '/ckeditor5/ui/editableui/editableui.js';
+import Model from '/ckeditor5/ui/model.js';
+import testUtils from '/tests/utils/_utils/utils.js';
+
+describe( 'EditableUI', () => {
+	let editable, editableUI, editor;
+
+	beforeEach( () => {
+		editor = new Editor();
+		editable = new Editable( editor, 'foo' );
+		editableUI = new EditableUI( editor, editable );
+	} );
+
+	describe( 'constructor', () => {
+		it( 'sets all properties', () => {
+			expect( editableUI.editor ).to.equal( editor );
+			expect( editableUI.viewModel ).to.be.instanceof( Model );
+		} );
+	} );
+
+	describe( 'viewModel', () => {
+		it( 'constains observable attributes', () => {
+			expect( editableUI.viewModel ).to.have.property( 'isEditable', true );
+			expect( editableUI.viewModel ).to.have.property( 'isFocused', false );
+		} );
+
+		it( 'binds isFocused to editable.isFocused', () => {
+			testUtils.assertBinding(
+				editableUI.viewModel,
+				{ isFocused: false },
+				[
+					[ editable, { isFocused: true } ]
+				],
+				{ isFocused: true }
+			);
+		} );
+
+		it( 'binds isEditable to editable.isEditable', () => {
+			testUtils.assertBinding(
+				editableUI.viewModel,
+				{ isEditable: true },
+				[
+					[ editable, { isEditable: false } ]
+				],
+				{ isEditable: false }
+			);
+		} );
+	} );
+} );

+ 7 - 11
packages/ckeditor5-ui/tests/editable/editableview.js → packages/ckeditor5-ui/tests/editableui/editableuiview.js

@@ -8,15 +8,15 @@
 'use strict';
 
 import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
-import EditableView from '/ckeditor5/ui/editable/editableview.js';
+import EditableUIView from '/ckeditor5/ui/editableui/editableuiview.js';
 import Model from '/ckeditor5/ui/model.js';
 
-describe( 'EditableView', () => {
+describe( 'EditableUIView', () => {
 	let model, view, editableElement;
 
 	beforeEach( () => {
 		model = new Model( { isEditable: true, isFocused: false } );
-		view = new EditableView( model );
+		view = new EditableUIView( model );
 		editableElement = document.createElement( 'div' );
 
 		return view.init();
@@ -49,18 +49,14 @@ describe( 'EditableView', () => {
 			expect( editableElement.contentEditable ).to.equal( 'false' );
 		} );
 
-		it( 'sets the model.isFocused based on element#focus and element#blur events', () => {
+		it( 'sets the contentEditable attribute to model.isEditable', () => {
 			view.setEditableElement( editableElement );
 
-			expect( model.isFocused ).to.equal( false );
-
-			editableElement.dispatchEvent( new Event( 'focus' ) );
-
-			expect( model.isFocused ).to.equal( true );
+			expect( editableElement.classList.contains( 'ck-blurred' ) ).to.be.true;
 
-			editableElement.dispatchEvent( new Event( 'blur' ) );
+			model.isFocused = true;
 
-			expect( model.isFocused ).to.equal( false );
+			expect( editableElement.classList.contains( 'ck-focused' ) ).to.be.true;
 		} );
 	} );
 } );

+ 4 - 0
packages/ckeditor5-ui/tests/editorui/editorui.js

@@ -26,5 +26,9 @@ describe( 'EditorUI', () => {
 
 			expect( editorUI.collections.get( 'body' ) ).to.be.instanceof( ControllerCollection );
 		} );
+
+		it( 'sets editor.ui property', () => {
+			expect( editor ).to.have.property( 'ui', editorUI );
+		} );
 	} );
 } );