使用Firefox的附加SDK创建动态首选项面板

时间:2014-11-15 19:09:52

标签: javascript html firefox firefox-addon firefox-addon-sdk

我创建了一个简单的Firefox附加组件,每次用户在页面上选择一些文本时,会出现一个带有用户搜索引擎的小弹出窗口,然后您可以单击该搜索引擎搜索网页。它模仿this one或FastestFox的弹出式面板等插件。

该插件默认使用所有用户的搜索引擎,但我想让用户隐藏某些引擎来自我的面板,而不会影响浏览器&# 39;搜索引擎经理。使用SDK simple-prefs,我可以在packages.json中创建设置:int值,按钮(控件),复选框,下拉菜单等。但是,搜索引擎各有不同用户和动态(可以在浏览器中添加或删除它们。)

我在附加组件的首选项菜单中添加了一个按钮:

Example of a simple-prefs button that does *something*

此按钮应打开某个显示所有搜索引擎的窗口,并在每个搜索引擎背后隐藏复选框(在我的弹出窗口中启用/禁用它们)。我想我可以使用simple-storage保存这些额外的设置。但现在我不知道如何从这里开始。

这是Adblock的作用:

Adblock's simple-prefs + button for extra settings window

我还在HTML页面中看到了至少一个附加位置的所有设置。

实际问题:我应该为此创建一个窗口吗? (我应该使用什么API?)或者更好的方法是生成网页并通过HTML和JavaScript处理所有内容? (似乎更难!)

这是我尝试为Firefox开发的第一个插件,我很难在网上查找信息。我的插件中的所有内容都来自Add-on SDK的高级API(无覆盖扩展。没有XUL。)实际上,让所有这些选项让我感到困惑。

2 个答案:

答案 0 :(得分:1)

由于我不想将附加SDK(高级模块)与XUL扩展开发混合,我最终创建了一个在单击“从可用搜索引擎中选择”按钮时触发的功能。此函数创建一个HTML面板(sdk / panel),然后使用可用的搜索引擎填充,在每个面板后面放置一个复选框。还设置了一些事件,以便在单击复选框时,使用sdk / simple-storage模块保存引擎的状态(启用/禁用)。

这是附加选项中的按钮代码(在package.json中):

...
"preferences": [
{
    "name": "selectEnginesButton",
    "title": "Select from available search engines",
    "type": "control",
    "description": "Enable/disable the search engines that show on the popup panel.",
    "label": "Select"
},
...

然后,在main.js中:

var simplePrefs = require('sdk/simple-prefs');
var simpleStorage = require("sdk/simple-storage");

// ...some code for other things here...

if (!simpleStorage.storage.searchEngines) {
    simpleStorage.storage.searchEngines = {};
}

simplePrefs.on("selectEnginesButton", function() {
    createSettingsPanel();
});

function createSettingsPanel()
{
    var visibleEngines = searchService.getVisibleEngines({});
    var engines = visibleEngines.filter(function(engine) { return !engine.hidden; });

    // Create simple objects with engine information to pass to the panel's content script
    // This is because only main.js can work with the search engine objects themselves
    // i.e. the ones in "engines"
    var engineObjects = engines.map(function(engine) {
        var engineObject = {};
        engineObject.name = engine.name;
        engineObject.iconSpec = (engine.iconURI != null ? engine.iconURI.spec : null);
        engineObject.active = isEngineActive(engine);
        return engineObject;
    });

    var pan = panel.Panel({
        contentURL: data.url("engine-settings.html"),
        contentScriptFile: data.url("engine-settings.js"),
        width: 400,
        height: 225
    });

    pan.port.emit('setupPanel', engineObjects);
    pan.port.on("onSearchEngineToggle", onSearchEngineToggle);

    pan.show();
}

function onSearchEngineToggle(engine)
{
    simpleStorage.storage.searchEngines[engine.name] = engine.active;
}

function isEngineActive(engine)
{
    return simpleStorage.storage.searchEngines[engine.name];
}

最后,面板的HTML(engine-settings.html):

<html>
<head>
    <!-- some css and other stuff -->
</head>
<body>
    <div id="title">Select what search engines are shown on the popup panel:</div>
    <div id="engines"></div>
</body>
</html>

...和面板的JavaScript(engine-settings.js):

self.port.on('setupPanel', setupPanel);
self.port.on('logInnerHTML', logInnerHTML);

function setupPanel(engines)
{
    engines.forEach(addEngineToLayout);
}

function addEngineToLayout(engine)
{
    // WARNING: this might not be the best way to populate HTML from js. I'm certainly no expert here :)

    var element = document.createElement("div");
    var description = document.createTextNode(engine.name);
    var checkbox = document.createElement("input");

    checkbox.type = "checkbox";
    checkbox.value = engine.name;
    checkbox.checked = engine.active;

    element.appendChild(checkbox);

    var icon = document.createElement("img");
    // default.png is a png of mine, in case an engine has no icon
    icon.setAttribute("src", (engine.iconSpec != null ? engine.iconSpec : "default.png"));
    element.appendChild(document.createElement("span"));
    element.appendChild(icon);

    element.appendChild(document.createElement("span"));
    element.appendChild(description);

    document.getElementById('engines').appendChild(element);

    checkbox.addEventListener("mouseup", function(e) {
        engine.active = !engine.active;
        self.port.emit('onSearchEngineToggle', engine);
    });
}

当然,这不是一个完美的解决方案,但是当您单击附加组件首选项中的按钮时,您会看到一个简单的面板,显示在其他设置之上。当你在外面按下它时会消失。

请注意,此代码默认情况下已禁用引擎,因为它们不会出现在simpleStorage.storage.searchEngines中。您可以在isEngineActive

中执行此操作来更改此设置
function isEngineActive(engine)
{
    if (!simpleStorage.storage.searchEngines.hasOwnProperty(engine.name)) {
        simpleStorage.storage.searchEngines[engine.name] = true;
    }
    return simpleStorage.storage.searchEngines[engine.name];
}

当从浏览器中删除引擎时,它们仍将永远存在于simpleStorage.storage.searchEngines中。您可以通过在main.js运行时查看其中的所有内容并删除不再存在的引擎来轻松解决此问题。

我希望这有助于某人! :)

答案 1 :(得分:0)

让您的控制按钮具有此oncommand功能:

<setting title="Do Something" type="control">
  <button id="myaddon-button" label="Click Me" oncommand="Services.wm.getMostRecentWindow('navigator:browser').BrowserSearch.searchBar.openManager(event)"/>
</setting>