<?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; Google</title> <atom:link href="http://davidwalsh.name/tutorials/google/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>Thoughts on&#160;Google+</title><link>http://davidwalsh.name/google-plus</link> <comments>http://davidwalsh.name/google-plus#comments</comments> <pubDate>Mon, 11 Jul 2011 15:52:59 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5264</guid> <description><![CDATA[It&#8217;s been a few weeks now since Google+ has hit the scene and and I&#8217;ve had a good amount of time to play with it.  The following are some unorganized thoughts about Google+: The joke about &#8220;Google finally hired a designer&#8221; is old but true &#8212; the new design looks simplistic but elegant. When I [...]<p><a
href="http://davidwalsh.name/google-plus">Thoughts on&nbsp;Google+</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>It&#8217;s been a few weeks now since Google+ has hit the scene and and I&#8217;ve had a good amount of time to play with it.  The following are some unorganized thoughts about Google+:</p><ul><li>The joke about &#8220;Google finally hired a designer&#8221; is old but true &#8212; the new design looks simplistic but elegant.</li><li>When I mentioned I had invites to give away, I assumed I&#8217;d get anywhere from 80  to 120 requests.  I&#8217;ve gotten well over 1,200 now.  That speaks to how much buzz there&#8217;s been about this new service within the web development world.  Quite impressive.</li><li>From the start, the service just felt like it would be more useful than Wave.  I anticipate G+ will stick.</li><li>I see this app as a direct competitor to Facebook but not so much to Twitter.  The appeal of Twitter&#8217;s 140 character limit will never get old.</li><li>Facebook&#8217;s saving grace is that its user base is already massive, and non-techies wont care to adopt G+.  Where Google has an advantage over other community builders is the number of GMail and Google Apps users that will stumble upon G+.</li><li>&#8220;Circles&#8221; instead of &#8220;lists&#8221; is just a fancy term, but they seem more pronounced on G+.  The nice &#8220;Add to circles&#8221; mouseover effect reinforces that.  As someone who likes his information organized, this feature pleases me quite a bit.</li><li>LOL at &#8220;Sparks.&#8221;  Those will last a month.</li><li>Profile pages are a billion times cleaner than Facebook&#8217;s profile pages;  with Facebook, there&#8217;s way too much going on.</li><li>The photo upload feature and display system are pretty sweet from start to finish.  From photo drag/drop upload, to live progress bars, to all of the great mouseover effects, G+ is able to utilize a lot of HTML5/CSS3 features without becoming a major turn-off.  Well done to them.</li><li>I realize that services like Facebook Places and Foursquare are popular, but check-in features are a surefire way to annoy the hell out of me and clog up my feed with crap.</li><li>The long-polling (and probably future WebSocket) technology Google uses makes their app seem lightning fast.  Probably difficult to construct the system but well worth it for all G+ users.</li><li>I love the stream&#8217;s auto-fit-width and height.  Loved it on Google Image search, love it here.  Comment bubbles are a nice touch too.</li><li>I don&#8217;t see a way to change a photo album&#8217;s name.  Lame.</li><li>I&#8217;m hoping that Google implements friendly links by username instead of the horrendously long profile URLs.  I&#8217;d much prefer &#8220;/davidwalsh83&#8243; to &#8220;/114538814489633467974&#8243;.  Maybe that would too easily expose email address handles though?</li><li>I don&#8217;t use Facebook&#8217;s &#8220;Like&#8221; very much, so I don&#8217;t anticipate using &#8220;+1&#8243; much either.</li><li>Johnathan Snook made some really good points about <a
href="https://plus.google.com/101231306660961225805/posts">G+&#8217;s focus styles</a>.  Google&#8217;s done a great job with them but could probably do better.</li><li>The small &#8220;Send an Email&#8221; feature is quite nice.  No need to jump into Gmail, no need for access to direct email address.</li><li>Profile editing somehow manages to stay elegant and organized despite being a one-page, inline process.</li><li>The real test is when Google creates an API for G+;  can G+ stay clean and organized then too?  Or will G+ turn into a Facebook Farmville mess?</li></ul><p>Those are my thoughts on Google+.  What do you think about G+?</p><p><a
href="http://davidwalsh.name/google-plus">Thoughts on&nbsp;Google+</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/google-plus/feed</wfw:commentRss> <slash:comments>19</slash:comments> </item> <item><title>Create a Google+ Mac App for Your&#160;Dock</title><link>http://davidwalsh.name/google-app</link> <comments>http://davidwalsh.name/google-app#comments</comments> <pubDate>Tue, 05 Jul 2011 18:13:19 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5263</guid> <description><![CDATA[If you follow me on Twitter, you know that Google+ is my new tech porn.  Google+ is the same technological marvel we&#8217;ve come to expect from Google apps, but the elegant but still simplistic design is a welcomed change from Google.  I want to get used to using Google+ but I don&#8217;t want to be conscious of [...]<p><a
href="http://davidwalsh.name/google-app">Create a Google+ Mac App for Your&nbsp;Dock</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[<img
src="http://davidwalsh.name/dw-content/googleDock.png" alt="Google Plus Icon" class="image" /><p>If you <a
href="http://twitter.com/davidwalshblog">follow me on Twitter</a>, you know that Google+ is my new tech porn.  Google+ is the same technological marvel we&#8217;ve come to expect from Google apps, but the elegant but still simplistic design is a welcomed change from Google.  I want to get used to using Google+ but I don&#8217;t want to be conscious of keeping the tab open in Chrome.  Luckily MooTools developer Olmo Maldonado shared a slick method creating a custom Google+ app without the need for Fluid, and you can place the app in your dock for easy access!</p><p><em>This technique would allow you to create an app for any website, but the focus of this post will be Google+.  You could use Fluid.app for this, but the technique presented here allows for avoid Fluid.app.</em></p><h2>Grab the Google+&nbsp;Logo</h2><p>Download the following Google+ logo to the Downloads directory of your computer:</p><p><img
src="http://davidwalsh.name/dw-content/googleplus-icon.png" alt="Google Plus Icon" /></p><p>This logo will be used as the application and dock logo.</p><h2>Download and Execute&nbsp;makeapp.sh</h2><p>There&#8217;s an outstanding <a
href="http://lifehacker.com/5611711/create-application-shortcuts-in-google-chrome-for-mac-with-a-shell-script" rel="nofollow">script available on LifeHacker</a> which provides the user a trio of simple prompts and creates an app based on the input.  Behind the scenes, <code>makeapp.sh</code> copies Google&#8217;s Chrome and creates separate settings paths (for cookie and history separation).  With those created, an executable is created which opens the Chrome copy to the Google+ url.</p><p>Run the script from command line with:</p><pre class="shell">
chmod +x ./makeapp.sh &#038;&#038; ./makeapp.sh
</pre><p>The script will ask you for three arguments;  provide the following:</p><ul><li>Application name:  Google+</li><li>Web URL:  <a
href="http://plus.google.com/" rel="nofollow">http://plus.google.com/</a></li><li>Icon Location:  <code>/Users/{yourUserName}/Downloads/googleplus-icon.png</code></li></ul><p><img
src="http://davidwalsh.name/dw-content/googleplusbrowser.png" alt="Google Plus Browser" /></p><p>Now open your applications folder and you&#8217;ll see a new app called Google+!  Drag the app icon to the dock and now you have a Google+ app in your dock!  The separate history and cookie pool is important so that your traditional Chrome install doesn&#8217;t muck with your Google+ app&#8217;s information, and visa versa.  Have fun with Google+!</p><p><a
href="http://davidwalsh.name/google-app">Create a Google+ Mac App for Your&nbsp;Dock</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/google-app/feed</wfw:commentRss> <slash:comments>17</slash:comments> </item> <item><title>Add a Google+1 Badge to Your&#160;Website</title><link>http://davidwalsh.name/google-plus-badge</link> <comments>http://davidwalsh.name/google-plus-badge#comments</comments> <pubDate>Thu, 30 Jun 2011 22:47:17 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[APIs]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Markup]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5261</guid> <description><![CDATA[Google&#8217;s new Google+ service is taking the development world by storm, and why shouldn&#8217;t it?  It&#8217;s minimalistic UI, use of cutting edge web techniques, and overall usability make it Google+ one of the more impressive web applications I&#8217;ve seen in quite a while (I was going to say &#8220;since Google Wave&#8221;, but that one didn&#8217;t [...]<p><a
href="http://davidwalsh.name/google-plus-badge">Add a Google+1 Badge to Your&nbsp;Website</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[<img
src="http://davidwalsh.name/dw-content/plusOneLogo.png" alt="Google+ Badge" class="image" /><p>Google&#8217;s new Google+ service is taking the development world by storm, and why shouldn&#8217;t it?  It&#8217;s minimalistic UI, use of cutting edge web techniques, and overall usability make it Google+ one of the more impressive web applications I&#8217;ve seen in quite a while <em>(I was going to say &#8220;since Google Wave&#8221;, but that one didn&#8217;t end up well, did it?)</em> Google+ allows you to share photos, links, statuses, and much more;  consider it a mesh between Twitter and Facebook.</p><p>Google+ will only gain more traction, meaning that the information we share will be pushed to more and more people.  This presents an excellent opportunity to promote our websites, much in the way that Twitter and Facebook have.  Let me show you a few different ways to add the new Google+1 badge to your website.</p><h2>The Simple&nbsp;HTML</h2><p>Adding a Google+1 badge is as easy as adding a few HTML tags:</p><pre class="html">
&lt;!-- one button, uses canonical link or current URL --&gt;
&lt;g:plusone&gt;&lt;/g:plusone&gt;

&lt;!-- customized for a specific address --&gt;
&lt;g:plusone href="http://davidwalsh.name/google-plus-badge"&gt;&lt;/g:plusone&gt;

&lt;!-- include the JS file --&gt;
&lt;script src="https://apis.google.com/js/plusone.js"&gt;&lt;/script&gt;
</pre><p>Provide the <code>g:plusone</code> tag the URL to share via the <code>HREF</code> attribute <em>(if none is provided, the page&#8217;s <a
href="http://davidwalsh.name/canonical-link-rel">canonical link</a> will be searched for and used, otherwise the current URL is used)</em> and the desired size of button via the size attribute.  This tag should be added wherever within the page that you&#8217;d like the button to appear;  the SCRIPT tag should be found at the bottom of the page.  If you&#8217;d prefer not to dabble with the HTML yourself, Google provides a <a
href="http://www.google.com/intl/en/webmasters/+1/button/index.html">Google+1 button builder</a> to do the dirty work for you.  Four button sizes are currently offered.</p><p>You could also use the following HTML5 code to render your button:</p><pre class="html">
&lt;div class="g-plusone" data-size="standard" data-count="true"&gt;&lt;/div&gt;
</pre><p>Your button must have the <code>g-plusone</code> CSS class and <code>data-</code> attributes for options.</p><h2>Deferring&nbsp;Loading</h2><p>The HTML code above will render with the rest of the page, but what if you want to render a button on your own schedule?  No worries &#8212; Google&#8217;s API allows you to render buttons whenever you&#8217;d like:</p><pre class="html">
&lt;!-- one button, uses canonical link or current URL --&gt;
&lt;g:plusone&gt;&lt;/g:plusone&gt;

&lt;!-- Place this tag in your head or just before your close body tag --&gt;
&lt;script src="https://apis.google.com/js/plusone.js"&gt;
  {parsetags: 'explicit'}
&lt;/script&gt;

&lt;!-- Now render! --&gt;
&lt;script&gt;
	gapi.plusone.go();
&lt;/script&gt;
</pre><p>Using <code>{parsetags: 'explicit'}</code> and <code>gapi.plusone.go()</code> will turn your <code>g:plusone</code> tags into badges whenever you&#8217;d like.  You can also render a specific button with the following JavaScript code:</p><pre class="js">
&lt;script type="text/javascript" src="https://apis.google.com/js/plusone.js"&gt;
	{"parsetags": "explicit"}
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
	function renderPlusone() {
		gapi.plusone.render("plusone-div");
	}
&lt;/script&gt;
&lt;body&gt;
	&lt;a href="#" onClick="renderPlusone();"&gt;Render the +1 button&lt;/a&gt;
	&lt;div id="plusone-div"&gt;&lt;/div&gt;
&lt;/body&gt;
</pre><p>Full API information as well as an introductory video is <a
href="http://code.google.com/apis/+1button/">available here</a>.  There are a few more small customization options available so check them out if you&#8217;re looking to specify language or play with custom rendering.</p><p>Don&#8217;t miss out on another avenue for sharing your awesome web content with everyone!  Implementing Twitter, Facebook, and Google+1 sharing buttons takes 5 minutes but the amount of traffic you can gain via these referral avenues is tremendous!</p><p><a
href="http://davidwalsh.name/google-plus-badge">Add a Google+1 Badge to Your&nbsp;Website</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/google-plus-badge/feed</wfw:commentRss> <slash:comments>26</slash:comments> </item> <item><title>Google+&#160;Invites</title><link>http://davidwalsh.name/google-invites</link> <comments>http://davidwalsh.name/google-invites#comments</comments> <pubDate>Thu, 30 Jun 2011 02:03:46 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5259</guid> <description><![CDATA[Whenever I get an invite to a hot new web app, I feel like Charlie when he got the golden ticket.  Obviously I&#8217;m easy to impress, but I&#8217;m sure some of you may be too.  I could just give them to whoever asks, but that&#8217;s far too easy.  And if I&#8217;m honest, far too boring [...]<p><a
href="http://davidwalsh.name/google-invites">Google+&nbsp;Invites</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><img
src="http://davidwalsh.name/dw-content/googlePlus.png" alt="Google Plus" /></p><p>Whenever I get an invite to a hot new web app, I feel like Charlie when he got the golden ticket.  Obviously I&#8217;m easy to impress, but I&#8217;m sure some of you may be too.  I could just give them to whoever asks, but that&#8217;s far too easy.  And if I&#8217;m honest, far too boring for me.  When Google Wave came out, I ran a contest where I made users post their favorite picture of Christina Ricci in order to get an invite.  It was, in a word, <em>glorious</em>.</p><p>Now I have a bunch of Google+ invites.  This time I&#8217;m going to ask you to <strong>post a photo of your favorite actor/actress followed by &#8220;{actorName} FTW!&#8221;</strong>.  It appears that I have 500 invites so have at it and you&#8217;ll likely get one!  <strong>Don&#8217;t forget to add your Google handle so I can add you</strong>!</p><p><a
href="http://davidwalsh.name/google-invites">Google+&nbsp;Invites</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/google-invites/feed</wfw:commentRss> <slash:comments>1475</slash:comments> </item> <item><title>Edge &amp; Mobile&#160;Browsers</title><link>http://davidwalsh.name/edge-mobile-browsers</link> <comments>http://davidwalsh.name/edge-mobile-browsers#comments</comments> <pubDate>Mon, 20 Jun 2011 14:29:03 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Browsers]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[Microsoft]]></category> <category><![CDATA[Mobile]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5247</guid> <description><![CDATA[From a developer&#8217;s perspective, the Web is moving faster than ever. Thanks to reinvigorated browser vendors, frequent releases of new mobile devices, and our own need for better APIs and tools, we&#8217;re seeing loads of movement across each platform. Since browser venders like Mozilla, Chrome, Safari, Internet Explorer, and Opera know we need the ability [...]<p><a
href="http://davidwalsh.name/edge-mobile-browsers">Edge &#038; Mobile&nbsp;Browsers</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[<img
src="http://davidwalsh.name/dw-content/my-browsers.png" alt="Web Browsers" class="image" /><p>From a developer&#8217;s perspective, the Web is moving faster than ever.  Thanks to reinvigorated browser vendors, frequent releases of new mobile devices, and our own need for better APIs and tools, we&#8217;re seeing loads of movement across each platform.  Since browser venders like Mozilla, Chrome, Safari, Internet Explorer, and Opera know we need the ability to test these features on desktop and mobile platforms, they have <em>mostly</em> been helpful in providing edge versions of their browsers.  This post will show you what each vendor provides in the way of edge versions, as well as how to get them.</p><p><em>Most browser vendors offer edge and/or mobile versions in Windows, Mac, and Linux flavors, but this post will focus on Mac offerings.  Their other OS counterparts are generally found in the same place.</em></p><h2>Mozilla:  Nightly &amp;&nbsp;Aurora</h2><img
src="http://davidwalsh.name/dw-content/browsers-aurora.png" alt="Mozilla Firefox Aurora" class="image" /><p>Mozilla Aurora is a sneak peak into the next few versions of Mozilla.  As of now (still within a few months of FireFox 4&#8242;s official release), Aurora is a snapshot of Firefox 6.  Aurora is full of APIs and features that will be introduced in future versions of Firefox, including a re-enabled Web Sockets, the Element.dataset API, and so on.  The nightly version is also available if you prefer to stick closer to the current version of Firefox.  Nightly can be updated each day while a new version of Aurora is available every few weeks.  Click the &#8220;Check For Updates&#8221; button within the &#8220;About&#8221; menu to update your version of each browser.</p><div
class="actions"> <a
href="http://www.mozilla.com/en-US/firefox/channel/" class="demo">Mozilla Aurora</a> <a
href="http://nightly.mozilla.org/" class="demo">Firefox Nightly</a><div
class="clear"></div></div><h2>Mozilla Mobile Emulator &#8211;&nbsp;&#8220;Fennec&#8221;</h2><img
src="http://davidwalsh.name/dw-content/screen-start-mobile.png" alt="Firefox Mobile Fennec" class="image" /><p>Fennec is the codename for Mozilla&#8217;s mobile version of Firefox.  Firefox Mobile is available for Android-based devices, but you can test your website with the Fennec emulator, available on each desktop platform.</p><div
class="actions"><a
href="http://www.mozilla.com/en-US/mobile/download/" class="demo">Mozilla Mobile</a><div
class="clear"></div></div><h2>WebitKit&nbsp;Nighty</h2><img
src="http://davidwalsh.name/dw-content/browsers-webnightly.png" alt="Webkit Nightly" class="image" /><p>WebKit Nightly offers a nightly snapshot of the WebKit codebase.  At the time of publish, radial gradients are not supported by Safari but I was able to test them using Webkit Nightly.  Webkit Nightly prompts you to update each day.  WebKit Nightly could be considered a a beta for Safari.</p><div
class="actions"><a
href="http://nightly.webkit.org/" class="demo">WebKit Nightly</a><div
class="clear"></div></div><h2>Chrome Canary &amp;&nbsp;Chromium</h2><img
src="http://davidwalsh.name/dw-content/browsers-canary.png" alt="Chrome Canary" class="image" /><p>Google Chrome Canary is a mesh between Google Chrome and the <a
href="http://www.chromium.org/">Chromium project</a>, which is bleeding edge.  Much like Mozilla&#8217;s Aurora, Chrome Canary is two to four versions ahead of the current release. <a
href="http://www.makeuseof.com/tag/google-chrome-canary-technology-explained/">Click here</a> to read the story behind the name  &#8220;Canary&#8221;.  Open the About dialog to update your version of Canary.  If you feel up to it, you can instead create a custom build of the Chromium trunk.</p><div
class="actions"> <a
href="http://tools.google.com/dlpage/chromesxs" class="demo">Chrome Canary</a> <a
href="http://www.chromium.org/Home" class="demo">Chromium</a><div
class="clear"></div></div><h2>Opera&nbsp;Next</h2><img
src="http://davidwalsh.name/dw-content/browsers-operanext.png" alt="Opera Next" class="image" /><p>Opera Next is the pre-release version of the Opera browser. The latest alphas and betas are automatically installed, so you can try out Opera&#8217;s latest technologies.  What I love about Next is that while Opera often releases snapshots, Next meshes those in automatically.</p><div
class="actions"><a
href="http://my.opera.com/desktopteam/blog/swordfish-and-opera-next" class="demo">Opera Next</a><div
class="clear"></div></div><h2>Opera Mobile&nbsp;Emulator</h2><img
src="http://davidwalsh.name/dw-content/browsers-opera-mobile.png" alt="Opera Mobile" class="image" /><p>I wasn&#8217;t surprised to see that Opera was looking to offer a mobile solution, but I was pleasantly surprised as to how awesome Opera mobile was.  Had Opera mobile been disappointing, I wouldn&#8217;t have considered trying to support it for my website.  What I also like about Opera Mobile is they provided a nice emulator app, unlike the Android emulators.</p><div
class="actions"><a
href="http://www.opera.com/developer/tools/mobile/" class="demo">Mobile Opera</a><div
class="clear"></div></div><p><em>Note:  I also have an Opera wii emulator but I couldn&#8217;t find where I got it so I have not included it within this post.</em></p><h2>Legacy Safari&nbsp;Installs</h2><img
src="http://davidwalsh.name/dw-content/browsers-oldsafari.png" alt="Safari 3" class="image" /><p>The <a
href="http://michelf.com/projects/multi-safari/">Multi-Safari</a> project provides multiple versions of Safari that you can test your websites against.  This proved extremely helpful for me when I needed to support Safari 4 and 5, right around the original Safari 5 release.  Provided you have a compatible operating system, you can get the original version of Safari!</p><div
class="actions"><a
href="http://michelf.com/projects/multi-safari/" class="demo">Multi-Safari</a><div
class="clear"></div></div><p>Live on the bleeding edge of web development by testing and experimenting with code by using these edge browsers.  Let me know if you have suggestions for additions to this page!</p><p><a
href="http://davidwalsh.name/edge-mobile-browsers">Edge &#038; Mobile&nbsp;Browsers</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/edge-mobile-browsers/feed</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Track AJAX Link Clicks Using Google&#160;Analytics</title><link>http://davidwalsh.name/ajax-analytics</link> <comments>http://davidwalsh.name/ajax-analytics#comments</comments> <pubDate>Sun, 01 May 2011 13:53:36 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category> <category><![CDATA[MooTools]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=736</guid> <description><![CDATA[4/22/2011: This blog post was completely rewritten to describe page tracking with Analytics&#8217; asynchronous loading method. With more and more websites becoming completely AJAX-driven, the typical &#8220;do this every time a page loads&#8221; strategy isn&#8217;t always enough. This is especially try if you&#8217;re using Google Analytics or other analytics tracking software. Google is, of course, [...]<p><a
href="http://davidwalsh.name/ajax-analytics">Track AJAX Link Clicks Using Google&nbsp;Analytics</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[<div
class="update"><p>4/22/2011:  This blog post was completely rewritten to describe page tracking with Analytics&#8217; asynchronous loading method.</p></div><p>With more and more websites becoming completely AJAX-driven, the typical &#8220;do this every time a page loads&#8221; strategy isn&#8217;t always enough.  This is especially try if you&#8217;re using Google Analytics or other analytics tracking software.  Google is, of course, forward-thinking so they&#8217;ve provided a way to easily track page views of AJAX requests.</p><h2>The Google Analytics&nbsp;JavaScript</h2><p>The current standard for loading Google Analytics is the asynchronous method:</p><pre class="js">
var _gaq=[["_setAccount","UA-#######-#"],["_trackPageview"]];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.async=1;
g.src=("https:"==location.protocol?"//ssl":"//www")+".google-analytics.com/ga.js";
s.parentNode.insertBefore(g,s)}(document,"script"));
</pre><p>That bit tracks the initial page load but not subsequent AJAX calls.  Any time you want to track a page load, place add the following snippet:</p><pre class="js">
// "_trackEvent" is the pageview event, 
_gaq.push(['_trackPageview', '/some-page']);
</pre><p><code>_trackPageview</code> is used again but this time we provide the URL of the AJAX address that was loaded.  Using the small JavaScript snippet above allows you to keep track of pageviews just as you would if the entire page reloaded.  I&#8217;d recommend using this snippet with <a
href="/mootools-history">MooTools&#8217; History plugin</a>.</p><h2>The Old&nbsp;Method</h2><p>If you&#8217;re still using the synchronous method of loading Google Analytics, the following snippet will accomplish the same task:</p><pre class="js">
pageTracker._trackPageview('/some-page');
</pre><p>It&#8217;s great to know that Google Analytics is as dynamic as your web applications.  Allowing developers to track AJAX page clicks prevents the need to code apps just to keep track of statistics.</p><p><a
href="http://davidwalsh.name/ajax-analytics">Track AJAX Link Clicks Using Google&nbsp;Analytics</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/ajax-analytics/feed</wfw:commentRss> <slash:comments>12</slash:comments> </item> <item><title>Google PageRank PHP&#160;Class</title><link>http://davidwalsh.name/google-pagerank</link> <comments>http://davidwalsh.name/google-pagerank#comments</comments> <pubDate>Wed, 27 Apr 2011 13:42:42 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[Google]]></category> <category><![CDATA[MooTools]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5206</guid> <description><![CDATA[It appears that Google has changed their Page Rank mechanism. I&#8217;m currently investigating ways to restore the functionality of this class. While developers and designers can debate about the important of different search engine optimizations strategies, one metric that simply can&#8217;t be argued is a website&#8217;s Google PageRank, or its importance in driving traffic to [...]<p><a
href="http://davidwalsh.name/google-pagerank">Google PageRank PHP&nbsp;Class</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[<div
class="update"><p>It appears that Google has changed their Page Rank mechanism.  I&#8217;m currently investigating ways to restore the functionality of this class.</p></div><img
src="http://davidwalsh.name/dw-content/pagerank.png" alt="Google PageRank Checker" class="image" /><p>While developers and designers can debate about the important of different search engine optimizations strategies, one metric that simply can&#8217;t be argued is a website&#8217;s Google PageRank, or its importance in driving traffic to the site.  Achieving a better PageRank was a consideration when redesigning this blog.  We can discuss how to achieve a better PageRank in another post &#8212; this post will focus on how you can retrieve a page&#8217;s Google PageRank using a small PHP class that I have created.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/pagerank-checker.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>The&nbsp;PHP</h2><p>The <a
href="http://www.lampdeveloper.co.uk/wp-content/secretuploads/2007/11/pagerank.php">base functions</a> within this class were created by <a
href="http://www.lampdeveloper.co.uk/">Jamie Scott</a> &#8212; all credit for the base functions go to him.  I&#8217;ve simply placed the functionality into PHP class format for easy use and updated the code to be a bit more transparent.  As far as PHP classes go, this one is quite small:</p><pre class="php">
// Declare the class
class GooglePageRankChecker {
	
	// Track the instance
	private static $instance;
	
	// Constructor
	function getRank($page) {
		// Create the instance, if one isn't created yet
		if(!isset(self::$instance)) {
			self::$instance = new self();
		}
		// Return the result
		return self::$instance->check($page);
	}
	
	
	// Convert string to a number
	function stringToNumber($string,$check,$magic) {
		$int32 = 4294967296;  // 2^32
	    $length = strlen($string);
	    for ($i = 0; $i < $length; $i++) {
	        $check *= $magic; 	
	        //If the float is beyond the boundaries of integer (usually +/- 2.15e+9 = 2^31), 
	        //  the result of converting to integer is undefined
	        //  refer to http://www.php.net/manual/en/language.types.integer.php
	        if($check >= $int32) {
	            $check = ($check - $int32 * (int) ($check / $int32));
	            //if the check less than -2^31
	            $check = ($check < -($int32 / 2)) ? ($check + $int32) : $check;
	        }
	        $check += ord($string{$i}); 
	    }
	    return $check;
	}
	
	// Create a url hash
	function createHash($string) {
		$check1 = $this->stringToNumber($string, 0x1505, 0x21);
	    $check2 = $this->stringToNumber($string, 0, 0x1003F);
	
		$factor = 4;
		$halfFactor = $factor/2;

	    $check1 >>= $halfFactor;
	    $check1 = (($check1 >> $factor) &#038; 0x3FFFFC0 ) | ($check1 &#038; 0x3F);
	    $check1 = (($check1 >> $factor) &#038; 0x3FFC00 ) | ($check1 &#038; 0x3FF);
	    $check1 = (($check1 >> $factor) &#038; 0x3C000 ) | ($check1 &#038; 0x3FFF);	

	    $calc1 = (((($check1 &#038; 0x3C0) << $factor) | ($check1 &#038; 0x3C)) << $halfFactor ) | ($check2 &#038; 0xF0F );
	    $calc2 = (((($check1 &#038; 0xFFFFC000) << $factor) | ($check1 &#038; 0x3C00)) << 0xA) | ($check2 &#038; 0xF0F0000 );

	    return ($calc1 | $calc2);
	}
	
	// Create checksum for hash
	function checkHash($hashNumber)
	{
	    $check = 0;
		$flag = 0;

		$hashString = sprintf('%u', $hashNumber) ;
		$length = strlen($hashString);

		for ($i = $length - 1;  $i >= 0;  $i --) {
			$r = $hashString{$i};
			if(1 === ($flag % 2)) {			  
				$r += $r;	 
				$r = (int)($r / 10) + ($r % 10);
			}
			$check += $r;
			$flag ++;	
		}

		$check %= 10;
		if(0 !== $check) {
			$check = 10 - $check;
			if(1 === ($flag % 2) ) {
				if(1 === ($check % 2)) {
					$check += 9;
				}
				$check >>= 1;
			}
		}

		return '7'.$check.$hashString;
	}
	
	function check($page) {

		// Open a socket to the toolbarqueries address, used by Google Toolbar
		$socket = fsockopen("toolbarqueries.google.com", 80, $errno, $errstr, 30);

		// If a connection can be established
		if($socket) {
			// Prep socket headers
			$out = "GET /search?client=navclient-auto&#038;ch=".$this->checkHash($this->createHash($page))."&#038;features=Rank&#038;q=info:".$page."&#038;num=100&#038;filter=0 HTTP/1.1\r\n";
			$out .= "Host: toolbarqueries.google.com\r\n";
			$out .= "User-Agent: Mozilla/4.0 (compatible; GoogleToolbar 2.0.114-big; Windows XP 5.1)\r\n";
			$out .= "Connection: Close\r\n\r\n";

			// Write settings to the socket
			fwrite($socket, $out);

			// When a response is received...
			$result = "";
			while(!feof($socket)) {
				$data = fgets($socket, 128);
				$pos = strpos($data, "Rank_");
				if($pos !== false){
					$pagerank = substr($data, $pos + 9);
					$result += $pagerank;
				}
			}
			// Close the connection
			fclose($socket);
			
			// Return the rank!
			return $result;
		}
	}
}
</pre><p>The createHash and checkHash methods perform the deep down mathematical operations.  Once those are out of the way, the check method connects to Google&#8217;s toolbar server, disguising itself as a toolbar via the User-Agent header, to get the page&#8217;s PageRank.  A singleton pattern is used since creating individual instances isn&#8217;t important:</p><pre class="php">
$rank = GooglePageRankChecker::getRank("davidwalsh.name"); // returns "5"
</pre><p>The number provided back represents the PageRank for the URL provided!  This PHP class can be used on its own, but I&#8217;ve created a MooTools-powered script to retrieve an address&#8217; PageRank via some simple AJAX.</p><h2>The MooTools&nbsp;JavaScript</h2><p>This MooTools quick inline MooTools script responds to a button click, making an AJAX call to a PHP script that runs the class provided above:</p><pre class="js">
// When the DOM is ready
window.addEvent("domready",function() {
	
	// When the form is submitted...
	var form = document.id("rankForm"), request, display, domain;
	form.addEvent("submit",function(e) {
		// Stop the event
		if(e) e.stop();
		
		// Create request, if not already created
		if(!request) {
			domain = document.id("domain");
			display = document.id("rankerDisplay");
			request = new Request({
				url: "pagerank-checker.php", 
				method: "post",
				onComplete: function(response) {
					display.setStyle("display","block").set("text","Page rank for " + domainValue + " is: " + response);
				}
			});
		}
		
		// Get the value fo the URL
		domainValue = domain.get("value");
		
		// Send the request
		request.send({ data: { domain: domainValue } });
	});
	
});
</pre><p>Using a JavaScript snippet like this, you could easily add a JavaScript-fronted Google PageRank checker with the framework of your choosing.</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/pagerank-checker.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Outstanding work by Jamie Scott in creating the base functions to retrieve a page&#8217;s Google PageRank with PHP.  Hopefully my class makes the PageRank code a bit more portable and recognizable.</p><p><a
href="http://davidwalsh.name/google-pagerank">Google PageRank PHP&nbsp;Class</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/google-pagerank/feed</wfw:commentRss> <slash:comments>31</slash:comments> </item> <item><title>Translate Content with the Google Translate API and&#160;JavaScript</title><link>http://davidwalsh.name/google-translate-api</link> <comments>http://davidwalsh.name/google-translate-api#comments</comments> <pubDate>Mon, 07 Feb 2011 15:28:49 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[APIs]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[MooTools]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5165</guid> <description><![CDATA[Note:  For this tutorial, I&#8217;m using version1 of the Google Translate API.  A newer REST-based version is available. In an ideal world, all websites would have a feature that allowed the user to translate a website into their native language (or even more ideally, translation would be done before the user sees anything on the [...]<p><a
href="http://davidwalsh.name/google-translate-api">Translate Content with the Google Translate API and&nbsp;JavaScript</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><em>Note:  For this tutorial, I&#8217;m using version1 of the Google Translate API.  A newer REST-based version is available.</em></p><p>In an ideal world, all websites would have a feature that allowed the user to translate a website into their native language (or even more ideally, translation would be done before the user sees anything on the page).  In the real world, most small businesses can&#8217;t afford to invest money into website translation.   Luckily a small startup named &#8220;Google&#8221; provides an outstanding <a
href="http://code.google.com/apis/language/translate/overview.html">Translate API</a> to translate simple text from one language to another!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/google-language-api.php" class="demo">View Demo</a><div
class="clear"></div></div><h2>Sample&nbsp;HTML</h2><p>Google&#8217;s awesome Translate API allows you to send HTML &#8212; you don&#8217;t need to extract the text yourself! That&#8217;s a huge feature because parsing HTML and putting it all back again would be a nightmare!  Let&#8217;s put together some sample content:</p><pre class="html">
&lt;script src="https://www.google.com/jsapi?key=YOUR_GOOGLE_KEY"&gt;&lt;/script&gt;
&lt;div id="languages"&gt;&lt;p&gt;
	&lt;a href="?lang=en" rel="en"&gt;English&lt;/a&gt; / &lt;a href="?lang=es" rel="es"&gt;Spanish&lt;/a&gt; / &lt;a href="?lang=it" rel="it"&gt;Italian&lt;/a&gt; /
	&lt;a href="?lang=fr" rel="fr"&gt;French&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;

&lt;div id="languageBlock"&gt;
	&lt;p&gt;Lights go out and I can't be saved &lt;br /&gt;
	Tides that I tried to swim against  &lt;br /&gt;
	Brought me down upon my knees  &lt;br /&gt;
	Oh I beg, I beg and plead &lt;/p&gt;

	&lt;p&gt;Singin', come out if things aren't said  &lt;br /&gt;
	Shoot an apple off my head  &lt;br /&gt;
	And a, trouble that can't be named  &lt;br /&gt;
	Tigers waitin' to be tamed &lt;/p&gt;

	&lt;p&gt;Singing, yooooooooooooo ohhhhhh  &lt;br /&gt;
	Yoooooooooooo ohhhhhh &lt;/p&gt;

	&lt;p&gt;Home, home, where I wanted to go &lt;br /&gt; 
	Home, home, where I wanted to go  &lt;br /&gt;
	Home, home, where I wanted to go  &lt;br /&gt;
	Home, home, where I wanted to go&lt;/p&gt;
&lt;/div&gt;
</pre><p>We will use this #languageBlock element to send to Google for translation.  Note that each link has a rel attribute which holds the code for the language to switch to.</p><h2>Google Translate API&nbsp;JavaScript</h2><p><em>For the sake of keeping the code short, I&#8217;m using MooTools to access elements and add DOM events.  Feel free to stick to simple JavaScript or your framework of choice.</em></p><pre class="js">
// Set the original/default language
var lang = "en";
var currentClass = "currentLang";

// Load the language lib
google.load("language",1);

// When the DOM is ready....
window.addEvent("domready",function(){
	// Retrieve the DIV to be translated.
	var translateDiv = document.id("languageBlock");
	// Define a function to switch from the currentlanguage to another
	var callback = function(result) {
		if(result.translation) {
			translateDiv.set("html",result.translation);
		}
	};
	// Add a click listener to update the DIV
	$$("#languages a").addEvent("click",function(e) {
		// Stop the event
		if(e) e.stop();
		// Get the "to" language
		var toLang = this.get("rel");
		// Set the translation into motion
		google.language.translate(translateDiv.get("html"),lang,toLang,callback);
		// Set the new language
		lang = toLang;
		// Add class to current
		this.getSiblings().removeClass(currentClass);
		this.addClass(currentClass);
	});
});
</pre><p>The first step in the process is using google.load to load the Translate API.  When the the API is loaded, we grab the DIV to be translated.  We then define a callback for when the translation returns from Google.  This callback simply updates the content of the DIV.  The last step is adding a click event handler to each language link.  A google.language.translate call sends the content to Google for translation.  When the translated content returns, the content is updated by our callback!</p><div
class="actions"><a
href="http://davidwalsh.name/dw-content/google-language-api.php" class="demo">View Demo</a><div
class="clear"></div></div><p>Thanks to Google&#8217;s Translate API, we can effortlessly translate data!  It&#8217;s important that I note that Google&#8217;s content size limit is quite small so you shouldn&#8217;t rely on the Translate API to completely translate your a page.  It is, however, an excellent way to translate an alert or status message in a give language!</p><p><a
href="http://davidwalsh.name/google-translate-api">Translate Content with the Google Translate API and&nbsp;JavaScript</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/google-translate-api/feed</wfw:commentRss> <slash:comments>25</slash:comments> </item> <item><title>Google URL Shortener PHP&#160;Class</title><link>http://davidwalsh.name/google-url</link> <comments>http://davidwalsh.name/google-url#comments</comments> <pubDate>Wed, 02 Feb 2011 15:25:30 +0000</pubDate> <dc:creator>David Walsh</dc:creator> <category><![CDATA[APIs]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[PHP]]></category><guid
isPermaLink="false">http://davidwalsh.name/?p=5162</guid> <description><![CDATA[Google has had a URL shortening domain for quite a while now but it wasn&#8217;t until recently that Google exposed the URL shortening API to the public.  I took a few minutes to review their API and created a very basic GoogleUrlApi class that will shorten long URLs and expand shortened URLs. The&#160;PHP The class [...]<p><a
href="http://davidwalsh.name/google-url">Google URL Shortener PHP&nbsp;Class</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>Google has had a URL shortening domain for quite a while now but it wasn&#8217;t until recently that Google exposed the <a
href="http://code.google.com/apis/urlshortener/" rel="nofollow">URL shortening API</a> to the public.  I took a few minutes to review their API and created a very basic <code>GoogleUrlApi</code> class that will shorten long URLs and expand shortened URLs.</p><h2>The&nbsp;PHP</h2><p>The class itself is quite compact and the code should be easy to read:</p><pre class="php">
// Declare the class
class GoogleUrlApi {
	
	// Constructor
	function GoogleURLAPI($key,$apiURL = 'https://www.googleapis.com/urlshortener/v1/url') {
		// Keep the API Url
		$this-&gt;apiURL = $apiURL.'?key='.$key;
	}
	
	// Shorten a URL
	function shorten($url) {
		// Send information along
		$response = $this-&gt;send($url);
		// Return the result
		return isset($response['id']) ? $response['id'] : false;
	}
	
	// Expand a URL
	function expand($url) {
		// Send information along
		$response = $this-&gt;send($url,false);
		// Return the result
		return isset($response['longUrl']) ? $response['longUrl'] : false;
	}
	
	// Send information to Google
	function send($url,$shorten = true) {
		// Create cURL
		$ch = curl_init();
		// If we're shortening a URL...
		if($shorten) {
			curl_setopt($ch,CURLOPT_URL,$this-&gt;apiURL);
			curl_setopt($ch,CURLOPT_POST,1);
			curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode(array("longUrl"=&gt;$url)));
			curl_setopt($ch,CURLOPT_HTTPHEADER,array("Content-Type: application/json"));
		}
		else {
			curl_setopt($ch,CURLOPT_URL,$this-&gt;apiURL.'&amp;shortUrl='.$url);
		}
		curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
		// Execute the post
		$result = curl_exec($ch);
		// Close the connection
		curl_close($ch);
		// Return the result
		return json_decode($result,true);
	}		
}
</pre><p>The constructor requires your <a
href="https://code.google.com/apis/console/" rel="nofollow">Google API key</a>.  A second argument may be provided to the URL of the Google API.  As the API is currently in version 1, changing this URL would be more harmful than useful.  The class features two main methods:  shorten and expand.  Each method takes the long or short URL, contacts Google, and returns its counterpart.  If no counterpart is found, or the Google URL Shortener API is down, a result of false is returned, so please be sure to use your own error handling.</p><p>Now let&#8217;s create an instance of <code>GoogleUrlApi</code> to shorten and then expand a URL:</p><pre class="php">
// Create instance with key
$key = 'xhjkhzkhfuh38934hfsdajkjaf';
$googer = new GoogleURLAPI($key);

// Test: Shorten a URL
$shortDWName = $googer-&gt;shorten("http://davidwalsh.name");
echo $shortDWName; // returns http://goo.gl/i002

// Test: Expand a URL
$longDWName = $googer-&gt;expand($shortDWName);
echo $longDWName; // returns http://davidwalsh.name

</pre><p>The <code>shorten()</code> and <code>expand()</code> methods return their counterparts, as expected.  Quite painless, no?</p><p>The Google URL Shortener API provides much more than what my class provides, including user URL listing and usage tracking.  My class provides only the basics;  I&#8217;m assuming that 90%+ care only about getting the URL shortened so I&#8217;ve catered to that audience.  I had also thought about adding a caching mechanism to the class but since most everyone has their own method of caching information, I thought it best to leave that out.  Hopefully this class has some use for you all!</p><p><a
href="http://davidwalsh.name/google-url">Google URL Shortener PHP&nbsp;Class</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/google-url/feed</wfw:commentRss> <slash:comments>30</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><a
href="http://davidwalsh.name/google-ajax-search">Implement the Google AJAX Search&nbsp;API</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/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><a
href="http://davidwalsh.name/google-ajax-search">Implement the Google AJAX Search&nbsp;API</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/google-ajax-search/feed</wfw:commentRss> <slash:comments>39</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/68 queries in 0.063 seconds using disk: basic
Object Caching 1448/1563 objects using disk: basic

Served from: davidwalsh.name @ 2012-05-23 22:28:43 -->
