<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-11521728</id><updated>2012-01-30T13:46:46.833-08:00</updated><title type='text'>The Strange Zen Of JavaScript</title><subtitle type='html'>We got your Ajax right here.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>81</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-11521728.post-6930404989243451109</id><published>2011-02-17T15:00:00.000-08:00</published><updated>2011-02-17T15:18:30.570-08:00</updated><title type='text'>Why must we still close SCRIPT elements?</title><content type='html'>&lt;p&gt;I was wondering why in the world we still have to terminate SCRIPT elements with &amp;lt;/script&amp;gt; tags in 2011, fer Pete's sake.&lt;/p&gt;

&lt;p&gt;i.e. why does this work:&lt;/p&gt;

&lt;pre&gt;&amp;lt;script src="foo.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;but this:&lt;/p&gt;

&lt;pre&gt;&amp;lt;script src="foo.js" /&amp;gt;&lt;/pre&gt;

&lt;p&gt;does not?&lt;/p&gt;

&lt;p&gt;For years I thought it was just a bad implementation from the NS4 days that nobody bothered to correct. Not so! Turns out there's a valid (if a bit irritating) reason.&lt;/p&gt;

&lt;p&gt;The tl;dr answer is: &lt;strong&gt;&amp;lt;script /&amp;gt; is valid XML, but invalid HTML.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you serve your HTML pages as text/html, a browser will likely use its HTML parser to render the page. And since &amp;lt;script /&amp;gt; is invalid HTML, the HTML parser treats it as unrecognized junk.&lt;/p&gt;

&lt;p&gt;(In theory, if you serve your pages as text/xml or application/xhtml+xml, the browser would use its XML parser, recognize the &amp;lt;script /&amp;gt; as valid, and load/execute the associated JS. But that also presumes your documents are also perfectly-formed, valid XML and not tag soup. Can you make that claim?)&lt;/p&gt;

&lt;p&gt;As to the question of why &amp;lt;script /&amp;gt; is invalid while &amp;lt;img /&amp;gt; is perfectly okay:&lt;/p&gt;

&lt;p&gt;The XHTML spec (and therefore HTML5, which &lt;a href="http://www.w3.org/TR/html5/infrastructure.html#html-elements"&gt;imports the element definitions from the XHTML DTD&lt;/a&gt;) defines the SCRIPT tag as containing "document text." It cannot, by definition, be "empty."&lt;/p&gt;

&lt;p&gt;SCRIPT is often considered analogous to the IMG element -- and mistakenly so -- because they both use the "src" attribute. In reality, SCRIPT is more akin to the P (paragraph) element, which also cannot be empty (writing &amp;lt;p /&amp;gt; is invalid -- you must instead write &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;)&lt;/p&gt;

&lt;p&gt;For comparison, here are the starting element definitions from the XHTML DTD:&lt;/p&gt;

&lt;pre&gt;&amp;lt;!ELEMENT script (#PCDATA)&amp;gt;

&amp;lt;!ELEMENT img EMPTY&amp;gt;&lt;/pre&gt;

&lt;p&gt;This is why &amp;lt;img /&amp;gt; is fine, while &amp;lt;script /&amp;gt; is a no-no.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-6930404989243451109?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/6930404989243451109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=6930404989243451109' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/6930404989243451109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/6930404989243451109'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2011/02/why-must-we-still-close-script-elements.html' title='Why must we still close SCRIPT elements?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-4916376152512521951</id><published>2010-01-31T16:48:00.000-08:00</published><updated>2010-01-31T17:16:33.241-08:00</updated><title type='text'>HTML 5 audio player demo</title><content type='html'>&lt;p&gt;To teach myself a little about HTML 5 and its built-in support for rich media, I built a &lt;a href="http://www.scottandrew.com/pub/html5audioplayer/"&gt;proof-of-concept HTML5 audio player&lt;/a&gt;, written entirely in HTML 5, JQuery and CSS 3. It more or less replaces all the functionality of the &lt;a href="http://www.scottandrew.com"&gt;Flash audio player on my music site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It took a little over two hours starting from nothing. Developed it in Safari 4.0 and works great with that browser. Haven't yet tested it in Firefox 3.5, which claims HTML 5 audio/video media support as well. (UPDATE: &lt;a href="https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox"&gt;Firefox doesn't support the MP3 format&lt;/a&gt;. You're stuck with Ogg or WAV.) It "works" in Mobile Safari on my iPhone 3G, but it's not pretty: the audio element is visible and the MP3 launches a Quicktime player.&lt;/p&gt;

&lt;p&gt;Think what you want about the iPad and Apple's non-support of Adobe Flash. If you're a web developer and not excited about creating rich media experiences with HTML, Javascript and CSS, you just might be a dried-out husk.&lt;/p&gt;

&lt;p&gt;Feel free to hack this code. You can send screenshots (links only, please!) and bug reports to me &lt;a href="mailto:scottandrew@gmail.com"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-4916376152512521951?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/4916376152512521951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=4916376152512521951' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/4916376152512521951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/4916376152512521951'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2010/01/html-5-audio-player-demo.html' title='HTML 5 audio player demo'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-2315634316723098991</id><published>2009-10-28T15:30:00.000-07:00</published><updated>2009-10-28T15:56:17.441-07:00</updated><title type='text'>Using the "in" operator in conditionals</title><content type='html'>&lt;p&gt;Most of us are familiar with the for..in loop construct:&lt;/p&gt;

&lt;pre&gt;for (var i in object) {
   /* some iterative action here */
}&lt;/pre&gt;

&lt;p&gt;Less well-known is the use of "in" as an operator to test if a named property exists on an object:&lt;/p&gt;

&lt;pre&gt;&gt;&gt;&gt; var x = {foo:1, bar:2, baz:'cat'};

&gt;&gt;&gt; ('foo' in x)
true

&gt;&gt;&gt; ('bar' in x)
true

&gt;&gt;&gt; ('qux' in x)
false&lt;/pre&gt;

This works on methods, too:

&lt;pre&gt;&gt;&gt;&gt; ('toString' in x)
true&lt;/pre&gt;

&lt;p&gt;It's particularly neato for testing the existence of properties with &lt;a href="http://jszen.blogspot.com/2005/08/beware-of-false-falses-or-something.html"&gt;values that could be interpreted as false&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&gt;&gt;&gt; var x = {foo:null, bar:false, baz:0};

&gt;&gt;&gt; (x.foo)
null

&gt;&gt;&gt; ('foo' in x);
true

&gt;&gt;&gt; (x.bar)
false

&gt;&gt;&gt; ('bar' in x)
true&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-2315634316723098991?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/2315634316723098991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=2315634316723098991' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2315634316723098991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2315634316723098991'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2009/10/using-in-operator-in-conditionals.html' title='Using the &quot;in&quot; operator in conditionals'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-7745967192553326564</id><published>2009-10-09T17:49:00.000-07:00</published><updated>2009-10-09T17:55:29.917-07:00</updated><title type='text'>IE conditional comment gotcha</title><content type='html'>&lt;p&gt;Here's one for the books:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;!-- [if IE]&gt;

&amp;lt;p&gt;Some IE-specific stuff here&amp;lt;/p&gt;

&amp;lt;![endif] --&gt;
&lt;/pre&gt;

&lt;p&gt;This will be ignored by IE. Why?&lt;/p&gt;

&lt;p&gt;Because IE doesn't like the whitespace between the comment delimiters and square brackets. Here's the correct way:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;!--[if IE]&gt;

&amp;lt;p&gt;Some IE-specific stuff here&amp;lt;/p&gt;

&amp;lt;![endif]--&gt;
&lt;/pre&gt;

&lt;p&gt;Note the difference:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;!-- [if IE]&gt; (bad)
&amp;lt;!--[if IE]&gt;  (good)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-7745967192553326564?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/7745967192553326564/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=7745967192553326564' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/7745967192553326564'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/7745967192553326564'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2009/10/ie-conditional-comment-gotcha.html' title='IE conditional comment gotcha'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-1431131293346391346</id><published>2009-05-30T11:05:00.000-07:00</published><updated>2009-05-30T12:15:36.219-07:00</updated><title type='text'>HTML 5</title><content type='html'>&lt;p&gt;The recent buzz over&lt;a href="http://radar.oreilly.com/2009/05/google-bets-big-on-html-5.html"&gt; HTML 5&lt;/a&gt; this week at Google I/O could not have come at a better time.&lt;/p&gt;

&lt;p&gt;It reminds me of another time, back in 2005, when the economy was just starting to recover from the dotcom bust. &lt;a href="http://jszen.blogspot.com/2005/05/ajaxed-out.html"&gt;Ajax made the scene&lt;/a&gt; (heavily backed by Google in the form of Suggest and Maps) and got people excited about doing cool things on the web again.&lt;/p&gt;

&lt;p&gt;Now the economy is in the crapper again, and here comes HTML 5 (again backed by Google in the form of Chrome and Wave). Looking at some of the &lt;a href="http://htmlfive.appspot.com/"&gt;demos&lt;/a&gt;, I feel the same exhilaration I once felt when I first recognized the potential of DHTML. In many ways, HTML 5 picks up where DHTML -- or DOM scripting of whatever -- left off long ago.&lt;/p&gt;

&lt;p&gt;I offer no analysis. It's the most excited I've been about web development in years.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-1431131293346391346?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/1431131293346391346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=1431131293346391346' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1431131293346391346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1431131293346391346'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2009/05/html-5.html' title='HTML 5'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-3809484516096890866</id><published>2009-02-03T15:08:00.000-08:00</published><updated>2009-02-03T15:15:09.659-08:00</updated><title type='text'>Constraining elements to the browser window</title><content type='html'>&lt;p&gt;I recently worked on a demo that used tooltip-like "popover" menus that appeared when the mouse pointer hovered over certain page elements. The initial approach was pretty straightforward: find the offsetTop and offsetLeft of the target element, then move the menu to those coordinates.&lt;/p&gt;

&lt;p&gt;Two challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If an item was too close to the left or bottom edge of the browser window, the menu would appear partially offscreen. So I had to figure out how to constrain the menu to the visible window area.&lt;/li&gt;
&lt;li&gt;I had to account for any additional window scrolling.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;The following seemed to do the trick. Note that this is pseudo-JavaScript;  I leave it to you to figure out how to actually obtain the necessary values and make the appropriate substitutions.&lt;/p&gt;

&lt;pre&gt;
// element = target element that gets the menu
// menu = the menu popover DIV

var bottomEdge = element.offsetTop + menu.height - document.scrollTop;
if ( bottomEdge &gt; window.height )  {
    menu.top = element.offsetTop - (bottomEdge - window.height);
}

var leftEdge = element.offsetLeft + menu.width - document.scrollLeft;
if ( leftEdge &gt; window.width)  {
    menu.left = element.offsetLeft - (leftEdge - window.width);
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-3809484516096890866?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/3809484516096890866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=3809484516096890866' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/3809484516096890866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/3809484516096890866'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2009/02/i-recently-worked-on-app-that-used.html' title='Constraining elements to the browser window'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-1638512874447774374</id><published>2008-11-12T08:28:00.000-08:00</published><updated>2008-11-12T09:07:29.141-08:00</updated><title type='text'>Does your website disappear in IE8?</title><content type='html'>&lt;p&gt;Mine did.&lt;/p&gt;

&lt;p&gt;I was recently given a pretty large redesign project, and during the planning stages I took the opportunity to add a long-missing DOCTYPE to the site. I chose a nice HTML 4.01 Transitional flavor because there was &lt;em&gt;no way in hell&lt;/em&gt; the site was going to resemble anything close to XHTML anytime soon. At the very least, it would 1) get the site out of quirks mode, and 2) give us an eventual path to validation.&lt;/p&gt;

&lt;p&gt;(I'm including this info to illustrate: we had a proper DOCTYPE, and knew the site would not be valid HTML going in.)&lt;/p&gt;

&lt;p&gt;Months after the project was complete and launched, word came down that the site was missing in IE8. Not broken. MISSING. Like, "the page is blank."&lt;/p&gt;

&lt;p&gt;No partial loading, no sudden flicker, no error message. The site simply would not render.&lt;/p&gt;

&lt;p&gt;I was considering hard liquor as my preferred solution when one of my co-workers mentioned something he'd heard about a new META element, something about versioning. Ah, yes, that &lt;a href="http://www.google.com/search?ie=UTF-8&amp;oe=UTF-8&amp;sourceid=navclient&amp;gfns=1&amp;q=IE+version+targeting"&gt;version targeting thing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I added the following to the global website header:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;meta http-equiv="X-UA-Compatible" content="IE=7" /&gt;
&lt;/pre&gt;

&lt;p&gt;...and suddenly the site worked in IE8.&lt;p&gt;

&lt;p&gt;This is not a "solution." I still don't know &lt;em&gt;why&lt;/em&gt; the site vanishes in IE8. I mean, it rendered perfectly fine in IE5, IE5.5, IE6 and IE7 so OF COURSE IT MAKES &lt;strong&gt;TOTAL SENSE&lt;/strong&gt; THAT IT COMPLETELY VANISHES IN IE8. Right?&lt;/p&gt;

&lt;p&gt;No. It does not make sense. Anyway, when I do discover the root cause, I'll post it here. In the meantime, I guess I'll be asking IE8 to dumb it down to my level.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-1638512874447774374?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/1638512874447774374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=1638512874447774374' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1638512874447774374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1638512874447774374'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2008/11/does-your-site-disappear-in-ie8.html' title='Does your website disappear in IE8?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-1727968444475023351</id><published>2008-07-17T08:00:00.000-07:00</published><updated>2008-11-16T17:50:00.360-08:00</updated><title type='text'>Missing form ACTIONs</title><content type='html'>&lt;p&gt;Say you want to disable a submit button when it's clicked, to prevent the user from submitting twice:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;form name="myform"&gt;
  &amp;lt;input type="submit" value="Submit" onclick="this.disabled = 'true';"&gt;        
&amp;lt;/form&gt;
&lt;/pre&gt;

&lt;p&gt;On Windows, this works fine in IE but not in Firefox. Or so it appears. What's going on?&lt;/p&gt;

&lt;p&gt;Oops, you forgot an ACTION attribute in your form. (It's okay, this is common if you're planning an Ajax-style app.) Without it, IE just ignores the submit click, but Firefox uses the current page as the default action. So it effectively reloads the page, resetting the button state.&lt;/p&gt;

&lt;p&gt;The thing is, the submit button &lt;em&gt;is&lt;/em&gt; being disabled in FF, just like in IE, but depending on how fast the page reloads, you might not even notice.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-1727968444475023351?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/1727968444475023351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=1727968444475023351' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1727968444475023351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1727968444475023351'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2008/07/missing-form-actions.html' title='Missing form ACTIONs'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-1466826099685280758</id><published>2008-07-16T11:30:00.000-07:00</published><updated>2008-07-16T11:35:46.895-07:00</updated><title type='text'>Function reference vs. function call</title><content type='html'>Here's a JavaScript function definition:

&lt;pre&gt;
function foo() {
  alert('foo!');
}
&lt;/pre&gt;

You can &lt;em&gt;refer&lt;/em&gt; to that function like this:

&lt;pre&gt;foo&lt;/pre&gt;

And here is how to &lt;em&gt;call&lt;/em&gt; (execute) the function:

&lt;pre&gt;foo()&lt;/pre&gt;

Even experienced developers new to JS tend to get these confused. For example, jQuery's getJSON method allows you to specify a function to be executed once the operation is complete. Be careful not to plug in the function &lt;em&gt;call&lt;/em&gt; when what you really need is a function &lt;em&gt;reference&lt;/em&gt;:

&lt;pre&gt;
$.getJSON( "action.php", {data:'some data here'}, foo() );
&lt;/pre&gt;

This will execute the foo function instantly. Not what you want. So leave off the parens:

&lt;pre&gt;
$.getJSON( "action.php", {data:'some data here'}, foo );
&lt;/pre&gt;

This merely passes a reference to the function. It won't execute until it's called by jQuery.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-1466826099685280758?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/1466826099685280758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=1466826099685280758' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1466826099685280758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/1466826099685280758'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2008/07/function-reference-vs-function-call.html' title='Function reference vs. function call'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-2534146412173404240</id><published>2008-04-16T10:00:00.000-07:00</published><updated>2008-04-16T10:20:21.408-07:00</updated><title type='text'>A good enough addEvent</title><content type='html'>&lt;p&gt;O HAI, this blog is nearly dead these days. But before it truly shuffles off into the sunset, allow me to point you to filosofo's &lt;a href="http://www.ilfilosofo.com/blog/2008/04/14/addevent-preserving-this/"&gt;"good enough" addEvent&lt;/a&gt;. Austin gets around PPK's pesky requirements by ignoring one of them (namely, having a corresponding removeEvent).&lt;/p&gt;

&lt;p&gt;I love this solution because it mirrors much of my recent experiences with JavaScript.  Honestly, I can't remember the last time I needed anything more than some variation of toggle() and I can count on one hand the number of times I've need to &lt;em&gt;detach&lt;/em&gt; an event since 1998.&lt;/p&gt;

&lt;p&gt;Kudos to Austin for thinking differently.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-2534146412173404240?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/2534146412173404240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=2534146412173404240' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2534146412173404240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2534146412173404240'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2008/04/good-enough-addevent.html' title='A good enough addEvent'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-2798742148854710062</id><published>2007-07-01T19:31:00.000-07:00</published><updated>2007-07-01T23:41:38.094-07:00</updated><title type='text'>Some reader contributions to Calendar tutorial</title><content type='html'>&lt;p&gt;When I started SZOJ I promised myself I wouldn't abruptly shut down the blog if I lost interest; I'd just go radio silent until my interest was piqued again. That said, it's been a long while. So here are two things:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.soylentred.net/ "&gt;Rory Parle&lt;/a&gt; wrote in to point out you can use Math.ceil to determine the number of rows you'd need to safely render a calendar:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;Math.ceil((monthLength + startingDay) / 7);&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="http://michiel.wordpress.com"&gt;Michiel van der Blonk&lt;/a&gt; suggested a way to determine the number of days in a month:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
var d = new Date(nYear, nMonth + 1, 0); // nMonth is 0 thru 11
return(d.getDate());
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The mechanism here is the Date constructor will attempt to convert year, month and day values to the nearest valid date. So in the above code, nMonth is incremented to find the following month, and then a Date object is created with &lt;em&gt;zero&lt;/em&gt; days. Since this is an invalid date, the Date object defaults to the last valid day of the &lt;em&gt;previous&lt;/em&gt; month &amp;mdash; which is the month we're interested in to begin with. Then getDate() returns the day (1-31) of that date &amp;mdash; &lt;em&gt;voil&amp;aacute;&lt;/em&gt;, we have the number of days.&lt;/p&gt;

&lt;p&gt;Bonus: it also seems to automatically correct for leap year. It &lt;em&gt;feels&lt;/em&gt; like a hack but it seems to work consistently.&lt;/p&gt;

&lt;p&gt;Thanks to Rory and Michiel for their contributions.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-2798742148854710062?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/2798742148854710062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=2798742148854710062' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2798742148854710062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/2798742148854710062'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/07/some-reader-contributions-to-calendar.html' title='Some reader contributions to Calendar tutorial'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117436538370756127</id><published>2007-03-19T22:34:00.000-07:00</published><updated>2007-03-19T22:54:04.270-07:00</updated><title type='text'>How to build a simple calendar with JavaScript</title><content type='html'>&lt;p&gt;While there are lots of JavaScript-based calendar widgets out there, there's not much in the way of explaining how they work for the JS acolyte. I recently had the opportunity of building one from memory (and best of all, for no particular reason), using none of the popular JS libraries. &lt;em&gt;This is the tutorial I wish I had found five years ago.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This series of posts will cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;how to create a simple calendar view with JavaScript&lt;/li&gt;
&lt;li&gt;how to tie the calendar to an HTML element for rendering&lt;/li&gt;
&lt;li&gt;how to add next/previous month controls&lt;/li&gt;
&lt;li&gt;how to add date picker functionality&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Part One: a basic calendar display&lt;/h2&gt;

&lt;p&gt;We're ready to start laying the groundwork for our calendar widget. Here are the steps we'll be taking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;define some global variables to hold common values&lt;/li&gt;
&lt;li&gt;define the calendar object and its arguments&lt;/li&gt;
&lt;li&gt;write a method to generate the HTML needed to render the calendar&lt;/li&gt;
&lt;li&gt;write a method to return the HTML&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;The Date object&lt;/h3&gt;

&lt;p&gt;I used to fear the JavaScript Date object, but it's actually fairly simple. In short, here's what it does:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;parses a given date, and provides useful information about that date&lt;/li&gt;
&lt;li&gt;if no date is specified, the current date is used as the default&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A full discussion of the Date object is beyond the scope of this tutorial. &lt;a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Date"&gt;You can find documentation here&lt;/a&gt;. However, for the purposes of this project, it's important to understand what the Date object &lt;em&gt;doesn't&lt;/em&gt; do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it doesn't know the names of months or days of the week&lt;/li&gt;
&lt;li&gt;it doesn't know how many days are in a given month&lt;/li&gt;
&lt;li&gt;it doesn't compensate for leap year&lt;/li&gt;
&lt;li&gt;it doesn't know the day of the week on which a given month begins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Surprisingly, the Date object isn't used in this widget as much as you'd expect. It's primarily used to determine the current date (if needed) and the starting day of the week for the specified month.&lt;/p&gt;

&lt;h3&gt;Global variables&lt;/h3&gt;

&lt;p&gt;As stated above, the Date object doesn't provide us with everything we need, so we have to compensate with a few predefined arrays of values.&lt;/p&gt;

&lt;pre&gt;

// these are labels for the days of the week
cal_days_labels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

// these are human-readable month name labels, in order
cal_months_labels = ['January', 'February', 'March', 'April',
                     'May', 'June', 'July', 'August', 'September',
                     'October', 'November', 'December'];

// these are the days of the week for each month, in order
cal_days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
&lt;/pre&gt;

These are intentionally defined in the global scope, as they may be shared with multiple calendar widgets. The naming convention is arbitrary; you may prefer to append them to the calendar constructor to prevent collisions with other variables.

Since the Date object returns integers for month (0-11) and day (1-31), we'll be able to use those as indexes for looking up the human-readable labels, as well as the number of days in the specified month.

&lt;blockquote&gt;&lt;p&gt;But wait, how do we compensate for leap year when February is hard-coded at 28 days? Don't worry, it's coming later in this tutorial.&lt;/p&gt;&lt;/blockquote&gt;

In addition, we'll need a Date object representing the current date, as a fallback:

&lt;pre&gt;
// this is the current date
cal_current_date = new Date(); 
&lt;/pre&gt;

&lt;h3&gt;The Calendar constructor&lt;/h3&gt;

Our constructor is pretty basic at the moment. I've designed it to take two arguments, a month and year (both integers) which will represent the intial calendar state. If these arguments are missing or null, the global default date object will be used instead.

&lt;pre&gt;
function Calendar(month, year) {
  this.month = (isNaN(month) || month == null) ? cal_current_date.getMonth() : month;
  this.year  = (isNaN(year) || year == null) ? cal_current_date.getFullYear() : year;
  this.html = '';
}
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;Right now you might be saying "hey, why the long syntax? Can't we just do a shortcut like this?"&lt;/p&gt;
&lt;pre&gt;
this.month = month || cal_current_date.getMonth();
&lt;/pre&gt;

&lt;p&gt;One of the pitfalls of this method is that &lt;a href="http://jszen.blogspot.com/2005/08/beware-of-false-falses-or-something.html"&gt;zero can be interpreted as false&lt;/a&gt;, which means if we specify zero (January) for our month, this expression would use the default month instead.&lt;/p&gt;

&lt;p&gt;We also want the option to pass &lt;strong&gt;null&lt;/strong&gt; for one or both of the values. The isNaN() function returns &lt;em&gt;true&lt;/em&gt; when passed a null value, which will produce an incorrect result. So we have to test for both conditions: the argument must either be not a number or null for the default to be used.&lt;/p&gt;

&lt;/blockquote&gt;

&lt;h3&gt;HTML generation&lt;/h3&gt;

&lt;p&gt;Here's where we take the date info and stitch together an HTML calendar grid view. Let's start with an empty method definition:&lt;/p&gt;

&lt;pre&gt;
Calendar.prototype.generateHTML = function(){

}
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;Not familiar with object prototyping in JavaScript? &lt;a href="#"&gt;Here's some good reading.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now let's step through everything this method has to handle.&lt;/p&gt;

&lt;h4&gt;First day of the week&lt;/h4&gt;

&lt;p&gt;March 2007 begins on a Thursday, but the Date object doesn't know that. However, if we specifically give it the date of "March 1 2007" to parse, it can tell us that day of the week as an integer (from 0-6). So, let's feed it such a date:

&lt;pre&gt;
var firstDay = new Date(this.year, this.month, 1);
&lt;/pre&gt;

&lt;p&gt;We can now query the new Date object for the day of the week:&lt;/p&gt;

&lt;pre&gt;
var startingDay = firstDay.getDay();
// returns 4 (Thursday)
&lt;/pre&gt;

&lt;p&gt;So now the widget knows that March 2007 starts on the 5th day of the first week (remember, we're counting from zero like computers do).&lt;/p&gt;

&lt;h4&gt;Number of days in the month&lt;/h4&gt;

&lt;p&gt;This one's easy. Just use the numeric month value to look up the value in our days-in-month array:&lt;/p&gt;

&lt;pre&gt;
var monthLength = cal_days_in_month[this.month];
&lt;/pre&gt;

&lt;h4&gt;Compensate for leap year&lt;/h4&gt;

&lt;p&gt;Right, how &lt;em&gt;does&lt;/em&gt; the widget know if it's leap year or not? This stumped me until I did a Google code search and found a &lt;a href="http://www.google.com/codesearch?q=leap+year&amp;hl=en&amp;btnG=Search+Code"&gt;widely-implemented approach&lt;/a&gt; that uses the &lt;a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Arithmetic_Operators#.25_.28Modulus.29"&gt;modulus operator&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;
if (this.month == 1) { // February only!
  if ((this.year % 4 == 0 &amp;&amp; this.year % 100 != 0) || this.year % 400 == 0){
    monthLength = 29;
  }
}
&lt;/pre&gt;

&lt;p&gt;Damn, I'm glad I didn't have to figure that out. Thanks, Google Code!&lt;/p&gt;

&lt;h4&gt;Constructing the HTML&lt;/h4&gt;

&lt;p&gt;We're ready to start building the HTML string for our calendar view. First, the header stuff:

&lt;pre&gt;
var monthName = cal_months_labels[this.month];
var html = '&amp;lt;table class="calendar-table"&gt;';
html += '&amp;lt;tr&gt;&amp;lt;th colspan="7"&gt;';
html +=  monthName + "&amp;amp;nbsp;" + this.year;
html += '&amp;lt;/th&gt;&amp;lt;/tr&gt;';
html += '&amp;lt;tr class="calendar-header"&gt;';
for (var i = 0; i &lt;= 6; i++ ){
  html += '&amp;lt;td class="calendar-header-day"&gt;';
  html += cal_days_labels[i];
  html += '&amp;lt;/td&gt;';
}
html += '&amp;lt;/tr&gt;&amp;lt;tr&gt;';
&lt;/pre&gt;

&lt;p&gt;It's pretty straightforward: we begin with a table and header containing the month and year. Then we use a &lt;a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:for"&gt;for loop&lt;/a&gt; to iterate over our human-readable days-of-the-week array and create the first row of column headers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are more efficient ways of concatenating HTML, but I thought this was the most clear. And don't gimme no lip about using a TABLE vs. a bunch of floated DIVs &amp;mdash; I may be a &lt;em&gt;standardista&lt;/em&gt; but I'm not a masochist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now for the tricky part, the remaining boxes. We need to make sure that we don't start filling in boxes until we've reached the first weekday of the month, and then stop filling them in when we've reached the maximum number of days for that month.&lt;/p&gt;

&lt;p&gt;Since we don't know how many rows we'll need, we'll just generate a safe number of rows &amp;mdash; like ten or so &amp;mdash; and break out of the loop once we've run out of days. Here we go:&lt;/p&gt;

&lt;pre&gt;
var day = 1;
// this loop is for is weeks (rows)
for (var i = 0; i &lt; 9; j++) {
  // this loop is for weekdays (cells)
  for (var j = 0; j &lt;= 6; j++) { 
    html += '&amp;lt;td class="calendar-day"&gt;';
    if (day &lt;= monthLength &amp;&amp; (i &gt; 0 || j &gt;= startingDay)) {
      html += day;
      day++;
    }
    html += '&amp;lt;/td&gt;';
  }
  // stop making rows if we've run out of days
  if (day &gt; monthLength) {
    break;
  } else {
    html += '&amp;lt;/tr&gt;&amp;lt;tr&gt;';
  }
}

html += '&amp;lt;/tr&gt;&amp;lt;/table&gt;';

this.html = html;

&lt;/pre&gt;


&lt;p&gt;The real brain-twister is here:&lt;/p&gt;

&lt;pre&gt;
if (day &lt;= monthLength &amp;&amp; (i &gt; 0 || j &gt;= startingDay)) {
&lt;/pre&gt;

&lt;p&gt;...which roughly translates to "fill the cell only if we haven't run out of days, and we're sure we're not in the first row, or this day is after the starting day for this month." Whew!&lt;/p&gt;

&lt;p&gt;Here's the complete code for our HTML-generating method:&lt;/p&gt;

&lt;pre&gt;
Calendar.prototype.generateHTML = function(){

  // get first day of month
  var firstDay = new Date(this.year, this.month, 1);
  var startingDay = firstDay.getDay();
  
  // find number of days in month
  var monthLength = cal_days_in_month[this.month];
  
  // compensate for leap year
  if (this.month == 1) { // February only!
    if((this.year % 4 == 0 &amp;&amp; this.year % 100 != 0) || this.year % 400 == 0){
      monthLength = 29;
    }
  }
  
  // do the header
  var monthName = cal_months_labels[this.month]
  var html = '&amp;lt;table class="calendar-table"&gt;';
  html += '&amp;lt;tr&gt;&amp;lt;th colspan="7"&gt;';
  html +=  monthName + "&amp;amp;nbsp;" + this.year;
  html += '&amp;lt;/th&gt;&amp;lt;/tr&gt;';
  html += '&amp;lt;tr class="calendar-header"&gt;';
  for(var i = 0; i &lt;= 6; i++ ){
    html += '&amp;lt;td class="calendar-header-day"&gt;';
    html += cal_days_labels[i];
    html += '&amp;lt;/td&gt;';
  }
  html += '&amp;lt;/tr&gt;&amp;lt;tr&gt;';

  // fill in the days
  var day = 1;
  // this loop is for is weeks (rows)
  for (var i = 0; i &lt; 9; i++) {
    // this loop is for weekdays (cells)
    for (var j = 0; j &lt;= 6; j++) { 
      html += '&amp;lt;td class="calendar-day"&gt;';
      if (day &lt;= monthLength &amp;&amp; (i &gt; 0 || j &gt;= startingDay)) {
        html += day;
        day++;
      }
      html += '&amp;lt;/td&gt;';
    }
    // stop making rows if we've run out of days
    if (day &gt; monthLength) {
      break;
    } else {
      html += '&amp;lt;/tr&gt;&amp;lt;tr&gt;';
    }
  }
  html += '&amp;lt;/tr&gt;&amp;lt;/table&gt;';

  this.html = html;
}
&lt;/pre&gt;

&lt;h3&gt;Returning the HTML&lt;/h3&gt;

&lt;p&gt;By design, the generateHTML method doesn't return the finished HTML string. Instead, it stores it in a property of the calendar object. Let's write a getter method to access that string.&lt;/p&gt;

&lt;pre&gt;
Calendar.prototype.getHTML = function() {
  return this.html;
}
&lt;/pre&gt;

&lt;p&gt;Okay, let's see what we've got!&lt;/p&gt;

&lt;h3&gt;Using the calendar&lt;/h3&gt;

&lt;p&gt;The widget may be complex on the inside, but it's ridiculously easy to implement. Here's how to embed a calendar displaying the current month into a web page:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;script type="text/javascript"&gt;
  var cal = new Calendar();
  cal.generateHTML();
  document.write(cal.getHTML());
&amp;lt;/script&gt;
&lt;/pre&gt;

&lt;p&gt;Now let's set it to September 2009:&lt;/p&gt;

&lt;pre&gt;
&amp;lt;script type="text/javascript"&gt;
  var cal = new Calendar(8,2009);
  cal.generateHTML();
  document.write(cal.getHTML());
&amp;lt;/script&gt;
&lt;/pre&gt;

&lt;h4&gt;The Demo!&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://s3.amazonaws.com/scottandrew-html/calendar-lesson-1.1.html"&gt;Here's our calendar widget in action.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;That's nice, but...&lt;/h3&gt;

&lt;p&gt;We're stuck displaying only one month?&lt;/p&gt;
&lt;p&gt;Shouldn't generateHTML and getHTML be called automatically?&lt;/p&gt;
&lt;p&gt;And WTF is up with that lame &lt;em&gt;document.write?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yep, this simple calendar is "simple" alright. Later this week we'll look at a much slicker way to integrate the calendar into webpages and add controls to transform our humble static calendar view into a full-blown datepicker.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117436538370756127?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/117436538370756127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=117436538370756127' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117436538370756127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117436538370756127'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/03/how-to-build-simple-calendar-with.html' title='How to build a simple calendar with JavaScript'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117330248648162387</id><published>2007-03-07T13:15:00.000-08:00</published><updated>2007-03-07T13:22:23.116-08:00</updated><title type='text'>The Mark Of The n00b</title><content type='html'>&lt;p&gt;When I'm debugging or otherwise vetting someone's JavaScript work, I tend to look for evidence that indicates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the author is new to JavaScript, and/or&lt;/li&gt;
&lt;li&gt;the author cut-and-pasted this code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither of these are showstoppers, especially if the result is a neat-o web application or widget. But it does tend to drive me a little nuts sometimes.&lt;/p&gt;

&lt;p&gt;Case in point: using "javascript:" in HREFs, a pet peeve of mine. It's not &lt;em&gt;technically&lt;/em&gt; incorrect and it "just works" almost all modern browsers. It's just "wrong," in the same way that using &amp;lt;b&gt; instead of &amp;lt;strong&gt; is "wrong" and using TABLEs for layout is "wrong."&lt;/p&gt;

&lt;p&gt;It's wrong from a &lt;em&gt;craft&lt;/em&gt; point of view. It's the JavaScript equivalent of "eh, let's just shove the table markup into the database along with the content."&lt;/p&gt;

&lt;p&gt;(Worse yet is "JavaScript:" (camel-cased) or something like "onclick='JavaScript:...'" I don't know of a single browser that falls over when the latter is used, but when someone sends me broken code to debug that has "JavaScript:" in the &lt;em&gt;event handlers&lt;/em&gt;, the first thing I wonder is, "hm, what else is being overlooked here?")&lt;/p&gt;

&lt;p&gt;Thing is, I don't expect JS newbies to know this stuff* because other than some tongue-clucking from old JS cranks like myself, there aren't any hard consequences.&lt;/p&gt;

&lt;p&gt;And you. Do you have any favorite "mark of the newbie" things that drive you insane?&lt;/p&gt;

&lt;p&gt;* that's why I run this blog&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117330248648162387?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/117330248648162387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=117330248648162387' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117330248648162387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117330248648162387'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/03/mark-of-n00b.html' title='The Mark Of The n00b'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117330032555021039</id><published>2007-03-07T12:43:00.000-08:00</published><updated>2007-03-07T12:47:53.196-08:00</updated><title type='text'>Return false to prevent jumping scrollbars</title><content type='html'>&lt;p&gt;I like what &lt;a href="http://www.harrymaugans.com"&gt;Harry Maugans&lt;/a&gt; is doing over at his site with his JavaScript how-tos. It's back-to-basics stuff, but judging from the number of Diggs he gets, people are interested in how this stuff works under the hood.&lt;/p&gt;

&lt;p&gt;In his tutorial "&lt;a href="http://www.harrymaugans.com/2007/03/05/how-to-create-a-collapsible-div-with-javascript-and-css/"&gt;How To Create A Collapsible DIV with JavaScript and CSS&lt;/a&gt;," Harry writes regarding the use of the HREF attribute in anchors that trigger JS actions:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Another common do-nothing insert to use for the href property is a pound sign (#), and while that will work, it'll also move the user’s scroll bar to the very top of your website, which can get quite annoying.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way to get around the scrolling problem is to include a "return false;" in your event handler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&amp;lt;a href="#" onmousedown="toggleDiv('mydiv'); &lt;strong&gt;return false;&lt;/strong&gt;"&gt;
  Toggle Div Visibility
&amp;lt;/a&gt;
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, basic stuff, easily overlooked.&lt;/p&gt;

&lt;p&gt;(I wrote to Harry about this but I don't think he approved my comment. That's okay; it's why we have Trackback :)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117330032555021039?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117330032555021039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117330032555021039'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/03/return-false-to-prevent-jumping.html' title='Return false to prevent jumping scrollbars'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117251576248651792</id><published>2007-02-26T10:47:00.000-08:00</published><updated>2007-02-26T10:49:22.830-08:00</updated><title type='text'>How to parse HTML strings into DOM nodes without innerHTML</title><content type='html'>&lt;p&gt;Here's a way of parsing a string of HTML into a series of DOM nodes in Firefox and other Mozilla-similar ("mozimilar") browsers:&lt;/p&gt;

&lt;pre&gt;
var range = document.createRange();
range.selectNode(document.body);
var parsedHTML = range.createContextualFragment(SomeStringOfHTML);

document.body.appendChild(parsedHTML)
&lt;/pre&gt;

&lt;p&gt;The call to selectNode() is required as you have to point the empty range at something before you can use it; Firefox throws an exception without it. You can use &lt;a href="http://developer.mozilla.org/en/docs/DOM:range#Positioning_Methods"&gt;other range positioning methods&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;Also of note: createContextualFragment() is not part of any DOM specification AFAICT, so you should feel appropriately shameful about using it as you would innerHTML.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117251576248651792?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117251576248651792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117251576248651792'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/02/how-to-parse-html-strings-into-dom.html' title='How to parse HTML strings into DOM nodes without innerHTML'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117106431800005762</id><published>2007-02-09T15:32:00.000-08:00</published><updated>2007-02-09T15:39:32.143-08:00</updated><title type='text'>SCRIPT and innerHTML: a losing combination</title><content type='html'>&lt;p&gt;One day you may be tempted to skip all the cumbersome creation of SCRIPT elements via DOM methods and just cram stuff into the page with innerHTML. Woe unto you. This does not work:&lt;/p&gt;

&lt;pre&gt;
var script = '&amp;lt;script type="text/javascript"&gt;alert("boo");&amp;lt;/script&gt;';
document.body.innerHTML = script;
&lt;/pre&gt;

&lt;p&gt;In fact, this will produce an unterminated string error in IE6 and Firefox, because you still need to split up that closing &amp;lt;/script&gt; like in ye olde days:&lt;/p&gt;

&lt;pre&gt;
var script = '&amp;lt;script type="text/javascript"&gt;alert("boo");&amp;lt;/scr' + 'ipt&gt;';
document.body.innerHTML = script;
&lt;/pre&gt;

&lt;p&gt;Hooray, no error!&lt;/p&gt;

&lt;p&gt;Except it still won't execute the script.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117106431800005762?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117106431800005762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117106431800005762'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/02/script-and-innerhtml-losing.html' title='SCRIPT and innerHTML: a losing combination'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117096259341785592</id><published>2007-02-08T11:22:00.000-08:00</published><updated>2007-02-10T08:13:37.516-08:00</updated><title type='text'>Fix your login system, you freakin' idiots</title><content type='html'>&lt;p&gt;&lt;strong&gt;Don't say "username" when you want "email address"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is simple: if your app uses email addresses as usernames (ala OpenID or whatever), don't put "enter username" on the login page. That way I don't have to put a fist through the screen after "scottandrew" is rejected 99 times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong username or password? Which is it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Did I type the wrong username? Did I misspell the password? Did I screw up both? Tell me. Don't get lazy and display "Incorrect username or password." What, do I get a prize if I guess correctly? Freakin' lazy, that's what you are.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Edit:&lt;/b&gt; I'm totally off-base on this one. A reader points out that specifying the incorrect field give hackers a vital clue. This is why I'm not in security; I'm all about making the user experience smoother &amp;mdash; for hackers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tell me if you're going to limit login attempts, and don't hide password retrieval.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some apps will throttle the number of login attempts to thwart malicious hackers. Generally I think this is dumb, but if you do this, be kind and let me know. Don't suddenly cut me off after three attempts.&lt;/p&gt;

&lt;p&gt;And if you do cut me off, for the love of god, don't also lock me out of any password retrieval link. Move that link outside of whatever if-then you're using to display the login box. Please.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When possible, redirect me to where I was headed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I click "Edit Profile" in your app. My session has timed out, so you redirect me to a login to reauthenticate. Then you dump me on the "Welcome!" page. Wha?&lt;/p&gt;

&lt;p&gt;Okay, so won't always have an HTTP_REFERRER to work with, but if I'm already working within your application and have to be redirected to a login, can't you save the original destination from the GET request or something?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117096259341785592?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117096259341785592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117096259341785592'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/02/fix-your-login-system-you-freakin.html' title='Fix your login system, you freakin&apos; idiots'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-117010797435988030</id><published>2007-01-29T13:57:00.000-08:00</published><updated>2007-01-29T14:02:20.026-08:00</updated><title type='text'>Dynamic SCRIPT elements and Safari 2.0</title><content type='html'>&lt;p&gt;Patrick Hunlock's excellent article &lt;a href="http://www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS"&gt;Howto Dynamically Insert Javascript And CSS&lt;/a&gt; reminded me of a caveat I ran across last summmer: early 2.0 versions of Safari have a bug that prevents dynamic SCRIPT elements from loading JavaScript content. The bug was fixed in version 2.0.2.&lt;/p&gt;

&lt;p&gt;That's probably the edgiest of edge cases, but it had me slamming my forehead against the wall for a few days. I was forced to do version sniffing since dynamic SCRIPT insertion was the only way to perform the cross-domain Ajax operations required.&lt;/p&gt;

&lt;p&gt;Here are &lt;a href="http://bugs.webkit.org/show_bug.cgi?id=3526"&gt;two&lt;/a&gt; &lt;a href="http://bugs.webkit.org/show_bug.cgi?id=4403"&gt;bugs&lt;/a&gt; I found while researching the problem last year.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-117010797435988030?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117010797435988030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/117010797435988030'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/01/dynamic-script-elements-and-safari-20.html' title='Dynamic SCRIPT elements and Safari 2.0'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-116976428622956245</id><published>2007-01-25T14:30:00.000-08:00</published><updated>2007-01-25T14:36:14.980-08:00</updated><title type='text'>IE6 SELECT value gotcha</title><content type='html'>&lt;p&gt;Consider the following HTML and JavaScript snippet, which attempts to grab the selected value of a SELECT element:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&amp;lt;select name="city" id="citySelector"&amp;gt;
  &amp;lt;option&amp;gt;Seattle&amp;lt;/option&amp;gt;
  &amp;lt;option selected="true"&amp;gt;Tacoma&amp;lt;/option&amp;gt;
  &amp;lt;option&amp;gt;Bellingham&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;pre&gt;
var s = document.getElementById("citySelector");
var v = s.options[s.selectedIndex].value;
alert(v);&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Firefox the result will be the string of selected city ("Tacoma"). IE6 however will return a blank string. Why?&lt;/p&gt;

&lt;p&gt;Look at the HTML. None of the options have a value attribute. This is pretty common in markup where the option text is the same as the value. When used with a form POST or GET, most browsers send the option text in lieu of the missing value attribute.&lt;/p&gt;

&lt;p&gt;But when accessing the value from JavaScript, Firefox plays fast and loose, whereas IE6 is stricter, returning nothing for the value because none was explicity given.&lt;/p&gt;

&lt;p&gt;Here's a solution that works in both browsers:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
var v = s.options[s.selectedIndex].text;
&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-116976428622956245?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/116976428622956245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/116976428622956245'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2007/01/ie6-select-value-gotcha.html' title='IE6 SELECT value gotcha'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-114184496183006914</id><published>2006-03-08T11:08:00.000-08:00</published><updated>2006-03-08T11:09:21.883-08:00</updated><title type='text'>Non-attachment</title><content type='html'>&lt;em&gt;&lt;p&gt;When Kitano Gempo, abbot of Eihei temple, was twenty-eight he studied Chinese calligraphy and poetry. He grew so skillful in these arts that his teacher praised him.&lt;/p&gt;

&lt;p&gt;Kitano mused: "If I don't stop now, I'll be a poet, not a Zen teacher." So he never wrote another poem.&lt;/p&gt;&lt;/em&gt;

&lt;p style="text-align:right"&gt;&amp;mdash; Zen Flesh, Zen Bones&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-114184496183006914?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/114184496183006914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=114184496183006914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/114184496183006914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/114184496183006914'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/03/non-attachment.html' title='Non-attachment'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-114004091097350710</id><published>2006-02-15T13:35:00.000-08:00</published><updated>2006-02-15T14:02:42.966-08:00</updated><title type='text'>Happy birthday "Ajax"</title><content type='html'>&lt;p&gt;Well, almost. February 18th is the official one-year anniversary of &lt;a href="http://www.adaptivepath.com/publications/essays/archives/000385.php"&gt;Jesse James Garrett's essay&lt;/a&gt; that coined the term "Ajax" to describe what applications like Google Maps were using under the hood.&lt;/p&gt;

&lt;p&gt;Thus rekindling interest in what some longtime web developers have pooh-poohed as old news: DHTML. But &lt;span style="font-style:italic;"&gt;man.&lt;/span&gt; &lt;a href="http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;tag=scottandrewco-20&amp;camp=1789&amp;creative=9325&amp;path=external-search%3Fsearch-type=ss%26keyword=ajax%20javascript%26index=books"&gt;Books&lt;/a&gt;. &lt;a href="http://del.icio.us/popular/ajax"&gt;Articles and tutorials&lt;/a&gt;. &lt;a href="http://www.google.com/search?q=ajax+conference"&gt;Conferences&lt;/a&gt;! &lt;a href="http://www.google.com/search?q=ajax+workshops"&gt;Workshops&lt;/a&gt;! And the prime indicator that a concept has gained serious traction, &lt;a href="http://www.google.com/search?q=ajax+sucks"&gt;haters&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Not bad for something once considered just a few short years ago to be too broken, unevenly-supported, and often downright ridiculous to be of any use.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-114004091097350710?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/114004091097350710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=114004091097350710' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/114004091097350710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/114004091097350710'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/02/happy-birthday-ajax.html' title='Happy birthday &quot;Ajax&quot;'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113994687220836284</id><published>2006-02-14T11:50:00.000-08:00</published><updated>2006-02-14T11:55:06.663-08:00</updated><title type='text'>Y! Design Pattern Library</title><content type='html'>While it's awesome that Yahoo! has released a suite of JS tools, I'm actually more enamored of the &lt;a href="http://developer.yahoo.net/ypatterns/"&gt;Yahoo! Design Pattern Library&lt;/a&gt;.

&lt;blockquote&gt;The Yahoo! Design Pattern Library is an evolving set of sophisticated design guidelines for building web pages and applications. Our design patterns do not require the Yahoo! UI Library components, although using our UI Library can help you more easily implement the patterns described in these pages.&lt;/blockquote&gt;

Very cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113994687220836284?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113994687220836284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113994687220836284' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113994687220836284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113994687220836284'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/02/y-design-pattern-library.html' title='Y! Design Pattern Library'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113994655432053885</id><published>2006-02-14T11:36:00.000-08:00</published><updated>2006-02-14T11:49:44.166-08:00</updated><title type='text'>Safari quirk: Copying innerHTML</title><content type='html'>&lt;p&gt;Here's a fun one. Given the following HTML, let's attempt to copy the contents of div1 to div2, then grab a reference to the SPAN element "foo."&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&amp;lt;div id="div1"&gt;
  &amp;lt;span id="foo"&gt;Foo span&amp;lt;/span&gt;
&amp;lt;/div&gt;

&amp;lt;div id="div2"&gt;&amp;lt;/div&gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The easy way out is to just copy innerHTML from one element to the other, then destroy the contents of the original element:&lt;/p&gt;
 
&lt;blockquote&gt;&lt;pre&gt;document.getElementById('div2').innerHTML = 
    document.getElementById('div1').innerHTML;
document.getElementById('div1').innerHTML = '';
alert(document.getElementById('foo'));&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;In most browsers, the alert dialog displays "Element SPAN" or something similar. But in Safari 1.3 and above, the dialog displays &lt;em&gt;null&lt;/em&gt;. Why?&lt;/p&gt;

&lt;p&gt;For a brief moment, when we copy the innerHTML, we create two SPANs with identical IDs of "foo." Even after we destroy the contents of div1 (leaving only the one SPAN), the DOM is screwed up enough to confuse Safari, which continues to return null even after the DOM is "fixed." By contrast, Firefox for OS X is far more forgiving.&lt;/p&gt;

&lt;p&gt;The solution seems to be: duh, don't copy from element to element. Instead, hold the contents in a variable until it's safe to reinsert them into the page:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;var tempHTML = document.getElementById('div1').innerHTML;
document.getElementById('div1').innerHTML = '';
document.getElementById('div2').innerHTML = tempHTML;
alert(document.getElementById('foo'));&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;The dialog should now display "Object SPAN" in Safari. Of course, astute JS developers would probably prefer to skip using innerHTML altogether&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113994655432053885?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113994655432053885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113994655432053885' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113994655432053885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113994655432053885'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/02/safari-quirk-copying-innerhtml.html' title='Safari quirk: Copying innerHTML'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113744495709599896</id><published>2006-01-16T12:43:00.000-08:00</published><updated>2006-01-16T12:55:57.150-08:00</updated><title type='text'>Automatic JavaScript documentation generation</title><content type='html'>&lt;p&gt;I'm looking for some recommendations for auto-generating API docs for JS libraries. There doesn't seem to be a lot of info out there on Google, so let's build a list here.&lt;/p&gt;

&lt;p&gt;I'm interested in everything from mods to existing packages like DocBook, JavaDocs, etc. to Perl scripts you've stitched together back in 1999. Have at it!&lt;/p&gt;

&lt;p&gt;Non-Blogger members can &lt;a href="mailto:delimiter@gmail.com"&gt;email me&lt;/a&gt; and I'll post your link.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113744495709599896?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113744495709599896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113744495709599896' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113744495709599896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113744495709599896'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/01/automatic-javascript-documentation.html' title='Automatic JavaScript documentation generation'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113714608344682741</id><published>2006-01-13T01:53:00.000-08:00</published><updated>2006-01-13T01:57:04.340-08:00</updated><title type='text'>Tip: the MS Script Debugger</title><content type='html'>&lt;p&gt;I'm surprised that more JavaScript developers don't know (or maybe have forgotten) about the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=2f465be0-94fd-4569-b3c4-dffdf19ccd99&amp;DisplayLang=en"&gt;Microsoft Script Debugger&lt;/a&gt;. If you're weary of IE script errors that report "Line 324: Object expected" and no filename when you have 500K of script divided over 12 files, install this beastie, then open IE and go to &lt;strong&gt;Tools &gt; Internet Options &gt; Advanced&lt;/strong&gt; and uncheck "Disable Script Debugging (Internet Explorer)."&lt;/p&gt;

&lt;p&gt;Restart IE and the next time you encounter a JS error, a dialog box should pop up asking you if you wish to debug it. Clicking OK will launch the debugger, taking you to the file (hallelujah!) and the line at which it occurred.&lt;/p&gt;

&lt;p&gt;It's not specifically tailored for JS like &lt;a href="http://www.mozilla.org/projects/venkman/"&gt;Venkman&lt;/a&gt;, but it's waaaaay better than IE's native JS error reporting.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113714608344682741?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113714608344682741/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113714608344682741' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113714608344682741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113714608344682741'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2006/01/tip-ms-script-debugger.html' title='Tip: the MS Script Debugger'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113501980401997649</id><published>2005-12-19T11:12:00.000-08:00</published><updated>2005-12-19T11:16:44.020-08:00</updated><title type='text'>Follow-up: Safari and String.replace() caveat</title><content type='html'>&lt;p&gt;Following up on the &lt;a href="http://jszen.blogspot.com/2005/12/safari-and-stringreplace-method.html"&gt;Safari and String.replace() issue&lt;/a&gt;, it looks like this is a &lt;a href="http://bugzilla.opendarwin.org/show_bug.cgi?id=5834"&gt;known bug&lt;/a&gt; that is fixed in the Webkit CVS tree but not yet part of any public release of Safari. So, if you're a junkie for &lt;a href="http://nightly.webkit.org/"&gt;nightly builds&lt;/a&gt;, you should be golden. (Your customers, on the other hand, are probably not so golden.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113501980401997649?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113501980401997649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113501980401997649' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113501980401997649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113501980401997649'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/12/follow-up-safari-and-stringreplace.html' title='Follow-up: Safari and String.replace() caveat'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113501845318754809</id><published>2005-12-19T10:47:00.000-08:00</published><updated>2005-12-19T10:54:13.246-08:00</updated><title type='text'>MacIE's numbered days</title><content type='html'>&lt;p&gt;MSFT is officially &lt;a href="http://www.microsoft.com/mac/products/internetexplorer/internetexplorer.aspx?pid=internetexplorer"&gt;pulling the plug&lt;/a&gt; IE5 for the Mac:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In accordance with published support lifecycle policies, Microsoft will end support for Internet Explorer for Mac on December 31st, 2005, and will provide no further security or performance updates.&lt;/p&gt;

&lt;p&gt;Additionally, as of January 31st, 2006, Internet Explorer for the Mac will no longer be available for download from Mactopia. It is recommended that Macintosh users migrate to more recent web browsing technologies such as Apple's Safari.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So long, old buddy.&lt;/p&gt;

&lt;p&gt;BONUS: &lt;a href="http://apple.slashdot.org/comments.pl?sid=171546&amp;cid=14287631"&gt;best comment&lt;/a&gt; via Slashdot: "Couldn't they have just emailed both people still using IE on the Mac and saved themselves the trouble of a whole press release."&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113501845318754809?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113501845318754809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113501845318754809' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113501845318754809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113501845318754809'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/12/macies-numbered-days.html' title='MacIE&apos;s numbered days'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113475474456984259</id><published>2005-12-16T09:36:00.000-08:00</published><updated>2005-12-16T09:39:04.593-08:00</updated><title type='text'>Y! JavaScript Dev Center</title><content type='html'>&lt;p&gt;Yahoo!'s &lt;a href="http://ws1.inf.scd.yahoo.com/javascript/"&gt;JavaScript Developer Center&lt;/a&gt; looks pretty sweet.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113475474456984259?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113475474456984259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113475474456984259' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113475474456984259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113475474456984259'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/12/y-javascript-dev-center.html' title='Y! JavaScript Dev Center'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113462570410182943</id><published>2005-12-14T21:46:00.000-08:00</published><updated>2005-12-14T22:09:21.580-08:00</updated><title type='text'>Safari and the String.replace() method</title><content type='html'>&lt;p&gt;JavaScript strings have a cool method called &lt;code&gt;replace()&lt;/code&gt; which allows you to supply a regular expression and replace the matched bits of the string with another string.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;var str = "my dog has fleas";
str = str.replace(/dog/, "cat");&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Output:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;my cat has fleas&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;One of the cooler things about this is you can provide an expression as the second argument. This can be a variable:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;var str = "my dog has fleas";
var str2 = "cat"
str = str.replace(/dog/, str2);&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;...or even a function:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;function Cat() {
  return "cat";
}
str = str.replace(/dog/, Cat);&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This works great in IE, and Firefox on both Windows and OS X.&lt;/p&gt;

&lt;p&gt;But Safari? Not so much. Here's the output of that last example in Safari:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;my function Cat() {return "cat";} has fleas&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Ugh, what happened? It appears that when given a function in this context, Safari does not evaluate it as an expression, but instead calls the &lt;code&gt;toString()&lt;/code&gt; method of the function, casting it into a string.&lt;/p&gt;

&lt;p&gt;I haven't found a workaround. Have you?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113462570410182943?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113462570410182943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113462570410182943' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113462570410182943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113462570410182943'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/12/safari-and-stringreplace-method.html' title='Safari and the String.replace() method'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113148033809681698</id><published>2005-11-08T11:58:00.000-08:00</published><updated>2005-11-08T21:41:47.110-08:00</updated><title type='text'>Safari and DOM 2 HTML</title><content type='html'>&lt;p&gt;Does Safari support a HTML element hierarchy/interface, similar to Firefox's support of the &lt;a href="http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/ecma-script-binding.html"&gt;DOM 2 HTML interface&lt;/a&gt;? It does not appear to be so. Or if it does, it doesn't expose it to scripting. True or false? Google is silent on the matter.&lt;/p&gt;

&lt;p&gt;Links and pointers welcome.&lt;/p&gt;

&lt;p&gt;Okay, some clarification: there's &lt;a href="http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/"&gt;DOM 2 Core&lt;/a&gt;, which is the node/element interface we know and love, which allows us to express a document as a hierarchy of objects. On top of this is &lt;a href="http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/ecma-script-binding.html"&gt;DOM 2 HTML&lt;/a&gt; which goes a step further by defining specific kinds of node/element classes to represent HTML elements. A DIV is an HTMLDivElement, an IMG is an HTMLImageElement, etc.&lt;/p&gt;

&lt;p&gt;Each of these element node are descendants of the Mother Of All HTML Subclasses, HTMLElement.&lt;/p&gt;

&lt;p&gt;I'm trying to determine if Safari supports DOM 2 HTML. So far, all signs point to no. In Safari, a DIV is a DIV and an IMG is an IMG. I can't really discern if the HTML elements are subclasses of some super-duper element &amp;mdash; my guess is if there is one, it's not exposed to scripting as it is in Mozilla/Firefox. I'd love to be proven wrong.&lt;/p&gt;

&lt;p&gt;UPDATE: &lt;a href="http://webkit.opendarwin.org/blog/?p=27"&gt;according to this table&lt;/a&gt;, Safari 2.0.1 was 99% compliant with the DOM 2 HTML spec. So it's there. Is it scriptable? I'll have to upgrade and let you know.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113148033809681698?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113148033809681698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113148033809681698' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113148033809681698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113148033809681698'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/11/safari-and-dom-2-html.html' title='Safari and DOM 2 HTML'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113018602008467172</id><published>2005-10-24T13:32:00.000-07:00</published><updated>2005-10-24T13:34:49.496-07:00</updated><title type='text'>Got ActiveX?</title><content type='html'>&lt;p&gt;&lt;a href="http://www.flickr.com/photos/scottandrew/54626894/" title="Photo Sharing"&gt;&lt;img src="http://static.flickr.com/24/54626894_d8639870e1_m.jpg" width="240" height="173" alt="ActiveX required?" align="right" /&gt;&lt;/a&gt;To use PassAlong's digital distribution service, you must have ActiveX installed. Got Firefox? No worries, &lt;span style="font-style:italic;"&gt;there's a plug-in&lt;/span&gt; just for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com/photos/scottandrew/54626894/"&gt;Yuck.&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113018602008467172?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113018602008467172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113018602008467172' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113018602008467172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113018602008467172'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/10/got-activex.html' title='Got ActiveX?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113017965335057499</id><published>2005-10-24T11:39:00.000-07:00</published><updated>2005-10-24T13:20:03.380-07:00</updated><title type='text'>Kickass form assistance</title><content type='html'>&lt;p&gt;So have you seen &lt;a href="http://www.rememberthemilk.com/"&gt;Remember The Milk&lt;/a&gt; yet? It's a to-do list service that has some very next-gen features, including some Ajaxy stuff to speed things like form entry and validation:&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/2496/1/1600/rememberthemilk.gif"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/2496/1/400/rememberthemilk.gif" border="0" alt="" /&gt;&lt;/a&gt;

&lt;p&gt;Remember The Milk checks to see if the username I've selected is available &lt;i&gt;as I type it&lt;/i&gt; and puts little checkmarks next to completed fields. I'm totally in love with this approach. How many times have you filled out a form with a kabillion fields, only to be forced to do it &lt;i&gt;again&lt;/i&gt; because one or two fields were invalid?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113017965335057499?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113017965335057499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113017965335057499' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113017965335057499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113017965335057499'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/10/kickass-form-assistance.html' title='Kickass form assistance'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-113017863476006711</id><published>2005-10-24T11:21:00.000-07:00</published><updated>2005-10-24T11:34:41.386-07:00</updated><title type='text'>"Samy" explained</title><content type='html'>&lt;p&gt;&lt;a href="http://namb.la/popular/tech.html"&gt;Here's a detailed examination&lt;/a&gt; of the MySpace Samy/JS.Spacehero worm, a JavaScript hack that enabled one MySpace user to automatically add himself to the "friends" lists of thousands of MySpace members and add the line "Samy is my hero" to their profiles.&lt;/p&gt;

&lt;p&gt;Looks like the perp found a way to execute JavaScript by stuffing a "javascript:" pseudo-protocol inside a CSS background:url(...) rule, then used XMLHTTP to execute a series of POSTs. Much of the code looks pretty IE-specific in this case.&lt;/p&gt;

&lt;p&gt;Mmmm, Ajax badness.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-113017863476006711?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/113017863476006711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=113017863476006711' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113017863476006711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/113017863476006711'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/10/samy-explained.html' title='&quot;Samy&quot; explained'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112793218415998935</id><published>2005-09-28T11:29:00.000-07:00</published><updated>2005-09-28T11:35:42.553-07:00</updated><title type='text'>The Ghost of NS4</title><content type='html'>&lt;p&gt;There are times when you simply have to throw in the towel and do something evil. Such as, oh, make Firefox behave like Netscape 4.&lt;/p&gt;

&lt;p&gt;A widely-used utility script was causing fatal errors in Firefox. These errors were halting the JS interpreter completely, which shut down my own code before it could even be executed. Closer examination revealed that the utility script jammed all browsers into the IE4 or NS4 category, and made extensive use of NS4-only properties like document.layers, layer.clip and layer.pageX.&lt;/p&gt;

&lt;p&gt;Fixing the utility script to work with Firefox was not an option. The script is deployed to literally hundreds of thousands of existing websites as part of a popular WYSIWYG program. Even if I was able to provide a patch to the script, there would be no way to compel people to upgrade.&lt;/p&gt;

&lt;p&gt;Not to mention that &lt;span style="font-style: italic;"&gt;I'd&lt;/span&gt; be the one stuck maintaining and supporting a script that I didn't write.&lt;/p&gt;

&lt;p&gt;Worse, browser detection was buried deep inside the utility script and done on the fly in several spots, all with locally-scoped variables that were impossible to overwrite.&lt;/p&gt;

&lt;p&gt;I had to find a way to unblock these errors without touching the script.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;p&gt;document.layers = document.getElementsByTagName("*");&lt;/p&gt;

&lt;p&gt;Unngh! It &lt;span style="font-style: italic;"&gt;hurts!&lt;/span&gt; Make it &lt;span style="font-style: italic;"&gt;stop!&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;HTMLElement.prototype.pageX getter = function () { return this.offsetLeft; };&lt;br /&gt;
HTMLElement.prototype.pageY getter = function () { return this.offsetTop; };
&lt;/p&gt;
&lt;p&gt;Please kill me now.&lt;/p&gt;

&lt;p&gt;I'll leave it to you to figure out how I took care of things like the getting and setting of properties like clip.left, clip.top, clip.right, etc. (hint: it involves the use of getComputedStyle, parseInt, a number of string methods and IT AIN'T PRETTY, THAT'S FOR SURE.)&lt;/p&gt;

&lt;p&gt;Oh wait, IE6 chokes on this and tells me it's expecting a semicolon. Well, of course. IE doesn't support getter/setter. So I have to wrap this whole thing in a &lt;span style="font-style: italic;"&gt;server-side&lt;/span&gt; UA sniff to ensure that it's never delivered to IE.&lt;/p&gt;

&lt;p&gt;The ghost of NS4 continues to haunt, its icy incorporeal fingers reaching out to mess with my head.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112793218415998935?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112793218415998935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112793218415998935' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112793218415998935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112793218415998935'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/09/ghost-of-ns4.html' title='The Ghost of NS4'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112777992108949927</id><published>2005-09-26T17:09:00.000-07:00</published><updated>2005-09-26T17:12:01.096-07:00</updated><title type='text'>Del.icio.us with Blogspot blogs?</title><content type='html'>&lt;p&gt;I thought I'd be able to use &lt;a href="http://del.icio.us"&gt;del.icio.us&lt;/a&gt; links in conjunction with this blog (not as a sidebar, but the handy daily automated post feature), but it's been a long while since I used the Blogger API, and there doesn't seem to be a target URI for posting that I know of. Anyone out there know how I can get this working? Or am I just hosed?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112777992108949927?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112777992108949927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112777992108949927' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112777992108949927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112777992108949927'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/09/delicious-with-blogspot-blogs.html' title='Del.icio.us with Blogspot blogs?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112618986456221968</id><published>2005-09-08T07:22:00.000-07:00</published><updated>2005-09-08T07:31:23.950-07:00</updated><title type='text'>addEvent() recoding contest</title><content type='html'>&lt;p&gt;Peter-Paul Koch has &lt;a href="http://www.quirksmode.org/blog/archives/2005/09/addevent_recodi.html"&gt;put together a contest&lt;/a&gt; to recreate my addEvent() and removeEvent() utilities in a way that compensates for its inherent shortcomings:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Write your own version of addEvent() and removeEvent(), submit it by adding a comment to this page, and win JavaScript fame.&lt;/p&gt;

&lt;p&gt;Entries will be judged by a panel consisting of Scott Andrew LePera, Dean Edwards and myself on script quality, simplicity and portability, and the clarity of your explanation.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;I'll also &lt;a href="http://www.scottandrew.com/weblog/articles/cbs-events"&gt;update the original tutorial&lt;/a&gt; that introduced addEvent() with a link to the winning entry.&lt;/p&gt;

&lt;p&gt;Previously: &lt;a href="http://jszen.blogspot.com/2005/08/know-your-event-sources.html"&gt;Know your (event) sources&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112618986456221968?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112618986456221968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112618986456221968' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112618986456221968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112618986456221968'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/09/addevent-recoding-contest.html' title='addEvent() recoding contest'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112585619197417092</id><published>2005-09-04T10:38:00.000-07:00</published><updated>2005-09-04T10:49:51.986-07:00</updated><title type='text'>A treasure trove of quirks</title><content type='html'>&lt;p&gt;If you're not already reading &lt;a href="http://my.opera.com/hallvors/journal/"&gt;Hallvord R. M. Steen's Miscoded Blog&lt;/a&gt;, you probably should be. Hallvord's a JavaScript QA tester for &lt;a href="http://www.opera.com/"&gt;Opera Software&lt;/a&gt;, and uses his blog to record many of the JS and browser quirks and caveats he comes across. Some sample posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://my.opera.com/hallvors/journal/56"&gt;IE's event transparency logic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://my.opera.com/hallvors/journal/57"&gt;document.all offers another IE quirk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://my.opera.com/hallvors/journal/47"&gt;meetup.com captures events by mistake&lt;/a&gt; (&lt;code&gt;addEvent()&lt;/code&gt; strikes again!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good stuff. Read it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112585619197417092?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112585619197417092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112585619197417092' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112585619197417092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112585619197417092'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/09/treasure-trove-of-quirks.html' title='A treasure trove of quirks'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112544372239746091</id><published>2005-08-30T16:15:00.000-07:00</published><updated>2005-08-30T19:03:51.590-07:00</updated><title type='text'>Know your (event) sources</title><content type='html'>&lt;p&gt;A loooong time ago I wrote &lt;a href="http://www.scottandrew.com/weblog/articles/cbs-events"&gt;this tutoral on JavaScript events&lt;/a&gt;, in which I included a cross-browser event handling script called &lt;code&gt;addEvent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Today, Peter-Paul Koch: &lt;a href="http://www.quirksmode.org/blog/archives/2005/08/addevent_consid.html"&gt;addEvent Considered Harmful&lt;/a&gt;. And he's right, you can get into all kinds of headaches using IE's &lt;code&gt;attachEvent&lt;/code&gt; method, as my own &lt;code&gt;addEvent&lt;/code&gt; snippet does. Be sure to read the ensuing comment thread for some interesting alternative approaches.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Caveat implementor&lt;/i&gt;, my friends.&lt;/p&gt;

&lt;p&gt;PS: I'm rather pleased that something I wrote merits a "considered harmful" treatise! &lt;a href="http://www.google.com/search?hl=en&amp;q=considered+harmful"&gt;I'm in good company.&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112544372239746091?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112544372239746091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112544372239746091' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112544372239746091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112544372239746091'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/know-your-event-sources.html' title='Know your (event) sources'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112509115286397548</id><published>2005-08-26T14:05:00.000-07:00</published><updated>2005-08-28T19:26:03.360-07:00</updated><title type='text'>Firefox document.all caveat</title><content type='html'>&lt;p&gt;&lt;code&gt;document.all&lt;/code&gt; is a proprietary feature of Microsoft Internet Explorer; a JavaScript-accessible collection of all page elements and precursor to the W3C &lt;code&gt;document.getElementById()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Firefox doesn't support &lt;code&gt;document.all&lt;/code&gt;. Or does it?&lt;/p&gt;

&lt;p&gt;Beware: Firefox &lt;i&gt;does&lt;/i&gt; sport a &lt;code&gt;document.all&lt;/code&gt; when a page is in quirks mode. In fact, you can see it with the DOM Inspector tool. It doesn't have any child elements so I suspect it's some sort of wrapper for &lt;code&gt;getElementById&lt;/code&gt;. Try referencing it from code and you may get this friendly warning:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Warning: Non-standard document.all property was used. Use W3C standard document.getElementById() instead.&lt;p&gt;&lt;/blockquote&gt;

&lt;p&gt;Switch to a standards-compliant page and &lt;code&gt;document.all&lt;/code&gt; is undefined, as expected.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;Obviously this puts code that employs quick old-school browser checking with &lt;code&gt;document.all&lt;/code&gt; at risk &amp;mdash; especially if your code is meant to be portable or drop-in.&lt;/del&gt; Updated: see below.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; looks like support for document.all was &lt;a href="http://weblogs.mozillazine.org/asa/archives/007118.html"&gt;introduced in Moz 1.7.5&lt;/a&gt; back in December 2004.&lt;p&gt;

&lt;p&gt;&lt;b&gt;Update #2&lt;/b&gt; Confusion. The Mozillazine note says the document.all is "undetectable", but the way I discovered this was because FF was taking an IE code path based on the existence of document.all, exactly what &lt;i&gt;shouldn't&lt;/i&gt; be happening. So I dunno.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update #3&lt;/b&gt; I haven't been able to reproduce the case that led me to discover Firefox's &lt;code&gt;document.all&lt;/code&gt; implementation, so I think the bug must have been in my code. (Shocking, I know!) In any case, it does look like a test for &lt;code&gt;document.all&lt;/code&gt; in Firefox should return &lt;i&gt;false&lt;/i&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112509115286397548?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112509115286397548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112509115286397548' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112509115286397548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112509115286397548'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/firefox-documentall-caveat.html' title='Firefox document.all caveat'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112504089673467196</id><published>2005-08-26T00:08:00.000-07:00</published><updated>2005-08-26T00:25:08.256-07:00</updated><title type='text'>Google Talk</title><content type='html'>&lt;p&gt;Raise your hand if you were underwhelmed by Google Talk not only being Windows-only, but a desktop app. ::raises hand::&lt;/p&gt;

&lt;p&gt;I'm sure I'm not the only one scratching my head over Google's decision to do a desktop app as opposed to a web client. It's not like it hasn't been done before &amp;mdash; AOL's &lt;a href="https://my.screenname.aol.com"&gt;AIM Express&lt;/a&gt; is, as far as I can tell, a pure DHTML IM client although I can't tell for sure if it's a persistent connection or polling. Actually, I don't care; AIM Express rocks. It does the job, works in Moz, 'nuff said.&lt;/p&gt;

&lt;p&gt;Most likely Google Talk is chained to the desktop due to it's VoIP features. Fair enough, I don't think, uh, VoIP-over-HTTP is a worthwhile endeavor right now. Maybe the IM features are just a nice-to-have thrown in on top of an app that was initially designed to make VoIP as easy as IM.&lt;/p&gt;

&lt;p&gt;But still, kind of a strange sideways move for Google.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112504089673467196?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112504089673467196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112504089673467196' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112504089673467196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112504089673467196'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/google-talk.html' title='Google Talk'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112407833833691347</id><published>2005-08-14T20:58:00.000-07:00</published><updated>2005-08-14T21:00:14.506-07:00</updated><title type='text'>Here come the Ajax books</title><content type='html'>&lt;p&gt;It's only been six months since Jesse James Garrett &lt;a href="http://www.adaptivepath.com/publications/essays/archives/000385.php"&gt;neatly rechristened&lt;/a&gt; the combination of JavaScript, DOM and behind-the-scenes HTTP requests as "Ajax," and there are already three books available for preorder at Amazon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/1932394613/scottandrewco-20"&gt;Ajax in Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/1590595823/scottandrewco-20"&gt;Foundations of AJAX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0471777781/scottandrewco-20"&gt;Professional Ajax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've also heard rumblings of books from O'Reilly, Sitepoint, etc.&lt;/p&gt;

&lt;p&gt;Are &lt;em&gt;you&lt;/em&gt; working on an Ajax book? Hit us with a comment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112407833833691347?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112407833833691347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112407833833691347' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112407833833691347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112407833833691347'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/here-come-ajax-books.html' title='Here come the Ajax books'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112398281669262392</id><published>2005-08-13T18:25:00.000-07:00</published><updated>2005-08-13T18:29:23.636-07:00</updated><title type='text'>Beware of false falses, or something like that</title><content type='html'>&lt;p&gt;This is a really, really common gotcha that trips up even expert webdevs.&lt;/p&gt;

&lt;p&gt;When you're checking for the existence of an object or property, make sure what you're testing is not going to return an unexpected value. For example.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;if (document.documentElement.scrollTop) {...}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Right away, we're in trouble. Why? Because the default value of scrollTop is &lt;em&gt;zero&lt;/em&gt; (for a page that hasn't been scrolled yet). In JavaScript (and many other "real" programming languages), zero is the same as &lt;em&gt;false&lt;/em&gt;. So in the above statement, the conditional in parenthesis will fail, and the code will make the wrong choice &amp;mdash; and we haven't even tested for document.body yet.&lt;/p&gt;

&lt;p&gt;What about this?&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;if (document.documentElement &amp;&amp; document.documentElement.scrollTop) {...}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Also no good if scrollTop returns zero. Here's a better way:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;if (document.documentElement) {...}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This test will return &lt;em&gt;undefined&lt;/em&gt; if documentElement is missing, which is correct behavior. In a pseudo-Boolean check like this one, undefined is as good as false.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112398281669262392?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112398281669262392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112398281669262392' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112398281669262392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112398281669262392'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/beware-of-false-falses-or-something.html' title='Beware of false falses, or something like that'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112313887262663507</id><published>2005-08-03T23:56:00.000-07:00</published><updated>2005-08-12T14:25:08.963-07:00</updated><title type='text'>The dark despair of DOCTYPEs</title><content type='html'>&lt;p&gt;It bears repeating: the use of different DOCTYPEs can change the DOM interface in unexpected ways. It shouldn't, but it does. To wit: &lt;pre&gt;document.body.scrollTop&lt;/pre&gt; becomes &lt;pre&gt;document.documentElement.scrollTop&lt;/pre&gt;...depending on which DOCTYPE is used. (The former property doesn't disappear, but stops being updated, returning 0 (zero) no matter how much you scroll). This seems to be true for both IE6 and Firefox. So be sure to test for both if your web app depends on accurately measuring the scroll offset of a page. &lt;i&gt;Double&lt;/i&gt;-especially if your app is something to be dropped into existing webpages with DOCTYPEs you cannot know in advance.&lt;/p&gt;

&lt;p&gt;IE has a neato &lt;pre&gt;document.compatMode&lt;/pre&gt; property that returns "BackCompat" if the DOCTYPE is allowing the page to behave like old-school IE, with the broken box model and the stuff and the thing. "CSS1Compat" indicates DOCTYPE-triggered "standards-compliance" mode. So you can have your app test for this and adjust accordingly.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112313887262663507?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112313887262663507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112313887262663507' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112313887262663507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112313887262663507'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/dark-despair-of-doctypes.html' title='The dark despair of DOCTYPEs'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-112305234313924462</id><published>2005-08-02T23:58:00.000-07:00</published><updated>2005-08-02T23:59:03.146-07:00</updated><title type='text'>IE style rule gotcha</title><content type='html'>&lt;p&gt;I've been busy with massive project at the day job (launching soon, 
hope to mention it in detail here), and soon I'll be preoccupied with a 
C++ course, so I don't expect to be posting with any regular frequency
here for the remainder of the summer.&lt;/p&gt;

&lt;p&gt;I will share this, though: just because you can set style properties 
with a string:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;elm.style.fontSize = "12px";&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;...doesn't mean IE will accept &lt;i&gt;any&lt;/i&gt; old string:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;elm.style.fontSize = "12px !important";
/* causes 'invalid argument' error in IE */&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Firefox has no problem with this. Of course.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-112305234313924462?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/112305234313924462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=112305234313924462' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112305234313924462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/112305234313924462'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/08/ie-style-rule-gotcha.html' title='IE style rule gotcha'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111997700005553653</id><published>2005-06-28T09:43:00.000-07:00</published><updated>2005-06-28T09:43:20.060-07:00</updated><title type='text'>MS rolling out Ajax toolkit</title><content type='html'>&lt;p&gt;Looks like Microsoft will be &lt;a href="http://news.com.com/2102-1007_3-5765197.html?tag=st.util.print"&gt;rolling out an Ajax-enabling toolkit&lt;/a&gt; called Atlas.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Microsoft's Atlas is a "Web client framework" designed to make the job of building AJAX-style applications simpler, said Charles Fitzgerald, the company's general manager for platform technologies.&lt;/p&gt;

&lt;p&gt;"People who do (AJAX development) are rocket scientists," Fitzgerald said. "In some ways, this papers over the mess that is JavaScript development. It's easy-to-build 'spaghetti' code."&lt;/p&gt;

&lt;p&gt;Atlas--which is a downloadable piece of JavaScript code--gives developers a more structured environment for building applications, providing time-saving services such as an object model and debugging, he said. It will work across any Web browser that supports AJAX technologies.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;The "rocket science" quote is funny, 'cause one of the questions posed at the Ajax Summit I attended last month was along the lines of "is Ajax rocket science?" Answer: only if you want to build rockets.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111997700005553653?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111997700005553653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111997700005553653' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111997700005553653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111997700005553653'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/ms-rolling-out-ajax-toolkit.html' title='MS rolling out Ajax toolkit'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111963314142625264</id><published>2005-06-24T10:11:00.000-07:00</published><updated>2005-06-24T10:12:21.433-07:00</updated><title type='text'>Don't do these anymore</title><content type='html'>&lt;p&gt;&lt;a href="http://www.wait-till-i.com/index.php?p=104"&gt;Six JavaScript features we do not need any longer&lt;/a&gt;. I still see plenty of instances of "javascript:" in modern JS code. My favorite is seeing it used in an event handler, like this:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&amp;lt;a href="#" onclick="JavaScript:doThis();"&amp;gt;Do This!&amp;lt;/a&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;With &lt;span style="font-style:italic;"&gt;capitalization&lt;/span&gt;, even. Hello?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111963314142625264?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111963314142625264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111963314142625264' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111963314142625264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111963314142625264'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/dont-do-these-anymore.html' title='Don&apos;t do these anymore'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111957168723610236</id><published>2005-06-23T17:07:00.000-07:00</published><updated>2005-06-23T17:08:07.240-07:00</updated><title type='text'>Spot The WTF: JavaScript edition</title><content type='html'>&lt;p&gt;&lt;a href="http://thedailywtf.com"&gt;The Daily WTF&lt;/a&gt; has a doozy of a JavaScript challenge: the most &lt;a href="http://thedailywtf.com/forums/36898/ShowPost.aspx"&gt;jaw-dropping test for alphanumeric characters&lt;/a&gt;, &lt;i&gt;evar&lt;/i&gt;. Wow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111957168723610236?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111957168723610236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111957168723610236' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111957168723610236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111957168723610236'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/spot-wtf-javascript-edition.html' title='Spot The WTF: JavaScript edition'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111945725849750051</id><published>2005-06-22T09:20:00.000-07:00</published><updated>2005-06-22T09:20:58.503-07:00</updated><title type='text'>I made some science</title><content type='html'>&lt;a href="http://blogsurvey.media.mit.edu/request"&gt;&lt;img src="http://blogsurvey.media.mit.edu/images/survey-science.gif" alt="Take the MIT Weblog Survey" style="border:none" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111945725849750051?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111945725849750051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111945725849750051' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111945725849750051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111945725849750051'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/i-made-some-science.html' title='I made some science'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111893801717827790</id><published>2005-06-16T09:05:00.000-07:00</published><updated>2005-06-16T09:22:20.756-07:00</updated><title type='text'>TiddlyWiki hack: exporting tiddler HTML</title><content type='html'>&lt;p&gt;I was trying to figure out how to export rendered HTML from a &lt;a href="http://www.tiddlywiki.com"&gt;TiddlyWiki&lt;/a&gt; tiddler so I could paste it into an MS Word document. Since there doesn't seem to be a supported way to do this in TiddlyWiki, I found two methods that seem to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're using Firefox, just highlight the tiddler text, then right-click your selection and choose "View Selection Source." I dunno why this works, but it does.&lt;/li&gt;
&lt;li&gt;Otherwise, I threw together the Ugliest TiddlyWiki Hack Ever!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I may be reinventing the wheel here, but whatever.&lt;/p&gt;

&lt;p&gt;Save a backup of your TiddlyWiki file, then open it in a text editor and search for the &lt;b&gt;createTiddlerToolbar&lt;/b&gt; function. In that function, look for the section that adds buttons to the non-editor toolbar and add the following lines to that block:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
insertSpacer(theToolbar);
createTiddlyButton(
  theToolbar,
  "html",
  "show/hide HTML of this tiddler",
  onClickToolbarShowHTML
);
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Now add the following function somewhere in the page, preferably near where the other button handlers live:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
function onClickToolbarShowHTML(e)
{
  hideMessage();
  if(this.parentNode.id) {
    var viewer = 
      document.getElementById("viewer" + this.parentNode.id.substr(7));
    if (!viewer.isHTMLView) {
      viewer.innerHTML = viewer.innerHTML.replace(/\&amp;lt;/g,"&amp;amp;lt;");
      viewer.isHTMLView = true;
    } else {
      viewer.isHTMLView = false;
      displayTiddler(
        null,this.parentNode.id.substr(7),1,null,null,false
      );
    }
  }
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This is admittedly a gross hack: we're just grabbing the HTML of the viewer tiddler and replacing all the left angle brackets with HTML entities, then stuffing the HTML back into the tiddler. Since calling &lt;b&gt;displayTiddler&lt;/b&gt; refreshes the tiddler content, we can use that to undo the damage without manipulating the string again.&lt;/p&gt;

&lt;p&gt;This has been pretty useful to me, since I love the simple TiddlyWiki table markup for doing spec work, but usually have to cut and paste it into a report written in HTML or Word. Now, I just hit that "html" tiddler button, copy/paste the HTML, then toggle it back.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111893801717827790?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111893801717827790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111893801717827790' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111893801717827790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111893801717827790'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/tiddlywiki-hack-exporting-tiddler-html.html' title='TiddlyWiki hack: exporting tiddler HTML'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111852355387653437</id><published>2005-06-11T13:53:00.000-07:00</published><updated>2005-06-11T14:02:46.396-07:00</updated><title type='text'>Proposed event sourcing in HTML 5</title><content type='html'>&lt;p&gt;From the &lt;a href="http://www.ajaxian.com/archives/2005/06/html_5_vs_xhtml.html"&gt;Ajaxian&lt;/a&gt; blog, a rundown of proposed HTML 5 features from &lt;a href="http://www.whatwg.org/"&gt;WHAT-WG&lt;/a&gt;. They also link to &lt;a href="http://www.hixie.ch/advocacy/whatwg-presentation/"&gt;Hixie's slides&lt;/a&gt;, which don't work in Firefox. Feh.&lt;/p&gt;

&lt;p&gt;There's a lot of interesting stuff that walks the line between semantic vs. presentational, etc. My favorite, though, is this the proposal for event sources:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;event-source src="/some/path" onevent="process(event)"/&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;This is exciting to me because &lt;a href="http://mod-pubsub.org"&gt;mod-pubsub&lt;/a&gt; comes extremely close to this implementation with their JavaScript/DOM engine, which allowed HTML elements to process and display remote server events with just a few non-standard attributes:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;div kn_topic="/some/path" kn_onmessage="process(event)"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Of course we had a very freakishly large and complex JavaScript engine to handle all the Ajaxy goodness. At the time, we called it a &lt;em&gt;microserver&lt;/em&gt;, since the idea was that the JS engine could serve events from client to server as well as to other parts of the client. A web application could comprise of several mini-applications tied together with a JS message bus &amp;mdash; which isn't so different from desktop OS programming.&lt;/p&gt;

&lt;p&gt;At one point it was generally agreed that the notion of a microserver wouldn't be exciting for much longer, since it seemed to make sense that this "JS message bus" would eventually be baked into the browser &amp;mdash; if only people would see the usefulness of it! (This was in 2001; Google Suggest and Google Maps were a few years away.)&lt;/p&gt;

&lt;p&gt;For something like WHAT-WG's event-source to work, there has to be support for such functionality in the browser. But I'm glad to see this development, and am looking forward to the time when we won't have to drag around additional JS libraries to implement event-driven web apps.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111852355387653437?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111852355387653437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111852355387653437' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111852355387653437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111852355387653437'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/proposed-event-sourcing-in-html-5.html' title='Proposed event sourcing in HTML 5'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111818864373262667</id><published>2005-06-07T16:56:00.000-07:00</published><updated>2005-06-07T16:57:23.736-07:00</updated><title type='text'>Dig!</title><content type='html'>&lt;p&gt;Great Athena! It's &lt;a href="http://193.151.73.87/games/lemmings/index.html"&gt;DHTML Lemmings!&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111818864373262667?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111818864373262667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111818864373262667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111818864373262667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111818864373262667'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/06/dig.html' title='Dig!'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111757630180690902</id><published>2005-05-31T14:50:00.000-07:00</published><updated>2005-05-31T14:52:42.013-07:00</updated><title type='text'>Why Google Maps wins</title><content type='html'>&lt;p&gt;It occurs to me that the real winning feature of &lt;a href="http://maps.google.com"&gt;Google Maps&lt;/a&gt; is not its DHTML-goodness, its endless scrolling surfaces, its Ajax underpinnings nor its satellite photo views. Rather, the winning feature is the user types the address into a &lt;i&gt;single input box&lt;/i&gt;. No more entering street address, city, state and zip into separate boxes. You don't even need commas, AFAICT.&lt;/p&gt;

&lt;p&gt;It seems like such a trivial detail, but to me it's everything. Why can't every address input interface be that simple?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111757630180690902?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111757630180690902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111757630180690902' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111757630180690902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111757630180690902'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/why-google-maps-wins.html' title='Why Google Maps wins'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111712988358635557</id><published>2005-05-26T10:45:00.000-07:00</published><updated>2005-05-26T10:51:47.380-07:00</updated><title type='text'>Summer Slump</title><content type='html'>&lt;p&gt;This is one of those posts to inform readers that blogging will continue to be light over the next few weeks as things get crazy with the &lt;a href="http://www.scottandrew.com"&gt;music thing&lt;/a&gt; the day job is taking away what little time is left. Plus, I've got a backlog of &lt;i&gt;Lost&lt;/i&gt; episodes to watch.&lt;/p&gt;

&lt;p&gt;Of course, I fully expect to discover a bunch of post-worthy things the moment I click "Save" on this entry :)&lt;/p&gt;

&lt;p&gt;In the meantime, behold the wonder that &lt;a href="http://www.tiddlywiki.com/"&gt;TiddlyWiki&lt;/a&gt; has become. It's got some of the cleanest JS code I've seen in a long time, and local load/save options? Heaven. I came up with a hack to add checkboxed list items but it's so ugly and wrong I'm too embarrassed to release it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111712988358635557?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111712988358635557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111712988358635557' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111712988358635557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111712988358635557'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/summer-slump.html' title='Summer Slump'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111669963180626678</id><published>2005-05-21T11:15:00.000-07:00</published><updated>2005-05-21T11:20:31.813-07:00</updated><title type='text'>Secure IFRAME gotcha</title><content type='html'>&lt;p&gt;A simple caveat from an anonynmous JS whiz: when you create a new IFRAME element on a secure page, IE sets the default SRC to a non-secure blank page, thus popping a security alert dialog.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;var el = document.createElement('iframe');&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Since creating IFRAMEs in IE this way is already problematic, the solution might be to insert the IFRAME with innerHTML rather than using createElement. YMMV.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111669963180626678?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111669963180626678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111669963180626678' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111669963180626678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111669963180626678'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/secure-iframe-gotcha.html' title='Secure IFRAME gotcha'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111592710296345283</id><published>2005-05-12T12:40:00.000-07:00</published><updated>2005-05-12T12:45:02.966-07:00</updated><title type='text'>Ajax @ Amazon?</title><content type='html'>&lt;p&gt;Given that I was one of the lone attendees without a demo to show at the Ajax Summit earlier this week, I wish I had known about &lt;a href="http://www.amazon.com/gp/search/finder/?productGroupID=loose%5fdiamonds"&gt;Amazon's new Diamond Search&lt;/a&gt;, which uses a combo of DHTML and Ajax-style backend communication to allow users to narrow search results in a purely visual way. Move the sliders back and forth and watch as some mysterious process fetches the number of search results in real time.&lt;/p&gt;

&lt;p&gt;Full disclosure: I didn't build this and have no idea how it works under the hood. A press release went out last Wednesday and the app has been publically available for at least a week. News to me.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111592710296345283?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111592710296345283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111592710296345283' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111592710296345283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111592710296345283'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/ajax-amazon.html' title='Ajax @ Amazon?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111579851417901469</id><published>2005-05-11T01:01:00.000-07:00</published><updated>2005-05-11T01:13:13.543-07:00</updated><title type='text'>Ajaxed out</title><content type='html'>&lt;p&gt;For the past two days I've been attending an "Ajax summit" event thrown by &lt;a href="http://www.oreilly.com"&gt;O'Reilly&lt;/a&gt; and &lt;a href="http://www.adaptivepath.com"&gt;Adaptive Path&lt;/a&gt;. I think "summit" is an apt term to describe it, as it included a cool cross-section of individuals from various disciplines &amp;mdash; web developers, network engineers, interaction designers and others &amp;mdash; and many, many people who've been doing this type of work for a long, long time. I thought this was an important distinction, as the application of Ajax (however you might define it)  brings new solutions to old problems while creating new problems that reach outside the scope of what is generally thought of as "webdev."&lt;/p&gt;

&lt;p&gt;I'm way tired, so here're some frazzled notes and takeaways.&lt;/p&gt;

&lt;h3&gt;Ajax, grunge rock and convergence&lt;/h3&gt;

&lt;p&gt;I found a parallel in the &lt;a href="http://www.tomorrowtoday.biz/generations/xpaper2011.htm"&gt;thoughts&lt;/a&gt; of Generation X author Douglas Coupland on the hypermarketing of the twentysomethings in the early 90s:&lt;/p&gt;

&lt;p&gt;&lt;blockquote&gt;&lt;em&gt;Generation X's&lt;/em&gt; tiny, March 1991 printing had no publicity, and received almost no reviews. But that summer a Texan my age named Richard Linklater released the movie "Slacker"...And in Seattle, a new form of music was exploding...As the media goes, two's nothing, but three's a trend. Thus were born the most abused buzzwords of the early 90s: "generation X", "slacker", and "grunge".&lt;/blockquote&gt;&lt;/p&gt;

&lt;p&gt;Similarly, I felt three things happened to converge, coincidentally: the flattening of the browser landscape; the buzz built around Google's trial-balloon apps like Google Suggest, and the coining of the highly-buzzable term "Ajax."&lt;/p&gt;

&lt;p&gt;Thus, Ajax is the GenX of web development: suddenly a movement and a market where before there was just a bunch of neato stuff.&lt;/p&gt;

&lt;h3&gt;What Ajax is, what Ajax isn't&lt;/h3&gt;

&lt;p&gt;No attempt was made to define "Ajax" or identify the patterns inherent in an Ajax application. No one was gonna touch that with a twenty-foot pole.&lt;/p&gt;

&lt;p&gt;That said, I have my own thoughts on what Ajax is, and I think if we want to effectively communicate to people that Google Maps != Ajax (more on this below) it's important to recognize the larger components:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;Ajax the methodology - this is the concept, the approach: fetching small pieces of data from the server, without a whole page refresh.&lt;/li&gt;
 &lt;li&gt;Ajax the technology - the libraries and toolkits: JavaScript, Flash, XML, HTML, etc. whatever enables #1 above.&lt;/li&gt;
 &lt;li&gt;Ajax the implementation - it can be as boring (and useful!) as a "smart" HTML form that validates fields as you tab between them, or as sexy as Google Maps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Gotta keep 'em separated, because we gotta be prepared for the questions: what is Ajax? Is this something we should be doing? I think our energies are better spent on deciding whether the Ajax methodology is an appropriate approach to solving a particular problem.&lt;/p&gt;

&lt;p&gt;For it all to work, the methodology must be a win for the business person, the technology must be a win for the IT department, and the implementation must be a win for the user. If cost &gt; value in any of these, don't bother. "You're building a car around a bicycle." (&lt;a href="http://www.powazek.com"&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;Threats&lt;/h3&gt;

&lt;p&gt;Skip Intro - we need to avoid a repeat of the "Flash is 99% Bad" debacle that took years for Macromedia to shake. If there's no win in applying an Ajax approach, don't bother.&lt;/p&gt;
&lt;p&gt;XML Fairy Dust - for awhile in 2000, it seemed that XML was suddenly the answer to everything, a magical fairy dust that increased ROI and garnered more seat licenses. It wasn't. Neither is Ajax.&lt;/p&gt;
&lt;p&gt;Microsoft? Nah, I don't buy this. They gave us XmlHttpRequest and I doubt they care enough to break it.&lt;/p&gt;

&lt;h3&gt;Is Flash Ajax?&lt;/h3&gt;

&lt;p&gt;No. Is it capable of enabling an Ajax-style applications? Yes. Dunno what's so hard about this question.&lt;/p&gt;

&lt;h3&gt;Browser Beefs&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.flickr.com"&gt;Flickr's&lt;/a&gt; Eric Costello gave a presentation that was part satisfying rant at the remaining dissimilarities between the browsers, and vented some frustration at long-standing and long-annoying problems like the Back Button Issue, DOM manipulations that aren't cached, CSS-immune FORM elements, etc. It was a high point.&lt;/p&gt;

&lt;h3&gt;Etc.&lt;/h3&gt;

&lt;p&gt;Desktop apps are trying to be more like web apps, and web apps like desktop apps. Where do they meet? (Later: who cares?)&lt;/p&gt;

&lt;p&gt;Still need a killer app. Everyone points to Google Maps but it feels overblown. I think the real value will come from making boring stuff better, making static interfaces responsive. &lt;a href="http://www.dashes.com/anil"&gt;Anil&lt;/a&gt;: making web pages act the way users expect them to act, but who have been trained to expect less.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.powazek.com"&gt;Derek Powazek&lt;/a&gt;: full-page request/response is to email as Ajax is to instant messaging. Smaller chunks of data, in a simplified format, traveling faster.&lt;/p&gt;

&lt;p&gt;Saw lots of demos. Not gonna talk about 'em. Suffice to say there's some very cool stuff being built.&lt;/p&gt;

&lt;p&gt;Jason Kottke rolled out &lt;a href="http://www.kottke.org/05/05/ajax-weblogs"&gt;Ajax-powered blog archives&lt;/a&gt; on his website while the sessions were going on. Nice, but I think &lt;a href="http://www.1976design.com/blog/"&gt;Dunstan Orchard's live search&lt;/a&gt; is equally impressive (and Dunstan's attention to progressive enhancment is admirable).&lt;/p&gt;

&lt;p&gt;I'm pretty sure I was the only one (out of about 40 attendees) without a laptop. About 70% of laptops were Macs. At times I felt like I had forgot my duck. At other times, I was glad I didn't have the distraction of email, IM, etc.&lt;/p&gt;

&lt;p&gt;Probably more to report once I get some rest.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111579851417901469?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111579851417901469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111579851417901469' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111579851417901469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111579851417901469'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/ajaxed-out.html' title='Ajaxed out'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111524747721591031</id><published>2005-05-04T15:57:00.000-07:00</published><updated>2005-05-04T15:57:57.220-07:00</updated><title type='text'>Have we won yet?</title><content type='html'>&lt;p&gt;A blast from the past: &lt;a href="http://www.newarchitectmag.com/documents/s=7158/new1020217917753/"&gt;Why DHTML Will Win&lt;/a&gt;, by Steve Champeon in the now-defunct &lt;a href="http://www.newarchitectmag.com"&gt;New Architect&lt;/a&gt; magazine, June 2002. I especially like this bit here:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;DHTML, you say? Tried that, hated it. It didn't work the way you had expected in [insert your favorite browser here], right? Well, it's time to take a second look. What you may think of as DHTML has advanced greatly since the early days of Web design. Back then, Microsoft and Netscape were in a pitched battle over which Document Object Model (DOM) would rule the Web: document.all or document.layers. But that has all changed. In the end, reason and the W3C have prevailed. Even Netscape, the company that created the &lt;layer&gt; element, has abandoned it in favor of the standard &amp;lt;div&amp;gt;. Developers no longer have to code for two different APIs.&lt;/p&gt;

&lt;p&gt;So why the resistance to DHTML? Perhaps it's time for a new name.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It's been three years. Has DHTML won?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111524747721591031?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111524747721591031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111524747721591031' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111524747721591031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111524747721591031'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/have-we-won-yet.html' title='Have we won yet?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111515706354127226</id><published>2005-05-03T14:49:00.000-07:00</published><updated>2005-05-03T14:51:03.543-07:00</updated><title type='text'>Who needs XML?</title><content type='html'>&lt;p&gt;Been thinking about the "and XML" part of Ajax and wondering why we need XML at all.&lt;/p&gt;

&lt;p&gt;For example, 37 Signals recently rolled out its new &lt;a href="http://www.backpackit.com/"&gt;Backpack&lt;/a&gt; web-based PIM application, and I've read a few complaints about how it doesn't work in browsers like Opera and older versions of Safari, presumably (I haven't looked under Backpack's hood personally so I'm going on word of mouth here, careful!) its heavy reliance on XMLHttpRequest for client-server data transfer.&lt;/p&gt;

&lt;p&gt;(BTW, that's not meant to be a negative comment on Backpack on my part. Backpack looks VERY cool, and I intend to play with it extensively.)&lt;/p&gt;

&lt;p&gt;So here's my thought: what's wrong with just the "AJ" part of the Ajax equation? Seems to me that there are lots of sturdy JS libraries that can deliver and receive pseudo-asynchronous data to/from the server that don't require the overhead of an XML parser. It's relatively easy to &lt;a href="http://jszen.blogspot.com/2005/03/make-your-apache-http-errors-more-ajax.html"&gt;bootstrap a JavaScript message format&lt;/a&gt; at the server level, so why do we insist on pushing XML back the browser?&lt;/p&gt;

&lt;p&gt;The obvious reason is, I guess, compatibility with other apps that read XML, but that doesn't seem particularly compelling when 99% of the apps I've seen are built to be run in a JS capable-browser. Why wouldn't you optimize your data format to suit the target environment?&lt;/p&gt;

&lt;p&gt;As far as XMLHttpRequest is concerned, as one Opera user stated, "shouldn't it just work without it?"&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111515706354127226?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111515706354127226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111515706354127226' title='61 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111515706354127226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111515706354127226'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/05/who-needs-xml.html' title='Who needs XML?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>61</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111481826812701816</id><published>2005-04-29T16:43:00.000-07:00</published><updated>2005-05-02T09:28:13.680-07:00</updated><title type='text'>IE bold text + opacity problem</title><content type='html'>&lt;p&gt;You know how IE's alpha opacity filter ruins boldface text?&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&amp;lt;div style="width:100%;
     filter:alpha(opacity=90);
     font-weight:bold;"&amp;gt;
  Hello world!
&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;If you're using IE, you can see the problem in action here:&lt;/p&gt;

&lt;blockquote&gt;&lt;div style="font-size:1.2em;width:100%; filter:alpha(opacity=90); font-weight:bold;"&gt;
Hello world!
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;I discovered this while tweaking the &lt;a href="http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html"&gt;opacity filter function&lt;/a&gt; I wrote about earlier.&lt;/p&gt;

&lt;p&gt;After much fruitless Googling and consulting with webdev experts, I couldn't find a fix. And like most solutions, I had to stumble upon it at the eleventh hour: adding a background color or image to the container element will fix the IE opacity rendering problem.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&amp;lt;div style="width:100%;
     filter:alpha(opacity=90);
     font-weight:bold;
     &lt;b&gt;background-color:#fff&lt;/b&gt;"&amp;gt;
  Hello world!
&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Here it is again, with the fix:&lt;/p&gt;

&lt;blockquote&gt;&lt;div style="font-size:1.2em;width:100%; filter:alpha(opacity=90); font-weight:bold; background-color:#fff"&gt;
Hello world!
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;Hopefully the search engines will find this page and no one will have to suffer as I have ever again.&lt;/p&gt;

&lt;p&gt;UPDATE: SZOJ reader Andre points out that this bug probably surfaced when MS introduced ClearType rendering, which probably explains why the bug goes away when "font smoothing" is disabled.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111481826812701816?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111481826812701816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111481826812701816' title='68 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111481826812701816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111481826812701816'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/ie-bold-text-opacity-problem.html' title='IE bold text + opacity problem'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>68</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111421354701815533</id><published>2005-04-22T16:44:00.000-07:00</published><updated>2005-04-22T16:49:01.120-07:00</updated><title type='text'>Ugliest line trunc hack EVER</title><content type='html'>&lt;p&gt;Warning: this hack is dumb and should not be used by anyone.&lt;/p&gt;

&lt;p&gt;The challenge: given some text of abitrary length, figure out where to best truncate the text so that &lt;i&gt;only&lt;/i&gt; the first two lines are displayed, regardless of the width of the containing element.&lt;/p&gt;

&lt;p&gt;By the way, the element is inline, you have no control over its dimensions, and the spot where you truncate the text must end in an ellipsis (&amp;#8230;) Don't ask. Q: can't we just cut it at 20 characters and call it a day? A: no, it must fully fill the two lines, do as we say or we will be cranky.&lt;/p&gt;

&lt;p&gt;Given that the fonts used were not fixed-width, I threw out the idea of counting character widths. However, I knew that the &lt;i&gt;line-height&lt;/i&gt; CSS rule for this element was 14 pixels, and using &lt;a href="http://www.mozilla.org/docs/dom/domref/dom_el_ref18.html"&gt;offsetHeight&lt;/a&gt; I could determine if the height of the containing element, in this case a SPAN. (Word to the wise: offsetHeight is what you want. In the absence of a specific rule, the computed CSS height property for an element seems to be either blank, undefined or "auto", none of which are particularly helpful.)&lt;/p&gt;

&lt;p&gt;Armed with this knowledge, I set out to write the ugliest hack I could manage:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;var elm = document.getElementById("DivOne");
while (parseInt(elm.offsetHeight) &gt; 28){
    var txt = elm.innerHTML;
    txt = txt.substring(0, txt.length-2) + "&amp;amp;#8230;";
    elm.innerHTML = txt;
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;In a nutshell: take the text, shave off the last character, append an ellipsis HTML entity, then shove the text back into the element and measure the height. Repeat until the SPAN is finally 28px high (twice the line height == two visible lines).&lt;/p&gt;

&lt;p&gt;Ugh. I'm lucky that the strings I was working with were no more than 30 characters long, and only 3-5 strings had to be dealt with in any given page. Excuse me while I go take a shower.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111421354701815533?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111421354701815533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111421354701815533' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111421354701815533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111421354701815533'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/ugliest-line-trunc-hack-ever.html' title='Ugliest line trunc hack EVER'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111410890882024000</id><published>2005-04-21T11:40:00.000-07:00</published><updated>2005-04-21T11:41:48.820-07:00</updated><title type='text'>DOM 0 with XHTML caveat</title><content type='html'>&lt;p&gt;Here's an interesting gotcha, unearthed from Bobby van der Sluis' &lt;a href="http://www.bobbyvandersluis.com/articles/goodpractices.php"&gt;popular article&lt;/a&gt; on JavaScript good practices that's making the rounds: when you serve an XHTML document as application/xhtml+xml, the good old DOM Level 0 collections like document.images and document.forms go bye-bye, at least in Mozilla-based browsers.&lt;/p&gt;

&lt;p&gt;I'm okay with this, but I love me some backwards-compatible DOM 0, especially when I know exactly which element I need to access via script. Luckily, it's perfectly okay to serve XHTML 1.0 as "HTML compatible" text/html. It's when you start serving XHTML 1.1 as text/html that people start yelling and pointing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=111514"&gt;Here's the Bugzilla discussion&lt;/a&gt; of this behavior.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111410890882024000?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111410890882024000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111410890882024000' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111410890882024000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111410890882024000'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/dom-0-with-xhtml-caveat.html' title='DOM 0 with XHTML caveat'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111385532416000379</id><published>2005-04-18T13:13:00.000-07:00</published><updated>2005-04-18T13:23:35.450-07:00</updated><title type='text'>Odd and ends 4/18/2005</title><content type='html'>&lt;p&gt;If you sent me a message in the past month, my apologies: I forgot to turn on Gmail forwarding and just discovered a backlog of SZOJ email. I'll catch up in a few.&lt;/p&gt;

&lt;p&gt;Speaking of Gmail, here's some reverse JS Zen: &lt;a href="http://gmail.google.com/support/bin/answer.py?answer=15046"&gt;Gmail now works in nearly all browsers&lt;/a&gt;, including some legacy ones. Gmail falls back on a basic HTML version if it detects that the browser can't support the more advanced features. So while you might not have all the real-time widgetry, you'll never be locked out of your account when you're stuck with Netscape 4.&lt;/p&gt;

&lt;p&gt;I've heard lots of comments from developers in years past about how users have to expect a greatly degraded experience if they're not willing or able to upgrade at the client end. Unfortunately, "degraded" often means "not even minimally supported." The Gmail developers weren't willing to settle for that, and neither should the rest of us. Design your web app for the web &lt;i&gt;first&lt;/i&gt;. (Now, if only we can get more Flash developers to buy in to this.)&lt;/p&gt;

&lt;p&gt;On a different tangent: earlier this week I wrote a post about what I thought about the whole "controversy" over the use of "Ajax" as a suitable term to describe DOM + JS + behind-the-scenes HTTP. I ended up scrapping it because I want this weblog to focus on practical stuff. &lt;a href="http://a.wholelottanothing.org/2005/04/note_to_geeks_l.html"&gt;Leave it to Matt&lt;/a&gt; to sum up my thoughts, nearly to the letter. So I'm going allow myself a (hopefully infrequent) opinionated post: &lt;i&gt;hello&lt;/i&gt;, our technology just became interesting again to the world at large, and y'all want to complain about &lt;i&gt;buzzwords?&lt;/i&gt; Who the heck cares what they end up calling it?&lt;/p&gt;

&lt;p&gt;I hereby call a moratorium on the snarkiness, name-calling and faux outrage over something we failed to do ourselves: make DHTML popular.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111385532416000379?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111385532416000379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111385532416000379' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111385532416000379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111385532416000379'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/odd-and-ends-4182005.html' title='Odd and ends 4/18/2005'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111359466650676283</id><published>2005-04-15T12:49:00.000-07:00</published><updated>2005-04-15T12:54:07.870-07:00</updated><title type='text'>Shorter JS Iron Chef!</title><content type='html'>&lt;p&gt;The challenge: write a JS function that takes a given hex color and returns a suitably-contrasted greyscale shade, in as few lines of JS as possible.&lt;/p&gt;

&lt;p&gt;My first pass went like this:&lt;/p&gt;


&lt;blockquote&gt;&lt;pre&gt;function contrast(c) {
    var av = (parseInt(c.substring(1,3),16) +
              parseInt(c.substring(3,5),16) +
              parseInt(c.substring(5,7),16)) / 3;
    av = (av &gt;= 100)? av-100:av+100;
    return "rgb(" + av +"," + av + "," + av + ")";
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;A quick overview of what's happening here. c is the 6-character hex color (sans the "#"). The first JS statement uses the &lt;code&gt;substring&lt;/code&gt; function to break the hex color string into its three 2-character hex pairs, which are then passed to &lt;code&gt;parseInt&lt;/code&gt; to convert them to decimal values. Then we find the average by adding them and dividing by 3.&lt;/p&gt;

&lt;p&gt;So, FF0000 (pure red) becomes FF+00+00 becomes 255+0+0 becomes 255/3 becomes 85.&lt;/p&gt;

&lt;p&gt;The function then looks at this average and, using 100 as its "bias" point, either adds or subtracts 100 (an arbitrary value that produced the best results for our needs). The last line returns a greyscale RGB value (&lt;a href="http://www.w3.org/TR/REC-CSS2/syndata.html#color-units"&gt;perfectly valid in CSS!&lt;/a&gt; No need to convert back to hex!).&lt;/p&gt;

&lt;p&gt;Now the fun: I sent this off to another webdev for review and challenged him to make it even shorter. He came back with this:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;function f(c,n) {return parseInt(c.substring(n,n+2),16);}

function contrast(c) {
    var av=(f(c,1)+f(c,2)+f(c,3))/3;
    av+=100*(av&gt;=100)?-1:1;
    return "rgb("+av+","+av+","+av+")";
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Nice, but I pointed out that &lt;code&gt;av&lt;/code&gt; wasn't being calculated correctly without an additional set of parenthesis. Plus, we could shave off a few characters by replacing &lt;code&gt;substring&lt;/code&gt; with the shorter &lt;code&gt;substr&lt;/code&gt; to the same effect. I countered with this:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;function f(c,n) {return parseInt(c.substr(n,2),16);}

function x(c) {
    var av=(f(c,1)+f(c,3)+f(c,5))/3;
    av+=(av&gt;=100)?-100:100;
    return "rgb("+av+","+av+","+av+")";
}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Of course, I hadn't thought to remove the whitespace yet :) His riposte:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;function f(c,n){return parseInt(c.substr(n,2),16);}
function x(c){var a=(f(c,1)+f(c,3)+f(c,5))/3;c=100;
  a+=(a&gt;c)?-c:c;c=",";return "rgb("+a+c+a+c+a+")";}&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Bested but not broken by his ingenious re-use of local variables, I nonetheless proclaimed victory by deleting the requirement for such a JS function from the spec, reducing the necessary code to:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;

&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Don't ever let it be said I don't think outside the box!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111359466650676283?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111359466650676283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111359466650676283' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111359466650676283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111359466650676283'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/shorter-js-iron-chef.html' title='Shorter JS Iron Chef!'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111331894547055132</id><published>2005-04-12T08:06:00.000-07:00</published><updated>2005-04-12T08:15:45.470-07:00</updated><title type='text'>Memory leaks explained</title><content type='html'>&lt;p&gt;If you're new to building complex web apps that use tons of JavaScript-powered DOM manipulation, you are hereby &lt;i&gt;required&lt;/i&gt; to read Joel Webber's excellent article &lt;a href="http://jgwebber.blogspot.com/2005/01/dhtml-leaks-like-sieve.html"&gt;DHTML Leaks Like A Sieve&lt;/a&gt;, which eloquently summarizes the challenge of memory leakage in JS-heavy applications.&lt;/p&gt;

&lt;p&gt;You may in fact wish to &lt;a href="http://jgwebber.blogspot.com/"&gt;bookmark Joel's weblog&lt;/a&gt; and follow along as he unearths neato facts about Google Maps and other modern web apps.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111331894547055132?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111331894547055132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111331894547055132' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111331894547055132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111331894547055132'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/memory-leaks-explained.html' title='Memory leaks explained'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111298753607736393</id><published>2005-04-08T12:11:00.000-07:00</published><updated>2005-04-29T16:58:10.863-07:00</updated><title type='text'>IE6 opacity filter caveat</title><content type='html'>&lt;p&gt;This one was a real pain. I was lucky to guess the solution.&lt;/p&gt;

&lt;p&gt;I was working on a very small function to set alpha transparency on elements. This is what I came up with:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;

var ie = (document.all) ? 1 : 0;
var p = (ie) ? "filter" : "MozOpacity";

/* n is the element node
   v is the opacity value, from 0 to 100. */

function op(n,v){
    v = (ie) ? "alpha(opacity="+v+")" : v/100;
    n.style[p] = v;
}
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Yes, I know I left Opera and Safari/KHTML out of the equation.)&lt;/p&gt;

&lt;p&gt;This function worked great in Firefox but nothing was happening in IE6. I tried a bunch of different tweaks, none of which worked. Adding an &lt;code&gt;alert(n.style.filter);&lt;/code&gt; at the tail end of the function returned "alpha(opacity=50)" indicating that the value was being set correctly for IE6. But the element still rendered at 100% opacity.&lt;/p&gt;

&lt;p&gt;Finally, I threw the function out altogether and applied the filter directly to the DIV element via CSS:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;div id="myDiv" &lt;b&gt;style="filter:alpha(opacity=50);"&lt;/b&gt;&amp;gt;
&amp;lt;img src="MyImage.gif" alt="Some Image Here" 
  width="50" height="50" /&amp;gt;
&amp;lt;br /&amp;gt;
This should be transparent.
&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;But it &lt;em&gt;still&lt;/em&gt; didn't work! IE6 stubbornly ignored the opacity rule. Even more confusing was that moving the opacity rule to the image alone &lt;em&gt;did work&lt;/em&gt;. But only on the &lt;em&gt;image&lt;/em&gt;, of course.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;div id="myDiv"&amp;gt;
&amp;lt;img &lt;b&gt;style="filter:alpha(opacity=50);"&lt;/b&gt; src="MyImage.gif" 
  alt="Some Image Here" width="50" height="50" /&amp;gt;
&amp;lt;br /&amp;gt;
This should be transparent.
&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;I really needed the opacity applied to both the text and image. I was about to give up when it occurred to me that maybe the image width and height dimensions has something to do with it. By default, a block element takes on the width of its containing element and height of its content, but maybe IE6 was ignoring this when applying the alpha filter. So I tried this:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;div id="myDiv" 
  &lt;b&gt;style="filter:alpha(opacity=50);
     width:100%; height:100%;&lt;/b&gt;"&amp;gt;
&amp;lt;img src="MyImage.gif" alt="Some Image Here" 
  width="50" height="50" /&amp;gt;
&amp;lt;br /&amp;gt;
This should be transparent.
&amp;lt;/div&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Yes! Opacity was now being applied to both the image &lt;em&gt;and&lt;/em&gt; the text. I removed opacity rule from the DIV and was then able to correctly set opacity via the JavaScript function.&lt;/p&gt;

&lt;p&gt;I don't have the luxury of testing this across the different flavors of IE, but it appears that &lt;b&gt;alpha opacity in IE6 requires certain elements to have a specified width and height&lt;/b&gt;. What's funny is that when I tried Googling for answers to my problem, I found a ton of working examples that used opacity in IE6 successfully. Looking back now, &lt;em&gt;all&lt;/em&gt; of those examples specified a CSS width and height on the element, but didn't make any specific mention of it as a requirement for IE. Removing the width and height caused those examples to fail, too.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;UPDATE:&lt;/b&gt; &lt;a href="http://dean.edwards.name"&gt;Dean Edwards&lt;/a&gt; points us to the &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp"&gt;MSDN documentation&lt;/a&gt; for this little-known behavior. IE filters only apply to elements with "layout."&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111298753607736393?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111298753607736393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111298753607736393' title='34 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111298753607736393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111298753607736393'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/ie6-opacity-filter-caveat.html' title='IE6 opacity filter caveat'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111281044797894609</id><published>2005-04-06T10:50:00.000-07:00</published><updated>2005-04-06T11:01:11.153-07:00</updated><title type='text'>Variable scoping gotchas</title><content type='html'>&lt;p&gt;&lt;a href="http://www.philringnalda.com"&gt;Phil&lt;/a&gt; points to this great bit by Scott Issacs about &lt;a href="http://spaces.msn.com/members/siteexperts/Blog/cns!1pNcL8JwTfkkjv4gg6LkVCpw!418.entry"&gt;JavaScript variable scoping&lt;/a&gt;. I've seen hardcore programmers as well as JS newbies make the same simple mistake:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
function Foo() {
  bar = 1;
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;You might assume &lt;code&gt;bar&lt;/code&gt; is private to &lt;code&gt;Foo&lt;/code&gt;, but you'd be mistaken. Variables declared without the &lt;code&gt;var&lt;/code&gt; operator are global by default. The correct syntax is:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
function Foo() {
  var bar = 1;
}
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Check out &lt;a href="http://spaces.msn.com/members/siteexperts/Blog"&gt;Scott's weblog&lt;/a&gt; for more scripty goodness.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111281044797894609?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111281044797894609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111281044797894609' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111281044797894609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111281044797894609'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/04/variable-scoping-gotchas.html' title='Variable scoping gotchas'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111214805087764707</id><published>2005-03-29T20:40:00.000-08:00</published><updated>2005-04-04T08:16:40.273-07:00</updated><title type='text'>Make your Apache HTTP errors more Ajax-friendly</title><content type='html'>&lt;p&gt;Applications that use &lt;a href="http://www.ashleyit.com/rs/main.htm"&gt;remote scripting&lt;/a&gt; or &lt;a href="http://www.adaptivepath.com/publications/essays/archives/000385.php"&gt;Ajax-style&lt;/a&gt; communications can have problems when things go wrong at the server end. How does one detect a 404 or 500 error inside your hidden IFRAME, and how can an application be designed to handle such an error?&lt;/p&gt;

&lt;p&gt;A client-side developer would probably suggest walking the DOM tree out to the IFRAME document and looking for the status text. But why not make it easier by having the server hand back HTTP errors to your application &lt;i&gt;as JavaScript&lt;/i&gt;? This can be done with relative ease with Apache (I'm sure other servers can be configured similarly) with three basic steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a custom error page&lt;/li&gt;
&lt;li&gt;Include JavaScript in the error page that interacts with the application (via the containing frame or IFRAME)&lt;/li&gt;
&lt;li&gt;Use Apache's ErrorDocument directive to tell the server to deliver the custom error page when an error occurs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Below is a sample error page written in PHP.  Apache provides the basic variables needed to determine the status; here, we just pluck them from PHP's global variables and plug them into a JavaScript block. Once loaded, the JavaScript looks for an &lt;code&gt;onServerError&lt;/code&gt; handler in the parent window (assuming the page request is made from a frame or IFRAME) and invokes it with the HTTP status information.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;?
  /* error.php */
  /* this line ensures the client gets the HTTP status */
  header("Status:" . $REDIRECT_STATUS);
?&amp;gt;
&amp;lt;!-- include DOCTYPE of choice here --&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Error &amp;lt;? print $REDIRECT_STATUS; ?&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;script&amp;gt;
    var win = (window.parent) ? window.parent : window;
    if (win.onServerError) {
      win.onServerError(
        {
          status:'&amp;lt;? print $REDIRECT_STATUS; ?&amp;gt;',
          url:   '&amp;lt;? print $REDIRECT_URL; ?&amp;gt;',
        }
      );
    }
  &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;Error &amp;lt;? print $REDIRECT_STATUS; ?&amp;gt;&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;
     This page should have invoked a 
     JavaScript onServerError handler 
     if one was provided.
  &amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;We'll save this file as &lt;code&gt;error.php&lt;/code&gt; and place it in a directory named &lt;code&gt;/rs-errors/&lt;/code&gt;. Next, we have to tell Apache to use our error page for selected HTTP error statuses. We can do this by adding &lt;code&gt;ErrorDocument&lt;/code&gt; directives to an .htaccess file placed inside the directory at which our remote scripting requests are targeted. For example, if you're sending requests to &lt;code&gt;http://appserver.example.com/api&lt;/code&gt; you'll want to put these in the .htaccess file for that directory:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;ErrorDocument 404 /rs-errors/error.php
ErrorDocument 500 /rs-errors/error.php&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Now, if a 404 or 500 error occurs inside of &lt;code&gt;/api&lt;/code&gt; Apache will use our &lt;code&gt;error.php&lt;/code&gt; as the error document served to the browser.&lt;/p&gt;

&lt;p&gt;It should be relatively simple to implement this in a JavaScript application now:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;script&amp;gt;
  function onServerError(e) {
    switch (e.status) {
      case '500':
        // handle a 500 error here
        break;
      case '404':
        // handle a 404 error here
        break;
    }
  }
&amp;lt;/script&amp;gt;

...

&amp;lt;iframe src="http://appserver.example.com/api/some-bogus-request-here"&amp;gt;
&amp;lt;/iframe&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;When the IFRAME attempts to load the bogus URI, Apache will throw a 404 error and invoke &lt;code&gt;error.php&lt;/code&gt;. The JavaScript in the head of our error page will attempt the &lt;code&gt;onServerError&lt;/code&gt; handler defined in the application. The application can now decide how to best communicate the error state to the user without appearing broken.&lt;/p&gt;

&lt;p&gt;Caveat: don't forget that IE will attempt to serve up its own custom 500 page from the local machine, so it might be a good idea to pad your error page with &lt;del&gt;512K&lt;/del&gt; 512 bytes (or more) of whitespace or commented text to convince IE that your error is the one to show.&lt;/p&gt;

&lt;p&gt;If you prefer an "Ajax (The X Is For 'XML' Dammit!)" approach, you can easily write your custom error page to deliver HTTP statuses as an XML payload instead of JavaScript. I prefer JavaScript myself since I don't have to parse it, but XML might be preferred if you're sharing data across different apps on different platforms.&lt;/p&gt;

&lt;h2&gt;Reference:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://httpd.apache.org/docs/custom-error.html"&gt;Custom errors in Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;Q294807"&gt;Turning off IE's "friendly" HTTP error messages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111214805087764707?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111214805087764707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111214805087764707' title='51 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111214805087764707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111214805087764707'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/make-your-apache-http-errors-more-ajax.html' title='Make your Apache HTTP errors more Ajax-friendly'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>51</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111202864950444095</id><published>2005-03-28T08:49:00.000-08:00</published><updated>2005-03-28T09:38:42.260-08:00</updated><title type='text'>Dynamic old-school IFRAMEs</title><content type='html'>&lt;p&gt;Three years ago I lifted the following code for dynamically creating an IFRAME from Eric Costello's ADC article, &lt;a href="http://developer.apple.com/internet/webcontent/iframe.html"&gt;Remote Scripting With IFRAME&lt;/a&gt;, and I've used some variation of it for years in my own development work. I modified it a bit since its original purpose was as part of a remote scripting engine; all I wanted was the IFRAME-generation code. Check out the crazy bit where Eric "fakes up" the IFRAME for IE5.&lt;/p&gt;

&lt;p&gt;It's a wicked piece of code for the time it was written. It's one of those techniques that you can only learn about after several hours of &lt;em&gt;doing&lt;/em&gt; &amp;mdash; that is, messing around in a browser trying to get stuff to work. There's just no textbook for this kind of stuff.&lt;/p&gt;

&lt;p&gt;Dunno if it works in Safari, Konqueror or Opera, although I'd love to hear if it does or doesn't.&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;

/*
dynamic IFRAME code
original JS by Eric Costello (glish.com) for ADC
http://developer.apple.com/internet/webcontent/iframe.html
*/

var iframe, iframeDocument;
var iframeID = "MyHiddenIFrame";

if (document.createElement) {   
  try {
   
    var tempIFrame = document.createElement('iframe');
    tempIFrame.setAttribute('id',iframeID);
    tempIFrame.style.border = '0px';
    tempIFrame.style.width = '0px';
    tempIFrame.style.height = '0px';
    iframe = document.body.appendChild(tempIFrame);
      
    if (document.frames) {
      
      /* IE5 Mac only allows access to the document
      of the IFrame through frames collection */
        
      iframe = document.frames[iframeID];
    }
      
  } catch (ex) {
    
    /* This part is CRAZY! -- scottandrew */

    /* IE5 PC does not allow dynamic creation and 
    manipulation of an iframe object. Instead, we'll fake
    it up by creating our own objects. */
      
    var iframeHTML = '\&amp;lt;iframe id="' + iframeID + '"';
    iframeHTML += ' style="border:0px; width:0px; height:0px;';
    iframeHTML += '"&gt;&amp;lt;\/iframe&amp;gt;';
    document.body.innerHTML += iframeHTML;
    iframe = new Object();
    iframe.document = new Object();
    iframe.document.location = new Object();
    iframe.document.location.iframe = 
      document.getElementById(iframeID);
    iframe.document.location.replace = 
      function(location) {
        this.iframe.src = location;
      }
  }
  
  if (iframe.contentDocument) { // For NS6
    iframeDocument = iframe.contentDocument; 
  } else if (iframe.contentWindow) { // For IE5.5 and IE6
    iframeDocument = iframe.contentWindow.document;
  } else if (iframe.document) { // For IE5
    iframeDocument = iframe.document;
  } else { // damn!
    alert("Error: could not find IFRAME document");
  }
}
&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111202864950444095?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111202864950444095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111202864950444095' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111202864950444095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111202864950444095'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/dynamic-old-school-iframes.html' title='Dynamic old-school IFRAMEs'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111187526087784576</id><published>2005-03-26T14:13:00.000-08:00</published><updated>2005-03-26T14:14:20.876-08:00</updated><title type='text'>Cool rounded corners with CSS and Javascript</title><content type='html'>&lt;p&gt;Rounded corners in web design are neat, but usually require a handful of semantically meaningless positioned elements to achieve. Alessandro Fulciniti simply &lt;a href="http://pro.html.it/esempio/nifty/"&gt;inserts those elements with some unobtrusive JavaScript&lt;/a&gt;. Check out the JS code and take a look at his custom get&lt;code&gt;ElementsBySelector()&lt;/code&gt; function, too.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111187526087784576?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111187526087784576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111187526087784576' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111187526087784576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111187526087784576'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/cool-rounded-corners-with-css-and.html' title='Cool rounded corners with CSS and Javascript'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111153625560832546</id><published>2005-03-22T16:03:00.000-08:00</published><updated>2005-03-22T16:06:46.773-08:00</updated><title type='text'>A global event...in Firefox?</title><content type='html'>&lt;p&gt;This is kind of nice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
function someHandler(a,x,y){
    alert(a.type);
}

&amp;lt;a href="#"
   onclick="someHandler(event,'x','y'); return false;"&gt;
   Do it&amp;lt;/a&amp;gt;
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Apparently, Firefox does support a global event object when passed as a parameter to an event handler, so the above code works in both Firefox and IE on Windows. You can't call &lt;code&gt;window.event&lt;/code&gt; inside the function though, else Firefox will complain.&lt;/p&gt;

&lt;p&gt;I've been doing the check for &lt;code&gt;e&lt;/code&gt; for so long (see the previous post), like, waaaaay back in my DynAPI v1.0 days, that I hadn't noticed this technique was available.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111153625560832546?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111153625560832546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111153625560832546' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111153625560832546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111153625560832546'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/global-eventin-firefox.html' title='A global event...in Firefox?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111122261284972443</id><published>2005-03-21T00:54:00.000-08:00</published><updated>2005-03-21T12:51:27.003-08:00</updated><title type='text'>Really basic event confusion</title><content type='html'>&lt;p&gt;This is another no-brainer, but I still see this all the time:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
function someEventHandler(e) {
    alert(e.type);
}
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Works in Firefox and other Moz browsers. IE pops an error. Why? Because in IE browsers, the event (e) object is a property of the window, not a local argument passed to the handler. So e is undefined, in IE's view. To get around this, try:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
function someEventHandler(e) {
    if (!e) e = window.event;
    alert(e.type);
}
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The amusing thing about having to post this is I hear this question a lot from developers who are used to coding &lt;span style="font-style:italic;"&gt;only for Firefox.&lt;/span&gt; How times change, eh?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111122261284972443?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111122261284972443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111122261284972443' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111122261284972443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111122261284972443'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/really-basic-event-confusion.html' title='Really basic event confusion'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111120258891584998</id><published>2005-03-18T19:20:00.000-08:00</published><updated>2005-03-18T19:23:29.366-08:00</updated><title type='text'>Cross-domain security woes</title><content type='html'>&lt;p&gt;You're developing an &lt;a href="http://www.adaptivepath.com/publications/essays/archives/000385.php"&gt;Ajax-based application&lt;/a&gt;. You have an application server at example.com which serves up all your JavaScript, HTML and CSS, and a data server at xml.example.com which delivers all the XML data to the application via a hidden IFRAME.&lt;/p&gt;

&lt;p&gt;You know that &lt;a href="http://msdn.microsoft.com/workshop/author/om/xframe_scripting_security.asp"&gt;cross-domain security&lt;/a&gt; will prevent any JavaScript from accessing the data in the IFRAME. so, you configure the data server to set the security domain of the IFRAME to "example.com" &amp;mdash; the common suffix between the two domains &amp;mdash; with a small piece of JavaScript:&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;&amp;lt;script type="text/javascript"&gt;
  document.domain="example.com";
&amp;lt;/script&amp;gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having done this, you test your application and get a "permission denied" error. What happened?&lt;/p&gt;

&lt;p&gt;Depending on your browser, it may not be enough to only set the security domain of the IFRAME. You must set &lt;i&gt;all&lt;/i&gt; of the frames and windows to the same domain, too. This is true even if the domain name you're trying to set &lt;i&gt;already matches&lt;/i&gt; the domain of the server that's currently serving the page. For example, if you have two frames with pages served from example.com and you use JavaScript to set the security domain of one frame to "example.com" the frames will be unable to communicate.&lt;/p&gt;

&lt;p&gt;Older browsers might let you get away with this.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111120258891584998?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111120258891584998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111120258891584998' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111120258891584998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111120258891584998'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/cross-domain-security-woes.html' title='Cross-domain security woes'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111119730130339689</id><published>2005-03-18T17:54:00.000-08:00</published><updated>2005-03-18T20:37:29.716-08:00</updated><title type='text'>About this site</title><content type='html'>&lt;p&gt;The &lt;a href="http://jszen.blogspot.com/"&gt;Strange Zen Of JavaScript&lt;/a&gt; is an offshoot of and successor to &lt;a href="http://www.scottandrew.com/delimiter"&gt;Delimiter&lt;/a&gt;, a weblog about web application design focused on JavaScript, CSS, Flash and other client-side technologies. Unlike Delimiter, this weblog will try to keep the focus on JavaScript quirks, caveats odd hacks, curiosities and collected wisdom, and only delve into topics like CSS where they intersect. I'm also going to try and refrain from commenting on every cool JS-based app released unless there's a useful technique or exploit to be learned from reverse-engineering.&lt;/p&gt;

&lt;p&gt;I got the idea for SZOJ while perusing the Delimiter archives and rediscovering a series of numbered posts dealing with strange little JS gotchas I'd uncovered. I decided to consolidate these posts in a new weblog, and I'll probably end up plundering some old content from my formerly-all-scripting site &lt;a href="http://www.scottandrew.com"&gt;scottandrew.com&lt;/a&gt; and seeing how it's held up.&lt;/p&gt;

&lt;p&gt;Some of these posts might contain stuff that advanced developers will find forehead-slappingly obvious, but everyone starts somewhere. My hope is that web app developers who run into trouble might Google this site and find an answer, or at least something interesting.&lt;/p&gt;

&lt;p&gt;Feel free to send me any JS weirdness you discover, and I'll be happy to post it. Be sure to include a name and a URL so I can credit you. &lt;a href="mailto:delimiter@gmail.com"&gt;Here's the address&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111119730130339689?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111119730130339689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111119730130339689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119730130339689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119730130339689'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/about-this-site.html' title='About this site'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111119488521123063</id><published>2005-03-18T17:05:00.000-08:00</published><updated>2005-03-18T17:17:18.086-08:00</updated><title type='text'>XMLHTTP and readyState</title><content type='html'>&lt;p&gt;Given how the world of web design is currently enamored with &lt;a href="http://www.adaptivepath.com/publications/essays/archives/000385.php"&gt;Ajax&lt;/a&gt; &amp;mdash; a.k.a. Asynchronous JavaScript + XML, a.k.a. &lt;a href="http://www.ashleyit.com/rs/main.htm"&gt;remote scripting&lt;/a&gt; with XML messages, a.k.a. a technology that back in 2000 was considered way too rawk star and subversive until Google started playing with it recently &amp;mdash; I thought I'd unearth this oldie-but-goodie from 2002. Enjoy.&lt;/p&gt;

&lt;div style="background-color:#eee; padding:8px;"&gt;

&lt;p&gt;Microsoft's &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk30/htm/xmobjxmlhttprequest.asp"&gt;XMLHTTP object&lt;/a&gt; is an ActiveX component that lets you perform HTTP requests. The object has 
four different states that it cycles through when performing a request. One of those states is called "interactive" and is decribed as such (from the MSDN documentation):&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;
(3) INTERACTIVE&lt;br&gt;
Some data has been received. You can call responseBody
and responseText to get the current partial results.
&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;...meaning that at that point you should be able to examine the contents of the response so far. Let's try this, shall we?&lt;/p&gt;


&lt;blockquote&gt;&lt;pre&gt;
var xmlHTTP = new ActiveXObject("Microsoft.XMLHTTP");
xmlHTTP.onreadystatechange = handleStateChange;

function handleStateChange()
{        
    if (xmlHTTP.readyState == 3)
    {
        alert(xmlHTTP.responseText);
    }
}

xmlHTTP.open("POST","/some/uri",true);
xmlHTTP.send();
&lt;/pre&gt;&lt;/blockquote&gt;


&lt;p&gt;Execution of this code produces an error in the handler:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;
The data necessary to complete this operation is not yet available.
&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;...which troubles me greatly. Waiting until readyState is 4 (complete) works perfectly, but there's an added complication: the URI &lt;code&gt;/some/uri&lt;/code&gt; establishes a persistent connection, which means that unless the connection is terminated by the script or the server, readyState will &lt;em&gt;always&lt;/em&gt; be 3 (interactive). According to the docs, I should be able grab the incomplete response from the server at this time, but apparently not. Possible reasons:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;the MSDN documentation is &lt;span style="text-decoration:line-through"&gt;a big fat lie&lt;/span&gt; incorrect&lt;/li&gt;

 &lt;li&gt;the XMLHTTP object has a huge buffer to fill before it will make the response available&lt;/li&gt;
 &lt;li&gt;the object needs to see some sort of delimiter, like a null byte, as a signal to make the response text available&lt;/li&gt;
 &lt;li&gt;I'm horribly misunderstanding the whole thing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;UPDATE 3/4/2004&lt;/b&gt;: many. many people have written me to ask if I have found a workaround since I first posted this. I'm sorry to say that I have not.&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111119488521123063?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111119488521123063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111119488521123063' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119488521123063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119488521123063'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/xmlhttp-and-readystate.html' title='XMLHTTP and readyState'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111119385149189496</id><published>2005-03-18T16:47:00.000-08:00</published><updated>2005-03-18T16:57:31.573-08:00</updated><title type='text'>Inline script documentation with comment hacking</title><content type='html'>&lt;p&gt;I'm still in love with Tantek's extremely clever way to &lt;a href="http://www.tantek.com/log/2002/11.html#L20021121t1730"&gt;include HTML documentation for JavaScript code&lt;/a&gt; inside the same document using comment hacks.&lt;/p&gt;

&lt;p&gt;The particular (and peculiar) sequence of SGML comments &amp;lt!-- --&amp;gt; and C-style comments &lt;code&gt;/* */&lt;/code&gt; allow the document to be parsed as either HTML or JavaScript depending on the way it's imported into the document. Load the script with a &lt;code&gt;SCRIPT&lt;/code&gt; element and it's interpreted as JavaScript, but load the script directly into the browser and it's displayed as glorious, technicolor HTML. One caveat: you must leave off the .js file extension so that IE will interpret the file as text/html when you drop it into a browser.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111119385149189496?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111119385149189496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111119385149189496' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119385149189496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111119385149189496'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2005/03/inline-script-documentation-with.html' title='Inline script documentation with comment hacking'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109822283089221</id><published>2004-07-22T14:23:00.000-07:00</published><updated>2005-03-18T19:34:52.443-08:00</updated><title type='text'>Table rows...revealed!</title><content type='html'>&lt;p&gt; By setting the CSS rule &lt;code&gt;display:none&lt;/code&gt; on a TR element, you can collapse and hide whole rows of table data from the user. This is a popular technique for managing the visual display of tabular data in a web application.&lt;/p&gt;

&lt;p&gt;However, there's a small challenge that arises when we attempt to make the TR visible. The intuitive thing to try is to set the CSS &lt;code&gt;display&lt;/code&gt; property to &lt;code&gt;block&lt;/code&gt;. IE is perfectly happy with this, but Firefox 0.8 mangles the final rendering, as this screenshot shows:&lt;/p&gt;

&lt;img alt="table-row-display.png" src="http://www.scottandrew.com/delimiter/img/table-row-display.png" width="252" height="96" border="0" /&gt;

&lt;p&gt;The proper CSS rule &lt;em&gt;should&lt;/em&gt; be &lt;code&gt;display:table-row&lt;/code&gt;. Firefox like this a lot better and expands the TR without the mangling. But IE for Windows will throw an error, because &amp;mdash; unlike its MacIE cousin &amp;mdash; it doesn't support &lt;code&gt;table-row&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What to do? Aside from waiting for IE to support &lt;code&gt;table-row&lt;/code&gt; or for Firefox to support &lt;code&gt;block&lt;/code&gt; in place of it, the simple solution is to set the CSS display property to an empty string. Both Firefox and IE should fall back on their respective default values.&lt;/p&gt;

&lt;p&gt;Try this example:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;script type="text/javascript"&amp;gt;
function applyDisplay(value)
{
 document.getElementById("foo").style.display = value;
}
&amp;lt;/script&amp;gt;

&amp;lt;table border="1"&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;R1 C1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R1 C2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R1 C3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;R2 C1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R2 C2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R2 C3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;tr id="foo"&amp;gt;&amp;lt;td&amp;gt;R3 C1&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R3 C2&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;R3 C3&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;p&amp;gt;
&amp;lt;a href="#" 
   onclick="applyDisplay('none'); return false;"&amp;gt;
   Apply "display:none" to Row 3
&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;a href="#" 
   onclick="applyDisplay('block'); return false;"&amp;gt;
   Apply "display:block" to Row 3
&amp;lt;/a&amp;gt; (error in IE)&amp;lt;br&amp;gt;
&amp;lt;a href="#" 
   onclick="applyDisplay('table-row'); return false;"&amp;gt;
   Apply "display:table-row" to Row 3
&amp;lt;/a&amp;gt; (mangled display in Firefox)&amp;lt;br&amp;gt;
&amp;lt;a href="#" 
   onclick="applyDisplay(''); return false;"&amp;gt;
   Apply "display:" to Row 3
&amp;lt;/a&amp;gt; (should work in both)
&amp;lt;/p&amp;gt;
&lt;/pre&gt;
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109822283089221?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111109822283089221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111109822283089221' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109822283089221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109822283089221'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/table-rowsrevealed.html' title='Table rows...revealed!'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109814785929965</id><published>2004-07-21T14:21:00.000-07:00</published><updated>2005-03-17T14:22:27.876-08:00</updated><title type='text'>What's in a NAME?</title><content type='html'>&lt;p&gt;The little-used &lt;code&gt;getElementsByName()&lt;/code&gt; method is part of the DOM Level 1 specification and is supported by both Internet Explorer and Mozilla/Firefox. &lt;code&gt;getElementsByName()&lt;/code&gt; is part of the &lt;a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-26809268"&gt;HTML application of the DOM&lt;/a&gt;, meaning it is specific to HTML documents, and explains why you won't find it in the &lt;a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-core.html"&gt;DOM Core spec&lt;/a&gt;, which applies to &lt;em&gt;any&lt;/em&gt; XML-like document.&lt;/p&gt;

&lt;p&gt;Given a string as an argument, &lt;code&gt;getElementsByName()&lt;/code&gt; retrieves all elements that have a NAME attribute that matches that string. Or does it?&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&amp;lt;div name="foo"&amp;gt;DIV one&amp;lt;/div&amp;gt;
&amp;lt;div name="foo"&amp;gt;DIV two&amp;lt;/div&amp;gt;
&amp;lt;div name="foo"&amp;gt;DIV three&amp;lt;/div&amp;gt;

&amp;lt;script type="text/javascript"&amp;gt;
var divs = document.getElementsByName("foo");
alert(divs.length);
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moz/Firefox will report a length of 3. MSIE will report a length of zero. Huh?&lt;/p&gt;

&lt;p&gt;According to the HTML 4.01 spec, the &lt;a href="http://www.w3.org/TR/html401/index/attributes.html"&gt;only elements that support NAME attributes&lt;/a&gt; are BUTTON, TEXTAREA, APPLET, SELECT, FORM, FRAME, IFRAME, IMG, A, INPUT, OBJECT, MAP, PARAM and META. So to place a NAME inside a DIV is actually invalid HTML.&lt;/p&gt;

&lt;p&gt;Moz/Firefox doesn't have a problem with this and will happily return all three DIV elements. But MSIE treats it the invalid NAME attribute as an &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/expando.asp"&gt;expando attribute&lt;/a&gt; and excludes those elements. From the &lt;a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getelementsbyname.asp"&gt;MSDN documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;"Elements that support both the NAME and the ID attribute are included in the collection returned by the getElementsByName method, but not elements with a NAME expando."&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It seems that MSIE's implementation of &lt;code&gt;getElementsByName()&lt;/code&gt; is actually &lt;em&gt;more&lt;/em&gt; compliant with the W3C standard than Moz/Firefox's. Just not nearly as useful.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109814785929965?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111109814785929965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111109814785929965' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109814785929965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109814785929965'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/whats-in-name.html' title='What&apos;s in a NAME?'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109807324747710</id><published>2004-07-20T14:20:00.000-07:00</published><updated>2005-03-17T14:21:13.246-08:00</updated><title type='text'>Form values and innerHTML</title><content type='html'>&lt;p&gt;&lt;a href="http://www.kokogiak.com/"&gt;Alan Taylor&lt;/a&gt; has discovered another intriguing JS quirk: changing form values in Internet Explorer actually changes the underlying HTML structure, so that the value returned by innerHTML is altered. &lt;a href="http://www.kokogiak.com/thatboxinthecorner/innerHTML_formvals.html"&gt;See Alan's example here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109807324747710?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109807324747710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109807324747710'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/form-values-and-innerhtml.html' title='Form values and innerHTML'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109787358755604</id><published>2004-07-16T14:16:00.000-07:00</published><updated>2005-03-17T14:17:53.600-08:00</updated><title type='text'>Script-killer comments</title><content type='html'>&lt;p&gt;This one seems like a no-brainer, but it had several of our best JS experts stumped for a good while, until we saw what was right in front of us all along.&lt;/p&gt;

&lt;p&gt;A script for preloading images was failing. The source was similar to this (imagine 20 or more lines of unbroken script):&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
&amp;lt;script type="text/javascript"&amp;gt;
&amp;lt;!-- preload_images ("header1.gif", "header2.gif", "logo.gif");
//--&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Notice how the first line of script is preceded by an HTML comment delimiter. This prevented the &lt;code&gt;preload_images&lt;/code&gt; function from running, as the JS interpreter just skipped over the entire line. For the want of a linebreak, the script was hosed.&lt;/p&gt;

&lt;p&gt;This seems to be common when JS is generated from some backend process. The above JavaScript was generated from a server-side application written in C++.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109787358755604?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111109787358755604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111109787358755604' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109787358755604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109787358755604'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/script-killer-comments.html' title='Script-killer comments'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109767769832663</id><published>2004-07-15T14:13:00.000-07:00</published><updated>2005-03-17T14:18:54.576-08:00</updated><title type='text'>Window args and errors</title><content type='html'>&lt;p&gt;What's wrong with this picture?&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
window.open("example.html","Example Window",
"scrollbars=no");
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Moz/Firefox will pop open a new window, but IE6 will throw an "Invalid Argument" error. Why?&lt;/p&gt;

&lt;p&gt;The second argument to &lt;code&gt;window.open&lt;/code&gt; is the name of the window. In IE6, this cannot contain any spaces or special characters. Some people mistakenly think this argument is for the &lt;em&gt;title&lt;/em&gt; of the window. So they put in something human-readable (like "Example Window"), thus the error.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109767769832663?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111109767769832663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111109767769832663' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109767769832663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109767769832663'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/window-args-and-errors.html' title='Window args and errors'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11521728.post-111109756687854440</id><published>2004-07-14T14:11:00.000-07:00</published><updated>2005-03-17T14:19:11.423-08:00</updated><title type='text'>Array length headaches</title><content type='html'>&lt;p&gt;A co-worker of mine stumbled across this little gem:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;
var foo = ['a', 'b', 'c', 'd',];
document.write(foo.length);
&lt;/pre&gt;&lt;/blockquote&gt;

&lt;p&gt;Moz/Firefox will print 4. IE6 will print 5. Why?&lt;/p&gt;

&lt;p&gt;Look again at the array. See the extra comma on the right? IE6 interprets this as an additional element with an undefined value. Moz/Firefox ignores it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11521728-111109756687854440?l=jszen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://jszen.blogspot.com/feeds/111109756687854440/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11521728&amp;postID=111109756687854440' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109756687854440'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11521728/posts/default/111109756687854440'/><link rel='alternate' type='text/html' href='http://jszen.blogspot.com/2004/07/array-length-headaches.html' title='Array length headaches'/><author><name>scottandrew</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>20</thr:total></entry></feed>
