diff options
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/api.js | 37 | ||||
| -rw-r--r-- | ext/bg/js/backend.js | 1 | ||||
| -rw-r--r-- | ext/bg/js/search-query-parser.js | 97 | 
3 files changed, 127 insertions, 8 deletions
| diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index df73aa2a..064903ca 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -79,6 +79,43 @@ async function apiTermsFind(text, details, optionsContext) {      return {length, definitions};  } +async function apiTextParse(text, optionsContext) { +    const options = await apiOptionsGet(optionsContext); +    const translator = utilBackend().translator; + +    const results = []; +    while (text) { +        let [definitions, length] = await translator.findTerms(text, {}, options); +        if (definitions.length > 0) { +            definitions = dictTermsSort(definitions); +            const {expression, source, reading} = definitions[0]; + +            let stemLength = source.length; +            while (source[stemLength - 1] !== expression[stemLength - 1]) { +                --stemLength; +            } +            const offset = source.length - stemLength; + +            for (const result of jpDistributeFurigana( +                source.slice(0, offset === 0 ? source.length : source.length - offset), +                reading.slice(0, offset === 0 ? reading.length : source.length + (reading.length - expression.length) - offset) +            )) { +                results.push(result); +            } + +            if (stemLength !== source.length) { +                results.push({text: source.slice(stemLength)}); +            } + +            text = text.slice(source.length); +        } else { +            results.push({text: text[0]}); +            text = text.slice(1); +        } +    } +    return results; +} +  async function apiKanjiFind(text, optionsContext) {      const options = await apiOptionsGet(optionsContext);      const definitions = await utilBackend().translator.findKanji(text, options); diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index efad153a..d0e404f2 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -180,6 +180,7 @@ Backend.messageHandlers = {      optionsSet: ({changedOptions, optionsContext, source}) => apiOptionsSet(changedOptions, optionsContext, source),      kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext),      termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext), +    textParse: ({text, optionsContext}) => apiTextParse(text, optionsContext),      definitionAdd: ({definition, mode, context, optionsContext}) => apiDefinitionAdd(definition, mode, context, optionsContext),      definitionsAddable: ({definitions, modes, optionsContext}) => apiDefinitionsAddable(definitions, modes, optionsContext),      noteView: ({noteId}) => apiNoteView(noteId), diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index debe53b4..c3a3900b 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -23,22 +23,103 @@ class QueryParser {          this.queryParser = document.querySelector('#query-parser'); -        // TODO also enable for mouseover scanning -        this.queryParser.addEventListener('click', (e) => this.onTermLookup(e)); +        this.queryParser.addEventListener('click', (e) => this.onClick(e)); +        this.queryParser.addEventListener('mousemove', (e) => this.onMouseMove(e));      }      onError(error) {          logError(error, false);      } -    async onTermLookup(e) { -        const {textSource} = await this.search.onTermLookup(e, {isQueryParser: true}); -        if (textSource) { -            textSource.select(); +    onClick(e) { +        this.onTermLookup(e, {disableScroll: true, selectText: true}); +    } + +    async onMouseMove(e) { +        if ( +            (e.buttons & 0x1) !== 0x0 // Left mouse button +        ) { +            return; +        } + +        const scanningOptions = this.search.options.scanning; +        const scanningModifier = scanningOptions.modifier; +        if (!( +            QueryParser.isScanningModifierPressed(scanningModifier, e) || +            (scanningOptions.middleMouse && (e.buttons & 0x4) !== 0x0) // Middle mouse button +        )) { +            return;          } + +        await this.onTermLookup(e, {disableScroll: true, selectText: true, disableHistory: true}) +    } + +    onTermLookup(e, params) { +        this.search.onTermLookup(e, params);      } -    setText(text) { -        this.queryParser.innerText = text; +    async setText(text) { +        this.search.setSpinnerVisible(true); + +        const results = await apiTextParse(text, this.search.getOptionsContext()); + +        const tempContainer = document.createElement('div'); +        for (const {text, furigana} of results) { +            if (furigana) { +                const rubyElement = document.createElement('ruby'); +                const furiganaElement = document.createElement('rt'); +                furiganaElement.innerText = furigana; +                rubyElement.appendChild(document.createTextNode(text)); +                rubyElement.appendChild(furiganaElement); +                tempContainer.appendChild(rubyElement); +            } else { +                tempContainer.appendChild(document.createTextNode(text)); +            } +        } +        this.queryParser.innerHTML = ''; +        this.queryParser.appendChild(tempContainer); + +        this.search.setSpinnerVisible(false); +    } + +    async parseText(text) { +        const results = []; +        while (text) { +            const {definitions, length} =  await apiTermsFind(text, {}, this.search.getOptionsContext()); +            if (length) { +                results.push(definitions); +                text = text.slice(length); +            } else { +                results.push(text[0]); +                text = text.slice(1); +            } +        } +        return results; +    } + +    popupTimerSet(callback) { +        const delay = this.options.scanning.delay; +        if (delay > 0) { +            this.popupTimer = window.setTimeout(callback, delay); +        } else { +            Promise.resolve().then(callback); +        } +    } + +    popupTimerClear() { +        if (this.popupTimer !== null) { +            window.clearTimeout(this.popupTimer); +            this.popupTimer = null; +        } +    } + +    static isScanningModifierPressed(scanningModifier, mouseEvent) { +        switch (scanningModifier) { +            case 'alt': return mouseEvent.altKey; +            case 'ctrl': return mouseEvent.ctrlKey; +            case 'shift': return mouseEvent.shiftKey; +            case 'none': return true; +            default: return false; +        }      }  } |