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

<channel>
	<title>The True Tribe &#187; admin</title>
	<atom:link href="http://www.thetruetribe.com/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.thetruetribe.com</link>
	<description>Vroom! That&#039;s us leaving IE in the dust.</description>
	<lastBuildDate>Fri, 22 Jan 2010 23:34:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Random Integer Javascript snippet</title>
		<link>http://www.thetruetribe.com/2009/09/random-integer-javascript-snippet/</link>
		<comments>http://www.thetruetribe.com/2009/09/random-integer-javascript-snippet/#comments</comments>
		<pubDate>Sun, 06 Sep 2009 00:31:53 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.thetruetribe.com/?p=236</guid>
		<description><![CDATA[returns a random number between two digits passed in as arguments.

function randomInteger(low, high)
{
    return low + Math.floor(Math.random() * (high - low));
}

]]></description>
			<content:encoded><![CDATA[<p>returns a random number between two digits passed in as arguments.</p>
<pre class="js" name="code">
function randomInteger(low, high)
{
    return low + Math.floor(Math.random() * (high - low));
}
</pre>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F09%2Frandom-integer-javascript-snippet%2F&amp;linkname=Random%20Integer%20Javascript%20snippet"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/09/random-integer-javascript-snippet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scrolling to an element when outside of the viewport with prototypejs</title>
		<link>http://www.thetruetribe.com/2009/08/scrolling-to-an-element-when-outside-of-the-viewport-with-prototypejs/</link>
		<comments>http://www.thetruetribe.com/2009/08/scrolling-to-an-element-when-outside-of-the-viewport-with-prototypejs/#comments</comments>
		<pubDate>Fri, 28 Aug 2009 23:17:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Prototype]]></category>

		<guid isPermaLink="false">http://www.thetruetribe.com/?p=234</guid>
		<description><![CDATA[Often times you&#8217;ll have be playing, say, videos with a list of videos down the page. If the list gets too long the video player becomes out of sight as the user scrolls down. This can be a big confuser to users: they click on a link to see a video and they don&#8217;t see [...]]]></description>
			<content:encoded><![CDATA[<p>Often times you&#8217;ll have be playing, say, videos with a list of videos down the page. If the list gets too long the video player becomes out of sight as the user scrolls down. This can be a big confuser to users: they click on a link to see a video and they don&#8217;t see anything happen because the video player is out of sight. Here&#8217;s what you can do: scroll to the video player if it is out of sight like so:</p>
<pre class="js" name="code">
if ($("videoplayer").viewportOffset()[1] < 0) {
 Effect.ScrollTo('videoplayer', {duration: 0.2});
}
</pre>
<p>Requires both prototype and effects.js in scriptaculous.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F08%2Fscrolling-to-an-element-when-outside-of-the-viewport-with-prototypejs%2F&amp;linkname=Scrolling%20to%20an%20element%20when%20outside%20of%20the%20viewport%20with%20prototypejs"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/08/scrolling-to-an-element-when-outside-of-the-viewport-with-prototypejs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Grab last item in XSLT for-each</title>
		<link>http://www.thetruetribe.com/2009/08/grab-last-item-in-xslt-for-each/</link>
		<comments>http://www.thetruetribe.com/2009/08/grab-last-item-in-xslt-for-each/#comments</comments>
		<pubDate>Fri, 28 Aug 2009 22:08:50 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.thetruetribe.com/?p=228</guid>
		<description><![CDATA[This is simple and fun!
Here&#8217;s an example of doing something in all instances EXCEPT the last one. Reversing this is obvious:

 


  

 

Often times you want a horizontal rule in all instances except the last item. You can also use this method for adding a class name to the last item:


 
  [...]]]></description>
			<content:encoded><![CDATA[<p>This is simple and fun!</p>
<p>Here&#8217;s an example of doing something in all instances EXCEPT the last one. Reversing this is obvious:</p>
<pre name="code" class="xml">
 <xsl:if test="not(position() = last())">
<div class="hr">
<hr />
  </div>

 </xsl:if>
</pre>
<p>Often times you want a horizontal rule in all instances except the last item. You can also use this method for adding a class name to the last item:</p>
<pre name="code" class="xml">
<li>
 <xsl:if test="position()=last()">
  <xsl:attribute name="class">last</xsl:attribute>
 </xsl:if>
</li>
</pre>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F08%2Fgrab-last-item-in-xslt-for-each%2F&amp;linkname=Grab%20last%20item%20in%20XSLT%20for-each"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/08/grab-last-item-in-xslt-for-each/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Best Way to Get Gmail in Ruby on Rails</title>
		<link>http://www.thetruetribe.com/2009/08/best-way-to-get-gmail-in-ruby-on-rails/</link>
		<comments>http://www.thetruetribe.com/2009/08/best-way-to-get-gmail-in-ruby-on-rails/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 07:27:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[gmail]]></category>

		<guid isPermaLink="false">http://www.thetruetribe.com/2009/08/best-way-to-get-gmail-in-ruby-on-rails/</guid>
		<description><![CDATA[Gmail is not as easy as sendmail, unless you have this tutorial. This gem/tutorial is by far the best solution.
action_mailer_tls
There are a lot of solutions out there so it can be hard to know which to choose. I have tried many and found this to be dead simple. Takes 5 minutes to setup. 
]]></description>
			<content:encoded><![CDATA[<p>Gmail is not as easy as sendmail, unless you have this tutorial. This gem/tutorial is by far the best solution.</p>
<p><a href="http://github.com/openrain/action_mailer_tls/tree/master">action_mailer_tls</a></p>
<p>There are a lot of solutions out there so it can be hard to know which to choose. I have tried many and found this to be dead simple. Takes 5 minutes to setup. </p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F08%2Fbest-way-to-get-gmail-in-ruby-on-rails%2F&amp;linkname=Best%20Way%20to%20Get%20Gmail%20in%20Ruby%20on%20Rails"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/08/best-way-to-get-gmail-in-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails Time Saver &#8211; delete development.log</title>
		<link>http://www.thetruetribe.com/2009/08/ruby-on-rails-delete-development-log/</link>
		<comments>http://www.thetruetribe.com/2009/08/ruby-on-rails-delete-development-log/#comments</comments>
		<pubDate>Wed, 12 Aug 2009 00:22:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[timesaver]]></category>

		<guid isPermaLink="false">http://www.thetruetribe.com/?p=221</guid>
		<description><![CDATA[When uploading your local build to a server delete your development.log file because they tend to get long and thus heavy on kilobytes. 
]]></description>
			<content:encoded><![CDATA[<p>When uploading your local build to a server delete your development.log file because they tend to get long and thus heavy on kilobytes. </p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F08%2Fruby-on-rails-delete-development-log%2F&amp;linkname=Ruby%20on%20Rails%20Time%20Saver%20%26%238211%3B%20delete%20development.log"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/08/ruby-on-rails-delete-development-log/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to order by most recently updated in Rails</title>
		<link>http://www.thetruetribe.com/2009/07/how-to-order-by-most-recently-updated-in-rails/</link>
		<comments>http://www.thetruetribe.com/2009/07/how-to-order-by-most-recently-updated-in-rails/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 05:15:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://wordpress.thetruetribe.com/?p=196</guid>
		<description><![CDATA[This is a simple one but sometimes hard to figure out for beginners in Rails. There are a number of ways to do it but this is one of the most simple. It includes actually doing a sql query inside your find method.
@posts = Post.find(:all,  rder =&#62; 'updated_at DESC')
That&#8217;s it. I&#8217;m ordering by the [...]]]></description>
			<content:encoded><![CDATA[<p>This is a simple one but sometimes hard to figure out for beginners in Rails. There are a number of ways to do it but this is one of the most simple. It includes actually doing a sql query inside your find method.</p>
<pre class="ruby" name="code">@posts = Post.find(:all, <img src='http://www.thetruetribe.com/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> rder =&gt; 'updated_at DESC')</pre>
<p>That&#8217;s it. I&#8217;m ordering by the updated_at column in the Posts table.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2009%2F07%2Fhow-to-order-by-most-recently-updated-in-rails%2F&amp;linkname=How%20to%20order%20by%20most%20recently%20updated%20in%20Rails"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2009/07/how-to-order-by-most-recently-updated-in-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing Synergy For Linux and Windows</title>
		<link>http://www.thetruetribe.com/2008/06/installing-synergy-for-linux-and-windows/</link>
		<comments>http://www.thetruetribe.com/2008/06/installing-synergy-for-linux-and-windows/#comments</comments>
		<pubDate>Wed, 18 Jun 2008 08:43:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://wordpress.thetruetribe.com/?p=44</guid>
		<description><![CDATA[Synergy 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.
Here is a description [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://synergy2.sourceforge.net/">Synergy</a> 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.<span id="more-44"></span></p>
<p>Here is a description and image from the Synergy site which demonstrates this functionality:</p>
<blockquote><p>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.</p>
<p><img src="http://synergy2.sourceforge.net/images/warp.gif" alt="" />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.</p></blockquote>
<p>I&#8217;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.</p>
<p><span style="font-weight: bold;">Let&#8217;s get started</span> installing Synergy, shall we? The Windows set up is easier because it has a GUI. In Windows, go to the <a href="http://synergy2.sourceforge.net/">Synergy SourceForge</a> page to download the latest release (version 1.3.1 as of this writing).  Here&#8217;s the download link if you don&#8217;t want to be bothered with navigating the SourceForge page:</p>
<ul>
<li> <a href="http://downloads.sourceforge.net/synergy2/SynergyInstaller-1.3.1.exe?modtime=1143984577&amp;big_mirror=0">Download SynergyInstaller-1.3.1.exe from SourceForge</a></li>
</ul>
<p>Once it&#8217;s downloaded, install it and open the <span style="font-style: italic;">synergy.exe</span> file to launch the program.</p>
<p>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&#8217;t had issues with Vista or XP in either configuration.</p>
<p>For now, let&#8217;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 <span class="code" style="font-style: italic;">Use another computer&#8217;s shared keyboard and mouse (client)</span>. Then, enter the Linux computer&#8217;s host name next to <span class="code" style="font-style: italic;">Other Computer&#8217;s Host Name</span>. For me, this is &#8216;ubuntu&#8217; but you may have been more creative with your host name.</p>
<p>We&#8217;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:</p>
<p><span style="font-family: courier new;">sudo apt-get install synergy</span></p>
<p>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&#8217;s how to do either way:</p>
<p><span style="font-weight: bold;">The manual way</span> 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 <span style="font-style: italic;">synergy.conf</span> that looks like this:</p>
<pre>    section: screens
      <span class="arg">screen1</span>:
      <span class="arg">screen2</span>:
   end
   section: links
      <span class="arg">screen1</span>:
          right = <span class="arg">screen2</span>
      <span class="arg">screen2</span>:
          left = <span class="arg">screen1</span>
   end</pre>
<p>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&#8217;s sake.</p>
<p>For me, this file says:</p>
<pre>    section: screens
      ubuntu:
      laptop<span class="arg"> </span>:
   end
   section: links
      <span class="arg">screen1</span>:
          right = <span class="arg">laptop
</span> <span class="arg">screen2</span>:
          left = ubuntu<span class="arg"> </span>
   end</pre>
<p>My laptop is, of course, named &#8216;laptop&#8217; &#8212; again, feel free to use more imaginative names (as long as it is actually the name of the computer). It isn&#8217;t necessary to use the name of the computer as the name of the screen but it requires extra configuration otherwise.  (See <a href="http://synergy2.sourceforge.net/">the official documentation</a> for more information on this).</p>
<p>Now that you&#8217;ve created the file, you&#8217;re ready to launch Synergy. Give it a try with this line:</p>
<pre>    synergys -f --config synergy.conf</pre>
<p>Assuming it starts correctly, jump back to Windows and click &#8216;Test&#8217; in Synergy there. It should say that it connected OK and everything is fine and dandy. If that&#8217;s the case, then just click &#8216;Start&#8217; and you&#8217;re done. If not, visit <a href="http://synergy2.sourceforge.net/">the docs page</a> and scroll towards the bottom to troubleshoot the issue.</p>
<p><span style="font-weight: bold;">If you prefer graphically configuring Synergy</span>, that&#8217;s an option, too. I guess I should have put the GUI solution first for us lazy developers, but it&#8217;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.</p>
<p>That being said, the GUI (called QuickSynergy) is very straightforward and easy to use. To install QuickSynergy, type the following in a Linux terminal:</p>
<p><span style="font-family: courier new;">sudo apt-get install quicksynergy</span></p>
<p>Once it&#8217;s installed, you can type <span style="font-style: italic;">quicksynergy</span> to launch it (add &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.</p>
<p><img src="http://quicksynergy.sourceforge.net/imagens/QuickSynergyLinux.png" border="0" alt="" align="middle" /></p>
<p>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 &#8216;ubuntu&#8217;) is on the left and my Vista laptop (named &#8216;laptop&#8217;) is on the right, so I just made sure that the fields to the left and right of the computer image said &#8216;ubuntu&#8217; and &#8216;laptop&#8217;, respectively.</p>
<p>QuickSynergy is theoretically easier to use than the command line way detailed above, so I won&#8217;t go into much depth here. If you get stuck with QuickSynergy, either try the command line way, or visit the <a href="http://quicksynergy.sourceforge.net/">QuickSynergy SourceForge site </a>to see screenshots and example configurations.</p>
<p><span style="font-weight: bold;">Extra Features:</span></p>
<ul>
<li>Synergy has the ability to auto-sync starting and stopping of screensavers</li>
<li>You can copy and paste between Linux and Windows (this is a huge time-saver!)</li>
<li>Easily lock the mouse/keyboard to the current screen by toggling scroll lock (assignable to any other key)</li>
</ul>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2008%2F06%2Finstalling-synergy-for-linux-and-windows%2F&amp;linkname=Installing%20Synergy%20For%20Linux%20and%20Windows"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2008/06/installing-synergy-for-linux-and-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What&#8217;s New in MooTools 1.2</title>
		<link>http://www.thetruetribe.com/2008/06/whats-new-in-mootools-1-2/</link>
		<comments>http://www.thetruetribe.com/2008/06/whats-new-in-mootools-1-2/#comments</comments>
		<pubDate>Tue, 17 Jun 2008 07:50:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MooTools]]></category>

		<guid isPermaLink="false">http://wordpress.thetruetribe.com/?p=43</guid>
		<description><![CDATA[I&#8217;m happy to announce that MooTools (Wikipedia link) has released version 1.2 of their excellent JavaScript library. MooTools, which stands for &#8216;My Object Oriented Tools&#8217;, was developed in 2006 by Valerio Proietti and his colleagues. It evolved out of Moo.fx, a lightweight effects library which plugged into the Prototype framework. It was similar, although smaller [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce that MooTools (<a href="http://en.wikipedia.org/wiki/MooTools">Wikipedia link</a>) has released version 1.2 of their excellent JavaScript library. MooTools, which stands for &#8216;My Object Oriented Tools&#8217;, was developed in 2006 by <a href="http://mad4milk.net/">Valerio Proietti</a> and <a href="http://mootools.net/developers">his colleagues</a>. It evolved out of <a href="http://en.wikipedia.org/wiki/Moo.fx">Moo.fx</a>, 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.<span id="more-43"></span></p>
<p>Even before MooTools&#8217; 1.0 release on January 29, 2007, it had garnered quite a bit of buzz. There were even <a href="http://snook.ca/archives/javascript/mootools_r83_cheatsheet/">cheat sheets</a> created for the beta MooTools library.</p>
<p><a href="http://mootools.net/" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://mootools.net//assets/images/mootools.png" border="0" alt="" /></a></p>
<p>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&#8217;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&#8217;ve been following this blog, chances are you&#8217;ve already been exposed to some of the new features in 1.2. Regardless, here&#8217;s a full list of features and enhancements you&#8217;ll find in the new release:</p>
<ul>
<li><a href="http://blog.mootools.net/2008/2/12/what-s-new-in-1-2-swiff">Swiff</a>, support for working with Flash SWF files, similar to the <a href="http://code.google.com/p/swfobject/">swfobject</a> library</li>
<li><a href="http://blog.mootools.net/2008/1/22/Element_Storage">Element storage</a> allows you to store data in custom properties on HTML elements without leaking memory in IE</li>
<li>Overhaul of Fx classes with <a href="http://blog.mootools.net/2007/10/23/The_Best_Javascript_Effects_Now_Even_Better">many improvements</a>, including creating a <a href="http://docs.mootools.net/Fx/Fx.Tween">Tween</a> class to create reusable animation tweens</li>
<li>Overhauled Ajax requests; renamed Ajax class to <a href="http://docs.mootools.net/">Request </a>, with JSON and HTML subclasses (for easily handling their respective data formats as Ajax responses)</li>
<li><a href="http://docs.mootools.net/Element/Element.Dimensions">Element.Dimensions</a> &#8211; 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</li>
<li>Created a <a href="http://docs.mootools.net/Core/Browser">Browser</a> 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. <span style="font-style:italic;">trident4</span> instead of <span style="font-style:italic;">ie6</span>.</li>
<p>In addition to the changes to the API and codebase, the following changes occured as well:</p>
<li>MooTools now adheres to <a href="http://blog.mootools.net/2007/10/20/what-s-new-in-1-2-spec-runner">behavior driven development</a> using specs</li>
<li><a href="http://blog.mootools.net/2007/10/8/what-s-new-in-1-2-the-hash">The Hash Object</a> &#8211; with <span style="font-style:italic;">get, put, each, some</span> and a whole lot of other methods for manipulating data in a hash</li>
<li>MooTools developed using <a href="http://blog.mootools.net/2008/6/12/mootools-1-2-it-s-official">Git</a> instead of Subversion now &#8211; this will only affect you if you&#8217;re used to grabbing code from svn (or if you&#8217;re a contributor!)</li>
<li>MooTools uses <a href="http://mootools.lighthouseapp.com/">Lighthouse</a> instead of Trac for bug tracking now</li>
</ul>
<p>In light of all these improvements to an already excellent library, I think it&#8217;s apparent that MooTools is really growing up and coming into its own. It&#8217;s a force to be reckoned with and certainly a heavyweight contender against Prototype, jQuery, YUI and others.</p>
<p>I hope you&#8217;ve enjoyed this brief overview of some of the new features in MooTools 1.2. Now get out there and start coding!</p>
<h5>Related links:</h5>
<ul>
<li><a href="http://www.mootools.net">MooTools homepage</a></li>
</ul>
<h5>Docs and Demos</h5>
<ul>
<li><a href="http://docs.mootools.net">1.2 Documentation</a></li>
<li><a href="http://demos.mootools.net">1.2 Demos</a></li>
</ul>
<h5>Compatibility</h5>
<ul>
<li><a href="http://mootools.net/js/mootools-compat-core.js">Core Compatibility File</a></li>
<li><a href="http://mootools.net/js/mootools-compat-more.js">Plugin Compatibility File</a></li>
</ul>
<h5>Git Repositories</h5>
<ul>
<li><a href="http://github.com/mootools/mootools-core">Core Repository</a></li>
<li><a href="http://github.com/mootools/mootools-more">Plugin Repository</a></li>
</ul>
<h5>Bug Tracking</h5>
<ul>
<li><a href="http://mootools.lighthouseapp.com/">MooTools at Lighthouse</a></li>
</ul>
<h5>MooTools User Groups</h5>
<ul>
<li><a href="http://groups.google.com/group/mootools-users/">MooTools Users at Google Groups</a></li>
<li><a href="irc://irc.freenode.org/#mootools">#mootools on Freenode</a></li>
</ul>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2008%2F06%2Fwhats-new-in-mootools-1-2%2F&amp;linkname=What%26%238217%3Bs%20New%20in%20MooTools%201.2"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2008/06/whats-new-in-mootools-1-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Saving State: What To Do When Users Leave</title>
		<link>http://www.thetruetribe.com/2008/06/saving-state-what-to-do-when-users-leave/</link>
		<comments>http://www.thetruetribe.com/2008/06/saving-state-what-to-do-when-users-leave/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 06:10:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JSON]]></category>

		<guid isPermaLink="false">http://wordpress.thetruetribe.com/?p=41</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>In this era of rich JavaScript applications, so much<br />
focus is given to the features of the application that one<br />
crucial element is often overlooked: What happens when the<br />
user leaves the page? We take it for granted that pages<br />
will look the same when we leave and return, but a new<br />
question merges for sites using rich JavaScript<br />
interaction: If the user leaves and returns to the page,<br />
will the application state be preserved?<span id="more-41"></span></p>
<p>The effects of losing application state can range from<br />
minor annoyances like losing what page you&#8217;re on, to<br />
all-out frustration after losing a carefully-typed message<br />
because you accidentally triggered the browser&#8217;s back<br />
button. (It&#8217;s easier than you think&#8211; hitting backspace<br />
when the document is in focus triggers the back button in<br />
most browsers). Couple this with the fact that some users<br />
may expect pages to save form data, because of their prior<br />
experience to that effect, and it becomes apparent that a<br />
robust strategy for preserving application state must be<br />
devised.</p>
<p>Browsers automatically save data entered into form<br />
fields, but all JavaScript variables are lost when the user<br />
leaves the page. Furthermore, any form fields that were<br />
created by JavaScript will also be lost. So, for all but<br />
the most simple applications, JavaScript must have a<br />
strategy for saving state that deals with these<br />
limitations.</p>
<p>Some sites like <a href="&lt;br"></a> &#8220;http://www.thesixtyone.com&#8221;&gt;<em>thesixtyone.com</em><br />
reside entirely on a single page and capture users&#8217; back<br />
button clicks with named anchors. But, try writing a wall<br />
post on Facebook and you&#8217;ll find that it does not save the<br />
post if you leave the page. Accidentally pressing backspace<br />
is all too easy in cases like this where typing is<br />
involved, which is why sites like Gmail and Blogger warn<br />
users that they will lose data before leaving the page.</p>
<h3>How To Warn Users Before Leaving the Page</h3>
<p>One way you can do this is by assigning a confirmation<br />
message to the return value of the<br />
<em>window.onbeforeunload</em> event handler. The user will<br />
be presented with two choices, <em>OK</em> and<br />
<em>Cancel</em>, along with a custom message of your<br />
choosing.</p>
<p>In the following example, we regsiter an anonymous<br />
function as the event handler for<br />
<em>window.onbeforeunload</em>, and add our own custom<br />
message:</p>
<h5>Using <em>window.onbeforeunload</em> to confirm if a<br />
user wants to leave the page (<a href="&lt;br"></a> &#8220;/examples/saving-state/example-1.html&#8221;&gt;example 1)</h5>
<pre class="js:nocontrols">window.onbeforeunload = function() {
  return "You will lose any unsaved information.";
};</pre>
<p>The browser displays your custom message, given in the<br />
return statement of the <em>onbeforeunload</em> event<br />
handler, along with the browser default message. In<br />
Firefox, the result is:</p>
<blockquote><p>Are you sure you want to navigate away from this<br />
page?<br />
You will lose any unsaved information.<br />
Press OK to continue, or Cancel to stay on the current<br />
page.</p></blockquote>
<h3>Retaining Data When Users Do Leave the Page</h3>
<p>You may opt to silently save the user&#8217;s data when they<br />
leave the page. This may give a better user experience<br />
since they are not confronted with a choice, and their data<br />
is saved automatically.</p>
<p>This is one of the times where Ajax comes in handy.<br />
However, there are also other ways to do this without using<br />
Ajax, such as cleverly storing information in named anchors<br />
or hidden form fields. We&#8217;ll examine each of these<br />
practices in more depth, but suffice it to say that the<br />
hidden form fields approach works better for conventional<br />
websites that are spread across many pages, whereas storing<br />
data in named anchors is better for single-page, pure<br />
JavaScript applications.</p>
<p>It turns out that while you could (and should) save<br />
state to the server using Ajax, for some cases you will<br />
want to avoid Ajax altogether and use a simpler,<br />
clientside-only model.</p>
<h3>Using Hidden Form Fields to Save State</h3>
<p>As mentioned, all JavaScript objects are lost when the<br />
user leaves or refreshes the page. But, browsers will<br />
retain data in form fields, provided that the form elements<br />
were not generated using JavaScript. Given this limitation,<br />
it is necessary to save JavaScript variables (or the<br />
serialized JSON strings of such objects) to hidden form<br />
fields if they need to be retained.</p>
<p>Here is a basic example showing how variables can be<br />
stored to hidden form fields and restored on page load:</p>
<pre class="html:nocontrols">
<input id="saved-data" type="hidden" /></pre>
<h5>Saving data in hidden form fields (<a href="&lt;br"></a> &#8220;/examples/saving-state/example-2.html&#8221;&gt;example 2)</h5>
<pre class="js:nocontrols">// 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;
   }
}</pre>
<p>In the above example, all we&#8217;re saving is one string<br />
from the user. But what about cases where we need to save<br />
many different values? For instance, what if we&#8217;re using<br />
object-oriented code and have numerous nested objects<br />
within objects we need to store? At times like this,<br />
<strong>serializing objects with JSON</strong> is the<br />
easiest way to store the data. Without using JSON, you&#8217;d<br />
have to create a hidden form field for each value you want<br />
to save, whereas JSON can create string representations of<br />
complex data structures that you can easily <em>eval</em><br />
back into JavaScript objects once they&#8217;re fetched from the<br />
DOM.</p>
<h3>So What is JSON, Anyway?</h3>
<p>JSON (pronounced &#8220;Jason&#8221;), short for <em>JavaScript<br />
Object Notation</em> is a lightweight, human- and<br />
machine-readable way to represent the string serializations<br />
of objects. These strings can be evaluated back into<br />
JavaScript objects as needed. For instance, say I create a<br />
JavaScript object to represent a person (in this case,<br />
me):</p>
<pre class="js:nocontrols">var person = new Object();
person.name = "Jonah";
person.age = 24;
person.gender = "male";
person.location = "Seattle, WA";</pre>
<p>The JSON representation of this object is as<br />
follows:</p>
<pre class="js:nocontrols">{
    'person': {
        'name': 'Jonah',
        'age': 24,
        'gender': 'male',
        'location': 'Seattle, WA'
    }
}</pre>
<p>Then, if you need to reconstruct the object at a later<br />
point, you can simply eval the JSON string:</p>
<pre class="js:nocontrols">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');</pre>
<p>If you&#8217;ve written JavaScript using object literal syntax<br />
before, this should be familiar to you. The only minor<br />
difference between JSON and the standard JavaScript object<br />
literal syntax is that JSON requires quotes around key in a<br />
key/value pair. So, <em>name</em> is a valid JavaScript key<br />
but in JSON it would have to be <em>&#8216;name&#8217;</em>. (Note: It<br />
doesn&#8217;t matter if you use single- or double-quotes, as long<br />
as they are matched).</p>
<h3>Stringifying Objects in JSON</h3>
<p>To use JSON, it&#8217;s necessary to include a library of JSON<br />
methods. Don&#8217;t worry, the library is quite small. The<br />
entire thing shouldn&#8217;t be more than 2k and can be obtained<br />
from <a href="http://www.json.org/js.html">json.org</a>.<br />
Eventually, the JSON methods will be included as part of<br />
the core JavaScript language, but for the time being, we&#8217;re<br />
left to use the methods provided by json.org or those found<br />
in libraries such as MooTools, Prototype and jQuery.</p>
<p>Depending on the library used, the method names for<br />
serializing an object into a JSON string are different.<br />
But, they are all used in rather similar fashion. For now,<br />
we&#8217;ll assume you&#8217;re using the library from <a href="&lt;br"></a> &#8220;http://www.json.org/js.html&#8221;&gt;json.org and use the<br />
method names provided in its API.</p>
<h5>Saving complex JavaScript data structures as JSON<br />
strings (<a href="/examples/saving-state/example-3.html">example 3</a>)</h5>
<pre class="js">// 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);
}</pre>
<p>This example is pretty similar to the previous one where<br />
we saved a string. The only difference is that in this<br />
case, the string is a representation of a complex<br />
JavaScript object. In fact, you can save the entire state<br />
of your application in one JSON string, as long as the<br />
application state is completely stored as properties of a<br />
single object. There are a few minor gotchas, such as<br />
having to add parentheses around the JSON string when<br />
evaluating it. But, overall this is a clean and<br />
straightforward approach that is very useful when complex<br />
data structures must be retained.</p>
<h3>Using Named Anchors to Save State</h3>
<p>An alternate option for retaining state is to not<br />
actually let the user leave the page at all. Rather, when<br />
following links on the site, update the named anchor<br />
(everything after the number sign in a URL), instead of<br />
changing the actual document being displayed.</p>
<p>The problem that this is trying to solve is the fact<br />
that Ajax applications will normally break the back button.<br />
A user loads the application on the homepage and clicks to<br />
visit a different page, but since the new page is loaded in<br />
via Ajax, the browser URL doesn&#8217;t change. Then the user<br />
clicks the back button and leaves the application<br />
altogether&#8211; not the intention of the user, who just wanted<br />
to get back to the homepage.</p>
<p>Storing data in named anchors offers a solution to this<br />
problem. Each time the application state changes,<br />
JavaScript updates the named anchor with a token<br />
representing the application state. When the page is<br />
loaded, data is read from the named anchors and the state<br />
can be restored.</p>
<p>Say you&#8217;re on the homepage of an ecommerce Ajax<br />
application and click on a product you&#8217;d like to view.<br />
Instead of changing URLs to the detail page, the<br />
application loads in new data with Ajax. So, when a user<br />
clicks on the new Brad Mehldau CD for instance, instead of<br />
going to a different URL (yoursite.com/brad-mehldau/) the<br />
document URL remains the same, but JavaScript updates the<br />
named anchor: yoursite.com/#brad-mehldau.</p>
<p>One site which does this unbelievably well is <a href="&lt;br"></a> &#8220;http://www.thesixtyone.com&#8221;&gt;<em>thesixtyone.com</em><br />
(Thanks, Derek!). The entire site resides in one document,<br />
truly a rich JavaScript application if I&#8217;ve ever seen one.<br />
But, despite the fact that the entire application is<br />
contained in a single document URL, due to clever use of<br />
named anchors, the site has full back button support and<br />
you can even email working links to friends.</p>
<p>Implementing code to save state in named anchors is out<br />
of scope for this article, but you can see how it is<br />
somewhat similar to saving data in hidden form fields. In<br />
this case, there are a few more issues to mitigate and it&#8217;s<br />
somewhat tricky, but the reward is an Ajax site with fully<br />
functional back button support and the ability to share<br />
links &#8212; worth all the effort, in my book.</p>
<h3>So What Use is Ajax, Then?</h3>
<p>Since we&#8217;ve made it this far, you might think that there<br />
is no use for Ajax in all this. Actually, Ajax is great for<br />
saving state to the server, especially for saving data<br />
beyond the lifespan of the browser session. Ajax can be<br />
used to save messages periodically (like how Gmail and<br />
Google Docs automatically save on a timer every few<br />
minutes). It can also be used to send data when the user<br />
leaves the page by capturing the <em>onbeforeunload</em><br />
event, but this is unreliable and I would not depend on<br />
this Ajax request to complete. Instead, try to save the<br />
data before the user attempts to leave the page, by either<br />
firing the Ajax request on a timer or another event on the<br />
page (leaving focus on a form element, for example).</p>
<p>Some frameworks like Prototype have serialize() methods<br />
that return URL query string representations of objects.<br />
This is perfect for saving data through GET requests. Yes,<br />
GET requests have a 2000-character limit and other<br />
limitations, but in most cases this won&#8217;t be an issue. Even<br />
without helper methods to serialize objects, it&#8217;s a fairly<br />
simple matter to construct an Ajax request that will save<br />
the necessary data to the server.</p>
<h3>Wrapping Up</h3>
<p>To re-cap, it is a good practice to check if users are<br />
sure they want to leave a page when they are entering<br />
information, but it&#8217;s even better to silently save that<br />
information for them. (Arguably you would want to do both,<br />
like how Gmail and Blogger save state <em>and</em> ask<br />
users if they are sure they want to leave the page). There<br />
are many different ways to save state, some purely<br />
client-side and others relying on saving data to the server<br />
with Ajax. The solutions which save data to the server are<br />
suitable for times when the data needs to be saved beyond<br />
the browsing session.</p>
<p>Of the two client-side solutions explored, hidden form<br />
fields and named anchors, the former is more suitable for<br />
conventional websites spanning many pages while the latter<br />
better suits single-page Ajax applications. Using named<br />
anchors also has the added benefit of allowing users to<br />
bookmark and send links to the JavaScript application in<br />
various states, and the state is preserved beyond the<br />
browsing session.</p>
<p>Whatever strategy you follow, your users will thank you<br />
for the time saved and frustration avoided of having to<br />
re-enter lost information.</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2008%2F06%2Fsaving-state-what-to-do-when-users-leave%2F&amp;linkname=Saving%20State%3A%20What%20To%20Do%20When%20Users%20Leave"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2008/06/saving-state-what-to-do-when-users-leave/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>AJAX Google API to Minify Javascript using Ruby on Rails</title>
		<link>http://www.thetruetribe.com/2008/06/ajax-google-api-to-minify-javascript-using-ruby-on-rails/</link>
		<comments>http://www.thetruetribe.com/2008/06/ajax-google-api-to-minify-javascript-using-ruby-on-rails/#comments</comments>
		<pubDate>Sun, 08 Jun 2008 05:36:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://wordpress.thetruetribe.com/?p=38</guid>
		<description><![CDATA[How to optimizing JavaScript performance 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&#8217;ll explore including it from [...]]]></description>
			<content:encoded><![CDATA[<p>How to <span style="font-weight: bold;">optimizing JavaScript performance</span> 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&#8217;ll explore including it from Google&#8217;s <a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a>.<span id="more-38"></span></p>
<p>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.</p>
<p>We&#8217;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.</p>
<h3>Including JavaScript in Ruby on Rails</h3>
<p>First of all, let&#8217;s look at how JavaScript is included in Ruby on Rails, the <span style="font-family:Courier New;">javascript_include_tag</span> 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:</p>
<pre class="code">  javascript_include_tag("script1.js", "script2.js", "script3.js")</pre>
<p><strong>Result:</strong></p>
<p style="font-family: Courier,monospace;">&lt;script type=&#8221;text/javascript&#8221; src=&#8221;/javascripts/script1.js&#8221;&gt;&lt;/script&gt;</p>
<p>&lt;script type=&#8221;text/javascript&#8221; src=&#8221;/javascripts/script2.js&#8221;&gt;&lt;/script&gt;</p>
<p>&lt;script type=&#8221;text/javascript&#8221; src=&#8221;/javascripts/script3.js&#8221;&gt;&lt;/script&gt;</p>
<p>There&#8217;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:</p>
<pre class="code">  javascript_include_tag :all, :cache =&gt; true # when ActionController::Base.perform_caching is true</pre>
<p>The resulting code is:</p>
<p style="font-family: Courier,monospace;">&lt;script type=&#8221;text/javascript&#8221; src=&#8221;/javascripts/all.js&#8221;&gt;&lt;/script&gt;</p>
<p>If you don&#8217;t want them concatenated into a single file, e.g. for development purposes, you could do something like this:</p>
<pre class="code"># 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:</pre>
<p>I&#8217;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.</p>
<p>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 <span style="font-family:Courier New;">environments/development.rb file.</span> For more information, view the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#M001024">docs for the javascript_include_tag</a>.</p>
<h3>JavaScript Concatenation and Minification</h3>
<p>Next, we&#8217;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&#8217;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&#8217;ll show my implementation as an example regardless.</p>
<p>I&#8217;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 (&gt;&gt;). Here goes:</p>
<pre>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</pre>
<p>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.</p>
<p>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&#8217; packer). Unfortunately, I can&#8217;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.</p>
<p>If you are going to use YUICompressor, <strong>you must have Java installed</strong> and included in your path. If it isn&#8217;t in your path, you can use the full path to Java, for instance, <span style="font-family:Courier New;">&#8220;C:\Program Files\Java\bin\java.exe&#8221; -jar [filename] [options].</span></p>
<h3><span style="font-family:Courier New;">Using the Google AJAX Libraries</span></h3>
<p><span style="font-family:Courier New;"><br />
<a href="http://code.google.com/apis/ajaxlibs/" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://www.thetruetribe.com/uploaded_images/google-ajax-api-735798.png" border="0" alt="" /></a><br />
</span></p>
<p>Depending on your opinion about Google&#8217;s recent offer to host the world&#8217;s JavaScript frameworks with its <a href="http://code.google.com/apis/ajaxlibs/">AJAX Libraries API</a>, you may not find this suggestion too useful, but I think it&#8217;s helpful, especially to those without access to their hosting provider&#8217;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&#8217;s API, their servers are configured &#8220;correctly&#8221; for best performance (far future expires headers, Gzip, etc).</p>
<p>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&#8217;s impossible to debug minified JavaScript (don&#8217;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.</p>
<h3>Toggling Minified Google JS</h3>
<p>Here&#8217;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:</p>
<p>&lt;</p>
<p>Or, if you didn&#8217;t want to include everything in the JS folder, and wanted to granularly include only specific files, you might rewrite it like so:</p>
<p>That&#8217;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&#8217;t worry about when it&#8217;s in production since it will always serve up the minified, concatenated JavaScript. The logic ensures that you won&#8217;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;</p>
<a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?linkurl=http%3A%2F%2Fwww.thetruetribe.com%2F2008%2F06%2Fajax-google-api-to-minify-javascript-using-ruby-on-rails%2F&amp;linkname=AJAX%20Google%20API%20to%20Minify%20Javascript%20using%20Ruby%20on%20Rails"><img src="http://www.thetruetribe.com/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share/Bookmark"/></a>]]></content:encoded>
			<wfw:commentRss>http://www.thetruetribe.com/2008/06/ajax-google-api-to-minify-javascript-using-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
