From 75883ed885961e2252f972e4ce7e9a26ede5cabe Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 3 Nov 2019 16:18:43 -0500 Subject: Remove dexie --- ext/bg/background.html | 1 - 1 file changed, 1 deletion(-) (limited to 'ext/bg/background.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 3ab68639..bbfbd1e1 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -14,7 +14,6 @@
- -- cgit v1.2.3 From 41020289ab68ef22a0691a9f268a79d6a706df6b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 3 Nov 2019 05:08:57 +0200 Subject: add mecab support --- ext/bg/background.html | 1 + ext/bg/js/api.js | 48 ++++++++++++++++++------------ ext/bg/js/backend.js | 2 ++ ext/bg/js/mecab.js | 63 ++++++++++++++++++++++++++++++++++++++++ ext/bg/js/search-query-parser.js | 3 +- ext/fg/js/api.js | 4 +++ ext/manifest.json | 3 +- ext/mixed/js/japanese.js | 35 ++++++++++++++++++++-- 8 files changed, 136 insertions(+), 23 deletions(-) create mode 100644 ext/bg/js/mecab.js (limited to 'ext/bg/background.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index bbfbd1e1..6e6e7c26 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -21,6 +21,7 @@ + diff --git a/ext/bg/js/api.js b/ext/bg/js/api.js index 7c9a72a7..2ab01af3 100644 --- a/ext/bg/js/api.js +++ b/ext/bg/js/api.js @@ -91,25 +91,10 @@ async function apiTextParse(text, optionsContext) { definitions = dictTermsSort(definitions); const {expression, reading} = definitions[0]; const source = text.slice(0, sourceLength); - - let stemLength = 0; - const shortest = Math.min(source.length, expression.length); - while (stemLength < shortest && source[stemLength] === expression[stemLength]) { - ++stemLength; - } - const offset = source.length - stemLength; - - for (const {text, furigana} of jpDistributeFurigana( - source.slice(0, offset === 0 ? source.length : source.length - offset), - reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) - )) { - term.push({text, reading: furigana || ''}); - } - - if (stemLength !== source.length) { - term.push({text: source.slice(stemLength)}); + for (const {text, furigana} of jpDistributeFuriganaInflected(expression, reading, source)) { + // can't use 'furigana' in templates + term.push({text, reading: furigana}); } - text = text.slice(source.length); } else { term.push({text: text[0]}); @@ -120,6 +105,33 @@ async function apiTextParse(text, optionsContext) { return results; } +async function apiTextParseMecab(text, optionsContext) { + const options = await apiOptionsGet(optionsContext); + const mecab = utilBackend().mecab; + + const results = []; + for (const parsedLine of await mecab.parseText(text)) { + for (const {expression, reading, source} of parsedLine) { + const term = []; + if (expression && reading) { + for (const {text, furigana} of jpDistributeFuriganaInflected( + expression, + jpKatakanaToHiragana(reading), + source + )) { + // can't use 'furigana' in templates + term.push({text, reading: furigana}); + } + } else { + term.push({text: source}); + } + results.push(term); + } + results.push([{text: '\n'}]); + } + 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 d0e404f2..e97f32b5 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -21,6 +21,7 @@ class Backend { constructor() { this.translator = new Translator(); this.anki = new AnkiNull(); + this.mecab = new Mecab(); this.options = null; this.optionsContext = { depth: 0, @@ -181,6 +182,7 @@ Backend.messageHandlers = { kanjiFind: ({text, optionsContext}) => apiKanjiFind(text, optionsContext), termsFind: ({text, details, optionsContext}) => apiTermsFind(text, details, optionsContext), textParse: ({text, optionsContext}) => apiTextParse(text, optionsContext), + textParseMecab: ({text, optionsContext}) => apiTextParseMecab(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/mecab.js b/ext/bg/js/mecab.js new file mode 100644 index 00000000..dc46ded2 --- /dev/null +++ b/ext/bg/js/mecab.js @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +class Mecab { + constructor() { + this.listeners = {}; + this.sequence = 0; + this.startListener(); + } + + async parseText(text) { + return await this.invoke('parse_text', {text}); + } + + startListener() { + this.port = chrome.runtime.connectNative('mecab'); + this.port.onMessage.addListener((message) => { + const {sequence, data} = message; + const {callback, timer} = this.listeners[sequence] || {}; + if (timer) { + clearTimeout(timer); + delete this.listeners[sequence]; + callback(data); + } + }); + } + + invoke(action, params) { + return new Promise((resolve, reject) => { + const sequence = this.sequence++; + + this.listeners[sequence] = { + callback: (data) => { + resolve(data); + }, + timer: setTimeout(() => { + delete this.listeners[sequence]; + reject(`Mecab invoke timed out in ${Mecab.timeout} ms`); + }, 1000) + } + + this.port.postMessage({action, params, sequence}); + }); + } +} + +Mecab.timeout = 1000; diff --git a/ext/bg/js/search-query-parser.js b/ext/bg/js/search-query-parser.js index 8a7db69a..0c74e550 100644 --- a/ext/bg/js/search-query-parser.js +++ b/ext/bg/js/search-query-parser.js @@ -74,7 +74,8 @@ class QueryParser { preview: true }); - const results = await apiTextParse(text, this.search.getOptionsContext()); + // const results = await apiTextParse(text, this.search.getOptionsContext()); + const results = await apiTextParseMecab(text, this.search.getOptionsContext()); const content = await apiTemplateRender('query-parser.html', { terms: results.map((term) => { diff --git a/ext/fg/js/api.js b/ext/fg/js/api.js index cc1e0e90..92330d9c 100644 --- a/ext/fg/js/api.js +++ b/ext/fg/js/api.js @@ -33,6 +33,10 @@ function apiTextParse(text, optionsContext) { return utilInvoke('textParse', {text, optionsContext}); } +function apiTextParseMecab(text, optionsContext) { + return utilInvoke('textParseMecab', {text, optionsContext}); +} + function apiKanjiFind(text, optionsContext) { return utilInvoke('kanjiFind', {text, optionsContext}); } diff --git a/ext/manifest.json b/ext/manifest.json index fabceafd..4d75cd54 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -42,7 +42,8 @@ "", "storage", "clipboardWrite", - "unlimitedStorage" + "unlimitedStorage", + "nativeMessaging" ], "optional_permissions": [ "clipboardRead" diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js index d24f56a6..78c419b2 100644 --- a/ext/mixed/js/japanese.js +++ b/ext/mixed/js/japanese.js @@ -61,12 +61,11 @@ function jpDistributeFurigana(expression, reading) { const group = groups[0]; if (group.mode === 'kana') { - if (reading.startsWith(group.text)) { - const readingUsed = reading.substring(0, group.text.length); + if (jpKatakanaToHiragana(reading).startsWith(jpKatakanaToHiragana(group.text))) { const readingLeft = reading.substring(group.text.length); const segs = segmentize(readingLeft, groups.splice(1)); if (segs) { - return [{text: readingUsed}].concat(segs); + return [{text: group.text}].concat(segs); } } } else { @@ -95,3 +94,33 @@ function jpDistributeFurigana(expression, reading) { return segmentize(reading, groups) || fallback; } + +function jpDistributeFuriganaInflected(expression, reading, source) { + const output = []; + + let stemLength = 0; + const shortest = Math.min(source.length, expression.length); + const sourceHiragana = jpKatakanaToHiragana(source); + const expressionHiragana = jpKatakanaToHiragana(expression); + while ( + stemLength < shortest && + // sometimes an expression can use a kanji that's different from the source + (!jpIsKana(source[stemLength]) || (sourceHiragana[stemLength] === expressionHiragana[stemLength])) + ) { + ++stemLength; + } + const offset = source.length - stemLength; + + for (const segment of jpDistributeFurigana( + source.slice(0, offset === 0 ? source.length : source.length - offset), + reading.slice(0, offset === 0 ? reading.length : reading.length - expression.length + stemLength) + )) { + output.push(segment); + } + + if (stemLength !== source.length) { + output.push({text: source.slice(stemLength)}); + } + + return output; +} -- cgit v1.2.3 From 7e94fca7c7a07f94de40ddeb56a3f06e43000e25 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 17:29:52 -0500 Subject: Rename extension.js to core.js to better reflect its use --- ext/bg/background.html | 2 +- ext/bg/context.html | 2 +- ext/bg/search.html | 2 +- ext/bg/settings-popup-preview.html | 2 +- ext/bg/settings.html | 2 +- ext/fg/float.html | 2 +- ext/manifest.json | 2 +- ext/mixed/js/core.js | 150 +++++++++++++++++++++++++++++++++++++ ext/mixed/js/extension.js | 150 ------------------------------------- 9 files changed, 157 insertions(+), 157 deletions(-) create mode 100644 ext/mixed/js/core.js delete mode 100644 ext/mixed/js/extension.js (limited to 'ext/bg/background.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 6e6e7c26..3b337e18 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -18,7 +18,7 @@ - + diff --git a/ext/bg/context.html b/ext/bg/context.html index bd62270b..52ca255d 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -178,7 +178,7 @@ - + diff --git a/ext/bg/search.html b/ext/bg/search.html index e819ebe6..16074022 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -60,7 +60,7 @@ - + diff --git a/ext/bg/settings-popup-preview.html b/ext/bg/settings-popup-preview.html index d27a9a33..574b6707 100644 --- a/ext/bg/settings-popup-preview.html +++ b/ext/bg/settings-popup-preview.html @@ -117,7 +117,7 @@ - + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 262386e9..b2af3759 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -864,7 +864,7 @@ - + diff --git a/ext/fg/float.html b/ext/fg/float.html index 73118917..e04c1402 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -31,7 +31,7 @@ - + diff --git a/ext/manifest.json b/ext/manifest.json index 43a887cd..69ee0c4f 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -18,7 +18,7 @@ "content_scripts": [{ "matches": ["http://*/*", "https://*/*", "file://*/*"], "js": [ - "mixed/js/extension.js", + "mixed/js/core.js", "fg/js/api.js", "fg/js/document.js", "fg/js/frontend-api-receiver.js", diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js new file mode 100644 index 00000000..12ed9c1f --- /dev/null +++ b/ext/mixed/js/core.js @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +// toIterable is required on Edge for cross-window origin objects. +function toIterable(value) { + if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { + return value; + } + + if (value !== null && typeof value === 'object') { + const length = value.length; + if (typeof length === 'number' && Number.isFinite(length)) { + const array = []; + for (let i = 0; i < length; ++i) { + array.push(value[i]); + } + return array; + } + } + + throw new Error('Could not convert to iterable'); +} + +function extensionHasChrome() { + try { + return typeof chrome === 'object' && chrome !== null; + } catch (e) { + return false; + } +} + +function extensionHasBrowser() { + try { + return typeof browser === 'object' && browser !== null; + } catch (e) { + return false; + } +} + +function errorToJson(error) { + return { + name: error.name, + message: error.message, + stack: error.stack + }; +} + +function jsonToError(jsonError) { + const error = new Error(jsonError.message); + error.name = jsonError.name; + error.stack = jsonError.stack; + return error; +} + +function logError(error, alert) { + const manifest = chrome.runtime.getManifest(); + let errorMessage = `${manifest.name} v${manifest.version} has encountered an error.\n`; + errorMessage += `Originating URL: ${window.location.href}\n`; + + const errorString = `${error.toString ? error.toString() : error}`; + const stack = `${error.stack}`.trimRight(); + errorMessage += (!stack.startsWith(errorString) ? `${errorString}\n${stack}` : `${stack}`); + + errorMessage += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; + + console.error(errorMessage); + + if (alert) { + window.alert(`${errorString}\n\nCheck the developer console for more details.`); + } +} + +const EXTENSION_IS_BROWSER_EDGE = ( + extensionHasBrowser() && + (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) +); + +if (EXTENSION_IS_BROWSER_EDGE) { + // Edge does not have chrome defined. + chrome = browser; +} + +function promiseTimeout(delay, resolveValue) { + if (delay <= 0) { + return Promise.resolve(resolveValue); + } + + let timer = null; + let promiseResolve = null; + let promiseReject = null; + + const complete = (callback, value) => { + if (callback === null) { return; } + if (timer !== null) { + window.clearTimeout(timer); + timer = null; + } + promiseResolve = null; + promiseReject = null; + callback(value); + }; + + const resolve = (value) => complete(promiseResolve, value); + const reject = (value) => complete(promiseReject, value); + + const promise = new Promise((resolve, reject) => { + promiseResolve = resolve; + promiseReject = reject; + }); + timer = window.setTimeout(() => { + timer = null; + resolve(resolveValue); + }, delay); + + promise.resolve = resolve; + promise.reject = reject; + + return promise; +} + +function stringReplaceAsync(str, regex, replacer) { + let match; + let index = 0; + const parts = []; + while ((match = regex.exec(str)) !== null) { + parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); + index = regex.lastIndex; + } + if (parts.length === 0) { + return Promise.resolve(str); + } + parts.push(str.substring(index)); + return Promise.all(parts).then(v => v.join('')); +} diff --git a/ext/mixed/js/extension.js b/ext/mixed/js/extension.js deleted file mode 100644 index 12ed9c1f..00000000 --- a/ext/mixed/js/extension.js +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2019 Alex Yatskov - * Author: Alex Yatskov - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -// toIterable is required on Edge for cross-window origin objects. -function toIterable(value) { - if (typeof Symbol !== 'undefined' && typeof value[Symbol.iterator] !== 'undefined') { - return value; - } - - if (value !== null && typeof value === 'object') { - const length = value.length; - if (typeof length === 'number' && Number.isFinite(length)) { - const array = []; - for (let i = 0; i < length; ++i) { - array.push(value[i]); - } - return array; - } - } - - throw new Error('Could not convert to iterable'); -} - -function extensionHasChrome() { - try { - return typeof chrome === 'object' && chrome !== null; - } catch (e) { - return false; - } -} - -function extensionHasBrowser() { - try { - return typeof browser === 'object' && browser !== null; - } catch (e) { - return false; - } -} - -function errorToJson(error) { - return { - name: error.name, - message: error.message, - stack: error.stack - }; -} - -function jsonToError(jsonError) { - const error = new Error(jsonError.message); - error.name = jsonError.name; - error.stack = jsonError.stack; - return error; -} - -function logError(error, alert) { - const manifest = chrome.runtime.getManifest(); - let errorMessage = `${manifest.name} v${manifest.version} has encountered an error.\n`; - errorMessage += `Originating URL: ${window.location.href}\n`; - - const errorString = `${error.toString ? error.toString() : error}`; - const stack = `${error.stack}`.trimRight(); - errorMessage += (!stack.startsWith(errorString) ? `${errorString}\n${stack}` : `${stack}`); - - errorMessage += '\n\nIssues can be reported at https://github.com/FooSoft/yomichan/issues'; - - console.error(errorMessage); - - if (alert) { - window.alert(`${errorString}\n\nCheck the developer console for more details.`); - } -} - -const EXTENSION_IS_BROWSER_EDGE = ( - extensionHasBrowser() && - (!extensionHasChrome() || (typeof chrome.runtime === 'undefined' && typeof browser.runtime !== 'undefined')) -); - -if (EXTENSION_IS_BROWSER_EDGE) { - // Edge does not have chrome defined. - chrome = browser; -} - -function promiseTimeout(delay, resolveValue) { - if (delay <= 0) { - return Promise.resolve(resolveValue); - } - - let timer = null; - let promiseResolve = null; - let promiseReject = null; - - const complete = (callback, value) => { - if (callback === null) { return; } - if (timer !== null) { - window.clearTimeout(timer); - timer = null; - } - promiseResolve = null; - promiseReject = null; - callback(value); - }; - - const resolve = (value) => complete(promiseResolve, value); - const reject = (value) => complete(promiseReject, value); - - const promise = new Promise((resolve, reject) => { - promiseResolve = resolve; - promiseReject = reject; - }); - timer = window.setTimeout(() => { - timer = null; - resolve(resolveValue); - }, delay); - - promise.resolve = resolve; - promise.reject = reject; - - return promise; -} - -function stringReplaceAsync(str, regex, replacer) { - let match; - let index = 0; - const parts = []; - while ((match = regex.exec(str)) !== null) { - parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); - index = regex.lastIndex; - } - if (parts.length === 0) { - return Promise.resolve(str); - } - parts.push(str.substring(index)); - return Promise.all(parts).then(v => v.join('')); -} -- cgit v1.2.3 From 96aad50340b4d0374979ac981cd1c481cc8dcd94 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Tue, 26 Nov 2019 18:47:16 -0500 Subject: Create DOM utility file --- ext/bg/background.html | 1 + ext/bg/context.html | 1 + ext/bg/search.html | 1 + ext/bg/settings-popup-preview.html | 2 ++ ext/bg/settings.html | 1 + ext/fg/float.html | 1 + ext/fg/js/document.js | 19 ++-------------- ext/fg/js/frontend.js | 14 +----------- ext/manifest.json | 1 + ext/mixed/js/dom.js | 46 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 57 insertions(+), 30 deletions(-) create mode 100644 ext/mixed/js/dom.js (limited to 'ext/bg/background.html') diff --git a/ext/bg/background.html b/ext/bg/background.html index 3b337e18..5a6970c3 100644 --- a/ext/bg/background.html +++ b/ext/bg/background.html @@ -19,6 +19,7 @@ + diff --git a/ext/bg/context.html b/ext/bg/context.html index 52ca255d..eda09a68 100644 --- a/ext/bg/context.html +++ b/ext/bg/context.html @@ -179,6 +179,7 @@ + diff --git a/ext/bg/search.html b/ext/bg/search.html index 16074022..ef24af89 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -61,6 +61,7 @@ + diff --git a/ext/bg/settings-popup-preview.html b/ext/bg/settings-popup-preview.html index 574b6707..9ca59e44 100644 --- a/ext/bg/settings-popup-preview.html +++ b/ext/bg/settings-popup-preview.html @@ -118,6 +118,8 @@ + + diff --git a/ext/bg/settings.html b/ext/bg/settings.html index b2af3759..908c618c 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -865,6 +865,7 @@ + diff --git a/ext/fg/float.html b/ext/fg/float.html index e04c1402..38439c79 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -32,6 +32,7 @@ + diff --git a/ext/fg/js/document.js b/ext/fg/js/document.js index 8161c85a..3dd12a40 100644 --- a/ext/fg/js/document.js +++ b/ext/fg/js/document.js @@ -223,7 +223,7 @@ function isPointInRange(x, y, range) { const {node, offset, content} = TextSourceRange.seekForward(range.endContainer, range.endOffset, 1); range.setEnd(node, offset); - if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) { + if (!isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) { return true; } } finally { @@ -234,7 +234,7 @@ function isPointInRange(x, y, range) { const {node, offset, content} = TextSourceRange.seekBackward(range.startContainer, range.startOffset, 1); range.setStart(node, offset); - if (!isWhitespace(content) && isPointInAnyRect(x, y, range.getClientRects())) { + if (!isWhitespace(content) && DOM.isPointInAnyRect(x, y, range.getClientRects())) { // This purposefully leaves the starting offset as modified and sets the range length to 0. range.setEnd(node, offset); return true; @@ -248,21 +248,6 @@ function isWhitespace(string) { return string.trim().length === 0; } -function isPointInAnyRect(x, y, rects) { - for (const rect of rects) { - if (isPointInRect(x, y, rect)) { - return true; - } - } - return false; -} - -function isPointInRect(x, y, rect) { - return ( - x >= rect.left && x < rect.right && - y >= rect.top && y < rect.bottom); -} - const caretRangeFromPoint = (() => { if (typeof document.caretRangeFromPoint === 'function') { // Chrome, Edge diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 6002dfcb..81c159db 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -159,7 +159,7 @@ class Frontend { this.preventNextClick = false; const primaryTouch = e.changedTouches[0]; - if (Frontend.selectionContainsPoint(window.getSelection(), primaryTouch.clientX, primaryTouch.clientY)) { + if (DOM.isPointInSelection(primaryTouch.clientX, primaryTouch.clientY, window.getSelection())) { return; } @@ -456,18 +456,6 @@ class Frontend { return -1; } - static selectionContainsPoint(selection, x, y) { - for (let i = 0; i < selection.rangeCount; ++i) { - const range = selection.getRangeAt(i); - for (const rect of range.getClientRects()) { - if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { - return true; - } - } - } - return false; - } - setTextSourceScanLength(textSource, length) { textSource.setEndOffset(length); if (this.ignoreNodes === null || !textSource.range) { diff --git a/ext/manifest.json b/ext/manifest.json index 69ee0c4f..dc670633 100644 --- a/ext/manifest.json +++ b/ext/manifest.json @@ -19,6 +19,7 @@ "matches": ["http://*/*", "https://*/*", "file://*/*"], "js": [ "mixed/js/core.js", + "mixed/js/dom.js", "fg/js/api.js", "fg/js/document.js", "fg/js/frontend-api-receiver.js", diff --git a/ext/mixed/js/dom.js b/ext/mixed/js/dom.js new file mode 100644 index 00000000..4525dace --- /dev/null +++ b/ext/mixed/js/dom.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 Alex Yatskov + * Author: Alex Yatskov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +class DOM { + static isPointInRect(x, y, rect) { + return ( + x >= rect.left && x < rect.right && + y >= rect.top && y < rect.bottom + ); + } + + static isPointInAnyRect(x, y, rects) { + for (const rect of rects) { + if (DOM.isPointInRect(x, y, rect)) { + return true; + } + } + return false; + } + + static isPointInSelection(x, y, selection) { + for (let i = 0; i < selection.rangeCount; ++i) { + const range = selection.getRangeAt(i); + if (DOM.isPointInAnyRect(x, y, range.getClientRects())) { + return true; + } + } + return false; + } +} -- cgit v1.2.3