Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
3
rated 0 times [  8] [ 5]  / answers: 1 / hits: 6700  / 10 Years ago, sun, june 29, 2014, 12:00:00

Subsequent to removeEventListener in bootstrapped addon not working when addon disabled, I am exploring other possibilities.



Beside using bind() and caching the bound function, is there a way to use 'this' and pass argument?



// works fine but can't pass argeement
contextMenu.addEventListener('popupshowing',
this.contextPopupShowing, false);

// passes the argument but 'this' is no longer available
contextMenu.addEventListener('popupshowing',
function(){this.contextPopupShowing(window);}, false);


I have been using a number of event listeners with bind() and I am looking for alternative methods without using bind()



I even tried to grab window with a recursive function from <menupopup id=contentAreaContextMenu ...>



Update: bind() interferes with removeEventListener


More From » firefox

 Answers
4

Since we're talking restartless add-ons... A lot of restartless add-ons use unload and unloadWindow helper functions, to make it easier to implement shutdown properly and also help with stuff like addEventListener, so bear with me for a bit.



The helpers - unload



First, unload is a helper function that you pass another function to, that will be run upon shutdown (or can be called manually). Most implementations are extremely similar to this:



var unloaders = []; // Keeps track of unloader functions.

function unload(fn) {
if (typeof(fn) != function) {
throw new Error(unloader is not a function);
}
unloaders.push(fn);
return function() {
try {
 fn();
}
catch (ex) {
Cu.reportError(unloader threw + fn.toSource());
Cu.reportError(ex);
}
unloaders = unloaders.filter(function(c) { return c != fn; });
};
}


You'd then hook up shutdown to do the right thing:



function shutdown() {
...
for (let i = unloaders.length - 1; i >= 0; --i) {
try {
unloaders[i]();
}
catch (ex) {
Cu.reportError(unloader threw on shutdown + fn.toSource());
Cu.reportError(ex);
}
}
unloaders.length = 0;
}


Using unload



Now you can do stuff like:



function startup() {
setupSomething();
unload(removeSomething);

setupSomethingElse();
var manualRemove = unload(removeSomethingElse);
...
if (condition) {
manualRemove();
  }
}


The helpers - unloadWindow



You'll usually want to create a second function unloadWindow to unload stuff when either your add-on is shut down or the window gets closed, whatever happens first. Not removing stuff when the window gets closed can be very tricky, and create Zombie compartments of your bootstrap.js and/or code modules very easily (this is from experience writing and reviewing restartless add-ons).



function unloadWindow(window, fn) {
let handler = unload(function() {
window.removeEventListener('unload', handler, false);
try {
fn();
}
catch (ex) {
Cu.reportError(window unloader threw + fn.toSource());
Cu.reportError(ex);
}
});
window.addEventListener('unload', handler, false);
};


(Some people might want to optimize this, as to have only one unload handler, but usually you only have so unloadWindow calls that it won't matter.)



Putting it all together



Now you can .bind stuff and do whatever and let the the unloader closures keep track of it. Also, you can use this to keep your shut down code next to your initialization code, which might increase readability.



function setupWindow(window, document) {
var bound = this.contextPopupShowing.bind(this);
contextMenu.addEventListener('popupshowing', bound, false);
unloadWindow(window, function() {
contextMenu.removeEventListener('popupshowing', bound, false);
});

// Or stuff like
var element = document.createElement(...);
contextMenu.appendChild(element);
unloadWindow(window, function() {
contextMenu.removeChild(element);
});

// Or just combine the above into a single unloader
unloadWindow(window, function() {
contextMenu.removeEventListener('popupshowing', bound, false);
contextMenu.removeChild(element);
});
}

[#44244] Friday, June 27, 2014, 10 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
hadens

Total Points: 142
Total Questions: 98
Total Answers: 100

Location: Kenya
Member since Mon, Jun 14, 2021
3 Years ago
;