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 #79 from ckeditor/t/ckeditor5/479
Browse files Browse the repository at this point in the history
Feature: Enabled the classic editor placeholder (see ckeditor/ckeditor5#479).
  • Loading branch information
Piotr Jasiun authored Feb 7, 2019
2 parents 9b88989 + 77bfcd4 commit 3450c23
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 55 deletions.
3 changes: 1 addition & 2 deletions src/classiceditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class ClassicEditor extends Editor {

this.model.document.createRoot();

this.ui = new ClassicEditorUI( this, new ClassicEditorUIView( this.locale ) );
this.ui = new ClassicEditorUI( this, new ClassicEditorUIView( this.locale, this.editing.view ) );

attachToForm( this );
}
Expand Down Expand Up @@ -173,7 +173,6 @@ export default class ClassicEditor extends Editor {
resolve(
editor.initPlugins()
.then( () => editor.ui.init( isElement( sourceElementOrData ) ? sourceElementOrData : null ) )
.then( () => editor.editing.view.attachDomRoot( editor.ui.getEditableElement() ) )
.then( () => {
const initialData = isElement( sourceElementOrData ) ?
getDataFromElement( sourceElementOrData ) :
Expand Down
114 changes: 90 additions & 24 deletions src/classiceditorui.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 { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';
import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';

/**
Expand Down Expand Up @@ -67,9 +68,78 @@ export default class ClassicEditorUI extends EditorUI {
init( replacementElement ) {
const editor = this.editor;
const view = this.view;
const editingView = editor.editing.view;
const editable = view.editable;
const editingRoot = editingView.document.getRoot();

// 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.
editable.name = editingRoot.rootName;

view.render();

// 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 BalloonEditor.create().
const editableElement = editable.element;

// Register the editable UI view in the editor. A single editor instance can aggregate multiple
// editable areas (roots) but the classic 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 );

// If an element containing the initial data of the editor was provided, replace it with
// an editor instance's UI in DOM until the editor is destroyed. For instance, a <textarea>
// can be such element.
if ( replacementElement ) {
this._elementReplacer.replace( replacementElement, this.element );
}

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

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

this._elementReplacer.restore();
editingView.detachDomRoot( view.editable.name );
view.destroy();

super.destroy();
}

/**
* Initializes the editor toolbar.
*
* @private
*/
_initToolbar() {
const editor = this.editor;
const view = this.view;
const editingView = editor.editing.view;

// Set–up the sticky panel with toolbar.
view.stickyPanel.bind( 'isActive' ).to( this.focusTracker, 'isFocused' );
view.stickyPanel.limiterElement = view.element;
Expand All @@ -78,40 +148,36 @@ export default class ClassicEditorUI extends EditorUI {
view.stickyPanel.viewportTopOffset = this._toolbarConfig.viewportTopOffset;
}

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

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

this.focusTracker.add( view.editable.element );

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

enableToolbarKeyboardFocus( {
origin: editor.editing.view,
origin: editingView,
originFocusTracker: this.focusTracker,
originKeystrokeHandler: editor.keystrokes,
toolbar: view.toolbar
} );

if ( replacementElement ) {
this._elementReplacer.replace( replacementElement, this.element );
}

this.fire( 'ready' );
}

/**
* @inheritDoc
* Enable the placeholder text on the editing root, if any was configured.
*
* @private
*/
destroy() {
this._elementReplacer.restore();

this.view.destroy();

super.destroy();
_initPlaceholder() {
const editor = this.editor;
const editingView = editor.editing.view;
const editingRoot = editingView.document.getRoot();

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

if ( placeholderText ) {
enablePlaceholder( {
view: editingView,
element: editingRoot,
text: placeholderText,
isDirectHost: false
} );
}
}
}
5 changes: 3 additions & 2 deletions src/classiceditoruiview.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ export default class ClassicEditorUIView extends BoxedEditorUIView {
* Creates an instance of the classic editor UI view.
*
* @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.
* @param {module:engine/view/view~View} editingView The editing view instance this view is related to.
*/
constructor( locale ) {
constructor( locale, editingView ) {
super( locale );

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

/**
Expand Down
Loading

0 comments on commit 3450c23

Please sign in to comment.