从XUL访问Add-On SDK'main'

时间:2014-06-03 09:43:01

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

在我的附加组件中,我使用XUL来显示对话框窗口,因为我可以自定义它们的外观以适应附加组件的一般样式(如自定义titlebar)。

使用migration guide,我可以轻松完成此操作。问题是,我想在XUL对话框中调用加载项main模块中的某些函数。

经过一番搜索,我找到了loader module,这似乎能够完全符合我的要求。但是,我在使用它访问main模块时遇到了麻烦。

首先,我尝试了文档中提到的显而易见的方法;

xul_dialog.js

let {Loader} = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js');
let loader = Loader.Loader({
    paths: {
        'toolkit/': 'resource://gre/modules/commonjs/toolkit/',
        '': 'resource:///modules/',
        './': 'resource://<my-addon-name>/root/'
    }
});

let main = Loader.main(loader, './main');

我收到'./main'未找到resource://<my-addon-name>/root/的错误消息。确定我使用了不正确的路径,我进行了一些实验,直到我可以删除所有与路径相关的错误。

xul_dialog.js

let {Loader} = Components.utils.import('resource://gre/modules/commonjs/toolkit/loader.js');
let loader = Loader.Loader({
    paths: {
        'toolkit/': 'resource://gre/modules/commonjs/toolkit/',
        '': 'resource://gre/modules/commonjs/',
        './': 'resource://<my-addon-id>-at-jetpack/<my-addon-name>/lib/'
    }
});

let main = Loader.main(loader, './main');

这次我在loader.js, line 279发现了一个相当混乱的错误。

Components is not available in this context.
Functionality provided by Components may be available in an SDK
module: https://jetpack.mozillalabs.com/sdk/latest/docs/

However, if you still need to import Components, you may use the
`chrome` module's properties for shortcuts to Component properties:

Shortcuts:
    Cc = Components.classes
    Ci = Components.interfaces
    Cu = Components.utils
    CC = Components.Constructor
Example:
    let { Cc, Ci } = require('chrome');

使用Loader.Require(loader, {id: './main'})代替Loader.main时出现同样的错误。在实例化加载器时,我甚至尝试将Components传递为globals,但没有太多运气。

我相当肯定我做了很多错事。即使在loader.js中花了相当多的时间,我也不明白为什么我会收到错误。另外,我还认为除了必须使用{-1}}路径的附加ID之外,还有更好的选择;硬编码似乎并不正确。

任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:1)

您需要做的是找到Loader的特定实例,而不是创建新实例。

在main.js

const { id, name, prefixURI } = require("@loader/options");
//pass these to the XUL dialog

在xul.js(或xul对话框脚本的名称)

Components.utils.import("resource://gre/modules/addons/XPIProvider.jsm");
var extensionscope = XPIProvider.bootstrapScopes[id];
var mainjssandbox = extensionscope.loader.sandboxes[prefixURI + name + "/lib/main.js"];

假设main.js上有一个foo函数,你可以像

一样调用它
 mainjssandbox.foo();

当然,不要期望事情能像XUL和附加SDK实际混合成一件事一样。

答案 1 :(得分:1)

如果您的 XUL对话框应与您的插件进行互动,请不要使用Loader内容,特别是不要建议XPIProvider.bootstrapScopes @paa。虽然这可能有效(目前),但应该注意的是,它依赖于大量的实施细节,这些细节在任何时候都会发生变化,使得这个解决方案非常脆弱。

相反,还有其他几个选项(不是详尽的清单):

  • 如果SDK部分打开窗口,您可以使用.openDialog支持将参数传递给创建的窗口,这些参数甚至可以是对象和函数。此外,您可以通过addEventListener window来电回复.openDialog来获取窗口调度(自定义)事件以及SDK部件可以收听的事件。
  • 如果窗口是从其他地方创建的(例如,由于AddonManager来自em:optionsURL),那么nsIObserverService是另一种通信方式。窗口可以是例如.notifyObservers DOMContentLoaded {}包含对自身的引用。 SDK部分只需要通过addObserver观察此类通知。
  • 另一种方式,有点hacky但有效,是SDK部分通过nsIWindowWatcher.registerNotification监听新窗口,然后将一些API注入例如browser.xul的{​​{1}}个窗口。

请务必妥善处理卸货或附加装置 - 它仍然无法重启 - 即撤消您已完成的任何更改并删除任何观察员等等。

如果您想与不是由您创建的SDK插件进行交互,那么XPCNativeWrapper.unwrap(subject.QueryInterface(Ci.nsIDOMWindow)).myAddonAPI = something路由可能是唯一可行的。但是,可能值得联系附加组件的作者,首先要求添加一些公共API,而不是深入攻击AddonManager和SDK加载器内部。

PS:

如果您愿意,可以考虑通过XPIProviderrequire或全局范围传递到您的窗口。将其放入openDialog

,以获取全球范围
main.js