{"id":271,"date":"2009-03-05T17:40:32","date_gmt":"2009-03-05T22:40:32","guid":{"rendered":"http:\/\/mikeconley.ca\/blog\/?p=271"},"modified":"2023-12-20T16:25:21","modified_gmt":"2023-12-20T21:25:21","slug":"making-my-first-firefox-extension-before-5pm-today","status":"publish","type":"post","link":"https:\/\/mikeconley.ca\/blog\/2009\/03\/05\/making-my-first-firefox-extension-before-5pm-today\/","title":{"rendered":"Making my First Firefox Extension&#8230;in 90 Minutes"},"content":{"rendered":"<p>It&#8217;s a race.<\/p>\n<p>I&#8217;m going to attempt to create a simple Firefox extension that will display the DOM ID of an element that my mouse cursor is hovering over in the status bar.<\/p>\n<p>There are probably a ton of Firefox extensions that will do that already, but I want to give it a shot as a project.<\/p>\n<p>It&#8217;s 3:30PM right now, and I want to try to get this done by 5:00PM.\u00a0 I&#8217;m going to be using Ubuntu 8.04, gEdit, and Google to get me started.<\/p>\n<p>And I&#8217;m going to record my progress here in this blog post.<\/p>\n<p><strong>Note: <\/strong> After I&#8217;m done, I&#8217;m going to edit my sporadic notes so that they make more sense.\u00a0 So if you&#8217;re wondering just how I managed to stay so cool, calm, and collected in my prose under such time pressure, and why the publish date on this article is after 5PM, now you know.<\/p>\n<h2>3:35PM:<\/h2>\n<p>Gonna start with Google:\u00a0 &#8220;building a firefox extension&#8221;<\/p>\n<p><a href=\"http:\/\/lifehacker.com\/software\/programming\/how-to-build-a-firefox-extension-264490.php\">Ok, found an article about how to create a Firefox extension.<\/a><\/p>\n<p>Apparently, the first thing I want to do is try setting up a development profile in Firefox.<\/p>\n<h2>3:41PM<\/h2>\n<p>Finished setting up my dev profile by opening up FF with this command:<\/p>\n<pre>firefox -no-remote -P<\/pre>\n<p>Then created a profile called &#8220;Development&#8221;.\u00a0 After that, I typed &#8220;about:config&#8221; in the URL bar, and changed some settings as instructed on <a href=\"http:\/\/developer.mozilla.org\/en\/docs\/Setting_up_extension_development_environment\">this site.<\/a><\/p>\n<h2>3:49PM<\/h2>\n<p>According to that last article, I can create a skeleton Extension project using <a href=\"http:\/\/ted.mielczarek.org\/code\/mozilla\/extensionwiz\/\">this site<\/a>.\u00a0 Done &#8211; calling the project DOM ID Displayer<\/p>\n<h2>3:53PM<\/h2>\n<p><a href=\"https:\/\/addons.mozilla.org\/en-US\/firefox\/addon\/7434\">Installed this Extension <\/a>&#8211; apparently, it&#8217;ll be some help.\u00a0 Will let me reload Firefox&#8217;s chrome\u00a0 shtuff without restarting the browser each time.\u00a0 Useful.<\/p>\n<h2>3:55PM<\/h2>\n<p><a href=\"https:\/\/developer.mozilla.org\/en\/Creating_a_status_bar_extension\">Found this article<\/a> on making a status bar extension in XUL.\u00a0 Easy as pie.<\/p>\n<h2>4:05PM<\/h2>\n<p>Ok, I&#8217;ve coded something in XUL that should display a new panel in the status bar.<\/p>\n<pre>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;?xml-stylesheet href=\"chrome:\/\/domiddisplayer\/skin\/overlay.css\" type=\"text\/css\"?&gt;\r\n&lt;!DOCTYPE overlay SYSTEM \"chrome:\/\/domiddisplayer\/locale\/domiddisplayer.dtd\"&gt;\r\n\r\n&lt;overlay id=\"domiddisplayer-overlay\" xmlns=\"http:\/\/www.mozilla.org\/keymaster\/gatekeeper\/there.is.only.xul\"&gt;\r\n&lt;script src=\"overlay.js\"\/&gt;\r\n\r\n&lt;!-- Firefox --&gt;\r\n&lt;statusbar id=\"status-bar\"&gt;\r\n  &lt;statusbarpanel id=\"domiddisplayer\" label=\"Hello, World!\" tooltiptext=\"Dom ID Displayer\" \/&gt;\r\n&lt;\/statusbar&gt;\r\n&lt;\/overlay&gt;<\/pre>\n<p>I put that in the &#8220;overlay.js&#8221; file in my ~\/Experiments\/Extensions\/domidinspector\/content folder that was created using that Wizard from 3:49.<\/p>\n<p>Now, to get this thing to run in my Development profile, I create a symbolic link to it in the Development profile&#8217;s extensions directory<\/p>\n<pre>ln -s ~\/Projects\/Experiments\/Extensions\/domidinspector ~\/.mozilla\/firefox\/nzuzbdpz.Development\/extensions\/domiddisplayer@mike.conley<\/pre>\n<p>Open Firefox with Development profile:<\/p>\n<pre>firefox -P Development &amp;<\/pre>\n<h2>4:16PM<\/h2>\n<p>Looks like I can access and relabel the XULElement that I&#8217;ve ID&#8217;d as &#8220;domiddisplayer&#8221; using this:<\/p>\n<pre>domiddisplayer.updateDisplay = function(event) {\r\nvar dom_element_id = event.relatedTarget.id;\r\ndocument.getElementById('domiddisplayer').setAttribute('label', dom_element_id);\r\n}<\/pre>\n<p>Cool &#8211; I can now change my text in the Firefox status window.\u00a0 Now I just need to capture any time a mouse moves over a DOM element&#8230;.yikes, that might be tricky.<\/p>\n<h2>4:33PM<\/h2>\n<p>Been tinkering with this as a way of putting a mouseover event listener on everything in the window:<\/p>\n<pre>window.addEventListener(\"mouseover\", function(e) {\r\n  domiddisplayer.updateDisplay(e);\r\n}, false);<\/pre>\n<h2>4:35PM<\/h2>\n<p>Seems to only be capturing mouseover\/mouseout events on Chrome elements &#8211; so I can get the ID&#8217;s of the statusbar, etc.\u00a0 These are XUL Elements, not the DOM elements of a web page&#8230;<\/p>\n<p>So I&#8217;m close.<\/p>\n<h2>4:44PM<\/h2>\n<p><a href=\"http:\/\/www.quirksmode.org\/js\/events_mouse.html\">This page<\/a> is super helpful&#8230;<\/p>\n<p>Apparently, I need to wait for the content of the page to load before I can attach observers to all of its sub-elements.\u00a0 Makes total sense.<\/p>\n<p>So, in my domiddisplayer.onLoad function, I write this:<\/p>\n<pre>var appcontent = document.getElementById(\"appcontent\");\r\nif(appcontent)\r\n  appcontent.addEventListener(\"DOMContentLoaded\", domiddisplayer.onPageLoad, true);<\/pre>\n<p>And now, I create a function called onPageLoad, which looks like this:<\/p>\n<pre>domiddisplayer.onPageLoad = function(aEvent) {\r\n\/\/Runs when the page is loaded\r\n  window.content.document.addEventListener(\"mouseover\",\r\n  function(e) {\r\n    domiddisplayer.updateDisplay(e);\r\n  }, false);\r\n}<\/pre>\n<h2>5:03PM<\/h2>\n<p>Done.\u00a0 I&#8217;m over time, but I&#8217;ve finished a (relatively) working extension.<\/p>\n<p>Here, it&#8217;s a mess, but you can download the whole thing right here if you want to tinker with what I did.<\/p>\n<p><a href=\"http:\/\/mikeconley.ca\/blog\/wp-content\/uploads\/2009\/03\/domiddisplayer.zip\">Download domiddisplayer.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s a race. I&#8217;m going to attempt to create a simple Firefox extension that will display the DOM ID of an element that my mouse cursor is hovering over in the status bar. There are probably a ton of Firefox extensions that will do that already, but I want to give it a shot as [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[5,220,44,68,79,1],"tags":[69,131,125,1212,35,132,133],"class_list":["post-271","post","type-post","status-publish","format-standard","hentry","category-computer-science","category-firefox-extensions","category-internet","category-javascript","category-technology","category-uncategorized","tag-dom","tag-extensions","tag-firefox","tag-javascript","tag-mozilla","tag-programming","tag-xul"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/prmTy-4n","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/posts\/271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/comments?post=271"}],"version-history":[{"count":24,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/posts\/271\/revisions"}],"predecessor-version":[{"id":400,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/posts\/271\/revisions\/400"}],"wp:attachment":[{"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/media?parent=271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/categories?post=271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mikeconley.ca\/blog\/wp-json\/wp\/v2\/tags?post=271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}