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

Commit

Permalink
Merge pull request #38 from ckeditor/t/37
Browse files Browse the repository at this point in the history
Feature: Editor can now be created with initial data passed to the constructor. Closes #37.

BREAKING CHANGE: The `InlineEditor#element` property was renamed to `InlineEditor#sourceElement`. See ckeditor/ckeditor5-core#64.
  • Loading branch information
Reinmar committed Jul 3, 2018
2 parents c148346 + 6e17bbf commit cfd8c53
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 15 deletions.
74 changes: 61 additions & 13 deletions src/inlineeditor.js
Expand Up @@ -17,6 +17,7 @@ import InlineEditorUIView from './inlineeditoruiview';
import setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';
import getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';
import mix from '@ckeditor/ckeditor5-utils/src/mix';
import isElement from '@ckeditor/ckeditor5-utils/src/lib/lodash/isElement';

/**
* The {@glink builds/guides/overview#inline-editor inline editor} implementation.
Expand Down Expand Up @@ -53,24 +54,34 @@ export default class InlineEditor extends Editor {
* {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.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} 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-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}.
* @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
*/
constructor( element, config ) {
constructor( sourceElementOrData, config ) {
super( config );

this.element = element;

this.data.processor = new HtmlDataProcessor();

this.model.document.createRoot();

this.ui = new InlineEditorUI( this, new InlineEditorUIView( this.locale, element ) );
if ( isElement( sourceElementOrData ) ) {
this.sourceElement = sourceElementOrData;
}

this.ui = new InlineEditorUI( this, new InlineEditorUIView( this.locale, this.sourceElement ) );

attachToForm( this );
}

/**
* @inheritDoc
*/
get element() {
return this.ui.view.editable.element;
}

/**
* Destroys the editor instance, releasing all resources used by it.
*
Expand All @@ -86,11 +97,15 @@ export default class InlineEditor extends Editor {
this.ui.destroy();

return super.destroy()
.then( () => setDataInElement( this.element, data ) );
.then( () => {
if ( this.sourceElement ) {
setDataInElement( this.sourceElement, data );
}
} );
}

/**
* Creates a inline editor instance.
* Creates an inline editor instance.
*
* Creating instance when using {@glink builds/index CKEditor build}:
*
Expand Down Expand Up @@ -123,23 +138,56 @@ export default class InlineEditor 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 a DOM element:
*
* import InlineEditor from '@ckeditor/ckeditor5-editor-inline/src/inlineeditor';
* 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 ...
*
* InlineEditor
* .create( '<p>Hello world!</p>' )
* .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/inlineeditor~InlineEditor#setData loaded} to the editor on startup and the element
* itself will be used as the editor's editable element.
*
* If a data is provided, then `editor.element` will be created automatically and needs to be added
* manually to the DOM.
* @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-inline/inlineeditor~InlineEditor} instance.
*/
static create( element, config ) {
static create( sourceElementOrData, config ) {
return new Promise( resolve => {
const editor = new this( element, config );
const editor = new this( sourceElementOrData, config );

resolve(
editor.initPlugins()
.then( () => {
editor.ui.init();
editor.fire( 'uiReady' );
} )
.then( () => editor.data.init( getDataFromElement( element ) ) )
.then( () => {
const initialData = isElement( sourceElementOrData ) ?
getDataFromElement( sourceElementOrData ) :
sourceElementOrData;

return editor.data.init( initialData );
} )
.then( () => {
editor.fire( 'dataReady' );
editor.fire( 'ready' );
Expand Down
36 changes: 34 additions & 2 deletions tests/inlineeditor.js
Expand Up @@ -54,11 +54,11 @@ describe( 'InlineEditor', () => {
} );

it( 'has a Data Interface', () => {
testUtils.isMixed( InlineEditor, DataApiMixin );
expect( testUtils.isMixed( InlineEditor, DataApiMixin ) ).to.be.true;
} );

it( 'has a Element Interface', () => {
testUtils.isMixed( InlineEditor, ElementApiMixin );
expect( testUtils.isMixed( InlineEditor, ElementApiMixin ) ).to.be.true;
} );

it( 'creates main root element', () => {
Expand Down Expand Up @@ -95,6 +95,30 @@ describe( 'InlineEditor', () => {
} );
} );
} );

it( 'allows to pass data to the constructor', () => {
return InlineEditor.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 InlineEditor.create( '<p>Hello world!</p>', {
plugins: [ Paragraph ]
} ).then( editor => {
expect( editor.sourceElement ).to.be.undefined;
} );
} );

it( 'editor.element should contain the whole editor (with UI) element', () => {
return InlineEditor.create( '<p>Hello world!</p>', {
plugins: [ Paragraph ]
} ).then( editor => {
expect( editor.editing.view.getDomRoot() ).to.equal( editor.element );
} );
} );
} );

describe( 'create()', () => {
Expand Down Expand Up @@ -264,5 +288,13 @@ describe( 'InlineEditor', () => {
.to.equal( '<p>a</p><heading>b</heading>' );
} );
} );

it( 'should not throw an error if editor was initialized with the data', () => {
return InlineEditor
.create( '<p>Foo.</p>', {
plugins: [ Paragraph, Bold ]
} )
.then( newEditor => newEditor.destroy() );
} );
} );
} );
18 changes: 18 additions & 0 deletions tests/manual/inlineeditor-data.html
@@ -0,0 +1,18 @@
<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/inlineeditor-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 InlineEditor from '../../src/inlineeditor';
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';

window.editors = [];
const container = document.querySelector( '.container' );
let counter = 1;

function initEditor() {
InlineEditor
.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/inlineeditor-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 editor" all editors should be removed from the document.

0 comments on commit cfd8c53

Please sign in to comment.