Google hCalendar

By Scott Reynen Last update Apr 14, 2006 — Installed 800 times.
// Google hCalendar
// version 1.01
// 2006-04-23
// Copyright 2006, Scott Reynen
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details:
// <http://www.gnu.org/licenses/gpl.txt>
//
// Revision history:
// 1.0  2006-04-13 initial version
// 1.01 2006-04-23 added support for datetimes with space delimiter
//
// ==UserScript==
// @name          Google hCalendar
// @namespace     http://greasemonkey.makedatamakesense.com/googlehcalendar/
// @description   Finds vevents and adds a link to send them to Google Calendar
// @include       *
// ==/UserScript==

( function() {

var innerText = function( node )
{

  var regex = /<\S[^>]*>/g;
  var withHTML = node.innerHTML;
  
  return withHTML.replace( regex , '' );

} // innerText

var trim = function( inString ) 
{
  
  return inString.replace( /^\s+|\s+$/ , '' );
  
} // trime

// Adapted from http://www.forgetfoo.com/?blogid=4077

var getElementsByClassName = function( node , classname )
{

	var a = [];
	var re = new RegExp( '(^| )' + classname + '( |$)' );
	var els = node.getElementsByTagName( "*" );
	for ( var i=0 , j=els.length; i<j; i++ )
		if ( re.test( els[i].className ) ) a.push( els[i] );
	return a;

} // getElementsByClassName

// Adapted from http://delete.me.uk/2005/03/iso8601.html

Date.prototype.setISO8601 = function ( string )
{

    var regexp = "([0-9]{4})(-?([0-9]{2})(-?([0-9]{2})" +
        "([T ]([0-9]{2}):?([0-9]{2})(:?([0-9]{2})(\.([0-9]+))?)?" +
        "(Z|(([-+])([0-9]{2}):?([0-9]{2})))?)?)?)?";

    var d = string.match( new RegExp( regexp ) );

    var offset = 0;
    var date = new Date( d[1] , 0 , 1 );

    if ( d[3] ) date.setMonth( d[3] - 1 );
    if ( d[5] ) date.setDate( d[5] );
    if ( d[7] ) date.setUTCHours( d[7] );
    if ( d[8] ) date.setUTCMinutes( d[8]);
    if ( d[10] ) date.setUTCSeconds( d[10]);
    if ( d[12] ) date.setMilliseconds( Number( '0.' + d[12] ) * 1000 );
    if ( d[14] ) 
    {
    
        offset = ( Number( d[16] ) * 60 ) + Number( d[17] );
        offset*= ( ( d[15] == '-' ) ? 1 : -1 );
        
    } // if

    // offset-= date.getTimezoneOffset();
    time = ( Number( date ) + ( offset * 60 * 1000 ) );
    this.setTime( Number( time ) );

} // Date.prototype.setISO8601

var parseDuration = function( duration )
{

	var regexp = "P(([0-9]+)D)?(T([0-9]+)([HM]))?";
	var d = duration.match( new RegExp( regexp ) );
	var response = 0;
	
	if ( d[2] ) response+= 60 * 24 * d[2];
	if ( d[4] ) response+= ( d[5] == 'H' ) ? 60 * d[4] : d[4];

	return response;

} // parseDuration

var googleDate = function( date )
{

	var year = date.getUTCFullYear();
	var month = date.getUTCMonth() + 1;
	if ( month < 10 ) month = '0' + month;
	var day = date.getUTCDate();
	if ( day < 10 ) day = '0' + day;
	var hours = date.getUTCHours();
	if ( hours < 10 ) hours = '0' + hours;
	var minutes = date.getUTCMinutes();
	if ( minutes < 10 ) minutes = '0' + minutes;
	var seconds = date.getUTCSeconds();
	if ( seconds < 10 ) seconds = '0' + seconds;
	
	return '' + year + month + day + 'T' + hours + minutes + seconds + 'Z';
	
} // googleDate

var addGoogleLink = function( event ) 
{

	var durations = getElementsByClassName( event , 'duration' );
	var duration = 60;
	
	if ( durations.length > 0 ) 
		duration = ( durations[0].title != '' ) ?
			parseDuration( durations[0].title ) :
			parseDuration( innerText( durations[0] ) );

	var dtStarts = getElementsByClassName( event , 'dtstart' );
	var dtStart = '';
	var dtEnd = '';

	if ( dtStarts.length > 0 ) 
	{
	
		var dtStartRaw = ( dtStarts[0].title != '' ) ?
			dtStarts[0].title : innerText( dtStarts[0] );
	
		dtStart = new Date();
		dtEnd = new Date();
		dtStart.setISO8601( trim( dtStartRaw ) );
		dtEnd.setISO8601( trim( dtStartRaw ) );
		dtEnd.setTime( Number( dtEnd ) + ( duration * 60 * 1000 ) );
		
	} // if
	
	var dtEnds = getElementsByClassName( event , 'dtend' );
	if ( dtEnds.length > 0 ) 
	{
	
		var dtEndRaw = ( dtEnds[0].title != '' ) ?
			dtEnds[0].title : innerText( dtEnds[0] );
	
		dtEnd = new Date();
		dtEnd.setISO8601( trim( dtEndRaw ) );
	
	} // if
	
	var locations = getElementsByClassName( event , 'location' );
	var location = ( locations.length > 0 ) ? 
		innerText( locations[0] ) : '';

	var summaries = getElementsByClassName( event , 'summary' );
	var summary = ( summaries.length > 0 ) ? 
		innerText( summaries[0] ) : '';
	
	var descriptions = getElementsByClassName( event , 'description' );
	var description = ( descriptions.length > 0 ) ? 
		innerText( descriptions[0] ) : '';
	

	var googleLink = document.createElement( 'a' );
	var googleImg = document.createElement( 'img' );
	
	googleLink.href = 'http://www.google.com/calendar/event?action=TEMPLATE&dates=' + googleDate( dtStart ) + '/' + googleDate( dtEnd ) + '&location=' + trim( location )  + '&text=' + trim( summary ) + '&details=' + trim( description );
	googleImg.src = 'http://www.google.com/calendar/images/ext/gc_button1.gif';
	googleImg.style.border = '0px';
	googleLink.appendChild( googleImg );

	event.appendChild( googleLink );

} // addGoogleLink

var vevents = getElementsByClassName( document , 'vevent' );

for ( var i = 0; i < vevents.length; i++ )
  addGoogleLink( vevents[i] );

} )();