UNPKG

devexpress-richedit

Version:

DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.

176 lines (175 loc) 10.9 kB
import { LayoutPositionCreatorConflictFlags, LayoutPositionMainSubDocumentCreator, LayoutPositionOtherSubDocumentCreator } from '../../layout-engine/layout-position-creator'; import { DocumentLayoutDetailsLevel } from '../../layout/document-layout-details-level'; import { TableCellIterator } from '../../layout/table/table-cell-iterator'; import { TableCellUtils } from '../../model/tables/table-utils'; import { Errors } from '@devexpress/utils/lib/errors'; import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed'; import { ListUtils } from '@devexpress/utils/lib/utils/list'; import { SearchUtils } from '@devexpress/utils/lib/utils/search'; import { ScrollState } from '../../scroll/model-states'; import { RichEditClientCommand } from '../client-command'; import { SelectionCommandBase } from './selection-command-base'; export class GoToLineVerticallyCommandBase extends SelectionCommandBase { extendTableCellsSelection() { const currentLayoutPosition = this.getInitialLayoutPosition(); if (!currentLayoutPosition) return false; const cellIterator = new TableCellIterator(currentLayoutPosition, this.control.layout, this.control.measurer); const selectedCells = this.getSelectedCells(); const areCellsSelectedInSeries = this.selection.tableInfo.extendedData.areCellsSelectedInSeries; if (this.extendSelection() && (selectedCells.length > 1 || this.canGoToNextTableRow(cellIterator)) && areCellsSelectedInSeries) { let isForward = this.selection.isCollapsed() ? this.isForwardDirection() : this.selection.forwardDirection; let table = selectedCells[0][0].parentRow.parentTable; let currentRow = this.getCurrentTableRow(selectedCells); let currentRowIndex = SearchUtils.binaryIndexOf(table.rows, (row) => row.getStartPosition() - currentRow.getStartPosition()); if (this.checkTableRowIndex(currentRowIndex, table.rows.length)) { let nextRow = this.getNextTableRow(table, currentRowIndex); let firstSelectedCell = selectedCells[0][0]; let lastSelectedCell = selectedCells[selectedCells.length - 1][selectedCells[selectedCells.length - 1].length - 1]; return this.performTableCellsSelection(isForward, nextRow, firstSelectedCell, lastSelectedCell); } this.performSelectionOnTheLastTableRow(isForward, selectedCells); } return false; } getSelectedCells() { let selectedCells = ListUtils.map(this.selection.tableInfo.rawData.rows, (rowInfo) => ListUtils.map(rowInfo.cells, (cellInfo) => cellInfo.cell)); let position = LayoutPositionMainSubDocumentCreator.createLightLayoutPosition(this.control.layout, this.selection.activeSubDocument, this.getInitialSelectionEndPosition(), this.selection.pageIndex, DocumentLayoutDetailsLevel.Character, true, false); if (!selectedCells.length && position.row.tableCellInfo) { let modelTable = position.row.tableCellInfo.parentRow.parentTable.logicInfo.grid.table; let modelRowIndex = position.row.tableCellInfo.parentRow.rowIndex; selectedCells = []; for (let i = 0; i <= modelRowIndex; i++) selectedCells.push(modelTable.rows[i].cells); } return selectedCells; } getLogPositionByX(layoutPosition, x) { var newLayoutPosition = layoutPosition.clone(); var xOffsetBoxLevel = Math.max(0, x - (newLayoutPosition.page.x + newLayoutPosition.pageArea.x + newLayoutPosition.column.x + newLayoutPosition.row.x)); var boxIndex = SearchUtils.normedInterpolationIndexOf(newLayoutPosition.row.boxes, (b) => b.x, xOffsetBoxLevel); if (boxIndex < 0) boxIndex = 0; newLayoutPosition.box = newLayoutPosition.row.boxes[boxIndex]; var isNoVisibleBoxesInRow = false; if (!newLayoutPosition.box.isVisible()) { var lastVisibleBoxIndexInRow = newLayoutPosition.row.getLastVisibleBoxIndex(); if (lastVisibleBoxIndexInRow < 0) { lastVisibleBoxIndexInRow = 0; isNoVisibleBoxesInRow = true; } newLayoutPosition.boxIndex = lastVisibleBoxIndexInRow; newLayoutPosition.box = newLayoutPosition.row.boxes[lastVisibleBoxIndexInRow]; } var xOffsetCharLevel = isNoVisibleBoxesInRow ? 0 : xOffsetBoxLevel - newLayoutPosition.box.x; return newLayoutPosition.getLogPosition(DocumentLayoutDetailsLevel.Box) + newLayoutPosition.box.calculateCharOffsetByPointX(this.control.measurer, xOffsetCharLevel); } isEndOfLine(layoutPosition, position) { return position === layoutPosition.getLogPosition(DocumentLayoutDetailsLevel.Row) + layoutPosition.row.getLastBoxEndPositionInRow(); } selectTableCellsRange(parameters) { return this.control.commandManager.getCommand(RichEditClientCommand.SelectTableCellsRange).execute(this.control.commandManager.isPublicApiCall, parameters); } executeCore(_state, _options) { if (this.extendTableCellsSelection()) return true; var selection = this.selection; var layout = this.control.layout; var subDocument = this.selection.activeSubDocument; let initialLayoutPosition = this.getInitialLayoutPosition(); if (!initialLayoutPosition) return false; var keepX = selection.keepX; if (keepX < 0) keepX = initialLayoutPosition.page.x + initialLayoutPosition.pageArea.x + initialLayoutPosition.column.x + initialLayoutPosition.row.x + initialLayoutPosition.box.x + initialLayoutPosition.box.getCharOffsetXInPixels(this.control.measurer, initialLayoutPosition.charOffset); var newLayoutPosition; var cellIterator = new TableCellIterator(initialLayoutPosition, layout, this.control.measurer); if (this.canAdvanceToNextRow(cellIterator)) newLayoutPosition = cellIterator.getModifyPosition(); else { var currentPosition = initialLayoutPosition.getLogPosition(DocumentLayoutDetailsLevel.Character); newLayoutPosition = this.getNewLayoutPositionRowLevel(initialLayoutPosition); if (newLayoutPosition && this.extendSelection()) { var isEdgeDocumentPosition = currentPosition == 0 || currentPosition == subDocument.getDocumentEndPosition(); var needKeepCurrentLine = isEdgeDocumentPosition && currentPosition != this.getLogPositionByX(initialLayoutPosition, keepX); if (needKeepCurrentLine) newLayoutPosition = initialLayoutPosition.clone(); } else if (!newLayoutPosition) { var edgeLinePosition = this.getPositionForEdgeLine(initialLayoutPosition); if (this.extendSelection() && currentPosition != edgeLinePosition) { this.selection.changeState((newState) => newState.extendLastInterval(edgeLinePosition).setKeepX(keepX) .setEndOfLine(this.isEndOfLine(initialLayoutPosition, edgeLinePosition))); return true; } else if (!this.extendSelection()) { var lastInterval = selection.lastSelectedInterval; if (lastInterval && lastInterval.length > 0) selection.deprecatedSetSelection(edgeLinePosition, edgeLinePosition, this.isEndOfLine(initialLayoutPosition, edgeLinePosition), keepX, true); } return false; } } var newLogPosition = this.getLogPositionByX(newLayoutPosition, keepX); if (newLogPosition == initialLayoutPosition.getLogPosition()) return false; var endOfLine = this.isEndOfLine(newLayoutPosition, newLogPosition); if (this.extendSelection()) { this.selection.changeState((newState) => newState.extendLastInterval(newLogPosition).setKeepX(keepX).setEndOfLine(endOfLine)); this.selection.scrollManager.setScroll(new ScrollState() .byModelPosition(this.selection) .setModelPosition(newLogPosition) .useStdRelativePosition() .useStdOffset()); } else selection.deprecatedSetSelection(newLogPosition, newLogPosition, endOfLine, keepX, true); return true; } getInitialLayoutPosition() { const selection = this.selection; const subDocument = selection.activeSubDocument; const initialSelectionEndPosition = this.getInitialSelectionEndPosition(); const useBoxEndPos = selection.endOfLine; return (subDocument.isMain() ? new LayoutPositionMainSubDocumentCreator(this.control.layout, subDocument, initialSelectionEndPosition, DocumentLayoutDetailsLevel.Character) : new LayoutPositionOtherSubDocumentCreator(this.control.layout, subDocument, initialSelectionEndPosition, selection.pageIndex, DocumentLayoutDetailsLevel.Character)) .create(new LayoutPositionCreatorConflictFlags().setDefault(useBoxEndPos), new LayoutPositionCreatorConflictFlags().setDefault(false)); } canGoToNextTableRow(_cellInterator) { return false; } checkTableRowIndex(_rowIndex, _length) { throw new Error(Errors.NotImplemented); } getCurrentTableRow(_selectedCells) { throw new Error(Errors.NotImplemented); } getNextTableRow(_table, _rowIndex) { throw new Error(Errors.NotImplemented); } performTableCellsSelection(isForward, nextRow, firstCell, lastCell) { let lastSelectedCell = isForward ? lastCell : firstCell; let lastCellIndex = TableCellUtils.getCellIndexByColumnIndex(nextRow, TableCellUtils.getStartColumnIndex(lastSelectedCell)); const newFirstCell = isForward ? firstCell : lastCell; const newLastCell = nextRow.cells[lastCellIndex]; if (newFirstCell === newLastCell) { const firstPos = newFirstCell.startParagraphPosition.value; const lastPos = newFirstCell.endParagrapPosition.value - 1; this.selection.changeState(state => state.setInterval(FixedInterval.fromPositions(firstPos, lastPos)).setForwardDirection(isForward)); return true; } else return this.selectTableCellsRange({ firstCell: newFirstCell, lastCell: newLastCell }); } performSelectionOnTheLastTableRow(_isForward, _selectedCells) { throw new Error(Errors.NotImplemented); } isForwardDirection() { throw new Error(Errors.NotImplemented); } }