UNPKG

@syncfusion/ej2-documenteditor

Version:

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

1,055 lines (1,054 loc) 68.4 kB
/* eslint-disable */ import { TextPosition, TextSearchResults } from '../index'; import { beforeXmlHttpRequestSend } from './../../index'; import { Dictionary } from '../../base/dictionary'; import { TextElementBox, ErrorTextElementBox, TableCellWidget, FieldElementBox } from '../viewer/page'; import { isNullOrUndefined } from '@syncfusion/ej2-base'; /** * The spell checker module */ var SpellChecker = /** @class */ (function () { function SpellChecker(documentHelper) { this.langIDInternal = 0; /** * Specifies whether spell check has to be performed or not. */ this.enableSpellCheckInternal = true; /** * @private */ /* eslint-disable @typescript-eslint/no-explicit-any */ this.uniqueSpelledWords = {}; /** * Every time rendering text elementbox we are checking the key length of the uniqueSpelledWords object. This causes performance issue So optimizing it. */ this.uniqueSpelledWordsCount = 0; this.spellSuggestionInternal = true; /** * @private */ this.uniqueKey = ''; this.removeUnderlineInternal = false; this.combinedElements = []; /** * @default 1000 */ this.uniqueWordsCountInternal = 15000; this.performOptimizedCheck = true; /** * @private */ this.isChangeAll = false; this.ignoreUppercaseInternal = false; this.documentHelper = documentHelper; this.errorWordCollection = new Dictionary(); this.uniqueWordsCollection = new Dictionary(); this.errorSuggestions = new Dictionary(); this.ignoreAllItems = []; this.uniqueSpelledWords = {}; if (!isNullOrUndefined(this.documentHelper) && !isNullOrUndefined(this.documentHelper.owner)) { this.textSearchResults = new TextSearchResults(this.documentHelper.owner); this.uniqueKey = this.documentHelper.owner.element.id + '_' + this.createGuid(); } } Object.defineProperty(SpellChecker.prototype, "ignoreUppercase", { /** * Gets a value indicating whether to ignore words written in uppercase during spell check. */ get: function () { return this.ignoreUppercaseInternal; }, /** * Sets a value indicating whether to ignore words written in uppercase during spell check. */ set: function (value) { this.ignoreUppercaseInternal = value; }, enumerable: true, configurable: true }); /** * Gets module name. */ SpellChecker.prototype.getModuleName = function () { return 'SpellChecker'; }; Object.defineProperty(SpellChecker.prototype, "enableOptimizedSpellCheck", { /** * Gets the boolean indicating whether optimized spell check to be performed. * * @aspType bool * @returns {boolean} Returns enableOptimizedSpellCheck */ get: function () { return this.performOptimizedCheck; }, /** * Sets the boolean indicating whether optimized spell check to be performed. * * @aspType bool */ set: function (value) { this.performOptimizedCheck = value; }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "uniqueWordsCount", { /** * Gets the spell checked Unique words. * * @aspType int */ get: function () { return isNullOrUndefined(this.uniqueWordsCountInternal) ? 0 : this.uniqueWordsCountInternal; }, /** * Sets the spell checked Unique words. * * @aspType int */ set: function (value) { this.uniqueWordsCountInternal = value; }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "languageID", { /** * Gets the languageID. * * @aspType int */ get: function () { return isNullOrUndefined(this.langIDInternal) ? 0 : this.langIDInternal; }, /** * Sets the languageID. * * @aspType int */ set: function (value) { this.langIDInternal = value; }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "allowSpellCheckAndSuggestion", { /** * Getter indicates whether suggestion enabled. * * @aspType bool */ get: function () { return this.spellSuggestionInternal; }, /** * Setter to enable or disable suggestion * * @aspType bool */ set: function (value) { this.spellSuggestionInternal = value; }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "removeUnderline", { /** * Getter indicates whether underline removed for mis-spelled word. * * @aspType bool */ get: function () { return this.removeUnderlineInternal; }, /** * Setter to enable or disable underline for mis-spelled word * * @aspType bool */ set: function (value) { this.removeUnderlineInternal = value; this.documentHelper.owner.editorModule.reLayout(this.documentHelper.selection); }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "enableSpellCheck", { /** * Getter indicates whether spell check has to be performed or not. * * @aspType bool */ get: function () { return this.enableSpellCheckInternal; }, /** * Setter to enable or disable spell check has to be performed or not * * @aspType bool */ set: function (value) { this.enableSpellCheckInternal = value; this.documentHelper.owner.editorModule.reLayout(this.documentHelper.selection); }, enumerable: true, configurable: true }); Object.defineProperty(SpellChecker.prototype, "viewer", { get: function () { return this.documentHelper.owner.viewer; }, enumerable: true, configurable: true }); /** * Method to manage replace logic * * @private */ SpellChecker.prototype.manageReplace = function (content, dialogElement) { this.documentHelper.triggerSpellCheck = true; var exactText = ''; var elementInfo; if (!isNullOrUndefined(dialogElement) && dialogElement instanceof ErrorTextElementBox) { var exactText_1 = dialogElement.text; this.documentHelper.selection.start = dialogElement.start.clone(); this.documentHelper.selection.end = dialogElement.end.clone(); if (content !== 'Ignore Once') { content = this.manageSpecialCharacters(exactText_1, content); this.documentHelper.owner.editorModule.insertTextInternal(content, true); this.documentHelper.selection.start.setPositionInternal(this.documentHelper.selection.end); this.documentHelper.clearSelectionHighlight(); return; } else { this.currentContextInfo = { 'text': exactText_1, 'element': dialogElement }; } } if (!isNullOrUndefined(this.currentContextInfo) && this.currentContextInfo.element && content !== 'Ignore Once') { var elementBox = this.currentContextInfo.element; exactText = this.currentContextInfo.element.text; this.documentHelper.selection.start = elementBox.start.clone(); this.documentHelper.selection.end = elementBox.end.clone(); } else { this.handleReplace(content); } if (content !== 'Ignore Once') { this.documentHelper.owner.editorModule.insertTextInternal(content, true); if (!isNullOrUndefined(this.currentContextInfo)) { this.removeErrorsFromCollection(this.currentContextInfo); } this.documentHelper.selection.start.setPositionInternal(this.documentHelper.selection.end); this.documentHelper.clearSelectionHighlight(); } //this.documentHelper.owner.errorWordCollection.remove(content); this.documentHelper.triggerSpellCheck = false; }; /** * Method to handle replace logic * * @private */ SpellChecker.prototype.handleReplace = function (content) { var startPosition = this.documentHelper.selection.start; var offset = startPosition.offset; var startIndex = 0; var startInlineObj = startPosition.currentWidget.getInline(offset, startIndex, false, true); var startOffset = startInlineObj.element.line.getOffset(startInlineObj.element, 0) + startInlineObj.element.length; if (startOffset === offset) { this.retrieveExactElementInfo(startInlineObj); } var exactText = startInlineObj.element.text; var startPattern = new RegExp('^[#\\@\\!\\~\\$\\%\\^\\&\\*\\(\\)\\-\\_\\+\\=\\{\\}\\[\\]\\:\\;\\"\'\\,\\<\\.\\>\\/\\?\\`\\s]+', 'g'); var matches = []; var matchInfo; // eslint-disable no-cond-assign while (!isNullOrUndefined(matchInfo = startPattern.exec(exactText))) { matches.push(matchInfo); } if (content === 'Ignore Once') { this.handleIgnoreOnce(startInlineObj); return; } startPosition.offset = offset - startInlineObj.index; if (!isNullOrUndefined(matches) && matches.length > 0) { startPosition.offset += matches[0].toString().length; } startPosition.location = this.documentHelper.owner.selectionModule.getPhysicalPositionInternal(startPosition.currentWidget, startPosition.offset, true); startPosition = this.documentHelper.owner.searchModule.textSearch.getTextPosition(startPosition.currentWidget, startPosition.offset.toString()); //startPosition.location = this.owner.selection.getPhysicalPositionInternal(span.line, offset, true); startPosition.setPositionParagraph(startPosition.currentWidget, startPosition.offset); var index = (startPosition.offset + startInlineObj.element.length) - startPosition.offset; var endOffset = startPosition.currentWidget.getOffset(startInlineObj.element, index); var lineWidget = startPosition.currentWidget; var endPattern = new RegExp('[#\\@\\!\\~\\$\\%\\^\\&\\*\\(\\)\\-\\_\\+\\=\\{\\}\\[\\]\\:\\;\\"\'\\,\\<\\.\\>\\/\\?\\s\\`]+$', 'g'); matches = []; // eslint-disable no-cond-assign while (!isNullOrUndefined(matchInfo = endPattern.exec(exactText))) { matches.push(matchInfo); } if (!isNullOrUndefined(matches) && matches.length > 0) { endOffset -= matches[0].toString().length; } this.documentHelper.selection.end = this.documentHelper.owner.searchModule.textSearch.getTextPosition(lineWidget, endOffset.toString()); this.documentHelper.selection.end.location = this.documentHelper.owner.selectionModule.getPhysicalPositionInternal(startPosition.currentWidget, endOffset, true); this.documentHelper.selection.end.setPositionParagraph(lineWidget, endOffset); this.currentContextInfo = { 'element': startInlineObj.element, 'text': startInlineObj.element.text }; }; /** * Method to retrieve exact element info * * @private */ SpellChecker.prototype.retrieveExactElementInfo = function (startInlineObj) { var nextElement = startInlineObj.element.nextElement; if (!isNullOrUndefined(nextElement) && nextElement instanceof TextElementBox) { var nextTextElBox = nextElement; if (nextTextElBox.text.trim() != "") { startInlineObj.element = nextElement; } } }; /** * Method to handle to ignore error Once * * @private */ SpellChecker.prototype.handleIgnoreOnce = function (startInlineObj) { if (this.documentHelper.owner && this.documentHelper.owner.editorModule) { this.documentHelper.owner.editor.initHistory('IgnoreOnce'); } var textElement = startInlineObj.element; // If text is split into multiple text elements, then we need to add ignoreOnceItems for all the text elements. So gets the start and end position of the text element and checks the same text exist which is in error element. if (!isNullOrUndefined(this.currentContextInfo) && this.currentContextInfo.element && this.currentContextInfo.element instanceof ErrorTextElementBox) { this.handleIgnoreOnceInternal(this.currentContextInfo.element, false); } else { var exactText = this.manageSpecialCharacters(textElement.text, undefined, true); if (textElement.ignoreOnceItems.indexOf(exactText) === -1) { textElement.ignoreOnceItems.push(exactText); } } this.documentHelper.owner.editorModule.reLayout(this.documentHelper.selection); }; /** * Method to handle to ignore error Once intenral * * @private */ SpellChecker.prototype.handleIgnoreOnceInternal = function (errorElement, isundoing) { var startPosition = errorElement.start; var endPosition = errorElement.end; var startInlineObj = startPosition.currentWidget.getInline(startPosition.offset, 0, false, true).element; var endInlineObj = endPosition.currentWidget.getInline(endPosition.offset, 0, false, true).element; while (true) { var exactText = this.manageSpecialCharacters(errorElement.text, undefined, true); var textIndex = startInlineObj.ignoreOnceItems.indexOf(exactText); if (isundoing) { if (textIndex !== -1) { startInlineObj.ignoreOnceItems.splice(textIndex, 1); } } else { if (textIndex === -1) { startInlineObj.ignoreOnceItems.push(exactText); } } if (startInlineObj === endInlineObj) { break; } startInlineObj = startInlineObj.nextNode; } }; /** * Method to handle ignore all items * * @private */ SpellChecker.prototype.handleIgnoreAllItems = function (contextElement) { var contextItem = (!isNullOrUndefined(contextElement)) ? contextElement : this.retriveText(); var retrievedText = this.manageSpecialCharacters(contextItem.text, undefined, true); if (this.ignoreAllItems.indexOf(retrievedText) === -1) { this.ignoreAllItems.push(retrievedText); this.removeErrorsFromCollection(contextItem); this.documentHelper.triggerSpellCheck = true; this.documentHelper.owner.editorModule.reLayout(this.documentHelper.selection); this.documentHelper.triggerSpellCheck = false; this.documentHelper.clearSelectionHighlight(); } }; /** * Method to handle dictionary * * @private */ SpellChecker.prototype.handleAddToDictionary = function (contextElement) { var _this = this; var contextItem = (!isNullOrUndefined(contextElement)) ? contextElement : this.retriveText(); var retrievedText = this.manageSpecialCharacters(contextItem.text, undefined, true); /* eslint-disable @typescript-eslint/no-explicit-any */ this.callSpellChecker(this.languageID, retrievedText, false, false, true).then(function (data) { if (!isNullOrUndefined(_this.documentHelper)) { _this.documentHelper.triggerSpellCheck = true; _this.removeErrorsFromCollection(contextItem); _this.ignoreAllItems.push(retrievedText); _this.documentHelper.owner.editorModule.reLayout(_this.documentHelper.selection, true); _this.documentHelper.triggerSpellCheck = false; } }); }; /** * Method to append/remove special characters * * @private */ SpellChecker.prototype.manageSpecialCharacters = function (exactText, replaceText, isRemove) { if (!isNullOrUndefined(exactText)) { var isRemoveSpecChar = false; if (isNullOrUndefined(replaceText)) { isRemoveSpecChar = true; replaceText = exactText; } var pattern = new RegExp('^[#\\@\\!\\$\\%\\^\\&\\*\\(\\)\\-\\_\\+\\=\\{\\}\\[\\]\\:\\;\\"\\”\'\\,\\<\\.\\>\\/\\?\\`\\s\\’]+', 'g'); var matches = []; var matchInfo = void 0; // eslint-disable no-cond-assign while (!isNullOrUndefined(matchInfo = pattern.exec(exactText))) { matches.push(matchInfo); } if (matches.length > 0) { for (var i = 0; i < matches.length; i++) { /* eslint-disable @typescript-eslint/no-explicit-any */ var match = matches[i]; replaceText = (!isRemove) ? match[0] + replaceText : replaceText.replace(match[0], ''); } } var endPattern = new RegExp('[#\\@\\!\\$\\%\\^\\&\\*\\(\\)\\-\\_\\+\\=\\{\\}\\[\\]\\:\\;\\"\\”\'\\,\\<\\>\\/\\?\\s\\`\\’]+$', 'g'); matches = []; var originalText = replaceText; if (!isRemove) { originalText = exactText; } // eslint-disable no-cond-assign while (!isNullOrUndefined(matchInfo = endPattern.exec(originalText))) { matches.push(matchInfo); } if (matches.length > 0) { for (var i = 0; i < matches.length; i++) { /* eslint-disable @typescript-eslint/no-explicit-any */ var match = matches[i]; replaceText = (!isRemove) ? replaceText + match[0] : replaceText.slice(0, match.index); } } // if the text contains zero width characters, remove them. var zeroWidthPattern = /[\u200B-\u200D\uFEFF]/g; replaceText = replaceText.replace(zeroWidthPattern, ''); } return replaceText; }; /** * Method to remove errors * * @private */ SpellChecker.prototype.removeErrorsFromCollection = function (contextItem) { if (!isNullOrUndefined(contextItem.text) && this.errorWordCollection.containsKey(contextItem.text)) { var textElement = this.errorWordCollection.get(contextItem.text); if (textElement.indexOf(contextItem.element) >= 0) { textElement.splice(0, 1); } if (textElement.length === 0) { this.errorWordCollection.remove(contextItem.text); } } }; /** * Method to retrieve exact text * * @private */ SpellChecker.prototype.retriveText = function () { var exactText; var currentElement; if (!isNullOrUndefined(this.currentContextInfo) && this.currentContextInfo.element) { currentElement = this.currentContextInfo.element; exactText = this.currentContextInfo.element.text; this.documentHelper.selection.start = currentElement.start.clone(); this.documentHelper.selection.end = currentElement.end.clone(); } else { var startPosition = this.documentHelper.selection.start; var offset = startPosition.offset; var startIndex = 0; var startInlineObj = startPosition.currentWidget.getInline(offset, startIndex); currentElement = startInlineObj.element; exactText = startInlineObj.element.text; } return { 'text': exactText, 'element': currentElement }; }; /** * Method to handle suggestions * * @private */ /* eslint-disable @typescript-eslint/no-explicit-any */ SpellChecker.prototype.handleSuggestions = function (allsuggestions) { this.spellCheckSuggestion = []; if (allsuggestions.length === 0) { this.spellCheckSuggestion.push(this.documentHelper.owner.contextMenuModule.locale.getConstant('Add to Dictionary')); } else { allsuggestions = (allsuggestions.length > 3) ? this.constructInlineMenu(allsuggestions) : allsuggestions; this.spellCheckSuggestion.push(this.documentHelper.owner.contextMenuModule.locale.getConstant('Add to Dictionary')); } /* eslint-disable @typescript-eslint/no-explicit-any */ var spellSuggestion = []; if (this.spellCheckSuggestion.length > 0) { for (var _i = 0, _a = this.spellCheckSuggestion; _i < _a.length; _i++) { var str = _a[_i]; spellSuggestion.push({ text: str, id: this.documentHelper.owner.element.id + '_contextmenu_otherSuggestions_spellcheck_' + (str === this.documentHelper.owner.contextMenuModule.locale.getConstant('Add to Dictionary') ? 'Add to Dictionary' : str), iconCss: '' }); } } return spellSuggestion; }; /** * Method to check whether text element has errors * * @private */ SpellChecker.prototype.checktextElementHasErrors = function (text, element, left) { var hasError = false; var erroElements = []; text = text.replace(/[\s]+/g, ''); if (!isNullOrUndefined(element.errorCollection) && element.errorCollection.length > 0) { if (!this.documentHelper.isScrollHandler && (element.isChangeDetected || element.paragraph.isChangeDetected) && !element.istextCombined) { this.updateStatusForGlobalErrors(element.errorCollection, element); element.errorCollection = []; element.isChangeDetected = true; return { 'errorFound': hasError, 'elements': erroElements }; } for (var i = 0; i < element.errorCollection.length; i++) { if (this.handleErrorCollection(element.errorCollection[i])) { hasError = true; erroElements.push(element.errorCollection[i]); } } } else if (!this.documentHelper.isScrollHandler && element.paragraph.isChangeDetected) { element.isChangeDetected = true; } else if (!element.isChangeDetected && this.handleErrorCollection(element)) { hasError = true; erroElements.push(element); } return { 'errorFound': hasError, 'elements': erroElements }; }; SpellChecker.prototype.updateStatusForGlobalErrors = function (erroElements, parentElement) { if (erroElements.length > 0) { for (var i = 0; i < erroElements.length; i++) { var exactText = this.manageSpecialCharacters(erroElements[i].text, undefined, true); if (this.errorWordCollection.containsKey(exactText)) { var elements = this.errorWordCollection.get(exactText); for (var j = 0; j < elements.length; j++) { if (elements[j] instanceof ErrorTextElementBox && elements[j] === erroElements[i]) { elements[j].isChangeDetected = true; elements[j].start.offset = parentElement.line.getOffset(parentElement.istextCombined ? this.getCombinedElement(parentElement) : parentElement, 0); elements[j].line = parentElement.line; break; } } } } } }; /** * Method to handle document error collection. * * @param {string} errorInElement * @private */ SpellChecker.prototype.handleErrorCollection = function (errorInElement) { var errors = this.errorWordCollection; var exactText = this.manageSpecialCharacters(errorInElement.text, undefined, true); if (errors.containsKey(exactText) && errorInElement.length > 1) { var ignoreAllIndex = this.ignoreAllItems.indexOf(exactText); if (ignoreAllIndex > -1) { if (errors.containsKey(exactText)) { errors.remove(exactText); } return false; } return true; } return false; }; /* eslint-disable @typescript-eslint/no-explicit-any */ SpellChecker.prototype.constructInlineMenu = function (inlineSuggestion) { for (var i = inlineSuggestion.length - 1; i > 0; i--) { if (inlineSuggestion.length > 3) { this.spellCheckSuggestion.push(inlineSuggestion[i]); inlineSuggestion.pop(); } } return inlineSuggestion; }; /** * Method to retrieve error element text * * @private */ SpellChecker.prototype.findCurretText = function () { var insertPosition = this.documentHelper.selection.start; /* eslint-disable @typescript-eslint/no-explicit-any */ var element; /* eslint-disable @typescript-eslint/no-explicit-any */ var inlineObj = insertPosition.currentWidget.getInline(this.documentHelper.selection.start.offset, 0); var text; if (!isNullOrUndefined(inlineObj.element)) { if (!isNullOrUndefined(inlineObj.element.errorCollection) && inlineObj.element.errorCollection.length > 0) { for (var i = 0; i < inlineObj.element.errorCollection.length; i++) { var errorElement = inlineObj.element.errorCollection[i]; // If the cursor is in error element, then we need to retrieve the text from that error element. if (errorElement.start.isExistBefore(this.documentHelper.selection.start) && errorElement.end.isExistAfter(this.documentHelper.selection.start)) { text = errorElement.text; element = errorElement; break; } } } else { text = inlineObj.element.text; } if (text === ' ') { inlineObj = insertPosition.currentWidget.getInline(this.documentHelper.selection.start.offset + 1, 0); text = inlineObj.element.text; } } return { 'text': text, 'element': element }; }; SpellChecker.prototype.addErrorCollection = function (text, elementToCompare, suggestions) { text = this.manageSpecialCharacters(text, undefined, true); if (this.errorWordCollection.containsKey(text)) { var errorElements = this.errorWordCollection.get(text); if (elementToCompare instanceof ErrorTextElementBox) { if (!this.compareErrorTextElement(elementToCompare, errorElements)) { errorElements.push(elementToCompare); } } else if (elementToCompare instanceof TextElementBox) { if (!this.compareTextElement(elementToCompare, errorElements)) { errorElements.push(elementToCompare); } } } else { if (!isNullOrUndefined(suggestions) && suggestions.length > 0) { this.errorSuggestions.add(text, suggestions); } this.errorWordCollection.add(text, [elementToCompare]); if (!this.uniqueWordsCollection.containsKey(text)) { this.uniqueWordsCollection.add(text, true); } } }; SpellChecker.prototype.addCorrectWordCollection = function (text) { text = this.manageSpecialCharacters(text, undefined, true); if (!this.uniqueWordsCollection.containsKey(text)) { this.uniqueWordsCollection.add(text, false); } }; /** * @private */ SpellChecker.prototype.isInUniqueWords = function (text) { text = text.replace(/[\s]+/g, ''); return this.uniqueWordsCollection.containsKey(text); }; /** * @private */ SpellChecker.prototype.isErrorWord = function (text) { text = text.replace(/[\s]+/g, ''); return this.uniqueWordsCollection.get(text); }; /** * @private */ SpellChecker.prototype.isCorrectWord = function (text) { text = text.replace(/[\s]+/g, ''); return !this.uniqueWordsCollection.get(text); }; SpellChecker.prototype.compareErrorTextElement = function (errorElement, errorCollection) { var copyElement = []; var isChanged = false; for (var i = 0; i < errorCollection.length; i++) { copyElement.push(errorCollection[i]); } var length = errorCollection.length; for (var i = 0; i < length; i++) { if (copyElement[i] instanceof ErrorTextElementBox) { if (copyElement[i].isChangeDetected) { var exactText = this.manageSpecialCharacters(copyElement[i].text, undefined, true); isChanged = true; this.removeErrorsFromCollection({ 'element': copyElement[i], 'text': exactText }); } else { var currentElement = copyElement[i]; if (errorElement.start.offset === currentElement.start.offset && errorElement.end.offset === currentElement.end.offset) { return true; } } } } if (isChanged) { this.errorWordCollection.add(this.manageSpecialCharacters(errorElement.text, undefined, true), [errorElement]); } return false; }; /** * Method to compare text elements * * @private */ SpellChecker.prototype.compareTextElement = function (errorElement, errorCollection) { for (var i = 0; i < errorCollection.length; i++) { if (errorCollection[i] instanceof TextElementBox) { var currentElement = errorCollection[i]; if (currentElement === errorElement) { return true; } } } return false; }; /** * Method to handle Word by word spell check * * @private */ SpellChecker.prototype.handleWordByWordSpellCheck = function (jsonObject, elementBox, left, top, underlineY, baselineAlignment, isSamePage, currentText) { if (isNullOrUndefined(currentText)) { currentText = elementBox.text; } if (jsonObject.HasSpellingError && isSamePage) { this.addErrorCollection(currentText, elementBox, jsonObject.Suggestions); if (currentText === elementBox.text.trim()) { var backgroundColor = (elementBox.line.paragraph.containerWidget instanceof TableCellWidget) ? elementBox.line.paragraph.containerWidget.cellFormat.shading.backgroundColor : this.documentHelper.backgroundColor; this.documentHelper.render.renderWavyLine(elementBox, left, top, underlineY, '#FF0000', 'Single', baselineAlignment, backgroundColor); elementBox.isSpellChecked = true; } } else { this.addCorrectWordCollection(currentText); elementBox.isSpellChecked = true; } }; /** * Method to check errors for combined elements * * @private */ SpellChecker.prototype.checkElementCanBeCombined = function (elementBox, underlineY, beforeIndex, callSpellChecker, textToCombine, isNext, isPrevious, canCombine) { var currentText = isNullOrUndefined(textToCombine) ? '' : textToCombine; var isCombined = isNullOrUndefined(canCombine) ? false : canCombine; var checkPrevious = !isNullOrUndefined(isPrevious) ? isPrevious : true; var checkNext = !isNullOrUndefined(isNext) ? isNext : true; var line = this.documentHelper.selection.getLineWidget(elementBox, 0); var index = line.children.indexOf(elementBox); var prevText = elementBox.text; if (this.combinedElements.indexOf(elementBox) === -1) { this.combinedElements.push(elementBox); } var difference = (isPrevious) ? 0 : 1; var prevCombined = false; var isPrevField = false; if (elementBox.text !== '\v') { if (checkPrevious) { var textElement = undefined; for (var i = index - difference; i >= 0; i--) { textElement = line.children[i]; if (!isNullOrUndefined(textElement) && textElement.revisionLength > 0 && textElement.getRevision(0).revisionType === "Deletion") { break; } if (textElement instanceof TextElementBox && !isPrevField) { if (prevText.indexOf(' ') !== 0 && textElement.text.lastIndexOf(' ') !== textElement.text.length - 1) { prevCombined = !isNullOrUndefined(textToCombine) ? true : false; currentText = textElement.text + currentText; prevText = textElement.text; isPrevField = false; if (this.combinedElements.indexOf(textElement) === -1) { this.combinedElements.push(textElement); } isCombined = true; } else if (!isNullOrUndefined(textElement)) { textElement = textElement.nextElement; break; } } else if (textElement instanceof FieldElementBox && textElement.fieldType !== 1) { isPrevField = true; } } var currentElement = (isCombined) ? textElement : elementBox; if (this.lookThroughPreviousLine(currentText, prevText, currentElement, underlineY, beforeIndex)) { this.combinedElements.length = 0; return true; } } if (isPrevious) { currentText = (prevCombined) ? currentText : elementBox.text + currentText; } else { currentText += elementBox.text; } isPrevField = false; var nextText = elementBox.text; if (checkNext) { var canCombine_1 = false; var element = undefined; for (var i = index + 1; i < line.children.length; i++) { element = line.children[i]; if (!isNullOrUndefined(element) && element.revisionLength > 0 && element.getRevision(0).revisionType === "Deletion") { break; } if (element instanceof TextElementBox && !isPrevField) { if (nextText.lastIndexOf(' ') !== nextText.length - 1 && element.text.indexOf(' ') !== 0) { currentText += element.text; nextText = element.text; isPrevField = false; this.combinedElements.push(element); canCombine_1 = true; isCombined = true; } else if (!isNullOrUndefined(element)) { element = element.previousElement; break; } } else if (element instanceof FieldElementBox && element.fieldType !== 2) { isPrevField = true; } } var currentElement = (canCombine_1) ? element : elementBox; if (currentElement.text !== '\f' && currentElement.text !== String.fromCharCode(14) && this.lookThroughNextLine(currentText, prevText, currentElement, underlineY, beforeIndex)) { this.combinedElements.length = 0; return true; } } } if (isCombined && callSpellChecker && !this.checkCombinedElementsBeIgnored(this.combinedElements, currentText)) { if (isPrevious || isNext) { for (var i = 0; i < this.combinedElements.length; i++) { this.combinedElements[i].isChangeDetected = false; if (i !== 0) { this.combinedElements[i].istextCombined = true; this.combinedElements[i].errorCollection = this.combinedElements[0].errorCollection; } } } else { this.combinedElements.length = 0; } this.handleCombinedElements(elementBox, currentText, underlineY); } this.combinedElements.length = 0; return isCombined; }; SpellChecker.prototype.lookThroughPreviousLine = function (currentText, prevText, currentElement, underlineY, beforeIndex) { if (!isNullOrUndefined(currentElement) && currentElement.indexInOwner === 0 && !isNullOrUndefined(currentElement.line.previousLine)) { var previousLine = currentElement.line.previousLine; var index = previousLine.children.length - 1; if (!isNullOrUndefined(previousLine.children[index]) && previousLine.children[index] instanceof TextElementBox) { var firstElement = previousLine.children[index]; if (!isNullOrUndefined(currentElement.text)) { if (currentElement.text.indexOf(' ') !== 0 && firstElement.text.lastIndexOf(' ') !== firstElement.text.length - 1 && !(firstElement.text === '\v' || firstElement.text === '\t' || firstElement.text === '\f')) { currentText = (currentText.length > 0) ? currentText : prevText; this.checkElementCanBeCombined(firstElement, underlineY, beforeIndex, true, currentText, false, true, true); return true; } } } } return false; }; SpellChecker.prototype.lookThroughNextLine = function (currentText, prevText, elementBox, underlineY, beforeIndex) { if (elementBox instanceof TextElementBox && !isNullOrUndefined(elementBox) && elementBox.indexInOwner === elementBox.line.children.length - 1 && !isNullOrUndefined(elementBox.line.nextLine)) { var nextLine = elementBox.line.nextLine; if (!isNullOrUndefined(nextLine.children[0]) && nextLine.children[0] instanceof TextElementBox) { var firstElement = nextLine.children[0]; if (elementBox.text.lastIndexOf(' ') !== elementBox.text.length - 1 && firstElement.text.indexOf(' ') !== 0 && !(elementBox.text === '\v' || elementBox.text === '\t' || elementBox.text === '\f')) { currentText = (currentText.length > 0) ? currentText : prevText; this.checkElementCanBeCombined(firstElement, underlineY, beforeIndex, true, currentText, true, false, true); return true; } } } return false; }; /** * Method to handle combined elements * * @param {TextElementBox} elementBox * @param {string} currentText * @param {number} underlineY * @param {number} beforeIndex * @private */ SpellChecker.prototype.handleCombinedElements = function (elementBox, currentText, underlineY) { var splittedText = currentText.split(/[\s]+/); if (this.ignoreAllItems.indexOf(currentText) === -1 && elementBox instanceof TextElementBox && elementBox.ignoreOnceItems.indexOf(currentText) === -1) { if (splittedText.length > 1) { for (var i = 0; i < splittedText.length; i++) { var currentText_1 = splittedText[i]; currentText_1 = this.manageSpecialCharacters(currentText_1, undefined, true); this.documentHelper.render.handleUnorderedElements(currentText_1, elementBox, underlineY, i, 0, i === splittedText.length - 1, this.combinedElements); } } else { currentText = this.manageSpecialCharacters(currentText, undefined, true); this.documentHelper.render.handleUnorderedElements(currentText, elementBox, underlineY, 0, 0, true, this.combinedElements); } } }; /** * Method to check error element collection has unique element * * @param {ErrorTextElementBox[]} errorCollection * @param {ErrorTextElementBox} elementToCheck * @private */ SpellChecker.prototype.checkArrayHasSameElement = function (errorCollection, elementToCheck) { for (var i = 0; i < errorCollection.length; i++) { var errorText = errorCollection[i]; if ((errorText.start.location.x === elementToCheck.start.location.x) && (errorText.start.location.y === elementToCheck.start.location.y)) { return true; } } return false; }; /** * @private */ SpellChecker.prototype.handleSplitWordSpellCheck = function (jsonObject, currentText, elementBox, isSamePage, underlineY, iteration, markIndex, isLastItem, combinedElements) { if (jsonObject.HasSpellingError && elementBox.text !== ' ' && isSamePage) { var textSearch = this.documentHelper.owner.searchModule.textSearch; var matchResults = this.getMatchedResultsFromElement(elementBox, currentText); // Handled combined elements split to multiple lines when textResults is empty. // Only the first element will be rendered with wavy line. Other elements will be rendered in renderTextElementBox method in render Element. if (!isNullOrUndefined(combinedElements) && matchResults.textResults.length === 0 && combinedElements.length > 0) { var combinedElement = combinedElements[0]; matchResults = this.getMatchedResultsFromElement(combinedElement, combinedElement.text); markIndex = combinedElement.line.getOffset(this.getCombinedElement(combinedElement), 0); textSearch.updateMatchedTextLocation(matchResults.matches, matchResults.textResults, matchResults.elementInfo, 0, combinedElement, false, null, markIndex); this.handleMatchedResults(matchResults.textResults, combinedElement, underlineY, iteration, jsonObject.Suggestions, false, currentText, combinedElements); } else { markIndex = (elementBox.istextCombined) ? elementBox.line.getOffset(this.getCombinedElement(elementBox), 0) : markIndex; textSearch.updateMatchedTextLocation(matchResults.matches, matchResults.textResults, matchResults.elementInfo, 0, elementBox, false, null, markIndex); this.handleMatchedResults(matchResults.textResults, elementBox, underlineY, iteration, jsonObject.Suggestions, isLastItem); } } else { this.addCorrectWordCollection(currentText); if (isLastItem) { elementBox.isSpellChecked = true; } } this.updateUniqueWord([{ Text: currentText, HasSpellError: jsonObject.HasSpellingError }]); }; SpellChecker.prototype.handleMatchedResults = function (results, elementBox, wavyLineY, index, suggestions, isLastItem, errorText, combinedElements) { if (results.length === 0 && isLastItem) { elementBox.isSpellChecked = true; return; } for (var i = 0; i < results.length; i++) { var span = this.createErrorElementWithInfo(results.innerList[i], elementBox); // Updated the error text and text position for combined elements. if (!isNullOrUndefined(errorText)) { span.text = errorText; var startElement = combinedElements[0]; var endElement = combinedElements[combinedElements.length - 1]; // Set the start and end position for the error element when text is splitted into multiple lines. if (startElement && endElement) { var offset = startElement.line.getOffset(startElement, 0); var startPosition = new TextPosition(this.documentHelper.owner); startPosition.setPositionParagraph(startElement.line, offset); offset = endElement.line.getOffset(endElement, (endElement.length)); var endPosition = new TextPosition(this.documentHelper.owner); endPosition.setPositionParagraph(endElement.line, offset); span.start = startPosition; span.end = endPosition; } } var color = '#FF0000'; if (!isNullOrUndefined(elementBox.errorCollection) && !this.checkArrayHasSameElement(elementBox.errorCollection, span)) { elementBox.errorCollection.splice(index, 0, span); } this.addErrorCollection(span.text, span, suggestions); var elements = this.errorWordCollection.get(span.text); if (!isNullOrUndefined(elements) && elements.indexOf(elementBox) !== -1 && elements.indexOf(elementBox) !== elements.indexOf(span)) { elements.splice(elements.indexOf(elementBox), 1); } var backgroundColor = (elementBox.line.paragraph.containerWidget instanceof TableCellWidget) ? elementBox.paragraph.containerWidget.cellFormat.shading.backgroundColor : this.documentHelper.backgroundColor; var para = elementBox.line.paragraph; var lineY = para.y; for (var i_1 = 0; i_1 < para.childWidgets.length; i_1++) { if (para.childWidgets[i_1] == elementBox.line) break; lineY += para.childWidgets[i_1].height; } if (elementBox.isRightToLeft) { this.documentHelper.render.renderWavyLine(span, span.end.location.x, lineY, wavyLineY, color, 'Single', elementBox.characterFormat.baselineAlignment, backgroundColor); } else { this.documentHelper.render.renderWavyLine(span, span.start.location.x, lineY, wavyLineY, color, 'Single', elementBox.characterFormat.baselineAlignment, backgroundColor); } if (isLastItem) { elementBox.isSpellChecked = true; } } }; /** * Calls the spell checker service. * @private */ /* eslint-disable @typescript-eslint/no-explicit-any */ SpellChecker.prototype.callSpellChecker = function (languageID, word, checkSpelling, checkSuggestion, addWord, isByPage) { var _this = this; var spellchecker = this; return new Promise(function (resolve, reject) { if (!isNullOrUndefined(_this)) { var httpRequest_1 = new XMLHttpRequest(); var service_1 = _this.documentHelper.owner.serviceUrl; service_1 = (isByPage) ? service_1 + _this.documentHelper.owner.serverActionSettings.spellCheckByPage : service_1 + _this.documentHelper.owner.serverActionSettings.spellCheck; httpRequest_1.open('POST', service_1, true); httpRequest_1.setRequestHeader('Content-Type', 'application/json'); var headers = _this.documentHelper.owner.headers; /* eslint-disable @typescript-eslint/no-explicit-any */ if (isByPage) { word = word.replace(String.fromCharCode(160), ' '); } var spellCheckData = { LanguageID: languageID, TexttoCheck: word, CheckSpelling: checkSpelling, CheckSuggestion: checkSuggestion, AddWord: addWord, IgnoreUppercase: _this.ignoreUppercase }; var httprequestEventArgs = { serverActionType: 'SpellCheck', headers: headers, timeout: 0, cancel: false, withCredentials: false }; headers = httprequestEventArgs.headers; _this.documentHelper.owner.trigger(beforeXmlHttpRequestSend, httprequestEventArgs); _this.setCustomHeaders(httpRequest_1, httprequestEventArgs.headers); httpRequest_1.withCredentials = httprequestEventArgs.withCredentials; if (!httprequestEventArgs.cancel) { httpRequest_1.send(JSON.stringify(spellCheckData)); } httpRequest_1.onreadystatechange = function () { if (httpRequest_1.readyState === 4) { if (httpRequest_1.status === 200 || httpRequest_1.status === 304) { resolve(httpRequest_1.response); } else { var result = {