Страница настроек Firefox WebExtension

У меня есть страница настроек на моем WebExtension, но я не знаю, как получить доступ к значениям настроек с помощью javascript.

Current .xul-File:

<?xml version="1.0"?>
<!DOCTYPE mydialog SYSTEM "chrome://myaddon/locale/mydialog.dtd">

<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <setting type="string" pref="extensions.check.email" title="email" desc="please insert your email here" />
</vbox>

Как мне получить значение "электронная почта"? Могу ли я просто написать что-то вроде "getPreferences('email')"?

1 ответов


не используйте XUL в надстройке WebExtension:
Если вы используете XUL из WebExtension, то что-то, вероятно, неправильно. Если вы пишете WebExtension, и вы начинаете делать XUL:сделать шаг назад. Убедитесь, что это действительно что вы должны делать. Одним из пунктов WebExtensions является то, что он изолирует надстройку от внутренних компонентов Firefox (т. е. от XUL).

панель настроек и страницы:
В общем случае параметры должны храниться в хранения.местные (или хранения.синхронизация, если поддерживается). Если вы пытаетесь связаться со страницы параметров или панели обратно в основной фоновый скрипт, есть, по крайней мере, 4 несколько разных способа сделать это:

  1. параметры сохраняются в хранения.местные на параметры.js код. Фоновый код прослушивает события из storage.onChanged. Нет нужно передавать сообщения туда и обратно. Нет необходимости для ваших опций/кода панели специально уведомлять фоновую страницу о произошедших изменениях.
  2. параметры сохраняются в хранения.местные на параметры.js код. Затем параметры.js непосредственно вызывает функцию a в фоновом скрипте, чтобы фоновый скрипт перечитал параметры. В приведенном ниже коде это непосредственно вызывается параметры.js код.
  3. параметры сохраняются в хранения.местные на параметры.js код. Использовать chrome.runtime.sendMessage() чтобы отправить сообщение в фоновую страницу, что параметры изменились. В приведенном ниже коде: после хранения параметров в storage.local на параметры.js передает optionsUpdated сообщение фоновому скрипту о том, что параметры были обновлены. Затем фоновый сценарий перечитывает опции. [Сообщение может быть любым, что вы хотите, что указывает на это. optionsUpdated это просто то, что я выбрал в качестве сообщения в коде ниже.]
  4. использовать chrome.runtime.sendMessage() чтобы отправить сообщение со всеми данными параметров на фоновую страницу. В коде внизу:optionsData сообщение отправлено параметры.js код на фоновой странице, когда параметры изменяются, который содержит data полезная нагрузка со всеми параметрами. Параметры сохраняются в хранилище.local in фоновый сценарий. После сохранения параметров фоновый скрипт отправляет optionsStored сообщение параметры.js код. The параметры.js код указывает пользователю, что параметры были сохранены. [Сообщение может быть любым, что вы хотите, что указывает на это. optionsData и optionsStored это просто то, что я выбрал в качестве сообщения в коде ниже.]

Ниже приведен WebExtension, который демонстрирует эти четыре различных метода получения измененные данные обратно на фоне сценария.

Примечание: код ниже использует browser_action кнопка для вызова панели с теми же параметрами, что и для options_ui. Это делается с целью демонстрации. Если у вас будет кнопка, которая открывает ваши параметры, возможно, лучше сразу открыть ваш options_ui страница runtime.openOptionsPage(). Что вы делаете, зависит от пользовательского интерфейса, который вы хотите представить пользователь.

фон.js:

var useDirect=0; //Holds the state of how we communicate with options.js
var emailAddress=''; //The email address from options.
const useDirectTypes=[ 'Listen to chrome.storage changes'
                      ,'Directly invoke functions in the background script from'
                          + ' the options/panel code'
                      ,'Send a message that data in storage.local was updated'
                      ,'Send a message with all options data' ];


//Register the message listener 
chrome.runtime.onMessage.addListener(receiveMessage);

function receiveMessage(message,sender,sendResponse){
    //Receives a message that must be an object with a property 'type'.
    //  This format is imposed because in a larger extension we may
    //  be using messages for multiple purposes. Having the 'type'
    //  provides a defined way for other parts of the extension to
    //  both indicate the purpose of the message and send arbitrary
    //  data (other properties in the object).
    console.log('Received message: ',message);
    if(typeof message !== 'object' || !message.hasOwnProperty('type')){
        //Message does not have the format we have imposed for our use.
        //Message is not one we understand.
        return;
    }
    if(message.type === "optionsUpdated"){
        //The options have been updated and stored by options.js.
        //Re-read all options.
        getOptions();
    }
    if(message.type === "optionsData"){
        saveOptionsSentAsData(message.data,function(){
            //Callback function executed once data is stored in storage.local
            console.log('Sending response back to options page/panel');
            //Send a message back to options.js that the data has been stored.
            sendResponse({type:'optionsStored'});
            //Re-read all options.
            getOptions();
        });
        //Return true to leave the message channel open so we can 
        //  asynchronously send a message back to options.js that the
        //  data has actually been stored.
        return true;
    }
}

function detectStorageChange(change){
    //Ignore the change information. Just re-get all options
    console.log('Background.js: Detected storage change');
    getOptions();
}

function listenToStorageChanges(){
    chrome.storage.onChanged.addListener(detectStorageChange);
}

function stopListeningToStorageChanges(){
    chrome.storage.onChanged.removeListener(detectStorageChange);
}

function getOptions(){
    //Options are normally in storage.sync (sync'ed across the profile).
    //This example is using storage.local.
    //Firefox does not currently support storage.sync.
    chrome.storage.local.get({
        useDirect: 0,
        emailAddress: ''
    }, function(items) {
        if(typeof items.useDirect !== 'number' || items.useDirect <0
            || items.useDirect >= useDirectTypes.length) {
            items.useDirect=0;
        }
        useDirect = items.useDirect;
        emailAddress = items.emailAddress;
        console.log('useDirect=' + useDirectTypes[useDirect]);
        console.log('email address=' + emailAddress);
    });
}

function saveOptionsSentAsData(data,callback) {
    //Options data received as a message from options.js is 
    //  stored in storeage.local.
    chrome.storage.local.set(data, function() {
        //Invoke a callback function if we were passed one.
        if(typeof callback === 'function'){
            callback();
        }
    });
}

//Read the options stored from prior runs of the extension.
getOptions();

//On Firefox, open the Browser Console:
//To determine if this is Chrome, multiple methods which are not implemented
//  in Firefox are checked. Multiple ones are used as Firefox will eventually 
//  support more APIs.
var isChrome = !! window.InstallTrigger
               || (!!chrome.extension.setUpdateUrlData
               && !!chrome.runtime.reload
               && !!chrome.runtime.restart);
if(!isChrome) {
    //In Firefox cause the Browser Console to open by using alert()
    window.alert('Open the console. isChrome=' + isChrome);
}

параметры.js:

// Saves options to chrome.storage.local.
// It is recommended by Google that options be saved to chrome.storage.sync.
// Firefox does not yet support storage.sync.
function saveOptions(data, callback) {
    chrome.storage.local.set(data, function() {
        if(typeof callback === 'function'){
            callback();
        }
        // Update status to let user know options were saved.
        notifyOptionsSaved();
    });
}

function optionsChanged() {
    //Get the selected option values from the DOM
    let useDirectValue = document.getElementById('useDirect').value;
    let email = document.getElementById('email').value;
    useDirectValue = +useDirectValue; //Force to number, not string
    //Put all the option data in a single object
    let optionData = {
        useDirect: useDirectValue,
        emailAddress: email
    }
    setBackgroundPageNotListeningToStorageChanges();
    if(useDirectValue == 0 ) {
        //Use listening to storage changes
        //console.log('Going to listen for storage changes');
        setBackgroundPageListeningToStorageChanges();
        saveOptions(optionData);
    } else if (useDirectValue == 1) {
        //We save the options in the options page, or popup
        saveOptions(optionData, function(){
            //After the save is complete:
            //The getOptions() functon already exists to retrieve options from
            //  storage.local upon startup of the extension. It is easiest to use that.
            //  We could remove and add the listener here, but that code already
            //  exists in background.js. There is no reason to duplicate the code here.
            let backgroundPage = chrome.extension.getBackgroundPage();
            backgroundPage.getOptions();
        });
    } else if (useDirectValue == 2) {
        //We save the options in the options page, or popup
        saveOptions(optionData, function(){
            //Send a message to background.js that options in storage.local were updated.
            chrome.runtime.sendMessage({type:'optionsUpdated'});
        });
    } else {
        //Send all the options data to background.js and let it be dealt with there.
        chrome.runtime.sendMessage({
            type:'optionsData',
            data: optionData
        }, function(message){
            //Get a message back that may indicate we have stored the data.
            if(typeof message === 'object' && message.hasOwnProperty('type')){
                if(message.type === 'optionsStored') {
                    //The message received back indicated the option data has
                    //  been stored by background.js.
                    //Notify the user that the options have been saved.
                    notifyOptionsSaved();
                }
            }
        });
    }
}

function setBackgroundPageListeningToStorageChanges(){
    //Normally the listener would be set up once, and only once, within the
    //  background page script.  We are doing it here to demonstrate switing
    //  between the different methods of notification.
    let backgroundPage = chrome.extension.getBackgroundPage();
    //either add the listener directly:
    chrome.storage.onChanged.addListener(backgroundPage.detectStorageChange);
    //or let the background page add it:
    //backgroundPage.listenToStorageChanges();
}

function setBackgroundPageNotListeningToStorageChanges(){
    //Normally the listener would be set up once, and only once, within the
    //  background page script.  We are doing it here to demonstrate switing
    //  between the different methods of notification.
    let backgroundPage = chrome.extension.getBackgroundPage();
    //either remove the listener directly:
    chrome.storage.onChanged.removeListener(backgroundPage.detectStorageChange);
    //or let the background page add it:
    //backgroundPage.stopListeningToStorageChanges();
}

// Restores select box and input using the preferences
// stored in chrome.storage.
function useStoredOptionsForDisplayInDOM() {
    chrome.storage.local.get({
        useDirect: 0,
        emailAddress: ''
    }, function(items) {
        //Store retrieved options as the selected values in the DOM
        document.getElementById('useDirect').value = items.useDirect;
        document.getElementById('email').value = items.emailAddress;
    });
    //notifyStatusChange('Option read');
}

function notifyOptionsSaved(callback){
    //Notify the user that the options have been saved
    notifyStatusChange('Options saved.',callback);
}

function notifyStatusChange(newStatus,callback){
    let status = document.getElementById('status');
    status.textContent = newStatus;
    //Clear the notification after a second
    setTimeout(function() {
        status.textContent = '';
        if(typeof callback === 'function'){
            callback();
        }
    }, 1000);
}

document.addEventListener('DOMContentLoaded', useStoredOptionsForDisplayInDOM);
document.getElementById('optionsArea').addEventListener('change',optionsChanged);
//In order to track the change if this is open in _both_ the browser_action panel
//  and the add-on options page, we need to listen for changes to storage.
//  There is already a function which reads all of the options, so don't
//  use the information as to what changed, just that a change occurred.
chrome.storage.onChanged.addListener(useStoredOptionsForDisplayInDOM);

параметры.HTML-код:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>WebRequest Logging Options</title>
    <style>
        body: { padding: 10px; }
    </style>
</head>

<body>
    <div id="optionsArea">
        Communication with background page:
        <select id="useDirect">
            <option value="0">Listen for storage changes</option>
            <option value="1">Directly call background page functions</option>
            <option value="2">Send a Message Updated storage.local</option>
            <option value="3">Send a Message with all Data</option>
        </select>
        <div>Email:
            <input id="email"></input>
        </div>
    </div>
    <div id="status" style="top:0px;display:inline-block;"></div>

    <script src="options.js"></script>
</body>
</html>

манифест.в JSON:

{
    "description": "Demonstrate an email field in options with various ways of communicating with the background script.",
    "manifest_version": 2,
    "name": "email-in-options-demo",
    "version": "0.1",

    "applications": {
        "gecko": {
            //Firefox: must define id to use option_ui:
            "id": "email-in-options-demo@example.example",
            "strict_min_version": "48.0"
        }
    },

    "permissions": [
        "storage"
    ],

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

    "browser_action": {
        "default_icon": {
            "48": "myIcon.png"
        },
        "default_title": "Show panel",
        "browser_style": true,
        "default_popup": "options.html"
    },

    "options_ui": {
      "page": "options.html",
      "chrome_style": true
    }
}

код выше основан на коде в моем ответе на обновление WebExtension webRequest.настройки URL прослушивателя onBeforeRequest из отдельного скрипта.