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 #61 from ckeditor/t/60
Browse files Browse the repository at this point in the history
Feature: The toolbar should support a vertical offset from the top of the web page. Closes #60.
  • Loading branch information
Reinmar authored Jul 24, 2017
2 parents 71fef28 + ac3adee commit 6739afc
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 11 deletions.
18 changes: 17 additions & 1 deletion src/classiceditorui.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';
import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
import enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';
import normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig';

/**
* The classic editor UI class.
Expand Down Expand Up @@ -44,6 +45,14 @@ export default class ClassicEditorUI {
*/
this.focusTracker = new FocusTracker();

/**
* A normalized `config.toolbar` object.
*
* @type {Object}
* @private
*/
this._toolbarConfig = normalizeToolbarConfig( editor.config.get( 'toolbar' ) );

// Set–up the view.
view.set( 'width', editor.config.get( 'ui.width' ) );
view.set( 'height', editor.config.get( 'ui.height' ) );
Expand All @@ -52,6 +61,10 @@ export default class ClassicEditorUI {
view.toolbar.bind( 'isActive' ).to( this.focusTracker, 'isFocused' );
view.toolbar.limiterElement = view.element;

if ( this._toolbarConfig && this._toolbarConfig.viewportTopOffset ) {
view.toolbar.viewportTopOffset = this._toolbarConfig.viewportTopOffset;
}

// Setup the editable.
const editingRoot = editor.editing.createRoot( 'div' );
view.editable.bind( 'isReadOnly' ).to( editingRoot );
Expand All @@ -67,7 +80,10 @@ export default class ClassicEditorUI {
const editor = this.editor;

this.view.init();
this.view.toolbar.fillFromConfig( editor.config.get( 'toolbar' ), this.componentFactory );

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

enableToolbarKeyboardFocus( {
origin: editor.editing.view,
Expand Down
87 changes: 77 additions & 10 deletions tests/classiceditorui.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,29 @@ describe( 'ClassicEditorUI', () => {
editorElement = document.createElement( 'div' );
document.body.appendChild( editorElement );

editor = new ClassicTestEditor( editorElement, {
return ClassicTestEditor.create( editorElement, {
toolbar: [ 'foo', 'bar' ],
ui: {
width: 100,
height: 200
}
} )
.then( newEditor => {
editor = newEditor;

view = new ClassicEditorUIView( editor.locale );
ui = new ClassicEditorUI( editor, view );
editable = editor.editing.view.getRoot();

ui.componentFactory.add( 'foo', viewCreator( 'foo' ) );
ui.componentFactory.add( 'bar', viewCreator( 'bar' ) );
} );
} );

view = new ClassicEditorUIView( editor.locale );
ui = new ClassicEditorUI( editor, view );
editable = editor.editing.view.getRoot();
afterEach( () => {
editorElement.remove();

ui.componentFactory.add( 'foo', viewCreator( 'foo' ) );
ui.componentFactory.add( 'bar', viewCreator( 'bar' ) );
editor.destroy();
} );

describe( 'constructor()', () => {
Expand Down Expand Up @@ -77,6 +86,35 @@ describe( 'ClassicEditorUI', () => {
it( 'sets view.toolbar#limiterElement', () => {
expect( view.toolbar.limiterElement ).to.equal( view.element );
} );

it( 'doesn\'t set view.toolbar#viewportTopOffset, if not specified in the config', () => {
expect( view.toolbar.viewportTopOffset ).to.equal( 0 );
} );

it( 'sets view.toolbar#viewportTopOffset, when specified in the config', () => {
editorElement = document.createElement( 'div' );
document.body.appendChild( editorElement );

return ClassicTestEditor.create( editorElement, {
toolbar: {
items: [ 'foo', 'bar' ],
viewportTopOffset: 100
}
} )
.then( editor => {
view = new ClassicEditorUIView( editor.locale );
ui = new ClassicEditorUI( editor, view );
editable = editor.editing.view.getRoot();

ui.componentFactory.add( 'foo', viewCreator( 'foo' ) );
ui.componentFactory.add( 'bar', viewCreator( 'bar' ) );

expect( view.toolbar.viewportTopOffset ).to.equal( 100 );

editorElement.remove();
return editor.destroy();
} );
} );
} );

describe( 'editable', () => {
Expand Down Expand Up @@ -127,11 +165,40 @@ describe( 'ClassicEditorUI', () => {
sinon.assert.calledOnce( spy );
} );

it( 'fills view.toolbar#items with editor config', () => {
const spy = testUtils.sinon.spy( view.toolbar, 'fillFromConfig' );
describe( 'view.toolbar#items', () => {
it( 'are filled with the config.toolbar (specified as an Array)', () => {
const spy = testUtils.sinon.spy( view.toolbar, 'fillFromConfig' );

ui.init();
sinon.assert.calledWithExactly( spy, editor.config.get( 'toolbar' ), ui.componentFactory );
ui.init();
sinon.assert.calledWithExactly( spy, editor.config.get( 'toolbar' ), ui.componentFactory );
} );

it( 'are filled with the config.toolbar (specified as an Object)', () => {
editorElement = document.createElement( 'div' );
document.body.appendChild( editorElement );

return ClassicTestEditor.create( editorElement, {
toolbar: {
items: [ 'foo', 'bar' ],
viewportTopOffset: 100
}
} )
.then( editor => {
view = new ClassicEditorUIView( editor.locale );
ui = new ClassicEditorUI( editor, view );

ui.componentFactory.add( 'foo', viewCreator( 'foo' ) );
ui.componentFactory.add( 'bar', viewCreator( 'bar' ) );

const spy = testUtils.sinon.spy( view.toolbar, 'fillFromConfig' );

ui.init();
sinon.assert.calledWithExactly( spy,
editor.config.get( 'toolbar.items' ),
ui.componentFactory
);
} );
} );
} );

it( 'initializes keyboard navigation between view#toolbar and view#editable', () => {
Expand Down
3 changes: 3 additions & 0 deletions tests/classiceditoruiview.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ describe( 'ClassicEditorUIView', () => {
it( 'returns editable\'s view element', () => {
document.body.appendChild( view.element );

view.toolbar.limiterElement = view.element;
view.init();

expect( view.editableElement.getAttribute( 'contentEditable' ) ).to.equal( 'true' );

view.destroy();
} );
} );
Expand Down
37 changes: 37 additions & 0 deletions tests/manual/tickets/60/1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div id="editor">
<h2>Hello world!</h2>
<p>This is an editor instance.</p>
<p>This is an editor instance.</p>
<p>This is an editor instance.</p>
<p>This is an editor instance.</p>
<p>This is an editor instance.</p>
<p>This is an editor instance.</p>
</div>

<div id="fixed">The toolbar should stick to me instead of the viewport.</div>

<style>
body {
height: 10000px;
}

.ck-editor {
margin-top: 200px;
margin-left: 100px;
margin-bottom: 200px;
width: 450px;
}

#fixed {
width: 100%;
height: 100px;
position: fixed;
top: 0;
z-index: 9999;
background: green;
opacity: .8;
color: #fff;
box-sizing: border-box;
padding: 40px;
}
</style>
32 changes: 32 additions & 0 deletions tests/manual/tickets/60/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

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

import ClassicEditor from '../../../../src/classiceditor';
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';

ClassicEditor.create( document.querySelector( '#editor' ), {
plugins: [ Enter, Typing, Paragraph, Undo, Heading, Bold, Italic ],
toolbar: {
items: [ 'headings', 'bold', 'italic', 'undo', 'redo' ],
viewportTopOffset: 100
}
} )
.then( newEditor => {
console.log( 'Editor was initialized', newEditor );
console.log( 'You can now play with it using global `editor` and `editable` variables.' );

window.editor = newEditor;
} )
.catch( err => {
console.error( err.stack );
} );
20 changes: 20 additions & 0 deletions tests/manual/tickets/60/1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
### The toolbar should support a vertical offset from the top of the web page [#60](https://github.com/ckeditor/ckeditor5-editor-classic/issues/60)

## Focus then scroll

1. Focus the editor.
2. Scroll the web page until the toolbar reaches the green box boundaries.

**Expected:**

1. The toolbar should stick to the green box instead of the viewport edge, respecting `toolbar.viewportTopOffset` configuration.
2. At some point, the toolbar should disappear below the green box, leaving some space for the last paragraph of the content to remain visible.

## Scroll then focus

1. Scroll the web page until the toolbar is underneath the green box.
2. Focus the editor.

**Expected:**

1. The toolbar should stick to the lower boundary of the green box.

0 comments on commit 6739afc

Please sign in to comment.