From bb78e2e54796bee72f45246b46b70f5f05b0db30 Mon Sep 17 00:00:00 2001 From: panr Date: Tue, 14 Jan 2020 12:32:24 +0100 Subject: [PATCH 01/98] Fix: Set balloon toolbar's max-width to be half of the editable's width and make it groupable --- src/toolbar/balloon/balloontoolbar.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index a593d959..cd8aa674 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -147,7 +147,7 @@ export default class BalloonToolbar extends Plugin { * @returns {module:ui/toolbar/toolbarview~ToolbarView} */ _createToolbarView() { - const toolbarView = new ToolbarView( this.editor.locale ); + const toolbarView = new ToolbarView( this.editor.locale, { shouldGroupWhenFull: true } ); toolbarView.extendTemplate( { attributes: { @@ -189,6 +189,12 @@ export default class BalloonToolbar extends Plugin { this._balloon.updatePosition( this._getBalloonPositionData() ); } ); + // Set toolbar's max-width to be half of the editable's width. + const editableRect = new Rect( this.editor.editing.view.getDomRoot() ); + const maxToolbarWidth = editableRect.width / 2; + + this.toolbarView.element.style.maxWidth = `${ maxToolbarWidth }px`; + // Add the toolbar to the common editor contextual balloon. this._balloon.add( { view: this.toolbarView, From 82747ef0a88eb22b07858a016d9bb02d2f501144 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 15 Jan 2020 15:26:42 +0100 Subject: [PATCH 02/98] Tests: Add scenario for a setting toolbar max-width --- tests/toolbar/balloon/balloontoolbar.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/toolbar/balloon/balloontoolbar.js b/tests/toolbar/balloon/balloontoolbar.js index 57277fc0..02d2a9ba 100644 --- a/tests/toolbar/balloon/balloontoolbar.js +++ b/tests/toolbar/balloon/balloontoolbar.js @@ -344,6 +344,19 @@ describe( 'BalloonToolbar', () => { balloonToolbar.show(); sinon.assert.calledOnce( balloonAddSpy ); } ); + + it( 'should set balloon toolbar max-width to half of the editable width', () => { + const spy = sinon.spy( balloonToolbar, '_setToolbarMaxWidth' ); + testUtils.sinon.stub( editingView.getDomRoot(), 'getBoundingClientRect' ).returns( { width: 100 } ); + + setData( model, 'b[a]r' ); + + balloonToolbar.show(); + + sinon.assert.calledOnce( balloonAddSpy ); + sinon.assert.calledOnce( spy ); + expect( balloonToolbar.toolbarView.element.style.maxWidth ).to.be.equal( '50px' ); + } ); } ); describe( 'hide()', () => { From 085c2551012e2af96ebcb9942ac5e99a52b54093 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 15 Jan 2020 15:27:29 +0100 Subject: [PATCH 03/98] Tests: Add scenario to test if toolbar will group items --- tests/toolbar/toolbarview.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/toolbar/toolbarview.js b/tests/toolbar/toolbarview.js index aae2fec1..e8ea197a 100644 --- a/tests/toolbar/toolbarview.js +++ b/tests/toolbar/toolbarview.js @@ -70,6 +70,11 @@ describe( 'ToolbarView', () => { toolbar.destroy(); } ); + + it( 'toolbar should group items by default', () => { + const toolbar = new ToolbarView( locale, { shouldGroupWhenFull: true } ); + expect( toolbar.options.shouldGroupWhenFull ).to.be.true; + } ); } ); it( 'should create view#items collection', () => { From ac3c31fc1304985fcafefc6078fa041741178015 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 15 Jan 2020 15:30:16 +0100 Subject: [PATCH 04/98] Fix: Refactor setting max-width for toolbar as a private method for testing purposes --- src/toolbar/balloon/balloontoolbar.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index cd8aa674..a39c3180 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -190,10 +190,9 @@ export default class BalloonToolbar extends Plugin { } ); // Set toolbar's max-width to be half of the editable's width. - const editableRect = new Rect( this.editor.editing.view.getDomRoot() ); - const maxToolbarWidth = editableRect.width / 2; + const maxToolbarWidth = new Rect( this.editor.editing.view.getDomRoot() ).width; - this.toolbarView.element.style.maxWidth = `${ maxToolbarWidth }px`; + this._setToolbarMaxWidth( maxToolbarWidth / 2 ); // Add the toolbar to the common editor contextual balloon. this._balloon.add( { @@ -268,6 +267,15 @@ export default class BalloonToolbar extends Plugin { this.focusTracker.destroy(); } + /** + * Set max-width for toolbar. + * + * @private + */ + _setToolbarMaxWidth( width ) { + this.toolbarView.element.style.maxWidth = `${ width }px`; + } + /** * This event is fired just before the toolbar shows up. Stopping this event will prevent this. * From 69560b9ce70dffc567b3293631b6b15d89ccd6d2 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 22 Jan 2020 14:55:35 +0100 Subject: [PATCH 05/98] Add maxWidth observable to ToolbarView class --- src/toolbar/toolbarview.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/toolbar/toolbarview.js b/src/toolbar/toolbarview.js index ca06b4b4..22669eb5 100644 --- a/src/toolbar/toolbarview.js +++ b/src/toolbar/toolbarview.js @@ -21,6 +21,9 @@ import global from '@ckeditor/ckeditor5-utils/src/dom/global'; import { createDropdown, addToolbarToDropdown } from '../dropdown/utils'; import { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import verticalDotsIcon from '@ckeditor/ckeditor5-core/theme/icons/three-vertical-dots.svg'; +import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; + +const toPx = toUnit( 'px' ); import '../../theme/components/toolbar/toolbar.css'; @@ -61,6 +64,14 @@ export default class ToolbarView extends View { */ this.set( 'ariaLabel', t( 'Editor toolbar' ) ); + /** + * Maximum width of the toolbar element. + * + * @default 'auto' + * @member {String} #maxWidth + */ + this.set( 'maxWidth', 'auto' ); + /** * A collection of toolbar items (buttons, dropdowns, etc.). * @@ -171,7 +182,10 @@ export default class ToolbarView extends View { bind.to( 'class' ) ], role: 'toolbar', - 'aria-label': bind.to( 'ariaLabel' ) + 'aria-label': bind.to( 'ariaLabel' ), + style: { + maxWidth: bind.to( 'maxWidth', maxWidth => toPx( maxWidth ) ) + } }, children: this.children, From 438d8445416ada25faeae044cb54c76a235206f0 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 12:29:51 +0100 Subject: [PATCH 06/98] Refactor toolbar view maxWidth binding --- src/toolbar/toolbarview.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/toolbar/toolbarview.js b/src/toolbar/toolbarview.js index 22669eb5..98dabd55 100644 --- a/src/toolbar/toolbarview.js +++ b/src/toolbar/toolbarview.js @@ -21,9 +21,6 @@ import global from '@ckeditor/ckeditor5-utils/src/dom/global'; import { createDropdown, addToolbarToDropdown } from '../dropdown/utils'; import { attachLinkToDocumentation } from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import verticalDotsIcon from '@ckeditor/ckeditor5-core/theme/icons/three-vertical-dots.svg'; -import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; - -const toPx = toUnit( 'px' ); import '../../theme/components/toolbar/toolbar.css'; @@ -184,7 +181,7 @@ export default class ToolbarView extends View { role: 'toolbar', 'aria-label': bind.to( 'ariaLabel' ), style: { - maxWidth: bind.to( 'maxWidth', maxWidth => toPx( maxWidth ) ) + maxWidth: bind.to( 'maxWidth' ) } }, From f63022002865969f45b4866e34ef772ea8f5caac Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 12:31:48 +0100 Subject: [PATCH 07/98] Move setting toolbar max-width to initializer instead of running it when toolbar should be shown --- src/toolbar/balloon/balloontoolbar.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index a39c3180..311d860c 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -15,6 +15,10 @@ import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; import normalizeToolbarConfig from '../normalizetoolbarconfig'; import { debounce } from 'lodash-es'; +import getResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/getresizeobserver'; +import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; + +const toPx = toUnit( 'px' ); /** * The contextual toolbar. @@ -125,6 +129,19 @@ export default class BalloonToolbar extends Plugin { this.show(); } } ); + + this.listenTo( editor, 'ready', () => { + const editableElement = this.editor.ui.view.editable.element; + + // Set toolbar's max-width on the initialization and update it on the editable resize. + const widthObserver = getResizeObserver( ( [ entry ] ) => { + // In the balloon editor toolbar's max-width should be set to half of the editable's width. + // It's a safe value, because at the moment we don't re-calculate it when position of the selection changes. + this._setToolbarMaxWidth( entry.contentRect.width / 2 ); + } ); + + widthObserver.observe( editableElement ); + } ); } /** @@ -189,11 +206,6 @@ export default class BalloonToolbar extends Plugin { this._balloon.updatePosition( this._getBalloonPositionData() ); } ); - // Set toolbar's max-width to be half of the editable's width. - const maxToolbarWidth = new Rect( this.editor.editing.view.getDomRoot() ).width; - - this._setToolbarMaxWidth( maxToolbarWidth / 2 ); - // Add the toolbar to the common editor contextual balloon. this._balloon.add( { view: this.toolbarView, @@ -273,7 +285,7 @@ export default class BalloonToolbar extends Plugin { * @private */ _setToolbarMaxWidth( width ) { - this.toolbarView.element.style.maxWidth = `${ width }px`; + this.toolbarView.maxWidth = toPx( width ); } /** From 56d7300cd88080490c3ed9d6d64f14e8d7994588 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 12:32:50 +0100 Subject: [PATCH 08/98] Add test for toolbar max-width binding --- tests/toolbar/toolbarview.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/toolbar/toolbarview.js b/tests/toolbar/toolbarview.js index e8ea197a..743024b5 100644 --- a/tests/toolbar/toolbarview.js +++ b/tests/toolbar/toolbarview.js @@ -172,6 +172,22 @@ describe( 'ToolbarView', () => { expect( view.element.classList.contains( 'bar' ) ).to.be.false; } ); } ); + + describe( 'style', () => { + it( 'reacts on view#maxWidth', () => { + view.maxWidth = '100px'; + expect( view.element.style.maxWidth ).to.equal( '100px' ); + + view.maxWidth = undefined; + expect( view.element.style.maxWidth ).to.equal( '' ); + + view.maxWidth = null; + expect( view.element.style.maxWidth ).to.equal( '' ); + + view.maxWidth = '200px'; + expect( view.element.style.maxWidth ).to.equal( '200px' ); + } ); + } ); } ); describe( 'render()', () => { From aaa73fe32daa226fe60844725a2d2370344e5a2b Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 12:33:30 +0100 Subject: [PATCH 09/98] Change test for setting balloon toolbar max-width --- tests/toolbar/balloon/balloontoolbar.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/toolbar/balloon/balloontoolbar.js b/tests/toolbar/balloon/balloontoolbar.js index 02d2a9ba..77f71f49 100644 --- a/tests/toolbar/balloon/balloontoolbar.js +++ b/tests/toolbar/balloon/balloontoolbar.js @@ -20,7 +20,7 @@ import { stringify as viewStringify } from '@ckeditor/ckeditor5-engine/src/dev-u import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; -/* global document, window, Event */ +/* global document, window, Event, setTimeout */ describe( 'BalloonToolbar', () => { let editor, model, selection, editingView, balloonToolbar, balloon, editorElement; @@ -345,17 +345,24 @@ describe( 'BalloonToolbar', () => { sinon.assert.calledOnce( balloonAddSpy ); } ); - it( 'should set balloon toolbar max-width to half of the editable width', () => { - const spy = sinon.spy( balloonToolbar, '_setToolbarMaxWidth' ); - testUtils.sinon.stub( editingView.getDomRoot(), 'getBoundingClientRect' ).returns( { width: 100 } ); + it( 'should set balloon toolbar max-width to half of the editable width, otherwise it can be wider then editor', done => { + const viewElement = editor.ui.view.editable.element; - setData( model, 'b[a]r' ); + setData( model, 'b[ar]' ); - balloonToolbar.show(); + expect( document.body.contains( viewElement ) ).to.be.true; - sinon.assert.calledOnce( balloonAddSpy ); - sinon.assert.calledOnce( spy ); - expect( balloonToolbar.toolbarView.element.style.maxWidth ).to.be.equal( '50px' ); + viewElement.style.width = '400px'; + + // Unfortunately we have to wait for async ResizeObserver execution. + // ResizeObserver which has been called after changing width of viewElement, + // needs 2x requestAnimationFrame or timeout to update a layout. + // See more: https://twitter.com/paul_irish/status/912693347315150849/photo/1 + setTimeout( () => { + expect( balloonToolbar.toolbarView.maxWidth ).to.be.equal( '200px' ); + + done(); + }, 100 ); } ); } ); From fd6151ab3d45025e281f224be4d2d877ff9aa0dc Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 16:38:35 +0100 Subject: [PATCH 10/98] Refactor access to balloon toolbar config and pass down shouldGroupWhenFull option to the toolbar view constructor --- src/toolbar/balloon/balloontoolbar.js | 36 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index 311d860c..f4a7badf 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -48,6 +48,14 @@ export default class BalloonToolbar extends Plugin { constructor( editor ) { super( editor ); + /** + * A normalized `config.balloonToolbar` object. + * + * @type {Object} + * @private + */ + this._balloonConfig = normalizeToolbarConfig( this.editor.config.get( 'balloonToolbar' ) ); + /** * The toolbar view displayed in the balloon. * @@ -130,18 +138,20 @@ export default class BalloonToolbar extends Plugin { } } ); - this.listenTo( editor, 'ready', () => { - const editableElement = this.editor.ui.view.editable.element; + if ( !this._balloonConfig.shouldNotGroupWhenFull ) { + this.listenTo( editor, 'ready', () => { + const editableElement = editor.ui.view.editable.element; - // Set toolbar's max-width on the initialization and update it on the editable resize. - const widthObserver = getResizeObserver( ( [ entry ] ) => { - // In the balloon editor toolbar's max-width should be set to half of the editable's width. - // It's a safe value, because at the moment we don't re-calculate it when position of the selection changes. - this._setToolbarMaxWidth( entry.contentRect.width / 2 ); - } ); + // Set toolbar's max-width on the initialization and update it on the editable resize. + const widthObserver = getResizeObserver( ( [ entry ] ) => { + // In the balloon editor toolbar's max-width should be set to half of the editable's width. + // It's a safe value, because at the moment we don't re-calculate it when position of the selection changes. + this._setToolbarMaxWidth( entry.contentRect.width / 2 ); + } ); - widthObserver.observe( editableElement ); - } ); + widthObserver.observe( editableElement ); + } ); + } } /** @@ -151,10 +161,9 @@ export default class BalloonToolbar extends Plugin { * @inheritDoc */ afterInit() { - const config = normalizeToolbarConfig( this.editor.config.get( 'balloonToolbar' ) ); const factory = this.editor.ui.componentFactory; - this.toolbarView.fillFromConfig( config.items, factory ); + this.toolbarView.fillFromConfig( this._balloonConfig.items, factory ); } /** @@ -164,7 +173,8 @@ export default class BalloonToolbar extends Plugin { * @returns {module:ui/toolbar/toolbarview~ToolbarView} */ _createToolbarView() { - const toolbarView = new ToolbarView( this.editor.locale, { shouldGroupWhenFull: true } ); + const shouldGroupWhenFull = !this._balloonConfig.shouldNotGroupWhenFull; + const toolbarView = new ToolbarView( this.editor.locale, { shouldGroupWhenFull } ); toolbarView.extendTemplate( { attributes: { From d44f716915b3d82c2ec4d9b161181fa1e0ae9993 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 16:42:57 +0100 Subject: [PATCH 11/98] Add test for checking if grouping items can be disabled from balloon toolbar config --- tests/toolbar/balloon/balloontoolbar.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/toolbar/balloon/balloontoolbar.js b/tests/toolbar/balloon/balloontoolbar.js index 77f71f49..ee20d62b 100644 --- a/tests/toolbar/balloon/balloontoolbar.js +++ b/tests/toolbar/balloon/balloontoolbar.js @@ -102,6 +102,27 @@ describe( 'BalloonToolbar', () => { } ); } ); + it( 'balloon toolbar should not group items when shouldNotGroupWhenFull option is enabled', () => { + const editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + + return ClassicTestEditor.create( editorElement, { + plugins: [ Paragraph, Bold, Italic, Underline, BalloonToolbar ], + balloonToolbar: { + items: [ 'bold', 'italic', 'underline' ], + shouldNotGroupWhenFull: true + } + } ).then( editor => { + const balloonToolbar = editor.plugins.get( BalloonToolbar ); + + expect( balloonToolbar.toolbarView.options.shouldGroupWhenFull ).to.be.false; + + return editor.destroy(); + } ).then( () => { + editorElement.remove(); + } ); + } ); + it( 'should fire internal `_selectionChangeDebounced` event 200 ms after last selection change', () => { const clock = testUtils.sinon.useFakeTimers(); const spy = testUtils.sinon.spy(); From 08a505845c931debddeadf1e48ea00df0ca53a0c Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 23 Jan 2020 17:12:43 +0100 Subject: [PATCH 12/98] Increase test timeout while waiting for ResizeObserver --- tests/toolbar/balloon/balloontoolbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/toolbar/balloon/balloontoolbar.js b/tests/toolbar/balloon/balloontoolbar.js index ee20d62b..75131cdc 100644 --- a/tests/toolbar/balloon/balloontoolbar.js +++ b/tests/toolbar/balloon/balloontoolbar.js @@ -383,7 +383,7 @@ describe( 'BalloonToolbar', () => { expect( balloonToolbar.toolbarView.maxWidth ).to.be.equal( '200px' ); done(); - }, 100 ); + }, 500 ); } ); } ); From bb97620183d2ebbe920bdea271b41238500a89be Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 29 Jan 2020 17:07:41 +0100 Subject: [PATCH 13/98] Add _enableGroupingOnMaxWidthChange() private method --- src/toolbar/toolbarview.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/toolbar/toolbarview.js b/src/toolbar/toolbarview.js index 98dabd55..dd2ad8d7 100644 --- a/src/toolbar/toolbarview.js +++ b/src/toolbar/toolbarview.js @@ -571,6 +571,7 @@ class DynamicGrouping { this.viewElement = view.element; this._enableGroupingOnResize(); + this._enableGroupingOnMaxWidthChange( view ); } /** @@ -697,6 +698,21 @@ class DynamicGrouping { this._updateGrouping(); } + /** + * Enables the grouping functionality, just like {@link #_enableGroupingOnResize} but the difference is that + * it listens to the {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth} changes. + * + * Note: Right now it works only with {@link module:editor-inline/inlineeditor~InlineEditor} and + * {@link module:editor-balloon/ballooneditor~BalloonEditor}. + * + * @private + */ + _enableGroupingOnMaxWidthChange( view ) { + view.on( 'change:maxWidth', () => { + this._updateGrouping(); + } ); + } + /** * When called, it will remove the last item from {@link #ungroupedItems} and move it back * to the {@link #groupedItems} collection. From b3da94f1696ed2f52aaa16a095335bc98387655f Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 30 Jan 2020 10:39:52 +0100 Subject: [PATCH 14/98] Update ToolbarView#maxWidth observable with note describing how it may work in certain scenarios --- src/toolbar/toolbarview.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/toolbar/toolbarview.js b/src/toolbar/toolbarview.js index dd2ad8d7..d5f34c97 100644 --- a/src/toolbar/toolbarview.js +++ b/src/toolbar/toolbarview.js @@ -62,7 +62,18 @@ export default class ToolbarView extends View { this.set( 'ariaLabel', t( 'Editor toolbar' ) ); /** - * Maximum width of the toolbar element. + * The maximum width of the toolbar element. + * + * Note: + * You should not change the toolbar's max-width manually, because by default it's binded + * with the editor's editable element's width and it will be applied automatically each time its value will change. + * + * If you set `config.toolbar.shouldNotGroupWhenFull: true` and also set `ToolbarView#maxWidth`, + * the max-width will be applied and — in this case — you should be careful, because if you set + * the value to be too small, this may cause visual and usability issues with your toolbar. + * + * Another scenario is when the toolbar is grouping overflowing items and you will be trying to set `ToolbarView#maxWidth`. + * This new value will be immediately overridden and will not be applied. * * @default 'auto' * @member {String} #maxWidth From fcc0e296e5a8e1fb4ee1ef73b3297b74daefb2b2 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 30 Jan 2020 10:44:33 +0100 Subject: [PATCH 15/98] Fix ballon toolbar code - Remove radundant helper for setting max-width - Add condintion checking if editable element is in the DOM already - Minor fix in the constructor code --- src/toolbar/balloon/balloontoolbar.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index f4a7badf..fbf54042 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -54,7 +54,7 @@ export default class BalloonToolbar extends Plugin { * @type {Object} * @private */ - this._balloonConfig = normalizeToolbarConfig( this.editor.config.get( 'balloonToolbar' ) ); + this._balloonConfig = normalizeToolbarConfig( editor.config.get( 'balloonToolbar' ) ); /** * The toolbar view displayed in the balloon. @@ -143,10 +143,17 @@ export default class BalloonToolbar extends Plugin { const editableElement = editor.ui.view.editable.element; // Set toolbar's max-width on the initialization and update it on the editable resize. - const widthObserver = getResizeObserver( ( [ entry ] ) => { - // In the balloon editor toolbar's max-width should be set to half of the editable's width. + const widthObserver = getResizeObserver( () => { + // We need to check if there's already the editable element in the DOM. + // Otherwise the `Rect` instance will complain that source (editableElement) is not available + // to obtain the element's geometry. + if ( !editableElement.ownerDocument.body.contains( editableElement ) ) { + return; + } + + // In the balloon editor toolbar's max-width should be set to the 2/3 of the editable's width. // It's a safe value, because at the moment we don't re-calculate it when position of the selection changes. - this._setToolbarMaxWidth( entry.contentRect.width / 2 ); + this.toolbarView.maxWidth = toPx( new Rect( editableElement ).width * 0.66 ); } ); widthObserver.observe( editableElement ); @@ -289,15 +296,6 @@ export default class BalloonToolbar extends Plugin { this.focusTracker.destroy(); } - /** - * Set max-width for toolbar. - * - * @private - */ - _setToolbarMaxWidth( width ) { - this.toolbarView.maxWidth = toPx( width ); - } - /** * This event is fired just before the toolbar shows up. Stopping this event will prevent this. * From 8e04fe0534af1fe06ec77dd841c6bb5e80477924 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 30 Jan 2020 10:44:52 +0100 Subject: [PATCH 16/98] Remove obsolete test from ToolbarView tests --- tests/toolbar/toolbarview.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/toolbar/toolbarview.js b/tests/toolbar/toolbarview.js index 743024b5..b5ab71a1 100644 --- a/tests/toolbar/toolbarview.js +++ b/tests/toolbar/toolbarview.js @@ -70,11 +70,6 @@ describe( 'ToolbarView', () => { toolbar.destroy(); } ); - - it( 'toolbar should group items by default', () => { - const toolbar = new ToolbarView( locale, { shouldGroupWhenFull: true } ); - expect( toolbar.options.shouldGroupWhenFull ).to.be.true; - } ); } ); it( 'should create view#items collection', () => { From 6f9eeae5f050350339dda4646cd1a326835121a2 Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 30 Jan 2020 10:46:28 +0100 Subject: [PATCH 17/98] Fix balloon toolbar tests - Fix test descriptions - Use global from utils and new Rect instance to get a proper width that contains padding --- tests/toolbar/balloon/balloontoolbar.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/toolbar/balloon/balloontoolbar.js b/tests/toolbar/balloon/balloontoolbar.js index 75131cdc..1687a64f 100644 --- a/tests/toolbar/balloon/balloontoolbar.js +++ b/tests/toolbar/balloon/balloontoolbar.js @@ -14,10 +14,16 @@ import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold'; import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic'; import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import global from '@ckeditor/ckeditor5-utils/src/dom/global'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { stringify as viewStringify } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; +import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; +import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; + +const toPx = toUnit( 'px' ); + import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; /* global document, window, Event, setTimeout */ @@ -102,7 +108,7 @@ describe( 'BalloonToolbar', () => { } ); } ); - it( 'balloon toolbar should not group items when shouldNotGroupWhenFull option is enabled', () => { + it( 'should not group items when the shouldNotGroupWhenFull option is enabled', () => { const editorElement = document.createElement( 'div' ); document.body.appendChild( editorElement ); @@ -366,12 +372,12 @@ describe( 'BalloonToolbar', () => { sinon.assert.calledOnce( balloonAddSpy ); } ); - it( 'should set balloon toolbar max-width to half of the editable width, otherwise it can be wider then editor', done => { + it( 'should set the toolbar max-width to half of the editable width', done => { const viewElement = editor.ui.view.editable.element; setData( model, 'b[ar]' ); - expect( document.body.contains( viewElement ) ).to.be.true; + expect( global.document.body.contains( viewElement ) ).to.be.true; viewElement.style.width = '400px'; @@ -380,7 +386,9 @@ describe( 'BalloonToolbar', () => { // needs 2x requestAnimationFrame or timeout to update a layout. // See more: https://twitter.com/paul_irish/status/912693347315150849/photo/1 setTimeout( () => { - expect( balloonToolbar.toolbarView.maxWidth ).to.be.equal( '200px' ); + // The expected width should be 2/3 of the editor's editable element's width. + const expectedWidth = toPx( new Rect( viewElement ).width * 0.66 ); + expect( balloonToolbar.toolbarView.maxWidth ).to.be.equal( expectedWidth ); done(); }, 500 ); From a316c8dde858f6017decacbf955734c52ad8c56c Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 6 Feb 2020 15:10:26 +0100 Subject: [PATCH 18/98] Add "ck-balloon-toolbar_min-width" class to set default min-width for the balloon toolbar --- src/toolbar/balloon/balloontoolbar.js | 2 +- theme/components/toolbar/toolbar.css | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index fbf54042..cc587dd8 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -185,7 +185,7 @@ export default class BalloonToolbar extends Plugin { toolbarView.extendTemplate( { attributes: { - class: [ 'ck-toolbar_floating' ] + class: [ 'ck-toolbar_floating', 'ck-balloon-toolbar_min-width' ] } } ); diff --git a/theme/components/toolbar/toolbar.css b/theme/components/toolbar/toolbar.css index 87e94b60..f575bc3d 100644 --- a/theme/components/toolbar/toolbar.css +++ b/theme/components/toolbar/toolbar.css @@ -51,4 +51,13 @@ display: none; } } + + /* Balloon Toolbar + * + * This class can be used to set a different min-width for the balloon toolbar. + * NOTE: It can also overrule a width and max-width of the balloon toolbar if it will be set with a higher value. + */ + &.ck-balloon-toolbar_min-width { + min-width: 180px; + } } From 8e4882e4ffc98e8bbe2ece364837be47a9cf87a3 Mon Sep 17 00:00:00 2001 From: panr Date: Fri, 21 Feb 2020 14:03:41 +0100 Subject: [PATCH 19/98] Use ResizeObserver class instead of getResizeObserver helper --- src/toolbar/balloon/balloontoolbar.js | 7 +++---- src/toolbar/toolbarview.js | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/toolbar/balloon/balloontoolbar.js b/src/toolbar/balloon/balloontoolbar.js index cc587dd8..5dc7f618 100644 --- a/src/toolbar/balloon/balloontoolbar.js +++ b/src/toolbar/balloon/balloontoolbar.js @@ -15,7 +15,7 @@ import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; import normalizeToolbarConfig from '../normalizetoolbarconfig'; import { debounce } from 'lodash-es'; -import getResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/getresizeobserver'; +import ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver'; import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit'; const toPx = toUnit( 'px' ); @@ -143,7 +143,7 @@ export default class BalloonToolbar extends Plugin { const editableElement = editor.ui.view.editable.element; // Set toolbar's max-width on the initialization and update it on the editable resize. - const widthObserver = getResizeObserver( () => { + this.widthObserver = new ResizeObserver( editableElement, () => { // We need to check if there's already the editable element in the DOM. // Otherwise the `Rect` instance will complain that source (editableElement) is not available // to obtain the element's geometry. @@ -155,8 +155,6 @@ export default class BalloonToolbar extends Plugin { // It's a safe value, because at the moment we don't re-calculate it when position of the selection changes. this.toolbarView.maxWidth = toPx( new Rect( editableElement ).width * 0.66 ); } ); - - widthObserver.observe( editableElement ); } ); } } @@ -294,6 +292,7 @@ export default class BalloonToolbar extends Plugin { this._fireSelectionChangeDebounced.cancel(); this.toolbarView.destroy(); this.focusTracker.destroy(); + this.widthObserver.destroy(); } /** diff --git a/src/toolbar/toolbarview.js b/src/toolbar/toolbarview.js index d5f34c97..9153d514 100644 --- a/src/toolbar/toolbarview.js +++ b/src/toolbar/toolbarview.js @@ -14,7 +14,7 @@ import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker'; import FocusCycler from '../focuscycler'; import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler'; import ToolbarSeparatorView from './toolbarseparatorview'; -import getResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/getresizeobserver'; +import ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver'; import preventDefault from '../bindings/preventdefault.js'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; import global from '@ckeditor/ckeditor5-utils/src/dom/global'; @@ -246,6 +246,7 @@ export default class ToolbarView extends View { */ destroy() { this._behavior.destroy(); + this.resizeObserver.destroy(); return super.destroy(); } @@ -696,7 +697,7 @@ class DynamicGrouping { let previousWidth; // TODO: Consider debounce. - this.resizeObserver = getResizeObserver( ( [ entry ] ) => { + this.resizeObserver = new ResizeObserver( this.viewElement, entry => { if ( !previousWidth || previousWidth !== entry.contentRect.width ) { this._updateGrouping(); @@ -704,8 +705,6 @@ class DynamicGrouping { } } ); - this.resizeObserver.observe( this.viewElement ); - this._updateGrouping(); } From 09475dcb53055f91d450c8a0013803447db382ee Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Thu, 7 Nov 2019 13:43:03 +0100 Subject: [PATCH 20/98] Make notifications context plugin. --- src/notification/notification.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notification/notification.js b/src/notification/notification.js index b72ad2aa..b4822634 100644 --- a/src/notification/notification.js +++ b/src/notification/notification.js @@ -9,7 +9,7 @@ /* globals window */ -import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin'; /** * The Notification plugin. @@ -23,7 +23,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; * * @extends module:core/plugin~Plugin */ -export default class Notification extends Plugin { +export default class Notification extends ContextPlugin { /** * @inheritDoc */ From ffa11c3e161a703bac926af6acca5f8c355eaa1a Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Fri, 8 Nov 2019 16:57:35 +0100 Subject: [PATCH 21/98] Export body collection to the separate file. --- src/editorui/bodycollection.js | 41 ++++++++++++++++++++++++++++++++++ src/editorui/editoruiview.js | 34 ++++------------------------ 2 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 src/editorui/bodycollection.js diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js new file mode 100644 index 00000000..cfa2bae1 --- /dev/null +++ b/src/editorui/bodycollection.js @@ -0,0 +1,41 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module ui/editorui/BodyCollection + */ + +/* globals document */ + +import Template from '../template'; +import ViewCollection from '../viewcollection'; + +export default class BodyCollection extends ViewCollection { + render() { + this._bodyCollectionContainer = new Template( { + tag: 'div', + attributes: { + class: [ + 'ck', + 'ck-reset_all', + 'ck-body', + 'ck-rounded-corners' + ], + dir: this.locale.uiLanguageDirection, + }, + children: this + } ).render(); + + document.body.appendChild( this._bodyCollectionContainer ); + } + + destroy() { + super.destroy(); + + if ( this._bodyCollectionContainer ) { + this._bodyCollectionContainer.remove(); + } + } +} diff --git a/src/editorui/editoruiview.js b/src/editorui/editoruiview.js index 8c2ddde9..d182c2fe 100644 --- a/src/editorui/editoruiview.js +++ b/src/editorui/editoruiview.js @@ -7,10 +7,8 @@ * @module ui/editorui/editoruiview */ -/* globals document */ - import View from '../view'; -import Template from '../template'; +import BodyCollection from './bodycollection'; import '../../theme/components/editorui/editorui.css'; @@ -35,7 +33,7 @@ export default class EditorUIView extends View { * @readonly * @member {module:ui/viewcollection~ViewCollection} #body */ - this.body = this.createCollection(); + this.body = new BodyCollection( locale ); /** * The element holding elements of the 'body' region. @@ -51,39 +49,15 @@ export default class EditorUIView extends View { render() { super.render(); - this._renderBodyCollection(); + this.body.render(); } /** * @inheritDoc */ destroy() { - this._bodyCollectionContainer.remove(); + this.body.destroy(); return super.destroy(); } - - /** - * Creates and appends to `` the {@link #body} collection container. - * - * @private - */ - _renderBodyCollection() { - const locale = this.locale; - const bodyElement = this._bodyCollectionContainer = new Template( { - tag: 'div', - attributes: { - class: [ - 'ck', - 'ck-reset_all', - 'ck-body', - 'ck-rounded-corners' - ], - dir: locale.uiLanguageDirection, - }, - children: this.body - } ).render(); - - document.body.appendChild( bodyElement ); - } } From 65230520ef196a435212389b920e766c768a9e8e Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Wed, 13 Nov 2019 15:42:08 +0100 Subject: [PATCH 22/98] Applied changes to the body collection API. --- src/editorui/bodycollection.js | 23 ++++++++++++++++++++--- src/editorui/editoruiview.js | 4 ++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index cfa2bae1..5a0392ee 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -12,8 +12,10 @@ import Template from '../template'; import ViewCollection from '../viewcollection'; +import createElement from '@ckeditor/ckeditor5-utils/src/dom/createElement'; + export default class BodyCollection extends ViewCollection { - render() { + attachToDOM() { this._bodyCollectionContainer = new Template( { tag: 'div', attributes: { @@ -28,14 +30,29 @@ export default class BodyCollection extends ViewCollection { children: this } ).render(); - document.body.appendChild( this._bodyCollectionContainer ); + let wrapper = document.querySelector( '.ck-body-wrapper' ); + + if ( !wrapper ) { + wrapper = createElement( document, 'div', { class: 'ck-body-wrapper' } ); + document.body.appendChild( wrapper ); + } + + console.log( wrapper ); + + wrapper.appendChild( this._bodyCollectionContainer ); } - destroy() { + detachFromDOM() { super.destroy(); if ( this._bodyCollectionContainer ) { this._bodyCollectionContainer.remove(); } + + const wrapper = document.querySelector( '.ck-body-wrapper' ); + + if ( wrapper.childElementCount == 0 ) { + wrapper.remove(); + } } } diff --git a/src/editorui/editoruiview.js b/src/editorui/editoruiview.js index d182c2fe..d5f48dac 100644 --- a/src/editorui/editoruiview.js +++ b/src/editorui/editoruiview.js @@ -49,14 +49,14 @@ export default class EditorUIView extends View { render() { super.render(); - this.body.render(); + this.body.attachToDOM(); } /** * @inheritDoc */ destroy() { - this.body.destroy(); + this.body.detachFromDOM(); return super.destroy(); } From 61c52464e90aabbfb1e204285405f0d36cdc9065 Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Wed, 13 Nov 2019 17:13:26 +0100 Subject: [PATCH 23/98] Removed console.log. --- src/editorui/bodycollection.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 5a0392ee..170e3489 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -37,8 +37,6 @@ export default class BodyCollection extends ViewCollection { document.body.appendChild( wrapper ); } - console.log( wrapper ); - wrapper.appendChild( this._bodyCollectionContainer ); } From 4a248ced2d5d0fcd14b3482a03cfea0c4e822be4 Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Tue, 19 Nov 2019 15:37:56 +0100 Subject: [PATCH 24/98] Fix broken import. --- src/editorui/bodycollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 170e3489..f0ef1997 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -12,7 +12,7 @@ import Template from '../template'; import ViewCollection from '../viewcollection'; -import createElement from '@ckeditor/ckeditor5-utils/src/dom/createElement'; +import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; export default class BodyCollection extends ViewCollection { attachToDOM() { From 38ffe70f3e6a6253551835dae20b4501c7503f19 Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Wed, 20 Nov 2019 13:52:10 +0100 Subject: [PATCH 25/98] Tests: introduce tests for body collection. Update tests broken after changes. --- src/editorui/bodycollection.js | 2 +- src/notification/notification.js | 2 +- tests/editorui/bodycollection.js | 186 +++++++++++++++++++++++++++++ tests/editorui/editoruiview.js | 35 +----- tests/notification/notification.js | 4 +- 5 files changed, 196 insertions(+), 33 deletions(-) create mode 100644 tests/editorui/bodycollection.js diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index f0ef1997..a607610e 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -49,7 +49,7 @@ export default class BodyCollection extends ViewCollection { const wrapper = document.querySelector( '.ck-body-wrapper' ); - if ( wrapper.childElementCount == 0 ) { + if ( wrapper && wrapper.childElementCount == 0 ) { wrapper.remove(); } } diff --git a/src/notification/notification.js b/src/notification/notification.js index b4822634..dde9bab1 100644 --- a/src/notification/notification.js +++ b/src/notification/notification.js @@ -21,7 +21,7 @@ import ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin'; * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert. * See {@link module:ui/notification/notification~Notification#showWarning}. * - * @extends module:core/plugin~Plugin + * @extends module:core/contextplugin~ContextPlugin */ export default class Notification extends ContextPlugin { /** diff --git a/tests/editorui/bodycollection.js b/tests/editorui/bodycollection.js new file mode 100644 index 00000000..831c8bcc --- /dev/null +++ b/tests/editorui/bodycollection.js @@ -0,0 +1,186 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* global document */ + +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import Locale from '@ckeditor/ckeditor5-utils/src/locale'; + +import BodyCollection from '../../src/editorui/bodycollection'; +import View from '../../src/view'; + +describe( 'BodyCollection', () => { + let locale; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + locale = new Locale(); + } ); + + afterEach( () => { + const wrappers = Array.from( document.querySelectorAll( '.ck-body-wrapper' ) ); + + for ( const wrapper of wrappers ) { + wrapper.remove(); + } + } ); + + describe( 'attachToDOM', () => { + it( 'should create wrapper and put the collection in that wrapper', () => { + const body = new BodyCollection( locale ); + + body.attachToDOM(); + + const wrappers = Array.from( document.querySelectorAll( '.ck-body-wrapper' ) ); + + expect( wrappers.length ).to.equal( 1 ); + expect( wrappers[ 0 ].parentNode ).to.equal( document.body ); + + const el = body._bodyCollectionContainer; + + expect( el.parentNode ).to.equal( wrappers[ 0 ] ); + expect( el.classList.contains( 'ck' ) ).to.be.true; + expect( el.classList.contains( 'ck-body' ) ).to.be.true; + expect( el.classList.contains( 'ck-rounded-corners' ) ).to.be.true; + expect( el.classList.contains( 'ck-reset_all' ) ).to.be.true; + } ); + + it( 'sets the right dir attribute to the body region (LTR)', () => { + const body = new BodyCollection( locale ); + + body.attachToDOM(); + + const el = body._bodyCollectionContainer; + + expect( el.getAttribute( 'dir' ) ).to.equal( 'ltr' ); + } ); + + it( 'sets the right dir attribute to the body region (RTL)', () => { + const locale = new Locale( { uiLanguage: 'ar' } ); + const body = new BodyCollection( locale ); + + body.attachToDOM(); + + const el = body._bodyCollectionContainer; + + expect( el.getAttribute( 'dir' ) ).to.equal( 'rtl' ); + } ); + + it( 'should put all body elements to the same wrapper', () => { + const body1 = new BodyCollection( locale ); + body1.attachToDOM(); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); + expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 1 ); + + const body2 = new BodyCollection( locale ); + body2.attachToDOM(); + + const bodyElements = document.querySelectorAll( '.ck-body' ); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); + expect( bodyElements.length ).to.equal( 2 ); + expect( bodyElements[ 0 ].parentNode ).to.equal( bodyElements[ 1 ].parentNode ); + } ); + + it( 'should render views in proper body collections', () => { + const body1 = new BodyCollection( locale ); + + const view1 = new View(); + view1.setTemplate( { + tag: 'div', + attributes: { + class: [ 'foo' ] + } + } ); + + // Should work if body is attached before the view is added... + body1.attachToDOM(); + body1.add( view1 ); + + const body2 = new BodyCollection( locale ); + + const view2 = new View(); + view2.setTemplate( { + tag: 'div', + attributes: { + class: [ 'bar' ] + } + } ); + + // ...and it should work if body is attached after the view is added. + body2.add( view2 ); + body2.attachToDOM(); + + const wrappers = Array.from( document.querySelectorAll( '.ck-body-wrapper' ) ); + + expect( wrappers.length ).to.equal( 1 ); + + const wrapper = wrappers[ 0 ]; + const body1Element = body1._bodyCollectionContainer; + const body2Element = body2._bodyCollectionContainer; + + expect( body1Element.parentNode ).to.equal( wrapper ); + expect( body1Element.childNodes.length ).to.equal( 1 ); + expect( body1Element.childNodes[ 0 ].classList.contains( 'foo' ) ).to.be.true; + + expect( body2Element.parentNode ).to.equal( wrapper ); + expect( body2Element.childNodes.length ).to.equal( 1 ); + expect( body2Element.childNodes[ 0 ].classList.contains( 'bar' ) ).to.be.true; + } ); + } ); + + describe( 'detachFromDOM', () => { + it( 'removes the body collection from DOM', () => { + const body = new BodyCollection( locale ); + + body.attachToDOM(); + body.detachFromDOM(); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 0 ); + expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 0 ); + } ); + + it( 'removes the multiple body collections from dom and remove the wrapper when the last is removed', () => { + const body1 = new BodyCollection( locale ); + body1.attachToDOM(); + + const body2 = new BodyCollection( locale ); + body2.attachToDOM(); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); + expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 2 ); + + body1.detachFromDOM(); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); + expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 1 ); + + body2.detachFromDOM(); + + expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 0 ); + expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 0 ); + } ); + + it( 'should not throw when be called multiple times', () => { + const body = new BodyCollection( locale ); + body.attachToDOM(); + + expect( () => { + body.detachFromDOM(); + body.detachFromDOM(); + } ).to.not.throw(); + } ); + + it( 'should not throw if attachToDOM was not called before', () => { + const body = new BodyCollection( locale ); + + expect( () => { + body.detachFromDOM(); + } ).to.not.throw(); + } ); + } ); +} ); diff --git a/tests/editorui/editoruiview.js b/tests/editorui/editoruiview.js index 5dec615a..0bc3ffd8 100644 --- a/tests/editorui/editoruiview.js +++ b/tests/editorui/editoruiview.js @@ -37,41 +37,18 @@ describe( 'EditorUIView', () => { } ); describe( 'render()', () => { - it( 'sets the right class set to the body region', () => { - const el = view._bodyCollectionContainer; - - expect( el.parentNode ).to.equal( document.body ); - expect( el.classList.contains( 'ck' ) ).to.be.true; - expect( el.classList.contains( 'ck-body' ) ).to.be.true; - expect( el.classList.contains( 'ck-rounded-corners' ) ).to.be.true; - expect( el.classList.contains( 'ck-reset_all' ) ).to.be.true; - } ); - - it( 'sets the right dir attribute to the body region (LTR)', () => { - const el = view._bodyCollectionContainer; - - expect( el.getAttribute( 'dir' ) ).to.equal( 'ltr' ); - } ); - - it( 'sets the right dir attribute to the body region (RTL)', () => { - const locale = new Locale( { uiLanguage: 'ar' } ); - const view = new EditorUIView( locale ); - - view.render(); - - const el = view._bodyCollectionContainer; - - expect( el.getAttribute( 'dir' ) ).to.equal( 'rtl' ); - - view.destroy(); + it( 'attach the body collection', () => { + expect( view.body._bodyCollectionContainer.parentNode.classList.contains( 'ck-body-wrapper' ) ).to.be.true; + expect( view.body._bodyCollectionContainer.parentNode.parentNode ).to.equal( document.body ); } ); } ); describe( 'destroy()', () => { - it( 'removes the body region container', () => { - const el = view._bodyCollectionContainer; + it( 'detach the body collection', () => { + const el = view.body._bodyCollectionContainer; view.destroy(); + expect( el.parentNode ).to.be.null; } ); diff --git a/tests/notification/notification.js b/tests/notification/notification.js index a67868df..590cd5f2 100644 --- a/tests/notification/notification.js +++ b/tests/notification/notification.js @@ -7,7 +7,7 @@ import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; -import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin'; import Notification from '../../src/notification/notification'; describe( 'Notification', () => { @@ -29,7 +29,7 @@ describe( 'Notification', () => { describe( 'init()', () => { it( 'should create notification plugin', () => { expect( notification ).to.instanceof( Notification ); - expect( notification ).to.instanceof( Plugin ); + expect( notification ).to.instanceof( ContextPlugin ); } ); } ); From 872cfccc982c0d5a297de9fe087c2c631a54cfa7 Mon Sep 17 00:00:00 2001 From: Piotr Jasiun Date: Wed, 20 Nov 2019 16:42:55 +0100 Subject: [PATCH 26/98] Docs: added API docs to the body collection. --- src/editorui/bodycollection.js | 33 ++++++++++++++++++++++++++++++++- src/editorui/editoruiview.js | 7 ------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index a607610e..d693efd7 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -4,7 +4,7 @@ */ /** - * @module ui/editorui/BodyCollection + * @module ui/editorui/bodycollection */ /* globals document */ @@ -14,8 +14,35 @@ import ViewCollection from '../viewcollection'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; +/** + * This is the special {@link module:ui/viewcollection~ViewCollection ViewCollection} dedicated to elements that are detached + * from the DOM structure of the editor, like panels, icons, etc. + * + * CKEditor creates the body collection as {@link module:ui/editorui/editoruiview~EditorUIView#body editor.ui.view.body} property. + * Any plugin can add a {@link module:ui/view~View view} to this collection. The editor will detach and destroy this collection + * when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}. + * + * If you need to control the live cycle of the body collection on your own, you can create your own instance of this class. + * + * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDOM}. + * If you create multiple body collections this class will create a special wrapper element in the DOM to limit the number of + * elements created directly in the body and remove it when the last body collection will be + * {@link ~BodyCollection#detachFromDOM detached}. + * + * @extends module:ui/viewcollection~ViewCollection + */ export default class BodyCollection extends ViewCollection { + /** + * Attaches the body collection to the DOM body element. You need to execute this method to render the content of + * the body collection. + */ attachToDOM() { + /** + * The element holding elements of the 'body' region. + * + * @protected + * @member {HTMLElement} #_bodyCollectionContainer + */ this._bodyCollectionContainer = new Template( { tag: 'div', attributes: { @@ -40,6 +67,10 @@ export default class BodyCollection extends ViewCollection { wrapper.appendChild( this._bodyCollectionContainer ); } + /** + * Detach the collection from the DOM structure. Use this method when you do not need to use the body collection + * anymore to clean-up the DOM structure. + */ detachFromDOM() { super.destroy(); diff --git a/src/editorui/editoruiview.js b/src/editorui/editoruiview.js index d5f48dac..463c24a8 100644 --- a/src/editorui/editoruiview.js +++ b/src/editorui/editoruiview.js @@ -34,13 +34,6 @@ export default class EditorUIView extends View { * @member {module:ui/viewcollection~ViewCollection} #body */ this.body = new BodyCollection( locale ); - - /** - * The element holding elements of the 'body' region. - * - * @private - * @member {HTMLElement} #_bodyCollectionContainer - */ } /** From 74b6034df5728e49531cb5293c0f8619a65adbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:05:43 +0100 Subject: [PATCH 27/98] Renamed attachToDOM() to attachToDom(). --- src/editorui/bodycollection.js | 4 ++-- src/editorui/editoruiview.js | 2 +- tests/editorui/bodycollection.js | 26 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index d693efd7..ee782e26 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -24,7 +24,7 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * * If you need to control the live cycle of the body collection on your own, you can create your own instance of this class. * - * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDOM}. + * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}. * If you create multiple body collections this class will create a special wrapper element in the DOM to limit the number of * elements created directly in the body and remove it when the last body collection will be * {@link ~BodyCollection#detachFromDOM detached}. @@ -36,7 +36,7 @@ export default class BodyCollection extends ViewCollection { * Attaches the body collection to the DOM body element. You need to execute this method to render the content of * the body collection. */ - attachToDOM() { + attachToDom() { /** * The element holding elements of the 'body' region. * diff --git a/src/editorui/editoruiview.js b/src/editorui/editoruiview.js index 463c24a8..06924646 100644 --- a/src/editorui/editoruiview.js +++ b/src/editorui/editoruiview.js @@ -42,7 +42,7 @@ export default class EditorUIView extends View { render() { super.render(); - this.body.attachToDOM(); + this.body.attachToDom(); } /** diff --git a/tests/editorui/bodycollection.js b/tests/editorui/bodycollection.js index 831c8bcc..1ed59d1d 100644 --- a/tests/editorui/bodycollection.js +++ b/tests/editorui/bodycollection.js @@ -28,11 +28,11 @@ describe( 'BodyCollection', () => { } } ); - describe( 'attachToDOM', () => { + describe( 'attachToDom', () => { it( 'should create wrapper and put the collection in that wrapper', () => { const body = new BodyCollection( locale ); - body.attachToDOM(); + body.attachToDom(); const wrappers = Array.from( document.querySelectorAll( '.ck-body-wrapper' ) ); @@ -51,7 +51,7 @@ describe( 'BodyCollection', () => { it( 'sets the right dir attribute to the body region (LTR)', () => { const body = new BodyCollection( locale ); - body.attachToDOM(); + body.attachToDom(); const el = body._bodyCollectionContainer; @@ -62,7 +62,7 @@ describe( 'BodyCollection', () => { const locale = new Locale( { uiLanguage: 'ar' } ); const body = new BodyCollection( locale ); - body.attachToDOM(); + body.attachToDom(); const el = body._bodyCollectionContainer; @@ -71,13 +71,13 @@ describe( 'BodyCollection', () => { it( 'should put all body elements to the same wrapper', () => { const body1 = new BodyCollection( locale ); - body1.attachToDOM(); + body1.attachToDom(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 1 ); const body2 = new BodyCollection( locale ); - body2.attachToDOM(); + body2.attachToDom(); const bodyElements = document.querySelectorAll( '.ck-body' ); @@ -98,7 +98,7 @@ describe( 'BodyCollection', () => { } ); // Should work if body is attached before the view is added... - body1.attachToDOM(); + body1.attachToDom(); body1.add( view1 ); const body2 = new BodyCollection( locale ); @@ -113,7 +113,7 @@ describe( 'BodyCollection', () => { // ...and it should work if body is attached after the view is added. body2.add( view2 ); - body2.attachToDOM(); + body2.attachToDom(); const wrappers = Array.from( document.querySelectorAll( '.ck-body-wrapper' ) ); @@ -137,7 +137,7 @@ describe( 'BodyCollection', () => { it( 'removes the body collection from DOM', () => { const body = new BodyCollection( locale ); - body.attachToDOM(); + body.attachToDom(); body.detachFromDOM(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 0 ); @@ -146,10 +146,10 @@ describe( 'BodyCollection', () => { it( 'removes the multiple body collections from dom and remove the wrapper when the last is removed', () => { const body1 = new BodyCollection( locale ); - body1.attachToDOM(); + body1.attachToDom(); const body2 = new BodyCollection( locale ); - body2.attachToDOM(); + body2.attachToDom(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 2 ); @@ -167,7 +167,7 @@ describe( 'BodyCollection', () => { it( 'should not throw when be called multiple times', () => { const body = new BodyCollection( locale ); - body.attachToDOM(); + body.attachToDom(); expect( () => { body.detachFromDOM(); @@ -175,7 +175,7 @@ describe( 'BodyCollection', () => { } ).to.not.throw(); } ); - it( 'should not throw if attachToDOM was not called before', () => { + it( 'should not throw if attachToDom was not called before', () => { const body = new BodyCollection( locale ); expect( () => { From 75995471ba26eaf45ae91231911d664edd4d026c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:07:56 +0100 Subject: [PATCH 28/98] Renamed detachFromDOM() to detachFromDom(). --- src/editorui/bodycollection.js | 4 ++-- src/editorui/editoruiview.js | 2 +- tests/editorui/bodycollection.js | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index ee782e26..7e51cd38 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -27,7 +27,7 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}. * If you create multiple body collections this class will create a special wrapper element in the DOM to limit the number of * elements created directly in the body and remove it when the last body collection will be - * {@link ~BodyCollection#detachFromDOM detached}. + * {@link ~BodyCollection#detachFromDom detached}. * * @extends module:ui/viewcollection~ViewCollection */ @@ -71,7 +71,7 @@ export default class BodyCollection extends ViewCollection { * Detach the collection from the DOM structure. Use this method when you do not need to use the body collection * anymore to clean-up the DOM structure. */ - detachFromDOM() { + detachFromDom() { super.destroy(); if ( this._bodyCollectionContainer ) { diff --git a/src/editorui/editoruiview.js b/src/editorui/editoruiview.js index 06924646..4307c11b 100644 --- a/src/editorui/editoruiview.js +++ b/src/editorui/editoruiview.js @@ -49,7 +49,7 @@ export default class EditorUIView extends View { * @inheritDoc */ destroy() { - this.body.detachFromDOM(); + this.body.detachFromDom(); return super.destroy(); } diff --git a/tests/editorui/bodycollection.js b/tests/editorui/bodycollection.js index 1ed59d1d..12e35f41 100644 --- a/tests/editorui/bodycollection.js +++ b/tests/editorui/bodycollection.js @@ -133,12 +133,12 @@ describe( 'BodyCollection', () => { } ); } ); - describe( 'detachFromDOM', () => { + describe( 'detachFromDom', () => { it( 'removes the body collection from DOM', () => { const body = new BodyCollection( locale ); body.attachToDom(); - body.detachFromDOM(); + body.detachFromDom(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 0 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 0 ); @@ -154,12 +154,12 @@ describe( 'BodyCollection', () => { expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 2 ); - body1.detachFromDOM(); + body1.detachFromDom(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 1 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 1 ); - body2.detachFromDOM(); + body2.detachFromDom(); expect( document.querySelectorAll( '.ck-body-wrapper' ).length ).to.equal( 0 ); expect( document.querySelectorAll( '.ck-body' ).length ).to.equal( 0 ); @@ -170,8 +170,8 @@ describe( 'BodyCollection', () => { body.attachToDom(); expect( () => { - body.detachFromDOM(); - body.detachFromDOM(); + body.detachFromDom(); + body.detachFromDom(); } ).to.not.throw(); } ); @@ -179,7 +179,7 @@ describe( 'BodyCollection', () => { const body = new BodyCollection( locale ); expect( () => { - body.detachFromDOM(); + body.detachFromDom(); } ).to.not.throw(); } ); } ); From 9edbdc267de74773864e6388c0001d4147b18fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:09:53 +0100 Subject: [PATCH 29/98] Docs improvements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Piotrek Koszuliński --- src/editorui/bodycollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 7e51cd38..8d1fc457 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -15,7 +15,7 @@ import ViewCollection from '../viewcollection'; import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; /** - * This is the special {@link module:ui/viewcollection~ViewCollection ViewCollection} dedicated to elements that are detached + * This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached * from the DOM structure of the editor, like panels, icons, etc. * * CKEditor creates the body collection as {@link module:ui/editorui/editoruiview~EditorUIView#body editor.ui.view.body} property. From 3ffa6b8f29500ea5087887c8623e6cc685933a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:10:10 +0100 Subject: [PATCH 30/98] Docs improvements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Piotrek Koszuliński --- src/editorui/bodycollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 8d1fc457..61a5aff1 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -18,7 +18,7 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached * from the DOM structure of the editor, like panels, icons, etc. * - * CKEditor creates the body collection as {@link module:ui/editorui/editoruiview~EditorUIView#body editor.ui.view.body} property. + * The body collection is available in the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property. * Any plugin can add a {@link module:ui/view~View view} to this collection. The editor will detach and destroy this collection * when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}. * From 70c867b3aea43643acbc1b84e87530d2a24b89a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:10:32 +0100 Subject: [PATCH 31/98] Docs improvements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Piotrek Koszuliński --- src/editorui/bodycollection.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 61a5aff1..116a4e2f 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -19,7 +19,8 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * from the DOM structure of the editor, like panels, icons, etc. * * The body collection is available in the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property. - * Any plugin can add a {@link module:ui/view~View view} to this collection. The editor will detach and destroy this collection + * Any plugin can add a {@link module:ui/view~View view} to this collection. Those views will render in a container placed directly in the `` element. + * The editor will detach and destroy this collection * when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}. * * If you need to control the live cycle of the body collection on your own, you can create your own instance of this class. From de73f725db37195b53d9f44f370c7a27d0186330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:11:22 +0100 Subject: [PATCH 32/98] Docs improvements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Piotrek Koszuliński --- src/editorui/bodycollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 116a4e2f..2fa58478 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -23,7 +23,7 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * The editor will detach and destroy this collection * when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}. * - * If you need to control the live cycle of the body collection on your own, you can create your own instance of this class. + * If you need to control the life cycle of the body collection on your own, you can create your own instance of this class. * * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}. * If you create multiple body collections this class will create a special wrapper element in the DOM to limit the number of From e577621d6a0c68aa220d05db063ae6cee7c2f57e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Wr=C3=B3bel?= Date: Thu, 19 Dec 2019 09:12:39 +0100 Subject: [PATCH 33/98] Docs improvements. --- src/editorui/bodycollection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editorui/bodycollection.js b/src/editorui/bodycollection.js index 2fa58478..5d528d9a 100644 --- a/src/editorui/bodycollection.js +++ b/src/editorui/bodycollection.js @@ -25,7 +25,7 @@ import createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement'; * * If you need to control the life cycle of the body collection on your own, you can create your own instance of this class. * - * Body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}. + * A body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}. * If you create multiple body collections this class will create a special wrapper element in the DOM to limit the number of * elements created directly in the body and remove it when the last body collection will be * {@link ~BodyCollection#detachFromDom detached}. @@ -39,7 +39,7 @@ export default class BodyCollection extends ViewCollection { */ attachToDom() { /** - * The element holding elements of the 'body' region. + * The element holding elements of the body region. * * @protected * @member {HTMLElement} #_bodyCollectionContainer From 9db89a5ac36e76f09024a5c1722de2ccce964179 Mon Sep 17 00:00:00 2001 From: Aleksander Nowodzinski Date: Tue, 14 Jan 2020 16:44:45 +0100 Subject: [PATCH 34/98] Brought LabeledView. Aligned DropdownView to LabeledView interface. --- src/dropdown/dropdownview.js | 23 +++- src/label/labelview.js | 9 ++ src/labeledview/creators.js | 45 ++++++++ src/labeledview/labeledview.js | 205 +++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 src/labeledview/creators.js create mode 100644 src/labeledview/labeledview.js diff --git a/src/dropdown/dropdownview.js b/src/dropdown/dropdownview.js index 3b0b3502..34152145 100644 --- a/src/dropdown/dropdownview.js +++ b/src/dropdown/dropdownview.js @@ -130,6 +130,23 @@ export default class DropdownView extends View { */ this.set( 'class' ); + /** + * (Optional) The `id` attribute of the dropdown (i.e. to pair with a `