{"id":271,"date":"2009-01-28T15:46:49","date_gmt":"2009-01-28T22:46:49","guid":{"rendered":"http:\/\/blog.mozilla.org\/addons\/?p=271"},"modified":"2020-02-14T14:13:37","modified_gmt":"2020-02-14T22:13:37","slug":"how-to-develop-a-firefox-extension","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/","title":{"rendered":"How to develop a Firefox extension"},"content":{"rendered":"<p><strong><span style=\"color: #ff0000;\">Update: <\/span><\/strong><strong>Firefox has used the WebExtensions API as its extension API since 2017. We encourage you to visit <a href=\"https:\/\/extensionworkshop.com\/?utm_source=blog.mozilla.org&amp;utm_medium=post&amp;utm_campaign=how-to-develop-a-firefox-extension\">Extension Workshop<\/a> to learn more about browser extensions and how you can build an extension for Firefox. You can find reference documentation for the WebExtensions API on <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Mozilla\/Add-ons\/WebExtensions\/?utm_source=blog.mozilla.org&amp;utm_medium=post&amp;utm_campaign=how-to-develop-a-firefox-extension\">MDN<\/a>. <\/strong><\/p>\n<p><strong>Please do not reference this article for extension development, as it is out-of-date. If you are the developer of a legacy add-on, please refer to <a href=\"https:\/\/extensionworkshop.com\/documentation\/develop\/porting-a-legacy-firefox-extension\/?utm_source=blog.mozilla.org&amp;utm_medium=post&amp;utm_campaign=how-to-develop-a-firefox-extension\">this page<\/a> for resources to help you migrate to the current API.<\/strong><\/p>\n<hr \/>\n<h2>Our objective<\/h2>\n<p>We will create a Firefox extension to find all links in the current web page, highlight those which have a <code>target<\/code> attribute and alert you how many links it found. The good part is that once you have done this, you have both an understanding of Firefox extension development as well as a blueprint for any extension you would want to develop in the future.<\/p>\n<hr \/>\n<h2>What you need &#8211; setting up the developing environment<\/h2>\n<p>First, let\u2019s start with setting up your development environment. You need Firefox (duh) and basically whatever code editor you prefer. Then, there are some recommended things to do to prepare Firefox:<\/p>\n<h3>Create a different development profile<\/h3>\n<p>The first step is to create a different profile in Firefox, since you will do some settings and changes that you probably don\u2019t want for your regular profile. In my case, I\u2019ve created a new development profile named \u201cdev\u201d. The steps to do this are:<\/p>\n<h4>Profile manager on Windows<\/h4>\n<p>Open the Windows Start menu and choose the Run option (on Vista, it might not be there &#8211; just press <kbd>Windows key<\/kbd> + <kbd>R<\/kbd> in that case). In the run dialog, write <code>firefox -P<\/code> and press <kbd>enter<\/kbd>\/click OK. Choose Create Profile in the dialog and follow the steps.<\/p>\n<h4>Profile manager on Mac<\/h4>\n<p>Open the Terminal (located under \/Applications\/Utilities) and type in <code>\/Applications\/Firefox.app\/Contents\/MacOS\/firefox -profilemanager<\/code>. Choose Create Profile in the dialog and follow the steps.<\/p>\n<h4>Profile manager on Linux<\/h4>\n<p>Open a terminal, use <code><span class=\"lowercase\"><acronym title=\"Compact Disk\">CD<\/acronym><\/span><\/code> to navigate to your Firefox directory and then enter <code>.\/firefox -profilemanager<\/code>. Choose Create Profile in the dialog and follow the steps.<\/p>\n<h3>Configuration settings for Firefox<\/h3>\n<p>Open Firefox through the Profile Manager (process described above, or set the development profile as default during extension development). Then enter <code>about:config<\/code> in the address bar. It will warn you about changing settings, but it\u2019s ok since what you will do is only minor changes for development. You can filter the existing settings, and if any of the below settings don\u2019t exist, you can just create them.<\/p>\n<h4>Recommended settings<\/h4>\n<p>These are good to enable extension errors in the Firefox Error Console (Tools &gt; Error Console), disable XUL caching and such.<\/p>\n<ul>\n<li><code>javascript.options.showInConsole = true<\/code><\/li>\n<li><code>nglayout.debug.disable_xul_cache = true<\/code><\/li>\n<li><code>browser.dom.window.dump.enabled = true<\/code><\/li>\n<\/ul>\n<h4>Optional settings<\/h4>\n<p>These aren\u2019t necessary, but they might help you out. Personally, I don\u2019t use these.<\/p>\n<ul>\n<li><code>javascript.options.strict = true<\/code><\/li>\n<li><code>extensions.logging.enabled = true<\/code><\/li>\n<\/ul>\n<h2>Point your Firefox extensions directory to your extension<\/h2>\n<p>Instead of constantly preparing and reinstalling your extension, there\u2019s a simple way to add a pointer from your Firefox extensions directory to your code location. To do this, you must first find your profile directory:<\/p>\n<h3>Find your profile directory<\/h3>\n<p>The profile directory is where you will find all the settings for your Firefox profiles, including extension information.<\/p>\n<h4>Find profile directory on Windows<\/h4>\n<p>In Windows 2000 and XP, open Explorer and go to <code>C:\\Documents and Settings\\[your user name]\\Application Data\\Mozilla\\Firefox\\Profiles<\/code> and in Vista, go to <code>C:\\Users\\[your user name]\\AppData\\Roaming<\/code>.<\/p>\n<h4>Find profile directory on Mac<\/h4>\n<p>Open the Terminal and type in <code><span class=\"lowercase\"><acronym title=\"Compact Disk\">CD<\/acronym><\/span> ~\/Library\/Application\\ Support\/Firefox\/profiles\/<\/code>. There you will find your Firefox profiles, and they will be named with letters and numbers, followed by a dot (.) and then your profile name, e.g. <code>12a3bc4d.dev<\/code>.<\/p>\n<h4>Find profile directory on Linux<\/h4>\n<p>Open a terminal and type in <code><span class=\"lowercase\"><acronym title=\"Compact Disk\">CD<\/acronym><\/span> ~\/.mozilla\/<\/code>. In that location, you will find all your Firefox profiles, and they will be named with letters and numbers, followed by a dot (.) and then your profile name, e.g. <code>12a3bc4d.dev<\/code>.<\/p>\n<h3>Pointing to an extension<\/h3>\n<p>In your development profile folder, you will find a folder named <code>extensions<\/code>. In it, you will have code for all your installed extensions. Instead of placing your code there, you can create a pointer file. Do that by creating a file with a unique name for you (this will have to be the same as you chose for your <code>em:id<\/code> value in your <code>install.rdf<\/code> file &#8211; more on that below).<\/p>\n<p>In the case of our example, create a file named <code>linktargetfinder@robertnyman.com<\/code>, without any extension, and in it just point it to where you will have your code, e.g. <code>C:\\extensions\\<\/code> (Windows) or <code>~\/Sites\/linktargetfinder\/<\/code> (Mac).<\/p>\n<h2>Creating folder structure and files<\/h2>\n<p>What is needed to have a good base for your extension development, is to create the structure of the extension code. Start by creating this hierarchy:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png\" alt=\"A picture of a hierarchy with four folders, named chrome, defaults, locale and skin. The chrome has a child folder named content, the defaults folder has a child named preferences and the locale folders has a child folder named en-US. The root also contains two files, chrome.manifest and install.rdf\" \/><\/p>\n<h3><span class=\"lowercase\">i<\/span>nstall.rdf<\/h3>\n<p>We begin with the intimidating code of <code>install.rdf<\/code>. This is where you will have all the meta information about your extension, which versions of Firefox it supports and other assorted information. Our <code>install.rdf<\/code> will look like this:<\/p>\n<pre class=\"code\"><code>&lt;?xml version=\"1.0\"?&gt;\r\n\r\n&lt;<acronym title=\"Resource Description Framework\">RDF<\/acronym> xmlns=\"http:\/\/www.w3.org\/1999\/02\/22-<acronym title=\"Resource Description Framework\">RDF<\/acronym>-syntax-ns#\"\r\n     xmlns:em=\"http:\/\/www.mozilla.org\/2004\/em-<acronym title=\"Resource Description Framework\">rdf<\/acronym>#\"&gt;\r\n\r\n\t&lt;Description about=\"urn:mozilla:install-manifest\"&gt;\r\n\t\t&lt;em:id&gt;linktargetfinder@robertnyman.com&lt;\/em:id&gt;\r\n\r\n\t\t&lt;em:name&gt;Link Target Finder&lt;\/em:name&gt;\r\n\t\t&lt;em:version&gt;1.0&lt;\/em:version&gt;\r\n\t\t&lt;em:type&gt;2&lt;\/em:type&gt;\r\n\t\t&lt;em:creator&gt;Robert Nyman&lt;\/em:creator&gt;\r\n\r\n\t\t&lt;em:description&gt;Finds links that have a target attribute&lt;\/em:description&gt;\r\n\t\t&lt;em:homepageURL&gt;http:\/\/www.robertnyman.com\/&lt;\/em:homepageURL&gt;\r\n\t\t&lt;em:optionsURL&gt;chrome:\/\/linktargetfinder\/content\/options.xul&lt;\/em:optionsURL&gt;\r\n\r\n\t\t&lt;em:targetApplication&gt;\r\n\r\n\t\t\t&lt;Description&gt;\r\n\t\t\t\t&lt;em:id&gt;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&lt;\/em:id&gt;\r\n\t\t\t\t&lt;em:minVersion&gt;2.0&lt;\/em:minVersion&gt;\r\n\t\t\t\t&lt;em:maxVersion&gt;3.1b2&lt;\/em:maxVersion&gt;\r\n\r\n\t\t\t&lt;\/Description&gt;\r\n\t\t&lt;\/em:targetApplication&gt;\r\n\t&lt;\/Description&gt;\r\n&lt;\/RDF&gt;<\/code><\/pre>\n<p>Scary, right? Well, even if your not used to <acronym title=\"Resource Description Framework\">RDF<\/acronym> it\u2019s not that bad at all. Like most code, there\u2019s some mandatory information that you will never need to change, and then some of your own to sprinkle in. The interesting parts for us are:<\/p>\n<h4>In the <code>Description<\/code> node<\/h4>\n<dl>\n<dt><code>em:id<\/code><\/dt>\n<dd>This is where you add your unique developer id, of your own choosing. Note that this has to be the same as the pointer file you created above.<\/dd>\n<dt><code>em:name<\/code><\/dt>\n<dd>The name of your extension.<\/dd>\n<dt><code>em:version<\/code><\/dt>\n<dd>Current version of your extension.<\/dd>\n<dt><code>em:type<\/code><\/dt>\n<dd>The type declares that is an extension, as opposed to, for instance, a theme.<\/dd>\n<dt><code>em:creator<\/code><\/dt>\n<dd>Well, you!<\/dd>\n<dt><code>em:description<\/code><\/dt>\n<dd>Describes your extension functionality. Will be shown in the Tools &gt; Add-ons window.<\/dd>\n<dt><code>em:homepageURL<\/code><\/dt>\n<dd>The <acronym title=\"Uniform Resource Locator\">URL<\/acronym> of your extension\u2019s web site.<\/dd>\n<dt><code>em:optionsURL<\/code><\/dt>\n<dd>The <acronym title=\"Uniform Resource Locator\">URL<\/acronym> to where you will have your file for editing options\/preferences.<\/dd>\n<\/dl>\n<h4>In the <code>Description\/em:targetApplication<\/code> node<\/h4>\n<dl>\n<dt><code>em:id<\/code><\/dt>\n<dd>This value is the actual id of Firefox. Change this if you want to develop for Thunderbird or something else.<\/dd>\n<dt><code>em:minVersion<\/code><\/dt>\n<dd>The minimum version of Firefox required to run the extension. <a href=\"https:\/\/addons.mozilla.org\/en-US\/firefox\/pages\/appversions\">Valid Application Versions<\/a>.<\/dd>\n<dt><code>em:maxVersion<\/code><\/dt>\n<dd>The maximum version of Firefox required to run the extension. <a href=\"https:\/\/addons.mozilla.org\/en-US\/firefox\/pages\/appversions\">Valid Application Versions<\/a>.<\/dd>\n<\/dl>\n<p>Read about more options in <a href=\"https:\/\/developer.mozilla.org\/en\/Install_Manifests\">Install Manifests<\/a>.<\/p>\n<h3><span class=\"lowercase\">c<\/span>hrome.manifest<\/h3>\n<p>The chrome of Firefox is everything around the content window. i.e. web browser toolbar, menus, statusbar etc. The next file for our extension, which will probably feel a bit awkward to edit, is the <code>chrome.mainfest<\/code> file. This one, however, is in conjunction with <code>install.rdf<\/code> the key to how your extension will be added to Firefox, and how it will work. Our <code>chrome.manifest<\/code> file looks like this:<\/p>\n<pre class=\"code\"><code>content     linktargetfinder    chrome\/content\/\r\ncontent     linktargetfinder    chrome\/content\/ contentaccessible=yes\r\noverlay chrome:\/\/browser\/content\/browser.xul chrome:\/\/linktargetfinder\/content\/browser.xul\r\n\r\nlocale\tlinktargetfinder\ten-US\tlocale\/en-US\/\r\n\r\nskin\tlinktargetfinder\tclassic\/1.0\tskin\/\r\nstyle\tchrome:\/\/global\/content\/customizeToolbar.xul\tchrome:\/\/linktargetfinder\/skin\/skin.css<\/code><\/pre>\n<p>So, what are all those options? Let\u2019s go through them:<\/p>\n<dl>\n<dt><code>content linktargetfinder chrome\/content\/<\/code><\/dt>\n<dd>The path to where your extension content files will be found.<\/dd>\n<dt><code>content linktargetfinder chrome\/content\/ contentaccessible=yes<\/code><\/dt>\n<dd>Same as the above, but when <code>contentaccessible=yes<\/code> is added, it allows Firefox 3 and later to access the extension\u2019s files and show them in the web browser (like within a web page). Found this excellent help through <a href=\"http:\/\/adblockplus.org\/blog\/web-pages-accessing-chrome-is-forbidden\">Web pages accessing chrome:\/\/ is forbidden<\/a>.<\/dd>\n<dt><code>overlay chrome:\/\/browser\/content\/browser.xul chrome:\/\/linktargetfinder\/content\/browser.xul<\/code><\/dt>\n<dd>The path to which file you will use to override web browser elements, and add items to the toolbar, menu and statusbar.<\/dd>\n<dt><code>locale linktargetfinder en-US locale\/en-US\/<\/code><\/dt>\n<dd>Used for localization of content.<\/dd>\n<dt><code>skin linktargetfinder classic\/1.0 skin\/<\/code><\/dt>\n<dd>Skin reference.<\/dd>\n<dt><code>style chrome:\/\/global\/content\/customizeToolbar.xul chrome:\/\/linktargetfinder\/skin\/skin.css<\/code><\/dt>\n<dd>Style overlays for chrome pages.<\/dd>\n<\/dl>\n<p>More information can be found in <a href=\"https:\/\/developer.mozilla.org\/en\/Chrome_Manifest\">Chrome Manifest<\/a>.<\/p>\n<h3><span class=\"lowercase\">c<\/span>hrome folder<\/h3>\n<p>Ok, once the mandatory parts are out of the way, now things start to get interesting. This is also when we start to look at XUL, which stands for <acronym title=\"eXtensible Markup Language\">XML<\/acronym> User Interface Language. It is developed by Mozilla to create interfaces in Firefox, Thunderbird etc.<\/p>\n<p>First, within the <code>chrome\/content<\/code> folder, create three files:<\/p>\n<ul>\n<li><code>browser.xul<\/code><\/li>\n<li><code>options.xul<\/code><\/li>\n<li><code>linkTargetFinder.js<\/code><\/li>\n<\/ul>\n<h4><code><span class=\"lowercase\">b<\/span>rowser.xul<\/code><\/h4>\n<p>This is the file we will use to override some of the default look of the web browser, i.e. add a button to the toolbar, an item to the Tools menu and a statusbar icon. Let\u2019s look at the complete browser.xul file and then break it down:<\/p>\n<pre class=\"code\"><code>&lt;?xml version=\"1.0\"?&gt;\r\n&lt;?xml-stylesheet href=\"chrome:\/\/linktargetfinder\/skin\/skin.css\" type=\"text\/css\"?&gt;\r\n&lt;!DOCTYPE linktargetfinder SYSTEM \"chrome:\/\/linktargetfinder\/locale\/translations.dtd\"&gt;\r\n&lt;overlay id=\"sample\" xmlns=\"http:\/\/www.mozilla.org\/keymaster\/gatekeeper\/there.is.only.xul\"&gt;\r\n\r\n\t\t&lt;script src=\"linkTargetFinder.js\" \/&gt;\r\n\r\n\t\t&lt;menupopup id=\"menu_ToolsPopup\"&gt;\r\n\t\t\t&lt;menuitem label=\"&amp;runlinktargetfinder;\" key=\"link-target-finder-run-key\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n\t\t&lt;\/menupopup&gt;\r\n\r\n\t\t&lt;keyset&gt;\r\n\r\n\t\t\t&lt;key id=\"link-target-finder-run-key\" modifiers=\"accel alt shift\" key=\"L\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n\t\t&lt;\/keyset&gt;\r\n\r\n\t\t&lt;statusbar id=\"status-bar\"&gt;\r\n\t\t\t&lt;statusbarpanel id=\"link-target-finder-status-bar-icon\" class=\"statusbarpanel-iconic\" src=\"chrome:\/\/linktargetfinder\/skin\/status-bar.png\" tooltiptext=\"&amp;runlinktargetfinder;\" onclick=\"linkTargetFinder.run()\" \/&gt;\r\n\t\t&lt;\/statusbar&gt;\r\n\r\n\t\t&lt;toolbarpalette id=\"BrowserToolbarPalette\"&gt;\r\n\t\t\t&lt;toolbarbutton id=\"link-target-finder-toolbar-button\" label=\"Link Target Finder\" tooltiptext=\"&amp;runlinktargetfinder;\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n\t\t&lt;\/toolbarpalette&gt;\r\n&lt;\/overlay&gt;<\/code><\/pre>\n<p>First, there some general <acronym title=\"eXtensible Markup Language\">XML<\/acronym> syntax, then you include your <acronym title=\"Cascading Style Sheets\">CSS<\/acronym> code and set a DOCTYPE for localization. It\u2019s followed by the <code>overlay<\/code> root element with its Ghostbuster-inspired namespace (developers are truly geeks <img decoding=\"async\" class=\"wp-smiley\" src=\"http:\/\/www.robertnyman.com\/wp-includes\/images\/smilies\/icon_smile.gif\" alt=\":-)\" \/> ).<\/p>\n<p>After that you\u2019re free to write whatever XUL you want, and basically it\u2019s like <acronym title=\"HyperText Markup Language\">HTML<\/acronym> should\u2019ve been. What I mean with that is that it is filled with basic interface options that can\u2019t be found anywhere in <acronym title=\"HyperText Markup Language\">HTML<\/acronym>. For a complete overview of what you can do, please read the <a href=\"https:\/\/developer.mozilla.org\/en\/XUL_Reference\">XUL Reference<\/a>.<\/p>\n<p>In our code here, we start with adding a menu option to the Tools menu in Firefox, and connect it to a keyboard shortcut:<\/p>\n<pre class=\"code\"><code>&lt;menupopup id=\"menu_ToolsPopup\"&gt;\r\n\r\n\t&lt;menuitem label=\"&amp;runlinktargetfinder;\" key=\"link-target-finder-run-key\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n&lt;\/menupopup&gt;\r\n\r\n&lt;keyset&gt;\r\n\t&lt;key id=\"link-target-finder-run-key\" modifiers=\"accel alt shift\" key=\"L\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n&lt;\/keyset&gt;<\/code><\/pre>\n<p>Followed by adding an icon to the Firefox statusbar:<\/p>\n<pre class=\"code\"><code>&lt;statusbar id=\"status-bar\"&gt;\r\n\r\n\t&lt;statusbarpanel id=\"link-target-finder-status-bar-icon\" class=\"statusbarpanel-iconic\" src=\"chrome:\/\/linktargetfinder\/skin\/status-bar.png\" tooltiptext=\"&amp;runlinktargetfinder;\" onclick=\"linkTargetFinder.run()\" \/&gt;\r\n&lt;\/statusbar&gt;<\/code><\/pre>\n<p>And at the end, we add a button to the Firefox toolbar:<\/p>\n<pre class=\"code\"><code>&lt;toolbarpalette id=\"BrowserToolbarPalette\"&gt;\r\n\t&lt;toolbarbutton id=\"link-target-finder-toolbar-button\" label=\"Link Target Finder\" tooltiptext=\"&amp;runlinktargetfinder;\" oncommand=\"linkTargetFinder.run()\"\/&gt;\r\n&lt;\/toolbarpalette&gt;<\/code><\/pre>\n<p>Note that you need to go to View &gt; Toolbars &gt; Customize\u2026 to add your button to the visible toolbar.<\/p>\n<p>In the above examples, you might have noticed the <code>&amp;runlinktargetfinder;<\/code> code. That is used for localizing text, and its translation can be found in the <code>locale<\/code> folder. More on that later.<\/p>\n<p>Another thing to notice, which can be tricky at first, is that some ids and classes for XUL elements actually have meaning for its display, stemming from core Firefox code. Make sure to read the <a href=\"https:\/\/developer.mozilla.org\/en\/XUL_Reference\">XUL Reference<\/a> thoroughly for the elements you\u2019re using.<\/p>\n<p>If you want to use regular <acronym title=\"HyperText Markup Language\">HTML<\/acronym> elements instead of\/together with XUL, you can include the <acronym title=\"eXtensible HyperText Markup Language - HTML reformulated as XML\">XHTML<\/acronym> definition in your root element, and then include any <acronym title=\"HyperText Markup Language\">HTML<\/acronym> element with the <code>html:<\/code> prefix. Like this:<\/p>\n<pre class=\"code\"><code>&lt;overlay id=\"sample\" xmlns=\"http:\/\/www.mozilla.org\/keymaster\/gatekeeper\/there.is.only.xul\" xmlns:<acronym title=\"HyperText Markup Language\">HTML<\/acronym>=\"http:\/\/www.w3.org\/1999\/xhtml\"&gt;\r\n\r\n&lt;html:input type=\"submit\" value=\"Send\" \/&gt;\r\n<\/code><\/pre>\n<h4><code><span class=\"lowercase\">o<\/span>ptions.xul<\/code><\/h4>\n<p>This file is used for the options\/preferences dialog for your extension, and its path is pointed out in the <code>install.rdf<\/code> file in the <code>Description\/em:optionsURL<\/code> node. The complete options file for our extension looks like this:<\/p>\n<pre class=\"code\"><code>&lt;?xml version=\"1.0\"?&gt;\r\n&lt;?xml-stylesheet href=\"chrome:\/\/global\/skin\/\" type=\"text\/css\"?&gt;\r\n\r\n&lt;prefwindow\r\n     title=\"Link Target Finder Preferences\"\r\n     xmlns=\"http:\/\/www.mozilla.org\/keymaster\/gatekeeper\/there.is.only.xul\"&gt;\r\n\r\n\t&lt;prefpane label=\"Link Target Finder Preferences\"&gt;\r\n\t\t&lt;preferences&gt;\r\n\t\t\t&lt;preference id=\"link-target-finder-autorun\" name=\"extensions.linktargetfinder.autorun\" type=\"bool\"\/&gt;\r\n\r\n\t\t&lt;\/preferences&gt;\r\n\r\n\t\t&lt;groupbox&gt;\r\n\t\t\t&lt;caption label=\"Settings\"\/&gt;\r\n\t\t\t&lt;grid&gt;\r\n\t\t\t\t&lt;columns&gt;\r\n\t\t\t\t\t&lt;column flex=\"4\"\/&gt;\r\n\r\n\t\t\t\t\t&lt;column flex=\"1\"\/&gt;\r\n\t\t\t\t&lt;\/columns&gt;\r\n\t\t\t\t&lt;rows&gt;\r\n\t\t\t\t\t&lt;row&gt;\r\n\t\t\t\t\t\t&lt;label control=\"autorun\" value=\"Autorun\"\/&gt;\r\n\t\t\t\t\t\t&lt;checkbox id=\"autorun\" preference=\"link-target-finder-autorun\"\/&gt;\r\n\r\n\t\t\t\t\t&lt;\/row&gt;\r\n\t\t\t\t&lt;\/rows&gt;\r\n\t\t\t&lt;\/grid&gt;\r\n\t\t&lt;\/groupbox&gt;\t\r\n\r\n\t&lt;\/prefpane&gt;\r\n\r\n&lt;\/prefwindow&gt;<\/code><\/pre>\n<p>Again, some regular <acronym title=\"eXtensible Markup Language\">XML<\/acronym> information and styling of the content. It then uses some XUL to layout the content of the preferences dialog. The interesting part here, though, is connecting the user input to the actual settings for the extension (those settings are to be found in the <code>prefs.js<\/code> file, mentioned in detail below).<\/p>\n<p>To start with, you create a <code>preferences<\/code> group in the <code>options.xul<\/code> file with your desired preferences. Then, give each preference an id and connect it to the extension\u2019s real preferences with the <code>name<\/code> attribute:<\/p>\n<pre class=\"code\"><code>&lt;preferences&gt;\r\n\t&lt;preference id=\"link-target-finder-autorun\" name=\"extensions.linktargetfinder.autorun\" type=\"bool\"\/&gt;\r\n&lt;\/preferences&gt;<\/code><\/pre>\n<p>Then you create an element and add a <code>preference<\/code> attribute to it, pointing to the before-chosen <code>id<\/code>attribute for the preference in the <code>preferences<\/code> group. It will then automatically connect its value to that specific preference.<\/p>\n<pre class=\"code\"><code>&lt;checkbox id=\"autorun\" preference=\"link-target-finder-autorun\"\/&gt;<\/code><\/pre>\n<p>Note that you don\u2019t need to add an OK button for the dialog &#8211; for instance, on Macs there won\u2019t be one while it\u2019s automatically added for Windows users. All about system compatibility, my friends.<\/p>\n<h4><code><span class=\"lowercase\">l<\/span>inkTargetFinder.js<\/code><\/h4>\n<p>If you\u2019re like me, this is where you will feel at home. Good ol\u2019 JavaScript code. <img decoding=\"async\" class=\"wp-smiley\" src=\"http:\/\/www.robertnyman.com\/wp-includes\/images\/smilies\/icon_smile.gif\" alt=\":-)\" \/><\/p>\n<p>What\u2019s nice here is that you can script any element in the XUL <em>and<\/em> any element in the <acronym title=\"HyperText Markup Language\">HTML<\/acronym> content window as well. All you need to access the content window is to precede your document call with the <code>content<\/code> keyword, like this:<\/p>\n<pre class=\"code\"><code><strong>content<\/strong>.document.getElementsByTagName(\"a\");<\/code><\/pre>\n<p>Here\u2019s the complete code of the <code>linkTargetFinder.js<\/code> file:<\/p>\n<pre class=\"code\"><code>var linkTargetFinder = function () {\r\n\tvar prefManager = Components.classes[\"@mozilla.org\/preferences-service;1\"].getService(Components.interfaces.nsIPrefBranch);\r\n\treturn {\r\n\t\tinit : function () {\r\n\t\t\tgBrowser.addEventListener(\"load\", function () {\r\n\t\t\t\tvar autoRun = prefManager.getBoolPref(\"extensions.linktargetfinder.autorun\");\r\n\t\t\t\tif (autoRun) {\r\n\t\t\t\t\tlinkTargetFinder.run();\r\n\t\t\t\t}\r\n\t\t\t}, false);\r\n\t\t},\r\n\r\n\t\trun : function () {\r\n\t\t\tvar head = content.document.getElementsByTagName(\"head\")[0],\r\n\t\t\t\tstyle = content.document.getElementById(\"link-target-finder-style\"),\r\n\t\t\t\tallLinks = content.document.getElementsByTagName(\"a\"),\r\n\t\t\t\tfoundLinks = 0;\r\n\r\n\t\t\tif (!style) {\r\n\t\t\t\tstyle = content.document.createElement(\"link\");\r\n\t\t\t\tstyle.id = \"link-target-finder-style\";\r\n\t\t\t\tstyle.type = \"text\/css\";\r\n\t\t\t\tstyle.rel = \"stylesheet\";\r\n\t\t\t\tstyle.href = \"chrome:\/\/linktargetfinder\/skin\/skin.css\";\r\n\t\t\t\thead.appendChild(style);\r\n\t\t\t}\t\r\n\r\n\t\t\tfor (var i=0, il=allLinks.length; i&lt;il; i++) {\r\n\t\t\t\telm = allLinks[i];\r\n\t\t\t\tif (elm.getAttribute(\"target\")) {\r\n\t\t\t\t\telm.className += ((elm.className.length &gt; 0)? \" \" : \"\") + \"link-target-finder-selected\";\r\n\t\t\t\t\tfoundLinks++;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (foundLinks === 0) {\r\n\t\t\t\talert(\"No links found with a target attribute\");\r\n\t\t\t}\r\n\t\t\telse {\r\n\t\t\t\talert(\"Found \" + foundLinks + \" links with a target attribute\");\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n}();\r\nwindow.addEventListener(\"load\", linkTargetFinder.init, false);<\/code><\/pre>\n<p>While it\u2019s a fair bit of code, it is also very basic. When the window loads, it runs the <code>init<\/code> method of the <code>linkTargetFinder<\/code> object. If the preference <code>autorun<\/code> is set to true, it calls its <code>run<\/code> method immediately. Otherwise, it will only be called when the toolbar button, menu item or statusbar icon is clicked. This happens through the <code>oncommand<\/code> attribute on the elements in the <code>browser.xul<\/code> file.<\/p>\n<p>The code in the <code>run<\/code> method is pretty straight-forward. It adds a <acronym title=\"Cascading Style Sheets\">CSS<\/acronym> file from the extensions chrome folder to the current document, finds all links in it, loops through them and checks if they have a <code>target<\/code> attribute, counts those, highlights them and alerts you with the number of hits.<\/p>\n<p>As you can see, there\u2019s a pointer in the code to something called <code>gBrowser<\/code>. That is how to get a reference to the current web browser, and you could also use <code>getBrowser()<\/code> as well. Note that this sort of code is only available from within the XUL context of the web browser. More information and options can be found in <a href=\"https:\/\/developer.mozilla.org\/en\/Code_snippets\/Tabbed_browser\">Tabbed Browser.<\/a><\/p>\n<p>The only unusual part for a JavaScript is the variable <code>prefManager<\/code>, which connects to Firefox preference manager, and later gets the <code>autorun<\/code> preference with the help of this code:<\/p>\n<pre class=\"code\"><code>var autoRun = prefManager.getBoolPref(\"extensions.linktargetfinder.autorun\");<\/code><\/pre>\n<p>The three types of extension preferences are string, integer and boolean, and the six methods to work with them are:<\/p>\n<ul>\n<li><code>getBoolPref()<\/code><\/li>\n<li><code>setBoolPref()<\/code><\/li>\n<li><code>getCharPref()<\/code><\/li>\n<li><code>setCharPref()<\/code><\/li>\n<li><code>getIntPref()<\/code><\/li>\n<li><code>setIntPref()<\/code><\/li>\n<\/ul>\n<h3><span class=\"lowercase\">d<\/span>efaults folder<\/h3>\n<p>Within the <code>defaults<\/code> folder, you create a <code>preferences<\/code> folder and in that one a file named <code>pref.js<\/code>. This is used for the preferences you want to use for your extension, and looks like this:<\/p>\n<pre class=\"code\"><code>pref(\"extensions.linktargetfinder.autorun\", false);<\/code><\/pre>\n<h3><span class=\"lowercase\">l<\/span>ocale folder<\/h3>\n<p>Used for localization. In our case here, we just have one child folder for <code>en-US<\/code> content, but it can be easily extended. That folder has a file named <code>translations.dtd<\/code>, which contains translations for entities used in XUL files. Our file looks like this:<\/p>\n<pre class=\"code\"><code>&lt;!ENTITY runlinktargetfinder \"Run Link Target Finder\"&gt;<\/code><\/pre>\n<p>Remember <code>&amp;runlinktargetfinder;<\/code> in the <code>browser.xul<\/code> file? This is where it gets its translation.<\/p>\n<h3><span class=\"lowercase\">s<\/span>kin folder<\/h3>\n<p>Now when we have all functionality in place, let\u2019s make things a little more pretty (just a little, ok?). In our <code>skin<\/code> folder, we have three files: <code>skin.css<\/code>, <code>status-bar.png<\/code> and <code>toolbar-large.png<\/code>. The images are, naturally, used for the toolbar and statusbar respectively.<\/p>\n<p>The <acronym title=\"Cascading Style Sheets\">CSS<\/acronym> in <code>skin.css<\/code> is used for setting the image for the toolbar, the size and space for the statusbar icon and the highlight look of links with a <code>target<\/code> attribute. The code looks like this:<\/p>\n<pre class=\"code\"><code>#link-target-finder-toolbar-button {\r\n\tlist-style-image: <acronym title=\"Uniform Resource Locator\">URL<\/acronym>(\"chrome:\/\/linktargetfinder\/skin\/toolbar-large.png\");\r\n}\r\n\r\n#link-target-finder-status-bar-icon {\r\n\twidth: 83px;\r\n\tmargin: 0 5px;\r\n}\r\n\r\n.link-target-finder-selected {\r\n\toutline: 2px solid red !important;\r\n}<\/code><\/pre>\n<h2>Packaging and installing<\/h2>\n<p>Firefox extensions are delivered like XPI files, and those are basically just ZIP files with another extension. Therefore, when you\u2019re finished with your extension, all you need to do is ZIP your files together and give it an XPI extension. Note: do <em>not<\/em> ZIP the containing folder for your extension, just its contents (<code>chrome<\/code> folder, <code>chrome.manifest<\/code> and <code>install.rdf<\/code> files etc).<\/p>\n<p>Once you have your XPI file, you can just drag and drop it into Firefox, and it will automatically install.<\/p>\n<h3>Packaging with Windows<\/h3>\n<p>Select all the contents of your extension folder, right-click and choose <code>Send To &gt; Compressed (Zipped) Folder<\/code>. Rename it to <code>.xpi<\/code> instead of <code>.zip<\/code> and you\u2019re done!<\/p>\n<h3>Packaging with Mac<\/h3>\n<p>Open the Terminal, navigate to your extension with the <code><span class=\"lowercase\"><acronym title=\"Compact Disk\">CD<\/acronym><\/span><\/code> command and then type in <code>zip -r LinkTargetFinder.xpi *<\/code>. Ta daa!<\/p>\n<h3>Packaging with Linux<\/h3>\n<p>Open a terminal, get to your extension folder, and type in <code>zip -r LinkTargetFinder.xpi *<\/code> All done!<\/p>\n<h2>Distribution of your extension<\/h2>\n<p>There are two options of distributing your extension. Either use <a href=\"http:\/\/addons.mozilla.org\/\">addons.mozilla.org<\/a> or host it yourself. If you do it yourself, you can specify an <code>updateURL<\/code> in your <code>install.rdf<\/code> file, but note that since Firefox 3 it has to be a secure location, e.g. through <acronym title=\"Secure Sockets Layer (a security protocol)\">SSL<\/acronym> or similar.<\/p>\n<p>Personally, I\u2019d recommend addons.mozilla.org for greater reach, auto-update pushing and statistics. The downside of it, though, is that the review process can take quite some time for your extension to get an approval. Before that it can still be downloaded as an experimental add-on, but people need to have an addons.mozilla account and log in to do so.<\/p>\n<p>To make sure it doesn\u2019t take longer than necessary, I recommend reading <a href=\"http:\/\/blog.mozilla.org\/addons\/2009\/01\/14\/successfully-getting-your-addon-reviewed\/\"><br \/>\nSuccessfully Getting your Addon Reviewed<\/a>.<\/p>\n<h2>Downloads<\/h2>\n<p>All the code I\u2019ve created here is available both as a ZIP file of everything, so you can start experimenting, change stuff and see what happens. It is also available as an XPI file, which you can install in your Firefox just to test the functionality (drag and drop it into Firefox).<\/p>\n<ul>\n<li><a href=\"http:\/\/www.robertnyman.com\/extensions\/LinkTargetFinder.zip\">Download Link Target Finder code as a ZIP file<\/a>.<\/li>\n<li><a href=\"http:\/\/www.robertnyman.com\/extensions\/LinkTargetFinder.xpi\">Download Link Target Finder as an XPI file<\/a>.<\/li>\n<\/ul>\n<h2>Happy extension developing!<\/h2>\n<p>I hope this has been a good, albeit long, introduction to Firefox extension development and that it has helped you to grasp concepts you hadn\u2019t gotten full control over yet. Good luck, and don\u2019t hesitate to ask if you have any questions!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Update: Firefox has used the WebExtensions API as its extension API since 2017. We encourage you to visit Extension Workshop to learn more about browser extensions and how you can &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/\">Read more<\/a><\/p>\n","protected":false},"author":173,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[44,295],"tags":[278876,543],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to develop a Firefox extension - 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\/2009\/01\/28\/how-to-develop-a-firefox-extension\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jorge Villalobos\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/\",\"name\":\"How to develop a Firefox extension - Mozilla Add-ons Community Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage\"},\"thumbnailUrl\":\"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png\",\"datePublished\":\"2009-01-28T22:46:49+00:00\",\"dateModified\":\"2020-02-14T22:13:37+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage\",\"url\":\"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png\",\"contentUrl\":\"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/addons\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to develop a Firefox extension\"}]},{\"@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\/a098261b4b5510d408ff31f492606925\",\"name\":\"Jorge Villalobos\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"caption\":\"Jorge Villalobos\"},\"description\":\"Jorge is the Product Manager for addons.mozilla.org\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to develop a Firefox extension - 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\/2009\/01\/28\/how-to-develop-a-firefox-extension\/","twitter_misc":{"Written by":"Jorge Villalobos","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/","url":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/","name":"How to develop a Firefox extension - Mozilla Add-ons Community Blog","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/addons\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage"},"image":{"@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage"},"thumbnailUrl":"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png","datePublished":"2009-01-28T22:46:49+00:00","dateModified":"2020-02-14T22:13:37+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#primaryimage","url":"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png","contentUrl":"http:\/\/blog.mozilla.org\/addons\/files\/2009\/01\/extension-structure.png"},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/addons\/2009\/01\/28\/how-to-develop-a-firefox-extension\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/addons\/"},{"@type":"ListItem","position":2,"name":"How to develop a Firefox extension"}]},{"@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\/a098261b4b5510d408ff31f492606925","name":"Jorge Villalobos","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","caption":"Jorge Villalobos"},"description":"Jorge is the Product Manager for addons.mozilla.org","url":"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/271"}],"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\/173"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/comments?post=271"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/271\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/media?parent=271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/categories?post=271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/tags?post=271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}