diff --git a/src/protyleHelper.ts b/src/protyleHelper.ts index a5ae0cc..742f7e5 100644 --- a/src/protyleHelper.ts +++ b/src/protyleHelper.ts @@ -41,6 +41,28 @@ export class ProtyleHelper { return document.querySelector(`div.underline-overlay[for-block-id="${blockID}"]`) } + public static getElementAtTextIndex(root: Element, index: number): Node { + let currentOffset = 0; + const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null); + + while (walker.nextNode()) { + let node = walker.currentNode + const textLength = node.textContent.length; + + if (currentOffset + textLength >= index) { + let parent: Element = node.parentElement; + while (parent && parent != root) { + node = parent + parent = node.parentElement + } + return node; // The element containing this text + } + currentOffset += textLength; + } + + return null; + } + // given an element such as a span inside a block, return its blockID public static getNodeId(el: Element) { let i = 0; diff --git a/src/spellCheckerUI.ts b/src/spellCheckerUI.ts index a662687..d932fd5 100644 --- a/src/spellCheckerUI.ts +++ b/src/spellCheckerUI.ts @@ -49,7 +49,7 @@ export class SpellCheckerUI { // Find the text nodes and character positions const range = this.createRangeFromCharacterIndices(startIndex, endIndex); if (range) { - this.createUnderlineFromRange(range, endIndex - startIndex); + this.createUnderlineFromRange(range); } } @@ -101,7 +101,7 @@ export class SpellCheckerUI { return null; } - private createUnderlineFromRange(range: Range, charsCount: number) { + private createUnderlineFromRange(range: Range) { const rects = range.getClientRects(); const editorRect = this.block.getBoundingClientRect(); @@ -120,19 +120,10 @@ export class SpellCheckerUI { underline.style.top = (top + 2 + offset.v) + 'px'; underline.style.width = width + 'px'; - if(!SpellCheckerUI.checkDontUnderline(width, charsCount)) { - this.overlay.appendChild(underline); - } + this.overlay.appendChild(underline); } } - // if the underline is too wide for the number of characters that are underlined, we don't render it - // this is a consequence of using .innerText: things like tags are only a character - private static checkDontUnderline(width: number, charsCount: number) { - const maxWidthPerChar = 16; - return width > maxWidthPerChar * charsCount - } - private static distance(elA: HTMLElement, elB: HTMLElement): {h: number, v: number} { const rectA = elA.getBoundingClientRect(); const rectB = elB.getBoundingClientRect(); diff --git a/src/suggestions.ts b/src/suggestions.ts index eb95692..d43340a 100644 --- a/src/suggestions.ts +++ b/src/suggestions.ts @@ -20,6 +20,12 @@ export class SuggestionEngine { private blockStorage: BlockStorage = {}; private plugin: SpellCheckPlugin; + private static blacklisted: string[] = [ + "span[data-type='inline-math']", + "span[data-type='img']", + "span[data-type='code']" + ]; + constructor(plugin: SpellCheckPlugin) { this.plugin = plugin } @@ -127,7 +133,8 @@ export class SuggestionEngine { thisBlock.spellChecker.clearUnderlines() thisBlock.suggestions?.forEach(suggestion => { - if(!Settings.isInCustomDictionary(this.suggestionToWrongText(suggestion, blockID), this.plugin.settingsUtil)) { + if(this.shouldSuggest(blockID, thisBlock, suggestion) && + !Settings.isInCustomDictionary(this.suggestionToWrongText(suggestion, blockID), this.plugin.settingsUtil)) { try { thisBlock.spellChecker.highlightCharacterRange(suggestion.offset, suggestion.offset + suggestion.length) }catch (_) { @@ -138,6 +145,20 @@ export class SuggestionEngine { } + private shouldSuggest(blockID: string, block: StoredBlock, suggestion: Suggestion): boolean { + + const element = block.protyle.fastGetBlockElement(blockID) + const eai = ProtyleHelper.getElementAtTextIndex(element, suggestion.offset + suggestion.length) + + for(let blacklisted of SuggestionEngine.blacklisted) { + if(eai instanceof Element && eai.matches(blacklisted)) { + return false + } + } + return true + + } + public suggestionToWrongText(suggestion: Suggestion, blockID: string): string { if(!(blockID in this.blockStorage)) { return