UNPKG

@syncfusion/ej2-documenteditor

Version:

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

856 lines 243 kB
import { WParagraphFormat } from '../format/paragraph-format'; import { WSectionFormat } from '../format/section-format'; import { WCharacterFormat } from '../format/character-format'; import { WListFormat } from '../format/list-format'; import { HistoryInfo } from '../index'; import { ModifiedLevel, RowHistoryFormat, TableHistoryInfo } from './history-helper'; import { BlockWidget, ParagraphWidget, BodyWidget, TableCellWidget, FieldElementBox, TableWidget, TableRowWidget, BookmarkElementBox, HeaderFooterWidget, CheckBoxFormField, TextFrame, TextElementBox, FootnoteElementBox, ImageElementBox, ListTextElementBox } from '../viewer/page'; import { Dictionary } from '../../base/dictionary'; import { abstractListsProperty, listIdProperty, listsProperty, nsidProperty } from '../../index'; import { TextPosition, ImageSizeInfo } from '../index'; import { isNullOrUndefined } from '@syncfusion/ej2-base'; import { ElementBox, CommentCharacterElementBox } from '../viewer/page'; import { WTableFormat, WRowFormat, WCellFormat, WParagraphStyle } from '../format/index'; import { HelperMethods } from '../editor/editor-helper'; import { CONTROL_CHARACTERS } from '../../base/types'; // Code for Comparing the offset calculated using old approach and optimized approach // /** // * @private // */ // export class MyError extends Error { // constructor(message: string) { // super(message); // } // } // export function throwCustomError(condition: boolean, message: string) { // if (condition) { // throw new MyError(message); // } // } /** * @private */ var BaseHistoryInfo = /** @class */ (function () { function BaseHistoryInfo(node) { this.cellOperation = []; this.splittedRevisions = []; this.isRemovedNodes = false; this.modifiedFormatOperation = []; this.revisionOperation = []; /** * @private */ this.markerData = []; this.ownerIn = node; this.documentHelper = node.documentHelper; this.modifiedPropertiesIn = []; this.modifiedNodeLength = []; this.removedNodesIn = []; this.insertedNodes = []; } Object.defineProperty(BaseHistoryInfo.prototype, "owner", { //Properties //gets owner control get: function () { return this.ownerIn; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "editorHistory", { get: function () { return this.owner.editorHistoryModule; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "action", { get: function () { return this.actionIn; }, set: function (value) { this.actionIn = value; if (this.owner.enableCollaborativeEditing && !this.editorHistory.isUndoing && this.cellOperation.length === 0) { if (value === 'DeleteColumn' || value === 'DeleteCells' || value === 'ClearCells' || value === 'MergeCells') { if (!(this.owner.selectionModule.isTableSelected(true) || this.owner.selectionModule.isRowSelect()) || value === 'ClearCells' || value === 'MergeCells') { this.insertedText = CONTROL_CHARACTERS.Cell; this.deleteColumnOperation(this.action); } } else if (value === 'Accept Change' || value === 'Reject Change') { this.createAcceptRejectOperation(this.action); } else if (value === 'SectionBreak') { this.insertedText = CONTROL_CHARACTERS.Section_Break; this.type = 'NewPage'; } else if (value === 'SectionBreakContinuous') { this.insertedText = CONTROL_CHARACTERS.Section_Break; this.type = 'Continuous'; } } }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "modifiedProperties", { get: function () { return this.modifiedPropertiesIn; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "removedNodes", { /* eslint-enable */ get: function () { return this.removedNodesIn; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "selectionStart", { //gets or sets selection start get: function () { return this.selectionStartIn; }, set: function (value) { this.selectionStartIn = value; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "selectionEnd", { get: function () { return this.selectionEndIn; }, set: function (value) { this.selectionEndIn = value; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "insertPosition", { get: function () { return this.insertPositionIn; }, set: function (value) { this.insertPositionIn = value; if (this.owner.enableCollaborativeEditing && !this.owner.editorModule.isRemoteAction && value !== '' && !isNullOrUndefined(value) && value.indexOf('C') === -1) { //TODO: Insert position not needed in all the cases. Need to optimize it. this.insertIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(value); // Code for Comparing the offset calculated using old approach and optimized approach // this.owner.selection.isNewApproach = true; // this.newInsertIndex = this.owner.selection.getAbsolutePositionFromRelativePosition(value); // this.owner.selection.isNewApproach = false; // throwCustomError(this.newInsertIndex !== this.insertIndex, "New InsertIndex " + this.newInsertIndex + " and old insertIndex " + this.insertIndex + " doesnot match"); } }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "endPosition", { get: function () { return this.endPositionIn; }, set: function (value) { this.endPositionIn = value; }, enumerable: true, configurable: true }); Object.defineProperty(BaseHistoryInfo.prototype, "viewer", { get: function () { return this.ownerIn.viewer; }, enumerable: true, configurable: true }); BaseHistoryInfo.prototype.updateSelection = function () { this.updateCollaborativeSelection(this.owner.selectionModule.start.clone(), this.owner.selectionModule.end.clone()); var blockInfo = this.owner.selectionModule.getParagraphInfo(this.owner.selectionModule.start); this.selectionStart = this.owner.selectionModule.getHierarchicalIndex(blockInfo.paragraph, blockInfo.offset.toString()); blockInfo = this.owner.selectionModule.getParagraphInfo(this.owner.selectionModule.end); this.selectionEnd = this.owner.selectionModule.getHierarchicalIndex(blockInfo.paragraph, blockInfo.offset.toString()); }; BaseHistoryInfo.prototype.updateCollaborativeSelection = function (start, end) { if (this.owner.enableCollaborativeEditing && !this.owner.editorModule.isRemoteAction) { //TODO: Need to consider formard and backward selection if (this.action === 'RemoveEditRange') { var startEdit = this.owner.selectionModule.getEditRangeStartElement(); var position = this.owner.selectionModule.getPosition(startEdit); start = position.startPosition; end = position.endPosition; } else { this.updateTableSelection(start, end); } this.startIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(start); // Code for Comparing the offset calculated using old approach and optimized approach // this.owner.selection.isNewApproach = true; // this.newStartIndex = this.owner.selection.getAbsolutePositionFromRelativePosition(start); // this.owner.selection.isNewApproach = false; this.owner.selectionModule.isEndOffset = true; this.endIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(end); // Code for Comparing the offset calculated using old approach and optimized approach // this.owner.selection.isNewApproach = true; // this.newEndIndex = this.owner.selection.getAbsolutePositionFromRelativePosition(end); // this.owner.selection.isNewApproach = false; this.owner.selectionModule.isEndOffset = false; var isForward = this.owner.selectionModule.isForward; if (isForward) { this.startIndex -= this.owner.selectionModule.getTableRelativeValue(start, end); } else { this.endIndex -= this.owner.selectionModule.getTableRelativeValue(end, start); } // if (this.action === 'BackSpace' || this.action === 'Delete') { var isParagraphStart = isForward ? (start.paragraph.equals(end.paragraph) && start.isAtParagraphStart) : (start.paragraph.equals(end.paragraph) && end.isAtParagraphStart); if ((isParagraphStart || !start.paragraph.equals(end.paragraph))) { if (isForward) { this.endIndex += this.paraInclude(end); } else { this.startIndex += this.paraInclude(start); } } // } if (!this.owner.enableTrackChanges) { this.splitOperationForDelete(start, end); } // Code for Comparing the offset calculated using old approach and optimized approach // throwCustomError(this.newStartIndex !== this.startIndex, "New StartIndex " + this.newStartIndex + " and old StartIndex " + this.startIndex + " doesnot match"); // throwCustomError(this.newEndIndex !== this.endIndex, "New EndIndex " + this.newEndIndex + " and old EndIndex " + this.endIndex + " doesnot match"); } }; BaseHistoryInfo.prototype.paraInclude = function (position) { var paragrapthInfo = this.owner.selectionModule.getParagraphInfo(position); if (position.paragraph.getTotalLength() < paragrapthInfo.offset) { if (!(position.paragraph.isInsideTable && position.paragraph.equals(position.paragraph.associatedCell.lastChild))) { return 1; } } return 0; }; /** * This method will set position when the multple cell selected. * * @param {TextPosition} startPosition - Specifies the start position. * @param {TextPosition} endPosition - Specifies the end position. * @private * @returns {void} */ BaseHistoryInfo.prototype.updateTableSelection = function (startPosition, endPosition) { var start = startPosition; var end = endPosition; if (!this.owner.selectionModule.isForward) { start = endPosition; end = startPosition; } if (start.paragraph.isInsideTable) { var firstPara = this.owner.selectionModule.getFirstParagraph(start.paragraph.associatedCell); if (end.paragraph.isInsideTable) { if (!start.paragraph.associatedCell.equals(end.paragraph.associatedCell)) { var lastPara = this.owner.selectionModule.getLastParagraph(end.paragraph.associatedCell); start.setPosition(firstPara.firstChild, true); end.setPositionParagraph(lastPara.lastChild, lastPara.lastChild.getEndOffset() + 1); } } else { start.setPosition(firstPara.firstChild, true); } } else if (end.paragraph.isInsideTable) { var lastPara = this.owner.selectionModule.getLastParagraph(end.paragraph.associatedCell); end.setPositionParagraph(lastPara.lastChild, lastPara.lastChild.getEndOffset() + 1); } }; /** * start is para and end is in row. * * @param {TextPosition} startPosition - Specifies the start position. * @param {TextPosition} endPosition - Specifies the end position. * @private * @returns {void} */ BaseHistoryInfo.prototype.splitOperationForDelete = function (startPosition, endPosition) { // when start is para and end is row. we are building the operation like: // fisrt delete the end table from table start to selection end. // second need to paste the content from the start para and need to paste it in the next row. // third delete the start paragraph to before wiget of end table. var start = startPosition; var end = endPosition; if (!this.owner.selectionModule.isForward) { start = endPosition; end = startPosition; } if (!start.paragraph.isInsideTable && end.paragraph.isInsideTable && (this.action === 'BackSpace' || this.action === 'Delete')) { var lastParagraph = this.owner.selectionModule.getLastBlockInLastCell(end.paragraph.associatedCell.ownerTable); if (!lastParagraph.associatedCell.equals(end.paragraph.associatedCell)) { var PasteLength = this.startIndex; var endLineWidget = start.currentWidget; var endOffset = start.offset; start.setPosition(start.paragraph.firstChild, true); this.startIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(start); var startIndex = this.startIndex; var table = this.owner.documentHelper.layout.getParentTable(end.paragraph.associatedCell.ownerTable); var paragraphInfo = { 'paragraph': null, 'offset': 0 }; var tableStart = this.owner.selectionModule.getPositionInfoForHeaderFooter(paragraphInfo, { position: 0, done: false }, table).position; // Table start will get the offset for table. So adding plus one to row offset. this.startIndex = tableStart + 1; this.cellOperation.push(this.getDeleteOperation(this.action)); // This will add the paste content in first and first cell so adding plus 3. this.startIndex = tableStart + 3; if (endOffset !== 0) { this.pasteContent = this.owner.sfdtExportModule.write((this.owner.documentEditorSettings.optimizeSfdt ? 1 : 0), start.currentWidget, start.offset, endLineWidget, endOffset, false, true); this.cellOperation.push(this.getPasteOpertion(this.pasteContent, PasteLength - startIndex)); } this.endIndex = tableStart; this.startIndex = startIndex; this.cellOperation.push(this.getDeleteOperation(this.action)); } } if (this.action === 'PasteColumn' || this.action === 'PasteOverwrite' || this.action === 'PasteRow') { //when inserting new colomn in paste. first deleting the table and inserting the whole table. var table = startPosition.paragraph.associatedCell.ownerTable; var paragraphInfo = { 'paragraph': null, 'offset': 0 }; this.startIndex = this.owner.selectionModule.getPositionInfoForHeaderFooter(paragraphInfo, { position: 0, done: false }, table).position; this.endIndex = this.startIndex + this.owner.selectionModule.getBlockLength(undefined, table, 0, { done: false }, true, undefined, undefined); } }; BaseHistoryInfo.prototype.setBookmarkInfo = function (bookmark) { this.removedNodes.push({ 'bookmark': bookmark, 'startIndex': bookmark.indexInOwner, 'endIndex': bookmark.reference.indexInOwner }); }; BaseHistoryInfo.prototype.setContentControlInfo = function (contentControl) { this.removedNodes.push({ 'contentcontrol': contentControl, 'startIndex': contentControl.indexInOwner, 'endIndex': contentControl.reference.indexInOwner }); }; BaseHistoryInfo.prototype.setFormFieldInfo = function (field, value) { this.removedNodes.push({ 'formField': field, 'value': value }); }; BaseHistoryInfo.prototype.setEditRangeInfo = function (editStart) { this.removedNodes.push({ 'editStart': editStart, 'startIndex': editStart.indexInOwner, 'endIndex': editStart.editRangeEnd.indexInOwner }); }; BaseHistoryInfo.prototype.revertFormTextFormat = function () { /* eslint-disable @typescript-eslint/no-explicit-any */ var fieldInfo = this.removedNodes[0]; var text = fieldInfo.value; /* eslint-enable @typescript-eslint/no-explicit-any */ var formField = fieldInfo.formField; if (this.editorHistory.isUndoing) { this.owner.editorModule.applyTextFormatInternal(formField, text); this.editorHistory.recordChanges(this); } else { text = HelperMethods.formatText(formField.formFieldData.format, text); this.owner.editorModule.applyTextFormatInternal(formField, text); this.editorHistory.undoStack.push(this); } }; BaseHistoryInfo.prototype.revertFormField = function () { /* eslint-disable @typescript-eslint/no-explicit-any */ var fieldInfo = this.removedNodes[0]; /* eslint-enable @typescript-eslint/no-explicit-any */ var field = fieldInfo.formField; if (field.formFieldData instanceof CheckBoxFormField) { this.owner.editorModule.toggleCheckBoxFormField(field, true, fieldInfo.value); } else { this.owner.editorModule.updateFormField(field, fieldInfo.value); } }; BaseHistoryInfo.prototype.revertContentControl = function () { var contentControlInfo = this.removedNodes[0]; var contentcontrol = contentControlInfo.contentcontrol; if (this.editorHistory.isUndoing) { var markerData = this.owner.editorModule.getMarkerData(contentcontrol); this.documentHelper.contentControlCollection.push(contentcontrol); this.markerData.push(markerData); contentcontrol.line.children.splice(contentControlInfo.startIndex, 0, contentcontrol); //const previousNode: ElementBox = contentControl.previousNode; this.markerData.push(markerData); contentcontrol.reference.line.children.splice(contentControlInfo.endIndex, 0, contentcontrol.reference); this.editorHistory.recordChanges(this); this.viewer.updateScrollBars(); this.owner.editorModule.fireContentChange(); } else { this.owner.editorModule.removeContentControlInternal(); this.editorHistory.undoStack.push(this); } }; BaseHistoryInfo.prototype.revertBookmark = function () { var bookmarkInfo = this.removedNodes[0]; var bookmark = bookmarkInfo.bookmark; if (this.editorHistory.isUndoing) { var markerData = this.owner.editorModule.getMarkerData(bookmark); this.documentHelper.bookmarks.add(bookmark.name, bookmark); this.markerData.push(markerData); bookmark.line.children.splice(bookmarkInfo.startIndex, 0, bookmark); var previousNode = bookmark.previousNode; if (previousNode instanceof FieldElementBox && !isNullOrUndefined(previousNode.formFieldData)) { previousNode.formFieldData.name = bookmark.name; } this.markerData.push(markerData); bookmark.reference.line.children.splice(bookmarkInfo.endIndex, 0, bookmark.reference); this.editorHistory.recordChanges(this); if (this.owner.documentEditorSettings.showBookmarks === true) { this.viewer.updateScrollBars(); } this.owner.editorModule.fireContentChange(); } else { this.owner.editorModule.deleteBookmarkInternal(bookmark); this.editorHistory.undoStack.push(this); } }; BaseHistoryInfo.prototype.revertComment = function () { var editPosition = this.insertPosition; var comment = this.removedNodes[0]; var insert = false; if (this.action === 'ResolveComment') { this.editorHistory.currentBaseHistoryInfo = this; this.owner.editorModule.resolveOrReopenComment(comment, !comment.isResolved); return; } if (this.action === 'EditComment') { var modifiedCommentObject = this.modifiedProperties[0]; this.editorHistory.currentBaseHistoryInfo = this; var commentView = this.owner.commentReviewPane.commentPane.comments.get(comment); commentView.commentText.innerText = modifiedCommentObject.text; modifiedCommentObject.text = comment.text; comment.text = commentView.commentText.innerText; this.owner.editorHistoryModule.updateHistory(); this.owner.fireContentChange(); return; } if (this.action === 'InsertCommentWidget') { insert = (this.editorHistory.isRedoing); } else if (this.action === 'DeleteCommentWidget') { insert = (this.editorHistory.isUndoing); } if (insert) { if (comment) { this.insertedElement = comment.clone(); if (comment.isReply) { this.owner.editorModule.addReplyComment(comment, this.insertPosition); } else { this.owner.editorModule.addCommentWidget(comment, false, true, true); } } } else { var commentElement = this.owner.editorModule.getCommentElementBox(editPosition); this.owner.editorModule.deleteCommentWidget(commentElement); } }; BaseHistoryInfo.prototype.revertEditRangeRegion = function () { var editRangeInfo = this.removedNodes[0]; var editStart = editRangeInfo.editStart; if (this.editorHistory.isUndoing) { var user = editStart.user === '' ? editStart.group : editStart.user; this.owner.editorModule.updateRangeCollection(editStart, user); this.markerData.push(this.owner.editorModule.getMarkerData(editStart)); this.markerData.push(this.owner.editorModule.getMarkerData(editStart.editRangeEnd)); editStart.line.children.splice(editRangeInfo.startIndex, 0, editStart); editStart.editRangeEnd.line.children.splice(editRangeInfo.endIndex, 0, editStart.editRangeEnd); this.editorHistory.recordChanges(this); } else { this.owner.editorModule.removeUserRestrictionsInternal(editStart); this.editorHistory.undoStack.push(this); } this.owner.editorModule.fireContentChange(); }; /* eslint-disable */ BaseHistoryInfo.prototype.revert = function () { if (this.action === 'FormTextFormat') { this.revertFormTextFormat(); return; } if (this.action === 'UpdateFormField') { this.revertFormField(); return; } if (this.action === 'DeleteBookmark') { this.revertBookmark(); return; } if (this.action === 'RemoveContentControl') { this.revertContentControl(); return; } if (this.action === 'RemoveEditRange') { this.revertEditRangeRegion(); return; } if (this.action === 'InsertCommentWidget' || this.action === 'DeleteCommentWidget' || this.action === 'ResolveComment' || this.action === 'EditComment') { this.revertComment(); return; } if (this.action === 'ListFormat' && this.owner.editorModule.listNumberFormat !== '') { var abstractList = this.documentHelper.lists[0].abstractList.levels[this.owner.editorModule.listLevelNumber]; var currentListLevelPattern = abstractList.listLevelPattern; var currentNUmberFormat = abstractList.numberFormat; abstractList.listLevelPattern = this.owner.editorModule.listLevelPattern; abstractList.numberFormat = this.owner.editorModule.listNumberFormat; this.owner.editorModule.listLevelPattern = currentListLevelPattern; this.owner.editorModule.listNumberFormat = currentNUmberFormat; } this.owner.isShiftingEnabled = true; var selectionStartTextPosition = undefined; var selectionEndTextPosition = undefined; var start = this.selectionStart; var end = this.selectionEnd; this.collabStart = this.selectionStart; this.collabEnd = this.selectionEnd; var isForwardSelection = TextPosition.isForwardSelection(start, end); if (this.modifiedProperties.length > 0 || this.action === 'Selection' || this.action === 'ClearCharacterFormat' || this.action === 'ClearParagraphFormat') { selectionStartTextPosition = !isNullOrUndefined(start) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(start) : undefined; selectionEndTextPosition = !isNullOrUndefined(end) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(end) : undefined; if (this.owner.enableCollaborativeEditing) { this.updateCollaborativeSelection(selectionStartTextPosition, selectionEndTextPosition); } this.revertModifiedProperties(selectionStartTextPosition, selectionEndTextPosition); } else { if (this.owner.enableCollaborativeEditing) { if (!isNullOrUndefined(this.insertPosition)) { this.insertIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(this.insertPosition); } if (!isNullOrUndefined(this.endPosition)) { var startPosition = this.owner.selection.getTextPosBasedOnLogicalIndex(this.insertPosition); var endPosition = this.owner.selection.getTextPosBasedOnLogicalIndex(this.endPosition); this.updateCollaborativeSelection(startPosition, endPosition); } } var sel = this.owner.selectionModule; var deletedNodes = this.removedNodes; if (this.removedNodes.length > 0) { if (this.action === 'InsertTable' && this.editorHistory.isRedoing) { for (var i = 0; i < this.removedNodes.length; i++) { this.insertedNodes.push(this.removedNodes[parseInt(i.toString(), 10)]); } } this.isRemovedNodes = true; } else { this.isRemovedNodes = false; } this.removedNodesIn = []; if (isNullOrUndefined(this.endPosition)) { this.endPosition = this.insertPosition; } var isForward = TextPosition.isForwardSelection(this.insertPosition, this.endPosition); var insertTextPosition = sel.getTextPosBasedOnLogicalIndex(isForward ? this.insertPosition : this.endPosition); var endTextPosition = sel.getTextPosBasedOnLogicalIndex(isForward ? this.endPosition : this.insertPosition); // Set the endRevisionLogicalIndex based on undo stack value when the selection contains a table with the above paragraph (undoing). if (this.action === 'RemoveRowTrack' && this.editorHistory.isUndoing) { this.owner.selectionModule.select(this.selectionEnd, this.selectionEnd); var isLastChild = (this.owner.selectionModule.start.paragraph === this.owner.editor.getLastParaForBodywidgetCollection(this.owner.selectionModule.start.paragraph)); if (this.owner.selectionModule.start.paragraph.isInsideTable || isLastChild && this.owner.selectionModule.end.paragraph.isEmpty() && deletedNodes.length > 0 && deletedNodes[0] instanceof TableWidget) { this.endRevisionLogicalIndex = this.selectionEnd; } } if (this.editorHistory.isUndoing) { if (this.lastElementRevision && isNullOrUndefined(this.isAcceptOrReject) && deletedNodes.length > 0 && deletedNodes[0] instanceof ParagraphWidget && deletedNodes[0].isEmpty()) { this.endRevisionLogicalIndex = this.selectionEnd; } else if (this.action === 'Delete' && this.editorHistory.currentHistoryInfo && this.editorHistory.currentHistoryInfo.action === 'RemoveHyperlink' && this.lastElementRevision instanceof FieldElementBox) { // Bug 873011: Updated the selection for delete operation on "RemoveHyperlink" undo case. this.endRevisionLogicalIndex = this.selectionEnd; } else if (this.lastElementRevision && isNullOrUndefined(this.endRevisionLogicalIndex)) { this.updateEndRevisionInfo(); } else if (this.action === 'RemoveRowTrack') { this.endRevisionLogicalIndex = this.selectionEnd; } } if (this.action === 'ClearRevisions') { // Bug 873011: Handled the separate undo revision for field begin and field end for "ClearRevisions" action on hyperlink undo. var fieldBegin = sel.getHyperlinkField(); if (this.isHyperlinkField && !isNullOrUndefined(fieldBegin)) { var offset = fieldBegin.fieldSeparator.line.getOffset(fieldBegin.fieldSeparator, 1); endTextPosition.setPositionParagraph(fieldBegin.fieldSeparator.line, offset); this.undoRevisionForElements(insertTextPosition, endTextPosition, deletedNodes[deletedNodes.length - 1]); var fieldEnd = fieldBegin.fieldEnd; insertTextPosition.setPositionParagraph(fieldEnd.line, fieldEnd.line.getOffset(fieldEnd, 0)); endTextPosition.setPositionParagraph(fieldEnd.line, fieldEnd.line.getOffset(fieldEnd, 1)); this.undoRevisionForElements(insertTextPosition, endTextPosition, deletedNodes[deletedNodes.length - 1]); } else { this.owner.selectionModule.select(this.selectionEnd, this.selectionEnd); this.undoRevisionForElements(insertTextPosition, endTextPosition, deletedNodes[deletedNodes.length - 1]); } this.removedNodes.push(deletedNodes[deletedNodes.length - 1]); deletedNodes = []; } if (this.action === 'Uppercase') { sel.selectPosition(insertTextPosition, endTextPosition); this.editorHistory.currentBaseHistoryInfo = this; var editModule = this.owner.editorModule; editModule.changeSelectedTextCase(sel, insertTextPosition, endTextPosition, this.action.toString(), deletedNodes); editModule.reLayout(sel); return; } if (this.action === 'Lowercase') { sel.selectPosition(insertTextPosition, endTextPosition); this.editorHistory.currentBaseHistoryInfo = this; var editModule = this.owner.editorModule; editModule.changeSelectedTextCase(sel, insertTextPosition, endTextPosition, this.action.toString(), deletedNodes); editModule.reLayout(sel); return; } if (this.action === 'CapitalizeEachWord') { sel.selectPosition(insertTextPosition, endTextPosition); this.editorHistory.currentBaseHistoryInfo = this; var editModule = this.owner.editorModule; editModule.changeSelectedTextCase(sel, insertTextPosition, endTextPosition, this.action.toString(), deletedNodes); editModule.reLayout(sel); return; } if (this.action === 'SentenceCase') { sel.selectPosition(insertTextPosition, endTextPosition); this.editorHistory.currentBaseHistoryInfo = this; var editModule = this.owner.editorModule; editModule.changeSelectedTextCase(sel, insertTextPosition, endTextPosition, this.action.toString(), deletedNodes); editModule.reLayout(sel); return; } if (this.action === 'ToggleCase') { sel.selectPosition(insertTextPosition, endTextPosition); this.editorHistory.currentBaseHistoryInfo = this; var editModule = this.owner.editorModule; editModule.changeSelectedTextCase(sel, insertTextPosition, endTextPosition, this.action.toString(), deletedNodes); editModule.reLayout(sel); return; } if (insertTextPosition.isAtSamePosition(endTextPosition)) { sel.selectContent(insertTextPosition, true); } else { sel.selectPosition(insertTextPosition, endTextPosition); } if (this.action === 'InsertHyperlink' && this.editorHistory.isRedoing) { var fieldBegin = this.owner.selectionModule.getHyperlinkField(); if (!isNullOrUndefined(fieldBegin)) { var offset = (fieldBegin.line).getOffset(fieldBegin, 0); insertTextPosition.setPositionParagraph(fieldBegin.line, offset); this.owner.selectionModule.start.setPositionInternal(insertTextPosition); offset = fieldBegin.fieldEnd.line.getOffset(fieldBegin.fieldEnd, 1); endTextPosition.setPositionParagraph(fieldBegin.fieldEnd.line, offset); } } this.editorHistory.currentBaseHistoryInfo = this; this.selectionStart = this.insertPosition; this.insertPosition = undefined; this.selectionEnd = this.endPosition; this.endPosition = undefined; // Use this property to skip deletion if already selected content deleted case. var isRemoveContent = false; var isDeletecell = false; if (this.action === 'DeleteCells' || this.action === 'RemoveRowTrack') { isDeletecell = true; } if (this.endRevisionLogicalIndex && deletedNodes.length > 0) { var currentPosition = sel.getTextPosBasedOnLogicalIndex(this.endRevisionLogicalIndex); if (this.editorHistory.isUndoing || (this.editorHistory.isRedoing && insertTextPosition.isAtSamePosition(endTextPosition))) { sel.selectPosition(insertTextPosition, currentPosition); } this.collabEnd = this.endRevisionLogicalIndex; if (this.owner.enableCollaborativeEditing) { this.endIndex = this.owner.selectionModule.getAbsolutePositionFromRelativePosition(currentPosition); this.endIndex += this.paraInclude(currentPosition); } if (this.editorHistory.isUndoing || (this.editorHistory.isRedoing && !this.owner.selectionModule.isEmpty && deletedNodes.length > 0)) { this.owner.editorModule.deleteSelectedContents(sel, true, isDeletecell); isRemoveContent = true; } } if (!insertTextPosition.isAtSamePosition(endTextPosition) && !isRemoveContent) { isRemoveContent = this.action === 'BackSpace' || this.action === 'Delete' || this.action === 'ClearCells' || this.action === 'DeleteCells'; var skipDelete = (deletedNodes.length > 0 && this.action === 'ParaMarkTrack') || this.action === 'ClearRevisions' || this.action === 'AcceptTOC'; if (!(isRemoveContent) && this.action !== 'MergeCells' && this.action !== 'InsertRowAbove' && this.action !== 'InsertRowBelow' && this.action !== 'InsertColumnLeft' && this.action !== 'InsertColumnRight' && this.action !== 'Borders' && this.action !== 'DeleteTable' && this.action !== 'DeleteColumn' && this.action !== 'DeleteRow') { sel.end.setPositionInternal(endTextPosition); if (!this.owner.selectionModule.isEmpty && !skipDelete) { if (this.editorHistory.isRedoing && this.action !== 'Accept Change' && this.action !== 'ParaMarkTrack' && this.action !== 'ParaMarkReject' && this.action !== 'RemoveRowTrack') { this.owner.editorModule.removeSelectedContents(sel); } else { // Bug 873011: Handled the separate deletion for field begin and field end for "Accept Change" action on hyperlink redo. var fieldBegin = sel.getHyperlinkField(); if (this.isHyperlinkField && !isNullOrUndefined(fieldBegin) && this.editorHistory.isRedoing && this.action === 'Accept Change') { var fieldEnd = fieldBegin.fieldEnd; sel.start.setPositionParagraph(fieldBegin.line, (fieldBegin.line).getOffset(fieldBegin, 0)); sel.end.setPositionParagraph(fieldBegin.fieldSeparator.line, (fieldBegin.fieldSeparator.line).getOffset(fieldBegin.fieldSeparator, 1)); this.owner.editorModule.deleteSelectedContents(sel, true); if (this.editorHistory && this.editorHistory.currentBaseHistoryInfo) { this.editorHistory.currentBaseHistoryInfo.removedNodes.reverse(); } sel.start.setPositionParagraph(fieldEnd.line, (fieldEnd.line).getOffset(fieldEnd, 0)); sel.end.setPositionParagraph(fieldEnd.line, (fieldEnd.line).getOffset(fieldEnd, 1)); this.owner.editorModule.deleteSelectedContents(sel, true); if (this.editorHistory && this.editorHistory.currentBaseHistoryInfo) { this.editorHistory.currentBaseHistoryInfo.removedNodes.reverse(); } } else { this.owner.editorModule.deleteSelectedContents(sel, true); } } if (!isNullOrUndefined(this.editorHistory.currentHistoryInfo) && this.editorHistory.currentHistoryInfo.action === 'PageBreak' && this.documentHelper.blockToShift) { this.documentHelper.layout.shiftLayoutedItems(false); } } } } else if (this.action === 'SectionBreakContinuous' && insertTextPosition && this.editorHistory.isUndoing) { if (insertTextPosition.offset === 0 && !isNullOrUndefined(insertTextPosition.paragraph.previousRenderedWidget) && insertTextPosition.paragraph.previousRenderedWidget instanceof ParagraphWidget && insertTextPosition.paragraph.previousRenderedWidget.isEndsWithPageBreak && insertTextPosition.paragraph.containerWidget instanceof BodyWidget && insertTextPosition.currentWidget === insertTextPosition.currentWidget.paragraph.firstChild && insertTextPosition.paragraph.containerWidget.sectionFormat.breakCode === 'NoBreak') { var section = insertTextPosition.paragraph.previousRenderedWidget.containerWidget; this.owner.editorModule.combineSectionInternal(this.owner.selectionModule, section, insertTextPosition.paragraph.containerWidget); this.owner.editorModule.layoutWholeDocument(); } } else { isRemoveContent = false; if (!insertTextPosition.isAtSamePosition(endTextPosition)) { isRemoveContent = this.action === 'BackSpace' || this.action === 'Delete' || this.action === 'ClearCells' || this.action === 'DeleteCells'; } } var isRedoAction = (this.editorHistory.isRedoing && !isRemoveContent); isRemoveContent = this.lastElementRevision ? false : isRemoveContent; this.revertModifiedNodes(deletedNodes, isRedoAction, isForwardSelection ? start : end, start === end, isForwardSelection ? end : start); // Use this property to delete table or cell based on history action. if (isRemoveContent) { this.removeContent(insertTextPosition, endTextPosition, isDeletecell); } //this.owner.editorModule.reLayout(this.documentHelper.selection); } var isSelectionChanged = false; var updateSelection = false; if (!isNullOrUndefined(this.editorHistory.currentHistoryInfo) && (this.editorHistory.currentHistoryInfo.action === 'Reject All' || this.editorHistory.currentHistoryInfo.action === 'Accept All' || this.editorHistory.currentHistoryInfo.action === 'Paste')) { updateSelection = true; } if (this.action !== 'TrackingPageBreak' && ((this.editorHistory.isUndoing || this.endRevisionLogicalIndex || this.action === 'RemoveRowTrack' || updateSelection) && isNullOrUndefined(this.editorHistory.currentHistoryInfo) || updateSelection) || ((this.action === 'InsertRowAbove' || this.action === 'Borders' || this.action === 'InsertRowBelow' || this.action === 'InsertColumnLeft' || this.action === 'InsertColumnRight' || this.action === 'Accept Change' || this.action === 'PasteColumn' || this.action === 'PasteRow' || this.action === 'PasteOverwrite' || this.action === 'PasteNested') && (this.editorHistory.isRedoing || this.editorHistory.currentHistoryInfo.action === 'Paste'))) { if (this.action === 'RemoveRowTrack' && this.editorHistory.isRedoing) { selectionStartTextPosition = !isNullOrUndefined(this.selectionStart) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(this.selectionStart) : undefined; selectionEndTextPosition = !isNullOrUndefined(this.selectionEnd) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(this.selectionEnd) : undefined; } else { selectionStartTextPosition = !isNullOrUndefined(start) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(start) : undefined; selectionEndTextPosition = !isNullOrUndefined(end) ? this.owner.selectionModule.getTextPosBasedOnLogicalIndex(end) : undefined; } if (this.action !== 'ModifyStyle') { this.owner.selectionModule.selectRange(selectionStartTextPosition, selectionEndTextPosition); } this.documentHelper.updateFocus(); isSelectionChanged = true; } this.owner.trackChangesPane.isTrackingPageBreak = false; var index = this.insertIndex; // Updates insert position of history info instance. this.insertPosition = start; this.endPosition = end; if (this.action === 'InsertHyperlink') { this.insertIndex = index; } if (!isNullOrUndefined(this.editorHistory.currentHistoryInfo) && (this.editorHistory.currentHistoryInfo.action === 'Accept All' || this.editorHistory.currentHistoryInfo.action === 'Reject All' || this.editorHistory.currentHistoryInfo.action === 'RemoveComment')) { if (this.owner.documentHelper.blockToShift) { this.owner.documentHelper.layout.shiftLayoutedItems(false); } } this.owner.editorModule.reLayout(this.owner.selectionModule, this.owner.selectionModule.isEmpty); if (this.editorHistory.isUndoing && this.action === 'SectionBreak') { this.owner.editorModule.isSkipOperationsBuild = this.owner.enableCollaborativeEditing; this.owner.editorModule.layoutWholeDocument(); this.owner.editorModule.isSkipOperationsBuild = false; } if (isSelectionChanged) { this.documentHelper.scrollToPosition(this.owner.selectionModule.start, this.owner.selectionModule.end); } this.highlightListText(); }; BaseHistoryInfo.prototype.highlightListText = function () { if (!isNullOrUndefined(this.editorHistory.currentHistoryInfo)) { if (this.action === 'ListCharacterFormat' || (this.editorHistory.currentHistoryInfo.action === 'ListSelect' && this.action === 'ListFormat')) { var selectionStartTextPosition = this.owner.selectionModule.getTextPosBasedOnLogicalIndex(this.selectionStart); var widget = selectionStartTextPosition.currentWidget; this.documentHelper.selection.highlightListText(widget); } } }; BaseHistoryInfo.prototype.removeContent = function (insertTextPosition, endTextPosition, isDeletecell) { //If the base parent of the insert text position and end text position is null //then the paragraphs already removed. //Example scenario: In table editing that is delete cells operation // we will backed up the entire table ad it will be replaced on undo operation. //At that time if the positions are in table //which is already replaced in undo (revert modified nodes method) then the base parent of the paragraph will be null. //So again, selecting the content and deleting is unnecessary // and it will cause improper position updates and null reference exceptions. if ((!isNullOrUndefined(insertTextPosition.paragraph.containerWidget) && insertTextPosition.paragraph.containerWidget instanceof BodyWidget && (!isNullOrUndefined(endTextPosition.paragraph.containerWidget) && endTextPosition.paragraph.containerWidget instanceof BodyWidget)) || (!isNullOrUndefined(insertTextPosition.paragraph.containerWidget) && !isNullOrUndefined(endTextPosition.paragraph.containerWidget) && insertTextPosition.paragraph.containerWidget instanceof TableCellWidget && endTextPosition.paragraph.containerWidget instanceof TableCellWidget && !isNullOrUndefined(insertTextPosition.paragraph.bodyWidget)) || (!isNullOrUndefined(insertTextPosition.paragraph.containerWidget) && !isNullOrUndefined(endTextPosition.paragraph.containerWidget) && insertTextPosition.paragraph.containerWidget instanceof TextFrame && endTextPosition.paragraph.containerWidget instanceof TextFrame)) { //Removes if any empty paragraph is added while delete. this.owner.selectionModule.selectRange(insertTextPosition, endTextPosition); this.documentHelper.updateFocus(); var isDelete = false; if (this.action === 'BackSpace' || this.action === 'Uppercase' || this.action === 'RemoveRowTrack') { isDelete = true; } this.owner.editorModule.deleteSelectedContents(this.owner.selectionModule, isDelete, isDeletecell); } }; BaseHistoryInfo.prototype.updateEndRevisionInfo = function () { this.lastElementRevision = this.checkAdjacentNodeForMarkedRevision(this.lastElementRevision); var currentRevision = this.retrieveEndPosition(this.lastElementRevision); var blockInfo = this.owner.selectionModule.getParagraphInfo(currentRevision); var isLastChild = (blockInfo.paragraph == this.owner.editor.getLastParaForBodywidgetCollection(blockInfo.paragraph)); if (blockInfo.paragraph.isInsideTable && blockInfo.paragraph == this.owner.selection.getLastParagraph(blockInfo.paragraph.associatedCell)) { isLastChild = true; } if (blockInfo.paragraph.getLength() == blockInfo.offset && !isLastChild) { blockInfo.offset++; } this.endRevisionLogicalIndex = this.owner.selectionModule.getHierarchicalIndex(blockInfo.paragraph, blockInfo.offset.toString()); this.lastElementRevision.isMarkedForRevision = false; }; BaseHistoryInfo.prototype.retrieveEndPosition = function (elementBox) { var endPosition = new TextPosition(this.owner); var offset = elementBox.line.getOffset(elementBox, 0) + elementBox.length; endPosition.setPositionFromLine(elementBox.line, offset); return endPosition; }; /** * Method to retrieve exact spitted node which is marked as last available element. * * @param {ElementBox} elementBox - Specifies the element box * @returns {ElementBox} - Returns ele