<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>GridWorlds</title>
	
	<link>http://blog.gridworlds.com</link>
	<description>A software development blog about GridWorlds.</description>
	<pubDate>Sun, 09 Nov 2008 21:30:39 +0000</pubDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/gridworlds" type="application/rss+xml" /><item>
		<title>Animation Chains with jQuery</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/ksls46uD0No/animation-chains-with-jquery</link>
		<comments>http://blog.gridworlds.com/js/animation-chains-with-jquery#comments</comments>
		<pubDate>Sun, 09 Nov 2008 21:30:39 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/?p=21</guid>
		<description><![CDATA[Using the <a href="http://docs.jquery.com/Effects/animate">animate()</a> function built into the core jQuery library, you can generate complex, multi-step movement or visual effects using any element on your Web page. No Flash or Silverlight is needed, just the CSS and JavaScript capabilities built into your browser. The secret to complex animations is jQuery's ability to "chain" multiple functions together to apply actions sequentially. Read on to learn how it's done.]]></description>
			<content:encoded><![CDATA[<p>Using the <a href="http://docs.jquery.com/Effects/animate">animate()</a> function built into the core jQuery library, you can generate complex, multi-step movement or visual effects using any element on your Web page. No Flash or Silverlight is needed, just the CSS and JavaScript capabilities built into your browser. The secret to complex animations is jQuery&#8217;s ability to &#8220;chain&#8221; multiple functions together to apply actions sequentially. Here&#8217;s a sample:</p>
<div style="width:50%; height:32px; margin-left:25%"><img src="/wp-content/uploads/2008/10/avatar.gif" alt="Avatar" width="32" height="32" id="avatar" style="float:left" /><img src="/wp-content/uploads/2008/10/missile.gif" alt="Missile" width="32" height="32" id="missile" style="position:absolute; z-index: 1; display:none"/><img src="/wp-content/uploads/2008/10/gauth.gif" alt="Gauth" width="32" height="32" style="float:right; z-index:0" id="gauth"/></div>
<p></p>
<p>In the animation above, notice how the missile first travels from the avatar to the monster, then turns into a starburst that fades out and disappears. This effect is actually three separate animate() functions chained together. Let&#8217;s break it apart to see how it works.</p>
<h3>First, Some Setup</h3>
<p>I have placed three images on the page: an avatar graphic, a monster graphic, and a missile graphic which is initially hidden (display: none). I actually put all three of them inside a div to keep them together, but this is not strictly necessary &#8212; they can be anywhere on the page. I also give each &lt;img&gt; tag a unique id I can reference later.</p>
<pre>
&lt;div style="width:50%; height:32px; margin-left:25%"&gt;
    &lt;img src="avatar.gif" alt="Avatar" width="32" height="32" id="avatar" style="float:left" /&gt;
    &lt;img src="missile.gif" alt="Missile" width="32" height="32" id="missile" style="position:absolute; z-index: 1; display:none"/&gt;
    &lt;img src="gauth.gif" alt="Gauth" width="32" height="32" style="float:right; z-index:0" id="gauth"/&gt;
&lt;/div&gt;
</pre>
<h3>Bring On jQuery</h3>
<p>Now I pull in jQuery from <a href="http://code.google.com/apis/ajaxlibs/">Google&#8217;s AJAX Libraries</a> API page. Google has made many of the most popular JavaScript libraries freely available for developers via hosted URLs so you don&#8217;t even need to download and install them on your server. That&#8217;s just awesome.</p>
<pre>
&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"&gt;&lt;/script&gt;
</pre>
<p>I have chosen the minified version of jQuery 1.2.6, but you can get the latest version automatically if you prefer.</p>
<h3>Where&#8217;s the Missile?</h3>
<p>For convenience I assign the missile image (selected with that unique id I set above) to a $missile variable. Now I need to figure out where to send the missile. JQuery provides a method to find the position of any element named, oddly enough, <a href="http://docs.jquery.com/CSS/position">position()</a>. I select the gauth and assign the position object to a $end variable. The position object contains two properties: top and left.</p>
<pre>
&lt;script type="text/javascript"&gt;
    $missile = $("#missile");
    $end = $("#gauth").position();
    $missile.show();
</pre>
<p>Just before firing off the animation, I display the image using the <a href="http://docs.jquery.com/Effects/show">show()</a> function.</p>
<h3>Let&#8217;s Animate!</h3>
<p>The general form of a chained animation is a series of animate() calls for each step of the animation:</p>
<blockquote><p>jQueryObject.animate().animate().animate().etc.</p></blockquote>
<p>For each animate() step, any number of style properties can be set as endpoints for that stage of the animation. When you chain the animate() functions together, you create more complex animations or effects. Here are all three parts of the animation chain:</p>
<pre>
    $missile.animate(
        {top: $end.top + "px", left: $end.left + "px"},
        900,
        "linear",
        function() { $missile.attr({ src: "hit.gif" }); }
    ).animate(
        {opacity: 0.5},
        600,
        "swing"
    ).animate(
        {top: "hide"},
        1
    );
</pre>
<p>In this example, the three animate() functions correspond to these three steps in the animation:</p>
<ol>
<li>Move the missile from avatar to monster</li>
<li>Fade out the missile</li>
<li>Hide the missile</li>
</ol>
<p>In the first step, the graphic moves to new top and left coordinates in 900 milliseconds at a constant &#8220;linear&#8221; velocity. In the second step, the graphic becomes 50% transparent in 600 milliseconds at a non-linear &#8220;swing&#8221; rate. The final step is to make the graphic disappear instantly (actually, in one millisecond) by setting a CSS property to a value of &#8220;hide.&#8221;</p>
<h3>Something is Missing</h3>
<p>A missing step is swapping the missile image with a starburst image to represent a &#8220;hit.&#8221; JQuery&#8217;s animate() function only supports changing style properties, and even then it only works with style properties using numeric values. So, for example, I can&#8217;t change a background graphic or set a src attribute on an &lt;img&gt; tag. However, animate() supports a handy callback function that virtually eliminates limitations like this.</p>
<p>Here&#8217;s how it works: At any step in the animate() chain, pass a function parameter as a callback. When that step of the animation is done, it will halt the chain, call your function, and then continue with the next step in the chain. This means you can insert callbacks to do virtually anything, even operations completely outside the scope of the animation.</p>
<p>I use a callback as the fourth parameter in the first animate() function, which looks like this:</p>
<pre>
function() { $missile.attr({ src: "hit.gif" }); }
</pre>
<p>In this callback I swap the missile graphic with a hit.gif starburst graphic. This occurs before the second step of the animation begins.</p>
<h3>Putting It All Together</h3>
<p>Here is the complete code to create this animation:</p>
<pre>
&lt;div style="width:50%; height:32px; margin-left:25%"&gt;
    &lt;img src="avatar.gif" alt="Avatar" width="32" height="32" id="avatar" style="float:left" /&gt;
    &lt;img src="missile.gif" alt="Missile" width="32" height="32" id="missile" style="position:absolute; z-index: 1; display:none"/&gt;
    &lt;img src="gauth.gif" alt="Gauth" width="32" height="32" style="float:right; z-index:0" id="gauth"/&gt;
&lt;/div&gt;

&lt;script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"&gt;&lt;/script&gt;

&lt;script type="text/javascript"&gt;
    $missile = $("#missile");
    $end = $("#gauth").position();
    $missile.show();
    $missile.animate(
        {top: $end.top + "px", left: $end.left + "px"},
        900,
        "linear",
        function() { $missile.attr({ src: "hit.gif" }); }
    ).animate(
        {opacity: 0.5},
        600,
        "swing"
    ).animate(
        {top: "hide"},
        1
    );
&lt;/script&gt;
</pre>
<p><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script><br />
<script type="text/javascript">
$(document).ready(window.setInterval(attack, 3000));
function attack() {
    $missile = $("#missile");
    $start = $("#avatar").position();
    $end = $("#gauth").position();
    $width = $("#avatar").width();
    $missile.css({ top: $start.top, left: $start.left + $width, opacity: 1 });
    $missile.attr({ src: "/wp-content/uploads/2008/10/missile.gif" });
    $missile.show();
    $missile.animate(
        {top: $end.top + "px", left: $end.left + "px"},
        900,
        "linear",
        function() { $missile.attr({ src: "/wp-content/uploads/2008/10/hit.gif" }); }
    ).animate(
        {opacity: 0.5},
        600,
        "swing"
    ).animate(
        {top: "hide"},
        1
    );
}
</script></p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/ksls46uD0No" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/js/animation-chains-with-jquery/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/js/animation-chains-with-jquery</feedburner:origLink></item>
		<item>
		<title>Build 42 Released</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/BcYszDd3268/build-42-released</link>
		<comments>http://blog.gridworlds.com/grid/build-42-released#comments</comments>
		<pubDate>Wed, 24 Sep 2008 03:50:08 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[GridWorlds]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/grid/build-42-released</guid>
		<description><![CDATA[Here is a summary of this release: Yesterday I deployed build number 42 to my DreamHost server. Everything was broken, so I rolled back to build 31. Everything was still broken. Today, I re-deployed 42 and everything works again. So, what happened?]]></description>
			<content:encoded><![CDATA[<p>Here is a summary of this release: Yesterday I deployed build number 42 to my DreamHost server. Everything was broken, so I rolled back to build 31. Everything was still broken. Today, I re-deployed 42 and everything works again. So, what happened?</p>
<h3>Untyped and Unterminated</h3>
<p>After deployment, I was getting &#8220;untyped binary data&#8221; errors on random pages in Firefox (also known as the dreaded &#8220;application/octet-stream&#8221; issue on the Windows side) and &#8220;unterminated string literal&#8221; errors in all my Ajax calls. I spent much time and effort pulling out my hair trying to figure out how code that worked so smoothly on my MacBook Pro could die so spectacularly in production. Did I forget to check something in? Did I not test enough? Am I just unlucky?</p>
<p>As is often the case, the problem was the server configuration and not the code. I have been using <a href="http://www.fastcgi.com">FastCGI</a> on <a href="http://www.dreamhost.com">DreamHost</a> since I launched <a href="http://gridworlds.com">GridWorlds</a>, and for a while now it has been working well. All that changed recently, which apparently caused my application to wig out quite badly.</p>
<h3>Enter Passenger</h3>
<p>Thankfully, the solution was at hand. I have been meaning to switch over to <a href="http://www.modrails.com">Passenger</a> (also known as &#8220;mod_rails&#8221;) since <a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/">DreamHost announced it</a> earlier this year. Since I had no idea what was wrong with FastCGI, and I absolutely hate messing with obscure server configuration problems (and yes, I was desperate to find a solution), I thought I&#8217;d give it a try sooner rather than later.</p>
<p>DreamHost has a wonderful <a href="http://wiki.dreamhost.com/Passenger">&#8220;one-click&#8221; Passenger setup</a> that is 100% seamless and actually works beautifully. I didn&#8217;t have to change one thing in my Rails app to make it work, and all the weird errors I was seeing magically vanished. Switching to Passenger reminded me why I enjoy working with Rails in the first place: it&#8217;s easy to set up, and you don&#8217;t have to go digging in XML files to get your application to run.</p>
<h3>What&#8217;s In This Release?</h3>
<p>This time around, I added a whole bunch of new features to GridWorlds, including combat with animation and sound effects (yes, you can finally kill things!), character creation, and automatic saved games. I also added a lot of &#8220;polish&#8221; with clearer screen flow, better error handling, and nicer form layout. Here are the highlights:</p>
<ul>
<li>Implemented a combat system, including animation, sound effects, damage, and death</li>
<li>Built a character creation screen to customize your new character&#8217;s attributes, HP, starting gold, etc.</li>
<li>Replaced JS prompt()-based talk feature with an in-line text editing talk mode (much more immersive)</li>
<li>Enhanced inhabitant talk options to include random responses, hello and goodbye responses (and no more |-delimited text)</li>
<li>Reworked inhabitant &#8220;behavior&#8221; system to allow for changing behaviors after being attacked (so a friendly inhabitant will turn nasty if you take a swing at him)</li>
<li>Added an avatar stats box, so you can see details about your avatar during game play</li>
<li>Applied a new layout to all forms</li>
<li>Cleaned up validation and error message styling</li>
<li>Simplified navigation and screen flow to make things clearer for new players (fewer things to click, less confusing)</li>
<li>Added a &#8220;Rest&#8221; command to allow the avatar to heal &#8212; but it only works when there are no monsters around</li>
<li>Implemented a save game feature, which stores the current state of each map. There&#8217;s also an auto-save feature that automatically saves the game every time the avatar enters a new map.</li>
<li>And of course, tons of bug fixes, refactored code, etc.</li>
</ul>
<h3>42</h3>
<p>The number <a href="http://www.dailygalaxy.com/my_weblog/2007/07/42-hitchikers-g.html">42</a> has a certain significance that will not be lost upon most who read this. I didn&#8217;t plan to release a build number 42, it just happened that way. Kinda spooky, isn&#8217;t it?</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/BcYszDd3268" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/grid/build-42-released/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/grid/build-42-released</feedburner:origLink></item>
		<item>
		<title>Secrets of Links in Rails</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/67LtR6JrgWQ/secrets-of-links-in-rails</link>
		<comments>http://blog.gridworlds.com/rails/secrets-of-links-in-rails#comments</comments>
		<pubDate>Mon, 25 Aug 2008 02:40:06 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/rails/secrets-of-links-in-rails</guid>
		<description><![CDATA[Rails provides a handy method for creating a link in your views:

<pre>
link_to "Home Page", "http://gridworlds.com"
<em>=&#62;  &#60;a href="http://gridworlds.com"&#62;Home Page&#60;/a&#62;</em>
</pre>

Of course, if this were all the link_to() method did, there would be little reason to use it instead of just typing the HTML directly.]]></description>
			<content:encoded><![CDATA[<p>Rails provides a handy method for creating a link in your views:</p>
<pre>
link_to "Home Page", "http://gridworlds.com"
<em>=&gt;  &lt;a href="http://gridworlds.com"&gt;Home Page&lt;/a&gt;</em>
</pre>
<p>Of course, if this were all the link_to() method did, there would be little reason to use it instead of just typing the HTML directly. This method makes it easy to generate links that tie directly to controllers and actions. For example:</p>
<pre>
link_to :Edit, :controller => :user, :action => :edit
<em>=&gt;  &lt;a href="/user/edit"&gt;Edit&lt;/a&gt;</em>
</pre>
<p>If you leave out the controller, Rails assumes the controller that called the view:</p>
<pre>
link_to :Edit, :action => :index
<em>=&gt;  &lt;a href="/user"&gt;Edit&lt;/a&gt;</em>
</pre>
<h3>Conditional Links</h3>
<p>The <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html">UrlHelper</a> module includes several other methods to make linking easier. Sometimes you need to display a link conditionally. For example, in a navigation menu you may not want to link the active navigation item for the current page. You could always wrap a link in an if/then statement, like this:</p>
<pre>
if navigation != active
  link_to "FAQ", "/faq"
end
</pre>
<p>But why use three statements when one will do?</p>
<pre>
link_to_if navigation != active, "FAQ", "/faq"
</pre>
<p>Rails includes two other conditional link methods you may find useful: link_to_unless() and link_to_unless_current().</p>
<h3>Secret Life of Links</h3>
<p>The secret of link_to() is that it uses url_for() to generates these URLs. The url_for() method allows you to generate only a URL without the corresponding &lt;a href=&#8221;&#8230;&#8221;&gt; tag. When would you do this? How about in a JavaScript onclick handler:</p>
<pre>
&lt;div onclick="window.location = '&lt;%= url_for :action =&gt; :edit %&gt;'"&gt;
I want this whole div to be clickable
&lt;/div&gt;
</pre>
<p>url_for() also includes a bunch of options for setting the host, protocol, anchor, generating absolute or relative links, etc. Check out the <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001600">Rails docs</a> for full details.</p>
<h3>What About Query Parameters?</h3>
<p>Both link_to() and url_for() provide an undocumented way to include additional query parameters in your URLs. While it is easy to include an ID, like this&#8230;</p>
<pre>
link_to "Edit User", :controller => :user, :action => :edit, :id => 12
<em>=&gt;  &lt;a href="/user/edit/12"&gt;Edit User&lt;/a&gt;</em>
</pre>
<p>&#8230;what if you want to generate a URL with both an ID and separate query parameters? Just tack on additional parameters at the end, like this:</p>
<pre>
link_to "Edit User", :controller => :user, :action => :edit, :id => 12, :firstname => "Joe", :lastname => "Smith"
<em>=&gt;  &lt;a href="/user/edit/12?firstname=Joe&#038;lastname=Smith"&gt;Edit User&lt;/a&gt;</em>
</pre>
<p>There&#8217;s one gotcha here: Rails tries to guess which parameters are options for the link_to() or url_for() methods and which should be converted to query parameters. If you aren&#8217;t explicitly using {:curley => :brackets} in your method call, Rails may interpret your options as query parameters. Here&#8217;s a good example:</p>
<pre>
link_to :Test1, :controller => :user, :action => :edit, :id => 12, :confirm => "Are you sure?"
<em>=&gt;  &lt;a href="/user/edit/12?confirm=Are+you+sure%3F"&gt;Test1&lt;/a&gt;</em>

link_to :Test2, { :controller => :user, :action => :edit, :id => 12 }, :confirm => "Are you sure?"
<em>=&gt;  &lt;a href="/user/edit/12" onclick="return confirm('Are you sure?')"&gt;Test2&lt;/a&gt;</em>
</pre>
<p>Notice in the first example the :confirm symbol is just another query parameter, while in the second example :confirm is a JavaScript dialog. The only difference between the two is the addition of curly brackets to make the confirm explicit.</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/67LtR6JrgWQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/rails/secrets-of-links-in-rails/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/rails/secrets-of-links-in-rails</feedburner:origLink></item>
		<item>
		<title>Build 31 Released</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/nr4TXylzYZs/build-31-released</link>
		<comments>http://blog.gridworlds.com/grid/build-31-released#comments</comments>
		<pubDate>Mon, 26 May 2008 17:50:27 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[GridWorlds]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/grid/build-31-released</guid>
		<description><![CDATA[What's been happening with GridWorlds lately? Another three months have passed since the last update, and while I'm not trying to do quarterly releases it seems to be happening unintentionally. This release brings a fairly major architectural change to GridWorlds, which partially explains the delay.]]></description>
			<content:encoded><![CDATA[<p>What&#8217;s been happening with GridWorlds lately? Another three months have passed since the last update, and while I&#8217;m not trying to do quarterly releases it seems to be happening unintentionally.</p>
<p>This release brings a fairly major architectural change to GridWorlds, which partially explains the delay. Since the early days I had been trying to turn this into a multi-player game, so different avatars could interact and explore the same dungeons. That&#8217;s a great idea for a big client-server game with lots of powerful servers and network bandwidth (I&#8217;m talking about you, <a href="http://www.worldofwarcraft.com">WoW</a>), but not so practical for a small, Web-based game like this one.</p>
<p>As I added new features for the next release, I noticed the game becoming slower and slower, until it no longer resembled a real-time RPG so much as a tedious turn-based game. A few tests quickly showed that even a handful of gamers playing simultaneously would bring almost any server to its knees.</p>
<p>Therefore, I reluctantly gave up on the idea of multi-player, and switched to a much simpler single-player implementation. While this removes some of the cool features like real-time chatting with other avatars, I think it returns to the roots of games like Ultima that I have been trying to emulate all along. Not only will this speed up game play, but it has dramatically simplified the code base. This will make it much easier to build out game features more quickly, rather than wrestling with multi-player performance issues.</p>
<p>Besides, single-player games can be just as much fun as multi-player! Try out this new version, and let me know if you agree.</p>
<p>Build 31 includes the following updates:</p>
<ul>
<li>Stripped out all of the multi-player code, which streamlined everything considerably</li>
<li>Converted worlds into groups of maps - each world has a default map so avatars always enter the world at the same location and map editors can create separate &#8220;campaigns&#8221; (unfortunately, this forced me to wipe out any existing maps people may have already created&#8230; sorry about that)</li>
<li>Modified maps to support multiple tilesets (mix and match tiles on the same map!)</li>
<li>Implemented spawning of random encounters (so new monsters can appear on the map over time)</li>
<li>Implemented different movement patterns for inhabitants and encounters, including wandering, approaching, and avoiding</li>
<li>Added a &#8220;Look&#8221; command to view info about anything on the map</li>
<li>Added an &#8220;Attack&#8221; command to kill things on the map (no real combat yet - they die instantly and don&#8217;t defend themselves)</li>
<li>Added a handy &#8220;edge of the map&#8221; border line on the map editor</li>
<li>Implemented a much better cross-browser JS-only player for sound effects (thank you, <a href="http://www.zwitserloot.com/files/soundkit/soundcheck.html">Zwitserloot</a>)</li>
<li>Improved drawing routines to speed up maps and eliminate flicker in Firefox</li>
<li>Implemented Rails single-table inheritance for denizens to handle the distinction between inhabitants and encounters more cleanly</li>
<li>Added drag-and-drop in map editor to easily move portals, messages, inhabitants, and encounters (using the very slick <a href="http://ui.jquery.com/">jQuery UI</a> library)</li>
<li>Upgraded to Rails 2.0.2 to eliminate annoying JSON bugs, convert to cookie-based sessions, and take advantage of other framework improvements</li>
<li>Upgraded to jQuery 1.2.5 just for the heck of it</li>
<li>Moved most of the JavaScript code under a single &#8220;grid&#8221; global variable to avoid potential namespace collisions (see <a href="http://yuiblog.com/blog/2006/06/01/global-domination/">Global Domination</a> blog entry for more info)</li>
<li>Tracked down a major performance issue with Safari 3 and <a href="https://bugs.webkit.org/show_bug.cgi?id=18998">reported it</a> to the WebKit team: rapidly swapping out dozens of background images will quickly eat up lots of memory</li>
<li>Added the <a href="http://code.google.com/p/bundle-fu/">bundle-fu</a> plug-in to merge JS and CSS files into bundles for much better performance</li>
<li>Numerous other small bug fixes and enhancements</li>
</ul>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/nr4TXylzYZs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/grid/build-31-released/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/grid/build-31-released</feedburner:origLink></item>
		<item>
		<title>Build 21 Released</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/WUD7wQpO2Qc/build-21-released</link>
		<comments>http://blog.gridworlds.com/grid/build-21-released#comments</comments>
		<pubDate>Sat, 16 Feb 2008 03:11:07 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[GridWorlds]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/grid/build-21-released</guid>
		<description><![CDATA[After a considerable hiatus since my last update (according to Subversion it's been almost three months), I finally deployed a new release this morning. This update combines several smaller checkins, but includes some larger features...]]></description>
			<content:encoded><![CDATA[<p>After a considerable hiatus since my last update (according to Subversion it&#8217;s been almost three months), I finally deployed a new release this morning. This update combines several smaller checkins, but includes some larger features including talking to NPC inhabitants and directional talk with avatars so you can now chat privately with other players nearby. This release also lays the the foundation for adding random encounters with monsters later on &#8212; which brings the game one step closer to combat.</p>
<p>Build 21 includes the following updates and fixes:</p>
<ul>
<li>Updated navigation and screen flow, flash messages, and delete confirmations</li>
<li>Added random encounter maintenance for the world editor (monsters are still not showing up during play, but that&#8217;s next)</li>
<li>Refactored monster-related code to separate from inhabitants</li>
<li>Refactored avatar controller to move logic into avatar, inhabitant, and message models</li>
<li>Implemented click to view on map grid</li>
<li>Implemented talking to an inhabitant by choosing a direction when standing next to him/her/it (T + arrow key)</li>
<li>Implemented talking to another avatar by choosing a direction when standing next to him/her (T + arrow key) or by yelling (Y) so every avatar nearby can hear you</li>
<li>Prepopulating contact info in contact form if user is logged in</li>
<li>Linked blog post titles for better SEO</li>
<li>Changed title tag to put &#8220;GridWorlds&#8221; at the end (for better SEO)</li>
<li>Added unique meta description for each public page for SEO</li>
<li>Verified site via Google&#8217;s webmaster tools by adding empty verification file</li>
<li>Fixed double-message bug when entering a world on a sticky message</li>
<li>Fixed vertical spacing issues in blog styles</li>
<li>Fixed bug in inhabitant icon picker (was not showing correct icon groups)</li>
<li>Fixed inconsistent main navs in blog template</li>
<li>Set up missing macFFBgHack.png reference for Thickbox</li>
<li>Lots of other small changes and refactorings</li>
</ul>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/WUD7wQpO2Qc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/grid/build-21-released/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/grid/build-21-released</feedburner:origLink></item>
		<item>
		<title>Delete or delete? Removing things in Rails</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/a8WYufcKsSU/delete-or-delete-removing-things-in-rails</link>
		<comments>http://blog.gridworlds.com/rails/delete-or-delete-removing-things-in-rails#comments</comments>
		<pubDate>Fri, 15 Feb 2008 12:00:02 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/rails/delete-or-delete-removing-things-in-rails</guid>
		<description><![CDATA[Yesterday, while I was refactoring some code, I inadvertently confused myself about the various delete and destroy methods in Ruby and Rails. Between the two, there are over 20 different ways to remove objects, so I suppose I shouldn't feel too bad I didn't pick the right one. If you ever wanted to know the best way to make things go away in Rails, you've come to the right article.]]></description>
			<content:encoded><![CDATA[<p>Yesterday, while I was refactoring some code, I inadvertently confused myself about the various delete and destroy methods in Ruby and Rails. Between the two, there are over 20 different ways to remove objects, so I suppose I shouldn&#8217;t feel too bad I didn&#8217;t pick the right one. If you ever wanted to know the best way to make things go away in Rails, you&#8217;ve come to the right article.</p>
<p>Let&#8217;s start with an array of message objects, like this:</p>
<pre>
messages = Message.find(:all)
</pre>
<p>If I want to remove an element from this collection, it&#8217;s easy enough using the Ruby array.delete method. If I pass in an object and it matches one of the objects in the array, it is removed (or if the object doesn&#8217;t exist in the array, it just returns nil).</p>
<pre>
messages.delete(message)
</pre>
<p>Now let&#8217;s say I have a World model that has_many :messages, and I want to create a method to delete a message. My first thought is to use the same Ruby delete function:</p>
<pre>
class World &lt; ActiveRecord::Base
    has_many :messages
    def remove_message(message_to_delete)
        messages = Message.find(:all)
        messages.delete(message_to_delete)
    end
end
</pre>
<p>The tricky part here is that message_to_delete is removed from the array in memory, but ActiveRecord knows nothing about it &#8212; message_to_delete is still sitting in the database, untouched. Then it occurred to me: because I set up a has_many relationship, my world instance already has a collection of messages just waiting for me, and ActiveRecord knows all about it! I don&#8217;t have to bother instantiating a collection of messages with the find method:</p>
<pre>
class World &lt; ActiveRecord::Base
    has_many :messages
    def remove_message(message_to_delete)
        <del>messages = Message.find(:all)</del>
        messages.delete(message_to_delete)
    end
end
</pre>
<h3>Rails Persistence Inconsistence</h3>
<p>However, there&#8217;s another problem here, and it has to do with how Rails persists changes to collections managed by ActiveRecord. The message I want to delete is removed from memory, but Rails does not actually delete it from the database. Instead, Rails breaks the relationship between the message and the world by setting the world_id to null for that message. Here&#8217;s the SQL that Rails generates for the messages.delete call above:</p>
<pre>
UPDATE messages SET world_id = NULL WHERE (world_id = 1 AND id IN (1))
</pre>
<p>In other words, message_to_delete is not actually deleted, it is orphaned in the database. Far be it from me to question the wisdom of the Rails Gods<sup><small>TM</small></sup>, but this seems like an odd choice. Preserving data integrity starts with managing foreign key relationships &#8212; and avoids leaving unattached data cluttering up my tables. If I delete something, it should be gone.</p>
<h3>Realization Sets In</h3>
<p>However, then I realized my real mistake: I was using Ruby&#8217;s array.delete rather than one of the handy methods provided by ActiveRecord::Base in Rails. There are several choices:</p>
<ul>
<li><em>Class</em>.delete(id)</li>
<li><em>Class</em>.delete_all(conditions)</li>
<li><em>object</em>.destroy</li>
<li><em>Class</em>.destroy(id)</li>
<li><em>Class</em>.destroy_all(conditions)</li>
</ul>
<p>The ones that start with &#8220;Class&#8221; are all static class methods, so I might use them like this:</p>
<pre>
Message.delete(message_to_delete.id)
Message.delete_all(:conditions => ["world_id = ?", world.id])
</pre>
<p>What&#8217;s the difference between delete and destroy methods? The delete methods all send SQL delete statements directly to the database without instantiating any objects. The destroy methods first instantiate objects to trigger any callbacks and filters before the record is deleted. Of course, destroy is much less efficient than delete, but it lets you perform any cleanup operations on an object before it goes away forever.</p>
<h3>Destruction is the answer</h3>
<p>What have I learned? Since my message object has already been instantiated, the correct method is the instance destroy method. The finished product looks like this:</p>
<pre>
class World &lt; ActiveRecord::Base
    has_many :messages
    def remove_message(message_to_delete)
        message_to_delete.destroy
    end
end
</pre>
<p>I hope this clarifies some of the ways that Rails handles the elimination of objects. Now that you have this knowledge, go forth and destroy.</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/a8WYufcKsSU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/rails/delete-or-delete-removing-things-in-rails/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/rails/delete-or-delete-removing-things-in-rails</feedburner:origLink></item>
		<item>
		<title>Date and Time Calculations in Rails</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/BVTcsgEhUIA/date-and-time-calculations-in-rails</link>
		<comments>http://blog.gridworlds.com/rails/date-and-time-calculations-in-rails#comments</comments>
		<pubDate>Tue, 01 Jan 2008 19:21:58 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/rails/date-and-time-calculations-in-rails</guid>
		<description><![CDATA[Calculating dates and times has always been a challenge for programmers. How many days until the next New Years Eve party (oh, did you forget 2008 is a leap year)? How long ago was the last backup (convert that to GMT, please)? What day of the week is 19 days, 42 hours, and 374 minutes from now (and how many milliseconds is that again)? And don't even get me started on Y2K!]]></description>
			<content:encoded><![CDATA[<p>Calculating dates and times has always been a challenge for programmers. How many days until the next New Years Eve party (oh, did you forget 2008 is a leap year)? How long ago was the last backup (convert that to GMT, please)? What day of the week is 19 days, 42 hours, and 374 minutes from now (and how many milliseconds is that again)? And don&#8217;t even get me started on Y2K!</p>
<p>Almost all programming languages or frameworks provide some facilities for date and time calculations, but they often amount to instantiating multiple date objects and calling obscure methods. Many inexperienced coders end up rolling their own, either out of ignorance or due to the sheer complexity of existing date/time libraries.</p>
<h3>Get on Rails Time</h3>
<p>Due to Ruby&#8217;s inherent &#8220;everything is an object&#8221; design, the ActiveSupport libraries in Rails makes date and time calculations, if not trivial, at least radically easier. Let&#8217;s take a look at some examples &#8212; you can follow along by firing up an <a href="http://www.rubycentral.com/pickaxe/irb.html">irb</a> console for your favorite Rails app, like so:</p>
<pre>
cd /path/to/your/favorite/rails/app
script/console
</pre>
<p>Now type this in the irb shell:</p>
<pre>
>> 15.minutes.ago
</pre>
<p>You should see something like this:</p>
<pre>
=> Tue Jan 01 12:17:51 -0600 2008
</pre>
<p>Very nice! &#8220;15.minutes.ago&#8221; is functionally equivalent to:</p>
<pre>
Time.now.advance(:minutes => -15)
</pre>
<p>But as you can see, the former is much easier to read than the latter.</p>
<h3>Rails Time Calculations</h3>
<p>Time calculations in Rails are just as easy. For example:</p>
<pre>
>> (19.days + 42.hours + 374.minutes).seconds.from_now
=> Tue Jan 22 13:02:06 -0600 2008
</pre>
<p>For convenience, Rails automatically converts everything to seconds, which means I can chain the seconds() and from_now() methods to get the exact date and time in the future.</p>
<h3>Simple Time Zone Adjustments</h3>
<p>Although time zone conversions are inherently nasty, Rails handles them as smoothly as possible. Say, for instance, I want to convert a time value into GMT. First, I would set up a new time_zone instance, like so:</p>
<pre>
>> time_zone = TimeZone.new(0)
=> #&lt;timezone :0x23bbaf8 @utc_offset=0, @name="Casablanca"&gt;
</pre>
<p>This creates a time zone object with an offset of zero (in Casablanca, no less). Next, I would pass a time to the adjust() method on that time_zone:</p>
<pre>
>> time_zone.adjust(15.minutes.ago)
=> Tue Jan 01 18:51:16 -0600 2008
</pre>
<p>There you have it &#8212; date and time calculations, including time zone adjustments, that won&#8217;t give you a headache!</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/BVTcsgEhUIA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/rails/date-and-time-calculations-in-rails/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/rails/date-and-time-calculations-in-rails</feedburner:origLink></item>
		<item>
		<title>Working With Thickbox</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/8syfPN6Aav0/working-with-thickbox</link>
		<comments>http://blog.gridworlds.com/js/working-with-thickbox#comments</comments>
		<pubDate>Sun, 25 Nov 2007 20:26:50 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/js/working-with-thickbox</guid>
		<description><![CDATA[I've recently had the pleasure of working with <a href="http://jquery.com/demo/thickbox/">Thickbox</a>, a lightbox implementation using the excellent <a href="http://jquery.com/">jQuery</a> JavaScript library. There are <a href="http://www.blinklist.com/tag/lightbox/">dozens of lightbox options</a> available, so why did I choose Thickbox?]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently had the pleasure of working with <a href="http://jquery.com/demo/thickbox/">Thickbox</a>, a lightbox implementation using the excellent <a href="http://jquery.com/">jQuery</a> JavaScript library. There are <a href="http://www.blinklist.com/tag/lightbox/">dozens of lightbox options</a> available, so why did I choose Thickbox?</p>
<h3>Simplicity, Thy Name is Thickbox</h3>
<p>Thickbox is the slickest lightbox I have seen &#8212; it has a great user interface and it is trivially easy to set up. Here is some example code:</p>
<pre>
&lt;script type="text/javascript" src="path-to-file/jquery.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="path-to-file/thickbox.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" href="path-to-file/thickbox.css" type="text/css" media="screen"&gt;

&lt;a href="image.jpg" title="image caption" class="thickbox"&gt;&lt;img src="images/thumbnail.jpg" alt="an image"/&gt;&lt;/a&gt;
</pre>
<p>The first three lines pull in jQuery, the Thickbox library, and the Thickbox CSS. The last line is where the magic happens: the &lt;a&gt; tag wrapping the image includes a reference to a &#8220;thickbox&#8221; class which will trigger the lightbox effect when clicked. That&#8217;s it! There&#8217;s nothing else to set up, although you can include an optional title attribute if you want a caption on the image.</p>
<p>Since it is built on top of jQuery (46K minified), the Thickbox code is extremely lightweight and fast loading (less than 5K minified). Browser compatibility is also excellent due to jQuery &#8212; supported browsers include IE 6 and 7, Firefox 2, Safari 2 and 3, and Opera 9.</p>
<h3>It&#8217;s Flexible Too</h3>
<p>Thickbox includes baked in support for all of the most common ways to use a lightbox-style dialog:</p>
<ol>
<li>A single image</li>
<li>Multiple images in a gallery</li>
<li>HTML content within the page</li>
<li>HTML content from another page or site (as an iframe)</li>
<li>HTML content loaded dynamically via Ajax</li>
</ol>
<p>I won&#8217;t bore you with the details of each one. Check out the <a href="http://jquery.com/demo/thickbox/index#examples">documentation</a> for examples.</p>
<h3>Calling Thickbox via JavaScript</h3>
<p>It is also possible to create a Thickbox dialog programmatically via JavaScript, but this technique is strangely undocumented. At first I thought this might not be easy to do, but after cracking open the Thickbox source code (the un-minified version, thank you very much), I immediately noticed this function:</p>
<pre>
tb_show(caption, url, imageGroup)
</pre>
<p>This makes it easy to trigger a Thickbox dialog in code or via an event by passing in a caption string and a URL. The optional imageGroup parameter can also be used to pass in an array of images for a single or multiple image slide show gallery.</p>
<p>The only tricky part is constructing a URL, which needs to include the frame size and any other attributes you might need. Say, for example, you want to display some HTML content in a 300&#215;200 dialog, you might do something like this:</p>
<pre>
&lt;script&gt;
var url = "http://www.blah.com/something?KeepThis=true&#038;TB_iframe=true&#038;width=300&#038;height=200";
tb_show("My Caption", url);
&lt;/script&gt;
</pre>
<p>You can pass in any custom parameters in the URL string, as long as they are <em>before</em> the &#8220;TB_iframe&#8221; parameter.</p>
<h3>Go Easy on the Lightbox</h3>
<p>One final note: a lightweight, easy-to-implement user interface effect like Thickbox gives Web developers another tool in their toolbox of rich UI elements. But as much as I love cool Web effects like this one, there is always a danger that they will become overused. Thickbox is one of the best lightbox implementations I have seen, but remember to use it only when it makes sense.</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/8syfPN6Aav0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/js/working-with-thickbox/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/js/working-with-thickbox</feedburner:origLink></item>
		<item>
		<title>How To Calculate Text Size in JavaScript</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/-nvXjXtepI0/how-to-calculate-text-size-in-javascript</link>
		<comments>http://blog.gridworlds.com/js/how-to-calculate-text-size-in-javascript#comments</comments>
		<pubDate>Fri, 19 Oct 2007 03:37:11 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/js/how-to-calculate-text-size-in-javascript</guid>
		<description><![CDATA[Here's a JavaScript challenge: find the height and width of a string of text. Sounds easy, right? But there is more to this problem than meets the eye.]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a JavaScript challenge: find the height and width of a string of text. Sounds easy, right? But there is more to this problem than meets the eye. Let&#8217;s say I have some text on the page:</p>
<pre>How big is this text?</pre>
<p>There is no way to get the size of the text itself, but I can get the size of an element wrapped around it. So let&#8217;s wrap the text in a span tag with an id:</p>
<pre>&lt;span id="howbig"&gt;How big is this text?&lt;/span&gt;</pre>
<p>Okay, now I can use the <a href="http://www.quirksmode.org/js/elementdimensions.html">clientHeight and clientWidth</a> properties to find the size of the span, right?</p>
<pre>
var box = document.getElementById('howbig');
alert(box.clientWidth + ' x ' + box.clientHeight);
</pre>
<p>Let&#8217;s try it out:</p>
<p><span id="howbig" style="border: 1px solid black">How big is this text?</span><br />
<input value="Show Size" onclick="var box = document.getElementById('howbig'); alert(box.clientWidth + ' x ' + box.clientHeight);" type="button" />
<p>If you&#8217;re using Safari 2, you should see this:</p>
<div class="centeralign"><img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-relative-safari.png" alt="Display Relative in Safari" /></div>
<p>However, with Firefox 2 and IE 7 you will see something like this:</p>
<div class="centeralign"><img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-relative-firefox.png" alt="Display Relative in Firefox" /> <img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-none-ie.png" alt="Display Relative in IE" /></div>
<h4>Browser Inconsistencies</h4>
<p>What&#8217;s going on here? Firefox and IE always set clientHeight and clientWidth to 0 for relatively positioned inline elements. This leaves me with three alternatives:</p>
<ol>
<li>Use <a href="http://www.quirksmode.org/js/elementdimensions.html">offsetHeight and offsetWidth</a> properties instead of clientHeight and clientWidth.</li>
<li>Change my inline element (span) into a block-level element (div).</li>
<li>Switch my element to absolute positioning.</li>
</ol>
<p>The first option will work fine; however, the offset properties include borders in their size, which may not always be desirable. Changing to a relatively-positioned div means the box will expand to fill any available horizontal space, like this:</p>
<div id="howbig2" style="border: 1px solid black">How big is this text?</div>
<input value="Show Size" onclick="var box = document.getElementById('howbig2'); alert(box.clientWidth + ' x ' + box.clientHeight);" type="button" />
<p>Instead of the width of the text, clientWidth is now giving me the width of the div (588px) in Firefox and Safari, and 0 in IE. That&#8217;s certainly not what I want! The third option, switch to absolute positioning, is the best alternative since it will work with both inline and block-level elements &#8212; plus the width of the element will always match the width of the text.</p>
<h4>Playing Hide the Element</h4>
<p>However, I still have a problem: I now have an absolutely positioned element floating on top of my other content. I could hide it by setting display to none, like this:</p>
<pre>&lt;span id="howbig" style="position:absolute; display:none;"&gt;How big is this text?&lt;/span&gt;</pre>
<p>Try this one out (the span is hidden, but the button will still test it):</p>
<p><span id="howbig3" style="position: absolute; display: none">How big is this text?</span><br />
<input value="Show Size" onclick="var box = document.getElementById('howbig3'); alert(box.clientWidth + ' x ' + box.clientHeight);" type="button" />
<p>Now all three browsers are giving me problems:</p>
<div class="centeralign"><img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-none-safari.png" alt="Display None in Safari" /> <img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-relative-firefox.png" alt="Display None in Firefox" /> <img src="http://blog.gridworlds.com/wp-content/uploads/2007/10/display-none-ie.png" alt="Display None in IE" /></div>
<p>Clearly I can&#8217;t hide the span with &#8220;display:none,&#8221; but there is another option: <a href="http://www.w3schools.com/css/pr_pos_z-index.asp">z-index</a>. In Firefox a z-index of -1 will hide an element. The element will still be visible in Safari and IE, but it&#8217;s easy enough to position it behind another element on the page to conceal it (under a logo or content area, for example).</p>
<h4>Putting It All Together</h4>
<p>Here&#8217;s the final version, which includes absolute positioning and a z-index of -1:</p>
<pre>
&lt;span id="howbig" style="position:absolute; z-index:-1"&gt;How big is this text?&lt;/span&gt;
&lt;input type="button" value="Show Size" onclick="var box = document.getElementById('howbig'); alert(box.clientWidth + ' x ' + box.clientHeight);" /&gt;
</pre>
<p>You won&#8217;t be able to see the span text &#8220;hidden&#8221; on this page, but click the button to try it out:</p>
<input value="Show Size" onclick="var box = document.getElementById('howbig4'); alert(box.clientWidth + ' x ' + box.clientHeight);" type="button" /><span id="howbig4" style="position: absolute; z-index: -1">How big is this text?</span><br />
<code></code></p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/-nvXjXtepI0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/js/how-to-calculate-text-size-in-javascript/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/js/how-to-calculate-text-size-in-javascript</feedburner:origLink></item>
		<item>
		<title>How To Replace innerHTML with DOM methods</title>
		<link>http://feedproxy.google.com/~r/gridworlds/~3/UwU8WFI26O4/how-to-replace-innerhtml-with-dom-methods</link>
		<comments>http://blog.gridworlds.com/js/how-to-replace-innerhtml-with-dom-methods#comments</comments>
		<pubDate>Wed, 10 Oct 2007 04:03:34 +0000</pubDate>
		<dc:creator>Jason Gibb</dc:creator>
		
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.gridworlds.com/js/how-to-replace-innerhtml-with-dom-methods</guid>
		<description><![CDATA[JavaScript's <a href="http://www.w3schools.com/htmldom/prop_anchor_innerhtml.asp">innerHTML</a> method is a handy way to grab or update text from any node within your HTML document. It's simple to use, works great in every modern browser, and even has good backward compatibility with older browsers. There's just one little problem: innerHTML is <strong>not</strong> a <a href="http://www.w3.org">W3C</a> standard. To maintain standards-compliance in your JavaScript code, you need to use Document Object Model (DOM) methods. This brief tutorial will show you how.]]></description>
			<content:encoded><![CDATA[<p>JavaScript&#8217;s <a href="http://www.w3schools.com/htmldom/prop_anchor_innerhtml.asp">innerHTML</a> method is a handy way to grab or update text from any element within your HTML document. Here&#8217;s how it works:</p>
<pre>
// set the text
var welcome = document.getElementById("hello");
welcome.innerHTML = "Howdy!";

// get the text
alert(welcome.innerHTML); // displays "Howdy!"
</pre>
<p>It&#8217;s simple to use, works great in every modern browser, and even has good backward compatibility with older browsers. There&#8217;s just one little problem: innerHTML is <strong>not</strong> a <a href="http://www.w3.org">W3C</a> standard.</p>
<h3>Enter the DOM</h3>
<p>To maintain standards-compliance in your JavaScript code, you need to use Document Object Model (DOM) methods to access text nodes within your HTML document. Here are some of the attributes and methods you can use (for a complete list, check out the <a href="http://www.howtocreate.co.uk/tutorials/javascript/domstructure">tutorial</a> on the &#8220;How to Create&#8221; site):</p>
<ul>
<li>parent.firstChild - returns the first element under the &#8220;parent&#8221; node</li>
<li>parent.hasChildNodes() - returns true if the &#8220;parent&#8221; node has any children</li>
<li>node.nodeValue - returns the value of the node (if it is a text node or attribute)</li>
<li>createTextNode(&#8221;the text&#8221;) - creates new text you can add to your document</li>
<li>appendChild(parent) - inserts a node into the DOM tree under a parent node</li>
<li>replaceChild(newNode, oldNode) - replaces the old node with new</li>
</ul>
<p>Unfortunately, with all this talk of &#8220;nodes&#8221; and &#8220;DOM trees,&#8221; using these methods is not quite as straightforward as innerHTML. The key is to think of the text you want to manipulate as just another element within your HTML document. Using getElementById() and these methods, you can target and modify specific text elements within the page.</p>
<h3>Get Text with DOM Methods</h3>
<p>Let&#8217;s start with a simple example. Let&#8217;s say I have a &lt;div&gt; with some text somewhere on my page:</p>
<pre>
&lt;div id="hello"&gt;Hello World&lt;/div&gt;
</pre>
<p>If I want to grab that text and display it in an alert, I can do this:</p>
<pre>
&lt;script&gt;
var welcome = document.getElementById("hello");
alert(welcome.firstChild.nodeValue); // displays "Hello World"
&lt;/script&gt;
</pre>
<p>Notice how I have to specify firstChild.nodeValue to get at the text? Unlike innerHTML, which indiscriminately grabs whatever is between &lt;div&gt; and &lt;/div&gt;, these DOM methods don&#8217;t assume the content is always text (it could be other HTML elements, for example). The child element is considered just another node in the tree, which in this case happens to be text.</p>
<p>However, what if my &lt;div&gt; is empty? This presents a problems, because it means the node I&#8217;m looking for doesn&#8217;t actually exist! This example will error out because it can&#8217;t find the &#8220;firstChild&#8221; node:</p>
<pre>
&lt;div id="hello"&gt;&lt;/div&gt;

&lt;script&gt;
var welcome = document.getElementById("hello");
alert(welcome.firstChild.nodeValue); // ERROR!
&lt;/script&gt;
</pre>
<p>The solution is to check whether your element has any children before accessing it:</p>
<pre>
if (welcome.hasChildNodes()) {
    alert(welcome.firstChild.nodeValue);
}
</pre>
<h3>Update Text with DOM Methods</h3>
<p>Okay, so I can get text from my HTML document, but how do I change it on the fly? Changing text is a two-part operation:</p>
<ol>
<li>Create a new text node</li>
<li>Replace the current text node with the new text node</li>
</ol>
<p>Here&#8217;s an example:</p>
<pre>
&lt;div id="hello"&gt;Hello World&lt;/div&gt;

&lt;script&gt;
var newText = document.createTextNode("Howdy!");
var welcome = document.getElementById("hello");
welcome.replaceChild(newText, welcome.firstChild);
&lt;/script&gt;
</pre>
<p>Let&#8217;s step through it: First I start with a &lt;div&gt; containing my original &#8220;Hello World&#8221; text that I want to replace. Next I call createTextNode() with my new &#8220;Howdy!&#8221; message. At this point the text node is floating somewhere in DOM-space and I need to attach it to something, so I target the &lt;div&gt; using getElementById(). Finally, I call replaceChild() to swap the old text with the new text.</p>
<p>I can simplify this a little by merging the call to createTextNode() into the replaceChild() method, like so:</p>
<pre>
var welcome = document.getElementById("hello");
welcome.replaceChild(document.createTextNode("Howdy!"), welcome.firstChild);
</pre>
<h3>Another Gotcha</h3>
<p>Once again, empty nodes create problems. The replaceChild() method works just fine if the target element already contains text, but it will error out if the element is empty. We can solve this by adding the text node using appendChild() if it doesn&#8217;t exist. As before, hasChildNodes() comes to our rescue:</p>
<pre>
var welcome = document.getElementById("hello");
if (welcome.hasChildNodes()) {
    welcome.replaceChild(document.createTextNode("Howdy!"), welcome.firstChild);
} else {
    welcome.appendChild(document.createTextNode("Howdy!"));
}
</pre>
<p>In other words, if the &lt;div&gt; is not empty, replace the old text node with a new one, otherwise append a new text node.</p>
<p>I hope this gives you a little more insight into manipulating text in the DOM &#8212; without resorting to innerHTML.</p>
<img src="http://feeds.feedburner.com/~r/gridworlds/~4/UwU8WFI26O4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.gridworlds.com/js/how-to-replace-innerhtml-with-dom-methods/feed</wfw:commentRss>
		<feedburner:origLink>http://blog.gridworlds.com/js/how-to-replace-innerhtml-with-dom-methods</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic Page Served (once) in 2.211 seconds --><!-- Cached page generated by WP-Super-Cache on 2009-07-03 09:54:54 --><!-- Compression = gzip -->
