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

Commit

Permalink
Merge 660d48d into 3f3c191
Browse files Browse the repository at this point in the history
  • Loading branch information
oleq committed Jan 23, 2019
2 parents 3f3c191 + 660d48d commit 26d8ad5
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/decouplededitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ export default class DecoupledEditor extends Editor {

this.model.document.createRoot();

this.ui = new DecoupledEditorUI( this, new DecoupledEditorUIView( this.locale, this.sourceElement ) );
const view = new DecoupledEditorUIView( this.locale, this.sourceElement, this.editing.view );
this.ui = new DecoupledEditorUI( this, view );
}

/**
Expand Down
91 changes: 74 additions & 17 deletions src/decouplededitorui.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import EditorUI from '@ckeditor/ckeditor5-core/src/editor/editorui';
import enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';
import normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig';
import { addPlaceholder, getRootPlaceholderElement } from '@ckeditor/ckeditor5-engine/src/view/placeholder';

/**
* The decoupled editor UI class.
Expand Down Expand Up @@ -59,38 +60,94 @@ export default class DecoupledEditorUI extends EditorUI {
init() {
const editor = this.editor;
const view = this.view;
const editingView = editor.editing.view;
const editable = view.editable;
const editingRoot = editingView.document.getRoot();

view.render();

// Set up the editable.
const editingRoot = editor.editing.view.document.getRoot();
view.editable.bind( 'isReadOnly' ).to( editingRoot );
view.editable.bind( 'isFocused' ).to( editor.editing.view.document );
editor.editing.view.attachDomRoot( view.editable.element );
view.editable.name = editingRoot.rootName;

this._editableElements.set( view.editable.name, view.editable.element );

this.focusTracker.add( view.editable.element );
// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.
// But it can be available earlier if a DOM element has been passed to DecoupledEditor.create().
const editableElement = editable.element;

this.view.toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );
// The editable UI and editing root should share the same name. Then name is used
// to recognize the particular editable, for instance in ARIA attributes.
view.editable.name = editingRoot.rootName;

enableToolbarKeyboardFocus( {
origin: editor.editing.view,
originFocusTracker: this.focusTracker,
originKeystrokeHandler: editor.keystrokes,
toolbar: this.view.toolbar
// Register the editable UI view in the editor. A single editor instance can aggregate multiple
// editable areas (roots) but the decoupled editor has only one.
this._editableElements.set( editable.name, editableElement );

// Let the global focus tracker know that the editable UI element is focusable and
// belongs to the editor. From now on, the focus tracker will sustain the editor focus
// as long as the editable is focused (e.g. the user is typing).
this.focusTracker.add( editableElement );

// Let the editable UI element respond to the changes in the global editor focus
// tracker. It has been added to the same tracker a few lines above but, in reality, there are
// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long
// as they have focus, the editable should act like it is focused too (although technically
// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.
// Doing otherwise will result in editable focus styles disappearing, once e.g. the
// toolbar gets focused.
view.editable.bind( 'isFocused' ).to( this.focusTracker );

// Bind the editable UI element to the editing view, making it an end– and entry–point
// of the editor's engine. This is where the engine meets the UI.
editingView.attachDomRoot( editableElement );

// The UI must wait until the data is ready to attach certain actions that operate
// on the editing view–level. They use the view writer to set attributes on the editable
// element and doing so before data is loaded into the model (ready) would destroy the
// original content.
editor.on( 'dataReady', () => {
view.editable.enableEditingRootListeners();

const placeholderText = editor.config.get( 'placeholder' ) ||
editor.sourceElement && editor.sourceElement.getAttribute( 'placeholder' );

if ( placeholderText ) {
const placeholderElement = getRootPlaceholderElement( editingRoot );

addPlaceholder( editingView, placeholderElement, placeholderText );
}
} );

this._initToolbar();
this.fire( 'ready' );
}

/**
* @inheritDoc
*/
destroy() {
this._view.destroy();
const view = this._view;
const editingView = this.editor.editing.view;

view.editable.disableEditingRootListeners();
editingView.detachDomRoot( view.editable.name );
view.destroy();

super.destroy();
}

/**
* Initializes the inline editor toolbar and its panel.
*
* @private
*/
_initToolbar() {
const editor = this.editor;
const view = this.view;
const toolbar = view.toolbar;

toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );

enableToolbarKeyboardFocus( {
origin: editor.editing.view,
originFocusTracker: this.focusTracker,
originKeystrokeHandler: editor.keystrokes,
toolbar
} );
}
}
4 changes: 2 additions & 2 deletions src/decouplededitoruiview.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class DecoupledEditorUIView extends EditorUIView {
* @param {HTMLElement} [editableElement] The editable element. If not specified, it will be automatically created by
* {@link module:ui/editableui/editableuiview~EditableUIView}. Otherwise, the given element will be used.
*/
constructor( locale, editableElement ) {
constructor( locale, editableElement, editingView ) {
super( locale );

/**
Expand All @@ -48,7 +48,7 @@ export default class DecoupledEditorUIView extends EditorUIView {
* @readonly
* @member {module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}
*/
this.editable = new InlineEditableUIView( locale, editableElement );
this.editable = new InlineEditableUIView( locale, editingView, editableElement );

// This toolbar may be placed anywhere in the page so things like font size need to be reset in it.
// Also because of the above, make sure the toolbar supports rounded corners.
Expand Down
3 changes: 3 additions & 0 deletions tests/manual/placeholder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div id="editor-1" placeholder="Placeholder from the attribute"></div>
<br />
<div id="editor-2" placeholder="Placeholder from the attribute"></div>
39 changes: 39 additions & 0 deletions tests/manual/placeholder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals console:false, document, window */

import DecoupledEditor from '../../src/decouplededitor';
import Enter from '@ckeditor/ckeditor5-enter/src/enter';
import Typing from '@ckeditor/ckeditor5-typing/src/typing';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Undo from '@ckeditor/ckeditor5-undo/src/undo';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';

window.editors = {};

function initEditor( element, placeholder ) {
DecoupledEditor
.create( element, {
plugins: [ Enter, Typing, Paragraph, Undo, Heading, Bold, Italic ],
toolbar: [ 'heading', '|', 'bold', 'italic', 'undo', 'redo' ],
placeholder
} )
.then( newEditor => {
console.log( 'Editor was initialized', newEditor );

element.parentNode.insertBefore( newEditor.ui.view.toolbar.element, element );

window.editors[ element.id ] = newEditor;
} )
.catch( err => {
console.error( err.stack );
} );
}

initEditor( document.querySelector( '#editor-1' ) );
initEditor( document.querySelector( '#editor-2' ), 'The placeholder from editor.config.placeholder' );
1 change: 1 addition & 0 deletions tests/manual/placeholder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO

0 comments on commit 26d8ad5

Please sign in to comment.