aboutsummaryrefslogtreecommitdiff
path: root/ext/mixed/js/text-scanner.js
diff options
context:
space:
mode:
Diffstat (limited to 'ext/mixed/js/text-scanner.js')
-rw-r--r--ext/mixed/js/text-scanner.js246
1 files changed, 150 insertions, 96 deletions
diff --git a/ext/mixed/js/text-scanner.js b/ext/mixed/js/text-scanner.js
index 5a64c14a..2aeac565 100644
--- a/ext/mixed/js/text-scanner.js
+++ b/ext/mixed/js/text-scanner.js
@@ -21,13 +21,16 @@
*/
class TextScanner extends EventDispatcher {
- constructor({node, ignoreElements, ignorePoint, search, documentUtil}) {
+ constructor({node, ignoreElements, ignorePoint, documentUtil, getOptionsContext, searchTerms=false, searchKanji=false, searchOnClick=false}) {
super();
this._node = node;
this._ignoreElements = ignoreElements;
this._ignorePoint = ignorePoint;
- this._search = search;
this._documentUtil = documentUtil;
+ this._getOptionsContext = getOptionsContext;
+ this._searchTerms = searchTerms;
+ this._searchKanji = searchKanji;
+ this._searchOnClick = searchOnClick;
this._isPrepared = false;
this._ignoreNodes = null;
@@ -125,41 +128,6 @@ class TextScanner extends EventDispatcher {
}
}
- async searchAt(x, y, cause) {
- try {
- this._scanTimerClear();
-
- if (this._pendingLookup) {
- return;
- }
-
- if (typeof this._ignorePoint === 'function' && await this._ignorePoint(x, y)) {
- return;
- }
-
- const textSource = this._documentUtil.getRangeFromPoint(x, y, this._deepContentScan);
- try {
- if (this._textSourceCurrent !== null && this._textSourceCurrent.equals(textSource)) {
- return;
- }
-
- this._pendingLookup = true;
- const result = await this._search(textSource, cause);
- if (result !== null) {
- this._causeCurrent = cause;
- this.setCurrentTextSource(textSource);
- }
- this._pendingLookup = false;
- } finally {
- if (textSource !== null) {
- textSource.cleanup();
- }
- }
- } catch (e) {
- yomichan.logError(e);
- }
- }
-
getTextSourceContent(textSource, length, layoutAwareScan) {
const clonedTextSource = textSource.clone();
@@ -206,35 +174,44 @@ class TextScanner extends EventDispatcher {
}
}
- async findTerms(textSource, optionsContext) {
- const scanLength = this._scanLength;
- const sentenceExtent = this._sentenceExtent;
- const layoutAwareScan = this._layoutAwareScan;
- const searchText = this.getTextSourceContent(textSource, scanLength, layoutAwareScan);
- if (searchText.length === 0) { return null; }
-
- const {definitions, length} = await api.termsFind(searchText, {}, optionsContext);
- if (definitions.length === 0) { return null; }
-
- textSource.setEndOffset(length, layoutAwareScan);
- const sentence = this._documentUtil.extractSentence(textSource, sentenceExtent, layoutAwareScan);
+ async search(textSource, cause) {
+ let definitions = null;
+ let sentence = null;
+ let type = null;
+ let error = null;
+ let searched = false;
+ let optionsContext = null;
- return {definitions, sentence, type: 'terms'};
- }
+ try {
+ if (this._textSourceCurrent !== null && this._textSourceCurrent.equals(textSource)) {
+ return;
+ }
- async findKanji(textSource, optionsContext) {
- const sentenceExtent = this._sentenceExtent;
- const layoutAwareScan = this._layoutAwareScan;
- const searchText = this.getTextSourceContent(textSource, 1, layoutAwareScan);
- if (searchText.length === 0) { return null; }
+ optionsContext = await this._getOptionsContext();
+ searched = true;
- const definitions = await api.kanjiFind(searchText, optionsContext);
- if (definitions.length === 0) { return null; }
+ const result = await this._findDefinitions(textSource, cause);
+ if (result !== null) {
+ ({definitions, sentence, type} = result);
+ this._causeCurrent = cause;
+ this.setCurrentTextSource(textSource);
+ }
+ } catch (e) {
+ error = e;
+ }
- textSource.setEndOffset(1, layoutAwareScan);
- const sentence = this._documentUtil.extractSentence(textSource, sentenceExtent, layoutAwareScan);
+ if (!searched) { return; }
- return {definitions, sentence, type: 'kanji'};
+ this.trigger('searched', {
+ textScanner: this,
+ type,
+ definitions,
+ sentence,
+ cause,
+ textSource,
+ optionsContext,
+ error
+ });
}
// Private
@@ -248,7 +225,7 @@ class TextScanner extends EventDispatcher {
_onMouseMove(e) {
this._scanTimerClear();
- if (this._pendingLookup || DocumentUtil.isMouseButtonDown(e, 'primary')) {
+ if (DocumentUtil.isMouseButtonDown(e, 'primary')) {
return;
}
@@ -262,18 +239,7 @@ class TextScanner extends EventDispatcher {
return;
}
- const search = async () => {
- if (this._modifier === 'none') {
- if (!await this._scanTimerWait()) {
- // Aborted
- return;
- }
- }
-
- await this.searchAt(e.clientX, e.clientY, 'mouse');
- };
-
- search();
+ this._searchAtFromMouse(e.clientX, e.clientY);
}
_onMouseDown(e) {
@@ -296,6 +262,10 @@ class TextScanner extends EventDispatcher {
}
_onClick(e) {
+ if (this._searchOnClick) {
+ this._searchAt(e.clientX, e.clientY, 'click');
+ }
+
if (this._preventNextClick) {
this._preventNextClick = false;
e.preventDefault();
@@ -334,25 +304,7 @@ class TextScanner extends EventDispatcher {
this._primaryTouchIdentifier = primaryTouch.identifier;
- if (this._pendingLookup) {
- return;
- }
-
- const textSourceCurrentPrevious = this._textSourceCurrent !== null ? this._textSourceCurrent.clone() : null;
-
- this.searchAt(primaryTouch.clientX, primaryTouch.clientY, 'touchStart')
- .then(() => {
- if (
- this._textSourceCurrent === null ||
- this._textSourceCurrent.equals(textSourceCurrentPrevious)
- ) {
- return;
- }
-
- this._preventScroll = true;
- this._preventNextContextMenu = true;
- this._preventNextMouseDown = true;
- });
+ this._searchAtFromTouchStart(primaryTouch.clientX, primaryTouch.clientY);
}
_onTouchEnd(e) {
@@ -384,7 +336,7 @@ class TextScanner extends EventDispatcher {
return;
}
- this.searchAt(primaryTouch.clientX, primaryTouch.clientY, 'touchMove');
+ this._searchAt(primaryTouch.clientX, primaryTouch.clientY, 'touchMove');
e.preventDefault(); // Disable scroll
}
@@ -425,13 +377,13 @@ class TextScanner extends EventDispatcher {
[this._node, 'mousedown', this._onMouseDown.bind(this)],
[this._node, 'mousemove', this._onMouseMove.bind(this)],
[this._node, 'mouseover', this._onMouseOver.bind(this)],
- [this._node, 'mouseout', this._onMouseOut.bind(this)]
+ [this._node, 'mouseout', this._onMouseOut.bind(this)],
+ [this._node, 'click', this._onClick.bind(this)]
];
}
_getTouchEventListeners() {
return [
- [this._node, 'click', this._onClick.bind(this)],
[this._node, 'auxclick', this._onAuxClick.bind(this)],
[this._node, 'touchstart', this._onTouchStart.bind(this)],
[this._node, 'touchend', this._onTouchEnd.bind(this)],
@@ -460,4 +412,106 @@ class TextScanner extends EventDispatcher {
}
return null;
}
+
+ async _findDefinitions(textSource, optionsContext) {
+ if (textSource === null) {
+ return null;
+ }
+ if (this._searchTerms) {
+ const results = await this._findTerms(textSource, optionsContext);
+ if (results !== null) { return results; }
+ }
+ if (this._searchKanji) {
+ const results = await this._findKanji(textSource, optionsContext);
+ if (results !== null) { return results; }
+ }
+ return null;
+ }
+
+ async _findTerms(textSource, optionsContext) {
+ const scanLength = this._scanLength;
+ const sentenceExtent = this._sentenceExtent;
+ const layoutAwareScan = this._layoutAwareScan;
+ const searchText = this.getTextSourceContent(textSource, scanLength, layoutAwareScan);
+ if (searchText.length === 0) { return null; }
+
+ const {definitions, length} = await api.termsFind(searchText, {}, optionsContext);
+ if (definitions.length === 0) { return null; }
+
+ textSource.setEndOffset(length, layoutAwareScan);
+ const sentence = this._documentUtil.extractSentence(textSource, sentenceExtent, layoutAwareScan);
+
+ return {definitions, sentence, type: 'terms'};
+ }
+
+ async _findKanji(textSource, optionsContext) {
+ const sentenceExtent = this._sentenceExtent;
+ const layoutAwareScan = this._layoutAwareScan;
+ const searchText = this.getTextSourceContent(textSource, 1, layoutAwareScan);
+ if (searchText.length === 0) { return null; }
+
+ const definitions = await api.kanjiFind(searchText, optionsContext);
+ if (definitions.length === 0) { return null; }
+
+ textSource.setEndOffset(1, layoutAwareScan);
+ const sentence = this._documentUtil.extractSentence(textSource, sentenceExtent, layoutAwareScan);
+
+ return {definitions, sentence, type: 'kanji'};
+ }
+
+ async _searchAt(x, y, cause) {
+ if (this._pendingLookup) { return; }
+
+ try {
+ this._pendingLookup = true;
+ this._scanTimerClear();
+
+ if (typeof this._ignorePoint === 'function' && await this._ignorePoint(x, y)) {
+ return;
+ }
+
+ const textSource = this._documentUtil.getRangeFromPoint(x, y, this._deepContentScan);
+ try {
+ await this.search(textSource, cause);
+ } finally {
+ if (textSource !== null) {
+ textSource.cleanup();
+ }
+ }
+ } catch (e) {
+ yomichan.logError(e);
+ } finally {
+ this._pendingLookup = false;
+ }
+ }
+
+ async _searchAtFromMouse(x, y) {
+ if (this._pendingLookup) { return; }
+
+ if (this._modifier === 'none') {
+ if (!await this._scanTimerWait()) {
+ // Aborted
+ return;
+ }
+ }
+
+ await this._searchAt(x, y, 'mouse');
+ }
+
+ async _searchAtFromTouchStart(x, y) {
+ if (this._pendingLookup) { return; }
+
+ const textSourceCurrentPrevious = this._textSourceCurrent !== null ? this._textSourceCurrent.clone() : null;
+
+ await this._searchAt(x, y, 'touchStart');
+
+ if (
+ this._textSourceCurrent !== null &&
+ !this._textSourceCurrent.equals(textSourceCurrentPrevious)
+ ) {
+ this._preventScroll = true;
+ this._preventNextContextMenu = true;
+ this._preventNextMouseDown = true;
+ }
+ }
}