Reputation: 150
This is my first attempt at writing a Firefox add-on.
I'm trying to read a text file that is contained in an Firefox Add-on I'm writing.
I'm following the example from MDN
let decoder = new TextDecoder(); // This decoder can be reused for several reads
let array = OS.File.read("file.txt"); // Read the complete file as an array
let text = decoder.decode(array); // Convert this array to a text
In my main.js
I have the following snippet of code :
Components.utils.import("resource://gre/modules/osfile.jsm");
var pathFile = OS.Path.join("_locales", "en", "messages.json");
let decoder = new TextDecoder('utf-8');
let promise = OS.File.read(pathFile);
promise = promise.then(
function onSuccess(array) {
return decoder.decode(array);
},
function onReject(array) {
console.log("onReject read: ");
}
);
When I run the add-on using the cfx run
command, I get the following error:
Message: ReferenceError: TextDecoder is not defined
I'm currently using Firefox 30, and the Firefox Add-on SDK 1.16.
Should I not use OS.File
in main.js
in an add-on?
Should I use FileUtils
instead, i.e. Components.utils.import("resource://gre/modules/FileUtils.jsm");
?
Upvotes: 2
Views: 1846
Reputation: 33162
First of all, you linked the OS.File
for Workers-docs. You don't use it in a worker (no new Worker
anywhere), but the main thread, so you'll instead want to refer to OS.File
for the main thread-docs.
SDK modules unfortunately don't get TextEncoder
/TextDecoder
automatically right now.
As @erikvold suggests, you could:
const { Buffer, TextEncoder, TextDecoder } = require('sdk/io/buffer');
or even get it from osfile.jsm
directly:
const { Cc, Ci, Cu } = require("chrome");
const { OS, TextEncoder, TextDecoder } = Cu.import("resource://gre/modules/osfile.jsm", {});
Now back to your original question:
In general OS.File
can be used in SDK add-ons and is a good way to read/write arbitrary file in the file system.
However OS.File
, FileUtils
, sdk/io/...
are not suited for reading files in your add-on, because usually those files won't be located directly in the user's file system, but instead be located within the installed XPI file (which is merely a zip file) and these APIs allow you to read files verbatim, but don't parse the container zip files (XPI) for you.
You have a couple of options, though:
l10n
module exactly for this purpose.data/
folder of your add-on can also be read with self.data.load()
, but you still need to decode/parse the data. XMLHttpRequest
, which the SDK makes available in the net/xhr
module. As an added bonus, you can have the XHR
object decode and/or parse the file for you by setting an appropriate .responseType
value.Constructing the URI for XHR
is easy if the file to read is located in the data/
folder of your add-on, e.g.
cont self = require("sdk/self");
var uri = self.data.url("en/messages.json");
// would map to data/en/messages.json
Otherwise, there isn't really an official, supported way to get URIs, but e.g. the following will work for lib/
(at the moment, but might fail in the future).
cont self = require("sdk/self");
var uri = self.data.url("../lib/main.js");
// would map to data/../lib/main.js -> lib/main.js
Placing your own files somewhere else is tricky, as the SDK will only package certain paths when building the XPI; in general lib/
, data/
, locale/
(see l10n
), chrome/
(see XUL Migration Guide)
Here is a minimal example using XHR
(but remember that for localization there is the l10n
module already):
const self = require("sdk/self");
const { XMLHttpRequest } = require("sdk/net/xhr");
// Assume data/some.json is:
// {"abc":123}
var req = new XMLHttpRequest();
req.onload = function() {
// req.response is an object containing the parsed JSON.
console.log(req.response.abc); // 123
};
req.open("GET", self.data.url("some.json"));
req.responseType = "json";
req.send();
PS: When working with OS.File
in particular and promises in general, consider using Task.jsm
which can make it much easier to write and re-read (maintain) code.
Upvotes: 3
Reputation: 16508
Try
const { Buffer, TextEncoder, TextDecoder } = require('sdk/io/buffer');
const { OS } = require("resource://gre/modules/osfile.jsm");
var pathFile = OS.Path.join("_locales", "en", "messages.json");
let decoder = new TextDecoder('utf-8');
let promise = OS.File.read(pathFile);
promise = promise.then(function onSuccess(array) {
return decoder.decode(array);
}, function onReject(array) {
console.log("onReject read: ");
});
Upvotes: 2