Majid Laissi
Majid Laissi

Reputation: 19788

Tab independent jQuery on Firefox extension

I'm developping a Firefox based on jQuery as described in this Answer here.

After implementing the example provided in the answer, eveything works fine, but the problem is the code between Firefox Tabs is somehow linked, and example.doc always refers to the last opened tab.

How can I make my code independent between tabs?

Here is an excrept from the code:

(function() {
    jQuery.noConflict();
    $ = function(selector,context) { 
        return new jQuery.fn.init(selector,context||example.doc); 
    };
    $.fn = $.prototype = jQuery.fn;

    example = new function(){};

    example.run = function(doc,aEvent) {
        if (doc.getElementById("plugin-example")) return;
        this.doc = doc;
        this.main = main = $('<div id="plugin-example">').appendTo(doc.body).html('Example Loaded!');
        this.main.click(function() { //<--- added this function
                example.main.html(example.doc.location.href);
        });
        main.css({ 
            background:'#FFF',color:'#000',position:'absolute',top:0,left:0,padding:8
        });
    };
    // Bind Plugin
    var delay = function(aEvent) { 
        var doc = aEvent.originalTarget; setTimeout(function() { 
            example.run(doc,aEvent); 
        }, 1); 
     };
    var load = function() { 
        gBrowser.addEventListener("DOMContentLoaded", delay, true); 
    };
    window.addEventListener("pageshow", load, false);

})();

Upvotes: 0

Views: 199

Answers (1)

nmaier
nmaier

Reputation: 33162

Your code (overlay script) will only run once per window, not once per tab. So there is only one example instance per window. And hence example.doc will be set to whatever dispatched DOMContentLoaded last.

Your function should properly close over the document and avoid global state. This is who I would write it (then again, I would avoid jquery (in add-ons) like the plague...)

// Use strict mode in particular to avoid implicitly var declarations
(function() {
  "use strict";

  // Main runner function for each content window.
  // Similar to SDK page-mod, but without the security boundaries.
  function run(window, document) {
    // jquery setup. per https://stackoverflow.com/a/496970/484441
    $ = function(selector,context) {
      return new jq.fn.init(selector,context || document); 
    };
    $.fn = $.prototype = jq.fn;

    if (document.getElementById("my-example-addon-container"))  {
      return;
    }
    let main = $('<div id="my-example-addon-container">');
    main.appendTo(document.body).text('Example Loaded!');
    main.click(function() { //<--- added this function
      main.text(document.location.href);
    });
    main.css({
      background:'#FFF',color:'#000',position:'absolute',top:0,left:0,padding:8
    });
  };

  const log = Components.utils.reportError.bind(Components.utils);

  // Do not conflict with other add-ons using jquery.
  const jq = jQuery.noConflict(true);

  gBrowser.addEventListener("DOMContentLoaded", function load(evt) {
    try {
      // Call run with this == window ;)
      let doc = evt.target.ownerDocument || evt.target;
      if (!doc.location.href.startsWith("http")) {
        // Do not even attempt to interact with non-http(s)? sites.
        return;
      }
      run.call(doc.defaultView, doc.defaultView, doc);
    }
    catch (ex) {
      log(ex);
    }
  }, true);
})();

Here is a complete add-on as a gist. Just drop in a copy of jquery and it should be good to go.

PS: Reposted this at in the jquery in extensions question

Upvotes: 2

Related Questions