Kaynağa Gözat

Merge branch 'master' into t/ckeditor5-engine/1436

Piotrek Koszuliński 7 yıl önce
ebeveyn
işleme
e60599112a

+ 28 - 3
packages/ckeditor5-table/src/commands/mergecellcommand.js

@@ -12,6 +12,7 @@ import Position from '@ckeditor/ckeditor5-engine/src/model/position';
 import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 import TableWalker from '../tablewalker';
 import { updateNumericAttribute } from './utils';
+import TableUtils from '../tableutils';
 
 /**
  * The merge cell command.
@@ -130,8 +131,12 @@ export default class MergeCellCommand extends Command {
 			return;
 		}
 
+		const tableUtils = this.editor.plugins.get( TableUtils );
+
 		// First get the cell on proper direction.
-		const cellToMerge = this.isHorizontal ? getHorizontalCell( element, this.direction ) : getVerticalCell( element, this.direction );
+		const cellToMerge = this.isHorizontal ?
+			getHorizontalCell( element, this.direction, tableUtils ) :
+			getVerticalCell( element, this.direction );
 
 		if ( !cellToMerge ) {
 			return;
@@ -154,8 +159,28 @@ export default class MergeCellCommand extends Command {
 // @param {module:engine/model/element~Element} tableCell
 // @param {String} direction
 // @returns {module:engine/model/node~Node|null}
-function getHorizontalCell( tableCell, direction ) {
-	return direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;
+function getHorizontalCell( tableCell, direction, tableUtils ) {
+	const horizontalCell = direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;
+
+	if ( !horizontalCell ) {
+		return;
+	}
+
+	// Sort cells:
+	const cellOnLeft = direction == 'right' ? tableCell : horizontalCell;
+	const cellOnRight = direction == 'right' ? horizontalCell : tableCell;
+
+	// Get their column indexes:
+	const { column: leftCellColumn } = tableUtils.getCellLocation( cellOnLeft );
+	const { column: rightCellColumn } = tableUtils.getCellLocation( cellOnRight );
+
+	const leftCellSpan = parseInt( cellOnLeft.getAttribute( 'colspan' ) || 1 );
+
+	// The cell on the right must have index that is distant to the cell on the left by the left cell's width (colspan).
+	const cellsAreTouching = leftCellColumn + leftCellSpan === rightCellColumn;
+
+	// If the right cell's column index is different it means that there are rowspanned cells between them.
+	return cellsAreTouching ? horizontalCell : undefined;
 }
 
 // Returns the cell that can be merged vertically.

+ 10 - 17
packages/ckeditor5-table/src/tabletoolbar.js

@@ -91,7 +91,7 @@ export default class TableToolbar extends Plugin {
 		this._toolbar.fillFromConfig( toolbarConfig, editor.ui.componentFactory );
 
 		// Show balloon panel each time table widget is selected.
-		this.listenTo( editor.editing.view, 'render', () => {
+		this.listenTo( editor.ui, 'update', () => {
 			this._checkIsVisible();
 		} );
 
@@ -108,17 +108,12 @@ export default class TableToolbar extends Plugin {
 	 */
 	_checkIsVisible() {
 		const editor = this.editor;
+		const viewSelection = editor.editing.view.document.selection;
 
-		if ( !editor.ui.focusTracker.isFocused ) {
+		if ( !editor.ui.focusTracker.isFocused || !isTableContentSelected( viewSelection ) ) {
 			this._hideToolbar();
 		} else {
-			const viewSelection = editor.editing.view.document.selection;
-
-			if ( isTableContentSelected( viewSelection ) ) {
-				this._showToolbar();
-			} else {
-				this._hideToolbar();
-			}
+			this._showToolbar();
 		}
 	}
 
@@ -132,14 +127,12 @@ export default class TableToolbar extends Plugin {
 
 		if ( this._isVisible ) {
 			repositionContextualBalloon( editor );
-		} else {
-			if ( !this._balloon.hasView( this._toolbar ) ) {
-				this._balloon.add( {
-					view: this._toolbar,
-					position: getBalloonPositionData( editor ),
-					balloonClassName
-				} );
-			}
+		} else if ( !this._balloon.hasView( this._toolbar ) ) {
+			this._balloon.add( {
+				view: this._toolbar,
+				position: getBalloonPositionData( editor ),
+				balloonClassName
+			} );
 		}
 	}
 

+ 41 - 39
packages/ckeditor5-table/tests/commands/insertcolumncommand.js

@@ -24,55 +24,57 @@ describe( 'InsertColumnCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 41 - 39
packages/ckeditor5-table/tests/commands/insertrowcommand.js

@@ -24,55 +24,57 @@ describe( 'InsertRowCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 42 - 40
packages/ckeditor5-table/tests/commands/inserttablecommand.js

@@ -25,56 +25,58 @@ describe( 'InsertTableCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			command = new InsertTableCommand( editor );
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = new InsertTableCommand( editor );
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 41 - 1
packages/ckeditor5-table/tests/commands/mergecellcommand.js

@@ -18,12 +18,16 @@ import {
 } from '../../src/converters/downcast';
 import upcastTable from '../../src/converters/upcasttable';
 import { formatTable, formattedModelTable, modelTable } from '../_utils/utils';
+import TableUtils from '../../src/tableutils';
 
 describe( 'MergeCellCommand', () => {
 	let editor, model, command, root;
 
 	beforeEach( () => {
-		return ModelTestEditor.create()
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
 			.then( newEditor => {
 				editor = newEditor;
 				model = editor.model;
@@ -116,6 +120,24 @@ describe( 'MergeCellCommand', () => {
 				expect( command.isEnabled ).to.be.false;
 			} );
 
+			it( 'should be false when next cell is rowspanned', () => {
+				setData( model, modelTable( [
+					[ '00', { rowspan: 3, contents: '01' }, '02' ],
+					[ '10[]', '12' ],
+					[ '20', '22' ]
+				] ) );
+
+				expect( command.isEnabled ).to.be.false;
+			} );
+
+			it( 'should be true when current cell is colspanned', () => {
+				setData( model, modelTable( [
+					[ { colspan: 2, contents: '00[]' }, '02' ]
+				] ) );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
 			it( 'should be false if not in a cell', () => {
 				setData( model, '<p>11[]</p>' );
 
@@ -216,6 +238,24 @@ describe( 'MergeCellCommand', () => {
 				expect( command.isEnabled ).to.be.false;
 			} );
 
+			it( 'should be false when next cell is rowspanned', () => {
+				setData( model, modelTable( [
+					[ '00', { rowspan: 3, contents: '01' }, '02' ],
+					[ '10', '12[]' ],
+					[ '20', '22' ]
+				] ) );
+
+				expect( command.isEnabled ).to.be.false;
+			} );
+
+			it( 'should be true when mergeable cell is colspanned', () => {
+				setData( model, modelTable( [
+					[ { colspan: 2, contents: '00' }, '02[]' ]
+				] ) );
+
+				expect( command.isEnabled ).to.be.true;
+			} );
+
 			it( 'should be false if not in a cell', () => {
 				setData( model, '<p>11[]</p>' );
 

+ 42 - 40
packages/ckeditor5-table/tests/commands/removecolumncommand.js

@@ -24,56 +24,58 @@ describe( 'RemoveColumnCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			command = new RemoveColumnCommand( editor );
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows', 'headingColumns' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = new RemoveColumnCommand( editor );
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows', 'headingColumns' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 58 - 56
packages/ckeditor5-table/tests/commands/setheadercolumncommand.js

@@ -24,63 +24,65 @@ describe( 'HeaderColumnCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			command = new SetHeaderColumnCommand( editor );
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isBlock: true,
-				isObject: true
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = new SetHeaderColumnCommand( editor );
+
+				const conversion = editor.conversion;
+				const schema = model.schema;
+
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isBlock: true,
+					isObject: true
+				} );
+
+				schema.register( 'tableRow', {
+					allowIn: 'table',
+					allowAttributes: [],
+					isBlock: true,
+					isLimit: true
+				} );
+
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isBlock: true,
+					isLimit: true
+				} );
+
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
+
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
+
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
+
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
+
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
+
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
 			} );
-
-			schema.register( 'tableRow', {
-				allowIn: 'table',
-				allowAttributes: [],
-				isBlock: true,
-				isLimit: true
-			} );
-
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isBlock: true,
-				isLimit: true
-			} );
-
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
-
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
-
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
-
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
-
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
-
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
-
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
-
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
 	} );
 
 	afterEach( () => {

+ 42 - 40
packages/ckeditor5-table/tests/commands/setheaderrowcommand.js

@@ -24,56 +24,58 @@ describe( 'HeaderRowCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			command = new SetHeaderRowCommand( editor );
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = new SetHeaderRowCommand( editor );
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 42 - 40
packages/ckeditor5-table/tests/commands/splitcellcommand.js

@@ -24,56 +24,58 @@ describe( 'SplitCellCommand', () => {
 	let editor, model, command;
 
 	beforeEach( () => {
-		return ModelTestEditor.create( {
-			plugins: [ TableUtils ]
-		} ).then( newEditor => {
-			editor = newEditor;
-			model = editor.model;
-			command = new SplitCellCommand( editor );
-
-			const conversion = editor.conversion;
-			const schema = model.schema;
-
-			schema.register( 'table', {
-				allowWhere: '$block',
-				allowAttributes: [ 'headingRows' ],
-				isObject: true
-			} );
+		return ModelTestEditor
+			.create( {
+				plugins: [ TableUtils ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				command = new SplitCellCommand( editor );
 
-			schema.register( 'tableRow', { allowIn: 'table' } );
+				const conversion = editor.conversion;
+				const schema = model.schema;
 
-			schema.register( 'tableCell', {
-				allowIn: 'tableRow',
-				allowContentOf: '$block',
-				allowAttributes: [ 'colspan', 'rowspan' ],
-				isLimit: true
-			} );
+				schema.register( 'table', {
+					allowWhere: '$block',
+					allowAttributes: [ 'headingRows' ],
+					isObject: true
+				} );
 
-			model.schema.register( 'p', { inheritAllFrom: '$block' } );
+				schema.register( 'tableRow', { allowIn: 'table' } );
 
-			// Table conversion.
-			conversion.for( 'upcast' ).add( upcastTable() );
-			conversion.for( 'downcast' ).add( downcastInsertTable() );
+				schema.register( 'tableCell', {
+					allowIn: 'tableRow',
+					allowContentOf: '$block',
+					allowAttributes: [ 'colspan', 'rowspan' ],
+					isLimit: true
+				} );
 
-			// Insert row conversion.
-			conversion.for( 'downcast' ).add( downcastInsertRow() );
+				model.schema.register( 'p', { inheritAllFrom: '$block' } );
 
-			// Remove row conversion.
-			conversion.for( 'downcast' ).add( downcastRemoveRow() );
+				// Table conversion.
+				conversion.for( 'upcast' ).add( upcastTable() );
+				conversion.for( 'downcast' ).add( downcastInsertTable() );
 
-			// Table cell conversion.
-			conversion.for( 'downcast' ).add( downcastInsertCell() );
+				// Insert row conversion.
+				conversion.for( 'downcast' ).add( downcastInsertRow() );
 
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
-			conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+				// Remove row conversion.
+				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-			// Table attributes conversion.
-			conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
-			conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+				// Table cell conversion.
+				conversion.for( 'downcast' ).add( downcastInsertCell() );
 
-			conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
-			conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
-		} );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
+				conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
+
+				// Table attributes conversion.
+				conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+				conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+
+				conversion.for( 'downcast' ).add( downcastTableHeadingColumnsChange() );
+				conversion.for( 'downcast' ).add( downcastTableHeadingRowsChange() );
+			} );
 	} );
 
 	afterEach( () => {

+ 11 - 9
packages/ckeditor5-table/tests/tabletoolbar.js

@@ -17,7 +17,7 @@ import View from '@ckeditor/ckeditor5-ui/src/view';
 import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
 describe( 'TableToolbar', () => {
-	let editor, model, doc, editingView, plugin, toolbar, balloon, editorElement;
+	let editor, model, doc, plugin, toolbar, balloon, editorElement;
 
 	beforeEach( () => {
 		editorElement = global.document.createElement( 'div' );
@@ -36,7 +36,6 @@ describe( 'TableToolbar', () => {
 				doc = model.document;
 				plugin = editor.plugins.get( TableToolbar );
 				toolbar = plugin._toolbar;
-				editingView = editor.editing.view;
 				balloon = editor.plugins.get( 'ContextualBalloon' );
 			} );
 	} );
@@ -112,23 +111,24 @@ describe( 'TableToolbar', () => {
 		} );
 	} );
 
-	describe( 'integration with the editor selection (#change event)', () => {
+	describe( 'integration with the editor selection (ui#update event)', () => {
 		beforeEach( () => {
 			editor.ui.focusTracker.isFocused = true;
 		} );
 
-		it( 'should not show the toolbar on render when the table is selected', () => {
+		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;
 		} );
 
-		it( 'should show the toolbar on render when the table content is selected', () => {
+		it( 'should show the toolbar on ui#update when the table content is selected', () => {
 			setData( model, '<paragraph>[foo]</paragraph><table><tableRow><tableCell>bar</tableCell></tableRow></table>' );
 
 			expect( balloon.visibleView ).to.be.null;
 
-			editingView.change( () => {} );
+			editor.ui.fire( 'update' );
+
 			expect( balloon.visibleView ).to.be.null;
 
 			model.change( writer => {
@@ -142,12 +142,13 @@ describe( 'TableToolbar', () => {
 
 			// Make sure successive change does not throw, e.g. attempting
 			// to insert the toolbar twice.
-			editingView.change( () => {} );
+			editor.ui.fire( 'update' );
 			expect( balloon.visibleView ).to.equal( toolbar );
 		} );
 
 		it( 'should not engage when the toolbar is in the balloon yet invisible', () => {
 			setData( model, '<table><tableRow><tableCell>x[y]z</tableCell></tableRow></table>' );
+
 			expect( balloon.visibleView ).to.equal( toolbar );
 
 			// Put anything on top of the ContextualBalloon stack above the table toolbar.
@@ -163,7 +164,8 @@ describe( 'TableToolbar', () => {
 
 			expect( balloon.visibleView ).to.equal( lastView );
 
-			editingView.change( () => {} );
+			editor.ui.fire( 'update' );
+
 			expect( balloon.visibleView ).to.equal( lastView );
 		} );
 
@@ -183,7 +185,7 @@ describe( 'TableToolbar', () => {
 
 			// Make sure successive change does not throw, e.g. attempting
 			// to remove the toolbar twice.
-			editingView.change( () => {} );
+			editor.ui.fire( 'update' );
 			expect( balloon.visibleView ).to.be.null;
 		} );
 	} );