<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>David Walsh :: Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞. &#187; AJAX</title> <atom:link href="http://davidwalsh.name/tutorials/ajax/feed" rel="self" type="application/rss+xml" /><link>http://davidwalsh.name</link> <description>Legendary scribbles about JavaScript, HTML5, AJAX, PHP, CSS, and ∞.</description> <lastBuildDate>Thu, 02 Sep 2010 03:13:15 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.0.1</generator> <item><title>Create a Twitter AJAX Button with MooTools, jQuery, or&#160;Dojo</title><link>http://davidwalsh.name/twitter-button</link> <comments>http://davidwalsh.name/twitter-button#comments</comments> <pubDate>Wed, 25 Aug 2010 03:28:19 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Dojo]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[jQuery]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5049</guid> <description><![CDATA[There&#8217;s nothing like a subtle, slick website widget that effectively uses CSS and JavaScript to enhance the user experience.  Of course widgets like that take many hours to perfect, but it doesn&#8217;t take long for that effort to be rewarded with above-average user retention and buzz.  One of the widgets I love is Twitter&#8217;s &#8220;Follow&#8221; [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/twitter-button">Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/dojo-twitter' rel='bookmark' title='Permanent Link: Create Twitter-Style Buttons with the Dojo&nbsp;Toolkit'>Create Twitter-Style Buttons with the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/github-css' rel='bookmark' title='Permanent Link: Create GitHub-Style Buttons with CSS and jQuery, MooTools, or Dojo&nbsp;JavaScript'>Create GitHub-Style Buttons with CSS and jQuery, MooTools, or Dojo&nbsp;JavaScript</a></li><li><a
href='http://davidwalsh.name/dojo-ajax' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;Dojo'>Animated AJAX Record Deletion Using&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/animated-button' rel='bookmark' title='Permanent Link: Create an Animated Sliding Button Using&nbsp;MooTools'>Create an Animated Sliding Button Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/twitter-dropdown-jquery' rel='bookmark' title='Permanent Link: Create Twitter-Style Dropdowns Using&nbsp;jQuery'>Create Twitter-Style Dropdowns Using&nbsp;jQuery</a></li></ol>]]></description> <content:encoded><![CDATA[<a
href="http://davidwalsh.name/dw-content/twitter-follow.php"><img
src="http://davidwalsh.name/dw-content/twitter-button.jpg" alt="Twitter Button" class="image" /></a><p>There&#8217;s nothing like a subtle, slick website widget that effectively uses CSS and JavaScript to enhance the user experience.  Of course widgets like that take many hours to perfect, but it doesn&#8217;t take long for that effort to be rewarded with above-average user retention and buzz.  One of the widgets I love is Twitter&#8217;s &#8220;Follow&#8221; button.  Let me show you how you can implement this functionality with three popular JavaScript toolkits:  MooTools, jQuery, and Dojo.</p><p><em>Note:  This tutorial will only display the client side handling of the form submission &#8212; NOT any PHP/MySQL/server-side handling of the request.</em></p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php" class="demo">View MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php?lib=dojo" class="demo">View Dojo Demo</a> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php?lib=jquery" class="demo">View jQuery Demo</a><div
class="clear"></div></div><h2>The HTML&nbsp;Structure</h2><pre class="html">
<form class="follow-form" method="post" action="twitter-follow.php">
	<input type="hidden" name="followID" value="123456" />
	<button type="submit" value="Actions" class="btn follow" title="123456">
		<i></i><span>follow</span>
	</button>
</form>
</pre><p>The HTML for the button is very simple.  The structure revolves around a BUTTON element which contains an I element and SPAN element.  You&#8217;re probably thinking &#8220;An I element?  WTF.&#8221;  I know I did.  The truth of the matter is that the I element is deprecated and, as far as I&#8217;m concerned, and be used for any purpose the developer would like.  I&#8217;m also sure that Twitter doesn&#8217;t mind saving bytes here or there.</p><h2>The CSS&nbsp;Styles</h2><pre class="css">
/* twitter button and its children */
button.btn { 
	-moz-border-radius:4px;
	-webkit-border-radius:4px;
	background-attachment:scroll;
	background-color:#ddd;
	background-image:url(http://s.twimg.com/a/1282150308/images/buttons/bg-btn.gif);
	background-position:0 0;
	background-repeat:repeat-x;
	border:1px solid #ddd;
	border-bottom:1px solid #ccc;
	color:#333;
	cursor:pointer;
	font-family:"Lucida Grande",sans-serif;
	font-size:11px;
	line-height:14px;
	padding:4px 8px 5px 8px;
	text-shadow:1px 1px 0 #fff;
	vertical-align:top;
}
button.btn:hover {
	border:1px solid #999;
	border-bottom-color:#888;
	color:#000;
	background-color:#d5d5d5;
	background-position:0 -6px;
}
button.btn:active {
	background-image:none !important;
	text-shadow:none !important;
}
			
button.btn i {
	background-image:url(http://s.twimg.com/a/1282150308/images/sprite-icons.png);
	background-position:-176px -32px;
	background-repeat:no-repeat;
	display:inline-block;
	height:13px;
	margin-right:5px;
	width:15px;
}
button.btn i.active	{ background:url(http://s.twimg.com/a/1282150308/images/spinner.gif); }

/* properties for the element that is generated *after* following */
span.following	{  background:#ffd; padding:5px 10px; }
span.following span { width:10px; height:9px; margin-right:5px; display:inline-block; background:url("http://s.twimg.com/a/1282150308/images/sprite-icons.png") -160px -16px no-repeat; }
</pre><p>Most of the styling for this button goes onto the BUTTON element itself.  You&#8217;ll notice directives to round the button;  leaving the button sharp also please the eye.  Through the regular, hover, and active button states, check out how Twitter users the background position and colors to nicely modify the button without the need for additional images.  You&#8217;ll also notice Twitter uses sprites&#8230;as should you.</p><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
/* with mootools */
window.addEvent('domready',function() {
	/* fetch elements */
	$$('form.follow-form').each(function(form) {
		/* stop form event */
		form.addEvent('submit',function(e) {
			/* stop event */
			if(e) e.stop();
			/* send ajax request */
			var i = form.getElement('i');
			new Request({
				url: 'twitter-follow.php',
				method: 'post',
				data: {
					followID: form.getElement('input').value
				},
				onRequest: function() {
					i.addClass('active');
				},
				onSuccess: function() {
					var button = form.getElement('button');
					button.setStyle('display','none');
					new Element('span',{
						html: '<span></span>Following!',
						'class': 'following'
					}).inject(button,'after');
				},
				onComplete: function() {
					i.removeClass('active');
				}
			}).send();
		});
	});
});
</pre><p>The first step is grabbing all of the FORM elements with the follow-form CSS class.  Upon form submission, the default submission action is stopped.  An AJAX request is fired, using the INPUT element&#8217;s ID as the user to follow.  When the request is fired, the I element&#8217;s background image is set to the spinner.  When the request is complete, the button is hidden and a new SPAN element is displayed informing the user that they are now following the given user!</p><h2>The jQuery&nbsp;JavaScript</h2><pre class="js">
// Idiomatic jQuery by Doug Neiner
jQuery(function ($) {
	/* fetch elements and stop form event */
	$("form.follow-form").submit(function (e) {
		/* stop event */
		e.preventDefault();
		/* "on request" */
		$(this).find('i').addClass('active');
		/* send ajax request */
		$.post('twitter-follow.php', {
			followID: $(this).find('input').val()
		}, function () {
			/* find and hide button, create element */
			$(e.currentTarget)
			  .find('button').hide()
			  .after('&lt;span class="following"&gt;&lt;span&gt;&lt;/span&gt;Following!&lt;/span&gt;');
		});
	});
});
</pre><p>The code above is based off of the MooTools code.  The workflow is exactly the same.</p><h2>The Dojo&nbsp;JavaScript</h2><pre class="js">
/* when the DOM is ready */
dojo.ready(function() {
	/* fetch elements */
	dojo.query('form.follow-form').forEach(function(form) {
		/* stop form event */
		dojo.connect(form,'onsubmit',function(e) {
			/* stop event */
			dojo.stopEvent(e);
			/* active class */
			dojo.query('i',form).addClass('active');
			/* get button */
			var button = dojo.query('button',form)[0];
			/* ajax request */
			dojo.xhrPost({
				form: form,
				load: function() {
					dojo.style(button,'display','none');
					dojo.create('span',{
						innerHTML: '<span></span>Following',
						className: 'following'
					},button,'after');
				}
			});
		});
	});
});
</pre><p>The code above is based off of the MooTools code.  The workflow is exactly the same.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php" class="demo">View MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php?lib=dojo" class="demo">View Dojo Demo</a> <a
href="http://davidwalsh.name/dw-content/twitter-follow.php?lib=jquery" class="demo">View jQuery Demo</a><div
class="clear"></div></div><p>This &#8220;Follow&#8221; button is only one of many details that Twitter has paid attention to, just to make the user experience on the site better.  Take note from the effort put forth by large websites &#8212; adding these types of details to your smaller websites can make the user experience much better for YOUR users!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/twitter-button">Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/dojo-twitter' rel='bookmark' title='Permanent Link: Create Twitter-Style Buttons with the Dojo&nbsp;Toolkit'>Create Twitter-Style Buttons with the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/github-css' rel='bookmark' title='Permanent Link: Create GitHub-Style Buttons with CSS and jQuery, MooTools, or Dojo&nbsp;JavaScript'>Create GitHub-Style Buttons with CSS and jQuery, MooTools, or Dojo&nbsp;JavaScript</a></li><li><a
href='http://davidwalsh.name/dojo-ajax' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;Dojo'>Animated AJAX Record Deletion Using&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/animated-button' rel='bookmark' title='Permanent Link: Create an Animated Sliding Button Using&nbsp;MooTools'>Create an Animated Sliding Button Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/twitter-dropdown-jquery' rel='bookmark' title='Permanent Link: Create Twitter-Style Dropdowns Using&nbsp;jQuery'>Create Twitter-Style Dropdowns Using&nbsp;jQuery</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/twitter-button/feed</wfw:commentRss> <slash:comments>8</slash:comments> </item> <item><title>Create a Dynamic Flickr Image Search with the Dojo&#160;Toolkit</title><link>http://davidwalsh.name/dojo-flickr</link> <comments>http://davidwalsh.name/dojo-flickr#comments</comments> <pubDate>Tue, 24 Aug 2010 01:46:49 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[APIs]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Dojo]]></category> <category><![CDATA[Markup]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5051</guid> <description><![CDATA[The Dojo Toolkit is a treasure chest of great JavaScript classes.  You can find basic JavaScript functionality classes for AJAX, node manipulation, animations, and the like within Dojo.  You can find elegant, functional UI widgets like DropDown Menus, tabbed interfaces, and form element replacements within Dijit.  In DojoX you can find charting libraries, special data [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dojo-flickr">Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/dojo-context-menu' rel='bookmark' title='Permanent Link: Create a Context Menu with Dojo and&nbsp;Dijit'>Create a Context Menu with Dojo and&nbsp;Dijit</a></li><li><a
href='http://davidwalsh.name/dojo-accordion' rel='bookmark' title='Permanent Link: Create a Simple Dojo&nbsp;Accordion'>Create a Simple Dojo&nbsp;Accordion</a></li><li><a
href='http://davidwalsh.name/dojo-dijit-charting' rel='bookmark' title='Permanent Link: Dive Into Dojo Series:  Dijit and&nbsp;Charting'>Dive Into Dojo Series:  Dijit and&nbsp;Charting</a></li><li><a
href='http://davidwalsh.name/dojo-digg' rel='bookmark' title='Permanent Link: Digg-Style Dynamic Share Widget Using the Dojo&nbsp;Toolkit'>Digg-Style Dynamic Share Widget Using the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/dojo-tabs' rel='bookmark' title='Permanent Link: Dijit&#8217;s TabContainer Layout:  Easy Tabbed&nbsp;Content'>Dijit&#8217;s TabContainer Layout:  Easy Tabbed&nbsp;Content</a></li></ol>]]></description> <content:encoded><![CDATA[<p><a
href="http://davidwalsh.name/dw-content/dojo-flickr.php"><img
src="http://davidwalsh.name/dw-content/dojo-flickr.jpg" alt="Dojo Flickr" /></a></p><p>The Dojo Toolkit is a treasure chest of great JavaScript classes.  You can find basic JavaScript functionality classes for AJAX, node manipulation, animations, and the like within Dojo.  You can find elegant, functional UI widgets like DropDown Menus, tabbed interfaces, and form element replacements within Dijit.  In DojoX you can find charting libraries, special data stores, vector graphic helpers, and much more.</p><p>This post aims to mesh the three collections together.  We&#8217;ll be creating a tabbed interface for grabbing Flickr images using Dijit&#8217;s TabContainer, <a
href="http://www.dojotoolkit.org/reference-guide/dojox/data/FlickrStore.html#dojox-data-flickrstore" rel="nofollow">DojoX&#8217;s Flickr data store</a>, and basic Dojo code for event handling and node manipulation.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/dojo-flickr.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>Select a&nbsp;Theme</h2><p>There are two main steps in adding a theme to the page:  importing the theme stylesheet and adding the theme as a class name to the <code>BODY</code> element.</p><pre class="css">
&lt;style type="text/css"&gt;
	/* bring in the claro theme */
	@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css";
	
	/* define styles per the images */
	a.thumb	{ display:inline-block; margin:0 20px 20px 0; }
	
&lt;/style&gt;
</pre><pre class="html">
&lt;body class="claro"&gt;
</pre><p>The claro theme is new in Dojo 1.5 and happens to be my favorite.</p><h2>Import Dojo From CDN,&nbsp;parseOnLoad:true</h2><p>Pulling from Google&#8217;s CDN makes Dojo load lightning-fast.  Adding a <code>djConfig</code> attribute with <code>parseOnLoad:true</code> instructs Dojo to scour the page looking for widgets.</p><pre class="html">
&lt;script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js" type="text/javascript" djConfig="parseOnLoad:true"&gt;&lt;/script&gt;
</pre><p>Alternatively you could configure Dojo by using the <code>djConfig</code> JavaScript variable:</p><pre class=" js">
djConfig = {
	parseOnLoad: true
};
</pre><p>Either way will suffice.</p><h2>Create the HTML Structure: Tab Container and Search&nbsp;Form</h2><p>Setting up the form comes first.  The form is going to be very simple, containing only a search box and a submit button.  Each node (<code>FORM</code>, <code>INPUT</code>, and <code>BUTTON</code>) is converted to its Dijit widget equivalent to provide extra functionality and themed display.</p><pre class="html">
&lt;!-- search will be here --&gt;
&lt;form dojoType="dijit.form.Form" id="searchForm"&gt;
	&lt;input dojoType="dijit.form.ValidationTextBox" id="searchBox" missingMessage="Please provide a term to search" placeholder="search term..." required="true" /&gt;
	&lt;button type="submit" dojoType="dijit.form.Button" id="searchButton"&gt;Submit Search&lt;/button&gt;
&lt;/form&gt;
</pre><p>The search box becomes a <code>dijit.form.ValidationTextBox</code> which allows me to require a value and display an error message if no term is provided.  I&#8217;ve also used the <code>placeholder</code> attribute to display a message in the search box when there is no value.  Dojo&#8217;s internal awesomeness adds JavaScript support for the same functionality if the user&#8217;s browser doesn&#8217;t support <code>placeholder</code> yet.</p><p>The second piece is placing the <code>TabContainer</code> and its initial content pane in the page.  The initial <code>ContentPane</code> content will simply be a &#8220;welcome&#8221; tab so that there&#8217;s always one tab within the container:</p><pre class="html">
&lt;!-- will set the eventual dimensions for the tab container --&gt;
&lt;div style="width:675px;height:400px"&gt;
	&lt;!-- will host all tabs and their content panes --&gt;
	&lt;div dojoType="dijit.layout.TabContainer" id="tabContainer" style="width:100%;height:100%;"&gt;
		&lt;!-- welcome pane: title is tab name, make this tab selected --&gt;
		&lt;div dojoType="dijit.layout.ContentPane" title="Welcome Pane" selected="true"&gt;
			&lt;p&gt;
				Welcome to the Flickr Search data store and Tab Container example.  
				Submit your search and watch the tab load!
			&lt;/p&gt;
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;
</pre><p>Future tabs will be closable.</p><h2>Require Dojo/Dijit/DojoX&nbsp;Dependencies</h2><p>Before we can create our widgets and use Dojo classes, we need to load them:</p><pre class="js">
/* require necessary classes */
dojo.require('dijit.layout.TabContainer');
dojo.require('dijit.layout.ContentPane');
dojo.require('dijit.form.Button');
dojo.require('dijit.form.Form');
dojo.require('dijit.form.ValidationTextBox');
dojo.require('dojox.data.FlickrStore');
dojo.require('dijit.Tooltip');
</pre><p>Dojo&#8217;s internal functionality will also direct dependencies of dependencies to be loaded.  If you aren&#8217;t familiar with Dojo class loading, be sure to read <a
href="http://davidwalsh.name/dojo-require">The Beauty of dojo.require()</a>.</p><h2>Dojo, Dijit, DojoX:  Make It&nbsp;Happen</h2><p>Now that the theme is in place, HTML structure is there, and we&#8217;ve required the necessary classes, we can code our application-specific JavaScript.  There&#8217;s a decent amount of JavaScript need to make this work so let&#8217;s break it down.</p><p>Start by creating an object which will hold all of our open tabs and an instance of <code>dojox.data.FlickrStore</code> which will be used to query Flickr:</p><pre class="js">
/* settings */
var tabSubjects = {};
var flickrStore = new dojox.data.FlickrStore();
</pre><p>Then collect the form elements as well as the <code>TabContainer</code>:</p><pre class="js">
/* collect proper elements */
var searchForm = dijit.byId('searchForm');
var searchBox = dijit.byId('searchBox');
var searchButton = dijit.byId('searchButton');
var tabContainer = dijit.byId('tabContainer');
</pre><p>Add a &#8220;submit&#8221; event listener to the <code>TabContainer</code>&#8230;</p><pre class="js">
/* connect click event to search */
dojo.connect(searchForm,'onSubmit',function(e) {
</pre><p>&#8230;which stops the normal form submission:</p><pre class="js">
//stop!
dojo.stopEvent(e);
</pre><p>&#8230;grabs the value of the search box:</p><pre class="js">
//store value - set to lower case to save to caching object
var value = searchBox.get('value').toLowerCase();
</pre><p>If a value is present, make sure there isn&#8217;t currently a search tab open for that term.  If there is, focus on it.  If this is a new search term, direct the <code>dojox.data.FlickrStore</code> instance to search and return images for the given term.  Upon search, a new tab for this term is created with a default title and content string, added to the TabContainer, and this new tab is selected:</p><pre class="js">
//if a value exists...
if(value) {
	//if the tab isn't already there...
	if(!tabSubjects[value]) {
		//do the search...
		flickrStore.fetch({
			query: { tags: value },
			onBegin: function() {
				//create the tab
				tabSubjects[value] = new dijit.layout.ContentPane({ 
					title:value, 
					content:'Searching for ' + value + '...', 
					closable:true,
					onClose: function() {
						//remove this from our saved tabs when closed
						tabSubjects[value] = null;
						return true;
					}
				});
				//add to tabcontainer and select
				tabContainer.addChild(tabSubjects[value]);
				tabContainer.selectChild(tabSubjects[value]);
			},
</pre><p>When the search is complete, we clear the contents of the tab&#8217;s pane and loop through each returned image, injecting it into the content pane.  Lastly, we create a tooltip for the image which displays the image name when the user focuses on the image:</p><pre class="js">
	onComplete: function(items) {
		//if we got items...
		if(items.length) {
			//clear the tab's content'
			tabSubjects[value].set('content','');
			//cycle through each image returned, inject into new tab, add tooltip
			dojo.forEach(items,function(item,i) {
				//create the link's ID for the tooltip
				var id = new Date().getTime() + '_' + i;
				var a = dojo.create('a',{ 
					href: flickrStore.getValue(item,'link'),
					className: 'thumb',
					target: '_blank',
					id:  id,
					innerHTML: '&lt;img src="' + flickrStore.getValue(item,'imageUrlSmall') + '" alt="' + flickrStore.getValue(item,'title') +'" /&gt;'
				},tabSubjects[value].domNode);
				//tooltip!
				new dijit.Tooltip({ label: flickrStore.getValue(item,'title'), connectId: id });
			});
		}
		else {
			//provide "no images" content
			tabSubjects[value].set('content','There were no images available for this term.');
		}
		//empty the search box
		searchBox.set('value','');
		
	}
});
</pre><p>Here&#8217;s the complete JavaScript block for this app:</p><pre class="js">
/* require necessary classes */
dojo.require('dijit.layout.TabContainer');
dojo.require('dijit.layout.ContentPane');
dojo.require('dijit.form.Button');
dojo.require('dijit.form.Form');
dojo.require('dijit.form.ValidationTextBox');
dojo.require('dojox.data.FlickrStore');
dojo.require('dijit.Tooltip');

/* when all classes have loaded... */
dojo.ready(function() {
	
	/* settings */
	var tabSubjects = {};
	var flickrStore = new dojox.data.FlickrStore();
	
	/* collect proper elements */
	var searchForm = dijit.byId('searchForm');
	var searchBox = dijit.byId('searchBox');
	var searchButton = dijit.byId('searchButton');
	var tabContainer = dijit.byId('tabContainer');
	
	/* connect click event to search */
	dojo.connect(searchForm,'onSubmit',function(e) {
		//stop!
		dojo.stopEvent(e);
		//store value
		var value = searchBox.get('value').toLowerCase();
		//if a value exists...
		if(value) {
			//if the tab isn't already there...
			if(!tabSubjects[value]) {
				//do the search...
				flickrStore.fetch({
					query: { tags: value },
					onBegin: function() {
						//create the tab
						tabSubjects[value] = new dijit.layout.ContentPane({ 
							title:value, 
							content:'Searching for ' + value + '...', 
							closable:true,
							onClose: function() {
								//remove this from our saved tabs when closed
								tabSubjects[value] = null;
								return true;
							}
						});
						//add to tabcontainer and select
						tabContainer.addChild(tabSubjects[value]);
						tabContainer.selectChild(tabSubjects[value]);
					},
					onComplete: function(items) {
						//if we got items...
						if(items.length) {
							//clear the tab's content'
							tabSubjects[value].set('content','');
							//cycle through each image returned, inject into new tab, add tooltip
							dojo.forEach(items,function(item,i) {
								//create the link's ID for the tooltip
								var id = new Date().getTime() + '_' + i;
								var a = dojo.create('a',{ 
									href: flickrStore.getValue(item,'link'),
									className: 'thumb',
									target: '_blank',
									id:  id,
									innerHTML: '&lt;img src="' + flickrStore.getValue(item,'imageUrlSmall') + '" alt="' + flickrStore.getValue(item,'title') +'" /&gt;'
								},tabSubjects[value].domNode);
								//tooltip!
								if(flickrStore.getValue(item,'title')) { new dijit.Tooltip({ label: flickrStore.getValue(item,'title'), connectId: id }); }
							});
						}
						else {
							//provide "no images" content
							tabSubjects[value].set('content','There were no images available for this term.');
						}
						//empty the search box
						searchBox.set('value','');
						
					}
				});
			}
			//if it does exist, focus on it
			else {
				tabContainer.selectChild(tabSubjects[value]);
			}
		}
	});
});
</pre><p>How long would you say this took to write?  Half hour?  Hour? Three hours?  Nope.  This mini-application only took me about 15 minutes to write!  DojoX also features a class for pulling images from Picasa.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/dojo-flickr.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Nice, huh?  Meshing Dojo, Dijit, and DojoX classes is a breeze thanks to Dojo&#8217;s tightly knit class system.  I challenge you to create a simple application and see what you can do in an hour.  Use <a
href="http://download.dojotoolkit.org/release-1.5.0/dojo-release-1.5.0/dijit/themes/themeTester.html">Theme Tester</a> as a helper should you need inspiration!  And always share what you&#8217;ve created when you&#8217;re done!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dojo-flickr">Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/dojo-context-menu' rel='bookmark' title='Permanent Link: Create a Context Menu with Dojo and&nbsp;Dijit'>Create a Context Menu with Dojo and&nbsp;Dijit</a></li><li><a
href='http://davidwalsh.name/dojo-accordion' rel='bookmark' title='Permanent Link: Create a Simple Dojo&nbsp;Accordion'>Create a Simple Dojo&nbsp;Accordion</a></li><li><a
href='http://davidwalsh.name/dojo-dijit-charting' rel='bookmark' title='Permanent Link: Dive Into Dojo Series:  Dijit and&nbsp;Charting'>Dive Into Dojo Series:  Dijit and&nbsp;Charting</a></li><li><a
href='http://davidwalsh.name/dojo-digg' rel='bookmark' title='Permanent Link: Digg-Style Dynamic Share Widget Using the Dojo&nbsp;Toolkit'>Digg-Style Dynamic Share Widget Using the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/dojo-tabs' rel='bookmark' title='Permanent Link: Dijit&#8217;s TabContainer Layout:  Easy Tabbed&nbsp;Content'>Dijit&#8217;s TabContainer Layout:  Easy Tabbed&nbsp;Content</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/dojo-flickr/feed</wfw:commentRss> <slash:comments>3</slash:comments> </item> <item><title>Implement the Google AJAX Search&#160;API</title><link>http://davidwalsh.name/google-ajax-search</link> <comments>http://davidwalsh.name/google-ajax-search#comments</comments> <pubDate>Mon, 02 Aug 2010 14:04:25 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[MooTools]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5020</guid> <description><![CDATA[Let&#8217;s be honest&#8230;WordPress&#8217; search functionality isn&#8217;t great. Let&#8217;s be more honest&#8230;no search functionality is better than Google&#8217;s. Luckily for us, Google provides an awesome method by which we can use their search for our own site: the Google AJAX Search API. Let me show you how to implement this awesome API within your own website! [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/google-ajax-search">Implement the Google AJAX Search&nbsp;API</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/search-options' rel='bookmark' title='Permanent Link: Search Type Options with&nbsp;MooTools'>Search Type Options with&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/dojo-flickr' rel='bookmark' title='Permanent Link: Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit'>Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/google-load' rel='bookmark' title='Permanent Link: google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API'>google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API</a></li><li><a
href='http://davidwalsh.name/ajax-username-availability-checker-mootools' rel='bookmark' title='Permanent Link: AJAX Username Availability Checker Using MooTools&nbsp;1.2'>AJAX Username Availability Checker Using MooTools&nbsp;1.2</a></li><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li></ol>]]></description> <content:encoded><![CDATA[<a
href="http://davidwalsh.name/dw-content/google-ajax-search.php"><img
src="http://davidwalsh.name/dw-content/ajax-search-example.jpg" alt="Google AJAX Search API" /></a><p>Let&#8217;s be honest&#8230;WordPress&#8217; search functionality isn&#8217;t great.  Let&#8217;s be more honest&#8230;no search functionality is better than Google&#8217;s.  Luckily for us, Google provides an awesome method by which we can use their search for our own site:  the Google AJAX Search API.  Let me show you how to implement this awesome API within your own website!</p><div
class="actions"><a
class="demo" href="http://davidwalsh.name/dw-content/google-ajax-search.php">View Demo</a><div
class="clear"></div></div><h2>Sign&nbsp;Up!</h2><p>Google&#8217;s AJAX Search API requires that you <a
href="http://code.google.com/apis/ajaxsearch/key.html">sign up for an API key</a>.  Signing up is free and you&#8217;ll be done with the process of retrieving a key in a few minutes.</p><p><a
href="http://davidwalsh.name/dw-content/google-ajax-search.php"><img
src="http://davidwalsh.name/dw-content/ajax-search-1.jpg" alt="Google AJAX Search API Sign Up" /></a></p><p>You&#8217;ll also need to provide a domain for which they key will work for; one key per domain.</p><h2>The&nbsp;HTML</h2><pre class="html">&lt;!-- SEARCH FORM --&gt;
&lt;form action="http://www.google.com/search" method="get"&gt;
	&lt;!-- HTML5 SEARCH BOX!  --&gt;
	&lt;input type="search" id="search-box" name="q" results="5" placeholder="Search..." autocomplete="on" /&gt;
	&lt;!-- SEARCH davidwalsh.name ONLY! --&gt;
	&lt;input type="hidden" name="sitesearch" value="davidwalsh.name" /&gt;
	&lt;!-- SEARCH BUTTON --&gt;
	&lt;input id="search-submit" type="submit" value="Search" /&gt;
&lt;/form&gt;

&lt;!-- ASYNCHRONOUSLY LOAD THE AJAX SEARCH API;  MOOTOOLS TOO! --&gt;
&lt;script type="text/javascript" src="http://www.google.com/jsapi?key=MY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_KEY"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
	google.load('mootools','1.2.4');
	google.load('search','1');
&lt;/script&gt;</pre><p>You&#8217;ll want to use a &#8220;real&#8221; form so that if the user doesn&#8217;t have JavaScript, they&#8217;ll get directed to Google for their search.  Beyond that, follow the hidden input line to ensure your search will work.  You may also note that the search box has autocomplete and placeholder attributes &#8212; those are HTML5 functionality, nothing to do with Google&#8217;s AJAX Search API.</p><h2>The&nbsp;CSS</h2><pre class="css">/* results positioning */
#search-results		{ position:absolute; z-index:90; top:40px; right:10px; visibility:hidden; }
/* triangle! */
#search-results-pointer { width:0px; height:0px; border-left:20px solid transparent; border-right:20px solid transparent; border-bottom:20px solid #eee; margin-left:80%; }
/* content DIV which holds search results! */
#search-results-content { position:relative; padding:20px; background:#fff; border:3px solid #eee; width:380px; min-height:200px; -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5) }</pre><p>The CSS above simply position the elements where I want them per my design.  I even used a CSS triangle!</p><h2>The&nbsp;JavaScript</h2><pre class="js">window.addEvent('domready',function(){

	/* search */
	var searchBox = $('search-box'), searchLoaded=false, searchFn = function() {

		/*
			We're lazyloading all of the search stuff.
			After all, why create elements, add listeners, etc. if the user never gets there?
		*/
		if(!searchLoaded) {
			searchLoaded = true; //set searchLoaded to "true"; no more loading!

			//build elements!
			var container = new Element('div',{ id: 'search-results' }).inject($('search-area'),'after');
			var wrapper = new Element('div',{
				styles: {
					position: 'relative'
				}
			}).inject(container);
			new Element('div',{ id: 'search-results-pointer' }).inject(wrapper);
			var contentContainer = new Element('div',{ id: 'search-results-content' }).inject(wrapper);
			var closer = new Element('a', {
				href: 'javascript:;',
				text: 'Close',
				styles: {
					position: 'absolute', //position the "Close" link
					bottom: 35,
					right: 20
				},
				events: {
					click: function() {
						container.fade(0);
					}
				}
			}).inject(wrapper);

			//google interaction
			var search = new google.search.WebSearch(),
				control = new google.search.SearchControl(),
				options = new google.search.DrawOptions();

			//set google options
			options.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);
			options.setInput(searchBox);

			//set search options
			search.setUserDefinedClassSuffix('siteSearch');
			search.setSiteRestriction('davidwalsh.name');
			search.setLinkTarget(google.search.Search.LINK_TARGET_SELF);

			//set search controls
			control.addSearcher(search);
			control.draw(contentContainer,options);
			control.setNoResultsString('No results were found.');

			//add listeners to search box
			searchBox.addEvents({
				keyup: function(e) {
					if(searchBox.value &amp;&amp; searchBox.value != searchBox.get('placeholder')) {
						container.fade(0.9);
						control.execute(searchBox.value);
					}
					else {
						container.fade(0);
					}
				}
			});
			searchBox.removeEvent('focus',searchFn);
		}
	};
	searchBox.addEvent('focus',searchFn);
});</pre><p>There&#8217;s a fair amount of JavaScript above so stay with me.  The following are the steps for implementing the Google AJAX API:</p><ul><li>Create an element to house the results of the search.</li><li>Create a &#8220;Close&#8221; link which will allow the user to close the search results window.</li><li>Create our Google-given class instance:<ul><li>A Web Search (you can also create Local Search if you&#8217;d like&#8230;). <a
rel="nofollow" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_class_GwebSearch">google.search.WebSearch options</a>.  I&#8217;ve chosen to add tabs and set the input as my search box.</li><li>A SearchControl instance. <a
rel="nofollow" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_class_GSearchControl">google.search.SearchControl options</a>.  &#8220;siteSearch&#8221; is my suffix for results, I&#8217;ve restricted my search to the davidwalsh.name domain, and form submission will trigger results to display in the current window (instead of a new window).</li><li>A DrawOptions instance. <a
rel="nofollow" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_class_GdrawOptions">google.search.DrawOptions options</a>.  With my DrawOptions instance, I&#8217;ve set search control, set the draw container with the options we&#8217;ve created, and I&#8217;ve decided to use Google&#8217;s default &#8220;no results&#8221; message</li></ul></li></ul><p>Once the search controls are created, it&#8217;s time to attach events to the search box to show and hide the search results container based on the contents of the search box.  That&#8217;s all!</p><p>As you can see, I&#8217;ve chosen to use the MooTools (FTW) JavaScript toolkit to create the element that houses the results, the &#8220;Close&#8221; link, and to bind events to the search box.  You could just as easily use Dojo or jQuery for element creation and even handling.</p><div
class="actions"><a
class="demo" href="http://davidwalsh.name/dw-content/google-ajax-search.php">View Demo</a><div
class="clear"></div></div><p>In all honesty, I couldn&#8217;t believe how easy it was to implement Google AJAX search.  It&#8217;s an easy want to implement search on your website, especially if you&#8217;re currently using WordPress&#8217; search.  I recommend taking the time to implement Google&#8217;s AJAX Search API &#8212; the day it takes you to get it working will save your users hours of pain!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/google-ajax-search">Implement the Google AJAX Search&nbsp;API</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/search-options' rel='bookmark' title='Permanent Link: Search Type Options with&nbsp;MooTools'>Search Type Options with&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/dojo-flickr' rel='bookmark' title='Permanent Link: Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit'>Create a Dynamic Flickr Image Search with the Dojo&nbsp;Toolkit</a></li><li><a
href='http://davidwalsh.name/google-load' rel='bookmark' title='Permanent Link: google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API'>google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API</a></li><li><a
href='http://davidwalsh.name/ajax-username-availability-checker-mootools' rel='bookmark' title='Permanent Link: AJAX Username Availability Checker Using MooTools&nbsp;1.2'>AJAX Username Availability Checker Using MooTools&nbsp;1.2</a></li><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/google-ajax-search/feed</wfw:commentRss> <slash:comments>30</slash:comments> </item> <item><title>AJAX Annoyances to&#160;Avoid</title><link>http://davidwalsh.name/ajax-tips</link> <comments>http://davidwalsh.name/ajax-tips#comments</comments> <pubDate>Fri, 28 May 2010 13:54:58 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[Theory / Ideas]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4973</guid> <description><![CDATA[The AJAX revolution has completely reinvigorated the web. Browsers are working hard to increase the speed of their JavaScript and rendering engines. Web Developers are working as quickly as possible to push the limits of the browsers even further. Users are feeling more entitled by the user experiences provided by AJAX-heavy websites like Facebook. Before [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-tips">AJAX Annoyances to&nbsp;Avoid</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-rules-to-live-by' rel='bookmark' title='Permanent Link: 6 AJAX Rules To Live&nbsp;By'>6 AJAX Rules To Live&nbsp;By</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/ajax-spinner' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;MooTools'>Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/book-review-enterprise-ajax-strategies-building-high-performance-web-applications' rel='bookmark' title='Permanent Link: Book Review:  Enterprise AJAX &#8212; Strategies For Building High Performance Web&nbsp;Applications'>Book Review:  Enterprise AJAX &#8212; Strategies For Building High Performance Web&nbsp;Applications</a></li><li><a
href='http://davidwalsh.name/periodical-ajax-requests-mootools-12' rel='bookmark' title='Permanent Link: Periodical AJAX Requests Using MooTools&nbsp;1.2'>Periodical AJAX Requests Using MooTools&nbsp;1.2</a></li></ol>]]></description> <content:encoded><![CDATA[<p>The AJAX revolution has completely reinvigorated the web.  Browsers are working hard to increase the speed of their JavaScript and rendering engines.  Web Developers are working as quickly as possible to push the limits of the browsers even further.  Users are feeling more entitled by the user experiences provided by AJAX-heavy websites like Facebook.  Before you thrust your website into the world of AJAX, be sure you&#8217;re doing it for the right reasons, otherwise you may run into the following annoyances.</p><h2>Using AJAX Because You&nbsp;Can</h2><p>If using AJAX doesn&#8217;t improve the user experience, there&#8217;s a good chance that using it will cause more harm that good.  There are many behaviors and functionalities you&#8217;ll need to account for (paging, scroll position, &#8220;back button&#8221;, etc.) that the browser traditionally handles.  Add to that things like browser bookmarking and there&#8217;s a good chance that using AJAX may not be the best bet, especially if you don&#8217;t want to put in the development and testing time to ensure that your users wont be led down an unreliable path.</p><h2>Forgetting Scroll&nbsp;Position/Paging</h2><p>A lot of websites now use a cute paging technique that loads more content once you&#8217;ve scrolled down near the bottom of a parent element.  That&#8217;s great and all but if I click a link, click my browser&#8217;s &#8220;Back&#8221; button, and only the first &#8220;page&#8221; of content loads, I&#8217;ll hunt down the site&#8217;s webmaster and shank him.  I&#8217;d rather wait for a full page load than continually need to scroll to the bottom of an element to get back to where I was.</p><h2>Providing No &#8220;Feedback&#8221;&nbsp;Imagery/Message</h2><p>There&#8217;s nothing worse than clicking on a button and &#8230;seeing&#8230;nothing&#8230;happen&#8230;Oh, there it is!  Communicating effectively with your user is paramount to a good user experience.  At least with a new page load the user would see the progress bar light up, the address bar change, and possibly even a different cursor.  If you plan on creating an effective AJAX-powered site, use something like <a
href="http://davidwalsh.name/js/dotter">Dotter</a> or another visual effect to communicate to the user that something is happening.</p><h2>Too Many Things Happening at&nbsp;Once</h2><p>Too frequently do I see AJAX-driven websites that have 100 things happening at once.  If there are a hundred things happening at once, how can you effectively communicate that to the user?  That&#8217;s quite a task.  It may be best to try to chunk requests together to better show your users &#8220;progress-by-volume.&#8221;</p><h2>Have&nbsp;More?</h2><p>I know I&#8217;m missing a few annoyances &#8212; share them!  If brave enough, cite websites that are currently making these mistakes!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-tips">AJAX Annoyances to&nbsp;Avoid</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-rules-to-live-by' rel='bookmark' title='Permanent Link: 6 AJAX Rules To Live&nbsp;By'>6 AJAX Rules To Live&nbsp;By</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/ajax-spinner' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;MooTools'>Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/book-review-enterprise-ajax-strategies-building-high-performance-web-applications' rel='bookmark' title='Permanent Link: Book Review:  Enterprise AJAX &#8212; Strategies For Building High Performance Web&nbsp;Applications'>Book Review:  Enterprise AJAX &#8212; Strategies For Building High Performance Web&nbsp;Applications</a></li><li><a
href='http://davidwalsh.name/periodical-ajax-requests-mootools-12' rel='bookmark' title='Permanent Link: Periodical AJAX Requests Using MooTools&nbsp;1.2'>Periodical AJAX Requests Using MooTools&nbsp;1.2</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/ajax-tips/feed</wfw:commentRss> <slash:comments>13</slash:comments> </item> <item><title>Animated AJAX Record Deletion Using&#160;Dojo</title><link>http://davidwalsh.name/dojo-ajax</link> <comments>http://davidwalsh.name/dojo-ajax#comments</comments> <pubDate>Tue, 11 May 2010 13:38:18 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Dojo]]></category> <category><![CDATA[Markup]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4965</guid> <description><![CDATA[I&#8217;m a huge fan of WordPress&#8217; method of individual article deletion. You click the delete link, the menu item animates red, and the item disappears. Here&#8217;s how to achieve that functionality with Dojo JavaScript. View Demo The PHP &#8211; Content &#38;&#160;Header The following snippet goes at the top of the page: if(isset($_GET['delete'])) { $query = [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dojo-ajax">Animated AJAX Record Deletion Using&nbsp;Dojo</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/animated-ajax-jquery' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;jQuery'>Animated AJAX Record Deletion Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-record-deletion-mootools' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;MooTools'>Animated AJAX Record Deletion Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/link-nudging-dojo' rel='bookmark' title='Permanent Link: Link Nudging Using&nbsp;Dojo'>Link Nudging Using&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/spyjax-dojo' rel='bookmark' title='Permanent Link: Spyjax:  Ajax For Evil Using&nbsp;Dojo'>Spyjax:  Ajax For Evil Using&nbsp;Dojo</a></li></ol>]]></description> <content:encoded><![CDATA[<p>I&#8217;m a huge fan of WordPress&#8217; method of individual article deletion.  You click the delete link, the menu item animates red, and the item disappears.  Here&#8217;s how to achieve that functionality with Dojo JavaScript.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/dojo-ajax-delete.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The PHP &#8211; Content &amp;&nbsp;Header</h2><p>The following snippet goes at the top of the page:</p><pre class="php">
if(isset($_GET['delete'])) {
	$query = 'DELETE FROM my_table WHERE item_id = '.(int)$_GET['delete'];
	$result = mysql_query($query,$link);
}
</pre><p>The following is used to display the records:</p><pre class="php">
$query = 'SELECT * FROM my_table ORDER BY title ASC';
$result = mysql_query($query,$link);
while($row = mysql_fetch_assoc($result)) {
	echo '&lt;div class="record" id="record-',$row['item_id'],'"&gt;
				&lt;a href="?delete=',$row['item_id'],'" class="delete"&gt;Delete&lt;/a&gt;
				&lt;strong&gt;',$row['title'],'&lt;/strong&gt;
			&lt;/div&gt;';
}
</pre><h2>The Dojo Toolkit&nbsp;JavaScript</h2><pre class="js">
dojo.addOnLoad(function() {
	dojo.query('a.delete').connect('onclick',function(e) {
		var a = this;
		dojo.anim(a.parentNode,{
			backgroundColor: '#fb6c6c'
		},300);
		dojo.stopEvent(e);
		dojo.xhr('get',{
			content: {
				ajax: 1
			},
			url: dojo.attr(a,'href'),
			load: function() {
				dojo.anim(a.parentNode,{
					opacity: 0
				},300,null,function() {
					dojo.query(a.parentNode).orphan();
				});
			}
		});
	});
});
</pre><p>For every link, we add a click event that triggers the AJAX request.  During the request, we transition the containing element to a red background.  When the AJAX request returns a &#8220;success&#8221; response, we slide the element off of the screen.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/dojo-ajax-delete.php" class="demo">View Demo</a><div
class="clear"></div></div><p>How would you use this?  Share!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dojo-ajax">Animated AJAX Record Deletion Using&nbsp;Dojo</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/animated-ajax-jquery' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;jQuery'>Animated AJAX Record Deletion Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-record-deletion-mootools' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;MooTools'>Animated AJAX Record Deletion Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/link-nudging-dojo' rel='bookmark' title='Permanent Link: Link Nudging Using&nbsp;Dojo'>Link Nudging Using&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/spyjax-dojo' rel='bookmark' title='Permanent Link: Spyjax:  Ajax For Evil Using&nbsp;Dojo'>Spyjax:  Ajax For Evil Using&nbsp;Dojo</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/dojo-ajax/feed</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>Using Dotter for Form&#160;Submissions</title><link>http://davidwalsh.name/dotter-submit-button</link> <comments>http://davidwalsh.name/dotter-submit-button#comments</comments> <pubDate>Tue, 27 Apr 2010 12:24:15 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[MooTools]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4957</guid> <description><![CDATA[One of the plugins I&#8217;m most proud of is Dotter. Dotter allows you to create the typical &#8220;Loading&#8230;&#8221; text without using animated images. I&#8217;m often asked what a sample usage of Dotter would be; form submission create the perfect situation. The following code changes a submit button&#8217;s text to &#8220;Submitting&#8230;&#8221; (and animated dot patterns) during [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dotter-submit-button">Using Dotter for Form&nbsp;Submissions</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/mootools-dotter' rel='bookmark' title='Permanent Link: Introducing MooTools&nbsp;Dotter'>Introducing MooTools&nbsp;Dotter</a></li><li><a
href='http://davidwalsh.name/disable-submit-button-click' rel='bookmark' title='Permanent Link: Disable Submit Button Upon Form&nbsp;Submission'>Disable Submit Button Upon Form&nbsp;Submission</a></li><li><a
href='http://davidwalsh.name/submit-button-enable' rel='bookmark' title='Permanent Link: Submit Button&nbsp;Enabling'>Submit Button&nbsp;Enabling</a></li><li><a
href='http://davidwalsh.name/php-form-helper-submit-listener' rel='bookmark' title='Permanent Link: PHP Form Helper &#8211; Submit&nbsp;Listener'>PHP Form Helper &#8211; Submit&nbsp;Listener</a></li><li><a
href='http://davidwalsh.name/prevent-early-form-submission-hijacking-enter-key' rel='bookmark' title='Permanent Link: Prevent Early Form Submission by Hijacking the Enter&nbsp;Key'>Prevent Early Form Submission by Hijacking the Enter&nbsp;Key</a></li></ol>]]></description> <content:encoded><![CDATA[<p>One of the plugins I&#8217;m most proud of is Dotter.  Dotter allows you to create the typical &#8220;Loading&#8230;&#8221; text without using animated images.  I&#8217;m often asked what a sample usage of Dotter would be;  form submission create the perfect situation.  The following code changes a submit button&#8217;s text to &#8220;Submitting&#8230;&#8221; (and animated dot patterns) during the submission process, resetting the button text when the AJAX request is complete.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/dotter-demo.php" class="demo">View Demo</a> <a
href="http://mootools.net/forge/p/dotter" class="demo" rel="nofollow">Get Dotter</a><div
class="clear"></div></div><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
window.addEvent('domready',function() {
	/* get elements */
	var submit = document.id('submit'), form = document.id('share-comment');
	/* create Dotter instance */
	var dotter = new Dotter(submit,{
		delay: 200, //character delay
		message: 'Submitting',
		property: 'value'
	});
	/* when the form is submitted */
	form.addEvent('submit',function(e) {
		//stop the event
		e.stop();
		//assuming it's a valid post...
		if(validatePost()) {
			//stop / failure action
			var action = function() {
				dotter.stop();
				submit.set('value','Submit');
			};
			//create an AJAX request
			var request = new Request({
				url: form.get('action'),
				method: form.get('method'),
				link: 'ignore',
				//start the Dotter when the request is sent
				onRequest: function() {
					dotter.start();
				},
				//stop it when the AJAX request is successful
				onSuccess: action,
				//stop it when the AJAX request is failure
				onSuccess: action
			}).send(document.id('share-comment').toQueryString());
			//put the form back!
		}
	});
});
</pre><p>When the form is submitted the Dotter instance begins its animation.  Once the AJAX request is complete (regardless of success or failure), the Dotter is stopped, changing the button text to its original text.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/dotter-demo.php" class="demo">View Demo</a> <a
href="http://mootools.net/forge/p/dotter" class="demo" rel="nofollow">Get Dotter</a><div
class="clear"></div></div><p>There you have it:  a practical, straight-forward usage of MooTools Dotter.  Feel free to <a
href="http://mootools.net/forge/p/dotter" rel="nofollow">download Dotter from the Forge</a> and let me know if you have questions or suggestions!</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/dotter-submit-button">Using Dotter for Form&nbsp;Submissions</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/mootools-dotter' rel='bookmark' title='Permanent Link: Introducing MooTools&nbsp;Dotter'>Introducing MooTools&nbsp;Dotter</a></li><li><a
href='http://davidwalsh.name/disable-submit-button-click' rel='bookmark' title='Permanent Link: Disable Submit Button Upon Form&nbsp;Submission'>Disable Submit Button Upon Form&nbsp;Submission</a></li><li><a
href='http://davidwalsh.name/submit-button-enable' rel='bookmark' title='Permanent Link: Submit Button&nbsp;Enabling'>Submit Button&nbsp;Enabling</a></li><li><a
href='http://davidwalsh.name/php-form-helper-submit-listener' rel='bookmark' title='Permanent Link: PHP Form Helper &#8211; Submit&nbsp;Listener'>PHP Form Helper &#8211; Submit&nbsp;Listener</a></li><li><a
href='http://davidwalsh.name/prevent-early-form-submission-hijacking-enter-key' rel='bookmark' title='Permanent Link: Prevent Early Form Submission by Hijacking the Enter&nbsp;Key'>Prevent Early Form Submission by Hijacking the Enter&nbsp;Key</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/dotter-submit-button/feed</wfw:commentRss> <slash:comments>13</slash:comments> </item> <item><title>Record Text Selections Using MooTools or jQuery&#160;AJAX</title><link>http://davidwalsh.name/text-selection-ajax</link> <comments>http://davidwalsh.name/text-selection-ajax#comments</comments> <pubDate>Tue, 03 Nov 2009 14:16:56 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=4010</guid> <description><![CDATA[One technique I&#8217;m seeing more and more these days (CNNSI.com, for example) is AJAX recording of selected text. It makes sense &#8212; if you detect users selecting the terms over and over again, you can probably assume your visitors are searching that term on Google, Yahoo, etc. I&#8217;ve duplicated this functionality using my favorite JavaScript [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/text-selection-ajax">Record Text Selections Using MooTools or jQuery&nbsp;AJAX</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/text-select-widget' rel='bookmark' title='Permanent Link: New York Times-Style Text Selection Widget Using MooTools or&nbsp;jQuery'>New York Times-Style Text Selection Widget Using MooTools or&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-jquery' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;jQuery'>Animated AJAX Record Deletion Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-record-deletion-mootools' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;MooTools'>Animated AJAX Record Deletion Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/broken-images-jquery-ajax' rel='bookmark' title='Permanent Link: Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX'>Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX</a></li></ol>]]></description> <content:encoded><![CDATA[<p>One technique I&#8217;m seeing more and more these days (CNNSI.com, for example) is AJAX recording of selected text.  It makes sense &#8212; if you detect users selecting the terms over and over again, you can probably assume your visitors are searching that term on Google, Yahoo, etc.  I&#8217;ve duplicated this functionality using my favorite JavaScript library, MooTools, and another JavaScript library, jQuery.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/ajax-selection-copy.php" class="demo">View MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/ajax-selection-copy.php?library=jquery" class="demo">View jQuery Demo</a><div
class="clear"></div></div><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
window.addEvent('domready',function(){
	//gets the selected text
	var getSelection = function() {
		return $try(
			function() { return window.getSelection(); },
			function() { return document.getSelection(); },
			function() { 
					var selection = document.selection &#038;&#038; document.selection.createRange();
					if(selection.text) { return selection.text; }
					return false;
		      }
		) || false;
	};
	//event to listen
	var selectRequest = new Request({
		url: 'ajax-selection-copy.php',
		method: 'post'
	});
	$('content-area').addEvent('mouseup',function(e) {
		var selection = getSelection();
		if(selection &amp;&amp; (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
			selectRequest.send('selection=' + encodeURI(selection));
		}
	});
});
</pre><p>The first step is attempting to grab the selected text during the <span
class="param	">mouseup</span> within our designated container.  If we find a text selection we fire an AJAX request to a PHP script which will save the text selection.</p><h2>The jQuery&nbsp;JavaScript</h2><pre class="js">
/* attempt to find a text selection */
function getSelected() {
	if(window.getSelection) { return window.getSelection(); }
	else if(document.getSelection) { return document.getSelection(); }
	else {
		var selection = document.selection &#038;&#038; document.selection.createRange();
		if(selection.text) { return selection.text; }
		return false;
	}
	return false;
}
/* create sniffer */
$(document).ready(function() {
	$('#content-area').mouseup(function() {
		var selection = getSelected();
		if(selection &amp;&amp; (selection = new String(selection).replace(/^\s+|\s+$/g,''))) {
			$.ajax({
				type: 'post',
				url: 'ajax-selection-copy.php',
				data: 'selection=' + encodeURI(selection)
			});
		}
	});
});
</pre><p>The MooTools code translated to jQuery.</p><h2>The&nbsp;PHP</h2><pre class="php">
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &amp;&amp; strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' &amp;&amp; $selection = trim($_POST['selection'])) {
	mysql_query('INSERT INTO text_selections (selection,date_selected) VALUES(\''.mysql_escape_string(stripslashes($selection)).'\',NOW())');
}
</pre><p>The above PHP code is very primitive.  Depending on the setup of your system (PHP Framework, security settings, etc.) you will want to implement additional measures to prevent attacks on this script.</p><div
class="actions"> <a
href="http://davidwalsh.name/dw-content/ajax-selection-copy.php" class="demo">View MooTools Demo</a> <a
href="http://davidwalsh.name/dw-content/ajax-selection-copy.php?library=jquery" class="demo">View jQuery Demo</a><div
class="clear"></div></div><p>Recording text selections is a great way to discover what topics and/or terms your audience is interested in.  You may also want to provide more information on these terms within posts.</p><p>What are your thoughts on this?  Do you think this is too much like <a
href="http://davidwalsh.name/ajax-evil-spyjax">Spyjax</a>?  Perfectly OK?</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/text-selection-ajax">Record Text Selections Using MooTools or jQuery&nbsp;AJAX</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/text-select-widget' rel='bookmark' title='Permanent Link: New York Times-Style Text Selection Widget Using MooTools or&nbsp;jQuery'>New York Times-Style Text Selection Widget Using MooTools or&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-jquery' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;jQuery'>Animated AJAX Record Deletion Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/animated-ajax-record-deletion-mootools' rel='bookmark' title='Permanent Link: Animated AJAX Record Deletion Using&nbsp;MooTools'>Animated AJAX Record Deletion Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/broken-images-jquery-ajax' rel='bookmark' title='Permanent Link: Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX'>Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/text-selection-ajax/feed</wfw:commentRss> <slash:comments>22</slash:comments> </item> <item><title>Form Element AJAX Spinner Attachment Using&#160;jQuery</title><link>http://davidwalsh.name/ajax-spinner-jquery</link> <comments>http://davidwalsh.name/ajax-spinner-jquery#comments</comments> <pubDate>Fri, 16 Oct 2009 12:49:34 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[Usability / Accessibility]]></category> <category><![CDATA[jQuery]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=3740</guid> <description><![CDATA[Yesterday I showed you how to attach an AJAX spinner next to a form element using my beloved MooTools. Today I&#8217;ll show you how to implement that same functionality using jQuery. View Demo The&#160;XHTML &#60;select class="ajax"&#62; &#60;option value=""&#62;-- Select a Site--&#60;/option&#62; &#60;option value="David Walsh Blog"&#62;David Walsh Blog&#60;/option&#62; &#60;option value="Script &#38; Style"&#62;Script &#38; Style&#60;/option&#62; &#60;option value="Band [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-spinner-jquery">Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-spinner' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;MooTools'>Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/noscript-compatible-select-form-element-onchange-event' rel='bookmark' title='Permanent Link: Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event'>Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event</a></li><li><a
href='http://davidwalsh.name/print-select-options' rel='bookmark' title='Permanent Link: Select Dropdowns, MooTools, and CSS&nbsp;Print'>Select Dropdowns, MooTools, and CSS&nbsp;Print</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/broken-images-jquery-ajax' rel='bookmark' title='Permanent Link: Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX'>Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX</a></li></ol>]]></description> <content:encoded><![CDATA[<p>Yesterday I showed you how to <a
href="http://davidwalsh.name/ajax-spinner">attach an AJAX spinner next to a form element using my beloved MooTools</a>.  Today I&#8217;ll show you how to implement that same functionality using jQuery.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/ajax-request-spinner.php?jquery" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;XHTML</h2><pre class="html">
&lt;select class="ajax"&gt;
	&lt;option value=""&gt;-- Select a Site--&lt;/option&gt;
	&lt;option value="David Walsh Blog"&gt;David Walsh Blog&lt;/option&gt;
	&lt;option value="Script &amp; Style"&gt;Script &amp; Style&lt;/option&gt;
	&lt;option value="Band Website Template"&gt;Band Website Template&lt;/option&gt;
&lt;/select&gt;

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

&lt;input type="text" id="my-text" class="ajax" /&gt;
</pre><p>Elements with the &#8220;ajax&#8221; CSS class will be our target.</p><h2>The jQuery&nbsp;JavaScript</h2><pre class="js">
$(document).ready(function() {
	//create image
	$('&lt;img src="move-spinner.gif" id="spinner" /&gt;').css('position','absolute').hide().appendTo('body');
	//for every field change
	$('.ajax').change(function() {
		//get element position
		var position = $(this).offset();
		//position image
		$('#spinner').css({ top: position.top , left: position.left + $(this).width() + 30 }).fadeIn();
		//ajax
		$.post('&lt;?php echo $_SERVER['REQUEST_URI']; ?&gt;',{
			ajax:1,
			value: $(this).val()
		},function() {
			$('#spinner').fadeOut();
		});
	});
});
</pre><p>We inject the spinner image into the page and reposition it depending on which field is doing the request.  Very simple!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/ajax-request-spinner.php?jquery" class="demo">View Demo</a><div
class="clear"></div></div><p>Isn&#8217;t JavaScript fun?  Oh yeah&#8230;and it makes the user experience better too.</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-spinner-jquery">Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-spinner' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;MooTools'>Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></li><li><a
href='http://davidwalsh.name/noscript-compatible-select-form-element-onchange-event' rel='bookmark' title='Permanent Link: Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event'>Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event</a></li><li><a
href='http://davidwalsh.name/print-select-options' rel='bookmark' title='Permanent Link: Select Dropdowns, MooTools, and CSS&nbsp;Print'>Select Dropdowns, MooTools, and CSS&nbsp;Print</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/broken-images-jquery-ajax' rel='bookmark' title='Permanent Link: Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX'>Send Email Notifications for Broken Images Using jQuery&nbsp;AJAX</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/ajax-spinner-jquery/feed</wfw:commentRss> <slash:comments>12</slash:comments> </item> <item><title>Form Element AJAX Spinner Attachment Using&#160;MooTools</title><link>http://davidwalsh.name/ajax-spinner</link> <comments>http://davidwalsh.name/ajax-spinner#comments</comments> <pubDate>Thu, 15 Oct 2009 13:12:02 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[CSS]]></category> <category><![CDATA[Markup]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[Usability / Accessibility]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=3732</guid> <description><![CDATA[Many times you&#8217;ll see a form dynamically change available values based on the value of a form field. For example, a &#8220;State&#8221; field will change based on which Country a user selects. What annoys me about these forms is that they&#8217;ll often do an AJAX request to grab the states but wont show any indicator [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-spinner">Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/noscript-compatible-select-form-element-onchange-event' rel='bookmark' title='Permanent Link: Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event'>Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event</a></li><li><a
href='http://davidwalsh.name/print-select-options' rel='bookmark' title='Permanent Link: Select Dropdowns, MooTools, and CSS&nbsp;Print'>Select Dropdowns, MooTools, and CSS&nbsp;Print</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/dotter-submit-button' rel='bookmark' title='Permanent Link: Using Dotter for Form&nbsp;Submissions'>Using Dotter for Form&nbsp;Submissions</a></li></ol>]]></description> <content:encoded><![CDATA[<p>Many times you&#8217;ll see a form dynamically change available values based on the value of a form field.  For example, a &#8220;State&#8221; field will change based on which Country a user selects.  What annoys me about these forms is that they&#8217;ll often do an AJAX request to grab the states but wont show any indicator to the user that something is happening.  We&#8217;re going to use MooTools to add an AJAX spinner image next to form fields that perform such AJAX requests.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/ajax-request-spinner.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;XHTML</h2><pre class="html">
&lt;select class="ajax"&gt;
	&lt;option value=""&gt;-- Select a Site--&lt;/option&gt;
	&lt;option value="David Walsh Blog"&gt;David Walsh Blog&lt;/option&gt;
	&lt;option value="Script &amp; Style"&gt;Script &amp; Style&lt;/option&gt;
	&lt;option value="Band Website Template"&gt;Band Website Template&lt;/option&gt;
&lt;/select&gt;

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

&lt;input type="text" id="my-text" class="ajax" /&gt;
</pre><p>Add the &#8220;ajax&#8221; class (or any class for that matter) to the elements you&#8217;d like the spinner to display by.</p><h2>The MooTools&nbsp;JavaScript</h2><pre class="js">
window.addEvent('domready',function() {
	//inject image
	var spinner = new Element('img',{
		src: 'move-spinner.gif',
		styles: {
			position:'absolute'
		},
		opacity: 0
	}).inject(document.body);
	//form element events
	$$('.ajax').each(function(el) {
		//get coordinates
		var coords = el.getCoordinates(document.body);
		//ajax request object
		var request = new Request({
			url: '<?php echo $_SERVER['REQUEST_URI']; ?>',
			method: 'post',
			onRequest: function() {
				spinner.setStyles({
					left: coords.right + 10,
					top: coords.top + 5
				}).fade('in');
			},
			onComplete: function() {
				spinner.fade('out');
			}
		});
		//change event
		el.addEvent('change',function() {
			//ajax request
			request.send({
				data: {
					ajax: 1,
					value: el.get('value')
				}
			});
		});
	});
});
</pre><p>We first add the spinner image to the document but hide it right away.  When any of the form elements with the &#8220;ajax&#8221; class changes value, we move the spinner image to the right of the element.  Then we use Reqeust&#8217;s onRequest and onComplete methods to show and hide the spinner.  Simple!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/ajax-request-spinner.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Look forward to a jQuery version tomorrow.</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/ajax-spinner">Form Element AJAX Spinner Attachment Using&nbsp;MooTools</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/ajax-spinner-jquery' rel='bookmark' title='Permanent Link: Form Element AJAX Spinner Attachment Using&nbsp;jQuery'>Form Element AJAX Spinner Attachment Using&nbsp;jQuery</a></li><li><a
href='http://davidwalsh.name/noscript-compatible-select-form-element-onchange-event' rel='bookmark' title='Permanent Link: Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event'>Create a NoScript Compatible Select Form Element with an onChange&nbsp;Event</a></li><li><a
href='http://davidwalsh.name/print-select-options' rel='bookmark' title='Permanent Link: Select Dropdowns, MooTools, and CSS&nbsp;Print'>Select Dropdowns, MooTools, and CSS&nbsp;Print</a></li><li><a
href='http://davidwalsh.name/twitter-button' rel='bookmark' title='Permanent Link: Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo'>Create a Twitter AJAX Button with MooTools, jQuery, or&nbsp;Dojo</a></li><li><a
href='http://davidwalsh.name/dotter-submit-button' rel='bookmark' title='Permanent Link: Using Dotter for Form&nbsp;Submissions'>Using Dotter for Form&nbsp;Submissions</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/ajax-spinner/feed</wfw:commentRss> <slash:comments>9</slash:comments> </item> <item><title>Remotely Download Google AJAX Libraries Using&#160;PHP</title><link>http://davidwalsh.name/download-google-ajax-libraries</link> <comments>http://davidwalsh.name/download-google-ajax-libraries#comments</comments> <pubDate>Wed, 30 Sep 2009 12:25:07 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[AJAX]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=3757</guid> <description><![CDATA[I don&#8217;t know how to use all of the JavaScript libraries but perusing their code is interesting. If I&#8217;m looking to code something I&#8217;ll look at how each of the other libraries accomplishes the task. The problem is that you need to go out and download each one. And of course they&#8217;re all on different [...]<p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/download-google-ajax-libraries">Remotely Download Google AJAX Libraries Using&nbsp;PHP</a></p>Related posts:<ol><li><a
href='http://davidwalsh.name/google-load' rel='bookmark' title='Permanent Link: google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API'>google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API</a></li><li><a
href='http://davidwalsh.name/detect-ajax' rel='bookmark' title='Permanent Link: Detect an AJAX Request in&nbsp;PHP'>Detect an AJAX Request in&nbsp;PHP</a></li><li><a
href='http://davidwalsh.name/google-ajax-search' rel='bookmark' title='Permanent Link: Implement the Google AJAX Search&nbsp;API'>Implement the Google AJAX Search&nbsp;API</a></li><li><a
href='http://davidwalsh.name/google-fonts-api' rel='bookmark' title='Permanent Link: Google Font&nbsp;API'>Google Font&nbsp;API</a></li><li><a
href='http://davidwalsh.name/download-urls-content-php-curl' rel='bookmark' title='Permanent Link: Download a URL&#8217;s Content Using PHP&nbsp;cURL'>Download a URL&#8217;s Content Using PHP&nbsp;cURL</a></li></ol>]]></description> <content:encoded><![CDATA[<p>I don&#8217;t know how to use all of the JavaScript libraries but perusing their code is interesting.   If I&#8217;m looking to code something I&#8217;ll look at how each of the other libraries accomplishes the task.  The problem is that you need to go out and download each one.  And of course they&#8217;re all on different development schedules so you&#8217;d also need to make sure to grab the latest version of the library.  Instead of manually accomplishing that task, I&#8217;ve chosen create a script that does all of that for me.</p><h2>The&nbsp;PHP</h2><pre class="php">//settings
$dir = 'js-libs/';
$url = 'http://code.google.com/apis/ajaxlibs/documentation/index.html';

//open file
$content = get_content($url);
echo 'Retrieved page from Google.';

//parse
$regex = '/http:\/\/ajax.googleapis.com\/ajax\/libs\/.*.js/isU';

//match?
preg_match_all($regex,$content,$matches);

//make sure there are no repeated files
$js_files = array_unique($matches[0]);

//download every file and save locally
foreach($js_files as $file) {
	//download
	$content = get_content($file);
	//save
	$filename = str_replace(array('http://ajax.googleapis.com/ajax/libs/','/'),array('','-'),$file);
	file_put_contents($dir.$filename,$content);
	//
	echo 'saving ',$file;
}

//function to grab content from a url
function get_content($url) {
	$ch = curl_init();
	curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13');
	curl_setopt($ch,CURLOPT_URL,$url);
	curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
	curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,5);
	$content = curl_exec($ch);
	curl_close($ch);
	return $content;
}</pre><p>Pow!  One quick script to get you all of the popular JavaScript libraries in 10 seconds.  You may not know how to use each library but it sure doesn&#8217;t hurt to have them around.</p><p><strong>Follow Me!</strong> <a
href="http://twitter.com/davidwalshblog">Twitter</a> | <a
href="http://www.facebook.com/#!/pages/David-Walsh-Blog/186644584869">Facebook</a> | <a
href="http://www.linkedin.com/in/davidjameswalsh">LinkedIn</a> | <a
href="http://mootools.net/forge/profile/davidwalsh">MooTools Forge.</a><br/><br/>Full David Walsh Blog Post: <a
href="http://davidwalsh.name/download-google-ajax-libraries">Remotely Download Google AJAX Libraries Using&nbsp;PHP</a></p><p>Related posts:<ol><li><a
href='http://davidwalsh.name/google-load' rel='bookmark' title='Permanent Link: google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API'>google.load():  Utilize Google&#8217;s AJAX Libraries&nbsp;API</a></li><li><a
href='http://davidwalsh.name/detect-ajax' rel='bookmark' title='Permanent Link: Detect an AJAX Request in&nbsp;PHP'>Detect an AJAX Request in&nbsp;PHP</a></li><li><a
href='http://davidwalsh.name/google-ajax-search' rel='bookmark' title='Permanent Link: Implement the Google AJAX Search&nbsp;API'>Implement the Google AJAX Search&nbsp;API</a></li><li><a
href='http://davidwalsh.name/google-fonts-api' rel='bookmark' title='Permanent Link: Google Font&nbsp;API'>Google Font&nbsp;API</a></li><li><a
href='http://davidwalsh.name/download-urls-content-php-curl' rel='bookmark' title='Permanent Link: Download a URL&#8217;s Content Using PHP&nbsp;cURL'>Download a URL&#8217;s Content Using PHP&nbsp;cURL</a></li></ol></p>]]></content:encoded> <wfw:commentRss>http://davidwalsh.name/download-google-ajax-libraries/feed</wfw:commentRss> <slash:comments>7</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced) (user agent is rejected)
Database Caching 134/362 queries in 8.261 seconds using disk

Served from: davidwalsh.name @ 2010-09-02 23:25:59 -->