aboutsummaryrefslogtreecommitdiff
path: root/ext/js/background/backend.js
diff options
context:
space:
mode:
authorjbukl <noreply@github.com>2023-10-20 02:37:47 -0400
committerjbukl <noreply@github.com>2023-10-20 15:25:52 -0400
commit9a39d0a7e2896edd4a6deebad00b8550cfffc15b (patch)
treeab4aa25d9c89856066ae9d1c347da3ad9bb6ea4e /ext/js/background/backend.js
parentc3be9af7b6f00dad7107fcdae60a8004cc81936a (diff)
fix: chromium clipboard access
on chromium, backend calls to clipboardGet are forwarded to an offscreen script
Diffstat (limited to 'ext/js/background/backend.js')
-rw-r--r--ext/js/background/backend.js73
1 files changed, 67 insertions, 6 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 565f4abf..57565eec 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -57,12 +57,19 @@ class Backend {
});
this._anki = new AnkiConnect();
this._mecab = new Mecab();
- this._clipboardReader = new ClipboardReader({
- // eslint-disable-next-line no-undef
- document: (typeof document === 'object' && document !== null ? document : null),
- pasteTargetSelector: '#clipboard-paste-target',
- richContentPasteTargetSelector: '#clipboard-rich-content-paste-target'
- });
+
+ this._clipboardReader = {
+ getText: this._getTextOffscreen.bind(this)
+ };
+ if (!chrome || !chrome.offscreen) {
+ this._clipboardReader = new ClipboardReader({
+ // eslint-disable-next-line no-undef
+ document: (typeof document === 'object' && document !== null ? document : null),
+ pasteTargetSelector: '#clipboard-paste-target',
+ richContentPasteTargetSelector: '#clipboard-rich-content-paste-target'
+ });
+ }
+
this._clipboardMonitor = new ClipboardMonitor({
japaneseUtil: this._japaneseUtil,
clipboardReader: this._clipboardReader
@@ -97,6 +104,8 @@ class Backend {
this._permissions = null;
this._permissionsUtil = new PermissionsUtil();
+ this._creatingOffscreen = null;
+
this._messageHandlers = new Map([
['requestBackendReadySignal', {async: false, contentScript: true, handler: this._onApiRequestBackendReadySignal.bind(this)}],
['optionsGet', {async: false, contentScript: true, handler: this._onApiOptionsGet.bind(this)}],
@@ -557,6 +566,21 @@ class Backend {
return this._clipboardReader.getText(false);
}
+ async _getTextOffscreen(useRichText) {
+ await this._setupOffscreenDocument();
+ return new Promise((resolve, reject) => {
+ const callback = (response) => {
+ try {
+ resolve(this._getMessageResponseResult(response));
+ } catch (error) {
+ reject(error);
+ }
+ };
+
+ chrome.runtime.sendMessage({action: 'clipboardGetOffscreen', params: {useRichText}}, callback);
+ });
+ }
+
async _onApiGetDisplayTemplatesHtml() {
return await this._fetchAsset('/display-templates.html');
}
@@ -2262,4 +2286,41 @@ class Backend {
return {targetTabId, targetFrameId};
}
+
+ // https://developer.chrome.com/docs/extensions/reference/offscreen/
+ async _setupOffscreenDocument() {
+ // Check all windows controlled by the service worker to see if one
+ // of them is the offscreen document with the given path
+ if (await this._hasOffscreenDocument()) {
+ return;
+ }
+
+ // create offscreen document
+ if (this._creatingOffscreen) {
+ await this._creatingOffscreen;
+ } else {
+ this._creatingOffscreen = chrome.offscreen.createDocument({
+ url: 'offscreen.html',
+ reasons: ['CLIPBOARD'],
+ justification: 'reason for needing the document'
+ });
+ await this._creatingOffscreen;
+ this._creatingOffscreen = null;
+ }
+ }
+ async _hasOffscreenDocument() {
+ const offscreenUrl = chrome.runtime.getURL('offscreen.html');
+ if (chrome.runtime.getContexts) {
+ const contexts = await chrome.runtime.getContexts({
+ contextTypes: ['OFFSCREEN_DOCUMENT'],
+ documentUrls: [offscreenUrl]
+ });
+ return Boolean(contexts.length);
+ } else {
+ const matchedClients = await clients.matchAll();
+ return await matchedClients.some((client) => {
+ client.url.includes(chrome.runtime.id);
+ });
+ }
+ }
}