Default Settings

The iCalendar specification (RFC 2445) defines a standard for 'interoperable calendaring and scheduling services for the Internet'.

The iCalendar functionality can easily be added to a division with appropriate default settings - although you do need to specify some of the details about the event itself. The resulting links allow the user to post details about an event to any number of iCalendar sites.
You can also remove the iCalendar widget if it is no longer required.

Two types of iCalendar sites exist - external and local. External ones exist on the Web and are invoked via a URL. Local ones reside on your desktop and are transferred via the clipboard (default) or via a textfield or a downloadable event file.

iCalendar with everyone:

 
 
Join us for an Australia Day lunch on your local beach
from 11:30 to 12:30 on January 26, 2008.

 

AustDayLunch = {start: new Date(2008, 1-1, 26, 11, 30, 00),
	end: new Date(2008, 1-1, 26, 12, 45, 00),
	title: 'Australia Day lunch',
	description: 'A traditional barbeque for our big day',
	location: 'On your local beach'};
$('#defaultICal').icalendar(AustDayLunch);

$('#removeICal').click(function() {
	var destroy = $(this).text() === 'Remove';
	$(this).text(destroy ? 'Re-attach' : 'Remove');
	$('#defaultICal').icalendar(destroy ? 'destroy' : AustDayLunch);
});

You can override the defaults globally as shown below:

$.icalendar.setDefaults({tipPrefix: 'Save to '});

Processed fields are marked with a class of hasICalendar and are not re-processed if targetted a second time.

Format Appearance

Control the appearance of the widget.

A select few:

$('#selectICal').icalendar(
	$.extend({sites: ['google', 'outlook']}, AustDayLunch));

Use a compact format:

$('#compactICal').icalendar($.extend({compact: true}, AustDayLunch));

Popup on demand:

$('#popupICal').icalendar($.extend({popup: true}, AustDayLunch));

Change on the fly:

$('#changeICal').icalendar(
	$.extend({sites: ['yahoo', 'icalendar']}, AustDayLunch));

$('#changeButton').click(function() {
	var google = $('#changeICal').icalendar('change', 'sites')[0] === 'yahoo';
	$('#changeICal').icalendar('change',
		{sites: google ? ['google', 'outlook'] : ['yahoo', 'icalendar']});
});
Local iCalendar Usage

For sites that are not external, such as iCalendar and Outlook, the iCalendar event is used locally. By default, the event definition is copied into the clipboard so that the user can paste it elsewhere. The copy is perfomed via a Flash download to make it common across the browsers. Confirmation is required by the user prior to the copy since they may not realise that the clipboard will be used and may want to retain content already stored there.

Copy to clipboard:

$('#clipboardICal').icalendar($.extend(
	{sites: ['icalendar']}, AustDayLunch));

If you set copyFlash to '' you can disable the clipboard copy. In this case the user sees the event details in a popup dialog box.

Disable clipboard:

$('#noClipboardICal').icalendar($.extend(
	{sites: ['outlook'], copyFlash: ''}, AustDayLunch));

Alternatively, you can specify a field that is to receive the iCalendar definition, instead of using the clipboard.

Copy to field:

 

$('#fieldICal').icalendar($.extend(
	{sites: ['icalendar'], echoField: '#fieldOut'}, AustDayLunch));

Or provide a downloadable file by specifying an echo Web site that correctly identifies the file type (MIME type 'text/calendar', file extension '.ics').

Downloadable file:

$('#downloadableICal').icalendar($.extend({sites: ['outlook'],
	echoUrl: 'http://keith-wood.name/iCalEcho.php'}, AustDayLunch));

The following PHP page echoes an iCalendar for you as an attachment with the correct type.

<?php
/*
 * Echo an iCalendar for jquery.icalendar.js
 *
 * Written by Keith Wood (kbwood{at}iinet.com.au) July 2008
 */
ini_set("display_errors", 1);
error_reporting(E_ALL & ~E_NOTICE);

$content = $_GET["content"];
header("Content-type: text/calendar");
header("Content-length: ".strlen($content));
header("Content-disposition: attachment; filename=event.ics");
echo $content;
?>

Or use the equivalent Java servlet fragment:

protected void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	String content = request.getParameter("content");
	response.setHeader("Content-type", "text/calendar"); 
	response.setHeader("Content-length", String.valueOf(content.length())); 
	response.setHeader("Content-disposition", "attachment; filename=event.ics");
	response.getOutputStream().write(content.getBytes());
}
Event Recurrences

An event may recur a number of times over various periods, specified as either a set of date/times or a recurrence rule.

Use the recurrence setting to implement this in the plugin. Look for the RDATE or RRULE entry in the event definition below.

Recurrences:

 

 

$('#recurICal').icalendar($.extend(
	{sites: ['icalendar'], echoField: '#recurOut'}, AustDayLunch));

var recurrences = [{dates: [new Date(2008, 2-1, 16), new Date(2008, 3-1, 6)]},
	{times: [new Date(2008, 2-1, 16, 10, 0, 0),
		new Date(2008, 3-1, 6, 12, 30, 0)]},
	{periods: [[new Date(2008, 2-1, 16, 10, 0, 0),
		new Date(2008, 2-1, 16, 11, 0, 0)],
		[new Date(2008, 3-1, 6, 12, 30, 0), 'PT30M']]},
	{freq: 'weekly'},
	{freq: 'daily', interval: 2},
	{freq: 'weekly', by: {type: 'day', values: ['TU', 'TH']}},
	{freq: 'monthly', until: new Date(2008, 12-1, 31)},
	{freq: 'monthly', count: 4},
	{freq: 'monthly', by: {type: 'monthday', values: [6, 26]}}];
	
$('#recurrence').change(function() {
	$('#recurICal').icalendar('change',
		{recurrence: recurrences[$(this).val()]});
	$('#recurICal a').click();
});
Additional Sites

You can add new sites to the list as shown below. Note: this example is not a real iCalendar site.
The parameters are the id, display name, icon URL or index, and site URL.
A special site URL of 'echo' indicates that the iCalendar definition should be used locally. Otherwise, within the site URL use:

Add your own:

 

$.icalendar.addSite('another', 'Another Cal', 'img/calendar-green.gif',
	'http://www.anothercal.com/add?title={t}&desc={d}' +
	'&start={s}&end={e}&loc={l}');

$('#addICal').icalendar($.extend(
	{sites: ['google', 'another'], compact: true}, AustDayLunch));
$('#add2ICal').icalendar($.extend(
	{sites: ['google', 'another']}, AustDayLunch));

The following list shows the current sites with their IDs:

var html = '';
$.each($.icalendar.getSites(), function(id, site) {
	if (id != 'another') {
		html += '<li>' + id + ' - ' + site.display + '</li>';
	}
});
$('#siteList').html(html);
Styling

You can format the links with a bit of CSS. The structure of the links is shown below, where the outermost div is the container you specify in your page:

<div id="defaultICal" class="hasICalendar">
	<ul class="icalendar_list">
		<li><a href="Submission URL"><img src="icon.png"/> Display Name</a></li>
		:
	</ul>
</div>

If the list is in the compact format then the ul also has the icalendar_compact class assigned to it and omits the text description of the sites.

Discrete styling: Save to my calendar

$('#discreteICal').icalendar($.extend({compact: true}, AustDayLunch));
#discreteICal ul { float: left; margin-left: 10px;
	background-color: transparent; border: none; }
#discreteICal li { margin: 0px 5px; }

Alternate styling:

$('#styleICal').icalendar(AustDayLunch);
#styleICal ul { float: left; border: 1px solid #247;
	background: #81c7fb url(img/bookmark-bg.jpg) center; }
#styleICal li { width: auto; margin: 2px; padding: 0px 5px;
	border: none; background: transparent; }
#styleICal a { color: #fff; font-weight: bold; }
Parsing iCalendar Data

This plugin provides a function for parsing the contents of an iCalendar definition. The result is a JavaScript object that you can easily navigate for further processing, e.g. ical.vevent.description. Further iCalendar examples are available in the specification.

Parse source:

 

Parsed model:

$('#parseButton').click(function() {
	var ical = $.icalendar.parse($('#parseInput').val());
	$('#parseOutput').val($.toJSON(ical, true));
});
Duration Calculations

iCalendar allows for the definition of durations, for events and alarms amongst others. They are defined as a number of weeks (PnnW), or a number of days/hours/minutes/seconds (PnnDTnnHnnMnnS). A duration may be prefixed by a negative sign (-) if it extends into the past. This plugin provides two functions for dealing with these durations.

The first function calculates the duration between two date/times and returns the value formatted for use within an iCalendar.

Calculate duration: to

 

 

 

$('#calcDuration').click(function() {
	var start = getDateTime('#date1', '#time1');
	var end = getDateTime('#date2', '#time2');
	$('#durationOut').val($.icalendar.calculateDuration(start, end));
});

The second function adds a duration to a start date/time to determine the end.

Add duration: plus

 

 

 

$('#addDuration').click(function() {
	var start = getDateTime('#date3', '#time3');
	var duration = $('#durationIn').val();
	try {
		$('#ending').val($.icalendar.addDuration(start, duration));
	}
	catch (e) {
		alert(e);
	}
});
In the Wild

This tab highlights examples of this plugin in use "in the wild".

To add another example, please contact me (wood.keith{at}optusnet.com.au) and provide the plugin name, the URL of your site, its title, and a short description of its purpose and where/how the plugin is used.

Quick Reference

A full list of all possible settings is shown below. Note that not all would apply in all cases. For more detail see the documentation reference page.

$(selector).icalendar({
	sites: [],  // List of site IDs to use, empty for all
	icons: 'icalendar.png', // Horizontal amalgamation of all site icons
	iconSize: 16,  // The size of the individual icons
	target: '_blank',  // The name of the target window for the iCalendar links
	compact: false,  // True if a compact presentation should be used, false for full
	popup: false,  // True to have it popup on demand, false to show always
	popupText: 'Send to my calendar...', // Text for the popup trigger
	tipPrefix: '',  // Additional text to show in the tool tip for each icon
	echoUrl: '',  // The URL to echo back iCalendar content, or blank for clipboard
	echoField: '', // The ID of a field to copy the iCalendar definition into,
		// or blank for clipboard
	start: null,  // The start date/time of the event
	end: null,  // The end date/time of the event
	title: '',  // The title of the event
	summary: '',  // The summary of the event
	description: '',  // The description of the event
	location: '',  // The location of the event
	url: '',  // A URL with more information about the event
	contact: '',  // An e-mail address for further contact about the event
	recurrence: null, // Details about a recurring event, an object with attributes:
		// dates (Date or Date[]) or times (Date or Date[]) or
		// periods (Date[2] or Date[][2] or [][Date, string]) or
		// freq (string - secondly, minutely, hourly, daily, weekly, monthly, yearly),
		// interval (number), until (Date), count (number), weekStart (number),
		// by (object[] - type (string - second, minute, day, monthday, yearday,
		// weekno, month, setpos), values (number or number[] or string or string[]))
	// Confirmation message for clipboard copy
	copyConfirm: 'The event will be copied to your clipboard. Continue?',
	// Success message during clipboard copy
	copySucceeded: 'The event has been copied to your clipboard',
	// Failure message during clipboard copy
	copyFailed: 'Failed to copy the event to the clipboard\n',
	copyFlash: 'clipboard.swf', // The URL for the Flash clipboard copy module
	// Clipboard not supported message
	copyUnavailable: 'The clipboard is unavailable, please copy the event details from below:\n'
});

$.icalendar.setDefaults({...}); // Change global defaults

$.icalendar.addSite(id, display, icon, url, override); // Add a new iCalendar site

$.icalendar.getSites(); // Get the list of known iCalendar sites

$(selector).icalendar('change', settings); // Change settings for iCalendar instances

$(selector).icalendar('destroy'); // Remove iCalendar functionality
		
$.icalendar.formatDate(date); // Convert a date to the iCalendar format

$.icalendar.formatDateTime(dateTime, local); // Convert a date/time to the iCalendar format

$.icalendar.calculateDuration(start, end); // Get the duration between two date/times

$.icalendar.addDuration(start, duration); // Add a duration to a date/time

$.icalendar.parse(content, options); // Convert iCalendar text into a JavaScript object model