<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6069745790539221961</id><updated>2011-07-20T12:43:31.098-07:00</updated><category term='linux'/><category term='apache'/><category term='mootools'/><category term='challenge'/><category term='information architecture'/><category term='javascript'/><category term='mysql'/><category term='tabs'/><category term='php'/><category term='cookies'/><category term='ajax'/><category term='menus'/><category term='firebug'/><category term='chaining'/><category term='events'/><category term='validation'/><category term='seo'/><category term='string'/><category term='firefox'/><category term='jquery'/><category term='ruby on rails'/><category term='accessibility'/><category term='css'/><category term='js'/><category term='graceful degradation'/><category term='cms'/><category term='browser'/><category term='HTML'/><category term='cross-browser'/><category term='accessability'/><category term='forms'/><category term='sprites'/><category term='prototype'/><category term='google'/><title type='text'>The True Tribe</title><subtitle type='html'>Web development, standards and best practices.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>41</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-6988429905326426303</id><published>2008-07-14T16:14:00.001-07:00</published><updated>2008-09-01T17:44:47.240-07:00</updated><title type='text'>The True Tribe Redesign Coming Soon</title><content type='html'>As you may have noticed, The True Tribe has been on a bit of a hiatus for articles over the past couple of weeks. This is because we have been devoting all of our effort into developing an entirely new site, built with Joomla rather than our current implementation on Blogger's platform.&lt;br&gt;&lt;br&gt;The new site will be more than just a web development blog-- it aims to provide resources such as articles, tutorials/walkthroughs, messageboards and community features.&lt;br&gt;&lt;br&gt;After much deliberation, we decided on Joomla as the framework for the back end. We will be using MooTools for the front end.&lt;br&gt;&lt;br&gt;Right now we are finalizing design, and simultaneously setting everything up in the back end. I estimate the new site will launch in August or September. In the meantime, check out our backlog of existing articles or peruse some of the links in the sidebar.&lt;br&gt;&lt;br&gt;Thanks for reading!&lt;br&gt;-Jonah&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-6988429905326426303?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/6988429905326426303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=6988429905326426303' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6988429905326426303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6988429905326426303'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/07/true-tribe-redesign-coming-soon.html' title='The True Tribe Redesign Coming Soon'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8380558187685501842</id><published>2008-06-18T01:43:00.000-07:00</published><updated>2008-09-01T17:44:54.405-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8380558187685501842?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8380558187685501842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8380558187685501842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8380558187685501842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8380558187685501842'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/installing-synergy-for-linux-and.html' title='Installing Synergy For Linux and Windows'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1905240291549601033</id><published>2008-06-17T00:50:00.001-07:00</published><updated>2008-09-01T17:45:11.254-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1905240291549601033?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/1905240291549601033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1905240291549601033' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1905240291549601033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1905240291549601033'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/whats-new-in-mootools-12.html' title='What&apos;s New in MooTools 1.2'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2915436468075828096</id><published>2008-06-15T23:01:00.001-07:00</published><updated>2008-09-01T17:45:16.882-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-2915436468075828096?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/2915436468075828096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2915436468075828096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2915436468075828096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2915436468075828096'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/javascript-image-rotator-viewer.html' title='Javascript image rotator viewer'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-6807877518524652831</id><published>2008-06-12T23:10:00.001-07:00</published><updated>2008-09-01T17:45:24.911-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-6807877518524652831?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/6807877518524652831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=6807877518524652831' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6807877518524652831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6807877518524652831'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/saving-state-what-to-do-when-users.html' title='Saving State: What To Do When Users Leave'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-5279328249574658398</id><published>2008-06-12T08:52:00.000-07:00</published><updated>2008-09-01T17:45:32.894-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-5279328249574658398?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/5279328249574658398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=5279328249574658398' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5279328249574658398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5279328249574658398'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/stylize-last-element-in-jquery.html' title='Stylize the last element in jQuery'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1629601160656236426</id><published>2008-06-12T08:47:00.000-07:00</published><updated>2008-09-01T17:45:39.626-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1629601160656236426?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/1629601160656236426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1629601160656236426' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1629601160656236426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1629601160656236426'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/stylize-last-element-in-prototype.html' title='Stylize the last element in prototype'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3897582473336321273</id><published>2008-06-07T22:36:00.001-07:00</published><updated>2008-09-01T17:51:32.044-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-3897582473336321273?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/3897582473336321273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3897582473336321273' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3897582473336321273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3897582473336321273'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/fun-with-ruby-on-rails-and-google-ajax.html' title='AJAX Google API to Minify Javascript using Ruby on Rails'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8699687954104567623</id><published>2008-06-06T14:33:00.000-07:00</published><updated>2008-09-01T17:45:54.130-07:00</updated><title type='text'>Optimizing JavaScript in Ruby on Rails</title><content type='html'>&lt;p&gt;
I'm learning Ruby on Rails for a current client of mine, and wanted to share this tip on 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.
&lt;/p&gt;
&lt;p&gt;The reason to do this is that it's faster for the client to download one file, compared to multiple files. In other words, 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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8699687954104567623?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8699687954104567623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8699687954104567623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8699687954104567623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8699687954104567623'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/optimizing-javascript-in-ruby-on-rails.html' title='Optimizing JavaScript in Ruby on Rails'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3595554248052194129</id><published>2008-06-02T23:33:00.000-07:00</published><updated>2008-09-01T17:45:59.976-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'!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-3595554248052194129?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/3595554248052194129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3595554248052194129' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3595554248052194129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3595554248052194129'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/06/xampp-all-in-one-web-development-stack.html' title='XAMPP All-in-one Web Development Stack'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1883456577685987465</id><published>2008-05-31T11:24:00.000-07:00</published><updated>2008-09-01T17:46:04.609-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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1883456577685987465?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1883456577685987465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1883456577685987465'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/information-architecture-graceful.html' title='Information Architecture Graceful Degradation Accessibility Case Studies'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-5294571296807548776</id><published>2008-05-27T23:44:00.001-07:00</published><updated>2008-09-01T17:46:14.113-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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-5294571296807548776?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/5294571296807548776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=5294571296807548776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5294571296807548776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5294571296807548776'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/what-is-bad-about-css-sprites.html' title='What is Bad About CSS Sprites?'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1804518959767263208</id><published>2008-05-25T19:03:00.000-07:00</published><updated>2008-09-01T17:46:26.690-07:00</updated><title type='text'>User Interface Design: DIY vs Copy-and-Paste</title><content type='html'>&lt;p&gt;Drawing from a SxSW 2008 talk titled &amp;quot;Filching Design,&amp;quot; I'd like to discuss some of the pros and cons of designing user interfaces completely from scratch versus lifting elements of them from other sites.&lt;/p&gt;

&lt;p&gt;First&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1804518959767263208?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/1804518959767263208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1804518959767263208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1804518959767263208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1804518959767263208'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/user-interface-design-diy-vs-copy-and.html' title='User Interface Design: DIY vs Copy-and-Paste'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2157333727698337712</id><published>2008-05-25T14:41:00.000-07:00</published><updated>2008-09-01T17:46:35.771-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-2157333727698337712?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/2157333727698337712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2157333727698337712' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2157333727698337712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2157333727698337712'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/conducting-technical-interviews-for-web.html' title='Conducting Technical Interviews for Web Developers'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-4140425707371882540</id><published>2008-05-20T17:24:00.000-07:00</published><updated>2008-09-01T17:51:09.875-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!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-4140425707371882540?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/4140425707371882540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=4140425707371882540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4140425707371882540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4140425707371882540'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/inspecting-javascript-with-firebug.html' title='Inspecting Javascript with Firebug'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7786018402121992842</id><published>2008-05-17T14:58:00.000-07:00</published><updated>2008-09-01T17:51:14.414-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7786018402121992842?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7786018402121992842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7786018402121992842' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786018402121992842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786018402121992842'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/group-class-in-mootools.html' title='The Group Class in MooTools'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2069/2166114756_1358c1a1f4_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2246659514431597256</id><published>2008-05-16T14:06:00.000-07:00</published><updated>2008-09-01T17:46:49.398-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;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-2246659514431597256?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/2246659514431597256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2246659514431597256' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2246659514431597256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2246659514431597256'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/mootools-mouseenter-and-mouseleave.html' title='MooTools mouseenter and mouseleave Events For Dropdowns'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7520137121068364110</id><published>2008-05-14T04:06:00.000-07:00</published><updated>2008-09-01T17:46:44.793-07:00</updated><title type='text'>Recursive Functions in JavaScript</title><content type='html'>&lt;p&gt;Recursive functions are functions which conditionally call themselves. A common use for recursive functions is anywhere you need to iterate on data, where you would normally use a &lt;span style="font-style:italic;"&gt;for()&lt;/span&gt; or &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop.&lt;/p&gt;

&lt;p&gt;I can't say that I've used much recursion in production code, but it's a fun topic to write about, as there are plenty of fun uses of recursion to explore.&lt;/p&gt;

&lt;p&gt;Let's start with a basic use of recursion, and replace a &lt;span style="font-style:italic;"&gt;for()&lt;/span&gt; loop with a recursive function. In this case, we'll implement a simple function to reverse a string, first using iteration and then recursion.&lt;/p&gt;

&lt;pre name="code" class="js:nocontrols"&gt;
// Iterative
function reverseString(str) {
    var rev = new String();
    for (var i = str.length - 1; i &gt;= 0; i--) {
        rev += str[i];
    }
    return rev;
}

console.log(reverseString('test')); // Logs 'tset'
&lt;/pre&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
// Recursive
function reverseString(str) {
    var firstLetter = str.charAt(0);

    function iterate(str) {
        if (str.charAt(str.length-1) != firstLetter) {
            var charToReverse = str.charAt(str.length-1);
            str.charAt(str.length-1) = '';
            return iterate(charToReverse + str);
        }
    }
    return iterate(str);
}

console.log(reverseString('test')); // Logs 'tset'
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7520137121068364110?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7520137121068364110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7520137121068364110' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7520137121068364110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7520137121068364110'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/recursive-functions-in-javascript.html' title='Recursive Functions in JavaScript'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7481335608401888897</id><published>2008-05-14T02:27:00.000-07:00</published><updated>2008-09-01T17:51:18.485-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;This code is more optimized and nicer to read. It has the same functionality but the &lt;span style="font-style:italic;"&gt;while()&lt;/span&gt; loop has been significantly simplified and the &lt;span style="font-style:italic;"&gt;checkForNextItem()&lt;/span&gt; method has been eliminated altogether. It's a good thing when you can reduce complexity like that.&lt;/p&gt;
&lt;p&gt;One other minor edit I made during refactoring was to change the function from returning &lt;span style="font-style:italic;"&gt;list.getAll()&lt;/span&gt; to just returning the list itself. After thinking about it, I prefer for the input and outputs to both be of type LinkedList and then you can just call getAll() on the result. It's a minor nuance but worth pointing out.&lt;/p&gt;
&lt;p&gt;Leave comments if you'd like a deeper explanation of a specific area of the code or if anything is unclear, and of course your own implementations are always welcome.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7481335608401888897?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7481335608401888897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7481335608401888897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7481335608401888897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7481335608401888897'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/javascript-challenge-reverse-linked.html' title='JavaScript Challenge: Reverse a Linked List'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7786081478105219139</id><published>2008-05-13T15:24:00.000-07:00</published><updated>2008-09-01T17:46:58.950-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'>LinkedList Class in MooTools</title><content type='html'>&lt;p&gt;A commonly used data structure in Java and other programming languages is the &lt;a href="http://www.wisetome.com/splat/2007/07/19/data-structure-linked-list/#more-231"&gt;linked list&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/Linked_list"&gt;Wikipedia&lt;/a&gt;). It is similar to an array in that it is a way to store a collection of objects in sequence, however unlike an array you cannot access items in the collection by index. Instead, you access them through links from other items in the collection, or from the initial head or tail link (which can typically accessed with &lt;span style="font-style: italic;"&gt;getFirst()&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;getLast()&lt;/span&gt; methods, respectively).&lt;/p&gt;
&lt;a href="http://www.wisetome.com/splat/2007/07/19/data-structure-linked-list/#more-231"&gt;&lt;img width="300" style="float: right; margin-left: 18px; margin-bottom: 4px;" src="http://www.wisetome.com/splat/wp-content/uploads/2007/07/linked-list.png" alt="Data Structure - Linked List" /&gt;&lt;/a&gt;&lt;p&gt;Each item in the collection has a &lt;span style="font-style: italic;"&gt;getNext()&lt;/span&gt; method which returns the next item in the collection. If it's a doubly-linked list then each item (save for the head and tail) will have both &lt;span style="font-style: italic;"&gt;getNext()&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;getPrevious()&lt;/span&gt; methods.&lt;/p&gt;
&lt;p&gt;In JavaScript, no such construct exists, so we'll create one. This is mostly for academic purposes but there's nothing to stop you from using it in real code if you're so inclined. For the sake of this practice, we'll just make a singly-linked list as it is a bit simpler.&lt;/p&gt;

&lt;p&gt;This also provides an introduction to defining classes in MooTools. We aren't using much MooTools-specific functionality here so it could easily be ported to another library, or even written without the use of a library. But, since I use MooTools for most of my projects, I decided to use it here. I think you'll find defining classes in MooTools to be quite easy.&lt;/p&gt;

&lt;h3 style="clear: both;"&gt;The LinkedListItem Class&lt;/h3&gt;
&lt;p&gt;Here is the code to define the LinkedListItem class. The LinkedListItem takes a value of any type (string, object, etc) and returns an object of type LinkedListItem, which has the original value stored as the &lt;span style="font-style: italic;"&gt;value&lt;/span&gt; property on the object. It also defines accessor methods for &lt;span style="font-weight:bold;"&gt;getting/setting the next item&lt;/span&gt; in the list. There is also an accessor method for getting the original value.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
// 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;Read on to see how the LinkedListItem class is used by the LinkedList.&lt;/p&gt;

&lt;h3&gt;Defining the LinkedList Class&lt;/h3&gt;
&lt;p&gt;The LinkedList class will take an array of objects of any type and create a linked list from those objects. The linking occurs in the order of the array. So, if you call it with &lt;span style="font-style: italic;"&gt;['a', 'b', 'c']&lt;/span&gt; you'll get back a linked list with &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; as the head, and &lt;span style="font-style: italic;"&gt;c&lt;/span&gt; as the tail. The list will be linked like so: &lt;span style="font-style: italic;"&gt;a -&amp;gt; b -&amp;gt; c&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The LinkedList class has three methods: &lt;span style="font-style: italic;"&gt;setFirst(), getFirst()&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt;. The former two are accessor methods for changing the first element, i.e. the head. The latter is a method which returns an array of all the items in the linked list, in the order they are linked.&lt;/p&gt;
&lt;p&gt;There are quite a few other methods you could implement for the LinkedList but for now, these will suffice. If you're particularly brave and inclined to add to the class, go ahead and check out the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/LinkedList.html"&gt;Java LinkedList docs&lt;/a&gt; to see what other methods are available.
&lt;/p&gt;
&lt;p&gt;Here's the LinkedList class I came up with:&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;
   }
});
&lt;/pre&gt;
&lt;p&gt;There are only two areas of the code that need explaining: constructing the list in the &lt;span style="font-style: italic;"&gt;initialize()&lt;/span&gt; method, and constructing an array from the list in the &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; method. I'll touch on each to make sure it is clear what exactly is going on.&lt;/p&gt;
&lt;p&gt;The initialize() method is called on each instance of the class, with the arguments given to the constructor of the class. Calling &lt;span style="font-style: italic;"&gt;new LinkedList(['foo', 'bar'])&lt;/span&gt; will call the &lt;span style="font-style: italic;"&gt;initialize()&lt;/span&gt; method with the argument ['foo', 'bar'] as well. This is an automatic function call handled by MooTools and should not be done manually, unlike Prototype where the developer must manually call the initialize() method after instantiating the class.&lt;/p&gt;
&lt;p&gt;The first thing our LinkedList initialize() method does is create the &lt;span style="font-style: italic;"&gt;collection&lt;/span&gt; property. This is so it can store the data internally, and this property is not meant to be publicly accessible to other code.  The &lt;span style="font-style: italic;"&gt;collection&lt;/span&gt; array will be used to store the LinkedListItem objects created from the input array.&lt;/p&gt;
&lt;p&gt;I use MooTools &lt;span style="font-style: italic;"&gt;each()&lt;/span&gt; method to iterate over the items in the input array (collection). For each item, I create a new LinkedListItem and add it to the &lt;span style="font-style: italic;"&gt;collection&lt;/span&gt; property where it will be stored. I then set the previous item's link (if it exists) to the current item, using the &lt;span style="font-style: italic;"&gt;setNext()&lt;/span&gt; method. &lt;/p&gt;

&lt;p&gt;Finally, once the &lt;span style="font-style: italic;"&gt;each()&lt;/span&gt; loop has finished iterating over all the items in the collection, I set the head link to be the first item in the array, using the &lt;span style="font-style: italic;"&gt;setFirst()&lt;/span&gt; method.&lt;/p&gt;

&lt;p&gt;The other interesting area is the &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; method, which does basically the opposite of the initialize() method. Instead of constructing a LinkedList from an array, the &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; method &lt;span style="font-weight:bold;"&gt;returns an array in the order of the LinkedList&lt;/span&gt;. So you could instantiate a LinkedList in a certain order, change the order around by various &lt;span style="font-style: italic;"&gt;setNext()&lt;/span&gt; calls, and then call &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; and get back an array in the new order. This might not seem very useful at the moment, but bear with me and I'll demonstrate its utility through a challenge or two.&lt;/p&gt;

&lt;p&gt;The &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; method uses a &lt;span style="font-style: italic;"&gt;while()&lt;/span&gt; loop instead of an &lt;span style="font-style: italic;"&gt;each()&lt;/span&gt; loop, because we don't know the length of the list. Even if the length of the &lt;span style="font-style: italic;"&gt;collection&lt;/span&gt; array is 10, for instance, we have no guarantee the list will be 10 items. The coder may have called &lt;span style="font-style: italic;"&gt;setNext(null)&lt;/span&gt; on the head, in which case the list would only have a length of 1. Therefore, we must use a &lt;span style="font-style: italic;"&gt;while()&lt;/span&gt; loop that continues as long as their are next items, in other words, as long as &lt;span style="font-style: italic;"&gt;getNext()&lt;/span&gt; on the current item is not null.&lt;/p&gt;
&lt;p&gt;Inside the &lt;span style="font-style: italic;"&gt;while()&lt;/span&gt; loop, we simply add the current item to the result array and then redefine the item variable to point to the next item. After the loop finishes, we return the result, which is an array in the order that the list is linked.&lt;/p&gt;

&lt;p&gt;You can test that this works by instantiating a LinkedList and calling &lt;span style="font-style: italic;"&gt;getAll()&lt;/span&gt; on it.&lt;/p&gt;

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

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

   console.log(list.getAll());
  
   // RESULT:
   // a,b,c,d,e,f,g,1,2,3,4,5
});
&lt;/pre&gt;
&lt;h3&gt;LinkedList Challenge&lt;/h3&gt;
&lt;p&gt;Next up, a LinkedList challenge! Can you write code that &lt;span style="font-weight: bold;"&gt;reverses a linked list&lt;/span&gt; in place, without creating a new array?&lt;/p&gt;
&lt;p&gt;My next post will provide an answer, but in the meantime, give it a try. To make it clear, the challenge is to reverse a singly-linked list, using either the LinkedList class defined here or your own implementation, in place. That is, without creating another array, hash or other data structure to store the data in the list temporarily before writing it again.
&lt;/p&gt;
&lt;p&gt;This is the expected outcome:&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
   var list = new LinkedList(['a', 'b', 'c', 'd',
                              'e', 'f', 'g', '1',
                              '2', '3', '4', '5']);

   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;I should also mention that you can't access the &lt;span style="font-style: italic;"&gt;collection&lt;/span&gt; array inside the linked list directly. Otherwise, you could just do something like this:&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
function reverseLinkedList(list) {
   return list.collection.reverse();
}
&lt;/pre&gt;
&lt;p&gt;That would be a cheap, and is not an acceptable solution. This challenge is to reverse the list in place, so your only choice for starting is to call getFirst() on the list:&lt;/p&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
function reverseLinkedList(list) {
   var head = list.getFirst();
}
&lt;/pre&gt;

&lt;p&gt;This challenge was given to me in Java by my mentor at Amazon, Chris. It took me a good 45 minutes to solve the first time (though Chris made me solve it on a whiteboard, which is always more difficult for me than typing it up). Good luck and stay tuned for the next post which will offer a solution to this challenge.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7786081478105219139?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7786081478105219139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7786081478105219139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786081478105219139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7786081478105219139'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/linkedlist-class-in-mootools.html' title='LinkedList Class in MooTools'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2816920554896811460</id><published>2008-05-12T17:55:00.001-07:00</published><updated>2008-09-01T17:47:06.622-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: Dispense Change</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;p&gt;This challenge is to write a function that takes an amount of change and returns a String Array with the coins to dispense.&lt;/p&gt;
&lt;p&gt;Examples:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;.25 &lt;i&gt;returns&lt;/i&gt; ['quarter']&lt;/li&gt;&lt;li&gt;.26 &lt;i&gt;returns&lt;/i&gt; ['quarter', 'penny']&lt;/li&gt;&lt;li&gt;.30 &lt;i&gt;returns &lt;/i&gt;['quarter', 'nickel']&lt;/li&gt;&lt;li&gt;1.01 &lt;i&gt;returns&lt;/i&gt; ['dollar', 'penny']&lt;/li&gt;&lt;li&gt;1.16 &lt;i&gt;returns &lt;/i&gt;['dollar', 'dime', 'nickel', 'penny']&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;One of the requirements is that this returns the least amount of units of currency as possible. In other words, you can't return 100 pennies or even 4 quarters when 1 dollar would suffice. This is modeled after how real-life vending machines work.&lt;/p&gt;

&lt;div pc_m="" photo_container="" style="float: left; width: 240px; margin-right: 18px; margin-bottom: 4px;"&gt;&lt;a title="Land of the Vending Machines" href="http://www.flickr.com/photos/gullevek/340562157/"&gt;&lt;img class="pc_img" alt="Land of the Vending Machines" src="http://farm1.static.flickr.com/166/340562157_921a63ed9e_m.jpg" height="160" width="240" /&gt;&lt;/a&gt;
         &lt;span style="font-size:10px;"&gt;Land of the Vending Machines      By &lt;a style="text-decoration: none;" href="http://www.flickr.com/photos/gullevek/"&gt;gullevek&lt;/a&gt;&lt;/span&gt;     &lt;/div&gt; 

&lt;p&gt;If you want to attempt to solve this challenge yourself, &lt;b&gt;read no further!&lt;/b&gt; The rest of the article will go on to describe my solution to this problem and some of the issues I encountered along the way.&lt;/p&gt;

&lt;h3 style="clear: left;"&gt;Using MooTools' &lt;i&gt;round()&lt;/i&gt; Method&lt;/h3&gt;

&lt;p&gt;I originally wrote my solution to this challenge without the use of JavaScript libraries. However, I ran into a common problem when dealing with dollar values, which is that I needed to round them to the 2nd decimal place. Without rounding to the 2nd place, you end up with subtle flaws in the data. &lt;/p&gt;&lt;p&gt;
For instance, I was using an if() statement to check if the change remaining to dispense is greater than or equal to 0.1 (one cent). Before I added the code to round to the 2nd decimal place, the if() statement wouldn't evaluate to true when there should be a penny left to dispense. The change remaining should have been .1, but it wasn't entering the &lt;span style="font-style:italic;"&gt;if(changeToDispense &gt;= 0.1)&lt;/span&gt; statement. How could this be? Well, I was subtracting the change, but upon closer inspection, some of the values were not what I expected. When I subtract .25 from .48, I ended up with 0.22999999999999998 for instance.
&lt;/p&gt;&lt;p&gt;Of course, I should have ended up with 0.23, not .022999 (repeating). But, without rounding the number, it ended up slightly less than the correct amount, introducing subtle bugs into the code. Since the full amount wasn't being subtracted, the last penny would never be dispensed because there wasn't a whole penny left (it was something like 0.09999999999999998). Thus, I rounded to the second decimal place and it solved the problem.
&lt;/p&gt;&lt;p&gt;
Using core JavaScript methods, it's possible to work around this problem. It involves multiplying by 100, rounding and then dividing by 100. But, since most of the projects I work on use JavaScript libraries and nearly all of them have round() functions in some form or another, I decided to get a little help from a library. Specifically, I use the MooTools &lt;i&gt;round()&lt;/i&gt; method for solving this problem. &lt;/p&gt;
&lt;p&gt;
The &lt;i&gt;round()&lt;/i&gt; method takes how many places after the decimal to round to, so by calling &lt;i&gt;round(2)&lt;/i&gt;, a number like 0.0999 (repeating) is converted to 0.1.&lt;/p&gt;

&lt;div style="float: left; margin-right: 18px; margin-bottom: 4px; width: 180px;"&gt;    &lt;span class="photo_container pc_m"&gt;&lt;a title="Vending Machine - Japan" href="http://www.flickr.com/photos/rytc/345331437/"&gt;&lt;img class="pc_img" alt="Vending Machine - Japan" src="http://farm1.static.flickr.com/132/345331437_7da8fd7cfc_m.jpg" height="240" width="180" /&gt;&lt;/a&gt;&lt;/span&gt;                    &lt;span style="font-size: 10px;"&gt; Vending Machine - Japan     
            By &lt;a style="text-decoration: none;" href="http://www.flickr.com/photos/rytc/"&gt;rytc&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;        
&lt;p&gt;Note that as the method is added to the prototype of the Number object (i.e. base class), it is called as an instance method of the number you want to round, &lt;i&gt;not&lt;/i&gt; as a method of the Math object as with core JS methods. Compare: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Core JS:&lt;/b&gt;   Math.round(1.8);&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MooTools:&lt;/b&gt; 1.8.round();&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style="clear: left;"&gt;Designing a Solution&lt;/h3&gt;
&lt;p&gt;
My idea for the solution is to store a hash of the coin values keyed by their name, and then iterate over them checking if each value is higher than the amount of remaining change to dispense. For this to work, I need to iterate over them in order from highest to lowest. Otherwise, if I start in random order, it will break one of the requirements: This must return the least units of currency as possible. If I start at the penny, then it would keep dispensing pennies until there was no change left, and never get on to the other units of currency.
&lt;/p&gt;
&lt;p&gt;Therefore, the loop needs to &lt;b&gt;iterate over the currency values in order of highest to lowest&lt;/b&gt;: dollar, quarter, dime, nickel, penny. Here is the hash object that I created to represent the currency values, and then we'll discuss how to iterate over them in order:
&lt;/p&gt;
&lt;pre class="js:nocontrols" name="code"&gt;
 var money =
     'dollar': 1.00,
     'quarter': 0.25,
     'dime': 0.10,
     'nickel': 0.05,
     'penny': 0.01                                 
 };
&lt;/pre&gt;
&lt;p&gt;You might think it's as easy as using a for/in loop, but unfortunately, browser compatibility issues prevent it from being this simple. Using a for/in loop will iterate over the items but there is no guarantee of the order. Internet Explorer and Firefox use the correct order (the order of declaration) as far as I know, but Safari in particular does not follow this. So, it's not as simple as:&lt;/p&gt;

&lt;pre class="js:nocontrols" name="code"&gt;
function dispenseChange(changeToDispense) {
 var result = new Array();
 for (var unit in money) {
     if (money[unit] &amp;gt; changeToDispense) result.push(unit);
 }
 return result;
}
&lt;/pre&gt;
&lt;p&gt;It would be nice if it were this simple, and indeed in most browsers it is. But due to obscure quirks with the order of iteration over objects of properties, we need to store the order in its own array.&lt;/p&gt;
&lt;div style="float: left; margin-right: 18px; margin-bottom: 4px; width: 180px;"&gt;    &lt;span class="photo_container pc_m"&gt;&lt;a title="Asahi Beer Vending Machine: Komatsu" href="http://www.flickr.com/photos/jpellgen/444636731/"&gt;&lt;img class="pc_img" alt="Asahi Beer Vending Machine: Komatsu" src="http://farm1.static.flickr.com/234/444636731_42117bff1b_m.jpg" height="240" width="180" /&gt;&lt;/a&gt;&lt;/span&gt;                            &lt;span style="font-size:10px;"&gt;  Asahi Beer Vending Machine: Komatsu     
By &lt;a style="text-decoration: none;" href="http://www.flickr.com/photos/jpellgen/"&gt;jpellgen&lt;/a&gt;
&lt;/span&gt;&lt;/div&gt;

&lt;h3 style="clear:both;"&gt;A Working Solution&lt;/h3&gt;

&lt;p&gt;I've changed the &lt;i&gt;money&lt;/i&gt; object to now contain two properties, a &lt;i&gt;values&lt;/i&gt; hash and an &lt;i&gt;order&lt;/i&gt; array.&lt;/p&gt;

&lt;pre class="js:nocontrols" name="code"&gt;
 var money = {
     values: {
         'dollar': 1.00,
         'quarter': 0.25,
         'dime': 0.10,
         'nickel': 0.05,
         'penny': 0.01                                 
     },
     order: ['dollar', 'quarter', 'dime', 'nickel', 'penny']
 };
&lt;/pre&gt;
&lt;p&gt;Now I can iterate over the &lt;i&gt;order&lt;/i&gt; array and use that to key the &lt;i&gt;values&lt;/i&gt; hash. It's one extra step in the process but it doesn't add too much bloat to the code, and it actually works (at least, in the browsers I've tested):&lt;/p&gt;

&lt;pre class="js:nocontrols" name="code"&gt;
function dispenseChange(changeToDispense) {         
 var result = new Array();
 while (changeToDispense.round(2) &amp;gt;= 0.01) {
     for (var i = 0; i &amp;lt; money.order.length; i++) {
         var value = money.values[money.order[i]]; // Number, e.g. 1.00
         if (changeToDispense.round(2) &amp;gt;= value) {
             result.push(money.order[i]); // String, e.g. "dollar"
             changeToDispense -= value;
             break;                      
         }
     }
 }
 return result;
}   
&lt;/pre&gt;

&lt;p&gt;You can test the function with logging statements:&lt;/p&gt;
&lt;pre class="js:nocontrols" name="code"&gt;
window.addEvent('domready', function() {
 var tests = [.01, .05, .11, .27, .74, 1.08, 1.99, 2.07];
 tests.each(function(testValue) {
     console.log(testValue.toString() +
                 ': ' +
                 dispenseChange(testValue)
     );
 });
});
&lt;/pre&gt;


&lt;h3 style="clear: left;"&gt;Improving the Implementation&lt;/h3&gt;
&lt;p&gt;
One area for improvement is the nested for() loop inside the while() loop. Right now it isn't ideal, since it will waste iterations checking for currency amounts higher than the current currency. To explain what I mean, let's look at the loop again:
&lt;/p&gt;
&lt;pre class="js:nocontrols" name="code"&gt;
 while (changeToDispense.round(2) &amp;gt;= 0.01) {
     for (var i = 0; i &amp;lt; money.order.length; i++) {
         // ...
         if (changeToDispense.round(2) &amp;gt;=
             money.values[money.order[i]) {
             // dispense unit of currency
             break;                      
         }
     }
 }
&lt;/pre&gt;
&lt;p&gt;I commented out some of the implementation details so we can focus on the structure. The reason that this is sub-optimal is that after each unit of currency is dispensed, the for() loop breaks and the while() loop starts it over again. Say there is less than a dollar remaining to dispense-- for each unit of currency dispensed, the for() loop will still check for a dollar.&lt;/p&gt;
&lt;p&gt;To optimize this code, we'd have to only iterate over the &lt;i&gt;order&lt;/i&gt; array once. This means the for() loop would be outside the while() loop, and for each unit of currency, the while() loop would continue to dispense change of that unit until the change remaining is less than the unit's value. It would be optimized to &lt;i&gt;n&lt;/i&gt; (see &lt;a href="http://en.wikipedia.org/wiki/Big_O_notation"&gt;Big O notation&lt;/a&gt; for details) at that point.&lt;/p&gt;
&lt;h3&gt;Optimized Code&lt;/h3&gt;
&lt;p&gt;Here is the &lt;b&gt;new and improved&lt;/b&gt; code with the optimized loops:&lt;/p&gt;
&lt;pre class="js" name="code"&gt;
var money = {
 values: {
     'dollar': 1.00,
     'quarter': 0.25,
     'dime': 0.10,
     'nickel': 0.05,
     'penny': 0.01                                 
 },
 order: ['dollar', 'quarter', 'dime', 'nickel', 'penny']
};
function dispenseChange(changeToDispense) {
  
 var result = new Array();
 money.order.each(function(unit, i) {
     var value = money.values[unit]; // Number, e.g. 1.00
     while (changeToDispense.round(2) &amp;gt;= value) {
         result.push(unit); // String, e.g. "dollar"
         changeToDispense -= value;
     }
 }); 
 return result;
}
  
window.addEvent('domready', function() {
 var tests = [.01, .05, .11, .27, .74, 1.08, 1.99, 2.07];
 tests.each(function(testValue) {
     console.log(testValue.toString() +
                 ': ' +
                 dispenseChange(testValue)
     );
 });
});
&lt;/pre&gt;
&lt;p&gt;An observant reader will notice that I changed the for() loop to use MooTools' each() method. The reason I did this is that we no longer need to break out of the for() loop, and I prefer the each() notation. (Thanks for recommending it, Lowell!)&lt;/p&gt;
&lt;p&gt;As always, feel free to post your own solutions to this challenge in the comments.&lt;/p&gt;
&lt;div&gt;    &lt;span class="photo_container pc_m"&gt;&lt;a title="The latest in Japanese vending machines" href="http://www.flickr.com/photos/fotopakismo/2228874582/"&gt;&lt;img class="pc_img" alt="The latest in Japanese vending machines" src="http://farm3.static.flickr.com/2414/2228874582_8494e45bda_m.jpg" height="240" width="160" /&gt;&lt;/a&gt;&lt;/span&gt;     &lt;/div&gt;                     &lt;span style="font-size:10px;"&gt;    The latest in Japanese vending machines     
              By &lt;a style="text-decoration: none;" href="http://www.flickr.com/photos/fotopakismo/"&gt;El Fotopakismo&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-2816920554896811460?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/2816920554896811460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2816920554896811460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2816920554896811460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2816920554896811460'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/javascript-challenge-dispense-change.html' title='JavaScript Challenge: Dispense Change'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm1.static.flickr.com/166/340562157_921a63ed9e_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-275515239008866038</id><published>2008-05-10T18:51:00.000-07:00</published><updated>2008-09-01T17:47:15.366-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='menus'/><title type='text'>jQuery drop down menu delay (setTimeout)</title><content type='html'>To create a navbar with a subnav (drop down menu for instance) with a delay before closing using jQuery (jQ) follow this code. An example can be found &lt;a href="http://www.salemrep.org/newsite"&gt;here&lt;/a&gt;.

Javascript (js):
&lt;pre class="js" name="code"&gt;
function navbar() {
// create variables
var subNavTimer;
var open;
// to make sure that when user mouses over sub menu ul it stays open
$(&amp;quot;ul.subNav&amp;quot;).mouseover(function() {
 $(this).show();
 // lets remember what's open
 open = $(this).parent();
});
 
// when user mouses over main item in navbar
$(&amp;quot;li.navMainLink&amp;quot;).mouseover(function() {
 // close other nav item submenus
 if (open != null) open.children(&amp;quot;ul&amp;quot;).hide();
 // stop the timer
 clearTimeout(subNavTimer);
 // show this nav item's sub menu
 if ($(this) != open) $(this).children(&amp;quot;ul:hidden&amp;quot;).show();
 
});

// when user's mouse leaves the navbar item
$(&amp;quot;li.navMainLink&amp;quot;).mouseout(function() {
 // lets keep tabs of what is open
  open = $(this);
 // start the timer for 2 seconds until it closes.
  subNavTimer = setTimeout('open.children(&amp;quot;ul:visible&amp;quot;).hide();', 2000);
});
}

$(document).ready(function() {
 navbar();
});
&lt;/pre&gt;

HTML:
&lt;pre class="html" name="code"&gt;
&amp;lt;ul id=&amp;quot;navMain&amp;quot;&amp;gt;
&amp;lt;li class=&amp;quot;navMainLink&amp;quot;&amp;gt;
  &amp;lt;a class=&amp;quot;navLink&amp;quot; href=&amp;quot;#&amp;quot;&amp;gt;Performances&amp;lt;/a&amp;gt;
  &amp;lt;ul class=&amp;quot;subNav&amp;quot;&amp;gt;
   &amp;lt;li&amp;gt;
    &amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;Season Subscriptions&amp;lt;/a&amp;gt;
   &amp;lt;/li&amp;gt;
   &amp;lt;li&amp;gt;
    &amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;About the Shows&amp;lt;/a&amp;gt;
   &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
 &amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/pre&gt;

CSS:
Your decision! Make it a vertical drop down or make it a horizontal fly out. &lt;span style="font-weight:bold;"&gt;Just make sure to have the ul.subNav be display: none; by default in your CSS.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-275515239008866038?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/275515239008866038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=275515239008866038' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/275515239008866038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/275515239008866038'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/jquery-drop-down-menu-delay-settimeout.html' title='jQuery drop down menu delay (setTimeout)'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7156472020431284943</id><published>2008-05-08T01:01:00.000-07:00</published><updated>2008-09-01T17:47:29.286-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='cookies'/><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><title type='text'>Using MooTools' Hash.Cookie API</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://docs12b.mootools.net/Plugins/Hash.Cookie"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://www.thetruetribe.com/uploaded_images/doobiecookie-722766.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;p&gt;MooTools makes working with cookies quite easy. Based on functions from Paul Peter Koch's &lt;a href="http://www.quirksmode.org/"&gt;QuirksMode&lt;/a&gt;, the MooTools API for handling cookies is intuitive and easy to remember.&lt;/p&gt;
&lt;p&gt;For storing simple bits of information on the browser, the &lt;a href="http://docs12b.mootools.net/Utilities/Cookie"&gt;Cookie methods&lt;/a&gt; &lt;span style="font-style:italic;"&gt;read(), write()&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;dispose()&lt;/span&gt; are adequate. As their names imply, these read, write and delete cookies from the browser, respectively.&lt;/p&gt;
&lt;p&gt;But, if you want to do something more complex, such as save a JSON string each time a method is called on the cookie, then &lt;a href="http://docs12b.mootools.net/Plugins/Hash.Cookie"&gt;Hash.Cookie&lt;/a&gt; is for you.&lt;/p&gt;
&lt;p&gt;What's the difference between the Hash.Cookie methods and the standard methods you say? For one, Hash.Cookie is its own module, so make sure the version of MooTools you're using has it included. Besides that, Hash.Cookie gives you all the functionality of the Hash class, including getters/setters, &lt;span style="font-style:italic;"&gt;each(), some(), filter(), has(), keyOf()&lt;/span&gt; and more. For the full documentation on all Hash methods available, view the &lt;a href="http://docs12b.mootools.net/Native/Hash/#Hash"&gt;Hash docs here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's an example that uses the Hash.Cookie class to store &lt;span style="font-weight:bold;"&gt;how many times a user has visited&lt;/span&gt; the page. Note that this uses Firebug so if you don't have it enabled, you'll need to override &lt;a href="http://www.thetruetribe.com/2008/04/redefining-consolelog-for-browsers.html"&gt;console.log()&lt;/a&gt;.&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
window.addEvent('domready', function() {
    var cookie = new Hash.Cookie('test-cookie');
    
    var numberOfVisits = $defined(cookie.get('numberOfVisits')) ? 
                         cookie.get('numberOfVisits') :
                         0;
                         
    cookie.set('numberOfVisits', numberOfVisits + 1);
    
    console.log('You have visited the page ' + 
                 cookie.get('numberOfVisits') + 
                 ' times.');        
});
&lt;/pre&gt;
&lt;p&gt;On line 1, we start by declaring everything to occur when the DOM is ready.
For MooTools developers, this should be a familiar practice. Although we aren't
manipulating the DOM in this example, I've left it in, as Firebug threw an error
when I tried to console.log() before the DOM was ready.&lt;/p&gt;
&lt;p&gt;
On line 2, we instantiate a new cookie named 'test-cookie' without any options. Interestingly, this also has the effect of &lt;span style="font-weight:bold;"&gt;loading the cookie&lt;/span&gt; if it already exists. This means that the first time the user visits the page, it will write a cookie, but on all subsequent visits it will read a cookie. The end result is the same: we have a reference to the cookie as a hash object, and can use the methods that the Hash class provides.&lt;/p&gt;
&lt;p&gt;
Next, on lines 4-6, we use a &lt;span style="font-weight:bold;"&gt;ternary operator&lt;/span&gt; to check if 'numberOfVisits' has already been written to the cookie. If so, we read it from the cookie. If not, it is initialized to 0.
&lt;/p&gt;
&lt;p&gt;On line 8, we increment 'numberOfVisits' using the &lt;span style="font-style:italic;"&gt;set()&lt;/span&gt; method. Finally, we log the number of visits using Firebug's &lt;span style="font-style:italic;"&gt;console.log()&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Getters, Setters and Auto-Saving Cookies&lt;/h3&gt;
&lt;p&gt;Getters and setters should be familiar to anyone versed in Java but I imagine some JavaScript developers may be unfamiliar with them. Essentially, &lt;span style="font-style:italic;"&gt;get()&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;set()&lt;/span&gt; methods are provided for you to use instead of directly accessing the data. For instance, cookie.hash.numberOfVisits and cookie.get('numberOfVisits') both return the same data, but the former directly accesses the data while the latter uses a wrapper method.&lt;/p&gt; 

&lt;p&gt;There are numerous reasons to use getters/setters instead of directly accessing the data, but one practical example is the use of Hash.Cookie's autoSave functionality. There is an &lt;span style="font-weight:bold;"&gt;autoSave flag in the options&lt;/span&gt; which, if enabled, will save the data after each operation on the hash. It defaults to 'true' which is why I didn't have to &lt;span style="font-style:italic;"&gt;write()&lt;/span&gt; the cookie in the above example.&lt;/p&gt;

&lt;p&gt;Since I didn't define a duration in the options object when instantiating the cookie (nor did I even include an options object, for that matter), it will only live for the duration of the browser. In other words, it's a session cookie: When the user exits the browser and restarts, the cookie will be destroyed. For the cookie to live beyond the lifespan of the browser, you can specify the duration of the cookie to live (in days).&lt;/p&gt;

&lt;p&gt;The other options which I omitted were &lt;span style="font-style:italic;"&gt;domain, path&lt;/span&gt; and &lt;span style="font-style:italic;"&gt;secure&lt;/span&gt;. None of those were important for my example but for some applications, setting domain- and path-specific cookies and ensuring they are only accessed over HTTPS may be necessary&lt;/p&gt;

&lt;p&gt;This example is somewhat simple but I hope it has provided an introduction to using MooTools' excellent Hash.Cookie API. Good luck and enjoy a tall glass of soymilk with your Hash Cookies!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7156472020431284943?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7156472020431284943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7156472020431284943' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7156472020431284943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7156472020431284943'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/using-mootools-hashcookie-api.html' title='Using MooTools&apos; Hash.Cookie API'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8984807058167393870</id><published>2008-05-06T17:21:00.001-07:00</published><updated>2008-09-01T17:47:33.585-07:00</updated><title type='text'>JavaScript Date Object</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p&gt;In this article I will explore the use of the &lt;b&gt;JavaScript date object&lt;/b&gt; and its methods. We won't be using any JavaScript libraries because the existing API is quite adequate, and most libraries don't really offer much in the way of extensions anyway.&lt;/p&gt;&lt;p&gt;Let's start with displaying the current time. You can do this by using the &lt;font face='Courier New'&gt;Date()&lt;/font&gt; constructor and calling the &lt;font face='Courier New'&gt;toString()&lt;/font&gt; method on it. If you have Firebug, open up the console and type this code:&lt;/p&gt;&lt;pre class='js:nocontrols' name='code'&gt;
var date = new Date();
date.toString();
&lt;/pre&gt;
&lt;p&gt;You'll see that &lt;font face='Courier New'&gt;date.toString()&lt;font face='sans-serif'&gt; evaluates to a string containing the current time in Greenwich Meridian Time (GMT). In my case, it is "Tue May 06 2008 16:06:39 GMT-0700 (Pacific Daylight Time)."&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face='Courier New'&gt;&lt;font face='sans-serif'&gt;There are a number of other &lt;i&gt;to&lt;/i&gt; methods available as well. You can paste these into the Firebug console to see what they evaluate to. I've put my example as a comment after each one:&lt;/font&gt;
&lt;/font&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;font face='Courier New'&gt;date.toDateString(); // &lt;/font&gt;&lt;span class='objectBox objectBox-string'&gt;"Tue May 06 2008"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;font face='Courier New'&gt;date.toGMTString(); // &lt;/font&gt;&lt;span class='objectBox objectBox-string'&gt;"Tue, 06 May 2008 23:06:39 GMT"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;font face='Courier New'&gt;date.toLocaleDateString(); // &lt;/font&gt;&lt;span class='objectBox objectBox-string'&gt;"Tuesday, May 06, 2008"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;font face='Courier New'&gt;date.toLocaleString(); // &lt;/font&gt;&lt;span class='objectBox objectBox-string'&gt;"Tuesday, May 06, 2008 4:06:39 PM"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;font face='Courier New'&gt;date.toLocaleTimeString(); // &lt;/font&gt;&lt;span class='objectBox objectBox-string'&gt;"4:06:39 PM"&lt;/span&gt;&lt;font face='Courier New'&gt;
&lt;/font&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Practical Applications of the JavaScript Date Object&lt;/h3&gt;&lt;p&gt;One of the most obvious applications of the date object is to display the current time, should you desire to do so. Oftentimes news websites will contain the day's date, and sometimes they have a clock as well. For example, see &lt;a href='http://www.bbc.co.uk/'&gt;the BBC's homepage&lt;/a&gt; which displays the day's date and an analog-style clock done in Flash:&lt;/p&gt;
&lt;a href='http://www.thetruetribe.com/uploaded_images/bbc-banner-799304.jpg' onblur='try {parent.deselectBloggerImageGracefully();} catch(e) {}'&gt;&lt;img border='0' alt='' src='http://www.thetruetribe.com/uploaded_images/bbc-banner-799301.jpg' style='cursor: pointer;'/&gt;&lt;/a&gt;&lt;p&gt;The BBC follows the format "Tuesday 6 May 2008" for example. Let's construct that using JavaScript:
 &lt;/p&gt;
&lt;pre class='js:nocontrols' name='code'&gt;
function getFormattedDate(date) {
    var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var day = days[date.getDay()];

    var months = ["January", "February", "March", "April", "May", "June", 
                  "July", "August", "September", "November", "December"];
    var month = months[date.getMonth()];

    // Returns a string formatted like "Tuesday 6 May 2008"
    return day + " " + 
           date.getDate() + " " +
           month + " " + 
           date.getFullYear();
}

getFormattedDate(new Date());
&lt;/pre&gt;
&lt;p&gt; You could also accomplish this with some &lt;b&gt;RegEx hackery&lt;/b&gt; but I think this is cleaner, albeit a bit more verbose. The benefit of doing this with RegEx is that you can use one of the existing &lt;font face='Courier New'&gt;toString()&lt;/font&gt; methods, such as &lt;font face='Courier New'&gt;toLocaleString()&lt;/font&gt;, and then parse the data you need from there. 
&lt;/p&gt;&lt;p&gt;Actually, given that the data is delimited by commas, you could accomplish this simply by splitting the returned string without the use of RegEx. Doing it that way would avoid the need to tediously specify the names of all the days and the months.
&lt;/p&gt;
&lt;h3&gt;Creating a Countdown Timer in JavaScript&lt;/h3&gt;&lt;p&gt;Another use case for the JavaScript date object is to count down the time remaining until a certain date. This could be the launch of a new website or product, the cut-off time for a submission, or anything else that requires notification of the time remaining until a specific date and time.&lt;/p&gt;

&lt;p&gt;On a website I previously worked on, &lt;a href='http://www.endless.com'&gt;Endless.com&lt;/a&gt;, there is a countdown timer in the banner that notifies the customer how long they have to order to get next day shipping. This is a fun idea because it adds a little pressure for the customer to make an impulse buy as the cutoff time comes closer. I've seen similar uses on other e-commerce sites and it adds a nice touch, for those sites which offer next-day shipping.&lt;/p&gt;

&lt;p&gt;To do something like this, I imagine you'd need two functions, one to update the HTML with the correct date string (given a date object as input), and another, possibly anonymous function that is declared with a setInterval, which decrements the current time and calls the update function. Without writing the implementation details, I imagine it would look something like this:&lt;/p&gt;

&lt;pre class='js:nocontrols' name='code'&gt;
function updateTimeRemaining(date) {
    // implementation details for parsing data from date object
    // and updating the DOM
}

window.onload = function() {
    var interval = setInterval(function() {
        updateTimeRemaining(new Date());
    }, 1000);
};
&lt;/pre&gt;

&lt;p&gt;The updateTimeRemaining() function would need to be written to output the time remaining given a date object. I feel that there may be a better way to do this than creating a new Date() instance every second, however. Could we not use the same date object but decrement its time manually every second? In any case, this isn't a full-fledged solution at this point, just an outline of one possible solution.&lt;/p&gt;

&lt;p&gt;What are your favorite uses of the JavaScript date object? Do you have other use cases that I've left out here? Please leave them in the comments and I may even devote a whole article to them. There is quite a bit you can do with date and time and I'm always on the lookout for new uses. Hopefully these short examples will get you thinking about how you can use the JavaScript date object on &lt;i&gt;your&lt;/i&gt; site.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8984807058167393870?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8984807058167393870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8984807058167393870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8984807058167393870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8984807058167393870'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/javascript-date-object.html' title='JavaScript Date Object'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3520436668482784810</id><published>2008-05-05T21:20:00.000-07:00</published><updated>2008-09-01T17:47:40.145-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'>Downloading the Full MooTools Library</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://mootools.net/download"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://www.thetruetribe.com/uploaded_images/mootools-all-selected-708490.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;p&gt;One of my minor frustrations on the &lt;a href="http://mootools.net/download"&gt;MooTools download page&lt;/a&gt; has always been having to manually select each component to add. While it is nice that you can keep the filesize down by omitting components that you don't need, I wish they had a way to select all components at once.&lt;/p&gt;

&lt;p&gt;Well, it turns out they do. I just found out that Mootools actually allows you to select all components by calling the &lt;span style="font-family: courier"&gt;Download.all()&lt;/span&gt; method. You can do this by opening the Firebug console while you're on the MooTools download page and entering &lt;span style="font-family: courier"&gt;Download.all()&lt;/span&gt; and clicking Run. Alternately, if you don't have Firebug, you can enter &lt;span style="font-family: courier"&gt;javascript:Download.all()&lt;/span&gt; into the addressbar and press enter. This will select all components on the page.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-3520436668482784810?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/3520436668482784810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3520436668482784810' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3520436668482784810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3520436668482784810'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/downloading-full-mootools-library.html' title='Downloading the Full MooTools Library'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-986871158678815706</id><published>2008-05-05T19:03:00.000-07:00</published><updated>2008-05-20T16:17:00.896-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>Truncating Text with JavaScript</title><content type='html'>&lt;p&gt;Since Alex posted an article on &lt;a href="http://www.thetruetribe.com/2008/05/how-to-truncate-in-prototype.html"&gt;truncating text with Prototype&lt;/a&gt;, I thought I would write an article on truncating text without the help of a JavaScript framework.&lt;/p&gt;

&lt;p&gt;I won't define a class like in his example, but I will try to provide the same functionality, and perhaps add some functionality as well. This code will search for all HTML elements with the class 'truncate', or with another className if one is specified, and will truncate to the nearest word less than the character-count you specify. It also defaults to appending '...' (the ellipsis) but you can override this with an empty string as the third optional parameter, if you prefer not to have anything appended.&lt;/p&gt;

&lt;p&gt;Note: I wrote in the comments on Alex's article that you may want to add ellipsis to his code. I realized after reading the &lt;a href="http://www.prototypejs.org/api/string/truncate"&gt;Prototype API docs&lt;/a&gt; that in fact, this is exactly what it does by default. Unless you specify an override with an optional parameter, the Prototype truncate() method will automatically add an ellipsis at the end of the string it returns.&lt;/p&gt;

&lt;p&gt;Here is my implementation of the truncate() function, without the use of JavaScript libraries:&lt;/p&gt;

&lt;pre name="code" class="js:nocontrols"&gt;

// Input parameters:
// String text, [Number length, String ellipsis]
//
// Returns:
// String text

function truncate(text, length, ellipsis) {    

    // Set length and ellipsis to defaults if not defined
    if (typeof length == 'undefined') var length = 100;
    if (typeof ellipsis == 'undefined') var ellipsis = '...';

    // Return if the text is already lower than the cutoff
    if (text.length &lt; length) return text;

    // Otherwise, check if the last character is a space.
    // If not, keep counting down from the last character
    // until we find a character that is a space
    for (var i = length-1; text.charAt(i) != ' '; i--) {
        length--;
    }

    // The for() loop ends when it finds a space, and the length var
    // has been updated so it doesn't cut in the middle of a word.
    return text.substr(0, length) + ellipsis;
}
&lt;/pre&gt;

&lt;h3&gt;Truncating Text by Class Name&lt;/h3&gt;
&lt;p&gt;In Alex's example, he wrote a class in Prototype that you initialize with an array of HTML elements. For this example, we'll register an event handler to the window onload that will look for &lt;span style="font-weight:bold;"&gt;all elements with the class 'truncate'&lt;/span&gt; and truncate them to our specifications.&lt;/p&gt;

&lt;pre name="code" class="js:nocontrols"&gt;
window.onload = function() {
    var elements = document.getElementsByClassName('truncate');
    for (var i = 0; i &lt; elements.length; i++) {
        elements[i].innerHTML = truncate(elements[i].innerHTML, 100);
    }
}
&lt;/pre&gt;

&lt;p&gt; It's basically doing the same thing as in Alex's example, except that I'm using the window.onload event instead of the custom 'domready' event (called &lt;a href="http://www.prototypejs.org/api/document/observe"&gt;dom:loaded in Prototype&lt;/a&gt;) which triggers much quicker. If you are using a framework, then use one of the custom 'domready' events because they trigger as soon as the DOM is accessible for manipulation, whereas the traditional window.onload event waits to fire until each and every image is finished downloading. Good grief!&lt;/p&gt;
&lt;p&gt;Note that this example will only work in Firefox 3 or Safari 3, as other browsers do not natively support document.getElementsByClassName. You could just implement your own getElementsByClassName function like so:&lt;/p&gt;


&lt;pre name="code" class="js"&gt;
function getElementsByClassName(className) {
    // RegExp from http://www.robertnyman.com
    //             /2005/11/07/the-ultimate-getelementsbyclassname/

    var match = new RegExp('(^|\\\\s)' + className + '(\\\\s|$)');

    // All elements which match are added to the array
    var matchingTags = new Array();

    var allTags = document.getElementsByTagName('*');
    for (var i = 0; i &lt; allTags.length; i++) {
        if (match.test(allTags[i].className)) {
            matchingTags.push(allTags[i]);
        }
    }   
    return matchingTags;
}


window.onload = function() {
    var elements = getElementsByClassName('truncate');
    for (var i = 0; i &lt; elements.length; i++) {
        elements[i].innerHTML = truncate(elements[i].innerHTML, 100);
    }
}
&lt;/pre&gt;

&lt;p&gt;Make sure that you only give the 'truncate' class to elements whose &lt;span style="font-weight:bold;"&gt;only child is a text node&lt;/span&gt;. If the element has other HTML children then this won't work correctly. It's possible to code around this but for the sake of this example, let's just keep it simple. Here are two examples that show proper and improper use:&lt;/p&gt;

&lt;p&gt;&lt;span style="font-weight:bold;"&gt;This is OK:&lt;/span&gt;&lt;/p&gt;
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;span class=&amp;quot;truncate&amp;quot;&amp;gt;some text &amp;lt;/span&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;This is not OK&lt;/span&gt;:
&lt;/p&gt;&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;span class=&amp;quot;truncate&amp;quot;&amp;gt;&amp;lt;span&amp;gt;some text &amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
&lt;/pre&gt;

&lt;p&gt;As always, feel free to post in the comments with any questions or alternative suggestions for the code. This is a fairly simplistic implementation and truth be told, if you're using a JavaScript library (which it seems most people are these days) then this may not be too relevant for you. But, hopefully it has been informative to explore this library-free, albeit simple, implementation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-986871158678815706?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/986871158678815706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=986871158678815706' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/986871158678815706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/986871158678815706'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/truncating-text-with-javascript.html' title='Truncating Text with JavaScript'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1203923879510498095</id><published>2008-05-05T09:16:00.000-07:00</published><updated>2008-05-05T15:08:24.714-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='string'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>How to Truncate in Prototype</title><content type='html'>This is to truncate multiple items in the javascript library Prototype. If it has the class="truncate" it will be truncated!

Simple way:
&lt;pre class="js" name="code"&gt;
var toTruncate = $$(".truncate");
var len = 190;
for(i=0;i&lt;toTruncate.length;i++) {
	toTruncate[i].innerHTML=toTruncate[i].innerHTML.truncate(len);
}
&lt;/pre&gt;


Class Based: 
&lt;pre class="js" name="code"&gt;
var TruncateIt = Class.create({

      initialize: function(sTruncate) {

            var toTruncate = (typeof sTruncate != 'undefined') ? $$(sTruncate) : $$('.truncate');

            var len = 100;

            for (var i = 0; i &lt; toTruncate.length; i++) {

                 toTruncate[i].innerHTML=toTruncate[i].innerHTML.truncate(len);

            }

      }

});

 

document.observe('dom:loaded', function(){ 

  var truncate = new TruncateIt('.truncate');

}); 

&lt;/pre&gt;

Thanks to Kris for helping me write this in a class as I'm totally new to prototype. See his hip new site at &lt;a href="http://komputerart.com/"&gt;komputerart.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1203923879510498095?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/1203923879510498095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1203923879510498095' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1203923879510498095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1203923879510498095'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/how-to-truncate-in-prototype.html' title='How to Truncate in Prototype'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-1659269380238878960</id><published>2008-05-05T01:01:00.000-07:00</published><updated>2008-05-06T19:37:44.941-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='forms'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='validation'/><title type='text'>jQuery Plugin Validation with AJAX</title><content type='html'>The JQuery plugin Validation by &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/"&gt;bassistance.de&lt;/a&gt; is extension, powerful, and quick-to-deploy. I recommend this library for people already using the jQ framework to provide high-quality, usable client-side form validation. We are going to discuss basic properties of this framework as well as AJAX and scalability. Here is the code we are going to step through. This code was specifically designed to create an ajax experience for the medical technology company eMedTV.com. The live example can be found at &lt;a href="http://research.emedtv.com/idiopathic-pulmonary-fibrosis-research/idiopathic-pulmonary-fibrosis-clinical-study-2.html"&gt;this address&lt;/a&gt;.


Here's &lt;span style="font-weight:bold;"&gt;my validation function&lt;/span&gt;:

&lt;pre class="js" name="code"&gt;
$(document).ready(function() {
    if (pageName=="researchCenter") {
// Just use a different variable for each form you use. It is too difficult to use just one for all forms because each form has it's own plethora of needs (usually).
    var validator = $("#researchCenterForm").validate({
// #messageBox holds the all encompassing message at the top to let all the users know  there is a problem.
         errorContainer:"#messageBox",
// This is very important for manipulating the placement and styles of the error message for individual cases, such as first name or zip. I'll explain this later.
         errorClass: "formError",
// wrapper is only needed if you want to wrap the error message in something. If you  want a list the errors it can be a &lt;li&gt;. I didn't really find any need for this  unless you were listing all the errors at the top.
         wrapper: null,
// errorPlacement is very important. It is where in the DOM you want the error of each  idividual case to appear. I wanted each error to be placed at the beginning of each  form element list item. See HTML example below. 
         errorPlacement: function(error, element) { 
            error.insertBefore(element);
        },
// On to the rules and without this the form wouldn't be what it is!
            rules: {
// All the methods are found as having the name's inside the form. Thus in order for  email to work I have to have a form element with name="email". 
                zip: {
// required:true is a must if you want the validator to check this element.
                    required:true,
// digits is one of the mime types of only digits. You put in alpha characters and it  lets you know it doesn't like that!
                    digits: true,
                    minlength: 5,
                    maxlength: 5
                },
                betterEmail: {
                    required: true,
                    email: true
                },
// If you have a confirm or email again area then we have some special rules to make  sure this works. 
                confirmEmail: {
                    required: true,
// #email is the id of the first email. For example, &lt;input id="email"  name="name"&gt;&lt;/input&gt;
                    equalTo: "#email",
                    email: true
                }   required:true
                        }
            },
//Here are all the messages for the different errors on the page. This is OOP so the  method (firstname:) must match the ID of the required field. If it is not required it will not receive an error message.
            messages: {
            firstname: "Please enter your first name.",
            lastname: "Please enter your last name.",
            username: {
                required: "Please enter a username.",
                minLength: "Your username must consist of at least 2 characters."
            },
            password: {
                required: "Please provide a password.",
                minLength: "Your password must be at least 5 characters long."
            },
            confirmPassword: {
                required: "Please provide a password.",
                minLength: "Your password must be at least 5 characters long.",
                equalTo: "Please enter the same password as above."
            },
            email: "Please enter a valid email address.",
            confirmEmail: "Please enter the same email.",
            zip: "Please enter a valid zip code.",
            agreeToService: "Please check the box."
        },
// Here is the fun part and the tricky part: AJAX
// SubmitHandler is called when the form is called. When the users clicks submit on  your form this is what happens. Since we want to do ajax you use the $.ajax jQ  object. It has to start with function() {} for it to work. 
  submitHandler: function() {
   $.ajax({
  See serialize here http://docs.jquery.com/Ajax/serialize
   data:$("#researchCenterForm").serialize(),
// The url you are going to submit to
   url: submit.php,
   timeout: 2000,
// Sends a message to the console if it failed for testing purposes.
   error: function() {
   console.log("Failed to submit");
   },
// If successful you can do something here. You can change elements, update text, or  simply alert the response to first test to see if it worked.
   success: function(response) {
       alert(response);
      }

  });
   
   }
 })
 }
}); 
&lt;/pre&gt;

First thing you'll probably notice is this plugin is formatted in object oriented programming. So it is very straight forward to know which methods and which properties to use for your form. Once you locate the &lt;a href="http://docs.jquery.com/Plugins/Validation/validate#options"&gt;ultimate guide&lt;/a&gt; to how to use the validator, it can become relatively straight forward to use.

&lt;span style="font-weight:bold;"&gt;How to stylize where error label fields go on the page&lt;/span&gt;

CSS:
&lt;pre class="css" name="code"&gt;
.formError {
        position: absolute;
        margin: 21px -13pt 0pt;
}
li {
        position: relative;
}
&lt;/pre&gt;
The margin is to position the error label below the form field, such as an email input box. Positioning it absolutely makes sure the forms look and feel is not altered by static elements.

HTML:
&lt;pre class="html" name="code"&gt;
&lt;ul&gt;
  &lt;li&gt;
   &lt;input class="betterEmail required" type="text" name="email"/&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;/pre&gt;
You'll notice the class name "betterEmail" and "required". This is to enter in jQ validation methods into the html markup itself. Cool huh?


The HTML after the error has been applied in real-time:
&lt;pre class="html" name="code"&gt;
&lt;ul&gt;
  &lt;li&gt;
   &lt;label class="formError" for="email" generated="true"&gt;Valid Email Please&lt;/label&gt;
   &lt;input class="betterEmail required formError" type="text" name="email"/&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;/pre&gt;

Once you have your form all setup you can start writing your own mime types if you include the mime type plugin as well.
Currently the validator checks if your &lt;span style="font-weight:bold;"&gt;email is alex@alexgrande and that's it. If you want to make sure there is a .com or .org, etc you need this:&lt;/span&gt;

&lt;pre class="js" name="code"&gt;
jQuery.validator.addMethod("betterEmail", function(value, element) {
 return this.optional(element) || /^[^\x00-\x20()&lt;&gt;@,;:\\".[\]\x7f-\xff]+(?:\.[^\x00-\x20()&lt;&gt;@,;:\\".[\]\x7f-\xff]+)*\@[^\x00-\x20()&lt;&gt;@,;:\\".[\]\x7f-\xff]+(?:\.[^\x00-\x20()&lt;&gt;@,;:\\".[\]\x7f-\xff]+)+$/i.test(value);
}, "Valid Email Please"); 
&lt;/pre&gt;
See I how I use betterEmail above.

Another is if you have a &lt;span style="font-weight:bold;"&gt;drop down menu like a select box with options. There isn't a default way to do this&lt;/span&gt;. My solution is the following. Notice the option with the value="none".

&lt;pre class="js" name="code"&gt;
jQuery.validator.addMethod("selectCountry", function(value, element) {
 return this.optional(element) || ( value.indexOf("none") == -1);
}, "Please choose a Country."); 
&lt;/pre&gt;

&lt;pre class="html" name="code"&gt;
&lt;select id="country" class="selectCountry" name="country"&gt;
 &lt;option value="none"&gt;Country&lt;/option&gt;
 &lt;option value="korea"&gt;Korea&lt;/option&gt;
 &lt;option value="nigeria"&gt;Nigeria&lt;/option&gt;
&lt;/select&gt;
&lt;/pre&gt;

Another problem I have found is if you have three different select boxes, such as month, day, and year and you want only one error message for all three since they are all related. My solution is to make all three error message overlap making it appear they are all the same to the user.

HTML:
&lt;pre class="html" name="code"&gt;
&lt;li id="date"&gt;
 &lt;p&gt;What is your (or the participant) date of birth?&lt;/p&gt;
 &lt;select id="DOBMonth" class="selectDate" name="DOBMonth"&gt;
 &lt;/select&gt;

 &lt;select id="DOBDay" class="selectDate" name="DOBDay"&gt;
 &lt;/select&gt;

 &lt;select id="DOBYear" class="research-signup-year selectDate" name="DOBYear"&gt;
 &lt;/select&gt;
&lt;/li&gt;
&lt;/pre&gt;

CSS:
&lt;pre class="css" name="code"&gt;
li#date .formError {
 left: 2px;
 bottom: -15px;
}
&lt;/pre&gt;
Thus every formError will overlap each other with the same position on the page.

Last problem is fixing error form position issues in IE. That's easy. If you read my article about &lt;a href="http://www.thetruetribe.com/2008/03/managing-cross-browser-issues-with-js.html"&gt;handling cross-browser issues&lt;/a&gt; then you'll know most of what to do. Since we positioned the error message absolutely we can position it using IE conditional comments only for IE.

CSS:
&lt;pre class="css" name="code"&gt;
.ie li#date .formError {
 top: 1000px;
}
&lt;/pre&gt;


This is all for this discussion. If I think of more I'll add to it later. In either case, please send questions or comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-1659269380238878960?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/1659269380238878960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=1659269380238878960' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1659269380238878960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/1659269380238878960'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/05/how-to-use-jquery-plugin-validation.html' title='jQuery Plugin Validation with AJAX'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8272164501500662312</id><published>2008-04-26T15:54:00.001-07:00</published><updated>2008-05-05T20:15:05.630-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='browser'/><title type='text'>Retaining Middle-Click Functionality With JavaScript</title><content type='html'>&lt;div style="width: 420px; float: left;"&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/547178990_316247fd37_o-750509.png"&gt;&lt;img style="cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/547178990_316247fd37_o-750504.png" alt="" border="0" /&gt;&lt;/a&gt;

&lt;span style="font-size:9;"&gt;Image used under a Creative Commons license. &lt;a href="http://www.flickr.com/photos/joshnunn/547178990/in/set-72157601413422631/"&gt;Source&lt;/a&gt;
&lt;/span&gt;

&lt;/div&gt;
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Browsers such as Firefox and Internet Explorer 7 allow users to middle-click on links to open them in a new tab. Oftentimes, JavaScript will be used to add an onclick event to a link that supersedes the link itself. But, when a Firefox or IE7 user middle-clicks the link they may be confronted with any number of sub-par user experiences, such as the new tab containing the same page they were on, or a blank page.
&lt;/p&gt;&lt;p&gt;In order to prevent this from happening,&lt;b&gt; a non-JavaScript fallback must be present&lt;/b&gt;. Some people only think about the small (estimated less than 5%) amount of users who have JavaScript disabled, and choose not to support those users. That's a conscious decision and I certainly understand it, and condone it as long as there are clearly defined messages to the JS-disabled user that they need to enable JavaScript to use the page.&lt;/p&gt;
&lt;p&gt;However, what some people fail to recognize is that even the 95% of users with JavaScript enabled will have sub-par user experiences if there are not non-JS fallbacks cases like this, where middle-clicking a link does nothing but waste the user's time. In order to offer the best user experience and fully utilize the capabilities of the browser, a conscientious JavaScript developer must take a number of measures that might not be apparent at first glance.
&lt;/p&gt;&lt;h3&gt;When Should Middle-Click Functionality Be Retained?&lt;/h3&gt;
&lt;p&gt;
There are many uses for JavaScript onclick events. Not all of them will need to support the middle click. To determine if it does, ask yourself if it appears as a link to the user. If it looks like a link (be it text, image or button that appears to lead to another page) then it should support middle-click behavior. If it is another use for an &lt;span style="font-family:Courier New;"&gt;onclick&lt;/span&gt; event, for instance, a button that clearly performs an action on the current page, then no alternative is necessary.&lt;/p&gt;
&lt;p&gt;Take the case of a fancy search results widget that heavily uses JavaScript and Ajax to present search results. Users with JavaScript disabled are presented with instructions on how to enable it, and informed that they won't be able to use the site with out it. So far so good, but unless the search results have a non-JavaScript fallback (unlikely) then middle-clicking them will not have the expected result of some users, which is to take the user to a product detail page.
&lt;/p&gt;&lt;p&gt;A real life example: I was interested in tickets to a jazz show and visited the tickets page for that festival. It has a link saying "Watch a video of this artist." I middle-clicked the link, as I usually do, but the next tab contained the exact same information I had just seen-- no video in sight. I inspected the HTML to see that it was a link, but the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; was set to &lt;span style="font-family:Courier New;"&gt;"#"&lt;/span&gt;, in other words, an empty name on the same page.&lt;/p&gt;&lt;p&gt;When I left-clicked the anchor tag, it executed a JavaScript function and opened a popup showing the video. But, middle-clicking proved pointless, as it was a "dummy" anchor tag that should have been a span with &lt;span style="font-family:Courier New;"&gt;cursor: pointer&lt;/span&gt; in the CSS.
&lt;/p&gt;
&lt;p&gt;In fact, I quite commonly see JavaScript &lt;span style="font-family:Courier New;"&gt;onclick&lt;/span&gt; events on anchor tags, where the anchor tag &lt;b&gt;serves no other purpose than to make the mouse cursor a pointer&lt;/b&gt;. Take the following code, for example:
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-family:Courier New;"&gt;&amp;lt;a href="#" onclick="showMoreResults();"gt;Show more results&amp;lt;/a&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you left-click the link, it will take you to the top of the page (implicit in the &lt;span style="font-family:Courier New;"&gt;"#"&lt;/span&gt; name) and execute the &lt;span style="font-family:Courier New;"&gt;showMoreResults()&lt;/span&gt; function, which does an Ajax call to fetch more search results, let's say. So far so good. But if you middle-click the link, it will take you to the same page &lt;i&gt;without&lt;/i&gt; executing the function. Furthermore, if it's a complex JavaScript application, the state of the application may be lost. In the case of search results, the newly-opened tab may have reset back to the original state of the application, frustrating the user. Of course they can just close the tab and use their existing tab, so all is not lost, but it is still a waste of time from the user's perspective.&lt;/p&gt;&lt;p&gt;If it is truly a JavaScript feature which does not appear as a link, the wise developer would remove the user's ability to middle-click it. By changing it to a span tag, middle-clicking would do nothing.&lt;/p&gt;&lt;p&gt;On the other hand, if it actually looks like a link (and in this case, I think it does), then a middle-click fallback would be nice. Say the user wants to open the next page of search results in the new tab, but stay on the existing page in this tab. Middle-clicking should work, right?
&lt;/p&gt;
&lt;h3&gt;How to Retain Middle-Click Functionality
&lt;/h3&gt;
&lt;p&gt;
The way to do this is to set the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; attribute of your anchor tags to a page presenting the user with the same content they would get by left-clicking. So, if your app uses Ajax to load in new results by left-clicking, then middle-clicking should take them to the same results on a new page. This is accomplished by &lt;b&gt;setting the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; attribute with the correct URL&lt;/b&gt; to the content. If you're on &lt;span style="font-family:Courier New;"&gt;search-results.php?page=1&lt;/span&gt; then you would need to set the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; to be &lt;span style="font-family:Courier New;"&gt;search-results.php?page=2&lt;/span&gt;. The solution varies from app to app but the general idea is to make sure that the &lt;span style="font-family:Courier New;"&gt;href &lt;/span&gt;of the link leads to the content advertised in the link.
&lt;/p&gt;&lt;p&gt;Next, you need to make sure the onclick event returns false. If you're using inline event registration, it looks like this:
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-family:Courier New;"&gt;&amp;lt;a href="search-results.php?page=2" onclick="showMoreResults(); return false;"&amp;gt;Show more results&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;
This is &lt;b&gt;the same as a&lt;/b&gt; &lt;b&gt;non-JavaScript fallback&lt;/b&gt; &lt;b&gt;for links.&lt;/b&gt; It's a good idea to do this anyway, regardless of middle-click support, as approximately 1-in-20 users will have JS disabled anyway (although this number may vary depending on your particular target market).&lt;/p&gt;&lt;p&gt;Something else to keep in mind is that if you are outputting the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; from the server and then showing new results with JavaScript, you'll need to update the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; tag as well. Otherwise, you could go to page 1, click "Show more results" and view page 2's results, and then middle-click "Show more results" and be presented with page 2's results again. Why? Because the href was set on page 1 to show page 2's results, and the JavaScript loaded in new results using Ajax. The solution to this is to make sure you update the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; to display the correct content each time the application state changes, be it with Ajax or otherwise.&lt;/p&gt;&lt;p&gt;It's fairly straightforward-- if you're on page 10, then when the &lt;span style="font-family:Courier New;"&gt;showMoreResults()&lt;/span&gt; function is called you load in new results for page 11 with Ajax, and set the &lt;span style="font-family:Courier New;"&gt;href&lt;/span&gt; of the "Show more results" link to point to page 12.
&lt;/p&gt;&lt;p&gt;This is just one example using search results, but the same principle applies to any JavaScript actions that the user perceives as links. When middle-clicking the link, or clicking it with JavaScript disabled, the user should be presented with the right content. Otherwise, they will feel like the site is broken, or like they did something wrong. Instead, make sure you've always placed non-JavaScript and middle-click fallbacks in your pages.
&lt;/p&gt;&lt;p&gt;Whenever adding an &lt;span style="font-family:Courier New;"&gt;onclick&lt;/span&gt;, ask yourself if it looks like a link or a button that would take the user to a new page. Unless the &lt;span style="font-family:Courier New;"&gt;onclick&lt;/span&gt; is operating directly on the contents of the current page and it's obvious to the user, consider using the methods outlined above.
&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8272164501500662312?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8272164501500662312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8272164501500662312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8272164501500662312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8272164501500662312'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/retaining-middle-click-functionality.html' title='Retaining Middle-Click Functionality With JavaScript'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8558058986645913353</id><published>2008-04-25T19:44:00.001-07:00</published><updated>2008-04-25T19:44:25.510-07:00</updated><title type='text'>IE Plugin to Detect JavaScript Memory Leaks</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;p&gt;Microsoft has released a free beta version of a plugin for Internet Explorer that looks for memory leaks. The plugin, plainly titled &lt;i&gt;JavaScript Memory Leak Detector&lt;/i&gt; &lt;i&gt;&lt;em&gt;(&lt;/em&gt;&lt;a mce_href='http://www.mseurojobs.members.winisp.net/JSLeaksDetector.msi.zip' href='http://www.mseurojobs.members.winisp.net/JSLeaksDetector.msi.zip' title='download installer' class=''&gt;&lt;em&gt;download&lt;/em&gt;&lt;/a&gt;&lt;/i&gt;&lt;em&gt;)&lt;/em&gt;, is available immediately and tests for both IE6 and IE7 leaks. Apparently, IE6 has far more leaks -- any time when you have a circular reference between DOM objects and JavaScript objects a leak would occur.&lt;/p&gt;

&lt;p&gt;Why are leaks a problem? Because the RAM leaked by a page will remain in use until the browser is closed. For developers of websites with heavy JavaScript usage, memory leaks can be a nightmare. I once worked on a site that would climb to hundreds of megabytes after a few pages of data loaded in through Ajax. Then, the RAM would continue to stay in use until I closed and restarted the browser.&lt;/p&gt;



&lt;a href='http://blogs.msdn.com/gpde/pages/javascript-memory-leak-detector.aspx'&gt;Excerpt from the article "JavaScript Memory Leak Detector"&lt;/a&gt; 
&lt;blockquote&gt;&lt;p mce_keep='true'&gt;&lt;img mce_src='http://blogs.msdn.com/photos/gpdepix/images/7108452/original.aspx' src='http://blogs.msdn.com/photos/gpdepix/images/7108452/original.aspx'/&gt;&lt;/p&gt; &lt;p mce_keep='true'&gt;The IE team has been working hard to solve the problem. With the initial versions of Internet Explorer 6 practically all circular references between Javascript and DOM objects caused a memory leak.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
    It seems than an update to IE6 alleviated this problem somewhat, but there are probably still many users who haven't upgraded, and even the later versions of IE6 and current versions of IE7 still have problems. Most of the problems are caused by closures, which really shouldn't be an issue, as Firefox, Opera and Safari generally handle them fine. I use closures all the time in my code so I shudder to think of what leaks lie beneath. But, I'm about to download this leak detector and give it a try. From the screenshots, it doesn't look too appealing, but I'm curious to find what it will detect on the past few sites I've made.
&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8558058986645913353?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8558058986645913353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8558058986645913353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8558058986645913353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8558058986645913353'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/ie-plugin-to-detect-javascript-memory.html' title='IE Plugin to Detect JavaScript Memory Leaks'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-8100141840507240503</id><published>2008-04-24T22:39:00.001-07:00</published><updated>2008-05-04T17:00:52.175-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cms'/><title type='text'>Using Blogger for Content Management</title><content type='html'>&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Despite the name, &lt;a href="http://www.blogger.com/"&gt;Blogger&lt;/a&gt; isn't just limited to blogs. It actually makesfor  a nifty Content Management System (CMS) for a wide range of sites, including e-commerce, informational and educational sites.
&lt;/p&gt;&lt;p&gt;
I've found it to be an easy and inexpensive (well, free) solution for simple content management, albeit a comparatively inflexible one. You won't get the rich plugin library of blogging platforms like &lt;a href="http://www.wordpress.org/"&gt;WordPress&lt;/a&gt; or CMS's like &lt;a href="http://www.joomla.org/"&gt;Joomla&lt;/a&gt;, &lt;a href="http://www.pligg.com/"&gt;Pligg&lt;/a&gt; or &lt;a href="http://www.drupal.org/"&gt;Drupal&lt;/a&gt;. But you will get the benefit of having a very fast setup time. I estimate once you get good at it, it only takes 15 minutes to be up and running with Blogger (not counting time developing the template of course).
&lt;/p&gt;&lt;p&gt;

If you already have an existing site layout, adding in Blogger functionality is a snap. Blogger uses special markup that is compartmentalized and easily pasted into an existing HTML layout.
&lt;/p&gt;&lt;p&gt;

Also, when deploying to your own web server, Blogger plays nice with with PHP. I'm not sure about other web languages such as ASP or Perl/Mason, but I imagine as long as it's an interpreted language, it should be fine.
&lt;/p&gt;&lt;p&gt;

Blogger is completely transparent to use. In other words, your users will have no idea you're using Blogger. One caveat: If you enable comments on your posts then it will be revealed when a user clicks to add a comment.
&lt;/p&gt;&lt;p&gt;

&lt;/p&gt;&lt;h3&gt;Setting up a Blog&lt;/h3&gt;
&lt;p&gt;
You have three options for hosting the blog. You can get free hosting and a sub-domain at blogspot.com, for instance, thetruetribe.blogspot.com. Or, you can register your own domain name with Blogger for a small fee (e.g. thetruetribe.com). Or, if you already have hosting and a domain name with another provider, you can publish to that domain from Blogger.
&lt;/p&gt;&lt;p&gt;

By far, most people have a sub-domain at blogspot.com. But, except for personal blogs, this isn't really appropriate most of the time. Although I do see e-commerce sites have blogs at blogspot.com addresses, this is somewhat of a faux pas in my opinion.
&lt;/p&gt;&lt;p&gt;

One reason not to have your blog on a separate domain is that it divides resources. If you have both &lt;span style="font-style: italic;"&gt;yoursite.com&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;yoursite.blogspot.com&lt;/span&gt;, the SEO will be twice as difficult as keyword relevance and backlinks will be split between the two web properties. From an SEO standpoint (and probably from a user's standpoint as well), it's ideal to have the blog or news page be on the same domain as the main site. You could also publish the blog to a sub-domain of the site, for instance &lt;span style="font-style: italic;"&gt;blog.yourdomain.com&lt;/span&gt;, without ill effect.
&lt;/p&gt;&lt;p&gt;

My recommendation is to go for one of the other two options unless it's a personal site, as you will want to have a custom domain in order to rank well for SEO and also for users to be able to easily recall the domain and access it.
&lt;/p&gt;&lt;p&gt;

The second option, registering the domain through Blogger and having them host it, has the benefit that you get free hosting and can use their powerful XML templates. The XML templates were released in 2007 and seem to have been complete rewrite of their templating engine. You don't get this functionality when publishing to your own FTP site, so this is the best option if you want to fully utilize what Blogger has to offer. Blogger's XML templates allow easy drag-and-drop rearranging of widgets on the page, as well as a variety of built in widgets including RSS feed aggregators, image galleries and so on.
&lt;/p&gt;&lt;p&gt;

The third option, publishing to your own FTP site, is appropriate if you already have a domain name and hosting or if you wish to utilize the flexibility having your own hosting can give you. But, take note that you will be limited to only using "Blogger 1.0" templates, without any of the new XML features or widgets. Still, this is usually sufficient for simple content management.&lt;/p&gt;

&lt;h3&gt;Publishing Via FTP from Blogger&lt;/h3&gt;
Here's a walkthrough to getting set up with Blogger on your own FTP server.
&lt;ol&gt;&lt;li&gt;Go to &lt;a href="http://www.blogger.com/"&gt;www.blogger.com&lt;/a&gt; and click "Create blog now"&lt;/li&gt;&lt;li&gt;Don't bother filling out any of the information just yet. Instead, click on "Advanced Blog Setup"
&lt;img src="http://lh5.ggpht.com/jdempcy/SBFmXv7ldmI/AAAAAAAAABk/EQfQsFqTNYA/%5BUNSET%5D.jpg" style="max-width: 800px;" /&gt;

&lt;/li&gt;&lt;li&gt;On the following page you can enter account details for your FTP server. You can choose what path and filename to publish to, as well as whether to publish using FTP or &lt;a href="http://en.wikipedia.org/wiki/SSH_file_transfer_protocol"&gt;SFTP&lt;/a&gt;. You can choose to publish to a .html file (&lt;i&gt;e.g.&lt;/i&gt; &lt;span style="font-family:Courier New;"&gt;index.html&lt;/span&gt;) or a .php file if your hosting supports it.
&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That's it! Assuming all the details have been entered correctly, Blogger should be set up to publish files to your FTP server now. It will publish the main page at the URL you specified, as well as archive pages and individual "permalink" pages for posts.&lt;/p&gt;

&lt;h3&gt;Customizing the Blogger Template&lt;/h3&gt;&lt;p&gt; After setting up the FTP details, The following page presents readymade templates for Blogger. I'll assume you already have a layout you'd like to use. If not, then now would be a good time to make one.&lt;/p&gt;

&lt;p&gt;Since we don't need to use the template for any layout, CSS or HTML other than the Blogger-specific code, it doesn't matter a great deal which template you choose. But for now, just choose Minima, so we're working with the same code base.&lt;/p&gt;
&lt;p&gt;Select Minima, continue, and publish a post (the obligatory "Hello, world!" of your new blog). The click on the Template tab to get down to business, cut-and-paste style.&lt;/p&gt;

&lt;img src="http://lh4.ggpht.com/jdempcy/SBFo_f7ldnI/AAAAAAAAABs/coMYWTbCLbk/%5BUNSET%5D.jpg"  /&gt;
&lt;p&gt;The next step is to open up your layout file in the editor of your choice (I prefer SciTE and Aptana personally) and get ready to cut-and-paste. &lt;/p&gt;
&lt;p&gt;The first tags to grab are &amp;lt;$BlogPageTitle$&amp;gt;  and &amp;lt;$BlogMetaData$&amp;gt;, which output the title of your blog and hook up the RSS feeds, respectively. The &amp;lt;$BlogPageTitle$&amp;gt; tag can be outputted as the page title (i.e. in &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt; tags) as well as the header, in an &amp;lt;h1&amp;gt;. &lt;/p&gt;
The resulting code should look like this:&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;
&amp;lt;head&amp;gt;
   &amp;lt;title&amp;gt;&amp;lt;$BlogPageTitle$&amp;gt;&amp;lt;/title&amp;gt;
   &amp;lt;$BlogMetaData$&amp;gt;
&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;/p&gt;&lt;p&gt;The &amp;lt;$BlogMetaData$&amp;gt; tag outputs a lot of good stuff including all flavors of RSS feeds (RSS 2.0, RSD, Atom).&lt;/p&gt;&lt;p&gt;Next, grab everything between and including the &amp;lt;Blogger&amp;gt;&amp;lt;/Blogger&amp;gt; tags. You'll want to paste this into the main wrapper of you site, where you want the dynamic content to be. This is typically something like &amp;lt;div id="main-content"&amp;gt;. It's a lot of code to paste, and the indentation may be a bit off, but if you've correctly copied it, it should work fine.&lt;/p&gt;

As for styling, you can inspect the resulting HTML using Firebug and see the pre-defined classes. Or you can always add classes yourself to the Blogger code. Just make sure not to add any &lt;span style="font-family:Courier New;"&gt;id&lt;/span&gt;s since the code will be repeated once for each post.&lt;p&gt;

&lt;/p&gt;&lt;h3&gt;The Sidebar: Recent Posts, Archives, Profile&lt;/h3&gt;
&lt;p&gt;You may want to include archived posts, recent posts or your Blogger profile. It's quite simple, really. Scrolling down towards the bottom of the &lt;i&gt;Minima&lt;/i&gt; HTML/Blogger tag source, you'll find an area marked with the comment "Begin #sidebar." Here is where we'll find the tags:&lt;/p&gt;
&lt;span style="font-family:Courier New;"&gt;   &amp;lt;$BlogMemberProfile$&amp;gt;
&lt;/span&gt;
This one outputs your Blogger profile pic and description. Nothing too useful but I guess it's nice for a blog site.
&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;ul id="recently"&amp;gt;
   &amp;lt;BloggerPreviousItems&amp;gt;
       &amp;lt;li&amp;gt;&amp;lt;a href="&amp;lt;$BlogItemPermalinkURL$&amp;gt;"&amp;gt;&amp;lt;$BlogPreviousItemTitle$&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/BloggerPreviousItems&amp;gt;
 &amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;This code outputs the recent posts, with links to their individual permalink pages.&lt;/p&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;ul class="archive-list"&amp;gt;
        &amp;lt;BloggerArchives&amp;gt;
       &amp;lt;li&amp;gt;&amp;lt;a href="&amp;lt;$BlogArchiveURL$&amp;gt;"&amp;gt;&amp;lt;$BlogArchiveName$&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
     &amp;lt;/BloggerArchives&amp;gt;

 &amp;lt;/ul&amp;gt;
&lt;/span&gt;&lt;p&gt;
This code links to the archive pages.
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;Hopefully this post has proven helpful and will give you the confidence to publish your own Blogger-powered dynamically driven sites! It's nothing fancy, but it gets the job done and is a breeze to set up. Post comments with any other tweaks you've found or issues you run into. Blogger certainly has its shortcomings but for the price (i.e. free), I'm not complaining, and it does a lot of things right too.&lt;/p&gt;&lt;p&gt;Have fun and happy bloggin'!&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-8100141840507240503?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/8100141840507240503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=8100141840507240503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8100141840507240503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/8100141840507240503'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/using-blogger-for-content-management.html' title='Using Blogger for Content Management'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/jdempcy/SBFmXv7ldmI/AAAAAAAAABk/EQfQsFqTNYA/s72-c/%5BUNSET%5D.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3282914198851382003</id><published>2008-04-23T19:28:00.000-07:00</published><updated>2008-04-24T11:14:37.438-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>PHP Starter Template</title><content type='html'>&lt;p&gt;Since Alex posted his &lt;a href="http://www.thetruetribe.com/2008/04/html-template-starter.html"&gt;HTML Starter Template&lt;/a&gt; article last week I was inspired to condense some of my starter code for building sites in PHP.
&lt;/p&gt;&lt;p&gt;
I use Aptana to code, so whenever I make a new project, I start by copying in files from 2 template projects I've made, &lt;span style="font-style: italic;"&gt;xhtml-template&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;php-template&lt;/span&gt;. Each project has its own file structure and stub files. Since Alex already posted a thorough XHTML starter, I'll focus on the PHP template today.
&lt;/p&gt;&lt;p&gt;

The files and folders I include are as follows:
&lt;/p&gt;
&lt;ul style="list-style-type: disc"&gt;&lt;li&gt;components
&lt;ul style="padding-left: 30px; list-style-type: circle"&gt;&lt;li&gt;banner.php&lt;/li&gt;
&lt;li&gt;doctype.php&lt;/li&gt;
&lt;li&gt;footer.php&lt;/li&gt;
&lt;li&gt;global.php&lt;/li&gt;
&lt;li&gt;head.php&lt;/li&gt;
&lt;li&gt;sidebar.php&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;css
&lt;ul style="padding-left: 30px; list-style-type: circle"&gt;&lt;li&gt;styles.css&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;images
&lt;/li&gt;
&lt;li&gt;js
&lt;ul style="padding-left: 30px; list-style-type: circle"&gt;&lt;li&gt;main.js&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;offline-files
&lt;ul style="padding-left: 30px; list-style-type: circle"&gt;&lt;li&gt;docs&lt;/li&gt;
&lt;li&gt;mocks&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;index.php&lt;/li&gt;
&lt;/ul&gt;All of the PHP files in the &lt;span style="font-style: italic;"&gt;components&lt;/span&gt; folder can be used by the pages on the site if need be, or deleted if not.
&lt;br /&gt;&lt;br /&gt;
This is how I include the files on the homepage, &lt;span style="font-style: italic;"&gt;index.php&lt;/span&gt;:

&lt;pre name="code" class="php"&gt;


&amp;lt;?
   include($_SERVER['DOCUMENT_ROOT'] . '/components/global.php');

 $metaTags['keywords'] = '';
 $metaTags['description'] = '';
 $metaTags['author'] = '';
 $metaTags['copyright'] = '';
 $metaTags['charset'] = 'UTF-8';
 
 $pageTitle = '';
 $pageId = '';

   include($_SERVER['DOCUMENT_ROOT'] . '/components/head.php');
?&amp;gt;

&amp;lt;body&amp;gt;
   &amp;lt;? include($_SERVER['DOCUMENT_ROOT'] . '/components/banner.php'); ?&amp;gt;


   &amp;lt;? include($_SERVER['DOCUMENT_ROOT'] . '/components/footer.php'); ?&amp;gt; 
&amp;lt;/body&amp;gt;
&lt;/pre&gt;
&lt;h3&gt;Inside the Components Directory&lt;/h3&gt;
&lt;p&gt;
Here are the default contents of those files:&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;h4&gt;global.php&lt;/h4&gt;
&lt;pre name="code" class="php"&gt;
&amp;lt;?php
 $metaTags = new ArrayObject();
 $metaTags['keywords'] = '';
 $metaTags['description'] = '';
 $metaTags['author'] = '';
 $metaTags['copyright'] = '';
 $metaTags['charset'] = 'UTF-8';
 
 $pageTitle = '';
?&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
This file contains global variables used by the whole site. You could store constants here as well. The $metaTags array stores the default meta tags for the site, which can be overridden on a per-page basis.
&lt;/p&gt;&lt;p&gt;
This page also contains the default page title for the whole site, stored in the $pageTitle variable. Again, this should be overridden on a page by page basis (for best SEO benefits) but it's just a fallback in case you forget to define the title of that page.&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;h4&gt;banner.php&lt;/h4&gt;
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;div id="banner"&amp;gt;
 
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The banner file doesn't actually contain any PHP code, just an empty div tag. It's a stub, ready to be added to if the site needs a banner (and really, most sites do).
&lt;/p&gt;&lt;p&gt;
You could go a step farther by adding in a default image, or h1 and h2 tags with &lt;a href="http://www.stopdesign.com/articles/replace_text/"&gt;CSS image replacement&lt;/a&gt;, but for me, this is sufficient.&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;h4&gt;doctype.php&lt;/h4&gt;
&lt;pre name="code" class="php:nocontrols"&gt;
&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
&lt;/pre&gt;
&lt;p&gt;You could combine the doctype file with the head file. It just comes down to preference for how granular you like the files to be, really.&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;h4&gt;footer.php&lt;/h4&gt;
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;div id="footer"&amp;gt;
 
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This is another stub. You could put default information such as copyright (using the &amp;amp;copy; HTML entity perhaps), or a homepage link. But I just leave it empty and customize it for whichever site I'm working on.&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;head.php&lt;/h4&gt;
&lt;pre class="php" name="code"&gt;

&amp;lt;?php include('doctype.php'); ?&amp;gt;

&amp;lt;head&amp;gt;
 
 &amp;lt;!-- CSS --&amp;gt;
 &amp;lt;link rel="stylesheet" href="css/styles.css" /&amp;gt;

 &amp;lt;!-- Meta tags --&amp;gt; 
 &amp;lt;meta name="keywords" content="&amp;lt;?php echo $metaTags['keywords'] ?&amp;gt;" /&amp;gt;
 &amp;lt;meta name="description" content="&amp;lt;?php echo $metaTags['description'] ?&amp;gt;" /&amp;gt;
 &amp;lt;meta name="author" content="&amp;lt;?php echo $metaTags['author'] ?&amp;gt;" /&amp;gt;
 &amp;lt;meta name="copyright" content="&amp;lt;?php echo $metaTags['copyright'] ?&amp;gt;" /&amp;gt;
 &amp;lt;meta name="robots" content="FOLLOW,INDEX" /&amp;gt;
 &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=&amp;lt;?php echo $metaTags['charset'] ?&amp;gt;" /&amp;gt;
 &amp;lt;meta name="MSSmartTagsPreventParsing" content="true" /&amp;gt;
       &amp;lt;meta http-equiv="imagetoolbar" content="no" /&amp;gt;  
 &amp;lt;!-- Title --&amp;gt;
 &amp;lt;title&amp;gt;&amp;lt;?php echo $pageTitle; ?&amp;gt;&amp;lt;/title&amp;gt;
 
 &amp;lt;!-- Shortcut icon --&amp;gt;
 &amp;lt;link rel="shortcut icon" href="/favicon.ico"  /&amp;gt;

&amp;lt;/head&amp;gt;

&lt;/pre&gt;
&lt;p&gt;
The head has some fun features. Let's go through one by one. First we include the doctype, as shown above. Then we start the head and include the default CSS file,  styles.css.
&lt;/p&gt;&lt;p&gt;
Next we include a number of &lt;span style="font-weight: bold;"&gt;meta tags&lt;/span&gt;, including a few you may not have heard about before. For instance, we include     &amp;lt;meta http-equiv="imagetoolbar" content="no" /&amp;gt; which causes IE to stop showing that annoying disk icon in the bottom right of images when you hover over them. We also include copyright and author tags, and another one to inform MS apps not to try to parse it with SmartTags. (I got this one from Blogger templates).&lt;/p&gt;&lt;p&gt;
After that, we just define the title (that's a must) and link the default &lt;span style="font-style: italic;"&gt;favicon&lt;/span&gt; file.&lt;/p&gt;&lt;p&gt;
An observant reader will notice that we &lt;span style="font-weight: bold;"&gt;didn't define the JavaScript in the head&lt;/span&gt;. The reason for this is that it usually hurts page performance to define it in the head. In this page template, I didn't include the link to the template, but I recommend either adding it to the &lt;span style="font-style: italic;"&gt;footer.php&lt;/span&gt; file after the closing div or creating a new file like so:
&lt;br /&gt;&lt;br /&gt;
&lt;/p&gt;&lt;h4&gt;javascript-includes.php&lt;/h4&gt;

&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;script src="/js/main.js" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;h3&gt;Default JavaScript to Include&lt;/h3&gt;
As for JavaScript, I don't have a lot of helper methods or anything that I like to include since that is all taken care of by the library, ideally. But I do include this one piece of code which &lt;span style="font-weight:bold;"&gt;enables CSS background-image caching&lt;/span&gt; in IE:

&lt;pre name="code" class="js:nocontrols"&gt;
// IE6 does not cache CSS background images by default.
// This code enables CSS background caching for the lifespan of the browsing session in IE6.

try {
    document.execCommand('BackgroundImageCache', false,true);
} catch(e) {};

&lt;/pre&gt;
Other than that, I don't really include any boilerplate code. But suggestions are welcome! What default JavaScript templates do you use? Feel free to post your own in the comments.
&lt;br /&gt;&lt;br /&gt;
&lt;h3&gt;Default CSS to Include&lt;/h3&gt;
I am a big fan of &lt;a href="meyerweb.com/eric/tools/css/reset/ "&gt;Eric Meyer's reset styles&lt;/a&gt;. My default CSS pretty much looks like that:

&lt;pre name="code" class="css"&gt;
/* Reset styles (adapted from Eric Meyer's Reset Reloaded) */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
 margin: 0;
 padding: 0;
 border: 0;
 outline: 0;
 font-weight: inherit;
 font-style: inherit;
 font-size: 100%;
 font-family: inherit;
 vertical-align: baseline;
}
/* remember to define focus styles! */
:focus {
 outline: 0;
}
body {
 line-height: 1;
 color: black;
 background: white;
}
ol, ul, li {
 list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
 border-collapse: separate;
 border-spacing: 0;
}
caption, th, td {
 text-align: left;
 font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
 content: "";
}
blockquote, q {
 quotes: "" "";
}

/* Site styles */

/* Legend:


*/

/* Sitewide */

body {
 font-size: 11px;
 font-family: Helvetica, Arial, sans-serif;
 color: #000000;
}

h1 {
 font-weight: bold;
 font-size: 27px;
}

h2 {
 font-weight: bold;
 font-size: 16px;
 color: #000000;
}

h3 {
 color: #000000;
 font-size: 15px;
 font-weight: bold;
}

h4 {
 font-size: 12px;
 font-weight: bold;

}

h5 {
 color: #000000;
 font-size: 11px;
}


a:link {
 color: #000000;
 text-decoration: none;
}
a:visited {
 color: #000000;
 text-decoration: none;
}

a:hover {
 color: #000000;
 text-decoration: underline;
}

a:active {
 color: #000000;
 text-decoration: underline;
}

/* wrapper */

div#wrapper {
    
}

/* banner */

div#banner {
    
}

/* footer */

div#footer {
    
}
&lt;/pre&gt;
&lt;p&gt;
I could probably stand to update the CSS a bit. Right now the stubs are, well, just stubs-- I intend to add stronger default styles that are consistent with most site defaults nowadays. Maybe that will be the topic of a future article. Regardless, this is a nice blank slate to start out with.&lt;/p&gt;
&lt;p&gt;What is &lt;span style="font-weight:bold;"&gt;your&lt;/span&gt; default template for starting websites? Comments are encouraged.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-3282914198851382003?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/3282914198851382003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3282914198851382003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3282914198851382003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3282914198851382003'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/php-starter-template.html' title='PHP Starter Template'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-4509065852729918130</id><published>2008-04-21T14:42:00.001-07:00</published><updated>2008-04-21T14:42:52.946-07:00</updated><title type='text'>MooTools 1.1 Cheatsheet</title><content type='html'>&lt;div xmlns='http://www.w3.org/1999/xhtml'&gt;&lt;a title='Get the mootools 1.1 cheat sheet by visiting this link' href='http://mediavrog.net/blog/2007/06/15/mootools/mootools-cheat-sheet/'&gt;&lt;img style='float: right;' alt='Get the mootools 1.1 cheat sheet by visiting this link' src='http://mediavrog.net/blog/wp-content/uploads/2007/06/mootools_11_cheat_sheet_mediavrognet_small.thumbnail.png'/&gt;&lt;/a&gt;This is probably old news to most MooTools developers out there but if you are just getting into MooTools, it's a life-saver. In June 2007, &lt;a title='About Maik Vlcek' href='http://mediavrog.net/blog/about/'&gt;Maik Vlcek&lt;/a&gt; of the &lt;a href='http://mediavrog.net/blog'&gt;mediaVROG Blog&lt;/a&gt; posted this excellent MooTools cheatsheet.&lt;br/&gt;&lt;br/&gt;Prior to this, I used the also-excellent MooTools beta cheatsheets released by &lt;a target='_blank' title='snook.ca in neuem Fenster öffnen' href='http://snook.ca/archives/javascript/mootools_r83_cheatsheet/'&gt;snook.ca&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Excerpt:&lt;br/&gt;&lt;br/&gt;&lt;a href='http://mediavrog.net/blog/2007/06/15/mootools/mootools-cheat-sheet/'&gt;mootools 1.1 - cheat sheet | mediaVROG Blog&lt;/a&gt; &lt;br/&gt; &lt;blockquote&gt;  			 				&lt;p&gt;Nine hours have passed and I'm finally up to present the &lt;span class='hilite'&gt;mootools&lt;/span&gt; &lt;span class='hilite2'&gt;1&lt;/span&gt;.&lt;span class='hilite1'&gt;&lt;span class='hilite2'&gt;1&lt;/span&gt;&lt;/span&gt; cheat sheet.&lt;/p&gt; &lt;p&gt;All classes documented have found their way into this sheet. Well, I had to embezzle the plugins as it would have gone beyond the scope of creating a compact overview of &lt;span class='hilite'&gt;mootools&lt;/span&gt;.&lt;/p&gt; &lt;p&gt;For all you &lt;span class='hilite'&gt;mootools&lt;/span&gt; lovers, here it is! Go print and paste it on your walls &lt;img class='wp-smiley' alt=';)' src='http://mediavrog.net/blog/wp-includes/images/smilies/icon_wink.gif'/&gt; Enjoy!&lt;a title='Get the mootools 1.1 cheat sheet by visiting this link' href='http://mediavrog.net/blog/2007/06/15/mootools/mootools-cheat-sheet/'/&gt;&lt;/p&gt;&lt;p&gt;&lt;a title='Get the mootools 1.1 cheat sheet by visiting this link' href='http://mediavrog.net/blog/2007/06/15/mootools/mootools-cheat-sheet/'&gt;&lt;span class='hilite'&gt;Link&lt;br/&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-4509065852729918130?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/4509065852729918130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=4509065852729918130' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4509065852729918130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4509065852729918130'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/mootools-11-cheatsheet.html' title='MooTools 1.1 Cheatsheet'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-2408061958634953282</id><published>2008-04-14T18:38:00.001-07:00</published><updated>2008-04-14T18:51:07.371-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title type='text'>HTML Template Starter</title><content type='html'>Dreamweaver, Aptana, and all the other editors have a base HTML code for the &amp;lt;html&amp;gt;, &amp;lt;head&amp;gt;, and &amp;lt;body&amp;gt;. I don't think any of these editors supply the web developer with all the need for a successful websites. I made one with comments that you can copy and paste in. 

&lt;pre class="js:nocontrols" name="code"&gt;
&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt; &amp;lt;!-- Just in case someone integrates a CMS that uses old tags like &amp;lt;font&amp;gt; or &amp;lt;b&amp;gt; --&amp;gt;
&amp;lt;html xmlns=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;&amp;gt;
 &amp;lt;head&amp;gt;
  &amp;lt;meta name=&amp;quot;keywords&amp;quot; content=&amp;quot;&amp;quot; /&amp;gt; &amp;lt;!-- Keywords relevent to your website or for SEO purposes go here. --&amp;gt;
  &amp;lt;meta name=&amp;quot;description&amp;quot; content=&amp;quot;&amp;quot; /&amp;gt; &amp;lt;!-- Sentences that describe your site and will be shown on search engines go here.  --&amp;gt;
  &amp;lt;meta name=&amp;quot;author&amp;quot; content=&amp;quot;&amp;quot; /&amp;gt; &amp;lt;!-- The author of the website, or webmaster's name goes here --&amp;gt;
  &amp;lt;meta name=&amp;quot;copyright&amp;quot; content=&amp;quot;Copyright &amp;Acirc;&amp;copy; 2007 YOUR_COMPANY_HERE.&amp;quot; /&amp;gt; &amp;lt;!-- This way you are more legally protected --&amp;gt;
  &amp;lt;meta name=&amp;quot;robots&amp;quot; content=&amp;quot;FOLLOW,INDEX&amp;quot; /&amp;gt; &amp;lt;!-- This makes sure search engines check out your website --&amp;gt;
  &amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=iso-8859-1&amp;quot; /&amp;gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;styles.css&amp;quot; /&amp;gt; &amp;lt;!-- You'll need a stylesheet. Most people call it styles.css. Which folder it goes in is up to you --&amp;gt;
  &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
 &amp;lt;/head&amp;gt;
 &amp;lt;body&amp;gt;
 &amp;lt;!--[if lte IE 5]&amp;gt;  &amp;lt;!-- These are IE conditional comment style classes to fix all those dumb IE problems --&amp;gt;
 &amp;lt;div class=&amp;quot;ie&amp;quot;&amp;gt;
 &amp;lt;![endif]--&amp;gt;
 &amp;lt;!--[if IE 6]&amp;gt;
 &amp;lt;div class=&amp;quot;ie ie6&amp;quot;&amp;gt;
 &amp;lt;![endif]--&amp;gt;
 &amp;lt;!--[if IE 7]&amp;gt;
 &amp;lt;div class=&amp;quot;ie ie7&amp;quot;&amp;gt;
 &amp;lt;![endif]--&amp;gt;



 &amp;lt;script src=&amp;quot;http://www.savethedevelopers.org/say.no.to.ie.6.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt; &amp;lt;!-- You'll probably need some sort of script and it should go to the bottom of the page; usually called main.js or jquery.js. This will warn your users they are using IE6. Bad user; no internet. --&amp;gt;
 &amp;lt;!--[if IE]&amp;gt; &amp;lt;!-- End of IE conditional comments --&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;![endif]--&amp;gt;  
 &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-2408061958634953282?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/2408061958634953282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=2408061958634953282' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2408061958634953282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/2408061958634953282'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/html-template-starter.html' title='HTML Template Starter'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7540100925493163465</id><published>2008-04-10T21:54:00.000-07:00</published><updated>2008-04-10T22:24:40.724-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='seo'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>What Are Good Styles to Use in All CSS Stylesheets?</title><content type='html'>These are a list of styles you &lt;b&gt;can't live without&lt;/b&gt;. I suggest using these in all your stylesheets to help in a variety of situations.

Because &lt;b&gt;headers matter A LOT in SEO&lt;/b&gt;. It is important to &lt;b&gt;avoid using h1, h2, h3, etc for ambiguous content&lt;/b&gt; such as "Contact Me" or "Support" titles that sit at the top of your page. What's more important for &lt;b&gt;headers is to use them for things specific to your site&lt;/b&gt;. For The True Tribe we would use headers for "CSS Good Practices" or "Alex Grande" , but not "Our Heros." At least we should... The way around this is to make classes called h1, h2, h3, etc and give them properties that are similar to headers.

&lt;pre class="js:nocontrols" name="code"&gt;
.h1 {
   font-size: 22px;
   font-weight: 600;
}

.h2 {
   font-size: 20px;
   font-weight: 600;
}

.h3 {
   font-size: 18px;
   font-weight: 600;
}

.h4 {
   font-size: 16px;
}

.h5 {
   font-size: 14px;
}
&lt;/pre&gt;
&lt;b&gt;Other font related styles&lt;/b&gt; include, but not limited to...
&lt;pre class="js:nocontrols" name="code"&gt;
.bold {
   font-weight: 600; /* I use this one a lot! Instead of using the b tag use 
&lt;span class="bold"&gt;I'm Bold&lt;/span&gt;...that's what she said...*/
}

.underline {
   text-decoration: underline;
}
&lt;/pre&gt;
&lt;b&gt;For positioning styles...&lt;/b&gt;
This is when all the children of a parent are removed from the page flow and need something to fill the wrapper parent.
&lt;pre class="js:nocontrols" name="code"&gt;

.clearFix { 
 clear: both;
 height: 0;
 width: 0;
 border: 0;
}
&lt;/pre&gt;

There are more but these are ones I use almost everyday for my clients. I hope you'll find it useful as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7540100925493163465?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7540100925493163465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7540100925493163465' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7540100925493163465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7540100925493163465'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/what-are-good-styles-to-use-in-all-css.html' title='What Are Good Styles to Use in All CSS Stylesheets?'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-6119545841504197838</id><published>2008-04-10T17:10:00.000-07:00</published><updated>2008-05-21T02:22:26.406-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='firebug'/><title type='text'>Redefining console.log() For Browsers Without Firebug</title><content type='html'>&lt;img src="http://www.thetruetribe.com/uploaded_images/firebug_logo-781750.png" alt="Firebug" border="0" /&gt;
&lt;p&gt;
I use Firebug's console.log() method extensively when developing code. But, when viewing the site in Internet Explorer, Safari, Opera or other browsers that don't have Firebug, console.log() throws an error. Rather than wrap each log statement in a &lt;a href="http://en.wikipedia.org/wiki/Exception_handling"&gt;try/catch&lt;/a&gt;, I just add this bit of code during development that checks for Firebug and redefines the console.log() method if Firebug isn't installed:
&lt;/p&gt;
&lt;pre class="js:nocontrols" name="code"&gt;
 // When logging messages with console.log()
 // if user doesn't have Firebug, write them to the DOM instead
 if (typeof console == "undefined") {
 
  // Create an unordered list to display log messages
  var logsOutput = document.createElement('ul');
  document.getElementsByTagName('body')[0].appendChild(logsOutput);
  
  // Define console.log() function
  console = {
   log: function(msg) {
    logsOutput.innerHTML += '&amp;lt;li&amp;gt;' + msg + '&amp;lt;/li&amp;gt;';
   }
  };
 }
&lt;/pre&gt;

&lt;h3&gt;Logging Statements in Production Code&lt;/h3&gt;
If you don't want to have to remove your console.log() statements in production code, you can set a &amp;quot;development mode&amp;quot; flag that ignores log messages.

&lt;pre class="js:nocontrols" name="code"&gt;
var DEVELOPMENT_MODE = true;

// When logging messages with console.log()
// if user doesn't have Firebug, write them to the DOM instead
if (typeof console == "undefined" &amp;&amp; DEVELOPMENT_MODE == true) {
 
  // Create an unordered list to display log messages
  var logsOutput = document.createElement('ul');
  document.getElementsByTagName('body')[0].appendChild(logsOutput);
  
  // Define console.log() function
  console = {
    log: function(msg) {
      logsOutput.innerHTML += '&amp;lt;li&amp;gt;' + msg + '&amp;lt;/li&amp;gt;';
    }
  };
} else if (DEVELOPMENT_MODE == false) {
  console = {
    log: function() {} // Do nothing
  };
}
&lt;/pre&gt;

I made the flag uppercase since it follows &lt;span style="font-weight: bold;"&gt;naming
conventions for constants&lt;/span&gt;. Now you can set the DEVELOPMENT_MODE flag when deploying to production environments and leave your logging messages intact, if you desire.

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

Take note that this adds unnecessary page-weight from the logging messages, so to fully optimize the code, logging should be removed. But, leaving some amount of logging in the production code is probably acceptable, as long as it doesn't add more than a few kilobytes to the page weight. As long as you're using &lt;a href="http://en.wikipedia.org/wiki/Gzip"&gt;GZip&lt;/a&gt;, &lt;a href="http://www.crockford.com/javascript/jsmin.html"&gt;minifying your JavaScript&lt;/a&gt; and serving it with &lt;a href="http://stevesouders.com/hpws/rule-expires.php"&gt;far future expires headers&lt;/a&gt;, a few extra &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; aren't going to hurt anything.

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

&lt;h3&gt;Redefining All Firebug Methods&lt;/h3&gt;
If you use other Firebug methods, such as assert(), trace() or error(), then you may want to use the following code, provided by the developers of Firebug as part of the &lt;a href="http://www.getfirebug.com/lite.html"&gt;Firebug Lite&lt;/a&gt; project.

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

This code redefines all Firebug methods as empty functions when Firebug isn't installed on the browser:

&lt;pre class="js:nocontrols" name="code"&gt;
if (!window.console || !console.firebug) {
  var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
  "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

  window.console = {};
  for (var i = 0; i &lt; names.length; ++i)
    window.console[names[i]] = function() {}
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-6119545841504197838?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/6119545841504197838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=6119545841504197838' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6119545841504197838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/6119545841504197838'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/redefining-consolelog-for-browsers.html' title='Redefining console.log() For Browsers Without Firebug'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-4407171390739781027</id><published>2008-04-06T21:55:00.000-07:00</published><updated>2008-04-17T13:29:53.173-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='sprites'/><category scheme='http://www.blogger.com/atom/ns#' term='tabs'/><title type='text'>How do I make tabs in Jquery? (Without jQ Tabs plugin)</title><content type='html'>Strategies and Technologies:

This is the beginning of a series where I build a tab presented component from scratch. Each series on the tab will increase in functionality and ux. For starters lets just build it. To see the finishing product of this lesson please check out &lt;a href="http://alexgrande.com/flickr-mashup/tab.html"&gt;this link to see a tab example&lt;/a&gt;. Because we are using CSS Sprites there is only one image for the tabs. &lt;a href="http://alexgrande.com/flickr-mashup/tab-select-nonselect.gif"&gt;Check out this link to see the image&lt;/a&gt;.
&lt;br /&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;!-- This is to deal with Internet Explorer--&amp;gt;
&amp;lt;!--[if lte IE 5]&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;div class=&amp;quot;ie&amp;quot;&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;![endif]--&amp;gt;
&amp;lt;!--[if IE 6]&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;div class=&amp;quot;ie ie6&amp;quot;&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;![endif]--&amp;gt;
&amp;lt;!--[if IE 7]&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;div class=&amp;quot;ie ie7&amp;quot;&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;![endif]--&amp;gt;

&amp;lt;!-- This is the list of tabs. Notice the id begins with the content in the tab. This can be easily replaced with 1, 2, 3 using a simple js loop. Or your backend developer can supply you with a variable to make it scalable. --&amp;gt;
&amp;lt;div id=&amp;quot;tabSelection&amp;quot;&amp;gt;
   &amp;lt;div class=&amp;quot;tab-selects&amp;quot; id=&amp;quot;salsa-tab&amp;quot;&amp;gt;
       &amp;lt;h3&amp;gt;salsa&amp;lt;/h3&amp;gt;
   &amp;lt;/div&amp;gt;
   &amp;lt;div class=&amp;quot;tab-selects&amp;quot; id=&amp;quot;fern-tab&amp;quot;&amp;gt;
       &amp;lt;h3&amp;gt;fern&amp;lt;/h3&amp;gt;
   &amp;lt;/div&amp;gt;
   &amp;lt;div class=&amp;quot;tab-selects&amp;quot; id=&amp;quot;jazz-tab&amp;quot;&amp;gt;
       &amp;lt;h3&amp;gt;jazz&amp;lt;/h3&amp;gt; 
   &amp;lt;/div&amp;gt;
   &amp;lt;div class=&amp;quot;tab-selects&amp;quot; id=&amp;quot;sodo-tab&amp;quot;&amp;gt;
       &amp;lt;h3&amp;gt;sodo&amp;lt;/h3&amp;gt;
   &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- This is the content of the tabs. See how the id matches the name in the tab?--&amp;gt;
&amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;
   &amp;lt;div id=&amp;quot;salsa-tab-content&amp;quot; class=&amp;quot;view-content&amp;quot;&amp;gt;
 &amp;lt;img src=&amp;quot;http://farm3.static.flickr.com/2205/2346526197_81a11816fa.jpg?v=0&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;fern-tab-content&amp;quot; class=&amp;quot;view-nonselected view-content&amp;quot;&amp;gt;
 &amp;lt;img src=&amp;quot;http://farm1.static.flickr.com/188/404190495_7c193a1873.jpg?v=0&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;jazz-tab-content&amp;quot; class=&amp;quot;view-nonselected view-content&amp;quot;&amp;gt;
 &amp;lt;img src=&amp;quot;http://farm4.static.flickr.com/3207/2338432523_c9029c38b9.jpg?v=0&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
   &amp;lt;div id=&amp;quot;sodo-tab-content&amp;quot; class=&amp;quot;view-nonselected view-content&amp;quot;&amp;gt;
 &amp;lt;img src=&amp;quot;http://farm4.static.flickr.com/3113/2339197062_01d0950920.jpg?v=0&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;!--[if IE]&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;&amp;lt;![endif]--&amp;gt;
&lt;/pre&gt;


&lt;h4&gt;CSS&lt;/h4&gt;
&lt;pre name="code" class="css:nocontrols"&gt;
body {
margin-top:50px;
}

/* Here are the sprites. Only the left part of the image is shown for the selected tab. I love sprites! */
div.tab-selects {
width:111px;
background:url(tab-select-nonselect.gif) no-repeat;
background-position:left center;
float:left;
margin:-40px 10px 0pt;
position:relative;
cursor:pointer;
height:51px;
}

/* Here is a non selected tab. The image on the right! */
div.tab-nonselected {
background-position:right center;
}

div.view-wrapper {
position:relative;
margin-top:74px;
}

/* IE sucks */
.ie div#content {
clear:both;
margin-top:-10px;
}

div#content {
width:610px;
position:relative;
cursor:default;
background-color:#5C81AD;
margin-top:-1px;
border-bottom:1px solid #9D8979;
border-right:1px solid #9D8979;
border-left:1px solid #9D8979;
height:410px;
}

div.view-content {
top:0px;
position:absolute;
width:100%;
overflow-y:auto;
height:410px;
}

div.tab-selects {
text-align:center;
}

div.view-content img {
padding:23px;
}

div.view-nonselected {
visibility:hidden;
}

&lt;/pre&gt;

&lt;h4&gt;jQuery Javascript Tabs&lt;/h4&gt;
&lt;pre name="code" class="js:nocontrols"&gt;

//The first tab is going to be opened. We need to know that.
$TabIsOpen = $("#tabSelection div:first");  
    
// The click event
 $('.tab-selects').click(
  function() {   
// So if what you click is not the tab that is already opened then lets change its class
   if ($(this) != $TabIsOpen) {
// Look at the CSS to see the properties of this clas
   $TabIsOpen.addClass('tab-nonselected');
    $(this).removeClass('tab-nonselected');
// Now that this tab is selected we gotta remember it.
   $TabIsOpen = $(this);
  
// jQ can be annoying in creating selectors. But basically we take the id of the tab and it is associated with the content item. We just have to add -content to the end. For instance, #salsa-content.
   contentIdChildDiv = "#" + $TabIsOpen.attr("id") + "-content";
// Same deal with the tabs; Hiding and showing.  
 $("div.view-content").addClass("view-nonselected");
   $(contentIdChildDiv).removeClass("view-nonselected");
  }
 });

// We want to make every instance but the first one hidden for both tabs and content. That's what that crazy div:not(div:first) is all about.
$("#content div:not(div:first)").addClass("view-nonselected");
$("#tabSelection div:not(div:first)").addClass("tab-nonselected");

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-4407171390739781027?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/4407171390739781027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=4407171390739781027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4407171390739781027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/4407171390739781027'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/how-do-i-make-tabs-in-jquery-without-jq.html' title='How do I make tabs in Jquery? (Without jQ Tabs plugin)'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-3300778380901705055</id><published>2008-04-02T14:55:00.000-07:00</published><updated>2008-04-03T14:25:19.488-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='challenge'/><title type='text'>JavaScript Challenge: Cardinal Numbers</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/Sesame-Street-Count-to-Ten-Print-C12204839-722892.jpeg"&gt;&lt;img style="cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/Sesame-Street-Count-to-Ten-Print-C12204839-722872.jpeg" alt="" border="0" /&gt;&lt;/a&gt;
&lt;br /&gt;&lt;br /&gt;
This challenge is to write functions to &lt;span style="font-weight: bold;"&gt;add and subtract numbers &lt;/span&gt; using the names of numbers as strings.  More precisely, the challenge is to write add() and subtract() functions that take two strings as input, and return one string. For example:

&lt;pre name="code" class="js:nocontrols"&gt;
add("one", "ten"); // should return "eleven"
subtract("twenty", "fifteen"); // should return "five"
&lt;/pre&gt;

For the purposes of this exercise, we will &lt;span style="font-weight: bold;"&gt;limit the maximum numbers handled to 99&lt;/span&gt;. So, you don't have to handle, say, &lt;span style="font-style: italic;"&gt;add("three-thousand-five-hundred-and-fifty-two", "ten-million-and-seven")&lt;/span&gt;. Though, you certainly get bonus points if you handle this case as well.
&lt;br /&gt;&lt;br /&gt;
Here is my solution below, which is by no means optimal. The following is my first attempt at solving this issue, coded in roughly 30 minutes, so go easy if you find any &lt;a href="http://en.wikipedia.org/wiki/SNAFU"&gt;SNAFUs&lt;/a&gt;.
&lt;br /&gt;&lt;br /&gt;
Note: I prefer 4-space indentation but I set it to 2-space for this article so the code example will fit on the page without horizontal scrolling.

&lt;pre name="code" class="js"&gt;
var cardinalNumbers = {
    "one": 1,
    "two": 2,
    "three": 3,
    "four": 4,
    "five": 5,
    "six": 6,
    "seven": 7,
    "eight": 8,
    "nine": 9,
    "ten": 10,
    "eleven": 11,
    "twelve": 12,
    "thirteen": 13,
    "fourteen": 14,
    "fifteen": 15,
    "sixteen": 16,
    "seventeen": 17,
    "eighteen": 18,
    "nineteen": 19
}

var multiplesOfTen = {
    "twenty": 20,
    "thirty": 30,
    "forty": 40,
    "fifty": 50,
    "sixty": 60,
    "seventy": 70,
    "eighty": 80,
    "ninety": 90
}
                        
function convertWordToNumber(word) {
  var number = new Number(); // this is where we will store the result              
  
  if (word.indexOf("-") == -1) { // If it is less than 20
    number = cardinalNumbers[word];
  } else {
    var multipleOfTen = word.split("-")[0];   // e.g. "seventy"
    var cardinalNumber = word.split("-")[1];   // e.g. "six"
    number = multiplesOfTen[multipleOfTen] + cardinalNumbers[cardinalNumber]; 
  } 
  
  return number;
}

function convertNumberToWord(number) {
  var word = new String(); // this is where we will store the result
    
  if (number &lt; 20) {
    for (var cardinalNumber in cardinalNumbers) {
      if (number == cardinalNumbers[cardinalNumber]) {
        word = cardinalNumber;
        break;
      }
    }
  } else if (number &lt; 100) {
    if (number % 10 == 0) { // If the number is a multiple of ten
      for (var multipleOfTen in multiplesOfTen) {
        if (number == multiplesOfTen[multipleOfTen]) {
          word = cardinalNumber;
          break;
        }
      }
    } else { // not a multiple of ten
      for (var multipleOfTen in multiplesOfTen) {
        for (var i = 9; i &gt; 0; i--) {
          if (number == multiplesOfTen[multipleOfTen] + i) {
            word = multipleOfTen + "-" + convertNumberToWord(i);
            break;
          }
        }
      }
    }
  } else {
    alert("We don't handle numbers greater than 99 yet.");
  }
    
  return word;
}

// These functions takes words as inputs, e.g. "one" and "two"

function add(x, y) {
  return convertNumberToWord(convertWordToNumber(x) + convertWordToNumber(y));
}

function subtract(x, y) {
  return convertNumberToWord(convertWordToNumber(x) - convertWordToNumber(y));
}


// Test convertWordToNumber()
alert(convertWordToNumber("three"));               // should alert 3
alert(convertWordToNumber("seventy-three"));       // should alert 73   


// Test convertNumberToWord()
alert(convertNumberToWord(8));                     // should alert "eight"
alert(convertNumberToWord(46));                    // should alert "forty-six"


// Test add() 
alert(add("one", "two"));                          // should alert "three"

// Test subtract() 
alert(subtract("fifteen", "eleven"));              // should alert "four"
&lt;/pre&gt;
Feel free to &lt;span style="font-weight: bold;"&gt;post your solutions in the comments&lt;/span&gt;. Particularly good solutions will get an entire article devoted to them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-3300778380901705055?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/3300778380901705055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=3300778380901705055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3300778380901705055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/3300778380901705055'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/04/javascript-challenge-cardinal-numbers.html' title='JavaScript Challenge: Cardinal Numbers'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-7476910311571361710</id><published>2008-03-27T12:41:00.000-07:00</published><updated>2008-04-03T14:26:28.159-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>JavaScript Method Overloading</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/overloading1-744629.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://www.thetruetribe.com/uploaded_images/overloading1-744621.jpg" border="0" alt="" /&gt;&lt;/a&gt;
&lt;br /&gt;&lt;br /&gt;
A feature of languages such as Java, C# and C++ is the ability to &lt;span style="font-style: italic;"&gt;overload&lt;/span&gt; methods with multiple parameters.  Overloaded methods execute different code depending on the type and amount of parameters supplied-- in other words, the &lt;a href="http://en.wikipedia.org/wiki/Type_signature"&gt;type signature&lt;/a&gt; of the method. Thus, overloading methods allows for a more flexible API which can handle different possible signatures.
&lt;br /&gt;&lt;br /&gt;
Here's an example of how it works in Java. Let's say that I have a record collection and want to be able to add records by name, ID number, or a Record object:
&lt;pre name="code" class="java:nocontrols"&gt;
public void addRecord(String name) {
 // implementation details
}

public void addRecord (Number id) {
 // implementation details
}

public void addRecord(Record record) {
 // implementation details
}
&lt;/pre&gt;

This is convenient because I can call &lt;span style="font-style: italic;"&gt;addRecord()&lt;/span&gt; elsewhere in the code and use whatever data is available at that time.
&lt;br /&gt;&lt;br /&gt;
Unfortunately, JavaScript does not currently allow you to do this, at least not in this manner.  One reason for this is that JavaScript does not have type signatures for its methods. The signatures of JavaScript methods are simply the names of the parameters, without any type information.
&lt;br /&gt;&lt;br /&gt;
Compare:
&lt;br /&gt;&lt;br /&gt;
&lt;span style="font-weight: bold;"&gt;Java&lt;/span&gt;
&lt;pre name="code" class="java:nocontrols"&gt;public void addRecord(String name) {}&lt;/pre&gt;
&lt;span style="font-weight: bold;"&gt;JavaScript&lt;/span&gt;
&lt;pre name="code" class="js:nocontrols"&gt;function addRecord(name) {}&lt;/pre&gt;
As you can see, JavaScript method declarations do not have the types of return values or parameters. This makes sense given that JavaScript is not a &lt;a href="http://en.wikipedia.org/wiki/Type_safety"&gt;typesafe&lt;/a&gt; language, or a strongly typed language at all.
&lt;br /&gt;&lt;br /&gt;
Regardless, JavaScript 2.0 will support method overloading inherently (so-called 'multifunctions'), but for now, we're left to devise our own solutions to this.
&lt;br /&gt;&lt;br /&gt;

&lt;h3&gt;JS Method Overloading: A First Attempt&lt;/h3&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/overloading2-700904.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://www.thetruetribe.com/uploaded_images/overloading2-700887.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

If your method only has a single argument, it's fairly easy to overload a method.
&lt;br /&gt;&lt;br /&gt;
For instance, here's an overloaded method that hides an element, given either its id (a string) or the HTML object itself.

&lt;pre name="code" class="js:nocontrols"&gt;
function hideElement(element) { // takes id of element (string) or HTML obj
  if (typeof element == 'string') {
      element = document.getElementById(element);
  }
  element.style.display = 'none';
}
&lt;/pre&gt;

In this example, a check of the argument's type (using the &lt;span style="font-style: italic;"&gt;typeof&lt;/span&gt; keyword) determines if it is a string. If so, it redefines element as the HTML object itself, instead of the string id.
&lt;br /&gt;&lt;br /&gt;
Here's how you might use it:

&lt;pre name="code" class="js:nocontrols"&gt;
// Create an element and append to the DOM
var myElement = document.createElement('div');
myElement.style.backgroundColor = '#00FF40'; // green
myElement.setAttribute('id', 'greenbox');
document.body.appendChild(myElement);

// Hide the element using a direct object reference
hideElement(myElement);

// Hide the element using the string id
hideElement('greenbox');
&lt;/pre&gt;
This is pretty rudimentary, and certainly doesn't allow for code reuse. Each time you want to overload a method, you have to do all these type checks using the &lt;span style="font-style: italic;"&gt;typeof&lt;/span&gt; keyword. Not the ideal solution, but workable if you are just overloading a method with one or two type signatures.
&lt;br /&gt;&lt;br /&gt;
&lt;h3&gt;JS Method Overloading: Making it reusable&lt;/h3&gt;Working from the end back, an ideal solution would be to have a simple utility function to add methods along with their type signature. Something like this:
&lt;pre name="code" class="js:nocontrols"&gt;
function addMethod(obj, name, method, signature) {
   // implementation details
}

obj .......... we add the method to this object
name ......... the name of the method
method ....... the method to be added
signature .... the signature of the method, e.g. ["string", "boolean", "number"]
&lt;/pre&gt;

It turns out that someone already came up with this! In November 2007, John Resig wrote a post on &lt;a href="http://ejohn.org/blog/javascript-method-overloading/"&gt;JavaScript method overloading&lt;/a&gt; that contains a version of this very function. However, although his version is useful and very clever, it does not take into account overloading by type. It only allows overloading based on a different number of arguments.
&lt;br /&gt;&lt;br /&gt;
Let's try implementing the addMethod() function now. Warning, &lt;span style="font-weight:bold;"&gt;this attempt fails&lt;/span&gt; (so don't copy from the code below, because it won't work) -- but it's educational to see the process of developing the code, so I've left this example in:

&lt;pre name="code" class="js:nocontrols"&gt;
function addMethod(obj, name, method, signature) {

    // we will use this variable to check if a method already exists 
    // with the same name

   var existingMethod; 
   
   if (typeof obj[name] == 'function') { // if method already exists
        existingMethod = obj[name];      // store a reference to it
    }

    obj[name] = function(arguments) {        
        var signatureMatches = true;
        for (var i = 0; i &lt; signature.length; i++) {
            if (signature[i] != typeof arguments[i]) signatureMatches = false;
        }

        if (signatureMatches) method((arguments);

        if (existingMethod) existingMethod(arguments);
    }
}
&lt;/pre&gt;

At first glance, this looks like it might work, but alas, does not. It somehow overwrites the existing methods so it is not working correctly. But fret not, for there is a working solution. As they say, when you fail, try, try again.
&lt;br /&gt;&lt;br /&gt;
&lt;h3&gt;Finally, a Working Solution&lt;/h3&gt;
This solution may not be the most elegant, but it gets the job done. This is licensed under the MIT license so feel free to use it for your projects (per the terms of the license).

&lt;pre name="code" class="js"&gt;
function addMethod(obj, name, method, signature) {
    // The first time addMethod() is called, define the method
    if (typeof obj[name] == 'undefined') {
        obj[name] = function() {
            for (var signatureString in obj.overloadedMethods[name].signatures) {
                var signatureArray = signatureString.split(",");
                
                var signatureMatches = true;                
                
                for (var i = 0; i &lt; arguments.length; i++) {
                    if (typeof arguments[i] != typeof signatureArray[i]) signatureMatches = false;
                }            
                
                if (signatureMatches) {
                    obj.overloadedMethods[name].signatures[signatureString](arguments);
                }

            }
        }
    }

    // The first time addMethod() is called, create overloadedMethods property
    if (typeof obj.overloadedMethods == 'undefined') {
        obj.overloadedMethods = {};
    }
    
    // The first time a method is added for a given name, create it
    if (typeof obj.overloadedMethods[name] == 'undefined') {
        obj.overloadedMethods[name] = {'signatures': {}};
    }
    
    // Store the method in an associative array (hash map)
    // keyed by the signature string, e.g. "number,boolean,array"
    obj.overloadedMethods[name].signatures[signature.toString()] = method;
}
&lt;/pre&gt;

This approach differs from the previous one in that I am saving an associative array of methods' signatures mapped to the method itself.

Here are some tests which demonstrate how to use it:

&lt;pre name="code" class="js:nocontrols"&gt;
// tests
var jonah = {};
addMethod(jonah, 'test', function(str) {alert("it's a string");}, ['string']);
addMethod(jonah, 'test', function(num) {alert("it's a number");}, ['number']);

jonah.test('string'); // alerts "its a string"
jonah.test(123); // alerts "it's a number"
&lt;/pre&gt;

The addMethod() function is actually only creating one method for "test", a method which iterates through the stored methods in the overloadedMethods object, checking the signature of each one. When it finds a match, it calls that method. Simple enough, I think.
&lt;br /&gt;&lt;br /&gt;
Here's another example:

&lt;pre name="code" class="js:nocontrols"&gt;
addMethod(jonah, 'test', function(bool, str) {alert("it's a boolean, and string");}, ['boolean', 'string']);

jonah.test(true); // this should do nothing
jonah.test(true, "this should work");
&lt;/pre&gt;

There is definitely room for improvement to this code. For one, you can break out of the outer for() loop once finding a match to save some cycles. 
&lt;br /&gt;&lt;br /&gt;
Another optimization is perhaps rewriting the way it finds the match. But I'll leave these for the topic of another article. Comments are welcome. Feel free to post your own improvements to the code, or alternate solutions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-7476910311571361710?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/7476910311571361710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=7476910311571361710' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7476910311571361710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/7476910311571361710'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/03/javascript-method-overloading.html' title='JavaScript Method Overloading'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-210094272610828783</id><published>2008-03-23T17:53:00.000-07:00</published><updated>2008-04-03T14:28:17.817-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='cross-browser'/><category scheme='http://www.blogger.com/atom/ns#' term='mootools'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Managing Cross Browser issues with JS browser detects &amp; Conditional Comments</title><content type='html'>Until all browsers completely comply with w3c specifications &lt;span style="font-weight: bold;"&gt;we have to find workarounds in order for our websites to be pixel perfect in various browsers&lt;/span&gt;. The browsers we need to be most concerned with include Internet Explorer, Safari, and Firefox.&lt;br /&gt;&lt;br /&gt;

&lt;span style="font-weight: bold;"&gt;Firefox is a web developers wet dream.&lt;/span&gt; It features many plugins that allow a web developer to write CSS, JS, and HTML in real time. Thus you do not need a hack or workaround for Firefox since you are developing your websites in Firefox.&lt;br /&gt;&lt;br /&gt;

With the release of Safari 3 for both Mac and Windows, Safari is becoming a strong player. When Safari-centric adjustments need to be made, you can use a browser detect, or when you write javascript that detects the user's browser and can set styles only to that browser. You may have heard that browser detects bad and should be avoided, but when you do not have any other options it may be your only hope. Using Core DOM API, or just plain old javascript, browser detect code can be confusing and long. &lt;span style="font-weight: bold;"&gt;A library, like dojo, prototype, or mootools, can make life get much easier and tasks can be checked off much faster. In jquery, a popular library, it is easy to detect the browser.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;

In this example, not only do &lt;span style="font-weight: bold;"&gt;I detect Safari but set a CSS class called "safari" to the  tag seen only by Safari's eyes.&lt;/span&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
// detects the browser in an if statement
if ($.browser.safari) {
   // Writes a class safar on the &amp;lt;body&amp;gt; tag. Or in other words, &amp;lt;body class="safari"&amp;gt;
   $("body").addClass("safari");
}
&lt;/pre&gt;
And in this example we write it in &lt;span style="font-weight: bold;"&gt;Mootools,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;pre name="code" class="js:nocontrols"&gt;
if (window.safari) {
   $$("body").addClass("safari");
}
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;
On to Internet Explorer. For styling (CSS) we can use &lt;span style="font-weight: bold;"&gt;conditional comments placed in your html. Right after the
tag&lt;/span&gt; insert the following code:
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;!--[if lte IE 5]&amp;gt;
&amp;lt;div class="ie"&amp;gt;
&amp;lt;![endif]--&amp;gt;
&amp;lt;!--[if IE 6]&amp;gt;
&amp;lt;div class="ie ie6"&amp;gt;
&amp;lt;![endif]--&amp;gt;
&amp;lt;!--[if IE 7]&amp;gt;
&amp;lt;div class="ie ie7"&amp;gt;
&amp;lt;![endif]--&amp;gt;
&lt;/pre&gt;
Results:
&lt;br /&gt;&lt;br /&gt;
IE5+ gets &amp;lt;div class="ie"&amp;gt;
&lt;br /&gt;&lt;br /&gt;
IE6 gets &amp;lt;div class="ie6"&amp;gt;
&lt;br /&gt;&lt;br /&gt;
IE7 gets &amp;lt;div class="ie7"&amp;gt;
&lt;br /&gt;&lt;br /&gt;

At the bottom of your document, &lt;span style="font-weight: bold;"&gt;right before the closing tag&lt;/span&gt; add these lines of code to close the IE &amp;lt;div&amp;gt;s.
&lt;pre name="code" class="html:nocontrols"&gt;
&amp;lt;!--[if IE]&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;![endif]--&amp;gt;
&lt;/pre&gt;

On to the stylizing in CSS:
&lt;br /&gt;&lt;br /&gt;
To write styles for Safari just start any style rule with .safari. For instance,

&lt;pre name="code" class="css:nocontrols"&gt;
.safari div#title {
   margin: 0 0 3px 0;
}
&lt;/pre&gt;

And similar for IE:

&lt;pre name="code" class="css:nocontrols"&gt;
.ie div#title {
   position: relative;
}

.ie7 div#title {
   margin: 0 0 3px 0;
}

.ie6 div#title {
   left: 305px;
}
&lt;/pre&gt;

If you have to make browser specific Javascript adjustments only browser detects will suffice. We already covered Safari. For Internet explorer you can write:
&lt;br /&gt;&lt;br /&gt;
Jquery:
&lt;pre name="code" class="js:nocontrols"&gt;
if ($.browser.msie) {
   // js goes here for internet explorer
}
&lt;/pre&gt;

Mootools:
&lt;pre name="code" class="js:nocontrols"&gt;
if (window.ie) {
   // js goes here for internet explorer
}
&lt;/pre&gt;
Luckily, &lt;span style="font-weight: bold;"&gt;Safari and internet explorer styling adjustments are often similar&lt;/span&gt;. Having already adjusted IE to match Firefox, I usually need to apply similar Safari rules to the same trouble elements.
&lt;br /&gt;&lt;br /&gt;
For example,

&lt;pre name="code" class="js:nocontrols"&gt;
.ie div#rightNav,
.safari div#rightNav {
   top: -3px;
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-210094272610828783?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/210094272610828783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=210094272610828783' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/210094272610828783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/210094272610828783'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/03/managing-cross-browser-issues-with-js.html' title='Managing Cross Browser issues with JS browser detects &amp; Conditional Comments'/><author><name>Alex Grande</name><uri>http://www.blogger.com/profile/01750789401997148077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6069745790539221961.post-5627699345878894590</id><published>2008-03-21T05:58:00.001-07:00</published><updated>2008-05-21T02:22:35.980-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='firefox'/><category scheme='http://www.blogger.com/atom/ns#' term='firebug'/><title type='text'>Firebug Tutorial: Getting Started</title><content type='html'>Firebug is a plugin for Firefox that greatly aids CSS and JavaScript debugging. This guide will walk you through installing Firebug and using some of its functionality, including&lt;span style="font-weight: bold;"&gt; debugging JavaScript&lt;/span&gt;, inspecting the DOM and&lt;span style="font-weight: bold;"&gt; editing CSS on the fly.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;

&lt;h4&gt;Getting Started&lt;/h4&gt;First, make sure you're running Firefox. If you aren't, &lt;a href="http://www.getfirefox.com/" title="Firefox really is the best browser."&gt;get Firefox&lt;/a&gt; now. You won't be disappointed. Next, &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/1843"&gt;install Firebug&lt;/a&gt; by following the link and clicking "Install Now." After installing, restart Firefox and continue.&lt;br /&gt;&lt;br /&gt;

Now you can click the small icon in the bottom right corner of the Firefox window to open Firebug. Go ahead and open it-- the first time running, you may have to choose to enable it for sites on the world wide web.
&lt;br /&gt;&lt;br /&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thetruetribe.com/uploaded_images/html1-770907.gif"&gt;&lt;img style="cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/html1-770892.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;

&lt;h4&gt;Using the Console
&lt;/h4&gt;The first tab that's open in Firebug is the console. The console tab shows JavaScript error messages, as well as having a command line interface (CLI) where you can enter JavaScript and execute it in real time.&lt;br /&gt;&lt;br /&gt;

&lt;a href="http://www.getfirebug.com/cl.html" style="margin: 10px 0pt 10px 10px; float: right;"&gt;&lt;img class="miniscreen" src="http://www.getfirebug.com/screenHome-cl.gif" /&gt;&lt;/a&gt;Using the CLI, you can call functions, define variables, or even write new functions.&lt;br /&gt;&lt;br /&gt;

The JavaScript error messages are are also helpful for debugging since they show you which line the error occurred on, as well as a &lt;a href="http://en.wikipedia.org/wiki/Stack_trace"&gt;stack trace&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;

Another interesting feature is the ability to &lt;span style="font-weight: bold;"&gt;log messages to the console &lt;/span&gt;by using the method &lt;span style="font-style: italic;"&gt;console.log()&lt;/span&gt;. Note that this will throw an error in browsers which don't have Firebug installed, so it's just for development purposes.&lt;br /&gt;&lt;br /&gt;

Logging messages can be very useful when debugging complex JavaScript applications that have a lot of moving parts. It can also be used for page profiling. Here's an example of how you might use logging to the console to add some &lt;span style="font-weight: bold;"&gt;rudimentary speed profiling&lt;/span&gt; of a JavaScript function:
&lt;pre name="code" class="js:nocontrols"&gt;
function doStuff() {
var startTime = new Date().getTime(); // The current time in epoch milliseconds

// Add code here to be profiled

var endTime = new Date().getTime() - startTime;
console.log("The function doStuff() took " + endTime + " milliseconds to complete.");
}
&lt;/pre&gt;This would result in a message being logged to the console with the amount of milliseconds it took for that code to execute. Nothing fancy, but it gets the job done!&lt;br /&gt;&lt;br /&gt;

&lt;h4&gt;DOM Inspection
&lt;/h4&gt;Clicking the next tab over in Firebug, to &lt;span style="font-style: italic;"&gt;HTML&lt;/span&gt;, you'll find a two-paned window that allows you to browse the DOM on the left and edit CSS on the right.&lt;br /&gt;&lt;br /&gt;

Start opening HTML tags and mousing over them. You'll notice that the HTML element on the screen lights up when you hover over the tag. It's a nice feature that lets you quickly orient yourself in the code.&lt;br /&gt;&lt;br /&gt;

The highlighted area also shows how much space an element is taking up on the screen. The color blue denotes the element's &lt;span style="font-style: italic;"&gt;height&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;width&lt;/span&gt;, while yellow is &lt;span style="font-style: italic;"&gt;margin&lt;/span&gt; and purple is &lt;span style="font-style: italic;"&gt;padding&lt;/span&gt;.
&lt;br /&gt;&lt;br /&gt;
Clicking the &lt;span style="font-style: italic;"&gt;Inspect&lt;/span&gt; button (next to the bug icon in the top left corner of Firebug) will toggle a mode where you can click on HTML elements on the screen and it will go to that tag in the code.&lt;br /&gt;&lt;br /&gt;

There's another tab for DOM inspection, the aptly-named &lt;span style="font-style: italic;"&gt;DOM&lt;/span&gt; tab. Here you will find all of the DOM objects created by JavaScript, such as &lt;span style="font-weight: bold;"&gt;variables and functions&lt;/span&gt;, as well as the &lt;span style="font-weight: bold;"&gt;core DOM API&lt;/span&gt; (for example, the &lt;span style="font-style: italic;"&gt;window&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;document&lt;/span&gt; objects can be inspected here).
&lt;br /&gt;&lt;br /&gt;
I check this page when I want to view the current state of the page and watch it change as JavaScript executes. For example, say I have a variable that keeps track of how many items are in a shopping cart. I could watch this variable in the &lt;span style="font-style: italic;"&gt;DOM&lt;/span&gt; tab to make sure that it's incremented when I add an item to the cart.
&lt;br /&gt;&lt;br /&gt;
&lt;h4&gt;Editing CSS on the Fly
&lt;/h4&gt;Going back to the &lt;span style="font-style: italic;"&gt;HTML&lt;/span&gt; tab, notice that the pane on the right shows CSS styles for whichever element is currently selected. You can choose an element in the left pane (or by clicking &lt;span style="font-style: italic;"&gt;Inspect&lt;/span&gt; and then clicking the element), and the CSS styles for that element will be displayed. Furthermore, you can edit the properties and even add new ones.&lt;br /&gt;&lt;br /&gt;

Firebug has a different take on CSS editing than some other debugging programs, namely the &lt;span style="font-weight: bold;"&gt;Microsoft Web Developer Toolbar&lt;/span&gt;, so I'll clarify how it works: In Firebug, when you change a CSS style, it updates it for every element on the page. Conversely, in Microsoft Web Developer Toolbar, changing CSS styles only affects the currently selected element.&lt;br /&gt;&lt;br /&gt;

By way of example, say you have the CSS rule &lt;span style="font-style: italic;"&gt;p {padding: 10px;}&lt;/span&gt;. You then select a P tag and change it to &lt;span style="font-style: italic;"&gt;padding: 20px&lt;/span&gt;;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;using Firebug&lt;span style="font-style: italic;"&gt;. &lt;/span&gt;The result is that every P tag will now have 20px padding, unlike other programs where it would only affect the styles of the selected tag.&lt;br /&gt;&lt;br /&gt;

To add a new style, simply click twice in the whitespace inside of a style block, next to the existing declarations. Firebug even has a convenient auto-complete feature for writing CSS.
&lt;br /&gt;&lt;br /&gt;
In the right page, there are three tabs: &lt;span style="font-style: italic;"&gt;Style, Layout &lt;/span&gt;and &lt;span style="font-style: italic;"&gt;DOM&lt;/span&gt;. So far, we've been editing CSS in the &lt;span style="font-style: italic;"&gt;Style&lt;/span&gt; tab, but make sure to check out the other two as well. The &lt;span style="font-style: italic;"&gt;Layout&lt;/span&gt; tab offers an alternate view of the box model for the selected element, along with pixel-precise measurements of its dimensions. The &lt;span style="font-style: italic;"&gt;DOM&lt;/span&gt; tab shows all properties and methods for that element.&lt;br /&gt;&lt;br /&gt;

&lt;h4&gt;Page Profiling and Network Metrics
&lt;/h4&gt;&lt;a href="http://www.getfirebug.com/net.html" style="margin: 10px 10px 10px 0pt; float: left;"&gt;&lt;img class="miniscreen" src="http://www.getfirebug.com/screenHome-net.gif" /&gt;&lt;/a&gt;Nothing's worse than making a great site only to have it suffer from poor front end performance. (OK, well, a lot of things are worse -- but it's still frustrating!). The Firebug &lt;span style="font-style: italic;"&gt;Net&lt;/span&gt; profiler can help get to the source of that slowness.
&lt;br /&gt;&lt;br /&gt;
Although it is far from robust, the &lt;span style="font-style: italic;"&gt;Net &lt;/span&gt;tab offers semi-reliable metrics on the download speed of all assets including the HTML document, CSS, JavaScript, images and any other linked files.
&lt;br /&gt;&lt;br /&gt;
You can see which files are being downloaded concurrently and which are blocking (hint: it's the JavaScript), and how many connections are being opened with a given domain.&lt;br /&gt;&lt;br /&gt;

For more extensive page profiling, be sure to check out &lt;a href="http://developer.yahoo.com/yslow/"&gt;&lt;span style="font-style: italic;"&gt;YSlow&lt;/span&gt;!&lt;/a&gt;, a plugin for Firebug  (I guess that makes it an extension-of-an-extension) developed by Yahoo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6069745790539221961-5627699345878894590?l=thetruetribe.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thetruetribe.blogspot.com/feeds/5627699345878894590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6069745790539221961&amp;postID=5627699345878894590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5627699345878894590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6069745790539221961/posts/default/5627699345878894590'/><link rel='alternate' type='text/html' href='http://thetruetribe.blogspot.com/2008/03/firebug-tutorial-getting-started.html' title='Firebug Tutorial: Getting Started'/><author><name>Jonah Dempcy</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://img63.imageshack.us/img63/8103/autumnwalklivetracewithlevels9.jpg'/></author><thr:total>0</thr:total></entry></feed>
