<?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>I does Javascript! &#187; Beating IE into submission</title>
	<atom:link href="http://blog.stchur.com/category/beating-ie-into-submission/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.stchur.com</link>
	<description>If you don&#039;t expect too much from me, you might not be let down.</description>
	<lastBuildDate>Tue, 03 Jan 2012 16:01:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Hello Old Friend</title>
		<link>http://blog.stchur.com/2008/10/10/hello-old-friend/</link>
		<comments>http://blog.stchur.com/2008/10/10/hello-old-friend/#comments</comments>
		<pubDate>Fri, 10 Oct 2008 12:59:13 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[CSS Related]]></category>
		<category><![CDATA[MiniPosts]]></category>
		<category><![CDATA[Web-related]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[font-size]]></category>
		<category><![CDATA[IE6]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/10/10/hello-old-friend/</guid>
		<description><![CDATA[More evidence that I was right when I wrote this post. Won't be long now IE6...]]></description>
			<content:encoded><![CDATA[<p>More <a href = "http://orderedlist.com/articles/hello-old-friend" title = "font-size with pixels no longer considered harmful">evidence</a> that I was right when I wrote <a href = "http://blog.stchur.com/2008/01/15/ie5-is-dead-and-ie6-is-on-death-row/" title = "IE5 is Dead (and IE6 is on Death Row)">this post</a>.</p>

<p>Won't be long now IE6...</p>]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/10/10/hello-old-friend/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Ultimate addEvent(..) function</title>
		<link>http://blog.stchur.com/2008/09/25/the-ultimate-addevent-function/</link>
		<comments>http://blog.stchur.com/2008/09/25/the-ultimate-addevent-function/#comments</comments>
		<pubDate>Thu, 25 Sep 2008 18:32:17 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Advanced Javascript]]></category>
		<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[Cross-Browser]]></category>
		<category><![CDATA[Firefox Related]]></category>
		<category><![CDATA[Useful Functions]]></category>
		<category><![CDATA[Gimme]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Ultimate addEvent]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/09/25/the-ultimate-addevent-function/</guid>
		<description><![CDATA[Two articles in particular that I've written on this blog have garnered a lot of positive feedback. Fixing IE's attachEvent Failures mouseenter and mouseleave Events for Firefox (and other Non-IE Browsers) As time has gone on, I've seen mention of these articles pop up in programming forums here and there, and they still receive comments [...]]]></description>
			<content:encoded><![CDATA[	<p>Two articles in particular that I've written on this blog have garnered a lot of positive feedback.</p>
	<ol>
	<li><a href = "http://blog.stchur.com/2006/10/12/fixing-ies-attachevent-failures/" title = "Fixing IE's attachEvent Failures">Fixing IE's attachEvent Failures</a></li>
	<li><a href = "http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/" title = "mouseenter and mouseleave Events for Firefox (and other Non-IE Browsers)">mouseenter and mouseleave Events for Firefox (and other Non-IE Browsers)</a></li>
	</ol>
	<p>As time has gone on, I've seen mention of these articles pop up in programming forums here and there, and they still receive comments from time to time, which lets me know that people are still getting something out of them.</p>
	<p>Unfortunately, the code in them is a tad dated.  I've learned more and improved my code since I originally wrote them, and while these improvements have made their way into my <a href = "http://gimme.stchur.com" title = "The Gimme Javascript Library">Javascript Library</a>, I know that the majority of people are just grabbing the code directly from the blog entries.</p>
	<p>So I've decided to post an update: a sort of fusion between these two blog entries which offers functionality for addressing all of the issues discussed in the aforementioned entries (and then some).</p>
	<p>I consider this new function the "Ultimate addEvent Function" because I really believe it addresses the large majority of cross-browser issues that people face when dealing with events in Javascript.  And furthermore, this function goes beyond anything that any other Javascript library provides (at least as far as I know).</p>
	<p>So without further ado, I offer to you:</p>
	<h3>sstchur's Ultimate addEvent(..) function!</h3></p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> xb = <span class="br0">&#123;</span><span class="br0">&#125;</span>;<br />
<span class="br0">&#40;</span><span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> GUIDCounter = <span class="nu0">0</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> evtHash = <span class="br0">&#123;</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> pseudoEvents =<br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="st0">'mouseenter'</span>: <span class="kw2">function</span><span class="br0">&#40;</span>_fn, _useCapture, _listening<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> f = mouseEnter<span class="br0">&#40;</span>_fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_listening ?<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;xb.<span class="me1">addEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, <span class="st0">'mouseover'</span>, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span> :<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;xb.<span class="me1">removeEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, <span class="st0">'mouseover'</span>, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;f = <span class="kw2">null</span>;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>,<br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="st0">'mouseleave'</span>: <span class="kw2">function</span><span class="br0">&#40;</span>_fn, _useCapture, _listening<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> f = mouseEnter<span class="br0">&#40;</span>_fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_listening ?<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;xb.<span class="me1">addEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, <span class="st0">'mouseout'</span>, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span> :<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;xb.<span class="me1">removeEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, <span class="st0">'mouseout'</span>, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;f = <span class="kw2">null</span>;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;xb.<span class="me1">Helper</span> =<br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;getObjectGUID: getObjectGUID,<br />
&nbsp; &nbsp;&nbsp; &nbsp;storeHandler: storeHandler,<br />
&nbsp; &nbsp;&nbsp; &nbsp;retrieveHandler: retrieveHandler,<br />
&nbsp; &nbsp;&nbsp; &nbsp;isAnAncestorOf: isAnAncestorOf,<br />
&nbsp; &nbsp;&nbsp; &nbsp;mouseEnter: mouseEnter<br />
&nbsp; &nbsp;<span class="br0">&#125;</span>;&nbsp;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;xb.<span class="me1">addEvent</span> = <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> document.<span class="me1">addEventListener</span> !== <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> w3c_addEvent;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> document.<span class="me1">attachEvent</span> !== <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> ie_addEvent;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// no modern event support I guess <img src='http://blog.stchur.com/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> </span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// (you could use DOM 0 here if you really wanted to)</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">function</span> w3c_addEvent<span class="br0">&#40;</span>_elem, _evtName, _fn, _useCapture, _directCall<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> eventFn = pseudoEvents<span class="br0">&#91;</span>_evtName<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> eventFn === <span class="st0">'function'</span> &amp;&amp; _directCall !== <span class="kw2">false</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;eventFn.<span class="me1">call</span><span class="br0">&#40;</span>_elem, _fn, _useCapture, <span class="kw2">true</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_elem.<span class="me1">addEventListener</span><span class="br0">&#40;</span>_evtName, _fn, _useCapture<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">function</span> ie_addEvent<span class="br0">&#40;</span>_elem, _evtName, _fn, _useCapture, _directCall<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> eventFn = pseudoEvents<span class="br0">&#91;</span>_evtName<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> eventFn === <span class="st0">'function'</span> &amp;&amp; _directCall !== <span class="kw2">false</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;eventFn.<span class="me1">call</span><span class="br0">&#40;</span>_elem, _fn, _useCapture, <span class="kw2">true</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// create a key to identify this element/event/function combination</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> key = generateHandlerKey<span class="br0">&#40;</span>_elem, _evtName, _fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// if this element/event/combo has already been wired up, just return</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> f = evtHash<span class="br0">&#91;</span>key<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> f !== <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// create a helper function to fix IE's lack of standards support</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;f = <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// map .target to .srcElement</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">target</span> = e.<span class="me1">srcElement</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// map .relatedTarget to either .toElement or .fromElement</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>_evtName == <span class="st0">'mouseover'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> e.<span class="me1">relatedTarget</span> = e.<span class="me1">fromElement</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>_evtName == <span class="st0">'mouseout'</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> e.<span class="me1">relatedTarget</span> = e.<span class="me1">toElement</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">preventDefault</span> = <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> e.<span class="me1">returnValue</span> = <span class="kw2">false</span>; <span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">stopPropagation</span> = <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> e.<span class="me1">cancelBubble</span> = <span class="kw2">true</span>; <span class="br0">&#125;</span>;</p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// call the actual function, using entity (the element) as the 'this' object</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_fn.<span class="me1">call</span><span class="br0">&#40;</span>_elem, e<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// null out these properties to prevent memory leaks</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">target</span> = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">relatedTarget</span> = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">preventDefault</span> = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e.<span class="me1">stopPropagation</span> = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;e = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// add the helper function to the event hash</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;evtHash<span class="br0">&#91;</span>key<span class="br0">&#93;</span> = f;</p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// hook up the event (IE style)</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_elem.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'on'</span> + _evtName, f<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;key = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;f = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="br0">&#125;</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
	<p>&nbsp; &nbsp;xb.<span class="me1">defineEvent</span> = <span class="kw2">function</span><span class="br0">&#40;</span>_evtName, _logicFn<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;pseudoEvents<span class="br0">&#91;</span>_evtName<span class="br0">&#93;</span> = _logicFn;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span>;</p>
	<p>&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// Helper Functions</span><br />
&nbsp; &nbsp;<span class="kw2">function</span> storeHandler<span class="br0">&#40;</span>_key, _handler<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;evtHash<span class="br0">&#91;</span>_key<span class="br0">&#93;</span> = _handler;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> retrieveHandler<span class="br0">&#40;</span>_key<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> evtHash<span class="br0">&#91;</span>_key<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> generateHandlerKey<span class="br0">&#40;</span>_elem, _evtName, _handler<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="st0">'{'</span> + getObjectGUID<span class="br0">&#40;</span>_elem<span class="br0">&#41;</span> + <span class="st0">'/'</span> + _evtName + <span class="st0">'/'</span> + getObjectGUID<span class="br0">&#40;</span>_handler<span class="br0">&#41;</span> + <span class="st0">'}'</span>;&nbsp;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> isAnAncestorOf<span class="br0">&#40;</span>_ancestor, _descendant, _generation<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>_ancestor === _descendant<span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw1">return</span> <span class="kw2">false</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> gen = <span class="nu0">0</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">while</span> <span class="br0">&#40;</span>_descendant &amp;&amp; _descendant != _ancestor<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;gen++;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_descendant = _descendant.<span class="me1">parentNode</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;_generation = _generation || gen;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> _descendant === _ancestor &amp;&amp; _generation === gen;&nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> mouseEnter<span class="br0">&#40;</span>_fn<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span>&nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> key = xb.<span class="me1">Helper</span>.<span class="me1">getObjectGUID</span><span class="br0">&#40;</span>_fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> f = evtHash<span class="br0">&#91;</span>key<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> f === <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;f = evtHash<span class="br0">&#91;</span>key<span class="br0">&#93;</span> = <span class="kw2">function</span><span class="br0">&#40;</span>_evt<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> relTarget = _evt.<span class="me1">relatedTarget</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">this</span> === relTarget || isAnAncestorOf<span class="br0">&#40;</span><span class="kw1">this</span>, relTarget<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw1">return</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_fn.<span class="me1">call</span><span class="br0">&#40;</span><span class="kw1">this</span>, _evt<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> f;&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="kw2">function</span> getObjectGUID<span class="br0">&#40;</span>_elem<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>_elem === window<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="st0">'theWindow'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>_elem === document<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="st0">'theDocument'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> _elem.<span class="me1">uniqueID</span> !== <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> _elem.<span class="me1">uniqueID</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span></p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> ex = <span class="st0">'__$$GUID$$__'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> _elem<span class="br0">&#91;</span>ex<span class="br0">&#93;</span> === <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_elem<span class="br0">&#91;</span>ex<span class="br0">&#93;</span> = ex + GUIDCounter++;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> _elem<span class="br0">&#91;</span>ex<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
	<p><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
	<div class = "note">The code above, as is, won't work "out of the box" because (for the sake of brevity) I have not included the <code>xb.removeEvent(..)</code> function.  Fear not however.  There will be a link to a download of the full source code, complete with both <code>xb.addEvent(..)</code> and <code>xb.removeEvent(..)</code> at the end of this post.</div>
	<h3>Commentary</h3>
	<p>So some of you may be wondering: "Why <em>another</em> addEvent function.  Haven't we been through this?"  We have, but I think you'll find that this version does more than any other addEvent function you've seen.  For example:</p>
	<ul>
	<li>Works in all browsers that matter</li>
	<li>Ensures <em>one</em> event wire up for any given element/event/handler combination (this is mostly for IE)</li>
	<li>Forces IE to honor the <code>this</code> keyword from within event handler functions</li>
	<li>Normalizes the wire up mechanism in all browsers (no need to include the "on" prefix for IE)</li>
	<li>Forces IE to recognize the following properties/methods on event objects: <code>.stopPropagation()</code>, <code>.preventDefault()</code>, <code>.target</code>, <code>.relatedTarget</code></li>
	<li>Enhances Non-IE browsers to support <code>mouseenter</code> and <code>mouseleave</code> events</li>
	<li>Provides an extension mechanism so developers can write their own custom events that plug right in ('mousewheel' or 'DOMContentReady' for example)</li>
	</ul>
	<p>Given all that the Ultimate addEvent function does, it's not surprising that it has a bit of length to it.  But it isn't super long, and I think it's well worth it.</p>
	<h3>Usage</h3>
	<p>Using the function(s) is just as easy as you'd expect:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> myDiv = document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">'myDiv'</span><span class="br0">&#41;</span>;<br />
xb.<span class="me1">addEvent</span><span class="br0">&#40;</span>myDiv, <span class="st0">'click'</span>, clickHandler<span class="br0">&#41;</span>;</p>
	<p><span class="kw2">function</span> clickHandler<span class="br0">&#40;</span>e<span class="br0">&#41;</span></p>
	<p>
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'The this keywords works (even in IE!): '</span> + <span class="kw1">this</span>.<span class="me1">id</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span></div>
	<h3>Extending Functionality</h3>
	<p>Since I mentioned that it was possible to extend the Ultimate addEvent function with custom events that plug right in, I figure I'd better offer an example.  Actually, there already is an example built right into it.  Both the <code>mouseenter</code> and <code>mouseleave</code> events utilize the extension mechanism internally, but for demonstration purposes, let's go ahead and add a <code>mousewheel<code> event:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="co1">// Extend the Ultimate addEvent function to recognize a &quot;mousewheel&quot; event</span><br />
xb.<span class="me1">defineEvent</span><span class="br0">&#40;</span><span class="st0">'mousewheel'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>_fn, _useCapture, _listening<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// event name for IE, Opera and Safari</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> evtName = <span class="st0">'mousewheel'</span>;</p>
	<p>&nbsp; &nbsp;<span class="co1">// hander for IE, Opera, and Safari</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> f = _fn;<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<span class="co1">// if we're dealing with a Gecko browser, the event name</span><br />
&nbsp; &nbsp;<span class="co1">// and handler need some adjustment</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> ua = navigator.<span class="me1">userAgent</span>.<span class="me1">toLowerCase</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>ua.<span class="me1">indexOf</span><span class="br0">&#40;</span><span class="st0">'khtml'</span><span class="br0">&#41;</span> === <span class="nu0">-1</span> &amp;&amp; ua.<span class="me1">indexOf</span><span class="br0">&#40;</span><span class="st0">'gecko'</span><span class="br0">&#41;</span> !== <span class="nu0">-1</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;evtName = <span class="st0">'DOMMouseScroll'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;f = mouseWheel<span class="br0">&#40;</span>_fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
	<p>&nbsp; &nbsp;<span class="co1">// _listening represents whether this is an event attachment or detachment</span><br />
&nbsp; &nbsp;<span class="co1">// that 5th parameter? &nbsp;Don't worry about it; just always use false</span><br />
&nbsp; &nbsp;_listening ? xb.<span class="me1">addEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, evtName, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span> : xb.<span class="me1">removeEvent</span><span class="br0">&#40;</span><span class="kw1">this</span>, evtName, f, _useCapture, <span class="kw2">false</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>;</p>
	<p><span class="co1">// Helper function for dealing with mousewheel in Gecko browsers</span><br />
<span class="kw2">function</span> mouseWheel<span class="br0">&#40;</span>_fn<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw2">var</span> key = xb.<span class="me1">Helper</span>.<span class="me1">getObjectGUID</span><span class="br0">&#40;</span>_fn<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw2">var</span> f = xb.<span class="me1">Helper</span>.<span class="me1">retrieveHandler</span><span class="br0">&#40;</span>key<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> f === <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;f = <span class="kw2">function</span><span class="br0">&#40;</span>_evt<span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_evt.<span class="me1">wheelDelta</span> = -<span class="br0">&#40;</span>_evt.<span class="me1">detail</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_fn.<span class="me1">call</span><span class="br0">&#40;</span><span class="kw1">this</span>, _evt<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;_evt.<span class="me1">wheelDelta</span> = <span class="kw2">null</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;xb.<span class="me1">Helper</span>.<span class="me1">storeHandler</span><span class="br0">&#40;</span>key, f<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;<span class="kw1">return</span> f;<br />
<span class="br0">&#125;</span></div>
	<p>I'm glossing over some details here because I don't want this post to get bogged down in something that it isn't really about, but I trust you get the idea.</p>
	<p>Most of this code actually comes from the <a href = "http://gimme.stchur.com" title = "The Gimme Javascript Library">The Gimme Javascript Library</a>.  If you're using Gimme in any of your web pages, you already have all of this functionality for free.  The syntax is a touch different, but all the capabilities are the same.</p>
	<p>And if you happen to be the author of a Live Maps Mashup, you already have Gimme, as the latest version shipped with the most recent <a href = "http://dev.virtualearth.net" title = "Virtual Earth MapControl Developers">Virtual Earth MapControl</a>.</p>
	<p><a name="end"></a></p>
	<h3>Complete Source</h3>
	<p>As promised, here is the <a href = "http://blog.stchur.com/blogcode/ultimate_addevent/ultimate.zip" title = "The Ultimate addEvent function">complete source</a>, including both <code>xb.addEvent(..)</code> and <code>xb.removeEvent(..)</code></p>
	<p>Enjoy! And please don't hesitate to send your feedback, both good and bad (I'm very willing to address issues or try to make requested enhancements).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/09/25/the-ultimate-addevent-function/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Wither IE6?</title>
		<link>http://blog.stchur.com/2008/07/22/wither-ie6/</link>
		<comments>http://blog.stchur.com/2008/07/22/wither-ie6/#comments</comments>
		<pubDate>Tue, 22 Jul 2008 13:00:07 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[MiniPosts]]></category>
		<category><![CDATA[Opinions]]></category>
		<category><![CDATA[Web-related]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/07/22/wither-ie6/</guid>
		<description><![CDATA[Welcome aboard guys. Glad you finally decided to start thinking about what I discussed long ago.]]></description>
			<content:encoded><![CDATA[<p>Welcome aboard <a href = "http://ajaxian.com/archives/pondering-support-of-ie6" title = "Pondering Support for IE6">guys</a>.  Glad you <em>finally</em> decided to start thinking about what <a href = "http://blog.stchur.com/2008/01/15/ie5-is-dead-and-ie6-is-on-death-row/" title = "IE5 is dead (and IE6 is on death row)">I discussed</a> long ago.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/07/22/wither-ie6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE8 to act like IE8!</title>
		<link>http://blog.stchur.com/2008/03/03/ie8-to-act-like-ie8/</link>
		<comments>http://blog.stchur.com/2008/03/03/ie8-to-act-like-ie8/#comments</comments>
		<pubDate>Tue, 04 Mar 2008 03:39:57 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[MiniPosts]]></category>
		<category><![CDATA[Web-related]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/03/03/ie8-to-act-like-ie8/</guid>
		<description><![CDATA[Looks like all the whining and moaning finally paid off. Who said Microsoft doesn't listen to the community?]]></description>
			<content:encoded><![CDATA[<p>Looks like all the whining and moaning finally <a href = "http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx" title = "Microsoft's Interoperability Principles and IE8">paid off</a>.  Who said Microsoft doesn't listen to the community?</p>]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/03/03/ie8-to-act-like-ie8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE quirk with onload event for &lt;img&gt; elements</title>
		<link>http://blog.stchur.com/2008/02/26/ie-quirk-with-onload-event-for-img-elements/</link>
		<comments>http://blog.stchur.com/2008/02/26/ie-quirk-with-onload-event-for-img-elements/#comments</comments>
		<pubDate>Tue, 26 Feb 2008 17:50:26 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Gimme]]></category>
		<category><![CDATA[Javascript basics]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/02/26/ie-quirk-with-onload-event-for-img-elements/</guid>
		<description><![CDATA[I rediscovered something yesterday that I know I've come across in the past. Still, it was driving me crazy until I finally did a little web searching and found what I needed. It was one of those "oh right! I've encountered that before" moments. I was writing a script that dealt with images and I [...]]]></description>
			<content:encoded><![CDATA[	<p>I rediscovered something yesterday that I know I've come across in the past.  Still, it was driving me crazy until I finally did a little web searching and found what I needed.  It was one of those "oh right! I've encountered that before" moments.</p>
	<p>I was writing a script that dealt with images and I needed to know when an image had finished loading.  Simple enough.  Using Gimme (or your favorite addEvent(..)) equalizer the code looks something like:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> myImage = document.<span class="me1">createElement</span><span class="br0">&#40;</span><span class="st0">'img'</span><span class="br0">&#41;</span>;<br />
myImage.<span class="me1">src</span> = <span class="st0">'http://source.to.image/image.jpg'</span>;<br />
g<span class="br0">&#40;</span>myImage<span class="br0">&#41;</span>.<span class="me1">addEvent</span><span class="br0">&#40;</span><span class="st0">'load'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'Image is done loading!'</span><span class="br0">&#41;</span>; <span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
	<p>It turns out that my load handler wasn't always firing in IE (in Firefox it worked consistently). The solution though is super simple.</p>
	<p>You just need to make sure that you wire up the load handler <em>before</em> setting the image element's <code>.src</code> property.  Why?  Because if the image is being loaded from cache, IE (and Opera too) will load the image instantly.  In fact, it will have finished loading the image before your load event handler is even wired up, which means, it won't fire!</p>
	<p>Just change the code to something like this:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> myImage = document.<span class="me1">createElement</span><span class="br0">&#40;</span><span class="st0">'img'</span><span class="br0">&#41;</span>;<br />
myImage.<span class="me1">addEvent</span><span class="br0">&#40;</span><span class="st0">'load'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'Image is done loading!'</span><span class="br0">&#41;</span>; <span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
myImage.<span class="me1">src</span> = <span class="st0">'http://source.to.image/image.jpg'</span>;</div>
	<p>And there you have it.</p>
	<p>Nothing earth-shattering and probably common knowledge for a lot of scripters, but a little refresher never hurts.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/02/26/ie-quirk-with-onload-event-for-img-elements/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Style anything in IE</title>
		<link>http://blog.stchur.com/2008/01/28/style-anything-in-ie/</link>
		<comments>http://blog.stchur.com/2008/01/28/style-anything-in-ie/#comments</comments>
		<pubDate>Mon, 28 Jan 2008 19:11:48 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.stchur.com/2008/01/28/style-anything-in-ie/</guid>
		<description><![CDATA[A lot of people have been writing about this recently, and I can't take credit for discovering it. I first saw it here and then again here, but I'll recap it briefly on this blog for anyone who is too lazy to follow those links. Under normal circumstances, IE won't allow you style tags that [...]]]></description>
			<content:encoded><![CDATA[	<p>A lot of people have been writing about this recently, and I can't take credit for discovering it.  I first saw it <a href = "http://ajaxian.com/archives/getting-html-5-styles-in-ie-7" title = "Getting HTML5 Styles in IE 7">here</a> and then again <a href = "http://domscripting.com/blog/display/113" title = "ABBRacadabra">here</a>, but I'll recap it briefly on this blog for anyone who is too lazy to follow those links.</p>
	<p>Under normal circumstances, IE won't allow you style tags that it doesn't recognize.  But there is an interesting quirk in IE that will allow you to work around this and style unknown elements.  All you have to do is create an element whose tag name is that which you desire to style, like so:</p>
	<div class="dean_ch" style="white-space: nowrap;">document.<span class="me1">createElement</span><span class="br0">&#40;</span><span class="st0">'myNewTag'</span><span class="br0">&#41;</span>;</div>
	<div class = "note">Note that there is no need to actually add the newly created element to the DOM, or even store it in a variable.  Just the process of "creating" the element is enough to "wake IE up" to the fact that such a tag exists.</div>
	<p>With the Javascript in place, you could then do:</p>
	<div class="dean_ch" style="white-space: nowrap;">
&lt;style type = <span class="st0">&quot;text/css&quot;</span>&gt;<br />
myNewTag<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">border</span>: <span class="re3">5px</span> <span class="kw2">solid</span> <span class="re0">#f00</span>;<br />
&nbsp; &nbsp;<span class="kw1">background</span>: <span class="re0">#00f</span>;<br />
&nbsp; &nbsp;<span class="kw1">font-weight</span>: <span class="kw2">bold</span>;<br />
<span class="br0">&#125;</span><br />
&lt;/style&gt;</div>
	<div class="dean_ch" style="white-space: nowrap;"><span class="sc3"><span class="re1">&lt;myNewTag<span class="re2">&gt;</span></span></span>Brand new tag that has never existed before!<span class="sc3"><span class="re1">&lt;/myNewTag<span class="re2">&gt;</span></span></span></div>
	<p>Now IE will happily style all &lt;myNewTag&gt; elements with a red border, a blue background and bold text.</p>
	<p>This goes for <em>any</em> tag that IE would not normally recognize, but it may prove especially useful in handling <a href = "http://www.w3.org/html/wg/html5/" title = "HTML5 Spec">HTML5</a> down the road.</p>
	<p>So there ya go... another IE quirk "to the rescue."</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2008/01/28/style-anything-in-ie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clean up after your event listeners</title>
		<link>http://blog.stchur.com/2007/09/06/clean-up-after-your-event-listeners/</link>
		<comments>http://blog.stchur.com/2007/09/06/clean-up-after-your-event-listeners/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 06:01:02 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Javascript basics]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://stchur.com/blog2/2007/09/06/clean-up-after-your-event-listeners/</guid>
		<description><![CDATA[Memory leaks in Javascript are, unfortunately, a very real problem. Of course, it seems to be a problem mostly in IE (try disabling all add-ons if you think you're seeing them in Firefox). While there are a number of ways that memory can be leaked, I find that one of the most significant (and most [...]]]></description>
			<content:encoded><![CDATA[	<p>Memory leaks in Javascript are, unfortunately, a very real problem. Of course, it seems to be a problem mostly in IE (try disabling all add-ons if you think you're seeing them in Firefox).  While there are a number of ways that memory can be leaked, I find that one of the most significant (and most frequent) causes is failing to remove event handlers.</p>
	<div class = "note">
	<p><em>Important Update:</em>  I failed to mention when I originally wrote this post, that you should use caution with this 'unload' technique.  If you are manually unhooking events throughout the life of your web-app (or taking care to manually unhook them on 'unload'), then you might potentially be adding multiple (and unnecessary) 'unload' handlers to the browser.</p>
	<p>This might not seem like a big deal, but in a large and complex app it can actually <em>increase</em> memory consumption dramatically, thereby negating any gain you'd have gotten from the technique!</p>
	</div>
	<h3>Auto Detach with 'unload'</h3>
	<p>In IE, if you wire up an event listener and fail to remove that listener when your page unloads, you're probably asking for a leak. One effective technique to ensure that listeners get removed is to wire up an 'unload' event to the window which detaches the listener for you.  For example:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> elem = document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">'someElem'</span><span class="br0">&#41;</span>;<br />
elem.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, elemClick<span class="br0">&#41;</span>;<br />
window.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'onunload'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;elem.<span class="me1">detachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, elemClick<span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
	<p>Keen readers might have noticed that I solved one problem (removing the 'click' listener from <code>elem</code>) by creating another one (attaching a new, anonymous listener to the windows's 'unload' event).</p>
	<h3>Why is this a problem?</h3>
	<p>In a <a href = "http://ecmascript.stchur.com/2007/01/02/anonymous-function-quick-tips/">previous blog entry</a>, I mentioned that it wasn't possible to remove an event listener if that listener were anonymous, as in:</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="co1">// IE specific code</span><br />
<span class="kw2">var</span> elem = document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">'someElem'</span><span class="br0">&#41;</span>;<br />
elem.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'you clicked it!'</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>;</p>
	<p>elem.<span class="me1">detachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span>&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// WON'T WORK!</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'you clicked it!'</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
	<p>While it's true that the above code won't work, it's not <em>entirely</em> true to say that it's impossible to remove an anonymous listener. Why?  Because every function actually has a reference to itself through its own <code>arguments</code> object.  Specifically, through the <code>.callee</code> property of the <code>arguments</code> object.</p>
	<p>We can use this to our advantage to detach the anonymous 'unload' listener from <em>within</em> the listener itself.</p>
	<div class="dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> elem = document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">'someElem'</span><span class="br0">&#41;</span>;<br />
elem.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, elemClick<span class="br0">&#41;</span>;<br />
window.<span class="me1">attachEvent</span><span class="br0">&#40;</span><span class="st0">'onunload'</span>, <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;elem.<span class="me1">detachEvent</span><span class="br0">&#40;</span><span class="st0">'onclick'</span>, elemClick<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;window.<span class="me1">detachEvent</span><span class="br0">&#40;</span><span class="st0">'onunload'</span>, arguments.<span class="me1">callee</span><span class="br0">&#41;</span>;&nbsp; &nbsp; &nbsp;<span class="co1">// detach this anonymous listener</span><br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
	<h3>Why not just un-anonymize?</h3>
	<p>You certainly could just name all of your functions and then refer to them by name, but sometimes anonymous functions are very useful since they allow to create closures and do other nifty Javascript tricks.  In those cases where it's desirable to use an anonymous function, this technique might be just the ticket!</p>
	<h3>Conclusion</h3>
	<p>I've conveniently (for me anyway) left out any non IE-specific code in this post.  It's worth nothing that I don't generally use this technique except in IE, which means a little cross browser code is in order to ensure that this 'onunload' technique is only used for that browser.</p>
	<p>Of course, it isn't going to hurt anything for other browsers (and it might even help) so there'd be no harm is using it across the board, bu you'll still need to write some cross-browser code (obviously).  I'll leave that as an exercise for the reader though.</p>
	<p>Happy scripting.</p>
	<p>Comments welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2007/09/06/clean-up-after-your-event-listeners/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Introducing Gimme</title>
		<link>http://blog.stchur.com/2007/06/22/introducing-gimme/</link>
		<comments>http://blog.stchur.com/2007/06/22/introducing-gimme/#comments</comments>
		<pubDate>Fri, 22 Jun 2007 17:08:16 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[Cross-Browser]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Useful Functions]]></category>

		<guid isPermaLink="false">http://stchur.com/blog2/2007/06/22/introducing-gimme/</guid>
		<description><![CDATA[It's been quite a while since I've blogged anything significant regarding Javascript. This is largely due to the fact that I've been spending a good bit of my free time working on an open source project I started, called Gimme. Gimme is a Javascript Library designed to make performing common tasks, not only easier, but [...]]]></description>
			<content:encoded><![CDATA[	<p>It's been quite a while since I've blogged anything significant regarding Javascript.  This is largely due to the fact that I've been spending a good bit of my free time working on an open source project I started, called Gimme.</p>
	<p>Gimme is a Javascript Library designed to make performing common tasks, not only easier, but down-right trivial.</p>
	<h3>What does Gimme look like?</h3>
	<p>Gimme is remarkably easy to use and was purposely designed to be very readable.  Take the following snippet.</p>
	<div class="dean_ch" style="white-space: nowrap;">
g<span class="br0">&#40;</span><span class="st0">'.moveable'</span><span class="br0">&#41;</span>.<span class="me1">addClass</span><span class="br0">&#40;</span><span class="st0">'hasBeenMoved'</span><span class="br0">&#41;</span>.<span class="me1">slideToPoint</span><span class="br0">&#40;</span><span class="br0">&#123;</span>x: <span class="nu0">0</span>, y: <span class="nu0">0</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
	<p>This code snippet grabs all elements on the page that have the class "moveable", adds to them, the class "hasBeenMoved," and then slides the elements (in a nice accelerated fashion) to the point (0, 0) on the page.  Pretty easy right?</p>
	<p>Believe it not, most tasks in Gimme are this easy (or easier).</p>
	<h3>Get started with Gimme</h3>
	<ul>
	<li>See it in action on the <a href = "http://gimme.stchur.com/demopage.html">Gimme Demo Page</a></li>
	<li>Learn what it can do at the <a href = "http://www.codeplex.com/gimme/Wiki/View.aspx?title=Complete%20API%20Reference&#038;referringTitle=Home">Gimme API Reference Page</a>.</li>
	<li>Download the source on the <a href = "http://www.codeplex.com/gimme/Release/ProjectReleases.aspx">Gimme Releases Page</a>.</li>
	</ul>
	<h3>Your Feedback</h3>
	<p>Gimme is still very young, but I'd love to get your feedback.  Please don't hesitate to try it out and <a href = "mailto:sstchur@yahoo.com">let me know what you think</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2007/06/22/introducing-gimme/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>IE innerHTML Memory Leak</title>
		<link>http://blog.stchur.com/2007/05/16/ie-innerhtml-memory-leak/</link>
		<comments>http://blog.stchur.com/2007/05/16/ie-innerhtml-memory-leak/#comments</comments>
		<pubDate>Wed, 16 May 2007 16:04:11 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[Javascript basics]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://stchur.com/blog2/2007/05/16/ie-innerhtml-memory-leak/</guid>
		<description><![CDATA[Kristoffer Henriksson has got to be one of the most intelligent people I know. His ability to write, test, and debug code is second the none. Heck, I wouldn't be surprised if the guy can read and write machine code as if it were English. Recently, Kristoffer did a significant amount of investigation to track [...]]]></description>
			<content:encoded><![CDATA[	<p><a href = "http://blogs.msdn.com/Kristoffer">Kristoffer Henriksson</a> has got to be one of <em>the</em> most intelligent people I know.  His ability to write, test, and debug code is second the none.  Heck, I wouldn't be surprised if the guy can read and write machine code as if it were English.</p>
	<p>Recently, Kristoffer did a significant amount of investigation to track down a nasty IE memory leak issue.  IE's problems with memory leaks are well known, but most of the time, you'll hear people saying things like "closures are the cause of memory leaks," or "failing to detach events is what causes memory leaks," and (probably the most common), "circular references are the culprit -- they cause memory leaks."</p>
	<p>To some degree, all of these things are true.  Closures can sometimes lead to memory leaks, failing to detach events can also lead to memory leaks, and yes, circular references to DOM elements can also be the cause of memory leaks.</p>
	<p>One kind of leak that seems to get a little less attention though, is the one involving <code>.innerHTML</code>.  Fortunately (thanks to Kristoffer's investigation) this one is pretty easy to deal with.</p>
	<p>Before we can deal with the leak, we need to understand what causes it.  Three conditions are required:</p>
	<ol>
	<li>A orphaned DOM element must exist in memory.</li>
	<li>That element's innerHTML must be set to a string of markup the creates an element with some DOM 0 event wired up.</li>
	<li>The aforementioned innerHTML property must be set <em>before</em> the orphaned DOM element is "unorphaned" (added to the page).</li>
	</ol>
	<p>If these conditions are met, get ready to call the (Javascript) plumber, because you've got a leak!</p>
	<p>To make things a little less abstract, I'll write some code and explain piece by piece, how it fits the conditions above:</p>
	<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">// 1. &nbsp;An orphaned DOM element must exist in memory.</span><br />
<span class="kw2">var</span> elem = document.<span class="me1">createElement</span><span class="br0">&#40;</span><span class="st0">'div'</span><span class="br0">&#41;</span>;<br />
<span class="co1">// poor elem is just floating around in the page's memory without a parentNode</span></p>
	<p><span class="co1">// 2. &nbsp;elem's innerHTML must be set to a string of markup that creates an element with some DOM 0 event wired up.</span><br />
elem.<span class="me1">innerHTML</span> = <span class="st0">'&lt;a onclick = &quot;testFn()&quot;&gt;Test Link&lt;/a&gt;'</span>;<br />
<span class="co1">// elem contains an &lt;a&gt; tag with an onclick event</span></p>
	<p><span class="co1">// 3. &nbsp;elem is now added to the page, &lt;em&gt;after&lt;/em&gt; innerHTML has already been set.</span><br />
document.<span class="me1">body</span>.<span class="me1">appendChild</span><span class="br0">&#40;</span>elem<span class="br0">&#41;</span><br />
<span class="co1">// elem (and its child &lt;a&gt; tag) is now part of the page (remember, that innerHTML has already been set)</span></div>
	<p>As you can see, the code above is not at all an uncommon scenario.  Chances are though, if that's all you've got, you won't notice much of leak.  This issue really only manifests itself when multiplied, that is, when you set <code>.innerHTML</code> in the above manner over and over and over again on the same page.</p>
	<p>Why would ever do this?  Think Web 2.0, think AJAX, think dynamic page updates and you probably won't have to search too hard to find a situation where someone might do this.  Maybe you already know of (or helped write) a Web 2.0 app that does this.</p>
	<h3>Memory Leak Demo Page</h3>
	<p>Anyway, when above pattern <em>is</em> multiplied (whatever the reason) memory leaking chaos will ensue.  To illustrate the problem, I've put together a sample page  with a script that creates a orphaned &lt;div&gt; element, whose <code>.innerHTML</code> is set to a string of 2000 &lt;a&gt; tags with onclick events.  When you click the "Start Leak" button, the script executes repeatedly, until you click the "Stop Leak" button.  This give you a chance to use Perfmon to monitor memory consumption and see the results of the leak. The memory leak demo page can be found <a href = "http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html">here</a>.</p>
	<h3>The solution</h3>
	<p>It turns out, the solution is actually pretty easy:  simply make sure to set <code>.innerHTML</code> <em>after</em> appending the DOM element to the page.  That's it!</p>
	<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">// create the element in memory</span><br />
<span class="kw2">var</span> elem = document.<span class="me1">createElement</span><span class="br0">&#40;</span><span class="st0">'div'</span><span class="br0">&#41;</span>;</p>
	<p><span class="co1">// add it to the page before setting .innerHTML</span><br />
document.<span class="me1">body</span>.<span class="me1">appendChild</span><span class="br0">&#40;</span>elem<span class="br0">&#41;</span></p>
	<p><span class="co1">// now it's safe to set .innerHTML</span><br />
elem.<span class="me1">innerHTML</span> = <span class="st0">'&lt;a onclick = &quot;testFn()&quot;&gt;Test Link&lt;/a&gt;'</span>;</div>
	<div class = "note">
Of course there are other solutions, one of which is to avoid using <code>.innerHTML</code> at all.  As a general best practice, I encourage this (for a number of reasons that I don't have time to get into here), but I recognize that that suggestion may not also be desirable, or practical.
</div>
	<p>To see that this really does take care of the issue, I've put together another <a href = "http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/noleak.html">test page</a>.  In this one, the <code>.innerHTML</code> property is only set <em>after</em> the DOM element has been added to the page.</p>
	<p>If you click the "Start Leak" button on each page and let it run for about 60 seconds or so, you should notice that the first page continues to consume more and more memory as time goes on, whereas the second page's memory consumptions remains relatively constant.</p>
	<h3>Demo Links</h3>
	<p>In case you're the kind of person who doesn't like to read paragraphs to find embedded links (I'm like that), here are the links to the two demo pages, for your convenicne:</p>
	<ul>
	<li><a href = "http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html">Leak Demo</a></li>
	<li><a href = "http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/noleak.html">No Leak Demo</a></li>
	</ul>
	<p>So there ya go: a nasty bug, but thanks to Kristoffer's work tracking tracking down the exact causes of this leak, a fairly easy one to handle.</p>
	<p>Comments welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2007/05/16/ie-innerhtml-memory-leak/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Serializing Objects in Javascript</title>
		<link>http://blog.stchur.com/2007/04/06/serializing-objects-in-javascript/</link>
		<comments>http://blog.stchur.com/2007/04/06/serializing-objects-in-javascript/#comments</comments>
		<pubDate>Fri, 06 Apr 2007 06:12:06 +0000</pubDate>
		<dc:creator>sstchur</dc:creator>
				<category><![CDATA[Beating IE into submission]]></category>
		<category><![CDATA[Cross-Browser]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Mozilla-specific]]></category>
		<category><![CDATA[Useful Functions]]></category>

		<guid isPermaLink="false">http://stchur.com/blog2/2007/04/06/serializing-objects-in-javascript/</guid>
		<description><![CDATA[It's worth noting that this post is rather old at this point. I don't use the function listed in this post anymore and haven't for a rather long time. If you are using it and it's working for you, great! But as Ron in the comments sections points out, there are a few issues with [...]]]></description>
			<content:encoded><![CDATA[	<div class = "note">It's worth noting that this post is rather old at this point.  I don't use the function listed in this post anymore and haven't for a rather long time.  If you are using it and it's working for you, great!  But as Ron in the comments sections points out, there are a few issues with regards to strings and special characters.  I recommend following the link he posts if your needs merit a very robust version of JSON serialization.  I'm leaving this post up though, as I think it's helpful for folks who want to understand the general concept of recursion and serialization.</div>
	<p>Recently, in a personal project I'm working on, I came across a need to be able to represent any Javascript object as a string.  This isn't a problem since just about every object in Javascript can be represented with <abbr title = "Javascript Object Notation">JSON</abbr> (Javascript Object Notation).  Every modern browser can parse <abbr>JSON</abbr> for you easily enough through <code>eval(..)</code>, and Gecko-based browsers even have the ability to reverse the process ("uneval" if you will) and give you back a string representation of an object through a call to <code>.toSource()</code>.</p>
	<p>If you need this ability in any other browser though, you're gonna have to write it yourself.  I needed this ability, so I wrote it (and posted it here for your enjoyment!)</p>
	<p><span id="more-41"></span></p>
	<h3>Gecko-based browsers, .toSource():</h3>
	<p>Gecko-based browsers provide a handy function: <code>.toSource()</code> that you can call on any object in your Javascript code to get back a JSON-like representation of that object.</p>
	<div class="dean_ch" style="white-space: nowrap;">
<span class="kw2">function</span> Cat<span class="br0">&#40;</span><span class="kw3">name</span>, age<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="kw1">this</span>.<span class="kw3">Name</span> = <span class="kw3">name</span>;<br />
&nbsp; &nbsp;<span class="kw1">this</span>.<span class="me1">Age</span> = age;<br />
&nbsp; &nbsp;<span class="kw1">this</span>.<span class="me1">Speak</span> = <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="kw3">alert</span><span class="br0">&#40;</span><span class="st0">'Meow!'</span><span class="br0">&#41;</span>; <span class="br0">&#125;</span>;<br />
<span class="br0">&#125;</span></p>
	<p><span class="kw2">var</span> garfield = <span class="kw2">new</span> Cat<span class="br0">&#40;</span><span class="st0">'Garfield'</span>, <span class="nu0">5</span><span class="br0">&#41;</span>;<br />
<span class="kw3">alert</span><span class="br0">&#40;</span>garfield.<span class="me1">toSource</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</p>
	<p><span class="coMULTI">/* garfield.toSource() yields:<br />
({Name:&quot;Garfield&quot;, Age:5, Speak:(function () {alert(&quot;Meow!&quot;);})})<br />
*/</span><br />
&nbsp;</div>
	<p>Pretty simple right?  You have an object; you want a string.  Just invoke the object's <code>.toSource()</code> function.</p>
	<h3>Serializing objects in other browsers:</h3>
	<p>Serializing an object manually (as is required by non Gecko-based browsers) requires a bit of <a href = "http://en.wikipedia.org/wiki/Recursion">recursion</a>.  Simple types like integers, booleans, and even functions are trivial to represent as strings.  Objects though, are more complicated because they can contain simple types <em>or</em> custom objects (which would need to be serialized themselves).  Those "inner" objects could in turn, contain <em>more</em> custom objects, which would <em>also</em> need to be serialized, and this pattern could (theoretically) go on forever.</p>
	<p>In practice of course, this pattern <em>will</em> (had better) come to an end.  And we can leverage that fact to write a recursive function that will return a string representation (in <abbr>JSON</sbbr> format) of a given object.</p>
	<h3>The serialize(..) function:</h3>
	<p>First the code, then the explanation.</p>
	<div class="dean_ch" style="white-space: nowrap;">
<span class="kw2">function</span> serialize<span class="br0">&#40;</span>_obj<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp;<span class="co1">// Let Gecko browsers do this the easy way</span><br />
&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> _obj.<span class="me1">toSource</span> !== <span class="st0">'undefined'</span> &amp;&amp; <span class="kw1">typeof</span> _obj.<span class="me1">callee</span> === <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> _obj.<span class="me1">toSource</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span></p>
	<p>&nbsp; &nbsp;<span class="co1">// Other browsers must do it the hard way</span><br />
&nbsp; &nbsp;<span class="kw1">switch</span> <span class="br0">&#40;</span><span class="kw1">typeof</span> _obj<span class="br0">&#41;</span><br />
&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// numbers, booleans, and functions are trivial:</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// just return the object itself since its default .toString()</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// gives us exactly what we want</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">case</span> <span class="st0">'number'</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">case</span> <span class="st0">'boolean'</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">case</span> <span class="st0">'function'</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> _obj;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">break</span>;</p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;<span class="co1">// for JSON format, strings need to be wrapped in quotes</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">case</span> <span class="st0">'string'</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="st0">'<span class="es0">\'</span>'</span> + _obj + <span class="st0">'<span class="es0">\'</span>'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">break</span>;</p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">case</span> <span class="st0">'object'</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> str;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>_obj.<span class="me1">constructor</span> === Array || <span class="kw1">typeof</span> _obj.<span class="me1">callee</span> !== <span class="st0">'undefined'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;str = <span class="st0">'['</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> i, len = _obj.<span class="me1">length</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">for</span> <span class="br0">&#40;</span>i = <span class="nu0">0</span>; i &lt; len<span class="nu0">-1</span>; i++<span class="br0">&#41;</span> <span class="br0">&#123;</span> str += serialize<span class="br0">&#40;</span>_obj<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span> + <span class="st0">','</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;str += serialize<span class="br0">&#40;</span>_obj<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span> + <span class="st0">']'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">else</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;str = <span class="st0">'{'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">var</span> key;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">for</span> <span class="br0">&#40;</span>key <span class="kw1">in</span> _obj<span class="br0">&#41;</span> <span class="br0">&#123;</span> str += key + <span class="st0">':'</span> + serialize<span class="br0">&#40;</span>_obj<span class="br0">&#91;</span>key<span class="br0">&#93;</span><span class="br0">&#41;</span> + <span class="st0">','</span>; <span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;str = str.<span class="me1">replace</span><span class="br0">&#40;</span><span class="re0">/\,$/</span>, <span class="st0">''</span><span class="br0">&#41;</span> + <span class="st0">'}'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span><br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> str;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">break</span>;</p>
	<p>&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">default</span>:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">return</span> <span class="st0">'UNKNOWN'</span>;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;<span class="kw1">break</span>;<br />
&nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
	<p>Explaining a recursive function can be difficult, but I'll give it shot:</p>
	<p>The function accepts just one parameter: the object (<code>_obj</code>) to be serialized.  If you'll remember, I mentioned previously that simple types (string, boolean, number, etc...) were trivial because they all have an obvious string representation already.  Complex types though, are more difficult because they can be made up of additional complex types, which in turn could be made up of additional complex types (and so on).</p>
	<p>Of course, this pattern will eventually end; ultimately, everything is made up of simple types that have a string representation.  The trick is figuring out how to traverse through this maze of "types within types."  Recursion (simply stated: a function that calls itself) is perhaps the easiest way to solve this "types within types" problem.</p>
	<p>Recursive functions always have a termination case -- something which causes the function to <em>stop</em> calling itself.  Otherwise, the function would go into an infinite loop.  In our function, there are actually four different cases in which the <code>serialize(..)</code> doesn't need to call itself:</p>
	<ol>
	<li>typeof _obj is a number</li>
	<li>typeof _obj is a boolean</li>
	<li>typeof _obj is a function</li>
	<li>typeof _obj is a string</li>
	</ol>
	<p>If any of the above four conditions are met, returning a string representation is trivial, so we simply do it.</p>
	<div class = "note">
You'll notice that strings are treated separately from the other 3 types.  You'd think strings would be the most trivial case, but actually, there is one thing we must do before returning the "string representation" of <code>_obj</code> when it is of type string:  wrap it in quotes.  We need to do this, because JSON expects it, and if we ever want to be able to <code>eval(..)</code> the result of a <code>serialize(..)</code> call, we'll need these quotes.
</div>
	<p>The only other case to deal with is when <code>_obj</code> is of type <code>object</code>.  Within this case though, there are two "sub-cases" we need to deal with.  The first is when <code>_obj</code> is an <code>Array</code>, or when it has a <code>.callee</code> property (more on that later).  The second is well... anything else.</p>
	<h3>Basic Object Types</h3>
	<p>Your every-day, run-of-the-mill, object in Javascript can be represented as JSON with:</p>
	<p><code>{ key1: val1, key2: val2, ... }</code></p>
	<p>Where the keys are strings and the vals can be any simple type, or some custom object you've dreamed up.  The logic I've used is to simply loop through a given object's keys and build a string of comma delimited, <em>serialized</em> key/value pairs that are wrapped in { and }.</p>
	<p>Notice I said <em>serialized</em> key/value pairs.  Here, our function is calling itself as it builds the object representation.  This ensures that any objects within the object being serialized will <em>also</em> be serialized.  If we didn't do this, we'd end up with a lot of strings that looked (something) like this:</p>
	<p><code>{ key1: [object Object], key2: [object Object], etc... }</code></p>
	<p>And that's clearly not what we want.  We want those inner objects to be serialized as well, and that's what the recursive nature of our function will take care of for us.</p>
	<h3>Arrays</h3>
	<p>When <code>_obj</code> happens to be, not just any object, but more specifically, an <code>Array</code>, we have a better way of representing that as a string:</p>
	<p><code>[ val1, val2, val3, ... ]</code></p>
	<p>The logic I used here is to simply iterate through the array building a comma delimited list of <em>serialized</em> values, wrapped in [ and ].  Arrays in Javascript already have a <code>.toString()</code> function, but we can't use it here; if the Array contains objects, then the result of the Array 's <code>.toString()</code> could end up something like:</p>
	<p><code> [ [object Object], [object Object], etc... ]</code></p>
	<p>Again, not what we want, so we need to make sure we recursively serialize all of the elements in the array.</p>
	<h3>Arguments (the .callee "gotcha")</h3>
	<p>There's one bit of code I haven't discussed yet and it deals with the (possible) <code>.callee</code> property of the passed in <code>_obj</code>.  It turns out that <code>.toSource()</code> (native function used by Gecko-based browsers) doesn't do anything very useful when called on an <code>arguments</code> object.</p>
	<p>The <code>arguments</code> object is an array-like (but not an Array) object that is automatically available within the scope of every function.  Unfortunately, no matter what is contained within that <code>arguments</code> object, calling <code>.toSource()</code> on it will always return <code>"({})"</code></p>
	<p>In order to be able to serialize an <code>arguments</code> object then, we need some way to detect it and then treat it like an array.  The <code>.callee</code> property is a good choice because <code>arguments</code> objects have it, but other objects (to the best of my knowledge) do not.</p>
	<p>In the case of the <code>serialize(..)</code> function, I decided to use the native <code>.toSource()</code> function whenever it was available, <em>unless</em> the object were an <code>arguments</code> object, in which case, I send Gecko-based browsers down the same path as all other browsers for serialization.</p>
	<p>Finally, just for good measure, I've added a default case which returns the string <code>UNKNOWN</code> to handle a situation where no other cases applied.  Of course, we probably don't <em>want</em> <code> UNKNOWN</code> showing up in the our serialized strings, but it probably won't do much (immediate) harm if it ever does show up, <em>and</em> its presence would be a helpful indicator that there is some case not being met (that probably needs to be).</p>
	<h3>Conclusion:</h3>
	<p>What would you ever use a function like this for?  Well, In my case, I wanted to use a Javascript object as the key for a hash, but if I tried to do that, Javascript would just represent all of my (different) objects as the same string: <code>[object Object]</code>, which wouldn't do me any good.  By serializing the object, I can then use that serialized representation as a key in the hash.</p>
	<p>It's worked well for my need so far, but I haven't tested it a great deal.  If you find any bugs or short-comings, please let me know.</p>
	<p>As always, comments are welcome.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.stchur.com/2007/04/06/serializing-objects-in-javascript/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
	</channel>
</rss>

