|
@@ -12,7 +12,10 @@ import DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin
|
|
|
import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
|
|
import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
|
|
|
import DecoupledEditorUI from './decouplededitorui';
|
|
import DecoupledEditorUI from './decouplededitorui';
|
|
|
import DecoupledEditorUIView from './decouplededitoruiview';
|
|
import DecoupledEditorUIView from './decouplededitoruiview';
|
|
|
|
|
+import getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';
|
|
|
|
|
+import setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';
|
|
|
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#decoupled-editor decoupled editor} implementation.
|
|
* The {@glink builds/guides/overview#decoupled-editor decoupled editor} implementation.
|
|
@@ -28,11 +31,11 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
* In order to create a decoupled editor instance, use the static
|
|
* In order to create a decoupled editor instance, use the static
|
|
|
* {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`} method.
|
|
* {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`} method.
|
|
|
*
|
|
*
|
|
|
- * # Decoupled editor and document build
|
|
|
|
|
|
|
+ * # Decoupled editor and document editor build
|
|
|
*
|
|
*
|
|
|
* The decoupled editor can be used directly from source (if you installed the
|
|
* The decoupled editor can be used directly from source (if you installed the
|
|
|
* [`@ckeditor/ckeditor5-editor-decoupled`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-decoupled) package)
|
|
* [`@ckeditor/ckeditor5-editor-decoupled`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-decoupled) package)
|
|
|
- * but it is also available in the {@glink builds/guides/overview#document-editor document build}.
|
|
|
|
|
|
|
+ * but it is also available in the {@glink builds/guides/overview#document-editor document editor build}.
|
|
|
*
|
|
*
|
|
|
* {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from
|
|
* {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from
|
|
|
* source you need to take care of loading all plugins by yourself
|
|
* source you need to take care of loading all plugins by yourself
|
|
@@ -54,44 +57,80 @@ export default class DecoupledEditor extends Editor {
|
|
|
* {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`} method instead.
|
|
* {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`} method instead.
|
|
|
*
|
|
*
|
|
|
* @protected
|
|
* @protected
|
|
|
- * @param {String} data The data to be loaded into the editor.
|
|
|
|
|
|
|
+ * @param {HTMLElement|String} elementOrData The DOM element that serves as an editable.
|
|
|
|
|
+ * The data will be loaded from it and loaded back to it once the editor is destroyed.
|
|
|
|
|
+ * Alternatively, a data string to be loaded into the editor.
|
|
|
* @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
|
|
* @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.
|
|
|
*/
|
|
*/
|
|
|
- constructor( config ) {
|
|
|
|
|
|
|
+ constructor( elementOrData, config ) {
|
|
|
super( config );
|
|
super( config );
|
|
|
|
|
|
|
|
|
|
+ if ( isElement( elementOrData ) ) {
|
|
|
|
|
+ /**
|
|
|
|
|
+ * The element used as an editable. The data will be loaded from it and loaded back to
|
|
|
|
|
+ * it once the editor is destroyed.
|
|
|
|
|
+ *
|
|
|
|
|
+ * **Note:** The property is available only when such element has been passed
|
|
|
|
|
+ * to the {@link #constructor}.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @readonly
|
|
|
|
|
+ * @member {HTMLElement}
|
|
|
|
|
+ */
|
|
|
|
|
+ this.element = elementOrData;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
this.data.processor = new HtmlDataProcessor();
|
|
this.data.processor = new HtmlDataProcessor();
|
|
|
|
|
|
|
|
this.model.document.createRoot();
|
|
this.model.document.createRoot();
|
|
|
|
|
|
|
|
- this.ui = new DecoupledEditorUI( this, new DecoupledEditorUIView( this.locale ) );
|
|
|
|
|
|
|
+ this.ui = new DecoupledEditorUI( this, new DecoupledEditorUIView( this.locale, this.element ) );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Destroys the editor instance, releasing all resources used by it.
|
|
* Destroys the editor instance, releasing all resources used by it.
|
|
|
*
|
|
*
|
|
|
|
|
+ * **Note**: The decoupled editor does not remove the toolbar and editable when destroyed. You can
|
|
|
|
|
+ * do that yourself in the destruction chain:
|
|
|
|
|
+ *
|
|
|
|
|
+ * editor.destroy()
|
|
|
|
|
+ * .then( () => {
|
|
|
|
|
+ * // Remove the toolbar from DOM.
|
|
|
|
|
+ * editor.ui.view.toolbar.element.remove();
|
|
|
|
|
+ *
|
|
|
|
|
+ * // Remove the editable from DOM.
|
|
|
|
|
+ * editor.ui.view.editable.element.remove();
|
|
|
|
|
+ *
|
|
|
|
|
+ * console.log( 'Editor was destroyed' );
|
|
|
|
|
+ * } );
|
|
|
|
|
+ *
|
|
|
* @returns {Promise}
|
|
* @returns {Promise}
|
|
|
*/
|
|
*/
|
|
|
destroy() {
|
|
destroy() {
|
|
|
|
|
+ // Cache the data, then destroy.
|
|
|
|
|
+ // It's safe to assume that the model->view conversion will not work after super.destroy().
|
|
|
|
|
+ const data = this.getData();
|
|
|
|
|
+
|
|
|
this.ui.destroy();
|
|
this.ui.destroy();
|
|
|
|
|
|
|
|
- return super.destroy();
|
|
|
|
|
|
|
+ return super.destroy()
|
|
|
|
|
+ .then( () => {
|
|
|
|
|
+ if ( this.element ) {
|
|
|
|
|
+ setDataInElement( this.element, data );
|
|
|
|
|
+ }
|
|
|
|
|
+ } );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Creates a decoupled editor instance.
|
|
* Creates a decoupled editor instance.
|
|
|
*
|
|
*
|
|
|
- * Creating an instance when using the {@glink builds/index CKEditor build}:
|
|
|
|
|
|
|
+ * Creating an instance when using the {@glink builds/index CKEditor 5 build}:
|
|
|
*
|
|
*
|
|
|
* DecoupledEditor
|
|
* DecoupledEditor
|
|
|
- * .create( '<p>Editor data</p>', {
|
|
|
|
|
- * // The location of the toolbar in the DOM.
|
|
|
|
|
- * toolbarContainer: document.querySelector( 'body div.toolbar-container' ),
|
|
|
|
|
- *
|
|
|
|
|
- * // The location of the editable in the DOM.
|
|
|
|
|
- * editableContainer: document.querySelector( 'body div.editable-container' )
|
|
|
|
|
- * } )
|
|
|
|
|
|
|
+ * .create( document.querySelector( '#editor' ) )
|
|
|
* .then( editor => {
|
|
* .then( editor => {
|
|
|
|
|
+ * // Append the toolbar to the <body> element.
|
|
|
|
|
+ * document.body.appendChild( editor.ui.view.toolbar.element );
|
|
|
|
|
+ *
|
|
|
* console.log( 'Editor was initialized', editor );
|
|
* console.log( 'Editor was initialized', editor );
|
|
|
* } )
|
|
* } )
|
|
|
* .catch( err => {
|
|
* .catch( err => {
|
|
@@ -107,48 +146,48 @@ export default class DecoupledEditor extends Editor {
|
|
|
* import ...
|
|
* import ...
|
|
|
*
|
|
*
|
|
|
* DecoupledEditor
|
|
* DecoupledEditor
|
|
|
- * .create( '<p>Editor data</p>', {
|
|
|
|
|
|
|
+ * .create( document.querySelector( '#editor' ), {
|
|
|
* plugins: [ Essentials, Bold, Italic, ... ],
|
|
* plugins: [ Essentials, Bold, Italic, ... ],
|
|
|
- * toolbar: [ 'bold', 'italic', ... ],
|
|
|
|
|
- *
|
|
|
|
|
- * // The location of the toolbar in the DOM.
|
|
|
|
|
- * toolbarContainer: document.querySelector( 'div.toolbar-container' ),
|
|
|
|
|
- *
|
|
|
|
|
- * // The location of the editable in the DOM.
|
|
|
|
|
- * editableContainer: document.querySelector( 'div.editable-container' )
|
|
|
|
|
|
|
+ * toolbar: [ 'bold', 'italic', ... ]
|
|
|
* } )
|
|
* } )
|
|
|
* .then( editor => {
|
|
* .then( editor => {
|
|
|
|
|
+ * // Append the toolbar to the <body> element.
|
|
|
|
|
+ * document.body.appendChild( editor.ui.view.toolbar.element );
|
|
|
|
|
+ *
|
|
|
* console.log( 'Editor was initialized', editor );
|
|
* console.log( 'Editor was initialized', editor );
|
|
|
* } )
|
|
* } )
|
|
|
* .catch( err => {
|
|
* .catch( err => {
|
|
|
* console.error( err.stack );
|
|
* console.error( err.stack );
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
- * **Note**: The {@link module:core/editor/editorconfig~EditorConfig#toolbarContainer `config.toolbarContainer`} and
|
|
|
|
|
- * {@link module:core/editor/editorconfig~EditorConfig#editableContainer `config.editableContainer`} settings are optional.
|
|
|
|
|
- * It is possible to define the location of the UI elements manually once the editor is up and running:
|
|
|
|
|
|
|
+ * **Note**: It is possible to create the editor out of a pure data string. The editor will then render
|
|
|
|
|
+ * an editable element that must be inserted into the DOM for the editor to work properly:
|
|
|
*
|
|
*
|
|
|
* DecoupledEditor
|
|
* DecoupledEditor
|
|
|
* .create( '<p>Editor data</p>' )
|
|
* .create( '<p>Editor data</p>' )
|
|
|
* .then( editor => {
|
|
* .then( editor => {
|
|
|
- * console.log( 'Editor was initialized', editor );
|
|
|
|
|
- *
|
|
|
|
|
- * // Append the toolbar and editable straight into the <body> element.
|
|
|
|
|
|
|
+ * // Append the toolbar to the <body> element.
|
|
|
* document.body.appendChild( editor.ui.view.toolbar.element );
|
|
* document.body.appendChild( editor.ui.view.toolbar.element );
|
|
|
|
|
+ *
|
|
|
|
|
+ * // Append the editable to the <body> element.
|
|
|
* document.body.appendChild( editor.ui.view.editable.element );
|
|
* document.body.appendChild( editor.ui.view.editable.element );
|
|
|
|
|
+ *
|
|
|
|
|
+ * console.log( 'Editor was initialized', editor );
|
|
|
* } )
|
|
* } )
|
|
|
* .catch( err => {
|
|
* .catch( err => {
|
|
|
* console.error( err.stack );
|
|
* console.error( err.stack );
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
- * @param {String} data The data to be loaded into the editor.
|
|
|
|
|
|
|
+ * @param {HTMLElement|String} elementOrData The DOM element that serves as an editable.
|
|
|
|
|
+ * The data will be loaded from it and loaded back to it once the editor is destroyed.
|
|
|
|
|
+ * Alternatively, a data string to be loaded into the editor.
|
|
|
* @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-decoupled/decouplededitor~DecoupledEditor} instance.
|
|
* The promise returns the created {@link module:editor-decoupled/decouplededitor~DecoupledEditor} instance.
|
|
|
*/
|
|
*/
|
|
|
- static create( data, config ) {
|
|
|
|
|
|
|
+ static create( elementOrData, config ) {
|
|
|
return new Promise( resolve => {
|
|
return new Promise( resolve => {
|
|
|
- const editor = new this( config );
|
|
|
|
|
|
|
+ const editor = new this( elementOrData, config );
|
|
|
|
|
|
|
|
resolve(
|
|
resolve(
|
|
|
editor.initPlugins()
|
|
editor.initPlugins()
|
|
@@ -156,8 +195,9 @@ export default class DecoupledEditor extends Editor {
|
|
|
editor.ui.init();
|
|
editor.ui.init();
|
|
|
editor.fire( 'uiReady' );
|
|
editor.fire( 'uiReady' );
|
|
|
} )
|
|
} )
|
|
|
- .then( () => editor.editing.view.attachDomRoot( editor.ui.view.editableElement ) )
|
|
|
|
|
- .then( () => editor.data.init( data ) )
|
|
|
|
|
|
|
+ .then( () => {
|
|
|
|
|
+ editor.data.init( editor.element ? getDataFromElement( editor.element ) : elementOrData );
|
|
|
|
|
+ } )
|
|
|
.then( () => {
|
|
.then( () => {
|
|
|
editor.fire( 'dataReady' );
|
|
editor.fire( 'dataReady' );
|
|
|
editor.fire( 'ready' );
|
|
editor.fire( 'ready' );
|
|
@@ -169,51 +209,3 @@ export default class DecoupledEditor extends Editor {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
mix( DecoupledEditor, DataApiMixin );
|
|
mix( DecoupledEditor, DataApiMixin );
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * The configuration of the {@link module:editor-decoupled/decouplededitor~DecoupledEditor}.
|
|
|
|
|
- *
|
|
|
|
|
- * When specified, it controls the location of the {@link module:editor-decoupled/decouplededitoruiview~DecoupledEditorUIView#toolbar}:
|
|
|
|
|
- *
|
|
|
|
|
- * DecoupledEditor
|
|
|
|
|
- * .create( '<p>Hello world!</p>', {
|
|
|
|
|
- * // Append the toolbar to the <body> element.
|
|
|
|
|
- * toolbarContainer: document.body
|
|
|
|
|
- * } )
|
|
|
|
|
- * .then( editor => {
|
|
|
|
|
- * console.log( editor );
|
|
|
|
|
- * } )
|
|
|
|
|
- * .catch( error => {
|
|
|
|
|
- * console.error( error );
|
|
|
|
|
- * } );
|
|
|
|
|
- *
|
|
|
|
|
- * **Note**: If not specified, the toolbar must be manually injected into the DOM. See
|
|
|
|
|
- * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}
|
|
|
|
|
- * to learn more.
|
|
|
|
|
- *
|
|
|
|
|
- * @member {HTMLElement} module:core/editor/editorconfig~EditorConfig#toolbarContainer
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * The configuration of the {@link module:editor-decoupled/decouplededitor~DecoupledEditor}.
|
|
|
|
|
- *
|
|
|
|
|
- * When specified, it controls the location of the {@link module:editor-decoupled/decouplededitoruiview~DecoupledEditorUIView#editable}:
|
|
|
|
|
- *
|
|
|
|
|
- * DecoupledEditor
|
|
|
|
|
- * .create( '<p>Hello world!</p>', {
|
|
|
|
|
- * // Append the editable to the <body> element.
|
|
|
|
|
- * editableContainer: document.body
|
|
|
|
|
- * } )
|
|
|
|
|
- * .then( editor => {
|
|
|
|
|
- * console.log( editor );
|
|
|
|
|
- * } )
|
|
|
|
|
- * .catch( error => {
|
|
|
|
|
- * console.error( error );
|
|
|
|
|
- * } );
|
|
|
|
|
- *
|
|
|
|
|
- * **Note**: If not specified, the editable must be manually injected into the DOM. See
|
|
|
|
|
- * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}
|
|
|
|
|
- * to learn more.
|
|
|
|
|
- *
|
|
|
|
|
- * @member {HTMLElement} module:core/editor/editorconfig~EditorConfig#editableContainer
|
|
|
|
|
- */
|
|
|