<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-5586640457650668878</id><updated>2007-06-25T21:18:57.638-07:00</updated><title type='text'>Writing a Firefox Extension</title><link rel='alternate' type='text/html' href='http://www.gajos.org/hacking/ffextension/'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default'></link><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.gajos.org/hacking/ffextension/atom.xml'></link><author><name>Krzysztof Gajos</name></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5586640457650668878.post-3200100745371844097</id><published>2007-06-10T10:59:00.000-07:00</published><updated>2007-06-10T15:59:14.808-07:00</updated><title type='text'>Events, Event Listeners and Event Propagation Model</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;em&gt;Firefox version: 2.0.0.4 (Mac)&lt;br /&gt;&lt;/em&gt;&lt;br /&gt;&lt;strong&gt;Adding event listeners: the good and the bad&lt;/strong&gt;&lt;br /&gt;Typical syntax for adding listeners to page elements looks something like this:&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;element.onclick = myEventListener;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;where &lt;span class="code"&gt;onclick&lt;/span&gt; is an attribute and &lt;span class="code"&gt;myEventListener&lt;/span&gt; is a name of a function that takes zero or one arguments and is called when a particular event is triggered at element.  This is a common and convenient syntax for JavaScript embedded in the page but it has one major and important drawback for extension writers: adding an event listener this way causes all previous listeners registered at that element for that type of an event to be de-registered.  Therefore a better choice is the &lt;span class="code"&gt;addEventListener&lt;/span&gt; method, which allows multiple listeners to be notified of the same event type:&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;void addEventListener(in DOMString type,&lt;br /&gt;                        in EventListener listener,&lt;br /&gt;                        in boolean useCapture);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Where&lt;br /&gt;&lt;span class="code"&gt;&lt;strong&gt;type&lt;/strong&gt;&lt;/span&gt; is a string specifying the name of the event type (e.g., “mousedown”) &lt;br /&gt;&lt;span class="code"&gt;&lt;strong&gt;listener&lt;/strong&gt;&lt;/span&gt; is name of a function taking one parameter of type Event&lt;br /&gt;&lt;span class="code"&gt;&lt;strong&gt;useCapture&lt;/strong&gt;&lt;/span&gt; specifies whether events addressed to the descendants of this element should be captured by this listener first, before they reach their target (I will talk about capturing a little bit more below)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Event propagation model&lt;/strong&gt;&lt;br /&gt;The event propagation model in JavaScript is somewhat unusual and deserves some attention.  Any event can go through up to three phases: capturing, at target and bubbling (see the illustration below).  Let us assume that a mouseover event is triggered by a link element.  That event first travels through all of the ancestors of the link element, starting with the document element itself.  This is the &lt;em&gt;capturing phase&lt;/em&gt; and only event listeners registered with &lt;span class="code"&gt;useCapture = true&lt;/span&gt; are triggered during that phase.  Subsequently, the event reaches its target and is now in the &lt;em&gt;at target&lt;/em&gt; phase.  Finally, some (but not all) events will “bubble” upwards through the DOM tree all the way up to the document again.  During this &lt;em&gt;bubbling phase&lt;/em&gt; only events registered with &lt;span class="code"&gt;useCapture = false&lt;/span&gt; will be triggered.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://hacking.gajos.org/ffextension/uploaded_images/eventPropagation-702049.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://hacking.gajos.org/ffextension/uploaded_images/eventPropagation-702047.png" border="0" alt="illustration of how JavaScripts events propagate through the DOM" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are a number of methods for altering the propagation path of an event:&lt;br /&gt;&lt;br /&gt;- During capturing phase, a call to &lt;span class="code"&gt;event.stopPropagation()&lt;/span&gt; method will prevent the further propagation of the even although all other event listeners registered at the same level in the hierarchy will still receive the event;&lt;br /&gt;&lt;br /&gt;- During at target or bubbling phase, a call to &lt;span class="code"&gt;event.stopPropagation()&lt;/span&gt; method will prevent the further bubbling of the event, so no listeners registered higher up in the hierarchy will receive the event;&lt;br /&gt;&lt;br /&gt;- During capturing or at target phases, one may call &lt;span class="code"&gt;event.preventDefault()&lt;/span&gt; to prevent the event from triggering the default action in the browser (for example, to stop the browser from following a link in response to a mouse click).  This only applies to events that are designated as &lt;em&gt;cancelable&lt;/em&gt;. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Example: highlighting page elements on mouse-over&lt;br /&gt;&lt;/strong&gt;Note that the JavaScript event propagation model makes it possible to register just a single event listener at any point in the DOM hierarchy to receive all events of a particular type from all of the descendants of that element.  The example below shows how to change the background color of a page element (a leaf or an intermediate node) on a mouse-over event.  &lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;var&lt;/span&gt; &lt;span style='font-size: 11pt;'&gt;originalColors = {};&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;var&lt;/span&gt; &lt;span style='font-size: 11pt;'&gt;HelloWorld = {&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  instrumentCurrentPage: &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;function&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;() {&lt;br /&gt;        &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0064C8;'&gt;window&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.content.&lt;/span&gt;&lt;span style='font-size: 11pt; color: #0064C8;'&gt;document&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.addEventListener(&lt;/span&gt;&lt;span style='font-size: 11pt; color: #008000;'&gt;"mouseover"&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;, &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;this&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.handleMouseOverEvent, &lt;/span&gt;&lt;span style='font-size: 11pt; color: #C86400;'&gt;false&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;);&lt;br /&gt;        &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0064C8;'&gt;window&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.content.&lt;/span&gt;&lt;span style='font-size: 11pt; color: #0064C8;'&gt;document&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.addEventListener(&lt;/span&gt;&lt;span style='font-size: 11pt; color: #008000;'&gt;"mouseout"&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;, &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;this&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;.handleMouseOutEvent, &lt;/span&gt;&lt;span style='font-size: 11pt; color: #C86400;'&gt;false&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;);&lt;br /&gt;  },&lt;br /&gt;  &lt;br /&gt;  handleMouseOverEvent: &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;function&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;(event) {&lt;br /&gt;          originalColors[event.target] = event.target.style.background;&lt;br /&gt;          event.target.style.background = &lt;/span&gt;&lt;span style='font-size: 11pt; color: #008000;'&gt;"#f00"&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;;&lt;br /&gt;  },&lt;br /&gt;  &lt;br /&gt;  handleMouseOutEvent: &lt;/span&gt;&lt;span style='font-size: 11pt; color: #0000C8;'&gt;function&lt;/span&gt;&lt;span style='font-size: 11pt;'&gt;(event) {&lt;br /&gt;          event.target.style.background = originalColors[event.target];&lt;br /&gt;  },&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The &lt;span class="code"&gt;originalColors&lt;/span&gt; variable is used to store the original background colors of elements just before the highlight is applied, so that the &lt;span class="code"&gt;handleMouseOutEvent&lt;/span&gt; can restore the original background when the mouse is moved away.&lt;br /&gt;&lt;br /&gt;In this case, the event handlers are triggered during bubbling phase but the same effect is achieved if &lt;span class="code"&gt;useCapture&lt;/span&gt; were set to &lt;span class="code"&gt;true&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The screen shot below shows this extension script in action.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://hacking.gajos.org/ffextension/uploaded_images/highlightOnMouseover-713769.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://hacking.gajos.org/ffextension/uploaded_images/highlightOnMouseover-713766.png" border="0" alt="a screen shot showing a web page element being highlighted on mouse-over" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Resources&lt;br /&gt;&lt;/strong&gt;I learned the most from a W3C document on &lt;a href='http://www.w3.org/TR/DOM-Level-2-Events/events.html'&gt;Document Object Model Events&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;</content><link rel='alternate' type='text/html' href='http://www.gajos.org/hacking/ffextension/2007/06/events-event-listeners-and-event.html' title='Events, Event Listeners and Event Propagation Model'></link><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5586640457650668878&amp;postID=3200100745371844097' title='0 Comments'></link><link rel='replies' type='application/atom+xml' href='http://www.gajos.org/hacking/ffextension/atom.xml' title='Post Comments'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/3200100745371844097'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/3200100745371844097'></link><author><name>Krzysztof Gajos</name></author></entry><entry><id>tag:blogger.com,1999:blog-5586640457650668878.post-874256243299638667</id><published>2007-06-05T11:35:00.000-07:00</published><updated>2007-06-09T11:37:32.571-07:00</updated><title type='text'>Accessing page content from an extension</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;em&gt;Firefox version: 2.0.0.4 (Mac)&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;First roadblock&lt;br /&gt;&lt;/strong&gt;If JavaScript is embedded in a page, then the &lt;span class="code"&gt;document&lt;/span&gt; or &lt;span class="code"&gt;window.document&lt;/span&gt; variables point to the DOM model of the page.  When writing an extension,  &lt;span class="code"&gt;window.document&lt;/span&gt; points to the DOM model of the Firefox GUI.  How, then, does one get access to the contents of the page from an extension?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solutions&lt;br /&gt;&lt;/strong&gt;Mira and Raphael provided two solutions:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);" &gt;&lt;span style="font-family: courier new;" &gt;window.content.document&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;or a more complicated option:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 200); font-family: courier new;font-size:100%;" &gt;function&lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt; &lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;getBrowserWindow() {&lt;br /&gt; &lt;/span&gt;&lt;span style="color: rgb(0, 0, 200); font-family: courier new;font-size:100%;" &gt;var&lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt; &lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;wm = Components.classes[&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0); font-family: courier new;font-size:100%;" &gt;"&lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;&lt;a href="mailto:@mozilla.org"&gt;@mozilla.org&lt;/a&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0); font-family: courier new;font-size:100%;" &gt;/appshell/window-mediator;1"&lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;].&lt;br /&gt; getService(Components.interfaces.nsIWindowMediator );&lt;br /&gt; &lt;/span&gt;&lt;span style="color: rgb(0, 0, 200); font-family: courier new;font-size:100%;" &gt;return&lt;/span&gt;&lt;span style="font-family: courier new;"&gt; &lt;/span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;wm.getMostRecentWindow(&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0); font-family: courier new;font-size:100%;" &gt;"navigator:browser"&lt;/span&gt;&lt;span&gt;&lt;span style="font-family: courier new;font-size:100%;" &gt;).content.document;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I have tested both of them and they both return the pointer to the document in the currently visible window tab or window.  Are the two methods really equivalent or have I missed something?&lt;/div&gt;</content><link rel='alternate' type='text/html' href='http://www.gajos.org/hacking/ffextension/2007/06/accessing-page-content-from-extension.html' title='Accessing page content from an extension'></link><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5586640457650668878&amp;postID=874256243299638667' title='0 Comments'></link><link rel='replies' type='application/atom+xml' href='http://www.gajos.org/hacking/ffextension/atom.xml' title='Post Comments'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/874256243299638667'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/874256243299638667'></link><author><name>Krzysztof Gajos</name></author></entry><entry><id>tag:blogger.com,1999:blog-5586640457650668878.post-4731330908251907648</id><published>2007-06-04T21:56:00.000-07:00</published><updated>2007-06-05T13:39:03.632-07:00</updated><title type='text'>Getting started</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;em&gt;Firefox version: 2.0.0.4 (Mac)&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Why this blog?&lt;br /&gt;&lt;/strong&gt;I decided that I wanted to learn how to write Firefox extensions because some of the research I am doing will probably require that.  I very quickly realized that there is very little good documentation on the topic available (or at least easily findable) on the net so I thought I would try to document my learning process for the benefit of others who will need to go down this path.  Realizing that the relevant standards and implementations change very rapidly, I am going to include Firefox version number I am using in each post so that people can judge its relevance for their work.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What should you expect?&lt;/strong&gt;&lt;br /&gt;A few words about my background and what I want to accomplish.  I am a reasonably experienced Java developer and I am quite familiar with HTML and CSS but I haven’t touched JavaScript since 1997, I think.  I have also some experience manipulating XML from Java so I have had some exposure to the basic concepts from the Document Object Model (DOM).&lt;br /&gt;&lt;br /&gt;My research interests include adaptive user interfaces so over the course of the next several months I think I would like to learn how to do the following:&lt;br /&gt;- parse and analyze new pages as soon as the user navigates to them;&lt;br /&gt;- automatically instrument new pages (especially those containing AJAX applications) in order to see how the user interacts with the page (and therefore build a usage model);&lt;br /&gt;- keep persistent state;&lt;br /&gt;- automatically augment third-party pages with new elements;&lt;br /&gt;- exchange information with a central server.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Hello World!&lt;/strong&gt;&lt;br /&gt;The single most helpful resource for getting started was a &lt;a href="http://developer.mozilla.org/en/docs/Building_an_Extension"&gt;tutorial&lt;/a&gt; from the &lt;a href="http://developer.mozilla.org/"&gt;Mozilla Developer Center&lt;/a&gt; (MDC).  It explains all of the components that go into building the most basic extension (which a “Hello World!” message to the status bar) and includes pointers to all the other basic resources one needs.  This tutorial and several other sites also recommend an &lt;a href="http://kb.mozillazine.org/Getting_started_with_extension_development"&gt;older tutorial&lt;/a&gt; from &lt;a href="http://www.mozillazine.org/"&gt;mozillaZine&lt;/a&gt; -- the extension it describes, however, does not work with Firefox 2.0 (it seems to have been written for Firefox 1.5).  I still found that tutorial helpful because unlike the one from MDC, it included JavaScript, showed how to add a custom item to the Tools menu and how to pop up custom dialog boxes.  Using the structure from the first tutorial and some of the code from the second, I felt like I got a good handle on how to get started.&lt;br /&gt;&lt;br /&gt;The code is &lt;a href="http://hacking.gajos.org/ffextension/codesamples/helloWorld-20070604.zip"&gt;here&lt;/a&gt; and it shows the following features:&lt;br /&gt;• GUI: adding a custom element to the status bar and a custom menu item in the Tools menu&lt;br /&gt;• Localization: the labels are defined in .dtd files in the locale directory&lt;br /&gt;• JavaScript invoked by clicking on the custom menu item:&lt;br /&gt;&amp;nbsp;&amp;nbsp; • traverses Firefox GUI DOM model&lt;br /&gt;&amp;nbsp;&amp;nbsp; • logs to the JavaScript error console (available through the Tools menu) -- see more on &lt;a href="http://developer.mozilla.org/en/docs/nsIConsoleService"&gt;how to write to the console&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; • dynamically modifies the text in the custom status bar element&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Few other pointers&lt;br /&gt;&lt;/strong&gt;- A &lt;a href="http://developer.mozilla.org/en/docs/A_re-introduction_to_JavaScript"&gt;re-introduction to JavaScript&lt;/a&gt; from mozillaZine -- a good refresher for those, who already know Java or C/C++/C#&lt;br /&gt;- &lt;a href="http://www.xulplanet.com/"&gt;XULplanet&lt;/a&gt; -- a set of XUL references (XUL is the XML-based language that the Firefox user interface is written in)&lt;br /&gt;- A full &lt;a href="http://developer.mozilla.org/en/docs/Gecko_DOM_Reference"&gt;DOM reference&lt;/a&gt; from MDC&lt;br /&gt;&lt;a href="http://www.amazon.com/gp/product/1590595335/104-5641344-0360706?ie=UTF8&amp;tag=thewebsiteofk-20"&gt;&lt;img src="http://rcm-images.amazon.com/images/I/118GZVA9QAL._SL75_.jpg" align="right"&gt;&lt;/a&gt;- “&lt;a href="http://www.amazon.com/gp/product/1590595335/104-5641344-0360706?ie=UTF8&amp;tag=thewebsiteofk-20"&gt;DOM Scripting&lt;/a&gt;” by Jeremy Keith -- a very nice overview of the techniques for manipulating the DOM with JavaScript; written for people who are beginner programmers so if you already have some experience, you will be able to go through it very quickly.  It provides lots of examples and practical tips.  I found it quite helpful and got through the first five chapters in slightly over an hour.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Tools&lt;br /&gt;&lt;/strong&gt;There do not appear to be any “ideal” tools for Firefox extension writing.  I ended up installing &lt;a href="http://www.interaktonline.com/Products/Eclipse/JSEclipse/Installation-Update/"&gt;JSEclipse&lt;/a&gt; and &lt;a href="http://colorer.sourceforge.net/eclipsecolorer/"&gt;Eclipse Colorer&lt;/a&gt; plugins for &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; and I find that they are somewhat helpful but still lacking.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Acknowledgments&lt;br /&gt;&lt;/strong&gt;Besides the sources cited above, I am also learning a lot from &lt;a href="http://www.cs.washington.edu/homes/mirad/"&gt;Mira&lt;/a&gt;, &lt;a href="http://www.cs.washington.edu/homes/raphaelh/"&gt;Raphael&lt;/a&gt; and &lt;a href="http://www.cs.washington.edu/homes/jbigham/"&gt;Jeff&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;</content><link rel='alternate' type='text/html' href='http://www.gajos.org/hacking/ffextension/2007/06/getting-started.html' title='Getting started'></link><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5586640457650668878&amp;postID=4731330908251907648' title='0 Comments'></link><link rel='replies' type='application/atom+xml' href='http://www.gajos.org/hacking/ffextension/atom.xml' title='Post Comments'></link><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/4731330908251907648'></link><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5586640457650668878/posts/default/4731330908251907648'></link><author><name>Krzysztof Gajos</name></author></entry></feed>