devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
224 lines (223 loc) • 12.5 kB
JavaScript
import { CommandBase } from '../../common/commands/command-base';
import { SimpleCommandState } from '../../common/commands/command-states';
import { AlertMessageDialogParameters, AlertMessageText } from '../../common/commands/dialogs/dialog-alert-message-command';
import { DocumentInfo } from '../../common/rich-edit-core';
import { DocumentFormat, documentFormatIntoMimeType, mimeTypeIntoDocumentFormat } from '../../common/document-format';
import { FileNameHelper } from '../../common/formats/file-name-helper';
import { FontCorrector } from '../../common/model/creator/font-corrector';
import { FieldCodeParserHyperlink } from '../../common/model/fields/parsers/field-code-parser-hyperlink';
import { FieldCodeParserNumPages } from '../../common/model/fields/parsers/field-code-parser-num-pages';
import { FieldCodeParserPage } from '../../common/model/fields/parsers/field-code-parser-page';
import { FieldsWaitingForUpdate } from '../../common/model/fields/tree-creator';
import { updateFieldSequenceInfo } from '../../common/model/fields/update-sequence-info';
import { ChunkSizeCorrector } from '../../common/model/manipulators/text-manipulator/chunk-size-corrector';
import { ControlOptions, DocumentCapability } from '../../common/model/options/control';
import { Browser } from '@devexpress/utils/lib/browser';
import { Errors } from '@devexpress/utils/lib/errors';
import { Base64Utils } from '@devexpress/utils/lib/utils/base64';
import { isDefined, isString } from '@devexpress/utils/lib/utils/common';
import { FileUtils } from '@devexpress/utils/lib/utils/file';
import { NumberMapUtils } from '@devexpress/utils/lib/utils/map/number';
import { StringUtils } from '@devexpress/utils/lib/utils/string';
import { createImporter } from '../model-api/formats/importer';
import { NewDocumentCommand } from './new-document-command';
export class OpenDocumentCommand extends CommandBase {
constructor() {
super(...arguments);
this.suppressUpdateFields = false;
}
getState() {
var state = new SimpleCommandState(this.isEnabled());
state.visible = this.control.modelManager.richOptions.control.open !== DocumentCapability.Hidden;
return state;
}
executeCore(_state, options) {
if (this.control.getModifiedState() && !this.control.owner.confirmOnLosingChanges() ||
this.control.activeDocumentImporter)
return false;
const fileInfo = options.param;
if (fileInfo) {
const { file, documentFormat } = OpenDocumentCommand.getFileAndDocumentFormat(fileInfo);
const extension = OpenDocumentCommand.getDocumentExtensionByFileName(file.name);
const fileName = OpenDocumentCommand.getFileNameWithoutExtension(fileInfo.fileName);
return this.executeOpening(file, fileName, documentFormat, extension, fileInfo.callback);
}
else {
const input = document.createElement('input');
input.type = 'file';
input.accept = Browser.AndroidMobilePlatform ?
'text/plain,text/rtf,application/rtf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-word.document.macroEnabled.12' :
'.txt,.docx,.rtf,.docm,.html,.htm';
input.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
const format = OpenDocumentCommand.getDocumentFormatByFileName(file.name);
const extension = OpenDocumentCommand.getDocumentExtensionByFileName(file.name);
const fileName = OpenDocumentCommand.getFileNameWithoutExtension(file.name);
this.executeOpening(file, fileName, format, extension, null);
}
}, false);
input.click();
}
return true;
}
executeOpening(file, fileName, format, extension, callback) {
const core = this.control;
const throwInvalidFile = reason => {
throw new Error(Errors.InternalException + " " + reason);
};
core.activeDocumentImporter = createImporter(format, throwInvalidFile);
if (!core.activeDocumentImporter)
return false;
this.beforeOpen();
core.activeDocumentImporter.importFromFile(file, this.control.modelManager.richOptions, (documentModel, formatImagesImporter) => {
core.activeDocumentImporter = null;
this.openCore(fileName, format, documentModel, formatImagesImporter, extension);
if (!this.suppressUpdateFields)
this.updateSomeFields();
if (callback)
callback(true, null);
}, (reason) => {
core.activeDocumentImporter = null;
this.control.loadingPanelManager.loadingPanel.setVisible(false);
NewDocumentCommand.newDocumentInner.call(this);
if (callback)
callback(false, `Document importer error(${reason.toString()})`);
else
this.showErrorDialog();
});
return true;
}
showErrorDialog() {
const params = new AlertMessageDialogParameters();
params.messageTextId = AlertMessageText.DocumentImportError;
this.control.owner.showDialog("ErrorMessage", params, () => { }, () => { }, true);
}
updateSomeFields() {
this.control.beginUpdate();
NumberMapUtils.forEach(this.control.modelManager.model.subDocuments, (sd) => {
for (let field of sd.fields) {
const fieldParser = FieldsWaitingForUpdate.getParser(this.control.modelManager, this.control.layoutFormatterManager, this.control.createFieldRequestManager(), sd, field);
if ((fieldParser instanceof FieldCodeParserNumPages || fieldParser instanceof FieldCodeParserPage) && sd.isHeaderFooter() ||
fieldParser instanceof FieldCodeParserHyperlink && !field.getHyperlinkInfo()) {
fieldParser.parseCodeCurrentFieldInternal(null);
}
}
});
this.control.endUpdate();
this.control.modelManager.history.clear();
this.control.setModifiedFalse();
}
beforeOpen() {
this.control.closeDocument();
this.control.loadingPanelManager.loadingPanel.setVisible(true);
}
openCore(fileName, documentFormat, documentModel, formatImagesImporter, documentExtension) {
new ChunkSizeCorrector().correctChunkSizeAtChunkIndex(documentModel.mainSubDocument, 0);
new FontCorrector(this.control.modelManager.modelManipulator, documentModel, this.control.modelManager.richOptions.fonts).correct();
const documentInfo = new DocumentInfo(fileName, true, documentFormat, documentExtension);
this.control.initialize('', documentInfo, NumberMapUtils.mapLength(documentModel.subDocuments), documentModel);
updateFieldSequenceInfo(this.control.modelManager, this.control.layoutFormatterManager, this.control.createFieldRequestManager());
formatImagesImporter.import(this.control.modelManager.modelManipulator);
this.control.modelManager.modelManipulator.documentProtectionProperties.filterRangePermissions();
this.control.selection.beginUpdate();
const selectionUpdated = this.control.selection.changeState((newState) => newState.setPosition(0).resetKeepX().setEndOfLine(false)
.setPageIndex(-1).setSubDocument(this.control.modelManager.model.mainSubDocument));
this.control.layoutFormatterManager.openDocument();
this.control.inputPosition.reset();
this.control.layout.pageColor = documentModel.getActualPageBackgroundColor();
this.control.layoutFormatterManager.restartManager.restartFromPage(0, 0, true);
this.control.layoutFormatterManager.forceFormatPage(0);
this.control.barHolder.setEnabled(true);
this.control.horizontalRulerControl.setEnable(true);
this.control.selection.endUpdate();
if (!selectionUpdated)
this.control.selection.raiseSelectionChanged();
this.control.loadingPanelManager.loadingPanel.setVisible(false);
this.control.spellChecker.check();
this.control.layoutFormatterManager.runFormattingAsync();
this.control.barHolder.forceUpdate();
this.control.owner.raiseDocumentLoaded();
}
isEnabled() {
return super.isEnabled() && ControlOptions.isEnabled(this.control.modelManager.richOptions.control.open);
}
isEnabledInClosedDocument() {
return true;
}
isEnabledInReadOnlyMode() {
return true;
}
static getFileAndDocumentFormat(fileInfo) {
if (isString(fileInfo.fileContent)) {
let documentFormat;
const docFormatByMimeType = mimeTypeIntoDocumentFormat[Base64Utils.getKnownMimeType(fileInfo.fileContent)];
if (docFormatByMimeType !== undefined) {
documentFormat = docFormatByMimeType;
}
else {
documentFormat = isDefined(fileInfo.documentFormat) ?
fileInfo.documentFormat :
OpenDocumentCommand.getDocumentFormatByFileName(fileInfo.fileName);
}
const file = Base64Utils.getFileFromBase64(Base64Utils.deleteDataUrlPrefix(fileInfo.fileContent), '', {
type: documentFormatIntoMimeType[documentFormat]
});
return { file, documentFormat };
}
else if (FileUtils.isFile(fileInfo.fileContent)) {
let documentFormat;
if (isDefined(fileInfo.documentFormat)) {
documentFormat = fileInfo.documentFormat;
}
else {
const formatByMimeType = mimeTypeIntoDocumentFormat[fileInfo.fileContent.type];
if (formatByMimeType !== undefined) {
documentFormat = formatByMimeType;
}
else {
documentFormat = FileNameHelper.convertToDocumentFormat(fileInfo.fileContent.name);
if (documentFormat === DocumentFormat.Undefined)
documentFormat = OpenDocumentCommand.getDocumentFormatByFileName(fileInfo.fileName);
}
}
return { file: fileInfo.fileContent, documentFormat };
}
else if (fileInfo.fileContent instanceof Blob) {
const documentFormat = isDefined(fileInfo.documentFormat) ?
fileInfo.documentFormat :
OpenDocumentCommand.getDocumentFormatByFileName(fileInfo.fileName);
const file = FileUtils.createFile([fileInfo.fileContent], fileInfo.fileName, {
type: documentFormatIntoMimeType[documentFormat]
});
return { file, documentFormat };
}
else {
const documentFormat = isDefined(fileInfo.documentFormat) ?
fileInfo.documentFormat :
OpenDocumentCommand.getDocumentFormatByFileName(fileInfo.fileName);
return { file: FileUtils.createFile([fileInfo.fileContent], fileInfo.fileName, {
type: documentFormatIntoMimeType[documentFormat]
}), documentFormat };
}
}
static getDocumentFormatByFileName(fileName) {
const docFormatByFileName = FileNameHelper.convertToDocumentFormat(fileName);
return docFormatByFileName === DocumentFormat.Undefined ? DocumentFormat.OpenXml : docFormatByFileName;
}
static getDocumentExtensionByFileName(fileName) {
return FileNameHelper.convertToDocumentExtension(fileName);
}
static getFileNameWithoutExtension(fileName) {
const extension = OpenDocumentCommand.getDocumentExtensionByFileName(fileName);
return !!extension && StringUtils.endsAt(fileName, extension) ? fileName.slice(0, -extension.length) : fileName;
}
}
export class FileInfo {
constructor(callback, fileContent, fileName, documentFormat) {
this.callback = callback;
this.fileContent = fileContent;
this.fileName = fileName ? fileName : '';
this.documentFormat = documentFormat;
}
}