UNPKG

@syncfusion/ej2-documenteditor

Version:

Feature-rich document editor control with built-in support for context menu, options pane and dialogs.

1,098 lines 1.32 MB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import { TextPosition, ImageSizeInfo } from '../selection/selection-helper'; import { ParagraphWidget, LineWidget, ElementBox, TextElementBox, Margin, ImageElementBox, BlockWidget, BlockContainer, BodyWidget, TableWidget, TableCellWidget, TableRowWidget, Widget, ListTextElementBox, BookmarkElementBox, HeaderFooterWidget, FieldTextElementBox, TabElementBox, EditRangeStartElementBox, EditRangeEndElementBox, CommentElementBox, CommentCharacterElementBox, CheckBoxFormField, DropDownFormField, TextFormField, ShapeElementBox, TextFrame, ContentControl, FootnoteElementBox, FootNoteWidget, ShapeBase, FootnoteEndnoteMarkerElementBox, ContentControlProperties, CheckBoxState, ContentControlListItems, XmlMapping, FillFormat, LineFormat } from '../viewer/page'; import { WCharacterFormat } from '../format/character-format'; import { HelperMethods, Base64 } from './editor-helper'; import { isNullOrUndefined, Browser, classList, L10n } from '@syncfusion/ej2-base'; import { WParagraphFormat, WSectionFormat, WListFormat, WTableFormat, WRowFormat, WCellFormat, WBorder, WBorders, WTabStop } from '../index'; import { WList } from '../list/list'; import { WAbstractList } from '../list/abstract-list'; import { WListLevel } from '../list/list-level'; import { WLevelOverride } from '../list/level-override'; import { FieldElementBox } from '../viewer/page'; import { protectionTypeChangeEvent, imagesProperty, abstractListIdProperty, Comment, breakCodeProperty, nsidProperty, customXmlProperty } from '../../base/index'; import { SelectionCharacterFormat } from '../index'; import { PageLayoutViewer } from '../index'; import { WCharacterStyle, WStyles } from '../format/style'; import { HistoryInfo } from '../editor-history/index'; import { TableResizer } from './table-resizer'; import { Dictionary } from '../../base/dictionary'; import { WParagraphStyle } from '../format/style'; import { CONTROL_CHARACTERS } from '../../base/types'; import { showSpinner, hideSpinner } from '@syncfusion/ej2-popups'; import { DialogUtility } from '@syncfusion/ej2-popups'; import { Revision } from '../track-changes/track-changes'; import { XmlHttpRequestHandler } from '../../base/ajax-helper'; import { beforeCommentActionEvent, trackChangeEvent, beforeXmlHttpRequestSend, internalStyleCollectionChange } from '../../base/index'; import { SectionBreakType } from '../../base/types'; import { sectionsProperty, commentsProperty, revisionsProperty, lastParagraphMarkCopiedProperty, sectionFormatProperty, revisionIdProperty, paragraphFormatProperty, listsProperty, abstractListsProperty, listIdProperty, listFormatProperty, cellsProperty, rowsProperty, blocksProperty, stylesProperty, nameProperty, numberOfColumnsProperty } from '../../index'; import { SanitizeHtmlHelper } from '@syncfusion/ej2-base'; import { ChangesSingleView } from '../track-changes/track-changes-pane'; // Check box character is rendered smaller when compared to MS Word // So, mutiplied the font side by below factor to render check box character large. var CHECK_BOX_FACTOR = 1.35; /** * Editor module */ var Editor = /** @class */ (function () { /** * Initialize the editor module * * @param {DocumentHelper} documentHelper - Document helper * @private */ function Editor(documentHelper) { var _this = this; this.nodes = []; this.editHyperlinkInternal = false; /** * @private */ this.startParagraph = undefined; /** * @private */ this.endParagraph = undefined; this.formFieldCounter = 1; this.skipFieldDeleteTracking = false; this.skipFootNoteDeleteTracking = false; this.isForHyperlinkFormat = false; this.isTrackingFormField = false; this.isInsertText = false; this.casingIndex = -1; this.checkLastLetterSpace = ''; this.checkLastLetterSpaceDot = ''; this.pasteFootNoteType = ''; this.isInsertingText = false; this.isInternalPaste = false; /** * @private */ this.keywordIndex = 0; /** * @private */ this.dictionaryObjcetIDIncreament = 1; /** * @private */ this.dictionaryObjectIndexIncrement = 0; /** * @private */ this.XMLFilesCount = 1; /** * @private */ this.XMLFilesNameSpaceCount = 1; /** * @private */ this.xmlData = []; /** * @private */ this.dictionaryObject = []; /** * @private */ this.isFootnoteElementRemoved = false; /** * @private */ this.isEndnoteElementRemoved = false; /** * @private */ this.handledEnter = false; /** * @private */ this.handledTextInput = false; /** * @private */ this.removeEditRange = false; /** * @private */ this.isRemoveRevision = false; /** * @private */ this.isFootNoteInsert = false; /** * @private */ this.isTableInsert = false; /** * @private */ this.isFootNote = false; /** * @private */ this.isHandledComplex = false; /** * @private */ this.isUserInsert = false; /** * @private */ this.tableResize = undefined; /** * @private */ this.tocStyles = {}; /** * @private */ this.triggerPageSpellCheck = true; /** * @private */ this.chartType = false; /** * @private */ this.removedBookmarkElements = []; /** * @private */ this.removedEditRangeStartElements = []; /** * @private */ this.removedEditRangeEndElements = []; /** * @private */ this.removedContentControlElements = []; /** * @private */ this.tocBookmarkId = 0; /** * @private */ this.copiedData = undefined; /** * @private */ this.isPasteContentCheck = false; this.pageRefFields = {}; this.delBlockContinue = false; this.delBlock = undefined; this.delSection = undefined; /** * @private */ this.isInsertingTOC = false; /** * @private */ this.isMeasureParaWidth = false; this.editStartRangeCollection = []; this.skipReplace = false; this.skipTableElements = false; this.isPasteOverWriteCells = false; this.editRangeID = []; /** * @private */ this.isImageInsert = false; /** * @private */ this.isSkipOperationsBuild = false; /** * @private */ this.isCellFormatApplied = false; /** * @private */ this.revisionData = undefined; /** * @private */ this.splittedRevisions = []; /** * @private */ this.isSkipComments = false; /** * @private */ this.isRemoteAction = false; /** * @private */ this.isIncrementalSave = false; /** * @private */ this.listFormatInfo = undefined; /** * @private */ this.listLevelNumber = 0; /** * @private */ this.isXmlMapped = false; /** * @private */ this.restrictLayout = false; this.isAutoList = false; /** * @private */ this.isLastParaMarkCopied = false; this.combineLastBlock = false; /** * @private */ this.remotePasteRevision = []; /** * @private */ this.isFieldOperation = false; /** * @private */ this.decreasedIndent = false; /** * @private */ this.increasedIndent = false; /* eslint-disable @typescript-eslint/no-explicit-any */ /** * @private */ this.copiedContent = ''; /** * @private */ this.copiedTextContent = ''; /** * @private */ this.previousParaFormat = undefined; this.previousCharFormat = undefined; this.previousSectionFormat = undefined; this.pasteTextPosition = undefined; //public isSkipHistory: boolean = false; /** * @private */ this.isPaste = false; /** * @private */ this.isPasteListUpdated = false; /** * @private */ this.isHtmlPaste = false; /** * @private */ this.isInsertField = false; /** * @private */ this.isBordersAndShadingDialog = false; /** * @private */ this.pasteImageIndex = undefined; /** * @private * @returns {void} */ this.onTextInputInternal = function () { if (Browser.isDevice) { var documentHelper = _this.documentHelper; var nbsp = new RegExp(String.fromCharCode(160), 'g'); var lineFeed = new RegExp(String.fromCharCode(10), 'g'); documentHelper.prefix = documentHelper.prefix.replace(nbsp, ' ').replace(lineFeed, ' '); var text = documentHelper.editableDiv.textContent.replace(nbsp, ' ').replace(lineFeed, ' '); var textBoxText = text.substring(2); if (documentHelper.isCompositionStart && documentHelper.isCompositionUpdated) { documentHelper.isCompositionUpdated = false; if (!documentHelper.owner.isReadOnlyMode && documentHelper.owner.isDocumentLoaded && _this.canEditContentControl) { if (documentHelper.prefix.substring(2) !== textBoxText) { if (_this.selection.isEmpty) { /* eslint-disable-next-line max-len */ _this.selection.start.setPositionForLineWidget(documentHelper.selection.start.currentWidget, _this.selection.start.offset - (documentHelper.prefix.length - 2)); _this.handleTextInput(textBoxText); documentHelper.prefix = '@' + String.fromCharCode(160) + textBoxText; } else { _this.handleTextInput(textBoxText); documentHelper.prefix = '@' + String.fromCharCode(160) + textBoxText; } } } return; } else if (documentHelper.isCompositionStart && documentHelper.isCompositionEnd && documentHelper.suffix === '') { if (documentHelper.prefix.substring(2) !== textBoxText) { if (_this.selection.isEmpty && documentHelper.isCompositionStart) { documentHelper.isCompositionStart = false; /* eslint-disable-next-line max-len */ _this.selection.start.setPositionForLineWidget(documentHelper.selection.start.currentWidget, _this.selection.start.offset - documentHelper.prefix.substring(2).length); _this.selection.retrieveCurrentFormatProperties(); if (documentHelper.suffix === '' || textBoxText === '') { _this.handleTextInput(textBoxText); } } else if (!_this.selection.isEmpty) { documentHelper.isCompositionStart = false; _this.handleTextInput(textBoxText); } } else if (textBoxText === '') { documentHelper.isCompositionStart = false; _this.handleBackKey(); } else if (documentHelper.prefix.substring(2) === textBoxText && documentHelper.suffix === '') { documentHelper.isCompositionStart = false; _this.handleTextInput(' '); } documentHelper.isCompositionEnd = false; return; } else if (documentHelper.isCompositionEnd || documentHelper.isCompositionStart && !documentHelper.isCompositionUpdated) { if (textBoxText.length < documentHelper.prefix.length && /* eslint-disable-next-line max-len */ textBoxText === documentHelper.prefix.substring(2, documentHelper.prefix.length - 1) || documentHelper.editableDiv.innerText.length < 2) { _this.handleBackKey(); return; } else if (documentHelper.suffix !== '' && documentHelper.editableDiv.innerText[documentHelper.editableDiv.innerText.length - 1] !== String.fromCharCode(160)) { documentHelper.isCompositionStart = false; //When cursor is placed in between a word and chosen a word from predicted words. /* eslint-disable-next-line max-len */ _this.selection.start.setPositionForLineWidget(documentHelper.selection.start.currentWidget, _this.selection.start.offset - (documentHelper.prefix.length - 2)); /* eslint-disable-next-line max-len */ _this.selection.end.setPositionForLineWidget(documentHelper.selection.end.currentWidget, _this.selection.end.offset + documentHelper.suffix.length); //Retrieve the character format properties. Since the selection was changed manually. _this.selection.retrieveCurrentFormatProperties(); _this.handleTextInput(textBoxText); return; } } if (text !== '\r' && text !== '\b' && text !== String.fromCharCode(27) && !documentHelper.owner.isReadOnlyMode && documentHelper.isControlPressed === false && _this.canEditContentControl) { if (text === '@' || text[0] !== '@' || text === '' || text.length < documentHelper.prefix.length && textBoxText === documentHelper.prefix.substring(2, documentHelper.prefix.length - 1)) { _this.handleBackKey(); if (documentHelper.editableDiv.innerText.length < 2) { _this.predictText(); } } else if (text.indexOf(documentHelper.prefix) === 0 && text.length > documentHelper.prefix.length) { _this.handleTextInput(text.substring(documentHelper.prefix.length)); } else if (text.indexOf(documentHelper.prefix) === -1 && text[text.length - 1] !== String.fromCharCode(160) && text[text.length - 1] !== ' ') { if ((textBoxText.charAt(0).toLowerCase() + textBoxText.slice(1)) === documentHelper.prefix.substring(2)) { /* eslint-disable-next-line max-len */ _this.selection.start.setPositionParagraph(documentHelper.selection.start.currentWidget, _this.selection.start.offset - (documentHelper.prefix.length - 2)); } _this.handleTextInput(textBoxText); } else if (text.length !== 2) { _this.handleTextInput(' '); } } } else { var text = _this.documentHelper.editableDiv.innerText; if (text !== String.fromCharCode(160)) { if (text !== '\r' && text !== '\b' && text !== String.fromCharCode(27) && !_this.owner.isReadOnlyMode && _this.documentHelper.isControlPressed === false && _this.canEditContentControl) { _this.handleTextInput(text); } } else { _this.handleTextInput(' '); } _this.documentHelper.editableDiv.innerText = ''; } }; /** * Fired on paste. * * @param {ClipboardEvent} event - Specfies clipboard event * @private * @returns {void} */ this.onPaste = function (event) { if (!_this.owner.isReadOnlyMode && _this.canEditContentControl) { _this.pasteInternal(event); } event.preventDefault(); }; this.documentHelper = documentHelper; if (!isNullOrUndefined(this.documentHelper)) { this.tableResize = new TableResizer(this.documentHelper.owner); } this.base64 = new Base64(); } Object.defineProperty(Editor.prototype, "restrictFormatting", { /** * @private * @returns {boolean} - Returns the restrict formatting */ get: function () { return this.documentHelper.isDocumentProtected && (this.documentHelper.restrictFormatting || (!this.documentHelper.restrictFormatting && !this.selection.isSelectionInEditRegion())) && this.documentHelper.protectionType !== 'RevisionsOnly'; }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "restrictEditing", { /** * @private * @returns {boolean} - Returns the restrict editing */ get: function () { return this.documentHelper.isDocumentProtected && ((this.documentHelper.protectionType === 'ReadOnly' || this.documentHelper.isCommentOnlyMode) && !this.selection.isSelectionInEditRegion() || this.documentHelper.protectionType === 'FormFieldsOnly'); }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "canEditContentControl", { /** * @private * @returns {boolean} - Returns the can edit content control. */ get: function () { var currentContentControl = this.selection.currentContentControl; if (!isNullOrUndefined(currentContentControl)) { if (currentContentControl.contentControlProperties.lockContents || currentContentControl.contentControlProperties.type === 'DropDownList') { return false; } } else if (this.selection.checkContentControlLocked()) { return false; } if (this.owner.isReadOnly) { return false; } return true; }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "viewer", { get: function () { if (!isNullOrUndefined(this.owner)) { return this.owner.viewer; } return undefined; }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "editorHistory", { get: function () { return this.documentHelper.owner.editorHistoryModule; }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "selection", { get: function () { if (this.documentHelper) { return this.documentHelper.selection; } return undefined; }, enumerable: true, configurable: true }); Object.defineProperty(Editor.prototype, "owner", { get: function () { if (this.documentHelper) { return this.documentHelper.owner; } return undefined; }, enumerable: true, configurable: true }); Editor.prototype.getModuleName = function () { return 'Editor'; }; /** * Initiates a batch update mode where multiple editing operations can be grouped together. This prevents intermediate re-layout during the execution of grouped operations, improving performance for bulk updates. * * @returns {void} */ Editor.prototype.beginBatchEdit = function () { this.restrictLayout = true; }; /** * Ends the batch update mode and triggers a single re-relayout or change notification to reflect all the modifications made during the batch update. * * @returns {void} */ Editor.prototype.endBatchEdit = function () { this.restrictLayout = false; this.documentHelper.layout.layoutWholeDocument(); }; /** * Sets the field information for the selected field. * * @param { FieldInfo } fieldInfo – Specifies the field information. * @returns {void} * > Nested field gets replaced completely with the specified field information. */ Editor.prototype.setFieldInfo = function (fieldInfo) { var field = this.selection.getHyperlinkField(true); if (!isNullOrUndefined(field)) { this.selection.selectField(); this.insertField(fieldInfo.code, fieldInfo.result); } }; /** * Inserts the specified field at cursor position. * * @param {string} code Specify the field code. * @param {string} result Specify the field result. * @returns {void} */ Editor.prototype.insertField = function (code, result) { this.isInsertField = true; var fieldCode = code; fieldCode = HelperMethods.trimStart(fieldCode); if (fieldCode.substring(0, 8) === 'NUMPAGES') { this.insertPageCount(result); } else if (fieldCode.substring(0, 4) === 'PAGE') { this.insertPageNumber(result); } else { if (isNullOrUndefined(result)) { if (fieldCode.substring(0, 10) === 'MERGEFIELD') { fieldCode = fieldCode.substring(10).trim(); var index = fieldCode.indexOf('\\*'); result = '«' + fieldCode.substring(0, index).trim() + '»'; } } var paragraph = new ParagraphWidget(); var insertFormat = new WCharacterFormat(); var startParagraph = this.selection.start.paragraph; if (!this.selection.isForward) { startParagraph = this.selection.end.paragraph; } var currentInline = this.selection.start.currentWidget.getInline(this.selection.start.offset, 0); if (startParagraph.isEmpty()) { insertFormat = startParagraph.characterFormat; } else if (!isNullOrUndefined(currentInline.element)) { insertFormat = currentInline.element.characterFormat; } else { insertFormat = this.copyInsertFormat(insertFormat, false); } var line = new LineWidget(paragraph); var fieldBegin = new FieldElementBox(0); fieldBegin.characterFormat.assignFormat(insertFormat); line.children.push(fieldBegin); var fieldCodeSpan = new TextElementBox(); fieldCodeSpan.characterFormat.assignFormat(insertFormat); fieldCodeSpan.text = code; line.children.push(fieldCodeSpan); var fieldSeparator = new FieldElementBox(2); fieldSeparator.characterFormat.assignFormat(insertFormat); fieldSeparator.fieldBegin = fieldBegin; fieldBegin.fieldSeparator = fieldSeparator; line.children.push(fieldSeparator); var fieldResultSpan = new TextElementBox(); fieldResultSpan.text = result; fieldResultSpan.characterFormat.assignFormat(insertFormat); if (!this.documentHelper.textHelper.isRTLText(result) && fieldResultSpan.characterFormat.bidi) { fieldResultSpan.characterFormat.bidi = false; } line.children.push(fieldResultSpan); var fieldEnd = new FieldElementBox(1); fieldEnd.characterFormat.assignFormat(insertFormat); fieldEnd.fieldSeparator = fieldSeparator; fieldEnd.fieldBegin = fieldBegin; fieldBegin.fieldEnd = fieldEnd; fieldSeparator.fieldEnd = fieldEnd; line.children.push(fieldEnd); fieldBegin.line = line; paragraph.childWidgets.push(line); this.documentHelper.fields.push(fieldBegin); var section = new BodyWidget(); section.sectionFormat = new WSectionFormat(section); section.childWidgets.push(paragraph); this.pasteContentsInternal([section], false, startParagraph.paragraphFormat); } this.isInsertField = false; }; /** * @private */ Editor.prototype.isLinkedStyle = function (styleName) { var styleObj = this.documentHelper.styles.findByName(styleName); return !isNullOrUndefined(styleObj.link); }; /** * Applies the specified style for paragraph. * * @param {string} style Specify the style name to apply. * @param {boolean} clearDirectFormatting - Removes manual formatting (formatting not applied using a style) * from the selected text, to match the formatting of the applied style. Default value is false. * @returns {void} */ Editor.prototype.applyStyle = function (style, clearDirectFormatting) { clearDirectFormatting = isNullOrUndefined(clearDirectFormatting) ? false : clearDirectFormatting; var startPosition = undefined; var endPosition = undefined; var styleObj = this.documentHelper.styles.findByName(style); if (clearDirectFormatting) { this.initComplexHistory('ApplyStyle'); this.setOffsetValue(this.selection); startPosition = this.startOffset; endPosition = this.endOffset; var isSelectionEmpty = this.selection.isEmpty; this.isSkipOperationsBuild = this.owner.enableCollaborativeEditing; if (!isNullOrUndefined(styleObj) && (styleObj instanceof WCharacterStyle && styleObj.type === 'Character')) { this.clearFormattingInternal(false, true); } else { this.clearFormattingInternal(true, true); } this.isSkipOperationsBuild = false; if (isSelectionEmpty && !this.selection.isEmpty) { this.selection.end.setPositionInternal(this.selection.start); } } if (styleObj !== undefined) { if (styleObj instanceof WCharacterStyle && styleObj.type === 'Character') { if (this.selection.isEmpty) { var offset = this.selection.start.offset; var preservedStartPosition = this.selection.start.clone(); var preservedEndPosition = this.selection.end.clone(); this.selection.selectCurrentWord(); if (offset === this.selection.start.offset || offset === this.selection.end.offset - 1) { this.selection.start = preservedStartPosition; this.selection.end = preservedEndPosition; this.selection.characterFormat.copyFormat(styleObj.characterFormat); } else { this.onApplyCharacterFormat('styleName', styleObj, false, true); } } else { this.onApplyCharacterFormat('styleName', styleObj, false, true); } } else { this.onApplyParagraphFormat('styleName', styleObj, false, true); } } else { /* eslint-disable-next-line max-len */ this.documentHelper.owner.parser.parseStyle(JSON.parse(this.getCompleteStyles()), JSON.parse(this.documentHelper.preDefinedStyles.get(style)), this.documentHelper.styles); this.applyStyle(style); } if (this.editorHistory && this.editorHistory.currentHistoryInfo && this.editorHistory.currentHistoryInfo.action === 'ApplyStyle') { this.startOffset = startPosition; this.endOffset = endPosition; this.editorHistory.updateComplexHistory(); } this.startParagraph = undefined; this.endParagraph = undefined; }; // Public Implementation Starts /** * Moves the selected content in the document editor control to clipboard. * * @returns {void} */ Editor.prototype.cut = function () { if (this.owner.isReadOnlyMode || this.selection.isEmpty || !this.canEditContentControl) { return; } // As per MSWord behaviour, when we select the bookmark whole content except bookmark start & end and cut those content, then bookmark should be removed. var startPosition = this.selection.start; var endPosition = this.selection.end; var previousElementInfo = (startPosition.offset === 0) ? this.selection.getElementInfo(startPosition.currentWidget, startPosition.offset - 1) : this.selection.getElementInfo(startPosition.currentWidget, this.selection.isForward ? startPosition.offset : startPosition.offset + 1); var nextElementInfo = (endPosition.offset === 0) ? this.selection.getElementInfo(endPosition.currentWidget, endPosition.offset - 1) : this.selection.getElementInfo(endPosition.currentWidget, this.selection.isForward ? endPosition.offset + 1 : endPosition.offset); if (!isNullOrUndefined(previousElementInfo) && !isNullOrUndefined(nextElementInfo) && previousElementInfo.element && nextElementInfo.element && previousElementInfo.index !== -1 && nextElementInfo.index !== -1 && previousElementInfo.element instanceof BookmarkElementBox && nextElementInfo.element instanceof BookmarkElementBox && previousElementInfo.element.name === nextElementInfo.element.name && !(!isNullOrUndefined(previousElementInfo.element.nextElement) && !isNullOrUndefined(nextElementInfo.element.previousElement) && previousElementInfo.element.nextElement instanceof FieldElementBox && nextElementInfo.element.previousElement instanceof FieldElementBox)) { if (this.selection.isForward) { this.selection.start.setPositionParagraph(previousElementInfo.element.line, previousElementInfo.element.line.getOffset(previousElementInfo.element, 0)); this.selection.end.setPositionParagraph(nextElementInfo.element.line, nextElementInfo.element.line.getOffset(nextElementInfo.element, 1)); } else { this.selection.start.setPositionParagraph(previousElementInfo.element.line, previousElementInfo.element.line.getOffset(previousElementInfo.element, 1)); this.selection.end.setPositionParagraph(nextElementInfo.element.line, nextElementInfo.element.line.getOffset(nextElementInfo.element, 0)); } } this.selection.copySelectedContent(true); this.documentHelper.owner.parser.isCutPerformed = true; }; /** * Inserts the editing region in the current selection range for the specified user. * * @param {string} user Specifies the native rendering * @returns {void} */ Editor.prototype.insertEditingRegion = function (user) { this.insertEditRangeElement(user && user !== '' ? user : 'Everyone'); }; Editor.prototype.enforceProtection = function (credential, restrictFormatType, isReadOnly) { var typeOfProtection; var limitToFormatting; if (typeof (restrictFormatType) === 'boolean') { typeOfProtection = isReadOnly ? 'ReadOnly' : this.documentHelper.protectionType; limitToFormatting = restrictFormatType; } else { typeOfProtection = restrictFormatType; } if (!isNullOrUndefined(limitToFormatting)) { this.documentHelper.restrictFormatting = limitToFormatting; } this.documentHelper.protectionType = typeOfProtection; this.selection.isHighlightEditRegion = true; this.addProtection(credential, this.documentHelper.protectionType, false); }; Editor.prototype.enforceProtectionAsync = function (credential, restrictFormatType, isReadOnly) { return __awaiter(this, void 0, void 0, function () { var typeOfProtection, limitToFormatting; return __generator(this, function (_a) { switch (_a.label) { case 0: if (typeof (restrictFormatType) === 'boolean') { typeOfProtection = isReadOnly ? 'ReadOnly' : this.documentHelper.protectionType; limitToFormatting = restrictFormatType; } else { limitToFormatting = true; typeOfProtection = restrictFormatType; } this.documentHelper.restrictFormatting = limitToFormatting; this.documentHelper.protectionType = typeOfProtection; this.selection.isHighlightEditRegion = true; return [4 /*yield*/, this.addProtection(credential, this.documentHelper.protectionType, true)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; Editor.prototype.getCommentHierarchicalIndex = function (comment) { var index = ''; while (comment.ownerComment) { if (!isNullOrUndefined(comment.ownerComment)) { index = comment.ownerComment.replyComments.indexOf(comment) + ';' + index; comment = comment.ownerComment; } else { index = comment.replyComments.indexOf(comment) + ';' + index; comment = comment; } } index = 'C;' + this.documentHelper.comments.indexOf(comment) + ';' + index; return index; }; Editor.prototype.alertBox = function () { var localObj = new L10n('documenteditor', this.owner.defaultLocale); localObj.setLocale(this.owner.locale); DialogUtility.alert({ title: localObj.getConstant('Information'), content: localObj.getConstant('Multiple Comment') }); }; /** * Inserts a reply to a comment. * * @param {string} id - The unique identifier of the comment to reply to. * @param {string} text - The text of the reply. * @param {CommentProperties} commentProperties - The properties of the reply (author, isResolved, dateTime). * @returns {Comment} Returns the inserted reply comment. */ Editor.prototype.insertReplyComment = function (id, text, commentProperties) { var markerData = {}; var result = this.getCommentInfo(text); markerData = { author: commentProperties.author ? commentProperties.author : 'Guest user', initial: this.constructCommentInitial(commentProperties.author ? commentProperties.author : 'Guest user'), text: isNullOrUndefined(result.innerText) ? SanitizeHtmlHelper.sanitize(text) : SanitizeHtmlHelper.sanitize(result.innerText), commentId: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15), done: false, date: commentProperties.dateTime ? HelperMethods.getUtcDate(commentProperties.dateTime) : HelperMethods.getUtcDate(), }; var parentComment; if (this.documentHelper.comments.length > 0) { for (var i = 0; i < this.documentHelper.comments.length; i++) { if (this.documentHelper.comments[i].commentId === id) { parentComment = this.documentHelper.comments[i]; break; } } } this.replyComment(parentComment, isNullOrUndefined(result.innerText) ? text : result.innerText, result.itemData, markerData); var commentInfo = { author: markerData.author, isResolved: markerData.done, dateTime: this.parseDateTime(markerData.date), }; var newComment = new Comment(markerData.commentId, commentInfo, text); return newComment; }; Editor.prototype.getCommentInfo = function (text) { var itemData = []; var data = []; var result = []; var mailtoRegex = /<a href="mailto:([^"]+)">([^<]+)<\/a>/g; var lastIndex = 0; var match; while ((match = mailtoRegex.exec(text)) !== null) { if (match.index > lastIndex) { result.push({ text: text.substring(lastIndex, match.index) }); } result.push({ mailto: match[1], text: match[2] }); lastIndex = mailtoRegex.lastIndex; } if (lastIndex < text.length) { result.push({ text: text.substring(lastIndex) }); } var innerText = ''; if (result.length > 0) { for (var i = 0; i < result.length; i++) { if (result[i].mailto) { data.push({ text: result[i].text.replace('@', ''), value: result[i].mailto }); innerText += '<span contenteditable="false" class="e-mention-chip">' + result[i].text.replace('@', '') + '</span>'; } else if (result[i].text) { innerText += result[i].text.replace(/(\r\n|\n\r|\n|\r)/g, "<br>"); } } } else if (text !== '') { innerText = text.replace(/(\r\n|\n\r|\n|\r)/g, "<br>"); } itemData = data; return { itemData: itemData, innerText: innerText }; }; /** * Inserts the comment. * * @param {string} text Specify the comment text to be inserted. * @param {CommentProperties} commentProperties The properties of the comment (author, isResolved, dateTime). * @returns {Comment} */ Editor.prototype.insertComment = function (text, commentProperties) { if (isNullOrUndefined(this.selection.start) || (this.owner.isReadOnlyMode && !this.documentHelper.isCommentOnlyMode) || this.viewer.owner.enableHeaderAndFooter || !this.viewer.owner.enableComment || this.selection.isPlainContentControl()) { return; } if (this.viewer.owner.commentReviewPane.commentPane.isEditMode) { return this.alertBox(); } if (isNullOrUndefined(text)) { text = ''; } var markerData = {}; var result = this.getCommentInfo(text); if (!isNullOrUndefined(commentProperties)) { var authorInternal = isNullOrUndefined(commentProperties.author) ? this.owner.currentUser : commentProperties.author; markerData = { author: authorInternal, initial: this.constructCommentInitial(authorInternal), text: SanitizeHtmlHelper.sanitize(result.innerText === '' ? text : result.innerText), commentId: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15), done: commentProperties.isResolved ? commentProperties.isResolved : false, date: commentProperties.dateTime ? HelperMethods.getUtcDate(commentProperties.dateTime) : HelperMethods.getUtcDate() }; } else { markerData = { author: this.owner.currentUser ? SanitizeHtmlHelper.sanitize(this.owner.currentUser) : 'Guest user', initial: this.constructCommentInitial(this.owner.currentUser ? SanitizeHtmlHelper.sanitize(this.owner.currentUser) : 'Guest user'), text: SanitizeHtmlHelper.sanitize(text), commentId: Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15), done: false, date: HelperMethods.getUtcDate(), }; } this.insertCommentInternal(!isNullOrUndefined(result.innerText) ? result.innerText : '', markerData, result.itemData); var commentInfo = { author: markerData.author, isResolved: markerData.done, dateTime: this.parseDateTime(markerData.date), }; var newComment = new Comment(markerData.commentId, commentInfo, text); return newComment; }; /** * @private */ Editor.prototype.parseDateTime = function (dateTime) { var date = new Date(dateTime); var finalDate = new Date(date.getTime() + date.getTimezoneOffset() * 60000); return finalDate; }; Editor.prototype.insertCommentInternal = function (text, markerData, mentions) { this.documentHelper.layout.allowLayout = false; if (this.selection.isEmpty) { // If selection is at paragraph end, move selection to previous word similar to MS Word if (this.selection.start.isAtSamePosition(this.selection.end) && this.selection.start.isAtParagraphEnd) { var startOffset = this.selection.start.offset; this.selection.start.offset = startOffset - 1 !== -1 ? startOffset - 1 : startOffset; } this.selection.selectCurrentWord(); } // If paragraph mark selected, remove paragraph mark selection if (this.selection.isParagraphLastLine(this.selection.end.currentWidget) && this.selection.end.offset === this.selection.getLineLength(this.selection.end.currentWidget) + 1) { this.selection.end.offset -= 1; } var paragraphInfo = this.selection.getParagraphInfo(this.selection.start); var startIndex = this.selection.getHierarchicalIndex(paragraphInfo.paragraph, paragraphInfo.offset.toString()); var startPosition = this.selection.start; var endPosition = this.selection.end; var position = new TextPosition(this.owner); if (!this.selection.isForward) { startPosition = this.selection.end; endPosition = this.selection.start; } // Clones the end position. position.setPositionInternal(startPosition); this.initComplexHistory('InsertComment'); var commentRangeStart = new CommentCharacterElementBox(0); var commentRangeEnd = new CommentCharacterElementBox(1); // Adds comment end at selection end position. startPosition.setPositionInternal(endPosition); this.initInsertInline(commentRangeEnd); if (isNullOrUndefined(position.paragraph) || position.currentWidget.indexInOwner === -1) { var startPos = this.selection.getTextPosBasedOnLogicalIndex(startIndex); position.setPositionInternal(startPos); } // Adds comment end and comment at selection end position. startPosition.setPositionInternal(position); endPosition.setPositionInternal(position); this.initInsertInline(commentRangeStart); var commentAdv = new CommentElementBox(markerData.date); if (mentions && mentions.length > 0) { commentAdv.mentions = mentions; } if (this.owner.editorHistoryModule) { this.initHistory('InsertCommentWidget'); this.owner.editorHistoryModule.currentBaseHistoryInfo.insertedText = CONTROL_CHARACTERS.Marker_Start + CONTROL_CHARACTERS.Marker_End; this.owner.editorHistoryModule.currentBaseHistoryInfo.removedNodes.push(commentAdv); } this.updateCommentElement(commentAdv, commentRangeStart, commentRangeEnd, markerData); this.addCommentWidget(commentAdv, true, true, true); if (this.owner.isSpellCheck && commentRangeStart.previousElement && commentRangeStart.previousElement instanceof TextElementBox) { commentRangeStart.previousElement.ischangeDetected = true; } if (this.owner.isSpellCheck && commentRangeEnd.previousElement && commentRangeEnd.previousElement instanceof TextElementBox && commentRangeStart.line !== commentRangeEnd.line) { commentRangeEnd.previousElement.ischangeDetected = true; } if (this.editorHistory) { this.editorHistory.currentBaseHistoryInfo.insertPosition = this.getCommentHierarchicalIndex(commentAdv); this.editorHistory.updateHistory(); } // this.selection.selectPosition(this.selection.getTextPosBasedOnLogicalIndex(startIndex), this.selection.getTextPosBasedOnLogicalIndex(endIndex)); if (this.editorHistory) { this.editorHistory.updateComplexHistory(); } this.reLayout(this.selection, false); this.documentHelper.layout.allowLayout = true; if (!this.isUserInsert) { var comment = this.owner.commentReviewPane.commentPane.comments.get(commentAdv); if (mentions && mentions.length > 0) { comment.itemData = mentions; } comment.postComment(); } }; /** * @private */ Editor.prototype.updateCommentElement = function (commentAdv, commentRangeStart, commentRangeEnd, markerData) { commentAdv.author = markerData.author; commentAdv.initial = markerData.initial; commentAdv.text = markerData.text; commentAdv.commentId = markerData.commentId; if (!isNullOrUndefined(markerData.done)) { commentAdv.isResolved = markerData.done; } if (!isNullOrUndefined(markerData.isReply)) { commentAdv.isReply = markerData.isReply; } if (!isNullOrUndefined(commentRangeStart) && !isNullOrUndefined(commentRangeEnd)) { commentRangeStart.comment = commentAdv; commentRangeStart.commentId = commentAdv.commentId; commentRangeEnd.comment = commentAdv; commentRangeEnd.commentId = commentAdv.commentId; commentAdv.commentStart = commentRangeStart; commentAdv.commentEnd = commentRangeEnd; } return commentAdv; }; /** * Deletes all the comments in the current document. * * @returns {void} */ Editor.prototype.deleteAllComments = function () { if (this.documentHelper.comments.length === 0) { return; } //