<?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>Shane Tomlinson</title>
	<atom:link href="http://www.shanetomlinson.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.shanetomlinson.com</link>
	<description>Some nonsense from a mental wanderer</description>
	<lastBuildDate>Mon, 07 May 2012 21:44:45 +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>Browser Bugs and Inconsistencies in localStorage</title>
		<link>http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/</link>
		<comments>http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/#comments</comments>
		<pubDate>Mon, 07 May 2012 21:44:45 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=677</guid>
		<description><![CDATA[Even though localStorage has been around for several years, there are still inconsistencies across browsers when it comes to both removing items and reporting which items exist as members. IE8, Firefox Desktop]]></description>
			<content:encoded><![CDATA[<p>Even though localStorage has been around for several years, there are still inconsistencies across browsers when it comes to both removing items and reporting which items exist as members.  IE8, Firefox Desktop <= v13, Firefox Mobile, Opera and Opera Mobile all suffer from problems.</p>
<h4>Non-Existent Item Values</h4>
<p>In all tested browsers that support localStorage, a call to localStorage.getItem for an item that does not exist returns null.  In Firefox (versions <= 13), a call to localStorage.&lt;non_existent_item_name&gt; will return null as well.</p>
<pre>
// val === null in all tested browsers
var val = localStorage.getItem(&#8220;non_existent&#8221;);

// val === undefined in most browsers, in Firefox <= v13, val === null
var val = localStorage.non_existent;
</pre>
<p>Firefox&#8217;s discrepency has been fixed in Firefox 14, which is in the Aurora Channel at the time of writing this article.</p>
<h4>Using the `in` Operator on Non-Existent Items</h4>
<p>Both Firefox (versions <= 13) and Opera fail using the `in` operator.  Opera appears to always misreport an item as being `in` localStorage.  Firefox will report an item as being `in` localStorage after the item is removed using removeItem.  Firefox will correctly update its state when the page is reloaded.</p>
<pre>
// Opera always returns true.  All other browsers return false.
var hasItem = &#8220;non_existent&#8221; in localStorage;

localStorage.firstItem = &#8220;someValue&#8221;;

// hasItem will be false in Firefox <= v13 after delete
delete localStorage.firstItem;
var hasItem = "firstItem" in localStorage;

localStorage.secondItem = "newValue";

// hasItem will be true in Firefox <= v13 after removeItem
localStorage.removeItem("secondItem");
var hasItem = "secondItem" in localStorage;
</pre>
<h4>localStorage.hasOwnProperty</h4>
<p>Since `in` appears to be a no-go for a subset of browsers, perhaps localStorage.hasOwnProperty could help out.  It turns out that IE8 does not support hasOwnProperty on localStorage.  Opera returns true for every property that is queried.  </p>
<pre>
// IE8 excepts with `TypeError: Object doesn't support this property or method`
// Opera returns true
var hasItem = localStorage.hasOwnProperty("undefined_item")
</pre>
<h4>Removing Items &#8211; delete vs localStorage.removeItem</h4>
<p>The entire impetus for this post started in a code review where I saw an author do a mistake that I have been bitten by in the past &#8211; removing items from localStorage using the `delete` operator.  Unfortunately, IE8 will throw an exception if the item being deleted is not already in localStorage.</p>
<pre>
localStorage.item = "value";

// The first delete will work everywhere
delete localStorage.item;

// IE8 will throw `TypeError: Object doesn't support this property or method`
delete localStorage.item;
</pre>
<p>This is a problem, because it is not possible to reliably query whether an item is in localStorage in all browsers.  As noted above, both Firefox and Opera can return true using the `in` operator and IE8 and Opera both fail using localStorage.hasOwnProperty.</p>
<h4>What About Mobile?</h4>
<p>Mobile Safari on iOS 5.1 and the Default Android browser on Honeycomb have passed all the tests.  The current Mobile Firefox (Fennec) reports the same failures as Firefox 12/13.</p>
<h4>Where Are The Tests?</h4>
<p>The below JSFiddle contains the tests that I used.</p>
<p><iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/shane_tomlinson/N64fG/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe></p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Browser+Bugs+and+Inconsistencies+in+localStorage+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D677" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;title=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;title=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;t=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;title=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;title=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/&amp;title=Browser+Bugs+and+Inconsistencies+in+localStorage" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2012/localstorage-bugs-inconsistent-removeitem-delete/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>easierObject &#8211; Micro-library to Simplify Read/Write Operations at Random Locations in Javascript Object Trees</title>
		<link>http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/</link>
		<comments>http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/#comments</comments>
		<pubDate>Sat, 14 Apr 2012 10:14:13 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Projects]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=656</guid>
		<description><![CDATA[The Problem One of my pet peeves with working with Javascript objects is that there is no native way to read from or write to an arbitrary location in a Javascript object tree without first checking whether each internal node &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<h3>The Problem</h3>
<p>One of my pet peeves with working with Javascript objects is that there is no native way to read from or write to an arbitrary location in a Javascript object tree without first checking whether each internal node in the tree exists. It is easy to operate on a single object, but working with a tree necessitates boilerplate work.  What do I mean by this?</p>
<p>Say an object &#8220;data&#8221; exists that represents the root node of a tree of data. Assume this tree is already pre-populated from a web service API call. The current user&#8217;s name needs written to a specific location in the tree, then the data is passed on to another function that shows the data on the screen. </p>
<p>This would be easy if the user&#8217;s name could be set at &#8220;data.username&#8221;, but the template is expecting user related data to live under the &#8220;data.user&#8221; namespace, with the name being at &#8220;data.user.name&#8221;. </p>
<p>At first thought, this should be easy, write:</p>
<pre>
data.user = { name: "Billy Jim Bob" };
</pre>
<p>But what if data.user already existed and contained a field &#8220;userid&#8221;? The user&#8217;s userid is now lost. Uh oh. So we modify this to:</p>
<pre>
// data initially contains data.user.userid = 1;
// create new user object only if needed (in this case it is not)
data.user = data.user || {};

// do the interesting work.
data.user.name = "Billy Jim Bob";

// data.user now contains two fields, name, userid.
</pre>
<p>Fair enough, not too much code.  But what if this was taken a step further, what if name was further split into first, middle, and last, all under the data.user.name node?</p>
<pre>
// Boilerplate for each internal node to create the node
// only if needed.
data.user = data.user || {};
data.user.name = data.user.name || {};

// Actual work on the leaf nodes
data.user.name.first = "Billy";
data.user.name.middle = "Jim";
data.user.name.last = "Bob";
</pre>
<p>That two lines of boilerplate shouldn&#8217;t be necessary.</p>
<p>To read from an arbitrary location in a tree requires a different sort of boilerplate &#8211; a try/catch to avoid a TypeError when trying to read an item from an undefined object.</p>
<pre>
// data.user.address may or may not exist at this point.

try {
   var streetAddress = data.user.address.street;
}
catch(e) {
   // try/catch is used to avoid a TypeError if
   // address is not defined.
}
</pre>
<p>Why can&#8217;t this be easy?</p>
<h3>The Solution?</h3>
<p>I am working on two micro-libraries to simplify this, but I am not sure if I have an optimal interface yet. The first, called <a href="https://github.com/stomlinson/easierObject" title="easierObject GitHub Repo" target="_blank">easierObject</a>, is to work with normal Javascript objects.  The second is for working with localStorage and is called <a href="https://github.com/stomlinson/easierStorage" title="easierStorage GitHub Repo" target="_blank">easierStorage</a>. </p>
<p>The APIs are modeled after localStorage, using setItem, getItem and removeItem.</p>
<pre>
// Rewrite of full name example
data = new easierObject(data);
user.setItem("user", "name", "first", "Billy");
user.setItem("user", "name", "middle", "Jim");
user.setItem("user", "name", "last", "Bob");
</pre>
<p>Only one line of boilerplate, but at the same time, this seems just as verbose.</p>
<p>Reading an arbitrary location is very similar:</p>
<pre>
var firstName = data.getItem("user", "name", "first");
</pre>
<h3>A Better API?</h3>
<p>Instead of separating the name of each node, another possible approach is to have a single name field with each node name separated by a period &#8211; in keeping with normal Javascript notation.</p>
<pre>
data.setItem("user.name.first", "Billy");
data.setItem("user.name.middle", "Jim");
data.setItem("user.name.last", "Bob");

var firstName = data.getItem("user.name.first");
</pre>
<p>This seems a far easier to grok, but it prevents users from having node names that contain periods.  Is this an acceptable restriction? What if there was a special sequence &#8220;\.&#8221; that specified &#8220;this is not a separator&#8221;?</p>
<h3>Direction</h3>
<p>So obviously it is still a work in progress.</p>
<p>The code lives on <a href="https://github.com" title="GitHub" target="_blank">GitHub</a> at <a href="https://github.com/stomlinson/easierObject" title="easierObject GitHub Repo" target="_blank">https://github.com/stomlinson/easierObject</a>.</p>
<p>Any thoughts on a good way to go?</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D656" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;title=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;title=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;t=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;title=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;title=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/&amp;title=easierObject+%E2%80%93+Micro-library+to+Simplify+Read%2FWrite+Operations+at+Random+Locations+in+Javascript+Object+Trees" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2012/easierobject-micro-library-to-simplify-readwrite-operations-at-random-locations-in-javascript-object-trees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Where Are The Posts?</title>
		<link>http://www.shanetomlinson.com/2012/where-are-the-posts/</link>
		<comments>http://www.shanetomlinson.com/2012/where-are-the-posts/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 23:19:04 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[Meta]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=652</guid>
		<description><![CDATA[Since starting at Mozilla last June, the output of my writing has dropped considerably. This is a real shame because I feel like the quality of my writing has dropped considerably too. I am far more conscious of what and &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2012/where-are-the-posts/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Since starting at Mozilla last June, the output of my writing has dropped considerably. This is a real shame because I feel like the quality of my writing has dropped considerably too. I am far more conscious of what and how I write, especially in email to colleagues. This has the bewildering effect that instead of sending out well written messages explaining my point of view, I send out a bunch of jumbled thoughts riddled with spelling and grammatical errors. Such is the strange effect of self-consciousness.</p>
<p>The silly reason I have not been writing is because I added my blog to <a href="http://planet.mozilla.org/" title="Planet Mozilla" target="_blank">Planet Mozilla</a> and then became very self-conscious. Planet is a Mozilla hosted feed aggregation service about other Mozillians. While there are no hard rules as to what can be posted to Planet blogs, posts are generally Mozilla project related. When I first submitted my feed URL to Planet, I submitted the URL for my entire site not knowing that WordPress could namespace feeds based on category. Since I did not want my random projects, code snippets or ideas cluttering up everyone&#8217;s feed, I self-censored and stopped writing non-Mozilla related posts. This is a failure in more ways than I have fingers.</p>
<p>Enough of that.</p>
<p>I sorted out the feed thing. Now that I know WordPress can namespace feeds, I have updated my Planet feed to only include posts in the Mozilla category. Why didn&#8217;t I do this earlier?</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Where+Are+The+Posts%3F+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D652" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;title=Where+Are+The+Posts%3F" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;title=Where+Are+The+Posts%3F" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;t=Where+Are+The+Posts%3F" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;title=Where+Are+The+Posts%3F" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;title=Where+Are+The+Posts%3F" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2012/where-are-the-posts/&amp;title=Where+Are+The+Posts%3F" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2012/where-are-the-posts/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2012/where-are-the-posts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Experiments for Completing the User Registration Flow in BrowserID</title>
		<link>http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/</link>
		<comments>http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 21:25:43 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[BrowserID]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=603</guid>
		<description><![CDATA[Over the past several months BrowserID adoption by sites both inside and outside of Mozilla has started to take off. We have received a lot of feedback from site operators, some good, some bad. Far and away the biggest complaint &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Over the past several months BrowserID adoption by sites both inside and outside of Mozilla has started to take off. We have received a lot of feedback from site operators, some good, some bad.  Far and away the biggest complaint from site operators is that completing the new user flow in BrowserID is causing drop off in potential users converting to verified users. Because of this, our own User Researcher <a href="http://blog.mozilla.com/userresearch/author/mtrombleymozilla-com/">Mary Trombley</a> and UX guru <a href="http://skinnywhitegirl.com/blog/">Crystal Beasley</a> have made it their mission to make this experience as smooth as possible.</p>
<p>Mary user tested our current sign up flow with people who had never used BrowserID. The results were eye opening. Users are doing things we suspected may cause problems, but we did not realize the extent of the confusion we were witnessing.</p>
<p>The core problem is that users get lost once they verify their email with BrowserID. No clear indication is given for how to return to the original site being signing up to. Sometimes users close the original site, sometimes they open the verification page in a new window, sometimes they start on mobile and finish on their desktop, sometimes they do everything we expect but don&#8217;t realize the original site is still open in another tab. All users see after completing the new user flow is some text that says (paraphrased) &#8220;You have finished signing up to BrowserID&#8230;. You may now close this window.&#8221; </p>
<div class="thumbnail"><a href="https://skitch.com/set117/g6s8u/account-completion"><img src="https://img.skitch.com/20120204-gqsna1ujr32ws7hij6bs6s61j4.preview.jpg" alt="account_completion" /></a></div>
<p>Clearly, we have to do better.</p>
<p><a href="http://lloyd.io/">Lloyd Hilaiel</a> came up with some initial ideas outlined in the <a href="https://github.com/mozilla/browserid/issues/385">GitHub Tracking Issue</a>. Skinny (Crystal) took these ideas and ran. She&#8217;s got UX talent. The changes she suggested were so obvious it was like &#8220;duh, how did we not think of this before?&#8221; But then again, it&#8217;s easy to say that in retrospect &#8211; the process for coming up with a smooth flow is anything but smooth.</p>
<p>Lloyd and Skinny&#8217;s initial suggestion was to use some browser trickery to get the user back to the initial site once they have completed the verification step. </p>
<p>If the original site is still open, we can use a window.alert to return focus to its tab. This works in Firefox, Chrome and Safari &#8211; neither Opera nor IE play nicely. Mobile browsers universally show the alert message, but fail to return the user to the correct tab. </p>
<p>If the original site is no longer open, we can redirect the verification tab back to the original site.  Overall this offers a much better experience, but still leaves a huge hole &#8211; if we have to redirect the current tab to the original site, currently we have no way of indicating to that site that the user is now logged in. We think we have a solution to this using <a href="https://github.com/mozilla/browserid/issues/912">DOM events</a>. I did a quick proof of concept on this last night and will post a video once something more concrete is available.</p>
<p>These simple changes boosted our conversion rates quite a bit. Skinny then took the flow and made it even smoother. She thought &#8220;why not enter the password inside the dialog?&#8221; Brilliant &#8211; when the user opens the verification link from their email, they have no additional work to do &#8211; all they have to do is worry about logging in.</p>
<p><iframe src="http://player.vimeo.com/video/36202267?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></p>
<p><a href="http://vimeo.com/32957644">BrowserID New User Verification Flow Experiments Screencast</a> from <a href="http://vimeo.com/user9477456">Shane Tomlinson</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>Both of these flows can be tried with right now. This is experimental work made for user testing and feedback &#8211; these flows should not even be considered alpha quality. </p>
<p>Flow 1 &#8211; <a href="https://feature385.myfavoritebeer.org/" title="MyFavoriteBeer hooked up to feature385.hacksign.in" target="_blank">https://feature385.myfavoritebeer.org/</a> &#8211; window.alert if original site is still open or redirect to original site if closed.</p>
<p>Flow 2 &#8211; <a href="https://feature1000.myfavoritebeer.org/" title="MyFavoriteBeer hooked up to feature1000.hacksign.in" target="_blank">https://feature1000.myfavoritebeer.org/</a> &#8211; Same as flow 1 with initial password entry inside the dialog.</p>
<p>Note, for these experiments we are using &#8220;hacksign.in&#8221; as our test version of &#8220;browserid.org&#8221; &#8211; you are not being hacked.  Both domains are running in separate environments, so you will have to create an account on each.</p>
<p>I will be continue hacking on these flows over the next couple of weeks. Additional user tests will be done. We are going to keep refining until we get it right. Any and all feedback is welcomed and encouraged.</p>
<p>Check it out, see what you think. </p>
<p>Want to get involved?</p>
<ul>
<li>Check out the code on <a href="https://github.com/mozilla/browserid" target="_blank">GitHub</a>.</li>
<li>Message our mailing list at <a href="mailto:dev-identity@lists.mozilla.org">dev-identity@lists.mozilla.org</a> or <a href="https://lists.mozilla.org/listinfo/dev-identity">sign up</a> to receive daily updates.</li>
<li>Come see what we are up to in the <a href="http://identity.mozilla.com">Identity</a> group or visit us on IRC in the #identity channel on irc.mozilla.org.</li>
</ul>
<p>We&#8217;d love to hear from you about how we can make this better!</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D603" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;title=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;title=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;t=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;title=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;title=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/&amp;title=Experiments+for+Completing+the+User+Registration+Flow+in+BrowserID" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2012/browserid-complete-user-registration-flow-experiments/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Prototyping Profile Information in BrowserID</title>
		<link>http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/</link>
		<comments>http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/#comments</comments>
		<pubDate>Sat, 03 Dec 2011 22:58:08 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[BrowserID]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=584</guid>
		<description><![CDATA[Last week I started work on a simple prototype to provide user profile information as part of BrowserID. What is this? Imagine only entering your profile information once instead of on every site you sign up to. Other companies have &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>Last week I started work on a simple prototype to provide user profile information as part of <a href="https://browserid.org">BrowserID</a>. What is this? Imagine only entering your profile information once instead of on every site you sign up to. Other companies have this goal as well, but their offerings suffer from either a lack of adoption or the user has little control over what data is given to the site.</p>
<p>The goals for providing profile information in BrowserID are:</p>
<ol>
<li>Allow the user to enter their profile information once.</li>
<li>Provide profile information to sites through a DOM API that can be implemented by browsers.</li>
<li>Keep the user in control over what data is released.</li>
</ol>
<p>Our approach is to start simple and grow after we gain feedback.  The feature as I have implemented it only has two fields, a name and a user&#8217;s photo. By starting with only two fields, we can start to get feedback on UX and what user&#8217;s perceptions are in relation to this data.</p>
<p>For sites to get the information, they will have to explicitly request which fields they are interested in.  The user will then be shown the BrowserID dialog and will have the ability to deselect fields they do not wish to share.  This is useful in situations where a site may request a user&#8217;s name, email address and photo, but the user is only comfortable supplying their name and email address.</p>
<p>A video on how this early prototype works:</p>
<p><iframe src="http://player.vimeo.com/video/32957644?title=0&amp;byline=0&amp;portrait=0" width="600" height="400" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
<p><a href="http://vimeo.com/32957644">BrowserID Profile Screencast</a> from <a href="http://vimeo.com/user9477456">Shane Tomlinson</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>Again, this is early days yet, but please help us make profile information in BrowserID rock! Message our mailing list at <a href="mailto:dev-identity@lists.mozilla.org">dev-identity@lists.mozilla.org</a> or <a href="https://lists.mozilla.org/listinfo/dev-identity">sign up</a> to receive daily updates. Come see what we are up to in the <a href="http://identity.mozilla.com">Identity</a> group or visit us on IRC in the #identity channel on irc.mozilla.org.</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Prototyping+Profile+Information+in+BrowserID+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D584" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;title=Prototyping+Profile+Information+in+BrowserID" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;title=Prototyping+Profile+Information+in+BrowserID" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;t=Prototyping+Profile+Information+in+BrowserID" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;title=Prototyping+Profile+Information+in+BrowserID" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;title=Prototyping+Profile+Information+in+BrowserID" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/&amp;title=Prototyping+Profile+Information+in+BrowserID" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/prototyping-profile-information-in-browserid/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Jam Boxes for Node Knockout!</title>
		<link>http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/</link>
		<comments>http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/#comments</comments>
		<pubDate>Mon, 29 Aug 2011 02:01:54 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=565</guid>
		<description><![CDATA[48 hours of hacking, this is our result. Check out Jam Boxes, our entry into Node Knockout! I&#8217;m dead tired, but what a fun, intense weekend.]]></description>
			<content:encoded><![CDATA[<p>48 hours of hacking, this is our result.  Check out <a href="http://witty-team-name.nko2.nodeknockout.com/app.html">Jam Boxes</a>, our entry into <a href="http://nodeknockout.com/">Node Knockout!</a>  I&#8217;m dead tired, but what a fun, intense weekend.</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Jam+Boxes+for+Node+Knockout%21+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D565" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;title=Jam+Boxes+for+Node+Knockout%21" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;title=Jam+Boxes+for+Node+Knockout%21" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;t=Jam+Boxes+for+Node+Knockout%21" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;title=Jam+Boxes+for+Node+Knockout%21" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;title=Jam+Boxes+for+Node+Knockout%21" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/&amp;title=Jam+Boxes+for+Node+Knockout%21" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/jam-boxes-for-node-knockout/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Browser Sign In WordPress Plugin</title>
		<link>http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/</link>
		<comments>http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/#comments</comments>
		<pubDate>Sun, 14 Aug 2011 05:21:11 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[BrowserID]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=553</guid>
		<description><![CDATA[Warning: This post is no longer current, for the most up to date information, see MDN or the Identity Wiki. Hi all, A quick update to say that I am releasing the WordPress Plugin to support Browser Sign In. The &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><code><br />
Warning: This post is no longer current, for the most up to date information, see <a href="https://developer.mozilla.org/en/BrowserID" title="MDN">MDN</a> or the <a href="https://wiki.mozilla.org/Identity/BrowserID" title="BrowserID">Identity Wiki</a>.<br />
</code></p>
<p>Hi all,<br />
  A quick update to say that I am releasing the WordPress Plugin to support Browser Sign In.  The repository for the code can be found on <a href="https://github.com/stomlinson/browser_sign_in_wordpress">GitHub</a>.  The clone link is <a href="git://github.com/stomlinson/browser_sign_in_wordpress.git">git://github.com/stomlinson/browser_sign_in_wordpress.git</a>.</p>
<p>As an example of how to implement the Sessions API, I am including the initial version of the code.</p>
<pre>
&lt;?php
/*Plugin Name: Browser Sign In
Plugin URI: http://www.shanetomlinson.com
Description: Supports the Sessions API produced my Mozilla Labs.
Version: 0.0.1
Author: Shane Tomlinson
Author URI: http://www.shanetomlinson.com
License: MPL 1.1, GPL 2.0, LGPL 2.1
*/

function set_sessions() {
    echo "
        &lt;script type='text/javascript'&gt;
          var doc = window.document;
          // Do not blow up non-supporting browsers.
          if(navigator.id &#038;&#038; doc.addEventListener) {\n ";

    if(is_user_logged_in()) {
        global $userdata;
        get_currentuserinfo();
        echo "
            navigator.id.sessions = [ { email: '" . $userdata->user_login . "'} ];

            // The user is logged in, we only really need to listen for the
            // logout event
            doc.addEventListener('logout', function() {
                navigator.id.sessions = undefined;
                doc.location.href = '" . wp_logout_url() . "';
            }, false);\n";
    } else {
        echo "
            // The user is not logged in, we only have to listen for the login
            // event from the browser.
            navigator.id.sessions = [];
            doc.addEventListener('login', function() {
                doc.location.href = '" . wp_login_url() . "';
            }, false);\n";
    }

        echo "
          }
        &lt;/script&gt;";
}

add_action('wp_head', 'set_sessions');
add_action('admin_head', 'set_sessions');

?&gt;
</pre>
<p>The plugin can be found on the WordPress Plugins listing site under <a href="http://wordpress.org/extend/plugins/browser-sign-in-wordpress-plugin/">Browser Sign In</a>.</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Browser+Sign+In+WordPress+Plugin+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D553" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;title=Browser+Sign+In+WordPress+Plugin" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;title=Browser+Sign+In+WordPress+Plugin" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;t=Browser+Sign+In+WordPress+Plugin" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;title=Browser+Sign+In+WordPress+Plugin" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;title=Browser+Sign+In+WordPress+Plugin" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/&amp;title=Browser+Sign+In+WordPress+Plugin" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/mozillabrowser-sign-in-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mozilla&#8217;s Session API Tutorial</title>
		<link>http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/</link>
		<comments>http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/#comments</comments>
		<pubDate>Sat, 13 Aug 2011 05:01:44 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[BrowserID]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=477</guid>
		<description><![CDATA[Warning: This post is no longer current, for the most up to date information, see MDN or the Identity Wiki. With the introduction of BrowserID, Mozilla is beginning a big push towards securing and simplifying the management of the user&#8217;s &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p><code><br />
Warning: This post is no longer current, for the most up to date information, see <a href="https://developer.mozilla.org/en/BrowserID" title="MDN">MDN</a> or the <a href="https://wiki.mozilla.org/Identity/BrowserID" title="BrowserID">Identity Wiki</a>.<br />
</code></p>
<p>With the introduction of BrowserID, Mozilla is beginning a big push towards securing and simplifying the management of the user&#8217;s identity.  </p>
<h2>The Problem</h2>
<p>Up to this point, browsers have played a very small role in helping users sign in, sign out, and see their session information for the current site.  We think that by providing a single place within the browser to perform these functions, we can offer a streamlined user experience.</p>
<p>To do this, we need a little help from sites themselves.</p>
<h2>The Solution &#8211; Introducing the Sessions API!</h2>
<p>By using the Sessions API, sites indicate their willingness to work with the browser to help manage and display session information.  </p>
<h3>High Level Flow</h3>
<p>We want the user to have a single location with which to do all of their session management.  Currently, we are using a small portion of the URL bar next to the favicon as the focal point for this process.  Once a site has indicated that it supports the Sessions API, a &#8220;Sign In&#8221; button will be displayed.  If the user clicks on this button, the user will be logged in via the site&#8217;s authentication facilities.  Once the user is logged in, a button with their current session information will replace the &#8220;Sign In&#8221; button.  The user can click on their username to see more session information as well as to sign out.  Pressing the &#8220;Sign Out&#8221; button will trigger the site&#8217;s sign out mechanism.  The session information will be reset and display the &#8220;Sign In&#8221; button again.</p>
<h2>The API</h2>
<p>Below is a walk through of how the Session API can be used for a static site.</p>
<h3>Indicating Support</h3>
<p>First off, the site has to indicate that it supports the Session API.  Supporting the Session API means that it both sets sessions information and responds to the `login` and `logout` events.</p>
<pre>
/**
* Indicate support for the Sessions API by setting
* navigator.id.sessions to an empty array.  Browser will
* display a "Sign-In" button in a conspicuous place.
*/
if(navigator.id) {
  navigator.id.sessions = [];
}
</pre>
<p>Setting navigator.id.sessions to an empty array indicates support.  Notice that all code examples are wrapped in the &#8220;if(navigator.id) { /* code here */ }&#8221; block.  This is so that we do not cause errors on browsers that do not yet support the API.</p>
<p>When a site indicates that it supports the Sessions API, a button will be displayed in the URL bar.</p>
<p><a href="http://www.shanetomlinson.com/wp-content/uploads/2011/08/sign_in.png"><img src="http://www.shanetomlinson.com/wp-content/uploads/2011/08/sign_in-300x127.png" alt="&quot;Sign In&quot; in the URL Bar" title="sign_in" width="300" height="127" class="alignnone size-medium wp-image-505" /></a></p>
<h3>Login event</h3>
<p>If the user presses the &#8220;Sign In&#8221; button, a (drum roll) `login` DOM event on the page&#8217;s document is triggered.  To handle this, a `login` event handler must be registered on the window&#8217;s document.  When `login` is triggered, the site should take appropriate action such as redirect to a login page or call BrowserID.</p>
<pre>
if(navigator.id) {
/**
* Listen for the login event.  Take appropriate action to log the
* user in once the event is triggered.
*/
  ...

  // `login` is triggered whenever the user clicks "Sign In"
  // from within their browser.
  document.addEventListener("login", function(event) {
    // Redirect to login page, call BrowserID, etc.
    document.location.href = ...;
  }, false);
}
</pre>
<h3>Setting a Session</h3>
<p>Once the user is logged in, the site should set the session information to be displayed in the browser.  Session information should be set as soon as possible when the user lands at the page following the login page, preferably before the `load` event is triggered.</p>
<p>If session information is set, the user&#8217;s current login name will be displayed in the URL bar providing a visual link between the site and the user&#8217;s identity.</p>
<p><a href="http://www.shanetomlinson.com/wp-content/uploads/2011/08/signed_in.png"><img src="http://www.shanetomlinson.com/wp-content/uploads/2011/08/signed_in-300x144.png" alt="&quot;stomlinson@mozilla.com&quot; shown logged in in URL Bar" title="signed_in" width="300" height="144" class="alignnone size-medium wp-image-506" /></a></p>
<pre>
/**
* Indicate the user is logged in, not bound to any cookie.
* navigator.id.sessions will have to be updated on every page load.
* Browser will show the user's current login name where the
* "Sign-In" button was.
*/
if(navigator.id) {
  navigator.id.sessions = [{
      email: "stomlinson@mozilla.com"
  }];
}
</pre>
<p>Using the above method of setting the sessions, the session information MUST be set on every subsequent page load or else the previous page&#8217;s session information will be removed on the new page&#8217;s `load` event.  While session information can be set at any time, it is recommended to set it before the window `load` event to avoid flicker.</p>
<h3>Using Sessions with Bindings</h3>
<p>To avoid setting session information on every page, all you have to do is bind the session information to a cookie.  If a session is bound to a cookie, as long as no new session information is set and the cookie value remains the same, the session will be considered active.</p>
<p>An important caveat to the above is that the cookie information bound to an exact match domain name.  This means that if the original session information was set at http://foo.com, but the user is now at http://mail.foo.com, the cookie binding will be ignored and the session information must be set again.</p>
<pre>
/**
* Indicate the user is logged in, bind session to a cookie.
* Session will remain valid until the value of the cookie
* changes, navigator.id.sessions is updated, or user
* changes domains.
*/
if(navigator.id) {
  navigator.id.sessions = [{
    email: "stomlinson@mozilla.com",
    bound_to: {
      type: "cookie",
      cookie_name: "SID"
    }
  }];
}
</pre>
<h3>Logout event</h3>
<p>If there is session information set, the site should then listen for the `logout` event.  The `logout` event is triggered on the document whenever the user selects the &#8220;Sign Out&#8221; button from within the browser.</p>
<p><a href="http://www.shanetomlinson.com/wp-content/uploads/2011/08/logout.png"><img src="http://www.shanetomlinson.com/wp-content/uploads/2011/08/logout-300x175.png" alt="Logout dialog from URL Bar" title="logout" width="300" height="175" class="alignnone size-medium wp-image-507" /></a></p>
<pre>
if(navigator.id) {
...

/**
* `logout` event is triggered whenever the user selects the
* Sign Out button from within their browser.
*/
  document.addEventListener("logout", function(event) {
    // redirect to logout page
    document.location.href = ...;
  }, false);
}
</pre>
<h3>Resetting the Session Information</h3>
<p>Once the user has logged out, the sessions information should be reset so that the user&#8217;s previous session is no longer displayed in the browser.</p>
<pre>
/**
* Clear the session information, display "Sign-In" button.
*/
if(navigator.id) {
  navigator.id.sessions = [];
}
</pre>
<pre>
/**
* Putting it all together.
*/
if(navigator.id) {
  // indicate support
  navigator.id.sessions = [];

  // user logged in, no cookies
  navigator.id.sessions = [{ email: "stomlinson@mozilla.com" }];

  // user logged in, bound to cookie named SID.
  navigator.id.sessions = [{
    email: "stomlinson@mozilla.com",
    bound_to: {
      type: "cookie",
      cookie_name: "SID"
    }
  }];

  document.addEventListener("login", function(event) {
    // redirect to login page
    document.location.href = ...;

    // ... or ...

    // call BrowserID!
    navigator.id.getVerifiedEmail(function(assertion) {
      // send to server to verify, get email address
    });
  }, false);

  document.addEventListener("logout", function(event) {
    // redirect to logout page
    document.location.href = ...;
  }, false);
}
</pre>
<h2>Plugin</h2>
<p>We have a plugin!  I have been hard at work getting a Sessions API plugin ready for Firefox and an *experimental* version is ready! The plugin supports Firefox 4+ through to the current Aurora.  The screen shots above were all taken with Nightly.  A pre-built XPI can be found on <a href="https://github.com/mozilla/browserid_addon/raw/develop/addon/dist/browserid_addon.xpi">GitHub</a> which can be installed directly.</p>
<h3>Bugs (Yes, they do exist)</h3>
<p>The most important bug right now is when first opening Firefox with multiple instances, only the last instance opened will have Sessions support.  This will be addressed very soon.</p>
<p>Secondly, there are some visual inconsistencies with the Windows version.  I did not realize until too late that the styling of the favicon button was different in Windows than OSX.</p>
<h2>Seeing The API and Addon in Action</h2>
<p>You can see this in action either on this site <a href="http://www.shanetomlinson.com/wp-login.php?action=register">(registration required)</a> or on <a href="http://myfavoritebeer.org" title="My Favorite Beer" target="_blank">http://myfavoritebeer.org</a>.  myfavoritebeer.org has the added bonus of being integrated with <a href="https://browserid.org">BrowserID</a>!</p>
<h2>Future Directions</h2>
<p>Shortly in the future we want to support the ability to switch between multiple sessions &#8211; ala Google.  We are also looking at having the notion of &#8220;passive&#8221; and &#8220;active&#8221; sessions, but this has not yet been completely defined.  The addon is going to integrate directly with BrowserID providing the user with a seamless login experience.  Session and identity management are working their way into the browser more and more, and we think this is a good thing from both ease of use and security perspectives.  Soon, instead of logging into individual sites, you are going to be logging into your browser which will then take care of 90% of the rest of the work.</p>
<h2>Conclusion</h2>
<p>So things are pretty awesome, slowly we are bringing the user&#8217;s identity into the browser and providing a single place for the user to go for all of their session management tools.  We are providing a mechanism for the user to instantly know who they are currently signed in as.  We are working towards providing support for multiple sessions and being able to easily switch between two logins.  We integrate well with BrowserID.</p>
<p>Sure there are some rough spots, this is still an experimental product.  That is where you come in.  We need feedback.  We need people to install the addon and tell us what they think.  We need sites to implement the API and tell us where their pain points are and what can be changed, improved, added and removed.  If you are so inclined, you can even <a href="https://github.com/mozilla/browserid_addon">fork the repo</a> and submit pull requests.  I have rarely been submitted a pull request that I didn&#8217;t like (who is going to turn down free work?).  This should be community driven.</p>
<h3>Interested?</h3>
<p>Get the <a href="https://github.com/mozilla/browserid_addon/raw/develop/addon/dist/browserid_addon.xpi">addon</a> from GitHub or <a href="https://addons.mozilla.org/en-US/firefox/addon/browser-sign-in/">AMO</a>.<br />
Reach me directly at <a href="mailto:stomlinson@mozilla.com">stomlinson@mozilla.com</a>.<br />
Subscribe to the <a href="https://lists.mozilla.org/listinfo/dev-identity">identity mailing list.</a><br />
Join us on IRC at #identity @irc.mozilla.org.</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Mozilla%E2%80%99s+Session+API+Tutorial+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D477" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;title=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;title=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;t=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;title=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;title=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/&amp;title=Mozilla%E2%80%99s+Session+API+Tutorial" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/mozilla-session-api-tutorial/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PHP BrowserID Verifier</title>
		<link>http://www.shanetomlinson.com/2011/browserid-verifier-php/</link>
		<comments>http://www.shanetomlinson.com/2011/browserid-verifier-php/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 09:34:35 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[BrowserID]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=480</guid>
		<description><![CDATA[This is the first PHP code I have written in YEARS, so any comments would be welcome! I am in the middle of writing a MediaWiki extension for BrowserID and thought this might help some people out who are looking &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2011/browserid-verifier-php/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>This is the first PHP code I have written in YEARS, so any comments would be welcome! I am in the middle of writing a <a href="http://mediawiki.org" title="MediaWiki" target="_blank">MediaWiki</a> extension for <a href="https://browserid.org" title="BrowserID" target="_blank">BrowserID</a> and thought this might help some people out who are looking to get started with plugins of their own.</p>
<p>I am using cURL to do the actual verification, the only thing that baffles me is how the response to the cURL request gets returned as the value of the GET request that calls this code.  Any suggestions/reasons would be greatly appreciated!</p>
<pre>

&lt;?php 

Class BrowserIDVerify {
  public static function login($audience, $assertion) {
    $url = "https://browserid.org/verify";
    $data = array(
      'audience'=&gt;$audience,
      'assertion'=&gt;$assertion
    );
    return BrowserIDVerify::do_post_request($url, $data);
  }

  private static function do_post_request($url, $data) {
    $data_string = http_build_query($data);

    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,count($data));
    curl_setopt($ch,CURLOPT_POSTFIELDS,$data_string);
    $result = curl_exec($ch);
    $info = curl_getinfo($ch);

    curl_close($ch);

    // If anybody could explain to me how/why the result gets returned
    // as the response to the initial GET request that calls this code,
    // I'd be very grateful.
    return '';
  }

}

?&gt;
</pre>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=PHP+BrowserID+Verifier+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D480" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;title=PHP+BrowserID+Verifier" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;title=PHP+BrowserID+Verifier" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;t=PHP+BrowserID+Verifier" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;title=PHP+BrowserID+Verifier" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;title=PHP+BrowserID+Verifier" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/browserid-verifier-php/&amp;title=PHP+BrowserID+Verifier" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/browserid-verifier-php/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/browserid-verifier-php/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Web Intents/Activities as The Future of Web Development &#8211; A Fundamental Shift</title>
		<link>http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/</link>
		<comments>http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 02:20:20 +0000</pubDate>
		<dc:creator>Shane Tomlinson</dc:creator>
				<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[OpenWebApps]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shanetomlinson.com/?p=447</guid>
		<description><![CDATA[After reading both Paul Kinlan&#8217;s article on Web Intents and Ben Adida&#8217;s on what is happening with activities at Mozilla Labs, I thought it would be a great time to write an article about how this is currently being played &#8230;<p class="read-more"><a href="http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/">Read more &#187;</a></p>]]></description>
			<content:encoded><![CDATA[<p>After reading both Paul Kinlan&#8217;s <a href="http://paul.kinlan.me/web-intents-a-fresh-look#comment" target="_blank">article on Web Intents</a> and Ben Adida&#8217;s on <a href="http://mozillalabs.com/blog/2011/07/web-apps-update-experiments-in-web-activities-app-discovery/" target="_blank">what is happening with activities</a> at <a href="http://mozillalabs.com" target="_blank">Mozilla Labs</a>, I thought it would be a great time to write an article about how this is currently being played out at Mozilla.</p>
<p>As Paul points out in the closing line of his article &#8211; &#8220;This project will fundamentally change and improve the way we build applications on the web today for our users.”  His words perfectly describe how we are feeling at Mozilla as well.  Change is coming, and the change is going to be nothing short of revolutionary.</p>
<p>If you have not read anything on the purpose of Web Intents/Activities, Mike Hanson from Mozilla has a very thorough article outlining the <a href="http://www.open-mike.org/entry/using-web-applications-for-service-discovery" target="_blank">need for service discovery in web applications</a>.  Paul has written an <a href="http://webintents.appspot.com/" target="_blank">excellent introduction</a> on how intents can solve these issues.  Ben from Mozilla shows a demo of <a href="http://mozillalabs.com/blog/2011/07/web-apps-update-experiments-in-web-activities-app-discovery/" target="_blank">what can be done</a> using the New York Times and Flickr as an example.</p>
<h2>The Problem &#8211; Lack of Flexibility, Cluttered Interfaces</h2>
<p>To explain the problem, I&#8217;ll continue with the example that Paul mentions.</p>
<p>Imagine that you are a developer writing an image editing web app at &#8220;imageeditor.com&#8221;.  You want to allow the user to select a photo to edit, perform some sort of modification, and then save the image.  But, you want the user to be able to select a photo that is stored on either SmugMug, Picassa, Flickr, Instagram, or on their hard drive.  Using current technologies a button is presented to import a photo from each of these potential services, whether the user has an account there or not.  In this scenario five buttons are displayed, when the user may only be interested in one.  The extra buttons clutter up the interface, increase cognitive load on the user, and in the end may not even provide the user actually uses &#8211; perhaps all their photos are stored on Facebook.  So, as the app developer, you add a new button for Facebook.  Now there are 6 buttons displayed.  Another user tomorrow requests a button for Google+.  This madness is referred to as the <a href="http://factoryjoe.com/blog/2009/04/06/does-openid-need-to-be-hard/" target="_blank">NASCAR effect</a>.  There has to be a simpler way.</p>
<h3>Let&#8217;s Simplify</h3>
<p>From a user&#8217;s perspective, a better way is to present the user with one button &#8211; &#8220;Get Photo&#8221;.  Pressing this button then presents the user with a list of services that are actually relevant to them.  The user selects the photo from their site of choice and finally the photo data is returned to the image editing application.</p>
<p>From the developer&#8217;s perspective, a better way is to write code once and only once.  As a developer, I do not want to add a new button every time a new image storage application comes online.  As a developer, I do not want to have to write login routines nor store OAuth information for a myriad of services.  I want things to be clean, usable, secure, and automatic.  As a developer, I want to say &#8220;the user needs an image&#8221;, and let the rest of the work be taken care of for me.</p>
<p>A pipe dream?  Thankfully, no.</p>
<p>The coming model is going to change all of this.  Instead of every site having to build out/provide/include every necessary component, a page will be able to request information and functionality that is provided by a third-party app.  What does this mean?  The concept is simple.  Currently, every component that a site needs must be built by the app developer or included from a third party library.  Services and Intents aim to change this, instead of having to directly include code to provide a component, the app can ask the browser if any installed third party applications provide the necessary component.</p>
<h2>The Coming Reality &#8211; Installable Apps and Web Activities/Intents</h2>
<p>Both Mozilla and Google are working to make this a reality, and sooner than you think.</p>
<p>The idea that both companies have is that you should be able to &#8220;install&#8221; a web app into the browser.  These apps are nothing more than standard HTML5 pages, pages that use open, standards based HTML5 technologies that you are already using today.  The difference is that these pages provide some extra information that allows the browser to handle them as installed applications.  </p>
<p>These apps can either provide or consume bits of functionality, for instance maybe an installed Flickr app provides functionality to get an image.  When a second app needs to get an image, it can ask the browser to get it an image.  The browser, knowing that the Flickr app is both installed and can provide images, uses it to get image data.  If multiple apps are installed that provide image data, a dialog <em>showing only the services that the user cares about</em> is presented asking them to select from the list.</p>
<p>Where can this be used?  The possibilities are endless, but common scenarios include &#8220;Share with&#8221;, file retrieval/save, &#8220;save to calendar&#8221;, contact list management, and profile management.  Imagine having one definitive profile that can be used to feed profile information to all other apps requesting this information.</p>
<h2>The Mozilla Open Web Apps API</h2>
<p><strong>Note, this API *IS* going to change.  Both Mozilla and Google are working hard to create a common interface.</strong></p>
<p>So far, Mozilla&#8217;s take on using a service is slightly different than Google&#8217;s, but both companies are hard at work trying to find a common API that is optimal from both a user and developer perspective.</p>
<p>Mozilla Labs is rapidly piecing together the <a href="https://github.com/mozilla/openwebapps/" target="_blank">OpenWebApps plugin</a> for Firefox that provides native browser functionality for their proposed API.  Unfortunately for us at Mozilla, not the entire world runs Firefox.  For browsers that support a minimum of the HTML5 window.postMessage and localStorage, there is a polyfill that can be used to provide the same functionality. The polyfill can be included directly from <a href="https://myapps.mozillalabs.com/jsapi/include.js" target="_blank">https://myapps.mozillalabs.com/jsapi/include.js</a></p>
<p>The Mozilla API is documented on <a href="https://developer.mozilla.org/en/OpenWebApps" target="_blank">MDN</a>.  <a href="https://developer.mozilla.org/en/OpenWebApps/Getting_Started" target="_blank">Getting Started</a> gives a very good introduction into the goals of the project.  The window.navigator object is augmented to provide the app API under:</p>
<pre>
navigator.apps.*
</pre>
<h3>Application Manifest</h3>
<p>The first portion of a web app that a developer will care about is the <a href="https://developer.mozilla.org/en/OpenWebApps/The_Manifest" target="_blank">manifest</a>. The <a href="https://developer.mozilla.org/en/OpenWebApps/The_Manifest" target="_blank">application manifest</a> is a completely separate beast than the <a href="http://www.w3.org/TR/html5/offline.html#introduction-4" target="_blank">W3C offline application manifest</a>, but they can be used together.</p>
<p>The application manifest is a JSON object that provides the information necessary to install and run the app.  It includes things like application name, author name, author page, as well as a list of services that the application &#8220;provides,&#8221; and may include in the coming months a list of services that the application &#8220;consumes.&#8221;  More on what it means to provide or consume services later.</p>
<h3>Application Installation</h3>
<p>As an app developer, you are going to want users to install your app.  To do this, the navigator.apps.install function must be called, generally this is done from a button press.  Calling this will cause the browser to ask the user whether they want to install your app.  If the user approves, your application&#8217;s manifest will be requested and the app will be installed.</p>
<p>This call takes the form of (taken from MDN):</p>
<pre>
navigator.apps.install({
    url: "http://path.to/my/example.webapp",  /* path to the manifest */
    onsuccess: installCallback,
    onerror: errorCallback
});
</pre>
<p>So that you don&#8217;t annoy users, before presenting them with an install button, you can call navigator.apps.amInstalled to check whether your app is installed or not.</p>
<pre>
/* Check if the current page is installed as an app */
navigator.apps.amInstalled(callback);
</pre>
<p>MDN provides information on many <a href="https://developer.mozilla.org/en/OpenWebApps/The_JavaScript_API#Management_API_%28navigator.apps.mgmt.*%29" target="_blank">other functions</a>, but these are mainly of interest to Dashboards and Stores.</p>
<h3>Service Invocation</h3>
<p>The most important feature not yet outlined in MDN relates to service invocation.  This goes back to a photo editing site requesting a photo.</p>
<p>Earlier, I mentioned the notions of service providers and service consumers.  What do these mean?  In this scenario, &#8220;imageeditor.com&#8221; is the consumer of a service, the service of getting a photo.  Flickr, Picassa, or SmugMug are providers of a service, the service of giving a photo.  There is the notion of a mediator as well, this is normally taken care of by the browser.</p>
<p>Continuing with our example, this is how service invocation works:</p>
<ol>
<li>imageedit.com is the consumer.  The site makes a request to invoke a service, we will call the service &#8220;image.get.&#8221;</li>
<li>The mediator (normally the browser) sees that a service invocation request came from imageeditor.com, it looks in its list of installed applications for any that provide &#8220;image.get.&#8221;  It sees that the user has Flickr and Picassa installed.  The mediator asks the user to choose one of these, or to cancel the request.  Cancelling effectively denies access to imageeditor.com to make use of the service.  For this example, assume the user selects Flickr.</li>
<li>Flickr is the provider.  The Flickr app is informed that a request has been made for &#8220;image.get,&#8221; without ever knowing which app/site the request came from.  The Flickr app then presents the user with an interface where the user can select an image.  Once the user selects an image, it then sends the image data back to the mediator who proxies the data back to the originating app.
</li>
</ol>
<p>An important thing to know is that Flickr and imageedit.com know nothing of each other unless they explicitly share this information.  imageedit.com knows that it requested and received a photo.  Flickr knows that somebody requested a photo so it sent one.</p>
<p>The name of the service, &#8220;image.get&#8221; must be agreed upon by the two applications for the invocation to happen.  At this point there is no standards organization or process to decide on names and it is hoped that these will develop naturally and de facto standards will emerge.</p>
<h4>Provider Side &#8211; Back to the Manifest</h4>
<p>For an app to be discovered by the mediator, it must declare which services that it provides.  Mozilla&#8217;s proposal is to have this declaration take place in the <a href="https://developer.mozilla.org/en/OpenWebApps/The_Manifest" target="_blank">application manifest</a>.  Services are still experimental so their declarations are placed under the &#8220;experimental&#8221; section.  The exact form of this is still under heavy development and will likely change.</p>
<pre>
"experimental": {
    "services": {
        "service_name": {
            "endpoint": uri
        }
    }
}
</pre>
<p>An example of this for our Flickr provider could be:</p>
<pre>
"experimental": {
    "services": {
        "image.get": "/service_imageGet.html"
    }
}
</pre>
<p>What this means is that with the Flickr app installed, it can provide the service &#8220;image.get&#8221;.  &#8220;/service_imageGet.html&#8221; on the application&#8217;s server will be called to complete the task whenever another app requests &#8220;image.get&#8221;.</p>
<h5>Setting Up Communication</h5>
<p>Within &#8220;/service_imageGet.html&#8221; there has to be logic that says how to handle the service invocation.  At the moment, this too is under heavy development and being cleaned up.  For a provider to register which function to call within the provider page, it must register a handler for the service.  This is done using navigator.apps.services.registerHandler.</p>
<p>The form of the call is:</p>
<pre>
navigator.apps.services.registerHandler(serviceName, serviceHint, callback);
</pre>
<p>More concretely:</p>
<pre>
navigator.apps.services.registerHandler('image.get', 'getImage',
    function(args, callback) {
        // get image, place into imageData;
        var imageData = getImageData();
        callback({image: imageData});
    }
);
</pre>
<h4>Consumer Side &#8211; Invoking a Service</h4>
<p>For a consumer site or app to request to use a service, it uses navigator.app.invokeService.  The form of the call is:</p>
<pre>
/**
* Request to use a service
* @param {string} serviceName - name of the service to invoke
* @param {object} callData (optional) - optional data to pass to service provider
* @param {function} onSuccess - function to call on success.
* @param {function} onFailure - function to call on failure.
*/
navigator.apps.invokeService({
    serviceName,
    callData,
    onSuccess,
    onFailure
});
</pre>
<p>In our example, imageeditor.com wants an image that it can edit.  It uses navigator.apps.invokeService:</p>
<pre>
navigator.apps.invokeService({
    "image.get", null,
    function(data) {
        // handle success case.
        // data.image will be the imageData returned from above.
    },
    function(data) {
        // handle failure case
    }
});
</pre>
<h2>Conclusion</h2>
<p>So there it is, an overview of what is coming down the line.  Unfortunately, at the moment, I don&#8217;t have personally written examples of all of this in action.  Mozilla Labs has an <a href="https://apps.mozillalabs.com/appdir/" target="_blank">example application</a> page that shows how app installation and manifests work.  The <a href="https://github.com/mozilla" target="_blank">Mozilla account</a> on GitHub has several examples that can be run, most importantly is the site/tests directory in <a href="https://github.com/mozilla/openwebapps/" target="_blank">openwebapps</a> and the <a href="https://github.com/mozilla/openwebapps-photosite-connector" target="_blank">openwebapps-photosite-connector</a>.</p>
<p>Shorter posts with more detail are planned as these APIs are solidified.  These posts will have fuller explanations and examples. </p>
<p>Finally, I agree with Paul, these new technologies are going to fundamentally change the webapps ecosphere as we know it &#8211; it is an exciting time to be a developer.  See you soon!</p>
<div class="tweetthis" style="text-align:left;"><p> <a class="tt" href="http://twitter.com/intent/tweet?text=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift+http%3A%2F%2Fshanetomlinson.com%2F%3Fp%3D447" title="Post to Twitter"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/twitter/tt-twitter.png" alt="Post to Twitter" /></a> <a class="tt" href="http://delicious.com/post?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;title=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to Delicious"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/delicious/tt-delicious.png" alt="Post to Delicious" /></a> <a class="tt" href="http://digg.com/submit?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;title=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to Digg"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/digg/tt-digg.png" alt="Post to Digg" /></a> <a class="tt" href="http://www.facebook.com/share.php?u=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;t=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to Facebook"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/facebook/tt-facebook.png" alt="Post to Facebook" /></a> <a class="tt" href="http://www.google.com/buzz/post?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;imageurl=" title="Post to Google Buzz"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/gbuzz/tt-gbuzz.png" alt="Post to Google Buzz" /></a> <a class="tt" href="http://reddit.com/submit?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;title=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to Reddit"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/reddit/tt-reddit.png" alt="Post to Reddit" /></a> <a class="tt" href="http://slashdot.org/bookmark.pl?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;title=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to Slashdot"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/slashdot/tt-slashdot.png" alt="Post to Slashdot" /></a> <a class="tt" href="http://stumbleupon.com/submit?url=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/&amp;title=Web+Intents%2FActivities+as+The+Future+of+Web+Development+%E2%80%93+A+Fundamental+Shift" title="Post to StumbleUpon"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/su/tt-su.png" alt="Post to StumbleUpon" /></a> <a class="tt" href="http://technorati.com/faves?add=http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/" title="Post to Technorati"><img class="nothumb" src="http://www.shanetomlinson.com/wp-content/plugins/tweet-this/icons/en/technorati/tt-technorati.png" alt="Post to Technorati" /></a></p></div>]]></content:encoded>
			<wfw:commentRss>http://www.shanetomlinson.com/2011/intent_activity_invoke_fundamental_shift/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

