javascript - 我如何制作一个外观和行为都像切换按钮的浏览器操作按钮

标签 javascript firefox firefox-addon firefox-addon-webextensions

目标是获取 Firefox 的 WebExtension,用户可以在工具栏中激活/停用它,就像一个开/关开关。

我在这段代码中使用了 background.js:

browser.browserAction.onClicked.addListener(function (tab) {
    switch (button) {
        case 'turn-on':
            enable();
            break;
        case 'turn-off':
            disable();
            break;
    }
});
function enable() {
    browser.browserAction.setIcon({ path: '/ui/is-on.png', });
    browser.browserAction.setPopup({ popup: '/ui/turn-off.js', });
    browser.webNavigation.onCommitted.addListener(onTabLoad); 
} 
function disable() {
    browser.browserAction.setIcon({ path: '/ui/is-off.png', });
    browser.browserAction.setPopup({ popup: '/ui/turn-on.js', });
    browser.webNavigation.onCommitted.removeListener(onTabLoad); 
}
function onTabLoad(details) {
    browser.tabs.executeScript(details.tabId, {
        file: '/gc.js',
        allFrames true,
    }); 
}
enable(); // enable or disable by default

显然我做错了什么。我是编码方面的新手。这是我正在努力完成的个人项目。

最佳答案

你的代码

虽然您添加了 switch 语句来打开 button,但您从未定义 button,也没有更改其状态。您也没有默认情况,以防万一 button 变量不是您在 case 语句中测试的值之一。

您不应该使用 browserAction.setPopup() 来设置弹出窗口。设置弹出窗口将导致打开弹出窗口,而不是您的后台页面接收click 事件。此外,弹出窗口必须是 HTML 页面,而不是 JavaScript。

请参阅下面的部分,了解您需要在 onTabLoad() 中解决的 Firefox 错误。

聆听 webNavigation.onCommitted 不足以涵盖需要注入(inject)脚本的所有情况。换句话说,webNavigation.onCommitted 不会在每次加载页面时触发。要完全涵盖需要注入(inject)脚本的每种情况,您需要在另一个问题中提出。

var nextButtonState;
browser.browserAction.onClicked.addListener(function (tab) {
    switch (nextButtonState) {
        case 'turn-on':
            enable();
            break;
        case 'turn-off':
        default:
            disable();
            break;
    }
});
function enable() {
    browser.browserAction.setIcon({ path: '/ui/is-on.png', });
    //browser.browserAction.setPopup({ popup: '/ui/turn-off.js', });
    browser.webNavigation.onCommitted.addListener(onTabLoad); 
    nextButtonState = 'turn-off';
} 
function disable() {
    browser.browserAction.setIcon({ path: '/ui/is-off.png', });
    //browser.browserAction.setPopup({ popup: '/ui/turn-on.js', });
    browser.webNavigation.onCommitted.removeListener(onTabLoad); 
    nextButtonState = 'turn-on';
}
function onTabLoad(details) {
    //Add a setTimout to avoid a Firefox bug that Firefox is not quite ready to 
    //  have tabs.executeScript() inject a script when the onCommitted event fires.
    setTimeout(function(){
        chrome.tabs.executeScript(details.tabId, {
            file: '/gc.js',
            allFrames true,
        }); 
    },0);
}
enable(); // enable or disable by default

解决 Firefox webNavigation.onCommitted 错误

您的 onTabLoad() 代码需要更改,以便使用 webNavigation.onCommitted 监听器使用 tabs.executeScript() 注入(inject)脚本> 在 Firefox 中(这在 Chrome 中不需要)。这是由于 Firefox 中的错误导致 tabs.executeScript() 如果立即从 webNavigation.onCommitted 监听器执行则失败。我使用的解决方法是在 setTimeout(function,0) 延迟后注入(inject)脚本。这允许 Firefox 执行设置 executeScript() 正常运行所需的环境所需的代码。

function onTabLoad(details) {
    //Add a setTimout to avoid a Firefox bug that Firefox is not quite ready to 
    //  have tabs.executeScript() inject a script when the onCommitted event fires.
    setTimeout(function(){
        chrome.tabs.executeScript(details.tabId, {
            file: '/gc.js',
            allFrames true,
        }); 
    },0);
}

多状态按钮(例如切换按钮)的通用解决方案

我用来使浏览器操作按钮的行为类似于切换的代码如下。我已经修改了 browserButtonStates 对象,它描述了按钮的作用和它们的外观,以添加和删除您的 webNavigation.onCommitted 监听器,onTabLoad() 。有关 onTabLoad() 的问题,请参见上文。

下面的代码比您需要的更复杂。我写它的目的是能够将它从一个项目移动到另一个项目,只需要更改 browserButtonStates 对象的内容。然后,只需更改该对象,即可更改图标、文本、徽章文本、徽章颜色以及在每种状态下执行的操作(例如开/关)。

background.js

//The browserButtonStates Object describes the states the button can be in and the
//  'action' function to be called when the button is clicked when in that state.
//  In this case, we have two states 'on' and 'off'.
//  You could expand this to as many states as you desire.
//icon is a string, or details Object for browserAction.setIcon()
//title must be unique for each state. It is used to track the state.
//  It indicates to the user what will happen when the button is clicked.
//  In other words, it reflects what the _next_ state is, from the user's
//  perspective.
//action is the function to call when the button is clicked in this state.
var browserButtonStates = {
    defaultState: 'off',
    on: {
        icon         : '/ui/is-on.png'
        //badgeText  : 'On',
        //badgeColor : 'green',
        title        : 'Turn Off',
        action       : function(tab) {
                           chrome.webNavigation.onCommitted.removeListener(onTabLoad);
                       },
        nextState    : 'off'
    },
    off: {
        icon         : '/ui/is-off.png'
        //badgeText  : 'Off',
        //badgeColor : 'red',
        title        : 'Turn On',
        action       : function(tab) {
                           chrome.webNavigation.onCommitted.addListener(onTabLoad);
                       },
        nextState    : 'on'
    }
}

//This moves the Browser Action button between states and executes the action
//  when the button is clicked. With two states, this toggles between them.
chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.browserAction.getTitle({tabId:tab.id},function(title){
        //After checking for errors, the title is used to determine
        //  if this is going to turn On, or Off.
        if(chrome.runtime.lastError){
            console.log('browserAction:getTitle: Encountered an error: ' 
                + chrome.runtime.lastError);
            return;
        }
        //Check to see if the current button title matches a button state
        let newState = browserButtonStates.defaultState;
        Object.keys(browserButtonStates).some(key=> {
            if(key === 'defaultState') {
                return false;
            }
            let state = browserButtonStates[key];
            if(title === state.title) {
                newState = state.nextState;
                setBrowserActionButton(browserButtonStates[newState]);
                if(typeof state.action === 'function') {
                    //Do the action of the matching state
                    state.action(tab);
                }
                //Stop looking
                return true;
            }
        });
        setBrowserActionButton(browserButtonStates[newState]);
    });
});

function setBrowserActionButton(tabId,details){
    if(typeof tabId === 'object' && tabId !== null){
        //If the tabId parameter is an object, then no tabId was passed.
        details = tabId;
        tabId       = null;
    }
    let icon   = details.icon;
    let title  = details.title;
    let text   = details.badgeText;
    let color  = details.badgeColor;

    //Supplying a tabId is optional. If not provided, changes are to all tabs.
    let tabIdObject = {};
    if(tabId !== null && typeof tabId !== 'undefined'){
        tabIdObject.tabId = tabId;
    }
    if(typeof icon === 'string'){
        //Assume a string is the path to a file
        //  If not a string, then it needs to be a full Object as is to be passed to
        //  setIcon().
        icon = {path:icon};
    }
    if(icon) {
        Object.assign(icon,tabIdObject);
        chrome.browserAction.setIcon(icon);
    }
    if(title) {
        let detailsObject = {title};
        Object.assign(detailsObject,tabIdObject);
        chrome.browserAction.setTitle(detailsObject);
    }
    if(text) {
        let detailsObject = {text};
        Object.assign(detailsObject,tabIdObject);
        chrome.browserAction.setBadgeText(detailsObject);
    }
    if(color) {
        let detailsObject = {color};
        Object.assign(detailsObject,tabIdObject);
        chrome.browserAction.setBadgeBackgroundColor(detailsObject);
    }
}

//Set the starting button state to the default state
setBrowserActionButton(browserButtonStates[browserButtonStates.defaultState]);

list .json:

{
    "description": "Demo Button toggle",
    "manifest_version": 2,
    "name": "Demo Button toggle",
    "version": "0.1",

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

    "browser_action": {
        "default_icon": {
            "32": "myIcon.png"
        },
        "default_title": "Turn On",
        "browser_style": true
    }
}

关于javascript - 我如何制作一个外观和行为都像切换按钮的浏览器操作按钮,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40603655/

相关文章:

javascript - 如何使用 db 用户和密码启动 mongo docker 镜像

javascript - 循环内的 setTimeout 一次给出所有迭代

css - Youtube 视频坚持使用 Firefox 中的颜色框

javascript - 我可以将一个 javascript 请求重定向到另一个 javascript 操作吗?

javascript - 如何获得一个复选框的div的结果?

javascript捕获并篡改http请求

javascript - 在 Firefox 中检测关闭窗口事件

javascript - Downloads.jsm - 调用 cancel() 实际上并没有取消下载?

javascript - 从 javascript 打开 firefox multifox 窗口

php - 为 iSpeech 创建 Send-to Hook