In this article I’ll be showing you how to make a quick app that gets your location and at your request stores the information to your browser, as well as showing you how to use drag and drop to send a short tweet. This is all made possible thanks to the javascript APIs being developed at the moment in the new HTML5 specification, so lets find out a little more about what’s new in HTML5 and why the javascript APIs are so flipping awesome.
New HTML, new possibilities
I’m pretty sure everyone reading this will have at least heard something about HTML5… if not then what were you doing last year? Anyway I digress… HTML5 is definitely beginning to come in to play and change the shape of the web as we know it, and thankfully not many people are paying attention to the supposed 2022 completion date for the spec. With HTML5 comes new tags, new attributes, new semantics, but most importantly, new toys to play with! And today it’s these new toys we’re going to be concentrating on.
HTML5 brings a plethora of new APIs to play with, but as this is only meant to be a short introduction to something new I’m only going to play with a few of them. Some of the other toys you might want to play with are things like canvas, history, messaging, offline applications and the file API. Of course there are still loads of fantastic resources out there for you to learn about these as well and I’ve helpfully listed them at the end of the article for you to go and check out once you’ve finished playing here.
What toys are we going to be playing with
So now I’ve told you a little bit about HTML5 and some of the APIs available lets roll up our sleeves and get our digits dirty. So like I said at the start we’re going to create an application which grabs your location, asks whether you’d like to store that in the browser and then you can even use it to send a tweet via the web page. So by now you’ve probably guessed at least one of the APIs we’ll be using… no? Well here’s the details then:
Altogether we’ll be using 3 of the new HTML5 APIs:
- Geolocation
- Web storage (more specifically localStorage)
- Drag and Drop
So I’m going to shut up now and get cracking on the fun part, the code!
Getting local
Ok, so I was lying a little bit, I’m going to tell you a little bit about Geolocation first and then we’ll get to some code, I promise. So what geolocation does is pretty self explanatory I guess, however so far I’ve been telling you a small white lie when it comes to Geolocation (sorry) it’s not actually an HTML5 API at all! It’s part of a separate specification from the W3C but I’m sure you all already knew that! But it’s still really cool and allows you to do some fun things so lets not quibble over details. The first thing to mention is that Geolocation has major implications for people’s privacy, so very sensibly the specification says that the user must give explicit permission for the API to be allowed to run. On the plus side this is all taken care of by the browser so for us we don’t actually have to do anything.
So first what we need to do is check whether Geolocation is supported by the browser, to do this there is a handy function which we can run which returns true or false:
`if (navigator.geolocation) { // yay let's play :D } else { // sorry no geolocation support :( }`
Once we’ve checked that there’s support for geolocation we can run the method to get the users position. We have two options of how to do this, ‘getCurrentPosition’ and ‘watchPosition’; ‘getCurrentPosition’ is a one off and only returns once whereas ‘watchPosition’ will return every time the users position changes – handy eh! For now we’re going to just concentrate on the ‘getCurrentPosition’ method as we just want to grab the position the one time and store it in the browser. However both methods are handled in the same way so fundamentally they are the same.
getCurrentPosition
The ‘getCurrentPosition’ method takes 3 arguments with only the first one actually required but I’m not going to let you off that lightly, here’s the 3 arguments you can pass to the method:
- successCallback (required)
- errorCallback
- options
- enableHighAccuracy
- timeout
- maximumAge
So lets see it in action:
// setting a decent timeout value
var timeoutVal = 60 * 1000;
// the geolocation call
navigator.geolocation.getCurrentPosition(
location,
handleError,
{ enableHighAccuracy: true, timeout: timeoutVal, maximumAge: 0 }
);
Nothing revolutionary here I’m afraid, I’ve just set up a timeout value to be a minute and then asked it to use high accuracy with 0 as the maximumAge which means it will try to return a position object instantly ignoring cached positions. Before I get on to what the successCallback will be doing in this app I’ll show you the errorCallback:
function handleError(error) {
var errors = {
1: 'Permission denied',
2: 'Position unavailable',
3: 'Request timeout'
};
alert("Error: " + errors[error.code]);
}
There’s 3 possible errors that the `getCurrentPosition` function can return and so all we’re doing here is catching the error and well very unhelpfully using an alert function to show a message to the user, this could be done so much more elegantly (and not just copied straight from the html5doctor article) but we’re here to have fun aren’t we? So onto the good stuff…
Here’s what we’re going to do with the successCallback function:
function location(position)
{
var lat = position.coords.latitude,
lng = position.coords.longitude;
show_address(lat,lng);
}
Well that was a bit of an anticlimax wasn’t it…Well for this app there’s not really much more that we need to get from the function so I’m going to keep it simple. The function actually returns a lot more information than this, things like the accuracy of the location returned in metres, the altitude, the heading and speed, as well as a timestamp for when the location was retrieved. But that’s more than we actually need for this app so we’ll just, well, ignore those bits and just take the things we need.
Now you may have noticed that what’s been returned from the function is only really useful if we were going to plot the position on a map or something similar, but seen as we’re going to store this information in a nice way for the user to look back over their recent adventures the longitude and latitude isn’t really going to be of much use as they are. Well this is where we call on a handy little thing called geocoding.
Geocoding
Geocoding is the process of taking an address and turning it into latitude and longitude values so that it can be plotted on a map, but as we’ve already got the those we’ll need to do what’s called reverse-geocoding to get a readable address from the values. Now I spent quite a lot of time searching for the best way to do this using strictly javascript as I don’t want to have to do anything server-side in this app, the best way I found to do it was via Yahoo and their YQL (Yahoo Query Language) which can be used to request information from many of their web APIs. So here’s how we’re going to get the current address:
function show_address(lat, lng)
{
var url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text%20%3D%20%22"+lat+","+lng+"%22%20and%20gflags%3D%22R%22&format=json";
$.getJSON( url , function(data) {
var loc_data = data.query.results.Result,
locale = loc_data.street + ", " + loc_data.city + ", " + loc_data.country;
$("article h3 em").html( locale );
});
}
This was the function that was being called with the latitude and longitude values returned from the getCurrentLocation function, this takes those values and puts them into a Yahoo YQL query which is then retrieved by some jQuery and the result is built up from the returned data. That information is then added to the html via a bit of jQuery (as I’m being a bit lazy and it’s not really about these small bits).
NB: we’re going to be storing this data unencrypted in the browser (not the most secure thing) so I would strongly recommend not doing anything like this for a commercial product, the reason I’m doing this is to give you an introduction to a few APIs at once, also I wouldn’t normally use the street name on this type of application either but again I’ve done this so you can have a play without driving between towns :)
So there we go, we’ve now retrieved the user’s current location using the geolocation API and with a bit of reverse-geocoding we’ve shown them where they are in English! Next we’re going to give the user the option of saving this data to the browser…
No more cookies! Introducing web storage
So now we have the users location we’re going to store it to the browser so we can access that data later on when the user returns to the app and this is where the web storage API comes in. Again though I should mention that this API has now been moved from the HTML5 spec into it’s own specification.
So what does web storage offer? It gives us as developers a really simple way to store data to the browser both for the long term and short term using local storage and session storage respectively. Session storage is only kept whilst the browser is open and only in the one window or tab where the data was stored whereas local storage is persistent and will be kept even when the user has fully closed down the browser. What I’m going to show you today is local storage but again as with getPosition and watchPosition in the Geolocation API the principles are exactly the same.
There are quite a few methods that can be used for localStorage however they are all set up as getters, setters and deleters which means the code needed to use localStorage is extremely simple:
localStorage.name = “Adam”;
instead of:
localStorage.setItem(“name”,”Adam”);
which to be honest isn’t that much more confusing but it does save some time. Again to delete is just a simple:
delete localStorage.name;
This bit of code performs the method removeItem on the name localStorage variable instead of having to write that out ourselves.
There is also a handy way of checking when data has been stored to the browser via storage events. These events fire on any other window/tab where you have the site open, this means that you can detect any new data that may be stored by the user in another window and make use of it in the current window. This could be extremely handy if a user were ever asked to enter data that they may want to use in another window they have open therefore taking away the need for them to refresh the browser if for instance you were using cookies. So here’s a simple function to catch a storage event and do something with it – also included is support for IE8 by checking for the attachEvent, should you need to.
// The storage event handler, this will fire if there is data stored to the browser but in another window!
function storageEvent(e) {
e = event || window.event; // more IE8 support :(
alert("key " + e.key);
alert("newValue " + e.newValue);
}
// On storage events.
if (window.attachEvent) { // IE8 support
window.attachEvent('onstorage', storageEvent);
} else {
window.addEventListener('storage', storageEvent, false);
}
Complex data
Now we know how to store data to the browser I must mention one thing however. Currently it’s not possible to store anything more than strings in web storage, so for now if you want to store anything more complex you will need to use JSON to encode and decode arrays into strings for the storage to work. A bit like this:
// encode an array as a string using JSON
localStorage.locations = JSON.stringify( sLoc );
and
// decode a string to an array using JSON
sLoc = JSON.parse( localStorage.locations );
And that’s all there is to know about web storage for this app… next we’re going to add one last little touch to the app with the Drag and Drop API.
A little drop more
Drag and drop isn’t really anything new, it’s been around for donkey’s years in all different guises but now we’re able to talk about actual native drag and drop using the new HTML5 API. So this is actually the one and only API I will be talking about that is still in the HTML5 web spec, however it’s not actually that new, it’s based from something Microsoft developed for IE5!!
Again drag and drop is actually pretty simple and doesn’t really need that much code to get working, all you need to do is have something to drag, somewhere to drop it and a bit of javascript to be called when someone drops the draggable thing on the drop target. Simple.
There are elements that are draggable by default and then there are the other elements that we’ll need to set an attribute for and write a quick bit of code for to make them draggable. The <a>
and <img>
elements are both draggable by default, you may have even used them before without thinking about it, have you ever dragged an image into a new tab to view the image on it’s own? Well that’s an example of a draggable element.
To allow other elements to be draggable you should just need to set the draggable attribute to true, but unfortunately when trying this out, it wasn’t as simple as I’d hoped. HTML5 Doctor mentions that there is some javascript needed for it to work in Firefox however when I was working with it in Chrome it wasn’t working for me until I applied these small bits of javascript and CSS.
So, for any element you wish to be draggable as well as adding the draggable=”true” attribute to the element you need to add this bit of CSS:
-khtml-user-drag: element;
and this bit of javascript for it to work in Firefox (and Chrome from my experience):
// Get all draggable elements
var dragItems = document.querySelectorAll('[draggable=true]');
// Set up the drag elements with dragstart
for (var i = 0; i < dragItems.length; i++) {
addEvent(dragItems[i], 'dragstart', function (event) {
// store the ID of the element, and collect it on the drop later on
event.dataTransfer.setData('Text', this.id);
});
}
Next is to set up the javascript which tells the browser that an element is a drop target and to handle the drop event. To do this we need to first cancel any default action that the browser applies so that it knows we can drop the currently dragged item on our drop target.
// Tells the browser that we *can* drop on this target
addEvent(drop, 'dragover', cancel);
addEvent(drop, 'dragenter', cancel);
function cancel(e)
{
e.preventDefault();
return false;
}
The reason we have to use both dragover and dragenter and both preventDefault() and return false is for browser support and that’s all I’m going to say on the matter! Next is our drop event:
addEvent(drop, 'drop', function (e)
{
e.preventDefault();
var elem = e.dataTransfer.getData('Text');
tweetpopup( $("#"+elem).text() );
return false;
});
This is a really simple function that again uses both preventDefault() and return false to cancel any default browser action (like following the link if it’s a dragged <a>
tag). The more interesting part of this function is the bit that grabs the data from the element we dropped – remember we set that to be the ID of the element back when we set up the dragstart function – and then use that ID to grab the text from inside the draggable box.
So now we have all of our APIs working we now have the building blocks for a nice little app.
Putting it all together
Right, here’s the building blocks that we have from the APIs we’ve just used:
- The users location made into a readable human address
- A way to store data to the browser to be used the next time the user visits the site
- A way of getting information out of a draggable box when it’s dropped onto another element.
To put them together what we can do is update the text on the page to tell the user their location and update a bit of text in a draggable box that the user can then send to twitter via the dragging the text over to a twitter icon I’ve set up. Then we can ask the user whether they would like to store the data and using a lone input box get the users name along with the users current location adding to that the current time using javascript we can then store that in localStorage.
If the user is returning we check the localStorage to see if any data was stored and if so we can display this on the page for the user to see.
And that’s it. A really quick look at how simple some of the HTML5 APIs can be and how we can get a bit of use out of them to create a really simple app.
I hope you enjoyed playing with the APIs and that you can now take what you’ve done here and go and use that or more realistically build on it to create some really cool features for sites/applications. You can find a link to the completed app in the sidebar under resources as well as a link to the files built during this tutorial. Enjoy!
Some resources and a book!
- HTML5 Doctor – Geolocation
- HTML5 Doctor – Web Storage
- HTML5 Doctor – Drag and Drop
- HTML5 Doctor – Javascript APIs
- .Net Magazine – getting started with HTML5 Geolocation. A really comprehensive article about geolocation and how to use it alongside maps etc.
- A fantastic book from Bruce Lawson and Remy Sharp on all things HTML5 – be patient, 2nd Edition is on it’s way.