Kaynağa Gözat

Merge branch 't/52b'. Closes #52, closes #53, closes #202.

Aleksander Nowodzinski 10 yıl önce
ebeveyn
işleme
86316304e2

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

@@ -0,0 +1,90 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Controller from '../ui/controller.js';
+import Model from '../ui/model.js';
+import utils from '../utils.js';
+import ObservableMixin from '../observablemixin.js';
+
+/**
+ * @class core.editable.Editable
+ * @extends core.ui.Controller
+ * @mixins core.ObservableMixin
+ */
+export default class Editable extends Controller {
+	/**
+	 * Creates a new instance of the Editable class.
+	 *
+	 * @constructor
+	 */
+	constructor( editor ) {
+		super();
+
+		this.editor = editor;
+
+		/**
+		 * Whether the editable is in read-write or read-only mode.
+		 *
+		 * @property {Boolean} isEditable
+		 */
+		this.set( 'isEditable', true );
+
+		/**
+		 * Whether the editable is focused.
+		 *
+		 * @readonly
+		 * @property {Boolean} isFocused
+		 */
+		this.set( 'isFocused', false );
+
+		/**
+		 * @private {Model} _viewModel
+		 */
+	}
+
+	/**
+	 * The model for the editable view.
+	 *
+	 * @readonly
+	 * @property {core.ui.Model} viewModel
+	 */
+	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 );

+ 41 - 0
packages/ckeditor5-ui/src/editable/editableview.js

@@ -0,0 +1,41 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import View from '../ui/view.js';
+import CKEditorError from '../ckeditorerror.js';
+
+export default class EditableView extends View {
+	/**
+	 * The element which is the main editable element (usually the one with `contentEditable="true"`).
+	 *
+	 * @readonly
+	 * @property {HTMLElement} editableElement
+	 */
+
+	setEditableElement( editableElement ) {
+		if ( this.editableElement ) {
+			throw new CKEditorError(
+				'editableview-cannot-override-editableelement: The editableElement cannot be overriden.'
+			);
+		}
+
+		this.editableElement = editableElement;
+		this.editableElement.contentEditable = this.model.isEditable;
+
+		this.listenTo( editableElement, 'focus', () => {
+			this.model.isFocused = true;
+		} );
+
+		this.listenTo( editableElement, 'blur', () => {
+			this.model.isFocused = false;
+		} );
+
+		this.listenTo( this.model, 'change:isEditable', ( evt, value ) => {
+			editableElement.contentEditable = value;
+		} );
+	}
+}

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

@@ -0,0 +1,32 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Controller from './ui/controller.js';
+import utils from './utils.js';
+import ObservableMixin from './observablemixin.js';
+
+/**
+ * Base class for the editor main view controllers.
+ *
+ * @class core.EditorUI
+ * @extends core.ui.Controller
+ * @mixins core.ObservableMixin
+ */
+
+export default class EditorUI extends Controller {
+	constructor( editor ) {
+		super();
+
+		/**
+		 * @readonly
+		 * @property {core.Editor}
+		 */
+		this.editor = editor;
+	}
+}
+
+utils.mix( EditorUI, ObservableMixin );

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

@@ -0,0 +1,79 @@
+/**
+ * @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/core/editor.js';
+import Editable from '/ckeditor5/core/editable/editable.js';
+import Model from '/ckeditor5/core/ui/model.js';
+import coreTestUtils from '/tests/core/_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', () => {
+			coreTestUtils.assertBinding(
+				editable,
+				{ isFocused: false },
+				[
+					[ editable.viewModel, { isFocused: true } ]
+				],
+				{ isFocused: true }
+			);
+		} );
+
+		it( 'binds editable.isEditable to itself', () => {
+			coreTestUtils.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();
+		} );
+	} );
+} );

+ 66 - 0
packages/ckeditor5-ui/tests/editable/editableview.js

@@ -0,0 +1,66 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: editable */
+
+'use strict';
+
+import CKEditorError from '/ckeditor5/core/ckeditorerror.js';
+import EditableView from '/ckeditor5/core/editable/editableview.js';
+import Model from '/ckeditor5/core/ui/model.js';
+
+describe( 'EditableView', () => {
+	let model, view, editableElement;
+
+	beforeEach( () => {
+		model = new Model( { isEditable: true, isFocused: false } );
+		view = new EditableView( model );
+		editableElement = document.createElement( 'div' );
+
+		return view.init();
+	} );
+
+	describe( 'setEditableElement', () => {
+		it( 'sets the editableElement property', () => {
+			view.setEditableElement( editableElement );
+
+			expect( view ).to.have.property( 'editableElement', editableElement );
+		} );
+
+		it( 'throws when trying to use it twice', () => {
+			view.setEditableElement( editableElement );
+
+			expect( view ).to.have.property( 'editableElement', editableElement );
+
+			expect( () => {
+				view.setEditableElement( editableElement );
+			} ).to.throw( CKEditorError, /^editableview-cannot-override-editableelement/ );
+		} );
+
+		it( 'sets the contentEditable attribute to model.isEditable', () => {
+			view.setEditableElement( editableElement );
+
+			expect( editableElement.contentEditable ).to.equal( 'true' );
+
+			model.isEditable = false;
+
+			expect( editableElement.contentEditable ).to.equal( 'false' );
+		} );
+
+		it( 'sets the model.isFocused based on element#focus and element#blur events', () => {
+			view.setEditableElement( editableElement );
+
+			expect( model.isFocused ).to.equal( false );
+
+			editableElement.dispatchEvent( new Event( 'focus' ) );
+
+			expect( model.isFocused ).to.equal( true );
+
+			editableElement.dispatchEvent( new Event( 'blur' ) );
+
+			expect( model.isFocused ).to.equal( false );
+		} );
+	} );
+} );

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

@@ -0,0 +1,24 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editor from '/ckeditor5/core/editor.js';
+import EditorUI from '/ckeditor5/core/editorui.js';
+
+describe( 'EditorUI', () => {
+	let editor, editorUI;
+
+	beforeEach( () => {
+		editor = new Editor();
+		editorUI = new EditorUI( editor );
+	} );
+
+	describe( 'constructor', () => {
+		it( 'sets all the properties', () => {
+			expect( editorUI ).to.have.property( 'editor', editor );
+		} );
+	} );
+} );

+ 3 - 31
packages/ckeditor5-ui/tests/observablemixin.js

@@ -6,12 +6,15 @@
 'use strict';
 'use strict';
 
 
 import testUtils from '/tests/_utils/utils.js';
 import testUtils from '/tests/_utils/utils.js';
+import coreTestUtils from '/tests/core/_utils/utils.js';
 import ObservableMixin from '/ckeditor5/core/observablemixin.js';
 import ObservableMixin from '/ckeditor5/core/observablemixin.js';
 import EmitterMixin from '/ckeditor5/core/emittermixin.js';
 import EmitterMixin from '/ckeditor5/core/emittermixin.js';
 import EventInfo from '/ckeditor5/core/eventinfo.js';
 import EventInfo from '/ckeditor5/core/eventinfo.js';
 import CKEditorError from '/ckeditor5/core/ckeditorerror.js';
 import CKEditorError from '/ckeditor5/core/ckeditorerror.js';
 import utils from '/ckeditor5/core/utils.js';
 import utils from '/ckeditor5/core/utils.js';
 
 
+const assertBinding = coreTestUtils.assertBinding;
+
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 
 describe( 'ObservableMixin', () => {
 describe( 'ObservableMixin', () => {
@@ -781,35 +784,4 @@ describe( 'Observable', () => {
 			);
 			);
 		} );
 		} );
 	} );
 	} );
-
-	// Syntax given that observable `A` is bound to observables [`B`, `C`, ...]:
-	//
-	//		assertBinding( A,
-	//			{ initial `A` attributes },
-	//			[
-	//				[ B, { new `B` attributes } ],
-	//				[ C, { new `C` attributes } ],
-	//				...
-	//			],
-	//			{ `A` attributes after [`B`, 'C', ...] changed }
-	//		);
-	//
-	function assertBinding( observable, stateBefore, data, stateAfter ) {
-		let key, pair;
-
-		for ( key in stateBefore ) {
-			expect( observable[ key ] ).to.be.equal( stateBefore[ key ] );
-		}
-
-		// Change attributes of bound observables.
-		for ( pair of data ) {
-			for ( key in pair[ 1 ] ) {
-				pair[ 0 ][ key ] = pair[ 1 ][ key ];
-			}
-		}
-
-		for ( key in stateAfter ) {
-			expect( observable[ key ] ).to.be.equal( stateAfter[ key ] );
-		}
-	}
 } );
 } );