UNPKG

devexpress-richedit

Version:

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

226 lines (225 loc) 12.4 kB
import { ModelScrollManager } from '../../scroll/model-scroll-manager'; import { ControlOptions } from '../../model/options/control'; import { Table } from '../../model/tables/main-structures/table'; import { TableCellUtils } from '../../model/tables/table-utils'; 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 { CommandBase, CommandOptions } from '../command-base'; import { SimpleCommandState } from '../command-states'; import { isDefined } from '@devexpress/utils/lib/utils/common'; import { TableNavDirection } from '../../selection/table-nav-direction'; import { TableCellSelectionState } from '../../selection/selection-state'; export class SelectTableCommandBase extends CommandBase { getState() { let state = new SimpleCommandState(this.isEnabled()); state.visible = this.selection.tableInfo.extendedData.numRows > 0; return state; } isEnabled() { return super.isEnabled() && ControlOptions.isEnabled(this.control.modelManager.richOptions.control.tables); } addSelection(firstPos, lastPos, isFirstSelection, visibleModelPosition = ModelScrollManager.StandartScrollPosition) { if (isFirstSelection) this.selection.deprecatedSetSelection(firstPos, lastPos, false, -1, true, true, false, visibleModelPosition); else { this.selection.changeState((newState) => { newState.addInterval(FixedInterval.fromPositions(Math.min(firstPos, lastPos), Math.max(firstPos, lastPos))).resetKeepX().setEndOfLine(false); newState.forwardDirection = lastPos >= firstPos; }); if (visibleModelPosition !== ModelScrollManager.DontChangeScrollPosition) { this.selection.scrollManager.setScroll(new ScrollState() .byModelPosition(this.selection) .setModelPosition(lastPos) .useStdRelativePosition() .useStdOffset()); } } } isEnabledInReadOnlyMode() { return true; } } export class SelectTableCellCommand extends SelectTableCommandBase { executeCore(_state, _options) { const tableInfo = this.selection.tableInfo; let selectedCell = null; let lastCell = null; let isFirstCell = true; tableInfo.extendedData.foreach(() => { }, (cellInfo) => { if (!selectedCell) selectedCell = cellInfo.cell; lastCell = cellInfo.cell; const firstPos = cellInfo.cell.startParagraphPosition.value; const lastPos = cellInfo.cell.endParagraphPosition.value; this.addSelection(firstPos, lastPos, isFirstCell); isFirstCell = false; }); if (selectedCell) { const newSelectionState = new TableCellSelectionState(selectedCell.startParagraphPosition.value, lastCell.startParagraphPosition.value); this.selection.changeState((newState) => newState.setTableSelectionInfo(newSelectionState)); } return true; } } export class ExtendSelectTableCellCommand extends SelectTableCellCommand { addSelection(firstPos, lastPos, _isFirstSelection) { this.selection.changeState((newState) => newState.addInterval(FixedInterval.fromPositions(firstPos, lastPos)) .resetKeepX().setEndOfLine(false)); } } export class SelectTableColumnCommand extends SelectTableCommandBase { DEPRECATEDConvertOptionsParameter(parameter) { if (parameter) return parameter; const columnIndices = []; const tableInfo = this.selection.tableInfo; const table = tableInfo.table; const columnIndicesMap = {}; tableInfo.extendedData.foreach(() => { }, (cellInfo, rowInfo) => { const startColumnIndex = tableInfo.gridInfoManager.tableCellInfos[rowInfo.rowIndex][cellInfo.cellIndex].getGridCellIndex(); for (let span = 0; span < cellInfo.cell.columnSpan; span++) { let columnIndex = startColumnIndex + span; if (!columnIndicesMap[columnIndex]) { columnIndices.push(columnIndex); columnIndicesMap[columnIndex] = true; } } }); return { table: table, columnIndices: columnIndices }; } executeCore(_state, options) { let table = options.param.table; let columnIndices = options.param.columnIndices; let isFirstItem = true; let prevAddedCell = null; for (let i = 0, columnIndex; (columnIndex = columnIndices[i]) !== undefined; i++) { for (let rowIndex = 0, row; row = table.rows[rowIndex]; rowIndex++) { let cellIndex = TableCellUtils.getCellIndexByColumnIndex(row, columnIndex); let cell = row.cells[cellIndex]; if (cell && prevAddedCell !== cell) { let firstPos = cell.startParagraphPosition.value; let lastPos = cell.endParagraphPosition.value; this.addSelection(firstPos, lastPos, isFirstItem, ModelScrollManager.DontChangeScrollPosition); isFirstItem = false; } prevAddedCell = cell; } } return true; } } export class ExtendSelectTableColumnCommand extends SelectTableColumnCommand { addSelection(firstPos, lastPos, _isFirstSelection) { this.selection.changeState((newState) => newState.addInterval(FixedInterval.fromPositions(firstPos, lastPos)) .resetKeepX().setEndOfLine(false)); } } export class SelectTableRowCommandOptions extends CommandOptions { constructor(control, table, rowIndices, forwardDirection) { super(control); if (table) { this.forwardDirection = forwardDirection; this.rows = ListUtils.map(rowIndices, (rowIndex) => table.rows[rowIndex]); } else { this.forwardDirection = control.selection.forwardDirection; this.rows = ListUtils.map(control.selection.tableInfo.extendedData.rows, (rowInfo) => rowInfo.row); } } } export class SelectTableRowCommand extends SelectTableCommandBase { executeCore(_state, options) { if (!options.isSetManually) { options = new SelectTableRowCommandOptions(this.control, null, [], false); } for (let i = 0, row; row = options.rows[i]; i++) this.addSelection(options.forwardDirection ? row.getStartPosition() : row.getEndPosition(), options.forwardDirection ? row.getEndPosition() : row.getStartPosition(), i === 0); return true; } } export class ExtendSelectTableRowCommand extends SelectTableRowCommand { addSelection(firstPos, lastPos, _isFirstSelection) { this.selection.changeState((newState) => newState.addInterval(FixedInterval.fromPositions(firstPos, lastPos)) .resetKeepX().setEndOfLine(false)); } } export class SelectTableCommand extends SelectTableCommandBase { executeCore(_state) { let table = Table.getTableByPosition(this.selection.activeSubDocument.tables, this.selection.intervals[0].start, true); if (!isDefined(table)) return false; let firstPos = table.getFirstCell().startParagraphPosition.value; let lastPos = table.getLastCell().endParagraphPosition.value; this.addSelection(firstPos, lastPos, true); return true; } } export class ExtendSelectTableCommand extends SelectTableCommand { addSelection(firstPos, lastPos, _isFirstSelection) { this.selection.changeState((newState) => newState.addInterval(FixedInterval.fromPositions(firstPos, lastPos)) .resetKeepX().setEndOfLine(false)); } } export class SelectTableCellsRangeCommand extends SelectTableCommandBase { executeCore(_state, options) { const parameter = options.param; let defaultAnchor; let defaultActive; let defaultEol; if (parameter.singleCellEntryDirection !== TableNavDirection.None && parameter.singleCellEntryDirection != null) { defaultAnchor = this.selection.anchorPosition; defaultEol = this.selection.endOfLine; if (this.selection.forwardDirection) { defaultActive = this.selection.lastSelectedInterval.end; } else { defaultActive = this.selection.lastSelectedInterval.start; } } else { defaultAnchor = this.selection.tableTextSelectionAnchorPosition; defaultActive = this.selection.tableTextSelectionActivePosition; defaultEol = this.selection.tableTextSelectionEndOfLine; } const textSelectionAnchorPosition = parameter.textSelectionAnchorPosition ?? defaultAnchor; const textSelectionActivePosition = parameter.textSelectionActivePosition ?? defaultActive; const textSelectionEndOfLine = parameter.textSelectionEndOfLine ?? defaultEol; let forwardDirection = parameter.firstCell.startParagraphPosition.value <= parameter.lastCell.startParagraphPosition.value; if (parameter.lastCell.parentRow.parentTable !== parameter.firstCell.parentRow.parentTable) throw new Error("cells should be from the same table"); let table = parameter.firstCell.parentRow.parentTable; let startColumnIndex = TableCellUtils.getStartColumnIndex(parameter.firstCell); let endColumnIndex = TableCellUtils.getStartColumnIndex(parameter.lastCell); let minColumnIndex = Math.min(startColumnIndex, endColumnIndex); let maxColumnIndex = Math.max(startColumnIndex + parameter.firstCell.columnSpan - 1, endColumnIndex + parameter.lastCell.columnSpan - 1); let startRowIndex = SearchUtils.normedInterpolationIndexOf(table.rows, r => r.getStartPosition(), parameter.firstCell.startParagraphPosition.value); let endRowIndex = SearchUtils.normedInterpolationIndexOf(table.rows, r => r.getStartPosition(), parameter.lastCell.startParagraphPosition.value); let minRowIndex = Math.min(startRowIndex, endRowIndex); let maxRowIndex = Math.max(startRowIndex, endRowIndex); let isFirstSelection = true; for (let rowIndex = minRowIndex; rowIndex <= maxRowIndex; rowIndex++) { let row = table.rows[rowIndex]; let columnIndex = Math.max(row.gridBefore, minColumnIndex); if (columnIndex > maxColumnIndex) continue; let cellIndex = TableCellUtils.getCellIndexByColumnIndex(row, columnIndex); while (columnIndex <= maxColumnIndex) { let cell = row.cells[cellIndex]; if (!cell) break; this.addSelection(forwardDirection ? cell.startParagraphPosition.value : cell.endParagraphPosition.value, forwardDirection ? cell.endParagraphPosition.value : cell.startParagraphPosition.value, isFirstSelection && !parameter.extendSelection); isFirstSelection = false; columnIndex += cell.columnSpan; cellIndex++; } } const isSingleCellSelection = parameter.firstCell.startParagraphPosition.value === parameter.lastCell.startParagraphPosition.value; const entryDirection = isSingleCellSelection ? (parameter.singleCellEntryDirection ?? TableNavDirection.None) : TableNavDirection.None; const shrinkDirection = isSingleCellSelection ? (parameter.singleCellShrinkDirection ?? TableNavDirection.None) : TableNavDirection.None; const newSelectionState = new TableCellSelectionState(parameter.firstCell.startParagraphPosition.value, parameter.lastCell.startParagraphPosition.value, entryDirection, shrinkDirection, textSelectionAnchorPosition, textSelectionActivePosition, textSelectionEndOfLine); this.selection.changeState((newState) => newState.setTableSelectionInfo(newSelectionState)); return true; } }