Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How best for a Firefox extension to avoid polluting the global namespace?

I've been reading up on global namespace pollution when developing an extension for Firefox, and I want to avoid it as much as possible in my extension. There are several solutions, but generally, the solutions seem to center around only declaring one global variable for your extension, and putting everything in that. Thus you only add one extra variable to the global namespace, which isn't too bad.

As a brief aside, I have had a solution proposed to me that avoids putting any extra variables into the global namespace; wrap everything in a function. The problem here is that there's nothing to refer to in your XUL overlays. You have to declare elements in your overlays, and then in JS add a ton of addEventListeners to replace what would've been something like an oncommand="..." in XUL. I don't want to do this; I definitely want my XUL to include events in the XUL itself because I think it looks cleaner, so this isn't a solution for me. I therefore need at least 1 global variable for XUL oncommand="..." attributes to refer to.

So the consensus seems to be to have one (and only one) variable for your extension, and put all your code inside that. Here's the problem: generally, people recommend that that variable be named a nice long, unique name so as to have almost zero chance of colliding with other variables. So if my extension's ID is [email protected], I could name my variable myextensionAtMycompanyDotCom, or com.mycompany.myextension. This is good for avoiding collisions in the global namespace, but there's one problem; that variable name is long and unwieldy. My XUL is going to be littered with references to event handlers along the lines of oncommand="myextensionAtMycompanyDotCom.doSomeEvent". There's no way to avoid having to refer to the global namespace in my XUL overlays, because an overlay just gets added to the browser window's DOM; it doesn't have a namespace of its own, so we can't somehow limit our extension's variable scope only to our own overlays. So, as I see it, there are four solutions:

1. Just use the long variable name in XUL

This results in rather unwieldy, verbose XUL code like:

<statusbarpanel id="myStatusBar" onmousedown="myextensionAtMycompanyDotCom.onMyStatusBarClick();">

2. Add an element of randomness to a short variable name

We come up with a much nicer short variable name for our extension, let's say myExt, and add some random characters on to make it almost certainly unique, such as myExtAX8T9. Then in the XUL, we have:

<statusbarpanel id="myStatusBar" onmousedown="myExtAX8T9.onMyStatusBarClick();">

Clearly, this results in rather ugly and even confusing code as the random characters look odd, and make it look like some kind of temporary variable.

3. Don't declare any global variables at all

You could just wrap up everything in functions. This, of course, means that there is nothing to refer to in your XUL, and so every event must be attached to the XUL elements using addEventListener in your JavaScript code. I don't like this solution because, as mentioned above, I think it's cleaner to have the events referenced in the XUL code rather than having to search a ton of JS code to find which events are attached to which XUL elements.

4. Just use a short variable name in XUL

I could just call my extension's variable myExt, and then I get nice XUL code like:

<statusbarpanel id="myStatusBar" onmousedown="myExt.onMyStatusBarClick();">

Of course, this short name is much more likely to clash with something else in the global namespace and so isn't ideal.

So, have I missed something? Is there any alternative to the 4 solutions I proposed above? If not, what would be the best of the 4 (given that #3 is basically unacceptable to me), and why?

like image 526
Jez Avatar asked Jul 13 '11 09:07

Jez


2 Answers

We use the JavaScript module pattern described in this blog post: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth. You can export the symbols that you want to use in your XUL handlers as described.

In addition, we use a reversed host name as the module name prefix to ensure that we control the namespace:

/* Set up the global namespace. */
if (typeof(com) == "undefined") var com = {};
if (!com.salsitasoft) com.salsitasoft = {};

/* Main namespace. */
com.salsitasoft.myExtensionGlobalStuffGoesHere = (function (my) {
  return my;
})(com.salsitasoft.myExtensionGlobalStuffGoesHere || {});

Update: I changed this to pass com.salsitasoft.myExtensionGlobalStuffGoesHere into the closure if it already exists so that the namespace can be spread across multiple files.

like image 111
Matthew Gertner Avatar answered Sep 19 '22 14:09

Matthew Gertner


Your functions have to "live" somewhere either way, so you cannot avoid to claim some kind of namespace. I also agree to your point that defining the event in the XUL is better than attaching them. So, I propose a hybrid between 3+4:

  • Find a namespace that is unique for your plugin yet as catchy as possible, for example "catchyseo".
  • Place all the code of your plugin and all variables inside this namespace. Use the anonymous function wrapper pattern like (have a look at some jQuery plugins as code examples):

    window.catchyseo = (function(){var private = x; [...] })();
    
  • In your namespace, expose some event handlers which you can reference in your XUL.

This approach gives you the best of two worlds: you can define your events in XUL and you have a closed namespace without any global namespace pollution - except your one namespace variable.

like image 21
Steffen Müller Avatar answered Sep 19 '22 14:09

Steffen Müller