<?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>Carsonified &#187; JavaScript</title>
	<atom:link href="http://carsonified.com/blog/category/dev/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://carsonified.com</link>
	<description></description>
	<lastBuildDate>Thu, 11 Mar 2010 19:59:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Handy Tips from Tipster</title>
		<link>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/</link>
		<comments>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/#comments</comments>
		<pubDate>Fri, 01 May 2009 12:03:29 +0000</pubDate>
		<dc:creator>Ryan Carson</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[Geolocation]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://thinkvitamin.com/?p=1286</guid>
		<description><![CDATA[By <strong>Ryan Carson</strong><br />There have been a ton of helpful and interesting tips posted to Tipster recently, so I thought we&#8217;d pull a few out for you all (and give the submitters a bit of well-deserved publicity).
Topics that we&#8217;re covering are: MySQL, CSS, JavaScript, PHP, JQuery, life hacks and server admin.
MySQL Geo Search
Here&#8217;s a MySQL statement to search [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fhandy-tips-to-help-you-out%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fhandy-tips-to-help-you-out%2F" height="61" width="51" /></a></div><p>There have been a ton of helpful and interesting tips posted to <a href="http://tipster.carsonified.com">Tipster</a> recently, so I thought we&#8217;d pull a few out for you all (and give the submitters a bit of well-deserved publicity).</p>
<p>Topics that we&#8217;re covering are: MySQL, CSS, JavaScript, PHP, JQuery, life hacks and server admin.</p>
<h3><a href="http://tipster.carsonified.com/categories/web-apps/mysql-geo-search/">MySQL Geo Search</a></h3>
<p>Here&#8217;s a MySQL statement to search for nearest objects to you in a database, &#8216;lat&#8217; &amp; &#8216;lng&#8217; are fields in the &#8216;items&#8217; table with the location of object and $latitude &amp; $longitude are the users location. The distance field will be the calculated distance in Km between the user and the object:</p>
<p><code>SELECT *,(((acos(sin((&quot;.$latitude.&quot;*pi()/180)) * sin((`lat`*pi()/180))+cos((&quot;.$latitude.&quot;*pi()/180)) * cos((`lat`*pi()/180)) * cos(((&quot;.$longitude.&quot;- `lng`)*pi()/180))))*180/pi())*60*1.1515*1.609344) as distance FROM `items` ORDER BY distance;<!--formatted--></code></p>
<p>By: <a href="http://mogotion.com/">Sam Machin</a><br />
<a href="http://tipster.carsonified.com/categories/web-apps/mysql-geo-search/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/transparent-background-images-png-fix-for-ie6-a-fe/">Transparent background images &#8211; PNG fix for IE6 &#8211; a few reminders</a></h3>
<p>When using the MS filter (via The AlphaImageLoader) to fix PNG transparency for IE6 — in your CSS, remember to:</p>
<ol>
<li>Set width and height for the element/s containing the transparent background image.</li>
<li>First set background to none — then apply filter for background image.</li>
<li>Apply &#8216;position: relative;&#8217; to any contained links to ensure functionality</li>
</ol>
<p>(Also, bear in mind that the background images can no longer be tiled or positioned via &#8216;background-position&#8217;).</p>
<p>By: <a href="http://eyelearn.org/">Prisca</a><br />
<a href="http://tipster.carsonified.com/categories/css/transparent-background-images-png-fix-for-ie6-a-fe/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/javascript/address-longitude-and-latitude-in-google-maps/">Address Longitude and Latitude in Google Maps</a></h3>
<p>Google maps does not show the Longitude and Latitude of an address you search. To get this information, enter this piece of JavaScript into you browsers address bar and hit enter:</p>
<p><code>javascript:void(prompt(&#39;&#39;,gApplication.getMap().getCenter()));<!--formatted--></code></p>
<p>A little window will then pop-up displaying the Longitude and Latitude for you. Bingo!</p>
<p>[Editor's note: If you add this to your bookmarks toolbar, it's even easier to use. Just click it whenever you're on Google Maps. Hat tip to <a href="http://kyanmedia.com">Phil Balchin</a>.]</p>
<p>By: <a href="http://www.twitter.com/zoltarSpeaks">Pete Roome</a><br />
<a href="http://tipster.carsonified.com/categories/javascript/address-longitude-and-latitude-in-google-maps/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/php/custom-details-in-code-hints-zend-studio-for-eclip/">Custom Details in Code Hints &#8211; Zend Studio for Eclipse</a></h3>
<p>Zend Studio is a brilliant platform for PHP development. In my view, well worth the cost. One of the best things about it now being built on Eclipse is the project-wide code hinting.</p>
<p>When you see the built-in code hints and highlight an option, you get loads of lovely details regarding the functions and classes that you are about to use&#8230; as you would expect from most modern IDEs. However, Zend Studio for Eclipse takes this further for your own classes and functions!</p>
<p>When you have written your classes and functions, start placing a multi-line comment just above the opening line, i.e. /**, hit Return and Studio will prompt you for data types and descriptions for your method variables.</p>
<p>This is invaluable in understanding those classes you wrote at 3:47am, 3.5 years ago and haven&#8217;t used since!</p>
<p>By: <a href="http://flipstorm.co.uk/">Simon Hamp</a><br />
<a href="http://tipster.carsonified.com/categories/php/custom-details-in-code-hints-zend-studio-for-eclip/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/use-a-print-stylesheet/">Use a Print Stylesheet</a></h3>
<p>Print stylesheets allow you to change the style of your page when printing, without having to provide a separate &#8220;print version&#8221; of the markup.</p>
<p>You specify a print CSS by adding &#8220;media=&#8217;print&#8217;&#8221; as an attribute to the link tag.</p>
<p><code>&lt;link rel="stylesheet" type="text/css" media="print" href="print.css"/&gt;<!--formatted--></code></p>
<p>In the print CSS you should remove unnecessary elements such as sidebars, menus, background colours, presentational images, etc so as not to waste ink and paper on parts which don&#8217;t need to be printed. You can also change the font and size to make sure the text is clear on the printed page.</p>
<p>You can even add some CSS to show the URLs of links on the page, which wouldn&#8217;t normally be seen when printing.</p>
<p><code>a[href]:after { content: &quot; (&quot; attr(href) &quot;) &quot;; }<!--formatted--></code></p>
<p>By: <a href="http://wblinks.com/">Rich Adams</a><br />
<a href="http://tipster.carsonified.com/categories/css/use-a-print-stylesheet/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/css/make-your-links-easier-to-read/">Make your links easier to read</a></h3>
<p>Instead of using { text-decoration: underline; } on your links (as browsers do by default) use:</p>
<p><code>{ border-bottom: 1px solid; }.</code></p>
<p>This makes your links easier to read, as there will be more space between the text and the line underneath, so the line will no longer cross through your &#8216;y&#8217;s and &#8216;g&#8217;s.</p>
<p>You can also then style your underline with all the usual border stylings, much more exciting than a plain underline :)</p>
<p>By: <a href="http://laurakalbag.com/">Laura Kalbag</a><br />
<a href="http://tipster.carsonified.com/categories/css/make-your-links-easier-to-read/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/jquery/manual-filmstrips-in-jquery">Manual filmstrips in jQuery</a></h3>
<p>Really simple manual photo film-strip in jQuery. Used to swap a large image on a page with that of a thumbnail elsewhere on the page, such as different photos of a product in an e-commerce store.</p>
<p><code><br />
$(document).ready(function(){<br />
imageSwapper(&quot;.thumbnails a&quot;);<br />
});<br />
<!--formatted--></code></p>
<p><code><br />
function imageSwapper(link) {<br />
$(link).click(function(){<br />
$(&amp;#039;#largeimage&amp;#039;).attr(&amp;#039;src&amp;#039;, this.href);<br />
return false;<br />
});<br />
};<br />
<!--formatted--></code></p>
<p>Just link the thumbnails to their larger versions and pop them in a div or paragraph of class thumbnails, and give the large image an ID of large image, and you are good to go!</p>
<p>By: <a href="http://www.michaelpeacock.co.uk/">Michael Peacock</a><br />
<a href="http://tipster.carsonified.com/categories/jquery/manual-filmstrips-in-jquery">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/web-apps/store-user-passwords-as-salted-hashes/">Store user passwords as salted hashes</a></h3>
<p>Just using a hash of the user password is not strong enough. If two users have the same password, they&#8217;ll have the same hash. Dictionary attacks are also still possible as the attacker can have a list of dictionary word hashes. Using a salted hash involves generating a random string of characters, which you then concatenate with the password before hashing. Two users with the same password will then have different hashes, and the stored hash will never just be a hash of a common word if the user chose a weak password. You then store the salt, and the hashed value in your database.</p>
<p><code>hash_to_store = sha1(salt + real_pass)</code></p>
<p>There are many different methods you could use too, such as concatenating the salt with a hash of the password and then hashing that, etc.</p>
<p><code>hash_to_store = sha1(sha1(real_pass) + ...</code></p>
<p>By: <a href="http://wblinks.com/">Rich Adams</a><br />
<a href="http://tipster.carsonified.com/categories/web-apps/store-user-passwords-as-salted-hashes/">Vote on this tip</a></p>
<h3><a href="http://tipster.carsonified.com/categories/life-hacks/cddvd-stuck-in-macbook/">CD/DVD stuck in Macbook</a></h3>
<p>Having gotten a DVD stuck inside my Macbook the other day, i found the only way to force eject it was to hold down the trackpad button on reboot. DVD popped right out.</p>
<p>By: <a href="http://www.twitter.com/zoltarSpeaks">Pete Roome</a><br />
<a href="http://tipster.carsonified.com/categories/life-hacks/cddvd-stuck-in-macbook/">Vote on this tip</a></p>
<p>Photo credit: <a href="http://www.flickr.com/photos/mance">flickr.com/photos/mance</a></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1286&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/carsonified/features/handy-tips-to-help-you-out/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Streamline your Forms with Widgets</title>
		<link>http://carsonified.com/blog/dev/streamline-your-forms-with-widgets/</link>
		<comments>http://carsonified.com/blog/dev/streamline-your-forms-with-widgets/#comments</comments>
		<pubDate>Tue, 12 Feb 2008 09:00:39 +0000</pubDate>
		<dc:creator>Jason Long</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[widgets]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/css/streamline-your-forms-with-widgets</guid>
		<description><![CDATA[By <strong>Jason Long</strong><br />We all know that people don&#8217;t like filling out forms online, including the folks who design and build them.  Most good web designers working today know to keep them as concise and painless as possible.  A minimalist sign up process on your shiny new web app is sure to produce a higher sign [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fstreamline-your-forms-with-widgets%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fstreamline-your-forms-with-widgets%2F" height="61" width="51" /></a></div><p>We all know that people don&#8217;t like filling out forms online, including the folks who design and build them.  Most good web designers working today know to keep them as concise and painless as possible.  A minimalist sign up process on your shiny new web app is sure to produce a higher sign up rate than one that asks for a dozen pieces of irrelevant information.</p>
<p>Sometimes, however, you&#8217;ll want to develop a form that truly benefits from a large number of options.  Let&#8217;s design a search form for a fictional used automobile site.  Presenting every option in your database would probably be messy and intimidating.  Just one section might look something like this:</p>
<p><img src="/images/articles/custom-select/messy.png" alt="Messy" /></p>
<h3>An Alternative Presentation</h3>
<p>There may be times when keeping all of the available options visible makes the most sense.  Let&#8217;s assume for the time being, however, that you want to package the search options into a neater display.</p>
<p><img src="/images/articles/custom-select/options.png" alt="Neater" /></p>
<p>Using this technique, we&#8217;re able to save valuable screen real-estate and the user is, hopefully, less frightened by all those checkboxes.  In addition, you&#8217;ll have much more freedom to style your dropdown controls to match the look and feel of your application.</p>
<h3>Building the Widget</h3>
<p>This technique doesn&#8217;t require a fancy graphics treatment.  You could easily use vanilla HTML elements and wire up the interaction elements with Javascript (as we&#8217;ll discuss below) and you&#8217;ll be good to go.  However, if you&#8217;re wanting that little extra flair, let&#8217;s jump into Photoshop (or your graphics editor of choice).</p>
<p>I&#8217;ve built my widget to a fixed width with the idea that it&#8217;ll be smart enough to grow taller to accommodate longer text. Here&#8217;s how the plain widget looked:</p>
<p><img src="/images/articles/custom-select/plain_container.png" alt="Plain Container" /></p>
<p>And with the dropdown &#8220;trigger&#8221;:</p>
<p><img src="/images/articles/custom-select/container_and_trigger.png" alt="Container and trigger" /></p>
<p>As I mentioned, we want the widget to be able to expand vertically so that longer text doesn&#8217;t dangle outside it.  We&#8217;ll split our image into top and bottom pieces and stretch the top one out so it&#8217;s tall enough to hold the fullest possible amount of text.</p>
<p><strong>Top Piece</strong></p>
<p><img src="/images/articles/custom-select/dd_top.gif" alt="Top piece" /></p>
<p><strong>Bottom Piece</strong></p>
<p><img src="/images/articles/custom-select/dd_bottom.gif" alt="Bottom piece" /></p>
<p>Be sure you don&#8217;t simply resize the image to be tall enough since it will distort your masterpiece.  Simply select one horizontal row, copy it, paste it, and use the transform tool to create the &#8220;filler&#8221; region.</p>
<h3>Styling and Wiring</h3>
<p>Now it&#8217;s time to create the HTML, CSS, and Javascript needed to make your widget come to life.  In its most basic form, there is a wrapper container:</p>
<pre><code>
&lt;div class=&quot;dd_wrapper&quot;&gt;
&lt;div class=&quot;dd_bottom&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>The dd_wrapper class will contain our top background image and dd_bottom will contain the bottom one.</p>
<pre><code>
.dd_wrapper {
  color: #fff;
  width: 169px;
  background: url(../images/dd_top.gif) top left no-repeat;
  font-size: 11px;
  padding: 11px 30px 10px 14px;
  position: relative;
  line-height: 1.3em;
  min-height: 17px;
}

.dd_bottom {
  width: 213px;
  height: 18px;
  position: absolute;
  bottom: -1px;
  left: 0;
  background: url(../images/dd_bottom.gif) top left no-repeat;
  z-index: 0;
}
</code></pre>
<p>There&#8217;s nothing too fancy going on here.  The width of dd_wrapper is accounting for the image width minus the left and right padding (213 &#8211; 30 &#8211; 14 = 169).  The right padding is larger to allow room for the dropdown trigger graphic.  The position attribute is set to relative so that we can absolutely position our other elements within in.  The dd_bottom class is anchored to the bottom left of the parent container and its width is left at 213px since there is no padding for it.  We specify a height of 18px to match that of the bottom image so that it doesn&#8217;t collapse and disappear due to having no inner content.</p>
<p>Next, let&#8217;s add our dropdown trigger and a span wrapper for our text label.</p>
<pre><code>
&lt;div class=&quot;dd_wrapper&quot;&gt;
&lt;span class=&quot;inner&quot;&gt;
Engine &lt;span class=&quot;light&quot;&gt;(6 cylinder, 8 cylinder)&lt;/span&gt;
&lt;/span&gt;
&lt;a href=&quot;#&quot; class=&quot;dd_toggle&quot; title=&quot;Change&quot;&gt;
&lt;img src=&quot;../images/dd_toggle.gif&quot; alt=&quot;Change&quot; /&gt;
&lt;/a&gt;
&lt;div class=&quot;dd_bottom&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>The inner class will hold our text and the dd_toggle link is positioned on the right hand side.</p>
<pre><code>
.dd_wrapper .inner {
  position: relative;
  z-index: 100;
}

a.dd_toggle {
  position: absolute;
  top: 11px;
  right: 13px;
  z-index: 10;
}

.dd_wrapper .light {
  color: #a3bfe9;
}
</code></pre>
<p>The inner class is relatively positioned so that the z-index rule works properly.  These are used to keep the text above the background image of the dd_bottom container.</p>
<p>Now it&#8217;s time to add our dropdown panel.  It will be hidden by default and the dd_toggle link will call a Javascript function to handle the showing and hiding of the panel.</p>
<pre><code>
&lt;div class=&quot;dd_wrapper&quot;&gt;
  &lt;span class=&quot;inner&quot;&gt;
    Engine &lt;span class=&quot;light&quot;&gt;(6 cylinder, 8 cylinder)&lt;/span&gt;
  &lt;/span&gt;
  &lt;a href=&quot;#&quot; onclick=&quot;toggleDropdown(&#x27;engine_options&#x27;);return false;&quot; class=&quot;dd_toggle&quot; title=&quot;Change&quot;&gt;&lt;img src=&quot;../images/dd_toggle.gif&quot; alt=&quot;Change&quot;/&gt;&lt;/a&gt;
  &lt;div class=&quot;dd_bottom&quot;&gt;&lt;/div&gt;
  &lt;div id=&quot;engine_options&quot; class=&quot;dd_option_panel&quot; style=&quot;display:none;&quot;&gt;
    &lt;p&gt;Select which engine options you are interested in.&lt;/p&gt;
    &lt;ul&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_4&quot; /&gt;
      &lt;label for=&quot;engine_4&quot;&gt;4 cylinder&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_6&quot; checked=&quot;checked&quot; /&gt;
      &lt;label for=&quot;engine_6&quot;&gt;6 cylinder&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_8&quot; checked=&quot;checked&quot; /&gt;
      &lt;label for=&quot;engine_8&quot;&gt;8 cylinder&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_10&quot; /&gt;
      &lt;label for=&quot;engine_10&quot;&gt;10 cylinder&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_12&quot; /&gt;
      &lt;label for=&quot;engine_12&quot;&gt;12 cylinder&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_hybrid&quot; /&gt;
      &lt;label for=&quot;engine_hybrid&quot;&gt;Hybrid&lt;/label&gt;
    &lt;/li&gt;
    &lt;li&gt;&lt;input type=&quot;checkbox&quot; id=&quot;engine_elec&quot; /&gt;
      &lt;label for=&quot;engine_elec&quot;&gt;Electric&lt;/label&gt;
    &lt;/li&gt;
    &lt;/ul&gt;
    &lt;p class=&quot;buttons&quot;&gt;
      &lt;input type=&quot;image&quot; src=&quot;../images/save_choices.gif&quot; onclick=&quot;toggleDropdown(&#x27;engine_options&#x27;);return false;&quot;/&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>The toggleDropdown() function will toggle the requested panel and it will also ensure that all other panels are hidden.  This way, if one panel is open and the user clicks the trigger on another dropdown widget, only the newest panel will appear as open.  I am using the <a href="http://prototypejs.org">Prototype</a> Javascript library here, but this could easily be adapted to any other implementation.</p>
<pre><code>
function toggleDropdown(panel)
{
// toggle the requested one
Element.toggle(panel);

// then hide all of the others so that only
// one (at most) is open at a time
$$('body .dd_option_panel').each(function(node){
if (node != $(panel)) {
Element.hide(node);
}
});
}
</code></pre>
<h3>The Requisite IE Hacks</h3>
<p>You can always count on Internet Explorer to keep you on your toes.  If you choose to align your dropdown widgets vertically like I have in my example, you&#8217;ll notice that the higher dropdown panels render behind the lower widgets.  This is due to IE&#8217;s z-index implementation that is documented extensively elsewhere.  The fix is to wrap each dropdown container with an additional div element whose sole purpose is to force a proper z-index stack.</p>
<p>Also, keep observers may have noticed my use of min-height for the dd_wrapper container.  IE6, of course, doesn&#8217;t support this attribute but I&#8217;ve had success using Dustin Diaz&#8217;s <a href="http://www.dustindiaz.com/min-height-fast-hack/">Min-Height Fast Hack</a>.</p>
<pre><code>
.dd_wrapper {
  ...
  min-height: 17px;
  /* IE6 min-height hack: http://www.dustindiaz.com/min-height-fast-hack/ */
  height: auto ! important;
  height: 17px;
}
</code></pre>
<pre><code>
&lt;div style=&quot;position:relative;z-index:60;&quot;&gt;
&lt;div class=&quot;dd_wrapper&quot;&gt;
...
&lt;/div&gt;
&lt;/div&gt;

&lt;div style=&quot;position:relative;z-index:50;&quot;&gt;
&lt;div class=&quot;dd_wrapper&quot;&gt;
...
&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h3>Final Touches</h3>
<p>My example includes a save button that could be used to make an AJAX call.  This would be useful if your search updated the results on the fly as search options were changed.  If your form was going to be submitted normally, this button could be removed.</p>
<p>Keep in mind that you aren&#8217;t limited to checkbox fields in your dropdown panels.  You could use radio buttons or anything else.  With these types of hidden panels, you will be able to include some additional helper text for your users when it makes sense, but try to keep it short and to the point.</p>
<p>The final thing you&#8217;d want to add is some code to handle the updating of the text label when the options are updated.  Depending on your implementation, there are various ways to handle this.  For example, the result of an AJAX request might determine how the label gets updated.  You might want to have your toggleDropdown() function include some logic to update those DOM elements.</p>
<p>My final advice would be to put a little extra thought into making the text labels smart enough to show a concise view of the selections.  For example, if your user selects all of the options for Fuel, &#8220;Any Fuel&#8221; is easier to read (and actually indicates an all-inclusive selection) than &#8220;Fuel (Gasoline, Diesel, Alternative)&#8221;.</p>
<p>Hopefully this article gives you some ideas that you can incorporate into your next project.  The overall idea is quite simple, but there are endless ways that you could expand and improve upon it!</p>
<p><a href="/images/articles/custom-select/demo.html">View the completed demo</a>.</p>
<p><script src="http://digg.com/tools/diggthis.js" type="text/javascript"></script></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1772&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/streamline-your-forms-with-widgets/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Widgets and Plug-ins for Social Sites</title>
		<link>http://carsonified.com/blog/dev/widgets-and-plug-ins-for-social-sites/</link>
		<comments>http://carsonified.com/blog/dev/widgets-and-plug-ins-for-social-sites/#comments</comments>
		<pubDate>Mon, 14 Jan 2008 18:59:23 +0000</pubDate>
		<dc:creator>Matt Biddulph</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Social Media]]></category>
		<category><![CDATA[Business]]></category>
		<category><![CDATA[dopplr]]></category>
		<category><![CDATA[identity]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/training/webapps/widgets-and-plug-ins-for-social-sites/</guid>
		<description><![CDATA[By <strong>Matt Biddulph</strong><br />In this presentation, Matt Biddulph, CTO at Dopplr discusses how they worked with Facebook and also JavaScript (using JQuery) to create the social widgets and plug-ins that are essential to Dopplr&#8217;s make-up.
Matt also spoke about other critical stages in the development of Dopplr &#8211; including how they used the internet as a platform, and how [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fwidgets-and-plug-ins-for-social-sites%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fwidgets-and-plug-ins-for-social-sites%2F" height="61" width="51" /></a></div><p>In this presentation, Matt Biddulph, CTO at <a rel="nofollow" target="_blank" href="http://www.dopplr.com">Dopplr</a> discusses how they worked with Facebook and also JavaScript (using JQuery) to create the social widgets and plug-ins that are essential to Dopplr&#8217;s make-up.</p>
<p>Matt also spoke about other critical stages in the development of Dopplr &#8211; including how they used the internet as a platform, and how they deal with user identities.</p>
<p>This session is from <a rel="nofollow" target="_blank" href="http://futureofwebapps.com/2008/miami/pastevents.php">Future of Web Apps</a> London 2007, hosted by <a rel="nofollow" title="Carsonified" target="_blank" href="http://carsonified.com">Carsonified</a>. You can listen to the entire MP3 and download Matt&#8217;s presentation at the FOWA past events page.</p>
<p>The next FOWA is in Miami this February 28th &#8211; more details at the <a rel="nofollow" target="_blank" href="http://futureofwebapps.com/2008/miami/index.php">usual place!</a></p>
<p>
  <iframe class="embeddedvideo" src="http://www.youtube.com/v/KyQfnjnbHrY" type="application/x-shockwave-flash" width="425" height="350"> </iframe> </p>
<div class="feedflare">
<a href="http://feedproxy.google.com/~f/vitaminmasterfeed?a=tsNurXwo"><img src="http://feedproxy.google.com/~f/vitaminmasterfeed?d=960" border="0"></img></a> <a href="http://feedproxy.google.com/~f/vitaminmasterfeed?a=yuPDFia8"><img src="http://feedproxy.google.com/~f/vitaminmasterfeed?i=yuPDFia8" border="0"></img></a> <a href="http://feedproxy.google.com/~f/vitaminmasterfeed?a=s7rxYwhy"><img src="http://feedproxy.google.com/~f/vitaminmasterfeed?d=52" border="0"></img></a> <a href="http://feedproxy.google.com/~f/vitaminmasterfeed?a=3FeqypAx"><img src="http://feedproxy.google.com/~f/vitaminmasterfeed?d=50" border="0"></img></a> <a href="http://feedproxy.google.com/~f/vitaminmasterfeed?a=b87wvRG8"><img src="http://feedproxy.google.com/~f/vitaminmasterfeed?d=961" border="0"></img></a>
</div>
<p><img src="http://feedproxy.google.com/~r/vitaminmasterfeed/~4/MT0diClq3GQ" height="1" width="1"/></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1769&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/widgets-and-plug-ins-for-social-sites/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Setting &amp; Retrieving Accesskeys with JavaScript and DOM</title>
		<link>http://carsonified.com/blog/dev/setting-retrieving-accesskeys-with-javascript-and-dom/</link>
		<comments>http://carsonified.com/blog/dev/setting-retrieving-accesskeys-with-javascript-and-dom/#comments</comments>
		<pubDate>Thu, 22 Mar 2007 08:26:00 +0000</pubDate>
		<dc:creator>Ian Lloyd</dc:creator>
				<category><![CDATA[DOM]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Accesskeys]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/javascript/setting-and-retrieving-accesskeys-with-javascript-and-dom</guid>
		<description><![CDATA[By <strong>Ian Lloyd</strong><br />There are some things in the world of accessibility that appear, on the face of it, to be really wonderful ideas&#8230; until you scratch slightly below the service. What may seem feasible when putting together some guidelines on accessibility might not ultimately translate well to a real-world application. Hands up who can remember the last [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fsetting-retrieving-accesskeys-with-javascript-and-dom%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fsetting-retrieving-accesskeys-with-javascript-and-dom%2F" height="61" width="51" /></a></div><p>There are some things in the world of accessibility that appear, on the face of it, to be really wonderful ideas&#8230; until you scratch slightly below the service. What may seem feasible when putting together some guidelines on accessibility might not ultimately translate well to a real-world application. Hands up who can remember the last time they felt compelled to use a <code>longdesc</code> attribute?  And what about the <code>accesskey</code> attribute? Oh, you <em>have</em> used them you say. OK, let&#8217;s back up a little and find out what went wrong here.</p>
<h3>The Problem With Accesskeys</h3>
<p>The <code>accesskey</code> attribute is a neat little feature that is supposed to enable the user to quickly access a navigation, search, or some other feature of a page quickly. For example, I could use an <code>accesskey</code> of &#8217;s&#8217; for search on a site &#8211; on all sites that I might run &#8211; and have that as the trigger. Depending on the browser or other assistive technology (AT) used, that might involve the user hitting CTRL+s to activate it, or maybe ALT+S, or perhaps some other configuration.</p>
<p>However, those very same commands might be the same as existing commands in the browser or AT. So which command takes precedence? There is another factor to this &#8216;key already assigned&#8217; problem, and that&#8217;s one of localization. While you may think that your browser has a spare key that you could use, in many other languages this won&#8217;t be the case.</p>
<p>Another problem with the <code>accesskey</code> attribute is how do you let the user know about it? As with the <code>longdesc</code> attribute, the availability of the attribute is not really shouted from the rooftops (with the exception of the little-used iCab browser). Unless you make a point of informing the user of <code>accesskey</code>s being used on the site in a separate page, perhaps backed up by judicious use of the <code>title</code> attribute for the relevant links, the user may never know that you made them available.</p>
<p>So it seems that, while accesskeys are a great idea, they are largely hidden and also cause their own set of problems because of the potential overlap with other technology. But wait, maybe there&#8217;s life in the old dog just yet&#8230;</p>
<h3>Let the User Decide</h3>
<p>I have an idea, or rather I <em>had</em> an idea, about the way it might work. I actually used this approach a couple of years ago when I re-built <a href="http://accessify.com/">accessify.com</a>, providing a <a href="http://accessify.com/preferences/accesskeys/">method for the user to set their own accesskeys</a>. They are not forced upon anyone &#8211; it&#8217;s a total opt-in. But in all honesty, it was more of an experiment on a live site than anything else, and it&#8217;s not transferable to other sites unfortunately. The solution was built using PHP, but I always thought that it could be converted to a JavaScript solution. It just took me a couple of years to get around to it (and documenting it!).</p>
<h3>The JavaScript Approach</h3>
<p>In the JavaScript solution, the end result is exactly the same as the version used on Accessify, just the mechanics have changed. Rather than go into all the lines of code and explain everything line-by-line, I&#8217;ll summarise how it works in plain old English.</p>
<ul>
<li>There are a number of links on the example page (the links that we offer up as potential accesskey candidates) By default, they have no <code>accesskey</code> assigned, nor any <code>title</code> attribute:<br />
    <code>&lt;h3&gt;Navigation&lt;/h3&gt;<br />
&lt;ul&gt;<br />
&lt;li&gt;&lt;a href=&quot;/&quot; id=&quot;homelink&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;<br />
&lt;li&gt;&lt;a href=&quot;/search/&quot; id=&quot;searchlink&quot;&gt;Search&lt;/a&gt;&lt;/li&gt;<br />
&#8230;<br />
    </code><code> &lt;/ul&gt;</code></li>
<li>There&#8217;s a warning on the page that says &quot;you need Javascript to set your own accesskeys&quot; &#8211; this is set to display on screen by default<br />
    Finally, there&#8217;s a form that allows you to set the characters you want for the related sections on the page. This is hidden by default (using CSS)<br />
    <code>&lt;p id=&quot;warning&quot;&gt;Cookies are used to save these preferences, but you have either disabled JavaScript, set your browser not to accept cookies, or your browser supports neither. The site will work perfectly well without these preference options.&lt;/p&gt;</p>
<p>    #warning<br />
  {<br />
color:red;<br />
}</p>
<p>function hideWarning()<br />
  {<br />
  <strong>var elwarn = document.getElementById(&#8217;warning&#8217;);<br />
  elwarn.style.display=&quot;none&quot;;</strong><br />
var elsetter = document.getElementById(&#8217;setter&#8217;);<br />
elsetter.style.display=&quot;block&quot;;<br />
}</code></li>
</ul>
<p>If the user gets to the page with JavaScript disabled (or with the scripts not properly downloaded &#8211; perhaps blocked by a firewall), they will essentially get the default page that says &quot;You can&#8217;t do this, you need JavaScript to set this stuff&quot; and no facility to set it is displayed.</p>
<p>If JavaScript is available, though, it&#8217;s a slightly different scenario:</p>
<ul>
<li>The warning message that&#8217;s set to display by default gets suppressed (after page load, by having the CSS <code>display</code> property set to <code>none</code>)</li>
<li> The form that accepts the user&#8217;s desired <code>accesskey</code> assignments is made visible (again, using JavaScript to change the CSS <code>display</code> property)</li>
</ul>
<p>Now that we know that the user has JavaScript enabled and was able to get all the source files correctly, they can then go ahead and save their accesskeys.</p>
<h3>Saving the Accesskey Choices</h3>
<p>The process of saving the choices made by the user are fairly standard JavaScript/cookie methods &#8211; one long string is saved that has a number of property:value pairings (one for each link or button that can potentially be assigned an acccesskey). For example:</p>
<p><code>&lt;form action=&quot;set-access-keys.htm&quot; method=&quot;post&quot; name=&quot;frmAccessKeys&quot;&gt;<br />
&lt;fieldset&gt;</p>
<p>&lt;legend&gt;Set Accesskeys for &#8230; &lt;/legend&gt;</code></p>
<p><code>&lt;div&gt;<br />
&lt;label for=&quot;txthomelink&quot;&gt;Home link&lt;/label&gt;<br />
&lt;input value=&quot;&quot; name=&quot;txthomelink&quot; id=&quot;txthomelink&quot; type=&quot;text&quot; size=&quot;2&quot; maxlength=&quot;1&quot; /&gt;<br />
&lt;/div&gt;</code></p>
<p><code>&lt;div&gt;<br />
&lt;label for=&quot;txtsearchlink&quot;&gt;Search Box&lt;/label&gt;<br />
&lt;input value=&quot;&quot; name=&quot;txtsearchlink&quot; id=&quot;txtsearchlink&quot; type=&quot;text&quot; size=&quot;2&quot; maxlength=&quot;1&quot; /&gt;<br />
&lt;/div&gt;</code></p>
<p><code>...</code></p>
<p><code>&lt;/fieldset&gt;<br />
&lt;/form&gt;</code></p>
<p><code>strKeyVals += &quot;homelink=&quot; + document.forms['frmAccessKeys'].txthomelink.value + &quot;@@&quot;;<br />
  strKeyVals += &quot;searchlink=&quot; + document.forms[&#8217;frmAccessKeys&#8217;].txtsearchlink.value + &quot;@@&quot;;</code></p>
<p>The <code>@@</code> is simply there to make it easier to identify where to split the string when retrieving the data from the saved cookie later.</p>
<p>We also provide an option for the user to get a hint of the <code>accesskey</code> for each link or button with the use of a simple checkbox:</p>
<p><code>&lt;div&gt;<br />
&lt;input type=&quot;checkbox&quot; name=&quot;chkshowhint&quot; id=&quot;chkshowhint&quot; /&gt;<br />
&lt;label for=&quot;chkshowhint&quot; class=&quot;check&quot;&gt;Show accesskeys in links and buttons (displayed after link in brackets)&lt;/label&gt;<br />
&lt;/div&gt;</code></p>
<p><code>strKeyVals += &quot;showhint=&quot; + document.forms['frmAccessKeys'].chkshowhint.checked + &quot;@@&quot;;</code></p>
<p>The process for capturing the information is initiated by an <code>onclick</code> event attached to the submit button, which passes it through to an <code>addevent</code> function:</p>
<p><code>addEvent(document.getElementById('cmdSubmit'), 'click', accessKeySetter, false);</code></p>
<p>(The function accessKeySetter is where the JavaScript code snippets above appear)</p>
<h3>Remembering the Choices and Updating the Display on Page</h3>
<p>Assuming the user has entered some values and also chosen to have the accesskeys showing in the links or buttons, once the page has reloaded following the submit, this is where the DOM really takes over.</p>
<p>Remember, we start with a page that has a number of links that have neither default <code>accesskey</code> or <code>title</code> attributes present, then we use JavaScript to present the option to manipulate/store <code>accesskey</code>s (if JavaScript is not available for whatever reason, the default page display is to warn them that they can&#8217;t do this and need to get their JS in order, or words to that effect). So, already, we&#8217;re using JavaScript in a nice <a href="http://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancing</a> kinda way. The final stage is to use JavaScript and the DOM to update the page display depending on what&#8217;s found in the cookie. The steps to do this are as follows:</p>
<ol>
<li>Firstly, look for the presence of the <code>accesskey</code> cookie</li>
<li>Assuming it&#8217;s found, take the content of that string and split it up into the individual links/buttons that it repesents (separated by the <code>@@</code> characters that were shown earlier<br />
    <code>//get the cookie<br />
    var strAccessKeys = readCookie(&quot;accesskeys&quot;);<br />
    //split up the values<br />
  var arrAccesskeys = strAccessKeys.split(&quot;@@&quot;);</code></li>
<li>Then, each value found is split between the <code>id</code> of the link or button it represents and the value stored against each (the <code>accesskey</code> the user wants to assign)<br />
    <code>for (i=0;i&lt;(arrAccesskeys.length-2);i++)<br />
    {<br />
    var thisAccessKey 	= arrAccesskeys[i].split(&quot;=&quot;);<br />
    var accessKayEl 	= thisAccessKey[0];<br />
  var accessKayAttrib	= thisAccessKey[1];<br />
  &#8230;</code></li>
<li>Then it&#8217;s a case of running through the array of <code>id</code>s in the cookie that have values assigned and matching them up to the <code>id</code>s of elements on the page and then:
<ol>
<li>adding the accesskey value to the element<br />
        <code> if (accessKayAttrib.length&gt;0)<br />
        {<br />
        //set the attribute<br />
        document.getElementById(accessKayEl).setAttribute(&#8217;accesskey&#8217;, accessKayAttrib);</code></li>
<li>and updating the content of link or value of the button text to display the accesskey (if the user has requested this), and adding a title attribute too:<br />
        <code>    if (document.getElementById(accessKayEl).tagName==&quot;A&quot;)<br />
        {<br />
        var strLinkPhrase = document.getElementById(accessKayEl).childNodes[0].nodeValue;<br />
        }<br />
        if ((document.getElementById(accessKayEl).tagName==&quot;INPUT&quot;) &amp;&amp; ((document.getElementById(accessKayEl).type==&quot;submit&quot;)||<br />(document.getElementById(accessKayEl).type==&quot;button&quot;)))<br />
        {<br />
        var strLinkPhrase = document.getElementById(accessKayEl).value;<br />
        }<br />
        <strong>document.getElementById(accessKayEl).setAttribute(&#8217;title&#8217;, strLinkPhrase + &#8216;, access key = &#8216; + accessKayAttrib);<br />
        </strong>//display the accesskey hint, if that&#8217;s been chosen<br />
        if (blnShowHints)<br />
        {<br />
        <strong>strLinkPhrase = strLinkPhrase + &quot; [&quot; + accessKayAttrib + &quot;]&quot;;<br />
        </strong>if (document.getElementById(accessKayEl).tagName==&quot;A&quot;)<br />
        {<br />
        document.getElementById(accessKayEl).childNodes[0].nodeValue = strLinkPhrase;<br />
        }<br />
        if (document.getElementById(accessKayEl).tagName==&quot;INPUT&quot;)<br />
        {<br />
        document.getElementById(accessKayEl).value = strLinkPhrase;<br />
        }</code></li>
</ol>
</li>
<li>One final step, while traversing through the page, is to add the value chosen in to the form fields too, so they&#8217;re remembered, likewise the state of the checkbox.</li>
</ol>
<p>The <a href="http://www.thinkvitamin.com/misc/accesskeys/set-access-keys.htm">final result is a completely unobtrusive method for setting and remembering accesskey attributes</a> which doesn&#8217;t enforce itself on the user &#8211; it&#8217;s completely opt-in.</p>
<p>[<a href="http://www.thinkvitamin.com/misc/accesskeys/final.zip">download the zipped version with all files required here.</a>] </p>
<h3>Possible Improvements</h3>
<p>The biggest improvement that could happen with this script is to have it centralized somewhere, or some variant thereof, so that it could be re-used in some way. My thinking was that if this mechanism were possible to re-use across sites, then a user could potentially save some accesskey choices that would be usable for a number of different sites, but then there&#8217;s one fatal flaw in this idea &#8211; a cookie can only be read back by the same domain, thus if I were to set my choice for site whateverxyz.com, when I try to do the same for abcwhatever.com, it won&#8217;t be able to read back the same data. So I&#8217;m definitely open to suggestions as to how that might be made possible at some time in the future.</p>
<h3>Outside Reading </h3>
<p>This isn&#8217;t the first time someone has come up with a method for dealing with this, so here are a few other takes on how to solve the issue:</p>
<ul>
<li><a href="http://juicystudio.com/article/user-defined-accesskeys.php">Gez Lemon&#8217;s PHP-based accesskey setter</a></li>
<li><a href="http://golem.ph.utexas.edu/~distler/blog/archives/000723.html">Jacques Distler&#8217;s JavaScript approach  </a></li>
</ul>
<p>And if you want to to learn more about the background to the problem, here are a couple of recommended reads:</p>
<ul>
<li>Dave Shea: <a href="http://www.mezzoblue.com/archives/2005/01/05/keyboards_an/">Keyboards and Chaos</a>  </li>
<li>Derek Featherstone: <a href="http://www.boxofchocolates.ca/archives/2003/12/06/accesskey-conflicts">Accesskey Conflicts</a> </li>
</ul>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1739&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/setting-retrieving-accesskeys-with-javascript-and-dom/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Importance of Maintainable JavaScript</title>
		<link>http://carsonified.com/blog/dev/the-importance-of-maintainable-javascript/</link>
		<comments>http://carsonified.com/blog/dev/the-importance-of-maintainable-javascript/#comments</comments>
		<pubDate>Mon, 17 Jul 2006 08:00:56 +0000</pubDate>
		<dc:creator>Christian Heilmann</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/dev/the-importance-of-maintainable-javascript</guid>
		<description><![CDATA[By <strong>Christian Heilmann</strong><br />Forums and mailing lists are full of requests about Ajax, DOM Scripting and how to use this or that library or effect. There is also an extraordinary amount of scripts, libraries and effects being developed and showcased, and the blogs and news sites specialising in scripting hardly have time to look at the demos properly [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fthe-importance-of-maintainable-javascript%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fthe-importance-of-maintainable-javascript%2F" height="61" width="51" /></a></div><p>Forums and mailing lists are full of requests about Ajax, DOM Scripting and how to use this or that library or effect. There is also an extraordinary amount of scripts, libraries and effects being developed and showcased, and the blogs and news sites specialising in scripting hardly have time to look at the demos properly before they are on Digg.com or del.icio.us and making the rounds from these sites.<br />
Times to celebrate for those who have hung on to their skills when the DHTML craze subsided in 2001 and JavaScript became <em>persona non grata</em> on your CV as a main skill. </p>
<h3>Code that shows love to the visitor </h3>
<p>On the whole scripts released today are a lot cleaner than those of the DHTML era &#8211; most probably because of the lack of code forking necessary with browsers these days. I am also very pleased to see that the idea of <a href="http://onlinetools.org/articles/unobtrusivejavascript">Unobtrusive JavaScript</a> has become quite common and is regarded as a goal for aspiring developers rather than a necessary evil.<br />
One exception might be Ajax frameworks and code generators that spit out JavaScript &#8211; which lead some &#8216;JavaScript evangelists&#8217; such as <a href="http://www.adactio.com">Jeremy Keith</a> to coin new terms such as <a href="http://domscripting.com/blog/display/41">HIJAX</a> &#8211; which in essence is Ajax with progressive enhancement instead of JavaScript dependencies.<br />
All in all, it is a great time to be in the know and enthusiastic about JavaScript. Some behaviour patterns from the old days repeat themselves though. You see a lot of code that is &#8216;experimental&#8217; and &#8216;not fit for a live system&#8217; getting hyped and re-used without caring about the initial concerns of the developer &#8211; sometimes even blatantly omitting these warnings when reporting about the code experiment.<br />
You also see the old chestnut of recoding visual effects that were pretty useless in older technologies with newer technologies. An image reflected in an animated lake is a two second &#8216;wow&#8217; effect and from there on a nuisance, no matter if you achieve it using Java, Flash or JavaScript. </p>
<h4>10 PRINT &#8216;HELLO MAINTAINER: GOTO HELL</h4>
<p>So we&#8217;re making life a lot easier for the visitors coming to web sites by creating scripts that are not in their way, but only help then when and if their agents support it. On the other hand, as a maintainer a lot of code flung in my direction is a pain to sift through, debug and generally find the spots where I can customise or change settings. Call me Captain Obvious to the Rescue, but isn&#8217;t it time we &#8211; knowing very well that implementing and maintaining code is annoying and causes a lot of frustration &#8211; cut future maintainers of our code the same slack?<br />
  Unobtrusive JavaScript that is easy to maintain sounds like a winner that could help us spend less time with frustrating trial and error and give us some spare time we could spend on innovating or documenting what we do. </p>
<h3>Maintainable JavaScript? But how?</h3>
<p>So here&#8217;s  an eight step plan to show you what can be done to make your scripts easier for the maintainer. Yes, some of the steps may be very obvious to the jet-set, well travelled and seasoned JavaScript developer, but it can&#8217;t hurt to remind ourselves of their virtues.<br />
  Furthermore, I dare any one of you to look at some older code and test it against them &#8211; I am not ashamed to admit that at times I looked at code and uttered expletives about the person responsible, only to find out later on that it was in fact me a few months back. Scope and feature changes together with looming deadlines and budget cuts breed bad code; it is a fact of software development.</p>
<h4>Step 1: Keep Your Syntax and Structure Clean and Logical</h4>
<p>This means you indent your code, keep a line-length limit of say 80 characters and keep functions reasonably small. A rule of thumb is to keep each task in its own function rather than having one large function to do everything. As an additional benefit, this means that you can re-use these functions when you extend the script at a later stage. Don&#8217;t go the &#8216;IDE generated &#8211; Java&#8217; route though and create many many many one line functions &#8211; this can become more confusing than using one massive function.</p>
<p>There is a holy war going on about tabs vs. spaces for indenting and curly braces on an own line or on the same of the opening command. I don&#8217;t care, as long as you keep it consistent, and also consistent with the other code, were you to extend an already existing project. As an example let&#8217;s take a function that generates &#8216;close&#8217; and &#8216;print&#8217; links for a popup &#8211; links that only make sense when JavaScript is available and should therefore be generated with JavaScript.</p>
<pre><code>
function toolLinks(){
  var tools = document.createElement('ul');
  var item = document.createElement('li');
  var itemlink = document.createElement('a');
  itemlink.setAttribute('href', '#');
  itemlink.appendChild(document.createTextNode('close'));
  itemlink.onclick = function(){window.close();}
  item.appendChild(itemlink);
  tools.appendChild(item);
  var item2 = document.createElement('li');
  var itemlink2 = document.createElement('a');
  itemlink2.setAttribute('href', '#');
  itemlink2.appendChild(document.createTextNode('print'));
  itemlink2.onclick = function(){window.print();}
  item2.appendChild(itemlink2);
  tools.appendChild(item2);
  document.body.appendChild(tools);
}
</code></pre>
<p>You can make this a lot more readable by indenting and separating each task out into own functions:</p>
<pre><code>
function toolLinks(){
  var tools = document.createElement('ul');
  var item = document.createElement('li');
  var itemlink = createLink('#', 'close', closeWindow);
  item.appendChild(itemlink);
  tools.appendChild(item);
  var item2 = document.createElement('li');
  var itemlink2 = createLink('#', 'print', printWindow);
  item2.appendChild(itemlink2);
  tools.appendChild(item2);
  document.body.appendChild(tools);
}
function printWindow(){
  window.print();
}
function closeWindow() {
  window.close();
}
function createLink(url,text,func){
  var temp = document.createElement('a');
  temp.setAttribute('href', url);
  temp.appendChild(document.createTextNode(text));
  temp.onclick = func;
  return temp;
}
</code></pre>
<h4>Step 2: Use clever variable and function names</h4>
<p>This is basic good coding practice, although you see it done badly a lot. Once again, quick fixes and looming deadlines are to blame. In essence it means that you use variable and function names that tell the maintainer immediately what this chunk of data is. You can use underscores or camelCase to concatenate different words &#8211; personally I prefer camelCase, as that is consistent with the methods JavaScript provides you with (eg. <code>getElementsByTagName()</code>). It might even be a good idea to use generic names for variables that are just computed inside a function or loop and don&#8217;t need maintaining like the &#8216;temp&#8217; variable inside the <code>createLink()</code> function in the earlier example.<br />
  Take a leaf out of the book for good CSS design &#8211; make sure to keep your function and variable names generic and describe a task rather than a visual result. A <code>createFatRedBoxForLeftNavigation()</code> might become a <code>createTopBarForSectionNavigation()</code> in another code iteration but doesn&#8217;t have to if you had called it createSecondaryMenu() from the start.<br />
  It is also a very good to stick to English variable and function names &#8211; you never know if you have to share the code world wide or send it to another country for maintenance. </p>
<h4>Step 3: Comment your code </h4>
<p>Commenting can save a lot of time and grief. However, you can also overdo it. In tutorials and books you&#8217;ll find code that has a comment on each line explaining what is going on. This is because of the intended audience, and makes a lot of sense inside a tutorial but is rather superfluous in live code. Comments are needed when:</p>
<ul type="disc">
<li>There is a section of code that needs maintenance, eg. &#8216;Change ID names here&#8217;</li>
<li>There is a section that might become outdated as it fixes a problem for user agents that are hip right now </li>
<li>There is a reason why you programmed something in one way while there might be better ones and you want to      explain that</li>
<li>The code section is dependent on another script or gets parameters whose origin may not be obvious at first.</li>
</ul>
<h4>Step 4: Keep your scripts self-contained</h4>
<p>This step ties in with unobtrusive JavaScript, so let&#8217;s not dwell on it. In essence it means that a maintainer could add your script to any page and don&#8217;t risk overwriting other code by doing so. You can keep scripts self-contained by <a href="http://www.dustindiaz.com/namespace-your-javascript/">namespacing</a> them or wrapping them in an object via the <a href="http://www.wait-till-i.com/index.php?p=239">object literal</a>. You ensure you don&#8217;t hijack variables by keeping them in scope of your functions via the var keyword and you don&#8217;t hijack events by using <code>addEvent()</code> or its derivates.</p>
<h4>Step 5: Keep maintained variables separate and test dependencies</h4>
<p>This step is simple: Keep variables that need to be maintained at the beginning of the function and pre-set them with dummy values if necessary. That way the maintainer always knows where to change settings and doesn&#8217;t have to scan through the whole script and you won&#8217;t run into &#8216;not defined&#8217; errors.</p>
<pre><code>
function toolLinks(){
  var tools, closeWinItem, closeWinLink, printWinItem, printWinLink;

  // link labels, please edit
  <strong>var printLinkLabel = &#8216;print&#8217;;</strong>
  <strong> var closeLinkLabel = &#8216;close&#8217;;</strong>#

   tools = document.createElement(&#8217;ul&#8217;);
   closeWinItem = document.createElement(&#8217;li&#8217;);
   closeWinLink = createLink(&#8217;#', <strong>closeLinkLabel</strong>, closeWindow);
   closeWinItem.appendChild(closeWinLink);
   tools.appendChild(closeWinItem);
   printWinItem = document.createElement(&#8217;li&#8217;);
   printWinLink = createLink(&#8217;#', <strong>printLinkLabel</strong>, printWindow);
   printWinItem.appendChild(printWinLink);
   tools.appendChild(printWinItem);
   document.body.appendChild(tools);
}
</code></pre>
<p>Testing for dependencies is a trait of Unobtrusive JavaScript &#8211; you test for the existence of HTML elements before you access them via DOM methods. Taking this idea further, make sure you test if there are any dependencies in your scripts and alert the maintainer if there is a problem. This is a big issue with a lot of JavaScript libraries. Scripts that rely on the <a href="http://developer.yahoo.com/yui">Yahoo! User Interface library</a> will throw an error when it is not available, this could be prevented by testing for it and showing an alert instead. <a href="http://jquery.com/">Jquery</a> is even worse as it seems to suppress any errors, which makes debugging a gamble. </p>
<h4>Step 6: Separate and communicate the visuals</h4>
<p>When it comes to Unobtrusive JavaScript there is no way around applying and removing CSS class names dynamically to and from elements. There is hardly any situation where you need to access the style collection of an object directly, lest you want to make it harder for the maintainer. Exceptions are drag and drop interfaces, but even then all you change via JavaScript is the x and y coordinates of the element. The rest of the look and feel should stay where it was meant to be: in the CSS file. This ensures that CSS designers don&#8217;t mess around with your code and you don&#8217;t need to know all the ins and outs of CSS bugs in browsers &#8211; and there are a lot more than we&#8217;d like there to be. </p>
<p>The most basic way to communicate the names of these classes is keeping them in variables and commenting them at the beginning of your script:</p>
<pre><code>
demo = {
  // CSS classes
  hideClass : 'hide', // hide elements
  currentClass : 'current', // current navigation element
  hoverClass : 'over', // hover state
  [... rest of the code ...]
}
</code></pre>
<p>If you want to go even further in your separation then you could create an own include file called for example <code>cssClassNames.js</code> and use a <a href="http://www.json.org">JSON</a> notation in this one. </p>
<pre><code>
css={
  'hide' : 'hide', // hide elements
  'current' : 'current', // current navigation element
  'hover' : 'over', // hover state [... and so on for a lot of them...]
}
</code></pre>
<p>In your script you can reach the different class names with <code>css.hide</code> or <code>css.current</code> respectively. You could even use more natural labels like &#8216;hide elements&#8217; and reach them via css &#8216;hide elements&#8217;, which&#8217;ll make it easier for the maintainer but harder for you as a coder.<br />
One really easy trick is a class name to communicate with the CSS designer that you apply to the body of the document. This will allow the CSS designer to distinguish between styles that are applied to the non-JavaScript version and to the scripting enhanced version respectively.</p>
<pre><code>
  if(!document.getElementById || !document.createElement){return;}
  cssjs('add',document.body,'jsenabled');
</code></pre>
<p>CSS:</p>
<pre><code>
/* No JavaScript */
#nav li{
  [...settings...]
}
/* JavaScript */
body.jsenabled #nav li{
  [...settings...]
}
</code></pre>
<p>This is also very handy to hide a lot of elements via CSS instead of looping through all of them. In extreme cases, where you have a lot of styles and totally different settings for the scripting enabled version, you could even apply a totally different style sheet via JavaScript (either use <code>document.write()</code> or create a new LINK element). </p>
<h4>Step 7: Separate textual content and code</h4>
<p>The same tricks apply to textual content, you can either separate labels out as variables or &#8211; even better &#8211; into an own document called <code>textContent.js</code> in JSON format. An example that worked exceptionally well is this one:</p>
<pre><code>
var locales = {
  'en': {
    'homePageAnswerLink':'Answer a question now',
    'homePageQuestionLink':'Ask a question now',
    'contactHoverMessage':'Click to send this info as a message',
    'loadingMessage' : 'Loading your data...',
    'noQAmessage' : 'You have no Questions or Answers yet',
    'questionsDefault': 'You have not asked any questions yet',
    'answersDefault': 'You have not answered any questions yet.',
    'questionHeading' : 'My Questions',
    'answersHeading' : 'My Answers',
    'seeAllAnswers' : 'See all your Answers',
    'seeAllQuestions' : 'See all your Questions',
    'refresh': 'refresh'
  },
  'fr': {
  },
  'de': {
  }
};
</code></pre>
<p>It allowed the editorial staff to translate and maintain the labels in all the different languages without having to touch the code. I even managed to separate the IDs out for them to sort out with the HTML developers. All the JavaScript had to do was to read out the application&#8217;s locale setting and loop through the elements available:</p>
<pre><code>
  function doI18N(){
   var lang = yhost.PluginLocale;
   for(i in locales[lang]){
     if(document.getElementById(i)){
       document.getElementById(i).innerHTML = <strong>locales[lang][i]</strong>;
     }
   }
  }
</code></pre>
<h4>Step 8: Document your code</h4>
<p>Last but oh so not at all least: write documentation about your script / library / effect. Good documentation takes the audience into consideration, which means that for some libraries it is good to keep it a classic API documentation with all possible properties and parameters of methods explained in &#8216;techspeak&#8217;, but in general I have had much more success with &#8216;Explain by example, then list all possibilities&#8217; documentation. Good documentation saves the most time and money, actually a shame we hardly get the time to create it. Other programming languages tend to automatically generate documentation from code comments (PHP for example), however that does not necessarily make for better docs, just less work.</p>
<h3>What about high traffic sites?</h3>
<p>If you are working in a high traffic environment, or one that only allows for small code packets (mobile market) then you might frown upon the ideas explained here as they can bloat the code. The way around that problem is to maintain a code base and a live code repository, which is generated from the original code after stripping out the comments, replacing long variable names with shorter ones and performing other packing and minifying tasks. Tools to do that for you are Douglas Crockford&#8217;s <a href="(http://javascript.crockford.com/jsmin.html">jsmin</a> and Dean Edward&#8217;s <a href="http://dean.edwards.name/packer/">packer</a>.</p>
<h3>Summary</h3>
<p>I hope that the above examples have given you an idea how to make your code more maintainable or reminded you of some ideas that lay dormant in the back of your head. If you have other ideas, or you strongly disagree with some of the practices (and you have good reason to), please drop a comment here, as with everything that is &#8216;best practice&#8217;, it is a work in progress and collaboration can only make it better.</p>
<p><em>You can find out more about this subject, plus get a podcast from a recent talk Christian gave on the subject at <a href="http://muffinresearch.co.uk/archives/2006/07/17/after-the-first-wsg-meetup-in-london/">MuffinResearch</a></em></p>
<p class="diggit"><img src="http://www.digg.com/img/digg-guy-small.gif" alt="digg.com logo" /> Like this article? <a href="http://digg.com/programming/The_Importance_of_Maintainable_JavaScript/">Digg it</a>!</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1698&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/the-importance-of-maintainable-javascript/feed/</wfw:commentRss>
		<slash:comments>47</slash:comments>
		</item>
		<item>
		<title>15 Things You Can Do with Yahoo! UI</title>
		<link>http://carsonified.com/blog/dev/15-things-you-can-do-with-yahoo-ui/</link>
		<comments>http://carsonified.com/blog/dev/15-things-you-can-do-with-yahoo-ui/#comments</comments>
		<pubDate>Sun, 02 Jul 2006 08:00:25 +0000</pubDate>
		<dc:creator>Dustin Diaz</dc:creator>
				<category><![CDATA[DOM]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/javascript/15-things-you-can-do-with-yahoo-ui</guid>
		<description><![CDATA[By <strong>Dustin Diaz</strong><br />I will admit straight up front &#8211; I don&#8217;t like writing long articles. There, I said it. I passed College English convincing my professors that I should be rewarded more for my creativity rather than the length of my prose. I&#8217;m the kind of guy that spent more time writing short stories than huge complicated [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2F15-things-you-can-do-with-yahoo-ui%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2F15-things-you-can-do-with-yahoo-ui%2F" height="61" width="51" /></a></div><p>I will admit straight up front &#8211; I don&#8217;t like writing long articles. There, I said it. I passed College English convincing my professors that I should be rewarded more for my creativity rather than the length of my prose. I&#8217;m the kind of guy that spent more time writing short stories than huge complicated essays. Eventually I went on to write for the school Newspaper, a.k.a. <a href="http://www.statehornet.com" title="CSU Sacramento's Student Newspaper">The State Hornet</a> which gave me the freedom to keep my stories to a minimum of 500 words, or just a couple of paragraphs.</p>
<p>Today that legacy still stands and has transferred into my love for making widgets. No, not <a href="http://widgets.yahoo.com/" title="Previously known as Konfabulator">those widgets</a>. I&#8217;m talking about those little goofy things you do on a Sunday afternoon from when you had that idea on Saturday night which left you frustrated on Friday after work. Yes, you&#8217;re not the only one with crazy ideas.</p>
<p>I&#8217;m talking about sliders, yoyos, tooltips, shakers, better looking code, faster queries, and random jubilees of DOM hoopla. It&#8217;s those small things that some of us live to create and find it rewarding even if it&#8217;s one line of code. And although these little works of &#8216;code art&#8217; don&#8217;t always work on all browsers while having labels of &#8216;experimental&#8217; written all over them, don&#8217;t feel ashamed of them. They come from you and you should embrace your work. You are, a Web Professional.</p>
<h3>Segue</h3>
<p>In this article I&#8217;m going to share some of my <q>short stories</q>, <q>poems</q>, and random sonnets of affectionate escapades I&#8217;ve had with JavaScript during the last few months, which I&#8217;ve built using the <a href="http://developer.yahoo.com/yui" title="Yahoo. Woot!">Yahoo UI</a> utilities. Some are rather embarrassing, others useful, and yet others I feel are just downright sexy. If you see something you like, feel free to take it, tweak it, and make it your own. This is what some poetry afficionados of secret societies would call a <q>poetry slam</q>. So for want of a better phrase, this can be a &lt;code slam&gt;.</p>
<h3>Why YUI?</h3>
<p>The <abbr title="Yahoo User Interface">YUI</abbr> utilities give me the expressive freedom to do what I want. And although comparing libraries is generally silly, the best illustration I can give is the <a href="http://script.aculo.us">Script.aculo.us</a> Effects library vs the <a href="http://developer.yahoo.com/yui/animation">YUI Animation utility</a>. Script.aculo.us offers you some pretty sweet looking effects like Fade, SlideUp, BlindDown, Shake, etc.. You can even add Parallel effects (way to go Thomas). On the flip side, the animation util doesn&#8217;t aim to give you these canned effects to package up with your web app, but rather it lets you make up your own effects by giving you the finely crafted tools (like a utility knife) to make what you want. </p>
<p>Another reason I like YUI is that it isn&#8217;t out to change the language itself, but rather it solves many of the cross-browser incompatibilities that we run into on a daily basis. Beyond that, it does quite a few other sexy things that I think you might like.</p>
<h3>Code</h3>
<p>Below is a compilation of fifteen things that I have either developed over the last few months, or have been inspired by a friend (who will receive full credit on the original idea). <strong>Enjoy!</strong></p>
<h3>DOM + The getElementBy&#8217;s</h3>
<p>These days, when you&#8217;re working with the DOM, it&#8217;s all about getting the elements you want, with conditions applied. Thankfully the Dom util doesn&#8217;t go all out and try to do all the guesswork for you resulting in a bulky library with large sets of unwanted code. Instead it gives you a handy method for you to work with called getElementsBy.</p>
<h3>YAHOO.util.Dom.getElementsByClassName</h3>
<p>Let&#8217;s kick off our slam with the classic getElementsByClassName (which is actually in the utility by default). I like to think of it as our token example by the YUI folks showing off how getElementsBy can work natively within your functions. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-01.html">See Demo</a></p>
<h3>getElementsByAttribute</h3>
<p>This method is not in the Dom util by default, but demonstrates exactly how we can add it in if we wanted. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-02.html">See Demo</a></p>
<h3>getElementsByExternal &amp; getElementsByInternal</h3>
<p>This function allows you to get outbound or inbound links returned to you as an HTMLElement collection. At that point it&#8217;s up to you what you want to do with your array of elements (eg. bind event listeners or run a method against them). Currently this is untested on IP address URIs, but I presume that won&#8217;t be an issue for most situations. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-03.html">See Demo</a></p>
<h3>Random Effects of Love</h3>
<p>Because everyone enjoys California cheese.</p>
<h3>Pagination Slide Pattern</h3>
<p>Paginating through large data sets and keeping someone&#8217;s attention can be a tedious task. Sliding results within a container is one way to keep a person entertained. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-04.html">See Demo</a></p>
<h3>BlindUp &amp; BlindDown (Yoyo)</h3>
<p>These are classic effects that almost any animation lover would want in their toolkit. For the sake of making them a macro, here they are. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-05.html">See Demo</a></p>
<h3>BlindOut</h3>
<p>A demonstration of animating a box from any given corner. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-06.html">See Demo</a></p>
<h3>Faux Mutation Events with CustomEvent</h3>
<p>Most folk don&#8217;t know what mutation events are, mainly because they don&#8217;t work in IE6. These are events just like regular DOM events like &#8216;click&#8217;,&#8217;mouseover&#8217;, or &#8216;mouseout&#8217; that you can listen for. Just to name a few there are &#8216;DOMNodeInserted&#8217;, &#8216;DOMNodeRemoved&#8217;, and &#8216;DOMNodeInsertedIntoDocument&#8217;. For a better reference you can see <a href="http://en.wikipedia.org/wiki/DOM_Events">Wikipedia&#8217;s entry on DOM events</a> and search for the Mutation events within the event table. Anyway, here&#8217;s how you can simulate some of those events using the CustomEvent class.</p>
<h3>DOMNodeInserted</h3>
<p>Create some elements, listen for the event, then make them draggable. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-07.html">See Demo</a></p>
<h3>DOMNodeRemoved</h3>
<p>Create some elements, then remove them to update an information box. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-08.html">See Demo</a></p>
<h3>More with CustomEvents</h3>
<p>There really is an endless amount of Custom Events that you can create. So we&#8217;ll keep this to a minimum. Here are three places that the CustomEvent can come in useful:</p>
<h3>Extending the Drag and Drop</h3>
<p>Currently, the Drag and Drop utility is packaged with quite a few custom events you can override such as startDrag, onDrag, or endDrag. However the problem is that you can&#8217;t subscribe to any of these, only override. Here is one trick you can use to make them <q>subscribable</q>. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-09.html">See Demo</a></p>
<h3>onMenuOpen &amp; onMenuCollapse</h3>
<p>This is a combination of animation and custom events where we show menu items sliding into view and firing off subscribable events. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-10.html">See Demo</a></p>
<h3>General Recipes</h3>
<p>None of these have any rhyme or reason. But I tend to think that in some place or another, they can solve a problem.</p>
<h3>Sweet Titles (YUI Style)</h3>
<p>Here we have an OO version of <a href="http://www.dustindiaz.com/sweet-titles/">Sweet Titles</a> that allows us to declare multiple instances of tooltips on separate elements with some optional configuration parameters you can pass into the constructor object to get that exact look and feel you want out of a tooltip. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-11.html">See Demo</a></p>
<h3>Faux Lightbox Effect</h3>
<p>For the sake of doing something that&#8217;s already been done, here&#8217;s a faux light box effect that can be obtained using some core tools. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-12.html">See Demo</a></p>
<h3>Photo Batching</h3>
<p>YAHOO.util.Dom.batch alone may convince you of how cool the DOM Collection utility can be. This shows you how you can batch an HTML Element collection to a method. (Thanks Matt Sweeny) <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-13.html">See Demo</a></p>
<h3>Unobtrusive new windows links</h3>
<p>For some reason or another, this always seems to create some noise regardless of its controversial nature. Here is a very simple way to do it with Event, DOM, and some of the tools we&#8217;ve defined in this very article. <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-14.html">See Demo</a></p>
<h3>Layout Switching with Grids</h3>
<p>This is a combination of using the CSS Grids toolkit and swapping out the templates using JavaScript animation <a href="http://www.thinkvitamin.com/misc/yui-demos/demo-15.html">See Demo</a></p>
<h3>That&#8217;s All Folks</h3>
<p>At least for this article&#8217;s sake. There are plenty of other things you can making using the Yahoo! UI utilities and this has only scratched the surface. I hope it was as fun for you as it was for me.</p>
<p class="diggit"><img src="http://www.digg.com/img/digg-guy-small.gif" alt="digg.com logo" /> Like this article? <a href="http://digg.com/programming/15_things_with_Yahoo_UI">Digg it</a>!</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1696&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/15-things-you-can-do-with-yahoo-ui/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>Serving JavaScript Fast</title>
		<link>http://carsonified.com/blog/dev/serving-javascript-fast/</link>
		<comments>http://carsonified.com/blog/dev/serving-javascript-fast/#comments</comments>
		<pubDate>Sun, 21 May 2006 08:00:18 +0000</pubDate>
		<dc:creator>Cal Henderson</dc:creator>
				<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/webapps/serving-javascript-fast</guid>
		<description><![CDATA[By <strong>Cal Henderson</strong><br />With our so-called &#34;Web 2.0&#34; applications and their rich content and interaction, we expect our applications to increasingly make use of CSS and JavaScript. To make sure these applications are nice and snappy to use, we need to optimize the size and nature of content required to render the page, making sure we&#8217;re delivering the [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fserving-javascript-fast%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fdev%2Fserving-javascript-fast%2F" height="61" width="51" /></a></div><p>With our so-called &quot;Web 2.0&quot; applications and their rich content and interaction, we expect our applications to increasingly make use of CSS and JavaScript. To make sure these applications are nice and snappy to use, we need to optimize the size and nature of content required to render the page, making sure we&#8217;re delivering the optimum experience. In practice, this means a combination of making our content as small and fast to download as possible, while avoiding unnecessarily refetching unmodified resources.</p>
<p>This is complicated a little by the nature of CSS and JavaScript resources. In contrast to image assets, CSS and JavaScript source code is very likely to change many times as time goes by. When these resources change, we need our clients to download them all over again, invalidating the version in their local cache (and any versions stored in other caches along the way). In this article, we&#8217;ll look at ways we can make the whole experience as fast as possible for our users &#8211; the initial page load, subsequent page loads and ongoing resource loading as the application evolves and content changes.</p>
<p>I believe strongly in making things as simple as possible for developers, so we&#8217;ll also be looking at ways we can set up our systems to automatically take care of these optimization issues for us. With a little up front work, we can get the best of both worlds &#8211; an environment that makes development easy with great end-user performance &#8211; all without changing the way we work.</p>
<h3>Monolith</h3>
<p>The old school of thought was that we could achieve optimal performance by combining multiple CSS and JavaScript files into fewer, larger blocks. Rather than having ten 5k JavaScript files, we combine them into a single 50k file. While the total size of the code is still the same, we avoid having the overhead associated with multiple HTTP requests. Each request has a setup and teardown phase on both the client and server, incurs request and response header size overhead, and resource overhead on the server side in the form of more processes or threads (and perhaps more CPU time for on-the-fly gzipped content).</p>
<p>The parellization aspect is also important. By default, both Internet Explorer and Mozilla/Firefox will only download <a href="http://blogs.msdn.com/ie/archive/2005/04/11/407189.aspx">two resources</a> from a single domain at once when using persistent connections (as suggested in the <a href="http://www.ietf.org/rfc/rfc2616.txt">HTTP 1.1 spec</a>, section 8.1.4). This means that while we&#8217;re waiting to download those JavaScript files, 2 at a time, we&#8217;re not loading image assets &#8211; the page our users see during the loading phase will be missing its images.</p>
<p>However, there are a couple of downsides to this approach. By bundling all of our resources together, we force the user to download everything up front. By chunking content into multiple files we can spread out the cost of loading across several pages, amortizing the speed hit across a session (or avoiding some of the cost completely, depending on the path the user chooses). If we make the first page slow to speed up subsequent pages, we might find that we have more users who never wait around to request a second page.</p>
<p>The big downside to the single file approach has not often, historically, been considered. In an environment where we will have to often change our resources, <i>any</i> changes to a single-file system will require the client to re-download a copy of the entire CSS or JavaScript working set. If our application has a single monolithic 100k JavaScript source file, any tiny change to our code will force all clients to suck down the 100k all over again.</p>
<h3>A splintered approach</h3>
<p>The alternative approach lies somewhere in the middle &#8211; we split our CSS and JavaScript resources into multiple sub-files, while at the same time keeping that number functionally low. This compromise comes at a cost &#8211; we need to be able to develop applications with our code split out into logical chunks to increase development efficiency, while delivering merged files for performance. With a few additions to our build system (the set of tools which turn your development code into production code, ready for deployment), this needn&#8217;t be a compromise we have to make.</p>
<p>For an application environment with distinct development and production environments, you can use a few simple techniques to keep your code manageable. In your development environment, code can be split into many logical components to make separation clear. In <a href="http://smarty.php.net/">Smarty</a> (A PHP templating language) we can create a simple function to manage the loading of our JavaScript:</p>
<p><code><br />
SMARTY:<br />
{insert_js files="foo.js,bar.js,baz.js"}</p>
<p>PHP:<br />
function smarty_insert_js($args){<br />
  foreach (explode(',', $args['files']) as $file){</p>
<p>   echo "&lt;script type=&#92;"text/javascript&#92;" src=&#92;"/javascript/$file&#92;"&gt;&lt;/script&gt;&#92;n";<br />
  }<br />
}</p>
<p>OUTPUT:<br />
&lt;script type="text/javascript" src="/javascript/foo.js"&gt;&lt;/script&gt;<br />
&lt;script type="text/javascript" src="/javascript/bar.js"&gt;&lt;/script&gt;<br />
&lt;script type="text/javascript" src="/javascript/baz.js"&gt;&lt;/script&gt;<br />
</code></p>
<p>So far, so easy. But then we instruct our build process to merge certain files together into single resources. In our example, imagine we merged foo.js and bar.js into foobar.js, since they are nearly always loaded together. We can then record this fact in our application configuration and modify our template function to use this information.</p>
<p><code><br />
SMARTY:<br />
{insert_js files="foo.js,bar.js,baz.js"}</p>
<p>PHP:<br />
# map of where we can find .js source files after the build process<br />
# has merged as necessary</p>
<p>$GLOBALS['config']['js_source_map'] = array(<br />
  'foo.js'	=&gt; 'foobar.js',<br />
  'bar.js'	=&gt; 'foobar.js',<br />
  'baz.js'	=&gt; 'baz.js',<br />
);</p>
<p>function smarty_insert_js($args){</p>
<p>  if ($GLOBALS['config']['is_dev_site']){</p>
<p>    $files = explode(',', $args['files']);<br />
  }else{</p>
<p>    $files = array();</p>
<p>    foreach (explode(',', $args['files']) as $file){</p>
<p>      $files[$GLOBALS['config']['js_source_map'][$file]]++;<br />
    }</p>
<p>    $files = array_keys($files);<br />
  }</p>
<p>  foreach ($files as $file){</p>
<p>   echo "&lt;script type=&#92;"text/javascript&#92;" src=&#92;"/javascript/$file&#92;"&gt;&lt;/script&gt;&#92;n";<br />
  }<br />
}</p>
<p>OUTPUT:<br />
&lt;script type="text/javascript" src="/javascript/foobar.js"&gt;&lt;/script&gt;<br />
&lt;script type="text/javascript" src="/javascript/baz.js"&gt;&lt;/script&gt;<br />
</code></p>
<p>The source code in our templates doesn&#8217;t need to change between development and production, but allows us to keep files separated while developing and merged in production. For bonus points, we can write our merging process in PHP and use the same configuration block to perform the merge process, allowing us to keep a single configuration file and avoid having to keep anything in sync. For super-bonus points, we could analyze the occurrence of scripts and style sheets together on pages we serve, to determine which files would be best to merge (files that nearly always appear together are good candidates for merging).</p>
<p>For CSS, a useful model to start from is that of a master and subsection relationship. A single master style sheet controls style across your entire application, while multiple sub-sheets control various distinct feature areas. In this way, most pages will load only two sheets, one of which is cached the first time any page is requested (the master sheet).</p>
<p>For small CSS and JavaScript resource sets, this approach <i>may</i> be slower for the first request than a single large resource, but if you keep the number of components low then you&#8217;ll probably find it&#8217;s actually faster, since the data size per page is much lower. The painful loading costs are spread out around different application areas, so the number of parallel loads is kept to a minimum while also keeping the resources-per-page size low.</p>
<h3>Compression</h3>
<p>When talk about asset compression, most people think immediately of <a href="http://sourceforge.net/projects/mod-gzip/">mod_gzip</a>. Beware, however &#8211; mod_gzip is actually <i>evil</i>, or at the least, a resource hogging nightmare. The idea behind it is simple &#8211; browsers request resources and send along a header to show what kind of content encodings they accept. It looks something like this:</p>
<p><code>Accept-Encoding: gzip,deflate</code></p>
<p>When a server encounters this header, it can then gzip or deflate (compress) the content it&#8217;s sending to the client, where the client will then decompress it. This burns CPU time on both the client and server, while reducing the amount of data transferred. All well and good. The way mod_gzip works, however, is to create a temporary file on disk in which to compress the source data, serve that file out, then delete it. For high volume systems, you very quickly become bound by disk IO. We can avoid this by using <a href="http://httpd.apache.org/docs/2.0/mod/mod_deflate.html">mod_deflate</a> instead (Apache 2 only), which does all the compression in memory &#8211; sensible. For Apache 1 users, you can instead create a RAM disk and have mod_gzip writes its temporary files there &#8211; not quite as fast as pure in-memory compression, but not nearly as slow as writing to disk.</p>
<p>Even so, we can avoid the compression overhead completely by pre-compressing the relevant static resources and using mod_gzip to serve people the compressed version where appropriate. If we add this compression into our build process, it all happens transparently to us. The number of files that need compressing is typically quite low &#8211; we don&#8217;t compress images since we don&#8217;t gain much, if any, size benefit (since they&#8217;re already compressed) so we only need to compress our JavaScript and CSS (and any other uncompressed static content). Configuration options tell mod_gzip where to look for pre-compressed files.</p>
<p><code><br />
mod_gzip_can_negotiate	Yes<br />
mod_gzip_static_suffix	.gz<br />
AddEncoding	gzip	.gz<br />
</code></p>
<p>Newer versions of mod_gzip (starting with version 1.3.26.1a) can pre-compress files for you automatically by adding a single extra configuration option. You&#8217;ll need to make sure that Apache has the correct permissions to create and overwrite the gzipped files for this to work.</p>
<p><code>mod_gzip_update_static	Yes</code></p>
<p>However, it&#8217;s not that simple. Certain versions of Netscape 4 (specifically 4.06 to 4.08) identify themselves as being able to interpret gzipped content (they send a header saying they do), but they cannot correctly decompress it. Most other versions of Netscape 4 have issues with loading compressed JavaScript and CSS in different and exciting ways. We need to detect these agents on the server side and make sure they get served an uncompressed version. This is fairly easy to work around, but Internet Explorer (versions 4 through 6) has some more interesting issues. When loading gzipped JavaScript, Internet Explorer will sometimes <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;823386&amp;Product=ie600">incorrectly decompress</a> the resource, or halt compression halfway through, presenting half a file to the client. If you rely on your JavaScript working, you need to avoid sending gzipped content to Internet Explorer. In the cases where Internet Explorer <i>does</i> receive gzipped JavaScript correctly, some older 5.x versions won&#8217;t cache the file, regardless of it&#8217;s e-tag headers.</p>
<p>Since gzip compression of content is so problematic, we can instead turn our attention to compressing content without changing its format. There are many JavaScript compression scripts available, most of which use a regular expression driven rule set to reduce the size of JavaScript source. There are several things which can be done to make the source smaller &#8211; removing comments, collapsing whitespace, shortening privately scoped variable names and removing optional syntax.</p>
<p>Unfortunately, most of these scripts either obtain a fairly low compression rate, or are destructive under certain circumstances (or both). Without understanding the full parse tree, it&#8217;s difficult for a compressor to distinguish between a comment and what looks like a comment inside a quoted string. Adding closures to the mix, it&#8217;s not easy to find which variables have a private lexical scope using regular expressions, so some variable name shortening techniques will break certain kinds of closure code.</p>
<p>One compressor does avoid this fate &#8211; the <a href="http://dojotoolkit.org/docs/compressor_system.html">Dojo Compressor</a> (there&#8217;s a ready-to-use version <a href="http://alex.dojotoolkit.org/shrinksafe/">here</a>) works by using Rhino (Mozilla&#8217;s JavaScript engine implemented in Java) to build a parse tree, which it then reduces before serializing it to a file. The Dojo Compressor can give pretty good savings for a low cost &#8211; a single compression at build time. By building this compression into our build process, it all happens transparently for us. We can add as much whitespace and as many comments as we like to our JavaScript in our development environment, without worrying about bloating our production code.</p>
<p>Compared to JavaScript, CSS is relatively simple to compress. Because of a general lack of quoted strings (typically paths and font names) we can mangle the whitespace using regular expressions. In the cases where we <i>do</i> have quoted strings, we can nearly always collapse a whitespace sequence into a single space (since we don&#8217;t tend to find multiple spaces or tabs in URL paths or font names). A simple Perl script should be all we need:</p>
<p><code><br />
#!/usr/bin/perl</p>
<p>my $data = '';<br />
open F, $ARGV[0] or die "Can't open source file: $!";<br />
$data .= $_ while &lt;F&gt;;<br />
close F;</p>
<p>$data =~ s!&#92;/&#92;*(.*?)&#92;*&#92;/!!g;  # remove comments<br />
$data =~ s!&#92;s+! !g;           # collapse space<br />
$data =~ s!&#92;} !}&#92;n!g;         # add line breaks<br />
$data =~ s!&#92;n$!!;             # remove last break<br />
$data =~ s! &#92;{ ! {!g;         # trim inside brackets<br />
$data =~ s!; &#92;}!}!g;          # trim inside brackets</p>
<p>print $data;<br />
</code></p>
<p>We can then feed individual CSS files through the script to compress them like so:</p>
<p><code>perl compress.pl site.source.css &gt; site.compress.css</code></p>
<p>With these simple plaintext optimizations we can reduce the amount of data sent over the wire by as much as 50% (depending upon your coding style &#8211; it might be much less), which can translate to a much faster experience for our users. But what we&#8217;d really like to do is avoid users having to even request files unless completely necessary &#8211; and that&#8217;s where an intimate knowledge of HTTP caching comes in handy.</p>
<h3>Caching is your friend</h3>
<p>When a user agent requests a resource from a server for the first time, it caches the response to avoid making the same request in the future. How long it stores this response for is influenced by two factors &#8211; the agent configuration and any cache control response headers from the server. All browsers have subtly different configuration options and behaviors, but most will cache a given resource for at least the length of a session, unless explicitly told otherwise.</p>
<p>It&#8217;s quite likely you already send out anti-caching headers for dynamic content pages to avoid the browser caching pages which constantly change. In PHP, you can achieve this with a pair of function calls:</p>
<p><code><br />
&lt;?php<br />
  header("Cache-Control: private");<br />
  header("Cache-Control: no-cache", false);<br />
?&gt;<br />
</code></p>
<p>Sounds too easy? It is &#8211; some agents will ignore this header under certain circumstances. To <i>really</i> convince a browser not to cache a document, you&#8217;ll need to be a little more forceful:</p>
<p><code><br />
&lt;?php<br />
# 'Expires' in the past<br />
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");</p>
<p># Always modified<br />
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");</p>
<p># HTTP/1.1<br />
header("Cache-Control: no-store, no-cache, must-revalidate");<br />
header("Cache-Control: post-check=0, pre-check=0", false);</p>
<p># HTTP/1.0<br />
header("Pragma: no-cache");<br />
?&gt;<br />
</code></p>
<p>This is fine for content we don&#8217;t want to be cached, but for content that doesn&#8217;t change with every request we want to encourage the browser to cache it aggressively. The &#8220;If-Modified-Since&#8221; request header allows us to get part of the way there. If a client sends an &#8220;If-Modified-Since&#8221; header with its request, Apache (or your web server of choice) can respond with status code 304 (&#8221;Not Modified&#8221;), telling the browser that its cached copy of the file is already up to date. With this mechanism, we can avoid sending the contents of a file to the browser, but we still incur the overhead of an HTTP request. Hmmm.</p>
<p>Similar to the if-modified-since mechanism are entity tags. Under Apache, each response for a static resource is given an &#8220;ETag&#8221; header containing a checksum generated from the file&#8217;s modified-time, size and inode number. A browser can then perform a HEAD request to check the e-tag for a resource without downloading it. E-tags suffer from the same problem as the if-modified-since mechanism &#8211; the client still needs to perform an HTTP request to determine the validity of the locally cached copy.</p>
<p>In addition, you need to be careful with if-modified-since and e-tags if you serve content from multiple servers. With two load-balanced web servers, a single resource could be requested from either server by a single agent &#8211; and could be requested from each at different times. This is great &#8211; it&#8217;s why we load balance. However, if the two servers generate different e-tags or modified dates for the same files, then browsers won&#8217;t be able to properly cache content. By default, e-tags are generated using the inode number of the file, which will vary from server to server. You can turn this off using a single Apache configuration option:</p>
<p><code>FileETag MTime Size</code></p>
<p>With this option, Apache will use only the modification time and file size to determine the e-tag. This, unfortunately, leads us to the other problem with e-tags, which can affect if-modified-since too (though not nearly as badly). Since the e-tag relies on the modified time of the file, we need those times to be in sync. If we&#8217;re pushing files to multiple web servers, there&#8217;s always a chance that the time at which the files are pushed are subtly different by a second or two. In this case, the e-tags generated by two servers will still be different. We could change the configuration to generate e-tags only from the file size, but this means that we&#8217;ll generate the same e-tag if we change a file&#8217;s contents without changing its size. Not ideal.</p>
<h3>Caching is your <i>best</i> friend</h3>
<p>The problem here is that we are approaching the issue from the wrong direction. These possible caching strategies all revolve around the client asking the server if its cached copy is fresh. If we could notify the client when we change a file, it would know that its own cached copy was fresh, until we told it otherwise. But the web doesn&#8217;t work that way &#8211; the client makes requests to the server.</p>
<p>But that&#8217;s not quite true &#8211; before fetching any JavaScript or CSS files, the client makes a request to the server for the page which will be loading those files via &lt;script&gt; or &lt;link&gt; tags. We can use the response from the server to notify the client of any changes in those resources. This is all a little cryptic, so let&#8217;s spell it out &#8211; if we change the filenames of JavaScript and CSS files when we change their contents, we can tell the client to cache every URL forever, since the content of any given URL will never change.</p>
<p>If we are sure that a given resource will never change, then we can send out some seriously aggressive caching headers. In PHP, we just need a couple of lines:</p>
<p><code><br />
&lt;?php<br />
header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");<br />
header("Cache-Control: max-age=315360000");<br />
?&gt;<br />
</code></p>
<p>Here we tell the browser that the content will expire in 10 years (there are 315,360,000 seconds in 10 years, more or less) and that it can keep it around for 10 years. Of course, we&#8217;re probably not serving our JavaScript and CSS via PHP &#8211; we&#8217;ll address that in a few moments.</p>
<h3>Mistakes abound</h3>
<p>Manually changing the filenames of resources when the contents are modified is a dangerous task. What happens if you rename the file, but not the templates pointing to it? What happens if you change some templates but not others? What happens if you change the templates but don&#8217;t rename the file? Most likely of all, what happens if you modify a resource but forget to rename it or change any references to it. In the best of these cases, users will not see the new content and be stuck with the old versions. In the worst case, no valid resource is found and your site stops working. This sounds like a dumb idea.</p>
<p>Luckily computers are really good at this sort of thing &#8211; dull repetitive tasks which need to be done exactly right, over and over again, when some kind of change occurs.</p>
<p>The first step in making this process as painless as possible is to realize that we don&#8217;t need to rename files at all. URLs we serve content from and where the content is located on disk don&#8217;t have to have anything to do with each other. Using Apache&#8217;s <a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a> we can create a simple rule to redirect certain URLs to certain files.</p>
<p><code><br />
RewriteEngine on<br />
RewriteRule ^/(.*&#92;.)v[0-9.]+&#92;.(css|js|gif|png|jpg)$	/$1$2	[L]<br />
</code></p>
<p>This rule matches any URL with one of the specified extensions which also contains a &#8216;version&#8217; nugget. The rule then rewrites these URLs to a path without the version nugget. Some examples:</p>
<p><code><br />
URL			   Path<br />
/images/foo.v2.gif	-&gt; /images/foo.gif<br />
/css/main.v1.27.css	-&gt; /css/main.css<br />
/javascript/md5.v6.js	-&gt; /javascript/md5.js<br />
</code></p>
<p>With this rule in-place, we can change the URL (by changing the version number) without changing where the file lives on disk. Because the URL has changed, the browser treats it as a different resource. For bonus points, you can combine this with the script grouping function from earlier to produce a list of versioned &lt;script&gt; tags as needed.</p>
<p>At this point, you might ask why we don&#8217;t just add a query string to the end of the resource &#8211; /css/main.css?v=4. According the letter of the HTTP caching specification, user agents should <i>never</i> cache URLs with query strings. While Internet Explorer and Firefox ignore this, Opera and Safari don&#8217;t &#8211; to make sure all user agents can cache your resources, we need to keep query strings out of their URLs.</p>
<p>Now that we can change our URLs without moving the file, it would be nice to be able to have the URLs updated automatically. In a small production environment (or a development environment, for people with large production environments), we can do this really easily using a template function. This example is for Smarty, but applies equally well to other templating engines.</p>
<p><code><br />
SMARTY:<br />
&lt;link href="{version src='/css/group.css'}" rel="stylesheet" type="text/css" /&gt;</p>
<p>PHP:<br />
function smarty_version($args){</p>
<p>  $stat = stat($GLOBALS['config']['site_root'].$args['src']);<br />
  $version = $stat['mtime'];</p>
<p>  echo preg_replace('!&#92;.([a-z]+?)$!', ".v$version.&#92;$1", $args['src']);<br />
}</p>
<p>OUTPUT:<br />
&lt;link href="/css/group.v1234567890.css" rel="stylesheet" type="text/css" /&gt;<br />
</code></p>
<p>For each linked resource, we determine the file&#8217;s location on disk, check its mtime (the date and time the file was last modified on disk) and insert that into the URL as the version number. This works great for low traffic sites (where stat operations are cheap) and for development environments, but it doesn&#8217;t scale well to high volume deployments &#8211; each call to stat requires a disk read.</p>
<p>The solution is fairly simple. In a large system we already have a version number for each resource, in the form of the source control revision number (you&#8217;re already using source control, right?). At the point when we go to build our site for deployment, we simply check the revision numbers of all of our resource files and write them to a static configuration file.</p>
<p><code><br />
&lt;?php<br />
$GLOBALS['config']['resource_versions'] = array(</p>
<p>  '/images/foo.gif'    =&gt; '2.1',<br />
  '/css/main.css'      =&gt; '1.27',<br />
  '/javascript/md5.js' =&gt; '6.1.4',<br />
);<br />
?&gt;<br />
</code></p>
<p>We can then modify our templating function to use these version numbers when we&#8217;re operating in production.</p>
<p><code><br />
&lt;?php<br />
function smarty_version($args){</p>
<p>  if ($GLOBALS['config']['is_dev_site']){</p>
<p>    $stat = stat($GLOBALS['config']['site_root'].$args['src']);<br />
    $version = $stat['mtime'];<br />
  }else{<br />
    $version = $GLOBALS['config']['resource_versions'][$args['src']];<br />
  }</p>
<p>  echo preg_replace('!&#92;.([a-z]+?)$!', ".v$version.&#92;$1", $args['src']);<br />
}<br />
?&gt;<br />
</code></p>
<p>In this way, we don&#8217;t need to rename any files, or even remember when we modify resources &#8211; the URL will be automatically changed everywhere whenever we push out a new revision &#8211; lovely. We&#8217;re almost where we want to be.</p>
<h3>Bringing it all together</h3>
<p>When we talked about sending very-long-period cache headers with our static resources earlier, we noted that since this content isn&#8217;t usually served through PHP, we can&#8217;t easily add the cache headers. We have a couple of obvious choices for dealing with this; inserting PHP into the process or letting Apache do the work.</p>
<p>Getting PHP to do our work for us is fairly simple. All we need to do is change the rewrite rule for the static files to be routed through a PHP script, then have the PHP script output headers before outputting the content of the requested resource.</p>
<p><code><br />
Apache:<br />
RewriteRule ^/(.*&#92;.)v[0-9.]+&#92;.(css|js|gif|png|jpg)$  /redir.php?path=$1$2  [L]</p>
<p>PHP:<br />
header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");<br />
header("Cache-Control: max-age=315360000");</p>
<p># ignore paths with a '..'<br />
if (preg_match('!&#92;.&#92;.!', $_GET[path])){ go_404(); }</p>
<p># make sure our path starts with a known directory<br />
if (!preg_match('!^(javascript|css|images)!', $_GET[path])){ go_404(); }</p>
<p># does the file exist?<br />
if (!file_exists($_GET[path])){ go_404(); }</p>
<p># output a mediatype header<br />
$ext = array_pop(explode('.', $_GET[path]));<br />
switch ($ext){<br />
  case 'css':<br />
    header("Content-type: text/css");<br />
    break;<br />
  case 'js' :<br />
    header("Content-type: text/javascript");<br />
    break;<br />
  case 'gif':<br />
    header("Content-type: image/gif");<br />
    break;<br />
  case 'jpg':<br />
    header("Content-type: image/jpeg");<br />
    break;<br />
  case 'png':<br />
    header("Content-type: image/png");<br />
    break;<br />
  default:<br />
    header("Content-type: text/plain");<br />
}</p>
<p># echo the file's contents<br />
echo implode('', file($_GET[path]));</p>
<p>function go_404(){<br />
  header("HTTP/1.0 404 File not found");<br />
  exit;<br />
}<br />
</code></p>
<p>While this works, it&#8217;s not a great solution. PHP demands more memory and execution time than if we did everything in Apache. In addition, we have to be careful to protect against exploits made possible by sending us doctored values for the path query parameter. To avoid all this headache, we can have Apache add the headers directly. The RewriteRule directive allows us to set environment variables when a rule is matched, while the Header directive lets us add headers only when a given environment variable is set. Combining these two directives, we can easily chain the rewrite rule together with the header settings.</p>
<p><code><br />
RewriteEngine on<br />
RewriteRule ^/(.*&#92;.)v[0-9.]+&#92;.(css|js|gif|png|jpg)$ /$1$2 [L,E=VERSIONED_FILE:1]</p>
<p>Header add "Expires" "Mon, 28 Jul 2014 23:30:00 GMT" env=VERSIONED_FILE<br />
Header add "Cache-Control" "max-age=315360000" env=VERSIONED_FILE<br />
</code></p>
<p>Because of Apache&#8217;s order of execution, we need to add the RewriteRule line to the main configuration file (httpd.conf) and not a per-directory (.htaccess) configuration file, otherwise the Header lines get run first, before the environment variable gets set. The Header lines can either go in the main configuration file or in an .htaccess file &#8211; it makes no difference.</p>
<h3>Skinning rabbits</h3>
<p>By combining the above techniques, we can build a flexible development environment and a fast and performant production environment. Of course, this is far from the last word on speed. There are further techniques we could look at (separate serving of static content, multiple domain names for increased concurrency) and different ways of approaching the ones we&#8217;ve talked about (building an Apache filter to modify outgoing URLs in HTML source to add versioning information on the fly). Tell us about techniques and approaches that have worked well for you by leaving a comment.</p>
<h3>Read more</h3>
<p>Cal&#8217;s new book, <a href="http://www.amazon.com/exec/obidos/redirect?link_code=ur2&amp;tag=iamcal&amp;camp=1789&amp;creative=9325&amp;path=ASIN/0596102356/">Building Scalable Web Sites</a>, contains more tips and tricks to help you develop and manage the next generation of web applications.</p>
<p><img src="http://www.digg.com/img/digg-guy-small.gif" alt="digg.com logo" /> Like this article? <a href="http://digg.com/programming/How_To_Speed_Up_Your_Web_App">Digg it</a>!</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=1686&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/dev/serving-javascript-fast/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
	</channel>
</rss>
