devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
313 lines (312 loc) • 12.2 kB
JavaScript
import { Errors } from '@devexpress/utils/lib/errors';
import { IntervalAlgorithms } from '@devexpress/utils/lib/intervals/algorithms';
import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed';
import { StringUtils } from '@devexpress/utils/lib/utils/string';
import { LayoutTextBox } from '../../layout/main-structures/layout-boxes/layout-text-box';
import { ColumnChange } from '../changes/changes/column-change';
import { LayoutChangeType, RowChange } from '../changes/changes/layout-change-base';
import { PageAreaChange } from '../changes/changes/page-area-change';
import { PageChange } from '../changes/changes/page-change';
export class RemoveContentHelper {
static deleteInterval(layout, layoutPos, deletedInterval, pageChanges) {
RemoveContentHelper.deleteElementContent(0, [
new RemoveLayoutContent(FixedInterval.fromPositions(0, deletedInterval.end), pageChanges),
new RemovePageContent(layoutPos, layout.pages),
new RemovePageAreaContent(layoutPos),
new RemoveColumnContent(layoutPos),
new RemoveRowContent(layoutPos)
], deletedInterval);
}
static deleteElementContent(level, levelsInfo, deletedInterval) {
const currLevelInfo = levelsInfo[level];
currLevelInfo.contentDeleted = false;
let elementInterval = currLevelInfo.getElementInterval();
let elementStartPos = elementInterval.start;
let intersection = IntervalAlgorithms.getIntersection(elementInterval, deletedInterval);
let correctOffsets = false;
if (intersection && intersection.length > 0) {
if (elementInterval.length == intersection.length && level > 0) {
levelsInfo[level - 1].addChange(levelsInfo[level].deleteElement());
return true;
}
if (level + 1 == levelsInfo.length) {
const newRowLength = elementInterval.length - intersection.length;
const fakeBox = new LayoutTextBox(null, null, StringUtils.repeat(" ", newRowLength));
fakeBox.rowOffset = 0;
const row = currLevelInfo.getElement();
row.boxes = [fakeBox];
currLevelInfo.contentDeleted = true;
}
else {
const lowerLevelDeletedInterval = new FixedInterval(intersection.start - elementStartPos, intersection.length);
const nextLevelInfo = levelsInfo[level + 1];
if (level > 0)
currLevelInfo.assignChanges(levelsInfo[level - 1]);
while (nextLevelInfo.setElement()) {
if (!this.deleteElementContent(level + 1, levelsInfo, lowerLevelDeletedInterval))
nextLevelInfo.incElementIndex();
if (nextLevelInfo.contentDeleted) {
if (level == 1)
currLevelInfo.layoutPosition.page.isValid = false;
currLevelInfo.contentDeleted = true;
}
}
correctOffsets = true;
}
}
if (intersection) {
if (elementStartPos == intersection.start)
currLevelInfo.setElementOffset(deletedInterval.start);
}
else {
if (elementStartPos >= deletedInterval.end)
currLevelInfo.setElementOffset(Math.max(0, elementStartPos - deletedInterval.length));
}
if (correctOffsets)
currLevelInfo.correctOffsets();
if (level == 1) {
const change = currLevelInfo.updatePage(!!intersection);
if (change) {
levelsInfo[0].addChange(change);
return true;
}
}
return false;
}
}
class RemoveExistanceContent {
}
class RemoveLayoutContent extends RemoveExistanceContent {
constructor(delInterval, pageChanges) {
super();
this.delInterval = delInterval;
this.pageChanges = pageChanges;
}
setElement() {
return null;
}
incElementIndex() {
}
getElementInterval() {
return this.delInterval;
}
setElementOffset(_newOffset) {
}
deleteElement() {
return null;
}
correctOffsets() {
}
addChange(change) {
this.pageChanges.push(change);
}
assignChanges(_topLevel) {
}
}
class RemovePageContent extends RemoveExistanceContent {
constructor(layoutPosition, pages) {
super();
this.layoutPosition = layoutPosition;
this.pages = pages;
}
updatePage(isMarkPageIntervalsAsIncorrect) {
const page = this.layoutPosition.page;
if (isMarkPageIntervalsAsIncorrect)
page.markPageIntervalsAsIncorrect();
const pageIndex = this.layoutPosition.pageIndex;
const prevPage = this.pages[pageIndex - 1];
if (prevPage && page.getPosition() <= prevPage.getPosition()) {
page.index = pageIndex - 1;
page.y = page.index > 0 ? this.pages[page.index - 1].bottom : 0;
return this.deleteElement(page.index);
}
page.index = pageIndex;
page.y = prevPage ? prevPage.bottom : 0;
return null;
}
checkTableExceptionCase() {
const pageIndex = this.layoutPosition.pageIndex;
return pageIndex - 1 >= 0 && this.pages[pageIndex].getPosition() <= this.pages[pageIndex - 1].getPosition() ? this.deleteElement(pageIndex - 1) : null;
}
setElement() {
return !!(this.layoutPosition.page = this.pages[this.layoutPosition.pageIndex]);
}
incElementIndex() {
this.layoutPosition.pageIndex++;
}
getElementInterval() {
const elem = this.layoutPosition.page;
return FixedInterval.fromPositions(elem.getPosition(), elem.getEndPosition());
}
setElementOffset(newOffset) {
this.layoutPosition.page.setAbsolutePosition(newOffset);
}
deleteElement(index = this.layoutPosition.pageIndex) {
this.pages.splice(index, 1);
return new PageChange(index, LayoutChangeType.Deleted, [], []);
}
correctOffsets() {
RemovePageContent.correctPageOffsets(this.layoutPosition.page);
}
addChange(change) {
this.pageAreaChanges.push(change);
}
assignChanges(topLevel) {
this.pageAreaChanges = [];
topLevel.pageChanges.push(new PageChange(this.layoutPosition.pageIndex, LayoutChangeType.Updated, this.pageAreaChanges, []));
}
static correctPageOffsets(page) {
const pageAreas = page.mainSubDocumentPageAreas;
if (!pageAreas.length)
return;
const offsetFirstPageAreaFromPage = pageAreas[0].pageOffset;
if (offsetFirstPageAreaFromPage > 0) {
page.setAbsolutePosition(page.getPosition() + offsetFirstPageAreaFromPage);
for (let pageArea of pageAreas)
pageArea.pageOffset -= offsetFirstPageAreaFromPage;
}
}
}
class RemovePageAreaContent extends RemoveExistanceContent {
constructor(layoutPosition) {
super();
this.layoutPosition = layoutPosition;
}
setElement() {
if (this.layoutPosition.pageArea = this.layoutPosition.page.mainSubDocumentPageAreas[this.layoutPosition.pageAreaIndex])
return true;
else {
this.layoutPosition.pageAreaIndex = 0;
return false;
}
}
incElementIndex() {
this.layoutPosition.pageAreaIndex++;
}
getElementInterval() {
const elem = this.layoutPosition.pageArea;
return FixedInterval.fromPositions(elem.pageOffset, elem.getEndPosition());
}
setElementOffset(newOffset) {
this.layoutPosition.pageArea.pageOffset = newOffset;
}
deleteElement() {
const index = this.layoutPosition.pageAreaIndex;
this.layoutPosition.page.mainSubDocumentPageAreas.splice(index, 1);
return new PageAreaChange(index, LayoutChangeType.Deleted, []);
}
correctOffsets() {
RemovePageAreaContent.correctColumnOffsets(this.layoutPosition.pageArea);
}
addChange(change) {
this.columnChanges.push(change);
}
assignChanges(topLevel) {
this.columnChanges = [];
topLevel.pageAreaChanges.push(new PageAreaChange(this.layoutPosition.pageAreaIndex, LayoutChangeType.Updated, this.columnChanges));
}
static correctColumnOffsets(pageArea) {
const columns = pageArea.columns;
if (!columns.length)
return;
const offsetFirstColumnFromPageArea = columns[0].pageAreaOffset;
if (offsetFirstColumnFromPageArea > 0) {
pageArea.pageOffset += offsetFirstColumnFromPageArea;
for (let column of columns)
column.pageAreaOffset -= offsetFirstColumnFromPageArea;
}
}
}
class RemoveColumnContent extends RemoveExistanceContent {
constructor(layoutPosition) {
super();
this.layoutPosition = layoutPosition;
}
setElement() {
if (this.layoutPosition.column = this.layoutPosition.pageArea.columns[this.layoutPosition.columnIndex])
return true;
else {
this.layoutPosition.columnIndex = 0;
return false;
}
}
incElementIndex() {
this.layoutPosition.columnIndex++;
}
getElementInterval() {
const elem = this.layoutPosition.column;
return FixedInterval.fromPositions(elem.pageAreaOffset, elem.getEndPosition());
}
setElementOffset(newOffset) {
this.layoutPosition.column.pageAreaOffset = newOffset;
}
deleteElement() {
const index = this.layoutPosition.columnIndex;
this.layoutPosition.pageArea.columns.splice(index, 1);
return new ColumnChange(index, LayoutChangeType.Deleted, [], [], []);
}
correctOffsets() {
RemoveColumnContent.correctRowOffsets(this.layoutPosition.column);
}
addChange(change) {
this.rowChanges.push(change);
}
assignChanges(topLevel) {
this.rowChanges = [];
topLevel.columnChanges.push(new ColumnChange(this.layoutPosition.columnIndex, LayoutChangeType.Updated, this.rowChanges, [], []));
}
static correctRowOffsets(column) {
const rows = column.rows;
if (!rows.length)
return;
const offsetFirstRowFromColumn = rows[0].columnOffset;
if (offsetFirstRowFromColumn > 0) {
column.pageAreaOffset += offsetFirstRowFromColumn;
for (let row of rows)
row.columnOffset -= offsetFirstRowFromColumn;
}
}
}
class RemoveRowContent extends RemoveExistanceContent {
constructor(layoutPosition) {
super();
this.layoutPosition = layoutPosition;
}
getElement() {
return this.layoutPosition.row;
}
getElementParentContainer() {
return this.layoutPosition.column.rows;
}
setElement() {
if (this.layoutPosition.row = this.layoutPosition.column.rows[this.layoutPosition.rowIndex])
return true;
else {
this.layoutPosition.rowIndex = 0;
return false;
}
}
incElementIndex() {
this.layoutPosition.rowIndex++;
}
getElementInterval() {
const elem = this.layoutPosition.row;
return FixedInterval.fromPositions(elem.columnOffset, elem.getEndPosition());
}
setElementOffset(newOffset) {
if (newOffset < 0)
throw new Error(Errors.InternalException);
this.layoutPosition.row.columnOffset = newOffset;
}
deleteElement() {
const index = this.layoutPosition.rowIndex;
this.getElementParentContainer().splice(index, 1);
return new RowChange(index, LayoutChangeType.Deleted);
}
correctOffsets() {
}
addChange(_change) {
}
assignChanges(_topLevel) {
}
}