Skip to content

Commit

Permalink
Merge pull request #1600 from ckeditor/t/1599
Browse files Browse the repository at this point in the history
Docs: Improvements to the editor with multiple roots example and guide. Closes #1599.
  • Loading branch information
jodator authored Mar 26, 2019
2 parents 3da1bef + 87aa750 commit 806ff79
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 6 deletions.
7 changes: 7 additions & 0 deletions docs/_snippets/examples/multi-root-editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ <h3>Walking the capitals of Europe: Warsaw</h3>
</div>
</div>
</div>

<style>
/* Give the toolbar some space so it does not look like it belongs to the header root only. */
#snippet-inline-editor #toolbar {
margin-bottom: 1em;
}
</style>
58 changes: 55 additions & 3 deletions docs/_snippets/examples/multi-root-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,33 @@ class MultirootEditorUI extends EditorUI {
const editor = this.editor;
const editingView = editor.editing.view;

let lastFocusedEditableElement;

view.render();

// Keep track of the last focused editable element. Knowing which one was focused
// is useful when the focus moves from editable to other UI components like balloons
// (especially inputs) but the editable remains the "focus context" (e.g. link balloon
// attached to a link in an editable). In this case, the editable should preserve visual
// focus styles.
this.focusTracker.on( 'change:focusedElement', ( evt, name, focusedElement ) => {
for ( const editable of this.view.editables ) {
if ( editable.element === focusedElement ) {
lastFocusedEditableElement = editable.element;
}
}
} );

// If the focus tracker loses focus, stop tracking the last focused editable element.
// Wherever the focus is restored, it will no longer be in the context of that editable
// because the focus "came from the outside", as opposed to the focus moving from one element
// to another withing the editor UI.
this.focusTracker.on( 'change:isFocused', ( evt, name, isFocused ) => {
if ( !isFocused ) {
lastFocusedEditableElement = null;
}
} );

for ( const editable of this.view.editables ) {
// 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().
Expand All @@ -200,7 +225,29 @@ class MultirootEditorUI extends EditorUI {
// 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.
editable.bind( 'isFocused' ).to( this.focusTracker );
editable.bind( 'isFocused' ).to( this.focusTracker, 'isFocused', this.focusTracker, 'focusedElement',
( isFocused, focusedElement ) => {
// When the focus tracker is blurred, it means the focus moved out of the editor UI.
// No editable will maintain focus then.
if ( !isFocused ) {
return false;
}

// If the focus tracker says the editor UI is focused and currently focused element
// is the editable, then the editable should be visually marked as focused too.
if ( focusedElement === editableElement ) {
return true;
}
// If the focus tracker says the editor UI is focused but the focused element is
// not an editable, it is possible that the editable is still (context–)focused.
// For instance, the focused element could be an input inside of a balloon attached
// to the content in the editable. In such case, the editable should remain _visually_
// focused even though technically the focus is somewhere else. The focus moved from
// the editable to the input but the focus context remained the same.
else {
return lastFocusedEditableElement === editableElement;
}
} );

// 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.
Expand Down Expand Up @@ -261,7 +308,7 @@ class MultirootEditorUI extends EditorUI {
const editingRoot = editingView.document.getRoot( editable.name );
const sourceElement = this.getEditableElement( editable.name );

const placeholderText = editor.config.get( 'placeholder' ) ||
const placeholderText = editor.config.get( 'placeholder' )[ editable.name ] ||
sourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );

if ( placeholderText ) {
Expand Down Expand Up @@ -364,7 +411,12 @@ MultirootEditor
'mergeTableCells'
]
},
placeholder: 'Type your text here...',
placeholder: {
header: 'Header text goes here',
content: 'Type content here',
footerleft: 'Left footer content',
footerright: 'Right footer content'
},
cloudServices: CS_CONFIG
} )
.then( newEditor => {
Expand Down
58 changes: 55 additions & 3 deletions docs/framework/guides/custom-editor-creator.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,33 @@ class MultirootEditorUI extends EditorUI {
const editor = this.editor;
const editingView = editor.editing.view;

let lastFocusedEditableElement;

view.render();

// Keep track of the last focused editable element. Knowing which one was focused
// is useful when the focus moves from editable to other UI components like balloons
// (especially inputs) but the editable remains the "focus context" (e.g. link balloon
// attached to a link in an editable). In this case, the editable should preserve visual
// focus styles.
this.focusTracker.on( 'change:focusedElement', ( evt, name, focusedElement ) => {
for ( const editable of this.view.editables ) {
if ( editable.element === focusedElement ) {
lastFocusedEditableElement = editable.element;
}
}
} );

// If the focus tracker loses focus, stop tracking the last focused editable element.
// Wherever the focus is restored, it will no longer be in the context of that editable
// because the focus "came from the outside", as opposed to the focus moving from one element
// to another withing the editor UI.
this.focusTracker.on( 'change:isFocused', ( evt, name, isFocused ) => {
if ( !isFocused ) {
lastFocusedEditableElement = null;
}
} );

for ( const editable of this.view.editables ) {
// 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().
Expand All @@ -192,7 +217,29 @@ class MultirootEditorUI extends EditorUI {
// 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.
editable.bind( 'isFocused' ).to( this.focusTracker );
editable.bind( 'isFocused' ).to( this.focusTracker, 'isFocused', this.focusTracker, 'focusedElement',
( isFocused, focusedElement ) => {
// When the focus tracker is blurred, it means the focus moved out of the editor UI.
// No editable will maintain focus then.
if ( !isFocused ) {
return false;
}

// If the focus tracker says the editor UI is focused and currently focused element
// is the editable, then the editable should be visually marked as focused too.
if ( focusedElement === editableElement ) {
return true;
}
// If the focus tracker says the editor UI is focused but the focused element is
// not an editable, it is possible that the editable is still (context–)focused.
// For instance, the focused element could be an input inside of a balloon attached
// to the content in the editable. In such case, the editable should remain _visually_
// focused even though technically the focus is somewhere else. The focus moved from
// the editable to the input but the focus context remained the same.
else {
return lastFocusedEditableElement === editableElement;
}
} );

// 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.
Expand Down Expand Up @@ -253,7 +300,7 @@ class MultirootEditorUI extends EditorUI {
const editingRoot = editingView.document.getRoot( editable.name );
const sourceElement = this.getEditableElement( editable.name );

const placeholderText = editor.config.get( 'placeholder' ) ||
const placeholderText = editor.config.get( 'placeholder' )[ editable.name ] ||
sourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );

if ( placeholderText ) {
Expand Down Expand Up @@ -414,7 +461,12 @@ MultirootEditor
'mergeTableCells'
]
},
placeholder: 'Type your text here...'
placeholder: {
header: 'Header text goes here',
content: 'Type content here',
footerleft: 'Left footer content',
footerright: 'Right footer content'
},
} )
.then( newEditor => {
document.querySelector( '#toolbar' ).appendChild( newEditor.ui.view.toolbar.element );
Expand Down

0 comments on commit 806ff79

Please sign in to comment.