How to use jQuery in Firefox Extension

JavascriptJqueryFirefoxFirefox Addon

Javascript Problem Overview


I want to use jQuery inside a firefox extension, I imported the library in the xul file like this:

<script type="application/x-javascript" src="chrome://myExtension/content/jquery.js"> </script>

but the $() function is not recognized in the xul file neither do the jQuery().

I googled about the problem and found some solutions but no one did work with me: http://gluei.com/blog/view/using-jquery-inside-your-firefox-extension http://forums.mozillazine.org/viewtopic.php?f=19&t=989465

I've also tried to pass the 'content.document' object(which refrences the 'document' object) as the context parameter to the jQuery function like this:

$('img',content.document);

but still not working, does any one came across this problem before?

Javascript Solutions


Solution 1 - Javascript

I use the following example.xul:

<?xml version="1.0"?>
<overlay id="example" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<head></head>
<script type="application/x-javascript" src="jquery.js"></script>
<script type="application/x-javascript" src="example.js"></script>
</overlay>

And here is an example.js

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

    example = new function(){};
    example.log = function() { 
        Firebug.Console.logFormatted(arguments,null,"log"); 
    };
    example.run = function(doc,aEvent) {
        // Check for website
        if (!doc.location.href.match(/^http:\/\/(.*\.)?stackoverflow\.com(\/.*)?$/i))  
            return;

        // Check if already loaded
        if (doc.getElementById("plugin-example")) return;
  
        // Setup
        this.win = aEvent.target.defaultView.wrappedJSObject;
        this.doc = doc;
  
        // Hello World
        this.main = main = $('<div id="plugin-example">').appendTo(doc.body).html('Example Loaded!');
        main.css({ 
            background:'#FFF',color:'#000',position:'absolute',top:0,left:0,padding:8
        });
        main.html(main.html() + ' - jQuery <b>' + $.fn.jquery + '</b>');
    };

    // 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);

})();

Solution 2 - Javascript

The following solution makes it possibile to use jQuery in contentScriptFile (Targetting 1.5 Addon-sdk)

In your main.js:

exports.main = function() {
    var pageMod = require("page-mod");
            
    pageMod.PageMod({
          include: "*",
          contentScriptWhen: 'end',
          contentScriptFile: [data.url("jquery-1.7.1-min.js") , data.url("notifier.js") ,   data.url("message.js")],
          onAttach: function onAttach(worker) {
             //show the message
             worker.postMessage("Hello World");
          }
    });
    
};

In your message.js :

self.on("message", function(message){
    if(message !== "undefined"){
       Notifier.info(message); 
    }
});

Some pitfalls you need to watchs out for:

  • The order of the contentScriptFile array. if message.js would be placed first: jQuery won't be reconized.
  • Do not place a http:// url in the data.url (this does not work)!
  • All your javascript files should be in the data folder. (only main.js should be in lib folder)

Solution 3 - Javascript

There is an excellent article in the mozillaZine forums that describes this step-by-step: http://forums.mozillazine.org/viewtopic.php?f=19&t=2105087

I haven't tried it yet, though so I hesitate to duplicate the info here.

Solution 4 - Javascript

Turns out the current top-answer by @sunsean does not work as expected when it comes to handling multiple loads. The function should properly close over the document and avoid global state.

Also, you have to call jQuery.noConflict(true) to really avoid conflicts with other add-ons!

This is who I would write it (then again, I would avoid jquery (in add-ons) like the plague...). First the overlay XUL

<?xml version="1.0"?>
<overlay id="test-addon-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="text/javascript" src="jquery.js"/>
  <script type="text/javascript" src="overlay.js"/>
</overlay>

And then the overlay script:

// 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.

Solution 5 - Javascript

I think this is what Eric was saying, but you can load Javascript from the URL directly.

javascript:var%20s=document.createElement('script');s.setAttribute('src','http://YOURJAVASCRIPTFILE.js');document.getElementsByTagName('body')[0].appendChild(s);void(s);

Im assuming you want your extension to load JQuery so you can manipulate the page elements easily? My company's labs has something that does this using Javascript directly here: http://parkerfox.co.uk/labs/pixelperfect

Solution 6 - Javascript

It may be bad practice, but have you considered including it inline?

Solution 7 - Javascript

Instead of

$('img',content.document);

you can try

$('img',window.content.document);

In my case it works.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser434917View Question on Stackoverflow
Solution 1 - JavascriptsunseanView Answer on Stackoverflow
Solution 2 - JavascriptDavidView Answer on Stackoverflow
Solution 3 - JavascriptSkrudView Answer on Stackoverflow
Solution 4 - JavascriptnmaierView Answer on Stackoverflow
Solution 5 - JavascriptCraig StanfordView Answer on Stackoverflow
Solution 6 - JavascriptEric WendelinView Answer on Stackoverflow
Solution 7 - JavascriptAlexander LoginovView Answer on Stackoverflow