UNPKG

@syncfusion/ej2-documenteditor

Version:

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

419 lines (418 loc) 22.5 kB
import { Dictionary } from '../../base/dictionary'; import { isNullOrUndefined } from '@syncfusion/ej2-base'; import { TextPosition } from '../selection/selection-helper'; import { LineWidget, TextElementBox, ParagraphWidget, ListTextElementBox, FieldElementBox, ShapeElementBox, BookmarkElementBox, CommentCharacterElementBox } from '../viewer/page'; import { searchResultsChangeEvent } from '../../base/index'; /** * @private */ var TextSearch = /** @class */ (function () { function TextSearch(owner) { this.wordBefore = '\\b'; this.wordAfter = '\\b'; this.owner = owner; this.documentHelper = this.owner.documentHelper; } TextSearch.prototype.find = function (pattern, findOption) { var result = this.findNext(pattern, findOption, '0;0;0'); if (!isNullOrUndefined(result)) { var eventArgs = { source: this.documentHelper.owner }; this.documentHelper.owner.trigger(searchResultsChangeEvent, eventArgs); } return result; }; TextSearch.prototype.findNext = function (pattern, findOption, hierarchicalPosition) { if (typeof pattern === 'string') { pattern = this.stringToRegex(pattern, findOption); } if (hierarchicalPosition === undefined) { hierarchicalPosition = '0;0;0'; } this.owner.searchModule.textSearchResults.clearResults(); var results = this.owner.searchModule.textSearchResults; this.findDocument(results, pattern, true, findOption, hierarchicalPosition); return results.length > 0, results.currentSearchResult; }; TextSearch.prototype.stringToRegex = function (textToFind, option) { if (textToFind.indexOf('\\') > -1) { textToFind = textToFind.split('\\').join('\\\\'); } if (textToFind.indexOf('(') > -1 || textToFind.indexOf(')') > -1 || textToFind.indexOf('.') > -1 || textToFind.indexOf('[') > -1 || textToFind.indexOf(']') > -1 || textToFind.indexOf('$') > -1 || textToFind.indexOf('{') > -1 || textToFind.indexOf('}') > -1 || textToFind.indexOf('*') > -1 || textToFind.indexOf('|') > -1 || textToFind.indexOf('^') > -1 || textToFind.indexOf('?') > -1 || textToFind.indexOf('+') > -1) { var text = ''; for (var i = 0; i < textToFind.length; i++) { if (textToFind[parseInt(i.toString(), 10)] === '(' || textToFind[parseInt(i.toString(), 10)] === ')' || textToFind[parseInt(i.toString(), 10)] === '.' || textToFind[parseInt(i.toString(), 10)] === '[' || textToFind[parseInt(i.toString(), 10)] === ']' || textToFind[parseInt(i.toString(), 10)] === '$' || textToFind[parseInt(i.toString(), 10)] === '{' || textToFind[parseInt(i.toString(), 10)] === '}' || textToFind[parseInt(i.toString(), 10)] === '*' || textToFind[parseInt(i.toString(), 10)] === '|' || textToFind[parseInt(i.toString(), 10)] === '^' || textToFind[parseInt(i.toString(), 10)] === '?' || textToFind[parseInt(i.toString(), 10)] === '+') { text += '\\' + textToFind[parseInt(i.toString(), 10)]; } else { text += textToFind[parseInt(i.toString(), 10)]; } } textToFind = text; } if (option === 'WholeWord' || option === 'CaseSensitiveWholeWord') { textToFind = this.wordBefore + textToFind + this.wordAfter; } return RegExp(textToFind, (option === 'CaseSensitive' || option === 'CaseSensitiveWholeWord') ? 'g' : 'ig'); }; TextSearch.prototype.isPatternEmpty = function (pattern) { var wordEmpty = this.wordBefore + this.wordAfter; var patternRegExp = pattern.toString(); return (patternRegExp.length === 0 || patternRegExp === wordEmpty); }; TextSearch.prototype.findAll = function (pattern, findOption, hierarchicalPosition) { if (typeof pattern === 'string') { pattern = this.stringToRegex(pattern, findOption); } if (hierarchicalPosition === undefined) { hierarchicalPosition = '0;0;0'; } this.owner.searchModule.textSearchResults.clearResults(); var results = this.owner.searchModule.textSearchResults; this.findDocument(results, pattern, false, findOption, hierarchicalPosition); if (results.length > 0 && results.currentIndex < 0) { results.currentIndex = 0; } if (!isNullOrUndefined(results.currentSearchResult)) { var eventArgs = { source: this.documentHelper.owner }; this.documentHelper.owner.trigger(searchResultsChangeEvent, eventArgs); return results; } return undefined; }; TextSearch.prototype.getElementInfo = function (inlineElement, indexInInline, includeNextLine, pattern, findOption, isFirstMatch, results, selectionEnd, isSpellCheck) { var inlines = inlineElement; var stringBuilder = ''; var spans = new Dictionary(); // eslint-disable no-constant-condition var previousElementCount = 0; do { if (inlineElement instanceof TextElementBox && (!isNullOrUndefined(inlineElement.text) && inlineElement.text !== '')) { spans.add(inlineElement, isSpellCheck ? stringBuilder.length + previousElementCount : stringBuilder.length); previousElementCount = 0; // IndexInInline Handled specifically for simple find operation to start from starting point if (inlineElement === inlines) { stringBuilder = stringBuilder + (inlineElement.text.substring(indexInInline)); } else { stringBuilder = stringBuilder + (inlineElement.text); } } else if (inlineElement instanceof FieldElementBox) { var fieldBegin = inlineElement; if (!isNullOrUndefined(fieldBegin.fieldEnd)) { /* eslint-disable-next-line max-len */ inlineElement = isNullOrUndefined(fieldBegin.fieldSeparator) ? fieldBegin.fieldEnd : fieldBegin.fieldSeparator; } } else if (inlineElement instanceof ShapeElementBox && !isNullOrUndefined(inlineElement.textFrame) && inlineElement.textFrame.childWidgets.length > 0) { this.findInlineText(inlineElement.textFrame, pattern, findOption, isFirstMatch, results, selectionEnd); } if (!(inlineElement instanceof TextElementBox) && !(inlineElement instanceof ListTextElementBox)) { previousElementCount += inlineElement.length; } if (!isNullOrUndefined(inlineElement) && isNullOrUndefined(inlineElement.nextNode)) { var splittedParagraph = inlineElement.paragraph.nextSplitWidget; if (!isSpellCheck && !isNullOrUndefined(splittedParagraph) && splittedParagraph !== inlineElement.paragraph && splittedParagraph.childWidgets.length > 0 && splittedParagraph.childWidgets[0] instanceof LineWidget && splittedParagraph.childWidgets[0].children.length > 0) { inlineElement = splittedParagraph.childWidgets[0].children[0]; continue; } else { break; } } if (!isNullOrUndefined(inlineElement)) { if ((!isNullOrUndefined(includeNextLine) && !includeNextLine)) { var elementBoxes = inlineElement.line.children; var length_1 = inlineElement.line.children.length; if (elementBoxes.indexOf(inlineElement) < length_1 - 1) { inlineElement = inlineElement.nextNode; } else { inlineElement = undefined; break; } } else { inlineElement = inlineElement.nextNode; } } // eslint-disable-next-line no-constant-condition } while (true); var text = stringBuilder.toString(); return { elementsWithOffset: spans, fullText: text }; }; /* eslint-disable-next-line max-len */ TextSearch.prototype.updateMatchedTextLocation = function (matches, results, textInfo, indexInInline, inlines, isFirstMatch, selectionEnd, startPosition) { for (var i = 0; i < matches.length; i++) { var match = matches[parseInt(i.toString(), 10)]; var isMatched = void 0; if (!(isNullOrUndefined(startPosition)) && match.index < startPosition) { continue; } var result = results.addResult(); var spanKeys = textInfo.keys; var isContainField = false; for (var j = 0; j < spanKeys.length; j++) { var span = spanKeys[parseInt(j.toString(), 10)]; var startIndex = textInfo.get(span); var spanLength = span.length; // IndexInInline Handled specifically for simple find operation to start from starting point if (span === inlines) { spanLength -= indexInInline; } if (isNullOrUndefined(result.start) && match.index < startIndex + spanLength) { var index = match.index - startIndex; // IndexInInline Handled specifically for simple find operation to start from starting point if (span === inlines) { index += indexInInline; } var offset = (span.line).getOffset(span, index); result.start = this.getTextPosition(span.line, offset.toString()); result.start.location = this.owner.selectionModule.getPhysicalPositionInternal(span.line, offset, true); result.start.setPositionParagraph(span.line, offset); result.startOffset = this.owner.selectionModule.getHierarchicalIndexByPosition(result.start); } if (match.index + match[0].length <= startIndex + spanLength) { var index = (match.index + match[0].length) - startIndex; // IndexInInline Handled specifically for simple find operation to start from starting point if (span === inlines) { index += indexInInline; } if (!(!isNullOrUndefined(this.owner.searchModule.textSearchResults) && this.owner.searchModule.textSearchResults.length !== 0) && span.text.charAt(span.text.length - 1) !== ' ' && !isNullOrUndefined(span.nextElement) && (span.nextElement instanceof BookmarkElementBox || span.nextElement instanceof CommentCharacterElementBox)) { var element = span.nextElement; while (element) { element = element.nextElement; if (element instanceof TextElementBox) { break; } } if (element && element instanceof TextElementBox && element.text.charAt(0) !== ' ' && element.text.charAt(0) !== '') { isContainField = true; continue; } } if (!(!isNullOrUndefined(this.owner.searchModule.textSearchResults) && this.owner.searchModule.textSearchResults.length !== 0) && span.previousElement && (span.previousElement instanceof BookmarkElementBox || span.previousElement instanceof CommentCharacterElementBox)) { isContainField = true; } var offset = 0; if (isContainField) { offset = (span.line).getOffset(span, 0) + span.length; } else { offset = (span.line).getOffset(span, index); } result.end = this.getTextPosition(span.line, offset.toString()); result.end.location = this.owner.selectionModule.getPhysicalPositionInternal(span.line, offset, true); result.end.setPositionParagraph(span.line, offset); result.endOffset = this.owner.selectionModule.getHierarchicalIndexByPosition(result.end); isMatched = true; break; } } if (isFirstMatch) { results.currentIndex = 0; break; } else if (results.currentIndex < 0 && !isNullOrUndefined(selectionEnd) && (selectionEnd.isExistBefore(result.start) || selectionEnd.isAtSamePosition(result.start))) { results.currentIndex = results.indexOf(result); } if (!isNullOrUndefined(startPosition) && isMatched) { break; } } }; /* eslint-disable-next-line max-len */ TextSearch.prototype.findDocument = function (results, pattern, isFirstMatch, findOption, hierachicalPosition) { if (this.isPatternEmpty(pattern)) { return; } if (findOption === undefined) { findOption = 'None'; } var inline = undefined; var selectionEnd = undefined; if (hierachicalPosition !== undefined) { selectionEnd = this.owner.selectionModule.end; } if (hierachicalPosition !== undefined && isFirstMatch && selectionEnd !== undefined && selectionEnd.paragraph !== undefined) { if (selectionEnd.paragraph instanceof ParagraphWidget) { var indexInInline = 0; // IndexInInline Handled specifically for simple find operation to start from starting point /* eslint-disable-next-line max-len */ var inlineElement = selectionEnd.currentWidget.getInline(this.owner.selectionModule.start.offset, indexInInline); inline = inlineElement.element; indexInInline = inlineElement.index; if (!isNullOrUndefined(inline)) { var nextParagraphWidget = undefined; nextParagraphWidget = this.findInline(inline, pattern, findOption, indexInInline, isFirstMatch, results, selectionEnd); while (results.length === 0 && !isNullOrUndefined(nextParagraphWidget)) { while (!isNullOrUndefined(nextParagraphWidget) && nextParagraphWidget.childWidgets.length === 0) { /* eslint-disable-next-line max-len */ nextParagraphWidget = this.owner.selectionModule.getNextParagraph(nextParagraphWidget.containerWidget); } if (isNullOrUndefined(nextParagraphWidget)) { break; } var lineWidget = nextParagraphWidget.childWidgets[0]; if (lineWidget.children[0] instanceof ListTextElementBox) { inline = (lineWidget.children[2] instanceof TextElementBox) ? lineWidget.children[2] : undefined; } else { inline = lineWidget.children[0]; } if (isNullOrUndefined(inline)) { break; } nextParagraphWidget = this.findInline(inline, pattern, findOption, 0, isFirstMatch, results, selectionEnd); } if (results.length > 0) { return; } } } } var section; section = this.documentHelper.pages[0].bodyWidgets[0]; while (!isNullOrUndefined(section) && section.childWidgets.length === 0) { section = section.nextWidget; } if (isNullOrUndefined(section) || section.childWidgets.length === 0) { return; } this.findInlineText(section, pattern, findOption, isFirstMatch, results, selectionEnd); var headerFootersColletion = this.documentHelper.headersFooters; for (var i = 0; i < headerFootersColletion.length; i++) { var headerFooters = headerFootersColletion[parseInt(i.toString(), 10)]; if (headerFooters) { for (var index in headerFooters) { if (Object.prototype.hasOwnProperty.call(headerFooters, index)) { var headerFooter = headerFooters[parseInt(index.toString(), 10)]; if (!isNullOrUndefined(headerFooter) && !isNullOrUndefined(headerFooter.page)) { this.findInlineText(headerFooter, pattern, findOption, isFirstMatch, results, selectionEnd); } } } } } // (EJ2-854069) - Added below code to add the search results of the endnote and footnote in the results. var endNoteCollection = this.documentHelper.endnoteCollection; for (var i = 0; i < endNoteCollection.length; i++) { var endNote = endNoteCollection[parseInt(i.toString(), 10)]; if (endNote) { if (!isNullOrUndefined(endNote) && !isNullOrUndefined(endNote.bodyWidget.page)) { this.findInlineText(endNote.bodyWidget, pattern, findOption, isFirstMatch, results, selectionEnd); } } } var footNoteCollection = this.documentHelper.footnoteCollection; for (var i = 0; i < footNoteCollection.length; i++) { var footNote = footNoteCollection[parseInt(i.toString(), 10)]; if (footNote) { if (!isNullOrUndefined(footNote) && !isNullOrUndefined(footNote.bodyWidget.page)) { this.findInlineText(footNote.bodyWidget, pattern, findOption, isFirstMatch, results, selectionEnd); } } } if (isFirstMatch && !isNullOrUndefined(results) && results.length > 0) { return; } }; /* eslint-disable-next-line max-len */ TextSearch.prototype.findInlineText = function (section, pattern, findOption, isFirstMatch, results, selectionEnd) { var paragraphWidget = this.owner.documentHelper.getFirstParagraphBlock(section.childWidgets[0]); /* eslint-disable-next-line max-len */ while (!isNullOrUndefined(paragraphWidget) && paragraphWidget.childWidgets.length === 1 && paragraphWidget.childWidgets[0].children.length === 0) { paragraphWidget = this.owner.selectionModule.getNextParagraphBlock(paragraphWidget); } while (!isNullOrUndefined(paragraphWidget) && paragraphWidget.childWidgets.length > 0) { var inlineElement = paragraphWidget.childWidgets[0]; var inlineEle = inlineElement.children[0]; if (isNullOrUndefined(inlineEle)) { break; } this.findInline(inlineEle, pattern, findOption, 0, isFirstMatch, results, selectionEnd); paragraphWidget = this.owner.selectionModule.getNextParagraphBlock(paragraphWidget); /* eslint-disable-next-line max-len */ while (!isNullOrUndefined(paragraphWidget) && (((paragraphWidget.childWidgets.length === 1) && paragraphWidget.childWidgets[0].children.length === 0) || !isNullOrUndefined(paragraphWidget.previousSplitWidget))) { paragraphWidget = this.owner.selectionModule.getNextParagraphBlock(paragraphWidget); } } if (isFirstMatch && !isNullOrUndefined(results) && results.length > 0) { return; } }; /* eslint-disable-next-line max-len */ TextSearch.prototype.findInline = function (inlineElement, pattern, option, indexInInline, isFirstMatch, results, selectionEnd) { var inlines = inlineElement; var textInfo = this.getElementInfo(inlineElement, indexInInline, undefined, pattern, option, isFirstMatch, results, selectionEnd); var text = textInfo.fullText; var matches = []; var spans = textInfo.elementsWithOffset; var matchObject; // eslint-disable-next-line no-cond-assign while (!isNullOrUndefined(matchObject = pattern.exec(text))) { matches.push(matchObject); } this.updateMatchedTextLocation(matches, results, spans, indexInInline, inlines, isFirstMatch, selectionEnd); if (isFirstMatch) { return undefined; } /* eslint-disable-next-line max-len */ var paragraphWidget = this.owner.selectionModule.getNextParagraphBlock(inlineElement.line.paragraph); return paragraphWidget; }; TextSearch.prototype.getTextPosition = function (lineWidget, hierarchicalIndex) { var textPosition = new TextPosition(this.owner); var index = textPosition.getHierarchicalIndex(lineWidget, hierarchicalIndex); textPosition.setPositionForCurrentIndex(index); return textPosition; }; return TextSearch; }()); export { TextSearch }; /** * @private */ var SearchWidgetInfo = /** @class */ (function () { function SearchWidgetInfo(left, width) { this.leftInternal = 0; this.widthInternal = 0; this.leftInternal = left; this.widthInternal = width; } Object.defineProperty(SearchWidgetInfo.prototype, "left", { get: function () { return this.leftInternal; }, set: function (value) { this.leftInternal = value; }, enumerable: true, configurable: true }); Object.defineProperty(SearchWidgetInfo.prototype, "width", { get: function () { return this.widthInternal; }, set: function (value) { this.widthInternal = value; }, enumerable: true, configurable: true }); return SearchWidgetInfo; }()); export { SearchWidgetInfo };