December 30, 2006
GCalendar: Accessing Google Calendar from JavaScript
Introduction
Some weeks ago Google has added a nice new feature to their GData libraries: JSON data retrieval. This means that we now can retrieve data from some services of Google (Base, Blogger and Calendar for now) without having to proxy it through our servers (if you still don’t know, after thousands of posts about Cross-Domain issues, why you need to do this, just look here).
Why can we do this? Because we can just create a <script>-Element, points the src to the feed URL and tell the GData API what function to call upon load.
var headTag = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = feedurl;
headTag.appendChild(script);
I was a bit sorry to see that Google doesn’t
provide an API for Client side JavaScript. So once again, in one of those “don’t complain,
do it better“-moments I figured it would be nice to write it myself for the Calendar.
Off course some stuff can’t be done with JavaScript, we can only retrieve data, not submit new
data to Google, so we can’t add new entries directly, but hey it’s a start
The library
We start off by modelling the Entry class, as you might easily figure out by the following code we rely on the Prototype library.
var EventEntry = Class.create();
EventEntry.prototype = {
title: null,
content: null,
startDate: null,
endDate: null,
location: null,
initialize: function(entry){
this.title = entry.title.$t;
this.content = entry.content.$t;
this.startDate = DateConverter.rfc3339toDate(entry.gd$when[0].startTime);
this.endDate = DateConverter.rfc3339toDate(entry.gd$when[0].endTime);
this.location = entry.gd$where[0].valueString;
}
};
Next we create a class that takes care of loading the feed, calling the callbacks and so on.
var Calendar = Class.create();
Calendar.prototype = {
uri: "7cghno42lleqpbihmoi5qiikm8%40group.calendar.google.com",
orderby: "starttime",
singleEvents: true,
futureEvents: true,
sortOrder: "ascending",
entries: {},
initialize: function(u){
if(u){this.uri = u;}
},
buildURL: function(){
var str = "http://www.google.com/calendar/feeds/";
str += this.uri;
str += "/public/full-noattendees?orderby=" + this.orderby;
str += "&alt=json-in-script&callback=window.activeCalendar.parseFeed&";
str += "singleevents=" + this.singleEvents;
str += "&sortorder=" + this.sortOrder;
str += "&futureevents=" + this.futureEvents;
return str;
},
loadFeed: function(){
window.activeCalendar = this;
var headTag = document.getElementsByTagName('head')[0];
var script = document.createElement("script");
script.src = this.buildURL();
script.language = "JavaScript";
headTag.appendChild(script);
},
parseFeed: function(json){
e = json.feed.entry;
for(var i=0;i < e.length;i++){
this.entries[i] = new EventEntry(e[i])
}
try {
this.onsuccess(this);
} catch (e) {}
},
onsuccess: function(c){}
};
Notice the first line of the loadFeed? Yep, it’s a workaround, and an ugly one too. The problem
is that we want to have access to the Calendar-object once we have the feed data. So we add it
to the window-object. Anyway, this is the reason why you can load only one calendar at once.
And what would we be without some really ugly utility objects? So here you go, a pretty useless
date converter class:
/**
* Singleton object used to convert Dates from one format to another.
*/
var DateConverter = {
rfc3339toDate: function(t){
t = t.substr(0,19).replace(/-/g,"/").replace("T"," ");
var dt = new Date();
dt.setTime(Date.parse(t));
return dt;
}
};
So after all this code that you don’t have to write (because you can download it all here) now some code you have to write.
How to use it
I tried to keep it as simple as possible, if there are enough requests I may well extend it further, but for now it works nicely as it is. First you have to find out the feed identifier. Take the Feed URL as can be found in Google Calendar in the Calendar details and it will look something like this:
http://www.google.com/calendar/feeds/7cghno42lleqpbihmoi5qiikm8%40group.calendar.google.com/public/basic
Take the bold part and that’s the Feed Identifier that will then be used to create the instance of the Calendar:
var cal = new Calendar("7cghno42lleqpbihmoi5qiikm8%40group.calendar.google.com");
Next thing we need to do is add a callback function that is called once the Feed is loaded, and then kick the request off:
cal.onsuccess = function(c){alert(c);}
cal.loadFeed();
And that’s it
Now let’s see what we can do with it, and the reason I started fiddling with the Calendar in
the first place. My custom frontend to one of my calendars can be seen
here.
11 Comments
Gmail has added a feature that allows you to read mail from any other non-Gmail account within the Gmail interface.
To say this is convenient is an understatement. Set-up looks like a snap, and you can add up to five non-Gmail accounts.I’ll be able to consolidate my Yahoo, Outlook, and Hotmail accounts within about five minutes flat if I’m lucky. For the privacy conscious, you can disable email archiving (it’s not set by default), and you can also disable importing non-Gmail mail anytime you want to very easily.