Browse Source

TableToolbar will handle all table toolbar configs.

Maciej Bukowski 7 years ago
parent
commit
22af30228b

+ 68 - 14
packages/ckeditor5-table/src/tabletoolbar.js

@@ -8,17 +8,20 @@
  */
 
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import { isTableContentSelected } from './utils';
+import { isTableContentSelected, isTableWidgetSelected } from './utils';
 import WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';
 
 /**
- * The table toolbar class. It creates a table toolbar that shows up when the table content is selected.
+ * The table toolbar class. It creates toolbars for the table feature and its content (for now only for a table cell).
  *
- * Instances of toolbar components (e.g. buttons) are created using the editor's
- * {@link module:ui/componentfactory~ComponentFactory component factory}
- * based on the {@link module:table/table~TableConfig#toolbar `table.toolbar` configuration option}.
+ * Table toolbar shows up when the table widget is selected. Its components (e.g. buttons) are created based on the
+ * {@link module:table/table~TableConfig#toolbar `table.tableToolbar` configuration option}.
  *
- * The toolbar uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon} plugin.
+ * Table content toolbar shows up when the table cell is selected. It creates its component based on the
+ * {@link module:table/table~TableConfig#contentToolbar `table.contentToolbar` configuration option}.
+ *
+ * Note that the old {@link module:table/table~TableConfig#toolbar `table.toolbar` configuration option} is deprecated
+ * and will be removed in the next major release.
  *
  * @extends module:core/plugin~Plugin
  */
@@ -44,16 +47,49 @@ export default class TableToolbar extends Plugin {
 		const editor = this.editor;
 		const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
 
-		widgetToolbarRepository.register( 'table', {
-			items: editor.config.get( 'table.toolbar' ) || [],
-			visibleWhen: isTableContentSelected,
-		} );
+		const tableContentToolbarItems = editor.config.get( 'table.contentToolbar' );
+		const deprecatedTableContentToolbarItems = editor.config.get( 'table.toolbar' );
+
+		const tableToolbarItems = editor.config.get( 'table.tableToolbar' );
+
+		if ( deprecatedTableContentToolbarItems ) {
+			// eslint-disable-next-line
+			console.warn(
+				'`config.table.toolbar` is deprecated and will be removed in the next major release.' +
+				' Use `config.table.contentToolbar` instead.'
+			);
+		}
+
+		if ( tableContentToolbarItems || deprecatedTableContentToolbarItems ) {
+			widgetToolbarRepository.register( 'tableContent', {
+				items: tableContentToolbarItems || deprecatedTableContentToolbarItems,
+				visibleWhen: isTableContentSelected,
+			} );
+		}
+
+		if ( tableToolbarItems ) {
+			widgetToolbarRepository.register( 'table', {
+				items: tableToolbarItems,
+				visibleWhen: isTableWidgetSelected,
+			} );
+		}
 	}
 }
 
 /**
- * Items to be placed in the table toolbar.
- * This option is used by the {@link module:table/tabletoolbar~TableToolbar} feature.
+ * Items to be placed in the table content toolbar.
+ *
+ * **Note:** This is a deprecated configuration option! Use {@link module:table/table~TableConfig#contentToolbar} instead.
+ *
+ * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.
+ *
+ * @deprecated
+ * @member {Array.<String>} module:table/table~TableConfig#toolbar
+ */
+
+/**
+ * Items to be placed in the table content toolbar.
+ * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar working.
  *
  * Assuming that you use the {@link module:table/tableui~TableUI} feature, the following toolbar items will be available
  * in {@link module:ui/componentfactory~ComponentFactory}:
@@ -65,7 +101,7 @@ export default class TableToolbar extends Plugin {
  * You can thus configure the toolbar like this:
  *
  *		const tableConfig = {
- *			toolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]
+ *			contentToolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]
  *		};
  *
  * Of course, the same buttons can also be used in the
@@ -73,5 +109,23 @@ export default class TableToolbar extends Plugin {
  *
  * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.
  *
- * @member {Array.<String>} module:table/table~TableConfig#toolbar
+ * @member {Array.<String>} module:table/table~TableConfig#contentToolbar
+ */
+
+/**
+ * Items to be placed in the table toolbar.
+ * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar working.
+ *
+ * You can thus configure the toolbar like this:
+ *
+ *		const tableConfig = {
+ *			tableToolbar: [ 'blockQuote' ]
+ *		};
+ *
+ * Of course, the same buttons can also be used in the
+ * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.
+ *
+ * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.
+ *
+ * @member {Array.<String>} module:table/table~TableConfig#tableToolbar
  */

+ 0 - 43
packages/ckeditor5-table/src/tablewidgettoolbar.js

@@ -1,43 +0,0 @@
-/**
- * Copyright (c) 2016 - 2018, CKSource - Frederico Knabben. All rights reserved.
- */
-
-import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-import { isTableWidgetSelected } from '@ckeditor/ckeditor5-table/src/utils';
-import WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';
-
-/**
- * The table widget toolbar class. It creates a table toolbar that shows up when the table widget is selected.
- *
- * The toolbar uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.
- *
- * @extends module:core/plugin~Plugin
- */
-export default class TableWidgetToolbar extends Plugin {
-	/**
-	 * @inheritDoc
-	 */
-	static get requires() {
-		return [ WidgetToolbarRepository ];
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	static get pluginName() {
-		return 'TableWidgetToolbar';
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	afterInit() {
-		const editor = this.editor;
-		const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
-
-		widgetToolbarRepository.register( 'tableWidget', {
-			items: editor.config.get( 'table.widgetToolbar' ) || [],
-			visibleWhen: isTableWidgetSelected,
-		} );
-	}
-}

+ 1 - 1
packages/ckeditor5-table/tests/integration.js

@@ -12,7 +12,7 @@ import Table from '../src/table';
 import TableToolbar from '../src/tabletoolbar';
 import View from '@ckeditor/ckeditor5-ui/src/view';
 
-describe( 'TableToolbar integration', () => {
+describe( 'TableContentToolbar integration', () => {
 	describe( 'with the BalloonToolbar', () => {
 		let balloon, balloonToolbar, newEditor, editorElement;
 

+ 383 - 132
packages/ckeditor5-table/tests/tabletoolbar.js

@@ -3,9 +3,9 @@
  * For licensing, see LICENSE.md.
  */
 
-/* global document */
+/* global document, window */
 
-import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import ClassicTestEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
 import TableToolbar from '../src/tabletoolbar';
 import Table from '../src/table';
 import global from '@ckeditor/ckeditor5-utils/src/dom/global';
@@ -15,199 +15,450 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 import View from '@ckeditor/ckeditor5-ui/src/view';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+import WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';
+import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 
 describe( 'TableToolbar', () => {
-	let editor, model, doc, widgetToolbarRepository, toolbar, balloon, editorElement;
+	testUtils.createSinonSandbox();
 
-	beforeEach( () => {
-		editorElement = global.document.createElement( 'div' );
-		global.document.body.appendChild( editorElement );
+	describe( 'contentToolbar', () => {
+		let editor, model, doc, widgetToolbarRepository, toolbar, balloon, editorElement;
 
-		return ClassicEditor
-			.create( editorElement, {
-				plugins: [ Paragraph, Table, TableToolbar, FakeButton ],
-				table: {
-					toolbar: [ 'fake_button' ]
-				}
+		beforeEach( () => {
+			editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+
+			return ClassicTestEditor
+				.create( editorElement, {
+					plugins: [ Paragraph, Table, TableToolbar, FakeButton ],
+					table: {
+						contentToolbar: [ 'fake_button' ]
+					}
+				} )
+				.then( newEditor => {
+					editor = newEditor;
+					model = newEditor.model;
+					doc = model.document;
+					widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+					toolbar = widgetToolbarRepository._toolbars.get( 'tableContent' ).view;
+					balloon = editor.plugins.get( 'ContextualBalloon' );
+				} );
+		} );
+
+		afterEach( () => {
+			editorElement.remove();
+
+			return editor.destroy();
+		} );
+
+		it( 'should be loaded', () => {
+			expect( editor.plugins.get( TableToolbar ) ).to.be.instanceOf( TableToolbar );
+		} );
+
+		it( 'should not initialize if there is no configuration', () => {
+			const editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+
+			return ClassicTestEditor.create( editorElement, {
+				plugins: [ TableToolbar ]
 			} )
-			.then( newEditor => {
-				editor = newEditor;
-				model = newEditor.model;
-				doc = model.document;
-				widgetToolbarRepository = editor.plugins.get( 'WidgetToolbarRepository' );
-				toolbar = widgetToolbarRepository._toolbars.get( 'table' ).view;
-				balloon = editor.plugins.get( 'ContextualBalloon' );
+				.then( editor => {
+					const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+					expect( widgetToolbarRepository._toolbars.get( 'tableContent' ) ).to.be.undefined;
+
+					editorElement.remove();
+					return editor.destroy();
+				} );
+		} );
+
+		describe( 'toolbar', () => {
+			it( 'should use the config.table.toolbar to create items', () => {
+				expect( toolbar.items ).to.have.length( 1 );
+				expect( toolbar.items.get( 0 ).label ).to.equal( 'fake button' );
 			} );
-	} );
 
-	afterEach( () => {
-		editorElement.remove();
+			it( 'should set proper CSS classes', () => {
+				const spy = sinon.spy( balloon, 'add' );
 
-		return editor.destroy();
-	} );
+				editor.ui.focusTracker.isFocused = true;
 
-	it( 'should be loaded', () => {
-		expect( editor.plugins.get( TableToolbar ) ).to.be.instanceOf( TableToolbar );
-	} );
+				setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
 
-	it( 'should not initialize if there is no configuration', () => {
-		const editorElement = global.document.createElement( 'div' );
-		global.document.body.appendChild( editorElement );
+				sinon.assert.calledWithMatch( spy, {
+					view: toolbar,
+					balloonClassName: 'ck-toolbar-container'
+				} );
+			} );
+		} );
+
+		describe( 'integration with the editor focus', () => {
+			it( 'should show the toolbar when the editor gains focus and the table is selected', () => {
+				editor.ui.focusTracker.isFocused = true;
 
-		return ClassicEditor.create( editorElement, {
-			plugins: [ TableToolbar ]
-		} )
-			.then( editor => {
-				expect( editor.plugins.get( TableToolbar )._toolbar ).to.be.undefined;
+				setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
 
-				editorElement.remove();
-				return editor.destroy();
+				editor.ui.focusTracker.isFocused = false;
+				expect( balloon.visibleView ).to.be.null;
+
+				editor.ui.focusTracker.isFocused = true;
+				expect( balloon.visibleView ).to.equal( toolbar );
 			} );
-	} );
 
-	describe( 'toolbar', () => {
-		it( 'should use the config.table.toolbar to create items', () => {
-			expect( toolbar.items ).to.have.length( 1 );
-			expect( toolbar.items.get( 0 ).label ).to.equal( 'fake button' );
+			it( 'should hide the toolbar when the editor loses focus and the table is selected', () => {
+				editor.ui.focusTracker.isFocused = false;
+
+				setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
+
+				editor.ui.focusTracker.isFocused = true;
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				editor.ui.focusTracker.isFocused = false;
+				expect( balloon.visibleView ).to.be.null;
+			} );
 		} );
 
-		it( 'should set proper CSS classes', () => {
-			const spy = sinon.spy( balloon, 'add' );
+		describe( 'integration with the editor selection (ui#update event)', () => {
+			beforeEach( () => {
+				editor.ui.focusTracker.isFocused = true;
+			} );
+
+			it( 'should not show the toolbar on ui#update when the table is selected', () => {
+				setData( model, '<paragraph>foo</paragraph>[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
+
+				expect( balloon.visibleView ).to.be.null;
+			} );
 
-			editor.ui.focusTracker.isFocused = true;
+			it( 'should show the toolbar on ui#update when the table content is selected', () => {
+				setData(
+					model,
+					'<paragraph>[foo]</paragraph><table><tableRow><tableCell><paragraph>bar</paragraph></tableCell></tableRow></table>'
+				);
 
-			setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
+				expect( balloon.visibleView ).to.be.null;
 
-			sinon.assert.calledWithMatch( spy, {
-				view: toolbar,
-				balloonClassName: 'ck-toolbar-container'
+				editor.ui.fire( 'update' );
+
+				expect( balloon.visibleView ).to.be.null;
+
+				model.change( writer => {
+					// Select the <tableCell>[bar]</tableCell>
+					writer.setSelection(
+						Range.createOn( doc.getRoot().getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) )
+					);
+				} );
+
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				// Make sure successive change does not throw, e.g. attempting
+				// to insert the toolbar twice.
+				editor.ui.fire( 'update' );
+				expect( balloon.visibleView ).to.equal( toolbar );
 			} );
-		} );
-	} );
 
-	describe( 'integration with the editor focus', () => {
-		it( 'should show the toolbar when the editor gains focus and the table is selected', () => {
-			editor.ui.focusTracker.isFocused = true;
+			it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
+				setData( model, '<table><tableRow><tableCell><paragraph>x[y]z</paragraph></tableCell></tableRow></table>' );
 
-			setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
+				expect( balloon.visibleView ).to.equal( toolbar );
 
-			editor.ui.focusTracker.isFocused = false;
-			expect( balloon.visibleView ).to.be.null;
+				// Put anything on top of the ContextualBalloon stack above the table toolbar.
+				const lastView = new View();
+				lastView.element = document.createElement( 'div' );
 
-			editor.ui.focusTracker.isFocused = true;
-			expect( balloon.visibleView ).to.equal( toolbar );
-		} );
+				balloon.add( {
+					view: lastView,
+					position: {
+						target: document.body
+					}
+				} );
+
+				expect( balloon.visibleView ).to.equal( lastView );
+
+				editor.ui.fire( 'update' );
+
+				expect( balloon.visibleView ).to.equal( lastView );
+			} );
+
+			it( 'should hide the toolbar on render if the table is de–selected', () => {
+				setData(
+					model,
+					'<paragraph>foo</paragraph><table><tableRow><tableCell><paragraph>[]</paragraph></tableCell></tableRow></table>'
+				);
 
-		it( 'should hide the toolbar when the editor loses focus and the table is selected', () => {
-			editor.ui.focusTracker.isFocused = false;
+				expect( balloon.visibleView ).to.equal( toolbar );
 
-			setData( model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
+				model.change( writer => {
+					// Select the <paragraph>[...]</paragraph>
+					writer.setSelection(
+						Range.createIn( doc.getRoot().getChild( 0 ) )
+					);
+				} );
 
-			editor.ui.focusTracker.isFocused = true;
-			expect( balloon.visibleView ).to.equal( toolbar );
+				expect( balloon.visibleView ).to.be.null;
 
-			editor.ui.focusTracker.isFocused = false;
-			expect( balloon.visibleView ).to.be.null;
+				// Make sure successive change does not throw, e.g. attempting
+				// to remove the toolbar twice.
+				editor.ui.fire( 'update' );
+				expect( balloon.visibleView ).to.be.null;
+			} );
 		} );
 	} );
 
-	describe( 'integration with the editor selection (ui#update event)', () => {
-		beforeEach( () => {
-			editor.ui.focusTracker.isFocused = true;
+	describe( 'deprecated toolbar', () => {
+		let editor, editorElement, warnMock;
+
+		it( 'table.toolbar should work as table.contentToolbar', () => {
+			editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+			warnMock = sinon.stub( window.console, 'warn' );
+
+			return ClassicTestEditor
+				.create( editorElement, {
+					plugins: [ Paragraph, Table, TableToolbar, FakeButton ],
+					table: {
+						toolbar: [ 'fake_button' ]
+					}
+				} )
+				.then( newEditor => {
+					editor = newEditor;
+
+					const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+					const toolbarView = widgetToolbarRepository._toolbars.get( 'tableContent' ).view;
+
+					expect( toolbarView.items ).to.have.length( 1 );
+					expect( toolbarView.items.get( 0 ).label ).to.equal( 'fake button' );
+
+					sinon.assert.calledWith(
+						warnMock,
+						'`config.table.toolbar` is deprecated and will be removed in the next major release.' +
+						' Use `config.table.contentToolbar` instead.'
+					);
+				} );
 		} );
 
-		it( 'should not show the toolbar on ui#update when the table is selected', () => {
-			setData( model, '<paragraph>foo</paragraph>[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
+		it( 'table.contentToolbar should be used if both toolbars options are provided', () => {
+			editorElement = global.document.createElement( 'div' );
+			global.document.body.appendChild( editorElement );
+			warnMock = sinon.stub( window.console, 'warn' );
+
+			return ClassicTestEditor
+				.create( editorElement, {
+					plugins: [ Paragraph, Table, TableToolbar, FakeButton, FooButton ],
+					table: {
+						toolbar: [ 'fake_button' ],
+						contentToolbar: [ 'foo_button' ],
+					}
+				} )
+				.then( newEditor => {
+					editor = newEditor;
+
+					const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+					const toolbarView = widgetToolbarRepository._toolbars.get( 'tableContent' ).view;
+
+					expect( toolbarView.items ).to.have.length( 1 );
+					expect( toolbarView.items.get( 0 ).label ).to.equal( 'foo button' );
+				} );
+		} );
 
-			expect( balloon.visibleView ).to.be.null;
+		afterEach( () => {
+			editorElement.remove();
+
+			return editor.destroy();
 		} );
+	} );
 
-		it( 'should show the toolbar on ui#update when the table content is selected', () => {
-			setData(
-				model,
-				'<paragraph>[foo]</paragraph><table><tableRow><tableCell><paragraph>bar</paragraph></tableCell></tableRow></table>'
-			);
+	describe( 'tableToolbar', () => {
+		let editor, element, widgetToolbarRepository, balloon, toolbar, model;
 
-			expect( balloon.visibleView ).to.be.null;
+		beforeEach( () => {
+			element = document.createElement( 'div' );
+			document.body.appendChild( element );
 
-			editor.ui.fire( 'update' );
+			return ClassicTestEditor.create( element, {
+				plugins: [ Paragraph, Table, TableToolbar, FakeButton ],
+				table: {
+					tableToolbar: [ 'fake_button' ]
+				}
+			} ).then( _editor => {
+				editor = _editor;
+				widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+				toolbar = widgetToolbarRepository._toolbars.get( 'table' ).view;
+				balloon = editor.plugins.get( 'ContextualBalloon' );
+				model = editor.model;
+			} );
+		} );
 
-			expect( balloon.visibleView ).to.be.null;
+		afterEach( () => {
+			return editor.destroy()
+				.then( () => element.remove() );
+		} );
 
-			model.change( writer => {
-				// Select the <tableCell>[bar]</tableCell>
-				writer.setSelection(
-					Range.createOn( doc.getRoot().getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) )
-				);
+		describe( 'toolbar', () => {
+			it( 'should not initialize if there is no configuration', () => {
+				const editorElement = global.document.createElement( 'div' );
+				global.document.body.appendChild( editorElement );
+
+				return ClassicTestEditor.create( editorElement, {
+					plugins: [ TableToolbar ]
+				} )
+					.then( editor => {
+						const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
+						expect( widgetToolbarRepository._toolbars.get( 'table' ) ).to.be.undefined;
+
+						editorElement.remove();
+						return editor.destroy();
+					} );
 			} );
 
-			expect( balloon.visibleView ).to.equal( toolbar );
+			it( 'should use the config.table.tableWidget to create items', () => {
+				expect( toolbar.items ).to.have.length( 1 );
+				expect( toolbar.items.get( 0 ).label ).to.equal( 'fake button' );
+			} );
+
+			it( 'should set proper CSS classes', () => {
+				const spy = sinon.spy( balloon, 'add' );
+
+				editor.ui.focusTracker.isFocused = true;
 
-			// Make sure successive change does not throw, e.g. attempting
-			// to insert the toolbar twice.
-			editor.ui.fire( 'update' );
-			expect( balloon.visibleView ).to.equal( toolbar );
+				setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
+
+				sinon.assert.calledWithMatch( spy, {
+					view: toolbar,
+					balloonClassName: 'ck-toolbar-container'
+				} );
+			} );
 		} );
 
-		it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
-			setData( model, '<table><tableRow><tableCell><paragraph>x[y]z</paragraph></tableCell></tableRow></table>' );
+		describe( 'integration with the editor focus', () => {
+			it( 'should show the toolbar when the editor gains focus and the table is selected', () => {
+				editor.ui.focusTracker.isFocused = true;
 
-			expect( balloon.visibleView ).to.equal( toolbar );
+				setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
 
-			// Put anything on top of the ContextualBalloon stack above the table toolbar.
-			const lastView = new View();
-			lastView.element = document.createElement( 'div' );
+				editor.ui.focusTracker.isFocused = false;
+				expect( balloon.visibleView ).to.be.null;
 
-			balloon.add( {
-				view: lastView,
-				position: {
-					target: document.body
-				}
+				editor.ui.focusTracker.isFocused = true;
+				expect( balloon.visibleView ).to.equal( toolbar );
 			} );
 
-			expect( balloon.visibleView ).to.equal( lastView );
+			it( 'should hide the toolbar when the editor loses focus and the table is selected', () => {
+				editor.ui.focusTracker.isFocused = false;
 
-			editor.ui.fire( 'update' );
+				setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
 
-			expect( balloon.visibleView ).to.equal( lastView );
+				editor.ui.focusTracker.isFocused = true;
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				editor.ui.focusTracker.isFocused = false;
+				expect( balloon.visibleView ).to.be.null;
+			} );
 		} );
 
-		it( 'should hide the toolbar on render if the table is de–selected', () => {
-			setData(
-				model,
-				'<paragraph>foo</paragraph><table><tableRow><tableCell><paragraph>[]</paragraph></tableCell></tableRow></table>'
-			);
+		describe( 'integration with the editor selection', () => {
+			beforeEach( () => {
+				editor.ui.focusTracker.isFocused = true;
+			} );
+
+			it( 'should show the toolbar on ui#update when the table widget is selected', () => {
+				setData( editor.model, '<paragraph>[foo]</paragraph><table><tableRow><tableCell></tableCell></tableRow></table>' );
 
-			expect( balloon.visibleView ).to.equal( toolbar );
+				expect( balloon.visibleView ).to.be.null;
 
-			model.change( writer => {
-				// Select the <paragraph>[...]</paragraph>
-				writer.setSelection(
-					Range.createIn( doc.getRoot().getChild( 0 ) )
-				);
+				editor.ui.fire( 'update' );
+
+				expect( balloon.visibleView ).to.be.null;
+
+				editor.model.change( writer => {
+					// Select the [<table></table>]
+					writer.setSelection( editor.model.document.getRoot().getChild( 1 ), 'on' );
+				} );
+
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				// Make sure successive change does not throw, e.g. attempting
+				// to insert the toolbar twice.
+				editor.ui.fire( 'update' );
+				expect( balloon.visibleView ).to.equal( toolbar );
 			} );
 
-			expect( balloon.visibleView ).to.be.null;
+			it( 'should not show the toolbar on ui#update when the selection is inside a table cell', () => {
+				setData( editor.model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
 
-			// Make sure successive change does not throw, e.g. attempting
-			// to remove the toolbar twice.
-			editor.ui.fire( 'update' );
-			expect( balloon.visibleView ).to.be.null;
+				expect( balloon.visibleView ).to.be.null;
+
+				editor.ui.fire( 'update' );
+
+				expect( balloon.visibleView ).to.be.null;
+			} );
+
+			it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
+				setData( model, '<table><tableRow><tableCell></tableCell></tableRow></table>' );
+
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				const lastView = new View();
+				lastView.element = document.createElement( 'div' );
+
+				balloon.add( {
+					view: lastView,
+					position: {
+						target: document.body
+					}
+				} );
+
+				expect( balloon.visibleView ).to.equal( lastView );
+
+				editor.ui.fire( 'update' );
+
+				expect( balloon.visibleView ).to.equal( lastView );
+			} );
+
+			it( 'should hide the toolbar on ui#update if the table is de–selected', () => {
+				setData( model, '<paragraph>foo</paragraph>[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
+				expect( balloon.visibleView ).to.equal( toolbar );
+
+				model.change( writer => {
+					// Select the <paragraph>[...]</paragraph>
+					writer.setSelection( model.document.getRoot().getChild( 0 ), 'in' );
+				} );
+
+				expect( balloon.visibleView ).to.be.null;
+
+				// Make sure successive change does not throw, e.g. attempting
+				// to remove the toolbar twice.
+				editor.ui.fire( 'update' );
+				expect( balloon.visibleView ).to.be.null;
+			} );
 		} );
 	} );
+} );
 
-	// Plugin that adds fake_button to editor's component factory.
-	class FakeButton extends Plugin {
-		init() {
-			this.editor.ui.componentFactory.add( 'fake_button', locale => {
-				const view = new ButtonView( locale );
+// Plugin that adds fake_button to editor's component factory.
+class FakeButton extends Plugin {
+	init() {
+		this.editor.ui.componentFactory.add( 'fake_button', locale => {
+			const view = new ButtonView( locale );
 
-				view.set( {
-					label: 'fake button'
-				} );
+			view.set( {
+				label: 'fake button'
+			} );
 
-				return view;
+			return view;
+		} );
+	}
+}
+
+// Plugin that adds foo_button to editor's component factory.
+class FooButton extends Plugin {
+	init() {
+		this.editor.ui.componentFactory.add( 'foo_button', locale => {
+			const view = new ButtonView( locale );
+
+			view.set( {
+				label: 'foo button'
 			} );
-		}
+
+			return view;
+		} );
 	}
-} );
+}

+ 0 - 187
packages/ckeditor5-table/tests/tablewidgettoolbar.js

@@ -1,187 +0,0 @@
-/**
- * Copyright (c) 2016 - 2017, CKSource - Frederico Knabben. All rights reserved.
- */
-
-/* global document */
-
-import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
-import Table from '@ckeditor/ckeditor5-table/src/table';
-import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import TableWidgetToolbar from '../src/tablewidgettoolbar';
-import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
-import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
-import View from '@ckeditor/ckeditor5-ui/src/view';
-import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
-
-import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
-
-describe( 'TableWidgetToolbar', () => {
-	let editor, element, widgetToolbarRepository, balloon, toolbar, model;
-
-	testUtils.createSinonSandbox();
-
-	beforeEach( () => {
-		element = document.createElement( 'div' );
-		document.body.appendChild( element );
-
-		return ClassicTestEditor.create( element, {
-			plugins: [ Paragraph, Table, TableWidgetToolbar, FakeButton ],
-			table: {
-				widgetToolbar: [ 'fake_button' ]
-			}
-		} ).then( _editor => {
-			editor = _editor;
-			widgetToolbarRepository = editor.plugins.get( 'WidgetToolbarRepository' );
-			toolbar = widgetToolbarRepository._toolbars.get( 'tableWidget' ).view;
-			balloon = editor.plugins.get( 'ContextualBalloon' );
-			model = editor.model;
-		} );
-	} );
-
-	afterEach( () => {
-		return editor.destroy()
-			.then( () => element.remove() );
-	} );
-
-	it( 'should be loaded', () => {
-		expect( editor.plugins.get( TableWidgetToolbar ) ).to.be.instanceOf( TableWidgetToolbar );
-	} );
-
-	describe( 'toolbar', () => {
-		it( 'should use the config.table.tableWidget to create items', () => {
-			expect( toolbar.items ).to.have.length( 1 );
-			expect( toolbar.items.get( 0 ).label ).to.equal( 'fake button' );
-		} );
-
-		it( 'should set proper CSS classes', () => {
-			const spy = sinon.spy( balloon, 'add' );
-
-			editor.ui.focusTracker.isFocused = true;
-
-			setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
-
-			sinon.assert.calledWithMatch( spy, {
-				view: toolbar,
-				balloonClassName: 'ck-toolbar-container'
-			} );
-		} );
-	} );
-
-	describe( 'integration with the editor focus', () => {
-		it( 'should show the toolbar when the editor gains focus and the table is selected', () => {
-			editor.ui.focusTracker.isFocused = true;
-
-			setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
-
-			editor.ui.focusTracker.isFocused = false;
-			expect( balloon.visibleView ).to.be.null;
-
-			editor.ui.focusTracker.isFocused = true;
-			expect( balloon.visibleView ).to.equal( toolbar );
-		} );
-
-		it( 'should hide the toolbar when the editor loses focus and the table is selected', () => {
-			editor.ui.focusTracker.isFocused = false;
-
-			setData( model, '[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
-
-			editor.ui.focusTracker.isFocused = true;
-			expect( balloon.visibleView ).to.equal( toolbar );
-
-			editor.ui.focusTracker.isFocused = false;
-			expect( balloon.visibleView ).to.be.null;
-		} );
-	} );
-
-	describe( 'integration with the editor selection', () => {
-		beforeEach( () => {
-			editor.ui.focusTracker.isFocused = true;
-		} );
-
-		it( 'should show the toolbar on ui#update when the table widget is selected', () => {
-			setData( editor.model, '<paragraph>[foo]</paragraph><table><tableRow><tableCell></tableCell></tableRow></table>' );
-
-			expect( balloon.visibleView ).to.be.null;
-
-			editor.ui.fire( 'update' );
-
-			expect( balloon.visibleView ).to.be.null;
-
-			editor.model.change( writer => {
-				// Select the [<table></table>]
-				writer.setSelection( editor.model.document.getRoot().getChild( 1 ), 'on' );
-			} );
-
-			expect( balloon.visibleView ).to.equal( toolbar );
-
-			// Make sure successive change does not throw, e.g. attempting
-			// to insert the toolbar twice.
-			editor.ui.fire( 'update' );
-			expect( balloon.visibleView ).to.equal( toolbar );
-		} );
-
-		it( 'should not show the toolbar on ui#update when the selection is inside a table cell', () => {
-			setData( editor.model, '<table><tableRow><tableCell>[]</tableCell></tableRow></table>' );
-
-			expect( balloon.visibleView ).to.be.null;
-
-			editor.ui.fire( 'update' );
-
-			expect( balloon.visibleView ).to.be.null;
-		} );
-
-		it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
-			setData( model, '<table><tableRow><tableCell></tableCell></tableRow></table>' );
-
-			expect( balloon.visibleView ).to.equal( toolbar );
-
-			const lastView = new View();
-			lastView.element = document.createElement( 'div' );
-
-			balloon.add( {
-				view: lastView,
-				position: {
-					target: document.body
-				}
-			} );
-
-			expect( balloon.visibleView ).to.equal( lastView );
-
-			editor.ui.fire( 'update' );
-
-			expect( balloon.visibleView ).to.equal( lastView );
-		} );
-
-		it( 'should hide the toolbar on ui#update if the table is de–selected', () => {
-			setData( model, '<paragraph>foo</paragraph>[<table><tableRow><tableCell></tableCell></tableRow></table>]' );
-			expect( balloon.visibleView ).to.equal( toolbar );
-
-			model.change( writer => {
-				// Select the <paragraph>[...]</paragraph>
-				writer.setSelection( model.document.getRoot().getChild( 0 ), 'in' );
-			} );
-
-			expect( balloon.visibleView ).to.be.null;
-
-			// Make sure successive change does not throw, e.g. attempting
-			// to remove the toolbar twice.
-			editor.ui.fire( 'update' );
-			expect( balloon.visibleView ).to.be.null;
-		} );
-	} );
-
-	// Plugin that adds fake_button to editor's component factory.
-	class FakeButton extends Plugin {
-		init() {
-			this.editor.ui.componentFactory.add( 'fake_button', locale => {
-				const view = new ButtonView( locale );
-
-				view.set( {
-					label: 'fake button'
-				} );
-
-				return view;
-			} );
-		}
-	}
-} );