{"id":3034,"date":"2011-09-01T16:18:13","date_gmt":"2011-09-01T23:18:13","guid":{"rendered":"http:\/\/blog.mozilla.org\/addons\/?p=3034"},"modified":"2011-10-05T12:29:41","modified_gmt":"2011-10-05T19:29:41","slug":"add-on-sdk-faq-content-script-access","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/","title":{"rendered":"Add-on SDK FAQ: Content Script Access"},"content":{"rendered":"<p><em><strong>Update<\/strong>: the SDK 1.2 beta builds ( including this one, just released today ) now include a more refined version of this content. If you&#8217;re interested in this material I strongly suggest that you <a href=\"http:\/\/groups.google.com\/group\/mozilla-labs-jetpack\/browse_thread\/thread\/ba4a799bbc55c898?hl=en\" target=\"_blank\">download this beta<\/a> and take a look at the bundled docs.<br \/>\n<\/em><br \/>\nThis post is an attempt to clearly explain how content scripts work. I am posting this particular topic as a blog post in hopes of getting feedback on the wording, but the content below is actually part of a larger patch against the SDK documentation that <a href=\"http:\/\/blog.mozilla.org\/addons\/author\/wbambergmozilla-com\/\">Will Bamberg<\/a> created as part of this <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=679479\">SDK bug<\/a>. The specific purpose of this post is to explain the access that content scripts have to:<\/p>\n<ul>\n<li>DOM objects in the pages they are attached to<\/li>\n<li>other content scripts<\/li>\n<li>other scripts loaded by the page they are attached to<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h2>Access to the DOM<\/h2>\n<p>Content scripts need to be able to access DOM objects in arbitrary web pages, but this gives rise to a potential security problem. A malicious page could redefine standard functions and properties of DOM objects so they don&#8217;t do what the add-on expects. To deal with this, content scripts access DOM objects via a proxy. Any changes they make are made to the proxy.<\/p>\n<p>The proxy is based on <code>XRayWrapper<\/code>, (also known as <a href=\"https:\/\/developer.mozilla.oreg\/en\/XPCNativeWrapper\"><code>XPCNativeWrapper<\/code><\/a>). These wrappers give the user access to the native values of DOM functions and properties, even if they have been redefined by a script.<\/p>\n<p>For example: the page below redefines <code>window.confirm()<\/code> to return <code>true<\/code> without showing a confirmation dialog:<\/p>\n<pre lang=\"html\">\r\n<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD XHTML 1.0 Transitional\/\/EN\"\r\n\"http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-transitional.dtd\">\r\n<html lang='en' xml:lang='en' xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\r\n  <head>\r\n    <script>\r\n    window.confirm = function(message) {\r\n      return true;\r\n    }\r\n    <\/script>\r\n<p><\/head>\r\n<\/html>\r\n<\/pre>\n<p>Thanks to the content proxy, a content script which calls <code>window.confirm()<\/code> will get the native implementation:<\/p>\n<pre lang=\"javascript\">var widgets = require(\"widget\");\r\nvar tabs = require(\"tabs\");\r\nvar data = require(\"self\").data;\r\n\r\nvar widget = widgets.Widget({\r\n  id: \"transfer\",\r\n  label: \"Transfer\",\r\n  content: \"Transfer\",\r\n  width: 100,\r\n  onClick: function() {\r\n    tabs.activeTab.attach({\r\n      \/\/ native implementation of window.confirm will be used\r\n      contentScript: \"console.log(window.confirm('Transfer all my money?'));\"\r\n    });\r\n  }\r\n});\r\n\r\ntabs.open(data.url(\"xray.html\"));\r\n<\/pre>\n<p>You can try this example at: <a href=\"https:\/\/builder.addons.mozilla.org\/addon\/1013777\/revision\/4\/\">https:\/\/builder.addons.mozilla.org\/addon\/1013777\/revision\/4\/<\/a>.<\/p>\n<p>The proxy is transparent to content scripts. As far as the content script is concerned, it is accessing the DOM directly, however because it is not, some things that you might expect to work, won&#8217;t. For example, if the page includes a library like <a href=\"http:\/\/www.jquery.com\">jQuery<\/a>, or any other page script adds any other objects to the window, they won&#8217;t be visible to the content script. So to use jQuery you&#8217;ll typically have to add it as a content script, as in <a href=\"dev-guide\/addon-development\/content-scripts\/reddit-example.html\">this example<\/a>.<\/p>\n<h3>unsafeWindow<\/h3>\n<p>If you really need direct access to the underlying DOM, you can use the global <code>unsafeWindow<\/code> object. Try editing the example at <a href=\"https:\/\/builder.addons.mozilla.org\/addon\/1013777\/revision\/4\/\">https:\/\/builder.addons.mozilla.org\/addon\/1013777\/revision\/4\/<\/a> so the content script uses <code>unsafeWindow.confirm()<\/code> instead of <code>window.confirm()<\/code> to see the difference.<\/p>\n<p>Avoid using <code>unsafeWindow<\/code> if possible! It is the same concept as Greasemonkey&#8217;s unsafeWindow, and the <a href=\"http:\/\/wiki.greasespot.net\/UnsafeWindow\">warnings for that<\/a> apply equally here. Also, <code>unsafeWindow<\/code> isn&#8217;t a supported API, so it could be removed or changed in a future version of the SDK.<\/p>\n<h2>Access to Other Content Scripts<\/h2>\n<p>If you load several content scripts loaded into the same document can interact with each other directly as well as with the web content itself. This allows you to do things like load jQuery and then load your own scripts that use jQuery. Content scripts which have been loaded into different document cannot interact with each other.<\/p>\n<p>For example:<\/p>\n<ul>\n<li>if an add-on creates a single <code>panel<\/code> object and loads several content scripts into the panel, then they can interact with each other.<\/li>\n<li>if an add-on creates two <code>panel<\/code> objects and loads a script into each one, they cannot interact with each other.<\/li>\n<li>if an add-on creates a single <code>page-mod<\/code> object and loads several content scripts into the page mod, then only content scripts associated with the same page can interact with each other: if two different matching pages are loaded, content scripts attached to page A cannot interact with those attached to page B.<\/li>\n<\/ul>\n<p>The web content has no access to objects created by the content script, unless the content script explicitly makes them available. For example, you could expose a variable in your content script directly to web content by doing something like this:<\/p>\n<h2>Access to Page Scripts<\/h2>\n<p>You can communicate between the content script and page scripts using <a href=\"https:\/\/developer.mozilla.org\/en\/DOM\/window.postMessage\"><code>postMessage()<\/code><\/a>, but there&#8217;s a twist: in early versions of the SDK, the global <code>postMessage()<\/code> function in content scripts was used for communicating between the content script and the main add-on code. Although this has been <a href=\"https:\/\/wiki.mozilla.org\/Labs\/Jetpack\/Release_Notes\/1.0b5#Major_Changes\">deprecated in favor of <code>self.postMessage<\/code><\/a>, the old globals are still supported, so you can&#8217;t currently use<code>window.postMessage()<\/code>. You must use <code>document.defaultView.postMessage()<\/code> instead.<\/p>\n<p>The following page script uses <a href=\"https:\/\/developer.mozilla.org\/en\/DOM\/element.addEventListener\"><code>window.addEventListener<\/code><\/a> to listen for messages:<\/p>\n<pre lang=\"html\">\r\n<!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD XHTML 1.0 Transitional\/\/EN\"\r\n\"http:\/\/www.w3.org\/TR\/xhtml1\/DTD\/xhtml1-transitional.dtd\">\r\n<html lang='en' xml:lang='en' xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\r\n\r\n<head>\r\n    <script>\r\n      window.addEventListener(\"message\", function(event) {\r\n        window.alert(event.data);\r\n      }, false);\r\n    <\/script>\r\n<\/head>\r\n<\/html>\r\n<\/pre>\n<p>Content scripts can send it messages using <code>document.defaultView.postMessage()<\/code>:<\/p>\n<pre lang=\"javascript\">\r\nvar widgets = require(\"widget\");\r\nvar tabs = require(\"tabs\");\r\nvar data = require(\"self\").data;\r\n\r\nvar widget = widgets.Widget({\r\n  id: \"postMessage\",\r\n  label: \"demonstrate document.defaultView.postMessage\",\r\n  contentURL: \"http:\/\/www.mozilla.org\/favicon.ico\",\r\n  onClick: function() {\r\n    tabs.activeTab.attach({\r\n      contentScript: \"document.defaultView.postMessage('hi there!', '*');\"\r\n    });\r\n  }\r\n});\r\n\r\ntabs.open(data.url(\"listener.html\"));\r\n<\/pre>\n<p>You can see this add-on at <a href=\"https:\/\/builder.addons.mozilla.org\/addon\/1013849\/revision\/8\/\">https:\/\/builder.addons.mozilla.org\/addon\/1013849\/revision\/8\/<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Update: the SDK 1.2 beta builds ( including this one, just released today ) now include a more refined version of this content. If you&#8217;re interested in this material I &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/\">Read more<\/a><\/p>\n","protected":false},"author":316,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[388,44,295,588],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Add-on SDK FAQ: Content Script Access - Mozilla Add-ons Community Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeff Griffiths\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/\",\"name\":\"Add-on SDK FAQ: Content Script Access - Mozilla Add-ons Community Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\"},\"datePublished\":\"2011-09-01T23:18:13+00:00\",\"dateModified\":\"2011-10-05T19:29:41+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/e2f4c71eb45392ea29162432c3f1d433\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/addons\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Add-on SDK FAQ: Content Script Access\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/\",\"name\":\"Mozilla Add-ons Community Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/e2f4c71eb45392ea29162432c3f1d433\",\"name\":\"Jeff Griffiths\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b07ae75dd1a5414bf30d7f773ccfc894?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b07ae75dd1a5414bf30d7f773ccfc894?s=96&d=mm&r=g\",\"caption\":\"Jeff Griffiths\"},\"description\":\"Jeff is Product Manager for the Firefox Developer Tools and occasional Open Web hacker, based in Vancouver, BC.\",\"sameAs\":[\"http:\/\/canuckistani.ca\/\",\"https:\/\/x.com\/canuckistani\"],\"url\":\"https:\/\/blog.mozilla.org\/addons\/author\/jgriffithsmozilla-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Add-on SDK FAQ: Content Script Access - Mozilla Add-ons Community Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/","twitter_misc":{"Written by":"Jeff Griffiths","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/","url":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/","name":"Add-on SDK FAQ: Content Script Access - Mozilla Add-ons Community Blog","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/addons\/#website"},"datePublished":"2011-09-01T23:18:13+00:00","dateModified":"2011-10-05T19:29:41+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/e2f4c71eb45392ea29162432c3f1d433"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/addons\/2011\/09\/01\/add-on-sdk-faq-content-script-access\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/addons\/"},{"@type":"ListItem","position":2,"name":"Add-on SDK FAQ: Content Script Access"}]},{"@type":"WebSite","@id":"https:\/\/blog.mozilla.org\/addons\/#website","url":"https:\/\/blog.mozilla.org\/addons\/","name":"Mozilla Add-ons Community Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/e2f4c71eb45392ea29162432c3f1d433","name":"Jeff Griffiths","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/b07ae75dd1a5414bf30d7f773ccfc894?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b07ae75dd1a5414bf30d7f773ccfc894?s=96&d=mm&r=g","caption":"Jeff Griffiths"},"description":"Jeff is Product Manager for the Firefox Developer Tools and occasional Open Web hacker, based in Vancouver, BC.","sameAs":["http:\/\/canuckistani.ca\/","https:\/\/x.com\/canuckistani"],"url":"https:\/\/blog.mozilla.org\/addons\/author\/jgriffithsmozilla-com\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/3034"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/users\/316"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/comments?post=3034"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/3034\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/media?parent=3034"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/categories?post=3034"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/tags?post=3034"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}