Skip to content

Commit

Permalink
Merge pull request #7598 from ckeditor/i/3233
Browse files Browse the repository at this point in the history
Feature (engine): Added model `Position#findAncestor()` and `Element#findAncestor()` methods. Closes #3233.

Internal (table): Removed `findAncestor` helper.

MINOR BREAKING CHANGE (table): The `findAncestor()` utility function was removed.
  • Loading branch information
jodator authored Jul 13, 2020
2 parents 392f61f + aa535c1 commit a349af5
Show file tree
Hide file tree
Showing 27 changed files with 133 additions and 97 deletions.
22 changes: 22 additions & 0 deletions packages/ckeditor5-engine/src/model/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,28 @@ export default class Element extends Node {
return node;
}

/**
* Returns the parent element of the given name. Returns null if the element is not inside the desired parent.
*
* @param {String} parentName The name of the parent element to find.
* @param {Object} [options] Options object.
* @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included while searching.
* @returns {module:engine/model/element~Element|null}
*/
findAncestor( parentName, options = { includeSelf: false } ) {
let parent = options.includeSelf ? this : this.parent;

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

parent = parent.parent;
}

return null;
}

/**
* Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.
*
Expand Down
16 changes: 16 additions & 0 deletions packages/ckeditor5-engine/src/model/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,22 @@ export default class Position {
}
}

/**
* Returns the parent element of the given name. Returns null if the position is not inside the desired parent.
*
* @param {String} parentName The name of the parent element to find.
* @returns {module:engine/model/element~Element|null}
*/
findAncestor( parentName ) {
const parent = this.parent;

if ( parent.is( 'element' ) ) {
return parent.findAncestor( parentName, { includeSelf: true } );
}

return null;
}

/**
* Returns the slice of two position {@link #path paths} which is identical. The {@link #root roots}
* of these two paths must be identical.
Expand Down
27 changes: 27 additions & 0 deletions packages/ckeditor5-engine/tests/model/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,33 @@ describe( 'Element', () => {
} );
} );

describe( 'findAncestor', () => {
let p, td, tr, table;

beforeEach( () => {
p = new Element( 'p', [], [ new Text( 'foo' ) ] );
td = new Element( 'td', [], [ p ] );
tr = new Element( 'tr', [], [ td ] );
table = new Element( 'table', [], [ tr ] );
} );

it( 'should return ancestor', () => {
expect( p.findAncestor( 'p' ) ).to.be.null;
expect( p.findAncestor( 'td' ) ).to.equal( td );
expect( p.findAncestor( 'tr' ) ).to.equal( tr );
expect( p.findAncestor( 'table' ) ).to.equal( table );
expect( p.findAncestor( 'abc' ) ).to.be.null;
} );

it( 'should return ancestor or self (includeSelf = true)', () => {
expect( p.findAncestor( 'p', { includeSelf: true } ) ).to.equal( p );
expect( p.findAncestor( 'td', { includeSelf: true } ) ).to.equal( td );
expect( p.findAncestor( 'tr', { includeSelf: true } ) ).to.equal( tr );
expect( p.findAncestor( 'table', { includeSelf: true } ) ).to.equal( table );
expect( p.findAncestor( 'abc', { includeSelf: true } ) ).to.be.null;
} );
} );

describe( 'getChildIndex', () => {
it( 'should return child index', () => {
const element = new Element( 'elem', [], [ new Element( 'p' ), new Text( 'bar' ), new Element( 'h' ) ] );
Expand Down
20 changes: 20 additions & 0 deletions packages/ckeditor5-engine/tests/model/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,26 @@ describe( 'Position', () => {
} );
} );

describe( 'findAncestor()', () => {
it( 'should return position parent element', () => {
expect( new Position( root, [ 1, 1, 1 ] ).findAncestor( 'li' ) ).to.equal( li2 );
} );

it( 'should return deeper ancestor element', () => {
expect( new Position( root, [ 1, 1, 1 ] ).findAncestor( 'ul' ) ).to.equal( ul );
} );

it( 'should return null if ancestor is not found', () => {
expect( new Position( root, [ 1, 1, 1 ] ).findAncestor( 'p' ) ).to.be.null;
} );

it( 'should return null if position is not in an element', () => {
const docFrag = new DocumentFragment();

expect( new Position( docFrag, [ 0 ] ).findAncestor( 'li' ) ).to.be.null;
} );
} );

describe( 'getCommonPath()', () => {
it( 'returns the common part', () => {
const pos1 = new Position( root, [ 1, 0, 0 ] );
Expand Down
5 changes: 2 additions & 3 deletions packages/ckeditor5-table/src/commands/insertcolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import Command from '@ckeditor/ckeditor5-core/src/command';
import { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

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

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

this.isEnabled = !!tableParent;
}
Expand All @@ -77,7 +76,7 @@ export default class InsertColumnCommand extends Command {
const columnIndexes = getColumnIndexes( affectedTableCells );

const column = insertBefore ? columnIndexes.first : columnIndexes.last;
const table = findAncestor( 'table', affectedTableCells[ 0 ] );
const table = affectedTableCells[ 0 ].findAncestor( 'table' );

tableUtils.insertColumns( table, { columns: 1, at: insertBefore ? column : column + 1 } );
}
Expand Down
5 changes: 2 additions & 3 deletions packages/ckeditor5-table/src/commands/insertrowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import Command from '@ckeditor/ckeditor5-core/src/command';
import { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

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

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

this.isEnabled = !!tableParent;
}
Expand All @@ -76,7 +75,7 @@ export default class InsertRowCommand extends Command {
const rowIndexes = getRowIndexes( affectedTableCells );

const row = insertAbove ? rowIndexes.first : rowIndexes.last;
const table = findAncestor( 'table', affectedTableCells[ 0 ] );
const table = affectedTableCells[ 0 ].findAncestor( 'table' );

tableUtils.insertRows( table, { at: insertAbove ? row : row + 1, copyStructureFromAbove: !insertAbove } );
}
Expand Down
4 changes: 2 additions & 2 deletions packages/ckeditor5-table/src/commands/mergecellcommand.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 TableWalker from '../tablewalker';
import { getTableCellsContainingSelection } from '../utils/selection';
import { findAncestor, isHeadingColumnCell } from '../utils/common';
import { isHeadingColumnCell } from '../utils/common';
import { removeEmptyRowsColumns } from '../utils/structure';

/**
Expand Down Expand Up @@ -106,7 +106,7 @@ export default class MergeCellCommand extends Command {
writer.setSelection( writer.createRangeIn( cellToExpand ) );

const tableUtils = this.editor.plugins.get( 'TableUtils' );
const table = findAncestor( 'table', removedTableCellRow );
const table = removedTableCellRow.findAncestor( 'table' );

// Remove empty rows and columns after merging.
removeEmptyRowsColumns( table, tableUtils );
Expand Down
4 changes: 2 additions & 2 deletions packages/ckeditor5-table/src/commands/mergecellscommand.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 TableUtils from '../tableutils';
import { getSelectedTableCells, isSelectionRectangular } from '../utils/selection';
import { findAncestor, updateNumericAttribute } from '../utils/common';
import { updateNumericAttribute } from '../utils/common';
import { removeEmptyRowsColumns } from '../utils/structure';

/**
Expand Down Expand Up @@ -57,7 +57,7 @@ export default class MergeCellsCommand extends Command {
mergeTableCells( tableCell, firstTableCell, writer );
}

const table = findAncestor( 'table', firstTableCell );
const table = firstTableCell.findAncestor( 'table' );

// Remove rows and columns that become empty (have no anchored cells).
removeEmptyRowsColumns( table, tableUtils );
Expand Down
3 changes: 1 addition & 2 deletions packages/ckeditor5-table/src/commands/removecolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Command from '@ckeditor/ckeditor5-core/src/command';

import TableWalker from '../tablewalker';
import { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

/**
* The remove column command.
Expand All @@ -33,7 +32,7 @@ export default class RemoveColumnCommand extends Command {
const firstCell = selectedCells[ 0 ];

if ( firstCell ) {
const table = findAncestor( 'table', firstCell );
const table = firstCell.findAncestor( 'table' );
const tableColumnCount = this.editor.plugins.get( 'TableUtils' ).getColumns( table );

const { first, last } = getColumnIndexes( selectedCells );
Expand Down
5 changes: 2 additions & 3 deletions packages/ckeditor5-table/src/commands/removerowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import Command from '@ckeditor/ckeditor5-core/src/command';

import { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

/**
* The remove row command.
Expand All @@ -32,7 +31,7 @@ export default class RemoveRowCommand extends Command {
const firstCell = selectedCells[ 0 ];

if ( firstCell ) {
const table = findAncestor( 'table', firstCell );
const table = firstCell.findAncestor( 'table' );
const tableRowCount = this.editor.plugins.get( 'TableUtils' ).getRows( table );
const lastRowIndex = tableRowCount - 1;

Expand All @@ -56,7 +55,7 @@ export default class RemoveRowCommand extends Command {
const removedRowIndexes = getRowIndexes( referenceCells );

const firstCell = referenceCells[ 0 ];
const table = findAncestor( 'table', firstCell );
const table = firstCell.findAncestor( 'table' );

const columnIndexToFocus = this.editor.plugins.get( 'TableUtils' ).getCellLocation( firstCell ).column;

Expand Down
3 changes: 1 addition & 2 deletions packages/ckeditor5-table/src/commands/selectcolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Command from '@ckeditor/ckeditor5-core/src/command';

import TableWalker from '../tablewalker';
import { getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

/**
* The select column command.
Expand Down Expand Up @@ -42,7 +41,7 @@ export default class SelectColumnCommand extends Command {
const referenceCells = getSelectionAffectedTableCells( model.document.selection );
const firstCell = referenceCells[ 0 ];
const lastCell = referenceCells.pop();
const table = findAncestor( 'table', firstCell );
const table = firstCell.findAncestor( 'table' );

const tableUtils = this.editor.plugins.get( 'TableUtils' );
const startLocation = tableUtils.getCellLocation( firstCell );
Expand Down
3 changes: 1 addition & 2 deletions packages/ckeditor5-table/src/commands/selectrowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import Command from '@ckeditor/ckeditor5-core/src/command';

import { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { findAncestor } from '../utils/common';

/**
* The select row command.
Expand Down Expand Up @@ -41,7 +40,7 @@ export default class SelectRowCommand extends Command {
const referenceCells = getSelectionAffectedTableCells( model.document.selection );
const rowIndexes = getRowIndexes( referenceCells );

const table = findAncestor( 'table', referenceCells[ 0 ] );
const table = referenceCells[ 0 ].findAncestor( 'table' );
const rangesToSelect = [];

for ( let rowIndex = rowIndexes.first; rowIndex <= rowIndexes.last; rowIndex++ ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import Command from '@ckeditor/ckeditor5-core/src/command';

import {
findAncestor,
isHeadingColumnCell,
updateNumericAttribute
} from '../utils/common';
Expand Down Expand Up @@ -74,7 +73,7 @@ export default class SetHeaderColumnCommand extends Command {

const model = this.editor.model;
const selectedCells = getSelectionAffectedTableCells( model.document.selection );
const table = findAncestor( 'table', selectedCells[ 0 ] );
const table = selectedCells[ 0 ].findAncestor( 'table' );

const { first, last } = getColumnIndexes( selectedCells );
const headingColumnsToSet = this.value ? first : last + 1;
Expand Down
4 changes: 2 additions & 2 deletions packages/ckeditor5-table/src/commands/setheaderrowcommand.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 { findAncestor, updateNumericAttribute } from '../utils/common';
import { updateNumericAttribute } from '../utils/common';
import { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';
import { getVerticallyOverlappingCells, splitHorizontally } from '../utils/structure';

Expand Down Expand Up @@ -67,7 +67,7 @@ export default class SetHeaderRowCommand extends Command {
}
const model = this.editor.model;
const selectedCells = getSelectionAffectedTableCells( model.document.selection );
const table = findAncestor( 'table', selectedCells[ 0 ] );
const table = selectedCells[ 0 ].findAncestor( 'table' );

const { first, last } = getRowIndexes( selectedCells );
const headingRowsToSet = this.value ? first : last + 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

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

/**
* Injects a table layout post-fixer into the model.
Expand Down Expand Up @@ -238,12 +238,12 @@ function tableLayoutPostFixer( writer, model ) {

// Fix table on adding/removing table cells and rows.
if ( entry.name == 'tableRow' || entry.name == 'tableCell' ) {
table = findAncestor( 'table', entry.position );
table = entry.position.findAncestor( 'table' );
}

// Fix table on any table's attribute change - including attributes of table cells.
if ( isTableAttributeEntry( entry ) ) {
table = findAncestor( 'table', entry.range.start );
table = entry.range.start.findAncestor( 'table' );
}

if ( table && !analyzedTables.has( table ) ) {
Expand Down
7 changes: 2 additions & 5 deletions packages/ckeditor5-table/src/tableclipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import TableSelection from './tableselection';
import TableWalker from './tablewalker';
import {
findAncestor
} from './utils/common';
import TableUtils from './tableutils';
import { getColumnIndexes, getRowIndexes, getSelectionAffectedTableCells, isSelectionRectangular } from './utils/selection';
import {
Expand Down Expand Up @@ -165,7 +162,7 @@ export default class TableClipboard extends Plugin {
pastedTable = cropTableToDimensions( pastedTable, cropDimensions, writer );

// Content table to which we insert a pasted table.
const selectedTable = findAncestor( 'table', selectedTableCells[ 0 ] );
const selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );

replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer );
} );
Expand All @@ -186,7 +183,7 @@ export default class TableClipboard extends Plugin {
// @returns {Number} selection.lastColumn
// @returns {Number} selection.lastRow
function prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils ) {
const selectedTable = findAncestor( 'table', selectedTableCells[ 0 ] );
const selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );

const columnIndexes = getColumnIndexes( selectedTableCells );
const rowIndexes = getRowIndexes( selectedTableCells );
Expand Down
5 changes: 2 additions & 3 deletions packages/ckeditor5-table/src/tablekeyboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
getLocalizedArrowKeyCodeDirection
} from '@ckeditor/ckeditor5-utils/src/keyboard';
import { getSelectedTableCells, getTableCellsContainingSelection } from './utils/selection';
import { findAncestor } from './utils/common';

/**
* This plugin enables keyboard navigation for tables.
Expand Down Expand Up @@ -214,7 +213,7 @@ export default class TableKeyboard extends Plugin {
}

// Abort if we're not in a table cell.
const tableCell = findAncestor( 'tableCell', selection.focus );
const tableCell = selection.focus.findAncestor( 'tableCell' );

if ( !tableCell ) {
return false;
Expand Down Expand Up @@ -418,7 +417,7 @@ export default class TableKeyboard extends Plugin {
_navigateFromCellInDirection( focusCell, direction, expandSelection = false ) {
const model = this.editor.model;

const table = findAncestor( 'table', focusCell );
const table = focusCell.findAncestor( 'table' );
const tableMap = [ ...new TableWalker( table, { includeAllSlots: true } ) ];
const { row: lastRow, column: lastColumn } = tableMap[ tableMap.length - 1 ];

Expand Down
Loading

0 comments on commit a349af5

Please sign in to comment.