{"id":511,"date":"2009-02-22T15:42:14","date_gmt":"2009-02-22T15:42:14","guid":{"rendered":"http:\/\/dalelane.co.uk\/blog\/?p=511"},"modified":"2009-02-22T15:45:04","modified_gmt":"2009-02-22T15:45:04","slug":"beginners-guide-to-writing-a-firefox-extension","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=511","title":{"rendered":"Beginner&#8217;s guide to writing a Firefox extension"},"content":{"rendered":"<p>Last week, I shared my hack for <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=479\">syncing my browsing between my computer and mobile<\/a>. It&#8217;s built around a Firefox extension, so I thought I&#8217;d share my notes on how I got it to work.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/i267.photobucket.com\/albums\/ii311\/dale_lane\/090217-firefox1.png\" alt=\"screenshot\" align=\"left\" hspace=\"5\" vspace=\"5\"\/>This post is a complete sample for creating a Firefox extension to add a button to the browser toolbar. When you click on the button, it grabs the URL from the Firefox address bar and does something with it.<\/p>\n<p>I&#8217;ve gone through each file you need, explaining what it&#8217;s for and giving a sample ready for copy-and-pasting. <\/p>\n<p>In my <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=479\">browser sync hack<\/a> it sent the URL to my phone, but for this walkthrough I&#8217;m going with something simpler: opening the webpage in Internet Explorer. You can replace that bit of script with something more useful \ud83d\ude42<\/p>\n<p>I&#8217;m not an expert at this stuff by any means, and I found a lot of <a href=\"https:\/\/developer.mozilla.org\/En\/Code_snippets\">useful code snippets on mozilla.org<\/a> to get me going. But this seems to work, and as people that I&#8217;ve shown my extension to so far seemed surprised at how easy it was, I thought it might be useful to share.<\/p>\n<p>Apart from the Internet Explorer bit itself (which is a little Windows-specific), the rest of this should all work wherever Firefox does.<\/p>\n<p><!--more--><strong>Step 1 &#8211; Prepare a development environment<\/strong><\/p>\n<p>Create a working directory where you will work on your extension. <\/p>\n<p>Then create a text file in your Firefox extensions directory:<br \/>\n(e.g. C:\\Documents and Settings\\YourUserName\\Application Data\\Mozilla\\Firefox\\Profiles\\YourFirefoxProfile\\extensions\\)<\/p>\n<p>The file name should be named YourExtensionName@Your.Name<br \/>\ne.g. <code>sendtoie@dale.lane<\/code><\/p>\n<p>The file should contain the path where you put the working directory for your extension.<\/p>\n<p>This is enough for Firefox to find your extension &#8211; although you will need to restart the browser every time you make a change.<\/p>\n<p><strong>Step 2 &#8211; chrome.manifest<\/strong><\/p>\n<p>Create a <code>chrome.manifest<\/code> file in your working directory where you will list the files we need for our extension<\/p>\n<p>For example:<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">content sendtoie       content\/\r\nskin    sendtoie       classic\/1.0      skin\/\r\noverlay chrome:\/\/browser\/content\/browser.xul    chrome:\/\/sendtoie\/content\/firefoxOverlay.xul\r\nstyle   chrome:\/\/global\/content\/customizeToolbar.xul    chrome:\/\/sendtoie\/skin\/overlay.css<\/pre>\n<p><strong>Step 3 &#8211; install.rdf<\/strong><\/p>\n<p>Create an <code>install.rdf<\/code> file in your working directory where you describe the extension &#8211; information that will be shown in the Firefox Add-ons dialog.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;RDF xmlns=\"http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#\" \r\n xmlns:em=\"http:\/\/www.mozilla.org\/2004\/em-rdf#\"&gt;\r\n  &lt;Description about=\"urn:mozilla:install-manifest\"&gt;\r\n    &lt;em:id&gt;sendtoie@dale.lane&lt;\/em:id&gt;\r\n    &lt;em:name&gt;Send to Internet Explorer&lt;\/em:name&gt;\r\n    &lt;em:version&gt;0.1&lt;\/em:version&gt;\r\n    &lt;em:creator&gt;Dale Lane&lt;\/em:creator&gt;\r\n    &lt;em:description&gt;Send a webpage to Internet Explorer&lt;\/em:description&gt;\r\n    &lt;em:homepageURL&gt;http:\/\/dalelane.co.uk\/blog\/&lt;\/em:homepageURL&gt;\r\n    &lt;em:iconURL&gt;chrome:\/\/sendtoie\/content\/sendtoie.gif&lt;\/em:iconURL&gt;\r\n    &lt;em:targetApplication&gt;\r\n      &lt;Description&gt;\r\n        &lt;em:id&gt;{ec8030f7-c20a-464f-9b0e-13a3a9e97384}&lt;\/em:id&gt; &lt;!-- firefox --&gt;\r\n        &lt;em:minVersion&gt;2.0&lt;\/em:minVersion&gt;\r\n        &lt;em:maxVersion&gt;3.0.*&lt;\/em:maxVersion&gt;\r\n      &lt;\/Description&gt;\r\n    &lt;\/em:targetApplication&gt;\r\n  &lt;\/Description&gt;\r\n&lt;\/RDF&gt;<\/pre>\n<p><strong>Step 4 &#8211; content\/firefoxOverlay.xul<\/strong><\/p>\n<p>Create a &#8216;<code>content<\/code>&#8216; sub-directory in your working directory and create a <code>firefoxOverlay.xul<\/code> file. This is where you specify that a button should be added to the toolbar and identify what function should be run when you click on it.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;?xml-stylesheet href=\"chrome:\/\/sendtoie\/skin\/overlay.css\" type=\"text\/css\"?&gt;\r\n&lt;!DOCTYPE overlay SYSTEM \"chrome:\/\/sendtoie\/locale\/sendtoie.dtd\"&gt;\r\n&lt;overlay id=\"sendtoie-overlay\"\r\n         xmlns=\"http:\/\/www.mozilla.org\/keymaster\/gatekeeper\/there.is.only.xul\"&gt;\r\n  &lt;script type=\"application\/x-javascript\" src=\"overlay.js\"\/&gt;\r\n\r\n  &lt;toolbarpalette id=\"BrowserToolbarPalette\"&gt;\r\n     &lt;toolbarbutton id=\"sendtoie-toolbar-button\" \r\n        autoCheck=\"true\"\r\n        label=\"send page to IE\"\r\n        tooltiptext=\"Send current page to Internet Explorer\"\r\n        oncommand=\"SENDTOIE.onToolbarButtonCommand();\"\r\n        class=\"toolbarbutton-1 chromeclass-toolbar-additional\"\/&gt;\r\n  &lt;\/toolbarpalette&gt;\r\n&lt;\/overlay&gt;<\/pre>\n<p><strong>Step 5 &#8211; content\/overlay.js<\/strong><\/p>\n<p>Still in the &#8216;<code>content<\/code>&#8216; sub-directory in your working directory, create an <code>overlay.js<\/code> file where you put the main Javascript implementation of your extension.<\/p>\n<p>For this simple example, we use nsIProcess to invoke the Internet Explorer iexplore.exe process, passing it the URL from Firefox as an argument.<\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">var SENDTOIE = {\r\n\r\n    sendUrl : function() {\r\n\r\n        var urlbar = document.getElementById('urlbar');\r\n\r\n        if (urlbar) {\r\n            \/\/ create an nsILocalFile for the executable\r\n            var file = Components.classes[\"@mozilla.org\/file\/local;1\"].createInstance(Components.interfaces.nsILocalFile);\r\n            file.initWithPath(\"C:\\\\Program Files\\\\Internet Explorer\\\\iexplore.exe\");\r\n            \r\n            \/\/ create an nsIProcess\r\n            var process = Components.classes[\"@mozilla.org\/process\/util;1\"].createInstance(Components.interfaces.nsIProcess);\r\n            process.init(file);\r\n            \r\n            \/\/ Run the process.\r\n            \/\/ If first param is true, calling thread will be blocked until\r\n            \/\/ called process terminates.\r\n            \/\/ Second and third params are used to pass command-line arguments\r\n            \/\/ to the process.\r\n            var args = [urlbar.value];\r\n            process.run(false, args, args.length);\r\n        }\r\n    },\r\n\r\n    onToolbarButtonCommand : function(e) {\r\n        SENDTOIE.sendUrl();\r\n    },\r\n};<\/pre>\n<p><strong>Step 6 &#8211; skin\/overlay.css<\/strong><\/p>\n<p>Create a &#8216;<code>skin<\/code>&#8216; sub-directory in your working directory and create an <code>overlay.css<\/code> file in there. This is where you specify the style for the button you are adding to the toolbar. <\/p>\n<pre style=\"overflow: scroll; font-size: 1.1em; border: thin solid silver; background-color: #eeeeee; padding: 0.8em\">#sendtoie-toolbar-button\r\n{\r\n  list-style-image: url(\"chrome:\/\/sendtoie\/skin\/toolbar-button.png\");\r\n  -moz-image-region: rect(0px 24px 24px 0px);\r\n}\r\n#sendtoie-toolbar-button:hover\r\n{\r\n  -moz-image-region: rect(24px 24px 48px  0px);\r\n}\r\n[iconsize=\"small\"] #sendtoie-toolbar-button\r\n{\r\n  -moz-image-region: rect( 0px 40px 16px 24px);\r\n}\r\n[iconsize=\"small\"] #sendtoie-toolbar-button:hover\r\n{\r\n  -moz-image-region: rect(24px 40px 40px 24px);\r\n}<\/pre>\n<p><strong>Step 7 &#8211; skin\/toolbar-button.png<\/strong><\/p>\n<p>Now for images. First, the icon that goes on the toolbar button goes in the &#8216;<code>skin<\/code>&#8216; directory. <\/p>\n<p>You need at least four icons &#8211; one large icon, one large icon for when the mouse is hovering over it, one small icon, and one small icon for when the mouse is hovering over it.<\/p>\n<p>You use one image file for all the images needed &#8211; the stylesheet in Step 6 identifies the coordinates of a section of the file to use for each image.<\/p>\n<p>This is one of the images I created for a toolbar button in my <a href=\"http:\/\/dalelane.co.uk\/blog\/?p=479\">syncing extension<\/a>. (<em>Sadly, drawing this is the bit that probably took me the longest of the whole hack!<\/em>)<\/p>\n<p><a href=\"http:\/\/dalelane.co.uk\/blog\/post-images\/toolbar-button.png\"><img decoding=\"async\" width=80 height=96 src=\"http:\/\/dalelane.co.uk\/blog\/post-images\/toolbar-button.png\" style=\"border: thin black solid\"\/><\/a><\/p>\n<p><strong>Step 8 &#8211; content\/sendtoie.gif<\/strong><\/p>\n<p>The last quick step &#8211; you need an icon for the extension. This is the icon that will be shown the Firefox Add-ons dialog. I used this one, and put it in the &#8216;<code>content<\/code>&#8216; directory.<\/p>\n<p><a href=\"http:\/\/dalelane.co.uk\/blog\/post-images\/sendtoie.gif\"><img decoding=\"async\" width=100 height=100 src=\"http:\/\/dalelane.co.uk\/blog\/post-images\/sendtoie.gif\" style=\"border: thin black solid\"\/><\/a><\/p>\n<p><strong>Step 9 &#8211; debug \ud83d\ude42 <\/strong><\/p>\n<p>Something probably went wrong, so you now get into a cycle of tweaking something, and restarting Firefox and retesting. You need to restart the browser to pick up any changes you make.<\/p>\n<p>Once you are happy with it all, it&#8217;s time to package up your extension for sharing.<\/p>\n<p>Delete the text file you added to the Firefox extensions directory in Step 1, and restart Firefox &#8211; you want a clean browser ready to test installing your real extension next.<\/p>\n<p><strong>Step 10 &#8211; preparing an xpi<\/strong><\/p>\n<p>Firefox extensions are distributed as .xpi files. This is just a zip file, renamed to have a xpi extension. <\/p>\n<p>Zip up your working directory and give it a name that ends in .xpi. You can make this available as an installer for your extension for other Firefox users. <\/p>\n<p>All done. \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last week, I shared my hack for syncing my browsing between my computer and mobile. It&#8217;s built around a Firefox extension, so I thought I&#8217;d share my notes on how I got it to work. This post is a complete sample for creating a Firefox extension to add a button to the browser toolbar. When [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[152,337,338],"class_list":["post-511","post","type-post","status-publish","format-standard","hentry","category-code","tag-firefox","tag-firefox-extension","tag-xul"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=511"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/511\/revisions"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}