page-mod

  • Revision slug: Mozilla/Add-ons/SDK/High-Level_APIs/page-mod
  • Revision title: page-mod
  • Revision id: 510051
  • Created:
  • Creator: wbamberg
  • Is current revision? No
  • Comment

Revision Content

Stable

Run scripts in the context of web pages whose URL matches a given pattern.

Usage

To use page-mod, you specify:

  • one or more scripts to attach. The SDK calls these scripts "content scripts".
  • a pattern that a page's URL must match, in order for the script(s) to be attached to that page.

For example, the following add-on displays an alert whenever the user visits any page hosted at "mozilla.org":

var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScript: 'window.alert("Page matches ruleset");'
});

You can modify the document in your script:

var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScript: 'document.body.innerHTML = ' +
                 ' "<h1>Page matches ruleset</h1>";'
});

You can supply the content script(s) in one of two ways:

  • as a string literal, or an array of string literals, assigned to the contentScript option, as above
  • as separate files supplied in your add-on's "data" directory. In this case files are specified by a URL typically constructed using the url() method of the self module's data object:
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: data.url("my-script.js")
});
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: [data.url("jquery-1.7.min.js"),
                      data.url("my-script.js")]
});

Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

A page-mod only attaches scripts to documents loaded in tabs. It will not attach scripts to add-on panels, page-workers, widgets, or Firefox hidden windows.

To stop a page-mod from making any more modifications, call its destroy() method.

The PageMod constructor takes a number of other options to control its behavior, all documented in detail in the API Reference section below:

  • contentStyle or contentStyleFile list stylesheets to attach.
  • contentScriptOptions defines read-only values accessible to content scripts.
  • attachTo controls whether to attach scripts to tabs that were already open when the page-mod was created, and whether to attach scripts to iframes as well as the topmost document.
  • contentScriptWhen controls the point during document load at which content scripts are attached.

For all the details on content scripts, see the guide to content scripts.

Communicating With Content Scripts

Your add-on's "main.js" can't directly access the state of content scripts you load, but you can communicate between your add-on and its content scripts by exchanging messages.

To do this, you'll need to listen to the page-mod's attach event. This event is triggered every time the page-mod's content script is attached to a document. The listener is passed a worker object that your add-on can use to send and receive messages.

For example, the following add-on retrieves the HTML content of specific tags from documents that match the pattern. The main add-on code sends the desired tag to the content script, and the content script replies by sending the HTML content of all the elements with that tag.

/lib/main.js:

var tag = "p";
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: data.url("element-getter.js"),
  onAttach: function(worker) {
    worker.port.emit("getElements", tag);
    worker.port.on("gotElement", function(elementContent) {
      console.log(elementContent);
    });
  }
});

/data/element-getter.js:

self.port.on("getElements", function(tag) {
  var elements = document.getElementsByTagName(tag);
  for (var i = 0; i < elements.length; i++) {
    self.port.emit("gotElement", elements[i].innerHTML);
  }
});

When the user loads a document hosted at "mozilla.org":

  • The content script "element-getter.js" is attached to the document and runs. It adds a listener to the getElements message.
  • The attach event is sent to the "main.js" code. Its event handler sends the getElements message to the content script, and then adds a listener to the gotElement message.
  • The content script receives the getElements message, retrieves all elements of that type, and for each element sends a gotElement message containing the element's innerHTML.
  • The "main.js" code receives each gotElement message and logs the contents.

If multiple documents that match the page-mod's include pattern are loaded, then each document is loaded into its own execution context with its own copy of the content scripts. In this case the listener assigned to onAttach is called once for each loaded document, and the add-on code will have a separate worker for each document.

To learn much more about communicating with content scripts, see the guide to content scripts and in particular the chapter on communicating using port.

Mapping Workers to Tabs

The worker has a tab property which returns the tab associated with this worker. You can use this to access the tabs API for the tab associated with a specific document:

var pageMod = require("sdk/page-mod");
var tabs = require("sdk/tabs");

pageMod.PageMod({
  include: ["*"],
  onAttach: function onAttach(worker) {
    console.log(worker.tab.title);
  }
});

Destroying Workers

Workers generate a detach event when their associated document is closed: that is, when the tab is closed or the tab's location changes. If you are maintaining a list of workers belonging to a page-mod, you can use this event to remove workers that are no longer valid.

For example, if you maintain a list of workers attached to a page-mod:

var workers = [];

var pageMod = require("sdk/page-mod").PageMod({
  include: ['*'],
  contentScriptWhen: 'ready',
  contentScriptFile: data.url('pagemod.js'),
  onAttach: function(worker) {
    workers.push(worker);
  }
});

You can remove workers when they are no longer valid by listening to detach:

var workers = [];

function detachWorker(worker, workerArray) {
  var index = workerArray.indexOf(worker);
  if(index != -1) {
    workerArray.splice(index, 1);
  }
}

var pageMod = require("sdk/page-mod").PageMod({
  include: ['*'],
  contentScriptWhen: 'ready',
  contentScriptFile: data.url('pagemod.js'),
  onAttach: function(worker) {
    workers.push(worker);
    worker.on('detach', function () {
      detachWorker(this, workers);
    });
  }
});

Attaching Content Scripts to Tabs

We've seen that the page-mod API attaches content scripts to documents based on their URL. Sometimes, though, we don't care about the URL: we just want to execute a script on demand in the context of a particular tab.

For example, we might want to run a script in the context of the currently active tab when the user clicks a widget: to block certain content, to change the font style, or to display the document's DOM structure.

Using the attach method of the tab object, you can attach a set of content scripts to a particular tab. The scripts are executed immediately.

The following add-on creates a widget which, when clicked, highlights all the div elements in the document loaded into the active tab:

var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");

var widget = widgets.Widget({
  id: "div-show",
  label: "Show divs",
  contentURL: "http://www.mozilla.org/favicon.ico",
  onClick: function() {
    tabs.activeTab.attach({
      contentScript:
        'var divs = document.getElementsByTagName("div");' +
        'for (var i = 0; i < divs.length; ++i) {' +
          'divs[i].setAttribute("style", "border: solid red 1px;");' +
        '}'
    });
  }
});

Private Windows

If your add-on has not opted into private browsing, then your page-mods will not attach content scripts to documents loaded into private windows, even if their URLs match the pattern you have specified.

To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the documentation for the private-browsing module.

Globals

Constructors

PageMod(options)

Creates a page-mod.

Parameters

options : object
Required options:

Name Type  
include string,array

A match pattern string or an array of match pattern strings. These define the documents to which the page-mod applies. At least one match pattern must be supplied.

You can specify a URL exactly:

  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: "http://www.iana.org/domains/example/",
    contentScript: 'window.alert("Page matches ruleset");'
  });

You can specify a number of wildcard forms, for example:

  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: "*.mozilla.org",
    contentScript: 'window.alert("Page matches ruleset");'
  });

You can specify a set of URLs using a regular expression. The pattern must match the entire URL, not just a subset, and has global, ignoreCase, and multiline disabled.

  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: /.*developer.*/,
    contentScript: 'window.alert("Page matches ruleset");'
  });

To specify multiple patterns, pass an array of match patterns:

var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: ["*.developer.mozilla.org", "*.addons.mozilla.org"],
  contentScript: 'window.alert("Page matches ruleset");'
});

See the match-pattern module for a detailed description of match pattern syntax.

Optional options:

Name Type  
contentScriptFile string,array

This option specifies one or more content scripts to attach to targeted documents.

Each script is supplied as a separate file under your add-on's "data" directory, and is specified by a URL typically constructed using the url() method of the self module's data object.

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

To attach multiple scripts, pass an array of URLs.

var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*",
  contentScriptFile: [self.data.url("jquery-1.7.min.js"),
                      self.data.url("my-script.js")]
});

Content scripts specified using this option are loaded before those specified by the contentScript option.

contentScript string,array

This option specifies one or more content scripts to attach to targeted documents. Each script is supplied directly as a single string:

    var pageMod = require("sdk/page-mod");
    pageMod.PageMod({
      include: "*",
      contentScript: 'window.alert("Page matches ruleset");'
    });

To attach multiple scripts, supply an array of strings.

Content scripts specified by this option are loaded after those specified by the contentScriptFile option.

Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.

Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review.

contentScriptWhen string

By default, content scripts are attached after all the content (DOM, JS, CSS, images) for the document has been loaded, at the time the window.onload event fires. Using this option you can customize this behavior.

The option takes a single string that may take any one of the following values:

  • "start": load content scripts immediately after the document element is inserted into the DOM, but before the DOM content itself has been loaded
  • "ready": load content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event
  • "end": the default. Load content scripts once all the content (DOM, JS, CSS, images) has been loaded, at the time the window.onload event fires
   var pageMod = require("sdk/page-mod");
   pageMod.PageMod({
     include: "*",
     contentScript: 'window.alert("Page matches ruleset");',
     contentScriptWhen: "start"
   });

If you specify "start" for contentScriptWhen, your scripts will not be able to interact with the document's DOM right away (although they could listen for window.onload or DOMContentLoaded themselves).

contentScriptOptions object

You can use this option to define some read-only values for your content scripts.

The option consists of an object literal listing name:value pairs for the values you want to provide to the content script. For example:

var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: "*",
  contentScriptFile: data.url("my-script.js"),
  contentScriptOptions: {
    showOptions: true,
    someNumbers: [1, 2],
    greeting: "Hello!"
  }
});

The values are accessible to content scripts via the self.options property:

// my-script.js
if (self.options.showOptions) {
  window.alert(self.options.greeting);
  window.alert(self.options.someNumbers[0] + self.options.someNumbers[1]);
}

The values can be any JSON-serializable value: a string, number, boolean, null, array of JSON-serializable values, or an object whose property values are themselves JSON-serializable. This means you can't send functions, and if the object contains methods they won't be usable. You also can't pass cyclic values.

contentStyleFile string,array

Use this option to load one or more stylesheets into the targeted documents as user stylesheets.

Each stylesheet is supplied as a separate file under your add-on's "data" directory, and is specified by a URL typically constructed using the url() method of the self module's data object. To add multiple stylesheet files, pass an array of URLs.

var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.org",
  contentStyleFile: data.url("my-page-mod.css")
});

Content styles specified by this option are loaded before those specified by the contentStyle option.

You can't currently use relative URLs in stylesheets loaded in this way. For example, consider a CSS file that references an external file like this:

background: rgb(249, 249, 249) url('../../img/my-background.png') repeat-x top center;

If you attach this file using contentStyleFile, "my-background.png" will not be found.

As a workaround for this, you can build an absolute URL to a file in your "data" directory, and construct a contentStyle option embedding that URL in your rule. For example:

var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod").PageMod({
  include: "*",
  contentStyleFile: data.url("my-style.css"),
  // contentStyle is built dynamically here to include an absolute URL
  // for the file referenced by this CSS rule.
  // This workaround is needed because we can't use relative URLs
  // in contentStyleFile or contentStyle.
  contentStyle: "h1 { background: url(" + data.url("my-pic.jpg") + ")}"
});

This add-on uses a separate file "my-style.css", loaded using contentStyleFile, for all CSS rules except those that reference an external file. For the rule that needs to refer to "my-pic.jpg", which is stored in the add-on's "data" directory, it uses contentStyle.

Dynamically constructing code strings like those assigned to contentScript or contentStyle is usually considered an unsafe practice that may cause an add-on to fail AMO review. In this case it is safe, and should be allowed, but including a comment like that in the example above will help to prevent any misunderstanding.

contentStyle string,array

Use this option to load one or more stylesheet rules into the targeted documents.

Each stylesheet rule is supplied as a separate string. To supply multiple rules, pass an array of strings:

var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.org",
  contentStyle: [
    "div { padding: 10px; border: 1px solid silver}",
    "img { display: none}"
  ]
});

Content styles specified by this option are loaded after those specified by the contentStyleFile option.

attachTo string,array

If this option is not specified, content scripts:

  • are not attached to any tabs that are already open when the page-mod is created.
  • are attached to all documents whose URL matches the rule: so if your rule matches a specific hostname and path, and the topmost document that satisfies the rule includes ten iframes using a relative URL, then your page-mod is applied eleven times.

You can modify this behavior using the attachTo option.

It accepts the following values:

  • "existing": the page-mod will be automatically applied on already opened tabs.
  • "top": the page-mod will be applied to top-level tab documents
  • "frame": the page-mod will be applied to all iframes inside tab documents

If the option is set at all, you must set at least one of "top" and "frame".

For example, the following page-mod will be attached to already opened tabs, but not to any iframes:

   var pageMod = require("sdk/page-mod");
   pageMod.PageMod({
     include: "*",
     contentScript: "",
     attachTo: ["existing", "top"],
     onAttach: function(worker) {
       console.log("attached to: " + worker.tab.url);
     }
   });
onAttach function

Assign a listener function to this option to listen to the page-mod's attach event. See the documentation for attach and Communicating With Content Scripts.

PageMod

A page-mod object. Once created a page-mod will execute the supplied content scripts, and load any supplied stylesheets, in the context of any documents matching the pattern specified by the include property.

Methods

destroy()

Stops the page-mod from making any more modifications. Once destroyed the page-mod can no longer be used.

Modifications already made to open documents by content scripts will not be undone, but stylesheets added by contentStyle or contentStyleFile, will be unregistered immediately.

Properties

include

A list of match pattern strings. These define the documents to which the page-mod applies. See the documentation of the include option above for details of include syntax. Rules can be added to the list by calling its add method and removed by calling its remove method.

Events

attach

This event is emitted when the page-mod's content scripts are attached to a document whose URL matches the page-mod's include pattern.

The listener function is passed a worker object that you can use to communicate with the content scripts your page-mod has loaded into this particular document.

The attach event is triggered every time this page-mod's content scripts are attached to a document. So if the user loads several documents which match this page-mod's include pattern, attach will be triggered for each document, each time with a distinct worker instance.

Each worker then represents a channel of communication with the set of content scripts loaded by this particular page-mod into that particular document.

Arguments

Worker : The listener function is passed a Worker object that can be used to communicate with any content scripts attached to this document.

error

This event is emitted when an uncaught runtime error occurs in one of the page-mod's content scripts.

Arguments

Error : Listeners are passed a single argument, the Error object.

Revision Source

<div class="note">
 <p>Stable</p>
</div>
<p><span class="seoSummary">Run scripts in the context of web pages whose URL matches a given pattern.</span></p>
<h2 id="Usage">Usage</h2>
<p>To use page-mod, you specify:</p>
<ul>
 <li>one or more scripts to attach. The SDK calls these scripts "content scripts".</li>
 <li>a pattern that a page's URL must match, in order for the script(s) to be attached to that page.</li>
</ul>
<p>For example, the following add-on displays an alert whenever the user visits any page hosted at "mozilla.org":</p>
<pre class="brush: js">
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScript: 'window.alert("Page matches ruleset");'
});</pre>
<p>You can modify the document in your script:</p>
<pre class="brush: js">
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScript: 'document.body.innerHTML = ' +
                 ' "&lt;h1&gt;Page matches ruleset&lt;/h1&gt;";'
});</pre>
<p>You can supply the content script(s) in one of two ways:</p>
<ul>
 <li>as a string literal, or an array of string literals, assigned to the <code>contentScript</code> option, as above</li>
 <li>as separate files supplied in your add-on's "data" directory. In this case files are specified by a URL typically constructed using the <code>url()</code> method of the <a href="/en-US/Add-ons/SDK/High-Level_APIs/self#data"><code>self</code> module's <code>data</code> object</a>:</li>
</ul>
<!-- -->
<pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: data.url("my-script.js")
});</pre>
<!-- -->
<pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: [data.url("jquery-1.7.min.js"),
                      data.url("my-script.js")]
});</pre>
<div class="warning">
 <p>Unless your content script is extremely simple and consists only of a static string, don't use <code>contentScript</code>: if you do, you may have problems getting your add-on approved on AMO.</p>
 <p>Instead, keep the script in a separate file and load it using <code>contentScriptFile</code>. This makes your code easier to maintain, secure, debug and review.</p>
</div>
<p>A page-mod only attaches scripts to documents loaded in tabs. It will not attach scripts to add-on panels, page-workers, widgets, or Firefox hidden windows.</p>
<p>To stop a page-mod from making any more modifications, call its <code>destroy()</code> method.</p>
<p>The <code>PageMod</code> constructor takes a number of other options to control its behavior, all documented in detail in the <a href="modules/sdk/page-mod.html#API Reference">API Reference</a> section below:</p>
<ul>
 <li><code>contentStyle</code> or <code>contentStyleFile</code> list stylesheets to attach.</li>
 <li><code>contentScriptOptions</code> defines read-only values accessible to content scripts.</li>
 <li><code>attachTo</code> controls whether to attach scripts to tabs that were already open when the page-mod was created, and whether to attach scripts to iframes as well as the topmost document.</li>
 <li><code>contentScriptWhen</code> controls the point during document load at which content scripts are attached.</li>
</ul>
<p>For all the details on content scripts, see the <a href="dev-guide/guides/content-scripts/index.html">guide to content scripts</a>.</p>
<h3 id="Communicating_With_Content_Scripts">Communicating With Content Scripts</h3>
<p>Your add-on's "main.js" can't directly access the state of content scripts you load, but you can communicate between your add-on and its content scripts by exchanging messages.</p>
<p>To do this, you'll need to listen to the page-mod's <code>attach</code> event. This event is triggered every time the page-mod's content script is attached to a document. The listener is passed a <a href="modules/sdk/content/worker.html"><code>worker</code></a> object that your add-on can use to send and receive messages.</p>
<p>For example, the following add-on retrieves the HTML content of specific tags from documents that match the pattern. The main add-on code sends the desired tag to the content script, and the content script replies by sending the HTML content of all the elements with that tag.</p>
<p>/lib/main.js:</p>
<pre class="brush: js">
var tag = "p";
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.mozilla.org",
  contentScriptFile: data.url("element-getter.js"),
  onAttach: function(worker) {
    worker.port.emit("getElements", tag);
    worker.port.on("gotElement", function(elementContent) {
      console.log(elementContent);
    });
  }
});</pre>
<p>/data/element-getter.js:</p>
<pre class="brush: js">
self.port.on("getElements", function(tag) {
  var elements = document.getElementsByTagName(tag);
  for (var i = 0; i &lt; elements.length; i++) {
    self.port.emit("gotElement", elements[i].innerHTML);
  }
});</pre>
<p>When the user loads a document hosted at "mozilla.org":</p>
<ul>
 <li>The content script "element-getter.js" is attached to the document and runs. It adds a listener to the <code>getElements</code> message.</li>
 <li>The <code>attach</code> event is sent to the "main.js" code. Its event handler sends the <code>getElements</code> message to the content script, and then adds a listener to the <code>gotElement</code> message.</li>
 <li>The content script receives the <code>getElements</code> message, retrieves all elements of that type, and for each element sends a <code>gotElement</code> message containing the element's <code>innerHTML</code>.</li>
 <li>The "main.js" code receives each <code>gotElement</code> message and logs the contents.</li>
</ul>
<p><img alt="" src="https://mdn.mozillademos.org/files/6593/page-mod-messaging.png" style="width: 422px; height: 191px; display: block; margin-left: auto; margin-right: auto;" />If multiple documents that match the page-mod's <code>include</code> pattern are loaded, then each document is loaded into its own execution context with its own copy of the content scripts. In this case the listener assigned to <code>onAttach</code> is called once for each loaded document, and the add-on code will have a separate worker for each document.</p>
<p>To learn much more about communicating with content scripts, see the <a href="dev-guide/guides/content-scripts/index.html">guide to content scripts</a> and in particular the chapter on <a href="dev-guide/guides/content-scripts/using-port.html">communicating using <code>port</code></a>.</p>
<h3 id="Mapping_Workers_to_Tabs">Mapping Workers to Tabs</h3>
<p>The <code>worker</code> has a <code>tab</code> property which returns the tab associated with this worker. You can use this to access the <a href="modules/sdk/tabs.html"><code>tabs API</code></a> for the tab associated with a specific document:</p>
<pre class="brush: js">
var pageMod = require("sdk/page-mod");
var tabs = require("sdk/tabs");

pageMod.PageMod({
  include: ["*"],
  onAttach: function onAttach(worker) {
    console.log(worker.tab.title);
  }
});</pre>
<h3 id="Destroying_Workers">Destroying Workers</h3>
<p>Workers generate a <code>detach</code> event when their associated document is closed: that is, when the tab is closed or the tab's location changes. If you are maintaining a list of workers belonging to a page-mod, you can use this event to remove workers that are no longer valid.</p>
<p>For example, if you maintain a list of workers attached to a page-mod:</p>
<pre class="brush: js">
var workers = [];

var pageMod = require("sdk/page-mod").PageMod({
  include: ['*'],
  contentScriptWhen: 'ready',
  contentScriptFile: data.url('pagemod.js'),
  onAttach: function(worker) {
    workers.push(worker);
  }
});</pre>
<p>You can remove workers when they are no longer valid by listening to <code>detach</code>:</p>
<pre class="brush: js">
var workers = [];

function detachWorker(worker, workerArray) {
  var index = workerArray.indexOf(worker);
  if(index != -1) {
    workerArray.splice(index, 1);
  }
}

var pageMod = require("sdk/page-mod").PageMod({
  include: ['*'],
  contentScriptWhen: 'ready',
  contentScriptFile: data.url('pagemod.js'),
  onAttach: function(worker) {
    workers.push(worker);
    worker.on('detach', function () {
      detachWorker(this, workers);
    });
  }
});</pre>
<h3 id="Attaching_Content_Scripts_to_Tabs">Attaching Content Scripts to Tabs</h3>
<p>We've seen that the page-mod API attaches content scripts to documents based on their URL. Sometimes, though, we don't care about the URL: we just want to execute a script on demand in the context of a particular tab.</p>
<p>For example, we might want to run a script in the context of the currently active tab when the user clicks a widget: to block certain content, to change the font style, or to display the document's DOM structure.</p>
<p>Using the <code>attach</code> method of the <a href="modules/sdk/tabs.html"><code>tab</code></a> object, you can attach a set of content scripts to a particular tab. The scripts are executed immediately.</p>
<p>The following add-on creates a widget which, when clicked, highlights all the <code>div</code> elements in the document loaded into the active tab:</p>
<pre class="brush: js">
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");

var widget = widgets.Widget({
  id: "div-show",
  label: "Show divs",
  contentURL: "http://www.mozilla.org/favicon.ico",
  onClick: function() {
    tabs.activeTab.attach({
      contentScript:
        'var divs = document.getElementsByTagName("div");' +
        'for (var i = 0; i &lt; divs.length; ++i) {' +
          'divs[i].setAttribute("style", "border: solid red 1px;");' +
        '}'
    });
  }
});</pre>
<h3 id="Private_Windows">Private Windows</h3>
<p>If your add-on has not opted into private browsing, then your page-mods will not attach content scripts to documents loaded into private windows, even if their URLs match the pattern you have specified.</p>
<p>To learn more about private windows, how to opt into private browsing, and how to support private browsing, refer to the <a href="modules/sdk/private-browsing.html">documentation for the <code>private-browsing</code> module</a>.</p>
<h2 id="Globals">Globals</h2>
<h3 id="Constructors">Constructors</h3>
<h4 class="addon-sdk-api-name" id="PageMod(options)"><code>PageMod(options)</code></h4>
<p>Creates a page-mod.</p>
<h5 id="Parameters">Parameters</h5>
<p><strong>options : object</strong><br />
 Required options:</p>
<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Name</th>
   <th scope="col">Type</th>
   <th scope="col">&nbsp;</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>include</td>
   <td>string,array</td>
   <td>
    <p>A match pattern string or an array of match pattern strings. These define the documents to which the page-mod applies. At least one match pattern must be supplied.</p>
    <p>You can specify a URL exactly:</p>
    <pre class="brush: js">
  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: "http://www.iana.org/domains/example/",
    contentScript: 'window.alert("Page matches ruleset");'
  });</pre>
    <p>You can specify a number of wildcard forms, for example:</p>
    <pre class="brush: js">
  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: "*.mozilla.org",
    contentScript: 'window.alert("Page matches ruleset");'
  });</pre>
    <p>You can specify a set of URLs using a <a href="modules/sdk/util/match-pattern.html#Regular Expressions">regular expression</a>. The pattern must match the entire URL, not just a subset, and has <code>global</code>, <code>ignoreCase</code>, and <code>multiline</code> disabled.</p>
    <pre class="brush: js">
  var pageMod = require("sdk/page-mod");
  pageMod.PageMod({
    include: /.*developer.*/,
    contentScript: 'window.alert("Page matches ruleset");'
  });</pre>
    <p>To specify multiple patterns, pass an array of match patterns:</p>
    <pre class="brush: js">
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: ["*.developer.mozilla.org", "*.addons.mozilla.org"],
  contentScript: 'window.alert("Page matches ruleset");'
});</pre>
    <p>See the <a href="modules/sdk/util/match-pattern.html">match-pattern</a> module for a detailed description of match pattern syntax.</p>
   </td>
  </tr>
 </tbody>
</table>
<p>Optional options:</p>
<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">Name</th>
   <th scope="col">Type</th>
   <th scope="col">&nbsp;</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>contentScriptFile</td>
   <td>string,array</td>
   <td>
    <p>This option specifies one or more content scripts to attach to targeted documents.</p>
    <p>Each script is supplied as a separate file under your add-on's "data" directory, and is specified by a URL typically constructed using the <code>url()</code> method of the <a href="modules/sdk/self.html#data"><code>self</code> module's <code>data</code> object</a>.</p>
    <pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: "*",
  contentScriptFile: data.url("my-script.js")
});</pre>
    <p>To attach multiple scripts, pass an array of URLs.</p>
    <pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*",
  contentScriptFile: [self.data.url("jquery-1.7.min.js"),
                      self.data.url("my-script.js")]
});</pre>
    <p>Content scripts specified using this option are loaded before those specified by the <code>contentScript</code> option.</p>
   </td>
  </tr>
  <tr>
   <td>contentScript</td>
   <td>string,array</td>
   <td>
    <p>This option specifies one or more content scripts to attach to targeted documents. Each script is supplied directly as a single string:</p>
    <pre class="brush: js">
    var pageMod = require("sdk/page-mod");
    pageMod.PageMod({
      include: "*",
      contentScript: 'window.alert("Page matches ruleset");'
    });</pre>
    <p>To attach multiple scripts, supply an array of strings.</p>
    <p>Content scripts specified by this option are loaded after those specified by the <code>contentScriptFile</code> option.</p>
    <div class="warning">
     <p>Unless your content script is extremely simple and consists only of a static string, don't use <code>contentScript</code>: if you do, you may have problems getting your add-on approved on AMO.</p>
     <p>Instead, keep the script in a separate file and load it using <code>contentScriptFile</code>. This makes your code easier to maintain, secure, debug and review.</p>
    </div>
   </td>
  </tr>
  <tr>
   <td>contentScriptWhen</td>
   <td>string</td>
   <td>
    <p>By default, content scripts are attached after all the content (DOM, JS, CSS, images) for the document has been loaded, at the time the <a href="https://developer.mozilla.org/en/DOM/window.onload">window.onload event</a> fires. Using this option you can customize this behavior.</p>
    <p>The option takes a single string that may take any one of the following values:</p>
    <ul>
     <li><code>"start"</code>: load content scripts immediately after the document element is inserted into the DOM, but before the DOM content itself has been loaded</li>
     <li><code>"ready"</code>: load content scripts once DOM content has been loaded, corresponding to the <a href="https://developer.mozilla.org/en/Gecko-Specific_DOM_Events">DOMContentLoaded</a> event</li>
     <li><code>"end"</code>: the default. Load content scripts once all the content (DOM, JS, CSS, images) has been loaded, at the time the <a href="https://developer.mozilla.org/en/DOM/window.onload">window.onload event</a> fires</li>
    </ul>
    <!-- -->
    <pre class="brush: js">
   var pageMod = require("sdk/page-mod");
   pageMod.PageMod({
     include: "*",
     contentScript: 'window.alert("Page matches ruleset");',
     contentScriptWhen: "start"
   });</pre>
    <p>If you specify <code>"start"</code> for <code>contentScriptWhen</code>, your scripts will not be able to interact with the document's DOM right away (although they could listen for <code>window.onload</code> or <code>DOMContentLoaded</code> themselves).</p>
   </td>
  </tr>
  <tr>
   <td>contentScriptOptions</td>
   <td>object</td>
   <td>
    <p>You can use this option to define some read-only values for your content scripts.</p>
    <p>The option consists of an object literal listing <code>name:value</code> pairs for the values you want to provide to the content script. For example:</p>
    <pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
  include: "*",
  contentScriptFile: data.url("my-script.js"),
  contentScriptOptions: {
    showOptions: true,
    someNumbers: [1, 2],
    greeting: "Hello!"
  }
});</pre>
    <p>The values are accessible to content scripts via the <code>self.options</code> property:</p>
    <pre class="brush: js">
// my-script.js
if (self.options.showOptions) {
  window.alert(self.options.greeting);
  window.alert(self.options.someNumbers[0] + self.options.someNumbers[1]);
}</pre>
    <p>The values can be any JSON-serializable value: a string, number, boolean, null, array of JSON-serializable values, or an object whose property values are themselves JSON-serializable. This means you can't send functions, and if the object contains methods they won't be usable. You also can't pass cyclic values.</p>
   </td>
  </tr>
  <tr>
   <td>contentStyleFile</td>
   <td>string,array</td>
   <td>
    <p>Use this option to load one or more stylesheets into the targeted documents as <a href="https://developer.mozilla.org/en/CSS/Getting_Started/Cascading_and_inheritance">user stylesheets</a>.</p>
    <p>Each stylesheet is supplied as a separate file under your add-on's "data" directory, and is specified by a URL typically constructed using the <code>url()</code> method of the <a href="modules/sdk/self.html#data"><code>self</code> module's <code>data</code> object</a>. To add multiple stylesheet files, pass an array of URLs.</p>
    <pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.org",
  contentStyleFile: data.url("my-page-mod.css")
});</pre>
    <p>Content styles specified by this option are loaded before those specified by the <code>contentStyle</code> option.</p>
    <p>You can't currently use relative URLs in stylesheets loaded in this way. For example, consider a CSS file that references an external file like this:</p>
    <pre>
<code><code class="brush: css">background: rgb(249, 249, 249) url('../../img/my-background.png') repeat-x top center;</code></code></pre>
    <p>If you attach this file using <code>contentStyleFile</code>, "my-background.png" will not be found.</p>
    <p>As a workaround for this, you can build an absolute URL to a file in your "data" directory, and construct a <code>contentStyle</code> option embedding that URL in your rule. For example:</p>
    <pre class="brush: js">
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod").PageMod({
  include: "*",
  contentStyleFile: data.url("my-style.css"),
  // contentStyle is built dynamically here to include an absolute URL
  // for the file referenced by this CSS rule.
  // This workaround is needed because we can't use relative URLs
  // in contentStyleFile or contentStyle.
  contentStyle: "h1 { background: url(" + data.url("my-pic.jpg") + ")}"
});</pre>
    <p>This add-on uses a separate file "my-style.css", loaded using <code>contentStyleFile</code>, for all CSS rules except those that reference an external file. For the rule that needs to refer to "my-pic.jpg", which is stored in the add-on's "data" directory, it uses <code>contentStyle</code>.</p>
    <p>Dynamically constructing code strings like those assigned to <code>contentScript</code> or <code>contentStyle</code> is usually considered an unsafe practice that may cause an add-on to fail AMO review. In this case it is safe, and should be allowed, but including a comment like that in the example above will help to prevent any misunderstanding.</p>
   </td>
  </tr>
  <tr>
   <td>contentStyle</td>
   <td>string,array</td>
   <td>
    <p>Use this option to load one or more stylesheet rules into the targeted documents.</p>
    <p>Each stylesheet rule is supplied as a separate string. To supply multiple rules, pass an array of strings:</p>
    <pre class="brush: js">
var pageMod = require("sdk/page-mod");

pageMod.PageMod({
  include: "*.org",
  contentStyle: [
    "div { padding: 10px; border: 1px solid silver}",
    "img { display: none}"
  ]
});</pre>
    <p>Content styles specified by this option are loaded after those specified by the <code>contentStyleFile</code> option.</p>
   </td>
  </tr>
  <tr>
   <td>attachTo</td>
   <td>string,array</td>
   <td>
    <p>If this option is not specified, content scripts:</p>
    <ul>
     <li>are not attached to any tabs that are already open when the page-mod is created.</li>
     <li>are attached to all documents whose URL matches the rule: so if your rule matches a specific hostname and path, and the topmost document that satisfies the rule includes ten iframes using a relative URL, then your page-mod is applied eleven times.</li>
    </ul>
    <!-- -->
    <p>You can modify this behavior using the <code>attachTo</code> option.</p>
    <p>It accepts the following values:</p>
    <ul>
     <li><code>"existing"</code>: the page-mod will be automatically applied on already opened tabs.</li>
     <li><code>"top"</code>: the page-mod will be applied to top-level tab documents</li>
     <li><code>"frame"</code>: the page-mod will be applied to all iframes inside tab documents</li>
    </ul>
    <!-- -->
    <p>If the option is set at all, you must set at least one of <code>"top"</code> and <code>"frame"</code>.</p>
    <p>For example, the following page-mod will be attached to already opened tabs, but not to any iframes:</p>
    <pre class="brush: js">
   var pageMod = require("sdk/page-mod");
   pageMod.PageMod({
     include: "*",
     contentScript: "",
     attachTo: ["existing", "top"],
     onAttach: function(worker) {
       console.log("attached to: " + worker.tab.url);
     }
   });</pre>
   </td>
  </tr>
  <tr>
   <td>onAttach</td>
   <td>function</td>
   <td>
    <p>Assign a listener function to this option to listen to the page-mod's <code>attach</code> event. See the <a href="modules/sdk/page-mod.html#attach">documentation for <code>attach</code></a> and <a href="modules/sdk/page-mod.html#Communicating With Content Scripts">Communicating With Content Scripts</a>.</p>
   </td>
  </tr>
 </tbody>
</table>
<h2 id="PageMod">PageMod</h2>
<p>A page-mod object. Once created a page-mod will execute the supplied content scripts, and load any supplied stylesheets, in the context of any documents matching the pattern specified by the <code>include</code> property.</p>
<h3 id="Methods">Methods</h3>
<h4 class="addon-sdk-api-name" id="destroy()"><code>destroy()</code></h4>
<p>Stops the page-mod from making any more modifications. Once destroyed the page-mod can no longer be used.</p>
<p>Modifications already made to open documents by content scripts will not be undone, but stylesheets added by <code>contentStyle</code> or <code>contentStyleFile</code>, will be unregistered immediately.</p>
<h3 id="Properties">Properties</h3>
<h4 class="addon-sdk-api-name" id="include"><code>include</code></h4>
<p>A <a href="modules/sdk/util/list.html">list</a> of match pattern strings. These define the documents to which the page-mod applies. See the documentation of the <code>include</code> option above for details of <code>include</code> syntax. Rules can be added to the list by calling its <code>add</code> method and removed by calling its <code>remove</code> method.</p>
<h3 id="Events">Events</h3>
<h4 class="addon-sdk-api-name" id="attach"><code>attach</code></h4>
<p>This event is emitted when the page-mod's content scripts are attached to a document whose URL matches the page-mod's <code>include</code> pattern.</p>
<p>The listener function is passed a <a href="modules/sdk/content/worker.html"><code>worker</code></a> object that you can use to <a href="modules/sdk/page-mod.html#Communicating With Content Scripts">communicate with the content scripts</a> your page-mod has loaded into this particular document.</p>
<p>The <code>attach</code> event is triggered every time this page-mod's content scripts are attached to a document. So if the user loads several documents which match this page-mod's <code>include</code> pattern, <code>attach</code> will be triggered for each document, each time with a distinct <code>worker</code> instance.</p>
<p>Each worker then represents a channel of communication with the set of content scripts loaded by this particular page-mod into that particular document.</p>
<h5 id="Arguments">Arguments</h5>
<p><strong>Worker</strong> : The listener function is passed a <a href="modules/sdk/content/worker.html"><code>Worker</code></a> object that can be used to communicate with any content scripts attached to this document.</p>
<h4 class="addon-sdk-api-name" id="error"><code>error</code></h4>
<p>This event is emitted when an uncaught runtime error occurs in one of the page-mod's content scripts.</p>
<h5 id="Arguments">Arguments</h5>
<p><strong>Error</strong> : Listeners are passed a single argument, the <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error">Error</a> object.</p>
Revert to this revision