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

Merge pull request #19 from ckeditor/t/18

Feature: Editor can now be created with initial data passed to the `create()` method. Closes #18.

BREAKING CHANGE: The `BalloonEditor#element` property was renamed to `BalloonEditor#sourceElement`
Piotrek Koszuliński 7 лет назад
Родитель
Сommit
b3cfcaa482

+ 62 - 11
packages/ckeditor5-editor-balloon/src/ballooneditor.js

@@ -18,6 +18,7 @@ import DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin
 import ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';
 import ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';
 import attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';
 import attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
+import isElement from '@ckeditor/ckeditor5-utils/src/lib/lodash/isElement';
 
 
 /**
 /**
  * The {@glink builds/guides/overview#balloon-editor balloon editor} implementation (Medium-like editor).
  * The {@glink builds/guides/overview#balloon-editor balloon editor} implementation (Medium-like editor).
@@ -54,14 +55,17 @@ export default class BalloonEditor extends Editor {
 	 * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method instead.
 	 * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method instead.
 	 *
 	 *
 	 * @protected
 	 * @protected
-	 * @param {HTMLElement} element The DOM element that will be the source for the created editor
-	 * (on which the editor will be initialized).
+	 * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor
+	 * (on which the editor will be initialized) or initial data for the editor. For more information see
+	 * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.
 	 * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
 	 * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
 	 */
 	 */
-	constructor( element, config ) {
+	constructor( sourceElementOrData, config ) {
 		super( config );
 		super( config );
 
 
-		this.element = element;
+		if ( isElement( sourceElementOrData ) ) {
+			this.sourceElement = sourceElementOrData;
+		}
 
 
 		this.config.get( 'plugins' ).push( BalloonToolbar );
 		this.config.get( 'plugins' ).push( BalloonToolbar );
 		this.config.define( 'balloonToolbar', this.config.get( 'toolbar' ) );
 		this.config.define( 'balloonToolbar', this.config.get( 'toolbar' ) );
@@ -70,11 +74,18 @@ export default class BalloonEditor extends Editor {
 
 
 		this.model.document.createRoot();
 		this.model.document.createRoot();
 
 
-		this.ui = new BalloonEditorUI( this, new BalloonEditorUIView( this.locale, element ) );
+		this.ui = new BalloonEditorUI( this, new BalloonEditorUIView( this.locale, this.sourceElement ) );
 
 
 		attachToForm( this );
 		attachToForm( this );
 	}
 	}
 
 
+	/**
+	 * @inheritDoc
+	 */
+	get element() {
+		return this.ui.view.editable.element;
+	}
+
 	/**
 	/**
 	 * Destroys the editor instance, releasing all resources used by it.
 	 * Destroys the editor instance, releasing all resources used by it.
 	 *
 	 *
@@ -90,7 +101,11 @@ export default class BalloonEditor extends Editor {
 		this.ui.destroy();
 		this.ui.destroy();
 
 
 		return super.destroy()
 		return super.destroy()
-			.then( () => setDataInElement( this.element, data ) );
+			.then( () => {
+				if ( this.sourceElement ) {
+					setDataInElement( this.sourceElement, data );
+				}
+			} );
 	}
 	}
 
 
 	/**
 	/**
@@ -127,15 +142,45 @@ export default class BalloonEditor extends Editor {
 	 *				console.error( err.stack );
 	 *				console.error( err.stack );
 	 *			} );
 	 *			} );
 	 *
 	 *
-	 * @param {HTMLElement} element The DOM element that will be the source for the created editor
-	 * (on which the editor will be initialized).
+	 * Creating instance when using initial data instead of a DOM element:
+	 *
+	 *		import BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';
+	 *		import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
+	 *		import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
+	 *		import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
+	 *		import ...
+	 *
+	 *		BalloonEditor
+	 *			.create( '<p>Hello world!</p>', {
+	 *				plugins: [ Essentials, Bold, Italic, ... ],
+	 *				toolbar: [ 'bold', 'italic', ... ]
+	 *			} )
+	 *			.then( editor => {
+	 *				console.log( 'Editor was initialized', editor );
+	 *
+	 *				// Initial data was provided so `editor.element` needs to be added manually to the DOM.
+	 *				document.body.appendChild( editor.element );
+	 *			} )
+	 *			.catch( err => {
+	 *				console.error( err.stack );
+	 *			} );
+	 *
+	 * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor
+	 * (on which the editor will be initialized) or initial data for the editor.
+	 *
+	 * If a source element is passed, then its contents will be automatically
+	 * {@link module:editor-classic/ballooneditor~BalloonEditor#setData loaded} to the editor on startup and the element
+	 * itself will be used as the editor's editable element.
+	 *
+	 * If data is provided, then `editor.element` will be created automatically and needs to be added
+	 * to the DOM manually.
 	 * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
 	 * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
 	 * @returns {Promise} A promise resolved once the editor is ready.
 	 * @returns {Promise} A promise resolved once the editor is ready.
 	 * The promise returns the created {@link module:editor-balloon/ballooneditor~BalloonEditor} instance.
 	 * The promise returns the created {@link module:editor-balloon/ballooneditor~BalloonEditor} instance.
 	 */
 	 */
-	static create( element, config ) {
+	static create( sourceElementOrData, config ) {
 		return new Promise( resolve => {
 		return new Promise( resolve => {
-			const editor = new this( element, config );
+			const editor = new this( sourceElementOrData, config );
 
 
 			resolve(
 			resolve(
 				editor.initPlugins()
 				editor.initPlugins()
@@ -143,7 +188,13 @@ export default class BalloonEditor extends Editor {
 						editor.ui.init();
 						editor.ui.init();
 						editor.fire( 'uiReady' );
 						editor.fire( 'uiReady' );
 					} )
 					} )
-					.then( () => editor.data.init( getDataFromElement( element ) ) )
+					.then( () => {
+						const initialData = isElement( sourceElementOrData ) ?
+							getDataFromElement( sourceElementOrData ) :
+							sourceElementOrData;
+
+						return editor.data.init( initialData );
+					} )
 					.then( () => {
 					.then( () => {
 						editor.fire( 'dataReady' );
 						editor.fire( 'dataReady' );
 						editor.fire( 'ready' );
 						editor.fire( 'ready' );

+ 3 - 0
packages/ckeditor5-editor-balloon/src/ballooneditoruiview.js

@@ -20,6 +20,9 @@ export default class BalloonEditorUIView extends EditorUIView {
 	 * Creates an instance of the balloon editor UI view.
 	 * Creates an instance of the balloon editor UI view.
 	 *
 	 *
 	 * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.
 	 * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.
+	 * @param {HTMLElement} [editableElement] The editable element. If not specified, the
+	 * {@link module:ui/editableui/editableuiview~EditableUIView}
+	 * will create it. Otherwise, the existing element will be used.
 	 */
 	 */
 	constructor( locale, editableElement ) {
 	constructor( locale, editableElement ) {
 		super( locale );
 		super( locale );

+ 40 - 1
packages/ckeditor5-editor-balloon/tests/ballooneditor.js

@@ -102,6 +102,34 @@ describe( 'BalloonEditor', () => {
 				} );
 				} );
 			} );
 			} );
 		} );
 		} );
+
+		it( 'allows to pass data to the constructor', () => {
+			return BalloonEditor.create( '<p>Hello world!</p>', {
+				plugins: [ Paragraph ]
+			} ).then( editor => {
+				expect( editor.getData() ).to.equal( '<p>Hello world!</p>' );
+			} );
+		} );
+
+		it( 'should have undefined the #sourceElement if editor was initialized with data', () => {
+			return BalloonEditor
+				.create( '<p>Foo.</p>', {
+					plugins: [ Paragraph, Bold ]
+				} )
+				.then( newEditor => {
+					expect( newEditor.sourceElement ).to.be.undefined;
+
+					return newEditor.destroy();
+				} );
+		} );
+
+		it( 'editor.element should contain the whole editor (with UI) element', () => {
+			return BalloonEditor.create( '<p>Hello world!</p>', {
+				plugins: [ Paragraph ]
+			} ).then( editor => {
+				expect( editor.editing.view.getDomRoot() ).to.equal( editor.element );
+			} );
+		} );
 	} );
 	} );
 
 
 	describe( 'create()', () => {
 	describe( 'create()', () => {
@@ -128,7 +156,10 @@ describe( 'BalloonEditor', () => {
 		} );
 		} );
 
 
 		it( 'attaches editable UI as view\'s DOM root', () => {
 		it( 'attaches editable UI as view\'s DOM root', () => {
-			expect( editor.editing.view.getDomRoot() ).to.equal( editor.ui.view.editable.element );
+			const domRoot = editor.editing.view.getDomRoot();
+
+			expect( domRoot ).to.equal( editor.element );
+			expect( domRoot ).to.equal( editor.ui.view.editable.element );
 		} );
 		} );
 
 
 		it( 'creates the UI using BalloonEditorUI classes', () => {
 		it( 'creates the UI using BalloonEditorUI classes', () => {
@@ -276,5 +307,13 @@ describe( 'BalloonEditor', () => {
 						.to.equal( '<p>a</p><heading>b</heading>' );
 						.to.equal( '<p>a</p><heading>b</heading>' );
 				} );
 				} );
 		} );
 		} );
+
+		it( 'should not throw an error if editor was initialized with the data', () => {
+			return BalloonEditor
+				.create( '<p>Foo.</p>', {
+					plugins: [ Paragraph, Bold ]
+				} )
+				.then( newEditor => newEditor.destroy() );
+		} );
 	} );
 	} );
 } );
 } );

+ 19 - 0
packages/ckeditor5-editor-balloon/tests/manual/ballooneditor-data.html

@@ -0,0 +1,19 @@
+<p>
+	<button id="destroyEditors">Destroy editors</button>
+	<button id="initEditor">Init editor</button>
+</p>
+
+<div class="container"></div>
+
+<style>
+	body {
+		width: 10000px;
+		height: 10000px;
+	}
+
+
+	.container {
+		padding: 20px;
+		width: 500px;
+	}
+</style>

+ 43 - 0
packages/ckeditor5-editor-balloon/tests/manual/ballooneditor-data.js

@@ -0,0 +1,43 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* globals console:false, document, window */
+
+import BalloonEditor from '../../src/ballooneditor';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
+
+window.editors = [];
+const container = document.querySelector( '.container' );
+let counter = 1;
+
+function initEditor() {
+	BalloonEditor
+		.create( `<h2>Editor ${ counter }</h2><p>This is an editor instance.</p>`, {
+			plugins: [ ArticlePluginSet ],
+			toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ]
+		} )
+		.then( editor => {
+			counter += 1;
+			window.editors.push( editor );
+			container.appendChild( editor.element );
+		} )
+		.catch( err => {
+			console.error( err.stack );
+		} );
+}
+
+function destroyEditors() {
+	window.editors.forEach( editor => {
+		editor.destroy()
+			.then( () => {
+				editor.element.remove();
+			} );
+	} );
+	window.editors = [];
+	counter = 1;
+}
+
+document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
+document.getElementById( 'destroyEditors' ).addEventListener( 'click', destroyEditors );

+ 3 - 0
packages/ckeditor5-editor-balloon/tests/manual/ballooneditor-data.md

@@ -0,0 +1,3 @@
+1. Click "Init editor".
+2. New editor instance should be appended to the document with initial data in it. You can create more than one editor.
+3. After clicking "Destroy editors" all editors should be removed from the document.