devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
136 lines (135 loc) • 7.31 kB
JavaScript
import { Flag } from '@devexpress/utils/lib/class/flag';
import { EnumUtils } from '@devexpress/utils/lib/utils/enum';
import { ListUtils } from '@devexpress/utils/lib/utils/list';
import { MathUtils } from '@devexpress/utils/lib/utils/math';
import { SearchUtils } from '@devexpress/utils/lib/utils/search';
import { DocumentLayoutDetailsLevel } from '../../layout/document-layout-details-level';
import { BookmarkBox, LayoutBookmarkBoxType } from '../../layout/main-structures/layout-boxes/bookmark-box';
import { AnchoredObjectLevelType } from '../../layout/main-structures/layout-boxes/layout-anchored-object-box';
import { LayoutBoxType } from '../../layout/main-structures/layout-boxes/layout-box';
import { LayoutRow, LayoutRowStateFlags } from '../../layout/main-structures/layout-row';
import { BoxAligner } from './utils/box-aligner';
export var RowFormatterResultFlag;
(function (RowFormatterResultFlag) {
RowFormatterResultFlag[RowFormatterResultFlag["None"] = 0] = "None";
RowFormatterResultFlag[RowFormatterResultFlag["NotEnoughChunks"] = 1] = "NotEnoughChunks";
})(RowFormatterResultFlag || (RowFormatterResultFlag = {}));
export var BoxBracketsType;
(function (BoxBracketsType) {
BoxBracketsType[BoxBracketsType["None"] = 0] = "None";
BoxBracketsType[BoxBracketsType["Open"] = 1] = "Open";
BoxBracketsType[BoxBracketsType["Close"] = 2] = "Close";
})(BoxBracketsType || (BoxBracketsType = {}));
export class RowFormatterResult {
get rowStartPos() {
return this.rowFormatter.rowSizesManager.rowStartPos;
}
constructor(rowFormatter, minY) {
this.rowFormatter = rowFormatter;
this.newAnchoredObjects = [];
this.row = new LayoutRow(minY);
this.startRowFormatting(true);
}
startRowFormatting(deleteAnchoredObjects) {
this.flags = new Flag(RowFormatterResultFlag.None);
this.row.boxes = [];
this.rowBoxIndexStart = 0;
if (deleteAnchoredObjects)
this.newAnchoredObjects = [];
}
finishLogicalRow(currLogicRowEndPos) {
if (this.rowBoxIndexStart == this.row.boxes.length)
return;
this.rowFormatter.tabInfo.shiftBoxesAfterLastTab();
const dontJustifyLinesEndingInSoftLineBreak = this.rowFormatter.manager.model.compatibilitySettings.dontJustifyLinesEndingInSoftLineBreak;
BoxAligner.align(this.row, this.rowFormatter.paragraphProps.alignment, currLogicRowEndPos, this.rowBoxIndexStart, dontJustifyLinesEndingInSoftLineBreak);
this.rowBoxIndexStart = this.row.boxes.length;
}
deleteSomeAnchorObjects(index, posToRestart) {
this.newAnchoredObjects.splice(index);
this.rowFormatter.iterator.setPosition(posToRestart, false, false);
}
finishRow() {
this.finishLogicalRow(this.rowFormatter.rowSizesManager.rowFormattingInfo.lastNonEmptyInterval.end);
const lastBoxOffset = ListUtils.last(this.row.boxes).rowOffset;
for (let ind = 0, anc; anc = this.newAnchoredObjects[ind]; ind++) {
if (anc.rowOffset > lastBoxOffset) {
this.deleteSomeAnchorObjects(ind, anc.rowOffset);
break;
}
if (anc.levelType == AnchoredObjectLevelType.InText) {
this.deleteSomeAnchorObjects(ind + 1, anc.rowOffset + 1);
break;
}
}
const paragraphs = this.rowFormatter.subDocument.paragraphs;
this.row.applySpacingAfter(this.row.flags.get(LayoutRowStateFlags.ParagraphEnd) ?
LayoutRow.getParagraphSpacingAfter(paragraphs[this.paragraphIndex], paragraphs[this.paragraphIndex + 1]) :
0);
const rowStartPos = this.rowFormatter.rowSizesManager.rowStartPos;
for (let box of this.row.boxes) {
box.x -= this.row.x;
box.rowOffset -= rowStartPos;
}
const rowLength = this.row.boxes.length ? ListUtils.last(this.row.boxes).getEndPosition() : 0;
this.addBrackets(rowStartPos, rowLength);
if (this.row.numberingListBox) {
this.row.numberingListBox.textBox.x -= this.row.x;
if (this.row.numberingListBox.separatorBox)
this.row.numberingListBox.separatorBox.x -= this.row.x;
}
this.row.columnOffset = rowStartPos -
this.rowFormatter.manager.activeFormatter.layoutPosition.getLogPosition(DocumentLayoutDetailsLevel.Column);
const pictBox = this.onlyInlinePictureBox();
if (pictBox && pictBox.width > this.row.width)
this.row.width = pictBox.width;
const currState = this.rowFormatter.rowSizesManager.heightCalculator.currState;
this.row.increaseRowHeightFromSpacingBeforeAndAfter(currState.maxAscent, currState.maxDescent);
}
onlyInlinePictureBox() {
let pictBox;
for (let ind = this.row.boxes.length - 1; ind >= 0; ind--) {
const box = this.row.boxes[ind];
if (box.getType() == LayoutBoxType.Picture) {
pictBox = box;
}
else if (!EnumUtils.isAnyOf(box.getType(), LayoutBoxType.ParagraphMark, LayoutBoxType.SectionMark, LayoutBoxType.LineBreak, LayoutBoxType.PageBreak)) {
return null;
}
}
return pictBox;
}
addBracketBox(boxType, color, x, layoutBox) {
const box = new BookmarkBox(boxType);
box.x = x - (boxType == LayoutBookmarkBoxType.EndBox ? BookmarkBox.DEFAULT_BORDER_WIDTH : 0);
box.y = this.row.baseLine - layoutBox.getAscent() - this.row.getSpacingBefore();
box.width = BookmarkBox.DEFAULT_WIDTH;
box.height = layoutBox.height;
box.color = color;
this.row.bookmarkBoxes.push(box);
}
addBrackets(rowStartPos, rowLength) {
if (!this.row.boxes[0])
return;
const rowEndPos = rowStartPos + rowLength;
ListUtils.forEach(this.rowFormatter.iterator.getBracketInfo(rowStartPos, rowLength), (info) => {
const posOfCharInRow = info.absPos - rowStartPos;
const box = this.getBracketBox(posOfCharInRow);
const xPos = this.getBracketXPosition(posOfCharInRow, box);
if (info.flags.get(BoxBracketsType.Open) && info.absPos < rowEndPos)
this.addBracketBox(LayoutBookmarkBoxType.StartBox, info.color, xPos, box);
if (info.flags.get(BoxBracketsType.Close) &&
(info.length != 0 && info.absPos > rowStartPos || info.length == 0 && info.absPos <= rowStartPos))
this.addBracketBox(LayoutBookmarkBoxType.EndBox, info.color, xPos + (info.length == 0 ? BookmarkBox.DEFAULT_BORDER_WIDTH : 0), box);
});
}
getBracketBox(posOfCharInRow) {
const boxes = this.row.boxes;
const boxIndex = Math.max(0, SearchUtils.normedInterpolationIndexOf(boxes, (b) => b.rowOffset, posOfCharInRow));
return boxes[boxIndex];
}
getBracketXPosition(posOfCharInRow, box) {
const charOffset = MathUtils.restrictValue(posOfCharInRow - box.rowOffset, 0, box.getLength());
return box.x + box.getCharOffsetXInPixels(this.rowFormatter.manager.measurer, charOffset);
}
}