diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/bg/js/search.js | 97 | 
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 = { |