Răsfoiți Sursa

Prototyping.

Piotrek Koszuliński 10 ani în urmă
părinte
comite
7922d9fde9
23 a modificat fișierele cu 594 adăugiri și 1 ștergeri
  1. 42 0
      packages/ckeditor5-engine/src/creator.js
  2. 87 0
      packages/ckeditor5-engine/src/editable/editable.js
  3. 58 0
      packages/ckeditor5-engine/src/editable/view.js
  4. 10 1
      packages/ckeditor5-engine/src/editor.js
  5. 7 0
      packages/ckeditor5-engine/src/plugin.js
  6. 33 0
      packages/ckeditor5-engine/src/ui/ui.js
  7. 21 0
      packages/ckeditor5-engine/tests/_utils/ui/chrome/controller.js
  8. 23 0
      packages/ckeditor5-engine/tests/_utils/ui/chrome/view.js
  9. 22 0
      packages/ckeditor5-engine/tests/_utils/ui/chromeless/controller.js
  10. 19 0
      packages/ckeditor5-engine/tests/_utils/ui/editable/framed/controller.js
  11. 53 0
      packages/ckeditor5-engine/tests/_utils/ui/editable/framed/view.js
  12. 20 0
      packages/ckeditor5-engine/tests/_utils/ui/editable/inline/controller.js
  13. 22 0
      packages/ckeditor5-engine/tests/_utils/ui/editable/inline/view.js
  14. 0 0
      packages/ckeditor5-engine/tests/creator/creator.html
  15. 0 0
      packages/ckeditor5-engine/tests/creator/creator.js
  16. 41 0
      packages/ckeditor5-engine/tests/creator/manual/_utils/creator/classic.js
  17. 38 0
      packages/ckeditor5-engine/tests/creator/manual/_utils/creator/inline.js
  18. 8 0
      packages/ckeditor5-engine/tests/creator/manual/creator-classic.html
  19. 38 0
      packages/ckeditor5-engine/tests/creator/manual/creator-classic.js
  20. 3 0
      packages/ckeditor5-engine/tests/creator/manual/creator-classic.md
  21. 8 0
      packages/ckeditor5-engine/tests/creator/manual/creator-inline.html
  22. 38 0
      packages/ckeditor5-engine/tests/creator/manual/creator-inline.js
  23. 3 0
      packages/ckeditor5-engine/tests/creator/manual/creator-inline.md

+ 42 - 0
packages/ckeditor5-engine/src/creator.js

@@ -15,6 +15,48 @@ import Plugin from './plugin.js';
  */
 
 export default class Creator extends Plugin {
+	create() {
+		return this.editor.ui.init();
+	}
+
+	destroy() {
+		super.destroy();
+
+		if ( this._elementReplacement ) {
+			this.editor.element.style.display = '';
+			this._elementReplacement.remove();
+		}
+
+		const ui = this.editor.ui;
+		this.editor.ui = null;
+
+		return ui.destroy();
+	}
+
+	updateEditorElement() {
+		Creator.setDataInElement( this.editor.element, this.editor.getData() );
+	}
+
+	loadDataFromEditorElement() {
+		this.editor.setData( Creator.getDataFromElement( this.editor.element ) );
+	}
+
+	/**
+	 * @param {HTMLElement} [newElement]
+	 */
+	_replaceElement( newElement ) {
+		if ( !newElement ) {
+			newElement = this.editor.ui.chrome.view.element;
+		}
+
+		this._elementReplacement = newElement;
+
+		const editorEl = this.editor.element;
+
+		editorEl.style.display = 'none';
+		editorEl.parentNode.insertBefore( newElement, editorEl.nextSibling );
+	}
+
 	/**
 	 * Gets data from a given source element.
 	 *

+ 87 - 0
packages/ckeditor5-engine/src/editable/editable.js

@@ -0,0 +1,87 @@
+/**
+ * @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';
+
+/**
+ * @extends core.ui.Controller
+ * @mixins core.ObservableMixin
+ */
+export default class Editable extends Controller {
+	/**
+	 * Creates a new instance of the Editable class.
+	 * @constructor
+	 */
+	constructor() {
+		super();
+
+		/**
+		 * 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 );
+
+		/**
+		 * The parent editable of this editable
+		 *
+		 * @readonly
+		 * @property {Editable} parent
+		 */
+		this.parent = null;
+	}
+
+	/**
+	 * @protected
+	 */
+	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.setData( data );
+	}
+
+	/**
+	 * Temporary implementation (waiting for integration with the data model).
+	 *
+	 * @returns {String} HTML string.
+	 */
+	getData() {
+		return this.view.getData();
+	}
+}
+
+utils.mix( Editable, ObservableMixin );

+ 58 - 0
packages/ckeditor5-engine/src/editable/view.js

@@ -0,0 +1,58 @@
+/**
+ * @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"`).
+	 *
+	 * @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;
+		} );
+	}
+
+	/**
+	 * Temporary implementation (waiting for integration with the data model).
+	 *
+	 * @param {String} data HTML to be loaded.
+	 */
+	setData( data ) {
+		this.editableElement.innerHTML = data;
+	}
+
+	/**
+	 * Temporary implementation (waiting for integration with the data model).
+	 *
+	 * @returns {String} HTML string.
+	 */
+	getData() {
+		return this.editableElement.innerHTML;
+	}
+}

+ 10 - 1
packages/ckeditor5-engine/src/editor.js

@@ -62,8 +62,8 @@ export default class Editor {
 		/**
 		 * The chosen creator.
 		 *
-		 * @property {Creator} _creator
 		 * @protected
+		 * @property {Creator} _creator
 		 */
 	}
 
@@ -140,6 +140,7 @@ export default class Editor {
 		const that = this;
 
 		this.fire( 'destroy' );
+		this.stopListening();
 
 		return Promise.resolve()
 			.then( () => {
@@ -149,6 +150,14 @@ export default class Editor {
 				delete this.element;
 			} );
 	}
+
+	setData( data ) {
+		this.editable.setData( data );
+	}
+
+	getData() {
+		return this.editable.getData();
+	}
 }
 
 utils.mix( Editor, ObservableMixin );

+ 7 - 0
packages/ckeditor5-engine/src/plugin.js

@@ -50,6 +50,13 @@ export default class Plugin {
 	 * @returns {null/Promise}
 	 */
 	init() {}
+
+	/**
+	 * Destroys the plugin.
+	 *
+	 * TODO waits to be implemented (#186).
+	 */
+	destroy() {}
 }
 
 utils.mix( Plugin, ObservableMixin );

+ 33 - 0
packages/ckeditor5-engine/src/ui/ui.js

@@ -0,0 +1,33 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import ObservableMixin from '../observablemixin.js';
+import utils from '../utils.js';
+
+export default class Ui {
+	constructor( editor, chrome ) {
+		this.chrome = chrome;
+
+		this.set( 'width', editor.config.width );
+		this.set( 'height', editor.config.height );
+	}
+
+	init() {
+		return this.chrome.init();
+	}
+
+	destroy() {
+		const chrome = this.chrome;
+
+		this.stopListening();
+		this.chrome = null;
+
+		return chrome.destroy();
+	}
+}
+
+utils.mix( Ui, ObservableMixin );

+ 21 - 0
packages/ckeditor5-engine/tests/_utils/ui/chrome/controller.js

@@ -0,0 +1,21 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Model from '/ckeditor5/core/ui/model.js';
+import Controller from '/ckeditor5/core/ui/controller.js';
+import ControllerCollection from '/ckeditor5/core/ui/controllercollection.js';
+import ChromeView from './view.js';
+
+export default class ChromeController extends Controller {
+	constructor() {
+		const model = new Model();
+
+		super( model, new ChromeView( model ) );
+
+		this.collections.add( new ControllerCollection( 'main' ) );
+	}
+}

+ 23 - 0
packages/ckeditor5-engine/tests/_utils/ui/chrome/view.js

@@ -0,0 +1,23 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import View from '/ckeditor5/core/ui/view.js';
+
+export default class ChromeView extends View {
+	constructor( model ) {
+		super( model );
+
+		this.template = {
+			tag: 'div',
+			attrs: {
+				'class': [ 'ck-chrome' ]
+			}
+		};
+
+		this.register( 'main', el => el );
+	}
+}

+ 22 - 0
packages/ckeditor5-engine/tests/_utils/ui/chromeless/controller.js

@@ -0,0 +1,22 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Model from '/ckeditor5/core/ui/model.js';
+import Controller from '/ckeditor5/core/ui/controller.js';
+import ControllerCollection from '/ckeditor5/core/ui/controllercollection.js';
+import View from '/ckeditor5/core/ui/view.js';
+
+export default class ChromeLessController extends Controller {
+	constructor() {
+		const model = new Model();
+
+		super( model, new View( model ) );
+		this.view.register( 'editable', true );
+
+		this.collections.add( new ControllerCollection( 'editable' ) );
+	}
+}

+ 19 - 0
packages/ckeditor5-engine/tests/_utils/ui/editable/framed/controller.js

@@ -0,0 +1,19 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editable from '/ckeditor5/core/editable/editable.js';
+import FramedEditableView from './view.js';
+
+export default class FramedEditable extends Editable {
+	constructor( editor ) {
+		super( FramedEditableView );
+
+		this.viewModel.bind( 'width', 'height' ).to( editor.ui );
+
+		this.view = new FramedEditableView( this.viewModel );
+	}
+}

+ 53 - 0
packages/ckeditor5-engine/tests/_utils/ui/editable/framed/view.js

@@ -0,0 +1,53 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import EditableView from '/ckeditor5/core/editable/view.js';
+
+export default class FramedEditableView extends EditableView {
+	constructor( model ) {
+		super( model );
+
+		// Here's the tricky part - we must return the promise from init()
+		// because iframe loading may be asynchronous. However, we can't start
+		// listening to 'load' in init(), because at this point the element is already in the DOM
+		// and the 'load' event might already be fired.
+		// So here we store both - the promise and the deferred object so we're able to resolve
+		// the promise in _iframeLoaded.
+		this._iframePromise = new Promise( ( resolve, reject ) => {
+			this._iframeDeferred = { resolve, reject };
+		} );
+
+		this.template = {
+			tag: 'iframe',
+			attributes: {
+				class: [ 'ck-framededitable' ],
+				// It seems that we need to allow scripts in order to be able to listen to events.
+				// TODO: Research that. Perhaps the src must be set?
+				sandbox: 'allow-same-origin allow-scripts',
+				width: this.bindToAttribute( 'width' ),
+				height: this.bindToAttribute( 'height' )
+			},
+			on: {
+				load: 'loaded'
+			}
+		};
+
+		this.on( 'loaded', this._iframeLoaded, this );
+	}
+
+	init() {
+		super.init();
+
+		return this._iframePromise;
+	}
+
+	_iframeLoaded() {
+		this.setEditableElement( this.element.contentDocument.body );
+
+		this._iframeDeferred.resolve();
+	}
+}

+ 20 - 0
packages/ckeditor5-engine/tests/_utils/ui/editable/inline/controller.js

@@ -0,0 +1,20 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editable from '/ckeditor5/core/editable/editable.js';
+import InlineEditableView from './view.js';
+
+export default class InlineEditable extends Editable {
+	constructor( editor, editableElement ) {
+		super();
+
+		this.viewModel.bind( 'width', 'height' ).to( editor.ui );
+
+		this.view = new InlineEditableView( this.viewModel );
+		this.view.element = editableElement;
+	}
+}

+ 22 - 0
packages/ckeditor5-engine/tests/_utils/ui/editable/inline/view.js

@@ -0,0 +1,22 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import EditableView from '/ckeditor5/core/editable/view.js';
+
+export default class InlineEditableView extends EditableView {
+	init() {
+		this.setEditableElement( this.element );
+
+		super.init();
+	}
+
+	destroy() {
+		super.destroy();
+
+		this.editableElement.contentEditable = false;
+	}
+}

+ 0 - 0
packages/ckeditor5-engine/tests/creator.html → packages/ckeditor5-engine/tests/creator/creator.html


+ 0 - 0
packages/ckeditor5-engine/tests/creator.js → packages/ckeditor5-engine/tests/creator/creator.js


+ 41 - 0
packages/ckeditor5-engine/tests/creator/manual/_utils/creator/classic.js

@@ -0,0 +1,41 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Creator from '/ckeditor5/core/creator.js';
+import Ui from '/ckeditor5/core/ui/ui.js';
+import Chrome from '/tests/core/_utils/ui/chrome/controller.js';
+import FramedEditable from '/tests/core/_utils/ui/editable/framed/controller.js';
+
+export default class ClassicCreator extends Creator {
+	constructor( editor ) {
+		super( editor );
+
+		editor.ui = new Ui( editor, new Chrome() );
+	}
+
+	create() {
+		this._replaceElement();
+		this._setupEditable();
+
+		return super.create()
+			.then( () => this.loadDataFromEditorElement() );
+	}
+
+	destroy() {
+		this.updateEditorElement();
+
+		return super.destroy();
+	}
+
+	_setupEditable() {
+		const editor = this.editor;
+		const editable = new FramedEditable( editor );
+
+		this.editor.editable = editable;
+		this.editor.ui.chrome.collections.get( 'main' ).add( editable );
+	}
+}

+ 38 - 0
packages/ckeditor5-engine/tests/creator/manual/_utils/creator/inline.js

@@ -0,0 +1,38 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Creator from '/ckeditor5/core/creator.js';
+import Ui from '/ckeditor5/core/ui/ui.js';
+import ChromeLess from '/tests/core/_utils/ui/chromeless/controller.js';
+import InlineEditable from '/tests/core/_utils/ui/editable/inline/controller.js';
+
+export default class InlineCreator extends Creator {
+	constructor( editor ) {
+		super( editor );
+
+		editor.ui = new Ui( editor, new ChromeLess() );
+	}
+
+	create() {
+		this._setupEditable();
+
+		return super.create()
+			.then( () => this.loadDataFromEditorElement() );
+	}
+
+	destroy() {
+		this.updateEditorElement();
+
+		return super.destroy();
+	}
+
+	_setupEditable() {
+		this.editor.editable = new InlineEditable( this.editor, this.editor.element );
+
+		this.editor.ui.chrome.collections.get( 'editable' ).add( this.editor.editable );
+	}
+}

+ 8 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-classic.html

@@ -0,0 +1,8 @@
+<div id="editor">
+	<h1>Hello world!</h1>
+	<p>This is an editor instance.</p>
+</div>
+
+<button id="destroyEditor">Destroy editor</button>
+<button id="initEditor">Init editor</button>
+

+ 38 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-classic.js

@@ -0,0 +1,38 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global console:false */
+
+'use strict';
+
+import CKEDITOR from '/ckeditor.js';
+import ClassicCreator from '/tests/core/creator/manual/_utils/creator/classic.js';
+
+let editor;
+
+function initEditor() {
+	CKEDITOR.create( '#editor', {
+		creator: ClassicCreator
+	} )
+	.then( ( newEditor ) => {
+		console.log( 'Editor was initialized', newEditor );
+		console.log( 'You can now play with it using global `editor` variable.' );
+
+		window.editor = editor = newEditor;
+	} );
+}
+
+function destroyEditor() {
+	editor.destroy()
+		.then( () => {
+			window.editor = null;
+			editor = null;
+
+			console.log( 'Editor was destroyed' );
+		} );
+}
+
+document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
+document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );

+ 3 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-classic.md

@@ -0,0 +1,3 @@
+@bender-ui: collapsed
+
+Do you see the editor?

+ 8 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-inline.html

@@ -0,0 +1,8 @@
+<div id="editor">
+	<h1>Hello world!</h1>
+	<p>This is an editor instance.</p>
+</div>
+
+<button id="destroyEditor">Destroy editor</button>
+<button id="initEditor">Init editor</button>
+

+ 38 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-inline.js

@@ -0,0 +1,38 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global console:false */
+
+'use strict';
+
+import CKEDITOR from '/ckeditor.js';
+import InlineCreator from '/tests/core/creator/manual/_utils/creator/inline.js';
+
+let editor;
+
+function initEditor() {
+	CKEDITOR.create( '#editor', {
+		creator: InlineCreator
+	} )
+	.then( ( newEditor ) => {
+		console.log( 'Editor was initialized', newEditor );
+		console.log( 'You can now play with it using global `editor` variable.' );
+
+		window.editor = editor = newEditor;
+	} );
+}
+
+function destroyEditor() {
+	editor.destroy()
+		.then( () => {
+			window.editor = null;
+			editor = null;
+
+			console.log( 'Editor was destroyed' );
+		} );
+}
+
+document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
+document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );

+ 3 - 0
packages/ckeditor5-engine/tests/creator/manual/creator-inline.md

@@ -0,0 +1,3 @@
+@bender-ui: collapsed
+
+Do you see the editor?