UNPKG

devexpress-richedit

Version:

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

239 lines (238 loc) 11.6 kB
import { ListUtils } from '@devexpress/utils/lib/utils/list'; import { NumberMapUtils } from '@devexpress/utils/lib/utils/map/number'; import { Grid } from '../../layout-formatter/table/grid-engine/grid'; import { RunType } from '../runs/run-type'; import { SubDocument } from '../sub-document'; import { Table } from '../tables/main-structures/table'; import { TableCellMergingState } from '../tables/secondary-structures/table-base-structures'; import { PositionChecker } from './position'; export var ModelCheckerResult; (function (ModelCheckerResult) { ModelCheckerResult[ModelCheckerResult["None"] = 0] = "None"; ModelCheckerResult[ModelCheckerResult["Run"] = 1] = "Run"; ModelCheckerResult[ModelCheckerResult["Paragraph"] = 2] = "Paragraph"; ModelCheckerResult[ModelCheckerResult["Chunk"] = 3] = "Chunk"; ModelCheckerResult[ModelCheckerResult["Section"] = 4] = "Section"; ModelCheckerResult[ModelCheckerResult["SubDocument"] = 5] = "SubDocument"; ModelCheckerResult[ModelCheckerResult["Field"] = 6] = "Field"; ModelCheckerResult[ModelCheckerResult["Table"] = 7] = "Table"; ModelCheckerResult[ModelCheckerResult["PositionManager"] = 8] = "PositionManager"; ModelCheckerResult[ModelCheckerResult["RangePermission"] = 9] = "RangePermission"; })(ModelCheckerResult || (ModelCheckerResult = {})); export class ModelChecker { constructor(model) { this.results = []; this.model = model; } checkAll() { if (ModelChecker.disableCheckModel) return true; this.check([ this.checkModelProps, this.checkParagraphs, this.checkChunks, this.checkSections, this.checkParagraphChunk, this.checkFields, this.checkTables, this.checkPositions ]); return !this.results.length; } check(checks) { for (let check of checks) { const result = check.call(this); if (result != ModelCheckerResult.None && result !== null) { this.results.push(result); break; } } } checkModelProps() { if (!this.model.mainSubDocument) return ModelCheckerResult.SubDocument; if (!this.model.subDocuments[SubDocument.MAIN_SUBDOCUMENT_ID]) return ModelCheckerResult.SubDocument; return ModelCheckerResult.None; } checkParagraphs() { return NumberMapUtils.unsafeAnyOf(this.model.subDocuments, sd => { if (!sd.paragraphs[0] || sd.paragraphs[0].startLogPosition.value != 0) return ModelCheckerResult.Paragraph; let parPos = 0; for (let par of sd.paragraphs) { if (par.startLogPosition.value != parPos || par.length < 1 || !sd.getRunByPosition(par.getEndPosition() - 1).isParagraphOrSectionRun()) return ModelCheckerResult.Paragraph; const checkTabsResult = this.checkTabs(par.tabs); if (checkTabsResult) return checkTabsResult; parPos += par.length; } return ModelCheckerResult.None; }); } checkTabs(tabs) { for (let tab of tabs.tabsInfo) { if (tab.leader === undefined) return ModelCheckerResult.Paragraph; } return ModelCheckerResult.None; } checkChunks() { return NumberMapUtils.unsafeAnyOf(this.model.subDocuments, sd => { if (!sd.chunks[0] && sd.chunks[0].startLogPosition.value != 0) return ModelCheckerResult.Chunk; let chunkPos = 0; for (let chunk of sd.chunks) { if (chunk.textBuffer.length < 1 || chunk.textRuns.length < 1 || chunk.startLogPosition.value != chunkPos) return ModelCheckerResult.Chunk; for (let run of chunk.textRuns) { if (!run.maskedCharacterProperties.fontInfo || !run.characterStyle) return ModelCheckerResult.Run; } chunkPos += chunk.textBuffer.length; } return ModelCheckerResult.None; }); } checkSections() { const mainSubDoc = this.model.mainSubDocument; if (!this.model.sections[0] || this.model.sections[0].startLogPosition.value != 0) return ModelCheckerResult.Section; let sectionPos = 0; for (let section of this.model.sections) { if (sectionPos != section.startLogPosition.value || section.getLength() < 1 || !mainSubDoc.getRunByPosition(section.getEndPosition() - 1).isParagraphOrSectionRun()) return ModelCheckerResult.Section; sectionPos += section.getLength(); } if (ListUtils.last(this.model.sections).getEndPosition() != ListUtils.last(mainSubDoc.paragraphs).getEndPosition()) return ModelCheckerResult.Section; return ModelCheckerResult.None; } checkParagraphChunk() { return NumberMapUtils.unsafeAnyOf(this.model.subDocuments, sd => { const lastPos = ListUtils.last(sd.paragraphs).getEndPosition(); if (lastPos != ListUtils.last(sd.chunks).getEndPosition()) return ModelCheckerResult.Chunk; return ModelCheckerResult.None; }); } checkFields() { return NumberMapUtils.unsafeAnyOf(this.model.subDocuments, sd => { const fieldsCopy = ListUtils.shallowCopy(sd.fields).sort((a, b) => a.getFieldStartPosition() - b.getFieldStartPosition()); if (!ListUtils.allOf2(fieldsCopy, sd.fields, (a, b) => a.index == b.index)) return ModelCheckerResult.Field; return ListUtils.unsafeAnyOf(sd.fields, (field, index) => { if (field.index != index) return ModelCheckerResult.Field; const result = this.checkField(sd, field); return result; }); }); } checkTables() { return NumberMapUtils.unsafeAnyOf(this.model.subDocuments, sd => { const tablesCopy = ListUtils.shallowCopy(sd.tables); tablesCopy.sort(Table.comparer); if (!ListUtils.allOf2(tablesCopy, sd.tables, (a, b) => a.index == b.index)) return ModelCheckerResult.Table; if (sd.tables.length != ListUtils.accumulateNumber(sd.tablesByLevels, tblOnLevel => tblOnLevel.length)) return ModelCheckerResult.Table; if (ListUtils.unsafeAnyOf(sd.tablesByLevels, tablesOnLevel => ListUtils.unsafeAnyOf(tablesOnLevel, (table, index) => table.getStartPosition() - tablesOnLevel[index - 1].getEndPosition() < 1, 1))) return ModelCheckerResult.Table; return ListUtils.unsafeAnyOf(sd.tables, (table, index) => { if (table.index != index) return ModelCheckerResult.Table; const result = this.checkTable(sd, table); return result; }); }); } checkField(sd, field) { const startPos = field.getFieldStartPosition(); const codeStartPos = field.getCodeStartPosition(); const sepPos = field.getSeparatorPosition(); const resultStartPos = field.getResultStartPosition(); const resultEndPos = field.getResultEndPosition(); const endPos = field.getFieldEndPosition(); if (!(startPos + 1 == codeStartPos && sepPos + 1 == resultStartPos && resultEndPos + 1 == endPos && sepPos > startPos && resultEndPos - sepPos > 0 && sd.getRunByPosition(startPos).getType() == RunType.FieldCodeStartRun && sd.getRunByPosition(sepPos).getType() == RunType.FieldCodeEndRun && sd.getRunByPosition(resultEndPos).getType() == RunType.FieldResultEndRun)) { return ModelCheckerResult.Field; } if (field.parent) { if (!this.isParentOfField(field, field.parent)) return ModelCheckerResult.Field; } return ModelCheckerResult.None; } isParentOfField(field, parent) { const allFieldInterval = field.getAllFieldInterval(); const parentInterval = field.getFieldStartPosition() < parent.getSeparatorPosition() ? parent.getCodeInterval() : parent.getResultInterval(); return allFieldInterval.start >= parentInterval.start && allFieldInterval.end <= parentInterval.end; } checkTable(sd, table) { if (table.parentCell) { if (!table.parentCell.interval.containsIntervalWithoutEnd(table.interval)) return ModelCheckerResult.Table; } if (!table.rows[0] || !table.rows[0].cells[0]) return ModelCheckerResult.Table; let cellPos = table.rows[0].cells[0].startParagraphPosition.value; const numLogicalColumns = table.rows[0].getTotalCellsInRowConsiderGrid(); for (let row, rowIndex = 0; row = table.rows[rowIndex]; rowIndex++) { if (row.getTotalCellsInRowConsiderGrid() != numLogicalColumns || !row.cells[0]) return ModelCheckerResult.Table; for (let cell, cellIndex = 0; cell = row.cells[cellIndex]; cellIndex++) { const cellInterval = cell.interval; if (cellInterval.start != cellPos || cellInterval.length < 1 || sd.getRunByPosition(cellInterval.end - 1).getType() != RunType.ParagraphRun || cell.columnSpan < 1) { return ModelCheckerResult.Table; } cellPos += cellInterval.length; } } const grid = new Grid(table); for (let row, rowIndex = 0; row = table.rows[rowIndex]; rowIndex++) { for (let cell, cellIndex = 0; cell = row.cells[cellIndex]; cellIndex++) { const info = grid.tableCellInfos[rowIndex][cellIndex]; switch (cell.verticalMerging) { case TableCellMergingState.None: { if (!(rowIndex == info.getStartRowIndex() && rowIndex + 1 == info.getEndRowIndex())) { return ModelCheckerResult.Table; } } break; case TableCellMergingState.Continue: if (!(rowIndex > info.getStartRowIndex() && rowIndex < info.getEndRowIndex())) { return ModelCheckerResult.Table; } break; case TableCellMergingState.Restart: if (!(rowIndex == info.getStartRowIndex() && info.getEndRowIndex() > rowIndex + 1)) { return ModelCheckerResult.Table; } break; default: return ModelCheckerResult.Table; } } } return ModelCheckerResult.None; } checkPositions() { return new PositionChecker(this.model).check() ? ModelCheckerResult.None : ModelCheckerResult.PositionManager; } } ModelChecker.disableCheckModel = false;