[英]Access Add-On SDK 'main' from XUL
In my add-on, I'm using XUL to display dialog windows because I can customize their appearance to suit the add-on's general style (like a custom titlebar
). 在我的附加组件中,我使用XUL来显示对话框窗口,因为我可以自定义其外观以适合附加组件的常规样式(例如自定义
titlebar
)。
Using the migration guide , I'm able to do this easily. 使用迁移指南 ,我可以轻松做到这一点。 The thing is, I would like to call certain functions in the add-on's
main
module from the XUL dialog. 问题是,我想从XUL对话框中调用附加组件
main
模块中的某些功能。
After a bit of searching I found the loader
module , which seems to be able to do exactly what I want. 经过一番搜索,我发现了
loader
模块 ,它似乎能够完全满足我的要求。 But, I'm experiencing trouble in using it to access the main
module. 但是,使用它访问
main
模块时遇到麻烦。
First, I tried the obvious approach as mentioned in the documentation; 首先,我尝试了文档中提到的显而易见的方法。
xul_dialog.js : 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');
I got an error that './main'
was not found at resource://<my-addon-name>/root/
. 我在
resource://<my-addon-name>/root/
找不到'./main'
错误。 Figuring that I was using the incorrect paths, I experimented a bit until I could remove all path associated errors. 弄清楚我使用的路径不正确,我做了一些实验,直到可以消除所有与路径相关的错误。
xul_dialog.js : 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');
This time I got a rather confusing error at loader.js, line 279
. 这次,我在
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');
I get the same error when I use Loader.Require(loader, {id: './main'})
instead of Loader.main
. 当我使用
Loader.Require(loader, {id: './main'})
而不是Loader.main
时,出现相同的错误。 I even tried passing Components
as globals
when instantiating the loader, but without much luck. 我什至尝试在实例化加载程序时将
Components
作为globals
传递,但是运气不佳。
I'm fairly certain that I'm doing a lot of things wrong. 我可以肯定我做错了很多事情。 I don't understand why I'm getting the error, even after spending quite a bit of time in
loader.js
. 即使在
loader.js
花了很多时间,我也不明白为什么会出错。 Plus, I also think that there would be a better alternative than having to use the add-on id for the path to main.js
; 另外,我还认为,有一个更好的选择,那就是不必使用附加ID来
main.js
的路径; hard-coding it like that doesn't seem right. 像这样硬编码似乎不正确。
Any help would be really appreciated. 任何帮助将非常感激。
What you have to do is to find a specific instance of Loader
, not create a new one. 您要做的是找到
Loader
的特定实例,而不是创建一个新实例。
At main.js 在main.js
const { id, name, prefixURI } = require("@loader/options");
//pass these to the XUL dialog
At xul.js (or whatever is the name of the xul dialog script) 在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"];
Assuming there is a foo
function at main.js, you can call it like 假设main.js中有一个
foo
函数,您可以像这样调用它
mainjssandbox.foo();
Of course don't expect things to work as if XUL and Add-on SDK actually blended into one thing. 当然,不要指望事情像XUL和Add-on SDK实际上融为一体。
If it is your XUL dialog that should interact with your add-on, then please don't use the Loader
stuff and in particular do not go the XPIProvider.bootstrapScopes
@paa suggested. 如果这是你的 XUL对话框,应与你的附加组件交互,那么请不要使用
Loader
的东西,尤其是不走XPIProvider.bootstrapScopes
@paa建议。 While this might work (for now), it should be noted that it relies on tons of implementation details that are subject to change at any point making this solution extremely fragile. 尽管这可能行得通(暂时),但应注意,它依赖大量的实现细节,这些细节可能随时更改,从而使该解决方案非常脆弱。
Instead there are a couple of other options (not an exhaustive list): 而是有几个其他选项(不是详尽的列表):
.openDialog
which supports passing arguments to the created window, and these arguments can even be objects and functions. .openDialog
,它支持将参数传递给创建的窗口,这些参数甚至可以是对象和函数。 Also, you can have the window dispatch (custom) events, and which your SDK part can listen to by calling addEventListener
on the window
the .openDialog
call returns. .openDialog
调用返回的window
上调用addEventListener
来监听。 AddonManager
because of em:optionsURL
) then the nsIObserverService
is another way to communicate. em:optionsURL
AddonManager
而从AddonManager
创建),则nsIObserverService
是另一种通信方式。 The window could eg .notifyObservers
on DOMContentLoaded
containing a reference to itself. DOMContentLoaded
.notifyObservers
包含对自身的引用。 The SDK parts would just have to observe such notifications by addObserver
. addObserver
观察此类通知。 nsIWindowWatcher.registerNotification
and then injecting some API into eg browser.xul
windows by XPCNativeWrapper.unwrap(subject.QueryInterface(Ci.nsIDOMWindow)).myAddonAPI = something
. nsIWindowWatcher.registerNotification
侦听新窗口,然后通过XPCNativeWrapper.unwrap(subject.QueryInterface(Ci.nsIDOMWindow)).myAddonAPI = something
将一些API注入到browser.xul
窗口中XPCNativeWrapper.unwrap(subject.QueryInterface(Ci.nsIDOMWindow)).myAddonAPI = something
。 Be sure to handle unloading or your add-on well - it is still restartless -, ie reverse any changes you've done and remove any observers and so on again. 确保处理好卸载程序或附加组件-它仍然不会重启-即撤消所做的所有更改并再次删除所有观察者,依此类推。
If you want to interact with SDK addons not created by you, then the XPIProvider
route might be the only feasible. 如果要与您未创建的SDK插件进行交互,则
XPIProvider
路由可能是唯一可行的方法。 But still, it might be worth contacting the add-on author first asking for the addition of some public API instead of hacking deep into the AddonManager and SDK loader internals. 但是,仍然值得联系插件作者首先要求添加一些公共API,而不是深入了解AddonManager和SDK加载器内部。
PS: PS:
Considering passing require
or the global scope to your window via openDialog
if you want to. 如果需要,可以考虑通过
openDialog
将require
或全局范围传递给窗口。 Get the global scope by placing this into your main.js
: 通过将其放入
main.js
获取全局范围:
const globalScope = this;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.