On 15/09/2024 23:17, 'Cory Cooper' via Chromium Extensions wrote:
> If you are calling sidepanel.open() in a callback, .then(), or after an
> “await”, that does not work on any occasion. You must call it
> synchronously after the click handler is fired (i.e. synchronously in
> your browser message event handler).
User gesture context is a rather bizarre beast. In Firefox it is
insanely strict and really does not allow even a callback to read
settings from storage. In Chromium it seems single step callback (e.g.
the slowest one when multiple API calls are fired in parallel) works well.
Even await is possible if
1. The extension has the scripting permission,
2. The menu option is selected fast enough after opening context menu.
The following works for permissions.request as well. Credits: Rob Wu
<
https://stackoverflow.com/questions/28060485/can-a-chrome-extensions-content-script-guarantee-that-a-dom-event-was-user-init>
---- 8< -----
{
"manifest_version": 3,
"name": "Open sidebar",
"description": "sidePanel.open() and user gesture context",
"version": "0.1",
"permissions": ["scripting", "activeTab", "contextMenus", "sidePanel"],
"background": { "service_worker": "asp_bg.js" }
}
---- 8< ----
"use strict";
async function aspOnClicked(tab, click) {
const frameId = click?.frameId;
const tabId = click?.tabId ??
tab.id;
await chrome.sidePanel.setOptions({ path: "asp_panel.html" });
// Fails
try {
console.log("after await", await chrome.sidePanel.open({tabId}));
} catch (ex) {
console.error("after await", ex);
}
// May work
console.log(
"content script",
await chrome.scripting.executeScript({
target: { tabId, allFrames: false, frameIds: [ frameId ] },
func: async function asp_cs(tabId) {
return await chrome.runtime.sendMessage(
{type: "open", tabId});
},
args: [ tabId ],
}));
}
chrome.contextMenus.onClicked.addListener(
(clickData, tab) => void aspOnClicked(tab, clickData));
chrome.runtime.onInstalled.addListener(async () => {
await chrome.contextMenus.removeAll();
chrome.contextMenus.create({
id: "ASP",
title: "open sidebar", contexts: ["all"]
});
});
chrome.runtime.onMessage.addListener((msg, _port, sendResponse) => {
async function asp_msg(tabId) {
try {
console.log(
"from content script",
await chrome.sidePanel.open({tabId}));
return true;
} catch (ex) {
console.error("from content script", ex);
return false;
}
}
asp_msg(msg.tabId).then(r => sendResponse(r));
return true;
});