{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableutils.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tablewalker.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableediting.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableui.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableselection.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableclipboard.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tablekeyboard.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tablemouse/mouseeventsobserver.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tablemouse.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/table.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tablebackgroundcolorcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tablebordercolorcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tableborderstylecommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tableborderwidthcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tablewidthcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tableheightcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/commands/tablealignmentcommand.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/tablepropertiesediting.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/ui/tablepropertiesview.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties/tablepropertiesui.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tableproperties.js","webpack:///./node_modules/@ckeditor/ckeditor5-table/src/tabletoolbar.js"],"names":["TableUtils","this","decorate","tableCell","tableRow","parent","table","rowIndex","getChildIndex","tableWalker","TableWalker","row","cell","column","writer","options","createElement","rows","parseInt","columns","createEmptyRows","headingRows","updateNumericAttribute","headingColumns","model","editor","insertAt","at","rowsToInsert","isCopyStructure","undefined","copyStructureFromAbove","copyStructureFrom","getRows","getColumns","change","getAttribute","walkerEndRow","Math","max","tableIterator","endRow","rowColSpansMap","Array","fill","cellHeight","cellWidth","lastCellRow","isOverlappingInsertedRow","isReferenceRow","setAttribute","insert","cellIndex","length","colspan","insertPosition","createPositionAt","createEmptyTableCell","abs","columnsToInsert","tableColumns","includeAllSlots","tableSlot","cellAnchorColumn","cellAnchorRow","i","skipRow","createCells","getPositionBefore","getChildren","rowsToRemove","first","last","getCellsToMoveAndTrimOnRemoveRow","cellsToMove","cellsToTrim","size","rowAfterRemovedSection","moveCellsToRow","remove","getChild","rowspan","updateHeadingRows","removeEmptyColumns","removeEmptyRows","columnsToRemove","adjustHeadingColumns","removedColumnIndex","numberOfCells","breakSpanEvenly","newCellsSpan","updatedSpan","newCellsAttributes","cellsToInsert","createPositionAfter","tableMap","find","splitCellColumn","cellsToUpdate","filter","isOnSameColumn","spansOverColumn","splitCellRow","startRow","cellColumn","isAfterSplitCell","isInEvenlySplitRow","rowspanToSet","reduce","columnWidth","childCount","Plugin","tableCellToInsert","attributes","cells","span","floor","removedColumnIndexes","headingsRemoved","min","newRows","Map","lastRowOfCell","isCellStickingOutFromRemovedRows","rowspanInRemovedSection","rowSpanToSet","set","isCellOverlappingRemovedRows","rowspanAdjustment","push","targetRowIndex","previousCell","tableRowMap","isAnchor","has","get","cellToMove","targetPosition","move","createRangeOn","_table","_startRow","_endRow","_startColumn","startColumn","_endColumn","endColumn","_includeAllSlots","_skipRows","Set","_row","_column","_cellIndex","_spannedCells","_nextCellAtColumn","Symbol","iterator","_isOverEndRow","done","_isOverEndColumn","_advanceToNextRow","outValue","spanData","_getSpanned","_shouldSkipSlot","_formatOutValue","_recordSpans","next","add","anchorRow","anchorColumn","value","TableSlot","rowIsMarkedAsSkipped","rowIsBeforeStartRow","columnIsBeforeStartColumn","columnIsAfterEndColumn","rowMap","data","rowToUpdate","columnToUpdate","_markSpannedCell","rowSpans","root","document","TableEditing","schema","conversion","register","allowWhere","allowAttributes","isObject","isBlock","allowIn","isLimit","isSelectable","extend","addChildCheck","context","childDefinition","name","from","getNames","includes","for","upcastTable","downcastInsertTable","asWidget","elementToElement","view","skipEmptyTableRow","downcastInsertRow","downcastRemoveRow","ensureParagraphInTableCell","downcastInsertCell","convertParagraphInTableCell","converterPriority","attributeToAttribute","downcastTableHeadingColumnsChange","commands","InsertTableCommand","InsertRowCommand","order","InsertColumnCommand","RemoveRowCommand","RemoveColumnCommand","SplitCellCommand","direction","MergeCellsCommand","MergeCellCommand","SetHeaderColumnCommand","SetHeaderRowCommand","SelectRowCommand","SelectColumnCommand","injectTableHeadingRowsRefreshPostFixer","injectTableLayoutPostFixer","injectTableCellRefreshPostFixer","editing","mapper","injectTableCellParagraphPostFixer","TableUI","t","contentLanguageDirection","locale","isContentLtr","ui","componentFactory","insertTableView","command","dropdownView","createDropdown","bind","to","buttonView","icon","tableIcon","label","tooltip","on","InsertTableView","panelView","children","delegate","execute","focus","type","commandName","bindIsOn","_prepareDropdown","tableColumnIcon","tableRowIcon","_prepareMergeSplitButtonDropdown","tableMergeCellIcon","_fillDropdownWithListOptions","toMany","areEnabled","some","isEnabled","listenTo","evt","source","SplitButtonView","mergeCommandName","itemDefinitions","Collection","option","addListOption","addListToDropdown","Model","withText","TableSelection","args","_handleDeleteContent","priority","_defineSelectionConverter","_enablePluginDisabling","selection","selectedCells","getSelectedTableCells","documentFragment","createDocumentFragment","tableUtils","plugins","getColumnIndexes","firstColumn","lastColumn","getRowIndexes","firstRow","lastRow","sourceTable","findAncestor","adjustedLastRow","adjustedLastColumn","isSelectionRectangular","dimensions","adjustLastRowIndex","adjustLastColumnIndex","cropDimensions","cropTableToDimensions","anchorCell","targetCell","cellsToSelect","_getCellsToSelect","setSelection","map","backward","focusCellRange","getRanges","pop","element","getContainedElement","is","anchorCellRange","highlighted","clearHighlightedTableCells","previouslyHighlighted","removeClass","clear","dispatcher","conversionApi","viewWriter","viewElement","toViewElement","addClass","lastViewCell","position","range","getNearestSelectionRange","event","isBackward","selectedTableCells","stop","tableCellToSelect","deleteContent","createSelection","rangeToSelect","setTo","startLocation","getCellLocation","endLocation","selectionMap","walkerOptions","flipVertically","flipHorizontally","reverse","forEach","flat","TableClipboard","viewDocument","_onCopyCut","_onInsertContent","tableSelection","isReadOnly","preventDefault","dataController","content","toView","getSelectionAsFragment","fire","dataTransfer","method","selectable","pastedTable","getTableIfOnlyTableInContent","getSelectionAffectedTableCells","pastedDimensions","width","height","prepareTableForPasting","selectionHeight","selectionWidth","selectedTable","_replaceSelectedCellsWithPasted","selectionRanges","sortRanges","removeEmptyRowsColumns","pastedWidth","pastedHeight","pastedTableLocationMap","createLocationMap","selectedTableMap","pastedRow","pastedColumn","pastedCell","cellToInsert","cloneElement","newTableCell","_replaceTableSlotCell","trimTableCellIfNeeded","areHeadingRowsIntersectingSelection","areHeadingColumnsIntersectingSelection","columnsLimit","newCells","doHorizontalSplit","rowsLimit","doVerticalSplit","contentRange","createRangeIn","getItems","rangeBefore","createRange","start","createPositionBefore","hasContent","ignoreWhitespaces","rangeAfter","end","columnIndexes","rowIndexes","shouldExpandSelection","expandTableSize","splitCellsToRectangularSelection","expectedHeight","expectedWidth","tableWidth","tableHeight","insertColumns","insertRows","splitRow","limitColumns","overlappingCells","getVerticallyOverlappingCells","cellsToSplit","isAffectedBySelection","splitHorizontally","splitColumn","limitRows","getHorizontallyOverlappingCells","splitVertically","index","limit","endIndex","isInsideSelection","overlapsSelectionFromOutside","TableKeyboard","keystrokes","_handleTabOnSelectedTable","_getTabHandler","_onKeydown","priorities","cancel","selectedElement","getSelectedElement","isForward","domEventData","getTableCellsContainingSelection","getFocusCell","currentRowIndex","currentCellIndex","isFirstCellInRow","isLastCellInRow","isLastRow","cellToFocus","nextRow","previousRow","eventInfo","keyCode","isArrowKeyCode","getLocalizedArrowKeyCodeDirection","wasHandled","_handleArrowKeys","shiftKey","stopPropagation","expandSelection","focusCell","_navigateFromCellInDirection","isCollapsed","_isSelectionAtCellEdge","getLastPosition","getFirstPosition","getLimitElement","boundaryPosition","isTouching","probe","modifySelection","isEqual","currentCellInfo","isOutsideVertically","isBeforeFirstCell","isAfterLastCell","cellToSelect","cellInfo","getAnchorCell","setCellSelection","positionToSelect","MouseEventsObserver","domEventType","domEvent","DomEventObserver","TableMouse","addObserver","_enableShiftClickSelection","_enableMouseDragSelection","blockSelectionChange","_getModelTableCellFromDomEvent","haveSameTableParent","beganCellSelection","ctrlKey","altKey","buttons","newTargetCell","viewTargetElement","target","viewPosition","modelPosition","toModelPosition","modelElement","includeSelf","cellA","cellB","Table","Widget","TablePropertyCommand","attributeName","_getValue","batch","valueToSet","_getValueToSet","enqueueChange","removeAttribute","Command","TableBackgroundColorCommand","TableBorderColorCommand","getSingleValue","TableBorderStyleCommand","TableBorderWidthCommand","addDefaultUnitToNumericValue","TableWidthCommand","TableHeightCommand","TableAlignmentCommand","ALIGN_VALUES_REG_EXP","TablePropertiesEditing","addStyleProcessorRules","addBorderRules","enableBorderProperties","enableAlignmentProperty","enableTableToFigureProperty","addBackgroundRules","enableProperty","upcastBorderStyles","downcastTableAttribute","key","values","left","float","right","align","modelAttribute","styleName","upcastStyleToAttribute","downcastAttributeToStyle","ALIGNMENT_ICONS","icons","objectLeft","center","objectCenter","objectRight","TablePropertiesView","borderStyle","borderWidth","borderColor","backgroundColor","alignment","_createBorderFields","borderStyleDropdown","borderWidthInput","borderColorInput","borderRowLabel","_createBackgroundFields","backgroundRowLabel","backgroundInput","_createDimensionFields","widthInput","operatorLabel","heightInput","dimensionsLabel","_createAlignmentFields","alignmentToolbar","alignmentLabel","focusTracker","FocusTracker","KeystrokeHandler","createCollection","_createActionButtons","saveButtonView","cancelButtonView","_focusables","ViewCollection","_focusCycler","FocusCycler","focusables","keystrokeHandler","actions","focusPrevious","focusNext","FormHeaderView","FormRowView","labelView","class","setTemplate","tag","tabindex","submitHandler","focusFirst","colorInputCreator","getLabeledColorInputCreator","colorConfig","borderColors","LabelView","text","styleLabels","getBorderStyleLabels","LabeledFieldView","createLabeledDropdown","fieldView","isOn","_borderStyleValue","getBorderStyleDefinitions","createLabeledInputText","isBorderStyleSet","backgroundInputCreator","backgroundColors","View","ToolbarView","isCompact","ariaLabel","fillToolbar","toolbar","labels","_alignmentLabels","propertyName","nameToValue","ButtonView","fieldsThatShouldValidateToSave","check","errorTexts","every","errorText","uiLanguageDirection","ERROR_TEXT_TIMEOUT","propertyToCommandMap","TablePropertiesUI","config","define","defaultColors","ContextualBalloon","_balloon","_createPropertiesView","_undoStepBatch","tableProperties","_showView","Object","isCommandEnabled","destroy","borderColorsConfig","normalizeColorOptions","localizedBorderColors","getLocalizedColorOptions","backgroundColorsConfig","localizedBackgroundColors","render","_hideView","operations","clickOutsideHandler","emitter","activator","_isViewInBalloon","contextElements","callback","colorErrorText","getLocalizedColorErrorText","lengthErrorText","getLocalizedLengthErrorText","_getPropertyChangeCallback","_getValidatedPropertyChangeCallback","viewField","validator","colorFieldValidator","lineWidthFieldValidator","lengthFieldValidator","entries","property","_updateView","_fillViewFormFromCommandValues","getBalloonTablePositionData","createBatch","stopListening","getTableWidgetAncestor","_isViewVisible","repositionContextualBalloon","newValue","setErrorTextDebounced","debounce","visibleView","hasView","TableProperties","TableToolbar","widgetToolbarRepository","WidgetToolbarRepository","tableContentToolbarItems","tableToolbarItems","items","getRelatedElement","getSelectedTableWidget"],"mappings":"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","file":"js/chunk-vendors~17939906.7bbafb30.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableutils\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableWalker from './tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './utils/common';\nimport { removeEmptyColumns, removeEmptyRows } from './utils/structure';\n\n/**\n * The table utilities plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUtils extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUtils';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.decorate( 'insertColumns' );\n\t\tthis.decorate( 'insertRows' );\n\t}\n\n\t/**\n\t * Returns the table cell location as an object with table row and table column indexes.\n\t *\n\t * For instance, in the table below:\n\t *\n\t *\t\t 0 1 2 3\n\t *\t\t +---+---+---+---+\n\t *\t\t0 | a | b | c |\n\t *\t\t + + +---+\n\t *\t\t1 | | | d |\n\t *\t\t +---+---+ +---+\n\t *\t\t2 | e | | f |\n\t *\t\t +---+---+---+---+\n\t *\n\t * the method will return:\n\t *\n\t *\t\tconst cellA = table.getNodeByPath( [ 0, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellA );\n\t *\t\t// will return { row: 0, column: 0 }\n\t *\n\t *\t\tconst cellD = table.getNodeByPath( [ 1, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellD );\n\t *\t\t// will return { row: 1, column: 3 }\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @returns {Object} Returns a `{row, column}` object.\n\t */\n\tgetCellLocation( tableCell ) {\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row: rowIndex } );\n\n\t\tfor ( const { cell, row, column } of tableWalker ) {\n\t\t\tif ( cell === tableCell ) {\n\t\t\t\treturn { row, column };\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an empty table with a proper structure. The table needs to be inserted into the model,\n\t * for example, by using the {@link module:engine/model/model~Model#insertContent} function.\n\t *\n\t *\t\tmodel.change( ( writer ) => {\n\t *\t\t\t// Create a table of 2 rows and 7 columns:\n\t *\t\t\tconst table = tableUtils.createTable( writer, { rows: 2, columns: 7 } );\n\t *\n\t *\t\t\t// Insert a table to the model at the best position taking the current selection:\n\t *\t\t\tmodel.insertContent( table );\n\t *\t\t}\n\t *\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create.\n\t * @param {Number} [options.columns=2] The number of columns to create.\n\t * @param {Number} [options.headingRows=0] The number of heading rows.\n\t * @param {Number} [options.headingColumns=0] The number of heading columns.\n\t * @returns {module:engine/model/element~Element} The created table element.\n\t */\n\tcreateTable( writer, options ) {\n\t\tconst table = writer.createElement( 'table' );\n\n\t\tconst rows = parseInt( options.rows ) || 2;\n\t\tconst columns = parseInt( options.columns ) || 2;\n\n\t\tcreateEmptyRows( writer, table, 0, rows, columns );\n\n\t\tif ( options.headingRows ) {\n\t\t\tupdateNumericAttribute( 'headingRows', options.headingRows, table, writer, 0 );\n\t\t}\n\n\t\tif ( options.headingColumns ) {\n\t\t\tupdateNumericAttribute( 'headingColumns', options.headingColumns, table, writer, 0 );\n\t\t}\n\n\t\treturn table;\n\t}\n\n\t/**\n\t * Inserts rows into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\trow index\n\t *\t\t 0 +---+---+---+ `at` = 1, +---+---+---+ 0\n\t *\t\t | a | b | c | `rows` = 2, | a | b | c |\n\t *\t\t 1 + +---+---+ <-- insert here + +---+---+ 1\n\t *\t\t | | d | e | | | | |\n\t *\t\t 2 + +---+---+ will give: + +---+---+ 2\n\t *\t\t | | f | g | | | | |\n\t *\t\t 3 +---+---+---+ + +---+---+ 3\n\t *\t\t | | d | e |\n\t *\t\t + +---+---+ 4\n\t *\t\t + + f | g |\n\t *\t\t +---+---+---+ 5\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the rows will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The row index at which the rows will be inserted.\n\t * @param {Number} [options.rows=1] The number of rows to insert.\n\t * @param {Boolean|undefined} [options.copyStructureFromAbove] The flag for copying row structure. Note that\n\t * the row structure will not be copied if this option is not provided.\n\t */\n\tinsertRows( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst rowsToInsert = options.rows || 1;\n\t\tconst isCopyStructure = options.copyStructureFromAbove !== undefined;\n\t\tconst copyStructureFrom = options.copyStructureFromAbove ? insertAt - 1 : insertAt;\n\n\t\tconst rows = this.getRows( table );\n\t\tconst columns = this.getColumns( table );\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t// Inserting rows inside heading section requires to update `headingRows` attribute as the heading section will grow.\n\t\t\tif ( headingRows > insertAt ) {\n\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + rowsToInsert, table, writer, 0 );\n\t\t\t}\n\n\t\t\t// Inserting at the end or at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( !isCopyStructure && ( insertAt === 0 || insertAt === rows ) ) {\n\t\t\t\tcreateEmptyRows( writer, table, insertAt, rowsToInsert, columns );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Iterate over all the rows above the inserted rows in order to check for the row-spanned cells.\n\t\t\tconst walkerEndRow = isCopyStructure ? Math.max( insertAt, copyStructureFrom ) : insertAt;\n\t\t\tconst tableIterator = new TableWalker( table, { endRow: walkerEndRow } );\n\n\t\t\t// Store spans of the reference row to reproduce it's structure. This array is column number indexed.\n\t\t\tconst rowColSpansMap = new Array( columns ).fill( 1 );\n\n\t\t\tfor ( const { row, column, cellHeight, cellWidth, cell } of tableIterator ) {\n\t\t\t\tconst lastCellRow = row + cellHeight - 1;\n\n\t\t\t\tconst isOverlappingInsertedRow = row < insertAt && insertAt <= lastCellRow;\n\t\t\t\tconst isReferenceRow = row <= copyStructureFrom && copyStructureFrom <= lastCellRow;\n\n\t\t\t\t// If the cell is row-spanned and overlaps the inserted row, then reserve space for it in the row map.\n\t\t\t\tif ( isOverlappingInsertedRow ) {\n\t\t\t\t\t// This cell overlaps the inserted rows so we need to expand it further.\n\t\t\t\t\twriter.setAttribute( 'rowspan', cellHeight + rowsToInsert, cell );\n\n\t\t\t\t\t// Mark this cell with negative number to indicate how many cells should be skipped when adding the new cells.\n\t\t\t\t\trowColSpansMap[ column ] = -cellWidth;\n\t\t\t\t}\n\t\t\t\t// Store the colspan from reference row.\n\t\t\t\telse if ( isCopyStructure && isReferenceRow ) {\n\t\t\t\t\trowColSpansMap[ column ] = cellWidth;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( let rowIndex = 0; rowIndex < rowsToInsert; rowIndex++ ) {\n\t\t\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\t\t\twriter.insert( tableRow, table, insertAt );\n\n\t\t\t\tfor ( let cellIndex = 0; cellIndex < rowColSpansMap.length; cellIndex++ ) {\n\t\t\t\t\tconst colspan = rowColSpansMap[ cellIndex ];\n\t\t\t\t\tconst insertPosition = writer.createPositionAt( tableRow, 'end' );\n\n\t\t\t\t\t// Insert the empty cell only if this slot is not row-spanned from any other cell.\n\t\t\t\t\tif ( colspan > 0 ) {\n\t\t\t\t\t\tcreateEmptyTableCell( writer, insertPosition, colspan > 1 ? { colspan } : null );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip the col-spanned slots, there won't be any cells.\n\t\t\t\t\tcellIndex += Math.abs( colspan ) - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Inserts columns into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\t0 1 2 3 0 1 2 3 4 5\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| a | b | | a | b |\n\t *\t\t+ +---+ + +---+\n\t *\t\t| | c | | | c |\n\t *\t\t+---+---+---+ will give: +---+---+---+---+---+\n\t *\t\t| d | e | f | | d | | | e | f |\n\t *\t\t+---+ +---+ +---+---+---+ +---+\n\t *\t\t| g | | h | | g | | | | h |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| i | | i |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t ^---- insert here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the columns will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The column index at which the columns will be inserted.\n\t * @param {Number} [options.columns=1] The number of columns to insert.\n\t */\n\tinsertColumns( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst columnsToInsert = options.columns || 1;\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' );\n\n\t\t\t// Inserting columns inside heading section requires to update `headingColumns` attribute as the heading section will grow.\n\t\t\tif ( insertAt < headingColumns ) {\n\t\t\t\twriter.setAttribute( 'headingColumns', headingColumns + columnsToInsert, table );\n\t\t\t}\n\n\t\t\tconst tableColumns = this.getColumns( table );\n\n\t\t\t// Inserting at the end and at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( insertAt === 0 || tableColumns === insertAt ) {\n\t\t\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\t\t\tcreateCells( columnsToInsert, writer, writer.createPositionAt( tableRow, insertAt ? 'end' : 0 ) );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tableWalker = new TableWalker( table, { column: insertAt, includeAllSlots: true } );\n\n\t\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\t\tconst { row, cell, cellAnchorColumn, cellAnchorRow, cellWidth, cellHeight } = tableSlot;\n\n\t\t\t\t// When iterating over column the table walker outputs either:\n\t\t\t\t// - cells at given column index (cell \"e\" from method docs),\n\t\t\t\t// - spanned columns (spanned cell from row between cells \"g\" and \"h\" - spanned by \"e\", only if `includeAllSlots: true`),\n\t\t\t\t// - or a cell from the same row which spans over this column (cell \"a\").\n\n\t\t\t\tif ( cellAnchorColumn < insertAt ) {\n\t\t\t\t\t// If cell is anchored in previous column, it is a cell that spans over an inserted column (cell \"a\" & \"i\").\n\t\t\t\t\t// For such cells expand them by a number of columns inserted.\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + columnsToInsert, cell );\n\n\t\t\t\t\t// This cell will overlap cells in rows below so skip them (because of `includeAllSlots` option) - (cell \"a\")\n\t\t\t\t\tconst lastCellRow = cellAnchorRow + cellHeight - 1;\n\n\t\t\t\t\tfor ( let i = row; i <= lastCellRow; i++ ) {\n\t\t\t\t\t\ttableWalker.skipRow( i );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// It's either cell at this column index or spanned cell by a row-spanned cell from row above.\n\t\t\t\t\t// In table above it's cell \"e\" and a spanned position from row below (empty cell between cells \"g\" and \"h\")\n\t\t\t\t\tcreateCells( columnsToInsert, writer, tableSlot.getPositionBefore() );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes rows from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including `rowspan` attribute of table cells overlapping removed rows\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\trow index\n\t *\t\t ┌───┬───┬───┐ `at` = 1 ┌───┬───┬───┐\n\t *\t\t 0 │ a │ b │ c │ `rows` = 2 │ a │ b │ c │ 0\n\t *\t\t │ ├───┼───┤ │ ├───┼───┤\n\t *\t\t 1 │ │ d │ e │ <-- remove from here │ │ d │ g │ 1\n\t *\t\t │ │ ├───┤ will give: ├───┼───┼───┤\n\t *\t\t 2 │ │ │ f │ │ h │ i │ j │ 2\n\t *\t\t │ │ ├───┤ └───┴───┴───┘\n\t *\t\t 3 │ │ │ g │\n\t *\t\t ├───┼───┼───┤\n\t *\t\t 4 │ h │ i │ j │\n\t *\t\t └───┴───┴───┘\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing rows will start.\n\t * @param {Number} [options.rows=1] The number of rows to remove.\n\t */\n\tremoveRows( table, options ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst rowsToRemove = options.rows || 1;\n\t\tconst first = options.at;\n\t\tconst last = first + rowsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\t// Removing rows from the table require that most calculations to be done prior to changing table structure.\n\t\t\t// Preparations must be done in the same enqueueChange callback to use the current table structure.\n\n\t\t\t// 1. Preparation - get row-spanned cells that have to be modified after removing rows.\n\t\t\tconst { cellsToMove, cellsToTrim } = getCellsToMoveAndTrimOnRemoveRow( table, first, last );\n\n\t\t\t// 2. Execution\n\n\t\t\t// 2a. Move cells from removed rows that extends over a removed section - must be done before removing rows.\n\t\t\t// This will fill any gaps in a rows below that previously were empty because of row-spanned cells.\n\t\t\tif ( cellsToMove.size ) {\n\t\t\t\tconst rowAfterRemovedSection = last + 1;\n\t\t\t\tmoveCellsToRow( table, rowAfterRemovedSection, cellsToMove, writer );\n\t\t\t}\n\n\t\t\t// 2b. Remove all required rows.\n\t\t\tfor ( let i = last; i >= first; i-- ) {\n\t\t\t\twriter.remove( table.getChild( i ) );\n\t\t\t}\n\n\t\t\t// 2c. Update cells from rows above that overlap removed section. Similar to step 2 but does not involve moving cells.\n\t\t\tfor ( const { rowspan, cell } of cellsToTrim ) {\n\t\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cell, writer );\n\t\t\t}\n\n\t\t\t// 2d. Adjust heading rows if removed rows were in a heading section.\n\t\t\tupdateHeadingRows( table, first, last, writer );\n\n\t\t\t// 2e. Remove empty columns (without anchored cells) if there are any.\n\t\t\tif ( !removeEmptyColumns( table, this ) ) {\n\t\t\t\t// If there wasn't any empty columns then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty rows and we only removed one of them.\n\t\t\t\tremoveEmptyRows( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes columns from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including the `colspan` attribute of table cells overlapping removed columns\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\t 0 1 2 3 4 0 1 2\n\t *\t\t┌───────────────┬───┐ ┌───────┬───┐\n\t *\t\t│ a │ b │ │ a │ b │\n\t *\t\t│ ├───┤ │ ├───┤\n\t *\t\t│ │ c │ │ │ c │\n\t *\t\t├───┬───┬───┬───┼───┤ will give: ├───┬───┼───┤\n\t *\t\t│ d │ e │ f │ g │ h │ │ d │ g │ h │\n\t *\t\t├───┼───┼───┤ ├───┤ ├───┤ ├───┤\n\t *\t\t│ i │ j │ k │ │ l │ │ i │ │ l │\n\t *\t\t├───┴───┴───┴───┴───┤ ├───┴───┴───┤\n\t *\t\t│ m │ │ m │\n\t *\t\t└───────────────────┘ └───────────┘\n\t *\t\t ^---- remove from here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing columns will start.\n\t * @param {Number} [options.columns=1] The number of columns to remove.\n\t */\n\tremoveColumns( table, options ) {\n\t\tconst model = this.editor.model;\n\t\tconst first = options.at;\n\t\tconst columnsToRemove = options.columns || 1;\n\t\tconst last = options.at + columnsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\tadjustHeadingColumns( table, { first, last }, writer );\n\n\t\t\tfor ( let removedColumnIndex = last; removedColumnIndex >= first; removedColumnIndex-- ) {\n\t\t\t\tfor ( const { cell, column, cellWidth } of [ ...new TableWalker( table ) ] ) {\n\t\t\t\t\t// If colspaned cell overlaps removed column decrease its span.\n\t\t\t\t\tif ( column <= removedColumnIndex && cellWidth > 1 && column + cellWidth > removedColumnIndex ) {\n\t\t\t\t\t\tupdateNumericAttribute( 'colspan', cellWidth - 1, cell, writer );\n\t\t\t\t\t} else if ( column === removedColumnIndex ) {\n\t\t\t\t\t\t// The cell in removed column has colspan of 1.\n\t\t\t\t\t\twriter.remove( cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove empty rows that could appear after removing columns.\n\t\t\tif ( !removeEmptyRows( table, this ) ) {\n\t\t\t\t// If there wasn't any empty rows then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty columns and we only removed one of them.\n\t\t\t\tremoveEmptyColumns( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell vertically into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating colspans of other cells in a column\n\t * and inserting cells (columns) after that cell.\n\t *\n\t * In the table below, if cell \"a\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * it will result in the table below:\n\t *\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| a | | | b | c |\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+---+---+\n\t *\n\t * So cell \"d\" will get its `colspan` updated to `3` and 2 cells will be added (2 columns will be created).\n\t *\n\t * Splitting a cell that already has a `colspan` attribute set will distribute the cell `colspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `colspan=3` into 2 cells will create 1 cell with a `colspan=a` and cell \"a\" that will have `colspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellVertically( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( colspan > 1 ) {\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( colspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'colspan', updatedSpan, tableCell, writer );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tconst cellsToInsert = colspan > numberOfCells ? numberOfCells - 1 : colspan - 1;\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\t\t\t}\n\n\t\t\t// Second check - the cell has colspan of 1 or we need to create more cells then the currently one spans over.\n\t\t\tif ( colspan < numberOfCells ) {\n\t\t\t\tconst cellsToInsert = numberOfCells - colspan;\n\n\t\t\t\t// First step: expand cells on the same column as split cell.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t\t\t// Get the column index of split cell.\n\t\t\t\tconst { column: splitCellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Find cells which needs to be expanded vertically - those on the same column or those that spans over split cell's column.\n\t\t\t\tconst cellsToUpdate = tableMap.filter( ( { cell, cellWidth, column } ) => {\n\t\t\t\t\tconst isOnSameColumn = cell !== tableCell && column === splitCellColumn;\n\t\t\t\t\tconst spansOverColumn = ( column < splitCellColumn && column + cellWidth > splitCellColumn );\n\n\t\t\t\t\treturn isOnSameColumn || spansOverColumn;\n\t\t\t\t} );\n\n\t\t\t\t// Expand cells vertically.\n\t\t\t\tfor ( const { cell, cellWidth } of cellsToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + cellsToInsert, cell );\n\t\t\t\t}\n\n\t\t\t\t// Second step: create columns after split cell.\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\n\t\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tif ( headingColumns > splitCellColumn ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingColumns', headingColumns + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell horizontally into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating rowspans of other cells in the row and inserting rows with a single cell\n\t * below.\n\t *\n\t * If in the table below cell \"b\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * It will result in the table below:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * So cells \"a\" and \"b\" will get their `rowspan` updated to `3` and 2 rows with a single cell will be added.\n\t *\n\t * Splitting a cell that already has a `rowspan` attribute set will distribute the cell `rowspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+ +---+---+\n\t *\t\t| | f | g |\n\t *\t\t+ +---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `rowspan=4` into 3 cells will create 2 cells with a `rowspan=1` and cell \"a\" will have `rowspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+---+---+---+\n\t *\t\t| | f | g |\n\t *\t\t+---+---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellHorizontally( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst splitCellRow = table.getChildIndex( tableRow );\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t// Cache table map before updating table.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, {\n\t\t\t\t\tstartRow: splitCellRow,\n\t\t\t\t\tendRow: splitCellRow + rowspan - 1,\n\t\t\t\t\tincludeAllSlots: true\n\t\t\t\t} ) ];\n\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( rowspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'rowspan', updatedSpan, tableCell, writer );\n\n\t\t\t\tconst { column: cellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tfor ( const tableSlot of tableMap ) {\n\t\t\t\t\tconst { column, row } = tableSlot;\n\n\t\t\t\t\t// As both newly created cells and the split cell might have rowspan,\n\t\t\t\t\t// the insertion of new cells must go to appropriate rows:\n\t\t\t\t\t//\n\t\t\t\t\t// 1. It's a row after split cell + it's height.\n\t\t\t\t\tconst isAfterSplitCell = row >= splitCellRow + updatedSpan;\n\t\t\t\t\t// 2. Is on the same column.\n\t\t\t\t\tconst isOnSameColumn = column === cellColumn;\n\t\t\t\t\t// 3. And it's row index is after previous cell height.\n\t\t\t\t\tconst isInEvenlySplitRow = ( row + splitCellRow + updatedSpan ) % newCellsSpan === 0;\n\n\t\t\t\t\tif ( isAfterSplitCell && isOnSameColumn && isInEvenlySplitRow ) {\n\t\t\t\t\t\tcreateCells( 1, writer, tableSlot.getPositionBefore(), newCellsAttributes );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Second check - the cell has rowspan of 1 or we need to create more cells than the current cell spans over.\n\t\t\tif ( rowspan < numberOfCells ) {\n\t\t\t\t// We already split the cell in check one so here we split to the remaining number of cells only.\n\t\t\t\tconst cellsToInsert = numberOfCells - rowspan;\n\n\t\t\t\t// This check is needed since we need to check if there are any cells from previous rows than spans over this cell's row.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, { startRow: 0, endRow: splitCellRow } ) ];\n\n\t\t\t\t// First step: expand cells.\n\t\t\t\tfor ( const { cell, cellHeight, row } of tableMap ) {\n\t\t\t\t\t// Expand rowspan of cells that are either:\n\t\t\t\t\t// - on the same row as current cell,\n\t\t\t\t\t// - or are below split cell row and overlaps that row.\n\t\t\t\t\tif ( cell !== tableCell && row + cellHeight > splitCellRow ) {\n\t\t\t\t\t\tconst rowspanToSet = cellHeight + cellsToInsert;\n\n\t\t\t\t\t\twriter.setAttribute( 'rowspan', rowspanToSet, cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Second step: create rows with single cell below split cell.\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tcreateEmptyRows( writer, table, splitCellRow + 1, cellsToInsert, 1, newCellsAttributes );\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t\tif ( headingRows > splitCellRow ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the number of columns for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getColumns( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetColumns( table ) {\n\t\t// Analyze first row only as all the rows should have the same width.\n\t\tconst row = table.getChild( 0 );\n\n\t\treturn [ ...row.getChildren() ].reduce( ( columns, row ) => {\n\t\t\tconst columnWidth = parseInt( row.getAttribute( 'colspan' ) || 1 );\n\n\t\t\treturn columns + columnWidth;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * Returns the number of rows for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getRows( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetRows( table ) {\n\t\t// Simple row counting, not including rowspan due to #6427.\n\t\treturn table.childCount;\n\t}\n}\n\n// Creates empty rows at the given index in an existing table.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/element~Element} table\n// @param {Number} insertAt The row index of row insertion.\n// @param {Number} rows The number of rows to create.\n// @param {Number} tableCellToInsert The number of cells to insert in each row.\nfunction createEmptyRows( writer, table, insertAt, rows, tableCellToInsert, attributes = {} ) {\n\tfor ( let i = 0; i < rows; i++ ) {\n\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\twriter.insert( tableRow, table, insertAt );\n\n\t\tcreateCells( tableCellToInsert, writer, writer.createPositionAt( tableRow, 'end' ), attributes );\n\t}\n}\n\n// Creates cells at a given position.\n//\n// @param {Number} columns The number of columns to create\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/position~Position} insertPosition\nfunction createCells( cells, writer, insertPosition, attributes = {} ) {\n\tfor ( let i = 0; i < cells; i++ ) {\n\t\tcreateEmptyTableCell( writer, insertPosition, attributes );\n\t}\n}\n\n// Evenly distributes the span of a cell to a number of provided cells.\n// The resulting spans will always be integer values.\n//\n// For instance breaking a span of 7 into 3 cells will return:\n//\n//\t\t{ newCellsSpan: 2, updatedSpan: 3 }\n//\n// as two cells will have a span of 2 and the remainder will go the first cell so its span will change to 3.\n//\n// @param {Number} span The span value do break.\n// @param {Number} numberOfCells The number of resulting spans.\n// @returns {{newCellsSpan: Number, updatedSpan: Number}}\nfunction breakSpanEvenly( span, numberOfCells ) {\n\tif ( span < numberOfCells ) {\n\t\treturn { newCellsSpan: 1, updatedSpan: 1 };\n\t}\n\n\tconst newCellsSpan = Math.floor( span / numberOfCells );\n\tconst updatedSpan = ( span - newCellsSpan * numberOfCells ) + newCellsSpan;\n\n\treturn { newCellsSpan, updatedSpan };\n}\n\n// Updates heading columns attribute if removing a row from head section.\nfunction adjustHeadingColumns( table, removedColumnIndexes, writer ) {\n\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\tif ( headingColumns && removedColumnIndexes.first < headingColumns ) {\n\t\tconst headingsRemoved = Math.min( headingColumns - 1 /* Other numbers are 0-based */, removedColumnIndexes.last ) -\n\t\t\tremovedColumnIndexes.first + 1;\n\n\t\twriter.setAttribute( 'headingColumns', headingColumns - headingsRemoved, table );\n\t}\n}\n\n// Calculates a new heading rows value for removing rows from heading section.\nfunction updateHeadingRows( table, first, last, writer ) {\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tif ( first < headingRows ) {\n\t\tconst newRows = last < headingRows ? headingRows - ( last - first + 1 ) : first;\n\n\t\tupdateNumericAttribute( 'headingRows', newRows, table, writer, 0 );\n\t}\n}\n\n// Finds cells that will be:\n// - trimmed - Cells that are \"above\" removed rows sections and overlap the removed section - their rowspan must be trimmed.\n// - moved - Cells from removed rows section might stick out of. These cells are moved to the next row after a removed section.\n//\n// Sample table with overlapping & sticking out cells:\n//\n// +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 | 04 |\n// +----+ + + + +\n// | 10 | | | | |\n// +----+----+ + + +\n// | 20 | 21 | | | | <-- removed row\n// + + +----+ + +\n// | | | 32 | | | <-- removed row\n// +----+ + +----+ +\n// | 40 | | | 43 | |\n// +----+----+----+----+----+\n//\n// In a table above:\n// - cells to trim: '02', '03' & '04'.\n// - cells to move: '21' & '32'.\nfunction getCellsToMoveAndTrimOnRemoveRow( table, first, last ) {\n\tconst cellsToMove = new Map();\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, column, cellHeight, cell } of new TableWalker( table, { endRow: last } ) ) {\n\t\tconst lastRowOfCell = row + cellHeight - 1;\n\n\t\tconst isCellStickingOutFromRemovedRows = row >= first && row <= last && lastRowOfCell > last;\n\n\t\tif ( isCellStickingOutFromRemovedRows ) {\n\t\t\tconst rowspanInRemovedSection = last - row + 1;\n\t\t\tconst rowSpanToSet = cellHeight - rowspanInRemovedSection;\n\n\t\t\tcellsToMove.set( column, {\n\t\t\t\tcell,\n\t\t\t\trowspan: rowSpanToSet\n\t\t\t} );\n\t\t}\n\n\t\tconst isCellOverlappingRemovedRows = row < first && lastRowOfCell >= first;\n\n\t\tif ( isCellOverlappingRemovedRows ) {\n\t\t\tlet rowspanAdjustment;\n\n\t\t\t// Cell fully covers removed section - trim it by removed rows count.\n\t\t\tif ( lastRowOfCell >= last ) {\n\t\t\t\trowspanAdjustment = last - first + 1;\n\t\t\t}\n\t\t\t// Cell partially overlaps removed section - calculate cell's span that is in removed section.\n\t\t\telse {\n\t\t\t\trowspanAdjustment = lastRowOfCell - first + 1;\n\t\t\t}\n\n\t\t\tcellsToTrim.push( {\n\t\t\t\tcell,\n\t\t\t\trowspan: cellHeight - rowspanAdjustment\n\t\t\t} );\n\t\t}\n\t}\n\treturn { cellsToMove, cellsToTrim };\n}\n\nfunction moveCellsToRow( table, targetRowIndex, cellsToMove, writer ) {\n\tconst tableWalker = new TableWalker( table, {\n\t\tincludeAllSlots: true,\n\t\trow: targetRowIndex\n\t} );\n\n\tconst tableRowMap = [ ...tableWalker ];\n\tconst row = table.getChild( targetRowIndex );\n\n\tlet previousCell;\n\n\tfor ( const { column, cell, isAnchor } of tableRowMap ) {\n\t\tif ( cellsToMove.has( column ) ) {\n\t\t\tconst { cell: cellToMove, rowspan } = cellsToMove.get( column );\n\n\t\t\tconst targetPosition = previousCell ?\n\t\t\t\twriter.createPositionAfter( previousCell ) :\n\t\t\t\twriter.createPositionAt( row, 0 );\n\n\t\t\twriter.move( writer.createRangeOn( cellToMove ), targetPosition );\n\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cellToMove, writer );\n\n\t\t\tpreviousCell = cellToMove;\n\t\t} else if ( isAnchor ) {\n\t\t\t// If cell is spanned then `cell` holds reference to overlapping cell. See ckeditor/ckeditor5#6502.\n\t\t\tpreviousCell = cell;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablewalker\n */\n\n// @if CK_DEBUG // import { CKEditorError } from 'ckeditor5/src/utils';\n\n/**\n * The table iterator class. It allows to iterate over table cells. For each cell the iterator yields\n * {@link module:table/tablewalker~TableSlot} with proper table cell attributes.\n */\nexport default class TableWalker {\n\t/**\n\t * Creates an instance of the table walker.\n\t *\n\t * The table walker iterates internally by traversing the table from row index = 0 and column index = 0.\n\t * It walks row by row and column by column in order to output values defined in the constructor.\n\t * By default it will output only the locations that are occupied by a cell. To include also spanned rows and columns,\n\t * pass the `includeAllSlots` option to the constructor.\n\t *\n\t * The most important values of the iterator are column and row indexes of a cell.\n\t *\n\t * See {@link module:table/tablewalker~TableSlot} what values are returned by the table walker.\n\t *\n\t * To iterate over a given row:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { startRow: 1, endRow: 2 } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'A cell at row', tableSlot.row, 'and column', tableSlot.column );\n\t *\t\t}\n\t *\n\t * For instance the code above for the following table:\n\t *\n\t *\t\t+----+----+----+----+----+----+\n\t *\t\t| 00 | 02 | 03 | 04 | 05 |\n\t *\t\t| +----+----+----+----+\n\t *\t\t| | 12 | 14 | 15 |\n\t *\t\t| +----+----+----+ +\n\t *\t\t| | 22 | |\n\t *\t\t|----+----+----+----+----+ +\n\t *\t\t| 30 | 31 | 32 | 33 | 34 | |\n\t *\t\t+----+----+----+----+----+----+\n\t *\n\t * will log in the console:\n\t *\n\t *\t\t'A cell at row 1 and column 2'\n\t *\t\t'A cell at row 1 and column 4'\n\t *\t\t'A cell at row 1 and column 5'\n\t *\t\t'A cell at row 2 and column 2'\n\t *\n\t * To also iterate over spanned cells:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { row: 1, includeAllSlots: true } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'Slot at', tableSlot.row, 'x', tableSlot.column, ':', tableSlot.isAnchor ? 'is anchored' : 'is spanned' );\n\t *\t\t}\n\t *\n\t * will log in the console for the table from the previous example:\n\t *\n\t *\t\t'Cell at 1 x 0 : is spanned'\n\t *\t\t'Cell at 1 x 1 : is spanned'\n\t *\t\t'Cell at 1 x 2 : is anchored'\n\t *\t\t'Cell at 1 x 3 : is spanned'\n\t *\t\t'Cell at 1 x 4 : is anchored'\n\t *\t\t'Cell at 1 x 5 : is anchored'\n\t *\n\t * **Note**: Option `row` is a shortcut that sets both `startRow` and `endRow` to the same row.\n\t * (Use either `row` or `startRow` and `endRow` but never together). Similarly the `column` option sets both `startColumn`\n\t * and `endColumn` to the same column (Use either `column` or `startColumn` and `endColumn` but never together).\n\t *\n\t * @constructor\n\t * @param {module:engine/model/element~Element} table A table over which the walker iterates.\n\t * @param {Object} [options={}] An object with configuration.\n\t * @param {Number} [options.row] A row index for which this iterator will output cells.\n\t * Can't be used together with `startRow` and `endRow`.\n\t * @param {Number} [options.startRow=0] A row index from which this iterator should start. Can't be used together with `row`.\n\t * @param {Number} [options.endRow] A row index at which this iterator should end. Can't be used together with `row`.\n\t * @param {Number} [options.column] A column index for which this iterator will output cells.\n\t * Can't be used together with `startColumn` and `endColumn`.\n\t * @param {Number} [options.startColumn=0] A column index from which this iterator should start. Can't be used together with `column`.\n\t * @param {Number} [options.endColumn] A column index at which this iterator should end. Can't be used together with `column`.\n\t * @param {Boolean} [options.includeAllSlots=false] Also return values for spanned cells.\n\t */\n\tconstructor( table, options = {} ) {\n\t\t/**\n\t\t * The walker's table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @protected\n\t\t */\n\t\tthis._table = table;\n\n\t\t/**\n\t\t * A row index from which this iterator will start.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startRow = options.row !== undefined ? options.row : options.startRow || 0;\n\n\t\t/**\n\t\t * A row index at which this iterator will end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endRow = options.row !== undefined ? options.row : options.endRow;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells from a given column and following ones or cells that overlap them.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startColumn = options.column !== undefined ? options.column : options.startColumn || 0;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells up to a given column.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endColumn = options.column !== undefined ? options.column : options.endColumn;\n\n\t\t/**\n\t\t * Enables output of spanned cells that are normally not yielded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t * @private\n\t\t */\n\t\tthis._includeAllSlots = !!options.includeAllSlots;\n\n\t\t/**\n\t\t * Row indexes to skip from the iteration.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set}\n\t\t * @private\n\t\t */\n\t\tthis._skipRows = new Set();\n\n\t\t/**\n\t\t * The current row index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._row = 0;\n\n\t\t/**\n\t\t * The current column index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._column = 0;\n\n\t\t/**\n\t\t * The cell index in a parent row. For spanned cells when {@link #_includeAllSlots} is set to `true`,\n\t\t * this represents the index of the next table cell.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._cellIndex = 0;\n\n\t\t/**\n\t\t * Holds a map of spanned cells in a table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map.>}\n\t\t * @private\n\t\t */\n\t\tthis._spannedCells = new Map();\n\n\t\t/**\n\t\t * Index of the next column where a cell is anchored.\n\t\t *\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._nextCellAtColumn = -1;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the next table walker's value.\n\t *\n\t * @returns {module:table/tablewalker~TableSlot} The next table walker's value.\n\t */\n\tnext() {\n\t\tconst row = this._table.getChild( this._row );\n\n\t\t// Iterator is done when there's no row (table ended) or the row is after `endRow` limit.\n\t\tif ( !row || this._isOverEndRow() ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\tif ( this._isOverEndColumn() ) {\n\t\t\treturn this._advanceToNextRow();\n\t\t}\n\n\t\tlet outValue = null;\n\n\t\tconst spanData = this._getSpanned();\n\n\t\tif ( spanData ) {\n\t\t\tif ( this._includeAllSlots && !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( spanData.cell, spanData.row, spanData.column );\n\t\t\t}\n\t\t} else {\n\t\t\tconst cell = row.getChild( this._cellIndex );\n\n\t\t\tif ( !cell ) {\n\t\t\t\t// If there are no more cells left in row advance to the next row.\n\t\t\t\treturn this._advanceToNextRow();\n\t\t\t}\n\n\t\t\tconst colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );\n\t\t\tconst rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );\n\n\t\t\t// Record this cell spans if it's not 1x1 cell.\n\t\t\tif ( colspan > 1 || rowspan > 1 ) {\n\t\t\t\tthis._recordSpans( cell, rowspan, colspan );\n\t\t\t}\n\n\t\t\tif ( !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( cell );\n\t\t\t}\n\n\t\t\tthis._nextCellAtColumn = this._column + colspan;\n\t\t}\n\n\t\t// Advance to the next column before returning value.\n\t\tthis._column++;\n\n\t\tif ( this._column == this._nextCellAtColumn ) {\n\t\t\tthis._cellIndex++;\n\t\t}\n\n\t\t// The current value will be returned only if current row and column are not skipped.\n\t\treturn outValue || this.next();\n\t}\n\n\t/**\n\t * Marks a row to skip in the next iteration. It will also skip cells from the current row if there are any cells from the current row\n\t * to output.\n\t *\n\t * @param {Number} row The row index to skip.\n\t */\n\tskipRow( row ) {\n\t\tthis._skipRows.add( row );\n\t}\n\n\t/**\n\t * Advances internal cursor to the next row.\n\t *\n\t * @private\n\t * @returns {module:table/tablewalker~TableSlot}\n\t */\n\t_advanceToNextRow() {\n\t\tthis._row++;\n\t\tthis._column = 0;\n\t\tthis._cellIndex = 0;\n\t\tthis._nextCellAtColumn = -1;\n\n\t\treturn this.next();\n\t}\n\n\t/**\n\t * Checks if the current row is over {@link #_endRow}.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndRow() {\n\t\t// If #_endRow is defined skip all rows after it.\n\t\treturn this._endRow !== undefined && this._row > this._endRow;\n\t}\n\n\t/**\n\t * Checks if the current cell is over {@link #_endColumn}\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndColumn() {\n\t\t// If #_endColumn is defined skip all cells after it.\n\t\treturn this._endColumn !== undefined && this._column > this._endColumn;\n\t}\n\n\t/**\n\t * A common method for formatting the iterator's output value.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell The table cell to output.\n\t * @param {Number} [anchorRow] The row index of a cell anchor slot.\n\t * @param {Number} [anchorColumn] The column index of a cell anchor slot.\n\t * @returns {{done: Boolean, value: {cell: *, row: Number, column: *, rowspan: *, colspan: *, cellIndex: Number}}}\n\t */\n\t_formatOutValue( cell, anchorRow = this._row, anchorColumn = this._column ) {\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: new TableSlot( this, cell, anchorRow, anchorColumn )\n\t\t};\n\t}\n\n\t/**\n\t * Checks if the current slot should be skipped.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_shouldSkipSlot() {\n\t\tconst rowIsMarkedAsSkipped = this._skipRows.has( this._row );\n\t\tconst rowIsBeforeStartRow = this._row < this._startRow;\n\n\t\tconst columnIsBeforeStartColumn = this._column < this._startColumn;\n\t\tconst columnIsAfterEndColumn = this._endColumn !== undefined && this._column > this._endColumn;\n\n\t\treturn rowIsMarkedAsSkipped || rowIsBeforeStartRow || columnIsBeforeStartColumn || columnIsAfterEndColumn;\n\t}\n\n\t/**\n\t * Returns the cell element that is spanned over the current cell location.\n\t *\n\t * @private\n\t * @returns {module:engine/model/element~Element}\n\t */\n\t_getSpanned() {\n\t\tconst rowMap = this._spannedCells.get( this._row );\n\n\t\t// No spans for given row.\n\t\tif ( !rowMap ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If spans for given rows has entry for column it means that this location if spanned by other cell.\n\t\treturn rowMap.get( this._column ) || null;\n\t}\n\n\t/**\n\t * Updates spanned cells map relative to the current cell location and its span dimensions.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell A cell that is spanned.\n\t * @param {Number} rowspan Cell height.\n\t * @param {Number} colspan Cell width.\n\t */\n\t_recordSpans( cell, rowspan, colspan ) {\n\t\tconst data = {\n\t\t\tcell,\n\t\t\trow: this._row,\n\t\t\tcolumn: this._column\n\t\t};\n\n\t\tfor ( let rowToUpdate = this._row; rowToUpdate < this._row + rowspan; rowToUpdate++ ) {\n\t\t\tfor ( let columnToUpdate = this._column; columnToUpdate < this._column + colspan; columnToUpdate++ ) {\n\t\t\t\tif ( rowToUpdate != this._row || columnToUpdate != this._column ) {\n\t\t\t\t\tthis._markSpannedCell( rowToUpdate, columnToUpdate, data );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks the cell location as spanned by another cell.\n\t *\n\t * @private\n\t * @param {Number} row The row index of the cell location.\n\t * @param {Number} column The column index of the cell location.\n\t * @param {Object} data A spanned cell details (cell element, anchor row and column).\n\t */\n\t_markSpannedCell( row, column, data ) {\n\t\tif ( !this._spannedCells.has( row ) ) {\n\t\t\tthis._spannedCells.set( row, new Map() );\n\t\t}\n\n\t\tconst rowSpans = this._spannedCells.get( row );\n\n\t\trowSpans.set( column, data );\n\t}\n}\n\n/**\n * An object returned by {@link module:table/tablewalker~TableWalker} when traversing table cells.\n */\nclass TableSlot {\n\t/**\n\t * Creates an instance of the table walker value.\n\t *\n\t * @protected\n\t * @param {module:table/tablewalker~TableWalker} tableWalker The table walker instance.\n\t * @param {module:engine/model/element~Element} cell The current table cell.\n\t * @param {Number} anchorRow The row index of a cell anchor slot.\n\t * @param {Number} anchorColumn The column index of a cell anchor slot.\n\t */\n\tconstructor( tableWalker, cell, anchorRow, anchorColumn ) {\n\t\t/**\n\t\t * The current table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t */\n\t\tthis.cell = cell;\n\n\t\t/**\n\t\t * The row index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.row = tableWalker._row;\n\n\t\t/**\n\t\t * The column index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.column = tableWalker._column;\n\n\t\t/**\n\t\t * The row index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorRow = anchorRow;\n\n\t\t/**\n\t\t * The column index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorColumn = anchorColumn;\n\n\t\t/**\n\t\t * The index of the current cell in the parent row.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._cellIndex = tableWalker._cellIndex;\n\n\t\t/**\n\t\t * The table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @private\n\t\t */\n\t\tthis._table = tableWalker._table;\n\t}\n\n\t/**\n\t * Whether the cell is anchored in the current slot.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isAnchor() {\n\t\treturn this.row === this.cellAnchorRow && this.column === this.cellAnchorColumn;\n\t}\n\n\t/**\n\t * The width of a cell defined by a `colspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellWidth() {\n\t\treturn parseInt( this.cell.getAttribute( 'colspan' ) || 1 );\n\t}\n\n\t/**\n\t * The height of a cell defined by a `rowspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellHeight() {\n\t\treturn parseInt( this.cell.getAttribute( 'rowspan' ) || 1 );\n\t}\n\n\t/**\n\t * Returns the {@link module:engine/model/position~Position} before the table slot.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetPositionBefore() {\n\t\tconst model = this._table.root.document.model;\n\n\t\treturn model.createPositionAt( this._table.getChild( this.row ), this._cellIndex );\n\t}\n\n\t// @if CK_DEBUG // get isSpanned() { throwMissingGetterError( 'isSpanned' ); }\n\t// @if CK_DEBUG // get colspan() { throwMissingGetterError( 'colspan' ); }\n\t// @if CK_DEBUG // get rowspan() { throwMissingGetterError( 'rowspan' ); }\n\t// @if CK_DEBUG // get cellIndex() { throwMissingGetterError( 'cellIndex' ); }\n}\n\n/**\n * This `TableSlot`'s getter (property) was removed in CKEditor 5 v20.0.0.\n *\n * Check out the new `TableWalker`'s API in the documentation.\n *\n * @error tableslot-getter-removed\n * @param {String} getterName\n */\n\n// @if CK_DEBUG // function throwMissingGetterError( getterName ) {\n// @if CK_DEBUG //\t\tthrow new CKEditorError( 'tableslot-getter-removed', this, {\n// @if CK_DEBUG //\t\t\tgetterName\n// @if CK_DEBUG //\t\t} );\n// @if CK_DEBUG // }\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport upcastTable, { ensureParagraphInTableCell, skipEmptyTableRow } from './converters/upcasttable';\nimport {\n\tconvertParagraphInTableCell,\n\tdowncastInsertCell,\n\tdowncastInsertRow,\n\tdowncastInsertTable,\n\tdowncastRemoveRow,\n\tdowncastTableHeadingColumnsChange\n} from './converters/downcast';\n\nimport InsertTableCommand from './commands/inserttablecommand';\nimport InsertRowCommand from './commands/insertrowcommand';\nimport InsertColumnCommand from './commands/insertcolumncommand';\nimport SplitCellCommand from './commands/splitcellcommand';\nimport MergeCellCommand from './commands/mergecellcommand';\nimport RemoveRowCommand from './commands/removerowcommand';\nimport RemoveColumnCommand from './commands/removecolumncommand';\nimport SetHeaderRowCommand from './commands/setheaderrowcommand';\nimport SetHeaderColumnCommand from './commands/setheadercolumncommand';\nimport MergeCellsCommand from './commands/mergecellscommand';\nimport SelectRowCommand from './commands/selectrowcommand';\nimport SelectColumnCommand from './commands/selectcolumncommand';\nimport TableUtils from '../src/tableutils';\n\nimport injectTableLayoutPostFixer from './converters/table-layout-post-fixer';\nimport injectTableCellParagraphPostFixer from './converters/table-cell-paragraph-post-fixer';\nimport injectTableCellRefreshPostFixer from './converters/table-cell-refresh-post-fixer';\nimport injectTableHeadingRowsRefreshPostFixer from './converters/table-heading-rows-refresh-post-fixer';\n\nimport '../theme/tableediting.css';\n\n/**\n * The table editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\tschema.register( 'table', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'headingRows', 'headingColumns' ],\n\t\t\tisObject: true,\n\t\t\tisBlock: true\n\t\t} );\n\n\t\tschema.register( 'tableRow', {\n\t\t\tallowIn: 'table',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\tschema.register( 'tableCell', {\n\t\t\tallowIn: 'tableRow',\n\t\t\tallowAttributes: [ 'colspan', 'rowspan' ],\n\t\t\tisLimit: true,\n\t\t\tisSelectable: true\n\t\t} );\n\n\t\t// Allow all $block content inside a table cell.\n\t\tschema.extend( '$block', { allowIn: 'tableCell' } );\n\n\t\t// Disallow a table in a table.\n\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name == 'table' && Array.from( context.getNames() ).includes( 'table' ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\t// Table conversion.\n\t\tconversion.for( 'upcast' ).add( upcastTable() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertTable( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertTable() );\n\n\t\t// Table row conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableRow', view: 'tr' } );\n\t\tconversion.for( 'upcast' ).add( skipEmptyTableRow() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertRow() );\n\t\tconversion.for( 'editingDowncast' ).add( downcastRemoveRow() );\n\n\t\t// Table cell conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'td' } );\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'th' } );\n\t\tconversion.for( 'upcast' ).add( ensureParagraphInTableCell( 'td' ) );\n\t\tconversion.for( 'upcast' ).add( ensureParagraphInTableCell( 'th' ) );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertCell() );\n\n\t\t// Duplicates code - needed to properly refresh paragraph inside a table cell.\n\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'paragraph',\n\t\t\tview: convertParagraphInTableCell,\n\t\t\tconverterPriority: 'high'\n\t\t} );\n\n\t\t// Table attributes conversion.\n\t\tconversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );\n\t\tconversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );\n\n\t\t// Table heading columns conversion (a change of heading rows requires a reconversion of the whole table).\n\t\tconversion.for( 'editingDowncast' ).add( downcastTableHeadingColumnsChange() );\n\n\t\t// Define all the commands.\n\t\teditor.commands.add( 'insertTable', new InsertTableCommand( editor ) );\n\t\teditor.commands.add( 'insertTableRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );\n\t\teditor.commands.add( 'insertTableRowBelow', new InsertRowCommand( editor, { order: 'below' } ) );\n\t\teditor.commands.add( 'insertTableColumnLeft', new InsertColumnCommand( editor, { order: 'left' } ) );\n\t\teditor.commands.add( 'insertTableColumnRight', new InsertColumnCommand( editor, { order: 'right' } ) );\n\n\t\teditor.commands.add( 'removeTableRow', new RemoveRowCommand( editor ) );\n\t\teditor.commands.add( 'removeTableColumn', new RemoveColumnCommand( editor ) );\n\n\t\teditor.commands.add( 'splitTableCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );\n\t\teditor.commands.add( 'splitTableCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );\n\n\t\teditor.commands.add( 'mergeTableCells', new MergeCellsCommand( editor ) );\n\n\t\teditor.commands.add( 'mergeTableCellRight', new MergeCellCommand( editor, { direction: 'right' } ) );\n\t\teditor.commands.add( 'mergeTableCellLeft', new MergeCellCommand( editor, { direction: 'left' } ) );\n\t\teditor.commands.add( 'mergeTableCellDown', new MergeCellCommand( editor, { direction: 'down' } ) );\n\t\teditor.commands.add( 'mergeTableCellUp', new MergeCellCommand( editor, { direction: 'up' } ) );\n\n\t\teditor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );\n\t\teditor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );\n\n\t\teditor.commands.add( 'selectTableRow', new SelectRowCommand( editor ) );\n\t\teditor.commands.add( 'selectTableColumn', new SelectColumnCommand( editor ) );\n\n\t\tinjectTableHeadingRowsRefreshPostFixer( model );\n\t\tinjectTableLayoutPostFixer( model );\n\t\tinjectTableCellRefreshPostFixer( model, editor.editing.mapper );\n\t\tinjectTableCellParagraphPostFixer( model );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addListToDropdown, createDropdown, Model, SplitButtonView } from 'ckeditor5/src/ui';\nimport { Collection } from 'ckeditor5/src/utils';\n\nimport InsertTableView from './ui/inserttableview';\n\nimport tableIcon from './../theme/icons/table.svg';\nimport tableColumnIcon from './../theme/icons/table-column.svg';\nimport tableRowIcon from './../theme/icons/table-row.svg';\nimport tableMergeCellIcon from './../theme/icons/table-merge-cell.svg';\n\n/**\n * The table UI plugin. It introduces:\n *\n * * The `'insertTable'` dropdown,\n * * The `'tableColumn'` dropdown,\n * * The `'tableRow'` dropdown,\n * * The `'mergeTableCells'` split button.\n *\n * The `'tableColumn'`, `'tableRow'` and `'mergeTableCells'` dropdowns work best with {@link module:table/tabletoolbar~TableToolbar}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = this.editor.t;\n\t\tconst contentLanguageDirection = editor.locale.contentLanguageDirection;\n\t\tconst isContentLtr = contentLanguageDirection === 'ltr';\n\n\t\teditor.ui.componentFactory.add( 'insertTable', locale => {\n\t\t\tconst command = editor.commands.get( 'insertTable' );\n\t\t\tconst dropdownView = createDropdown( locale );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\t// Decorate dropdown's button.\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\ticon: tableIcon,\n\t\t\t\tlabel: t( 'Insert table' ),\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tlet insertTableView;\n\n\t\t\tdropdownView.on( 'change:isOpen', () => {\n\t\t\t\tif ( insertTableView ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Prepare custom view for dropdown's panel.\n\t\t\t\tinsertTableView = new InsertTableView( locale );\n\t\t\t\tdropdownView.panelView.children.add( insertTableView );\n\n\t\t\t\tinsertTableView.delegate( 'execute' ).to( dropdownView );\n\n\t\t\t\tdropdownView.buttonView.on( 'open', () => {\n\t\t\t\t\t// Reset the chooser before showing it to the user.\n\t\t\t\t\tinsertTableView.rows = 0;\n\t\t\t\t\tinsertTableView.columns = 0;\n\t\t\t\t} );\n\n\t\t\t\tdropdownView.on( 'execute', () => {\n\t\t\t\t\teditor.execute( 'insertTable', { rows: insertTableView.rows, columns: insertTableView.columns } );\n\t\t\t\t\teditor.editing.view.focus();\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableColumn', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableColumnHeader',\n\t\t\t\t\t\tlabel: t( 'Header column' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',\n\t\t\t\t\t\tlabel: t( 'Insert column left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',\n\t\t\t\t\t\tlabel: t( 'Insert column right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableColumn',\n\t\t\t\t\t\tlabel: t( 'Delete column' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableColumn',\n\t\t\t\t\t\tlabel: t( 'Select column' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Column' ), tableColumnIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableRow', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableRowHeader',\n\t\t\t\t\t\tlabel: t( 'Header row' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowAbove',\n\t\t\t\t\t\tlabel: t( 'Insert row above' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowBelow',\n\t\t\t\t\t\tlabel: t( 'Insert row below' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableRow',\n\t\t\t\t\t\tlabel: t( 'Delete row' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableRow',\n\t\t\t\t\t\tlabel: t( 'Select row' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Row' ), tableRowIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'mergeTableCells', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellUp',\n\t\t\t\t\t\tlabel: t( 'Merge cell up' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',\n\t\t\t\t\t\tlabel: t( 'Merge cell right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellDown',\n\t\t\t\t\t\tlabel: t( 'Merge cell down' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',\n\t\t\t\t\t\tlabel: t( 'Merge cell left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellVertically',\n\t\t\t\t\t\tlabel: t( 'Split cell vertically' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellHorizontally',\n\t\t\t\t\t\tlabel: t( 'Split cell horizontally' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareMergeSplitButtonDropdown( t( 'Merge cells' ), tableMergeCellIcon, options, locale );\n\t\t} );\n\t}\n\n\t/**\n\t * Creates a dropdown view from a set of options.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale );\n\t\tconst commands = this._fillDropdownWithListOptions( dropdownView, options );\n\n\t\t// Decorate dropdown's button.\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\t// Make dropdown button disabled when all options are disabled.\n\t\tdropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {\n\t\t\treturn areEnabled.some( isEnabled => isEnabled );\n\t\t} );\n\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Creates a dropdown view with a {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} for\n\t * merge (and split)–related commands.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareMergeSplitButtonDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale, SplitButtonView );\n\t\tconst mergeCommandName = 'mergeTableCells';\n\n\t\tthis._fillDropdownWithListOptions( dropdownView, options );\n\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisEnabled: true\n\t\t} );\n\n\t\t// Merge selected table cells when the main part of the split button is clicked.\n\t\tthis.listenTo( dropdownView.buttonView, 'execute', () => {\n\t\t\teditor.execute( mergeCommandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\t// Execute commands for events coming from the list in the dropdown panel.\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Injects a {@link module:ui/list/listview~ListView} into the passed dropdown with buttons\n\t * which execute editor commands as configured in passed options.\n\t *\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\n\t * @param {Array.} options The list of options for the dropdown.\n\t * @returns {Array.} Commands the list options are interacting with.\n\t */\n\t_fillDropdownWithListOptions( dropdownView, options ) {\n\t\tconst editor = this.editor;\n\t\tconst commands = [];\n\t\tconst itemDefinitions = new Collection();\n\n\t\tfor ( const option of options ) {\n\t\t\taddListOption( option, editor, commands, itemDefinitions );\n\t\t}\n\n\t\taddListToDropdown( dropdownView, itemDefinitions, editor.ui.componentFactory );\n\n\t\treturn commands;\n\t}\n}\n\n// Adds an option to a list view.\n//\n// @param {module:table/tableui~DropdownOption} option A configuration option.\n// @param {module:core/editor/editor~Editor} editor\n// @param {Array.} commands The list of commands to update.\n// @param {Iterable.} itemDefinitions\n// A collection of dropdown items to update with the given option.\nfunction addListOption( option, editor, commands, itemDefinitions ) {\n\tconst model = option.model = new Model( option.model );\n\tconst { commandName, bindIsOn } = option.model;\n\n\tif ( option.type === 'button' || option.type === 'switchbutton' ) {\n\t\tconst command = editor.commands.get( commandName );\n\n\t\tcommands.push( command );\n\n\t\tmodel.set( { commandName } );\n\n\t\tmodel.bind( 'isEnabled' ).to( command );\n\n\t\tif ( bindIsOn ) {\n\t\t\tmodel.bind( 'isOn' ).to( command, 'value' );\n\t\t}\n\t}\n\n\tmodel.set( {\n\t\twithText: true\n\t} );\n\n\titemDefinitions.add( option );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableselection\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\n\nimport { cropTableToDimensions, adjustLastRowIndex, adjustLastColumnIndex } from './utils/structure';\nimport { getColumnIndexes, getRowIndexes, getSelectedTableCells, isSelectionRectangular } from './utils/selection';\n\nimport '../theme/tableselection.css';\n\n/**\n * This plugin enables the advanced table cells, rows and columns selection.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableSelection extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableSelection';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tthis.listenTo( model, 'deleteContent', ( evt, args ) => this._handleDeleteContent( evt, args ), { priority: 'high' } );\n\n\t\tthis._defineSelectionConverter();\n\t\tthis._enablePluginDisabling(); // sic!\n\t}\n\n\t/**\n\t * Returns the currently selected table cells or `null` if it is not a table cells selection.\n\t *\n\t * @returns {Array.|null}\n\t */\n\tgetSelectedTableCells() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length == 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// This should never happen, but let's know if it ever happens.\n\t\t// @if CK_DEBUG //\t/* istanbul ignore next */\n\t\t// @if CK_DEBUG //\tif ( selectedCells.length != selection.rangeCount ) {\n\t\t// @if CK_DEBUG //\t\tconsole.warn( 'Mixed selection warning. The selection contains table cells and some other ranges.' );\n\t\t// @if CK_DEBUG //\t}\n\n\t\treturn selectedCells;\n\t}\n\n\t/**\n\t * Returns the selected table fragment as a document fragment.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetSelectionAsFragment() {\n\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\tif ( !selectedCells ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.editor.model.change( writer => {\n\t\t\tconst documentFragment = writer.createDocumentFragment();\n\t\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t\tconst { first: firstColumn, last: lastColumn } = getColumnIndexes( selectedCells );\n\t\t\tconst { first: firstRow, last: lastRow } = getRowIndexes( selectedCells );\n\n\t\t\tconst sourceTable = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tlet adjustedLastRow = lastRow;\n\t\t\tlet adjustedLastColumn = lastColumn;\n\n\t\t\t// If the selection is rectangular there could be a case of all cells in the last row/column spanned over\n\t\t\t// next row/column so the real lastRow/lastColumn should be updated.\n\t\t\tif ( isSelectionRectangular( selectedCells, tableUtils ) ) {\n\t\t\t\tconst dimensions = {\n\t\t\t\t\tfirstColumn,\n\t\t\t\t\tlastColumn,\n\t\t\t\t\tfirstRow,\n\t\t\t\t\tlastRow\n\t\t\t\t};\n\n\t\t\t\tadjustedLastRow = adjustLastRowIndex( sourceTable, dimensions );\n\t\t\t\tadjustedLastColumn = adjustLastColumnIndex( sourceTable, dimensions );\n\t\t\t}\n\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: firstRow,\n\t\t\t\tstartColumn: firstColumn,\n\t\t\t\tendRow: adjustedLastRow,\n\t\t\t\tendColumn: adjustedLastColumn\n\t\t\t};\n\n\t\t\tconst table = cropTableToDimensions( sourceTable, cropDimensions, writer );\n\n\t\t\twriter.insert( table, documentFragment, 0 );\n\n\t\t\treturn documentFragment;\n\t\t} );\n\t}\n\n\t/**\n\t * Sets the model selection based on given anchor and target cells (can be the same cell).\n\t * Takes care of setting the backward flag.\n\t *\n\t *\t\tconst modelRoot = editor.model.document.getRoot();\n\t *\t\tconst firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );\n\t *\t\tconst lastCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );\n\t *\n\t *\t\tconst tableSelection = editor.plugins.get( 'TableSelection' );\n\t *\t\ttableSelection.setCellSelection( firstCell, lastCell );\n\t *\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t */\n\tsetCellSelection( anchorCell, targetCell ) {\n\t\tconst cellsToSelect = this._getCellsToSelect( anchorCell, targetCell );\n\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection(\n\t\t\t\tcellsToSelect.cells.map( cell => writer.createRangeOn( cell ) ),\n\t\t\t\t{ backward: cellsToSelect.backward }\n\t\t\t);\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the focus cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element}\n\t */\n\tgetFocusCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst focusCellRange = [ ...selection.getRanges() ].pop();\n\t\tconst element = focusCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the anchor cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element} anchorCell\n\t */\n\tgetAnchorCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst anchorCellRange = first( selection.getRanges() );\n\t\tconst element = anchorCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Defines a selection converter which marks the selected cells with a specific class.\n\t *\n\t * The real DOM selection is put in the last cell. Since the order of ranges is dependent on whether the\n\t * selection is backward or not, the last cell will usually be close to the \"focus\" end of the selection\n\t * (a selection has anchor and focus).\n\t *\n\t * The real DOM selection is then hidden with CSS.\n\t *\n\t * @private\n\t */\n\t_defineSelectionConverter() {\n\t\tconst editor = this.editor;\n\t\tconst highlighted = new Set();\n\n\t\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => dispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\tclearHighlightedTableCells( viewWriter );\n\n\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\tif ( !selectedCells ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor ( const tableCell of selectedCells ) {\n\t\t\t\tconst viewElement = conversionApi.mapper.toViewElement( tableCell );\n\n\t\t\t\tviewWriter.addClass( 'ck-editor__editable_selected', viewElement );\n\t\t\t\thighlighted.add( viewElement );\n\t\t\t}\n\n\t\t\tconst lastViewCell = conversionApi.mapper.toViewElement( selectedCells[ selectedCells.length - 1 ] );\n\t\t\tviewWriter.setSelection( lastViewCell, 0 );\n\t\t}, { priority: 'lowest' } ) );\n\n\t\tfunction clearHighlightedTableCells( writer ) {\n\t\t\tfor ( const previouslyHighlighted of highlighted ) {\n\t\t\t\twriter.removeClass( 'ck-editor__editable_selected', previouslyHighlighted );\n\t\t\t}\n\n\t\t\thighlighted.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Creates a listener that reacts to changes in {@link #isEnabled} and, if the plugin was disabled,\n\t * it collapses the multi-cell selection to a regular selection placed inside a table cell.\n\t *\n\t * This listener helps features that disable the table selection plugin bring the selection\n\t * to a clear state they can work with (for instance, because they don't support multiple cell selection).\n\t */\n\t_enablePluginDisabling() {\n\t\tconst editor = this.editor;\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\t\tif ( !selectedCells ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\tconst position = writer.createPositionAt( selectedCells[ 0 ], 0 );\n\t\t\t\t\tconst range = editor.model.schema.getNearestSelectionRange( position );\n\n\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides the default `model.deleteContent()` behavior over a selected table fragment.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} event\n\t * @param {Array.<*>} args Delete content method arguments.\n\t */\n\t_handleDeleteContent( event, args ) {\n\t\tconst [ selection, options ] = args;\n\t\tconst model = this.editor.model;\n\t\tconst isBackward = !options || options.direction == 'backward';\n\t\tconst selectedTableCells = getSelectedTableCells( selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst tableCellToSelect = selectedTableCells[ isBackward ? selectedTableCells.length - 1 : 0 ];\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tfor ( const tableCell of selectedTableCells ) {\n\t\t\t\t\tmodel.deleteContent( writer.createSelection( tableCell, 'in' ) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tconst rangeToSelect = model.schema.getNearestSelectionRange( writer.createPositionAt( tableCellToSelect, 0 ) );\n\n\t\t\t// Note: we ignore the case where rangeToSelect may be null because deleteContent() will always (unless someone broke it)\n\t\t\t// create an empty paragraph to accommodate the selection.\n\n\t\t\tif ( selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( rangeToSelect );\n\t\t\t} else {\n\t\t\t\tselection.setTo( rangeToSelect );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an array of table cells that should be selected based on the\n\t * given anchor cell and target (focus) cell.\n\t *\n\t * The cells are returned in a reverse direction if the selection is backward.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t * @returns {Array.}\n\t */\n\t_getCellsToSelect( anchorCell, targetCell ) {\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst startLocation = tableUtils.getCellLocation( anchorCell );\n\t\tconst endLocation = tableUtils.getCellLocation( targetCell );\n\n\t\tconst startRow = Math.min( startLocation.row, endLocation.row );\n\t\tconst endRow = Math.max( startLocation.row, endLocation.row );\n\n\t\tconst startColumn = Math.min( startLocation.column, endLocation.column );\n\t\tconst endColumn = Math.max( startLocation.column, endLocation.column );\n\n\t\t// 2-dimensional array of the selected cells to ease flipping the order of cells for backward selections.\n\t\tconst selectionMap = new Array( endRow - startRow + 1 ).fill( null ).map( () => [] );\n\n\t\tconst walkerOptions = {\n\t\t\tstartRow,\n\t\t\tendRow,\n\t\t\tstartColumn,\n\t\t\tendColumn\n\t\t};\n\n\t\tfor ( const { row, cell } of new TableWalker( anchorCell.findAncestor( 'table' ), walkerOptions ) ) {\n\t\t\tselectionMap[ row - startRow ].push( cell );\n\t\t}\n\n\t\tconst flipVertically = endLocation.row < startLocation.row;\n\t\tconst flipHorizontally = endLocation.column < startLocation.column;\n\n\t\tif ( flipVertically ) {\n\t\t\tselectionMap.reverse();\n\t\t}\n\n\t\tif ( flipHorizontally ) {\n\t\t\tselectionMap.forEach( row => row.reverse() );\n\t\t}\n\n\t\treturn {\n\t\t\tcells: selectionMap.flat(),\n\t\t\tbackward: flipVertically || flipHorizontally\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableclipboard\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\nimport { getColumnIndexes, getRowIndexes, getSelectionAffectedTableCells, isSelectionRectangular, sortRanges } from './utils/selection';\nimport {\n\tcropTableToDimensions,\n\tgetHorizontallyOverlappingCells,\n\tgetVerticallyOverlappingCells,\n\tremoveEmptyRowsColumns,\n\tsplitHorizontally,\n\tsplitVertically,\n\ttrimTableCellIfNeeded,\n\tadjustLastRowIndex,\n\tadjustLastColumnIndex\n} from './utils/structure';\n\n/**\n * This plugin adds support for copying/cutting/pasting fragments of tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableClipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableClipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection, TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tthis.listenTo( viewDocument, 'copy', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( editor.model, 'insertContent', ( evt, args ) => this._onInsertContent( evt, ...args ), { priority: 'high' } );\n\n\t\tthis.decorate( '_replaceTableSlotCell' );\n\t}\n\n\t/**\n\t * Copies table content to a clipboard on \"copy\" & \"cut\" events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the handled event.\n\t * @param {Object} data Clipboard event data.\n\t */\n\t_onCopyCut( evt, data ) {\n\t\tconst tableSelection = this.editor.plugins.get( TableSelection );\n\n\t\tif ( !tableSelection.getSelectedTableCells() ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( evt.name == 'cut' && this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata.preventDefault();\n\t\tevt.stop();\n\n\t\tconst dataController = this.editor.data;\n\t\tconst viewDocument = this.editor.editing.view.document;\n\n\t\tconst content = dataController.toView( tableSelection.getSelectionAsFragment() );\n\n\t\tviewDocument.fire( 'clipboardOutput', {\n\t\t\tdataTransfer: data.dataTransfer,\n\t\t\tcontent,\n\t\t\tmethod: evt.name\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides default {@link module:engine/model/model~Model#insertContent `model.insertContent()`} method to handle pasting table inside\n\t * selected table fragment.\n\t *\n\t * Depending on selected table fragment:\n\t * - If a selected table fragment is smaller than paste table it will crop pasted table to match dimensions.\n\t * - If dimensions are equal it will replace selected table fragment with a pasted table contents.\n\t *\n\t * @private\n\t * @param evt\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t */\n\t_onInsertContent( evt, content, selectable ) {\n\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst tableUtils = this.editor.plugins.get( TableUtils );\n\n\t\t// We might need to crop table before inserting so reference might change.\n\t\tlet pastedTable = getTableIfOnlyTableInContent( content, model );\n\n\t\tif ( !pastedTable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedTableCells = getSelectionAffectedTableCells( model.document.selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\tremoveEmptyRowsColumns( pastedTable, tableUtils );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Override default model.insertContent() handling at this point.\n\t\tevt.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst pastedDimensions = {\n\t\t\t\twidth: tableUtils.getColumns( pastedTable ),\n\t\t\t\theight: tableUtils.getRows( pastedTable )\n\t\t\t};\n\n\t\t\t// Prepare the table for pasting.\n\t\t\tconst selection = prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils );\n\n\t\t\t// Beyond this point we operate on a fixed content table with rectangular selection and proper last row/column values.\n\n\t\t\tconst selectionHeight = selection.lastRow - selection.firstRow + 1;\n\t\t\tconst selectionWidth = selection.lastColumn - selection.firstColumn + 1;\n\n\t\t\t// Crop pasted table if:\n\t\t\t// - Pasted table dimensions exceeds selection area.\n\t\t\t// - Pasted table has broken layout (ie some cells sticks out by the table dimensions established by the first and last row).\n\t\t\t//\n\t\t\t// Note: The table dimensions are established by the width of the first row and the total number of rows.\n\t\t\t// It is possible to programmatically create a table that has rows which would have cells anchored beyond first row width but\n\t\t\t// such table will not be created by other editing solutions.\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: 0,\n\t\t\t\tstartColumn: 0,\n\t\t\t\tendRow: Math.min( selectionHeight, pastedDimensions.height ) - 1,\n\t\t\t\tendColumn: Math.min( selectionWidth, pastedDimensions.width ) - 1\n\t\t\t};\n\n\t\t\tpastedTable = cropTableToDimensions( pastedTable, cropDimensions, writer );\n\n\t\t\t// Content table to which we insert a pasted table.\n\t\t\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tconst cellsToSelect = this._replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer );\n\n\t\t\tif ( this.editor.plugins.get( 'TableSelection' ).isEnabled ) {\n\t\t\t\t// Selection ranges must be sorted because the first and last selection ranges are considered\n\t\t\t\t// as anchor/focus cell ranges for multi-cell selection.\n\t\t\t\tconst selectionRanges = sortRanges( cellsToSelect.map( cell => writer.createRangeOn( cell ) ) );\n\n\t\t\t\twriter.setSelection( selectionRanges );\n\t\t\t} else {\n\t\t\t\t// Set selection inside first cell if multi-cell selection is disabled.\n\t\t\t\twriter.setSelection( cellsToSelect[ 0 ], 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Replaces the part of selectedTable with pastedTable.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} pastedTable\n\t * @param {Object} pastedDimensions\n\t * @param {Number} pastedDimensions.height\n\t * @param {Number} pastedDimensions.width\n\t * @param {module:engine/model/element~Element} selectedTable\n\t * @param {Object} selection\n\t * @param {Number} selection.firstColumn\n\t * @param {Number} selection.firstRow\n\t * @param {Number} selection.lastColumn\n\t * @param {Number} selection.lastRow\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {Array.}\n\t */\n\t_replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer ) {\n\t\tconst { width: pastedWidth, height: pastedHeight } = pastedDimensions;\n\n\t\t// Holds two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n\t\tconst pastedTableLocationMap = createLocationMap( pastedTable, pastedWidth, pastedHeight );\n\n\t\tconst selectedTableMap = [ ...new TableWalker( selectedTable, {\n\t\t\tstartRow: selection.firstRow,\n\t\t\tendRow: selection.lastRow,\n\t\t\tstartColumn: selection.firstColumn,\n\t\t\tendColumn: selection.lastColumn,\n\t\t\tincludeAllSlots: true\n\t\t} ) ];\n\n\t\t// Selection must be set to pasted cells (some might be removed or new created).\n\t\tconst cellsToSelect = [];\n\n\t\t// Store next cell insert position.\n\t\tlet insertPosition;\n\n\t\t// Content table replace cells algorithm iterates over a selected table fragment and:\n\t\t//\n\t\t// - Removes existing table cells at current slot (location).\n\t\t// - Inserts cell from a pasted table for a matched slots.\n\t\t//\n\t\t// This ensures proper table geometry after the paste\n\t\tfor ( const tableSlot of selectedTableMap ) {\n\t\t\tconst { row, column } = tableSlot;\n\n\t\t\t// Save the insert position for current row start.\n\t\t\tif ( column === selection.firstColumn ) {\n\t\t\t\tinsertPosition = tableSlot.getPositionBefore();\n\t\t\t}\n\n\t\t\t// Map current table slot location to an pasted table slot location.\n\t\t\tconst pastedRow = row - selection.firstRow;\n\t\t\tconst pastedColumn = column - selection.firstColumn;\n\t\t\tconst pastedCell = pastedTableLocationMap[ pastedRow % pastedHeight ][ pastedColumn % pastedWidth ];\n\n\t\t\t// Clone cell to insert (to duplicate its attributes and children).\n\t\t\t// Cloning is required to support repeating pasted table content when inserting to a bigger selection.\n\t\t\tconst cellToInsert = pastedCell ? writer.cloneElement( pastedCell ) : null;\n\n\t\t\t// Replace the cell from the current slot with new table cell.\n\t\t\tconst newTableCell = this._replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer );\n\n\t\t\t// The cell was only removed.\n\t\t\tif ( !newTableCell ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Trim the cell if it's row/col-spans would exceed selection area.\n\t\t\ttrimTableCellIfNeeded( newTableCell, row, column, selection.lastRow, selection.lastColumn, writer );\n\n\t\t\tcellsToSelect.push( newTableCell );\n\n\t\t\tinsertPosition = writer.createPositionAfter( newTableCell );\n\t\t}\n\n\t\t// If there are any headings, all the cells that overlap from heading must be splitted.\n\t\tconst headingRows = parseInt( selectedTable.getAttribute( 'headingRows' ) || 0 );\n\t\tconst headingColumns = parseInt( selectedTable.getAttribute( 'headingColumns' ) || 0 );\n\n\t\tconst areHeadingRowsIntersectingSelection = selection.firstRow < headingRows && headingRows <= selection.lastRow;\n\t\tconst areHeadingColumnsIntersectingSelection = selection.firstColumn < headingColumns && headingColumns <= selection.lastColumn;\n\n\t\tif ( areHeadingRowsIntersectingSelection ) {\n\t\t\tconst columnsLimit = { first: selection.firstColumn, last: selection.lastColumn };\n\t\t\tconst newCells = doHorizontalSplit( selectedTable, headingRows, columnsLimit, writer, selection.firstRow );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\tif ( areHeadingColumnsIntersectingSelection ) {\n\t\t\tconst rowsLimit = { first: selection.firstRow, last: selection.lastRow };\n\t\t\tconst newCells = doVerticalSplit( selectedTable, headingColumns, rowsLimit, writer );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\treturn cellsToSelect;\n\t}\n\n\t/**\n\t * Replaces a single table slot.\n\t *\n\t * @private\n\t * @param {module:table/tablewalker~TableSlot} tableSlot\n\t * @param {module:engine/model/element~Element} cellToInsert\n\t * @param {module:engine/model/position~Position} insertPosition\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {module:engine/model/element~Element|null} Inserted table cell or null if slot should remain empty.\n\t */\n\t_replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer ) {\n\t\tconst { cell, isAnchor } = tableSlot;\n\n\t\t// If the slot is occupied by a cell in a selected table - remove it.\n\t\t// The slot of this cell will be either:\n\t\t// - Replaced by a pasted table cell.\n\t\t// - Spanned by a previously pasted table cell.\n\t\tif ( isAnchor ) {\n\t\t\twriter.remove( cell );\n\t\t}\n\n\t\t// There is no cell to insert (might be spanned by other cell in a pasted table) - advance to the next content table slot.\n\t\tif ( !cellToInsert ) {\n\t\t\treturn null;\n\t\t}\n\n\t\twriter.insert( cellToInsert, insertPosition );\n\n\t\treturn cellToInsert;\n\t}\n}\n\n/**\n * Extract table for pasting into table.\n *\n * @private\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/model~Model} model The editor model.\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getTableIfOnlyTableInContent( content, model ) {\n\tif ( !content.is( 'documentFragment' ) && !content.is( 'element' ) ) {\n\t\treturn null;\n\t}\n\n\t// Table passed directly.\n\tif ( content.is( 'element', 'table' ) ) {\n\t\treturn content;\n\t}\n\n\t// We do not support mixed content when pasting table into table.\n\t// See: https://github.com/ckeditor/ckeditor5/issues/6817.\n\tif ( content.childCount == 1 && content.getChild( 0 ).is( 'element', 'table' ) ) {\n\t\treturn content.getChild( 0 );\n\t}\n\n\t// If there are only whitespaces around a table then use that table for pasting.\n\n\tconst contentRange = model.createRangeIn( content );\n\n\tfor ( const element of contentRange.getItems() ) {\n\t\tif ( element.is( 'element', 'table' ) ) {\n\t\t\t// Stop checking if there is some content before table.\n\t\t\tconst rangeBefore = model.createRange( contentRange.start, model.createPositionBefore( element ) );\n\n\t\t\tif ( model.hasContent( rangeBefore, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Stop checking if there is some content after table.\n\t\t\tconst rangeAfter = model.createRange( model.createPositionAfter( element ), contentRange.end );\n\n\t\t\tif ( model.hasContent( rangeAfter, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// There wasn't any content neither before nor after.\n\t\t\treturn element;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Prepares a table for pasting and returns adjusted selection dimensions.\n//\n// @param {Array.} selectedTableCells\n// @param {Object} pastedDimensions\n// @param {Number} pastedDimensions.height\n// @param {Number} pastedDimensions.width\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:table/tableutils~TableUtils} tableUtils\n// @returns {Object} selection\n// @returns {Number} selection.firstColumn\n// @returns {Number} selection.firstRow\n// @returns {Number} selection.lastColumn\n// @returns {Number} selection.lastRow\nfunction prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils ) {\n\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\tconst columnIndexes = getColumnIndexes( selectedTableCells );\n\tconst rowIndexes = getRowIndexes( selectedTableCells );\n\n\tconst selection = {\n\t\tfirstColumn: columnIndexes.first,\n\t\tlastColumn: columnIndexes.last,\n\t\tfirstRow: rowIndexes.first,\n\t\tlastRow: rowIndexes.last\n\t};\n\n\t// Single cell selected - expand selection to pasted table dimensions.\n\tconst shouldExpandSelection = selectedTableCells.length === 1;\n\n\tif ( shouldExpandSelection ) {\n\t\tselection.lastRow += pastedDimensions.height - 1;\n\t\tselection.lastColumn += pastedDimensions.width - 1;\n\n\t\texpandTableSize( selectedTable, selection.lastRow + 1, selection.lastColumn + 1, tableUtils );\n\t}\n\n\t// In case of expanding selection we do not reset the selection so in this case we will always try to fix selection\n\t// like in the case of a non-rectangular area. This might be fixed by re-setting selected cells array but this shortcut is safe.\n\tif ( shouldExpandSelection || !isSelectionRectangular( selectedTableCells, tableUtils ) ) {\n\t\t// For a non-rectangular selection (ie in which some cells sticks out from a virtual selection rectangle) we need to create\n\t\t// a table layout that has a rectangular selection. This will split cells so the selection become rectangular.\n\t\t// Beyond this point we will operate on fixed content table.\n\t\tsplitCellsToRectangularSelection( selectedTable, selection, writer );\n\t}\n\t// However a selected table fragment might be invalid if examined alone. Ie such table fragment:\n\t//\n\t// +---+---+---+---+\n\t// 0 | a | b | c | d |\n\t// + + +---+---+\n\t// 1 | | e | f | g |\n\t// + +---+ +---+\n\t// 2 | | h | | i | <- last row, each cell has rowspan = 2,\n\t// + + + + + so we need to return 3, not 2\n\t// 3 | | | | |\n\t// +---+---+---+---+\n\t//\n\t// is invalid as the cells \"h\" and \"i\" have rowspans.\n\t// This case needs only adjusting the selection dimension as the rest of the algorithm operates on empty slots also.\n\telse {\n\t\tselection.lastRow = adjustLastRowIndex( selectedTable, selection );\n\t\tselection.lastColumn = adjustLastColumnIndex( selectedTable, selection );\n\t}\n\n\treturn selection;\n}\n\n// Expand table (in place) to expected size.\nfunction expandTableSize( table, expectedHeight, expectedWidth, tableUtils ) {\n\tconst tableWidth = tableUtils.getColumns( table );\n\tconst tableHeight = tableUtils.getRows( table );\n\n\tif ( expectedWidth > tableWidth ) {\n\t\ttableUtils.insertColumns( table, {\n\t\t\tat: tableWidth,\n\t\t\tcolumns: expectedWidth - tableWidth\n\t\t} );\n\t}\n\n\tif ( expectedHeight > tableHeight ) {\n\t\ttableUtils.insertRows( table, {\n\t\t\tat: tableHeight,\n\t\t\trows: expectedHeight - tableHeight\n\t\t} );\n\t}\n}\n\n// Returns two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n//\n// At given row & column location it might be one of:\n//\n// * cell - cell from pasted table anchored at this location.\n// * null - if no cell is anchored at this location.\n//\n// For instance, from a table below:\n//\n//\t\t+----+----+----+----+\n//\t\t| 00 | 01 | 02 | 03 |\n//\t\t+ +----+----+----+\n//\t\t| | 11 | 13 |\n//\t\t+----+ +----+\n//\t\t| 20 | | 23 |\n//\t\t+----+----+----+----+\n//\n// The method will return an array (numbers represents cell element):\n//\n//\tconst map = [\n//\t\t[ '00', '01', '02', '03' ],\n//\t\t[ null, '11', null, '13' ],\n//\t\t[ '20', null, null, '23' ]\n//\t]\n//\n// This allows for a quick access to table at give row & column. For instance to access table cell \"13\" from pasted table call:\n//\n//\t\tconst cell = map[ 1 ][ 3 ]\n//\nfunction createLocationMap( table, width, height ) {\n\t// Create height x width (row x column) two-dimensional table to store cells.\n\tconst map = new Array( height ).fill( null )\n\t\t.map( () => new Array( width ).fill( null ) );\n\n\tfor ( const { column, row, cell } of new TableWalker( table ) ) {\n\t\tmap[ row ][ column ] = cell;\n\t}\n\n\treturn map;\n}\n\n// Make selected cells rectangular by splitting the cells that stand out from a rectangular selection.\n//\n// In the table below a selection is shown with \"::\" and slots with anchor cells are named.\n//\n// +----+----+----+----+----+ +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 | | 00 | 01 | 02 | 03 |\n// + +----+ +----+----+ | ::::::::::::::::----+\n// | | 11 | | 13 | 14 | | ::11 | | 13:: 14 | <- first row\n// +----+----+ + +----+ +----::---| | ::----+\n// | 20 | 21 | | | 24 | select cells: | 20 ::21 | | :: 24 |\n// +----+----+ +----+----+ 11 -> 33 +----::---| |---::----+\n// | 30 | | 33 | 34 | | 30 :: | | 33:: 34 | <- last row\n// + + +----+ + | :::::::::::::::: +\n// | | | 43 | | | | | 43 | |\n// +----+----+----+----+----+ +----+----+----+----+----+\n// ^ ^\n// first & last columns\n//\n// Will update table to:\n//\n// +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 |\n// + +----+----+----+----+\n// | | 11 | | 13 | 14 |\n// +----+----+ + +----+\n// | 20 | 21 | | | 24 |\n// +----+----+ +----+----+\n// | 30 | | | 33 | 34 |\n// + +----+----+----+ +\n// | | | | 43 | |\n// +----+----+----+----+----+\n//\n// In th example above:\n// - Cell \"02\" which have `rowspan = 4` must be trimmed at first and at after last row.\n// - Cell \"03\" which have `rowspan = 2` and `colspan = 2` must be trimmed at first column and after last row.\n// - Cells \"00\", \"03\" & \"30\" which cannot be cut by this algorithm as they are outside the trimmed area.\n// - Cell \"13\" cannot be cut as it is inside the trimmed area.\nfunction splitCellsToRectangularSelection( table, dimensions, writer ) {\n\tconst { firstRow, lastRow, firstColumn, lastColumn } = dimensions;\n\n\tconst rowIndexes = { first: firstRow, last: lastRow };\n\tconst columnIndexes = { first: firstColumn, last: lastColumn };\n\n\t// 1. Split cells vertically in two steps as first step might create cells that needs to split again.\n\tdoVerticalSplit( table, firstColumn, rowIndexes, writer );\n\tdoVerticalSplit( table, lastColumn + 1, rowIndexes, writer );\n\n\t// 2. Split cells horizontally in two steps as first step might create cells that needs to split again.\n\tdoHorizontalSplit( table, firstRow, columnIndexes, writer );\n\tdoHorizontalSplit( table, lastRow + 1, columnIndexes, writer, firstRow );\n}\n\nfunction doHorizontalSplit( table, splitRow, limitColumns, writer, startRow = 0 ) {\n\t// If selection starts at first row then no split is needed.\n\tif ( splitRow < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getVerticallyOverlappingCells( table, splitRow, startRow );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { column, cellWidth } ) => isAffectedBySelection( column, cellWidth, limitColumns ) );\n\n\treturn cellsToSplit.map( ( { cell } ) => splitHorizontally( cell, splitRow, writer ) );\n}\n\nfunction doVerticalSplit( table, splitColumn, limitRows, writer ) {\n\t// If selection starts at first column then no split is needed.\n\tif ( splitColumn < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getHorizontallyOverlappingCells( table, splitColumn );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { row, cellHeight } ) => isAffectedBySelection( row, cellHeight, limitRows ) );\n\n\treturn cellsToSplit.map( ( { cell, column } ) => splitVertically( cell, column, splitColumn, writer ) );\n}\n\n// Checks if cell at given row (column) is affected by a rectangular selection defined by first/last column (row).\n//\n// The same check is used for row as for column.\nfunction isAffectedBySelection( index, span, limit ) {\n\tconst endIndex = index + span - 1;\n\tconst { first, last } = limit;\n\n\tconst isInsideSelection = index >= first && index <= last;\n\tconst overlapsSelectionFromOutside = index < first && endIndex >= first;\n\n\treturn isInsideSelection || overlapsSelectionFromOutside;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablekeyboard\n */\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { priorities, isArrowKeyCode, getLocalizedArrowKeyCodeDirection } from 'ckeditor5/src/utils';\nimport { getSelectedTableCells, getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables keyboard navigation for tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableKeyboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableKeyboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Handle Tab key navigation.\n\t\tthis.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Tab', this._getTabHandler( true ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Shift+Tab', this._getTabHandler( false ), { priority: 'low' } );\n\n\t\t// Note: This listener has the \"high-10\" priority because it should allow the Widget plugin to handle the default\n\t\t// behavior first (\"high\") but it should not be \"prevent–defaulted\" by the Widget plugin (\"high-20\") because of\n\t\t// the fake selection retention on the fully selected widget.\n\t\tthis.listenTo( viewDocument, 'keydown', ( ...args ) => this._onKeydown( ...args ), { priority: priorities.get( 'high' ) - 10 } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events for the Tab key executed\n\t * when the table widget is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} data Key event data.\n\t * @param {Function} cancel The stop/stopPropagation/preventDefault function.\n\t */\n\t_handleTabOnSelectedTable( data, cancel ) {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\tif ( !selectedElement || !selectedElement.is( 'element', 'table' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcancel();\n\n\t\teditor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeIn( selectedElement.getChild( 0 ).getChild( 0 ) ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a handler for {@link module:engine/view/document~Document#event:keydown keydown} events for the Tab key executed\n\t * inside table cells.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Whether this handler will move the selection to the next or the previous cell.\n\t */\n\t_getTabHandler( isForward ) {\n\t\tconst editor = this.editor;\n\n\t\treturn ( domEventData, cancel ) => {\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tlet tableCell = getTableCellsContainingSelection( selection )[ 0 ];\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\ttableCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t}\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcancel();\n\n\t\t\tconst tableRow = tableCell.parent;\n\t\t\tconst table = tableRow.parent;\n\n\t\t\tconst currentRowIndex = table.getChildIndex( tableRow );\n\t\t\tconst currentCellIndex = tableRow.getChildIndex( tableCell );\n\n\t\t\tconst isFirstCellInRow = currentCellIndex === 0;\n\n\t\t\tif ( !isForward && isFirstCellInRow && currentRowIndex === 0 ) {\n\t\t\t\t// Set the selection over the whole table if the selection was in the first table cell.\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t} );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst isLastCellInRow = currentCellIndex === tableRow.childCount - 1;\n\t\t\tconst isLastRow = currentRowIndex === table.childCount - 1;\n\n\t\t\tif ( isForward && isLastRow && isLastCellInRow ) {\n\t\t\t\teditor.execute( 'insertTableRowBelow' );\n\n\t\t\t\t// Check if the command actually added a row. If `insertTableRowBelow` execution didn't add a row (because it was disabled\n\t\t\t\t// or it got overwritten) set the selection over the whole table to mirror the first cell case.\n\t\t\t\tif ( currentRowIndex === table.childCount - 1 ) {\n\t\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet cellToFocus;\n\n\t\t\t// Move to the first cell in the next row.\n\t\t\tif ( isForward && isLastCellInRow ) {\n\t\t\t\tconst nextRow = table.getChild( currentRowIndex + 1 );\n\n\t\t\t\tcellToFocus = nextRow.getChild( 0 );\n\t\t\t}\n\t\t\t// Move to the last cell in the previous row.\n\t\t\telse if ( !isForward && isFirstCellInRow ) {\n\t\t\t\tconst previousRow = table.getChild( currentRowIndex - 1 );\n\n\t\t\t\tcellToFocus = previousRow.getChild( previousRow.childCount - 1 );\n\t\t\t}\n\t\t\t// Move to the next/previous cell.\n\t\t\telse {\n\t\t\t\tcellToFocus = tableRow.getChild( currentCellIndex + ( isForward ? 1 : -1 ) );\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( cellToFocus ) );\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onKeydown( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\tif ( !isArrowKeyCode( keyCode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst direction = getLocalizedArrowKeyCodeDirection( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst wasHandled = this._handleArrowKeys( direction, domEventData.shiftKey );\n\n\t\tif ( wasHandled ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tdomEventData.stopPropagation();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles arrow keys to move the selection around the table.\n\t *\n\t * @private\n\t * @param {'left'|'up'|'right'|'down'} direction The direction of the arrow key.\n\t * @param {Boolean} expandSelection If the current selection should be expanded.\n\t * @returns {Boolean} Returns `true` if key was handled.\n\t */\n\t_handleArrowKeys( direction, expandSelection ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\n\t\t// In case one or more table cells are selected (from outside),\n\t\t// move the selection to a cell adjacent to the selected table fragment.\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length ) {\n\t\t\tlet focusCell;\n\n\t\t\tif ( expandSelection ) {\n\t\t\t\tfocusCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t} else {\n\t\t\t\tfocusCell = isForward ? selectedCells[ selectedCells.length - 1 ] : selectedCells[ 0 ];\n\t\t\t}\n\n\t\t\tthis._navigateFromCellInDirection( focusCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// Abort if we're not in a table cell.\n\t\tconst tableCell = selection.focus.findAncestor( 'tableCell' );\n\n\t\tif ( !tableCell ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.\n\t\t// Selection for sure will not approach cell edge.\n\t\tif ( expandSelection && !selection.isCollapsed && selection.isBackward == isForward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Let's check if the selection is at the beginning/end of the cell.\n\t\tif ( this._isSelectionAtCellEdge( selection, tableCell, isForward ) ) {\n\t\t\tthis._navigateFromCellInDirection( tableCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns `true` if the selection is at the boundary of a table cell according to the navigation direction.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The current selection.\n\t * @param {module:engine/model/element~Element} tableCell The current table cell element.\n\t * @param {Boolean} isForward The expected navigation direction.\n\t * @returns {Boolean}\n\t */\n\t_isSelectionAtCellEdge( selection, tableCell, isForward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst focus = isForward ? selection.getLastPosition() : selection.getFirstPosition();\n\n\t\t// If the current limit element is not table cell we are for sure not at the cell edge.\n\t\t// Also `modifySelection` will not let us out of it.\n\t\tif ( !schema.getLimitElement( focus ).is( 'element', 'tableCell' ) ) {\n\t\t\tconst boundaryPosition = model.createPositionAt( tableCell, isForward ? 'end' : 0 );\n\n\t\t\treturn boundaryPosition.isTouching( focus );\n\t\t}\n\n\t\tconst probe = model.createSelection( focus );\n\n\t\tmodel.modifySelection( probe, { direction: isForward ? 'forward' : 'backward' } );\n\n\t\t// If there was no change in the focus position, then it's not possible to move the selection there.\n\t\treturn focus.isEqual( probe.focus );\n\t}\n\n\t/**\n\t * Moves the selection from the given table cell in the specified direction.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} focusCell The table cell that is current multi-cell selection focus.\n\t * @param {'left'|'up'|'right'|'down'} direction Direction in which selection should move.\n\t * @param {Boolean} [expandSelection=false] If the current selection should be expanded.\n\t */\n\t_navigateFromCellInDirection( focusCell, direction, expandSelection = false ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst table = focusCell.findAncestor( 'table' );\n\t\tconst tableMap = [ ...new TableWalker( table, { includeAllSlots: true } ) ];\n\t\tconst { row: lastRow, column: lastColumn } = tableMap[ tableMap.length - 1 ];\n\n\t\tconst currentCellInfo = tableMap.find( ( { cell } ) => cell == focusCell );\n\t\tlet { row, column } = currentCellInfo;\n\n\t\tswitch ( direction ) {\n\t\t\tcase 'left':\n\t\t\t\tcolumn--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'up':\n\t\t\t\trow--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'right':\n\t\t\t\tcolumn += currentCellInfo.cellWidth;\n\t\t\t\tbreak;\n\n\t\t\tcase 'down':\n\t\t\t\trow += currentCellInfo.cellHeight;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst isOutsideVertically = row < 0 || row > lastRow;\n\t\tconst isBeforeFirstCell = column < 0 && row <= 0;\n\t\tconst isAfterLastCell = column > lastColumn && row >= lastRow;\n\n\t\t// Note that if the table cell at the end of a row is row-spanned then isAfterLastCell will never be true.\n\t\t// However, we don't know if user was navigating on the last row or not, so let's stay in the table.\n\n\t\tif ( isOutsideVertically || isBeforeFirstCell || isAfterLastCell ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( column < 0 ) {\n\t\t\tcolumn = expandSelection ? 0 : lastColumn;\n\t\t\trow--;\n\t\t} else if ( column > lastColumn ) {\n\t\t\tcolumn = expandSelection ? lastColumn : 0;\n\t\t\trow++;\n\t\t}\n\n\t\tconst cellToSelect = tableMap.find( cellInfo => cellInfo.row == row && cellInfo.column == column ).cell;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\t\tconst tableSelection = this.editor.plugins.get( 'TableSelection' );\n\n\t\tif ( expandSelection && tableSelection.isEnabled ) {\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || focusCell;\n\n\t\t\ttableSelection.setCellSelection( anchorCell, cellToSelect );\n\t\t} else {\n\t\t\tconst positionToSelect = model.createPositionAt( cellToSelect, isForward ? 0 : 'end' );\n\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( positionToSelect );\n\t\t\t} );\n\t\t}\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableselection/mouseeventsobserver\n */\n\nimport { DomEventObserver } from 'ckeditor5/src/engine';\n\n/**\n * The mouse selection event observer.\n *\n * It registers listeners for the following DOM events:\n *\n * - `'mousemove'`\n * - `'mouseup'`\n * - `'mouseleave'`\n *\n * Note that this observer is disabled by default. To enable this observer, it needs to be added to\n * {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * The observer is registered by the {@link module:table/tableselection~TableSelection} plugin.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseEventsObserver extends DomEventObserver {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'mousemove', 'mouseup', 'mouseleave' ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when the mouse button is released over one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mouseup\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when the mouse is moved over one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mousemove\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when the mouse is moved out of one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mouseleave\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablemouse\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableSelection from './tableselection';\nimport MouseEventsObserver from './tablemouse/mouseeventsobserver';\n\nimport { getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables a table cells' selection with the mouse.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableMouse extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableMouse';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Currently the MouseObserver only handles `mouseup` events.\n\t\t// TODO move to the engine?\n\t\teditor.editing.view.addObserver( MouseEventsObserver );\n\n\t\tthis._enableShiftClickSelection();\n\t\tthis._enableMouseDragSelection();\n\t}\n\n\t/**\n\t * Enables making cells selection by Shift+click. Creates a selection from the cell which previously held\n\t * the selection to the cell which was clicked. It can be the same cell, in which case it selects a single cell.\n\t *\n\t * @private\n\t */\n\t_enableShiftClickSelection() {\n\t\tconst editor = this.editor;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !domEventData.domEvent.shiftKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || getTableCellsContainingSelection( editor.model.document.selection )[ 0 ];\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst targetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( targetCell && haveSameTableParent( anchorCell, targetCell ) ) {\n\t\t\t\tblockSelectionChange = true;\n\t\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t}\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tblockSelectionChange = false;\n\t\t} );\n\n\t\t// We need to ignore a `selectionChange` event that is fired after we render our new table cells selection.\n\t\t// When downcasting table cells selection to the view, we put the view selection in the last selected cell\n\t\t// in a place that may not be natively a \"correct\" location. This is – we put it directly in the `` element.\n\t\t// All browsers fire the native `selectionchange` event.\n\t\t// However, all browsers except Safari return the selection in the exact place where we put it\n\t\t// (even though it's visually normalized). Safari returns `

^foo` that makes our selection observer\n\t\t// fire our `selectionChange` event (because the view selection that we set in the first step differs from the DOM selection).\n\t\t// Since `selectionChange` is fired, we automatically update the model selection that moves it that paragraph.\n\t\t// This breaks our dear cells selection.\n\t\t//\n\t\t// Theoretically this issue concerns only Safari that is the only browser that do normalize the selection.\n\t\t// However, to avoid code branching and to have a good coverage for this event blocker, I enabled it for all browsers.\n\t\t//\n\t\t// Note: I'm keeping the `blockSelectionChange` state separately for shift+click and mouse drag (exact same logic)\n\t\t// so I don't have to try to analyze whether they don't overlap in some weird cases. Probably they don't.\n\t\t// But I have other things to do, like writing this comment.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Enables making cells selection by dragging.\n\t *\n\t * The selection is made only on mousemove. Mouse tracking is started on mousedown.\n\t * However, the cells selection is enabled only after the mouse cursor left the anchor cell.\n\t * Thanks to that normal text selection within one cell works just fine. However, you can still select\n\t * just one cell by leaving the anchor cell and moving back to it.\n\t *\n\t * @private\n\t */\n\t_enableMouseDragSelection() {\n\t\tconst editor = this.editor;\n\t\tlet anchorCell, targetCell;\n\t\tlet beganCellSelection = false;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Make sure to not conflict with the shift+click listener and any other possible handler.\n\t\t\tif ( domEventData.domEvent.shiftKey || domEventData.domEvent.ctrlKey || domEventData.domEvent.altKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tanchorCell = this._getModelTableCellFromDomEvent( domEventData );\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousemove', ( evt, domEventData ) => {\n\t\t\tif ( !domEventData.domEvent.buttons ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newTargetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( newTargetCell && haveSameTableParent( anchorCell, newTargetCell ) ) {\n\t\t\t\ttargetCell = newTargetCell;\n\n\t\t\t\t// Switch to the cell selection mode after the mouse cursor left the anchor cell.\n\t\t\t\t// Switch off only on mouseup (makes selecting a single cell possible).\n\t\t\t\tif ( !beganCellSelection && targetCell != anchorCell ) {\n\t\t\t\t\tbeganCellSelection = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Yep, not making a cell selection yet. See method docs.\n\t\t\tif ( !beganCellSelection ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tblockSelectionChange = true;\n\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\tdomEventData.preventDefault();\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tbeganCellSelection = false;\n\t\t\tblockSelectionChange = false;\n\t\t\tanchorCell = null;\n\t\t\ttargetCell = null;\n\t\t} );\n\n\t\t// See the explanation in `_enableShiftClickSelection()`.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Returns the model table cell element based on the target element of the passed DOM event.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t * @returns {module:engine/model/element~Element|undefined} Returns the table cell or `undefined`.\n\t */\n\t_getModelTableCellFromDomEvent( domEventData ) {\n\t\t// Note: Work with positions (not element mapping) because the target element can be an attribute or other non-mapped element.\n\t\tconst viewTargetElement = domEventData.target;\n\t\tconst viewPosition = this.editor.editing.view.createPositionAt( viewTargetElement, 0 );\n\t\tconst modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition );\n\t\tconst modelElement = modelPosition.parent;\n\n\t\treturn modelElement.findAncestor( 'tableCell', { includeSelf: true } );\n\t}\n}\n\nfunction haveSameTableParent( cellA, cellB ) {\n\treturn cellA.parent.parent == cellB.parent.parent;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/table\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Widget } from 'ckeditor5/src/widget';\n\nimport TableEditing from './tableediting';\nimport TableUI from './tableui';\nimport TableSelection from './tableselection';\nimport TableClipboard from './tableclipboard';\nimport TableKeyboard from './tablekeyboard';\nimport TableMouse from './tablemouse';\n\nimport '../theme/table.css';\n\n/**\n * The table plugin.\n *\n * For a detailed overview, check the {@glink features/table Table feature documentation}.\n *\n * This is a \"glue\" plugin that loads the following table features:\n *\n * * {@link module:table/tableediting~TableEditing editing feature},\n * * {@link module:table/tableselection~TableSelection selection feature},\n * * {@link module:table/tablekeyboard~TableKeyboard keyboard navigation feature},\n * * {@link module:table/tablemouse~TableMouse mouse selection feature},\n * * {@link module:table/tableclipboard~TableClipboard clipboard feature},\n * * {@link module:table/tableui~TableUI UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Table extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Table';\n\t}\n}\n\n/**\n * The configuration of the table feature. Used by the table feature in the `@ckeditor/ckeditor5-table` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttable: ... // Table feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TableConfig\n */\n\n/**\n * The configuration of the {@link module:table/table~Table} feature.\n *\n * Read more in {@link module:table/table~TableConfig}.\n *\n * @member {module:table/table~TableConfig} module:core/editor/editorconfig~EditorConfig#table\n */\n\n/**\n * An array of color definitions (either strings or objects).\n *\n *\t\tconst colors = [\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\tlabel: 'Grey'\n *\t\t\t},\n *\t\t\t'hsl(0, 0%, 80%)',\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\tlabel: 'Light grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\tlabel: 'White',\n *\t\t\t\thasBorder: true\n *\t\t\t},\n *\t\t\t'#FF0000'\n *\t\t]\n *\n * Usually used as a configuration parameter, for instance in\n * {@link module:table/table~TableConfig#tableProperties `config.table.tableProperties`}\n * or {@link module:table/table~TableConfig#tableCellProperties `config.table.tableCellProperties`}.\n *\n * @typedef {Array.} module:table/table~TableColorConfig\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablepropertycommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\n/**\n * The table cell attribute command.\n *\n * This command is a base command for other table property commands.\n *\n * @extends module:core/command~Command\n */\nexport default class TablePropertyCommand extends Command {\n\t/**\n\t * Creates a new `TablePropertyCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t * @param {String} attributeName Table cell attribute name.\n\t */\n\tconstructor( editor, attributeName ) {\n\t\tsuper( editor );\n\n\t\tthis.attributeName = attributeName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\tconst table = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!table;\n\t\tthis.value = this._getValue( table );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {*} [options.value] If set, the command will set the attribute on the selected table.\n\t * If not set, the command will remove the attribute from the selected table.\n\t * @param {module:engine/model/batch~Batch} [options.batch] Pass the model batch instance to the command to aggregate changes,\n\t * for example, to allow a single undo step for multiple executions.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\tconst { value, batch } = options;\n\n\t\tconst table = selection.getFirstPosition().findAncestor( 'table' );\n\t\tconst valueToSet = this._getValueToSet( value );\n\n\t\tmodel.enqueueChange( batch || 'default', writer => {\n\t\t\tif ( valueToSet ) {\n\t\t\t\twriter.setAttribute( this.attributeName, valueToSet, table );\n\t\t\t} else {\n\t\t\t\twriter.removeAttribute( this.attributeName, table );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the attribute value for a table.\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {String|undefined}\n\t * @private\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn table.getAttribute( this.attributeName );\n\t}\n\n\t/**\n\t * Returns the proper model value. It can be used to add a default unit to numeric values.\n\t *\n\t * @private\n\t * @param {*} value\n\t * @returns {*}\n\t */\n\t_getValueToSet( value ) {\n\t\treturn value;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablebackgroundcolorcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\n\n/**\n * The table background color command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBackgroundColor'` editor command.\n *\n * To change the background color of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBackgroundColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBackgroundColorCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBackgroundColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'backgroundColor' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablebordercolorcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table border color command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderColor'` editor command.\n *\n * To change the border color of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderColorCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderColor' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableborderstylecommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table style border command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderStyle'` editor command.\n *\n * To change the border style of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderStyle', {\n *\t\t\tvalue: 'dashed'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderStyleCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderStyleCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderStyle' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableborderwidthcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue, getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table width border command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderWidth'` editor command.\n *\n * To change the border width of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderWidth', {\n *\t\t\tvalue: '5px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableBorderWidth', {\n *\t\t\tvalue: '5'\n *\t\t} );\n *\n * will set the `borderWidth` attribute to `'5px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderWidthCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderWidth' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablewidthcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table width command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableWidth'` editor command.\n *\n * To change the width of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableWidth', {\n *\t\t\tvalue: '400px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableWidth', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `width` attribute to `'50px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableWidthCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'width' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableheightcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table height command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableHeight'` editor command.\n *\n * To change the height of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableHeight', {\n *\t\t\tvalue: '500px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableHeight', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `height` attribute to `'50px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableHeightCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableHeightCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'height' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablealignmentcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\n\n/**\n * The table alignment command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableAlignment'` editor command.\n *\n * To change the alignment of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableAlignment', {\n *\t\t\tvalue: 'right'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableAlignmentCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableAlignmentCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'alignment' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/tablepropertiesediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addBackgroundRules, addBorderRules } from 'ckeditor5/src/engine';\n\nimport TableEditing from '../tableediting';\nimport {\n\tdowncastAttributeToStyle,\n\tdowncastTableAttribute,\n\tupcastBorderStyles,\n\tupcastStyleToAttribute\n} from '../converters/tableproperties';\nimport TableBackgroundColorCommand from './commands/tablebackgroundcolorcommand';\nimport TableBorderColorCommand from './commands/tablebordercolorcommand';\nimport TableBorderStyleCommand from './commands/tableborderstylecommand';\nimport TableBorderWidthCommand from './commands/tableborderwidthcommand';\nimport TableWidthCommand from './commands/tablewidthcommand';\nimport TableHeightCommand from './commands/tableheightcommand';\nimport TableAlignmentCommand from './commands/tablealignmentcommand';\n\nconst ALIGN_VALUES_REG_EXP = /^(left|right)$/;\n\n/**\n * The table properties editing feature.\n *\n * Introduces table's model attributes and their conversion:\n *\n * - border: `borderStyle`, `borderColor` and `borderWidth`\n * - background color: `backgroundColor`\n * - horizontal alignment: `alignment`\n * - width & height: `width` & `height`\n *\n * It also registers commands used to manipulate the above attributes:\n *\n * - border: `'tableBorderStyle'`, `'tableBorderColor'` and `'tableBorderWidth'` commands\n * - background color: `'tableBackgroundColor'`\n * - horizontal alignment: `'tableAlignment'`\n * - width & height: `'tableWidth'` & `'tableHeight'`\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TablePropertiesEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TablePropertiesEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\teditor.data.addStyleProcessorRules( addBorderRules );\n\t\tenableBorderProperties( schema, conversion );\n\t\teditor.commands.add( 'tableBorderColor', new TableBorderColorCommand( editor ) );\n\t\teditor.commands.add( 'tableBorderStyle', new TableBorderStyleCommand( editor ) );\n\t\teditor.commands.add( 'tableBorderWidth', new TableBorderWidthCommand( editor ) );\n\n\t\tenableAlignmentProperty( schema, conversion );\n\t\teditor.commands.add( 'tableAlignment', new TableAlignmentCommand( editor ) );\n\n\t\tenableTableToFigureProperty( schema, conversion, 'width', 'width' );\n\t\teditor.commands.add( 'tableWidth', new TableWidthCommand( editor ) );\n\n\t\tenableTableToFigureProperty( schema, conversion, 'height', 'height' );\n\t\teditor.commands.add( 'tableHeight', new TableHeightCommand( editor ) );\n\n\t\teditor.data.addStyleProcessorRules( addBackgroundRules );\n\t\tenableProperty( schema, conversion, 'backgroundColor', 'background-color' );\n\t\teditor.commands.add( 'tableBackgroundColor', new TableBackgroundColorCommand( editor ) );\n\t}\n}\n\n// Enables `'borderStyle'`, `'borderColor'` and `'borderWidth'` attributes for table.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableBorderProperties( schema, conversion ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ 'borderWidth', 'borderColor', 'borderStyle' ]\n\t} );\n\tupcastBorderStyles( conversion, 'table' );\n\tdowncastTableAttribute( conversion, 'borderColor', 'border-color' );\n\tdowncastTableAttribute( conversion, 'borderStyle', 'border-style' );\n\tdowncastTableAttribute( conversion, 'borderWidth', 'border-width' );\n}\n\n// Enables the `'alignment'` attribute for table.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableAlignmentProperty( schema, conversion ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ 'alignment' ]\n\t} );\n\n\tconversion\n\t\t.attributeToAttribute( {\n\t\t\tmodel: {\n\t\t\t\tname: 'table',\n\t\t\t\tkey: 'alignment',\n\t\t\t\tvalues: [ 'left', 'right' ]\n\t\t\t},\n\t\t\tview: {\n\t\t\t\tleft: {\n\t\t\t\t\tkey: 'style',\n\t\t\t\t\tvalue: {\n\t\t\t\t\t\tfloat: 'left'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tright: {\n\t\t\t\t\tkey: 'style',\n\t\t\t\t\tvalue: {\n\t\t\t\t\t\tfloat: 'right'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tconverterPriority: 'high'\n\t\t} );\n\n\tconversion.for( 'upcast' )\n\t\t// Support for backwards compatibility and pasting from other sources.\n\t\t.attributeToAttribute( {\n\t\t\tview: {\n\t\t\t\tattributes: {\n\t\t\t\t\talign: ALIGN_VALUES_REG_EXP\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tname: 'table',\n\t\t\t\tkey: 'alignment',\n\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'align' )\n\t\t\t}\n\t\t} );\n}\n\n// Enables conversion for an attribute for simple view-model mappings.\n//\n// @param {String} modelAttribute\n// @param {String} styleName\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableProperty( schema, conversion, modelAttribute, styleName ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ modelAttribute ]\n\t} );\n\tupcastStyleToAttribute( conversion, 'table', modelAttribute, styleName );\n\tdowncastTableAttribute( conversion, modelAttribute, styleName );\n}\n\n// Enables conversion for an attribute for simple view (figure) to model (table) mappings.\n//\n// @param {String} modelAttribute\n// @param {String} styleName\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableTableToFigureProperty( schema, conversion, modelAttribute, styleName ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ modelAttribute ]\n\t} );\n\tupcastStyleToAttribute( conversion, 'table', modelAttribute, styleName );\n\tdowncastAttributeToStyle( conversion, 'table', modelAttribute, styleName );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/ui/tablepropertiesview\n */\n\nimport {\n\tButtonView,\n\tFocusCycler,\n\tFormHeaderView,\n\tLabelView,\n\tLabeledFieldView,\n\tToolbarView,\n\tView,\n\tViewCollection,\n\taddListToDropdown,\n\tcreateLabeledDropdown,\n\tcreateLabeledInputText,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\nimport {\n\tfillToolbar,\n\tgetBorderStyleDefinitions,\n\tgetBorderStyleLabels,\n\tgetLabeledColorInputCreator\n} from '../../utils/ui/table-properties';\nimport FormRowView from '../../ui/formrowview';\n\nimport '../../../theme/form.css';\nimport '../../../theme/tableform.css';\nimport '../../../theme/tableproperties.css';\n\nconst ALIGNMENT_ICONS = {\n\tleft: icons.objectLeft,\n\tcenter: icons.objectCenter,\n\tright: icons.objectRight\n};\n\n/**\n * The class representing a table properties form, allowing users to customize\n * certain style aspects of a table, for instance, border, background color, alignment, etc..\n *\n * @extends module:ui/view~View\n */\nexport default class TablePropertiesView extends View {\n\t/**\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {Object} options Additional configuration of the view.\n\t * @param {module:table/table~TableColorConfig} options.borderColors A configuration of the border\n\t * color palette used by the\n\t * {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView#borderColorInput}.\n\t * @param {module:table/table~TableColorConfig} options.backgroundColors A configuration of the background\n\t * color palette used by the\n\t * {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView#backgroundInput}.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tthis.set( {\n\t\t\t/**\n\t\t\t * The value of the border style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderStyle\n\t\t\t */\n\t\t\tborderStyle: '',\n\n\t\t\t/**\n\t\t\t * The value of the border width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderWidth\n\t\t\t */\n\t\t\tborderWidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the border color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderColor\n\t\t\t */\n\t\t\tborderColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the background color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #backgroundColor\n\t\t\t */\n\t\t\tbackgroundColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the table width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #width\n\t\t\t */\n\t\t\twidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the table height style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #height\n\t\t\t */\n\t\t\theight: '',\n\n\t\t\t/**\n\t\t\t * The value of the table alignment style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #alignment\n\t\t\t */\n\t\t\talignment: ''\n\t\t} );\n\n\t\t/**\n\t\t * Options passed to the view. See {@link #constructor} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object}\n\t\t */\n\t\tthis.options = options;\n\n\t\tconst { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();\n\t\tconst { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();\n\t\tconst { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();\n\t\tconst { alignmentToolbar, alignmentLabel } = this._createAlignmentFields();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * A dropdown that allows selecting the style of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.borderStyleDropdown = borderStyleDropdown;\n\n\t\t/**\n\t\t * An input that allows specifying the width of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.borderWidthInput = borderWidthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the color of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.borderColorInput = borderColorInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table background color.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.backgroundInput = backgroundInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table width.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.widthInput = widthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table height.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.heightInput = heightInput;\n\n\t\t/**\n\t\t * A toolbar with buttons that allow changing the alignment of an entire table.\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbar~ToolbarView}\n\t\t */\n\t\tthis.alignmentToolbar = alignmentToolbar;\n\n\t\t// Defer creating to make sure other fields are present and the Save button can\n\t\t// bind its #isEnabled to their error messages so there's no way to save unless all\n\t\t// fields are valid.\n\t\tconst { saveButtonView, cancelButtonView } = this._createActionButtons();\n\n\t\t/**\n\t\t * The \"Save\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = saveButtonView;\n\n\t\t/**\n\t\t * The \"Cancel\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = cancelButtonView;\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\t// Form header.\n\t\tthis.children.add( new FormHeaderView( locale, {\n\t\t\tlabel: this.t( 'Table properties' )\n\t\t} ) );\n\n\t\t// Border row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: borderRowLabel,\n\t\t\tchildren: [\n\t\t\t\tborderRowLabel,\n\t\t\t\tborderStyleDropdown,\n\t\t\t\tborderColorInput,\n\t\t\t\tborderWidthInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__border-row'\n\t\t} ) );\n\n\t\t// Background row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: backgroundRowLabel,\n\t\t\tchildren: [\n\t\t\t\tbackgroundRowLabel,\n\t\t\t\tbackgroundInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__background-row'\n\t\t} ) );\n\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\t// Dimensions row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tlabelView: dimensionsLabel,\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tdimensionsLabel,\n\t\t\t\t\t\twidthInput,\n\t\t\t\t\t\toperatorLabel,\n\t\t\t\t\t\theightInput\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-form__dimensions-row'\n\t\t\t\t} ),\n\t\t\t\t// Alignment row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tlabelView: alignmentLabel,\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\talignmentLabel,\n\t\t\t\t\t\talignmentToolbar\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-properties-form__alignment-row'\n\t\t\t\t} )\n\t\t\t]\n\t\t} ) );\n\n\t\t// Action row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t],\n\t\t\tclass: 'ck-table-form__action-row'\n\t\t} ) );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form',\n\t\t\t\t\t'ck-table-form',\n\t\t\t\t\t'ck-table-properties-form'\n\t\t\t\t],\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Enable the \"submit\" event for this view. It can be triggered by the #saveButtonView\n\t\t// which is of the \"submit\" DOM \"type\".\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\t[\n\t\t\tthis.borderStyleDropdown,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.widthInput,\n\t\t\tthis.heightInput,\n\t\t\tthis.alignmentToolbar,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t].forEach( view => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( view );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( view.element );\n\t\t} );\n\n\t\t// Mainly for closing using \"Esc\" and navigation using \"Tab\".\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist focusable field in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #borderStyleDropdown},\n\t * * {@link #borderWidthInput},\n\t * * {@link #borderColorInput}.\n\t *\n\t * @private\n\t * @returns {Object.}\n\t */\n\t_createBorderFields() {\n\t\tconst colorInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.borderColors,\n\t\t\tcolumns: 5\n\t\t} );\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst borderRowLabel = new LabelView( locale );\n\t\tborderRowLabel.text = t( 'Border' );\n\n\t\t// -- Style ---------------------------------------------------\n\n\t\tconst styleLabels = getBorderStyleLabels( this.t );\n\t\tconst borderStyleDropdown = new LabeledFieldView( locale, createLabeledDropdown );\n\t\tborderStyleDropdown.set( {\n\t\t\tlabel: t( 'Style' ),\n\t\t\tclass: 'ck-table-form__border-style'\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.set( {\n\t\t\tisOn: false,\n\t\t\twithText: true,\n\t\t\ttooltip: t( 'Style' )\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.bind( 'label' ).to( this, 'borderStyle', value => {\n\t\t\treturn styleLabels[ value ? value : 'none' ];\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.on( 'execute', evt => {\n\t\t\tthis.borderStyle = evt.source._borderStyleValue;\n\t\t} );\n\n\t\tborderStyleDropdown.bind( 'isEmpty' ).to( this, 'borderStyle', value => !value );\n\n\t\taddListToDropdown( borderStyleDropdown.fieldView, getBorderStyleDefinitions( this ) );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst borderWidthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\tborderWidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__border-width'\n\t\t} );\n\n\t\tborderWidthInput.fieldView.bind( 'value' ).to( this, 'borderWidth' );\n\t\tborderWidthInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\t\tborderWidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderWidth = borderWidthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Color ---------------------------------------------------\n\n\t\tconst borderColorInput = new LabeledFieldView( locale, colorInputCreator );\n\n\t\tborderColorInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-form__border-color'\n\t\t} );\n\n\t\tborderColorInput.fieldView.bind( 'value' ).to( this, 'borderColor' );\n\t\tborderColorInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\n\t\tborderColorInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderColor = borderColorInput.fieldView.value;\n\t\t} );\n\n\t\t// Reset the border color and width fields when style is \"none\".\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6227\n\t\tthis.on( 'change:borderStyle', ( evt, name, value ) => {\n\t\t\tif ( !isBorderStyleSet( value ) ) {\n\t\t\t\tthis.borderColor = '';\n\t\t\t\tthis.borderWidth = '';\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\tborderRowLabel,\n\t\t\tborderStyleDropdown,\n\t\t\tborderColorInput,\n\t\t\tborderWidthInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #backgroundInput}.\n\t *\n\t * @private\n\t * @returns {Object.}\n\t */\n\t_createBackgroundFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst backgroundRowLabel = new LabelView( locale );\n\t\tbackgroundRowLabel.text = t( 'Background' );\n\n\t\t// -- Background color input -----------------------------------\n\n\t\tconst backgroundInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.backgroundColors,\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\tconst backgroundInput = new LabeledFieldView( locale, backgroundInputCreator );\n\n\t\tbackgroundInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-properties-form__background'\n\t\t} );\n\n\t\tbackgroundInput.fieldView.bind( 'value' ).to( this, 'backgroundColor' );\n\t\tbackgroundInput.fieldView.on( 'input', () => {\n\t\t\tthis.backgroundColor = backgroundInput.fieldView.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tbackgroundRowLabel,\n\t\t\tbackgroundInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #widthInput}.\n\t * * {@link #heightInput}.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t */\n\t_createDimensionFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Label ---------------------------------------------------\n\n\t\tconst dimensionsLabel = new LabelView( locale );\n\t\tdimensionsLabel.text = t( 'Dimensions' );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst widthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\twidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__width'\n\t\t} );\n\n\t\twidthInput.fieldView.bind( 'value' ).to( this, 'width' );\n\t\twidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.width = widthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Operator ---------------------------------------------------\n\n\t\tconst operatorLabel = new View( locale );\n\t\toperatorLabel.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-table-form__dimension-operator'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{ text: '×' }\n\t\t\t]\n\t\t} );\n\n\t\t// -- Height ---------------------------------------------------\n\n\t\tconst heightInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\theightInput.set( {\n\t\t\tlabel: t( 'Height' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__height'\n\t\t} );\n\n\t\theightInput.fieldView.bind( 'value' ).to( this, 'height' );\n\t\theightInput.fieldView.on( 'input', () => {\n\t\t\tthis.height = heightInput.fieldView.element.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tdimensionsLabel,\n\t\t\twidthInput,\n\t\t\toperatorLabel,\n\t\t\theightInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #alignmentToolbar},\n\t *\n\t * @private\n\t * @returns {Object.}\n\t */\n\t_createAlignmentFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Label ---------------------------------------------------\n\n\t\tconst alignmentLabel = new LabelView( locale );\n\t\talignmentLabel.text = t( 'Alignment' );\n\n\t\t// -- Toolbar ---------------------------------------------------\n\n\t\tconst alignmentToolbar = new ToolbarView( locale );\n\t\talignmentToolbar.set( {\n\t\t\tisCompact: true,\n\t\t\tariaLabel: t( 'Table alignment toolbar' )\n\t\t} );\n\n\t\tfillToolbar( {\n\t\t\tview: this,\n\t\t\ticons: ALIGNMENT_ICONS,\n\t\t\ttoolbar: alignmentToolbar,\n\t\t\tlabels: this._alignmentLabels,\n\t\t\tpropertyName: 'alignment',\n\t\t\tnameToValue: name => {\n\t\t\t\treturn name === 'center' ? '' : name;\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\talignmentLabel,\n\t\t\talignmentToolbar\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form controls:\n\t *\n\t * * {@link #saveButtonView},\n\t * * {@link #cancelButtonView}.\n\t *\n\t * @private\n\t * @returns {Object.}\n\t */\n\t_createActionButtons() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst saveButtonView = new ButtonView( locale );\n\t\tconst cancelButtonView = new ButtonView( locale );\n\t\tconst fieldsThatShouldValidateToSave = [\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.widthInput,\n\t\t\tthis.heightInput\n\t\t];\n\n\t\tsaveButtonView.set( {\n\t\t\tlabel: t( 'Save' ),\n\t\t\ticon: icons.check,\n\t\t\tclass: 'ck-button-save',\n\t\t\ttype: 'submit',\n\t\t\twithText: true\n\t\t} );\n\n\t\tsaveButtonView.bind( 'isEnabled' ).toMany( fieldsThatShouldValidateToSave, 'errorText', ( ...errorTexts ) => {\n\t\t\treturn errorTexts.every( errorText => !errorText );\n\t\t} );\n\n\t\tcancelButtonView.set( {\n\t\t\tlabel: t( 'Cancel' ),\n\t\t\ticon: icons.cancel,\n\t\t\tclass: 'ck-button-cancel',\n\t\t\ttype: 'cancel',\n\t\t\twithText: true\n\t\t} );\n\n\t\tcancelButtonView.delegate( 'execute' ).to( this, 'cancel' );\n\n\t\treturn {\n\t\t\tsaveButtonView, cancelButtonView\n\t\t};\n\t}\n\n\t/**\n\t * Provides localized labels for {@link #alignmentToolbar} buttons.\n\t *\n\t * @private\n\t * @type {Object.}\n\t */\n\tget _alignmentLabels() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst left = t( 'Align table to the left' );\n\t\tconst center = t( 'Center table' );\n\t\tconst right = t( 'Align table to the right' );\n\n\t\t// Returns object with a proper order of labels.\n\t\tif ( locale.uiLanguageDirection === 'rtl' ) {\n\t\t\treturn { right, center, left };\n\t\t} else {\n\t\t\treturn { left, center, right };\n\t\t}\n\t}\n}\n\nfunction isBorderStyleSet( value ) {\n\treturn !!value;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/tablepropertiesui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui';\n\nimport { debounce } from 'lodash-es';\n\nimport TablePropertiesView from './ui/tablepropertiesview';\nimport tableProperties from './../../theme/icons/table-properties.svg';\nimport {\n\tcolorFieldValidator,\n\tgetLocalizedColorErrorText,\n\tgetLocalizedLengthErrorText,\n\tlengthFieldValidator,\n\tlineWidthFieldValidator,\n\tdefaultColors\n} from '../utils/ui/table-properties';\nimport { getTableWidgetAncestor } from '../utils/ui/widget';\nimport { getBalloonTablePositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';\n\nconst ERROR_TEXT_TIMEOUT = 500;\n\n// Map of view properties and related commands.\nconst propertyToCommandMap = {\n\tborderStyle: 'tableBorderStyle',\n\tborderColor: 'tableBorderColor',\n\tborderWidth: 'tableBorderWidth',\n\tbackgroundColor: 'tableBackgroundColor',\n\twidth: 'tableWidth',\n\theight: 'tableHeight',\n\talignment: 'tableAlignment'\n};\n\n/**\n * The table properties UI plugin. It introduces the `'tableProperties'` button\n * that opens a form allowing to specify visual styling of an entire table.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TablePropertiesUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TablePropertiesUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'table.tableProperties', {\n\t\t\tborderColors: defaultColors,\n\t\t\tbackgroundColors: defaultColors\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t/**\n\t\t * The properties form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView}\n\t\t */\n\t\tthis.view = this._createPropertiesView();\n\n\t\t/**\n\t\t * The batch used to undo all changes made by the form (which are live, as the user types)\n\t\t * when \"Cancel\" was pressed. Each time the view is shown, a new batch is created.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis._undoStepBatch = null;\n\n\t\teditor.ui.componentFactory.add( 'tableProperties', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Table properties' ),\n\t\t\t\ticon: tableProperties,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tthis.listenTo( view, 'execute', () => this._showView() );\n\n\t\t\tconst commands = Object.values( propertyToCommandMap )\n\t\t\t\t.map( commandName => editor.commands.get( commandName ) );\n\n\t\t\tview.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => (\n\t\t\t\tareEnabled.some( isCommandEnabled => isCommandEnabled )\n\t\t\t) );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1341.\n\t\tthis.view.destroy();\n\t}\n\n\t/**\n\t * Creates the {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} instance.\n\t *\n\t * @private\n\t * @returns {module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} The table\n\t * properties form view instance.\n\t */\n\t_createPropertiesView() {\n\t\tconst editor = this.editor;\n\t\tconst config = editor.config.get( 'table.tableProperties' );\n\t\tconst borderColorsConfig = normalizeColorOptions( config.borderColors );\n\t\tconst localizedBorderColors = getLocalizedColorOptions( editor.locale, borderColorsConfig );\n\t\tconst backgroundColorsConfig = normalizeColorOptions( config.backgroundColors );\n\t\tconst localizedBackgroundColors = getLocalizedColorOptions( editor.locale, backgroundColorsConfig );\n\t\tconst view = new TablePropertiesView( editor.locale, {\n\t\t\tborderColors: localizedBorderColors,\n\t\t\tbackgroundColors: localizedBackgroundColors\n\t\t} );\n\t\tconst t = editor.t;\n\n\t\t// Render the view so its #element is available for the clickOutsideHandler.\n\t\tview.render();\n\n\t\tthis.listenTo( view, 'submit', () => {\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\tthis.listenTo( view, 'cancel', () => {\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/6180\n\t\t\tif ( this._undoStepBatch.operations.length ) {\n\t\t\t\teditor.execute( 'undo', this._undoStepBatch );\n\t\t\t}\n\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\t// Close the balloon on Esc key press.\n\t\tview.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideView();\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: view,\n\t\t\tactivator: () => this._isViewInBalloon,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideView()\n\t\t} );\n\n\t\tconst colorErrorText = getLocalizedColorErrorText( t );\n\t\tconst lengthErrorText = getLocalizedLengthErrorText( t );\n\n\t\t// Create the \"UI -> editor data\" binding.\n\t\t// These listeners update the editor data (via table commands) when any observable\n\t\t// property of the view has changed. They also validate the value and display errors in the UI\n\t\t// when necessary. This makes the view live, which means the changes are\n\t\t// visible in the editing as soon as the user types or changes fields' values.\n\t\tview.on( 'change:borderStyle', this._getPropertyChangeCallback( 'tableBorderStyle' ) );\n\n\t\tview.on( 'change:borderColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderColorInput,\n\t\t\tcommandName: 'tableBorderColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:borderWidth', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderWidthInput,\n\t\t\tcommandName: 'tableBorderWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lineWidthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:backgroundColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.backgroundInput,\n\t\t\tcommandName: 'tableBackgroundColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:width', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.widthInput,\n\t\t\tcommandName: 'tableWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:height', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.heightInput,\n\t\t\tcommandName: 'tableHeight',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:alignment', this._getPropertyChangeCallback( 'tableAlignment' ) );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * In this method the \"editor data -> UI\" binding is happening.\n\t *\n\t * When executed, this method obtains selected table property values from various table commands\n\t * and passes them to the {@link #view}.\n\t *\n\t * This way, the UI stays up–to–date with the editor data.\n\t *\n\t * @private\n\t */\n\t_fillViewFormFromCommandValues() {\n\t\tconst commands = this.editor.commands;\n\n\t\tObject.entries( propertyToCommandMap )\n\t\t\t.map( ( [ property, commandName ] ) => [ property, commands.get( commandName ).value || '' ] )\n\t\t\t.forEach( ( [ property, value ] ) => this.view.set( property, value ) );\n\t}\n\n\t/**\n\t * Shows the {@link #view} in the {@link #_balloon}.\n\t *\n\t * **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains\n\t * all changes made to the document when the view is visible, allowing a single undo step\n\t * for all of them.\n\t *\n\t * @protected\n\t */\n\t_showView() {\n\t\tconst editor = this.editor;\n\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tthis._updateView();\n\t\t} );\n\n\t\t// Update the view with the model values.\n\t\tthis._fillViewFormFromCommandValues();\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.view,\n\t\t\tposition: getBalloonTablePositionData( editor )\n\t\t} );\n\n\t\t// Create a new batch. Clicking \"Cancel\" will undo this batch.\n\t\tthis._undoStepBatch = editor.model.createBatch();\n\n\t\t// Basic a11y.\n\t\tthis.view.focus();\n\t}\n\n\t/**\n\t * Removes the {@link #view} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_hideView() {\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\n\t\t// Blur any input element before removing it from DOM to prevent issues in some browsers.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\tthis.view.saveButtonView.focus();\n\n\t\tthis._balloon.remove( this.view );\n\n\t\t// Make sure the focus is not lost in the process by putting it directly\n\t\t// into the editing view.\n\t\tthis.editor.editing.view.focus();\n\t}\n\n\t/**\n\t * Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.\n\t *\n\t * @protected\n\t */\n\t_updateView() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tif ( !getTableWidgetAncestor( viewDocument.selection ) ) {\n\t\t\tthis._hideView();\n\t\t} else if ( this._isViewVisible ) {\n\t\t\trepositionContextualBalloon( editor, 'table' );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewVisible() {\n\t\treturn this._balloon.visibleView === this.view;\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewInBalloon() {\n\t\treturn this._balloon.hasView( this.view );\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon {@link #view view's} property change\n\t * executes a related editor command with the new property value.\n\t *\n\t * @private\n\t * @param {String} commandName\n\t * @returns {Function}\n\t */\n\t_getPropertyChangeCallback( commandName ) {\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tthis.editor.execute( commandName, {\n\t\t\t\tvalue: newValue,\n\t\t\t\tbatch: this._undoStepBatch\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon {@link #view view's} property change:\n\t * * executes a related editor command with the new property value if the value is valid,\n\t * * or sets the error text next to the invalid field, if the value did not pass the validation.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.commandName\n\t * @param {module:ui/view~View} options.viewField\n\t * @param {Function} options.validator\n\t * @param {String} options.errorText\n\t * @returns {Function}\n\t */\n\t_getValidatedPropertyChangeCallback( { commandName, viewField, validator, errorText } ) {\n\t\tconst setErrorTextDebounced = debounce( () => {\n\t\t\tviewField.errorText = errorText;\n\t\t}, ERROR_TEXT_TIMEOUT );\n\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tsetErrorTextDebounced.cancel();\n\n\t\t\tif ( validator( newValue ) ) {\n\t\t\t\tthis.editor.execute( commandName, {\n\t\t\t\t\tvalue: newValue,\n\t\t\t\t\tbatch: this._undoStepBatch\n\t\t\t\t} );\n\n\t\t\t\tviewField.errorText = null;\n\t\t\t} else {\n\t\t\t\tsetErrorTextDebounced();\n\t\t\t}\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TablePropertiesEditing from './tableproperties/tablepropertiesediting';\nimport TablePropertiesUI from './tableproperties/tablepropertiesui';\n\n/**\n * The table properties feature. Enables support for setting properties of tables (size, border, background, etc.).\n *\n * Read more in the {@glink features/table#table-and-cell-styling-tools Table and cell styling tools} section.\n * See also the {@link module:table/tablecellproperties~TableCellProperties} plugin.\n *\n * This is a \"glue\" plugin that loads the\n * {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing table properties editing feature} and\n * the {@link module:table/tableproperties/tablepropertiesui~TablePropertiesUI table properties UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableProperties extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableProperties';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TablePropertiesEditing, TablePropertiesUI ];\n\t}\n}\n\n/**\n * The configuration of the table properties user interface (balloon). It allows to define:\n *\n * * The color palette for the table border color style field (`tableProperties.borderColors`),\n * * The color palette for the table background style field (`tableProperties.backgroundColors`).\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableProperties: {\n *\t\t\t\tborderColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t],\n *\t\t\t\tbackgroundColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t]\n *\t\t\t}\n *\t\t};\n *\n * **Note**: The configurations do not impact the data loaded into the editor,\n * i.e. they do not limit or filter the colors in the data. They are used only in the user interface\n * allowing users to pick colors in a more convenient way.\n *\n * The default color palettes for the table background and the table border are the same\n * ({@link module:table/utils/ui/table-properties~defaultColors check out their content}).\n *\n * Both color palette configurations must follow the\n * {@link module:table/table~TableColorConfig table color configuration format}.\n *\n * Read more about configuring the table feature in {@link module:table/table~TableConfig}.\n *\n * @member {Object} module:table/table~TableConfig#tableProperties\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tabletoolbar\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { WidgetToolbarRepository } from 'ckeditor5/src/widget';\nimport { getSelectedTableWidget, getTableWidgetAncestor } from './utils/ui/widget';\n\n/**\n * The table toolbar class. It creates toolbars for the table feature and its content (for now only for the table cell content).\n *\n * The table toolbar shows up when a table widget is selected. Its components (e.g. buttons) are created based on the\n * {@link module:table/table~TableConfig#tableToolbar `table.tableToolbar` configuration option}.\n *\n * Table content toolbar shows up when the selection is inside the content of a table. It creates its component based on the\n * {@link module:table/table~TableConfig#contentToolbar `table.contentToolbar` configuration option}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetToolbarRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n\n\t\tconst tableContentToolbarItems = editor.config.get( 'table.contentToolbar' );\n\n\t\tconst tableToolbarItems = editor.config.get( 'table.tableToolbar' );\n\n\t\tif ( tableContentToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'tableContent', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableContentToolbarItems,\n\t\t\t\tgetRelatedElement: getTableWidgetAncestor\n\t\t\t} );\n\t\t}\n\n\t\tif ( tableToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'table', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableToolbarItems,\n\t\t\t\tgetRelatedElement: getSelectedTableWidget\n\t\t\t} );\n\t\t}\n\t}\n}\n\n/**\n * Items to be placed in the table content toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * Assuming that you use the {@link module:table/tableui~TableUI} feature, the following toolbar items will be available\n * in {@link module:ui/componentfactory~ComponentFactory}:\n *\n * * `'tableRow'`,\n * * `'tableColumn'`,\n * * `'mergeTableCells'`.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\tcontentToolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.} module:table/table~TableConfig#contentToolbar\n */\n\n/**\n * Items to be placed in the table toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableToolbar: [ 'blockQuote' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.} module:table/table~TableConfig#tableToolbar\n */\n"],"sourceRoot":""}