aboutsummaryrefslogtreecommitdiff
path: root/ext/bg/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2019-12-12 20:59:54 -0500
committertoasted-nutbread <toasted-nutbread@users.noreply.github.com>2019-12-22 20:35:26 -0500
commitbf93d9f5f923e8ad7571a6d588fbc756e1153742 (patch)
treecf996ca306b09a3282106d8428cb294cbe60a06f /ext/bg/js
parent362e317a5d282cd19ec22531e3a70020d542919e (diff)
Improve performance of DisplaySearch's clipboard monitor
Diffstat (limited to 'ext/bg/js')
-rw-r--r--ext/bg/js/search.js97
1 files changed, 65 insertions, 32 deletions
diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js
index 97b0561b..3d6024f0 100644
--- a/ext/bg/js/search.js
+++ b/ext/bg/js/search.js
@@ -16,13 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
-let IS_FIREFOX = null;
-(async () => {
- const {browser} = await apiGetEnvironmentInfo();
- IS_FIREFOX = ['firefox', 'firefox-mobile'].includes(browser);
-})();
-
class DisplaySearch extends Display {
constructor() {
super(document.querySelector('#spinner'), document.querySelector('#content'));
@@ -43,8 +36,12 @@ class DisplaySearch extends Display {
this.introVisible = true;
this.introAnimationTimer = null;
- this.clipboardMonitorIntervalId = null;
- this.clipboardPrevText = null;
+ this.isFirefox = false;
+
+ this.clipboardMonitorTimerId = null;
+ this.clipboardMonitorTimerToken = null;
+ this.clipboardInterval = 250;
+ this.clipboardPreviousText = null;
}
static create() {
@@ -56,6 +53,7 @@ class DisplaySearch extends Display {
async prepare() {
try {
await this.initialize();
+ this.isFirefox = await DisplaySearch._isFirefox();
if (this.search !== null) {
this.search.addEventListener('click', (e) => this.onSearch(e), false);
@@ -241,39 +239,63 @@ class DisplaySearch extends Display {
initClipboardMonitor() {
// ignore copy from search page
window.addEventListener('copy', () => {
- this.clipboardPrevText = document.getSelection().toString().trim();
+ this.clipboardPreviousText = document.getSelection().toString().trim();
});
}
startClipboardMonitor() {
- this.clipboardMonitorIntervalId = setInterval(async () => {
- let curText = null;
- // TODO get rid of this and figure out why apiClipboardGet doesn't work on Firefox
- if (IS_FIREFOX) {
- curText = (await navigator.clipboard.readText()).trim();
- } else if (IS_FIREFOX === false) {
- curText = (await apiClipboardGet()).trim();
- }
- if (curText && (curText !== this.clipboardPrevText) && jpIsJapaneseText(curText)) {
- if (this.isWanakanaEnabled()) {
- this.setQuery(window.wanakana.toKana(curText));
- } else {
- this.setQuery(curText);
+ const token = {};
+ const intervalCallback = async () => {
+ this.clipboardMonitorTimerId = null;
+
+ let text = await this.getClipboardText();
+ if (this.clipboardMonitorTimerToken !== token) { return; }
+
+ if (
+ typeof text === 'string' &&
+ (text = text.trim()).length > 0 &&
+ text !== this.clipboardPreviousText
+ ) {
+ this.clipboardPreviousText = text;
+ if (jpIsJapaneseText(text)) {
+ this.setQuery(this.isWanakanaEnabled() ? window.wanakana.toKana(text) : text);
+ window.history.pushState(null, '', `${window.location.pathname}?query=${encodeURIComponent(text)}`);
+ this.onSearchQueryUpdated(this.query.value, true);
}
+ }
+
+ this.clipboardMonitorTimerId = setTimeout(intervalCallback, this.clipboardInterval);
+ };
- const queryString = curText.length > 0 ? `?query=${encodeURIComponent(curText)}` : '';
- window.history.pushState(null, '', `${window.location.pathname}${queryString}`);
- this.onSearchQueryUpdated(this.query.value, true);
+ this.clipboardMonitorTimerToken = token;
- this.clipboardPrevText = curText;
- }
- }, 100);
+ intervalCallback();
}
stopClipboardMonitor() {
- if (this.clipboardMonitorIntervalId) {
- clearInterval(this.clipboardMonitorIntervalId);
- this.clipboardMonitorIntervalId = null;
+ this.clipboardMonitorTimerToken = null;
+ if (this.clipboardMonitorTimerId !== null) {
+ clearTimeout(this.clipboardMonitorTimerId);
+ this.clipboardMonitorTimerId = null;
+ }
+ }
+
+ async getClipboardText() {
+ /*
+ Notes:
+ apiClipboardGet doesn't work on firefox because document.execCommand('paste') requires
+ user interaction. Therefore, navigator.clipboard.readText() is used.
+
+ navigator.clipboard.readText() can't be used in Chrome for two reasons:
+ * Requires page to be focused, else it rejects with an exception.
+ * When the page is focused, Chrome will request clipboard permission, despite already
+ being an extension with clipboard permissions. It effectively asks for the
+ non-extension permission for clipboard access.
+ */
+ try {
+ return this.isFirefox ? await navigator.clipboard.readText() : await apiClipboardGet();
+ } catch (e) {
+ return null;
}
}
@@ -367,6 +389,17 @@ class DisplaySearch extends Display {
const match = /^[^?#]*\?(?:[^&#]*&)?query=([^&#]*)/.exec(url);
return match !== null ? decodeURIComponent(match[1]) : null;
}
+
+ static async _isFirefox() {
+ const {browser} = await apiGetEnvironmentInfo();
+ switch (browser) {
+ case 'firefox':
+ case 'firefox-mobile':
+ return true;
+ default:
+ return false;
+ }
+ }
}
DisplaySearch.onKeyDownIgnoreKeys = {