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

<channel>
	<title>Web 3.0, 6 Bladed Razors, 7 Minute Abs &#187; linkedin</title>
	<atom:link href="http://www.zachleat.com/web/tag/linkedin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zachleat.com/web</link>
	<description></description>
	<lastBuildDate>Mon, 06 Feb 2012 17:09:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>DOMContentLoaded Inconsistencies (in Browsers and JavaScript Libraries)</title>
		<link>http://www.zachleat.com/web/domcontentloaded-inconsistencies/</link>
		<comments>http://www.zachleat.com/web/domcontentloaded-inconsistencies/#comments</comments>
		<pubDate>Fri, 05 Dec 2008 04:54:24 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web Browsers]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=153</guid>
		<description><![CDATA[We all know the problem, but we may not all call it the same thing: DOMContentLoaded.  Every popular JavaScript library has its own name for the DOMContentLoaded event, and they're all implemented differently.  This, of course, partly due to the fact that web browsers are also inconsistent in their implementations.  Here's a run-down of those inconsistencies.]]></description>
			<content:encoded><![CDATA[<p><strong>Quick Summary</strong></p>
<ul>
<li><em>Prototype and Dojo are the only major JavaScript frameworks that correctly time the DOMContentLoaded inside of an iframe in Internet Explorer.  MooTools comes close and both YUI and jQuery both exhibit incorrect behavior.</em></li>
<li><em>Usually, browsers that have a native DOMContentLoaded event will fire it after both JavaScript and CSS (external script, link tags) have loaded.  But Opera fires prior to CSS link tags loading.</em></li>
</ul>
<p>We all know the problem, but we may not all call it the same thing.  Every popular JavaScript library has its own name for the DOMContentLoaded event.</p>
<table>
<thead>
<tr>
<th>JavaScript Library</th>
<th>Event Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI</td>
<td><a href="http://developer.yahoo.com/yui/docs/YAHOO.util.Event.html#method_onDOMReady">DOMReady</a></td>
</tr>
<tr>
<td>jQuery</td>
<td><a href="http://docs.jquery.com/Events/ready">ready</a></td>
</tr>
<tr>
<td>MooTools</td>
<td><a href="http://mootools.net/docs/Utilities/DomReady">domready</a></td>
</tr>
<tr>
<td>Prototype</td>
<td><a href="http://www.prototypejs.org/api/document/observe">dom:loaded</a></td>
</tr>
<tr>
<td>Dojo</td>
<td><a href="http://api.dojotoolkit.org/jsdoc/dojo/1.2/dojo.addOnLoad">addOnLoad</a></td>
</tr>
</tbody>
</table>
<p>But the naming scheme isn&#8217;t the only part about this event that&#8217;s inconsistent.  There are a few hacks strewn around the net that have been bastardized (read: modified to the will of library authors) into each individual framework.  These have been posted time and time again, but for post completeness are the following:</p>
<table>
<thead>
<tr>
<th>IE DOMContentLoaded Hack</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code><a href="http://javascript.nwbox.com/IEContentLoaded/">doScroll</a></code> by Diego Perini</td>
<td>Uses a <code>doScroll</code> method call, which will throw an error if the <code>ondocumentready</code> event hasn&#8217;t fired on the <strong>primary document</strong> (take note of the usage of the word primary).  Once <code>doScroll</code> doesn&#8217;t throw an error, it is assumed the DOM has loaded.</td>
</tr>
<tr>
<td><code><a href="http://msdn.microsoft.com/en-us/library/ms536957(VS.85).aspx">onreadystatechange</a></code> and <code><a href="http://msdn.microsoft.com/en-us/library/ms534359.aspx">readyState</a></code></td>
<td><code>onreadystatechange</code> <em>&#8220;fires when the state of the object has changed,&#8221;</em> and changes the <code>readyState</code> property of the object through the following states (not all apply to every type of element): <code>uninitialized</code>, <code>loading</code>, <code>loaded</code>, <code>interactive</code>, and <code>complete</code>.  (source: MSDN) Usually set on the document object, or a script element (as used in the Script Defer method described next.</td>
</tr>
<tr>
<td><a href="http://dean.edwards.name/weblog/2005/09/busted/">Script Defer</a> by Dean Edwards</td>
<td>document.write&#8217;s a script tag with a <code>defer</code> attribute.  Defer will cause the browser to delay execution of the script until the DOM has successfully loaded (using onreadystatechange on the script tag until its readyState is &#8220;complete&#8221;).  Without defer, the browser would execute any script tag immediately.</td>
</tr>
<tr>
<td><a href="http://dean.edwards.name/weblog/2005/09/busted2/">HTC Behavior</a> by Dean Edwards</td>
<td>Much less popular approach using proprietary HTC Behavior files.  Generally avoided due to the addition of an extra HTTP request to the page in order to download the external .htc file.  As a side note, if using this approach, the <code><a href="http://msdn.microsoft.com/en-us/library/ms531021.aspx">"oncontentready"</a></code> event will work better than the <a href="http://msdn.microsoft.com/en-us/library/ms531024.aspx">&#8220;ondocumentready&#8221;</a> event used by Mr. Edwards.</td>
</tr>
<tr>
<td>Ghetto Method</td>
<td>Of course, the easiest way to do it is to put a script tag right above your ending <code>&lt;/body&gt;</code> tag that triggers the event manually.  This really only works if you have full control of the content, and isn&#8217;t really a library solution.  Worth noting though.</td>
</tr>
</tbody>
</table>
<p><a href='http://zachleat.com/Projects/domcontentloaded/'><img src="http://www.zachleat.com/web/wp-content/uploads/2008/12/domcontentloaded.png" alt="Benchmark for Library DOMContentLoaded Implementations" title="domcontentloaded" width="500" height="224" class="aligncenter size-full wp-image-154" /><br/><br />
<em>Benchmark for Library DOMContentLoaded Implementations</em></a></p>
<p>I created a benchmark trying to answer the simple question: when does the DOMContentLoaded event fire?  Each implementation has different effects, especially in iframes and with stylesheets.</p>
<h1>What Works</h1>
<p>The Internet Explorer hacks presented above are reliable when used on a standalone document (not inside of an iframe).</p>
<p>Mozilla Firefox, Safari, Chrome, and Opera all contain a native DOMContentLoaded event that each framework uses to consistently fire at the correct time.  So, it isn&#8217;t even worth summarizing the results for tests in every browser with a native DOMContentLoaded event, except Opera.  Opera took a different design approach with their DOMContentLoaded event (certainly not wrong, just different), which we&#8217;ll analyze below.</p>
<h1>Internet Explorer inside an Iframe</h1>
<p><em>All libraries below did no branching based on IE versions, all used the same method for IE6, IE7, or IE8.  I performed no tests in IE8, however.</em></p>
<table>
<thead>
<tr>
<th rowspan="2">JavaScript Library</th>
<th rowspan="2">Method</th>
<th colspan="4">Waited for:</th>
</tr>
<tr>
<th>&lt;body&gt; &lt;script&gt;</th>
<th>&lt;head&gt; &lt;script&gt;</th>
<th>&lt;link&gt; CSS</th>
<th>&lt;img&gt;</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI 2.6.0</td>
<td>doScroll, setTimeout</td>
<td colspan="4">Incorrect: Fires almost immediately (~20ms)</td>
</tr>
<tr>
<td>jQuery 1.2.6</td>
<td>window onload</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td>Prototype 1.6.0.3</td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>MooTools 1.2.1</td>
<td>doScroll and set innerHTML, setTimeout</td>
<td>*</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>Dojo 1.2.0</td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td><a href="http://javascript.nwbox.com/IEContentLoaded/">IEContentLoaded</a></td>
<td>doScroll, document.onreadystatechange</td>
<td colspan="4">Incorrect: JavaScript error.</td>
</tr>
<tr>
<td><a href="http://www.thefutureoftheweb.com/blog/adddomloadevent">addDOMLoadEvent</a></td>
<td>Script Defer</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
</tbody>
</table>
<p>* <em>For some reason, not only did the MooTools library not wait for the body script to trigger DOMContentLoaded, the body script never executed at all.</em></p>
<p>The <strong>most important takeaway</strong> from this blog post are the successful methods of faking DOMContentLoaded in Internet Explorer.  The obvious <strong>library winners here are Prototype and Dojo</strong>, with the addDOMLoadEvent script also exhibiting correct behavior.  MooTools is a close runner up, and I would be interested to find out why it didn&#8217;t execute the body script (that&#8217;s left for another day, or perhaps a generous commenter).</p>
<h1>Opera 9.6</h1>
<table>
<thead>
<tr>
<th rowspan="2">JavaScript Library</th>
<th rowspan="2">Method</th>
<th colspan="4">Waited for:</th>
</tr>
<tr>
<th>&lt;body&gt; &lt;script&gt;</th>
<th>&lt;head&gt; &lt;script&gt;</th>
<th>&lt;link&gt; CSS</th>
<th>&lt;img&gt;</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI 2.6.0</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>jQuery 1.2.6</td>
<td>Native DOMContentLoaded + Code to wait for Stylesheets</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td>Prototype 1.6.0.3</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>MooTools 1.2.1</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Dojo 1.2.0</td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="http://javascript.nwbox.com/IEContentLoaded/">IEContentLoaded</a></td>
<td>N/A to Opera</td>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
</tr>
<tr>
<td><a href="http://www.thefutureoftheweb.com/blog/adddomloadevent">addDOMLoadEvent</a></td>
<td>Native DOMContentLoaded</td>
<td>X</td>
<td>X</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>As you can see above, <strong>Opera typically will fire DOMContentLoaded prior to stylesheets loading</strong> successfully (ignoring the jQuery specific code to provide consistency cross-browser)</p>
<p><em>Thanks to <a href="http://www.adamkoch.com/">Adam Koch</a> for first pointing me in the direction of jQuery in an iframe ignoring DOMContentLoaded in IE.</em></p>
<p><strong>Update:</strong> There is an open ticket for <a href="http://sourceforge.net/tracker/index.php?func=detail&#038;aid=2008289&#038;group_id=165715&#038;atid=836476">YUI on Sourceforge</a>, and I&#8217;ve opened a ticket for <a href="http://dev.jquery.com/ticket/3693">jQuery on their Trac site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/domcontentloaded-inconsistencies/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Dear IE6: Please Cache my Images.</title>
		<link>http://www.zachleat.com/web/dear-ie6-please-cache-my-images/</link>
		<comments>http://www.zachleat.com/web/dear-ie6-please-cache-my-images/#comments</comments>
		<pubDate>Sun, 19 Oct 2008 05:47:44 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=149</guid>
		<description><![CDATA[A few months ago, I took on a new role at Union Pacific Railroad as the lead architect for an internal project: a Union Pacific UI Library used in our IT department on all new web-based projects. Based on jQuery, it is similar to a project like jQuery UI, but it has a few more [...]]]></description>
			<content:encoded><![CDATA[<p>A few months ago, I took on a new role at <a href="http://www.unionpacific.jobs/careers/explore/prof/index.shtml">Union Pacific Railroad</a> as the lead architect for an internal project: a Union Pacific UI Library used in our IT department on all new web-based projects.  Based on <a href="http://jquery.com/">jQuery</a>, it is similar to a project like <a href="http://ui.jquery.com/">jQuery UI</a>, but it has a few more components and they&#8217;re branded to our color scheme and programmed to our usability requirements.</p>
<p>The project has allowed me to expand my knowledge of browser quirks, improving my frontend-fu with every closed support ticket.  What does that mean for you?  More blogs posts.  Learn from my mistakes (and from those I&#8217;ve inherited).</p>
<p>This week presented an interesting, albeit decreasingly relevant scenario, where a customer was seeing performance problems when loading a simple web page in Internet Explorer 6.  The only hint to the root cause was a claim that he witnessed &#8220;400 items remaining&#8221; in his status bar.  Naturally, this took awhile, but at least we had somewhere to start: Apache access logs.</p>
<p>Consider the following (jQuery) code to <strong>add three new images</strong> to the page using JavaScript:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;
&lt;html&gt;
    &lt;head&gt;
		&lt;script type=&quot;text/javascript&quot; src=&quot;jquery-1.2.6.min.js&quot;&gt;&lt;/script&gt;
		&lt;style type=&quot;text/css&quot;&gt;
		img.bacon { width: 100px; height: 67px; background-image: url(bacon.png); }
		&lt;/style&gt;
   &lt;/head&gt;
    &lt;body&gt;
        &lt;script type=&quot;text/javascript&quot;&gt;
		jQuery(function() {
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
			jQuery('body').append('&lt;img src=&quot;spacer.png&quot; class=&quot;bacon&quot;/&gt;');
		});
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre></div></div>

<p>Note how each image being added dynamically has a <strong>background-image</strong> as well.</p>
<p>In a <strong>normal</strong> web browser (read: Internet Explorer 7+, Firefox *), this would result in the following Apache <code>access.log</code> (with an empty browser cache) with only <strong>4 HTTP requests</strong> (ignoring favicon.ico, which is irrelevant to this study):</p>
<blockquote><p>
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/ HTTP/1.1&#8243; 200 657<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/jquery-1.2.6.min.js HTTP/1.1&#8243; 200 55774<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:59:09 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416
</p></blockquote>
<p>In Internet Explorer 6, however, this is the resulting Apache <code>access.log</code> (empty browser cache) with <strong>8 HTTP requests</strong>:</p>
<blockquote><p>
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/ HTTP/1.1&#8243; 200 657<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/jquery-1.2.6.min.js HTTP/1.1&#8243; 200 55774<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/spacer.png HTTP/1.1&#8243; 200 207<br />
127.0.0.1 &#8211; - [18/Oct/2008:22:57:48 -0500] &#8220;GET /ie6cache/bacon.png HTTP/1.1&#8243; 200 5416
</p></blockquote>
<p>When a web browser parses your markup and sees three image tags with identical src attributes, it makes only one HTTP request to the server for that image, and the rest of the images are loaded from the local web browser cache (no more HTTP requests are made).  This is standard behavior for all modern web browsers.  But in IE6, as you can see from the above log, made 3 requests to the server for both <code>spacer.png</code> and <code>bacon.png</code>.  Why?</p>
<p>Turns out there are two independent issues at play here:</p>
<ol>
<li>The classic <em><a href="http://www.mister-pixel.com/#Content__state=is_that_simple">IE6 background-image flicker</a></em> problem.  This has been documented extensively, and the problem is that IE6 bypasses its local web browser cache for any image requests made for CSS background-images inserted on the page dynamically.  The good news for this one is that the fix is a simple one.

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">msie</span> <span style="color: #339933;">&amp;&amp;</span> parseInt<span style="color: #009900;">&#40;</span>jQuery.<span style="color: #660066;">browser</span>.<span style="color: #660066;">version</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">6</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
    document.<span style="color: #660066;">execCommand</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;BackgroundImageCache&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">catch</span><span style="color: #009900;">&#40;</span>err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Note the simple check for IE 6 execution only.  This is optional, but keep in mind that this problem is not present in IE7+.  During your testing, also keep in mind that Mister Pixel reports (and I can confirm) that once you run this command, this setting <strong>will persist in your browser</strong>, even if you empty your cache and remove the code from your scripts.  You&#8217;ll need to close your browser window to reset the setting to default.</p>
<p><em>See also <a href="http://dean.edwards.name/my/flicker.html">Dean Edwards&#8217;</a> and <a href="http://www.hedgerwow.com/360/bugs/dom-fix-ie6-background-image-flicker.html">Hedger Wang&#8217;s</a> studies on this issue for more information.</em>  But this is really only half the problem.  This will fix the duplicate bacon.png HTTP requests, but we&#8217;ll still see 3 spacer.png HTTP requests in our logs.
</li>
<li>The other issue is a separate but equal problem with IE6 caching.  When inserting images with identical <code>src</code> attributes, IE6 will always go to the server (which means an extra HTTP request) for a new image.  This is a <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;319546">documented <em>feature</em> in IE6</a>, and the fix they have listed on their page isn&#8217;t ideal.  The best solution here is to <strong>eliminate the need for <code>spacer.png</code></strong> altogether.  I can put these bacon background&#8217;s on a div tag just as easily, emphasizing pragmatism over semantics in this case (it&#8217;s a small sacrifice, you&#8217;ll live).  If you have an <code>&lt;img&gt;</code> tag with a source you actually need, why not move it to the background image on a div tag?  Unfortunately here, the takeaway is that <strong>your logic may need to be restructured</strong> to workaround this issue.
<p>See also <a href="http://www.bazon.net/mishoo/articles.epl?art_id=958">Mihai Bazon&#8217;s study</a> for more information, but do keep in mind that grouping this issue with the background flicker problem is an incorrect categorization.  They are two separate issues and the fixes represented on that page don&#8217;t really fix the issue at all.  Implementing server side caching as a &#8220;fix&#8221; is like using a bandaid for a tourniquet. You don&#8217;t want an HTTP request to go to the server <strong>at all</strong>, I don&#8217;t care if the response is a 200 OK or a 304 Not Modified.  No HTTP request is always going to be faster than a server side cached response.
</li>
</ol>
<p>These issues will present themselves more frequently if you have the &#8220;Every visit to the page&#8221; caching option enabled in your Internet Tools in Internet Explorer.  Good luck.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/dear-ie6-please-cache-my-images/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Relative URLs including the Domain</title>
		<link>http://www.zachleat.com/web/relative-urls-including-the-domain/</link>
		<comments>http://www.zachleat.com/web/relative-urls-including-the-domain/#comments</comments>
		<pubDate>Thu, 16 Oct 2008 06:45:24 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Web Browsers]]></category>
		<category><![CDATA[linkedin]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=148</guid>
		<description><![CDATA[Just a neat little trick I saw while browsing the source code of Google Calendar.  In some of their CSS files, they link to background-images using URLs that include everything but the protocol, which is something I hadn't seen before.]]></description>
			<content:encoded><![CDATA[<p>Just a neat little trick I saw while browsing the source code of Google Calendar.  In some of their CSS files, they link to background-images using URLs that include everything but the protocol, which is something I hadn&#8217;t seen before.</p>
<p>The most common usage of a relative URL is linked from the root (note the slash at the beginning), like so:</p>
<p><img src="/web/wp-content/themes/hemingway/images/title.png"/><br />
&lt;img src=&#8221;<strong>/web/wp-content/themes/hemingway/images/title.png</strong>&#8220;/&gt;</p>
<p>You can also use <code>../</code> to navigate up a directory in your path, but that&#8217;s boring.  The interesting question is: what if I wanted to load content from a separate domain, while at the same time transparently using the protocol used on my page?</p>
<p>Do what Google Calendar does and use the following style:<br />
<img src="//calendar.google.com/googlecalendar/images/calendar_sm2_en.gif"/><br />
&lt;img src=&#8221;<strong>//calendar.google.com/googlecalendar/images/calendar_sm2_en.gif</strong>&#8220;/&gt;</p>
<p>Note the lack of <code>http:</code> or <code>https:</code> from the URL.  If this page <a href="https://www.zachleat.com/web/2008/10/16/relative-urls-including-the-domain/">were hosted on https</a> (we don&#8217;t pay for certificates around here, so you&#8217;ll have to put up with the security warning), the last image source will load from https as well at no additional development cost.</p>
<p>This seems like it would be especially useful if you were using the YDN Performance tip to <a href="http://developer.yahoo.com/performance/rules.html#split">Split Components Across Domains</a>.  Remember, we&#8217;re not just talking images. This involves how the browser resolves URLs, so could be used inside href tags, css urls (as Google Calendar did), etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/relative-urls-including-the-domain/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Rethinking JavaScript Grids and DataTables</title>
		<link>http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/</link>
		<comments>http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/#comments</comments>
		<pubDate>Sun, 13 Apr 2008 20:29:26 +0000</pubDate>
		<dc:creator>Zach Leatherman</dc:creator>
				<category><![CDATA[Interface Design]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Conservative Design]]></category>
		<category><![CDATA[Dojo]]></category>
		<category><![CDATA[ExtJS]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[linkedin]]></category>
		<category><![CDATA[YUI]]></category>

		<guid isPermaLink="false">http://www.zachleat.com/web/?p=122</guid>
		<description><![CDATA[In the world of front end engineering, one must consider the end-user of the interface first, and above all other things. The priorities should not start with development ease, nor external library preference. The priorities should start with the needs of the consumer of your end product. Evolution of your engineering skill is also a [...]]]></description>
			<content:encoded><![CDATA[<p>In the world of front end engineering, one must consider the end-user of the interface first, and above all other things.  The priorities should not start with development ease, nor external library preference.  The priorities should start with the needs of the consumer of your end product.</p>
<p>Evolution of your engineering skill is also a vital trait in this world, which means that as a developer increases his knowledge of good practices and proper methods, sometimes he must shirk his previous assertions about the world as he previously knew it.  And today I&#8217;m shirking a staple of the front end as all web users know it: The Grid (DataTable) Component.</p>
<p>Of course, I&#8217;ve written a few articles in the past about the <a href="http://developer.yahoo.com/yui/datatable/">YUI DataTable</a>, during my long love affair with Yahoo&#8217;s User Interface library.  Another popular one is jQuery&#8217;s <a href="http://tablesorter.com/docs/">TableSorter</a>.  Then there&#8217;s the <a href="http://dojotoolkit.org/book/dojo-book-0-9/docx-documentation-under-development/grid">Dojo Grid</a>, a component <a href="http://www.sitepen.com/blog/2007/09/16/the-dojo-grid/">inherited from TurboAjax</a>.  ExtJS has a variety of nice examples as well for their <a href="http://extjs.com/deploy/dev/examples/#sample-1">Ext 2.0 Grid</a>.</p>
<p>And after using these Grids and DataTables, I certainly respect the programming that went into developing these components.  But let&#8217;s take a step back for a second.  Why do the users need the bells and whistles in these components?  Are they worth the extra load time and complexity they add to the interface?</p>
<p>All we&#8217;re doing here is putting a nice coat of paint on a &lt;table&gt; tag.  Sure, it might have some nice ancillary features like Ajax Data Loading, but those don&#8217;t really matter &#8211; they are things that can be easily performed with some good Ajax and DOM insert utility functions.  In fact, most of the core features included in these components could be described as feature creep, and not beneficial to the end user at all.  Feature creep contributes to code bloat, which means the user is downloading bytes to their web browser that they don&#8217;t need, which can hamper performance.  Libraries usually have online examples of their components, and the include sizes are seen below.  (Gzip compression not considered)</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>JavaScript Size</th>
<th>Minimized</th>
<th>Link</th>
</tr>
</thead>
<tbody>
<tr>
<td>YUI DataTable</td>
<td>216.6 KB</td>
<td>Minimized</td>
<td><a href="http://developer.yahoo.com/yui/examples/datatable/dt_basic_clean.html">Example</a></td>
</tr>
<tr>
<td>Dojo Grid</td>
<td>338.4 KB</td>
<td>Unminimized</td>
<td><a href="http://dojotoolkit.org/book/dojo-book-0-9/docx-documentation-under-development/grid/simple-grid">Example</a></td>
</tr>
<tr>
<td>Ext Grid</td>
<td>545.5 KB</td>
<td>Minimized</td>
<td><a href="http://extjs.com/deploy/dev/examples/grid/array-grid.html">Example</a></td>
</tr>
<tr>
<td>jQuery TableSorter</td>
<td>66 KB</td>
<td>Minimized</td>
<td><a href="http://www.tablesorter.com/">Example</a></td>
</tr>
</tbody>
</table>
<p>The JavaScript include sizes listed above are directly proportional to the feature set that the components provide, and should give you an idea of the overhead involved with using them.  Do we need 545.5 KB of features coming down the pipe to give our users an extra bell, or an extra whistle?  Let&#8217;s analyze the features to rationalize their usage, and remove items from the feature set.</p>
<ul>
<li>Sorting</li>
<li>Modifying column order and display</li>
<li>Resizing columns</li>
<li>Editing of row data directly on the grid itself</li>
<li>Scrolling</li>
<li>Pagination</li>
</ul>
<p><strong>Sorting</strong></p>
<p>Data should be used in the context of its usefulness.  You have a list of messages in your e-mail inbox.  What&#8217;s the most useful context for this list?  In order of date received.  The default sort order provided by the application, to facilitate proper use of the application.  Is comparing the rows in the grid by any other method as useful?  Does the user need to see the list of messages ordered alphabetically by subject?  In these cases where the user is in need of a specific message, <em>searching and filtering</em> is more useful than sorting.  The default sort is useful, but allowing the user to resort on the client, in most cases, is not as useful as other methods of finding a row.</p>
<p><strong>Modifying column order and display</strong></p>
<p>The same argument can be made for any of the other methods of customization provided to the end user.  Does the user need to reorder or hide columns?  The context provided by the application should be sufficient to use the applications data in the way it was intended.  Don&#8217;t overcomplicate your user interface with needless features or a deluge of useless data.  Provide succinct, appropriate data, and the user needn&#8217;t reorder or change the interface.</p>
<p><strong>Resizing columns</strong></p>
<p>The default HTML &lt;table&gt; tag expands to fit the data inside of its cells.  Even when you set the width of the table explicitly, the cells adjust themselves accordingly to fit the data.  This should be the behavior of your table.  You needn&#8217;t monkey around with widths, the browser is smart enough to do it for you.  You can even customize a cell to wrap its text to multiple lines with CSS, if need be.</p>
<p><strong>Editing of row data directly on the grid itself</strong></p>
<p>If you&#8217;re providing an Excel spreadsheet interface for the end user to customize your data, you haven&#8217;t designed your interface correctly.  Rethink how the user needs to interact with the data you&#8217;ve provided, and give them a better, simpler way to edit the data.</p>
<p><strong>Scrolling</strong></p>
<p>Everyone knows that internal scrollbars on a page are evil.  I don&#8217;t even like scrollbars on textareas, to be honest.  Previously, I had worked and reworked the YUI DataTable to handle horizontal scrolling.  Looking back on this, it was a mistake.  There are better ways to handle lots of data in a table, without the heavy mouse interaction and scanning that scrolling require.  Which brings me to my next point.</p>
<p><strong>Pagination</strong></p>
<p>This is the one exception to the feature set cutting board.  This is the one feature that&#8217;s is a requirement, when the data set has too many records to fit on a single page.</p>
<p>Keep these in mind, and look at the feature set provided by a few sites using tabular data centric interfaces that know a thing or two about interface design:</p>

<a href='http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/gmail/' title='Google Mail'><img width="150" height="150" src="http://www.zachleat.com/web/wp-content/uploads/2008/04/gmail-150x150.png" class="attachment-thumbnail" alt="Google Mail" title="Google Mail" /></a>
<a href='http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/wordpress-admin/' title='Wordpress 2.5 Admin Interface'><img width="150" height="150" src="http://www.zachleat.com/web/wp-content/uploads/2008/04/wordpress-admin-150x150.png" class="attachment-thumbnail" alt="Wordpress 2.5 Admin Interface" title="Wordpress 2.5 Admin Interface" /></a>
<a href='http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/google-reader/' title='Google Reader List View'><img width="150" height="150" src="http://www.zachleat.com/web/wp-content/uploads/2008/04/google-reader-150x150.png" class="attachment-thumbnail" alt="Google Reader List View" title="Google Reader List View" /></a>

<p><strong>So, what should we include?</strong></p>
<p>A simple CSS class to style your table is sufficient, with links to paginate the table (properly) and/or a hover for row selection if needed.  You&#8217;re looking at 10-20 lines of jQuery code, maximum, and a few CSS declarations.  In lieu of sorting, of course, you&#8217;ll need to program in a mechanism for searching and filtering as well.  But really, the difficulty with programming this component is knowing what to leave out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zachleat.com/web/rethinking-javascript-grids-and-datatables/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

