Google Calendar from Evite

By Jon Parise Last update Nov 3, 2009 — Installed 1,386 times.

There are 5 previous versions of this script.

// ==UserScript==
// @name           Google Calendar from Evite
// @namespace      http://www.indelible.org/
// @description    Replaces the default calendar link in Evite invitations with a Google Calendar link instead.
// @author         Jon Parise
// @version        1.5
// @include        http://www.evite.com/pages/invite/*
// ==/UserScript==

function unwrap(e)
{
    // The desired content may be wrapped in a <div> element.
    var divs = e.getElementsByTagName('div');
    if (divs.length > 0) {
        return divs[0].innerHTML;
    }

    return e.innerHTML;
}

function getMonth(name)
{
    switch (name) {
        case 'January':     return '01';
        case 'February':    return '02';
        case 'March':       return '03';
        case 'April':       return '04';
        case 'May':         return '05';
        case 'June':        return '06';
        case 'July':        return '07';
        case 'August':      return '08';
        case 'September':   return '09';
        case 'October':     return '10';
        case 'November':    return '11';
        case 'December':    return '12';
    }

    return '00';
}

function getDateTime(text)
{
    // e.g. December 31, 7:00PM
    var fields = text.split(' ', 3);

    // e.g. December 31,
    var year = new Date().getUTCFullYear();
    var month = getMonth(fields[0]);
    var day = fields[1].slice(0, -1);

    // e.g. 7:00PM
    var time = fields[2].split(':');
    var hour = parseInt(time[0]);
    var minute = time[1].substr(0, 2);

    // Convert the hour field to 24-hour time if necessary.
    if (hour == 12 && time[1].search(/AM/) != -1) {
        hour = 0;
    } else if (hour < 12 && time[1].search(/PM/) != -1) {
        hour += 12;
    }
    hour = String(hour);

    // Zero-fill the day and hour fields if necessary.
    if (day.length == 1)  day = '0' + day;
    if (hour.length == 1) hour = '0' + hour;

    return [year + month + day, hour + minute + '00'];
}

function parseDates(e)
{
    // e.g. December 31, 7:00PM
    dates = e.innerHTML.match(/(\w+ \d+, )?\d+:\d+(?:AM|PM)/g);

    // We handle events with only a "start" time (in which case the "end" time
    // is set to the start time) or both a explicit "start" and "end" time.
    if (dates.length == 1) {
        dates[0] = getDateTime(dates[0]);
        dates[1] = dates[0];
    } else if (dates.length == 2) {
        // Handle the case where the start and end times are on the same day.
        // Evite only prints the day once in this case, so we borrow the date
        // portion from the start time and prepend it to the end time.
        var dayRE = /\w+ \d+, /;
        if (!dayRE.test(dates[1])) {
            day = dayRE.exec(dates[0]);
            dates[1] = day + dates[1];
        }

        dates[0] = getDateTime(dates[0]);
        dates[1] = getDateTime(dates[1]);

        // Compensate for events spanning the end of the year.
        end = parseInt(dates[1][0]);
        if (end < parseInt(dates[0][0])) {
            end += 10000;
            dates[1][0] = String(end);
        }
    }

    // Lastly, format the UTC dates as Google expects them.
    var start = dates[0][0] + 'T' + dates[0][1];
    var end   = dates[1][0] + 'T' + dates[1][1];

    return [start, end];
}

function parseLocation(e)
{
    var text = unwrap(e);
    text = text.replace(/<br\s*\/?>/gi, ', ');
    text = text.split("\n", 1)[0];

    // Attempt to separate the location string into a place name and an
    // address.  We split the string into comma-delimited parts, and if the
    // first part doesn't start with a number, it is used as the place name.
    //
    // Unfortunately, this fails to work for places whose names start with
    // numbers.  Fixing that probably involves considering the second part and
    // checking if it also starts with a number, in which case the second part
    // is probably the start of the address.  That may be more error prone,
    // however, and the current approach degrades safely.
    parts = text.split(/\s?,\s?/);
    if (parts.length > 1 && parts[0].match(/^\D/)) {
        text = parts.slice(1).join(', ');
        text += ' (' + parts[0] + ')';
    }

    return text;
}

function makeGoogleCalendarLink()
{
    // Event Title
    var title = document.getElementsByTagName('h1');
    if (title) { 
        title = title[0].innerHTML;
    }

    // Event Details
    var detailsIndex = -1, details, loc;
    var whenRE = /When:/, locationRE = /Location:/, phoneRE = /Phone:/;

    var tds = document.getElementsByTagName('td');
    for (var i = 0; i < tds.length; ++i) {
        if (tds[i].className != 'detailsName')
            continue;

        var text = tds[i].innerHTML;
        if (locationRE.test(text)) {
            loc = parseLocation(tds[++i]);
        } else if (whenRE.test(text)) {
            dates = parseDates(tds[++i]);
            detailsIndex = i + 1;
        } else if (phoneRE.test(text)) {
            detailsIndex = i + 2;
        }
    }

    var details = '';
    if (detailsIndex != -1) {
        details = unwrap(tds[detailsIndex]);

        // Trim off any leading whitespace.
        details = details.replace(/^\s*/, '');

        // We need to limit the length of the details string to avoid
        // exceeding the maximum accepted length of the GET request.
        if (details.length > 1000) {
            details = details.substr(0, 1000);
            details += '...';
        }

        // Add some space between the details and the appending Evite link.
        details += "\n\n";
    }
    details += document.location;

    // http://www.google.com/googlecalendar/event_publisher_guide_detail.html
    return 'http://www.google.com/calendar/event' +
        '?action=TEMPLATE&text=' + escape(title) +
        '&dates=' + dates[0] + '/' + dates[1] +
        '&details=' + escape(details) +
        '&location=' + escape(loc) +
        '&trp=true&sprop=website:www.evite.com&sprop=name:Evite';
}

// Find the exsting calendar link element.
var calendarRE = /Calendar/;
var link, links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; ++i) {
    if (calendarRE.test(links[i].innerHTML)) {
        link = links[i];
        break;
    }
}

// Replace the existing link with our Google Calendar link.
if (link) {
    link.innerHTML = 'Add to Google Calendar';
    link.setAttribute('href', makeGoogleCalendarLink());
}