Javascript 访问附加SDK';主要';来自XUL

Javascript 访问附加SDK';主要';来自XUL,javascript,firefox,firefox-addon,firefox-addon-sdk,Javascript,Firefox,Firefox Addon,Firefox Addon Sdk,在我的加载项中,我使用XUL显示对话框窗口,因为我可以自定义它们的外观以适应加载项的一般样式(如自定义标题栏) 使用,我可以很容易地做到这一点。问题是,我想从XUL对话框调用插件的main模块中的某些函数 经过一点搜索,我找到了,它似乎能够完全做到我想要的。但是,我在使用它访问main模块时遇到了问题 首先,我尝试了文档中提到的显而易见的方法 xul\u dialog.js: let {Loader} = Components.utils.import('resource://gre/modul

在我的加载项中,我使用XUL显示对话框窗口,因为我可以自定义它们的外观以适应加载项的一般样式(如自定义标题栏)

使用,我可以很容易地做到这一点。问题是,我想从XUL对话框调用插件的
main
模块中的某些函数

经过一点搜索,我找到了,它似乎能够完全做到我想要的。但是,我在使用它访问
main
模块时遇到了问题

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

xul\u 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');
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的第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
时,我会遇到同样的错误。在实例化加载程序时,我甚至尝试将
组件
作为
globals
传递,但运气不佳

我相当肯定我做了很多错事。我不明白为什么会出现错误,即使在
loader.js
中花费了相当多的时间。另外,我还认为还有一个更好的选择,那就是不必为
main.js
的路径使用附加id;像那样硬编码似乎不对


非常感谢您的帮助。

您需要做的是查找
加载程序的特定实例,而不是创建新实例

在main.js

const{id,name,prefixURI}=require(“@loader/options”);
//将这些传递给XUL对话框
在xul.js(或xul对话框脚本的名称)

假设main.js上有一个
foo
函数,您可以像这样调用它

 mainjssandbox.foo();

当然,不要期望事情像XUL和Add-on SDK实际上混合在一起一样工作

如果您的XUL对话框应该与您的加载项进行交互,那么请不要使用
加载程序
内容,尤其不要使用
XPIProvider.bootstrapScopes
@paa建议的。虽然这可能会起作用(目前),但应该注意的是,它依赖于大量的实现细节,这些细节在任何时候都可能发生变化,这使得该解决方案极为脆弱

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

  • 如果SDK部件打开窗口,您可以使用
    .openDialog
    ,它支持向创建的窗口传递参数,这些参数甚至可以是对象和函数。此外,您还可以拥有窗口调度(自定义)事件,您的SDK部件可以通过调用
    窗口上的
    addEventListener
    来侦听这些事件
  • 如果窗口是从其他地方创建的(例如,由于
    em:optionsURL
    ,因此从
    AddonManager
    ),则是另一种通信方式。例如,在
    DOMContentLoaded
    上的窗口可以包含对自身的引用。SDK部件只需通过
    addObserver
    观察这些通知即可
  • 另一种方法,有点老套,但很有效,就是SDK部分通过监听新窗口,然后通过
    XPCNativeWrapper.unwrap(subject.QueryInterface(Ci.nsIDOMWindow)).myAddonAPI=something
    将一些API注入例如
    browser.xul
    windows
一定要处理好卸载或您的加载项-它仍然是无重启的-也就是说,反转您所做的任何更改并删除任何观察者,等等

如果您想与非您创建的SDK插件交互,那么
XPIProvider
路由可能是唯一可行的。但是,还是有必要首先联系插件作者,请求添加一些公共API,而不是深入攻击AddonManager和SDK加载程序内部

附言:

如果愿意,可以考虑通过
openDialog
require
或全局范围传递到窗口。通过将其放入您的
main.js
,获取全局范围:

const globalScope = this;

再强调也不为过,我们没有设计这些API来与XUL一起工作,这里是dragons等等@canuckistani@paa我明白,我只需要一种方式让对话框与
main
模块进行通信,该模块将处理其余部分。我想,如果将参数传递给对话框是唯一的方法,那么我最好传递消息接收模块。会更干净。@Rikonator将对
require
的引用正确地传递到您的加载项中,但将您的公共函数导出到
中。或者只需将任何引用传递给
函数
。或者传递全局范围。我认为将对象作为参数传递是最好的方法。但是,我只传递希望对话框能够访问的对象,而不是全局范围。更干净、更安全。
const globalScope = this;