mozilla
Your Search Results

    Modifying Web Pages Based on URL

    To follow this tutorial you'll need to have installed the SDK and learned the basics of cfx.

    To modify any pages that match a particular pattern (for example, "http://example.org/") as they are loaded, use the page-mod module.

    To create a page-mod you need to specify two things:

    • one or more scripts to run. Because their job is to interact with web content, these scripts are called content scripts.
    • one or more patterns to match the URLs for the pages you want to modify

    Here's a simple example. The content script is supplied as the contentScript option, and the URL pattern is given as the include option:

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScript: 'document.body.innerHTML = ' +
                     ' "<h1>Page matches ruleset</h1>";'
    });
    

    Try it out:

    • create a new directory and navigate to it
    • run cfx init
    • open the lib/main.js file, and add the code above
    • run cfx run
    • open ietf.org in the browser window that opens

    This is what you should see:

    Specifying the Match Pattern

    The match pattern uses the match-pattern syntax. You can pass a single match-pattern string, or an array.

    Keeping the Content Script in a Separate File

    In the example above we've passed in the content script as a string. Unless the script is extremely simple, you should instead maintain the script as a separate file. This makes the code easier to maintain, debug, and review.

    To do this, you need to:

    • save the script in your add-on's data directory
    • use the contentScriptFile option instead of contentScript, and pass it the URL for the script. The URL can be obtained using self.data.url("my-script.js"). From Firefox 34 onwards you can just use "./my-script.js" instead

    For example, if we save the script above under the add-on's data directory in a file called my-script.js:

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
    // Import the self API
    var self = require("sdk/self");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScriptFile: self.data.url("my-script.js")
    });

    Or from Firefox 34 onwards:

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScriptFile: "./my-script.js"
    });

    Loading Multiple Content Scripts

    You can load more than one script, and the scripts can interact directly with each other. So, for example, you could rewrite my-script.js to use jQuery:

    $("body").html("<h1>Page matches ruleset</h1>");
    

    Then download jQuery to your add-on's data directory, and load the script and jQuery together (making sure to load jQuery first):

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
    // Import the self API
    var self = require("sdk/self");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScriptFile: [self.data.url("jquery-1.7.min.js"), self.data.url("my-script.js")]
    });
    

    You can use both contentScript and contentScriptFile in the same page-mod: if you do this, scripts loaded using contentScriptFile are loaded first:

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
    // Import the self API
    var self = require("sdk/self");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScriptFile: self.data.url("jquery-1.7.min.js"),
      contentScript: '$("body").html("<h1>Page matches ruleset</h1>");'
    });
    

    Note, though, that you can't load a script from a web site. The script must be loaded from data.

    Communicating With the Content Script

    Your add-on script and the content script can't directly access each other's variables or call each other's functions, but they can send each other messages.

    To send a message from one side to the other, the sender calls port.emit() and the receiver listens using port.on().

    • In the content script, port is a property of the global self object.
    • In the add-on script, you need to listen for the onAttach event to get passed a worker object that contains port.

    Let's rewrite the example above to pass a message from the add-on to the content script. The message will contain the new content to insert into the document. The content script now needs to look like this:

    // "self" is a global object in content scripts
    // Listen for a message, and replace the document's
    // contents with the message payload.
    self.port.on("replacePage", function(message) {
      document.body.innerHTML = "<h1>" + message + "</h1>";
    });
    

    In the add-on script, we'll send the content script a message inside onAttach:

    // Import the page-mod API
    var pageMod = require("sdk/page-mod");
    // Import the self API
    var self = require("sdk/self");
     
    // Create a page mod
    // It will run a script whenever a ".org" URL is loaded
    // The script replaces the page contents with a message
    pageMod.PageMod({
      include: "*.org",
      contentScriptFile: self.data.url("my-script.js"),
      // Send the content script a message inside onAttach
      onAttach: function(worker) {
        worker.port.emit("replacePage", "Page matches ruleset");
      }
    });
    

    The replacePage message isn't a built-in message: it's a message defined by the add-on in the port.emit() call.

    Injecting CSS

    Note that the feature described in this section is experimental at the moment: we'll very probably continue to support the feature, but details of the API might need to change.

    Rather than injecting JavaScript into a page, you can inject CSS by setting the page-mod's contentStyle option:

    var pageMod = require("sdk/page-mod").PageMod({
      include: "*",
      contentStyle: "body {" +
                    "  border: 5px solid green;" +
                    "}"
    });
    

    As with contentScript, there's a corresponding contentStyleFile option that's given the URL of a CSS file in your "data" directory, and it is good practice to use this option in preference to contentStyle if the CSS is at all complex:

    var pageMod = require("sdk/page-mod").PageMod({
      include: "*",
      contentStyleFile: require("sdk/self").data.url("my-style.css")
    });
    

    Or, from Firefox 34, you can use the simpler version:

    var pageMod = require("sdk/page-mod").PageMod({
      include: "*",
      contentStyleFile: "./my-style.css"
    });

    Learning More

    To learn more about page-mod, see its API reference page. In particular, the PageMod constructor takes several additional options to control its behavior:

    • By default, content scripts are not attached to any tabs that are already open when the page-mod is created, and are attached to iframes as well as top-level documents. To control this behavior use the attachTo option.

    • Define read-only values accessible to content scripts using the contentScriptOptions option.

    • By default, content scripts are attached after all the content (DOM, JS, CSS, images) for the page has been loaded, at the time the window.onload event fires. To control this behavior use the contentScriptWhen option.

    To learn more about content scripts in general, see the content scripts guide.

    Document Tags and Contributors

    Tags: 
    Contributors to this page: Canuckistani, wbamberg, hvrauhal, groovecoder, Delapouite
    Last updated by: hvrauhal,
    Hide Sidebar