Using OOP in firefox extension
-
14-04-2021 - |
Question
I'm using classic OOP code from Mozilla
var myExtension = {
init: function() {
// The event can be DOMContentLoaded, pageshow, pagehide, <b style="color:black;background-color:#99ff99">load</b> or unload.
if(gBrowser) gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad, false);
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
alert("<b style="color:black;background-color:#a0ffff">page</b> is loaded \n" +doc.location.href);
//OOPs, error here, username is undefined
Firefox.Console.log(this.userName);
},
anotherMethod: function (){
this.userName = 'UserName';
}
}
window.addEventListener("<b style="color:black;background-color:#99ff99">load</b>", function() { myExtension.init(); }, false);
The general question is how can initialize and user public variables in my class?
You know, this in this class is some browser's object (tab), but not a current class and I can't assign this.win = doc.defaultView
and use later like this.win.userName = 'UserName'
Solution
A couple of options:
Using Function#bind
:
I believe in a Firefox extension you should have most if not all ES5 features available to you, which means you can use Function#bind
to make sure your event handler gets called with this
set to your instance. E.g.:
if (gBrowser) {
gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad.bind(this), false);
}
Within the call to onPageLoad
, this
will refer to your instance. You won't have access to the normal this
Firefox gives the event handler (the tab or whatever).
Fuller example of the bind
option:
var myExtension = {
init: function() {
// The event can be DOMContentLoaded, pageshow, pagehide, <b style="color:black;background-color:#99ff99">load</b> or unload.
if(gBrowser) {
gBrowser.addEventListener("DOMContentLoaded", this.onPageLoad.bind(this), false);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
alert("<b style="color:black;background-color:#a0ffff">page</b> is loaded \n" +doc.location.href);
// This now works
Firefox.Console.log(this.userName);
// ...but you don't have access to the `this` that the browser gave
// the event handler (the tab or whatever)
},
anotherMethod: function (){
this.userName = 'UserName';
}
}
window.addEventListener("<b style="color:black;background-color:#99ff99">load</b>", function() { myExtension.init(); }, false);
Using a closure:
If I'm mistaken about ES5 in Firefox extensions, or if you want to have access to the this
that the event handler would normally receive, you can readily use a closure to do the same thing:
var self = this;
if (gBrowser) {
gBrowser.addEventListener("DOMContentLoaded", function(event) {
// Here, `self` refers to your instance, and `this` to the
// element, so for instance you can call your `onPageLoad`
// and pass it the element as a second argument:
return self.onPageLoad(event, this);
// Within the call to `onPageLoad`, `this` will be your instance
}, false);
}
(If "closure" is a new term to you, don't worry, closures are not complicated.)
Fuller example of the closure option:
var myExtension = {
init: function() {
var self = this;
// The event can be DOMContentLoaded, pageshow, pagehide, <b style="color:black;background-color:#99ff99">load</b> or unload.
if(gBrowser) {
gBrowser.addEventListener("DOMContentLoaded", function(event) {
return self.onPageLoad(event, this);
}, false);
}
},
onPageLoad: function(aEvent, aElement) {
var doc = aEvent.originalTarget; // doc is document that triggered the event
var win = doc.defaultView; // win is the window for the doc
alert("<b style="color:black;background-color:#a0ffff">page</b> is loaded \n" +doc.location.href);
// This now works
Firefox.Console.log(this.userName);
// If you needed the `this` that Firefox gives the event handler
// (the tab or whatever), it's accessible via `aElement`
},
anotherMethod: function (){
this.userName = 'UserName';
}
}
window.addEventListener("<b style="color:black;background-color:#99ff99">load</b>", function() { myExtension.init(); }, false);
OTHER TIPS
You might be hung up a little too much on using "this." Make your global variables properties of MyExtension and refer to variables by their full names rather than using "this," which can be ambiguous. For example:
var myExtension = {
username : '',
email : '',
init : function() {
if ((app = document.getElementById("appcontent"))) {
app.addEventListener("DOMContentLoaded", myExtension.run, true);
}
},
run : function(event) {
...
},
anotherMethod : function() {
// same as your example: this.username = 'Username';
myExtension.username = 'Username';
}
};