UNPKG

@atlaskit/renderer

Version:
64 lines (60 loc) 2.89 kB
// getIndexMatch finds the position of a given string within a given document, in accordance to the Confluence Annotation backend // The document is serialised into one large string, excluding any nodes that can not have annotations (eg: emojis, media). // Finds where the given query string is relative to the serialised partial document export function getIndexMatch(doc, schema, selectedText, startIndex) { var textContent = ''; var matchIndex = 0; var numMatches = 0; var blockNodePos; doc.descendants(function (node, pos) { var nodeType = node.type; var media = schema.nodes.media; // Mirrors Confluence backend and doesn't construct textContent if it doesn't allow annotations // Don't skip media node so that block node can be defined its startIndex in within [nodeStart, nodeEnd] if ((node.isText || !nodeType.allowsMarkType(schema.marks.annotation)) && nodeType !== media) { // Note: `return true` as a parent disallowing annotations does not mean a child disallows annotations. // Eg: panel (invalid) > p (valid) return true; } var nodeStart = pos; var nodeEnd = nodeStart + node.nodeSize; if (startIndex >= nodeStart && startIndex <= nodeEnd) { // if it's a node block, set position to pos to indicate to the backend // that it's an annotation on a block node if (nodeType === media) { blockNodePos = pos; } // If the start of the annotation selection is within the current node, we scan the document for previous occurrences // Find the index by counting all previous instances of the selectedText in the partial textContent // Need to scan from start, up to `startIndex` (which includes partial of the current node) textContent += doc.textBetween(nodeStart, startIndex - 1); matchIndex = countMatches(textContent, selectedText); // Complete appending of the node textContent += doc.textBetween(startIndex, nodeEnd); } else { textContent += node.textContent; } return true; }); // Count total number of matches in final text numMatches = countMatches(textContent, selectedText); return { numMatches: numMatches, matchIndex: matchIndex, textContent: textContent, blockNodePos: blockNodePos }; } // countMatches finds the total number of occurrences of `query` within a given `searchString` export function countMatches(searchString, query) { if (searchString === '' || query === '') { return 0; } // Escape characters that would trigger as syntax in a regex query before converting to the query // Ignored via go/ees005 // eslint-disable-next-line require-unicode-regexp // Ignored via go/ees005 // eslint-disable-next-line require-unicode-regexp var reg = new RegExp(query.replace(/(?=[.\\+*?[^\]$(){}\|])/g, '\\'), 'g'); return (searchString.match(reg) || []).length; }