<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>David DeWinter &#187; JavaScript</title>
	<atom:link href="http://davedewinter.com/category/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://davedewinter.com</link>
	<description>Just another WordPress site</description>
	<lastBuildDate>Tue, 09 Aug 2011 21:05:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Don&#8217;t Change Your Firefox Add-On&#8217;s ID!</title>
		<link>http://davedewinter.com/2009/03/28/dont-change-your-firefox-add-ons-id/</link>
		<comments>http://davedewinter.com/2009/03/28/dont-change-your-firefox-add-ons-id/#comments</comments>
		<pubDate>Sun, 29 Mar 2009 02:01:29 +0000</pubDate>
		<dc:creator>David DeWinter</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[addons.mozilla.org]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[firefox add-on]]></category>
		<category><![CDATA[firefox extension]]></category>
		<category><![CDATA[GUID]]></category>
		<category><![CDATA[ID]]></category>

		<guid isPermaLink="false">http://blogs.rev-net.com/ddewinter/2009/03/28/dont-change-your-firefox-add-ons-id/</guid>
		<description><![CDATA[That is, unless you want to experience pain. Two weeks ago I blogged about how someone had taken an add-on of mine that was in production and uploaded a derived version to https://addons.mozilla.org (AMO) without changing its ID. This means &#8230; <a href="http://davedewinter.com/2009/03/28/dont-change-your-firefox-add-ons-id/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>That is, unless you <em>want</em> to experience pain.</p>
<p>Two weeks ago <a href="http://blogs.rev-net.com/ddewinter/2009/03/15/burned-by-amo-and-oss/">I blogged</a> about how someone had taken an add-on of mine that was in production and uploaded a derived version to <a href="https://addons.mozilla.org">https://addons.mozilla.org</a> (AMO) without changing its ID. This means that because the AMO web site identifies add-ons by their ID, it would not allow me to upload my add-on. I tried to solve this problem by engineering a solution to change my add-on&#8217;s ID.</p>
<p>I thought this would work and even provided some sample code for my ideas in my previous blog entry; however, there were just too many problems to overcome.</p>
<p>The sample code <em>might </em>work if Firefox&#8217;s UI gave users a pleasant experience when an add-on&#8217;s automatic update facility installs an add-on with a different ID. (I&#8217;m not blaming Firefox here; it&#8217;s probably not a supported scenario.)     </p>
<p>Instead this is what the user sees:     </p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image-thumb2.png" width="545" height="430" /></a>&#160; </p>
<p>Compare this to what they should see:     </p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image-thumb3.png" width="545" height="430" /></a>&#160;</p>
<p>Notice anything missing? 5 points if you said the &quot;Restart Firefox&quot; button. It&#8217;s pretty important.</p>
<p>&quot;OK,&quot; I say, full of resolve, &quot;let&#8217;s just create an update with the same ID that downloads the new version for them.&quot; Essentially, we use an update with the same ID to get around the problem laid out above, but all that update does is to download the newest version of the add-on automatically. Finally, it uninstalls itself and then restarts Firefox. Here&#8217;s what I envisioned for the user experience:</p>
<ol>
<li>Joe Bloggs sees there&#8217;s an update for one of his extensions. Firefox guides him through the update process, at which point he sees the picture above to restart Firefox to complete his changes. </li>
<li>Joe clicks &quot;Restart,&quot; and as soon as this intermediate version of the extension springs into action and downloads the newest version of the extension. Firefox doesn&#8217;t have time to show its windows again before the download completes, and Firefox is forced to restart by the intermediate extension. </li>
<li>Joe sees his windows and tabs being restored, and he has the newest version of your extension. </li>
</ol>
<p>Unfortunately, it never quite worked out that well. This is closer to the end user experience:</p>
<ol>
<li>Joe sees there&#8217;s an update for one of his extensions. Firefox guides him through the update process, at which point he sees the picture above to restart Firefox to complete his changes. </li>
<li>Joe clicks &quot;Restart,&quot; and as soon as this intermediate version of the extension springs into action and downloads the newest version of the extension. <strong>Meanwhile, Joe sees his windows and tabs being restored. All of a sudden, all of his windows disappear.</strong> </li>
<li>Joe at this point could try and relaunch Firefox, but that wouldn&#8217;t work since Firefox is technically already restarted. If he waits long enough he&#8217;ll see Firefox return, but <strong>all of his windows and tabs have gone.</strong> </li>
</ol>
<p>Whether these were technical limitations of Firefox itself or problems in my code I never confirmed. What I knew was that the investigation had cost a lot of time, and I was very nervous about deploying something that could potentially frustrate a large percentage of my user base.</p>
<p>Turns out I made the right call. <a href="http://www.osunick.com">Nick Nguyen</a>, who was my liaison at AMO, allowed me to take over the extension that used my add-on&#8217;s ID. No more problems, and definitely no more hitting my head against a brick wall.</p>
<p>So if you have deployed an add-on publically, and you&#8217;re thinking of changing its ID, don&#8217;t do it. There&#8217;s a better way to achieve what you want.</p>
]]></content:encoded>
			<wfw:commentRss>http://davedewinter.com/2009/03/28/dont-change-your-firefox-add-ons-id/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Burned by AMO and OSS (An Idea on How to Change Your Firefox Add-On&#8217;s ID)</title>
		<link>http://davedewinter.com/2009/03/15/burned-by-amo-and-oss/</link>
		<comments>http://davedewinter.com/2009/03/15/burned-by-amo-and-oss/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 01:56:10 +0000</pubDate>
		<dc:creator>David DeWinter</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[add-on]]></category>
		<category><![CDATA[addons.mozilla.org]]></category>
		<category><![CDATA[AMO]]></category>
		<category><![CDATA[extension]]></category>
		<category><![CDATA[firefox add-on]]></category>
		<category><![CDATA[firefox extension]]></category>
		<category><![CDATA[GUID]]></category>
		<category><![CDATA[ID]]></category>

		<guid isPermaLink="false">http://blogs.rev-net.com/ddewinter/2009/03/15/burned-by-amo-and-oss/</guid>
		<description><![CDATA[I&#8217;ve helped to build a Firefox add-on called NAMFox over the past couple of years to help refine my skills with JavaScript and provide an avenue for more technical challenges. (Of course, I also like to provide value to customers, &#8230; <a href="http://davedewinter.com/2009/03/15/burned-by-amo-and-oss/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve helped to build a Firefox add-on called <a href="http://code.google.com/p/namfox/">NAMFox</a> over the past couple of years to help refine my skills with JavaScript and provide an avenue for more technical challenges. (Of course, I also like to provide value to customers, but that&#8217;s not the focus of this blog entry.) For add-on developers, AMO (<a title="https://addons.mozilla.org/" href="https://addons.mozilla.org/">https://addons.mozilla.org/</a>) is THE site to use to host your add-on and put your work out there for other people to use. Of course, you can always host the add-on on your own server, but if you want integration with Firefox&#8217;s add-on searching (see below) or an easy way to manage automatic updates, then you&#8217;ll use AMO.</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Firefox Add-On Search" border="0" alt="Firefox Add-On Search" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image-thumb.png" width="553" height="440" /></a> </p>
<h3>The Situation</h3>
<p>In early 2008 I wanted to upload NAMFox onto AMO for the reasons mentioned above, and because the server it was already hosted on wasn&#8217;t very reliable. I set up a new account and went through the process to upload my add-on, when I encountered an error saying that I didn&#8217;t have permission to upload the add-on.* At the time I thought it was because the ID of my extension (superfastoz@neoseeker.com) didn&#8217;t match the email I registered with. (This was <em>not</em> the case; read further….) I gave up on trying to host it at AMO and continued using the same server the product had always used. </p>
<p>…Until a year later, when after some significant code rewrites I decided to try my luck again with AMO. I got the same error message and decided to investigate further. This time I discovered that it was actually because an add-on with the same ID already existed on AMO. I certainly didn&#8217;t remember uploading it before, and the previous project owner professed that he didn&#8217;t upload it on AMO either. I began writing a piece of software to download all the add-ons on AMO and check their IDs for conflicts, but I figured it would be a much more efficient use of my time to enlist some at Mozilla for help.</p>
<p>Enter <a href="http://osunick.com/">Nick Nguyen</a>, who helped me figure out that another user had uploaded <a href="https://addons.mozilla.org/en-US/firefox/addon/3995/">an add-on</a> with the same ID as mine. I was a bit disappointed; then I figured out that someone had taken NAMFox back in 2007, amended it to work with GameFAQs instead of Neoseeker, and then uploaded it to AMO with <em>the same ID</em>. I was flabbergasted. I had wasted so many hours trying to get NAMFox onto AMO, only to find this. Unfortunately all Nick and I could do was to email the original developer of that account to see if he would be willing to relinquish ownership of the project. Unfortunately I can&#8217;t just take it over, even though there is currently no download on the page, nor have there ever been (0 total downloads since 2007). If we didn&#8217;t hear back from the developer in a couple of <em>months</em>, I could perhaps take over the project then.</p>
<p>Well…</p>
<ol>
<li>We haven&#8217;t heard back from the developer, and it&#8217;s been about two weeks now. </li>
<li>A couple of months is such a long period to go without a release or an update, especially since the add-on enhances a web site which is prone to change (and break NAMFox) without notice. </li>
</ol>
<p>There was another alternative—I should change the ID of my add-on. Then I could easily upload it to AMO for people to use. There are a couple of problems with this:</p>
<ol>
<li>Firefox treats two different add-on files as the same add-on if they have the same ID and as two separate add-ons if they have different IDs. This means that if anyone who had the old NAMFox installed downloaded the new version with a different ID, their Firefox would have <strong>two</strong> instances of the add-on running, the old one <strong>and</strong> the new one. </li>
<li>The same problem occurs with automatic updates. I can tell Firefox to download this updated NAMFox with a new ID, but now the customers that download the updates will have two instances of the add-on running. </li>
</ol>
<p><em>In theory there is a way around this limitation, but I haven&#8217;t tried it…</em></p>
<h3>The (Tentative) Solution</h3>
<p><strong><span style="color: red">DISCLAIMER</span>: </strong>I have not used the following techniques/code when releasing my add-on into the wild, so you should be careful if you&#8217;re going to adopt it.</p>
<p><strong>UPDATE:</strong> <strong>Don&#8217;t try this! </strong><a href="http://blogs.rev-net.com/ddewinter/2009/03/28/dont-change-your-firefox-add-ons-id/">My Findings</a></p>
<p>The great thing about Firefox is that you can control just about every part of the browser, including the add-ons that the users have installed. If you&#8217;re like me, you&#8217;re probably thinking you can use this to get around the two limitations I listed above. In fact, <em>I believe</em> we can.</p>
<p>We&#8217;ve already identified the two scenarios that users can get your add-on with a new ID: through a direct download and through automatic updates.</p>
<p>If a user doesn&#8217;t have your add-on installed already, then we can agree that there is no problem.</p>
<p>If a user does have your old add-on installed already, then the new add-on must recognize this and uninstall it. This action is required regardless of whether the user used automatic updates to install the new add-on.</p>
<p>Turns out this is actually quite simple and only requires a few lines of code:</p>
<div style="font-family: courier new; background: white; color: black; font-size: 10pt">
<p style="margin: 0px"><span style="color: blue">var</span> oldId = <span style="color: #a31515">&quot;superfastoz@neoseeker.com&quot;</span>;</p>
<p style="margin: 0px"><span style="color: blue">var</span> extensionManager = Components.classes[<span style="color: #a31515">&quot;@mozilla.org/extensions/manager;1&quot;</span>].</p>
<p style="margin: 0px">&#160;&#160;&#160; getService(Components.interfaces.nsIExtensionManager);</p>
<p style="margin: 0px"><span style="color: blue">var</span> oldAddon = extensionManager.getItemForID(oldId);</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">if</span> (oldAddon) {</p>
<p style="margin: 0px">&#160;&#160;&#160; extensionManager.uninstallItem(oldId);</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">var</span> nsIAppStartup = Components.interfaces.nsIAppStartup;</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">var</span> appManager = Components.classes[<span style="color: #a31515">&quot;@mozilla.org/toolkit/app-startup;1&quot;</span>].</p>
<p style="margin: 0px">&#160;&#160;&#160;&#160;&#160;&#160;&#160; getService(nsIAppStartup);</p>
<p style="margin: 0px">&#160;&#160;&#160; appManager.quit(nsIAppStartup.eForceQuit | nsIAppStartup.eRestart);</p>
<p style="margin: 0px">}</p>
</p></div>
<p>This code exists in the new add-on; for me it runs in an event listener for the window&#8217;s load event. It tries to find the old add-on with a certain ID. If it exists, it&#8217;s uninstalled and Firefox is restarted to commit the change. When Firefox restarts, only the new add-on remains.</p>
<p>I&#8217;m planning to try this soon. I&#8217;ll update this post with the good, the bad, and the ugly after I do.</p>
<p>*The AMO team did a great job of cleaning this error message up. You&#8217;ll now see this message, which is much clearer.</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image1.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/03/image-thumb1.png" width="636" height="139" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://davedewinter.com/2009/03/15/burned-by-amo-and-oss/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using FireUnit For Firefox Add-On Testing</title>
		<link>http://davedewinter.com/2009/01/06/using-fireunit-for-firefox-add-on-testing/</link>
		<comments>http://davedewinter.com/2009/01/06/using-fireunit-for-firefox-add-on-testing/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 14:41:35 +0000</pubDate>
		<dc:creator>David DeWinter</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[firefox add-on]]></category>
		<category><![CDATA[fireunit]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://blogs.rev-net.com/ddewinter/2009/01/06/using-fireunit-for-firefox-add-on-testing/</guid>
		<description><![CDATA[A friend of mine recently sent me a link to John Resig&#8217;s blog entry on a new JavaScript unit testing extension/framework called FireUnit. After reading it, I was very excited to see something like this available, because unit testing JavaScript &#8230; <a href="http://davedewinter.com/2009/01/06/using-fireunit-for-firefox-add-on-testing/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A friend of mine recently sent me a link to John Resig&#8217;s <a href="http://ejohn.org/blog/fireunit/">blog entry</a> on a new JavaScript unit testing extension/framework called FireUnit. After reading it, I was very excited to see something like this available, because unit testing JavaScript inside an add-on has not typically been a fun experience for me. I played with the extension this past weekend, and this entry documents my thoughts. (You should definitely read John&#8217;s post first if you are not familiar with FireUnit.)</p>
<p>The first step is obviously to download the extension, available at <a href="http://fireunit.org">http://fireunit.org</a>. I put a &quot;Hello World&quot;-type test together just to see the results. It should be no surprise that I saw the results in Firebug&#8217;s new Test panel when I opened the HTML page in Firefox.</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: blue">&lt;</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></p>
<p style="margin: 0px">fireunit.ok(<span style="color: #a31515">&quot;Hello World&quot;</span>, <span style="color: #a31515">&quot;&#8217;Hello World&#8217; is truthy!&quot;</span>);</p>
<p style="margin: 0px"><span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></p>
</p></div>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/01/image.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="127" alt="image" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/01/image-thumb.png" width="342" border="0" /></a> </p>
<p>So far so good. I noticed that FireUnit supported running tests from multiple HTML files, so I tried that based on what I found on the <a href="http://github.com/jeresig/fireunit/wikis/examples">FireUnit examples wiki page</a>.</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: blue">&lt;</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></p>
<p style="margin: 0px"><span style="color: blue">if</span> (fireunit.forceHttp()) {</p>
<p style="margin: 0px">&#160;&#160;&#160; fireunit.runTests(<span style="color: #a31515">&quot;1.html&quot;</span>, <span style="color: #a31515">&quot;2.html&quot;</span>);</p>
<p style="margin: 0px">}</p>
<p style="margin: 0px"><span style="color: blue">&lt;/</span><span style="color: #a31515">script</span><span style="color: blue">&gt;</span></p>
</p></div>
<p>I was a bit disappointed to see the following chrome error in Firebug when I ran this page:</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/01/image1.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="34" alt="image" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2009/01/image-thumb1.png" width="432" border="0" /></a> </p>
<p>What I should&#8217;ve done immediately was to download the source, but I was already sucked into hacking my local version to get it to work. I eventually did download the <a href="http://github.com/jeresig/fireunit/">FireUnit source</a>, but I still received errors like &quot;nsHttpServer is not defined.&quot; (I tried to discover the cause of this problem, but after a couple hours of tweaking the <a href="http://github.com/jeresig/fireunit/tree/master/chrome/content/fireunit/httpd.js">httpd.js file</a>, I decided to cut my losses and try something else.)</p>
<p>Not to be deterred (mainly because I really like the idea of FireUnit), I set out on writing an alternative to running test suites. What I created wasn&#8217;t pretty, but it was functional. I overwrote the fireunit.runTests function to take each argument and make a synchronous XMLHttpRequest for that specific page. Once I received the page, I would import all of the scripts on that page (i.e. importing the scripts in all of the script elements that had a src attribute). After all the scripts were imported, I would eval() the remaining inline scripts on the page which contained the tests themselves. Finally, I would repeat the process for the next test file, until all tests in all test files had run. It took a while to get this just right, but now I&#8217;m happy building tests instead of test infrastructure.</p>
<p>Another way I&#8217;m being unorthodox with FireUnit is that my tests are actually HTML files embedded in the add-on itself. This offers a few advantages over using a local HTML page but also comes with its own set of disadvantages. The main advantage is that I don&#8217;t have to deal with enabling the UniversalXPConnect privilege in every test function or (more importantly) the code I&#8217;m testing. The main disadvantage is that Firebug will not show the source for script files that exist in chrome (probably with good reason); perhaps this is just a Firebug preference that I&#8217;m missing.</p>
<p><strong>Thoughts on FireUnit</strong>? I like what the extension aims to do and what it allows me to do already, albeit with some heavy tweaking. I know it&#8217;s in its early stages, but I can&#8217;t imagine that everyone would be willing to spend as much time as I did to set up the environment. On the other hand, it&#8217;s possible that not everyone will run into the same issues I did, especially with the nsHttpServer. I can&#8217;t think of much to improve besides making it much easier to run tests from multiple HTML files. About the only thing I would enjoy it would be great to see a <a href="http://docs.jquery.com/QUnit">QUnit-like HTML report</a> for tests, with each module being a separate HTML file.</p>
<p>Now back to testing&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://davedewinter.com/2009/01/06/using-fireunit-for-firefox-add-on-testing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Accelerating Firefox Add-On Development with JavaScript IntelliSense in VS 2008</title>
		<link>http://davedewinter.com/2008/12/24/accelerating-firefox-add-on-development-with-javascript-intellisense-in-vs-2008/</link>
		<comments>http://davedewinter.com/2008/12/24/accelerating-firefox-add-on-development-with-javascript-intellisense-in-vs-2008/#comments</comments>
		<pubDate>Wed, 24 Dec 2008 20:07:16 +0000</pubDate>
		<dc:creator>David DeWinter</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Visual Studio 2008]]></category>
		<category><![CDATA[firefox add-on]]></category>
		<category><![CDATA[firefox extension]]></category>
		<category><![CDATA[intellisense]]></category>
		<category><![CDATA[vs2008]]></category>

		<guid isPermaLink="false">http://blogs.rev-net.com/ddewinter/2008/12/24/accelerating-firefox-add-on-development-with-javascript-intellisense-in-vs-2008/</guid>
		<description><![CDATA[Some folks on the Visual Studio team have done a phenomenal job of enhancing IntelliSense for JavaScript in Visual Studio 2008 and Visual Studio 2008 SP1. So far, I have found numerous articles and videos that discuss how it significantly &#8230; <a href="http://davedewinter.com/2008/12/24/accelerating-firefox-add-on-development-with-javascript-intellisense-in-vs-2008/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Some folks on the Visual Studio team have done a phenomenal job of enhancing IntelliSense for JavaScript in Visual Studio 2008 and Visual Studio 2008 SP1. So far, I have found numerous articles and videos that discuss how it significantly improves the development experience in ASP.NET, but I wanted to share the impact it has on what I do&#8212;Firefox add-ons.</p>
<p>If you&#8217;re not familiar with the architecture of Firefox add-ons, here&#8217;s an <em>extremely abridged</em> top-down view:</p>
<ul>
<li>Most add-ons are implemented with a combination of XUL (XML User Interface Language) for the UI and JavaScript to support it. </li>
<li>Instead of running the context of a web page, the JavaScript runs in the context of a <em>window.</em> </li>
<li>In order to share state across multiple windows, you must use and/or implement XPCOM components. </li>
</ul>
<p>XPCOM components provide services or objects that JavaScript running in a Firefox web page normally does not have privileges for. For example, there are services for file I/O, preference reading and writing, and writing to Firefox&#8217;s JavaScript console. You can also build your own XPCOM components (in JavaScript, C++, among other languages) that enable you to share data across the entire Firefox session or place logic that doesn&#8217;t fit well within the context of a single window.</p>
<p>My use of IDEs for add-ons shifted from Notepad++ to Visual Studio in early 2007 because I needed a better way to organize and search my files, but now I am glad I made the switch for other reasons. The hard about using XPCOM is that unless you have memorized your own interfaces as well as the interfaces of all the components you use, you often find yourself referring back to your IDL files or Mozilla&#8217;s documentation for the exact name of the attributes and functions you need. This arguably slows your momentum when working with XPCOM. But with the new improvements to Visual Studio&#8217;s JavaScript IntelliSense, this problem (almost) fades away completely.</p>
<p>Consider the following XPCOM interface:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px">[scriptable, <span style="color: blue">uuid</span>(770E43E2-7213-4639-ABEB-DED12A7188A9)]</p>
<p style="margin: 0px"><span style="color: blue">interface</span> ITrace : <a href="http://www.xulplanet.com/references/xpcomref/ifaces/nsISupports.html">nsISupports</a></p>
<p style="margin: 0px">{</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs an exception as an error to the JS Console.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;param name=&quot;e&quot;&gt;</span><span style="color: green">The exception to log.</span><span style="color: gray">&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">void</span> error(<span style="color: blue">in</span> <a href="http://www.xulplanet.com/references/xpcomref/ifaces/nsIException.html">nsIException</a> e);</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs a message to the JS Console and the dump window as an informational message.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;param name=&quot;message&quot;&gt;</span><span style="color: green">The message to write.</span><span style="color: gray">&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">void</span> info(<span style="color: blue">in</span> wstring message);</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs an exception to the JS Console as a warning.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;param name=&quot;e&quot;&gt;</span><span style="color: green">The exception to log.</span><span style="color: gray">&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">void</span> warn(<span style="color: blue">in</span> <a href="http://www.xulplanet.com/references/xpcomref/ifaces/nsIException.html">nsIException</a> e);</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs a message to the JS Console and the dump window as a verbose message.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// </span><span style="color: gray">&lt;param name=&quot;message&quot;&gt;</span><span style="color: green">The message to write.</span><span style="color: gray">&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: blue">void</span> verbose(<span style="color: blue">in</span> wstring message);</p>
<p style="margin: 0px">};</p>
</p></div>
<p>Creating an XPCOM component requires an interface specified in XPIDL (shown above) as well as an implementation (not important for this discussion). The interface above should be straightforward to interpret even if you are not familiar with XPIDL. The example shows a simple tracing interface which abstracts away the API pain points of logging data to Firefox&#8217;s JavaScript console. It inherits from <a href="https://developer.mozilla.org/en/NsISupports">nsISupports</a> (the XPCOM equivalent of IUnknown), and its methods take very simple parameters. The scriptable attribute specifies that this interface is callable from JavaScript and hence usable in our add-on. Here&#8217;s some sample code to show from JavaScript how we can invoke this interface.</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: blue">try</span> {</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">// Do something that can throw</span></p>
<p style="margin: 0px">}</p>
<p style="margin: 0px"><span style="color: blue">catch</span> (e) {</p>
<p style="margin: 0px">&#160;&#160;&#160; Components.classes[<span style="color: #a31515">&quot;@example.org/trace;1&quot;</span>].getService(Components.interfaces.ITrace).error(e);</p>
<p style="margin: 0px">}</p>
</p></div>
<p>The indexer on <a href="https://developer.mozilla.org/en/Components.classes">Components.classes</a> returns the object that follows the given contract ID. The contract ID is defined in the implementation (and we hope the documentation); from there we get the service that corresponds to the ITrace interface (this is like a QueryInterface call) and call the error function with the exception that we caught. Of course, there is <em>zero</em> IntelliSense help because Visual Studio doesn&#8217;t know what Components.classes and Components.interfaces are, nor would it have any idea how to find the XPIDL file for a given service to find what functions ITrace actually exposes. We can do much, much better.</p>
<p>Let&#8217;s expose a simple function called &quot;error&quot; that we can include from any other JavaScript file that allows us to do the same thing:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: green">// xpcom-interop.js</span></p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">function</span> logError(e) {</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs an exception as an error to the JS Console.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;param name=&quot;e&quot; type=&quot;nsIException&quot;&gt;The exception to log.&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; Components.classes[<span style="color: #a31515">&quot;@example.org/trace;1&quot;</span>].getService(Components.interfaces.ITrace).error(e);</p>
<p style="margin: 0px">}</p>
</p></div>
<p>Great! Now we have a utility function, we can replace our ugly code before:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: blue">try</span> {</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">// Do something that can throw</span></p>
<p style="margin: 0px">}</p>
<p style="margin: 0px"><span style="color: blue">catch</span> (e) {</p>
<p style="margin: 0px">&#160;&#160;&#160; logError(e);</p>
<p style="margin: 0px">}</p>
</p></div>
<p>Still, though, no love from IntelliSense:</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="280" alt="No JS IntelliSense" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image-thumb.png" width="321" border="0" /></a> </p>
<p>Here we can use the the reference tag in our JS file to enable Intellisense, like this:</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image1.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="312" alt="JS Function IntelliSense" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image-thumb1.png" width="486" border="0" /></a> </p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image2.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="185" alt="JS Parameter IntelliSense" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image-thumb2.png" width="364" border="0" /></a> </p>
<p>Very nice! If we flesh out this xpcom-interop file more, our development time can really improve.</p>
<p>Something you need to be aware of is that sometimes the XPCOM interop file can become too complicated for Visual Studio to parse correctly because it references objects that it might not know exist (<em>e.g.</em> Components.classes, Components.interfaces, Components.results). If this is the case, add an <em>xxx</em>.debug.js file in the same directory as the <em>xxx</em>.js file and write all of your documentation there. For example, I could keep xpcom-interop.js like this:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: green">// xpcom-interop.js</span></p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">function</span> logError(e) {</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs an exception as an error to the JS Console.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;param name=&quot;e&quot; type=&quot;nsIException&quot;&gt;The exception to log.&lt;/param&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; Components.classes[<span style="color: #a31515">&quot;@example.org/trace;1&quot;</span>].getService(Components.interfaces.ITrace).error(e);</p>
<p style="margin: 0px">}</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">var</span> prefService = Components.classes[<span style="color: #a31515">&quot;@mozilla.org/preferences-service;1&quot;</span>].getService(Components.interfaces.nsIPrefService);</p>
</p></div>
<p>(Note that because we reference Components.classes outside of the logError function we see this when updating IntelliSense (Ctrl+Shift+J).)</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image3.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="85" alt="IntelliSense Update Error" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image-thumb3.png" width="528" border="0" /></a> </p>
<p>And I could also create a new xpcom-interop.debug.js file for documentation purposes:</p>
<div style="font-size: 10pt; background: white; color: black; font-family: courier new">
<p style="margin: 0px"><span style="color: green">// xpcom-interop.debug.js</span></p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">function</span> logError(e) {</p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// Logs an exception as an error to the JS Console.</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;/summary&gt;</span></p>
<p style="margin: 0px">&#160;&#160;&#160; <span style="color: green">/// &lt;param name=&quot;e&quot; type=&quot;nsIException&quot;&gt;The exception to log.&lt;/param&gt;</span></p>
<p style="margin: 0px">}</p>
<p style="margin: 0px">&#160;</p>
<p style="margin: 0px"><span style="color: blue">var</span> prefService = {};</p>
</p></div>
<p>Notice that I don&#8217;t include any code for the logError function this time. This file is intended for documentation purposes only; it will <em>never</em> be included with the final Firefox add-on because it <em>doesn&#8217;t do anything</em>. If you go back to the default.js file and refresh IntelliSense (Ctrl+Shift+J), IntelliSense will display the same help for the logError function in addition to displaying the prefService variable. When you place the reference tag at the top of a file, Visual Studio will look for <em>filename</em>.debug.js before checking the actual file that the tag references, which is very useful in these situations.</p>
<p><a href="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image4.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="323" alt="prefService shown in IntelliSense" src="http://blogs.rev-net.com/ddewinter/wp-content/uploads/2008/12/image-thumb4.png" width="359" border="0" /></a>&#160;</p>
<h3></h3>
<h2>Ctrl+Shift+J Is Your Friend!</h2>
<p>Fiddling with JS IntelliSense can be frustrating if you&#8217;re not aware of how to get it to refresh itself. Ctrl+Shift+J should work. If not, you can find it in the Edit menu under the IntelliSense menu item. Also, you can bind a shortcut to the command &quot;Edit.UpdateJScriptIntelliSense&quot;.</p>
<h2>Resources</h2>
<ol>
<li><a href="http://weblogs.asp.net/bleroy/archive/2007/04/23/the-format-for-javascript-doc-comments.aspx">Format for JavaScript Doc Comments</a> </li>
<li><a href="http://blogs.msdn.com/webdevtools/archive/2008/11/07/hotfix-to-enable-vsdoc-js-intellisense-doc-files-is-now-available.aspx">Hotfix to Enable -vsdoc JS files</a> </li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://davedewinter.com/2008/12/24/accelerating-firefox-add-on-development-with-javascript-intellisense-in-vs-2008/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>AJAX Response Text and Question Marks (Replacement Characters)</title>
		<link>http://davedewinter.com/2007/07/02/ajax-response-text-and-question-marks-replacement-characters/</link>
		<comments>http://davedewinter.com/2007/07/02/ajax-response-text-and-question-marks-replacement-characters/#comments</comments>
		<pubDate>Mon, 02 Jul 2007 18:25:00 +0000</pubDate>
		<dc:creator>David DeWinter</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[overrideMimeType]]></category>
		<category><![CDATA[question marks]]></category>
		<category><![CDATA[replacement character]]></category>
		<category><![CDATA[ResponseText]]></category>
		<category><![CDATA[Web 2.0]]></category>
		<category><![CDATA[XHR]]></category>
		<category><![CDATA[XMLHttpRequest]]></category>

		<guid isPermaLink="false">http://dev.rev-net.com/blog/ddewinter/?p=15</guid>
		<description><![CDATA[So in my Firefox plugin development phase, I’ve been working with a lot of AJAX to enable new “Web 2.0″ functionality in some sites that I go to. Recently one of my testers encountered a bug with this AJAX that &#8230; <a href="http://davedewinter.com/2007/07/02/ajax-response-text-and-question-marks-replacement-characters/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div class="postentry">
<p>So in my Firefox plugin development phase, I’ve been working with a lot of AJAX to enable new “Web 2.0″ functionality in some sites that I go to. Recently one of my testers encountered a bug with this AJAX that caused non-ASCII characters (e.g. ») returned by the responseText property of the XMLHttpRequest object to turn into <a href="http://www.fileformat.info/info/unicode/char/fffd/index.htm">replacement characters</a>.</p>
<p>This has to do with the MIME encoding used by the server to return the response <strong></strong>you’re looking for. This is encapsulated in the Content-Type response header. If that header doesn’t contain the correct information to actually parse the response, then the XMLHttpRequest object will return these “replacement characters” (uFFFD) to substitute the characters it doesn’t recognize in its responseText.</p>
<p>One way to override this Content-Type so that the responseText will have the “expected” text is to use the <em>overrideMimeType</em> method on the object, which, as its name suggests, “overrides the mime type returned by the server (if any). This may be used, for example, to force a stream to be treated and parsed as text/xml, even if the server does not report it as such. This must be done before the send method is invoked.” (XULPlanet &#8211; http://www.xulplanet.com/references/objref/XMLHttpRequest.html#method_overrideMimeType)</p>
<p>For example:</p>
<p>// getXmlHttp() = browser-friendly way to create XMLHttpRequest</p>
<p>var xmlHttpRequest = getXmlHttp();<br />
xmlHttpRequest.overrideMimeType(”application/xml; charset=ISO-8859-1″);</p>
<p>// Do other work normally</p>
<p>The syntax for the String input for the overrideMimeType method is the same as the Content-Type response header. Setting the content-type as application/xml will also allow you to use the responseXML property of the XMLHttpRequest even though the server might not report the page as XML. Hope this helps anyone that’s been experiencing these sorts of problems.</p></div>
]]></content:encoded>
			<wfw:commentRss>http://davedewinter.com/2007/07/02/ajax-response-text-and-question-marks-replacement-characters/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

