Skip to content

Instantly share code, notes, and snippets.

@jelmervdl
Created February 3, 2012 00:56
Show Gist options
  • Save jelmervdl/1726824 to your computer and use it in GitHub Desktop.
Save jelmervdl/1726824 to your computer and use it in GitHub Desktop.
Userscript that adds iCal links to the De Oosterpoort website
// ==UserScript==
// @name iCal links for De Oosterpoort
// @namespace http://ikhoefgeen.nl/userscripts
// @description Create iCal events directly from De Oosterpoort website
// @include http://www.de-oosterpoort.nl/programma/*
// ==/UserScript==
// Credits:
// Base64 encode / decode
// http://www.webtoolkit.info/
//
var DeOosterpoort = {}
DeOosterpoort.findData = function(root)
{
var header = root.querySelector('#voorstelling h1'),
specs = root.querySelectorAll("#voorstelling .detail-info li > span"),
event = new iCal.Event;
if (!header || specs.size == 0)
return null;
event.name = header.firstChild.data.trim();
for (var i = 0; i < specs.length; ++i)
{
if (!specs[i].firstChild || !specs[i].nextSibling)
continue;
var label = specs[i].firstChild.data.trim(),
value = specs[i].nextSibling.data.trim();
if (label == "Datum") {
if (!DeOosterpoort.parseDatum(value, event))
return null;
}
else if (label == "Tijdstip") {
if (!DeOosterpoort.parseTijdstip(value, event))
return null;
}
else if (label == "Locatie") {
event.location = value;
}
}
return event;
};
DeOosterpoort.parseDatum = function(datum, event)
{
var parts = datum.match(/^\w+\ (\d+) (\w+) (\d+)$/);
if (!parts)
return false;
var month = [
'januari', 'februari', 'maart',
'april', 'mei', 'juni',
'juli', 'augustus', 'september',
'oktober', 'november', 'december'
].indexOf(parts[2]);
['from', 'till'].forEach(function(range) {
event[range].setYear(parts[3]);
event[range].setMonth(month);
event[range].setDate(parts[1]);
});
return true;
};
DeOosterpoort.parseTijdstip = function(tijdstip, event)
{
var parts = tijdstip.match(/^(\d{1,2}):(\d\d)(?:\s+tot (\d{1,2}):(\d\d))?$/);
if (!parts)
return false;
event.from.setHours(parts[1]);
event.from.setMinutes(parts[2]);
if (typeof parts[3] !== 'undefined' && typeof parts[4] !== 'undefined')
{
event.till.setHours(parts[3]);
event.till.setMinutes(parts[4]);
}
else
{
event.till.setHours(parseInt(parts[1]) + 1);
event.till.setMinutes(parts[2]);
}
return true;
}
function base64_encode(input)
{
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
while (i < input.length)
{
chr1 = input.charCodeAt(i++) & 0xFF;
chr2 = input.charCodeAt(i++) & 0xFF;
chr3 = input.charCodeAt(i++) & 0xFF;
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2))
enc3 = enc4 = 64;
else if (isNaN(chr3))
enc4 = 64;
output += _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
function align(length, filler, value)
{
value = "" + value; // now it is a string for sure! :P
return repeat(filler, length - value.length) + value;
}
function repeat(character, times)
{
var output = '';
while (times-- > 0)
output += character;
return output;
}
var iCal = {};
iCal.Event = function() {
this.from = new Date;
this.till = new Date;
this.name = '[name]';
this.location = '[location]';
this.link = document.location.href;
}
iCal.Event.prototype.toDataURI = function()
{
var ical_format = 'Ymd\THis\Z';
var timezone = [
'CALSCALE:GREGORIAN',
'BEGIN:VTIMEZONE',
'TZID:Europe/Amsterdam',
'BEGIN:DAYLIGHT',
'TZOFFSETFROM:+0100',
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU',
'DTSTART:19810329T020000',
'TZNAME:CEST',
'TZOFFSETTO:+0200',
'END:DAYLIGHT',
'BEGIN:STANDARD',
'TZOFFSETFROM:+0200',
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU',
'DTSTART:19961027T030000',
'TZNAME:CET',
'TZOFFSETTO:+0100',
'END:STANDARD',
'END:VTIMEZONE'
].join("\n");
var data = [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//hacksw/handcal//NONSGML v1.0//EN',
timezone,
'BEGIN:VEVENT',
'CREATED:' + iCal.formatDate(ical_format, new Date),
'DTSTAMP:' + iCal.formatDate(ical_format, new Date),
'DTSTART;TZID=Europe/Amsterdam:' + iCal.formatDate(ical_format, this.from),
'DTEND;TZID=Europe/Amsterdam:' + iCal.formatDate(ical_format, this.till),
'TRANSP:OPAQUE',
'SUMMARY:' + iCal.escapeData(this.name),
'LOCATION:' + iCal.escapeData(this.location),
'URL;VALUE=URI:' + this.link,
'END:VEVENT',
'END:VCALENDAR'
].join("\n");
return 'data:text/calendar;base64,' + base64_encode(data);
}
iCal.escapeData = function(data)
{
return data
.replace(/\\/, "\\\\")
.replace(/,/,"\\,")
.replace(/\n/, "\\n");
}
iCal.formatDate = function(format, date)
{
var output = '';
for (var i = 0; i < format.length; ++i)
{
switch (format[i])
{
case '\\':
output += format[++i];
break;
case 'Y':
output += date.getUTCFullYear();
break;
case 'm':
output += align(2, '0', date.getUTCMonth() + 1);
break;
case 'd':
output += align(2, '0', date.getUTCDate());
break;
case 'H':
output += align(2, '0', date.getUTCHours());
break;
case 'i':
output += align(2, '0', date.getUTCMinutes());
break;
case 's':
output += align(2, '0', date.getUTCSeconds());
break;
default:
output += format[i];
break;
}
}
return output;
}
function main()
{
var event = DeOosterpoort.findData(document);
if (!event)
return;
var link = document.createElement('a');
link.href = event.toDataURI();
link.appendChild(document.createTextNode('iCal'));
document.querySelector('#voorstelling .detail-info li').appendChild(link);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment