Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Allow to pass initial data to the editor constructor #19

Merged
merged 13 commits into from
Jul 3, 2018
63 changes: 53 additions & 10 deletions src/ballooneditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin
import ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';
import attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';
import mix from '@ckeditor/ckeditor5-utils/src/mix';
import isElement from '@ckeditor/ckeditor5-utils/src/lib/lodash/isElement';
import global from '@ckeditor/ckeditor5-utils/src/dom/global';

/**
* The {@glink builds/guides/overview#balloon-editor balloon editor} implementation (Medium-like editor).
Expand Down Expand Up @@ -54,14 +56,30 @@ export default class BalloonEditor extends Editor {
* {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method instead.
*
* @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} elementOrData 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 data is provided, `editor.element`
* will be created automatically and need to be added manually to the DOM. For more information see
* {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.
* @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
*/
constructor( element, config ) {
constructor( elementOrData, config ) {
super( config );

this.element = element;
/**
* The element on which the editor has been initialized.
* If editor was initialized with data instead of HTMLElement this property will keep a reference to newly
* created element that need to be added manually to the DOM. For more information see
* {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.
*
* @readonly
* @member {HTMLElement} #element
*/

if ( isElement( elementOrData ) ) {
this.element = elementOrData;
} else {
this.element = global.document.createElement( 'div' );
}

this.config.get( 'plugins' ).push( BalloonToolbar );
this.config.define( 'balloonToolbar', this.config.get( 'toolbar' ) );
Expand All @@ -70,7 +88,7 @@ export default class BalloonEditor extends Editor {

this.model.document.createRoot();

this.ui = new BalloonEditorUI( this, new BalloonEditorUIView( this.locale, element ) );
this.ui = new BalloonEditorUI( this, new BalloonEditorUIView( this.locale, this.element ) );

attachToForm( this );
}
Expand Down Expand Up @@ -127,23 +145,48 @@ export default class BalloonEditor extends Editor {
* 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 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} elementOrData 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 data is provided, `editor.element`
* will be created automatically and need to be added manually to the DOM. The element is initialized as a `div`
* element crated in current document's context.
* @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
* @returns {Promise} A promise resolved once the editor is ready.
* The promise returns the created {@link module:editor-balloon/ballooneditor~BalloonEditor} instance.
*/
static create( element, config ) {
static create( elementOrData, config ) {
return new Promise( resolve => {
const editor = new this( element, config );
const editor = new this( elementOrData, config );

resolve(
editor.initPlugins()
.then( () => {
editor.ui.init();
editor.fire( 'uiReady' );
} )
.then( () => editor.data.init( getDataFromElement( element ) ) )
.then( () => editor.data.init( isElement( elementOrData ) ? getDataFromElement( elementOrData ) : elementOrData ) )
.then( () => {
editor.fire( 'dataReady' );
editor.fire( 'ready' );
Expand Down
20 changes: 19 additions & 1 deletion tests/ballooneditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* For licensing, see LICENSE.md.
*/

/* globals document, Event */
/* globals document, Event, HTMLElement */

import BalloonEditorUI from '../src/ballooneditorui';
import BalloonEditorUIView from '../src/ballooneditoruiview';
Expand Down Expand Up @@ -102,6 +102,24 @@ 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( 'editor.element should contain created div element', () => {
return BalloonEditor.create( '<p>Hello world!</p>', {
plugins: [ Paragraph ]
} ).then( editor => {
expect( editor.element ).to.be.instanceOf( HTMLElement );
expect( editor.element.tagName ).to.equal( 'DIV' );
expect( editor.editing.view.getDomRoot() ).to.equal( editor.element );
} );
} );
} );

describe( 'create()', () => {
Expand Down
19 changes: 19 additions & 0 deletions tests/manual/ballooneditor-data.html
Original file line number Diff line number Diff line change
@@ -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 changes: 43 additions & 0 deletions tests/manual/ballooneditor-data.js
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions tests/manual/ballooneditor-data.md
Original file line number Diff line number Diff line change
@@ -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.