<?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/"
xmlns:series="http://unfoldingneurons.com/"
><channel><title>David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞. &#187; Optimization</title> <atom:link href="http://davidwalsh.name/tutorials/optimization/feed" rel="self" type="application/rss+xml" /><link>http://davidwalsh.name</link> <description>Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</description> <lastBuildDate>Sun, 20 May 2012 22:40:48 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.2</generator> <item><title>Lazy Load Content and Widgets with MooTools and&#160;RequireJS</title><link>http://davidwalsh.name/lazy-load-requirejs</link> <comments>http://davidwalsh.name/lazy-load-requirejs#comments</comments> <pubDate>Tue, 12 Jul 2011 16:52:30 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5266</guid> <description><![CDATA[The idea of lazy loading content is not new;  we&#8217;ve been lazy loading images (check out my MooTools LazyLoad plugin) for quite a while now.  And why wouldn&#8217;t you lazy load content?  There are SEO advantages, load time advantages, bandwidth savings, and more, so including a bit of extra JavaScript could help your large website immensely.  In [...]<p><a
href="http://davidwalsh.name/lazy-load-requirejs">Lazy Load Content and Widgets with MooTools and&nbsp;RequireJS</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>The idea of lazy loading content is not new;  we&#8217;ve been lazy loading images (check out my MooTools LazyLoad plugin) for quite a while now.  And why wouldn&#8217;t you lazy load content?  There are SEO advantages, load time advantages, bandwidth savings, and more, so including a bit of extra JavaScript could help your large website immensely.  In my latest redesign, I took the time to lazy load not just images but static content and social networking widgets to make my website&#8217;s initial load happen faster to make user experience and Google rank improve.  Let me show you how I used MooTools and RequireJS to lazy load content.</p><p>So what am I lazy loading within my current design?</p><ul><li>Twitter, Facebook, and Google Plus widgets for single blog posts.</li><li>Page footer;  since the footer content is out of sight during initial page load, it doesn&#8217;t need to be loaded right away.</li><li>LighterJS Syntax Highlighter; if no PRE tag is on the page, there&#8217;s no reason to grab the syntax highlighter.</li><li>Comment avatar images;  there&#8217;s no point to loading these images immediately as they must be scrolled to.  If someone hits the &#8220;#comments&#8221; portion of the page, my LazyLoad plugin can handle loading the initial images.</li><li>Tweets;  tweet content is non-essential so they needn&#8217;t be loaded right away.</li><li>MooTools StarRating;  again, only needed if it&#8217;s a post page.</li></ul><p>Of course, there needs to be a trigger for these items to load.  I&#8217;ve chosen three events to trigger loading of these components:  keydown, mousemove, and scroll.  Each of these events signify a human and &#8220;interested&#8221; presence.  Let me show you how I&#8217;ve implemented this lazy loading.</p><h2>Load Initial&nbsp;Scripts</h2><p>Not every script can be asynchronously loaded, so the scripts I do load synchronously are RequireJS and Google&#8217;s JSAPI (for Analytics and Google Search):</p><pre class="js">
&lt;!-- JavaScript at the bottom for fast page loading --&gt; 
&lt;script src="http://ajax.cdnjs.com/ajax/libs/require.js/0.23.0/require.min.js"&gt;&lt;/script&gt; 
&lt;script src="https://www.google.com/jsapi?key=MY_KEY"&gt;&lt;/script&gt; 
&lt;script&gt; 
	// Load MooTools, Google Search
	function loadScripts() { 
		require(["http://davidwalsh.name/wp-content/themes/klass/js/script.js"]); 
	}
	google.load("mootools", "1.3.0");
	google.load("search", "1");
	google.setOnLoadCallback(loadScripts);
&lt;/script&gt;
</pre><p>Once the scripts are loaded, my theme&#8217;s main JavaScript resources is required.</p><h2>Lazy Loading&nbsp;Code</h2><p>Since there are multiple tasks I want to run when the user &#8220;awakens,&#8221; I create an onAwaken array that will hold each of the tasks.  A series of functions will be pushed to the array, each representing a sign task.  For example, the task which loads Twitter, Facebook, and Google +1 badges looks like:</p><pre class="js">
// Create the array of awaken functions
var onAwaken = [];

// Get the share URL from this page via the canonical link
var cannons = $$("link[rel=canonical]"), shareUrl;
if(cannons.length) {
	shareUrl = cannons[0].get("href");
}

// If the PROMO DIV exists on the page
var promoDiv = document.id("promo");
if(promoDiv &amp;&amp; shareUrl) {
	onAwaken.push(function(){
	
		// Create a SPAN and A for the Twitter share link
		var span1 = new Element("span",{ style:"display:inline-block;float:left;" }).inject(promoDiv);
		new Element("a",{
			href: "http://twitter.com/share",
			"class": "twitter-share-button",
			"data-count": "horizontal"
		}).inject(span1);
		
		// Inject the Twitter SCRIPT tag into the SPAN
		new Element("script",{
			src: "http://platform.twitter.com/widgets.js",
			async: true
		}).inject(span1);
		
		// Create the Facebook IFRAME
		new Element("iframe",{
			src: "http://www.facebook.com/plugins/like.php?href=" + shareUrl,
			scrolling: "no",
			frameborder: 0,
			allowTransparency: true,
			style: "border:none; overflow:hidden; width:500px;"
		}).inject(new Element("span",{style:"display:inline-block;"}).inject(promoDiv));
		
		// Create the G+1 Button
		var el = document.id(document.createElement("g:plusone")).set({
			href: shareUrl,
			size: "medium"
		}).inject(new Element("span",{style:"display:inline-block;"}).inject(promoDiv));
		
		// Get the G+ SCRIPT
		require(["http://apis.google.com/js/plusone.js"],function() {
			// console.warn("G+1 is ready!");
		});
		
		// Fade in all of the lazy loaded content
		promoDiv.fade(1);
	});
}
</pre><p>Note that a require call is within this function, which could probably be considering lazy loading during lazy loading.  In all seriousness though, it&#8217;s important to note that entire resources are lazy loaded, not just execution of available functionality.</p><p>Another onAwaken function includes loading of my footer and right column content:</p><pre class="js">
// Uses Moo to load and place content
function loadAndPlace(url,where,then) {
	new Request({
		url: url,
		onSuccess: function(content) {
			document.id(where).set("html",content);
			if(then) then();
		}
	}).send();
}

// Load footer and right column upon awakening
onAwaken.push(function() { 
	loadAndPlace(themePath + "footer.html","footer"); 
});
onAwaken.push(function() { 
	loadAndPlace(themePath + "follow-trends.html","contentRightColumn", function(){ 
		$$(".contentRightColumn").fade(1); 
	}); 
});
</pre><p>And then I also lazy load the MooTools StarRating plugin:</p><pre class="js">
// Star ratings
var ratingForm = document.id("ratingForm"),
	themePath = "/wp-content/themes/klass/";
if(ratingForm) {
	// Get the post id
	var postId = document.id("postId").get("value");
	
	// Get star ratings
	require([themePath + "js/ratings/Source/moostarrating.js"], function() {
		// Set image vars
		MooStarRatingImages = {
			defaultImageFolder: themePath + 'js/ratings/Graphics/',
			defaultImageEmpty:  'star_boxed_empty.png',
			defaultImageFull:   'star_boxed_full.png',
			defaultImageHover:  'star_boxed_hover.png'
		};
		// Create star ratings
		var voted = false;
		var rater = new MooStarRating({
			form: ratingForm,
			radios: "rating",
			half: true,
			width: 16
		}).addEvent("click",function(value) {
			if(!voted){
				// Send request
				new Request({
					url: themePath + "rating.php",
					method: "post",
					data: {
						rating: value,
						id: postId
					}
				}).send();
				// Mark as voted
				voted = true;
			}
		});
		// Fix the value...wtf?!
		// Adding 0.5 because it's always showing up short 0.5 short.  WTF.
		rater.setValue((rater.currentIndex * 0.5) + 0.5);
		// Showtime
		ratingForm.setStyle("display","block");
	});
}
</pre><p>There is no limit to the number of functions you can fire when the user awakens, so let&#8217;s assume I have a bunch more functions ready to run.  Now it&#8217;s time to place JavaScript code into place to listen for the page&#8217;s awakening.  Here it goes:</p><pre class="js">
// Set up main register handler
var runEvents = ["keydown","mousemove","scroll"];
var runAwaken = function() {
	onAwaken.each(function(evt,index) {
		evt();
	});
	// Since we've run all items, let's remove the events
	runEvents.each(function(evtType){
		window.removeEvent(evtType,runAwaken);
	});
};
// Set registers in motion
runEvents.each(function(evtType){
	window.addEvent(evtType,runAwaken);
});
</pre><p>First we create an array of events we want the page to awaken on.  Next we create a function which will run upon awakening;  this function will run all awaken events and then remove the event from the window so that the runAwaken function will only run once.</p><p>The sky is the limit with the content you can lazy load.  I highly recommend evaluating your website for components which don&#8217;t hold search engine value, or may speed up the load of your page (especially synchronous SCRIPT tags!).  As always, have fun with your websites and do what you can to make them load faster!</p><p><a
href="http://davidwalsh.name/lazy-load-requirejs">Lazy Load Content and Widgets with MooTools and&nbsp;RequireJS</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/lazy-load-requirejs/feed</wfw:commentRss> <slash:comments>11</slash:comments> </item> <item><title>Introducing LazyLoad&#160;2.0</title><link>http://davidwalsh.name/lazyload-plugin</link> <comments>http://davidwalsh.name/lazyload-plugin#comments</comments> <pubDate>Wed, 29 Jun 2011 19:13:38 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Browsers]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5246</guid> <description><![CDATA[While improvements in browsers means more cool APIs for us to play with, it also means we need to maintain existing code.  With Firefox 4&#8242;s release came news that my MooTools LazyLoad plugin was not intercepting image loading &#8212; the images were loading regardless of the plugin, much like it always had with WebKit-based browsers. [...]<p><a
href="http://davidwalsh.name/lazyload-plugin">Introducing LazyLoad&nbsp;2.0</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>While improvements in browsers means more cool APIs for us to play with, it also means we need to maintain existing code.  With Firefox 4&#8242;s release came news that my <a
href="http://davidwalsh.name/js/lazyload">MooTools LazyLoad plugin</a> was not intercepting image loading &#8212; the images were loading regardless of the plugin, much like it always had with WebKit-based browsers.  Intercepting had continued to work within Internet Explorer but IE&#8217;s reign of dominance is dying.  Clearly I needed to bite the bullet and code LazyLoad to use custom data- attributes to store the real image path.</p><p><em>Note:  It was always apparent that using custom attributes would become a necessity, but I hated doing so.  The big issue is with this is that it completely bricks image viewing for browsers which don&#8217;t support JavaScript.  Since popular demand is calling for the data- attributes, and browsers are moving toward loading images before JS can intercept them, this was the really the only option.</em></p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/lazyload-2.0.php" class="demo">View Demo</a> <a
href="http://mootools.net/forge/p/lazyload" class="demo">Download LazyLoad</a><div
class="clear"></div></div><p>Enter LazyLoad 2.0.  This second generation of MooTools LazyLoad does introduce breaking changes but the class itself is more compact and dynamic.  Here&#8217;s the new class:</p><pre class="js">
var LazyLoad = new Class({

	Implements: [Options,Events],

	/* additional options */
	options: {
		range: 200,
		elements: "img",
		container: window,
		mode: "vertical",
		realSrcAttribute: "data-src",
		useFade: true
	},

	/* initialize */
	initialize: function(options) {
		
		// Set the class options
		this.setOptions(options);
		
		// Elementize items passed in
		this.container = document.id(this.options.container);
		this.elements = document.id(this.container == window ? document.body : this.container).getElements(this.options.elements);
		
		// Set a variable for the "highest" value this has been
		this.largestPosition = 0;
		
		// Figure out which axis to check out
		var axis = (this.options.mode == "vertical" ? "y": "x");
		
		// Calculate the offset
		var offset = (this.container != window &amp;&amp; this.container != document.body ? this.container : "");

		// Find elements remember and hold on to
		this.elements = this.elements.filter(function(el) {
			// Make opacity 0 if fadeIn should be done
			if(this.options.useFade) el.setStyle("opacity",0);
			// Get the image position
			var elPos = el.getPosition(offset)[axis];
			// If the element position is within range, load it
			if(elPos &lt; this.container.getSize()[axis] + this.options.range) {
				this.loadImage(el);
				return false;
			}
			return true;
		},this);
		
		// Create the action function that will run on each scroll until all images are loaded
		var action = function(e) {
			
			// Get the current position
			var cpos = this.container.getScroll()[axis];
			
			// If the current position is higher than the last highest
			if(cpos &gt; this.largestPosition) {
				
				// Filter elements again
				this.elements = this.elements.filter(function(el) {
					
					// If the element is within range...
					if((cpos + this.options.range + this.container.getSize()[axis]) &gt;= el.getPosition(offset)[axis]) {
						
						// Load the image!
						this.loadImage(el);
						return false;
					}
					return true;
					
				},this);
				
				// Update the "highest" position
				this.largestPosition = cpos;
			}
			
			// relay the class" scroll event
			this.fireEvent("scroll");
			
			// If there are no elements left, remove the action event and fire complete
			if(!this.elements.length) {
				this.container.removeEvent("scroll",action);
				this.fireEvent("complete");
			}
			
		}.bind(this);
		
		// Add scroll listener
		this.container.addEvent("scroll",action);
	},
	loadImage: function(image) {
		// Set load event for fadeIn
		if(this.options.useFade) {
			image.addEvent("load",function(){
				image.fade(1);
			});
		}
		// Set the SRC
		image.set("src",image.get(this.options.realSrcAttribute));
		// Fire the image load event
		this.fireEvent("load",[image]);
	}
});
</pre><p>Using LazyLoad is as simple as:</p><pre class="html">
&lt;script&gt;
/* do it! */
window.addEvent("domready",function() {
	var lazyloader = new LazyLoad();
});
&lt;/script&gt;

&lt;!-- then in the body --&gt;

&lt;!-- in-page image format --&gt;
&lt;img src="/images/blank.gif" data-src="/images/102_1139.jpg" /&gt;
&lt;img data-src="/images/102_1139.jpg" /&gt;
</pre><p>Changes to version 2.0 of LazyLoad include:</p><ul><li>You may now fade images in upon load</li><li>Uses a customizable data- attribute to store the <em>real</em> image src.</li><li>The resetDimensions options is no longer available</li><li>Document size is calculated during scroll, as dynamic pages change in size frequently.</li><li>Class code size is much smaller.</li></ul><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/lazyload-2.0.php" class="demo">View Demo</a> <a
href="http://mootools.net/forge/p/lazyload" class="demo">Download LazyLoad</a><div
class="clear"></div></div><p>Lazy-loading images will never go out of style, as it saves your server bandwidth and saves your users from load images that they never scroll to.  Adding a fade effect allows for images to be gracefully placed within the page.  Let me know if you have further ideas for LazyLoad, as it should only get better!</p><p><a
href="http://davidwalsh.name/lazyload-plugin">Introducing LazyLoad&nbsp;2.0</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/lazyload-plugin/feed</wfw:commentRss> <slash:comments>35</slash:comments> </item> <item><title>MooTools History&#160;Plugin</title><link>http://davidwalsh.name/mootools-history</link> <comments>http://davidwalsh.name/mootools-history#comments</comments> <pubDate>Mon, 02 May 2011 14:18:45 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5209</guid> <description><![CDATA[One of the reasons I love AJAX technology so much is because it allows us to avoid unnecessary page loads.  Why download the header, footer, and other static data multiple times if that specific data never changes?  It&#8217;s a waste of time, processing, and bandwidth.  Unfortunately, at this point in the web, constant refreshes are [...]<p><a
href="http://davidwalsh.name/mootools-history">MooTools History&nbsp;Plugin</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>One of the reasons I love AJAX technology so much is because it allows us to avoid unnecessary page loads.  Why download the header, footer, and other static data multiple times if that specific data never changes?  It&#8217;s a waste of time, processing, and bandwidth.  Unfortunately, at this point in the web, constant refreshes are the norm &#8212; but they don&#8217;t have to be.  Christoph Pojer, a MooTools Core Developer, has added <a
href="https://github.com/cpojer/mootools-history" rel="nofollow">History</a> to his <del>PojerTools</del> PowerTools library.  History replaces traditional same-site URL loading by providing a method to catch link clicks, load page content via AJAX (Mootools&#8217; <code>Request.HTML</code> class), modify the document&#8217;s location object to keep &#8220;history&#8221; records, and re-evaluate content links to allow developers to create a fast, efficient one-page website.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/mootools-history.php" class="demo">View Demo</a><div
class="clear"></div></div><p>The tradition method of dynamic history/&#8221;back button&#8221; management has always been hash-based JavaScript technology.  Newer technology, including <a
href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history" rel="nofollow">HTML5&#8242;s <code>window.onpopstate</code> and <code>history.pushState</code></a> methods, allow for more reliable methods for managing history.  MooTools&#8217; History plugin supports modern and legacy methods for history management.  Let me show you how to quickly implement the MooTools History plugin.</p><h2>HTML&nbsp;Structure</h2><p>The History plugin doesn&#8217;t require any HTML structure adjustments but at least one designated content should be identified; you can, of course, have as many content areas as you like, but you&#8217;ll most likely need multiple AJAX requests to retrieve their content, unless you use a <code>Request.JSON</code> request to retrieve content for multiple areas of the page.  For this simple demo, we&#8217;ll define a header, footer, and menu, and content area:</p><pre class="html">
&lt;div id="body"&gt;
	
	&lt;!-- header --&gt;
	&lt;header&gt;
		&lt;a href="/" data-noxhr&gt;David Walsh Blog&lt;/a&gt; 
		&lt;div&gt;MooTools History Plugin Demo&lt;/div&gt;
		&lt;div&gt;This is a simple example of the MooTools History plugin created by Christoph Pojer&lt;/div&gt;
		
	&lt;/header&gt;
		
	&lt;!-- menu --&gt;
	&lt;ul id="demoMenu"&gt;
		&lt;li&gt;&lt;a href="mootools-history.php"&gt;Home&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="mootools-history-david.php"&gt;About David Walsh&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="mootools-history-mootools.php"&gt;About MooTools&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="mootools-history-christoph"&gt;About Christoph Pojer&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;
	
	&lt;!-- content area --&gt;
	&lt;article id="contentHolder"&gt;
		
		&lt;!-- initial page content goes here --&gt;
		
	&lt;/article&gt;
	
	
	&lt;!-- footer --&gt;
	&lt;footer&gt;
	
	&lt;/footer&gt;
&lt;/div&gt;
</pre><p>The content area is the only area which will have its content change.  The page should load as usual</p><h2>The MooTools&nbsp;JavaScript</h2><p>Assuming that the <a
href="https://github.com/cpojer/mootools-history" rel="nofollow">MooTools History plugin</a> has been included in the page, there are a few functions that should be created upon <code>domready</code>.  The first is a method which will perform the request for content when a link is clicked:</p><pre class="js">
// Content holder (all content placed within this element)
var contentHolder = document.id("contentHolder");

// Create a Request object which will be reused when links are clicked
var request = new Request.HTML({
	onSuccess: function(nodeTree,elements,html) {
		// Set the content into the content holder
		contentHolder.set("html",html);
		// Execute directions that should be executed whenever a page changes
		onPageUpdate();
	}
});

// Create a function that loads the page content
var loadPage = function(url) {
	// Make a HTML request to get the content for this page
	request.send({ url: url });
};
</pre><p>The next step is creating a method <em>(which is theoretically option, but you&#8217;ll usually want to do something once content has loaded)</em> which will execute every time content is received:</p><pre class="js">
// Function that will execute whenever a page gets changed
var onPageUpdate = function() {
	
	// Do whatever you'd like here!  
	
	// Possibly manually record a Google Analytics page view?
	
};
</pre><p>History doesn&#8217;t request that you do anything when content is received, but you&#8217;ll likely want to do something.  Why manually <a
href="http://davidwalsh.name/ajax-analytics">record a page view within Google Analytics</a>?</p><p>This next piece is important in turning links to static pages into AJAX-ified History triggers.  Just one big <a
href="http://mootools.net/docs/more/Element/Element.Delegation" rel="nofollow">Element.Delegation</a> event delegation call will do the work for not just the initial page load, but every History AJAX load after that:</p><pre class="js">
// The listener that manages all clicks
var listener = function(evt){
	evt.preventDefault(); // Prevent following the URL
	History.push(this.get('href')); // Push the new URL into History
};

// Add event delegation to add clicks.  Both of these work:
//document.body.addEvent("click:relay(a:not([href=#]):not([href^=http://]):not([data-noxhr]))",listener);
document.body.addEvent("click:relay(a:not([href=#],[href^=http://],[data-noxhr]))",listener);
</pre><p>When any same-site, non-hashed link is clicked, the listener method stops the event and pushes the new URL into History, changing the address bar and managing back/forward button click.</p><p>A <code>back</code> function is also created so that we can provide a &#8220;back&#8221; link and a &#8220;forward&#8221; link to travel back and forward in page history, if we choose to use it:</p><pre class="js">
// Listener for the "Back" link
var back = function(evt){
	evt.preventDefault();
	History.back(); // Go back
};

// Listener for the "Forward" link
var forward = function(evt){
	evt.preventDefault();
	History.forward(); // Go back
};

// Add to links
document.id("backLink").addEvent("click",back);
document.id("forwardLink").addEvent("click",forward);
</pre><p>The next step is adding a <code>change</code> event to History itself to run our <code>loadPage</code> function when the page URL changes:</p><pre class="js">
// When the history changes, update the content 
History.addEvent('change',loadPage);
</pre><p>If the client doesn&#8217;t support the <code>history.pushState</code> method, the History plugin evaluates the hash and loads the page as necessary:</p><pre class="js">
// Handle the initial load of the page if the browser does not support pushState, check if the hash is set
if(!History.hasPushState()) {
	// Check if there is a hash
	var hash = document.location.hash.substr(1);
	if (!hash) return;

	// If the hash equals the current page, don't do anything
	var path = document.location.pathname.split('/');
	path = path[path.length - 1];
	if (hash == path) return;

	// Load the page specified in the hash
	loadPage(hash);
}
</pre><p>Lastly, running the <code>onPageUpdate</code> upon <code>domready</code> load doesn&#8217;t hurt since events are only added once within <code>onPageUpdate</code>:</p><pre class="js">
// Update the page
onPageUpdate();
</pre><p>Now the page is ready to support History-based, AJAX-driven content swapping.  Thanks to the <code>onPageUpdate</code> function, links are added to events as they come in so that even AJAX-retrieved content can be managed with History.</p><h2>Tips and Strategies for Hash/History-Managed&nbsp;Websites</h2><p>Plugins like Christoph&#8217;s History masterpiece are very helpful in enriching the user experience but do require a bit of developer logic:</p><ul><li><strong>Use Event Delegation</strong> &#8211; Remember that with a History-style system, assigning events to elements directly may not be the best solution because those elements may be gone with the next link click.  Using event delegation instead of traditional event assignments may save you a lot of trouble. Read my <a
href="http://davidwalsh.name/event-delegation">MooTools Element.Delegation</a> post if you aren&#8217;t familiar with event delegation.</li><li><strong>Don&#8217;t Assume JavaScript Support</strong> &#8211; Keep in mind that the client may not support JavaScript.  Search engines have added JavaScript support but it&#8217;s important to use URLs that will work with both on a History-managed site and a JavaScript-less website.</li><li><strong>Use AJAX Detection </strong>- MooTools provides an AJAX-specific header within the Request class called <code>HTTP_X_REQUESTED_WITH</code>.  <a
href="http://davidwalsh.name/detect-ajax">Click here</a> to learn how to use it to detect AJAX requests.  You will want to be able to detect AJAX so that those requests simply return the content and not the header and footer (etc.) with it. You could write a client-side script/regex to parse out the content but that&#8217;s largely inefficient.  My demo uses PHP to store the page content in variables as follows: <br
/><br
/><pre class="php">
// Load pages based on querystring
$qstring = $_SERVER['QUERY_STRING'];
if($qstring == 'home' || $qstring == '') {
	$content.= '&lt;h1&gt;Welcome Home!&lt;/h1&gt;';
	$content.= '&lt;p&gt;History Management via popstate or hashchange. Replaces the URL of the page without a reload and falls back to Hashchange on older browsers.&lt;/p&gt;&lt;p&gt;This demo page aims to teach you how you can use Christoph Pojer\'s outstanding History widget to load only the content you need, dynamically and reliably.&lt;/p&gt;';
}
elseif($qstring == 'about-david') {
	$content.= '&lt;h1&gt;About David Walsh&lt;/h1&gt;';
	$content.= '&lt;p&gt;My name is David Walsh. I\'m a 27 year old Web Developer from Madison, Wisconsin. In the web world, I am:&lt;/p&gt;
	&lt;ul&gt;
	&lt;li&gt;Founder and Lead Developer for Wynq Web Labs.&lt;/li&gt;
	&lt;li&gt;Software Engineer for SitePen.&lt;/li&gt;
	&lt;li&gt;Core Developer for the MooTools JavaScript framework.&lt;/li&gt;
	&lt;li&gt;Co-Founder of Script &amp; Style, a website aimed at making web developers and designers better.&lt;/li&gt;
	&lt;/ul&gt;
	&lt;p&gt;I don\'t design the websites - I make them work.&lt;/p&gt;
	&lt;p&gt;I am also an admirer of the great &lt;a href="?about-christoph"&gt;Christoph Pojer!&lt;/a&gt;.&lt;/p&gt;';
}
// and more....
// Page not found
else {
	$content.= '&lt;h1&gt;Page Not Found&lt;/h1&gt;';
	$content.= '&lt;p&gt;The page you were attempting to find could not be found.&lt;/p&gt;';
}

// If request was via AJAX, push it out.
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &amp;&amp; strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
	echo $content;
	exit();
}
</pre>Obviously your content management system would be pulling content from a database or other static files, but you get the point &#8212; load content before any page output, sniff for AJAX, and push content out accordingly.  If it&#8217;s not an AJAX request, push that content into the content area&#8217;s HTML via traditional methods.</li></ul><p>These tips should set you up well to use a History-based system.  Remember that JavaScript is meant to enhance &#8212; keep in mind that your user (or search engine bot) may not support JavaScript, so be sure to test your website thoroughly!</p><p><em>Give the example hell.  Click from page to page, use the back button, refresh the page, etc.  History is rock solid!</em></p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/mootools-history.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Thanks to Christoph Pojer for his outstanding MooTools History plugin.  Many History-style plugins have existed but the browsers haven&#8217;t been as feature-rich as they are now.  If you have any suggestions, tips, or experiences to share about creating hash-based websites, please share them.</p><p><a
href="http://davidwalsh.name/mootools-history">MooTools History&nbsp;Plugin</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/mootools-history/feed</wfw:commentRss> <slash:comments>21</slash:comments> </item> <item><title>Smarter Script Loading with&#160;LABjs</title><link>http://davidwalsh.name/labjs</link> <comments>http://davidwalsh.name/labjs#comments</comments> <pubDate>Wed, 01 Dec 2010 16:28:23 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5125</guid> <description><![CDATA[We all know that asynchronous resource loading is the key to preventing unwanted and unnecessary blocking within the browser.  There are many scripts/libraries available to help with async script loading but the ones that succeed are simple, compact, and reliable.  Those words describe Kyle Simpson&#8217;s LABjs, a lightweight utility for loading your scripts without blocking. [...]<p><a
href="http://davidwalsh.name/labjs">Smarter Script Loading with&nbsp;LABjs</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>We all know that asynchronous resource loading is the key to preventing unwanted and unnecessary blocking within the browser.  There are many scripts/libraries available to help with async script loading but the ones that succeed are simple, compact, and reliable.  Those words describe Kyle Simpson&#8217;s LABjs, a lightweight utility for loading your scripts without blocking.</p><h2>Download&nbsp;LABjs</h2><p>You can download LABjs at the <a
href="http://labjs.com/">LABjs website </a>or via <a
href="http://github.com/getify/LABjs">GitHub</a>.</p><h2>Traditional Script&nbsp;Inclusion</h2><p>Traditional script inclusion blocks subsequent resources from loading.  The following is traditional, blocking script inclusion:</p><pre class="html">
&lt;script src="mootools-1.3.js"&gt;&lt;/script&gt;
&lt;script src="lightface/Source/LightFace.js"&gt;&lt;/script&gt;
&lt;script src="lightface/Source/LightFace.Request.js"&gt;&lt;/script&gt;
&lt;script src="lightface/Source/LightFace.Static.js"&gt;&lt;/script&gt;
&lt;script src="Color.js"&gt;&lt;/script&gt;
</pre><p>Wait&#8230;wait&#8230;wait.  What a waste of time.  Other pieces of the page don&#8217;t rely on these scripts, so why should users have to wait for these scripts to load before other resources load?  LABjs fixes this mess.</p><h2>LABjs&nbsp;Usage</h2><p>LABjs itself needs to be included within the page via traditional SCRIPT tag:</p><pre class="html">
&lt;script src="LAB.js"&gt;&lt;/script&gt;
</pre><p>The <code>$LAB</code> variable is LABjs&#8217; handle.  You can load scripts using the script method:</p><pre class="js">
$LAB.script('mootools-1.3.js');
</pre><p>The <code>wait</code> method allows you to prevent script execution (<em>not loading</em>) before executing subsequent scripts in the chain:</p><pre class="js">
$LAB
.script('mootools-1.3.js').wait()
.script('mootools-dependent-script.js');
</pre><p>Using <code>wait</code> is a great way to manage dependencies.  For example, you cannot load MooTools More before MooTools Core, right?  Even though you direct Core to load first, More may load before Core.  That will cause many, many errors.  You can use <code>wait</code> to prevent that problem:</p><pre class="js">
$LAB
.script('mootools-1.3.js').wait()
.script('mootools-1.3-more.js');
</pre><p>The <code>wait</code> method also acts as a callback for when scripts are done loading:</p><pre class="js">
$LAB
.script('mootools-1.3.js').wait()
.script('mootools-1.3-more.js').wait(function() {
	
	// Now that the Fx.Accordion is available....
	var accordion = new Fx.Accordion(/* ... */);
	
});
</pre><p>To complete the example I started this post with:</p><pre class="js">
$LAB
.script('mootools-1.3.js').wait()
.script('lightface/Source/LightFace.js').wait()
.script('lightface/Source/LightFace.Request.js')
.script('lightface/Source/LightFace.Static.js').wait(function() {
	var modal = new LightFace.Request(/*  */);
})
.script('Color.js')
</pre><p>Using LABjs to load scripts is as simple as that!</p><h2>LABjs&nbsp;Options</h2><p>LABjs also provides a bevy of options to customize script loading to your personal needs.  Options may be set via the setOptions method:</p><pre class="js">
$LAB.setOptions({ AlwaysPreserveOrder:true });
</pre><p>A few of the options include:</p><ul><li><code>AlwaysPreserveOrder</code>:  Implicitly calls wait() after each script</li><li><code>UsePreloading</code>: Allows LABjs to try other loading tricks (<a
href="http://labjs.com/documentation.php">trick information here</a>)</li><li><code>BasePath</code>: Sets a base path for all scripts</li></ul><p>Many other options are available.  You can get more information about LABjs options by <a
href="http://labjs.com/documentation.php">reading the documentation</a>.</p><h2>LABjs + Async&nbsp;FTW</h2><p>LABjs is an awesome, awesome little utility:  compact, easy to  use, and reliable.  Twitter must agree with me because they are using LABjs.  Big props to Kyle for his outstanding work.  Be sure to give LABjs a try;  low risk, high reward.</p><p><a
href="http://davidwalsh.name/labjs">Smarter Script Loading with&nbsp;LABjs</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/labjs/feed</wfw:commentRss> <slash:comments>16</slash:comments> </item> <item><title>Load MooTools Classes on Demand with&#160;RequireJS</title><link>http://davidwalsh.name/mootools-requirejs</link> <comments>http://davidwalsh.name/mootools-requirejs#comments</comments> <pubDate>Mon, 04 Oct 2010 14:12:31 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5082</guid> <description><![CDATA[RequireJS is a hugely popular JavaScript project right now thanks to what it does:  asynchronously load JavaScript files and properly handle their introduction to a namespace flawlessly.  Of course, callbacks are provided which allow you to work with the new code one it has been loaded.  MooTools is a perfect match for RequireJS because of [...]<p><a
href="http://davidwalsh.name/mootools-requirejs">Load MooTools Classes on Demand with&nbsp;RequireJS</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>RequireJS is a hugely popular JavaScript project right now thanks to what it does:  asynchronously load JavaScript files and properly handle their introduction to a namespace flawlessly.  Of course, callbacks are provided which allow you to work with the new code one it has been loaded.  MooTools is a perfect match for RequireJS because of its modular structure.  Let me show you how you can lazy load MooTools classes with the robust RequireJS library.</p><h2>Grabbing and Using&nbsp;RequireJS</h2><p>You&#8217;ll obviously need to download RequireJS from the RequireJS website.  Once the file is in place on your server, place it within the page via the traditional method, a SCRIPT tag:</p><pre class="js">
&lt;script src="require.js"&gt;&lt;/script&gt;
</pre><p>Now you have the power of async JavaScript loading within the page!</p><div
class="actions"><a
href="http://requirejs.org/" class="demo">Download RequireJS</a><div
class="clear"></div></div><h2>Using RequireJS with&nbsp;MooTools</h2><p>With RequireJS available, all you need to do is use the require function, passing an array of files and a callback to execute once all of the files have loaded:</p><pre class="js">
//require ScrollSpy and Roar
require(['scrollspy.1.2.js','Roar.js'],function(){
	//callbacks
});
</pre><p>Once the classes have been loaded, I can use them!  Check it out:</p><pre class="js">
// require ScrollSpy and Roar
require(['scrollspy.1.2.js','Roar.js'],function(){
	//use them!
	var roar = new Roar();
	var spy = new ScrollSpy({
		onEnter: function() {
			//....
		}
	});
});
</pre><p>How about a practical usage?  If an element with a &#8220;lazyload&#8221; CSS class exists, load LazyLoad and create an instance:</p><pre class="js">
//when the DOM is ready
window.addEvent('domready',function(){
	//find image to lazyload
	var scrollspyElements = $$('.lazyload');
	//if there are images to lazyload...
	if(scrollspyElements.length) {
		//require the class and when done...
		require(['lazyload.js'],function(){
			//create a LazyLoad instance and use it!
			new LazyLoad({
			    range: 200,
			    image: 'Assets/blank.gif',
			    elements: $$('.lazyload')
			});
		});
	}
});
</pre><p>Not only do you load individual classes with RequireJS, but you can also nest require calls to load MooTools asynchronously!  Once MooTools is ready, you can make your checks and load MooTools classes:</p><pre class="js">
//load mootools with RequireJS!
require(['mootools-1.2.4.js'],function() {
	//when the DOM is ready
	require.ready(function(){
		//find image to lazyload
		var scrollspyElements = $$('.lazyload');
		//if there are images to lazyload...
		if(scrollspyElements.length) {
			//require the class and when done...
			require(['lazyload.js'],function(){
				//create a LazyLoad instance and use it!
				new LazyLoad({
				    range: 200,
				    image: 'Assets/blank.gif',
				    elements: $$('.lazyload')
				});
			});
		}
	});
});
</pre><p>Awesome!  The future of JavaScript is loading components (or even a whole framework) only if you need them!</p><h2>require.ready!</h2><p>If you aren&#8217;t using a JavaScript framework, RequireJS provides a ready method to trigger a function when the DOM is ready!</p><pre class="js">
// require ScrollSpy
require(['scrollspy.1.2.js','Roar.js'],function(){
	//use it when the dom is ready!
	require.ready(function(){
		//use them!
		var roar = new Roar();
		var spy = new ScrollSpy({
			container: document.id('someDiv'),
			onEnter: function() {
				//....
			}
		});	
	});
});
</pre><p>This is much like MooTools&#8217; domready event and Dojo and jQuery&#8217;s ready method.</p><h2>RequireJS and Other&nbsp;Frameworks</h2><p>Dojo currently contains its own asynchronous resource loading system but is looking toward the possibility of implementing RequireJS near its 2.0 release.  The RequireJS website also provides detailed instructions on <a
href="http://requirejs.org/docs/jquery.html">using RequireJS with jQuery</a>.</p><p><a
href="http://davidwalsh.name/mootools-requirejs">Load MooTools Classes on Demand with&nbsp;RequireJS</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/mootools-requirejs/feed</wfw:commentRss> <slash:comments>10</slash:comments> </item> <item><title>Quick Tip:  Object Indexing vs. Array&#160;Collection</title><link>http://davidwalsh.name/object-array-index</link> <comments>http://davidwalsh.name/object-array-index#comments</comments> <pubDate>Thu, 26 Aug 2010 13:47:13 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Optimization]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5052</guid> <description><![CDATA[The Setup &#38;&#160;Goal Let&#8217;s say that we have one large text document and we have a a bunch of keywords that we want to parse the document for.  We don&#8217;t care how many times times the keyword appears &#8212; we just care that it&#8217;s been used.  When we find a keyword, we need to record [...]<p><a
href="http://davidwalsh.name/object-array-index">Quick Tip:  Object Indexing vs. Array&nbsp;Collection</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<h2>The Setup &amp;&nbsp;Goal</h2><p>Let&#8217;s say that we have one large text document and we have a a bunch of keywords that we want to parse the document for.  We don&#8217;t care how many times times the keyword appears &#8212; we just care that it&#8217;s been used.  When we find a keyword, we need to record that keyword been found so that we may check at a later time.</p><h2>Inefficient Method:  Array Collection and&nbsp;Search</h2><p>The first method to record that a keyword has been found is by pushing the keyword into one array:</p><pre class="js">
//Assume an array called "foundKeywords" was defined above
if(shouldSave(keyword)) {
	foundKeywords.push(keyword);
}
</pre><p>At the end of the document search, we&#8217;d end up with an array like:</p><pre class="js">
//the foundKeywords array looks like:
//['keyword1','keyword2','keyword2',...]
</pre><p>When it comes to checking this array for the existence of a given keyword, this method will prove inefficient.  Why?  Because we&#8217;d need to loop through the array and search until we found the given keyword (if ever).  Those are a lot of &#8220;wasted&#8221; or fruitless cycles, even if we break the loop when the keyword was found.  Inefficient is the only word to describe this process.</p><h2>The Efficient Method:  Object with&nbsp;Index</h2><p>The fastest method of checking a storing keywords for later reference is by object (in JavaScript) or associative array (in PHP).  Instead of adding the keyword to an array, we add the keyword as an index to a master object, giving the value as 1:</p><pre class="js">
//Assume an object {} called "foundKeywords" was defined above
if(shouldSave(keyword)) {
	foundKeywords[keyword] = 1;
}
</pre><p>Why is this faster?  No wasted cycles looking blindly through an array.  The check is quick and simple:</p><pre class="js">
if(foundKeywords[keyword]) { //FOUND!
	//do something
}
</pre><p>It&#8217;s either an index or it&#8217;s not!  In PHP, we&#8217;d save the keyword to an associative array:</p><pre class="php">
//Assume an array called "$found_keywords" was defined above
if(shouldSave($keyword)) {
	$found_keywords[$keyword] = 1;
}

//Later: checking if the keyword was there...
if($found_keywords[$keyword]) { //or array_key_exists($keyword,$found_keywords)
	//FOUND!
}
</pre><p>In a word&#8230;awesome.  Not only fast but simple!</p><p>I cannot provide a benchmark because the speed of execution depends on how large the keyword array is.  Suffice to say, for the sake of simplicity and speed, using an object with keyword index is definitely the way to go!</p><p><a
href="http://davidwalsh.name/object-array-index">Quick Tip:  Object Indexing vs. Array&nbsp;Collection</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/object-array-index/feed</wfw:commentRss> <slash:comments>21</slash:comments> </item> <item><title>HTML5 Link&#160;Prefetching</title><link>http://davidwalsh.name/html5-prefetch</link> <comments>http://davidwalsh.name/html5-prefetch#comments</comments> <pubDate>Wed, 07 Jul 2010 13:55:23 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[HTML5]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5000</guid> <description><![CDATA[One effort shared by both browsers and developers is making the web browsing experience faster.  There are many common-known ways to keep your websites fast:  using CSS sprites and image optimization, using .htaccess to set file headers for longer caching, javascript file compression, using CDNs, and so on.  I&#8217;ve even detailed some of the website [...]<p><a
href="http://davidwalsh.name/html5-prefetch">HTML5 Link&nbsp;Prefetching</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>One effort shared by both browsers and developers is making the web browsing experience faster.  There are many common-known ways to keep your websites fast:  using <a
href="http://davidwalsh.name/css-sprites">CSS sprites</a> and <a
href="http://davidwalsh.name/pngcrush">image optimization</a>, using <a
href="http://davidwalsh.name/yslow-htaccess">.htaccess to set file headers for longer caching</a>, javascript file compression, using CDNs, and so on.  I&#8217;ve even detailed some of the <a
href="http://davidwalsh.name/speeding-website">website optimization efforts used on this website</a>.  Firefox introduces a new strategy for website optimization:  link prefetching.</p><p>What is link prefetching?  From the <a
href="https://developer.mozilla.org/en/link_prefetching_faq" rel="nofollow">MDC</a>:</p><blockquote><p>Link prefetching is a browser mechanism, which utilizes browser idle time to download or prefetch documents that the user might visit in the near future. A web page provides a set of prefetching hints to the browser, and after the browser is finished loading the page, it begins silently prefetching specified documents and stores them in its cache. When the user visits one of the prefetched documents, it can be served up quickly out of the browser&#8217;s cache.</p></blockquote><p>Simply put: the browser downloads designated documents (pages, images, etc.)  the user will likely visit after the current page.  It&#8217;s even super easy to implement!</p><h2>HTML5 Link Prefetch&nbsp;Tag</h2><pre class="html">
&lt;!-- full page --&gt;
&lt;link rel="prefetch" href="http://davidwalsh.name/css-enhancements-user-experience" /&gt;

&lt;!-- just an image --&gt;
&lt;link rel="prefetch" href="http://davidwalsh.name/wp-content/themes/walshbook3/images/sprite.png" /&gt;
</pre><p>HTML5 prefetching is done via the <span
class="tag">LINK</span> tag, specifying &#8220;prefetch&#8221; as the <span
class="attribute">rel</span> and the <span
class="attribute">href</span> being the path to the document.  Mozilla also answers to a few differently named <span
class="tag">LINK</span> <span
class="tag">rel</span> attributes:</p><pre class="html">
&lt;link rel="prefetch alternate stylesheet" title="Designed for Mozilla" href="mozspecific.css" /&gt;
&lt;link rel="next" href="2.html" /&gt;
</pre><p>HTTPS  fetches are also supported.</p><h2>When to Prefetch&nbsp;Content</h2><p>Whether prefetching is right for <em>your</em> website is up to you.  Here are a few ideas:</p><ul><li>When a series of pages is much like a slideshow, load the next 1-3 pages, previous 1-3 pages (assuming they aren&#8217;t massive).</li><li>Loading images to be used on most pages throughout the website.</li><li>Loading the next page of the search results on your website.</li></ul><h2>Preventing&nbsp;Prefetching</h2><p>Firefox allows you to disable link prefetching with the following setting snippet:</p><pre class="text">
user_pref("network.prefetch-next", false);
</pre><h2>Prefetching&nbsp;Notes</h2><p>A few more notes about link prefetching:</p><ul><li>Prefetching <em>does</em> work across domains, including pulling cookies from those sites.</li><li>Prefetching can throw off website statistics as the user doesn&#8217;t technically visit a given page.</li><li>Mozilla Firefox, currently the only browser to support prefetching, has actually supported prefetching since 2003.</li></ul><p>So what do you think?  Using spare time to download extra files seems both dangerous and exciting.  Let me know your thoughts!</p><p><a
href="http://davidwalsh.name/html5-prefetch">HTML5 Link&nbsp;Prefetching</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/html5-prefetch/feed</wfw:commentRss> <slash:comments>27</slash:comments> </item> <item><title>Using jQuery or MooTools For Drag, Drop, Sort,&#160;Save</title><link>http://davidwalsh.name/mootools-drag-ajax</link> <comments>http://davidwalsh.name/mootools-drag-ajax#comments</comments> <pubDate>Tue, 01 Jun 2010 13:55:04 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[CSS]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4980</guid> <description><![CDATA[One of my most popular posts has been Using MooTools 1.2 for Drag, Drop, Sort, Save. My post detailed how you can create a drag&#8217;n'drop, AJAX-ified system to allow the user to drag and drop elements and quickly save them with PHP and MySQL on the server side. I&#8217;ve chosen to update the post with [...]<p><a
href="http://davidwalsh.name/mootools-drag-ajax">Using jQuery or MooTools For Drag, Drop, Sort,&nbsp;Save</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<a
href="http://davidwalsh.name/dw-content/drag-drop-sort-save.php"><img
src="http://davidwalsh.name/dw-content/sort-save.jpg" alt="MooTools jQuery Drag Drop" class="image" /></a><p>One of my most popular posts has been <a
href="http://davidwalsh.name/mootools-drag-drop">Using MooTools 1.2 for Drag, Drop, Sort, Save</a>.  My post detailed how you can create a drag&#8217;n'drop, AJAX-ified system to allow the user to drag and drop elements and quickly save them with PHP and MySQL on the server side.  I&#8217;ve chosen to update the post with a faster, more efficient set of MooTools and PHP code.  I&#8217;ve also provided a jQuery equivalent.  Enjoy!</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/drag-drop-sort-save.php" class="demo">MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/drag-drop-sort-save-jquery.php" class="demo">jQuery Demo</a><div
class="clear"></div></div><h2>The MySQL&nbsp;Table</h2><table
border="0" cellspacing="0" cellpadding="0" class="poll-results"><tr><th>id</th><th>title</th><th>sort_order</th></tr><tr><td>1</td><td>Article 1</td><td>1</td></tr><tr><td>2</td><td>Article 2</td><td>2</td></tr><tr><td>3</td><td>Article 3</td><td>3</td></tr><tr><td>4</td><td>Article 4</td><td>4</td></tr><tr><td>5</td><td>Article 5</td><td>5</td></tr><tr><td>6</td><td>Article 6</td><td>6</td></tr></table><p>This table shows only the important fields per this functionality:  ID, Title, and Sort Order.  Your table will likely have many more columns.</p><h2>The PHP / HTML List&nbsp;Build</h2><pre class="php">
&lt;?php
	
	$query = 'SELECT id, title FROM test_table ORDER BY sort_order ASC';
	$result = mysql_query($query,$connection) or die(mysql_error().': '.$query);
	if(mysql_num_rows($result)) {
	
?&gt;
&lt;p&gt;Drag and drop the elements below.  The database gets updated on every drop.&lt;/p&gt;

&lt;div id="message-box"&gt;&lt;?php echo $message; ?&gt; Waiting for sortation submission...&lt;/div&gt;

&lt;form id="dd-form" action="&lt;?php echo $_SERVER['REQUEST_URI']; ?&gt;" method="post"&gt;
&lt;p&gt;
	&lt;input type="checkbox" value="1" name="autoSubmit" id="autoSubmit" &lt;?php if($_POST['autoSubmit']) { echo 'checked="checked"'; } ?&gt; /&gt;
	&lt;label for="autoSubmit"&gt;Automatically submit on drop event&lt;/label&gt;
&lt;/p&gt;

&lt;ul id="sortable-list"&gt;
	&lt;?php 
		$order = array();
		while($item = mysql_fetch_assoc($result)) {
			echo '&lt;li title="',$item['id'],'"&gt;',$item['title'],'&lt;/li&gt;';
			$order[] = $item['id'];
		}
	?&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;input type="hidden" name="sort_order" id="sort_order" value="&lt;?php echo implode(',',$order); ?&gt;" /&gt;
&lt;input type="submit" name="do_submit" value="Submit Sortation" class="button" /&gt;
&lt;/form&gt;
&lt;?php } else { ?&gt;
	
	&lt;p&gt;Sorry!  There are no items in the system.&lt;/p&gt;
	
&lt;?php } ?&gt;
</pre><p>We&#8217;ll start out by querying the database to retrieve all records from the table.  If there are no records available, we simply show a message saying so.  Once we have established that records are available, we:</p><ul><li>create a message box DIV that will notify users of the status of AJAX request actions.</li><li>create a form element.</li><li>create an &#8220;auto-save&#8221; option checkbox that directs whether or not the sort order should be saved on every drag/drop.</li><li>create a UL element that outputs the list of records in their current sort order.  Each LI element has its ID temporarily stored in its HTML attribute. <em>(For those of you who don&#8217;t mind using custom element attributes, feel free to create a custom attribute to store the record ID)</em>.</li><li>create a hidden INPUT element to dynamically store the current sort order.</li><li>create a submit button that will work via AJAX or typical form submission.</li></ul><p>There&#8217;s a lot of stuff going on here but it&#8217;s all necessary to ensure positive user experience, maximal functionality, and reliability.</p><h2>The&nbsp;CSS</h2><pre class="css">
#sortable-list		{ padding:0; }
#sortable-list li	{ padding:4px 8px; color:#000; cursor:move; list-style:none; width:500px; background:#ddd; margin:10px 0; border:1px solid #999; }
#message-box		{ background:#fffea1; border:2px solid #fc0; padding:4px 8px; margin:0 0 14px 0; width:500px; }
</pre><p>None of the code here is required by, as always, you need to style your elements to fit your website.  Since the drag and drop effect looks so cool, you&#8217;re going to want to make your elements look cool too.</p><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
/* when the DOM is ready */
window.addEvent('domready', function() {
	/* grab important elements */
	var sortInput = document.id('sort_order');
	var submit = document.id('autoSubmit');
	var messageBox = document.id('message-box');
	var list = document.id('sortable-list');
	
	/* get the request object ready;  re-use the same Request */
	var request = new Request({
		url: '&lt;?php echo $_SERVER["REQUEST_URI"]; ?&gt;',
		link: 'cancel',
		method: 'post',
		onRequest: function() {
			messageBox.set('text','Updating the sort order in the database.');
		},
		onSuccess: function() {
			messageBox.set('text','Database has been updated.');
		}
	});
	/* worker function */
	var fnSubmit = function(save) {
		var sortOrder = [];
		list.getElements('li').each(function(li) {
			sortOrder.push(li.retrieve('id'));
		});
		sortInput.value = sortOrder.join(',');
		if(save) {
			request.send('sort_order=' + sortInput.value + '&amp;ajax=' + submit.checked + '&amp;do_submit=1&amp;byajax=1');
		}
	};
	
	/* store values */
	list.getElements('li').each(function(li) {
		li.store('id',li.get('title')).set('title','');
	});
	
	/* sortables that also *may* */
	new Sortables(list,{
		constrain: true,
		clone: true,
		revert: true,
		onComplete: function(el,clone) {
			fnSubmit(submit.checked);
		}
	});
	
	/* ajax form submission */
	document.id('dd-form').addEvent('submit',function(e) {
		if(e) e.stop();
		fnSubmit(true);
	});
	
	
});
</pre><p>The first step in the process is rounding up the list of key elements in the page.  Then we create our Request instance which will be used for every AJAX request. Next we create fnSubmit the function that will round up the LI elements (records) and their sort order.  Lastly, we create our Sortables instance and connect submission event to the form&#8217;s submit button.  When you split the pieces apart, the system is actually quite simple.</p><h2>The jQuery&nbsp;JavaScript</h2><pre>
/* when the DOM is ready */
jQuery(document).ready(function() {
	/* grab important elements */
	var sortInput = jQuery('#sort_order');
	var submit = jQuery('#autoSubmit');
	var messageBox = jQuery('#message-box');
	var list = jQuery('#sortable-list');
	/* create requesting function to avoid duplicate code */
	var request = function() {
		jQuery.ajax({
			beforeSend: function() {
				messageBox.text('Updating the sort order in the database.');
			},
			complete: function() {
				messageBox.text('Database has been updated.');
			},
			data: 'sort_order=' + sortInput[0].value + '&amp;ajax=' + submit[0].checked + '&amp;do_submit=1&amp;byajax=1', //need [0]?
			type: 'post',
			url: '&lt;?php echo $_SERVER["REQUEST_URI"]; ?&gt;'
		});
	};
	/* worker function */
	var fnSubmit = function(save) {
		var sortOrder = [];
		list.children('li').each(function(){
			sortOrder.push(jQuery(this).data('id'));
		});
		sortInput.val(sortOrder.join(','));
		console.log(sortInput.val());
		if(save) {
			request();
		}
	};
	/* store values */
	list.children('li').each(function() {
		var li = jQuery(this);
		li.data('id',li.attr('title')).attr('title','');
	});
	/* sortables */
	list.sortable({
		opacity: 0.7,
		update: function() {
			fnSubmit(submit[0].checked);
		}
	});
	list.disableSelection();
	/* ajax form submission */
	jQuery('#dd-form').bind('submit',function(e) {
		if(e) e.preventDefault();
		fnSubmit(true);
	});
});
</pre><p>The jQuery code is surprisingly similar to the MooTools version.  Please note that duplicating the jQuery functionality will require that you also download the jQuery UI library.  It&#8217;s a good chunk of extra code but the functionality works great.</p><h2>The &#8220;Header&#8221;&nbsp;PHP/MySQL</h2><pre class="php">
/* on form submission */
if(isset($_POST['do_submit']))  {
	/* split the value of the sortation */
	$ids = explode(',',$_POST['sort_order']);
	/* run the update query for each id */
	foreach($ids as $index=&gt;$id) {
		$id = (int) $id;
		if($id != '') {
			$query = 'UPDATE test_table SET sort_order = '.($index + 1).' WHERE id = '.$id;
			$result = mysql_query($query,$connection) or die(mysql_error().': '.$query);
		}
	}
	
	/* now what? */
	if($_POST['byajax']) { die(); } else { $message = 'Sortation has been saved.'; }
}
</pre><p>The &#8220;header&#8221; or processing PHP file receives the sort order, splits the string apart by the comma delimiter, and executes queries to update the sort order.  Since PHP&#8217;s mysql_query function wont allow for more than one query at a time, queries need to be executed separately.  If you use another MySQL/PHP library (PDO, etc.) you may want to append the queries to a single string and execute them all at once.  Depending on the method by which the user submitted the update (AJAX or normal post), the PHP will either die out or reload the page per usual.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/drag-drop-sort-save.php" class="demo">MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/drag-drop-sort-save-jquery.php" class="demo">jQuery Demo</a><div
class="clear"></div></div><p>My clients have always loved this feature within their CMS.  Sorting records can be hugely important and allowing for an easy method by which to do so can make you look like a miracle worker.</p><p><a
href="http://davidwalsh.name/mootools-drag-ajax">Using jQuery or MooTools For Drag, Drop, Sort,&nbsp;Save</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/mootools-drag-ajax/feed</wfw:commentRss> <slash:comments>71</slash:comments> </item> <item><title>META Refresh vs. JavaScript&#160;Refresh</title><link>http://davidwalsh.name/meta-refresh-javascript</link> <comments>http://davidwalsh.name/meta-refresh-javascript#comments</comments> <pubDate>Tue, 24 Nov 2009 14:09:44 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4298</guid> <description><![CDATA[A few days back I was perusing the ESPN.com source code when I found the following snippet of code: &#60;script&#62; ESPN_refresh=window.setTimeout(function(){window.location.href=window.location.href},900000); &#60;/script&#62; &#60;noscript&#62; &#60;meta http-equiv=&#34;refresh&#34; content=&#34;900&#34; /&#62; &#60;/noscript&#62; I understand what the code was supposed to do but was confused as to why they&#8217;d use JavaScript as a primary method and META as a fallback [...]<p><a
href="http://davidwalsh.name/meta-refresh-javascript">META Refresh vs. JavaScript&nbsp;Refresh</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>A few days back I was perusing the ESPN.com source code when I found the following snippet of code:</p><pre class="html">
&lt;script&gt;
	ESPN_refresh=window.setTimeout(function(){window.location.href=window.location.href},900000);
&lt;/script&gt;
&lt;noscript&gt;
	&lt;meta http-equiv=&quot;refresh&quot; content=&quot;900&quot; /&gt;
&lt;/noscript&gt;
</pre><p>I understand what the code was supposed to do but was confused as to why they&#8217;d use JavaScript as a primary method and META as a fallback method.  Why not just use the META method?  I did some research and found the answer at Wikipedia:</p><blockquote><p>Use of meta refresh is discouraged by the W3C, since unexpected refresh can disorient users. Meta refresh also impairs the web browser&#8217;s &#8220;back&#8221; button in some browsers (including Internet Explorer 6 and before), although most modern browsers compensate for this (Mozilla Firefox, Opera, Internet Explorer 7).</p></blockquote><p>So there you have it.  Use JavaScript as your primary means for automatic page refreshes and a META tag as your fallback.</p><p><a
href="http://davidwalsh.name/meta-refresh-javascript">META Refresh vs. JavaScript&nbsp;Refresh</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/meta-refresh-javascript/feed</wfw:commentRss> <slash:comments>27</slash:comments> </item> <item><title>Create a Sprited Navigation Menu Using CSS and&#160;MooTools</title><link>http://davidwalsh.name/css-sprite-menu</link> <comments>http://davidwalsh.name/css-sprite-menu#comments</comments> <pubDate>Thu, 29 Oct 2009 13:03:08 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[CSS]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Optimization]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=3918</guid> <description><![CDATA[CSS sprites are all the rage these days. And why shouldn&#8217;t be? They&#8217;re easy to implement, have great upside, and usually take little effort to create. Dave Shea wrote an epic CSS sprites navigation post titled CSS Sprites2 &#8211; It’s JavaScript Time. In his post he outlined a method for enhancing the CSS sprite menu [...]<p><a
href="http://davidwalsh.name/css-sprite-menu">Create a Sprited Navigation Menu Using CSS and&nbsp;MooTools</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></description> <content:encoded><![CDATA[<p>CSS sprites are all the rage these days. And why shouldn&#8217;t be?  They&#8217;re easy to implement, have great upside, and usually take little effort to create.  Dave Shea wrote an epic CSS sprites navigation post titled <a
href="http://www.alistapart.com/articles/sprites2/">CSS Sprites2 &#8211; It’s JavaScript Time</a>.  In his post he outlined a method for enhancing the CSS sprite menu with jQuery.  I loved his post so much that I converted his jQuery CSS sprites menu to MooTools.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/sprites-menu.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The Sprite&nbsp;Image</h2><img
src="http://davidwalsh.name/dw-content/sprites-blue-nav.gif" alt="CSS Sprite Menu" /><p>This is a great example of an efficient, useful sprite image.</p><h2>The&nbsp;HTML</h2><pre class="html">
&lt;ul id=&quot;nav&quot;&gt;
	&lt;li id=&quot;home&quot; &lt;?php echo $current == '' || $current == 'home' ? 'class=&quot;current&quot;' : ''; ?&gt;&gt;&lt;a href=&quot;?home&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
	&lt;li id=&quot;about&quot; &lt;?php echo $current == 'about' ? 'class=&quot;current&quot;' : ''; ?&gt;&gt;&lt;a href=&quot;?about&quot;&gt;About&lt;/a&gt;&lt;/li&gt;
	&lt;li id=&quot;services&quot; &lt;?php echo $current == 'services' ? 'class=&quot;current&quot;' : ''; ?&gt;&gt;&lt;a href=&quot;?services&quot;&gt;Services&lt;/a&gt;&lt;/li&gt;
	&lt;li id=&quot;contact&quot; &lt;?php echo $current == 'contact' ? 'class=&quot;current&quot;' : ''; ?&gt;&gt;&lt;a href=&quot;?contact&quot;&gt;Contact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</pre><p>My code mostly mirrors the original ALA post&#8217;s code but I&#8217;ve chose to use IDs instead of CSS classes.</p><h2>The&nbsp;CSS</h2><pre class="css">
#nav { width: 401px; height: 48px; background: url(sprites-blue-nav.gif) no-repeat; position: absolute; top: 100px; left: 100px; padding:0; }
#nav li { display: inline; }
#nav li a:link, #nav li a:visited { position: absolute; top: 0; height: 48px; text-indent: -9000px; overflow: hidden; z-index: 10; }

#home a:link, #home a:visited { left: 23px; width: 76px; }
#home a:hover, #home a:focus { background: url(sprites-blue-nav.gif) no-repeat -23px -49px; }
#home a:active { background: url(sprites-blue-nav.gif) no-repeat -23px -98px; }
#home.current a:link, #home.current a:visited { background: url(sprites-blue-nav.gif) no-repeat -23px -147px; cursor: default; }
.nav-home, .nav-home-click { position: absolute; top: 0; left: 23px; width: 76px; height: 48px; background: url(sprites-blue-nav.gif) no-repeat -23px -49px; }
.nav-home-click { background: url(sprites-blue-nav.gif) no-repeat -23px -98px; }

#about a:link, #about a:visited { left: 100px; width: 82px; }
#about a:hover, #about a:focus { background: url(sprites-blue-nav.gif) no-repeat -100px -49px; }
#about a:active { background: url(sprites-blue-nav.gif) no-repeat -100px -98px; }
#about.current a:link, #about.current a:visited { background: url(sprites-blue-nav.gif) no-repeat -100px -147px; cursor: default; }
.nav-about, .nav-about-click { position: absolute; top: 0; left: 100px; width: 82px; height: 48px; background: url(sprites-blue-nav.gif) no-repeat -100px -49px; }
.nav-about-click { background: url(sprites-blue-nav.gif) no-repeat -100px -98px; }

#services a:link, #services a:visited { left: 183px; width: 97px; }
#services a:hover, #services a:focus { background: url(sprites-blue-nav.gif) no-repeat -183px -49px; }
#services a:active { background: url(sprites-blue-nav.gif) no-repeat -183px -98px; }
#services.current a:link, #services.current a:visited { background: url(sprites-blue-nav.gif) no-repeat -183px -147px; cursor: default; }
.nav-services, .nav-services-click { position: absolute; top: 0; left: 183px; width: 97px; height: 48px; background: url(sprites-blue-nav.gif) no-repeat -183px -49px; }
.nav-services-click { background: url(sprites-blue-nav.gif) no-repeat -183px -98px; }

#contact a:link, #contact a:visited { left: 281px; width: 97px; }
#contact a:hover, #contact a:focus { background: url(sprites-blue-nav.gif) no-repeat -281px -49px; }
#contact a:active { background: url(sprites-blue-nav.gif) no-repeat -281px -98px; }
#contact.current a:link, #contact.current a:visited { background: url(sprites-blue-nav.gif) no-repeat -281px -147px; cursor: default; }
.nav-contact, .nav-contact-click { position: absolute; top: 0; left: 281px; width: 97px; height: 48px; background: url(sprites-blue-nav.gif) no-repeat -281px -49px; }
.nav-contact-click { background: url(sprites-blue-nav.gif) no-repeat -281px -98px; }
</pre><p>Unfortunately there&#8217;s plenty of CSS.  That&#8217;s generally the one downside of using sprites but the payoff comes with less requests to the server.  My CSS differs from the original ALA post in that I accommodate for my IDs.</p><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
(function($) {
	window.addEvent('domready',function() {
		$('nav').getElements('li').each(function(li) {
			//settings
			var link = li.getFirst('a');
			//fix background image
			if(!li.hasClass('current')) {
				link.setStyle('background-image','none');
			}
			//utility div
			var div = new Element('div',{
				'class': 'nav-' + li.get('id'),
				opacity: 0
			}).inject(li);
			//background imagery
			li.addEvents({
				mouseenter: function() {
					div.fade('in');
				},
				mouseleave: function() {
					div.fade('out');
				},
				mousedown: function() {
					div.addClass('nav-' + li.get('id') + '-click');
				},
				mouseup: function() {
					div.removeClass('nav-' + li.get('id') + '-click');
				}
			});
		});
	});
})(document.id);
</pre><p>My MooTools version is less code and slightly more efficient as I&#8217;m not creating and disposing of the same DIVs over and over as the user hovers over each menu item.  The menu has original, selected, hovered, and mousedown states.  Awesome!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/sprites-menu.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Do you use sprites for any of your menus?  Share a link to a few &#8212; I&#8217;d love to see what you&#8217;ve done!</p><p><a
href="http://davidwalsh.name/css-sprite-menu">Create a Sprited Navigation Menu Using CSS and&nbsp;MooTools</a> is a post from: <a
href="http://davidwalsh.name">David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</a></p> ]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/css-sprite-menu/feed</wfw:commentRss> <slash:comments>23</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced (User agent is rejected)
Database Caching 1/59 queries in 0.041 seconds using disk: basic
Object Caching 1451/1554 objects using disk: basic

Served from: davidwalsh.name @ 2012-05-23 23:20:15 -->
