UNPKG

devexpress-richedit

Version:

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

294 lines (293 loc) 19 kB
import { BoxWrap } from '../../layout-formatter/box/box-wrap'; import { LayoutBox } from '../../layout/main-structures/layout-boxes/layout-box'; import { LayoutNumberingListBox } from '../../layout/main-structures/layout-boxes/layout-numbering-list-box'; import { LayoutTextBox } from '../../layout/main-structures/layout-boxes/layout-text-box'; import { LayoutRow } from '../../layout/main-structures/layout-row'; import { ColorModelInfo } from '../../model/color/color-model-info'; import { ListLevelFontBoldHistoryItem, ListLevelFontItalicHistoryItem, ListLevelFontNameHistoryItem, ListLevelFontSizeHistoryItem, ListLevelFontTextColorHistoryItem } from '../../model/history/items/list-level-character-properties-history-items'; import { ListLevelParagraphFirstLineIndentHistoryItem, ListLevelParagraphFirstLineIndentTypeHistoryItem, ListLevelParagraphLeftIndentHistoryItem } from '../../model/history/items/list-level-paragraph-properties-history-items'; import { ListLevelAlignmentHistoryItem, ListLevelDisplayFormatStringHistoryItem, ListLevelFormatHistoryItem, ListLevelSeparatorHistoryItem, ListLevelStartHistoryItem } from '../../model/history/items/list-level-properties-history-items'; import { AddAbstractNumberingListHistoryItem } from '../../model/history/items/numbering-list-history-items'; import { NumberConverterCreator } from '../../model/number-converters/number-converter-creator'; import { AbstractNumberingList, NumberingListBase, NumberingType } from '../../model/numbering-lists/numbering-list'; import { UnitConverter } from '@devexpress/utils/lib/class/unit-converter'; import { ColorUtils } from '@devexpress/utils/lib/utils/color'; import { RichEditClientCommand } from '../client-command'; import { CommandSimpleOptions } from '../command-base'; import { DialogParametersBase, ShowDialogCommandBase } from './show-dialog-command-base'; export class DialogCustomNumberingListCommand extends ShowDialogCommandBase { createParameters(options) { this.listType = options.param.listType; return options.param; } applyToCustomListLevels(sourcelevels, targetlevels, abstractNumberingListIndex) { const modelManipulator = this.modelManipulator; const history = this.history; for (let i = 0, length = targetlevels.length; i < length; i++) { const level = targetlevels[i]; const initLevel = sourcelevels[i]; if (level.displayFormatString != initLevel.displayFormatString) history.addAndRedo(new ListLevelDisplayFormatStringHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.displayFormatString)); if (level.format != initLevel.format) history.addAndRedo(new ListLevelFormatHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.format)); if (level.start != initLevel.start) history.addAndRedo(new ListLevelStartHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.start)); if (level.alignment != initLevel.alignment) history.addAndRedo(new ListLevelAlignmentHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.alignment)); if (level.separator != initLevel.separator) history.addAndRedo(new ListLevelSeparatorHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.separator)); if (level.leftIndent != initLevel.leftIndent) history.addAndRedo(new ListLevelParagraphLeftIndentHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.leftIndent, true)); if (level.firstLineIndent != initLevel.firstLineIndent) history.addAndRedo(new ListLevelParagraphFirstLineIndentHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.firstLineIndent, true)); if (level.firstLineIndentType != initLevel.firstLineIndentType) history.addAndRedo(new ListLevelParagraphFirstLineIndentTypeHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.firstLineIndentType, true)); const fontName = this.control.modelManager.model.cache.fontInfoCache.getItemByName(level.fontName); const initFontName = this.control.modelManager.model.cache.fontInfoCache.getItemByName(initLevel.fontName); if (fontName != initFontName) history.addAndRedo(new ListLevelFontNameHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, fontName, true)); if (ColorUtils.fromHashString(level.fontColor) != ColorUtils.fromHashString(initLevel.fontColor)) history.addAndRedo(new ListLevelFontTextColorHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, ColorModelInfo.makeByColor(ColorUtils.fromHashString(level.fontColor)), true)); if (level.fontSize != initLevel.fontSize) history.addAndRedo(new ListLevelFontSizeHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, level.fontSize, true)); const bold = !!(level.fontStyle & 1); const initBold = !!(initLevel.fontStyle & 1); if (bold != initBold) history.addAndRedo(new ListLevelFontBoldHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, bold, true)); const italic = !!(level.fontStyle & 2); const initItalic = !!(initLevel.fontStyle & 2); if (italic != initItalic) history.addAndRedo(new ListLevelFontItalicHistoryItem(modelManipulator, true, abstractNumberingListIndex, i, italic, true)); } } applyToListLevels(sourcelevels, targetlevels, abstractNumberingListIndex) { const numberingListManipulator = this.modelManipulator.numberingList; const activeSubDocument = this.selection.activeSubDocument; const model = activeSubDocument.documentModel; for (let i = 0, length = targetlevels.length; i < length; i++) { const targetLevel = targetlevels[i]; const sourceLevel = sourcelevels[i]; const levelPropertiesManipulator = numberingListManipulator.listLevelProperties; levelPropertiesManipulator.displayFormatString.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.displayFormatString); levelPropertiesManipulator.format.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.format); levelPropertiesManipulator.start.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.start); levelPropertiesManipulator.alignment.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.alignment); levelPropertiesManipulator.separator.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.separator); const paragraphManipulator = numberingListManipulator.listLevelParagraphProperties; paragraphManipulator.leftIndent.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.leftIndent, true); paragraphManipulator.firstLineIndent.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.firstLineIndent, true); paragraphManipulator.firstLineIndentType.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.firstLineIndentType, true); const listLevelCharacterProperties = numberingListManipulator.listLevelCharacterProperties; const fontInfo = targetLevel.getCharacterProperties().fontInfo.clone(); fontInfo.name = sourceLevel.fontName; listLevelCharacterProperties.fontName.setValue(model, true, abstractNumberingListIndex, i, fontInfo, true); listLevelCharacterProperties.fontSize.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.fontSize, true); listLevelCharacterProperties.fontBold.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.fontStyle == 1, true); listLevelCharacterProperties.fontItalic.setValue(model, true, abstractNumberingListIndex, i, sourceLevel.fontStyle == 2, true); } } applyCustomNumberingListParameters(initParams, newParams) { const activeSubDocument = this.selection.activeSubDocument; const firstParagraph = activeSubDocument.getParagraphByPosition(this.selection.intervals[0].start); const isMultilevel = this.listType == NumberingType.MultiLevel; if (initParams.equals(newParams) || isMultilevel) { this.control.commandManager.getCommand(RichEditClientCommand.InsertNumerationToParagraphs) .execute(this.control.commandManager.isPublicApiCall, new CommandSimpleOptions(this.control, newParams.initAbstractNumberingList)); if (isMultilevel) { const abstractNumberingListIndex = firstParagraph.getAbstractNumberingListIndex(); this.applyToListLevels(newParams.levels, newParams.initAbstractNumberingList.levels, abstractNumberingListIndex); } return; } let abstractNumberingList = null; let abstractNumberingListIndex = -1; if (this.selection.isCollapsed() && firstParagraph.isInList()) { abstractNumberingList = newParams.initAbstractNumberingList; abstractNumberingListIndex = firstParagraph.getNumberingList().abstractNumberingListIndex; newParams.applyToParagraph = false; } else { abstractNumberingList = new AbstractNumberingList(this.control.modelManager.model); abstractNumberingList.copyFrom(newParams.initAbstractNumberingList); this.history.addAndRedo(new AddAbstractNumberingListHistoryItem(this.modelManipulator, abstractNumberingList)); abstractNumberingListIndex = this.control.modelManager.model.abstractNumberingLists.length - 1; } this.applyToCustomListLevels(initParams.levels, newParams.levels, abstractNumberingListIndex); if (newParams.applyToParagraph) this.control.commandManager.getCommand(RichEditClientCommand.InsertNumerationToParagraphs) .execute(this.control.commandManager.isPublicApiCall, new CommandSimpleOptions(this.control, abstractNumberingList)); } applyParameters(_state, newParams) { const history = this.history; const initParams = new DialogCustomNumberingListParameters(); initParams.init(this.colorProvider, newParams.initAbstractNumberingList); history.beginTransaction(); this.applyCustomNumberingListParameters(initParams, newParams); history.endTransaction(); return true; } getDialogName() { switch (this.listType) { case NumberingType.Bullet: return "BulletedList"; case NumberingType.Simple: return "SimpleNumberingList"; case NumberingType.MultiLevel: return "MultiLevelNumberingList"; } return null; } } export class DialogCustomNumberingListParameters extends DialogParametersBase { constructor() { super(...arguments); this.currentLevel = 0; this.levels = []; this.coreInitialFontColors = []; this.applyToParagraph = true; } init(colorProvider, abstractNumberingList, currentLevel) { if (currentLevel != null) this.currentLevel = currentLevel; if (abstractNumberingList != null) { this.listType = abstractNumberingList.getListType(); this.initAbstractNumberingList = abstractNumberingList; for (var i = 0; i < abstractNumberingList.levels.length; i++) { var level = this.initLevel(colorProvider, abstractNumberingList.levels[i]); this.levels.push(level); } } } initLevel(colorProvider, listLevel) { const level = new CustomListlevel(); const listLevelProperties = listLevel.getListLevelProperties(); level.displayFormatString = listLevelProperties.displayFormatString; level.format = listLevelProperties.format; level.start = listLevelProperties.start; level.alignment = listLevelProperties.alignment; level.separator = listLevelProperties.separator; const paragraphProperties = listLevel.getParagraphProperties(); level.leftIndent = paragraphProperties.leftIndent; level.firstLineIndent = paragraphProperties.firstLineIndent; level.firstLineIndentType = paragraphProperties.firstLineIndentType; const characterProperties = listLevel.getCharacterProperties(); level.fontName = characterProperties.fontInfo.name; const foreColor = characterProperties.textColor.toRgb(colorProvider); level.fontColor = ColorUtils.colorToHash(foreColor); this.coreInitialFontColors.push(foreColor); level.fontSize = characterProperties.fontSize; level.fontStyle = (characterProperties.fontBold ? 1 : 0) | (characterProperties.fontItalic ? 2 : 0); return level; } copyFrom(obj) { super.copyFrom(obj); this.currentLevel = obj.currentLevel; this.listType = obj.listType; this.applyToParagraph = obj.applyToParagraph; this.copyLevelsFrom(obj.levels); } clone() { const newInstance = new DialogCustomNumberingListParameters(); newInstance.copyFrom(this); return newInstance; } applyConverter(_converter) { return this; } copyLevelsFrom(levels) { this.levels = []; for (var i = 0, length = levels.length; i < length; i++) { var level = new CustomListlevel(); level.copyFrom(levels[i]); this.levels.push(level); } } equals(obj) { for (var i = 0, level; level = obj.levels[i]; i++) { if (!level.equals(this.levels[i])) return false; } return true; } } export class CustomListlevel { copyFrom(obj) { this.displayFormatString = obj.displayFormatString; this.format = obj.format; this.start = obj.start; this.alignment = obj.alignment; this.separator = obj.separator; this.leftIndent = obj.leftIndent; this.firstLineIndent = obj.firstLineIndent; this.firstLineIndentType = obj.firstLineIndentType; this.fontName = obj.fontName; this.fontColor = obj.fontColor; this.fontSize = obj.fontSize; this.fontStyle = obj.fontStyle; } equals(obj) { return this.displayFormatString == obj.displayFormatString && this.format == obj.format && this.start == obj.start && this.alignment == obj.alignment && this.separator == obj.separator && this.leftIndent == obj.leftIndent && this.firstLineIndent == obj.firstLineIndent && this.firstLineIndentType == obj.firstLineIndentType && this.fontName == obj.fontName && this.fontColor == obj.fontColor && this.fontSize == obj.fontSize && this.fontStyle == obj.fontStyle; } } export class NumberingListFormPreviewHelper { constructor(richEdit, abstractNumberingList, currentLevel) { this.richEdit = richEdit; this.abstractNumberingList = abstractNumberingList; this.currentLevel = currentLevel; } createPreview() { var preview = document.createElement("div"); for (var i = 0; i < 4; i++) preview.appendChild(this.createRowElement(i)); return preview; } createRowElement(index) { var separatorWidth = 7; var rowHeight = 25; var margin = 10; var foreColor = 0xbbbbbbbb; var fakeString = "▬▬▬▬▬▬▬▬▬"; var isMultiLevel = this.abstractNumberingList.getListType() == NumberingType.MultiLevel; var currentLevelIndex = isMultiLevel ? index % NumberingListBase.depth : this.currentLevel; var currentMajorIndex = isMultiLevel ? Math.floor(index / NumberingListBase.depth) : index; var paragraphProperties = this.abstractNumberingList.levels[currentLevelIndex].getParagraphProperties(); var characterProperties = this.abstractNumberingList.levels[currentLevelIndex].getCharacterProperties(); var listBoxText = this.getNumberingListBoxText(currentLevelIndex, currentMajorIndex); var layoutNumberingListBox = new LayoutNumberingListBox(characterProperties, characterProperties.getLayoutColorInfo(this.richEdit.modelManager.model.colorProvider), listBoxText, ""); LayoutBox.initializeWithMeasurer([new BoxWrap(layoutNumberingListBox.textBox, null)], this.richEdit.measurer, false); var textBoxCharacterProperties = this.richEdit.modelManager.model.defaultCharacterProperties.clone(); textBoxCharacterProperties.textColor = ColorModelInfo.makeByColor(foreColor); var layoutTextBox = new LayoutTextBox(textBoxCharacterProperties, textBoxCharacterProperties.getLayoutColorInfo(this.richEdit.modelManager.model.colorProvider), fakeString); LayoutBox.initializeWithMeasurer([new BoxWrap(layoutTextBox, null)], this.richEdit.measurer, false); layoutTextBox.x = layoutNumberingListBox.textBox.width + separatorWidth; var layoutRow = new LayoutRow(); layoutRow.numberingListBox = layoutNumberingListBox; layoutRow.boxes.push(layoutTextBox); layoutRow.height = Math.max(layoutNumberingListBox.textBox.height, rowHeight); layoutRow.width = layoutNumberingListBox.textBox.width + layoutTextBox.width; layoutRow.x = isMultiLevel ? UnitConverter.twipsToPixels(paragraphProperties.leftIndent - paragraphProperties.firstLineIndent) + margin : margin; layoutRow.y = index * layoutRow.height + margin; return this.richEdit.viewManager.renderer.renderRow(layoutRow, 0); } getNumberingListBoxText(levelIndex, majorIndex) { const items = []; for (let j = 0; j <= levelIndex; j++) { const listLevelProperties = this.abstractNumberingList.levels[j].getListLevelProperties(); const converter = NumberConverterCreator.createConverter(listLevelProperties.format, this.richEdit.modelManager.model.simpleFormattersManager); items.push(converter.convertNumber(listLevelProperties.start + majorIndex)); } const displayFormatString = this.abstractNumberingList.levels[levelIndex].getListLevelProperties().displayFormatString; return this.richEdit.modelManager.model.simpleFormattersManager.formatString(displayFormatString, ...items); } }