Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #97 from ckeditor/t/56
Browse files Browse the repository at this point in the history
Feature: Support block content inside table. Closes #56.

BREAKING CHANGE: Removed `table/commands/utils~getParentTable()` method. Use `table/commands/utils~findAncestor()` instead.
  • Loading branch information
oskarwrobel authored Sep 6, 2018
2 parents 34c8ee1 + 22be0ec commit cdf718e
Show file tree
Hide file tree
Showing 46 changed files with 2,016 additions and 1,068 deletions.
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
"@ckeditor/ckeditor5-widget": "^10.2.0"
},
"devDependencies": {
"@ckeditor/ckeditor5-alignment": "^10.0.2",
"@ckeditor/ckeditor5-block-quote": "^10.0.2",
"@ckeditor/ckeditor5-clipboard": "^10.0.2",
"@ckeditor/ckeditor5-editor-classic": "^11.0.0",
"@ckeditor/ckeditor5-image": "^10.2.0",
"@ckeditor/ckeditor5-list": "^11.0.1",
"@ckeditor/ckeditor5-paragraph": "^10.0.2",
"@ckeditor/ckeditor5-undo": "^10.0.1",
"@ckeditor/ckeditor5-undo": "^10.0.2",
"@ckeditor/ckeditor5-utils": "^10.2.0",
"eslint": "^4.15.0",
"eslint-config-ckeditor5": "^1.0.7",
Expand Down
10 changes: 6 additions & 4 deletions src/commands/insertcolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import Command from '@ckeditor/ckeditor5-core/src/command';
import { getParentTable } from './utils';
import { findAncestor } from './utils';
import TableUtils from '../tableutils';

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export default class InsertColumnCommand extends Command {
refresh() {
const selection = this.editor.model.document.selection;

const tableParent = getParentTable( selection.getFirstPosition() );
const tableParent = findAncestor( 'table', selection.getFirstPosition() );

this.isEnabled = !!tableParent;
}
Expand All @@ -72,8 +72,10 @@ export default class InsertColumnCommand extends Command {
const selection = editor.model.document.selection;
const tableUtils = editor.plugins.get( TableUtils );

const table = getParentTable( selection.getFirstPosition() );
const tableCell = selection.getFirstPosition().parent;
const firstPosition = selection.getFirstPosition();

const tableCell = findAncestor( 'tableCell', firstPosition );
const table = tableCell.parent.parent;

const { column } = tableUtils.getCellLocation( tableCell );
const insertAt = this.order === 'after' ? column + 1 : column;
Expand Down
11 changes: 6 additions & 5 deletions src/commands/insertrowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import Command from '@ckeditor/ckeditor5-core/src/command';
import { getParentTable } from './utils';
import { findAncestor } from './utils';
import TableUtils from '../tableutils';

/**
Expand Down Expand Up @@ -54,7 +54,7 @@ export default class InsertRowCommand extends Command {
refresh() {
const selection = this.editor.model.document.selection;

const tableParent = getParentTable( selection.getFirstPosition() );
const tableParent = findAncestor( 'table', selection.getFirstPosition() );

this.isEnabled = !!tableParent;
}
Expand All @@ -71,10 +71,11 @@ export default class InsertRowCommand extends Command {
const selection = editor.model.document.selection;
const tableUtils = editor.plugins.get( TableUtils );

const tableCell = selection.getFirstPosition().parent;
const table = getParentTable( selection.getFirstPosition() );
const tableCell = findAncestor( 'tableCell', selection.getFirstPosition() );
const tableRow = tableCell.parent;
const table = tableRow.parent;

const row = table.getChildIndex( tableCell.parent );
const row = table.getChildIndex( tableRow );
const insertAt = this.order === 'below' ? row + 1 : row;

tableUtils.insertRows( table, { rows: 1, at: insertAt } );
Expand Down
2 changes: 1 addition & 1 deletion src/commands/inserttablecommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default class InsertTableCommand extends Command {
model.change( writer => {
const table = tableUtils.createTable( insertPosition, rows, columns );

writer.setSelection( Position.createAt( table.getChild( 0 ).getChild( 0 ) ) );
writer.setSelection( Position.createAt( table.getChild( 0 ).getChild( 0 ).getChild( 0 ) ) );
} );
}
}
Expand Down
46 changes: 36 additions & 10 deletions src/commands/mergecellcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
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 { findAncestor, updateNumericAttribute } from './utils';
import TableUtils from '../tableutils';

/**
Expand Down Expand Up @@ -83,7 +83,7 @@ export default class MergeCellCommand extends Command {
execute() {
const model = this.editor.model;
const doc = model.document;
const tableCell = doc.selection.getFirstPosition().parent;
const tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );
const cellToMerge = this.value;
const direction = this.direction;

Expand All @@ -97,9 +97,7 @@ export default class MergeCellCommand extends Command {
// Cache the parent of cell to remove for later check.
const removedTableCellRow = cellToRemove.parent;

// Remove table cell and merge it contents with merged cell.
writer.move( Range.createIn( cellToRemove ), Position.createAt( cellToExpand, 'end' ) );
writer.remove( cellToRemove );
mergeTableCells( cellToRemove, cellToExpand, writer );

const spanAttribute = this.isHorizontal ? 'colspan' : 'rowspan';
const cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );
Expand All @@ -125,26 +123,26 @@ export default class MergeCellCommand extends Command {
_getMergeableCell() {
const model = this.editor.model;
const doc = model.document;
const element = doc.selection.getFirstPosition().parent;
const tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );

if ( !element.is( 'tableCell' ) ) {
if ( !tableCell ) {
return;
}

const tableUtils = this.editor.plugins.get( TableUtils );

// First get the cell on proper direction.
const cellToMerge = this.isHorizontal ?
getHorizontalCell( element, this.direction, tableUtils ) :
getVerticalCell( element, this.direction );
getHorizontalCell( tableCell, this.direction, tableUtils ) :
getVerticalCell( tableCell, this.direction );

if ( !cellToMerge ) {
return;
}

// If found check if the span perpendicular to merge direction is equal on both cells.
const spanAttribute = this.isHorizontal ? 'rowspan' : 'colspan';
const span = parseInt( element.getAttribute( spanAttribute ) || 1 );
const span = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );

const cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );

Expand Down Expand Up @@ -254,3 +252,31 @@ function removeEmptyRow( removedTableCellRow, writer ) {

writer.remove( removedTableCellRow );
}

// Merges two table cells - will ensure that after merging cells with empty paragraph the result table cell will only have one paragraph.
// If one of the merged table cell is empty the merged table cell will have contents of the non-empty table cell.
// If both are empty the merged table cell will have only one empty paragraph.
//
// @param {module:engine/model/element~Element} cellToRemove
// @param {module:engine/model/element~Element} cellToExpand
// @param {module:engine/model/writer~Writer} writer
function mergeTableCells( cellToRemove, cellToExpand, writer ) {
if ( !isEmpty( cellToRemove ) ) {
if ( isEmpty( cellToExpand ) ) {
writer.remove( Range.createIn( cellToExpand ) );
}

writer.move( Range.createIn( cellToRemove ), Position.createAt( cellToExpand, 'end' ) );
}

// Remove merged table cell.
writer.remove( cellToRemove );
}

// Checks if passed table cell contains empty paragraph.
//
// @param {module:engine/model/element~Element} tableCell
// @returns {Boolean}
function isEmpty( tableCell ) {
return tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;
}
8 changes: 4 additions & 4 deletions src/commands/removecolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';

import TableWalker from '../tablewalker';
import TableUtils from '../tableutils';
import { updateNumericAttribute } from './utils';
import { findAncestor, updateNumericAttribute } from './utils';

/**
* The remove column command.
Expand All @@ -33,9 +33,9 @@ export default class RemoveColumnCommand extends Command {
const selection = editor.model.document.selection;
const tableUtils = editor.plugins.get( TableUtils );

const selectedElement = selection.getFirstPosition().parent;
const tableCell = findAncestor( 'tableCell', selection.getFirstPosition() );

this.isEnabled = selectedElement.is( 'tableCell' ) && tableUtils.getColumns( selectedElement.parent.parent ) > 1;
this.isEnabled = !!tableCell && tableUtils.getColumns( tableCell.parent.parent ) > 1;
}

/**
Expand All @@ -47,7 +47,7 @@ export default class RemoveColumnCommand extends Command {

const firstPosition = selection.getFirstPosition();

const tableCell = firstPosition.parent;
const tableCell = findAncestor( 'tableCell', firstPosition );
const tableRow = tableCell.parent;
const table = tableRow.parent;

Expand Down
8 changes: 4 additions & 4 deletions src/commands/removerowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +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 { findAncestor, updateNumericAttribute } from './utils';

/**
* The remove row command.
Expand All @@ -33,9 +33,9 @@ export default class RemoveRowCommand extends Command {
const model = this.editor.model;
const doc = model.document;

const element = doc.selection.getFirstPosition().parent;
const tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );

this.isEnabled = element.is( 'tableCell' ) && element.parent.parent.childCount > 1;
this.isEnabled = !!tableCell && tableCell.parent.parent.childCount > 1;
}

/**
Expand All @@ -46,7 +46,7 @@ export default class RemoveRowCommand extends Command {
const selection = model.document.selection;

const firstPosition = selection.getFirstPosition();
const tableCell = firstPosition.parent;
const tableCell = findAncestor( 'tableCell', firstPosition );
const tableRow = tableCell.parent;
const table = tableRow.parent;

Expand Down
10 changes: 5 additions & 5 deletions src/commands/setheadercolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import Command from '@ckeditor/ckeditor5-core/src/command';

import { getParentTable, updateNumericAttribute } from './utils';
import { findAncestor, updateNumericAttribute } from './utils';

/**
* The header column command.
Expand All @@ -36,9 +36,9 @@ export default class SetHeaderColumnCommand extends Command {
const selection = doc.selection;

const position = selection.getFirstPosition();
const tableParent = getParentTable( position );
const tableCell = findAncestor( 'tableCell', position );

const isInTable = !!tableParent;
const isInTable = !!tableCell;

this.isEnabled = isInTable;

Expand All @@ -50,7 +50,7 @@ export default class SetHeaderColumnCommand extends Command {
* @readonly
* @member {Boolean} #value
*/
this.value = isInTable && this._isInHeading( position.parent, tableParent );
this.value = isInTable && this._isInHeading( tableCell, tableCell.parent.parent );
}

/**
Expand All @@ -69,7 +69,7 @@ export default class SetHeaderColumnCommand extends Command {
const tableUtils = this.editor.plugins.get( 'TableUtils' );

const position = selection.getFirstPosition();
const tableCell = position.parent;
const tableCell = findAncestor( 'tableCell', position.parent );
const tableRow = tableCell.parent;
const table = tableRow.parent;

Expand Down
14 changes: 7 additions & 7 deletions src/commands/setheaderrowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import Command from '@ckeditor/ckeditor5-core/src/command';
import Position from '@ckeditor/ckeditor5-engine/src/model/position';

import { getParentTable, updateNumericAttribute } from './utils';
import { createEmptyTableCell, findAncestor, updateNumericAttribute } from './utils';
import TableWalker from '../tablewalker';

/**
Expand All @@ -37,9 +37,8 @@ export default class SetHeaderRowCommand extends Command {
const selection = doc.selection;

const position = selection.getFirstPosition();
const tableParent = getParentTable( position );

const isInTable = !!tableParent;
const tableCell = findAncestor( 'tableCell', position );
const isInTable = !!tableCell;

this.isEnabled = isInTable;

Expand All @@ -51,7 +50,7 @@ export default class SetHeaderRowCommand extends Command {
* @readonly
* @member {Boolean} #value
*/
this.value = isInTable && this._isInHeading( position.parent, tableParent );
this.value = isInTable && this._isInHeading( tableCell, tableCell.parent.parent );
}

/**
Expand All @@ -69,7 +68,7 @@ export default class SetHeaderRowCommand extends Command {
const selection = doc.selection;

const position = selection.getFirstPosition();
const tableCell = position.parent;
const tableCell = findAncestor( 'tableCell', position );
const tableRow = tableCell.parent;
const table = tableRow.parent;

Expand Down Expand Up @@ -170,8 +169,9 @@ function splitHorizontally( tableCell, headingRows, writer ) {

if ( columnIndex !== undefined && columnIndex === column && row === endRow ) {
const tableRow = table.getChild( row );
const tableCellPosition = Position.createFromParentAndOffset( tableRow, cellIndex );

writer.insertElement( 'tableCell', attributes, Position.createFromParentAndOffset( tableRow, cellIndex ) );
createEmptyTableCell( writer, tableCellPosition, attributes );
}
}

Expand Down
7 changes: 4 additions & 3 deletions src/commands/splitcellcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import Command from '@ckeditor/ckeditor5-core/src/command';
import TableUtils from '../tableutils';
import { findAncestor } from './utils';

/**
* The split cell command.
Expand Down Expand Up @@ -49,9 +50,9 @@ export default class SplitCellCommand extends Command {
const model = this.editor.model;
const doc = model.document;

const element = doc.selection.getFirstPosition().parent;
const tableCell = findAncestor( 'tableCell', doc.selection.getFirstPosition() );

this.isEnabled = element.is( 'tableCell' );
this.isEnabled = !!tableCell;
}

/**
Expand All @@ -63,7 +64,7 @@ export default class SplitCellCommand extends Command {
const selection = document.selection;

const firstPosition = selection.getFirstPosition();
const tableCell = firstPosition.parent;
const tableCell = findAncestor( 'tableCell', firstPosition );

const isHorizontally = this.direction === 'horizontally';

Expand Down
22 changes: 18 additions & 4 deletions src/commands/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
*/

/**
* Returns the parent table.
* Returns the parent element of given name. Returns undefined if position is not inside desired parent.
*
* @param {module:engine/model/position~Position} position
* @param {String} parentName Name of parent element to find.
* @param {module:engine/model/position~Position|module:engine/model/position~Position} position Position to start searching.
* @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}
*/
export function getParentTable( position ) {
export function findAncestor( parentName, position ) {
let parent = position.parent;

while ( parent ) {
if ( parent.name === 'table' ) {
if ( parent.name === parentName ) {
return parent;
}

Expand All @@ -41,3 +42,16 @@ export function updateNumericAttribute( key, value, item, writer, defaultValue =
writer.removeAttribute( key, item );
}
}

/**
* Common method to create empty table cell - it will create proper model structure as table cell must have at least one block inside.
*
* @param {module:engine/model/writer~Writer} writer Model writer.
* @param {module:engine/model/position~Position} insertPosition Position at which table cell should be inserted.
* @param {Object} attributes Element's attributes.
*/
export function createEmptyTableCell( writer, insertPosition, attributes = {} ) {
const tableCell = writer.createElement( 'tableCell', attributes );
writer.insertElement( 'paragraph', tableCell );
writer.insert( tableCell, insertPosition );
}
Loading

0 comments on commit cdf718e

Please sign in to comment.