From 9a10205c22bbd0172bdea39570684a0219b71022 Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Thu, 9 Jul 2020 17:59:08 +0200 Subject: [PATCH 1/2] Added model Position#findAncestor() and Element#findAncestor() methods. --- .../ckeditor5-engine/src/model/element.js | 22 +++++++++++++++ .../ckeditor5-engine/src/model/position.js | 16 +++++++++++ .../ckeditor5-engine/tests/model/element.js | 27 +++++++++++++++++++ .../ckeditor5-engine/tests/model/position.js | 20 ++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/packages/ckeditor5-engine/src/model/element.js b/packages/ckeditor5-engine/src/model/element.js index 7691850c491..6765d506dbc 100644 --- a/packages/ckeditor5-engine/src/model/element.js +++ b/packages/ckeditor5-engine/src/model/element.js @@ -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. * diff --git a/packages/ckeditor5-engine/src/model/position.js b/packages/ckeditor5-engine/src/model/position.js index 795d6d12e20..807331be4ef 100644 --- a/packages/ckeditor5-engine/src/model/position.js +++ b/packages/ckeditor5-engine/src/model/position.js @@ -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. diff --git a/packages/ckeditor5-engine/tests/model/element.js b/packages/ckeditor5-engine/tests/model/element.js index 84e92a98045..72d17da53be 100644 --- a/packages/ckeditor5-engine/tests/model/element.js +++ b/packages/ckeditor5-engine/tests/model/element.js @@ -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' ) ] ); diff --git a/packages/ckeditor5-engine/tests/model/position.js b/packages/ckeditor5-engine/tests/model/position.js index 2c6d3b6e68e..5a24150cb22 100644 --- a/packages/ckeditor5-engine/tests/model/position.js +++ b/packages/ckeditor5-engine/tests/model/position.js @@ -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 ] ); From aa535c19be7ac447004941ba1ccae1b25dd16573 Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Thu, 9 Jul 2020 18:03:12 +0200 Subject: [PATCH 2/2] Removed findAncestor() table helper. --- .../src/commands/insertcolumncommand.js | 5 ++--- .../src/commands/insertrowcommand.js | 5 ++--- .../src/commands/mergecellcommand.js | 4 ++-- .../src/commands/mergecellscommand.js | 4 ++-- .../src/commands/removecolumncommand.js | 3 +-- .../src/commands/removerowcommand.js | 5 ++--- .../src/commands/selectcolumncommand.js | 3 +-- .../src/commands/selectrowcommand.js | 3 +-- .../src/commands/setheadercolumncommand.js | 3 +-- .../src/commands/setheaderrowcommand.js | 4 ++-- .../src/converters/table-layout-post-fixer.js | 6 +++--- .../ckeditor5-table/src/tableclipboard.js | 7 ++----- packages/ckeditor5-table/src/tablekeyboard.js | 5 ++--- packages/ckeditor5-table/src/tablemouse.js | 7 +------ .../commands/tablepropertycommand.js | 6 ++---- .../ckeditor5-table/src/tableselection.js | 5 ++--- packages/ckeditor5-table/src/utils/common.js | 20 ------------------- .../ckeditor5-table/src/utils/selection.js | 7 +++---- .../src/utils/ui/contextualballoon.js | 5 ++--- .../ckeditor5-table/src/utils/ui/widget.js | 13 +++++++++++- .../tests/manual/tablemocking.js | 3 +-- .../ckeditor5-table/tests/utils/common.js | 19 +----------------- .../tests/utils/ui/contextualballoon.js | 3 +-- 23 files changed, 48 insertions(+), 97 deletions(-) diff --git a/packages/ckeditor5-table/src/commands/insertcolumncommand.js b/packages/ckeditor5-table/src/commands/insertcolumncommand.js index 55fd3e65be0..7e3160e1bee 100644 --- a/packages/ckeditor5-table/src/commands/insertcolumncommand.js +++ b/packages/ckeditor5-table/src/commands/insertcolumncommand.js @@ -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. @@ -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; } @@ -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 } ); } diff --git a/packages/ckeditor5-table/src/commands/insertrowcommand.js b/packages/ckeditor5-table/src/commands/insertrowcommand.js index f5c0c44eb90..0c9b5286b84 100644 --- a/packages/ckeditor5-table/src/commands/insertrowcommand.js +++ b/packages/ckeditor5-table/src/commands/insertrowcommand.js @@ -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. @@ -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; } @@ -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 } ); } diff --git a/packages/ckeditor5-table/src/commands/mergecellcommand.js b/packages/ckeditor5-table/src/commands/mergecellcommand.js index 7a59f9af2ab..dba203e9990 100644 --- a/packages/ckeditor5-table/src/commands/mergecellcommand.js +++ b/packages/ckeditor5-table/src/commands/mergecellcommand.js @@ -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'; /** @@ -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, writer.batch ); diff --git a/packages/ckeditor5-table/src/commands/mergecellscommand.js b/packages/ckeditor5-table/src/commands/mergecellscommand.js index f737e58d94b..bd7f5b98007 100644 --- a/packages/ckeditor5-table/src/commands/mergecellscommand.js +++ b/packages/ckeditor5-table/src/commands/mergecellscommand.js @@ -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'; /** @@ -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, writer.batch ); diff --git a/packages/ckeditor5-table/src/commands/removecolumncommand.js b/packages/ckeditor5-table/src/commands/removecolumncommand.js index 4c9c56c02b1..ef7d0247b6b 100644 --- a/packages/ckeditor5-table/src/commands/removecolumncommand.js +++ b/packages/ckeditor5-table/src/commands/removecolumncommand.js @@ -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. @@ -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 ); diff --git a/packages/ckeditor5-table/src/commands/removerowcommand.js b/packages/ckeditor5-table/src/commands/removerowcommand.js index 7df37cdc74d..ee927f8edb3 100644 --- a/packages/ckeditor5-table/src/commands/removerowcommand.js +++ b/packages/ckeditor5-table/src/commands/removerowcommand.js @@ -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. @@ -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; @@ -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; diff --git a/packages/ckeditor5-table/src/commands/selectcolumncommand.js b/packages/ckeditor5-table/src/commands/selectcolumncommand.js index 6f49be34db8..23519ce0224 100644 --- a/packages/ckeditor5-table/src/commands/selectcolumncommand.js +++ b/packages/ckeditor5-table/src/commands/selectcolumncommand.js @@ -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. @@ -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 ); diff --git a/packages/ckeditor5-table/src/commands/selectrowcommand.js b/packages/ckeditor5-table/src/commands/selectrowcommand.js index a49c25b6902..20ca7c3753d 100644 --- a/packages/ckeditor5-table/src/commands/selectrowcommand.js +++ b/packages/ckeditor5-table/src/commands/selectrowcommand.js @@ -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. @@ -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++ ) { diff --git a/packages/ckeditor5-table/src/commands/setheadercolumncommand.js b/packages/ckeditor5-table/src/commands/setheadercolumncommand.js index a6ccdfcc206..86ffcd673f7 100644 --- a/packages/ckeditor5-table/src/commands/setheadercolumncommand.js +++ b/packages/ckeditor5-table/src/commands/setheadercolumncommand.js @@ -10,7 +10,6 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; import { - findAncestor, isHeadingColumnCell, updateNumericAttribute } from '../utils/common'; @@ -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; diff --git a/packages/ckeditor5-table/src/commands/setheaderrowcommand.js b/packages/ckeditor5-table/src/commands/setheaderrowcommand.js index ed12880d23b..be0dc2bfff3 100644 --- a/packages/ckeditor5-table/src/commands/setheaderrowcommand.js +++ b/packages/ckeditor5-table/src/commands/setheaderrowcommand.js @@ -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'; @@ -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; diff --git a/packages/ckeditor5-table/src/converters/table-layout-post-fixer.js b/packages/ckeditor5-table/src/converters/table-layout-post-fixer.js index 8a282a1c49e..07e761624e0 100644 --- a/packages/ckeditor5-table/src/converters/table-layout-post-fixer.js +++ b/packages/ckeditor5-table/src/converters/table-layout-post-fixer.js @@ -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. @@ -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 ) ) { diff --git a/packages/ckeditor5-table/src/tableclipboard.js b/packages/ckeditor5-table/src/tableclipboard.js index 84ff5e5b65e..4d8487b5e51 100644 --- a/packages/ckeditor5-table/src/tableclipboard.js +++ b/packages/ckeditor5-table/src/tableclipboard.js @@ -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 { @@ -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 ); } ); @@ -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 ); diff --git a/packages/ckeditor5-table/src/tablekeyboard.js b/packages/ckeditor5-table/src/tablekeyboard.js index e5c5fb7c94f..c1b1352383a 100644 --- a/packages/ckeditor5-table/src/tablekeyboard.js +++ b/packages/ckeditor5-table/src/tablekeyboard.js @@ -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. @@ -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; @@ -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 ]; diff --git a/packages/ckeditor5-table/src/tablemouse.js b/packages/ckeditor5-table/src/tablemouse.js index 94d5f783c8a..5456b455c77 100644 --- a/packages/ckeditor5-table/src/tablemouse.js +++ b/packages/ckeditor5-table/src/tablemouse.js @@ -12,7 +12,6 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import TableSelection from './tableselection'; import MouseEventsObserver from './tablemouse/mouseeventsobserver'; -import { findAncestor } from './utils/common'; import { getTableCellsContainingSelection } from './utils/selection'; /** @@ -210,11 +209,7 @@ export default class TableMouse extends Plugin { const modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition ); const modelElement = modelPosition.parent; - if ( modelElement.is( 'tableCell' ) ) { - return modelElement; - } - - return findAncestor( 'tableCell', modelElement ); + return modelElement.findAncestor( 'tableCell', { includeSelf: true } ); } } diff --git a/packages/ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js b/packages/ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js index 977f261771f..f0784cc295b 100644 --- a/packages/ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js +++ b/packages/ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js @@ -9,8 +9,6 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; -import { findAncestor } from '../../utils/common'; - /** * The table cell attribute command. * @@ -38,7 +36,7 @@ export default class TablePropertyCommand extends Command { const editor = this.editor; const selection = editor.model.document.selection; - const table = findAncestor( 'table', selection.getFirstPosition() ); + const table = selection.getFirstPosition().findAncestor( 'table' ); this.isEnabled = !!table; this.value = this._getValue( table ); @@ -60,7 +58,7 @@ export default class TablePropertyCommand extends Command { const { value, batch } = options; - const table = findAncestor( 'table', selection.getFirstPosition() ); + const table = selection.getFirstPosition().findAncestor( 'table' ); const valueToSet = this._getValueToSet( value ); model.enqueueChange( batch || 'default', writer => { diff --git a/packages/ckeditor5-table/src/tableselection.js b/packages/ckeditor5-table/src/tableselection.js index 1015644807c..349b6a4d5a9 100644 --- a/packages/ckeditor5-table/src/tableselection.js +++ b/packages/ckeditor5-table/src/tableselection.js @@ -13,7 +13,6 @@ import first from '@ckeditor/ckeditor5-utils/src/first'; import TableWalker from './tablewalker'; import TableUtils from './tableutils'; -import { findAncestor } from './utils/common'; import { cropTableToDimensions, adjustLastRowIndex, adjustLastColumnIndex } from './utils/structure'; import { getColumnIndexes, getRowIndexes, getSelectedTableCells, isSelectionRectangular } from './utils/selection'; @@ -95,7 +94,7 @@ export default class TableSelection extends Plugin { const { first: firstColumn, last: lastColumn } = getColumnIndexes( selectedCells ); const { first: firstRow, last: lastRow } = getRowIndexes( selectedCells ); - const sourceTable = findAncestor( 'table', selectedCells[ 0 ] ); + const sourceTable = selectedCells[ 0 ].findAncestor( 'table' ); let adjustedLastRow = lastRow; let adjustedLastColumn = lastColumn; @@ -335,7 +334,7 @@ export default class TableSelection extends Plugin { endColumn }; - for ( const { row, cell } of new TableWalker( findAncestor( 'table', anchorCell ), walkerOptions ) ) { + for ( const { row, cell } of new TableWalker( anchorCell.findAncestor( 'table' ), walkerOptions ) ) { selectionMap[ row - startRow ].push( cell ); } diff --git a/packages/ckeditor5-table/src/utils/common.js b/packages/ckeditor5-table/src/utils/common.js index bef021eaea2..57ffbf6a703 100644 --- a/packages/ckeditor5-table/src/utils/common.js +++ b/packages/ckeditor5-table/src/utils/common.js @@ -7,26 +7,6 @@ * @module table/utils/common */ -/** - * Returns the parent element of the given name. Returns undefined if the position or the element is not inside the desired parent. - * - * @param {String} parentName The name of the parent element to find. - * @param {module:engine/model/position~Position|module:engine/model/position~Position} positionOrElement The position or - * the parentElement to start searching. - * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} - */ -export function findAncestor( parentName, positionOrElement ) { - let parent = positionOrElement.parent; - - while ( parent ) { - if ( parent.name === parentName ) { - return parent; - } - - parent = parent.parent; - } -} - /** * A common method to update the numeric value. If a value is the default one, it will be unset. * diff --git a/packages/ckeditor5-table/src/utils/selection.js b/packages/ckeditor5-table/src/utils/selection.js index fae446ea0f9..115da960769 100644 --- a/packages/ckeditor5-table/src/utils/selection.js +++ b/packages/ckeditor5-table/src/utils/selection.js @@ -8,7 +8,6 @@ */ import TableWalker from '../tablewalker'; -import { findAncestor } from './common'; /** * Returns all model table cells that are fully selected (from the outside) @@ -48,7 +47,7 @@ export function getTableCellsContainingSelection( selection ) { const cells = []; for ( const range of selection.getRanges() ) { - const cellWithSelection = findAncestor( 'tableCell', range.start ); + const cellWithSelection = range.start.findAncestor( 'tableCell' ); if ( cellWithSelection ) { cells.push( cellWithSelection ); @@ -110,7 +109,7 @@ export function getRowIndexes( tableCells ) { * @returns {Object} Returns an object with the `first` and `last` table column indexes. */ export function getColumnIndexes( tableCells ) { - const table = findAncestor( 'table', tableCells[ 0 ] ); + const table = tableCells[ 0 ].findAncestor( 'table' ); const tableMap = [ ...new TableWalker( table ) ]; const indexes = tableMap @@ -245,7 +244,7 @@ function getBiggestRectangleArea( rows, columns ) { // │ c │ c │ d │ d │ // └───┴───┴───┴───┘ function areCellInTheSameTableSection( tableCells ) { - const table = findAncestor( 'table', tableCells[ 0 ] ); + const table = tableCells[ 0 ].findAncestor( 'table' ); const rowIndexes = getRowIndexes( tableCells ); const headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 ); diff --git a/packages/ckeditor5-table/src/utils/ui/contextualballoon.js b/packages/ckeditor5-table/src/utils/ui/contextualballoon.js index 402db4fa589..ebec533a79d 100644 --- a/packages/ckeditor5-table/src/utils/ui/contextualballoon.js +++ b/packages/ckeditor5-table/src/utils/ui/contextualballoon.js @@ -10,7 +10,6 @@ import { centeredBalloonPositionForLongWidgets } from '@ckeditor/ckeditor5-widget/src/utils'; import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect'; import { getTableWidgetAncestor } from './widget'; -import { findAncestor } from '../common'; import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview'; const DEFAULT_BALLOON_POSITIONS = BalloonPanelView.defaultPositions; @@ -64,7 +63,7 @@ export function repositionContextualBalloon( editor, target ) { */ export function getBalloonTablePositionData( editor ) { const firstPosition = editor.model.document.selection.getFirstPosition(); - const modelTable = findAncestor( 'table', firstPosition ); + const modelTable = firstPosition.findAncestor( 'table' ); const viewTable = editor.editing.mapper.toViewElement( modelTable ); return { @@ -113,7 +112,7 @@ export function getBalloonCellPositionData( editor ) { function getTableCellAtPosition( position ) { const isTableCellSelected = position.nodeAfter && position.nodeAfter.is( 'tableCell' ); - return isTableCellSelected ? position.nodeAfter : findAncestor( 'tableCell', position ); + return isTableCellSelected ? position.nodeAfter : position.findAncestor( 'tableCell' ); } // Returns bounding rect for list of rects. diff --git a/packages/ckeditor5-table/src/utils/ui/widget.js b/packages/ckeditor5-table/src/utils/ui/widget.js index 12a2ffeeb2b..0cc9267d327 100644 --- a/packages/ckeditor5-table/src/utils/ui/widget.js +++ b/packages/ckeditor5-table/src/utils/ui/widget.js @@ -8,7 +8,6 @@ */ import { isWidget } from '@ckeditor/ckeditor5-widget/src/utils'; -import { findAncestor } from '../common'; /** * Returns a table widget editing view element if one is selected. @@ -49,3 +48,15 @@ export function getTableWidgetAncestor( selection ) { function isTableWidget( viewElement ) { return !!viewElement.getCustomProperty( 'table' ) && isWidget( viewElement ); } + +function findAncestor( parentName, positionOrElement ) { + let parent = positionOrElement.parent; + + while ( parent ) { + if ( parent.name === parentName ) { + return parent; + } + + parent = parent.parent; + } +} diff --git a/packages/ckeditor5-table/tests/manual/tablemocking.js b/packages/ckeditor5-table/tests/manual/tablemocking.js index 1f67b8f81e0..f26796415bf 100644 --- a/packages/ckeditor5-table/tests/manual/tablemocking.js +++ b/packages/ckeditor5-table/tests/manual/tablemocking.js @@ -15,7 +15,6 @@ import { debounce } from 'lodash-es'; import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; import TableWalker from '../../src/tablewalker'; import { getSelectionAffectedTableCells } from '../../src/utils/selection'; -import { findAncestor } from '../../src/utils/common'; ClassicEditor .create( document.querySelector( '#editor' ), { @@ -120,7 +119,7 @@ ClassicEditor const tableCells = getSelectionAffectedTableCells( selection ); if ( tableCells.length ) { - return findAncestor( 'table', tableCells[ 0 ] ); + return tableCells[ 0 ].findAncestor( 'table' ); } const element = selection.getSelectedElement(); diff --git a/packages/ckeditor5-table/tests/utils/common.js b/packages/ckeditor5-table/tests/utils/common.js index 26826b249a5..a1bb6588c35 100644 --- a/packages/ckeditor5-table/tests/utils/common.js +++ b/packages/ckeditor5-table/tests/utils/common.js @@ -10,7 +10,7 @@ import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import TableEditing from '../../src/tableediting'; import { modelTable } from '../_utils/utils'; -import { findAncestor, isHeadingColumnCell } from '../../src/utils/common'; +import { isHeadingColumnCell } from '../../src/utils/common'; describe( 'table utils', () => { let editor, model, modelRoot, tableUtils; @@ -32,23 +32,6 @@ describe( 'table utils', () => { } ); describe( 'common', () => { - describe( 'findAncestor()', () => { - it( 'should return undefined if not in table', () => { - setData( model, 'foo[]' ); - - expect( findAncestor( 'table', model.document.selection.focus ) ).to.be.undefined; - } ); - - it( 'should return table if position is in tableCell', () => { - setData( model, modelTable( [ [ '[]' ] ] ) ); - - const parentTable = findAncestor( 'table', model.document.selection.focus ); - - expect( parentTable ).to.not.be.undefined; - expect( parentTable.is( 'table' ) ).to.be.true; - } ); - } ); - describe( 'isHeadingColumnCell()', () => { it( 'should return "true" for a heading column cell', () => { setData( model, modelTable( [ diff --git a/packages/ckeditor5-table/tests/utils/ui/contextualballoon.js b/packages/ckeditor5-table/tests/utils/ui/contextualballoon.js index 35d95f4abed..3166c4107e7 100644 --- a/packages/ckeditor5-table/tests/utils/ui/contextualballoon.js +++ b/packages/ckeditor5-table/tests/utils/ui/contextualballoon.js @@ -16,7 +16,6 @@ import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { centeredBalloonPositionForLongWidgets } from '@ckeditor/ckeditor5-widget/src/utils'; import { modelTable } from '../../_utils/utils'; import { getTableCellsContainingSelection } from '../../../src/utils/selection'; -import { findAncestor } from '../../../src/utils/common'; import { getBalloonCellPositionData, repositionContextualBalloon } from '../../../src/utils/ui/contextualballoon'; describe( 'table utils', () => { @@ -117,7 +116,7 @@ describe( 'table utils', () => { '' ); repositionContextualBalloon( editor, 'table' ); - const modelTable = findAncestor( 'table', editor.model.document.selection.getFirstPosition() ); + const modelTable = editor.model.document.selection.getFirstPosition().findAncestor( 'table' ); const viewTable = editor.editing.mapper.toViewElement( modelTable ); sinon.assert.calledWithExactly( spy, {