gpt4 book ai didi

javascript - 如何创建用于在 Firefox (WebExtensions) 中打开 "browserAction"弹出窗口的全局热键?

转载 作者:搜寻专家 更新时间:2023-11-01 04:14:02 32 4
gpt4 key购买 nike

Chrome 似乎没有打开弹出窗口的 API,但有一个专用系统可以使用热键来打开弹出窗口:_execute_browser_action输入 commands .

_execute_browser_action 的特殊功能在 commands Firefox 不支持(1)。

我关心的弹窗类型是browserAction , 不是 pageAction .

我怎样才能得到 browserAction按下键盘快捷键/热键组合时弹出窗口打开?

最佳答案

Firefox 版本本地可用 >= 52

此功能将在 Firefox 52 中原生可用,目前为 Firefox Developer Edition (即 Firefox 52.0a2)。如您所知,对于 WebExtensions,您可以使用为 commands 键提供的对象中的 _execute_browser_action 键创建一个全局热键。例如:

"commands":{
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+Shift+J"
}
}
}

打开一个伪弹出窗口(在旧版本的 Firefox 中填充此功能)

虽然显式功能在 Firefox 52 之前不可用,但您可以通过定义名为 "_execute_browser_action" 的自定义命令在当前版本的 Firefox 中填充此功能。它看起来与您的普通弹出窗口有点不同,但它会起作用。它将位于一个面板中,您可能需要考虑一些关联的样式,这些样式仅在面板而不是弹出窗口中应用。当您的面板打开时,事件选项卡的内容也可能存在一些差异。但是,下面的代码至少在使用 chrome.tabs.query()browser.tabs.query() 执行查询时考虑到了这一点,方法是将响应设为如果它在真正的弹出窗口而不是面板中打开,将会发生什么。

相同的代码将继续在 Firefox 52+ 上运行。在 Firefox 52+ 上,"_execute_browser_action" 直接激活浏览器操作点击或弹出。

当您不使用弹出窗口时,最主要的是您不对 browserAction.onClicked 使用匿名函数。听众。这允许该功能也可以被 commands.onCommand 调用听众。 commands.onCommand 是在 Firefox 48 中引入的,因此它应该适用于 48+ 的任何版本。

可能在使用此 polyfill 时遇到一些需要权限而不是 activeTab 的问题。究竟需要什么(如果有的话)将取决于您的代码。

以下是一个扩展,当您按下键盘快捷键 Alt-Shift-J 时,它会导致通过浏览器操作按钮调用的功能被执行。它将激活 doActionButton() 函数,或者,如果定义了弹出窗口,它将打开您的弹出窗口作为面板,其行为类似于弹出窗口的正常行为,但它并不完美。它从当前为当前事件选项卡定义的文件中获取弹出文件的名称,就像单击 browserAction 按钮的情况一样。

list .json:

{
"description": "Polyfill browserAction keyboard shortcut, including popups.",
"manifest_version": 2,
"name": "Polyfill browserAction keyboard shortcut",
"version": "0.1",

"background": {
"scripts": [
"background.js"
]
},

"browser_action": {
"default_icon": {
"32": "myIcon.png"
},
"default_title": "Open popup",
"default_popup": "popup.html"
},

"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+Shift+J"
}
}
}
}

background.js:

chrome.browserAction.onClicked.addListener(doActionButton);

function doActionButton(tab){
console.log('Action Button clicked. Tab:',tab);
}

chrome.commands.onCommand.addListener(function(command) {
//Polyfill the Browser Action button
if(command === '_execute_browser_action') {
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
//Get the popup for the current tab
chrome.browserAction.getPopup({tabId:tabs[0].id},function(popupFile){
if(popupFile){
openPopup(tabs[0],popupFile);
} else {
//There is no popup defined, so we do what is supposed to be done for
// the browserAction button.
doActionButton(tabs[0]);
}
});
});
return;
} //else
});

//popupWindowId can be true, false, or the popup's window Id.
var popupWindowId = false;
var lastFocusedWin;
var lastActiveTab;
function openPopup(tab,popupFile){
chrome.windows.getLastFocused(function(win){
lastFocusedWin=win;
if(popupWindowId === false){
//This prevents user from pressing the button quickly multiple times in a row.
popupWindowId = true;
lastActiveTab = tab;
chrome.windows.create({
url: popupFile,
type: 'popup',
},function(win){
popupWindowId = win.id;
//Poll for the view of the window ID. Poll every 50ms for a
// maximum of 20 times (1 second). Then do a second set of polling to
// accommodate slower machines.
// Testing on a single moderately fast machine indicated the view
// was available after, at most, the second 50ms delay.
waitForWindowId(popupWindowId,50,20,actOnPopupViewFound,do2ndWaitForWinId);
});
return;
}else if(typeof popupWindowId === 'number'){
//The window is open, and the user pressed the hotkey combo.
// Close the window (as happens for a browserAction popup).
closePopup();
}
});
}

function closePopup(){
if(typeof popupWindowId === 'number'){
chrome.windows.remove(popupWindowId,function(){
popupWindowId = false;
});
}
}

chrome.windows.onRemoved.addListener(function(winId){
if(popupWindowId === winId){
popupWindowId = false;
}
});

chrome.windows.onFocusChanged.addListener(function(winId){
//If the focus is no longer the popup, then close the popup.
if(typeof popupWindowId === 'number'){
if(popupWindowId !== winId){
closePopup();
}
} else if(popupWindowId){
}
});

function actOnPopupViewFound(view){
//Make tabs.query act as if the panel is a popup.
if(typeof view.chrome === 'object'){
view.chrome.tabs.query = fakeTabsQuery;
}
if(typeof view.browser === 'object'){
view.browser.tabs.query = fakeTabsQuery;
}
view.document.addEventListener('DOMContentLoaded',function(ev){
let boundRec = view.document.body.getBoundingClientRect();
updatePopupWindow({
width:boundRec.width + 20,
height:boundRec.height + 40
});
});
updatePopupWindow({});
}

function updatePopupWindow(opt){
let width,height;
if(opt){
width =typeof opt.width === 'number'?opt.width :400;
height=typeof opt.height === 'number'?opt.height:300;
}
//By the time we get here it is too late to find the window for which we
// are trying to open the popup.
let left = lastFocusedWin.left + lastFocusedWin.width - (width +40);
let top = lastFocusedWin.top + 85; //Just a value that works in the default case.
let updateInfo = {
width:width,
height:height,
top:top,
left:left
};
chrome.windows.update(popupWindowId,updateInfo);
}

function waitForWindowId(id,delay,maxTries,foundCallback,notFoundCallback) {
if(maxTries--<=0){
if(typeof notFoundCallback === 'function'){
notFoundCallback(id,foundCallback);
}
return;
}
let views = chrome.extension.getViews({windowId:id});
if(views.length > 0){
if(typeof foundCallback === 'function'){
foundCallback(views[0]);
}
} else {
setTimeout(waitForWindowId,delay,id,delay,maxTries,foundCallback,notFoundCallback);
}
}

function do2ndWaitForWinId(winId,foundCallback){
//Poll for the view of the window ID. Poll every 500ms for a
// maximum of 40 times (20 seconds).
waitForWindowId(winId,500,40,foundCallback,windowViewNotFound);
}

function windowViewNotFound(winId,foundCallback){
//Did not find the view for the window. Do what you want here.
// Currently fail quietly.
}

function fakeTabsQuery(options,callback){
//This fakes the response of chrome.tabs.query and browser.tabs.query, which in
// a browser action popup returns the tab that is active in the window which
// was the current window when the popup was opened. We need to emulate this
// in the popup as panel.
//The popup is also stripped from responses if the response contains multiple
// tabs.
let origCallback = callback;
function stripPopupWinFromResponse(tabs){
return tabs.filter(tab=>{
return tab.windowId !== popupWindowId;
});
}
function stripPopupWinFromResponseIfMultiple(tabs){
if(tabs.length>1){
return stripPopupWinFromResponse(tabs);
}else{
return tabs;
}
}
function callbackWithStrippedTabs(tabs){
origCallback(stripPopupWinFromResponseIfMultiple(tabs));
}
if(options.currentWindow || options.lastFocusedWindow){
//Make the query use the window which was active prior to the panel being
// opened.
delete options.currentWindow;
delete options.lastFocusedWindow;
options.windowId = lastActiveTab.windowId;
}
if(typeof callback === 'function') {
callback = callbackWithStrippedTabs;
chrome.tabs.query.apply(this,arguments);
return;
}else{
return browser.tabs.query.apply(this,arguments)
.then(stripPopupWinFromResponseIfMultiple);
}
}

WebExtensions 仍在开发中:

WebExtensions API 仍在开发中。每个版本的 Firefox 都改进了工作。现在,您可能最好使用 Firefox Developer Edition 开发和测试您的 WebExtension 附加组件。 , 或 Firefox Nightly (对于 _execute_browser_action)。您还应该仔细记下您希望使用的功能需要哪个版本的 Firefox。此信息包含在 MDN 文档页面的“浏览器兼容性”部分。


这个问题中的部分代码是从我的其他各种答案中复制/修改的。

关于javascript - 如何创建用于在 Firefox (WebExtensions) 中打开 "browserAction"弹出窗口的全局热键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40282137/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com