From 8a57a5cd0339678829d9dde396130c625bde8983 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Thu, 20 Jul 2017 12:42:10 +0200 Subject: [PATCH 1/4] Tests: Added manual test for #60. --- tests/manual/tickets/60/1.html | 37 ++++++++++++++++++++++++++++++++++ tests/manual/tickets/60/1.js | 32 +++++++++++++++++++++++++++++ tests/manual/tickets/60/1.md | 20 ++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 tests/manual/tickets/60/1.html create mode 100644 tests/manual/tickets/60/1.js create mode 100644 tests/manual/tickets/60/1.md diff --git a/tests/manual/tickets/60/1.html b/tests/manual/tickets/60/1.html new file mode 100644 index 0000000..1028ea3 --- /dev/null +++ b/tests/manual/tickets/60/1.html @@ -0,0 +1,37 @@ +
+

Hello world!

+

This is an editor instance.

+

This is an editor instance.

+

This is an editor instance.

+

This is an editor instance.

+

This is an editor instance.

+

This is an editor instance.

+
+ +
The toolbar should stick to me instead of the viewport.
+ + diff --git a/tests/manual/tickets/60/1.js b/tests/manual/tickets/60/1.js new file mode 100644 index 0000000..1af79d1 --- /dev/null +++ b/tests/manual/tickets/60/1.js @@ -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' ], + verticalOffset: 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 ); +} ); diff --git a/tests/manual/tickets/60/1.md b/tests/manual/tickets/60/1.md new file mode 100644 index 0000000..b0e95d9 --- /dev/null +++ b/tests/manual/tickets/60/1.md @@ -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. From 02f01dc9a9cae64d69e3fdfb132a603370967cb9 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Thu, 20 Jul 2017 13:14:57 +0200 Subject: [PATCH 2/4] Other: The toolbar should support a vertical offset from the top of the web page. Closes #60. --- src/classiceditorui.js | 18 +++++++- tests/classiceditorui.js | 83 +++++++++++++++++++++++++++++++----- tests/classiceditoruiview.js | 3 ++ 3 files changed, 93 insertions(+), 11 deletions(-) diff --git a/src/classiceditorui.js b/src/classiceditorui.js index dba9b2d..2b5b982 100644 --- a/src/classiceditorui.js +++ b/src/classiceditorui.js @@ -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. @@ -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' ) ); @@ -52,6 +61,10 @@ export default class ClassicEditorUI { view.toolbar.bind( 'isActive' ).to( this.focusTracker, 'isFocused' ); view.toolbar.limiterElement = view.element; + if ( this._toolbarConfig ) { + view.toolbar.viewportTopOffset = this._toolbarConfig.viewportTopOffset; + } + // Setup the editable. const editingRoot = editor.editing.createRoot( 'div' ); view.editable.bind( 'isReadOnly' ).to( editingRoot ); @@ -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, diff --git a/tests/classiceditorui.js b/tests/classiceditorui.js index 409a575..cc116d6 100644 --- a/tests/classiceditorui.js +++ b/tests/classiceditorui.js @@ -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()', () => { @@ -77,6 +86,31 @@ describe( 'ClassicEditorUI', () => { it( 'sets view.toolbar#limiterElement', () => { expect( view.toolbar.limiterElement ).to.equal( view.element ); } ); + + it( 'sets view.toolbar#viewportTopOffset', () => { + 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', () => { @@ -127,11 +161,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', () => { diff --git a/tests/classiceditoruiview.js b/tests/classiceditoruiview.js index 8ca17d8..a5a7ac0 100644 --- a/tests/classiceditoruiview.js +++ b/tests/classiceditoruiview.js @@ -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(); } ); } ); From 2607afd55160cfe1c22e0836f156f56f6a3f0149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Koszuli=C5=84ski?= Date: Mon, 24 Jul 2017 11:24:54 +0200 Subject: [PATCH 3/4] Fixed config name in manual test. --- tests/manual/tickets/60/1.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/tickets/60/1.js b/tests/manual/tickets/60/1.js index 1af79d1..7c9c0b3 100644 --- a/tests/manual/tickets/60/1.js +++ b/tests/manual/tickets/60/1.js @@ -18,7 +18,7 @@ ClassicEditor.create( document.querySelector( '#editor' ), { plugins: [ Enter, Typing, Paragraph, Undo, Heading, Bold, Italic ], toolbar: { items: [ 'headings', 'bold', 'italic', 'undo', 'redo' ], - verticalOffset: 100 + viewportTopOffset: 100 } } ) .then( newEditor => { From ac3adee227b4b47cbf5b7ccf57e915c0c455cab5 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Mon, 24 Jul 2017 11:36:05 +0200 Subject: [PATCH 4/4] Fix: Wrong toolbar position when config.toolbar.viewportTopOffset is not specified. --- src/classiceditorui.js | 2 +- tests/classiceditorui.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/classiceditorui.js b/src/classiceditorui.js index 2b5b982..31b2589 100644 --- a/src/classiceditorui.js +++ b/src/classiceditorui.js @@ -61,7 +61,7 @@ export default class ClassicEditorUI { view.toolbar.bind( 'isActive' ).to( this.focusTracker, 'isFocused' ); view.toolbar.limiterElement = view.element; - if ( this._toolbarConfig ) { + if ( this._toolbarConfig && this._toolbarConfig.viewportTopOffset ) { view.toolbar.viewportTopOffset = this._toolbarConfig.viewportTopOffset; } diff --git a/tests/classiceditorui.js b/tests/classiceditorui.js index cc116d6..d672f72 100644 --- a/tests/classiceditorui.js +++ b/tests/classiceditorui.js @@ -87,7 +87,11 @@ describe( 'ClassicEditorUI', () => { expect( view.toolbar.limiterElement ).to.equal( view.element ); } ); - it( 'sets view.toolbar#viewportTopOffset', () => { + 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 );