Как я могу сделать кнопку действия браузера, которая выглядит и действует как переключатель

javascript firefox firefox-addon firefox-webextensions

1113 просмотра

1 ответ

Цель - получить WebExtension для Firefox, который пользователь может активировать / деактивировать на панели инструментов, например, включить / выключить переключатель.

Я использую 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

Очевидно, я делаю что-то не так. Я добрый новичок в коде. Это личный проект, который я пытаюсь закончить.

Автор: rafael1138 Источник Размещён: 12.11.2019 09:03

Ответы (1)


3 плюса

Ваш код

Добавляя switchоператор для включения button, вы никогда не определяли buttonи не меняли его состояние. У вас также не было случая по умолчанию, на случай, если buttonпеременная не была одним из значений, для которых вы проверяли свои caseутверждения.

Вы не должны использовать, browserAction.setPopup()чтобы установить всплывающее окно. Установка всплывающего окна приведет к тому, что всплывающее окно откроется, а фоновая страница не получит clickсобытие. Кроме того, всплывающее окно должно быть страницей HTML, а не JavaScript.

Смотрите ниже раздел об ошибке в Firefox, которую вам нужно обойти onTabLoad().

Прослушивания webNavigation.onCommittedнедостаточно, чтобы охватить все случаи, когда ваш сценарий нужно будет ввести. Другими словами, webNavigation.onCommittedне срабатывает каждый раз при загрузке страницы. Чтобы полностью охватить каждую ситуацию, в которой ваш сценарий должен быть введен, вам нужно задать другой вопрос.

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

Обходной путь для webNavigation.onCommittedошибки Firefox

В вашем onTabLoad()коде есть изменения, необходимые для использования webNavigation.onCommittedслушателя для вставки сценариев, используемых tabs.executeScript()в Firefox (в Chrome это не требуется). Это связано с ошибкой в ​​Firefox, которая приводит tabs.executeScript()к сбою, если выполняется немедленно из webNavigation.onCommittedслушателя. Обходной путь, который я использую, состоит в том, чтобы ввести скрипт после setTimeout(function,0)задержки. Это позволяет 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]);

manifest.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
    }
}
Автор: Makyen Размещён: 15.11.2016 07:35
Вопросы из категории :
32x32