<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'><id>tag:blogger.com,1999:blog-6069745790539221961</id><updated>2008-07-02T13:40:39.085-07:00</updated><title type='text'>The True Tribe</title><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/index.php'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default?start-index=26&amp;max-results=25'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8380558187685501842</id><published>2008-06-18T01:43:00.000-07:00</published><updated>2008-06-18T03:55:44.722-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Installing Synergy For Linux and Windows</title><content type='html'>&lt;p&gt;&lt;a href="http://synergy2.sourceforge.net/"&gt;Synergy&lt;/a&gt; is a great app that allows you to control your Linux and Windows computers via a single keyboard and mouse. You can plug in the keyboard/mouse to either Linux or Windows machines and fluidly switch between computers just as easily as you would switch between monitors in a dual-monitor set up.&lt;/p&gt;&lt;p&gt;Here is a description and image from the Synergy site which demonstrates this functionality:&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;In this example, the user is moving the mouse from left to right. When the cursor reaches the right edge of the left screen it jumps instantly to the left edge of the right screen. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;center&gt;&lt;img src="http://synergy2.sourceforge.net/images/warp.gif" /&gt;&lt;/center&gt; &lt;p&gt; You can arrange screens side-by-side, above and below one another, or any combination.  You can even have a screen jump to the opposite edge of itself.  Synergy also understands multiple screens attached to the same computer. &lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;I've been using it for a couple of years now and I find it an invaluable addition to the arsenal of any developer who works in both Windows and Linux. I built a new computer over the weekend and finished installing Ubuntu 8.08 Gutsy Gibbon tonight. One of the first things I did was install Synergy. Previously, I set it up on Red Hat Enterprise, but either way, the set up is pretty straightforward.&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight: bold;"&gt;Let's get started&lt;/span&gt; installing Synergy, shall we? The Windows set up is easier because it has a GUI. In Windows, go to the &lt;a href="http://synergy2.sourceforge.net/"&gt;Synergy SourceForge&lt;/a&gt; page to download the latest release (version 1.3.1 as of this writing).  Here's the download link if you don't want to be bothered with navigating the SourceForge page:&lt;/p&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://downloads.sourceforge.net/synergy2/SynergyInstaller-1.3.1.exe?modtime=1143984577&amp;amp;big_mirror=0"&gt;Download SynergyInstaller-1.3.1.exe from SourceForge&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Once it's downloaded, install it and open the &lt;span style="font-style: italic;"&gt;synergy.exe&lt;/span&gt; file to launch the program.
&lt;/p&gt;&lt;p&gt;
I prefer to set Windows as the client and Linux as the slave, although it was recommended in a forum post to do the opposite in Windows Vista. Regardless, I haven't had issues with Vista or XP in either configuration.&lt;/p&gt;&lt;p&gt;

For now, let's assume your keyboard and mouse is hooked into the Linux box and you want to make Windows the slave (client).  To do this, simply click the radio button next to &lt;span style="font-style: italic;" class="code"&gt;Use another computer's shared keyboard and mouse (client)&lt;/span&gt;. Then, enter the Linux computer's host name next to &lt;span style="font-style: italic;" class="code"&gt;Other Computer's Host Name&lt;/span&gt;. For me, this is 'ubuntu' but you may have been more creative with your host name.
&lt;/p&gt;&lt;p&gt;
We're not quite ready to test it yet, so leave this window open and go back to Linux for a moment. In Ubuntu, install Synergy by typing:
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-family: courier new;"&gt;sudo apt-get install synergy&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
If you prefer doing things in the console, then you can manually create the config files. Otherwise, you can use a GUI called QuickSynergy to get up and running. Here's how to do either way:&lt;/p&gt;&lt;p&gt;

&lt;span style="font-weight: bold;"&gt;The manual way&lt;/span&gt; might take a little longer, or not, depending on how good you are with command line interfaces. To install it manually, first you must create a configuration file called &lt;span style="font-style: italic;"&gt;synergy.conf&lt;/span&gt; that looks like this:
&lt;/p&gt;
&lt;pre&gt;    section: screens
      &lt;span class="arg"&gt;screen1&lt;/span&gt;:
      &lt;span class="arg"&gt;screen2&lt;/span&gt;:
   end
   section: links
      &lt;span class="arg"&gt;screen1&lt;/span&gt;:
          right = &lt;span class="arg"&gt;screen2&lt;/span&gt;
      &lt;span class="arg"&gt;screen2&lt;/span&gt;:
          left = &lt;span class="arg"&gt;screen1&lt;/span&gt;
   end
&lt;/pre&gt;&lt;p&gt;
You can place the config file in /etc/ or /usr/local/etc/ (whichever you prefer).  Just make sure it is somewhere in the environment PATH for convenience's sake.
&lt;/p&gt;&lt;p&gt;
For me, this file says:
&lt;/p&gt;
&lt;pre&gt;    section: screens
      ubuntu:
      laptop&lt;span class="arg"&gt;&lt;/span&gt;:
   end
   section: links
      &lt;span class="arg"&gt;screen1&lt;/span&gt;:
          right = &lt;span class="arg"&gt;laptop
&lt;/span&gt; &lt;span class="arg"&gt;screen2&lt;/span&gt;:
          left = ubuntu&lt;span class="arg"&gt;&lt;/span&gt;
   end
&lt;/pre&gt;&lt;p&gt;
My laptop is, of course, named 'laptop' -- again, feel free to use more imaginative names (as long as it is actually the name of the computer). It isn't necessary to use the name of the computer as the name of the screen but it requires extra configuration otherwise.  (See &lt;a href="http://synergy2.sourceforge.net/"&gt;the official documentation&lt;/a&gt; for more information on this).&lt;/p&gt;&lt;p&gt;

Now that you've created the file, you're ready to launch Synergy. Give it a try with this line:&lt;/p&gt;&lt;p&gt;
&lt;pre&gt;    synergys -f --config synergy.conf
&lt;/pre&gt;&lt;p&gt;Assuming it starts correctly, jump back to Windows and click 'Test' in Synergy there. It should say that it connected OK and everything is fine and dandy. If that's the case, then just click 'Start' and you're done. If not, visit &lt;a href="http://synergy2.sourceforge.net/"&gt;the docs page&lt;/a&gt; and scroll towards the bottom to troubleshoot the issue.&lt;/p&gt;&lt;p&gt;

&lt;span style="font-weight: bold;"&gt;If you prefer graphically configuring Synergy&lt;/span&gt;, that's an option, too. I guess I should have put the GUI solution first for us lazy developers, but it's good to be familiar with the non-graphical way anyway. I know that I managed to mess up my config file using the GUI and had to dive in to it regardless.&lt;/p&gt;&lt;p&gt;

That being said, the GUI (called QuickSynergy) is very straightforward and easy to use. To install QuickSynergy, type the following in a Linux terminal:
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-family: courier new;"&gt;sudo apt-get install quicksynergy&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
Once it's installed, you can type &lt;span style="font-style: italic;"&gt;quicksynergy&lt;/span&gt; to launch it (add &amp;amp; at the end if you want to retain your terminal window) and a window will popup that allows you to configure Synergy, either as host or client.
&lt;/p&gt;&lt;p&gt;
&lt;center&gt;&lt;img src="http://quicksynergy.sourceforge.net/imagens/QuickSynergyLinux.png" alt="" align="middle" border="0" /&gt;&lt;/center&gt; &lt;/p&gt;&lt;p&gt;
The default tab which opens is for host, and all you have to do is enter the correct screen names and then start it. For me, my Linux desktop (named 'ubuntu') is on the left and my Vista laptop (named 'laptop') is on the right, so I just made sure that the fields to the left and right of the computer image said 'ubuntu' and 'laptop', respectively.&lt;/p&gt;&lt;p&gt;

QuickSynergy is theoretically easier to use than the command line way detailed above, so I won't go into much depth here. If you get stuck with QuickSynergy, either try the command line way, or visit the &lt;a href="http://quicksynergy.sourceforge.net/"&gt;QuickSynergy SourceForge site &lt;/a&gt;to see screenshots and example configurations.
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight: bold;"&gt;Extra Features:

&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Synergy has the ability to auto-sync starting and stopping of screensavers

&lt;/li&gt;&lt;li&gt;You can copy and paste between Linux and Windows (this is a huge time-saver!)

&lt;/li&gt;&lt;li&gt;Easily lock the mouse/keyboard to the current screen by toggling scroll lock (assignable to any other key)
&lt;/li&gt;&lt;/ul&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/installing-synergy-for-linux-and.php' title='Installing Synergy For Linux and Windows'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8380558187685501842' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8380558187685501842'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8380558187685501842'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1905240291549601033</id><published>2008-06-17T00:50:00.001-07:00</published><updated>2008-06-17T01:26:56.761-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><title type='text'>What's New in MooTools 1.2</title><content type='html'>&lt;p&gt;I'm happy to announce that MooTools (&lt;a href="http://en.wikipedia.org/wiki/MooTools"&gt;Wikipedia link&lt;/a&gt;) has released version 1.2 of their excellent JavaScript library. MooTools, which stands for 'My Object Oriented Tools', was developed in 2006 by &lt;a href="http://mad4milk.net/"&gt;Valerio Proietti&lt;/a&gt; and &lt;a href="http://mootools.net/developers"&gt;his colleagues&lt;/a&gt;. It evolved out of &lt;a href="http://en.wikipedia.org/wiki/Moo.fx"&gt;Moo.fx&lt;/a&gt;, a lightweight effects library which plugged into the Prototype framework. It was similar, although smaller (and in my opinion, better) than the scriptaculous library. Moo.fx has now been fully integrated into the MooTools library and is not being developed further at this time.&lt;/p&gt;&lt;p&gt; Even before MooTools' 1.0 release on January 29, 2007, it had garnered quite a bit of buzz. There were even &lt;a href="http://snook.ca/archives/javascript/mootools_r83_cheatsheet/"&gt;cheat sheets&lt;/a&gt; created for the beta MooTools library.&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mootools.net/"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://mootools.net//assets/images/mootools.png" border="0" alt="" /&gt;&lt;/a&gt;
&lt;p&gt;Thus, it is with great excitement that I announce a new version of this marvelous framework, with a great deal of improvements and additions to the codebase. I've been using 1.2 beta for quite a while and I think the official release is mostly a bug fix of the beta, so if you've been following this blog, chances are you've already been exposed to some of the new features in 1.2. Regardless, here's a full list of features and enhancements you'll find in the new release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.mootools.net/2008/2/12/what-s-new-in-1-2-swiff"&gt;Swiff&lt;/a&gt;, support for working with Flash SWF files, similar to the &lt;a href="http://code.google.com/p/swfobject/"&gt;swfobject&lt;/a&gt; library&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.mootools.net/2008/1/22/Element_Storage"&gt;Element storage&lt;/a&gt;  allows you to store data in custom properties on HTML elements without leaking memory in IE&lt;/li&gt;
&lt;li&gt;Overhaul of Fx classes with &lt;a href="http://blog.mootools.net/2007/10/23/The_Best_Javascript_Effects_Now_Even_Better"&gt;many improvements&lt;/a&gt;, including creating a &lt;a href="http://docs.mootools.net/Fx/Fx.Tween"&gt;Tween&lt;/a&gt; class to create reusable animation tweens&lt;/li&gt;
&lt;li&gt;Overhauled Ajax requests; renamed Ajax class to &lt;a href="http://docs.mootools.net/"&gt;Request &lt;/a&gt;, with JSON and HTML subclasses (for easily handling their respective data formats as Ajax responses)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.mootools.net/Element/Element.Dimensions"&gt;Element.Dimensions&lt;/a&gt; - makes it a breeze to get width, height, x/y coordinates of an element (either relative to document or to positioning context) and scroll height/width&lt;/li&gt;
&lt;li&gt;Created a &lt;a href="http://docs.mootools.net/Core/Browser"&gt;Browser&lt;/a&gt; class to store browser, platform and feature information (e.g. whether the browser supports XPath or not). Before, browser info was stored on the window object. Also, this release renamed the properties from browser names to rendering engine names, e.g. &lt;span style="font-style:italic;"&gt;trident4&lt;/span&gt; instead of &lt;span style="font-style:italic;"&gt;ie6&lt;/span&gt;.&lt;/li&gt;
&lt;p&gt;In addition to the changes to the API and codebase, the following changes occured as well:&lt;/p&gt;
&lt;li&gt;MooTools now adheres to &lt;a href="http://blog.mootools.net/2007/10/20/what-s-new-in-1-2-spec-runner"&gt;behavior driven development&lt;/a&gt; using specs&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.mootools.net/2007/10/8/what-s-new-in-1-2-the-hash"&gt;The Hash Object&lt;/a&gt; - with &lt;span style="font-style:italic;"&gt;get, put, each, some&lt;/span&gt; and a whole lot of other methods for manipulating data in a hash&lt;/li&gt;
&lt;li&gt;MooTools developed using &lt;a href="http://blog.mootools.net/2008/6/12/mootools-1-2-it-s-official"&gt;Git&lt;/a&gt; instead of Subversion now - this will only affect you if you're used to grabbing code from svn (or if you're a contributor!)&lt;/li&gt;
&lt;li&gt;MooTools uses &lt;a href="http://mootools.lighthouseapp.com/"&gt;Lighthouse&lt;/a&gt; instead of Trac for bug tracking now&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In light of all these improvements to an already excellent library, I think it's apparent that MooTools is really growing up and coming into its own. It's a force to be reckoned with and certainly a heavyweight contender against Prototype, jQuery, YUI and others.&lt;/p&gt;
&lt;p&gt;I hope you've enjoyed this brief overview of some of the new features in MooTools 1.2. Now get out there and start coding!&lt;/p&gt;
&lt;h5&gt;Related links:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.mootools.net"&gt;MooTools homepage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Docs and Demos&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://docs.mootools.net"&gt;1.2 Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://demos.mootools.net"&gt;1.2 Demos&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Compatibility&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://mootools.net/js/mootools-compat-core.js"&gt;Core Compatibility File&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="http://mootools.net/js/mootools-compat-more.js"&gt;Plugin Compatibility File&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Git Repositories&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/mootools/mootools-core"&gt;Core Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/mootools/mootools-more"&gt;Plugin Repository&lt;/a&gt;
&lt;/ul&gt;

&lt;h5&gt;Bug Tracking&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://mootools.lighthouseapp.com/"&gt;MooTools at Lighthouse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;MooTools User Groups&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://groups.google.com/group/mootools-users/"&gt;MooTools Users at Google Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="irc://irc.freenode.org/#mootools"&gt;#mootools on Freenode&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/whats-new-in-mootools-12.php' title='What&apos;s New in MooTools 1.2'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1905240291549601033' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1905240291549601033'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1905240291549601033'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2915436468075828096</id><published>2008-06-15T23:01:00.001-07:00</published><updated>2008-06-19T17:02:37.800-07:00</updated><title type='text'>Javascript image rotator viewer</title><content type='html'>&lt;a href="See a demo at http://www.alexgrande.com"&gt;See a demo at http://www.alexgrande.com&lt;/a&gt;
&lt;br /&gt;
It is the images on the top right.
&lt;br /&gt;
I wrote this in Object Oriented format so you can use it again again on page.
&lt;br /&gt;

Javascript:&lt;br /&gt;
&lt;pre name="code" class="js"&gt;
var ImageGallery = new Function();

ImageGallery.prototype = {
 initialize: function(mainImage, listWrapper){
  // large image that is shown
  this.mainImage = document.getElementById(mainImage);
  // a list of all the anchors for the thumbnails. Must be a tags for graceful degradation
  this.thumbnails = document.getElementById(listWrapper).getElementsByTagName("a");
  // 0 image is shown already so the first one we want to switch to is the next image or 1
  this.i = 1;
  // this is a work around to allow calling this within nested functions
  var Scope = this;
  // Here starts the rotating of the image by first focusing the thumbnail, then switch the primary image
  this.start = setInterval(function(){
   Scope.focusCall();
  // Here we choose 5 seconds in between each image change. You may want to change this.
  }, 5000);
  // This lets the browser know to do something if one of the thumbnails is clicked
  this.clickEvent();
 },
 
 // This stops the rotation of the thumbnails. We do that if the user clicks one of them
 stop: function(){
  if (this.start) 
   clearInterval(this.start);
 },
 
 // When an thumbnail loses focus we must use this css class now
 resetBorderColor: function(reset){
  reset.getElementsByTagName("img")[0].className="thumbnailDefault";
 },
 
 // When the thumbnail gains focus we most give it the corresponding styles
 focusBorderColor: function(focused){
  focused.getElementsByTagName("img")[0].className="thumbnailFocus";
 },
 
 
 // Here we grab the href of the a tags and make their path be the path of the current image
 imageRotator: function(){
  this.mainImage.src = this.thumbnails[this.i].href;
  this.previousImage = this.thumbnails[this.i];
  this.i++;
  // This closes the loop for the rotation
  if (this.i == this.thumbnails.length) 
   this.i = 0;
 },
 
 // We focus the thumbnail
 focusCall: function(){
  // reset the last image that was shown
  if (typeof this.previousImage != 'undefined') 
   this.resetBorderColor(this.previousImage);
  // Remember the newer one
  this.currentImage = this.thumbnails[this.i];
  // Give the newer image some focus
  this.focusBorderColor(this.currentImage);
  var Scope = this;
  // Les that have image rotate to the new one 300 miliseconds after the thumbnails get the css focus
  window.setTimeout(function(){
   Scope.imageRotator()
  // You may want to change this number 
  }, 300);
  
 },
 
 // This is what happens when you click the thumbnails
 clickEvent: function(){
  var Scope = this;
  for (k = 0; k &lt; this.thumbnails.length; k++) {
   this.thumbnails[k].onclick = function(){
    if (typeof Scope.previousImage != 'undefined') 
     Scope.resetBorderColor(Scope.previousImage);
    Scope.focusBorderColor(this);
    // Stop the rotation 
    Scope.stop();
    // This is where the switching happens for the click
    Scope.mainImage.src = this.href;
    Scope.previousImage = this;
    // Make sure to not allow default behavior of the a tag
    return false;
   }
  }
 }
 
}
&lt;/pre&gt;

&lt;br /&gt;
&lt;br /&gt;
This is to load it on the window object and create an instance of the viewer
&lt;br /&gt;
&lt;pre name="code" class="js"&gt;
var imageGallery1 = new ImageGallery();

// Not sure where I got this.. I didn't write this but it allows you to load multiple functions on the window.onload.
function addLoadEvent(func) {
 var oldonload = window.onload;
 if (typeof window.onload != "function") {
  window.onload = func;
 } else {
  window.onload = function() {
   oldonload();
   func();
  }
 }
}

var onLoad = function() {
 imageGallery1.initialize("index_largepic_display", "index_thumbnail_display");
}
 

addLoadEvent(onLoad);
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
For the version on my homepage alexgrande.com here is the CSS and HTML. The CSS is up to you but I suggest following a similar mode with the HTML
&lt;br /&gt;
&lt;br /&gt;
HTML:
&lt;br /&gt;
&lt;pre name="code" class="html"&gt;
&amp;lt;div id=&amp;quot;gallery&amp;quot;&amp;gt;   
     &amp;lt;ul id=&amp;quot;index_thumbnail_display&amp;quot;&amp;gt;
        &amp;lt;li&amp;gt; 
   &amp;lt;a href=&amp;quot;images/index/fernlarge.jpg&amp;quot; &amp;gt;
  &amp;lt;img class=&amp;quot;thumbnailDefault&amp;quot; src=&amp;quot;images/index/fernthumb.jpg&amp;quot; alt=&amp;quot;A picture of a fern just as it is unraveling in front of a log.&amp;quot; /&amp;gt;
   &amp;lt;/a&amp;gt; 
 &amp;lt;/li&amp;gt;

        &amp;lt;li&amp;gt; 
   &amp;lt;a id=&amp;quot;partythumb&amp;quot; href=&amp;quot;images/index/partylarge.jpg&amp;quot; &amp;gt;
      &amp;lt;img class=&amp;quot;thumbnailDefault&amp;quot; src=&amp;quot;images/index/partythumb.jpg&amp;quot; alt=&amp;quot;Downtown Seattle at night.&amp;quot; /&amp;gt;
   &amp;lt;/a&amp;gt;
 &amp;lt;/li&amp;gt;

        &amp;lt;li&amp;gt; 
   &amp;lt;a id=&amp;quot;alexthumb&amp;quot; href=&amp;quot;images/index/alexlarge.jpg&amp;quot; &amp;gt;
      &amp;lt;img class=&amp;quot;thumbnailDefault&amp;quot; src=&amp;quot;images/index/alexthumb.jpg&amp;quot; alt=&amp;quot;I'm on a laptop at night in a field on using the internet via hacking a telephone box...legally.&amp;quot; /&amp;gt;
   &amp;lt;/a&amp;gt; 
 &amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt; 
   &amp;lt;a href=&amp;quot;images/index/trucks.jpg&amp;quot; &amp;gt;
     &amp;lt;img class=&amp;quot;thumbnailDefault&amp;quot; alt=&amp;quot;Trucks lined up in Sodo in Seattle at night.&amp;quot; src=&amp;quot;images/index/trucksthumb.jpg&amp;quot; /&amp;gt;
   &amp;lt;/a&amp;gt; 
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
      &amp;lt;img id=&amp;quot;index_largepic_display&amp;quot; src=&amp;quot;images/index/fernlarge.jpg&amp;quot; alt=&amp;quot;A picture of a fern just as it is unraveling in front of a log.&amp;quot; /&amp;gt; 
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;br /&gt;
&lt;br /&gt;
CSS:
&lt;br /&gt;
&lt;pre name="code" class="css"&gt;
div#gallery {
 position:relative; 
 float: left;
 overflow: hidden;
 width: 65%;
}

img#index_image_display {
 border:1px black solid;
 margin-bottom:20px;
}

ul#index_thumbnail_display {
 list-style-type:none;
 position:absolute; 
 top: 0;
 left: 0;
 margin-top: 15px;
}

ul#index_thumbnail_display li a {
 padding:10px;
}

.thumbnailDefault {border: 1px solid gray !important;}

.thumbnailFocus {border: 1px solid red !important;}

&lt;/pre&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/javascript-image-rotator-viewer.php' title='Javascript image rotator viewer'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2915436468075828096' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2915436468075828096'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2915436468075828096'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-6807877518524652831</id><published>2008-06-12T23:10:00.001-07:00</published><updated>2008-06-12T23:16:23.624-07:00</updated><title type='text'>Saving State: What To Do When Users Leave</title><content type='html'>&lt;p&gt;In this era of rich JavaScript applications, so much
        focus is given to the features of the application that one
        crucial element is often overlooked: What happens when the
        user leaves the page? We take it for granted that pages
        will look the same when we leave and return, but a new
        question merges for sites using rich JavaScript
        interaction: If the user leaves and returns to the page,
        will the application state be preserved?&lt;/p&gt;

        &lt;p&gt;The effects of losing application state can range from
        minor annoyances like losing what page you're on, to
        all-out frustration after losing a carefully-typed message
        because you accidentally triggered the browser's back
        button. (It's easier than you think-- hitting backspace
        when the document is in focus triggers the back button in
        most browsers). Couple this with the fact that some users
        may expect pages to save form data, because of their prior
        experience to that effect, and it becomes apparent that a
        robust strategy for preserving application state must be
        devised.&lt;/p&gt;

        &lt;p&gt;Browsers automatically save data entered into form
        fields, but all JavaScript variables are lost when the user
        leaves the page. Furthermore, any form fields that were
        created by JavaScript will also be lost. So, for all but
        the most simple applications, JavaScript must have a
        strategy for saving state that deals with these
        limitations.&lt;/p&gt;

        &lt;p&gt;Some sites like &lt;a href=
        "http://www.thesixtyone.com"&gt;&lt;em&gt;thesixtyone.com&lt;/em&gt;&lt;/a&gt;
        reside entirely on a single page and capture users' back
        button clicks with named anchors. But, try writing a wall
        post on Facebook and you'll find that it does not save the
        post if you leave the page. Accidentally pressing backspace
        is all too easy in cases like this where typing is
        involved, which is why sites like Gmail and Blogger warn
        users that they will lose data before leaving the page.&lt;/p&gt;

        &lt;h3&gt;How To Warn Users Before Leaving the Page&lt;/h3&gt;

        &lt;p&gt;One way you can do this is by assigning a confirmation
        message to the return value of the
        &lt;em&gt;window.onbeforeunload&lt;/em&gt; event handler. The user will
        be presented with two choices, &lt;em&gt;OK&lt;/em&gt; and
        &lt;em&gt;Cancel&lt;/em&gt;, along with a custom message of your
        choosing.&lt;/p&gt;

        &lt;p&gt;In the following example, we regsiter an anonymous
        function as the event handler for
        &lt;em&gt;window.onbeforeunload&lt;/em&gt;, and add our own custom
        message:&lt;/p&gt;

        &lt;h5&gt;Using &lt;em&gt;window.onbeforeunload&lt;/em&gt; to confirm if a
        user wants to leave the page (&lt;a href=
        "/examples/saving-state/example-1.html"&gt;example 1&lt;/a&gt;)&lt;/h5&gt;
  
&lt;pre name="code" class="js:nocontrols"&gt;
window.onbeforeunload = function() { 
  return "You will lose any unsaved information."; 
};
&lt;/pre&gt;

        &lt;p&gt;The browser displays your custom message, given in the
        return statement of the &lt;em&gt;onbeforeunload&lt;/em&gt; event
        handler, along with the browser default message. In
        Firefox, the result is:&lt;/p&gt;

        &lt;blockquote&gt;
            Are you sure you want to navigate away from this
            page?&lt;br /&gt;
            You will lose any unsaved information.&lt;br /&gt;
            Press OK to continue, or Cancel to stay on the current
            page.
        &lt;/blockquote&gt;

        &lt;h3&gt;Retaining Data When Users Do Leave the Page&lt;/h3&gt;

        &lt;p&gt;You may opt to silently save the user's data when they
        leave the page. This may give a better user experience
        since they are not confronted with a choice, and their data
        is saved automatically.&lt;/p&gt;

        &lt;p&gt;This is one of the times where Ajax comes in handy.
        However, there are also other ways to do this without using
        Ajax, such as cleverly storing information in named anchors
        or hidden form fields. We'll examine each of these
        practices in more depth, but suffice it to say that the
        hidden form fields approach works better for conventional
        websites that are spread across many pages, whereas storing
        data in named anchors is better for single-page, pure
        JavaScript applications.&lt;/p&gt;

        &lt;p&gt;It turns out that while you could (and should) save
        state to the server using Ajax, for some cases you will
        want to avoid Ajax altogether and use a simpler,
        clientside-only model.&lt;/p&gt;

        &lt;h3&gt;Using Hidden Form Fields to Save State&lt;/h3&gt;

        &lt;p&gt;As mentioned, all JavaScript objects are lost when the
        user leaves or refreshes the page. But, browsers will
        retain data in form fields, provided that the form elements
        were not generated using JavaScript. Given this limitation,
        it is necessary to save JavaScript variables (or the
        serialized JSON strings of such objects) to hidden form
        fields if they need to be retained.&lt;/p&gt;

        &lt;p&gt;Here is a basic example showing how variables can be
        stored to hidden form fields and restored on page load:&lt;/p&gt;
&lt;pre name="code" class="html:nocontrols"&gt;
    &lt;input id="saved-data" type="hidden" /&gt;
&lt;/pre&gt;

        &lt;h5&gt;Saving data in hidden form fields (&lt;a href=
        "/examples/saving-state/example-2.html"&gt;example 2&lt;/a&gt;)&lt;/h5&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
// The variable userData is some necessary information we need from the user.
// The first time the user visits the page, they must enter this data manually.
// But, when leaving and returning to the page (or refreshing the page), we'll check
// if they already entered the data, and if so, restore it from a hidden form field.

var userData;

// Register event handlers
window.onload = function() {
 restoreState();
 if (!userData) {
    userData = prompt('Please enter the data to save', 'test');
 }
 document.write("userData: " + userData);
}

window.onbeforeunload = saveState;

// This function is called onbeforeunload and writes the userData to the hidden form field
function saveState() {
   document.getElementById('saved-data').value = userData;
}

// This function is called onload and checks if any data is present in the hidden form field
// If so, it defines userData to be the saved data
function restoreState() {
   var savedData = document.getElementById('saved-data').value;
   if (savedData != "") {
        userData = savedData;
   }               
}

&lt;/pre&gt;

        &lt;p&gt;In the above example, all we're saving is one string
        from the user. But what about cases where we need to save
        many different values? For instance, what if we're using
        object-oriented code and have numerous nested objects
        within objects we need to store? At times like this,
        &lt;strong&gt;serializing objects with JSON&lt;/strong&gt; is the
        easiest way to store the data. Without using JSON, you'd
        have to create a hidden form field for each value you want
        to save, whereas JSON can create string representations of
        complex data structures that you can easily &lt;em&gt;eval&lt;/em&gt;
        back into JavaScript objects once they're fetched from the
        DOM.&lt;/p&gt;

        &lt;h3&gt;So What is JSON, Anyway?&lt;/h3&gt;

        &lt;p&gt;JSON (pronounced "Jason"), short for &lt;em&gt;JavaScript
        Object Notation&lt;/em&gt; is a lightweight, human- and
        machine-readable way to represent the string serializations
        of objects. These strings can be evaluated back into
        JavaScript objects as needed. For instance, say I create a
        JavaScript object to represent a person (in this case,
        me):&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
var person = new Object();
person.name = "Jonah";
person.age = 24;
person.gender = "male";
person.location = "Seattle, WA";
&lt;/pre&gt;

        &lt;p&gt;The JSON representation of this object is as
        follows:&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
{
    'person': {
        'name': 'Jonah',
        'age': 24,
        'gender': 'male',
        'location': 'Seattle, WA'
    }
}
&lt;/pre&gt;

        &lt;p&gt;Then, if you need to reconstruct the object at a later
        point, you can simply eval the JSON string:&lt;/p&gt;
        
&lt;pre name="code" class="js:nocontrols"&gt;
var jsonString = "{'person': {'name': 'Jonah', 'age': 24, 'gender': 'male', 'location': 'Seattle, WA'}}";
var person = eval( '(' + jsonString + ')' );    

console.assert(person.name == 'Jonah');
console.assert(person.age == 24);
console.assert(person.gender == 'male');
console.assert(person.location == 'Seattle, WA');
&lt;/pre&gt;

        &lt;p&gt;If you've written JavaScript using object literal syntax
        before, this should be familiar to you. The only minor
        difference between JSON and the standard JavaScript object
        literal syntax is that JSON requires quotes around key in a
        key/value pair. So, &lt;em&gt;name&lt;/em&gt; is a valid JavaScript key
        but in JSON it would have to be &lt;em&gt;'name'&lt;/em&gt;. (Note: It
        doesn't matter if you use single- or double-quotes, as long
        as they are matched).&lt;/p&gt;

        &lt;h3&gt;Stringifying Objects in JSON&lt;/h3&gt;

        &lt;p&gt;To use JSON, it's necessary to include a library of JSON
        methods. Don't worry, the library is quite small. The
        entire thing shouldn't be more than 2k and can be obtained
        from &lt;a href="http://www.json.org/js.html"&gt;json.org&lt;/a&gt;.
        Eventually, the JSON methods will be included as part of
        the core JavaScript language, but for the time being, we're
        left to use the methods provided by json.org or those found
        in libraries such as MooTools, Prototype and jQuery.&lt;/p&gt;

        &lt;p&gt;Depending on the library used, the method names for
        serializing an object into a JSON string are different.
        But, they are all used in rather similar fashion. For now,
        we'll assume you're using the library from &lt;a href=
        "http://www.json.org/js.html"&gt;json.org&lt;/a&gt; and use the
        method names provided in its API.&lt;/p&gt;

        &lt;h5&gt;Saving complex JavaScript data structures as JSON
        strings (&lt;a href="/examples/saving-state/example-3.html"&gt;example 3&lt;/a&gt;)&lt;/h5&gt;
        
&lt;pre name="code" class="js"&gt;
// The variable userData is some necessary information we need from the user.
// The first time the user visits the page, they must enter this data manually.
// But, when leaving and returning to the page (or refreshing the page), we'll check
// if they already entered the data, and if so, restore it from a hidden form field.

var userData;

// Register event handlers
window.onload = function() {
 restoreState();
 if (!userData) {
    userData = new Object();
    userData.name = prompt('Please enter a name', 'Jonah');
    userData.age = parseInt(prompt('Please enter an age', '24'));
    userData.gender = prompt('Please enter a gender', 'male');
    userData.location = prompt('Please enter a location', 'Seattle, WA');                             
 }
 displayData(userData);
}

window.onbeforeunload = saveState;

// This function is called onbeforeunload and writes the userData to the hidden form field
function saveState() {
   document.getElementById('saved-data').value = JSON.stringify(userData);
}

// This function is called onload and checks if any data is present in the hidden form field
// If so, it defines userData to be the saved data
function restoreState() {
   var savedData = document.getElementById('saved-data').value;
   if (savedData != "") {
        userData = eval( '(' + savedData + ')' );
   }               
}

// This is a helper function that iterates through each property in an object and renders it in HTML.
function displayData(obj) {
 var list = document.createElement('ul');
 for (var property in obj) {
    var text = document.createTextNode(property + ': ' + obj[property])
     var line = document.createElement('li');
     line.appendChild(text);                 
     list.appendChild(line);
 }
 document.getElementsByTagName('body')[0].appendChild(list);
}
&lt;/pre&gt;

        &lt;p&gt;This example is pretty similar to the previous one where
        we saved a string. The only difference is that in this
        case, the string is a representation of a complex
        JavaScript object. In fact, you can save the entire state
        of your application in one JSON string, as long as the
        application state is completely stored as properties of a
        single object. There are a few minor gotchas, such as
        having to add parentheses around the JSON string when
        evaluating it. But, overall this is a clean and
        straightforward approach that is very useful when complex
        data structures must be retained.&lt;/p&gt;

        &lt;h3&gt;Using Named Anchors to Save State&lt;/h3&gt;

        &lt;p&gt;An alternate option for retaining state is to not
        actually let the user leave the page at all. Rather, when
        following links on the site, update the named anchor
        (everything after the number sign in a URL), instead of
        changing the actual document being displayed.&lt;/p&gt;

        &lt;p&gt;The problem that this is trying to solve is the fact
        that Ajax applications will normally break the back button.
        A user loads the application on the homepage and clicks to
        visit a different page, but since the new page is loaded in
        via Ajax, the browser URL doesn't change. Then the user
        clicks the back button and leaves the application
        altogether-- not the intention of the user, who just wanted
        to get back to the homepage.&lt;/p&gt;

        &lt;p&gt;Storing data in named anchors offers a solution to this
        problem. Each time the application state changes,
        JavaScript updates the named anchor with a token
        representing the application state. When the page is
        loaded, data is read from the named anchors and the state
        can be restored.&lt;/p&gt;

        &lt;p&gt;Say you're on the homepage of an ecommerce Ajax
        application and click on a product you'd like to view.
        Instead of changing URLs to the detail page, the
        application loads in new data with Ajax. So, when a user
        clicks on the new Brad Mehldau CD for instance, instead of
        going to a different URL (yoursite.com/brad-mehldau/) the
        document URL remains the same, but JavaScript updates the
        named anchor: yoursite.com/#brad-mehldau.&lt;/p&gt;

        &lt;p&gt;One site which does this unbelievably well is &lt;a href=
        "http://www.thesixtyone.com"&gt;&lt;em&gt;thesixtyone.com&lt;/em&gt;&lt;/a&gt;
        (Thanks, Derek!). The entire site resides in one document,
        truly a rich JavaScript application if I've ever seen one.
        But, despite the fact that the entire application is
        contained in a single document URL, due to clever use of
        named anchors, the site has full back button support and
        you can even email working links to friends.&lt;/p&gt;

        &lt;p&gt;Implementing code to save state in named anchors is out
        of scope for this article, but you can see how it is
        somewhat similar to saving data in hidden form fields. In
        this case, there are a few more issues to mitigate and it's
        somewhat tricky, but the reward is an Ajax site with fully
        functional back button support and the ability to share
        links -- worth all the effort, in my book.&lt;/p&gt;

        &lt;h3&gt;So What Use is Ajax, Then?&lt;/h3&gt;

        &lt;p&gt;Since we've made it this far, you might think that there
        is no use for Ajax in all this. Actually, Ajax is great for
        saving state to the server, especially for saving data
        beyond the lifespan of the browser session. Ajax can be
        used to save messages periodically (like how Gmail and
        Google Docs automatically save on a timer every few
        minutes). It can also be used to send data when the user
        leaves the page by capturing the &lt;em&gt;onbeforeunload&lt;/em&gt;
        event, but this is unreliable and I would not depend on
        this Ajax request to complete. Instead, try to save the
        data before the user attempts to leave the page, by either
        firing the Ajax request on a timer or another event on the
        page (leaving focus on a form element, for example).&lt;/p&gt;

        &lt;p&gt;Some frameworks like Prototype have serialize() methods
        that return URL query string representations of objects.
        This is perfect for saving data through GET requests. Yes,
        GET requests have a 2000-character limit and other
        limitations, but in most cases this won't be an issue. Even
        without helper methods to serialize objects, it's a fairly
        simple matter to construct an Ajax request that will save
        the necessary data to the server.&lt;/p&gt;

        &lt;h3&gt;Wrapping Up&lt;/h3&gt;

        &lt;p&gt;To re-cap, it is a good practice to check if users are
        sure they want to leave a page when they are entering
        information, but it's even better to silently save that
        information for them. (Arguably you would want to do both,
        like how Gmail and Blogger save state &lt;em&gt;and&lt;/em&gt; ask
        users if they are sure they want to leave the page). There
        are many different ways to save state, some purely
        client-side and others relying on saving data to the server
        with Ajax. The solutions which save data to the server are
        suitable for times when the data needs to be saved beyond
        the browsing session.&lt;/p&gt;

        &lt;p&gt;Of the two client-side solutions explored, hidden form
        fields and named anchors, the former is more suitable for
        conventional websites spanning many pages while the latter
        better suits single-page Ajax applications. Using named
        anchors also has the added benefit of allowing users to
        bookmark and send links to the JavaScript application in
        various states, and the state is preserved beyond the
        browsing session.&lt;/p&gt;

        &lt;p&gt;Whatever strategy you follow, your users will thank you
        for the time saved and frustration avoided of having to
        re-enter lost information.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/saving-state-what-to-do-when-users.php' title='Saving State: What To Do When Users Leave'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=6807877518524652831' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6807877518524652831'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6807877518524652831'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-5279328249574658398</id><published>2008-06-12T08:52:00.000-07:00</published><updated>2008-06-12T08:55:20.268-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><title type='text'>Stylize the last element in jQuery</title><content type='html'>Here is how to stylize the border of the last element using jQuery.

&lt;pre class="code" name="js"&gt;
$(document).ready(function() {
    $("table.innercart tr:last").css("border", "none");
});
&lt;/pre&gt;

You can compare to prototype by going &lt;a href="http://www.thetruetribe.com/2008/06/stylize-last-element-in-prototype.php"&gt;here&lt;/a&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/stylize-last-element-in-jquery.php' title='Stylize the last element in jQuery'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=5279328249574658398' title='1 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5279328249574658398'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5279328249574658398'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1629601160656236426</id><published>2008-06-12T08:47:00.000-07:00</published><updated>2008-06-12T08:56:11.815-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>Stylize the last element in prototype</title><content type='html'>Here is an example of removing the last border in a list of elements.

&lt;pre class="code" name="js"&gt;
Event.observe(window, "load", function() {
    $$(".homepageContainer .upcomingEvents").last().setStyle({
        border: 0
    });
});
&lt;/pre&gt;

You can compare to jQuery by going &lt;a href="http://www.thetruetribe.com/2008/06/stylize-last-element-in-jquery.php"&gt;here&lt;/a&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/stylize-last-element-in-prototype.php' title='Stylize the last element in prototype'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1629601160656236426' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1629601160656236426'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1629601160656236426'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3897582473336321273</id><published>2008-06-07T22:36:00.001-07:00</published><updated>2008-06-09T18:31:15.506-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>AJAX Google API to Minify Javascript using Ruby on Rails</title><content type='html'>&lt;p&gt;How to &lt;span style="font-weight: bold;"&gt;optimizing JavaScript performance&lt;/span&gt; in Ruby on Rails. This will only focus on one aspect of JS performance optimization, namely, writing a build script to concatenate/minify the JS, and setting up Rails to easily toggle between the compressed and normal files. Also, if your site uses a JavaScript library, we'll explore including it from Google's &lt;a href="http://code.google.com/apis/ajaxlibs/"&gt;AJAX Libraries API&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;The reason to do these optimizations are for client-side performance. Concatenating many files together into one is especially effective: 10 1-kilobyte files are much slower to download than a single 10k file. You might not think it makes much of a difference, but I estimate that removing 10 additional JS files, for instance, will shave 500-1000ms off latency. Plus, all of the time spent loading the JS will leave the page blank, if you put it in the head.&lt;/p&gt;
&lt;p&gt;We'll need to be able to easily toggle between fully commented code and minified code, both for code hosted by us and code from the Google AJAX Libraries API. Since Google offers both minified and normal versions of the code, this should be no problem.&lt;/p&gt;
&lt;h3&gt;Including JavaScript in Ruby on Rails&lt;/h3&gt;
&lt;p&gt;First of all, let's look at how JavaScript is included in Ruby on Rails, the &lt;span style="font-family:Courier New;"&gt;javascript_include_tag&lt;/span&gt; method. The method quite simply takes any number of source URLs and returns an HTML script tag for each of the sources provided. For instance:
&lt;/p&gt;&lt;pre class="code" name="ruby"&gt;  javascript_include_tag("script1.js", "script2.js", "script3.js")
&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Result:&lt;/b&gt;
&lt;/p&gt;
&lt;p style="font-family: Courier,monospace;"&gt;
    &amp;lt;script type="text/javascript" src="/javascripts/script1.js"&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;script type="text/javascript" src="/javascripts/script2.js"&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;script type="text/javascript" src="/javascripts/script3.js"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/p&gt;
&lt;p&gt;There's a little bit of magic you can do which is to include all JavaScript files in the /public/javascripts folder automatically, as well as having them concatenated into a single file. It looks like this:
&lt;/p&gt;
&lt;pre class="code" name="ruby"&gt;  javascript_include_tag :all, :cache =&gt; true # when ActionController::Base.perform_caching is true&lt;/pre&gt;
&lt;p&gt;The resulting code is:&lt;/p&gt;
&lt;p style="font-family: Courier,monospace;"&gt;&amp;lt;script type="text/javascript" src="/javascripts/all.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;If you don't want them concatenated into a single file, e.g. for development purposes, you could do something like this:&lt;/p&gt;
&lt;pre class="code" name="ruby"&gt;
# config/environments.rb:
DEBUG_JS = false;

# environments/development.rb:
DEBUG_JS = true;

# app/views/layouts/site.html.erb or wherever you include the JavaScript in your site:
&lt;%=   javascript_include_tag(:all, :cache =&gt; true) if DEBUG_JS == false || ENV["RAILS_ENV"] != "development"
 javascript_include_tag(:all) if DEBUG_JS == true &amp;amp;&amp;amp; ENV["RAILS_ENV"] == "development"
%&gt;
&lt;/pre&gt;
&lt;p&gt;I'm not sure how to integrate JSMin, YUICompressor or any other minification into the cached file, though, so I will explore the options for manual building and inclusion next.&lt;/p&gt;
&lt;p&gt;Something else to remember is that caching needs ActionController::Base.perform_caching to be true in order to work. This is the default in production, but not development, though of course you can override it in your &lt;span style="font-family:Courier New;"&gt;environments/development.rb file.&lt;/span&gt; For more information, view the &lt;a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#M001024"&gt;docs for the javascript_include_tag&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;JavaScript Concatenation and Minification&lt;/h3&gt;
&lt;p&gt;Next, we'll write a custom build script to generate a concatenated, minified version of our files. Ideally, Rails would automatically run it through a minifier, but I'm not sure how to set that up. In the meantime, this is a working solution that is pretty straightforward and requires minimal effort. I wish I were more skilled at shell scripting (and I highly urge readers to contribute their own code), but I'll show my implementation as an example regardless.&lt;/p&gt;
&lt;p&gt;I'm on a Windows machine and wrote it as a batch file (.bat), but you can easily do this on linux, just using pipe (the | character) instead of the two right-angle brackets (&amp;gt;&amp;gt;). Here goes:&lt;/p&gt;
&lt;pre&gt;
java -jar yuicompressor-2.3.5.jar "script1.js" -o main.js
java -jar yuicompressor-2.3.5.jar "script2.js" &gt;&gt; main.js
java -jar yuicompressor-2.3.5.jar "script3.js" &gt;&gt; main.js
java -jar yuicompressor-2.3.5.jar "script4.js" &gt;&gt; main.js
&lt;/pre&gt;
&lt;p&gt;Nothing too sophisticated, just a straightforward script that generates main.js using the YUICompressor. To use it, simply run the batch file in the same folder as the JavaScripts and yuicompressor-2.3.5.jar. It will output a main.js file. I chose to run it separately for each individual file so if there are any errors, you can see where they occurred. If you concatenate all of the files into one and then compress it, debugging is difficult as the line number which threw the error is unknown.&lt;/p&gt;&lt;p&gt;I chose to use YUICompressor over JSMin since it seems to have better error messaging, warnings, and be a bit more strict. One of my former colleagues did some tests that determined that JSMin was faster in terms of using less CPU than YUICompressor (and certainly for minifiers which use eval(), such as Dean Edwards' packer). Unfortunately, I can't remember the specifics of the test or which platforms it was on, so that data is pretty much worthless. In any case, I decided on YUICompressor but you can use JSMin or whichever minifier you prefer.&lt;/p&gt;
&lt;p&gt;If you are going to use YUICompressor, &lt;b&gt;you must have Java installed&lt;/b&gt; and included in your path. If it isn't in your path, you can use the full path to Java, for instance, &lt;span style="font-family:Courier New;"&gt;"C:\Program Files\Java\bin\java.exe" -jar [filename] [options].&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;&lt;span style="font-family:Courier New;"&gt;Using the Google AJAX Libraries&lt;/span&gt;&lt;/h3&gt;&lt;span style="font-family:Courier New;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://code.google.com/apis/ajaxlibs/"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/google-ajax-api-735798.png" alt="" border="0" /&gt;&lt;/a&gt;
&lt;/span&gt;&lt;p&gt;Depending on your opinion about Google's recent offer to host the world's JavaScript frameworks with its &lt;a href="http://code.google.com/apis/ajaxlibs/"&gt;AJAX Libraries API&lt;/a&gt;, you may not find this suggestion too useful, but I think it's helpful, especially to those without access to their hosting provider's response header settings, to present here. Without going into too much detail, suffice it to say that besides the caching benefit of using Google's API, their servers are configured "correctly" for best performance (far future expires headers, Gzip, etc).&lt;/p&gt;&lt;p&gt;One thing, though, is that you will want to include a minified version of the JavaScript in production and a full version in development, to ease debugging. It's impossible to debug minified JavaScript (don't even try), so we have to set a toggle like in the above example. Say your site is including jQuery. You may want to include a minified version on the live server but read the full code locally.&lt;/p&gt;&lt;h3&gt;Toggling Minified Google JS&lt;/h3&gt;&lt;p&gt;Here's how you can include minified jQuery in the production Ruby on Rails code while including the full jQuery library, comments and all, in development:&lt;/p&gt;
&lt;pre class="code" name="ruby"&gt;
&lt;%=   
javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js",
                                            :all, :cache =&gt; true) if DEBUG_JS == false || ENV["RAILS_ENV"] != "development"

 javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js",
                                          :all) if DEBUG_JS == true &amp;&amp; ENV["RAILS_ENV"] == "development"
%&gt;
&lt;/pre&gt;&lt;&lt;p&gt;Or, if you didn't want to include everything in the JS folder, and wanted to granularly include only specific files, you might rewrite it like so:&lt;/p&gt;&lt;pre class="code" name="ruby"&gt;
&lt;%= if DEBUG_JS == false || ENV["RAILS_ENV"] != "development"
   javascript_include_tag ("http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js",
                                            "main.js)
    elsif DEBUG_JS == true &amp;amp;&amp;amp; ENV["RAILS_ENV"] == "development"
    javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js",
                                            "script1.js",
                                            "script2.js",
                                            "script3.js",
                                            "script4.js")
 end %&gt;
&lt;/pre&gt;&lt;p&gt;That's all there is to it! Just switch the DEBUG_JS flag when you want to test in development mode with/without compression, and don't worry about when it's in production since it will always serve up the minified, concatenated JavaScript. The logic ensures that you won't accidentally start serving up the separate files in production, while giving you the flexibility to store your JavaScript in as many files as you like without negative consequences on the front end, as well as reading fully-commented code./p&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/fun-with-ruby-on-rails-and-google-ajax.php' title='AJAX Google API to Minify Javascript using Ruby on Rails'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3897582473336321273' title='4 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3897582473336321273'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3897582473336321273'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3595554248052194129</id><published>2008-06-02T23:33:00.000-07:00</published><updated>2008-06-03T00:07:40.640-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><title type='text'>XAMPP All-in-one Web Development Stack</title><content type='html'>&lt;p style="float: left; margin-right: 8px;"&gt;&lt;img title="XAMPP" src="http://www.apachefriends.org/images/1240.jpg" border="0" /&gt;&lt;/p&gt;&lt;p&gt;
It's time consuming setting up web development environments and any seasoned developer will have most likely spent &lt;span style="font-weight:bold;"&gt;countless hours debugging&lt;/span&gt; obscure configuration issues. Also, with the plethora of options available, some newer developers can have a hard time locating and choosing what to install.
&lt;/p&gt;&lt;p&gt;It turns out that most dynamic websites use a fairly common setup known as &lt;a href="http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29"&gt;LAMP&lt;/a&gt;, short for Linux, Apache, MySQL and PHP/Perl.&lt;/p&gt;
&lt;p&gt;With this in mind, the developers at Apache Friends have released XAMPP, the X being an operating system of your choice. It comes with Apache, MySQL, PHP and Perl (along with a grab-bag of other goodies), and you can choose the package built for your OS.&lt;/p&gt;
&lt;p&gt;Although I'm a sometime Ubuntu user, my current development environment is primarily on a Vista laptop. I grabbed the &lt;a href="http://www.apachefriends.org/en/xampp-windows.html"&gt;Windows XAMPP package&lt;/a&gt; and was amazed at how easy the "no-config" install was.&lt;/p&gt;    &lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;img title="WIZARD" src="http://www.apachefriends.org/images/1159.jpg" border="0" /&gt;&lt;/p&gt;&lt;p&gt;It includes:

&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Apache_%28web_server%29"&gt;Apache&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/MySQL"&gt;MySQL&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/PHP"&gt;PHP&lt;/a&gt; + &lt;a href="http://en.wikipedia.org/wiki/PEAR"&gt;PEAR&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Perl"&gt;Perl&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/OpenSSL"&gt;OpenSSL&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/PhpMyAdmin"&gt;phpMyAdmin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Webalizer"&gt;Webalizer&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Mercury Mail Transport System&lt;/li&gt;&lt;li&gt;Ming&lt;/li&gt;&lt;li&gt;JpGraph&lt;/li&gt;&lt;li&gt;FileZilla FTP Server&lt;/li&gt;&lt;li&gt;mcrypt&lt;/li&gt;&lt;li&gt;eAccelerator&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/SQLite"&gt;SQLite&lt;/a&gt;, and
&lt;/li&gt;&lt;li&gt;WEB-DAV + mod_auth_mysql.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Whew!  They threw in everything and the kitchen sink. But, luckily the &lt;span style="font-weight:bold;"&gt;installation is painless &lt;/span&gt;and you don't have to worry about the stuff you might not use, plus it's nice to know it's there if you need it. phpMyAdmin makes managing the database a breeze and above all, everything &lt;span style="font-style: italic;"&gt;just works&lt;/span&gt;.
&lt;/p&gt;&lt;p&gt;
After downloading and installing the package to C:\xampp (they recommend against placing it in Program Files on Vista due to file permissions issues), I took it for a spin by visiting http://localhost in my browser. The user is presented with a handy control panel, with links pointing to all of the various parts of the XAMPP bundle.
&lt;/p&gt;&lt;p&gt;
Note: I chose to run Apache and MySQL as services, meaning they will always start when the computer boots up, but you may choose to run them as standalone programs if you don't use them much. If you didn't choose to install it as a service and are not getting a response from http://localhost, make sure you're running Apache and MySQL.
You can control which parts of XAMPP are running under Start / Programs / XAMPP. This is where you can start/stop servers as well as toggle them as services.
&lt;p&gt;&lt;img title="CONTROLPANEL" src="http://www.apachefriends.org/images/1161.jpg" border="0" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;i&gt;The XAMPP control panel for start/stop Apache, MySQL, FilaZilla &amp;amp; Mercury&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;
Assuming everything is working correctly, visiting http://localhost should result in the following screen:&lt;/p&gt;

&lt;p&gt;&lt;img title="xamppbrowser" src="http://www.apachefriends.org/images/1213.jpg" border="0" /&gt;&lt;/p&gt;&lt;p&gt;
If you need more options, such as Java/JSP support or Python, check out the add-ons available:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Perl Addon with Mod_Perl and a selection important Perl Modules  &lt;/li&gt;&lt;li&gt;Tomcat Addon (Requirement: SUN J2SE SDK must already be installed)  &lt;/li&gt;&lt;li&gt;Cocoon for Tomcat Addon (Requirement: Tomcat Addon must already be installed)  &lt;/li&gt;&lt;li&gt;Python Addon &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;
&lt;p&gt;A final note: This is for &lt;span style="font-weight:bold;"&gt;development purposes only&lt;/span&gt;, so it has absolutely no security. Don't even think about using this set up in a live environment. You've been warned. Don't believe me? Here's the list of security holes:
&lt;/p&gt;&lt;p&gt;
Here a &lt;a href="http://www.apachefriends.org/en/xampp-windows.html#644"&gt;list of missing security precautions&lt;/a&gt; in XAMPP:
&lt;/p&gt;&lt;p&gt;
   * The MySQL administrator (root) has no password. &lt;br /&gt;
   * The MySQL daemon is accessible via network. &lt;br /&gt;
   * PhpMyAdmin is accessible via network. &lt;br /&gt;
   * Examples are accessible via network. &lt;br /&gt;
   * The user of Mercury and FileZilla are known.
&lt;/p&gt;&lt;p&gt;
Even in development, it's a good idea to &lt;span style="font-weight:bold;"&gt;set passwords&lt;/span&gt; and disable unused services. You can do so by changing the settings at http://localhost/security in a web browser.
&lt;/p&gt;&lt;p&gt;
For more info on XAMPP, visit the site the FAQ:
&lt;/p&gt;&lt;p&gt;
&lt;a href="http://www.apachefriends.org/en/faq-xampp-windows.html" target="_new"&gt;&lt;img src="http://www.apachefriends.org/en/img/link.gif" border="0" /&gt; http://www.apachefriends.org/en/faq-xampp-windows.html&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
Or the forum:&lt;/p&gt;&lt;p&gt;
&lt;a href="http://www.apachefriends.org/f/" target="_new"&gt;&lt;img src="http://www.apachefriends.org/en/img/link.gif" border="0" /&gt; http://www.apachefriends.org/f/&lt;/a&gt;
&lt;/p&gt;Happy XAMPPin'!</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/06/xampp-all-in-one-web-development-stack.php' title='XAMPP All-in-one Web Development Stack'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3595554248052194129' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3595554248052194129'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3595554248052194129'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1883456577685987465</id><published>2008-05-31T11:24:00.000-07:00</published><updated>2008-06-03T15:29:39.474-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='accessibility'/><category scheme='http://www.blogger.com/atom/ns#' term='graceful degradation'/><category scheme='http://www.blogger.com/atom/ns#' term='information architecture'/><title type='text'>Information Architecture Graceful Degradation Accessibility Case Studies</title><content type='html'>Based on the following website case studies, here are rules for planning graceful degradation into the architecture of a website:




&lt;span&gt; 1. Use forms, scrollbars, and other features that do not rely on javascript to display content.&lt;/span&gt;


&lt;span&gt; 2. When content is hidden using JS-dependent components (such as tabs) figure out how to design websites to display all this content without breaking surrounding widgets and components.&lt;/span&gt;


&lt;span&gt; 3. Hide javascript-dependent functionality from javascript disabled users.&lt;/span&gt;


&lt;span&gt; 4. Make sure all displayed links (anchors) or buttons do something, like go to new page or scroll to specific content for users who don't have javascript.&lt;/span&gt;


&lt;span&gt; 5. Build new pages that display content that otherwise would only be seen by JS users. Then you can use normal anchors to reach those pages. You can have unobstructive javascript that has event listeners on those links for sexy ajaxy functionality that users with JS can experience.&lt;/span&gt;




&lt;span style="font-weight: bold;font-size:130%;" &gt;
&lt;a href="http://www.blogger.com/"&gt;Blogger.com&lt;/a&gt;&lt;/span&gt;


Right now I'm drafting this article in Blogger.com without javascript. A few things immediately drew my attention that are confusing or do not work. Sure I can type in a textbox; that is no surprise. Here are some things don't work:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/blogger-778944.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/blogger-778940.jpg" alt="" border="0" /&gt;&lt;/a&gt;
1. The shortcuts (shown at the bottom) for ctrl + B for bold or ctrl + P for publish do not work at all. They should have hidden these.

2. Post Options link that is normally a drop down menu for JS users does nothing at all- a dead anchor.

&lt;span style="font-weight: bold;"&gt;3. The top has an area called "Enclosures" with a URL input box and a MIME Type input box. I have no idea what these do.&lt;/span&gt;

Although I can still post, many of the features that are designed for JS users still show up and should be hidden or graceful degrade to a new page showing opinions and so forth. I'm turning JS back on to finish writing this article!




&lt;span style="font-weight: bold;font-size:130%;" &gt;
&lt;a href="http://www.siff.net/"&gt;Seattle International Film Festival&lt;/a&gt;

&lt;/span&gt;
&lt;div style="text-align: left;"&gt;At my company &lt;a href="http://www.pop.us/"&gt;Pop Inc&lt;/a&gt; we care a lot about graceful degradation. We recently remade the SIFF website. I hadn't checked it out without JS before so lets take it for a spin.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/siffwo-755601.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/siffwo-755583.jpg" alt="" border="0" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;span style="font-weight: bold;"&gt;I actually liked it more with javascript disabled.&lt;/span&gt; It loaded faster (without those JS scripts) and all the content was displayed on the page and not hidden in tabs and drop downs. I guess what to take from this website in the means of graceful degradation is designing the site ahead of time to be scalable to show all content without intruding on other components on the page.












&lt;a href="http://www.ford.com/"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Ford&lt;/span&gt;&lt;/a&gt;


About a year ago Ford's website displayed blank without javascript enabled. Since then they have stepped up and made a pretty nice graceful degraded homepage. &lt;span style="font-weight: bold;"&gt;They have honed in on a great tool to display content with minimal real estate: The scroll bar.&lt;/span&gt; While tabs, drop downs, carousels, accordions, and sliders all rely on javascript, the scrollbar works in any scenario as a way to show hidden information on the page.
Ford has taken advantage of a horizontal scrollbar to display different featured cars. Horizontal scrolling is a means that is not often utilized, but is nonetheless intriguing.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/fordwo-716348.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/fordwo-716316.jpg" alt="" border="0" /&gt;&lt;/a&gt;
&lt;a href="http://kexp.org/streamarchive/streamarchive.asp"&gt;&lt;span style="font-size:130%;"&gt;

&lt;span style="font-weight: bold;"&gt;KEXP&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;

KEXP is a Paul Allen/Publically owned radio station in Seattle. It is the source for indie rock music, as well as other speciality music shows. They have a pretty badass website featuring streaming archived radio shows of the past two weeks. You can listen live broadcasts anywhere in the world. &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/kexp-732980.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/kexp-732977.jpg" alt="" border="0" /&gt;&lt;/a&gt;
Their live stream gracefully degrades as it is an anchor to a .pla file that can be opened in your favorite streaming music client. But their archived "On Demand Radio" feature is completely broken for non-javascript users. &lt;span style="font-weight: bold;"&gt;Nothing is more maddening than to click a link or button and have nothing happen. &lt;/span&gt;That is exactly the case for KEXP's archived radio "go" button. It relies on a javascript intrusive function. Sadly, the "go" button's A tag's hyper reference reads  "javascript:selectArchive('program');".
This problem can be easily rectified by rewriting it as form  with the "go"action being a input submit button. This solution works up until you reach the archive player page, the final step before listening to music. This is where a small popup comes up with a Windows Media or Real&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/kexpPlayer-753997.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/kexpPlayer-753994.jpg" alt="" border="0" /&gt;&lt;/a&gt; Audio player that allows you listen but not download the radio broadcast. There may be legal reasons why this cannot be a downloadable file. If this is the case KEXP should notify their users with some sort of message detailing why you must have javascript enabled to use the archive player.














&lt;a href="http://www.aol.com/"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;AOL&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/aolImage-768907.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/aolImage-768894.jpg" alt="" border="0" /&gt;&lt;/a&gt;
AOL did it right with their news story switcher on their homepage. With javascript allows cycling through the latest news without a page refresh. What a nice user experience! If javascript is disabled the right and left arrows on the switcher does exactly the same action except with an additional page refresh. &lt;span style="font-weight: bold;"&gt;In other words, each news item has it's own page viewable to any user.&lt;/span&gt;






&lt;a href="http://www.igoogle.com/"&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;iGoogle&lt;/span&gt;&lt;/a&gt;


We all know that Google's products rely heavily on javascript. Without javascript their maps will&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/google-738854.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/google-738848.jpg" alt="" border="0" /&gt;&lt;/a&gt; not display and their web browser email client won't send mail. But even simple things like the calendar and date/time widgets on iGoogle.com are completely broken and blank. &lt;span style="font-weight: bold;"&gt;To a user who is not web savvy, this may be confusing to why the calendar is not loading while it says it is.&lt;/span&gt; Like blogger.com's issues, Google needs to hide functionality that is javascript-dependent for javascript disabled users or inform the user why it isn't showing.</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/information-architecture-graceful.php' title='Information Architecture Graceful Degradation Accessibility Case Studies'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1883456577685987465'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1883456577685987465'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-5294571296807548776</id><published>2008-05-27T23:44:00.001-07:00</published><updated>2008-05-27T23:50:52.877-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='accessability'/><category scheme='http://www.blogger.com/atom/ns#' term='sprites'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>What is Bad About CSS Sprites?</title><content type='html'>CSS Sprites have changed the way we think about website performance efficiency, but we should not be using them on every graphic and here is why:

1. &lt;span style="font-weight: bold;"&gt;Accessibility&lt;/span&gt;    How are you going to set alt tags to background images? You can't! Screen reader users will hate you if you use background images for all your graphics just to save some seconds on page load. Being hated is bad.

2. &lt;span style="font-weight: bold;"&gt;Printing&lt;/span&gt;     Core graphics should not be CSS Sprites because background images are not shown when printing.

In short, CSS Sprites are great for banners, rounded corners, drop shadows, certain icons, and certain buttons. But be careful how you use them. They should not be used everywhere.</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/what-is-bad-about-css-sprites.php' title='What is Bad About CSS Sprites?'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=5294571296807548776' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5294571296807548776'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5294571296807548776'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2157333727698337712</id><published>2008-05-25T14:41:00.000-07:00</published><updated>2008-05-27T13:56:55.743-07:00</updated><title type='text'>Conducting Technical Interviews for Web Developers</title><content type='html'>&lt;p&gt;Presumably most readers of this blog will have been through a technical interview, and I'm betting that some of them have to give technical interviews as well. The purpose of this article is to go over some of the points to consider while conducting the interview, as well as suggestions for coming up with good questions to ask.&lt;/p&gt;

&lt;p&gt;The first thing to understand as an interviewer is the requirements of the job position and what competencies a candidate must possess to be a good fit. If the job is for back-end development, then experience working with databases, performance tuning, and writing scalable code is crucial, and only a cursory understanding of HTML and CSS is required. Alternately, for UI development work, it isn't necessary to have a candidate who is wrapped up in the back-end code or has Big O notation at the tip of their tongue. There are certainly jacks-of-all-trades but when interviewing, it's better to &lt;span style="font-weight: bold;"&gt;focus on a few crucial areas&lt;/span&gt; than try to set high standards for all areas across the board.&lt;/p&gt;

&lt;p&gt;These are some of the areas you may want to explore, depending on the requirements of the position:&lt;/p&gt;

&lt;h3&gt;Software Development Skills&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Proficiency in at least one high-level programming language: C++, Java&lt;/li&gt;
&lt;li&gt;Basic understanding of object-oriented design &amp;amp; analysis: classes/inheritance, interface vs implementation, encapsulation&lt;/li&gt;
&lt;li&gt;Experience with source code version control: SVN, CVS, P4&lt;/li&gt;
&lt;li&gt;Algorithms: binary search, quicksort&lt;/li&gt;
&lt;li&gt;Data structures: array, hash, linked list&lt;/li&gt;
&lt;li&gt;Complexity/performance analysis: Big O notation, performance testing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Web Development Skills&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Candidate tests web-deployed code in big 3 browsers: IE6+, Firefox 2+, Safari 2+&lt;/li&gt;
&lt;li&gt;Candidate uses browser-specific debugging tools: IE Web Developer Toolbar, Script Debugger/Script Editor (IE), Firebug (Firefox), WebKit/Drosera (Safari)&lt;/li&gt;
&lt;li&gt;Extensive knowledge of at least one JS framework: jQuery, Prototype, MooTools, YUI&lt;/li&gt;
&lt;li&gt;Experience creating dynamic, database-driven websites: PHP/JSP/ASP, MySQL etc&lt;/li&gt;
&lt;li&gt;Candidate uses Selenium for front-end automated testing&lt;/li&gt;
&lt;li&gt;Proficient in Fireworks or other image editing software, and knowledgeable about how to best export images for the web (CSS sprites, GIF/JPG/PNG, etc)&lt;/li&gt;
&lt;li&gt;Follows front-end best practices like CSS-based layouts and unobtrusive JavaScript&lt;/li&gt;
&lt;li&gt;Experience developing rich user interfaces (drag-and-drop, Ajax, web applications/RIAs, animation effects)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;General and Miscellaneous Skills&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Familiarity with agile development methodology: scrum, burndown charts&lt;/li&gt;
&lt;li&gt;Proficiency at Search Engine Optimization (SEO), Search Engine Marketing (SEM), and related fields&lt;/li&gt;
&lt;li&gt;Knowledgeable about security vulnerabilities in code. Experience with threat analysis software (e.g. Fortify for Java)&lt;/li&gt;
&lt;li&gt;Familiarity with automated unit/integration tests: JUnit (Java), Selenium (front end)&lt;/li&gt;
&lt;li&gt;DBA-related skills such as database optimization&lt;/li&gt;
&lt;li&gt;Usability skills and knowledge of user behavior&lt;/li&gt;
&lt;li&gt;Project management skills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can choose from these or other criteria to create a baseline for what makes an ideal candidate, ignoring the skills which aren't relevant. Once you've determined the skills necessary for the position, you may find that a Ph.D. is less qualified than someone without a college degree, depending on the skills required. So, never make assumptions about candidates simply based on their credentials or previous work experience. Developers can take drastically different amounts of time to complete tasks based on their prior experience and their ability to learn new things quickly.&lt;/p&gt;

&lt;h3&gt;Criteria for Various Job Positions&lt;/h3&gt;
&lt;p&gt;Let's look at a few example job positions and apply criteria from the list above.&lt;/p&gt;
&lt;h4&gt;Quality Assurance Engineer&lt;/h4&gt;
&lt;p&gt;An ideal QA engineer for a website will be an expert at creating automated test suites for front and back end, and should also be aware of security issues. So you could focus the interview on how they choose to write test suites, and come up with sample test suites for real-life objects (e.g. an elevator). Then you could ask them to list some of the common security threats (e.g. &lt;a href="http://en.wikipedia.org/wiki/Cross-site_scripting"&gt;XSS&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;XSRF&lt;/a&gt;) and how to mitigate them.&lt;/p&gt;&lt;p&gt;Of course, if you already have a security engineer at your company, then you may not require your QA to wear another hat. But for most small- to medium-sized businesses, it's most efficient and cost effective for your developers to wear many hats. In fact, you may have a software developer who also does QA on the site, or a QA engineer who does project management. It all depends on the size of your company and the particular restraints in budget for your development team.&lt;/p&gt;
&lt;h4&gt;Software Developer / Programmer&lt;/h4&gt;
&lt;p&gt;Let me say right off the bat that I've never conducted a software development interview. But, I have been through a few, and I have an idea of what types of questions I would ask depending on the position.&lt;/p&gt;
&lt;p&gt;There are some general software development skills that I would consider, such as experience with SVN (or other source control), automated testing, knowledge of data structures and algorithms, and perhaps object oriented design and analysis.&lt;/p&gt;
&lt;p&gt;If the candidate is a Java developer, then you can ask about things like exception handling, reflection, familiarity with libraries (Swing, Struts, JSF etc), or other Java-specific questions. If they are a C++ developer then you should drill down into memory management, constructors/destructors, and other tropes of C++. It's up to you as the interviewer to determine the right questions to ask based on the job requirements, or to find someone else to conduct the interview if you can't. I know I would have a hard time conducting an interview with a C++ developer, unless I had a "cheatsheet" with all the correct answers to the questions.&lt;/p&gt;
&lt;h4&gt;Web Developer&lt;/h4&gt;
&lt;p&gt;For a web development position, the focus will be less on knowledge of traditional computer science and more on the candidate's knowledge of current best practices. Since best practices are always changing, the ideal web developer is enthusiastic and passionate about their field, and stays up to date by reading/contributing to blogs, belonging to email lists or other online communities and generally &lt;span style="font-weight: bold;"&gt;keeping "in the know" about the best way to solve problems&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Unlike traditional computer programming, in which code is executed in a controlled environment and changes to the language take years to complete, web development is a fast-paced field where changes happen all the time and code is executed in a wide range of environments, each with its own caveats and bugs. So, the ideal web developer is familiar with the issues surrounding development on each platform and environment, especially the Big 3 browsers (IE, Firefox and Safari).&lt;/p&gt;

&lt;h3&gt;Interview Coding Challenges&lt;/h3&gt;
&lt;p&gt;A great way to test a developer is to actually have them write some code for you. As they say, "the proof is in the pudding," and even a developer who successfully answers your questions may not be able to complete the test put forth. The test can be verbal (if conducting the interview by phone), on a whiteboard (if in person) or you can give the candidate a time limit and have them email you the code. The choice is yours, just make sure that you choose one modality for all candidates. It isn't fair comparing one candidate's typed code to what another said on the phone, or drew on a whiteboard. Also remember that generally &lt;span style="font-weight: bold;"&gt;typed code will be higher quality&lt;/span&gt; than that spoken over the phone or written on a whiteboard.&lt;/p&gt;

&lt;p&gt;I've posted a few JavaScript challenges on this blog that would make good interview questions for a JS developer. You could also adapt some of these to other languages such as C++, PHP or Java:&lt;/p&gt;
&lt;ul&gt;
 &lt;li&gt;&lt;a href="http://www.thetruetribe.com/2008/05/javascript-challenge-reverse-linked.html"&gt;Reverse a Linked List&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thetruetribe.com/2008/05/javascript-challenge-dispense-change.html"&gt;Dispense Change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.thetruetribe.com/2008/04/javascript-challenge-cardinal-numbers.html%20"&gt;Cardinal Numbers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other challenges include reversing a string, reversing the words in a string, finding words that occur in both files, converting a clock from digital time to degrees (e.g. for an analog clock's hands), or generally any other relatively simple test you can come up with.&lt;/p&gt;

&lt;h3&gt;Layouts and HTML/CSS&lt;/h3&gt;
&lt;p&gt;For candidates doing CSS, just send them a mock-up and give them a reasonable amount of time to complete the HTML/CSS for it. You could optionally send a PSD or layered PNG, but more commonly people just send flat images. Really, the test shouldn't be much -- maybe the wireframe for a site, or a navbar, menu or UI component. You can also give them some challenge questions about explaining various CSS properties and how to use them. Challenges I've had in the past are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make a banner and horizontal navbar that matches the dimensions of a wireframe&lt;/li&gt;
&lt;li&gt;Make a 3-column site with a fluid-width center column&lt;/li&gt;
&lt;li&gt;Create a vertical drop-down menu or horizontal flyout menu (bonus points for a cross-browser CSS-only solution, though JavaScript solutions are accepted)&lt;/li&gt;
&lt;li&gt;Explain the difference between absolute and relative positioning, and what happens when you put one type of element inside another&lt;/li&gt;
&lt;li&gt;Explain the difference in block and inline display&lt;/li&gt;
&lt;li&gt;Explain what effect float has on elements. Does float change elements' display property, and if so, does it make it block or inline? (Answer: block)&lt;/li&gt;
&lt;li&gt;Explain what effect z-index has on elements and the natural z-index order.&lt;/li&gt;
&lt;li&gt;Explain CSS specificity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On this last point, CSS specificity, I find it's fun to show a list of CSS rules and ask which rule wins out. If you know the trick how rules are calculated, it's easy to tell:&lt;/p&gt;

&lt;pre name="code" class="html:nocontrols"&gt;
&lt;!-- Sample HTML code --&gt;
&amp;lt;!-- Sample HTML code --&amp;gt;
&amp;lt;p class="description" id="main"&amp;gt;
&amp;nbsp; Some text.
&amp;nbsp; &amp;lt;span class="special"&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Some more text.
&amp;nbsp; &amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;pre name="code" class="css"&gt;
/* Challenge:
 * What color is the "special" text? */

body .description span {
   color: blue;
}

p.description {
   color: red;
}

body .description .special {
   color: pink;
}

#main .special {
   color: orange;
}

#main span {
   color: green;
}
&lt;/pre&gt;
&lt;p&gt;For those of you unfamiliar with how CSS specificity is calculated by browsers, it is a point-based system where the selector with the highest point value wins. The three main things selectors consist of are elements, classes and ids. These are worth 1 point, 10 points and 100 points respectively. Given this knowledge, do &lt;span style="font-style:italic;"&gt;you&lt;/span&gt; know which rule wins out in the above example?&lt;/p&gt;
&lt;p&gt;By calculating the point values of the rules, you see that the rule &lt;span style="font-style:italic;"&gt;#main .special&lt;/span&gt; is worth 110 points and is the winner, hence the color of the &amp;quot;special&amp;quot; text is &lt;span style="font-style:italic;"&gt;orange&lt;/span&gt;.
&lt;h3&gt;Hiring People who Write Good Code&lt;/h3&gt;
&lt;p&gt;Besides "just working", the criteria for what makes good code differs from person to person, but in general, you'll want to look for readability, useful comments, simplicity, accuracy, good formatting and code that doesn't repeat itself. So, even if two candidates submit working solutions to a problem, you can still determine which is the better candidate by analyzing the code itself with these criteria in mind.&lt;/p&gt;

&lt;p&gt;In addition to this, you may consider their talent, as opposed to their current skill in any one area. If the candidate is highly talented and passionate about the position, then they will most likely be able to learn any particular skills required for the position, within reason. Of course, talented individuals should demonstrate expertise in a number of domains already, which will give you an idea of their potential for growth in job-specific areas. You may also consider their participation in online forums, discussion groups and blogs (like this one, wink wink) related to their job field. Active participation in online communities demonstrates dedication and passion for those particular fields of interest.&lt;/p&gt;
&lt;p&gt;I hope this article has been informative for interviewers and perhaps interviewees as well. Feel free to post your favorite (or least favorite) interview questions.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/conducting-technical-interviews-for-web.php' title='Conducting Technical Interviews for Web Developers'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2157333727698337712' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2157333727698337712'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2157333727698337712'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-4140425707371882540</id><published>2008-05-20T17:24:00.000-07:00</published><updated>2008-05-21T12:41:05.872-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='firebug'/><title type='text'>Inspecting Javascript with Firebug</title><content type='html'>1. Go to &lt;a href="http://www.alexgrande.com/breakable/"&gt;http://www.alexgrande.com/breakable/&lt;/a&gt; and add the link to your bookmarks.
&lt;br /&gt;
&lt;img src="http://www.alexgrande.com/breakable/01.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;



2. Go to the page you are interested in inspecting and click on the bookmark in your browser called "Inspect JS". That will load breakable.js into the head of the page you are currently using.
&lt;br /&gt;

&lt;img src="http://www.alexgrande.com/breakable/02.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;



3. In firebug go into the scripts tab and view breakable.js.
&lt;br /&gt;


4. Set a break point on line 7 where it says funct();
&lt;br /&gt;

&lt;img src="http://www.alexgrande.com/breakable/03.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;



5. Find out what the ID is of the element that has the event listener.
&lt;br /&gt;

&lt;img src="http://www.alexgrande.com/breakable/04.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;



6. Click the console tab in firebug. Type in: breakOn("elementID", "eventTrigger");
Example: breakOn("prettyImageOver", "onmouseover"); Example 2: breakOn("ajaxImageChanger","onclick");
&lt;br /&gt;



&lt;img src="http://www.alexgrande.com/breakable/05.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;


7. (1)Initialize the event by mousing over it or whatever you you chose as the event trigger. If the original js author chose a mouse over event then you should also use a mouse over event. Because if you choose an onclick for an onmouseover event then by the time you click it the event has already passed you by..
&lt;br /&gt;


8. (2)Firebug will transfer over to the breakable.js in the scripts tab at the breakpoint funct(). Step into it by (3)clicking the arrow right in firebug script section.
&lt;br /&gt;
&lt;img src="http://www.alexgrande.com/breakable/06.jpg" /&gt;

&lt;br /&gt;&lt;br /&gt;


9. and you will enter into the javascript code of whatever function is called by the event.
&lt;br /&gt;

&lt;img src="http://www.alexgrande.com/breakable/07.jpg" /&gt;
&lt;br /&gt;&lt;br /&gt;




I love this! Big thanks to my friend Grady Morgan for writing this short script!</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/inspecting-javascript-with-firebug.php' title='Inspecting Javascript with Firebug'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=4140425707371882540' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4140425707371882540'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4140425707371882540'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7786018402121992842</id><published>2008-05-17T14:58:00.000-07:00</published><updated>2008-05-20T15:55:58.775-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><category scheme='http://www.blogger.com/atom/ns#' term='chaining'/><title type='text'>The Group Class in MooTools</title><content type='html'>&lt;p&gt;The MooTools Group class is for grouping a collection of objects and calling a function when all of those objects have fired a particular event. For instance, you could group an array of Element objects and fire an event when all of them have been clicked. Or, you could group a collection of Ajax request objects and fire an event when all have completed. (Both of these examples are straight from the &lt;a href="http://docs12b.mootools.net/Plugins/Group"&gt;MooTools 1.2 Beta docs for Plugins/Group&lt;/a&gt;).&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://docs12b.mootools.net/Plugins/Group"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/mootools-group-class-720828.jpg" alt="" border="0" /&gt;&lt;/a&gt;
&lt;p&gt;How is this useful? Well, it's a convenience for when events depend on each others' completion but occur asynchronously, either by Ajax or through use of timers. Let's look at an example of how to handle dependent events without grouping first, to see where there is room for improvement:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
// Flags to keep track of the request status
var firstRequestIsComplete = false;
var secondRequestIsComplete = false;

window.addEvent('domready', function() {
   var firstRequest = new Request({
       url: 'example-1.html',
       onSuccess: function() {
           firstRequestIsComplete = true;           
           if (secondRequestIsComplete) {
               console.log('Both requests are complete.');
           }
       }       
   }).send(); // Fire it
      
   var secondRequest = new Request({
       url: 'example-1.html',
       onSuccess: function() {
           secondRequestIsComplete = true;           
           if (firstRequestIsComplete) {
               console.log('Both requests are complete.');
           }
       }       
   }).send(); // Fire it   
});
&lt;/pre&gt;
&lt;p&gt;Obviously, this isn't a stellar solution. Having to keep track of which Ajax requests have already fired using flags is a hassle, and this example only uses two requests. Say you had 10 different requests and you wanted to fire an event once all of them had completed. You'd need to &lt;b&gt;store flags for which request had fired&lt;/b&gt; and which hadn't, perhaps in a hash table, and write a function that checks if all of the requests had fired or not. Then, for the &lt;i&gt;onSuccess&lt;/i&gt; event handler of each request, you'd need to set a condition that calls the function to check if all had succeeded, and performs your desired action if so (in the above example, logging to the console).&lt;/p&gt;
&lt;p&gt;What a hassle! All of this checking and logic duplicated in each request; there must be a better way.&lt;/p&gt;
&lt;h3&gt;Grouping Ajax Requests in MooTools&lt;/h3&gt;
&lt;div style="float: right; font-size: 10px; width: 166px; margin-left: 18px; margin-bottom: 4px;"&gt;    &lt;span class="photo_container pc_m"&gt;&lt;a href="http://www.flickr.com/photos/nickwheeleroz/2166114756/" title="Ajax"&gt;&lt;img src="http://farm3.static.flickr.com/2069/2166114756_1358c1a1f4_m.jpg" alt="Ajax" class="pc_img" height="240" width="166" /&gt;&lt;/a&gt;                Ajax by &lt;a href="http://www.flickr.com/photos/nickwheeleroz/"&gt;nickwheeleroz&lt;/a&gt;   &lt;/span&gt; &lt;/div&gt;&lt;p&gt;As it turns out, &lt;b&gt;there is a better way&lt;/b&gt;, thanks to MooTools. Let's see how this code is cleaned up by the use of grouping with MooTools' Group class:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
window.addEvent('domready', function() {   
   var firstRequest = new Request({url: 'example-1.html'});
   var secondRequest = new Request({url: 'example-1.html'});           

   var ajaxRequests = new Group(firstRequest, secondRequest);
   ajaxRequests.addEvent('onSuccess', function() {
       console.log('Both requests are complete.');
   });
  
   // Fire requests
   firstRequest.send();
   secondRequest.send();
});
&lt;/pre&gt;
&lt;p&gt;All right! Now we've removed the duplicate logging code and &lt;i&gt;onSuccess&lt;/i&gt; events, which were previously declared in two places. This code has the exact same effect as the previous implementation, but we're following the "write once" principle.&lt;/p&gt;
&lt;p&gt;You could make it &lt;b&gt;even more concise using chaining&lt;/b&gt;, if that's your thing:
&lt;/p&gt;&lt;pre name="code" class="js"&gt;
window.addEvent('domready', function() {   
   new Group(new Request({url: 'example-1.html'}),
                       new Request({url: 'example-1.html'}))
       .addEvent('onSuccess', function() {
           console.log('Both requests are complete.');
       }).instances.each(function(instance) {
           instance.send();
       });
});
&lt;/pre&gt;
&lt;p&gt;To me, the chaining isn't necessary here and iterating over the instances array stored in the group object probably isn't the best idea, since it's exposing the inner workings of the class by direct reference, rather than through the API. So, this example is only shown for the purposes of demonstrating how you can chain functions with MooTools, if you so desire.&lt;/p&gt;
&lt;h3&gt;Caveats and Gotchas with MooTools Groups&lt;/h3&gt;
&lt;p&gt;
There are a few crucial gotchas that will hang you up if you aren't aware of them. First, the API documentation for MooTools 1.2beta is not accurate. It may be accurate for 1.1, but it certainly isn't for 1.2. They show an example of grouping using the Ajax class which was renamed Request in MooTools 1.2. The docs call the &lt;i&gt;request()&lt;/i&gt; method to initiate an Ajax request but in actuality, it is the &lt;i&gt;send()&lt;/i&gt; method. Can you spot any other inaccuracies in the example provided by the docs?&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
// From http://docs12b.mootools.net/Plugins/Group
//
// NOTE: This code will not work for MooTools 1.2.
// Shown for educational purposes only.

var xhr1 = new Ajax('data.js', {evalScript: true});
var xhr2 = new Ajax('abstraction.js', {evalScript: true});
var xhr3 = new Ajax('template.js', {evalScript: true});

var group = new Group(xhr1, xhr2, xhr3);
group.addEvent('complete', function(){
   alert('All Scripts loaded');
});

xhr1.request();
xhr2.request();
xhr3.request();
&lt;/pre&gt;
&lt;p&gt;
A few other problems with the example: It shows the &lt;i&gt;onComplete&lt;/i&gt; event instead of &lt;i&gt;onSuccess&lt;/i&gt;, and the arguments passed to the Ajax constructor are incorrect as well. Finally, it shows the event to monitor without the 'on-' prefix. Given the plethora of inaccuracies in the docs, I believe these nuances warrant further discussion. Let's look at each of these in turn.&lt;/p&gt;
&lt;p&gt;The &lt;b&gt;Ajax class was renamed to Request &lt;/b&gt;in MooTools 1.2 and the API was significantly overhauled. Instead of calling &lt;i&gt;request()&lt;/i&gt; to initiate the request, now you must &lt;i&gt;send()&lt;/i&gt; it. Now, the constructor takes an &lt;i&gt;options&lt;/i&gt; object which has properties for all of the arguments, such as &lt;i&gt;url&lt;/i&gt;. In the example given, the URL is passed as the first argument, but in the current code you provide it as a property of the options object instead:
&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
// This code demonstrates the differences in how to make
// Ajax requests between MooTools 1.1 and MooTools 1.2:

// Old way
new Ajax('path/to/your/data', {
   // options go here
}).request(); // fire the request

// New way
new Request({
   url: 'path/to/your/data'
   // options go here
}).send(); // fire the request
&lt;/pre&gt;
&lt;p&gt;
As you can see, the URL is passed in via a property of the &lt;i&gt;options&lt;/i&gt; object, rather than as the first argument of the constructor. I prefer this, as the MooTools API has been made much more consistent in 1.2 with most classes simply taking an &lt;i&gt;options&lt;/i&gt; object, rather than a variety of parameters.&lt;/p&gt;
&lt;p&gt;Another problem with the example provided in the docs is that it shows the &lt;i&gt;onComplete&lt;/i&gt; event when this has been changed to &lt;i&gt;onSuccess&lt;/i&gt;.  And, to make matters worse, the docs exclude the 'on-' prefix in their example. Compare the right and wrong ways to monitor group events in MooTools 1.2:&lt;/p&gt;
&lt;pre name="code" class="javascript:nocontrols"&gt;
// Wrong way (as shown in docs)
group.addEvent('complete', function(){
   alert('All Scripts loaded');
});

// Right way
group.addEvent('onSuccess', function(){
   alert('All Scripts loaded');
});
&lt;/pre&gt;
&lt;p&gt;This is kind of odd, I'll admit, and inconsistent with the &lt;i&gt;addEvent()&lt;/i&gt; API. Usually, you register events without the 'on-' prefix. But, for some reason, when you monitor an event in the group, &lt;b&gt;you must use the 'on-' prefix&lt;/b&gt;. I discovered this after 20 minutes fruitlessly searching the web and stepping through my code, so hopefully this gem of information will save others that same trouble.&lt;/p&gt;

&lt;h3&gt;Testing MooTools Ajax Locally&lt;/h3&gt;
&lt;p&gt;Something crucial to be aware of when testing these examples is that
you &lt;b&gt;must serve the response to the Ajax request from a web server.&lt;/b&gt; If you access the page through the file:// protocol instead of http:// protocol, certain headers will not be present and MooTools won't fire the &lt;i&gt;onSuccess&lt;/i&gt; event.&lt;/p&gt;
&lt;p&gt;There's actually a funny story about this: At my old job, there was a contest to build an Ajax widget using various JavaScript frameworks. The MooTools team got hung up because they were testing through the file:// protocol (without a web server, just by opening the file directly with a web browser) and the Ajax requests were never firing their &lt;i&gt;onComplete&lt;/i&gt; event handlers (this was back in MooTools 1.1 where it was called &lt;i&gt;onComplete&lt;/i&gt; instead of &lt;i&gt;onSuccess&lt;/i&gt;). Well, what's funny about it is that the Ajax request would fire &lt;i&gt;onFailure&lt;/i&gt;, but it called the event handler with the Ajax response! The team building the widget actually got it working fine but it was "failing" every time-- the Ajax callback function was registered to the &lt;i&gt;onFailure&lt;/i&gt; event.&lt;/p&gt;
&lt;p&gt;So, the moral of the story is, try to avoid hacky workaround like this and serve up the Ajax responses &lt;b&gt;the right way, through a web server&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Besides Ajax, what are some other uses of groups you can think of? Post your ideas in the comments and they may become the basis of future articles.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/group-class-in-mootools.php' title='The Group Class in MooTools'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7786018402121992842' title='2 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786018402121992842'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786018402121992842'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2246659514431597256</id><published>2008-05-16T14:06:00.000-07:00</published><updated>2008-05-16T21:11:44.508-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><title type='text'>MooTools mouseenter and mouseleave Events For Dropdowns</title><content type='html'>&lt;p&gt;One of the frustrations many coders have encountered when creating JavaScript flyout menus is the fact that &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt; events &lt;span style="font-weight:bold;"&gt;fire when entering children elements&lt;/span&gt;. This is usually not the desired effect when creating popup, dropdown or flyout menus.&lt;/p&gt;
&lt;img style="float: right; margin-left: 18px; margin-bottom: 4px;" src="http://docs12b.mootools.net/assets/images/mootools.png" alt="MooTools" /&gt;
&lt;p&gt;MooTools offers its own &lt;span style="font-style:italic;"&gt;mouseenter&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;mouseleave&lt;/span&gt; events which alleviate the problem of the events firing when entering child elements, but before diving into that, let's explore why it's such a problem in the first place.&lt;/p&gt;

&lt;p&gt;At first thought, it would seem that you want &lt;span style="font-style:italic;"&gt;onmouseout &lt;/span&gt;to fire when leaving the element, right? Well, generally that's only the case when you're mousing off a flyout menu, for instance. But when you're staying inside the flyout menu and mousing over one of the child elements, you don't want the &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt; event to fire, since it will have an event handler registered to close the flyout.&lt;/p&gt;

Take, for example, this simple flyout menu. Shown here is the barebones HTML for the menu:

&lt;pre name="code" class="html:nocontrols"&gt;
&lt;ul class="flyout-main"&gt;
    &lt;li&gt;Level 1
        &lt;ul class="flyout-sub"&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;Level 1
        &lt;ul class="flyout-sub"&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li&gt;Level 1
        &lt;ul class="flyout-sub"&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
            &lt;li&gt;Level 2&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
&lt;/ul&gt;
&lt;/pre&gt;
&lt;p&gt;This results in a list with 3 top-level headings, each containing 1-3 sub headings. Each sub-heading is represented as a &lt;span style="font-style:italic;"&gt;ul&lt;/span&gt; element with class &lt;span style="font-style:italic;"&gt;flyout-sub&lt;/span&gt;, and will be hidden using CSS and only visible when the user mouses over its respective top level heading. Here's the CSS:&lt;/p&gt;
&lt;pre name="code" class="css:nocontrols"&gt;
ul.flyout-sub {
    display: none;
}
li.active ul.flyout-sub {
    display: block;
}
&lt;/pre&gt;
&lt;p&gt;Pretty simple stuff. We just hide the second level by default and show it if it has a parent &lt;span style="font-style:italic;"&gt;li&lt;/span&gt; with class &lt;span style="font-style:italic;"&gt;active&lt;/span&gt;. So, &lt;span style="font-weight:bold;"&gt;it's up to the JavaScript&lt;/span&gt; to toggle the &lt;span style="font-style:italic;"&gt;active&lt;/span&gt; class.
&lt;p&gt;Here is the JavaScript. Note the use of oldschool JavaScript event registration using the core DOM events &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt;.&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
window.addEvent('domready', function() {
    $$('ul.flyout-main &gt; li').each(function(li) {
        li.onmouseover = function() {
            li.addClass('active');
        }
        li.onmouseout = function() {
            li.removeClass('active');
        }
    });
});
&lt;/pre&gt;
&lt;p&gt;If you test this code, you'll see that it doesn't have the desired effect: The &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt; events fire when entering child elements so you're unable to mouse over the sub menu without closing it. A simple change to MooTools &lt;span style="font-style:italic;"&gt;mouseenter&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;mouseleave&lt;/span&gt; events (which only fire when entering/exiting from the parent) solves this problem nicely:&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
window.addEvent('domready', function() {
    $$('ul.flyout-main &gt; li').each(function(li) {
        li.addEvent('mouseenter', function() {
            li.addClass('active');
        });
        li.addEvent('mouseleave', function() {
            li.removeClass('active');
        });
    });
});
&lt;/pre&gt;
&lt;p&gt;Before I knew about MooTools' &lt;span style="font-style:italic;"&gt;mouseenter&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;mouseleave&lt;/span&gt; events, I devised a few workarounds to this using &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt;. One such solution was to have the event handler function check to see if the &lt;span style="font-style:italic;"&gt;targetElement&lt;/span&gt; of the event object was a child of the flyout menu. But, whichever solution I devised, it was sub-optimal and involved additional logic for something that should be free in a programming language. Now, thanks to MooTools, it is-- providing you include the MooTools library, of course.&lt;/p&gt;
&lt;p&gt;Armed with this knowledge of how &lt;span style="font-style:italic;"&gt;mouseenter&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;mouseleave&lt;/span&gt; differ from the conventional &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; events, you now have another powerful time-saving tool for making dynamic web interfaces. Instead of mitigating annoying issues with the limited set of core JavaScript events, you can focus on what you want the code to do, not how you want to do it.&lt;/p&gt;
&lt;p&gt;For more information, visit the &lt;a href="http://docs12b.mootools.net/Element/Element.Event#"&gt;MooTools 1.2 beta docs for Element.Event&lt;/a&gt;.&lt;/p&gt;</content><link rel='alternate' type='text/html' href='http://www.thetruetribe.com/2008/05/mootools-mouseenter-and-mouseleave.php' title='MooTools mouseenter and mouseleave Events For Dropdowns'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2246659514431597256' title='0 Comments'/><link rel='replies' type='application/atom+xml' href='http://www.thetruetribe.com/atom.xml' title='Post Comments'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2246659514431597256'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2246659514431597256'/><author><name>Jonah Dempcy</name><uri>http://www.blogger.com/profile/02468258890873289795</uri><email>noreply@blogger.com</email></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7481335608401888897</id><published>2008-05-14T02:27:00.000-07:00</published><updated>2008-05-15T17:25:43.302-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='challenge'/><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><title type='text'>JavaScript Challenge: Reverse a Linked List</title><content type='html'>&lt;p&gt;This article is a follow-up on my previous post on &lt;a href="http://www.thetruetribe.com/2008/05/linkedlist-class-in-mootools.html"&gt;writing a linked list class in MooTools&lt;/a&gt;. In that post, I offered an implementation of a singly-linked list in JavaScript and gave a challenge: To reverse a linked list in place, starting with only a reference to the head. The challenge also forbade the use of storing the data externally -- that is to say, you can't just iterate over the linked list and stuff the items in a new array, then reverse the array.&lt;/p&gt;

&lt;p&gt;As promised, &lt;span style="font-weight:bold;"&gt;here is my solution&lt;/span&gt; to the challenge. If you are planning on trying the challenge yourself, read no further.&lt;/p&gt;

&lt;p&gt;I've included the code for defining the LinkedList and LinkedListItem classes as well. It's separate from my solution, so if you want to give it a try yourself, go ahead and copy the code below.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
var LinkedList = new Class({

    // Input: Array collection
    // An array of items to turn into a singly linked list
    
    initialize: function(collection) {

        this.collection = new Array();
                   
        // Construct the linked list
        collection.each(function(item, i) {
            var item = new LinkedListItem(item);
            this.collection.push(item);
            
            if (i &gt; 0) {
                this.collection[i - 1].setNext(item);
            }
        }.bind(this));
        
        this.setFirst(this.collection[0]);
    },
    
    // Input: LinkedListItem item
    // Sets the head to be the given item
        
    setFirst: function(item) {
        this.head = item;
    },
        
    // Returns: LinkedListItem head
    
    getFirst: function() {
        return this.head;
    },
    
    // Returns: Array result
    // An array with all items' values, in the order they are linked
    
    getAll: function() {
       var result = new Array();
       
       result.push(this.getFirst().getValue());
       
       var item = this.getFirst().getNext();
       while (item) {
           result.push(item.getValue());
           item = item.getNext();
       }
       
       return result;
    }
});

// This class defines an individual item in the linked list.
// The value it is instantiated with is stored in the value property,
// and is accessible via getter/setter methods.

var LinkedListItem = new Class({
    initialize: function(item) {
        this.value = item;
    },
    
    getNext: function() {
        return this.next;
    },
    
    setNext: function(item) {
        this.next = item;
    },
    
    getValue: function() {
        return this.value;
    }
});

&lt;/pre&gt;

&lt;p&gt;For an in-depth discussion of this code including step-by-step commentary, check out the previous article, &lt;a href="http://www.thetruetribe.com/2008/05/linkedlist-class-in-mootools.html"&gt;LinkedList Class in MooTools&lt;/a&gt;.

&lt;h3&gt;Reverse a Linked List: Solution&lt;/h3&gt;

&lt;p&gt;This is what I came up with:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
window.addEvent('domready', function() {

    var list = new LinkedList(['a', 'b', 'c', 'd', 'e', 
                               'f', 'g', '1', '2', '3', 
                               '4', '5']);

    // Challenge: Reverse the linked list in place (list.collection) 
    //            without using another array

    // Input: LinkedList list

    function reverseLinkedList(list) {

        // Inputs: LinkedListItem item, LinkedListItem next
        //
        // Returns true if next item exists
        // If not, sets the head to be the existing item
        
        function checkForNextItem(item, next) {
            if (!$defined(next)) {
                list.setFirst(item);
                return false;
            } else {
                return true;
            }
        }
        
        // Our new tail is the old head
        var tail = list.getFirst(); // 0

        var itemOne = tail.getNext(); // 1

        // If there is only one element in the list, return it
        if (!$defined(itemOne)) {
            return list;
        }
        
        // Remove the old link from the tail
        tail.setNext(null);                      

       // Prepare third item variable for while() loop
        var itemThree = tail;
        
        // The while() loop will stop when the checkForNextItem() 
        // function fails to find a next item and calls 
        // list.setFirst() on the final existing item.
        
        while (list.getFirst() == tail) {
            
            itemTwo = itemOne.getNext(); // 2
            itemOne.setNext(itemThree); // link 1 to 0            
            if (!checkForNextItem(itemOne, itemTwo)) break;
                              
            itemThree = itemTwo.getNext(); // 3            
            itemTwo.setNext(itemOne); // link 2 to 1
            if (!checkForNextItem(itemTwo, itemThree)) break;
            
            itemOne = itemThree.getNext(); // 4
            itemThree.setNext(itemTwo); // link 3 to 2
            checkForNextItem(itemThree, itemOne);                       
            
        }
        
        return list.getAll();  
    }
    
    console.log('Forward: ' + list.getAll()); 
    console.log('Backward: ' + reverseLinkedList(list));
    
    // RESULT:
    //
    // Forward: a,b,c,d,e,f,g,1,2,3,4,5
    // Backward: 5,4,3,2,1,g,f,e,d,c,b,a    
});
&lt;/pre&gt;
&lt;p&gt;The main part of the function that does the work of reversing the linked list is the &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop. I use a helper method, &lt;span style="font-style:italic;"&gt;checkForNextItem()&lt;/span&gt;, which is declared at the top.&lt;/p&gt;&lt;p&gt;You'll notice I declared the function inside the &lt;span style="font-style:italic;"&gt;reverseLinkedList()&lt;/span&gt; function. The reason I did this is that &lt;span style="font-style:italic;"&gt;checkForNextItem()&lt;/span&gt; is a private method that shouldn't be accessible to code outside of the scope of the &lt;span style="font-style:italic;"&gt;reverseLinkedList()&lt;/span&gt; function. Just like declaring local variables when you don't need a global, you can declare private methods inside the scope of the function block. It's perfect for helper methods like this and it doesn't clutter the global namespace.&lt;/p&gt;
&lt;p&gt;To explain what the &lt;span style="font-style:italic;"&gt;checkForNextItem()&lt;/span&gt; actually does, let's examine the &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop where it's used.&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
        while (list.getFirst() == tail) {
            itemTwo = itemOne.getNext();
            itemOne.setNext(itemThree);         
            if (!checkForNextItem(itemOne, itemTwo)) break;
                              
            itemThree = itemTwo.getNext();           
            itemTwo.setNext(itemOne);
            if (!checkForNextItem(itemTwo, itemThree)) break;
            
            itemOne = itemThree.getNext();
            itemThree.setNext(itemTwo);
            checkForNextItem(itemThree, itemOne);                              
        }
&lt;/pre&gt;
&lt;p&gt;The &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop continues until list.getFirst() no longer returns the tail (the old head). At that point, the loop knows to finish because the &lt;span style="font-style:italic;"&gt;checkForNextItem()&lt;/span&gt; method, unable to find a next item, will set the head to be the final remaining item in the list. Thus, the old tail becomes the new head and the linked list is reversed.&lt;/p&gt;

&lt;p&gt;The only other area of the code which warrants discussion is the check if there is only one item in the list, and calling &lt;span style="font-style:italic;"&gt;setNext(null)&lt;/span&gt; on the new tail (the former head):&lt;/p&gt;

&lt;pre name="code" class="js:nocontrols"&gt;
        // Our new tail is the old head
        var tail = list.getFirst(); // 0

        var itemOne = tail.getNext(); // 1

        // If there is only one element in the list, return it
        if (!$defined(itemOne)) {
            return list;
        }
        
        // Remove the old link from the tail
        tail.setNext(null);        
&lt;/pre&gt;
&lt;p&gt;The check to make sure itemOne is defined is simply a fail-safe for linked lists with only one item. In that case, &lt;span style="font-style:italic;"&gt;tail.getNext()&lt;/span&gt; will be undefined so we just return the list as it is, with only one item. Originally I wrote the check using the JavaScript &lt;span style="font-style:italic;"&gt;typeof&lt;/span&gt; keyword (i.e. &lt;span style="font-style:italic;"&gt;if (typeof itemOne == 'undefined')&lt;/span&gt;), but then I remembered to use MooTools' nifty &lt;span style="font-style:italic;"&gt;$defined()&lt;/span&gt; method which is both more succinct and easier to read (in my opinion).&lt;/p&gt;
&lt;p&gt;Besides the check for single-item lists, I also had to &lt;span style="font-weight:bold;"&gt;&lt;/span&gt;remove the old link from the tail (formerly the head). If you don't remove the link, the while() loop will never end, since the tail will link to the next-to-last item which links back to the tail, forever and ever. So that's why I call &lt;span style="font-style:italic;"&gt;tail.setNext(null)&lt;/span&gt; there.&lt;/p&gt;
&lt;h3&gt;Refactoring the Code&lt;/h3&gt;
&lt;p&gt;After writing this, something just didn't feel right about the &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop. It was messy and seemed to be doing the same thing 3 times. I remembered back to the first time I solved this challenge and recalled a more elegant solution. After changing the code, I ended up with this:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
window.addEvent('domready', function() {
    var list = new LinkedList(['a', 'b', 'c', 'd', 'e', 
                               'f', 'g', '1', '2', '3', 
                               '4', '5']);


    // Input: LinkedList list
    // Returns: LinkedList list (reversed)

    function reverseLinkedList(list) {

        // Our new tail is the old head
        var current = list.getFirst(); // 0

        // If there is only one element in the list, return it
        if (!$defined(current.getNext())) {
            return list;
        }
                
        var previous = null;
        var next;       
        
        while (current != null) {
            next = current.getNext();
            current.setNext(previous);
            previous = current;
            current = next;        
        }
        list.setFirst(previous);
        
        return list;  
    }
    console.log('Forward: ' + list.getAll()); 
    console.log('Backward: ' + reverseLinkedList(list).getAll());
    
    // RESULT:
    //
    // Forward: a,b,c,d,e,f,g,1,2,3,4,5
    // Backward: 5,4,3,2,1,g,f,e,d,c,b,a    
});
&lt;/pre&gt;
&lt;p&gt;