2
votes

I would like to ask you how can I expose function to webpage content using addon. I have installed jpm tool (new cfm on node.js) to make package.

So I have to use Cu.exportFunction, ok it works, but then when adding content, unsafeWindow, window or anything as context jpm run throw error undefined. Full message: ReferenceError: unsafeWindow is not defined Sorry for basic question, but there are three ways to make addon, several classes, sdk and really scary amount of documentation, of which the most is deprecated or not working.

I want to give save to file access from website, without user interaction.

Target Firefox is 38+, platform windows, usage only local. I do not really care about security issues, it is my own computer, my script and script will be used locally by my coworker.

For some time I have been using enablePrivileged code, than workarounds, zipjs, php local server and so on. Workers solution from mdn does not work for me (simply similar errors and if it would work I'd rather use something without overhead).

Codes from Mozillas github are not working (lot of errors).

What am I doing step by step? Installed node.js (the newest version two days ago), installed jpm (also two days ago). jpm init Then copy pasted snippet to save canvas and export function. jpm run. That is everything. For two days I was trying to make it work, googled for answers, searched MDN and SO. Nothing.

How should it work? I am generating over 200 plots on canvas (code is irrelevant) based on given preferences and data, and then I want all canvas saved in directory. I gave names for each canvas, filetype is png. And when canvas is generated I would like to execute saveCanvas snipet, give it name and go further.

Workarounds like PHP, zip or else gives more than 2GB RAM overhead and several minutes to process. Sometimes it goes out of memory.

I do not want to make XUL extension to interact, add flash or another technologies. Simply save canvas using addon.

I am looking only for solution how to make this snippet work.

Thanks in advance.

//https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Canvas
function saveCanvas(canvas, path, type, options) {
    return Task.spawn(function *() {
        var reader = new FileReader;
        var blob = yield new Promise(accept => canvas.toBlob(accept, type, options));
        reader.readAsArrayBuffer(blob);

        yield new Promise(accept => { reader.onloadend = accept });

        return yield OS.File.writeAtomic(path, new Uint8Array(reader.result), { tmpPath: path + '.tmp' });
    });
}
let { Cu } = require('chrome');
    Cu.exportFunction(saveCanvas, unsafeWindow, {defineAs: "saveCanvas"});

Maybe there are better ways to apply it?

1
Easy, use Cu.exportFunction :) developer.mozilla.org/en-US/docs/… awesome work btw! - Noitidart
I am using this part, context given is not working - unsafeWindow is undefined. Also these codes are from MDN not mine. - Evil
exportFunction was used here check it out: github.com/IntelLabs/RiverTrail/blob/master/extension/lib/… - Noitidart

1 Answers

3
votes

Thank you Noitidart for good link, it helped with injecting the function.

If somebody knows better solution please do share, but for now this code works.

It saves PNG file from given canvas and file name on desktop directory without tmp file.

const { Cc, Ci, Cu } = require('chrome');
const { OS } = Cu.import("resource://gre/modules/osfile.jsm");
const { Task } = Cu.import("resource://gre/modules/Task.jsm");

function saveCanvas(canvas, name) {
    var path = OS.Path.join(OS.Constants.Path.desktopDir, name);
    return Task.spawn(function *() {
        var reader = Cc['@mozilla.org/files/filereader;1'].createInstance(Ci.nsIDOMFileReader);
        var blob = yield new Promise(accept => canvas.toBlob(accept));
        reader.readAsArrayBuffer(blob);
        yield new Promise(accept => { reader.onloadend = accept });
        return yield OS.File.writeAtomic(path, new Uint8Array(reader.result));
    });
}

function expose(event) {
    Cu.exportFunction(saveCanvas, event.subject, {defineAs: "saveCanvas"});
}

exports.main = function(options, callbacks) {
    var events = require("sdk/system/events");
    events.on("content-document-global-created", expose);
};