UNPKG

devexpress-richedit

Version:

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

437 lines (436 loc) 24 kB
import { createUnitConverter } from './utils/unit-converter'; import { DocumentFormat } from './document-format'; import { FileNameHelper } from './formats/file-name-helper'; import { FormatterManager } from './layout-formatter/managers/formatter-manager'; import { AnchorObjectsPositionInfo, DocumentLayout } from './layout/document-layout'; import { LayoutSelection } from './layout/selection/layout-selection'; import { Measurer } from './measurer/measurer'; import { FontInfoCache } from './model/caches/hashed-caches/font-info-cache'; import { CharacterPropertyDescriptor } from './model/character/character-property-descriptor'; import { DocumentModel } from './model/document-model'; import { IsModified } from './model/json/enums/json-top-level-enums'; import { RichUtils } from './model/rich-utils'; import { SubDocumentInterval, SubDocumentPosition } from './model/sub-document'; import { InnerClientProperties } from './rich-utils/inner-client-properties'; import { SpellCheckerLayoutChangesListener, SpellCheckerModelChangesListener } from './spelling/listeners'; import { Browser } from '@devexpress/utils/lib/browser'; import { PdfHelperFrame } from '@devexpress/utils/lib/pdf/helper-frame'; import { DomUtils } from '@devexpress/utils/lib/utils/dom'; import { afterFontsLoaded, fontWebApiAvailable } from '@devexpress/utils/lib/utils/fonts'; import { StringUtils } from '@devexpress/utils/lib/utils/string'; import { HtmlImporter } from './formats/html/import/html-importer'; import { AutoCorrectService } from './auto-correct/auto-correct-service'; import { SimpleViewCanvasSizeManager } from './canvas/renderes/common/document-renderer'; import { ViewManager } from './canvas/renderes/view-manager'; import { ClientSideEvents } from './client-side-events'; import { RichEditClientCommand } from './commands/client-command'; import { CommandBase, CommandSimpleOptions } from './commands/command-base'; import { UpdateFieldCommandParameters } from './commands/fields/update-field-command'; import { EventManager } from './event-manager'; import { FocusManager } from './focus-manager'; import { GlobalEventDispatcher } from './global-event-dispatcher'; import { InputController } from './input-controller'; import { ReadOnlyMode } from './interfaces/i-rich-edit-core'; import { HitTestManager } from './layout-engine/hit-test-manager/hit-test-manager'; import { SelectionFormatter } from './layout-engine/selection/selection-formatter'; import { BoxVisualizerManager } from './layout-engine/visualizers/box-visualizer-manager'; import { PopupMenuManager } from './popup-menu-manager'; import { ScrollFormatter } from './scroll/scroll-formatter'; import { InputPosition } from './selection/input-position'; import { InputPositionModelChangesListener } from './selection/input-position-model-changes-listener'; import { Selection } from './selection/selection'; import { SelectionModelChangesListener } from './selection/selection-model-changes-listener'; import { SpellCheckerSelectionChangesListener } from './spelling/spell-checker-selection-changes-listener'; import { HorizontalRulerControl } from './ui/ruler/ruler'; import { SearchManager } from './ui/search-manager'; import { isDefined } from '@devexpress/utils/lib/utils/common'; export class RichEditCore { get isReadOnlyPersistent() { return this.readOnly == ReadOnlyMode.Persistent; } get model() { return this.modelManager.model; } get isDisposed() { return this._isDisposed; } constructor(owner, name, element, clientGuid, readOnly, barHolder, unitsType, rulerSettings, richOptions, viewsSettings, stringResources) { this.isLoadingPictureFromClipboard = false; this.readOnly = ReadOnlyMode.None; this._isDisposed = false; this.lastSavedHistoryItemId = -1; if (this.isClientMode()) name = ""; this.beforeInitialization(richOptions); this.barHolder = barHolder; this.barHolder.initialize(this); CharacterPropertyDescriptor.fontInfo.defaultValue = FontInfoCache.defaultFontInfo; this.pdfHelperFrame = new PdfHelperFrame(element, "dxre-helperFrame"); this.owner = owner; this.clientGuid = clientGuid; this.readOnly = readOnly ? ReadOnlyMode.Persistent : ReadOnlyMode.None; this.modelManager = this.createModelManager(richOptions); this.stringResources = stringResources; this.measurer = new Measurer(name); this.boxVisualizerManager = new BoxVisualizerManager(this); this.eventManager = new EventManager(this, this.boxVisualizerManager); this.uiUnitConverter = createUnitConverter(unitsType); const viewElement = this.createViewElement(name, element); this.horizontalRulerControl = new HorizontalRulerControl(this, rulerSettings, viewElement); this.barHolder.horizontalRuler = this.horizontalRulerControl; this.inputController = new InputController(this, this.eventManager, viewElement); this.innerClientProperties = new InnerClientProperties(viewsSettings); this.viewManager = new ViewManager(this, viewElement, this.eventManager, this.stringResources, this.horizontalRulerControl, this.inputController, this.innerClientProperties, this, this, this.owner.internalApi, this.modelManager.richOptions.fields); this.loadingPanelManager = this.createLoadingPanelManager(); this.popupMenuManager = new PopupMenuManager(this.owner, this.viewManager, this.measurer, null); this.focusManager = new FocusManager(this.viewManager.canvasManager, this.owner, this.inputController, this.eventManager); this.commandManager = this.createCommandManager(); this.shortcutManager = this.createShortcutManager(); this.searchManager = new SearchManager(this); this.boxVisualizerManager.initListeners(this.viewManager); this.autoCorrectService = new AutoCorrectService(this, this.modelManager.richOptions.autoCorrect); this.clientSideEvents = new ClientSideEvents(this.owner); this.globalEventDispatcher = new GlobalEventDispatcher(this, () => { this.searchManager.raiseSearchReset(); this.clientSideEvents.raiseDocumentChanged(); }); this.simpleViewCanvasSizeManager = new SimpleViewCanvasSizeManager(this.viewManager.canvasManager, this); if (this.innerClientProperties.viewsSettings.isSimpleView) this.simpleViewCanvasSizeManager.setViewMode(true); if (fontWebApiAvailable()) afterFontsLoaded(() => { this.invalidateLayoutAfterFontsLoaded(); }); } beforeInitialization(_options) { } registerActiveContextTabManager() { } registerFontChangesListeners() { } initialize(sessionGuid, documentInfo, subDocumentsCounter, model, testMode = false) { this.closed = false; if (!model) model = new DocumentModel(this.modelManager.richOptions, subDocumentsCounter); this.setWorkSession(sessionGuid, documentInfo); this.modelManager.model = model; this.measurer.setCharacterPropertiesCache(this.modelManager.model.cache.mergedCharacterPropertiesCache); this.layout = new DocumentLayout(new AnchorObjectsPositionInfo(model)); this.selection = new Selection(this.modelManager.model, this.layout, this.modelManager.model.mainSubDocument); this.inputPosition = new InputPosition(this.selection); this.inputPositionModelChangesListener = new InputPositionModelChangesListener(this.inputPosition, this.selection); this.selection.inputPosition = this.inputPosition; this.popupMenuManager.setSelection(this.selection); this.selectionModelChangesListener = new SelectionModelChangesListener(this.selection); const layoutSelection = new LayoutSelection(this.selection.activeSubDocument.info, -1, this.innerClientProperties); this.viewManager.setWorkSession(this.layout, layoutSelection, this.modelManager.model.cache.imageCache); this.hitTestManager = new HitTestManager(this.layout, this.measurer); this.selectionFormatter = new SelectionFormatter(this.selection, this.measurer, layoutSelection, this.modelManager.richOptions.documentProtection); this.selectionFormatter.onSelectionLayoutChanged.add(this.viewManager); this.selection.onChanged.add(this.inputPositionModelChangesListener); this.selection.onChanged.add(this.selectionFormatter); this.selection.onChanged.add(this.boxVisualizerManager.fullTableSelectorVisualizer); this.selection.onSearchChanged.add(this.selectionFormatter); this.selection.onMisspelledSelectionChanged.add(this.selectionFormatter); this.scrollFormatter = new ScrollFormatter(this.selection); this.selection.scrollManager.onChanged.add(this.scrollFormatter); this.scrollFormatter.onScrollLayoutChanged.add(this.viewManager.canvasScrollManager); this.createSpellChecker(); this.layoutFormatterManager = new FormatterManager(this.measurer, this.innerClientProperties, this.modelManager.model, this.layout, this.selection, this.modelManager.richOptions.bookmarks, this.modelManager.richOptions.documentProtection, this.viewManager.canvasManager.controlHeightProvider, this.stringResources, [ this.viewManager, this.globalEventDispatcher, this.selectionFormatter, this.scrollFormatter, this.boxVisualizerManager.resizeBoxVisualizer, this.boxVisualizerManager.anchorVisualizer, this.boxVisualizerManager.fullTableSelectorVisualizer, new SpellCheckerLayoutChangesListener(this.spellChecker) ]); this.modelManager.modelManipulator.clearListeners(); this.modelManager.history.clear(); this.modelManager.modelManipulator.modelListeners.push(this.inputPositionModelChangesListener); this.modelManager.modelManipulator.modelListeners.push(this.layoutFormatterManager.modelChangesListener); this.modelManager.modelManipulator.modelListeners.push(this.selectionModelChangesListener); this.modelManager.modelManipulator.modelListeners.push(new SpellCheckerModelChangesListener(this.spellChecker)); if (this.barHolder.ribbon) this.modelManager.modelManipulator.modelListeners.push(this.barHolder.ribbon); this.modelManager.modelManipulator.modelListeners.push(this.barHolder.contextMenu); this.modelManager.modelManipulator.modelListeners.push(this.horizontalRulerControl); this.modelManager.modelManipulator.modelListeners.push(this.selectionFormatter); this.registerFontChangesListeners(); this.selection.onChanged.add(this.searchManager); this.selection.onChanged.add(this.boxVisualizerManager.resizeBoxVisualizer); this.selection.onChanged.add(this.boxVisualizerManager.anchorVisualizer); this.selection.onChanged.add(this.barHolder.contextMenu); if (this.barHolder.ribbon) this.selection.onChanged.add(this.barHolder.ribbon); this.barHolder.setEnabled(false); this.horizontalRulerControl.initialize(testMode); this.horizontalRulerControl.setEnable(false); this.selection.onChanged.add(this.horizontalRulerControl); this.spellChecker.initialize(this.selection.activeSubDocument); this.selection.onChanged.add(new SpellCheckerSelectionChangesListener(this.spellChecker)); this.selection.onChanged.add(this.globalEventDispatcher); this.selection.onChanged.add(this.barHolder.publicUiChangesListener); this.registerActiveContextTabManager(); this.modelManager.modelManipulator.modelListeners.push(this.globalEventDispatcher); this.modelManager.modelManipulator.modelListeners.push(this.barHolder.publicUiChangesListener); this.inputController.initExporter(); } dispose() { var _a, _b; if (this.isDisposed) return; this.pdfHelperFrame.dispose(); this.measurer.dispose(); this.horizontalRulerControl.dispose(); this.searchManager.dispose(); this.inputController.dispose(); this.viewManager.dispose(); this.layoutFormatterManager.dispose(); this.eventManager.dispose(); this.simpleViewCanvasSizeManager.dispose(); this.loadingPanelManager.dispose(); this.commandManager.dispose(); this.spellChecker.dispose(); this.selection.dispose(); (_b = (_a = this.barHolder).dispose) === null || _b === void 0 ? void 0 : _b.call(_a); this.modelManager = null; this.commandManager = null; this.shortcutManager = null; this.selection = null; this.inputPosition = null; this.hitTestManager = null; this.measurer = null; this.uiUnitConverter = null; this.horizontalRulerControl = null; this.spellChecker = null; this.autoCorrectService = null; this.searchManager = null; this.clientSideEvents = null; this.innerClientProperties = null; this.focusManager = null; this.inputController = null; this.layout = null; this.viewManager = null; this.layoutFormatterManager = null; this.barHolder = null; this.popupMenuManager = null; this.owner = null; this.eventManager = null; this.selectionFormatter = null; this.scrollFormatter = null; this.boxVisualizerManager = null; this.globalEventDispatcher = null; this.simpleViewCanvasSizeManager = null; this.selectionModelChangesListener = null; this.loadingPanelManager = null; this.inputPositionModelChangesListener = null; this._isDisposed = true; } beginUpdate() { var _a; this.layoutFormatterManager.beginUpdate(); this.selectionFormatter.beginUpdate(); this.scrollFormatter.beginUpdate(); this.viewManager.canvasManager.beginUpdate(); this.selectionModelChangesListener.beginUpdate(); this.selection.beginUpdate(); this.inputPositionModelChangesListener.beginUpdate(); (_a = this.barHolder.ribbon) === null || _a === void 0 ? void 0 : _a.beginUpdate(); this.barHolder.contextMenu.beginUpdate(); this.horizontalRulerControl.beginUpdate(); this.globalEventDispatcher.beginUpdate(); this.barHolder.publicUiChangesListener.beginUpdate(); } endUpdate() { var _a; this.layoutFormatterManager.endUpdate(); this.selectionFormatter.endUpdate(); this.scrollFormatter.endUpdate(); this.viewManager.canvasManager.endUpdate(); this.layoutFormatterManager.runFormattingAsync(); this.selectionModelChangesListener.endUpdate(); this.selection.endUpdate(); this.inputPositionModelChangesListener.endUpdate(); (_a = this.barHolder.ribbon) === null || _a === void 0 ? void 0 : _a.endUpdate(); this.barHolder.contextMenu.endUpdate(); this.horizontalRulerControl.endUpdate(); this.globalEventDispatcher.endUpdate(); this.barHolder.publicUiChangesListener.endUpdate(); } setPersistentReadOnly(readOnly) { if (readOnly) this.readOnly = ReadOnlyMode.Persistent; else if (!readOnly && this.readOnly === ReadOnlyMode.Persistent) { this.readOnly = ReadOnlyMode.None; this.inputController.inputEditor.initializeIfNotReadOnly(); } } setWorkSession(sessionGuid, documentInfo) { this.sessionGuid = sessionGuid; this.documentInfo = documentInfo; if (this.owner) this.owner.syncSessionGuid(sessionGuid); } beginLoading() { if (this.readOnly === ReadOnlyMode.None) { this.readOnly = ReadOnlyMode.Temporary; const ribbon = this.barHolder.ribbon; if (ribbon) { ribbon.suspendUpdate(); ribbon.updateItemsState(); ribbon.continueUpdate(); } this.loadingPanelManager.statusBarLoadingPanel.setVisible(true); } } endLoading() { if (this.readOnly === ReadOnlyMode.Temporary) { this.readOnly = ReadOnlyMode.None; const ribbon = this.barHolder.ribbon; if (ribbon) { ribbon.suspendUpdate(); ribbon.updateItemsState(); ribbon.continueUpdate(); } this.loadingPanelManager.statusBarLoadingPanel.setVisible(false); } } closeDocument() { this.selection.onChanged.remove(this.globalEventDispatcher); for (let ind = 0; ind < this.modelManager.modelManipulator.modelListeners.length; ind++) { if (this.modelManager.modelManipulator.modelListeners[ind] == this.globalEventDispatcher) { this.modelManager.modelManipulator.modelListeners.splice(ind, 1); break; } } this.barHolder.setEnabled(false); if (this.horizontalRulerControl) this.horizontalRulerControl.setEnable(false); this.layoutFormatterManager.closeDocument(); this.viewManager.closeDocument(); this.boxVisualizerManager.closeDocument(); this.closed = true; } importHtml(elements) { const interval = this.selection.lastSelectedInterval; this.beginUpdate(); var exportedRangeCopy = this.inputController.getExportedRangeCopy(); const charPropsBundle = this.inputPosition.charPropsBundle; const subDocument = this.selection.activeSubDocument; this.modelManager.history.beginTransaction(); CommandBase.addSelectionBefore(this); this.modelManager.modelManipulator.range.removeInterval(new SubDocumentInterval(subDocument, interval), true, true); let insertedInterval; if (exportedRangeCopy && this.isUsedInnerClipboard(elements)) insertedInterval = this.importInnerClipboard(exportedRangeCopy, this.selection); else { insertedInterval = new HtmlImporter(this.modelManager, this.measurer, new SubDocumentPosition(this.selection.activeSubDocument, interval.start), elements, charPropsBundle).import(); } const pos = subDocument.positionManager.registerPosition(insertedInterval.end); const afterUpdate = () => { CommandBase.addSelectionAfter(this, pos.value); subDocument.positionManager.unregisterPosition(pos); this.modelManager.history.endTransaction(); this.endUpdate(); }; const cmd = this.commandManager.getCommand(RichEditClientCommand.UpdateField); if (insertedInterval.length > 0 && this.modelManager.richOptions.fields.updateFieldsOnPaste && cmd.getState().enabled) { const params = new UpdateFieldCommandParameters(subDocument, [insertedInterval], () => afterUpdate()); params.options.updateFillIn = false; const opts = new CommandSimpleOptions(this, params); cmd.execute(this.commandManager.isPublicApiCall, opts); } else afterUpdate(); } importInnerClipboard(exportedRangeCopy, selection) { const interval = selection.lastSelectedInterval; const subDocument = this.selection.activeSubDocument; const insertPosition = new SubDocumentPosition(subDocument, interval.start); if (selection.tableInfo.isSelected) return exportedRangeCopy.insertToTable(this.modelManager.modelManipulator, insertPosition, selection.tableInfo); else return exportedRangeCopy.insertTo(this.modelManager.modelManipulator, insertPosition); } onViewTypeChanged() { this.viewManager.renderer.onViewTypeChanged(); this.horizontalRulerControl.onViewTypeChanged(); this.simpleViewCanvasSizeManager.setViewMode(this.innerClientProperties.viewsSettings.isSimpleView); } getModifiedState() { if (this.lastSavedHistoryItemId != this.modelManager.history.getCurrentItemId()) return IsModified.True; return IsModified.False; } setModifiedFalse() { this.lastSavedHistoryItemId = this.modelManager.history.getCurrentItemId(); } getGuidParams() { return { sguid: this.sessionGuid, cguid: this.clientGuid }; } isTouchMode() { return Browser.TouchUI && !Browser.MSTouchUI; } isRibbon(element) { return this.owner.isRibbon(element); } isClosed() { return this.closed; } invalidateLayoutAfterFontsLoaded() { if (!this.isDisposed && this.measurer && this.layoutFormatterManager && this.layoutFormatterManager.invalidator) { this.measurer.clearCache(); this.layoutFormatterManager.invalidator.onChangedAllLayout(); } } getExportModelOptions(initOptions = {}) { return { modelManager: isDefined(initOptions.modelManager) ? initOptions.modelManager : this.modelManager, pictureRenderer: this.viewManager.renderer, uiUnitConverter: this.uiUnitConverter, lastMaxNumPages: this.layout.lastMaxNumPages, pageIndex: this.selection.pageIndex, sessionGuid: this.sessionGuid, clientGuid: this.clientGuid, documentFormat: isDefined(initOptions.documentFormat) ? initOptions.documentFormat : this.getExportDocumentFormat(), }; } createViewElement(id, element) { const viewElement = document.createElement("DIV"); viewElement.id = id + "_View"; viewElement.className = "dxreView"; viewElement.tabIndex = 0; viewElement.setAttribute("role", "document"); element.appendChild(viewElement); return viewElement; } isUsedInnerClipboard(elements) { const elem = elements[0]; return elem && DomUtils.isHTMLElementNode(elem) && elem.id == RichUtils.getCopyPasteGuid(this.getGuidParams()); } getExportDocumentFormat() { const format = this.documentInfo.documentFormat; return format !== undefined && format !== null ? format : DocumentFormat.OpenXml; } } export class DocumentInfo { get fileName() { return this._fileName; } set fileName(val) { this._fileName = val; } get documentFormat() { return this._documentFormat; } set documentFormat(val) { if (typeof val === 'string') this._documentFormat = FileNameHelper.convertExtensionToDocumentFormat(val); else this._documentFormat = val; this._documentExtension = FileNameHelper.convertToString(val); } get documentExtension() { return this._documentExtension; } constructor(fileName, documentHasSource, documentFormat = DocumentInfo.defaultDocumentFormat, documentExtension = FileNameHelper.convertToString(documentFormat)) { this._fileName = fileName; this._documentFormat = documentFormat; this._documentExtension = documentExtension; this.documentHasSource = documentHasSource; } getFileNameForDownload(fileName) { if (!StringUtils.isNullOrEmpty(fileName)) return fileName; return StringUtils.isNullOrEmpty(this._fileName) ? DocumentInfo.defaultDocumentName : this._fileName; } } DocumentInfo.defaultDocumentName = 'document1'; DocumentInfo.defaultDocumentFormat = DocumentFormat.OpenXml;