Search code examples
javascriptfirefoxfirefox-addonfirefox-addon-sdk

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).

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.

After a bit of searching I found the loader module, which seems to be able to do exactly what I want. But, I'm experiencing trouble in using it to access the main module.

First, I tried the obvious approach as mentioned in the documentation;

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/. Figuring that I was using the incorrect paths, I experimented a bit until I could remove all path associated errors.

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.

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. I even tried passing Components as globals when instantiating the loader, but without much luck.

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. 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; hard-coding it like that doesn't seem right.

Any help would be really appreciated.


Solution

  • What you have to do is to find a specific instance of Loader, not create a new one.

    At 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)

    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

     mainjssandbox.foo();
    

    Of course don't expect things to work as if XUL and Add-on SDK actually blended into one thing.