- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
Chrome 似乎没有打开弹出窗口的 API,但有一个专用系统可以使用热键来打开弹出窗口:_execute_browser_action
输入 commands
.
_execute_browser_action
的特殊功能在 commands
Firefox 不支持(1)。
我关心的弹窗类型是browserAction
, 不是 pageAction
.
我怎样才能得到 browserAction
按下键盘快捷键/热键组合时弹出窗口打开?
最佳答案
此功能将在 Firefox 52 中原生可用,目前为 Firefox Developer Edition (即 Firefox 52.0a2)。如您所知,对于 WebExtensions,您可以使用为 commands
键提供的对象中的 _execute_browser_action
键创建一个全局热键。例如:
"commands":{
"_execute_browser_action": {
"suggested_key": {
"default": "Alt+Shift+J"
}
}
}
虽然显式功能在 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 API 仍在开发中。每个版本的 Firefox 都改进了工作。现在,您可能最好使用 Firefox Developer Edition 开发和测试您的 WebExtension 附加组件。 , 或 Firefox Nightly (对于 _execute_browser_action
)。您还应该仔细记下您希望使用的功能需要哪个版本的 Firefox。此信息包含在 MDN 文档页面的“浏览器兼容性”部分。
这个问题中的部分代码是从我的其他各种答案中复制/修改的。
关于javascript - 如何创建用于在 Firefox (WebExtensions) 中打开 "browserAction"弹出窗口的全局热键?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40282137/
我已经为桌面和移动 Firefox 开发了一些 Firefox 插件(扩展),但现在我无法将插件/扩展安装到在 Firefox OS 中运行的浏览器中(我正在使用模拟器插件)。请注意,我不想创建一个传
可以将选项卡/网址从移动 Firefox 发送到桌面 Firefox 浏览器,但是否可以以相反的方式执行此操作?从桌面版 Firefox 到移动版 Firefox,并像其他方向一样自动加载。我找不到除
我想等待 Firefox-Browser-Events (sessionstore-windows-restored, user-interaction-inactive,..) 以清除历史记录。我的
我在公司网络中,想为 Firefox 安装一些开发人员工具。不幸的是,政策禁止 Firefox 直接访问互联网,但还有其他浏览器可以访问互联网。现在:如何在没有 Firefox 的情况下直接下载 xp
是否有用于在 firefox 中执行选择性缓存的插件或方法?我可以disable caching entirely ,但我仍然希望能够缓存一些需要几秒钟才能加载的大型 javascript 库 (ex
我目前正在将 Chrome 扩展程序转换为 Firefox 插件,并希望复制 chrome.storage.sync 功能。 但是,我无法使用 simple-storage 找到是否由 Firefox
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 6年前关闭。 Improve thi
所以,我使用这个代码: var options = { enableHighAccuracy: true, timeout: 2000, maximumAge: 100 }; navi
有没有办法打开 Firefox 并强制它在启动时加载临时加载项(webextension)?通常我必须手动去about:debugging并选择我硬盘上的扩展名。我正在寻找一个可以在加载 Firefo
我正在密切关注教程 here当我尝试创建 Firefox 扩展时。我的扩展有以下树: backtosearch +-chrome +-content backtosearch.
如何从代码中正确地重启 firefox(没有任何“恢复 session ”的东西并且使用与以前相同的窗口)? 我知道 bash 脚本进程中“firefox-bin”的 pid,并且我已将自定义插件加载
自从 Firefox 的最后几次更新以来,我们心爱的 Firebug 已集成到 Firefox 开发人员工具中,并且包括我在内的很多人 don't like what happened到 Firebu
当你在某处上传图片时,在使用chrome时,你可以看到状态栏实际上显示了上传的“状态”,即上传完成的百分比。 Firefox 的状态栏有没有办法显示这个上传状态? 最佳答案 用谷歌搜索这个,发现这个:
例如 Chrome 保存在这里:~Library/Application Support/Google/Chrome/Default/Current Tabs和 Safari 在这里 ~/Librar
当火狐开发者版推出时,我很高兴,我可以使用WebIde、响应式设计工具、滴管等……今天我受够了。 里面有很多bug,我就不一一列举我和我的同事发送和批准了多少bug了…… 我在 google 中搜索过
我在 Ubuntu 上使用 Firefox,版本 39.0。我正在尝试调试一个附加组件,并希望在 chrome 权限下运行一些 JavaScript。根据 this page我应该能够在浏览器控制台中
几天前,我更改了我的网站的图标:打开网站后,它可以很好地工作: 我的网站也在我的书签中,但是显示了旧的收藏夹图标: 我已经看过here,但是答案并没有解决我的问题。 解决方法可能非常简单,但是到目前为
我正在使用web API从Firefox开发一个 native 消息传递应用程序。该扩展应该调用一个解析stdin的应用程序,然后基于它解析的一些数据调用我的另一个rust应用程序,但是出于显而易见的
在 Firefox 中有插件和扩展。你能解释一下为什么这些插件有不同的名称和标签吗?它们是否差异如此之大,以至于需要不同的名称?我认为区分这些东西有点不自然,扩展具有越来越多的功能,与插件相比它们缺少
我正在使用附加构建器和附加 SDK 编写 Firefox 扩展。到目前为止,我已经能够解决任何限制,而无需迁移到 XUL。但是,我遇到了障碍。 我的扩展程序有一个长时间运行的进程,可能会阻塞,因此我需
我是一名优秀的程序员,十分优秀!