summaryrefslogtreecommitdiff
path: root/ext/fg/js
diff options
context:
space:
mode:
authorAlex Yatskov <alex@foosoft.net>2016-10-08 17:39:21 -0700
committerAlex Yatskov <alex@foosoft.net>2016-10-08 17:39:21 -0700
commit1e9906c624828819f74628bac4ee42cca3cbe3b6 (patch)
tree8d752b94329dc2539db935cb9d8cbbffc6530009 /ext/fg/js
parent1d573f4179503ea9e1cc15327f67e8b52740adad (diff)
Automatically look up Kanji when cannot find definitions.
Allow text scanning without holding Shift key (resolves #18).
Diffstat (limited to 'ext/fg/js')
-rw-r--r--ext/fg/js/driver.js85
-rw-r--r--ext/fg/js/popup.js44
2 files changed, 86 insertions, 43 deletions
diff --git a/ext/fg/js/driver.js b/ext/fg/js/driver.js
index d0907e7d..1e817c1c 100644
--- a/ext/fg/js/driver.js
+++ b/ext/fg/js/driver.js
@@ -20,6 +20,7 @@
class Driver {
constructor() {
this.popup = new Popup();
+ this.popupTimer = null;
this.audio = {};
this.lastMousePos = null;
this.lastTextSource = null;
@@ -32,6 +33,7 @@ class Driver {
chrome.runtime.onMessage.addListener(this.onBgMessage.bind(this));
window.addEventListener('message', this.onFrameMessage.bind(this));
+ window.addEventListener('mouseover', this.onMouseOver.bind(this));
window.addEventListener('mousedown', this.onMouseDown.bind(this));
window.addEventListener('mousemove', this.onMouseMove.bind(this));
window.addEventListener('keydown', this.onKeyDown.bind(this));
@@ -46,25 +48,58 @@ class Driver {
});
}
+ popupTimerSet(callback) {
+ this.popupTimerClear();
+ this.popupTimer = window.setTimeout(callback, this.options.scanDelay);
+ }
+
+ popupTimerClear() {
+ if (this.popupTimer !== null) {
+ window.clearTimeout(this.popupTimer);
+ this.popupTimer = null;
+ }
+ }
+
onKeyDown(e) {
- if (this.enabled && this.lastMousePos !== null && (e.keyCode === 16 || e.charCode === 16)) {
- this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
+ this.popupTimerClear();
+
+ if (this.enabled && this.lastMousePos !== null && e.keyCode === 16 /* shift */) {
+ this.searchAt(this.lastMousePos, true);
} else {
this.hidePopup();
}
}
+ onMouseOver(e) {
+ if (e.target === this.popup.container && this.popuptimer !== null) {
+ this.popupTimerClear();
+ }
+ }
+
onMouseMove(e) {
+ this.popupTimerClear();
+
this.lastMousePos = {x: e.clientX, y: e.clientY};
- if (this.enabled && (e.shiftKey || e.which === 2)) {
- this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
+ if (!this.enabled) {
+ return;
+ }
+
+ if (this.options.holdShiftToScan && !e.shiftKey) {
+ return;
+ }
+
+ const searcher = () => this.searchAt(this.lastMousePos, false);
+ if (!this.popup.visible() || e.shiftKey || e.which === 2 /* mmb */) {
+ searcher();
+ } else {
+ this.popupTimerSet(searcher);
}
}
onMouseDown(e) {
this.lastMousePos = {x: e.clientX, y: e.clientY};
- if (this.enabled && (e.shiftKey || e.which === 2)) {
- this.searchAt(this.lastMousePos, e.ctrlKey ? 'kanji' : 'terms');
+ if (this.enabled && (e.shiftKey || !this.options.holdShiftToScan || e.which === 2 /* mmb */)) {
+ this.searchAt(this.lastMousePos, true);
} else {
this.hidePopup();
}
@@ -90,10 +125,10 @@ class Driver {
textSource.setEndOffset(this.options.scanLength);
this.pendingLookup = true;
- findTerm(textSource.text()).then(({definitions, length}) => {
+ return findTerm(textSource.text()).then(({definitions, length}) => {
if (definitions.length === 0) {
this.pendingLookup = false;
- this.hidePopup();
+ return false;
} else {
textSource.setEndOffset(length);
@@ -113,6 +148,8 @@ class Driver {
if (states !== null) {
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
}
+
+ return true;
});
}
});
@@ -122,10 +159,10 @@ class Driver {
textSource.setEndOffset(1);
this.pendingLookup = true;
- findKanji(textSource.text()).then(definitions => {
+ return findKanji(textSource.text()).then(definitions => {
if (definitions.length === 0) {
this.pendingLookup = false;
- this.hidePopup();
+ return false;
} else {
definitions.forEach(definition => definition.url = window.location.href);
@@ -139,34 +176,40 @@ class Driver {
if (states !== null) {
states.forEach((state, index) => this.popup.invokeApi('setActionState', {index, state, sequence}));
}
+
+ return true;
});
}
});
}
- searchAt(point, mode) {
+ searchAt(point, hideNotFound) {
if (this.pendingLookup) {
return;
}
const textSource = textSourceFromPoint(point);
if (textSource === null || !textSource.containsPoint(point)) {
- this.hidePopup();
+ if (hideNotFound) {
+ this.hidePopup();
+ }
+
return;
}
if (this.lastTextSource !== null && this.lastTextSource.equals(textSource)) {
- return;
+ return true;
}
- switch (mode) {
- case 'terms':
- this.searchTerms(textSource);
- break;
- case 'kanji':
- this.searchKanji(textSource);
- break;
- }
+ this.searchTerms(textSource).then(found => {
+ if (!found) {
+ this.searchKanji(textSource).then(found => {
+ if (!found && hideNotFound) {
+ this.hidePopup();
+ }
+ });
+ }
+ });
}
showPopup(textSource, content) {
diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js
index 31ff02d8..83da3fe1 100644
--- a/ext/fg/js/popup.js
+++ b/ext/fg/js/popup.js
@@ -19,16 +19,16 @@
class Popup {
constructor() {
- this.popup = null;
+ this.container = null;
this.offset = 10;
}
showAt(pos, content) {
this.inject();
- this.popup.style.left = pos.x + 'px';
- this.popup.style.top = pos.y + 'px';
- this.popup.style.visibility = 'visible';
+ this.container.style.left = pos.x + 'px';
+ this.container.style.top = pos.y + 'px';
+ this.container.style.visibility = 'visible';
this.setContent(content);
}
@@ -36,58 +36,58 @@ class Popup {
showNextTo(elementRect, content) {
this.inject();
- const popupRect = this.popup.getBoundingClientRect();
+ const containerRect = this.container.getBoundingClientRect();
let posX = elementRect.left;
- if (posX + popupRect.width >= window.innerWidth) {
- posX = window.innerWidth - popupRect.width;
+ if (posX + containerRect.width >= window.innerWidth) {
+ posX = window.innerWidth - containerRect.width;
}
let posY = elementRect.bottom + this.offset;
- if (posY + popupRect.height >= window.innerHeight) {
- posY = elementRect.top - popupRect.height - this.offset;
+ if (posY + containerRect.height >= window.innerHeight) {
+ posY = elementRect.top - containerRect.height - this.offset;
}
this.showAt({x: posX, y: posY}, content);
}
visible() {
- return this.popup !== null && this.popup.style.visibility !== 'hidden';
+ return this.container !== null && this.container.style.visibility !== 'hidden';
}
hide() {
- if (this.popup !== null) {
- this.popup.style.visibility = 'hidden';
+ if (this.container !== null) {
+ this.container.style.visibility = 'hidden';
}
}
setContent(content) {
- if (this.popup === null) {
+ if (this.container === null) {
return;
}
- const doc = this.popup.contentDocument;
+ const doc = this.container.contentDocument;
doc.open();
doc.write(content);
doc.close();
}
invokeApi(action, params) {
- if (this.popup !== null) {
- this.popup.contentWindow.postMessage({action, params}, '*');
+ if (this.container !== null) {
+ this.container.contentWindow.postMessage({action, params}, '*');
}
}
inject() {
- if (this.popup !== null) {
+ if (this.container !== null) {
return;
}
- this.popup = document.createElement('iframe');
- this.popup.id = 'yomichan-popup';
- this.popup.addEventListener('mousedown', e => e.stopPropagation());
- this.popup.addEventListener('scroll', e => e.stopPropagation());
+ this.container = document.createElement('iframe');
+ this.container.id = 'yomichan-popup';
+ this.container.addEventListener('mousedown', e => e.stopPropagation());
+ this.container.addEventListener('scroll', e => e.stopPropagation());
- document.body.appendChild(this.popup);
+ document.body.appendChild(this.container);
}
}