Wednesday, April 21, 2010

Showing events from multiple public Google Calendars using your own custom CSS

Today I hacked some code to produce a result I know others are looking for, so I thought I would share. So far what I have is the result of of an hour or so exploring the code to see if this was possible. In other words, there is room to make this much more elegant and I hope to do so at some point.

The seed of the issue is the inane inability to cusomize the color of the frame when embeding a Google Calendar. That really, really ought to be fixed by Google.

One solution to this problem which I found (yes, by Googling it...) is "calvis". The project home page is here: http://code.google.com/p/calvis/

Calvis uses the Google Data API to pull down calendar events and display them in on screen using JavaScript.

Unlike the embeded calendar, Calvis does not support displaying multiple Google Calendars. There is some discussion of this issue on the site's issue tracker (issue #3). This is the problem for which I now have a working solution.

Note that this solution has only been tested for the cases where all calendars used are public and will probably not work in its current form for private calendars.

Here's what I did:

The majority of the changes are within calvis-core.js and you can download the diff here.

1) I don't think it matters, but for what it's worth I replaced the projects jQuery 1.3.2 with the latest 1.4.2

2) I added a new variable, calList to the variables defined in the main() javascript funtion which is defined in-line on the calendar page. This variable holds an array of the calendars to be combined. Here's what my declaration looks like:

var calList = [ 'google@communitygreenguide.org',
'b0prga519c0g0t3crcnc0g9in0@group.calendar.google.com' ];

3) Also within the main() javascript function on the calendar page, I set the calList variable within the Calendar object, using a new setCalList() method defined in calvis-core.js (more on this in a minute).

calendar.setCalList(calList);

4) In the Calendar constructor, create a calList variable set to null:

this.calList = null;

5) Defind the setCalList() method:

calvis.Calendar.prototype.setCalList = function(calList) {
this.calList = calList;
}

6) Modify the existing getFeedUrl() method so that it returns an array of calendars and not just one calendar feed:

calvis.Calendar.prototype.getFeedUrl = function() {

feedUrlArray = new Array();
calList = this.calList;

for( var i=0; i < calList.length; i++ ) {
feedUrlArray[i] = ['http://www.google.com/calendar/feeds/',
calList[i], '/', this.visibility, '/full'].join('');
}

return feedUrlArray;
};


7) Change some code in the initLoginControl() method so that it can deal with getting an array of calendars. I don't believe this code will actually serve any purpose since we're only using public calendars, so I just use the first calendar in the array.

var feeds = calendar.getFeedUrl();
var scope = feeds[0];

8) In the two places overlayGData() is called, modify the calling code so that it calls overlayGData() once for each calendar, passing in the feedUrl as an attribute. This code appears near the bottom of the updateWeekView() method and at the bottom of the updateMonthView() method:

var feedUriArray = this.getFeedUrl();
calendar = this;
for( var i=0; i< feedUriArray.length; i++ ) {
calendar.overlayGData(firstDate, lastDate, feedUriArray[i]);
}

9) Change the method signature of overlayGData so that it will acced the feedUri as a parameter:

calvis.Calendar.prototype.overlayGData = function(startDate, endDate, feedUri)

10) Remove the line in the existing overlayGData() method that retrieved the feedUri from the object:

var feedUri = calendar.getFeedUrl();