devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
472 lines (471 loc) • 30.6 kB
JavaScript
import { EventDispatcher } from '../../utils/event-dispatcher';
import { MapCreator } from '../../utils/map-creator';
import { LayoutBoxIteratorMainSubDocument } from '../layout-box-iterator/layout-box-iterator-main-sub-document';
import { LayoutBoxIteratorOtherSubDocument } from '../layout-box-iterator/layout-box-iterator-other-sub-document';
import { LayoutPositionCreatorConflictFlags, LayoutPositionMainSubDocumentCreator, LayoutPositionOtherSubDocumentCreator } from '../layout-position-creator';
import { LayoutChangeType } from '../../layout-formatter/changes/changes/layout-change-base';
import { LayoutPageSelectionChange } from '../../layout-formatter/changes/changes/selection/layout-page-selection-change';
import { DocumentLayoutDetailsLevel } from '../../layout/document-layout-details-level';
import { LayoutBoxType } from '../../layout/main-structures/layout-boxes/layout-box';
import { LayoutRangePermissionItem, LayoutSelectionCursorItem, LayoutSelectionFloatingObjectItem, LayoutSelectionItem, LayoutSelectionMisspelledItem, LayoutSelectionSearchItem } from '../../layout/selection/layout-selection-items';
import { TableCellBoundFlags } from '../../layout/table/layout-table-cell-info';
import { ModelChangeType } from '../../model/changes/enums';
import { CharacterFormattingScript } from '../../model/character/enums';
import { Table } from '../../model/tables/main-structures/table';
import { Log } from '../../rich-utils/debug/logger/base-logger/log';
import { LogObjToStr } from '../../rich-utils/debug/logger/base-logger/log-obj-to-str';
import { LogSource } from '../../rich-utils/debug/logger/base-logger/log-source';
import { BatchUpdatableObject } from '@devexpress/utils/lib/class/batch-updatable';
import { UnitConverter } from '@devexpress/utils/lib/class/unit-converter';
import { Errors } from '@devexpress/utils/lib/errors';
import { Point } from '@devexpress/utils/lib/geometry/point';
import { Size } from '@devexpress/utils/lib/geometry/size';
import { IntervalAlgorithms } from '@devexpress/utils/lib/intervals/algorithms';
import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed';
import { EnumUtils } from '@devexpress/utils/lib/utils/enum';
import { ListUtils } from '@devexpress/utils/lib/utils/list';
import { NumberMapUtils } from '@devexpress/utils/lib/utils/map/number';
import { MathUtils } from '@devexpress/utils/lib/utils/math';
export var SimpleSelectionLayoutType;
(function (SimpleSelectionLayoutType) {
SimpleSelectionLayoutType[SimpleSelectionLayoutType["Search"] = 0] = "Search";
SimpleSelectionLayoutType[SimpleSelectionLayoutType["Misspelled"] = 1] = "Misspelled";
SimpleSelectionLayoutType[SimpleSelectionLayoutType["RangePermission"] = 2] = "RangePermission";
})(SimpleSelectionLayoutType || (SimpleSelectionLayoutType = {}));
export class SelectionFormatter extends BatchUpdatableObject {
get highlightRanges() { return this.documentProtectionSettings.highlightRanges; }
constructor(selection, measurer, layoutSelection, documentProtectionSettings) {
super();
this.onSelectionLayoutChanged = new EventDispatcher();
this.selection = selection;
this.measurer = measurer;
this.layoutSelection = layoutSelection;
this.documentProtectionSettings = documentProtectionSettings;
}
modelChanged(change) {
if (change.type == ModelChangeType.RangePermissionsPropertiesChanged)
this.onRangePermissionPropertiesChanged();
}
onRangePermissionPropertiesChanged() {
for (let pageInfo of this.layoutSelection.rangePermissionInfo.pageInfos)
pageInfo.beforeRecreatePageSelection();
if (this.highlightRanges) {
ListUtils.forEach(this.selection.layout.pages, (page) => {
this.buildRangePermissionSelection(this.selection.model.mainSubDocument, page.index);
NumberMapUtils.forEach(page.otherPageAreas, (pa) => this.buildRangePermissionSelection(pa.subDocument, this.selection.pageIndex));
});
}
else
this.layoutSelection.rangePermissionInfo.changes = [];
if (!this.isUpdateLocked())
this.raiseRangePermissionLayoutChanged();
}
NotifySelectionChanged(_selection) {
Log.print(LogSource.SelectionFormatter, "NotifySelectionChanged", () => `intervals: ${ListUtils.map(this.selection.intervals, (currI) => LogObjToStr.fixedInterval(currI)).join(" ")}, subDocId: ${this.selection.activeSubDocument.id}`);
this.updateSubDocumentInfo();
this.selectionChanged();
}
NotifySearchSelectionChanged() {
Log.print(LogSource.SelectionFormatter, "NotifySearchSelectionChanged", "");
this.layoutSelection.searchInfo.changes = [];
for (let pageInfo of this.layoutSelection.searchInfo.pageInfos)
pageInfo.beforeRecreatePageSelection();
const subDocument = this.selection.activeSubDocument;
this.createSimpleLayout(subDocument, this.intersectModelIntervalsWithValidPageIntervals(subDocument, this.selection.searchIntervals, this.layoutSelection.pageIndex), this.layoutSelection.searchInfo, SimpleSelectionLayoutType.Search);
if (!this.isUpdateLocked())
this.raiseSearchSelectionLayoutChanged();
}
NotifyMisspelledSelectionChanged() {
Log.print(LogSource.SelectionFormatter, "NotifyMisspelledSelectionChanged", "");
this.layoutSelection.misspelledInfo.changes = [];
for (let pageInfo of this.layoutSelection.misspelledInfo.pageInfos)
pageInfo.beforeRecreatePageSelection();
const subDocument = this.selection.activeSubDocument;
this.createSimpleLayout(subDocument, this.intersectModelIntervalsWithValidPageIntervals(subDocument, this.selection.misspelledIntervals, this.layoutSelection.pageIndex), this.layoutSelection.misspelledInfo, SimpleSelectionLayoutType.Misspelled);
if (!this.isUpdateLocked())
this.raiseMisspelledSelectionLayoutChanged();
}
NotifyPagesReady(pageChanges) {
Log.print(LogSource.SelectionFormatter, "NotifyPagesReady", "");
for (let pageChange of pageChanges) {
if (pageChange.changeType == LayoutChangeType.Deleted) {
this.layoutSelection.selectionInfo.pageInfos.splice(pageChange.index, 1);
this.layoutSelection.selectionInfo.changes.push(new LayoutPageSelectionChange(pageChange.index, LayoutChangeType.Deleted, []));
if (this.highlightRanges) {
this.layoutSelection.rangePermissionInfo.pageInfos.splice(pageChange.index, 1);
this.layoutSelection.rangePermissionInfo.changes.push(new LayoutPageSelectionChange(pageChange.index, LayoutChangeType.Deleted, []));
}
}
else {
this.buildPageSelection(pageChange.index);
if (this.highlightRanges) {
const pageInfo = this.layoutSelection.rangePermissionInfo.pageInfos[pageChange.index];
if (pageInfo)
pageInfo.beforeRecreatePageSelection();
this.buildRangePermissionSelection(this.selection.model.mainSubDocument, pageChange.index);
NumberMapUtils.forEach(this.selection.layout.pages[pageChange.index].otherPageAreas, (pa) => this.buildRangePermissionSelection(pa.subDocument, pageChange.index));
}
}
}
if (!this.isUpdateLocked()) {
this.raiseSelectionLayoutChanged();
if (this.highlightRanges)
this.raiseRangePermissionLayoutChanged();
else
this.layoutSelection.rangePermissionInfo.reset();
}
}
NotifyFullyFormatted(_pageCount) { }
;
onUpdateUnlocked(_occurredEvents) {
this.updateSubDocumentInfo();
Log.print(LogSource.SelectionFormatter, "onUpdateUnlocked", "");
this.raiseSelectionLayoutChanged();
this.raiseSearchSelectionLayoutChanged();
this.raiseMisspelledSelectionLayoutChanged();
if (this.highlightRanges)
this.raiseRangePermissionLayoutChanged();
else if (this.layoutSelection.rangePermissionInfo)
this.layoutSelection.rangePermissionInfo.reset();
}
selectionChanged() {
this.layoutSelection.selectionInfo.changes = [];
for (let pageInfo of this.layoutSelection.selectionInfo.pageInfos)
pageInfo.beforeRecreatePageSelection();
this.buildContiniousSelection();
if (!this.isUpdateLocked())
this.raiseSelectionLayoutChanged();
}
updateSubDocumentInfo() {
const needUpdate = this.layoutSelection.pageIndex != this.selection.pageIndex ||
this.layoutSelection.subDocumentInfo != this.selection.activeSubDocument.info;
if (needUpdate) {
this.layoutSelection.pageIndex = this.selection.pageIndex;
this.layoutSelection.subDocumentInfo = this.selection.activeSubDocument.info;
this.selectionChanged();
}
}
buildContiniousSelection() {
if (this.selection.isCollapsed())
this.createCollapsedSelectionLayout(-1);
else {
const layout = this.selection.layout;
const selIntervals = this.selection.intervals;
const subDoc = this.selection.activeSubDocument;
let validLayoutInterval;
if (subDoc.isMain())
validLayoutInterval = IntervalAlgorithms.getMergedIntervals(ListUtils.accumulate(layout.pages, [], (acc, page) => ListUtils.addListOnTail(acc, page.getContentIntervals()), 0, layout.validPageCount), true);
else {
if (this.selection.pageIndex < layout.validPageCount) {
const pageArea = layout.pages[this.selection.pageIndex].otherPageAreas[subDoc.id];
validLayoutInterval = pageArea ? [new FixedInterval(0, subDoc.getDocumentEndPosition())] : [];
}
else
validLayoutInterval = [];
}
for (let interval of IntervalAlgorithms.getIntersectionsTwoArraysOfInterval(validLayoutInterval, selIntervals))
this.createExtendedSelectionLayout(interval, this.layoutSelection.selectionInfo, selIntervals);
}
}
buildPageSelection(pageIndex) {
const selection = this.selection;
const pageInfo = this.layoutSelection.selectionInfo.pageInfos[pageIndex];
if (pageInfo)
pageInfo.beforeRecreatePageSelection();
if (selection.isCollapsed()) {
this.layoutSelection.selectionInfo.changes = [];
this.createCollapsedSelectionLayout(pageIndex);
}
else {
const page = selection.layout.pages[pageIndex];
const subDocument = selection.activeSubDocument;
let intersPageIntervalsAndSelectionIntervals = [];
if (subDocument.isMain())
intersPageIntervalsAndSelectionIntervals =
IntervalAlgorithms.getIntersectionsTwoArraysOfInterval(selection.intervals, page.getContentIntervals());
else if (page.otherPageAreas[subDocument.id] && pageIndex == selection.pageIndex)
intersPageIntervalsAndSelectionIntervals = selection.intervals;
for (let interval of intersPageIntervalsAndSelectionIntervals)
if (interval.length > 0)
this.createExtendedSelectionLayout(interval, this.layoutSelection.selectionInfo, selection.intervals);
}
}
buildRangePermissionSelection(subDocument, pageIndex) {
const selection = this.selection;
const page = selection.layout.pages[pageIndex];
const rpIntervals = ListUtils.map(subDocument.availableRangePermissions, (rp) => rp.interval);
const intersPageIntervalsAndSelectionIntervals = subDocument.isMain() ?
IntervalAlgorithms.getIntersectionsTwoArraysOfInterval(rpIntervals, page.getContentIntervals()) :
rpIntervals;
this.createSimpleLayout(subDocument, SelectionFormatter.translateInteralsToIterators(this.selection.layout, subDocument, pageIndex, intersPageIntervalsAndSelectionIntervals), this.layoutSelection.rangePermissionInfo, SimpleSelectionLayoutType.RangePermission);
}
createCollapsedSelectionLayout(dontCreateSelectionIfNotThisPageIndex) {
const selection = this.selection;
const selectionPosition = selection.intervals[0].start;
const layout = selection.layout;
const subDocument = selection.activeSubDocument;
const cursorPos = subDocument.isMain()
? new LayoutPositionMainSubDocumentCreator(layout, subDocument, selectionPosition, DocumentLayoutDetailsLevel.Character)
.create(new LayoutPositionCreatorConflictFlags().setDefault(selection.endOfLine), new LayoutPositionCreatorConflictFlags().setDefault(false))
: new LayoutPositionOtherSubDocumentCreator(layout, subDocument, selectionPosition, selection.pageIndex, DocumentLayoutDetailsLevel.Character)
.create(new LayoutPositionCreatorConflictFlags().setDefault(selection.endOfLine), new LayoutPositionCreatorConflictFlags().setDefault(false));
if (!cursorPos || dontCreateSelectionIfNotThisPageIndex >= 0 && cursorPos.pageIndex != dontCreateSelectionIfNotThisPageIndex ||
!cursorPos.page.isValid)
return;
let stepBackward = true;
while (EnumUtils.isAnyOf(cursorPos.box.getType(), LayoutBoxType.AnchorPicture, LayoutBoxType.AnchorTextBox)) {
if (stepBackward) {
if (!cursorPos.advanceToPrevBoxInRow())
stepBackward = false;
}
else {
if (!cursorPos.advanceToNextBoxInRow())
break;
}
}
const cellInfo = cursorPos.row.tableCellInfo;
if (cellInfo && cellInfo.boundFlags.get(TableCellBoundFlags.EndOnThisColumn)) {
const rowInfo = cellInfo.parentRow;
const tableGrid = rowInfo.parentTable.logicInfo.grid;
const cellGridInfo = tableGrid.tableCellGridInfos[rowInfo.rowIndex][cellInfo.cellGridIndex];
const cell = tableGrid.table.rows[cellGridInfo.getStartRowIndex()].cells[cellGridInfo.getCellIndex(0)];
if (selectionPosition == cell.endParagrapPosition.value - 1) {
for (let prevNestedTableColumnInfo of cursorPos.column.tablesInfo) {
if (prevNestedTableColumnInfo.logicInfo.grid.table.getEndPosition() == selectionPosition) {
const lastBorder = ListUtils.last(prevNestedTableColumnInfo.verticalBorders);
const prevLayoutRow = cursorPos.column.rows[cursorPos.rowIndex - 1];
const parMarkBoxHeight = cursorPos.row.boxes[0].height;
const floatingObjectId = SelectionFormatter.getFloatingObjId(subDocument, cursorPos.page);
const selectionCursor = new LayoutSelectionCursorItem();
selectionCursor.setPosition(new Point(cursorPos.pageArea.x + cursorPos.column.x + prevNestedTableColumnInfo.x + lastBorder.xPos + Math.max(1, lastBorder.borderInfo.width) + 1, cursorPos.pageArea.y + cursorPos.column.y + prevLayoutRow.bottom - parMarkBoxHeight));
selectionCursor.setSize(new Size(1, parMarkBoxHeight));
selectionCursor.floatingObjectId = floatingObjectId;
this.layoutSelection.selectionInfo.registerItem(cursorPos.pageIndex, selectionCursor);
return;
}
}
}
}
SelectionFormatter.setPositionOnVisibleBox(cursorPos);
if (cursorPos.row.height == 0 || cursorPos.row.width == 0)
return;
const floatingObjectId = SelectionFormatter.getFloatingObjId(subDocument, cursorPos.page);
const selectionCursor = LayoutSelectionItem.create(cursorPos, new Size(1, cursorPos.box.height), floatingObjectId, LayoutSelectionCursorItem);
selectionCursor.x += cursorPos.box.x + (cursorPos.box.isVisible() ? cursorPos.box.getCharOffsetXInPixels(this.measurer, cursorPos.charOffset) : 0);
selectionCursor.y += cursorPos.row.getSpacingBefore() + cursorPos.row.baseLine - cursorPos.box.getAscent() - cursorPos.row.getSpacingBefore();
if (cursorPos.box.characterProperties.script === CharacterFormattingScript.Subscript) {
const multiplier = cursorPos.box.characterProperties.fontInfo.scriptMultiplier;
selectionCursor.y += UnitConverter.pointsToPixelsF(cursorPos.box.characterProperties.fontSize) *
(cursorPos.box.characterProperties.fontInfo.subScriptOffset * multiplier - multiplier + 1);
}
this.layoutSelection.selectionInfo.registerItem(cursorPos.pageIndex, selectionCursor);
}
createExtendedSelectionLayout(interval, layoutSelectionInfo, allIntervals) {
const layout = this.selection.layout;
if (layout.pages.length == 0)
return;
const activeSubDocument = this.selection.activeSubDocument;
const isMainSubDoc = activeSubDocument.isMain();
const page = isMainSubDoc ? layout.getLastValidPage() : layout.pages[this.layoutSelection.pageIndex];
if (!page)
return;
if (this.selection.specialRunInfo.isPictureSelected() || (this.selection.specialRunInfo.isTextBoxSelected() && !activeSubDocument.isTextBox()))
return;
const startPos = interval.start;
const endPos = Math.min(interval.end, isMainSubDoc ? page.getEndPosition() : page.otherPageAreas[activeSubDocument.id].getEndPosition());
const iterator = isMainSubDoc ?
new LayoutBoxIteratorMainSubDocument(activeSubDocument, layout, startPos, endPos) :
new LayoutBoxIteratorOtherSubDocument(activeSubDocument, layout, startPos, endPos, this.layoutSelection.pageIndex);
if (!iterator.isInitialized())
throw new Error(Errors.InternalException);
let currentLayoutRow = null;
let currSelectionItem = null;
const selectedCellsCollector = new SelectedCellsCollector();
let currPageIndex = -1;
for (let isFirstBox = true; iterator.moveNext(new LayoutPositionCreatorConflictFlags().setDefault(!isFirstBox), new LayoutPositionCreatorConflictFlags().setDefault(true)); isFirstBox = false) {
if (currPageIndex < iterator.position.pageIndex) {
currPageIndex = iterator.position.pageIndex;
NumberMapUtils.forEach(iterator.position.page.anchoredObjectHolder.objects, (obj) => {
const pos = layout.anchorObjectsPositionInfo.getPosition(obj.objectId);
if (obj.belongsToSubDocId == this.layoutSelection.subDocumentInfo.subDocumentId &&
interval.containsInterval(new FixedInterval(pos, 1))) {
const ancObjSelItem = new LayoutSelectionFloatingObjectItem();
ancObjSelItem.copyFrom(obj.getOuterBounds(false));
layoutSelectionInfo.registerItem(currPageIndex, ancObjSelItem);
}
});
}
const currPosition = iterator.position;
const row = currPosition.row;
if (row.tableCellInfo) {
const cell = Table.getTableCellByPosition(activeSubDocument.tables, currPosition.getLogPosition(DocumentLayoutDetailsLevel.Box));
if (SelectionFormatter.isCellFullySelected(cell, allIntervals)) {
if (selectedCellsCollector.isNeedAddCellToSelection(cell, row.tableCellInfo)) {
currentLayoutRow = row;
const selectionBound = row.tableCellInfo.createRectangle();
selectionBound.x += currPosition.pageArea.x + currPosition.column.x;
selectionBound.y += currPosition.pageArea.y + currPosition.column.y;
currSelectionItem = new LayoutSelectionItem();
currSelectionItem.floatingObjectId = SelectionFormatter.getFloatingObjId(activeSubDocument, currPosition.page);
currSelectionItem.copyFrom(selectionBound);
layoutSelectionInfo.registerItem(currPosition.pageIndex, currSelectionItem);
}
continue;
}
}
const rightCharOffset = Math.min(endPos - currPosition.getLogPosition(DocumentLayoutDetailsLevel.Box), currPosition.box.getLength());
const currentBoxLeftOffsetX = currPosition.box.getCharOffsetXInPixels(this.measurer, currPosition.charOffset);
const currentBoxRightOffsetX = currPosition.box.getCharOffsetXInPixels(this.measurer, rightCharOffset);
const absRowOffsetX = currPosition.pageArea.x + currPosition.column.x + currPosition.row.x;
const absBoxOffsetX = currPosition.box.x + currentBoxLeftOffsetX + absRowOffsetX;
const thereIsGap = !!currSelectionItem && !MathUtils.numberCloseTo(absBoxOffsetX, currSelectionItem.x + currSelectionItem.width);
const isNeedCreateNewSelectionRow = row !== currentLayoutRow || thereIsGap;
if (isNeedCreateNewSelectionRow) {
currentLayoutRow = row;
const floatingObjectId = SelectionFormatter.getFloatingObjId(activeSubDocument, currPosition.page);
currSelectionItem = LayoutSelectionItem.create(currPosition, new Size(0, row.height), floatingObjectId, LayoutSelectionItem);
currSelectionItem.x += currPosition.box.x + currentBoxLeftOffsetX;
layoutSelectionInfo.registerItem(currPosition.pageIndex, currSelectionItem);
}
currSelectionItem.width += currentBoxRightOffsetX - currentBoxLeftOffsetX;
}
}
static isCellFullySelected(cell, allIntervals) {
if (!cell)
return false;
for (let interval of allIntervals)
if (cell.startParagraphPosition.value >= interval.start && cell.endParagrapPosition.value <= interval.end)
return true;
return false;
}
static translateInteralsToIterators(layout, subDocument, pageIndex, finalIntervals) {
const makeIter = subDocument.isMain() ?
(interval) => new LayoutBoxIteratorMainSubDocument(subDocument, layout, interval.start, interval.end) :
(interval) => new LayoutBoxIteratorOtherSubDocument(subDocument, layout, interval.start, interval.end, pageIndex);
return ListUtils.reducedMap(finalIntervals, (interval) => {
if (interval.length > 0) {
const iter = makeIter(interval);
return iter.isInitialized() ? iter : null;
}
return null;
});
}
intersectModelIntervalsWithValidPageIntervals(subDocument, modelIntervals, pageIndex) {
const layout = this.selection.layout;
if (layout.pages.length == 0)
return [];
if (subDocument.isMain()) {
const pageIntervals = ListUtils.accumulate(layout.pages, [], (acc, page) => ListUtils.addListOnTail(acc, page.getContentIntervals()), 0, layout.validPageCount);
const mergedIntervals = IntervalAlgorithms.getMergedIntervals(pageIntervals, true);
const finalIntervals = IntervalAlgorithms.getIntersectionsTwoArraysOfInterval(modelIntervals, mergedIntervals);
return SelectionFormatter.translateInteralsToIterators(this.selection.layout, subDocument, pageIndex, finalIntervals);
}
else {
const page = layout.pages[pageIndex];
if (!page || !page.otherPageAreas[subDocument.id])
return [];
return SelectionFormatter.translateInteralsToIterators(this.selection.layout, subDocument, pageIndex, modelIntervals);
}
}
createSimpleLayout(subDocument, iterators, layoutSelectionInfo, type) {
for (let iterator of iterators) {
let currentLayoutRow = null;
let currSelectionItem = null;
let color = this.documentProtectionSettings.rangeHighlightColor;
if (type == SimpleSelectionLayoutType.RangePermission) {
const currentInterval = new FixedInterval(iterator.intervalStart, iterator.intervalEnd - iterator.intervalStart);
const intersections = ListUtils.filter(subDocument.availableRangePermissions, (perm) => IntervalAlgorithms.getIntersection(perm.interval, currentInterval) != null);
if (intersections.length)
color = ListUtils.last(intersections).getRangePermissionColor(subDocument.documentModel, this.documentProtectionSettings);
}
for (let isFirstBox = true; iterator.moveNext(new LayoutPositionCreatorConflictFlags().setDefault(!isFirstBox), new LayoutPositionCreatorConflictFlags().setDefault(true)); isFirstBox = false) {
const currPosition = iterator.position;
const row = currPosition.row;
const rightCharOffset = Math.min(iterator.intervalEnd - currPosition.getLogPosition(DocumentLayoutDetailsLevel.Box), currPosition.box.getLength());
const currentBoxLeftOffsetX = currPosition.box.getCharOffsetXInPixels(this.measurer, currPosition.charOffset);
const currentBoxRightOffsetX = currPosition.box.getCharOffsetXInPixels(this.measurer, rightCharOffset);
const absRowOffsetX = currPosition.pageArea.x + currPosition.column.x + currPosition.row.x;
const absBoxOffsetX = currPosition.box.x + currentBoxLeftOffsetX + absRowOffsetX;
const thereIsGap = !!currSelectionItem && !MathUtils.numberCloseTo(absBoxOffsetX, currSelectionItem.x + currSelectionItem.width);
const isNeedCreateNewSelectionRow = row !== currentLayoutRow || thereIsGap;
if (isNeedCreateNewSelectionRow) {
currentLayoutRow = row;
const height = type == SimpleSelectionLayoutType.Misspelled ?
row.baseLine :
row.height - row.getSpacingAfter() - row.getSpacingBefore();
const yOffset = type == SimpleSelectionLayoutType.Misspelled ?
0 :
row.getSpacingBefore();
const floatingObjectId = SelectionFormatter.getFloatingObjId(subDocument, currPosition.page);
currSelectionItem = LayoutSelectionItem.create(currPosition, new Size(0, height), floatingObjectId, SelectionFormatter.itemConstructorsMap[type]);
if (type == SimpleSelectionLayoutType.RangePermission)
currSelectionItem.color = color;
currSelectionItem.x += currPosition.box.x + currentBoxLeftOffsetX;
currSelectionItem.y += yOffset;
layoutSelectionInfo.registerItem(currPosition.pageIndex, currSelectionItem);
}
currSelectionItem.width += currentBoxRightOffsetX - currentBoxLeftOffsetX;
}
}
}
raiseSelectionLayoutChanged() {
this.layoutSelection.selectionInfo.collectPageChanges(this.selection.layout);
this.layoutSelection.updatePageIndexWithSelection();
this.onSelectionLayoutChanged.listeners.forEach(listener => listener.NotifySelectionLayoutChanged());
}
raiseSearchSelectionLayoutChanged() {
this.layoutSelection.searchInfo.collectPageChanges(this.selection.layout);
this.onSelectionLayoutChanged.listeners.forEach(listener => listener.NotifySearchSelectionLayoutChanged());
}
raiseMisspelledSelectionLayoutChanged() {
this.layoutSelection.misspelledInfo.collectPageChanges(this.selection.layout);
this.onSelectionLayoutChanged.listeners.forEach(listener => listener.NotifyMisspelledSelectionLayoutChanged());
}
raiseRangePermissionLayoutChanged() {
this.layoutSelection.rangePermissionInfo.collectPageChanges(this.selection.layout);
this.onSelectionLayoutChanged.listeners.forEach(listener => listener.NotifyRangePermissionLayoutChanged());
}
static setPositionOnVisibleBox(cursorPos) {
if (cursorPos.charOffset != 0)
return;
for (let boxIndex = cursorPos.boxIndex - 1; boxIndex >= 0; boxIndex--) {
if (cursorPos.row.boxes[boxIndex].isVisible()) {
cursorPos.boxIndex = boxIndex;
cursorPos.box = cursorPos.row.boxes[cursorPos.boxIndex];
cursorPos.charOffset = cursorPos.box.getLength();
return;
}
}
}
static getFloatingObjId(subDocument, page) {
if (subDocument.isMain())
return LayoutSelectionItem.mainPageAreaSelection;
else if (subDocument.isHeaderFooter())
return LayoutSelectionItem.headerFooterPageAreaSelection;
else
return page.anchoredObjectHolder.getTextBoxByInternalSubDocId(subDocument.id).objectId;
}
}
SelectionFormatter.itemConstructorsMap = new MapCreator()
.add(SimpleSelectionLayoutType.Misspelled, LayoutSelectionMisspelledItem)
.add(SimpleSelectionLayoutType.RangePermission, LayoutRangePermissionItem)
.add(SimpleSelectionLayoutType.Search, LayoutSelectionSearchItem)
.get();
class SelectedCellsCollector {
constructor() {
this.fullySelectedCells = {};
}
isNeedAddCellToSelection(cell, cellInfo) {
const key = cell.endParagrapPosition.value;
const cellInfos = this.fullySelectedCells[key];
if (cellInfos === undefined) {
this.fullySelectedCells[key] = [cellInfo];
return true;
}
for (let info of cellInfos)
if (info === cellInfo)
return false;
cellInfos.push(cellInfo);
return true;
}
}