Parcourir la source

modified docs, added all new tests

Adam Shaw il y a 16 ans
Parent
commit
92e482089b
20 fichiers modifiés avec 1173 ajouts et 944 suppressions
  1. 14 10
      docs/events-and-sources.txt
  2. 2 2
      docs/methods.txt
  3. 1 1
      docs/triggered-actions.txt
  4. 16 0
      src/agenda.js
  5. 2 2
      src/css/grid.css
  6. 27 9
      src/css/main.css
  7. 5 5
      src/gcal.js
  8. 58 62
      src/grid.js
  9. 164 119
      src/main.js
  10. 4 4
      src/util.js
  11. 13 34
      src/view.js
  12. 0 134
      test/actions.html
  13. 115 0
      test/gcal.html
  14. 82 89
      test/locale.html
  15. 150 110
      test/methods.html
  16. 0 119
      test/new.html
  17. 109 99
      test/options.html
  18. 144 145
      test/sources.html
  19. 87 0
      test/theming.html
  20. 180 0
      test/triggers.html

+ 14 - 10
docs/events-and-sources.txt

@@ -77,6 +77,11 @@ CalEvent:
 
 **title**: String
 	The text on an event's element
+	
+**allDay**: Boolean (optional, defaults to ``true``)
+	Determines whether the start-date and end-date's times should be ignored.
+	If ``true``, times will be ignored. If ``false``, times will be considered,
+	displaying them on each event (like the text '3pm').
 
 **date**: Date
 	Alias for ``start``
@@ -91,18 +96,17 @@ CalEvent:
 
 **end**: Date (optional)
 	A javascript Date object indicating the date/time an event ends.
-	If the event is an all-day event, specifies the inclusive last day
-	of the event. (This is different from previous versions of FullCalendar).
+	As with ``start``, IETF and ISO8601 strings can be used.
 	
-	For example, an all-day event with start on *Nov 10* and end on *Nov 12*
-	would span *3 days*.
+	**If an event is all-day...**
 	
-	As with ``start``, IETF and ISO8601 strings can be used with an
-	:ref:`Event Source <event-sources>`.
-
-**allDay**: Boolean (optional, defaults to ``true``)
-	Determines whether an event's time is displayed (such as 3pm).
-	``false`` will show the time, ``true`` will not.
+	the end date is *inclusive*. This means an event with ``start`` *Nov 10* and
+	``end`` *Nov 12* will span *3 days* on the calendar.
+	
+	**If an event is NOT all-day...**
+	
+	the end date is *exclusive*. This is only a gotcha when your ``end`` has time 00:00.
+	It means your event ends on midnight, and it will *not* span through the next day.
 
 **className**: String/Array (optional)
 	A CSS class (or array of classes) that will be attached to this event's

+ 2 - 2
docs/methods.txt

@@ -35,8 +35,8 @@ jQuery object:
 	Renders a new event on the calendar. ``calEvent`` must have
 	at least a ``title`` and a ``start``.
 	
-	By default, the event will disappear once the user switches views
-	or clicks prev/next. However, specifying ``stick`` as ``true``
+	By default, the event will disappear once the calendar refetches its event
+	sources (example: when prev/next is clicked). However, specifying ``stick`` as ``true``
 	will cause the event to be permanently fixed to the calendar.
 	
 **removeEvents** - .fullCalendar('removeEvents', *[idOrFilter]*)

+ 1 - 1
docs/triggered-actions.txt

@@ -78,7 +78,7 @@ always available (:ref:`more below <view-object>`).
 	
 	``this`` is set to the event's element
 
-**eventResized**: function(*event, dayDelta, minuteDelta, jsEvent, ui, view*)
+**eventResize**: function(*calEvent, dayDelta, minuteDelta, jsEvent, ui, view*)
 	Triggered when an event is resized and *changed in duration*.
 	
 	``dayDelta`` holds the number of days the event's end time was moved

+ 16 - 0
src/agenda.js

@@ -1,4 +1,20 @@
 
+function segAfters(levels) { // TODO: put in agenda.js
+	var i, j, k, level, seg, seg2;
+	for (i=levels.length-1; i>0; i--) {
+		level = levels[i];
+		for (j=0; j<level.length; j++) {
+			seg = level[j];
+			for (k=0; k<segLevels[i-1].length; k++) {
+				seg2 = segLevels[i-1][k];
+				if (segsCollide(seg, seg2)) {
+					seg2.after = Math.max(seg2.after, seg.after+1);
+				}
+			}
+		}
+	}
+}
+
 /********************************* week view ***********************************/
 
 $.fullCalendar.views.week = function(element, options) {

+ 2 - 2
src/css/grid.css

@@ -6,12 +6,12 @@
 	width: 100%;
 	}
 	
-.fc-grid th {
+.fc .fc-grid th {
 	border-width: 0 0 0 1px;
 	text-align: center;
 	}
 	
-.fc-grid td {
+.fc .fc-grid td {
 	border-width: 1px 0 0 1px;
 	}
 	

+ 27 - 9
src/css/main.css

@@ -212,14 +212,6 @@ table.fc-header {
 	background-color: blue;
 	}
 	
-.fc-event-nobg,
-.fc-event-nobg a,
-.fc-agenda .fc-event-nobg .fc-event-time {
-	border-style: none;
-	background: none;
-	color: inherit;
-	}
-	
 .fc-event a {
 	overflow: hidden;
 	font-size: 11px;
@@ -239,6 +231,14 @@ table.fc-header {
 	height: 100%;
 	}
 	
+/* resizable */
+	
+.fc .ui-resizable-handle {
+	display: block;
+	position: absolute;
+	z-index: 99999;
+	}
+	
 	
 	
 /* Horizontal Events
@@ -271,8 +271,26 @@ table.fc-header {
 	border-right-width: 1px;
 	}
 	
+/* resizable */
+	
+.fc-event-hori .ui-resizable-e {
+	top: 0;
+	right: -5px;
+	width: 7px;
+	height: 100%;
+	cursor: e-resize;
+	}
+	
+.fc-event-hori .ui-resizable-w {
+	top: 0;
+	left: -5px;
+	width: 7px;
+	height: 100%;
+	cursor: w-resize;
+	}
+	
 .fc-event-hori .ui-resizable-handle {
-	_height: 10px; /* IE6 had 0 height */
+	_height: 14px; /* IE6 had 0 height */
 	}
 	
 

+ 5 - 5
src/gcal.js

@@ -26,12 +26,12 @@
 							var startStr = entry['gd$when'][0]['startTime'];
 							var start = $.fullCalendar.parseDate(startStr);
 							var end = $.fullCalendar.parseDate(entry['gd$when'][0]['endTime']);
-							var hasTime = startStr.indexOf('T') != -1;
+							var allDay = startStr.indexOf('T') == -1;
 							var classNames = [];
-							if (hasTime) {
-								classNames.push('fc-event-nobg');
+							if (allDay) {
+								end = new Date(end - 1); // make in inclusive
 							}else{
-								end = new Date(end - 1);
+								classNames.push('fc-event-nobg');
 							}
 							if (options.className) {
 								if (typeof options.className == 'string') {
@@ -48,7 +48,7 @@
 								end: end,
 								location: entry['gd$where'][0]['valueString'],
 								description: entry['content']['$t'],
-								hasTime: hasTime,
+								allDay: allDay,
 								className: classNames,
 								editable: options.editable || false
 							});

+ 58 - 62
src/grid.js

@@ -81,15 +81,16 @@ function Grid(element, options, methods) {
 	// initialize superclass
 	view = $.extend(this, viewMethods, methods, {
 		renderGrid: renderGrid,
+		renderEvents: renderEvents,
 		rerenderEvents: rerenderEvents,
 		updateSize: updateSize,
-		eventEnd: function(event) {
-			return event.end || cloneDate(event.start);
+		defaultEventEnd: function(event) {
+			return cloneDate(event.start);
 		},
 		visEventEnd: function(event) {
 			if (event.end) {
 				var end = cloneDate(event.end);
-				return (!event.hasTime || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
+				return (event.allDay || end.getHours() || end.getMinutes()) ? addDays(end, 1) : end;
 			}else{
 				return addDays(cloneDate(event.start), 1);
 			}
@@ -108,13 +109,12 @@ function Grid(element, options, methods) {
 	}
 
 	function renderGrid(r, c, colFormat, showNumbers, fetchEvents) {
-		//console.log('renderGrid!');
 		rowCnt = r;
 		colCnt = c;
 	
 		var month = view.start.getMonth(),
 			today = clearTime(new Date()),
-			s, s2, s3, i, j, d = cloneDate(view.visStart);
+			s, i, j, d = cloneDate(view.visStart);
 		
 		// update option-derived variables
 		tm = options.theme ? 'ui' : 'fc'; 
@@ -131,28 +131,23 @@ function Grid(element, options, methods) {
 		
 			var table = $("<table/>").appendTo(element);
 			
-			s = '';
+			s = "<thead><tr>";
 			for (i=0; i<colCnt; i++) {
-				s2 = "<th class='fc-" +
+				s += "<th class='fc-" +
 					dayIDs[d.getDay()] + ' ' + // needs to be first
-					tm + '-state-default ' +
+					tm + '-state-default' +
 					(i==dit ? ' fc-left' : '') +
-					"'>" + formatDate(d, colFormat, options) + "</th>"; // TODO: optionize
-				//if (rtl) {
-				//	s = s2 + s;
-				//}else{
-					s += s2;
-				//}
+					"'>" + formatDate(d, colFormat, options) + "</th>";
 				addDays(d, 1);
 			}
-			thead = $("<thead><tr>" + s + "</tr></thead>").appendTo(table);
+			thead = $(s + "</tr></thead>").appendTo(table);
 			
 			s = "<tbody>";
 			d = cloneDate(view.visStart);
 			for (i=0; i<rowCnt; i++) {
-				s2 = '';
+				s += "<tr class='fc-week" + i + "'>";
 				for (j=0; j<colCnt; j++) {
-					s3 = "<td class='fc-" +
+					s += "<td class='fc-" +
 						dayIDs[d.getDay()] + ' ' + // needs to be first
 						tm + '-state-default fc-day' + (i*colCnt+j) +
 						(j==dit ? ' fc-left' : '') +
@@ -162,14 +157,9 @@ function Grid(element, options, methods) {
 						' fc-not-today') + "'>" +
 						(showNumbers ? "<div class='fc-day-number'>" + d.getDate() + "</div>" : '') +
 						"<div class='fc-day-content'><div>&nbsp;</div></div></td>";
-					//if (rtl) {
-					//	s2 = s3 + s2;
-					//}else{
-						s2 += s3;
-					//}
 					addDays(d, 1);
 				}
-				s += "<tr class='fc-week" + i + "'>" + s2 + "</tr>";
+				s += "</tr>";
 			}
 			tbody = $(s + "</tbody>").appendTo(table);
 			tbody.find('td').click(dayClick);
@@ -182,60 +172,67 @@ function Grid(element, options, methods) {
 			if (rowCnt < prevRowCnt) {
 				tbody.find('tr:gt(' + (rowCnt-1) + ')').remove(); // remove extra rows
 			}
-			else if (rowCnt > prevRowCnt) {
+			else if (rowCnt > prevRowCnt) { // needs to create new rows...
 				s = '';
 				for (i=prevRowCnt; i<rowCnt; i++) {
-					s2 = '';
+					s += "<tr class='fc-week" + i + "'>";
 					for (j=0; j<colCnt; j++) {
-						s3 = "<td class='fc-" +
-							dayIDs[(j * dis + dit + weekStart) % 7] + ' ' + // needs to be first
-							tm + '-state-default fc-new fc-day' + (i*colCnt + j) +
+						s += "<td class='fc-" +
+							dayIDs[d.getDay()] + ' ' + // needs to be first
+							tm + '-state-default fc-new fc-day' + (i*colCnt+j) +
 							(j==dit ? ' fc-left' : '') + "'>" +
 							(showNumbers ? "<div class='fc-day-number'></div>" : '') +
 							"<div class='fc-day-content'><div>&nbsp;</div></div>" +
 							"</td>";
-						//if (rtl) {
-						//	s2 = s3 + s2;
-						//}else{
-							s2 += s3;
-						//}
+						addDays(d, 1);
 					}
-					s += "<tr class='fc-week" + i + "'>" + s2 + "</tr>";
+					s += "</tr>";
 				}
 				tbody.append(s);
 			}
 			tbody.find('td.fc-new').removeClass('fc-new').click(dayClick);
 			
 			// re-label and re-class existing cells
-			tbody.find('tr').each(function() {
-				for (i=0; i<colCnt; i++) {
-					var td = $(this.childNodes[i]); // * dis + dit TODO: clean
-					if (rowCnt > 1) {
-						if (d.getMonth() == month) {
-							td.removeClass('fc-other-month');
-						}else{
-							td.addClass('fc-other-month');
-						}
-					}
-					if (+d == +today) {
-						td.removeClass('fc-not-today')
-							.addClass('fc-today')
-							.addClass(tm + '-state-highlight');
+			d = cloneDate(view.visStart);
+			tbody.find('td').each(function() {
+				var td = $(this);
+				if (rowCnt > 1) {
+					if (d.getMonth() == month) {
+						td.removeClass('fc-other-month');
 					}else{
-						td.addClass('fc-not-today')
-							.removeClass('fc-today')
-							.removeClass(tm + '-state-highlight');
+						td.addClass('fc-other-month');
 					}
-					td.find('div.fc-day-number').text(d.getDate());
-					addDays(d, 1);
 				}
+				if (+d == +today) {
+					td.removeClass('fc-not-today')
+						.addClass('fc-today')
+						.addClass(tm + '-state-highlight');
+				}else{
+					td.addClass('fc-not-today')
+						.removeClass('fc-today')
+						.removeClass(tm + '-state-highlight');
+				}
+				td.find('div.fc-day-number').text(d.getDate());
+				addDays(d, 1);
 			});
 			
-			if (colCnt == 1) {
-				var startDay = this.visStart.getDay();
-				var td = tbody.find('td')[0];
-				td.className = td.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[startDay]);
-				thead.find('th').text(formatDate(this.start, colFormat, options));
+			if (rowCnt == 1) { // more likely changed (week or day view)
+			
+				// redo column header text and class
+				d = cloneDate(view.visStart);
+				thead.find('th').each(function() {
+					$(this).text(formatDate(d, colFormat, options));
+					this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+					addDays(d, 1);
+				});
+				
+				// redo cell day-of-weeks
+				d = cloneDate(view.visStart);
+				tbody.find('td').each(function() {
+					this.className = this.className.replace(/^fc-\w+(?= )/, 'fc-' + dayIDs[d.getDay()]);
+					addDays(d, 1);
+				});
+				
 			}
 		
 		}
@@ -297,7 +294,7 @@ function Grid(element, options, methods) {
 	
 	function renderEvents(events) {
 		view.reportEvents(events);
-		renderSegs(cachedSegs = compileSegs(events)); // view.visibleEvents(
+		renderSegs(cachedSegs = compileSegs(events));
 	}
 	
 	
@@ -388,10 +385,9 @@ function Grid(element, options, methods) {
 					}
 					eventElement = $("<div class='" + eventClasses.join(' ') + "'/>")
 						.append(eventAnchor = $("<a/>")
-							.append(event.hasTime ?
+							.append(event.allDay ? null :
 								$("<span class='fc-event-time'/>")
-									.html(formatDate(event.start, options.eventTimeFormat, options)) :
-								null)
+									.html(formatDates(event.start, event.end, options.timeFormat, options)))
 							.append($("<span class='fc-event-title'/>")
 								.text(event.title)));
 					if (event.url) {

+ 164 - 119
src/main.js

@@ -12,9 +12,9 @@ var defaults = {
 	defaultView: 'month',
 	aspectRatio: 1.35,
 	header: {
-		left: 'prev,next today',
-		center: 'title',
-		right: 'month,basicWeek,basicDay'
+		left: 'title',
+		center: '',
+		right: 'today prev,next'
 	},
 	
 	// event ajax
@@ -23,7 +23,7 @@ var defaults = {
 	cacheParam: '_',
 	
 	// time formats
-	eventTimeFormat: 'h(:mm)t',
+	timeFormat: 'h(:mm)t', // for events
 	titleFormat: {
 		month: 'MMMM yyyy',
 		week: "MMM d[ yyyy]{ '&#8212;'[ MMM] d yyyy}",
@@ -62,9 +62,9 @@ var defaults = {
 // right-to-left defaults
 var rtlDefaults = {
 	header: {
-		left: 'basicDay,basicWeek,month',
-		center: 'title',
-		right: 'today next,prev'
+		left: 'next,prev today',
+		center: '',
+		right: 'title'
 	},
 	buttonText: {
 		prev: '&#9658;',
@@ -254,7 +254,7 @@ $.fn.fullCalendar = function(options) {
 		// Fetch from a particular source. Append to the 'events' array
 		function fetchEventSource(src, callback) {
 			var prevDate = cloneDate(date),
-				reportEvents = function(a, dontPopLoading) {
+				reportEvents = function(a) {
 					if (+date == +prevDate) {
 						for (var i=0; i<a.length; i++) {
 							normalizeEvent(a[i]);
@@ -262,12 +262,13 @@ $.fn.fullCalendar = function(options) {
 						}
 						events = events.concat(a);
 					}
-					if (!dontPopLoading) {
-						popLoading();
-					}
 					if (callback) {
 						callback(a);
 					}
+				},
+				reportPopEvents = function(a) {
+					reportEvents(a);
+					popLoading();
 				};
 			if (typeof src == 'string') {
 				var params = {};
@@ -275,14 +276,14 @@ $.fn.fullCalendar = function(options) {
 				params[options.endParam] = Math.round(eventEnd.getTime() / 1000);
 				params[options.cacheParam] = (new Date()).getTime();
 				pushLoading();
-				$.getJSON(src, params, reportEvents);
+				$.getJSON(src, params, reportPopEvents);
 			}
 			else if ($.isFunction(src)) {
 				pushLoading();
-				src(cloneDate(eventStart), cloneDate(eventEnd), reportEvents);
+				src(cloneDate(eventStart), cloneDate(eventEnd), reportPopEvents);
 			}
 			else {
-				reportEvents(src, true); // src is an array
+				reportEvents(src); // src is an array
 			}
 		}
 		
@@ -329,73 +330,123 @@ $.fn.fullCalendar = function(options) {
 				render();
 			},
 			
-			gotoDate: function() {
+			gotoDate: function(year, month, dateNum) {
+				if (typeof year != 'undefined') {
+					date.setYear(year);
+				}
+				if (typeof month != 'undefined') {
+					date.setMonth(month);
+				}
+				if (typeof dateNum != 'undefined') {
+					date.setDate(dateNum);
+				}
+				render();
 			},
 			
-			moveDate: function() {
+			moveDate: function(years, months, days) {
+				if (typeof years != 'undefined') {
+					addYears(date, years);
+				}
+				if (typeof months != 'undefined') {
+					addMonths(date, months);
+				}
+				if (typeof days != 'undefined') {
+					addDays(date, days);
+				}
+				render();
 			},
 			
 			//
 			// Event Rendering
 			//
 			
-			renderEvent: function(event, stick) {
-				if (typeof event != 'object') {
-					event = eventsByID(event)[0]; // assumed to be ID
-					if (!event) return;
-				}else{
-					normalizeEvent(event);
-				}
+			updateEvent: function(event) {
 				var startDelta = event.start - event._start,
-					msDuration = event.end - event.start,
-					i, len = events.length, e,
-					found = false;
+					endDelta = event.end ? (event.end - (event._end || view.defaultEventEnd(event))) : 0,
+					i, len = events.length, e;
 				for (i=0; i<len; i++) {
 					e = events[i];
-					if (e._id == event._id) {
-						if (e != event) {
-							e._start = cloneDate(e.start = new Date(+e.start + startDelta));
-							e.end = new Date(+e.start + msDuration);
-							e.title = event.title;
-							e.hasTime = event.hasTime;
-							if (stick && !event.source) {
-								(event.source = eventSources[0]).push(event);
+					if (e._id == event._id && e != event) {
+						e.start = new Date(+e.start + startDelta);
+						if (event.end) {
+							if (e.end) {
+								e.end = new Date(+e.end + endDelta);
+							}else{
+								e.end = new Date(+view.defaultEventEnd(e) + endDelta);
 							}
+						}else{
+							e.end = null;
 						}
-						found = true;
+						e.title = event.title;
+						e.allDay = event.allDay;
+						normalizeEvent(e);
 					}
 				}
-				if (!found) {
+				normalizeEvent(event);
+				eventsChanged();
+			},
+			
+			renderEvent: function(event, stick) {
+				normalizeEvent(event);
+				if (!event.source) {
+					if (stick) {
+						(event.source = eventSources[0]).push(event);
+					}
 					events.push(event);
 				}
 				eventsChanged();
 			},
 			
-			removeEvent: function(id) {
-				if (typeof id == 'object') {
-					id = id._id;
+			removeEvents: function(filter) {
+				if (!filter) { // remove all
+					events = [];
+					// clear all array sources
+					for (var i=0; i<eventSources.length; i++) {
+						if (typeof eventSources[i] == 'object') {
+							eventSources[i] = [];
+						}
+					}
 				}else{
-					id += '';
+					if (!$.isFunction(filter)) { // an event ID
+						var id = filter + '';
+						filter = function(e) {
+							return e._id == id;
+						};
+					}
+					events = filterArray(events, function(e) {
+						return !filter(e);
+					});
+					// remove events from array sources
+					for (var i=0; i<eventSources.length; i++) {
+						if (typeof eventSources[i] == 'object') {
+							eventSources[i] = filterArray(eventSources[i], function(e) {
+								return !filter(e);
+							});
+						}
+					}
 				}
-				removeEvents(function(e) {
-					return e._id != id;
-				});
+				eventsChanged();
 			},
 			
 			clientEvents: function(filter) {
-				if (filter) {
+				if ($.isFunction(filter)) {
 					return filterArray(events, filter);
-				}else{
+				}
+				else if (filter) { // an event ID
+					filter += '';
+					return filterArray(events, function(e) {
+						return e._id == filter;
+					});
+				}
+				else {
 					return events;
 				}
 			},
 			
-			rerender: function() {
+			rerenderEvents: function() {
+				view.rerenderEvents();
 			},
 			
-			clientEventsByID: eventsByID,
-			removeEvents: removeEvents,
-			
 			//
 			// Event Source
 			//
@@ -418,46 +469,14 @@ $.fn.fullCalendar = function(options) {
 				eventsChanged();
 			},
 			
-			refetch: function() {
+			refetchEvents: function() {
+				fetchEvents(eventsChanged);
 			}
 			
 		};
 		
 		$.data(this, 'fullCalendar', publicMethods);
 		
-		function eventsByID(id) {
-			id += '';
-			return filterArray(events, function(e) {
-				e._id == id;
-			});
-		}
-		
-		function removeEvents(filter) {
-			var i, len = eventSources.length;
-			if (filter) {
-				events = filterArray(events, function(e) {
-					return !filter(e);
-				});
-				// remove events from array sources
-				for (i=0; i<len; i++) {
-					if (typeof eventSources[i] == 'object') {
-						eventSources[i] = filterArray(eventSources[i], function(e) {
-							return !filter(e);
-						});
-					}
-				}
-			}else{
-				events = [];
-				// clear all array sources
-				for (i=0; i<len; i++) {
-					if (typeof eventSources[i] == 'object') {
-						eventSources[i] = [];
-					}
-				}
-			}
-			eventsChanged();
-		}
-		
 		
 		
 		/* Header
@@ -489,47 +508,58 @@ $.fn.fullCalendar = function(options) {
 							tr.append("<td><h2 class='fc-header-title'/></td>");
 							prevTitle = true;
 						}else{
-							var button,
-								icon = options.theme ? options.buttonIcons[buttonNameShort] : null,
-								text = options.buttonText[buttonNameShort];
-							if (icon) {
-								button = $("<div class='fc-button-" + buttonName + " ui-state-default'>" +
-									"<a><span class='ui-icon ui-icon-" + icon + "'/></a></div>");
+							var buttonClick;
+							if (publicMethods[buttonNameShort]) {
+								buttonClick = publicMethods[buttonNameShort];
 							}
-							else if (text) {
-								button = $("<div class='fc-button-" + buttonName + " " + tm + "-state-default'>" +
-									"<a><span>" + text + "</span></a></div>");
+							else if (views[buttonName]) {
+								buttonClick = function() { switchView(buttonName) };
 							}
-							if (button) {
-								button
-									.mousedown(function() {
-										button.addClass(tm + '-state-down');
-									})
-									.mouseup(function() {
-										button.removeClass(tm + '-state-down');
-									})
-									.hover(function() {
-										button.addClass(tm + '-state-hover');
-									},
-									function() {
-										button.removeClass(tm + '-state-hover')
-											.removeClass(tm + '-state-down');
-									})
-									.appendTo($("<td/>").appendTo(tr));
-								if (publicMethods[buttonNameShort]) {
-									button.click(publicMethods[buttonNameShort]);
+							if (buttonClick) {
+								var button,
+									icon = options.theme ? options.buttonIcons[buttonNameShort] : null,
+									text = options.buttonText[buttonNameShort];
+								if (icon) {
+									button = $("<div class='fc-button-" + buttonName + " ui-state-default'>" +
+										"<a><span class='ui-icon ui-icon-" + icon + "'/></a></div>");
 								}
-								else if (views[buttonName]) {
-									button.click(function() {
-										switchView(buttonName);
-									});
+								else if (text) {
+									button = $("<div class='fc-button-" + buttonName + " " + tm + "-state-default'>" +
+										"<a><span>" + text + "</span></a></div>");
 								}
-								if (j == 0 || prevTitle) {
-									button.addClass(tm + '-corner-left');
-								}else{
-									button.addClass(tm + '-no-left');
+								if (button) {
+									button
+										.mousedown(function() {
+											button.addClass(tm + '-state-down');
+										})
+										.mouseup(function() {
+											button.removeClass(tm + '-state-down');
+										})
+										.hover(
+											function() {
+												button.addClass(tm + '-state-hover');
+											},
+											function() {
+												button.removeClass(tm + '-state-hover')
+													.removeClass(tm + '-state-down');
+											}
+										)
+										.appendTo($("<td/>").appendTo(tr));
+									if (publicMethods[buttonNameShort]) {
+										button.click(publicMethods[buttonNameShort]);
+									}
+									else if (views[buttonName]) {
+										button.click(function() {
+											switchView(buttonName);
+										});
+									}
+									if (j == 0 || prevTitle) {
+										button.addClass(tm + '-corner-left');
+									}else{
+										button.addClass(tm + '-no-left');
+									}
+									prevTitle = false;
 								}
-								prevTitle = false;
 							}
 						}
 					});
@@ -572,6 +602,8 @@ $.fn.fullCalendar = function(options) {
 	
 	});
 	
+	return this;
+	
 };
 
 
@@ -583,7 +615,20 @@ var fakeID = 0;
 
 function normalizeEvent(event) {
 	event._id = event._id || (typeof event.id == 'undefined' ? '_fc' + fakeID++ : event.id + '');
+	if (event.date) {
+		if (!event.start) {
+			event.start = event.date;
+		}
+		delete event.date;
+	}
 	event._start = cloneDate(event.start = parseDate(event.start));
 	event.end = parseDate(event.end);
+	if (event.end && event.end < event.start) {
+		event.end = cloneDate(event.start);
+	}
+	event._end = event.end ? cloneDate(event.end) : null;
+	if (typeof event.allDay == 'undefined') {
+		event.allDay = true;
+	}
 }
 

+ 4 - 4
src/util.js

@@ -4,14 +4,14 @@
 
 var DAY_MS = 86400000;
 
-function addMonths(d, n, keepTime) {
-	d.setMonth(d.getMonth() + n);
+function addYears(d, n, keepTime) {
+	d.setFullYear(d.getFullYear() + n);
 	if (keepTime) return d;
 	return clearTime(d);
 }
 
-function addYears(d, n, keepTime) {
-	d.setFullYear(d.getFullYear() + n);
+function addMonths(d, n, keepTime) {
+	d.setMonth(d.getMonth() + n);
 	if (keepTime) return d;
 	return clearTime(d);
 }

+ 13 - 34
src/view.js

@@ -8,7 +8,7 @@ var viewMethods = {
 	// - end
 	// - visStart
 	// - visEnd
-	// - eventEnd(event)
+	// - defaultEventEnd(event)
 	// - visEventEnd(event)
 	//
 	// - render
@@ -26,6 +26,8 @@ var viewMethods = {
 	
 	
 	
+	// trigger event handlers, always append view as last arg
+	
 	trigger: function(name, thisObj) {
 		if (this.options[name]) {
 			return this.options[name].apply(thisObj || this, Array.prototype.slice.call(arguments, 2).concat([this]));
@@ -34,6 +36,14 @@ var viewMethods = {
 	
 	
 	
+	//
+	
+	eventEnd: function(event) {
+		return event.end || this.defaultEventEnd(event);
+	},
+	
+	
+	
 	// event/element creation reporting
 	
 	reportEvents: function(events) {
@@ -64,21 +74,6 @@ var viewMethods = {
 	
 	
 	
-	// get events within visStart and visEnd TODO: need this? move it somewhere else?
-	
-	visibleEvents: function(events) {
-		var res=[], i, len=events.length, event;
-		for (i=0; i<len; i++) {
-			event = events[i];
-			if (this.visEventEnd(event) > this.visStart && event.start < this.visEnd) {
-				res.push(event);
-			}
-		}
-		return res;
-	},
-	
-	
-	
 	// event element manipulation
 	
 	clearEvents: function() { // just remove ELEMENTS
@@ -115,7 +110,7 @@ var viewMethods = {
 		var i, event2, events = this.eventsByID[event._id];
 		for (i=0; i<events.length; i++) {
 			event2 = events[i];
-			event2.hasTime = event.hasTime;
+			event2.allDay = event.allDay;
 			addMinutes(addDays(event2.start, days, true), minutes);
 			if (event.end) {
 				event2.end = addMinutes(addDays(this.eventEnd(event2), days, true), minutes);
@@ -239,27 +234,11 @@ function stackSegs(segs) {
 		}else{
 			levels[j] = [seg];
 		}
-		seg.after = 0;
+		//seg.after = 0;
 	}
 	return levels;
 }
 
-function segAfters(levels) { // TODO: put in agenda.js
-	var i, j, k, level, seg, seg2;
-	for (i=levels.length-1; i>0; i--) {
-		level = levels[i];
-		for (j=0; j<level.length; j++) {
-			seg = level[j];
-			for (k=0; k<segLevels[i-1].length; k++) {
-				seg2 = segLevels[i-1][k];
-				if (segsCollide(seg, seg2)) {
-					seg2.after = Math.max(seg2.after, seg.after+1);
-				}
-			}
-		}
-	}
-}
-
 function segCmp(a, b) {
 	return  (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
 }

+ 0 - 134
test/actions.html

@@ -1,134 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
-<link rel='stylesheet' type='text/css' href='jgrowl/jgrowl.css' />
-<script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/ui.core.js'></script>
-<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
-<script type='text/javascript' src='../fullcalendar/fullcalendar.js'></script>
-<script type='text/javascript' src='jgrowl/jgrowl.js'></script>
-<script type='text/javascript'>
-
-$(document).ready(function() {
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth();
-
-	$('#calendar').fullCalendar({
-	
-		monthDisplay: function(year, month, monthTitle) {
-			$.jGrowl("<b>monthDisplay</b><br />" +
-				year + "-" + month + "<br />" +
-				monthTitle);
-		},
-		
-		loading: function(bool) {
-			$.jGrowl("<b>loading</b>: " + bool);
-		},
-		
-		resize: function() {
-			$.jGrowl("<b>resize</b>");
-		},
-	
-		dayClick: function(date) {
-			$.jGrowl("<b>dayClick</b><br />" +
-				date + "<br />" +
-				this.nodeName);
-		},
-		
-		eventRender: function(event, element) {
-			if (event.id == 3) {
-				//return false;
-				return $("<div style='background:red' />").text(event.title);
-			}
-		},
-		
-		eventClick: function(event, ev) {
-			$.jGrowl("<b>eventClick</b><br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				this.nodeName);
-			//return false;
-		},
-		
-		/*eventMouseover: function(event, ev) {
-			$.jGrowl("<b>eventMouseover</b><br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				this.nodeName);
-		},
-		
-		eventMouseout: function(event, ev) {
-			$.jGrowl("<b>eventMouseout</b><br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				this.nodeName);
-		},*/
-		
-		eventDragStart: function(event, ev, ui) {
-			$.jGrowl("<b>eventDragStart</b><br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				ui);
-		},
-		
-		eventDragStop: function(event, ev, ui) {
-			$.jGrowl("<b>eventDragStop</b><br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				ui);
-		},
-		
-		eventDrop: function(event, delta, ev, ui) {
-			$.jGrowl("<b>eventDrop</b><br />" +
-				delta + "<br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				ui);
-		},
-		
-		draggable: true,
-		
-		events: [
-			{
-				id: 1,
-				title: "Long Event",
-				start: new Date(y, m, 6, 14, 0),
-				end: new Date(y, m, 11)
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(y, m, 2)
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(y, m, 9)
-			},
-			{
-				id: 3,
-				title: "Meeting",
-				start: new Date(y, m, 20, 9, 0)
-			},
-			{
-				id: 4,
-				title: "Click for Facebook",
-				start: new Date(y, m, 27, 16),
-				end: new Date(y, m, 29),
-				url: "http://facebook.com/"
-			}
-		]
-		
-	});
-
-});
-
-</script>
-</head>
-<body style='font-size:14px;font-family:Arial'>
-<div id='calendar' style='width:75%'></div>
-</body>
-</html>

+ 115 - 0
test/gcal.html

@@ -0,0 +1,115 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+
+	$(document).ready(function() {
+		$('#calendar').fullCalendar({
+			editable: true,
+			eventSources: [
+				$.fullCalendar.gcalFeed(
+					"http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic",
+					{
+						//editable: true,
+						className: 'holiday'
+					}
+				),
+				/*$.fullCalendar.gcalFeed(
+					"http://www.google.com/calendar/feeds/mike%40maddogsportsbar.com/private-4ad75f9427058f8fe6525c0857c59fbc/basic",
+					{
+						className: 'maddog'
+					}
+				),*/
+				[
+					{
+						id: 1,
+						title: "Long Event",
+						start: new Date(y, m, 6),
+						end: new Date(y, m, 10)
+					},
+					{
+						id: 2,
+						title: "Repeating",
+						start: new Date(y, m, 2)
+					},
+					{
+						id: 2,
+						title: "Repeating",
+						start: new Date(y, m, 9)
+					},
+					{
+						id: 3,
+						title: "Meeting",
+						start: new Date(y, m, 20, 9, 0),
+						end: new Date(y, m, 20, 10, 0),
+						allDay: false
+					},
+					{
+						id: 4,
+						title: "Click for Facebook",
+						start: new Date(y, m, 27),
+						end: new Date(y, m, 28),
+						url: "http://facebook.com/"
+					},
+					{
+						id: 5,
+						title: "timed event1",
+						start: new Date (y, m, 31, 17, 30),
+						allDay: false
+					},
+					{
+						id: 6,
+						title: "timed event1",
+						start: new Date (y, m+1, 2, 14, 15),
+						allDay: false
+					},
+					{
+						id: 7,
+						title: "timed event1",
+						start: new Date (y, m+1, 4, 15, 00),
+						end: new Date(y, m+1, 4, 17, 00),
+						allDay: false
+					}
+				]
+			]
+		});
+	});
+
+</script>
+<style>
+
+	.holiday,
+	.holiday a {
+		background: green;
+		border-color: green;
+		}
+		
+	.maddog,
+	.maddog a {
+		background: red;
+		border-color: red;
+		}
+		
+		
+
+	/* rescued from fullcalendar.css (not used here) */
+	
+	.fc-event-nobg,
+	.fc-event-nobg a,
+	.fc-agenda .fc-event-nobg .fc-event-time {
+		border-style: none;
+		background: none;
+		color: inherit;
+		}
+
+</style>
+</head>
+<body style='font-size:12px'>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 82 - 89
test/locale.html

@@ -1,89 +1,82 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
-<link rel='stylesheet' type='text/css' href='jgrowl/jgrowl.css' />
-<script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/ui.core.js'></script>
-<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
-<script type='text/javascript' src='../fullcalendar/fullcalendar.js'></script>
-<script type='text/javascript' src='jgrowl/jgrowl.js'></script>
-<script type='text/javascript'>
-
-$(document).ready(function() {
-
-	$.fullCalendar.monthNames = ["januari", "februari", "maart", "april", "mei", "juni","juli", "augustus", "september", "oktober", "november", "december"];
-	$.fullCalendar.monthAbbrevs = ["jan", "feb", "maa", "apr", "mei", "jun", "jul", "aug","sep", "okt", "nov", "dec"];
-	$.fullCalendar.dayNames = ['zondag', 'maandag', 'dinsdag', 'woensdag','donderdag', 'vrijdag', 'zaterdag'];
-	$.fullCalendar.dayAbbrevs = ["zo", "ma", "di", "wo", "do", "vr", "za", "zo"];
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth();
-
-	$('#calendar').fullCalendar({
-	
-		abbrevDayHeadings: false,
-		
-		weekStart: 1,
-		
-		//rightToLeft: true,
-		
-		events: [
-			{
-				id: 1,
-				title: "Long Event",
-				start: new Date(y, m, 6, 14, 0),
-				end: new Date(y, m, 11)
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(y, m, 2)
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(y, m, 9)
-			},
-			{
-				id: 3,
-				title: "Meeting",
-				start: new Date(y, m, 20, 9, 0)
-			},
-			{
-				id: 4,
-				title: "Click for Facebook",
-				start: new Date(y, m, 27, 16),
-				end: new Date(y, m, 29),
-				url: "http://facebook.com/"
-			}
-		],
-		
-		draggable: true,
-		
-		dayClick: function(date) {
-			$(this).css('background', 'lightblue');
-			$.jGrowl("<b>dayClick</b><br />" +
-				date + "<br />" +
-				this.nodeName);
-		},
-		
-		eventDrop: function(event, delta, ev, ui) {
-			$.jGrowl("<b>eventDrop</b><br />" +
-				delta + "<br />" +
-				event.title + "<br />" +
-				ev.pageX + "," + ev.pageY + "<br />" +
-				ui);
-		}
-		
-	});
-
-});
-
-</script>
-</head>
-<body style='font-size:14px;font-family:Arial'>
-<div id='calendar' style='width:75%'></div>
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+
+	$(document).ready(function() {
+		$('#calendar').fullCalendar({
+			header: {
+				center: 'month,basicWeek,basicDay'
+			},
+			editable: true,
+			
+			isRTL: true,
+			weekMode: 'variable',
+			
+			// TODO: add drag & resize tests
+			
+			events: [
+				{
+					id: 1,
+					title: "Long Event",
+					start: new Date(y, m, 6),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 2)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 9)
+				},
+				{
+					id: 3,
+					title: "Meeting",
+					start: new Date(y, m, 20, 9, 0),
+					end: new Date(y, m, 20, 10, 0),
+					allDay: false
+				},
+				{
+					id: 4,
+					title: "Click for Facebook",
+					start: new Date(y, m, 27),
+					end: new Date(y, m, 28),
+					url: "http://facebook.com/"
+				},
+				{
+					id: 5,
+					title: "timed event1",
+					start: new Date (y, m, 31, 17, 30),
+					allDay: false
+				},
+				{
+					id: 6,
+					title: "timed event1",
+					start: new Date (y, m+1, 2, 14, 15),
+					allDay: false
+				},
+				{
+					id: 7,
+					title: "timed event1",
+					start: new Date (y, m+1, 4, 15, 00),
+					end: new Date(y, m+1, 4, 17, 00),
+					allDay: false
+				}
+			]
+		});
+	});
+
+</script>
+</head>
+<body style='font-size:12px'>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 150 - 110
test/methods.html

@@ -1,110 +1,150 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
-<link rel='stylesheet' type='text/css' href='jgrowl/jgrowl.css' />
-<style type='text/css'>
-
-	.newclass { color: red }
-
-</style>
-<script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/ui.core.js'></script>
-<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
-<script type='text/javascript' src='../fullcalendar/fullcalendar.js'></script>
-<script type='text/javascript' src='jgrowl/jgrowl.js'></script>
-<script type='text/javascript'>
-
-$(document).ready(function() {
-
-	$('#calendar').fullCalendar({
-	
-		title: false,
-		buttons: false,
-		monthDisplay: function(year, month, title) {
-			$('h3').text(title);
-		},
-		
-		draggable: true
-		
-	});
-
-});
-
-function addTestEvents() {
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth()+1;
-	if (m<10) m = '0' + m;
-	
-	$('#calendar').fullCalendar('addEvent', {
-		id: 99,
-		title: 'Some event',
-		start: y+'-'+m+'-02'
-	});
-	
-	$('#calendar').fullCalendar('addEvent', {
-		id: 99,
-		title: 'Some event',
-		start: y+'-'+m+'-09'
-	});
-	
-	$('#calendar').fullCalendar('addEvent', {
-		id: 5,
-		title: 'Birthday',
-		start: y+'-'+m+'-20'
-	});
-	
-}
-
-function updateTestEvents() {
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth()+1;
-	if (m<10) m = '0' + m;
-
-	var reps = $('#calendar').fullCalendar('getEventsById', 99);
-	var e = reps[1];
-	e.title = "Better Title!";
-	e.start = y+'-'+m+'-11';
-	e.end = y+'-'+m+'-13';
-	e.className = 'newclass';
-	e.draggable = false;
-	e.showTime = true;
-	$('#calendar').fullCalendar('updateEvent', e);
-	
-}
-
-function removeTestEvents(therepeating) {
-	if (therepeating) {
-		$('#calendar').fullCalendar('removeEvent', 99);
-	}else{
-		$('#calendar').fullCalendar('removeEvent', 5);
-	}
-}
-
-</script>
-</head>
-<body style='font-size:14px;font-family:Arial'>
-
-<div style='float:right'>
-<input type='button' value='add test events' onclick='addTestEvents()' /><br />
-<input type='button' value='update test events' onclick='updateTestEvents()' /><br />
-<input type='button' value='delete repeating events' onclick='removeTestEvents(true)' /><br />
-<input type='button' value='delete single event' onclick='removeTestEvents(false)' /><br />
-</div>
-
-<h3></h3>
-<p>
-<a href='#' onclick="$('#calendar').fullCalendar('today')">today</a> &nbsp;
-<a href='#' onclick="$('#calendar').fullCalendar('prevMonth')">prev</a> &nbsp;
-<a href='#' onclick="$('#calendar').fullCalendar('nextMonth')">next</a> &nbsp;
-<a href='#' onclick="$('#calendar').fullCalendar('prevYear')">prevyear</a> &nbsp;
-<a href='#' onclick="$('#calendar').fullCalendar('nextYear')">nextyear</a> &nbsp;
-<a href='#' onclick="$('#calendar').fullCalendar('gotoMonth', 1986, 5)">June 1986</a>
-</p>
-<div id='calendar' style='width:75%'></div>
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var cal;
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+	
+	var staticEvents;
+
+	$(document).ready(function() {
+		cal = $('#calendar').fullCalendar({
+			editable: true,
+			header: {
+				left: 'prev,next today',
+				center: 'title',
+				right: 'month,basicWeek,basicDay'
+			},
+			events: staticEvents = [
+				{
+					id: 1,
+					title: "Long Event",
+					start: new Date(y, m, 6),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 2)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 9)
+				},
+				{
+					id: 3,
+					title: "Meeting",
+					start: new Date(y, m, 20, 9, 0),
+					end: new Date(y, m, 21, 0, 0),
+					allDay: false
+				},
+				{
+					id: 4,
+					title: "Click for Facebook",
+					start: new Date(y, m, 27),
+					end: new Date(y, m, 28),
+					url: "http://facebook.com/"
+				},
+				{
+					id: 5,
+					title: "timed event1",
+					start: new Date (y, m, 31, 17, 30),
+					allDay: false
+				},
+				{
+					id: 6,
+					title: "timed event1",
+					start: new Date (y, m+1, 2, 14, 15),
+					allDay: false
+				},
+				{
+					id: 7,
+					title: "timed event1",
+					start: new Date (y, m+1, 4, 15, 00),
+					end: new Date(y, m+1, 4, 17, 00),
+					allDay: false
+				}
+			]
+		});
+	});
+	
+	function updateEventStart() {
+		var event = cal.fullCalendar('clientEvents', 3)[0];
+		event.start = new Date(y, m, 25, 10, 30);
+		event.end = new Date(y, m, 26);
+		cal.fullCalendar('updateEvent', event);
+	}
+	
+	function updateRepeatingEvent() {
+		var event = cal.fullCalendar('clientEvents', 2)[0];
+		event.start = new Date(y, m, 4, 13, 30);
+		event.end = new Date(y, m, 5, 1, 0);
+		event.allDay = false;
+		event.title = "repeat yo";
+		cal.fullCalendar('updateEvent', event);
+		console.log(cal.fullCalendar('clientEvents', 2));
+	}
+	
+	function renderEvent(stick) {
+		cal.fullCalendar('renderEvent', {
+			start: new Date(y, m, 16),
+			title: 'heyman'
+		}, stick);
+	}
+	
+	var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");
+	
+	var jsonFeed = "../examples/json_events.php";
+
+</script>
+<style>
+
+	button {
+		font-size: 11px;
+	}
+
+</style>
+</head>
+<body style='font-size:12px'>
+<p>
+
+<button onclick="cal.fullCalendar('prev')">prev</button>
+<button onclick="cal.fullCalendar('next')">next</button>
+<button onclick="cal.fullCalendar('today')">today</button>
+<button onclick="cal.fullCalendar('gotoDate', 1999, 9, 31)">Oct 31 1999</button>
+<button onclick="cal.fullCalendar('moveDate', 1, 1, 1)">+1 +1 +1</button>
+<button onclick="cal.fullCalendar('moveDate', -1, -1, -1)">-1 -1 -1</button>
+
+<button onclick="updateEventStart()">update event start</button>
+<button onclick="updateRepeatingEvent()">update repeating event</button>
+<button onclick="renderEvent(false)">render new event</button>
+<button onclick="renderEvent(true)">render new sticky event</button>
+<br />
+
+<button onclick="cal.fullCalendar('removeEvents')">remove all</button>
+<button onclick="cal.fullCalendar('removeEvents', 2)">remove repeating events</button>
+<button onclick="cal.fullCalendar('removeEvents', function(e){return !e.allDay})">remove timed events</button>
+<button onclick="console.log(cal.fullCalendar('clientEvents'))">log events</button>
+<button onclick="console.log(cal.fullCalendar('clientEvents', '2'))">log repeating events</button>
+<button onclick="console.log(cal.fullCalendar('clientEvents', function(e){return e.allDay}))">log all-day events</button>
+<br />
+
+<button onclick="cal.fullCalendar('addEventSource', staticEvents)">+ static events</button>
+<button onclick="cal.fullCalendar('removeEventSource', staticEvents)">- static events</button>
+<button onclick="cal.fullCalendar('addEventSource', gcalFeed)">+ gcal</button>
+<button onclick="cal.fullCalendar('removeEventSource', gcalFeed)">- gcal</button>
+<button onclick="cal.fullCalendar('addEventSource', jsonFeed)">+ json</button>
+<button onclick="cal.fullCalendar('removeEventSource', jsonFeed)">- json</button>
+
+<button onclick="cal.fullCalendar('rerenderEvents')">rerender</button>
+<button onclick="cal.fullCalendar('refetchEvents')">refetch</button>
+
+</p>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 0 - 119
test/new.html

@@ -1,119 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<script type='text/javascript' src='loader.js'></script>
-<script type='text/javascript'>
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth();
-
-	$(document).ready(function() {
-		$('#calendar').fullCalendar({
-			windowResize: function() {
-				//alert('resize');
-			},
-			theme: false,
-			isRTL: false,
-			weekStart: 1,
-			weekMode: 'fixed',
-			//defaultView: 'dayBasic',
-			viewDisplay: function(date, view) {
-				//console.log(date + ', ' + view.name);
-			},
-			dayClick: function(date, view) {
-				//console.log(date + ', ' + view.name);
-			},
-			eventRender: function(event, element) {
-				//console.log(event.title + ' RENDER');
-			},
-			eventMouseover: function(event) {
-				//console.log('OVER ' + event.title);
-			},
-			eventMouseout: function(event) {
-				//console.log('OUT ' + event.title);
-			},
-			eventClick: function(event) {
-				//console.log('CLICK ' + event.title + ' /// ' + this.className);
-				//return false;
-			},
-			eventDragStart: function(event) {
-				console.log('DRAG START ' + event.title);
-			},
-			eventDragStop: function(event) {
-				console.log('DRAG STOP ' + event.title);
-			},
-			eventDrop: function(event, dayDelta, minuteDelta) {
-				console.log(dayDelta + ' ' + minuteDelta + ' --- ' + event.title);
-			},
-			eventResizeStart: function(event) {
-				//console.log('resize START');
-			},
-			eventResizeStop: function(event) {
-				//console.log('resize STOP');
-			},
-			eventResize: function(event, dayDelta, minuteDelta) {
-				//console.log(dayDelta + ' ' + minuteDelta + ' --- ' + event.title);
-			},
-			editable: true,
-			eventSources: [
-				$.fullCalendar.gcalFeed('http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic')
-			],
-			events: [
-				{
-					id: 1,
-					title: "Long Event",
-					start: new Date(y, m, 6),
-					end: new Date(y, m, 10)
-				},
-				{
-					id: 2,
-					title: "Repeating",
-					start: new Date(y, m, 2)
-				},
-				{
-					id: 2,
-					title: "Repeating",
-					start: new Date(y, m, 9)
-				},
-				{
-					id: 3,
-					title: "Meeting",
-					start: new Date(y, m, 20, 9, 0),
-					hasTime: true
-				},
-				{
-					id: 4,
-					title: "Click for Facebook",
-					start: new Date(y, m, 27),
-					end: new Date(y, m, 28),
-					url: "http://facebook.com/"
-				},
-				{
-					id: 5,
-					title: "timed event1",
-					start: new Date (y, m, 31, 17, 30),
-					hasTime: true
-				},
-				{
-					id: 6,
-					title: "timed event1",
-					start: new Date (y, m+1, 2, 14, 15),
-					hasTime: true
-				},
-				{
-					id: 7,
-					title: "timed event1",
-					start: new Date (y, m+1, 4, 15, 00),
-					end: new Date(y, m+1, 4, 17, 00),
-					hasTime: true
-				}
-			]
-		});
-	});
-
-</script>
-</head>
-<body style='font-size:12px'>
-<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
-</body>

+ 109 - 99
test/options.html

@@ -1,99 +1,109 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
-<link rel='stylesheet' type='text/css' href='jgrowl/jgrowl.css' />
-<style type='text/css'>
-
-	.full-calendar-month .rep td { background: green }
-	.full-calendar-month .cool td { color: yellow }
-	.full-calendar-month .long td { background: red }
-
-</style>
-<script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/ui.core.js'></script>
-<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
-<script type='text/javascript' src='../fullcalendar/fullcalendar.js'></script>
-<script type='text/javascript' src='jgrowl/jgrowl.js'></script>
-<script type='text/javascript'>
-
-$(document).ready(function() {
-
-	$('#calendar').fullCalendar({
-	
-		year: 2009,
-		month: 3,
-		
-		draggable: true,
-		
-		fixedWeeks: true,
-		
-		abbrevDayHeadings: false,
-		
-		//title: false,
-		titleFormat: 'm/Y', //'n/Y', //'M y',
-		
-		//buttons: false,
-		//buttons: { today:false },
-		//buttons: { today:false, prevMonth:"prev", nextMonth:"next" },
-		//buttons: { today:true, prevMonth:false, nextMonth:"next" },
-		//buttons: { prevYear:true, nextYear:true },
-		//buttons: { today:true, prevYear:"py", prevMonth:true, nextMonth:true, nextYear:"ny" },
-		
-		showTime: true,
-		timeFormat: 'ha', //'H:i', //'GA', //'gX',
-		
-		eventDragOpacity: .5,
-		eventRevertDuration: 2000,
-		
-		// test for CalEvent.source
-		eventDrop: function(event) {
-			$.jGrowl(event.source);
-		},
-		
-		events: [
-			{
-				id: 1,
-				title: "Long Event",
-				start: new Date(2009, 3, 6, 14, 0),
-				end: new Date(2009, 3, 11),
-				showTime: false,                  // showTime
-				className: 'long',
-				draggable: false                  // draggable
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(2009, 3, 2),
-				className: 'rep cool'
-			},
-			{
-				id: 2,
-				title: "Repeating Event",
-				start: new Date(2009, 3, 9),
-				className: ['rep', 'cool']
-			},
-			{
-				id: 3,
-				title: "Meeting",
-				date: new Date(2009, 3, 20, 9, 30) // date alias
-			},
-			{
-				id: 4,
-				title: "Click for Facebook",
-				start: new Date(2009, 3, 27, 16),
-				end: new Date(2009, 3, 29),
-				url: "http://facebook.com/"
-			}
-		]
-		
-	});
-
-});
-
-</script>
-</head>
-<body style='font-size:14px;font-family:Arial'>
-<div id='calendar' style='width:75%'></div>
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+
+	$(document).ready(function() {
+		$('#calendar').fullCalendar({
+		
+			/*
+			year: 2010,
+			month: 2,
+			date: 1,
+			
+			defaultView: 'basicDay',
+			
+			aspectRatio: 1,
+			*/
+			
+			header: {
+				left: 'title',
+				center: 'prev,month,basicWeek,basicDay,next',
+				right: 'today'
+			},
+			
+			editable: true,
+			//disableDragging: true,
+			//disableResizing: true,
+			dragOpacity: .5,
+			dragRevertDuration: 100,
+			
+			weekMode: 'liquid', //'variable'
+			
+			/*
+			titleFormat: {
+				month: "'hey!'"
+			},
+			*/
+			
+			columnFormat: {
+				month: "dddd"
+			},
+			
+			timeFormat: "H(:mm)[T]{ - H(:mm)T}",
+			
+			events: [
+				{
+					id: 1,
+					title: "Long Event",
+					start: new Date(y, m, 6),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 2)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 9)
+				},
+				{
+					id: 3,
+					title: "Meeting",
+					start: new Date(y, m, 20, 9, 0),
+					end: new Date(y, m, 20, 10, 0),
+					allDay: false
+				},
+				{
+					id: 4,
+					title: "Click for Facebook",
+					start: new Date(y, m, 27),
+					end: new Date(y, m, 28),
+					url: "http://facebook.com/"
+				},
+				{
+					id: 5,
+					title: "timed event1",
+					start: new Date (y, m, 31, 17, 30),
+					allDay: false
+				},
+				{
+					id: 6,
+					title: "timed event1",
+					start: new Date (y, m+1, 2, 14, 15),
+					allDay: false
+				},
+				{
+					id: 7,
+					title: "timed event1",
+					start: new Date (y, m+1, 4, 15, 00),
+					end: new Date(y, m+1, 4, 17, 00),
+					allDay: false
+				}
+			]
+		});
+	});
+
+</script>
+</head>
+<body style='font-size:12px'>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 144 - 145
test/sources.html

@@ -1,145 +1,144 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<link rel='stylesheet' type='text/css' href='../fullcalendar/fullcalendar.css' />
-<link rel='stylesheet' type='text/css' href='jgrowl/jgrowl.css' />
-<style type='text/css'>
-
-	.full-calendar-month .static td {
-		background: blue;
-		color: yellow;
-	}
-	
-	.full-calendar-month .gcal td {
-		background: lightgreen;
-	}
-
-</style>
-
-<!--
-<script type='text/javascript' src='legacy_jquery/jquery.js'></script>
-<script type='text/javascript' src='legacy_jquery/ui.core.js'></script>
-<script type='text/javascript' src='legacy_jquery/ui.draggable.js'></script>
--->
-
-<script type='text/javascript' src='../jquery/jquery.js'></script>
-<script type='text/javascript' src='../jquery/ui.core.js'></script>
-<script type='text/javascript' src='../jquery/ui.draggable.js'></script>
-
-<script type='text/javascript' src='../fullcalendar/fullcalendar.js'></script>
-<!--<script type='text/javascript' src='../build/fullcalendar.min.js'></script>-->
-<script type='text/javascript' src='../fullcalendar/gcal.js'></script>
-<script type='text/javascript' src='jgrowl/jgrowl.js'></script>
-<script type='text/javascript'>
-
-$(document).ready(function() {
-
-	var d = new Date();
-	var y = d.getFullYear();
-	var m = d.getMonth();
-	
-	var gcalSource = $.fullCalendar.gcalFeed(
-		'http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic',
-		{draggable: true, className: 'gcal'}
-	);
-	
-	var staticSource = [
-		{
-			id: 1,
-			title: "Long Event",
-			start: new Date(y, m, 6, 14, 0),
-			end: new Date(y, m, 11),
-			className: 'static'
-		},
-		{
-			id: 2,
-			title: "Repeating Event",
-			start: new Date(y, m, 2),
-			className: 'static'
-		},
-		{
-			id: 2,
-			title: "Repeating Event",
-			start: new Date(y, m, 9),
-			className: 'static'
-		},
-		{
-			id: 3,
-			title: "Meeting",
-			start: new Date(y, m, 20, 9, 0),
-			className: 'static'
-		},
-		{
-			id: 4,
-			title: "Click for Facebook",
-			start: new Date(y, m, 27, 16),
-			end: new Date(y, m, 29),
-			url: "http://facebook.com/",
-			className: 'static'
-		}
-	];
-	
-	var jsonSource = "../examples/json_events.php";
-
-	$('#calendar').fullCalendar({
-	
-		draggable: true,
-		
-		eventSources: [staticSource, gcalSource],
-		
-		loading: function(bool) {
-			if (bool) {
-				$('#loading').css('visibility', 'visible');
-			}else{
-				$('#loading').css('visibility', 'hidden');
-			}
-		}
-		
-	});
-	
-	window.addStaticSource = function() {
-		$('#calendar').fullCalendar('addEventSource', staticSource);
-	};
-	
-	window.addJsonSource = function() {
-		$('#calendar').fullCalendar('addEventSource', jsonSource);
-	};
-	
-	window.addGcalSource = function() {
-		$('#calendar').fullCalendar('addEventSource', gcalSource);
-	};
-	
-	window.removeStaticSource = function() {
-		$('#calendar').fullCalendar('removeEventSource', staticSource);
-	};
-	
-	window.removeJsonSource = function() {
-		$('#calendar').fullCalendar('removeEventSource', jsonSource);
-	};
-	
-	window.removeGcalSource = function() {
-		$('#calendar').fullCalendar('removeEventSource', gcalSource);
-	};
-
-});
-
-</script>
-</head>
-<body style='font-size:14px;font-family:Arial'>
-
-<div style='float:right'>
-<input type='button' value='add static event source' onclick='addStaticSource()' /><br />
-<input type='button' value='* add json event source' onclick='addJsonSource()' /><br />
-<input type='button' value='add gcal event source' onclick='addGcalSource()' /><br />
-<br />
-<input type='button' value='remove static event source' onclick='removeStaticSource()' /><br />
-<input type='button' value='remove json event source' onclick='removeJsonSource()' /><br />
-<input type='button' value='remove gcal event source' onclick='removeGcalSource()' /><br />
-<br />
-<input type='button' value='refresh' onclick="$('#calendar').fullCalendar('refresh')" />
-</div>
-
-<div style='visibility:hidden' id='loading'>loading...</div>
-<div id='calendar' style='float:left;width:75%'></div>
-</body>
-</html>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var cal;
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+	
+	var gcalFeed = $.fullCalendar.gcalFeed("http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic");
+	
+	var jsonFeed = "../examples/json_events.php";
+	
+	var staticEvents = [
+		{
+			id: 1,
+			title: "Long Event",
+			date: new Date(y, m, 6), //!
+			end: new Date(y, m, 10),
+			className: 'red-event'
+		},
+		{
+			id: 2,
+			title: "Repeating",
+			start: new Date(y, m, 2)
+		},
+		{
+			id: 2,
+			title: "Repeating",
+			start: new Date(y, m, 9)
+		},
+		{
+			id: 3,
+			title: "Meeting",
+			start: new Date(y, m, 20, 9, 0),
+			end: new Date(y, m, 21, 0, 0),
+			allDay: false,
+			//className: 'yellow-event black-text-event',
+			className: ['yellow-event', 'black-text-event'],
+			editable: false
+		},
+		{
+			id: 4,
+			title: "Click for Facebook",
+			start: new Date(y, m, 27),
+			end: new Date(y, m, 28),
+			url: "http://facebook.com/"
+		},
+		{
+			id: 5,
+			title: "timed event1",
+			start: new Date (y, m, 31, 17, 30),
+			allDay: false
+		},
+		{
+			id: 6,
+			title: "timed event1",
+			start: new Date (y, m+1, 2, 14, 15),
+			allDay: false
+		},
+		{
+			id: 7,
+			title: "timed event1",
+			start: new Date (y, m+1, 4, 15, 00),
+			end: new Date(y, m+1, 4, 17, 00),
+			allDay: false
+		}
+	];
+	
+	var customSource = function(start, end, callback) {
+		callback([
+			{
+				title: 'FIRST',
+				start: start
+			},
+			{
+				title: 'LAST',
+				start: new Date(end - 1)
+			}
+		]);
+	};
+
+	$(document).ready(function() {
+		cal = $('#calendar').fullCalendar({
+			editable: true,
+			header: {
+				left: 'prev,next today',
+				center: 'title',
+				right: 'month,basicWeek,basicDay'
+			},
+			//events: staticEvents,
+			eventSources: [
+				staticEvents,
+				jsonFeed,
+				gcalFeed,
+				customSource
+			],
+			loading: function(bool) {
+				if (bool) {
+					$('#loading').show();
+				}else{
+					$('#loading').hide();
+				}
+			}
+			/*
+			,
+			startParam: 'mystart',
+			endParam: 'myend',
+			cacheParam: 'uniq'
+			*/
+		});
+	});
+
+</script>
+<style>
+
+	.red-event a {
+		background: red;
+	}
+	
+	.yellow-event a {
+		background: yellow;
+	}
+	
+	.black-text-event a {
+		color: #000;
+	}
+
+	button {
+		font-size: 11px;
+	}
+
+</style>
+</head>
+<body style='font-size:12px'>
+<div id='loading' style='position:absolute;top:0;left:0;display:none'>loading...</div>
+<p>
+<button onclick="cal.fullCalendar('refetchEvents')">refetch</button>
+</p>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 87 - 0
test/theming.html

@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<link rel='stylesheet' type='text/css' href='../examples/redmond/theme.css' />
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+
+	$(document).ready(function() {
+		$('#calendar').fullCalendar({
+		
+			theme: true,
+			editable: true,
+			
+			header: {
+				center: 'month,basicWeek,basicDay'
+			},
+			
+			buttonIcons: {
+				prev: 'triangle-1-w',
+				next: 'triangle-1-e',
+				today: 'home'
+			},
+			
+			events: [
+				{
+					id: 1,
+					title: "Long Event",
+					start: new Date(y, m, 6),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 2)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 9)
+				},
+				{
+					id: 3,
+					title: "Meeting",
+					start: new Date(y, m, 20, 9, 0),
+					end: new Date(y, m, 20, 10, 0),
+					allDay: false
+				},
+				{
+					id: 4,
+					title: "Click for Facebook",
+					start: new Date(y, m, 27),
+					end: new Date(y, m, 28),
+					url: "http://facebook.com/"
+				},
+				{
+					id: 5,
+					title: "timed event1",
+					start: new Date (y, m, 31, 17, 30),
+					allDay: false
+				},
+				{
+					id: 6,
+					title: "timed event1",
+					start: new Date (y, m+1, 2, 14, 15),
+					allDay: false
+				},
+				{
+					id: 7,
+					title: "timed event1",
+					start: new Date (y, m+1, 4, 15, 00),
+					end: new Date(y, m+1, 4, 17, 00),
+					allDay: false
+				}
+			]
+		});
+	});
+
+</script>
+</head>
+<body style='font-size:12px'>
+<div id='calendar' style='width:900px;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>

+ 180 - 0
test/triggers.html

@@ -0,0 +1,180 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<script type='text/javascript' src='loader.js'></script>
+<script type='text/javascript'>
+
+	var d = new Date();
+	var y = d.getFullYear();
+	var m = d.getMonth();
+
+	$(document).ready(function() {
+		$('#calendar').fullCalendar({
+			header: {
+				left: 'prev,next today',
+				center: 'title',
+				right: 'month,basicWeek,basicDay'
+			},
+			editable: true,
+			weekMode: 'variable',
+			
+			viewDisplay: function(view) {
+				console.log('viewDisplay');
+				console.log(view);
+				console.log(this);
+			},
+			
+			//loading: // see sources.html
+			
+			windowResize: function(view) {
+				console.log('windowResize - ' + view.title);
+				console.log(this);
+			},
+			
+			dayClick: function(dayDate, view) {
+				console.log('dayClick - ' + dayDate + ' - ' + view.title);
+				console.log(this);
+			},
+			
+			eventRender: function(event, element, view) {
+				if (event.id == 555) {
+					return false;
+				}
+				else if (event.id == 666) {
+					return $("<div style='background:green'/>").text(event.title);
+				}
+				else if (event.id == 1) {
+					element.css('border-color', 'red');
+					console.log('renderEvent (' + event.title + ') - ' + view.title);
+				}
+			},
+			
+			eventClick: function(event, jsEvent, view) {
+				console.log('EVENT CLICK ' + event.title);
+				console.log(jsEvent);
+				console.log(view);
+				console.log(this);
+				return false;
+			},
+			/*
+			eventMouseover: function(event, jsEvent, view) {
+				console.log('MOUSEOVER ' + event.title);
+				console.log(jsEvent);
+				console.log(view);
+				console.log(this);
+			},
+			eventMouseout: function(event, jsEvent, view) {
+				console.log('MOUSEOUT ' + event.title);
+				console.log(jsEvent);
+				console.log(view);
+				console.log(this);
+			},
+			*/
+			
+			eventDragStart: function(event, jsEvent, ui, view) {
+				console.log('DRAG START ' + event.title);
+				console.log(this);
+			},
+			eventDragStop: function(event, jsEvent, ui, view) {
+				console.log('DRAG STOP ' + event.title);
+				console.log(this);
+			},
+			eventDrop: function(event, dayDelta, minuteDelta, jsEvent, ui, view) {
+				console.log('DROP ' + event.title);
+				console.log(dayDelta + ' days');
+				console.log(minuteDelta + ' minutes');
+				console.log(jsEvent);
+				console.log(ui);
+				console.log(view.title);
+				console.log(this);
+			},
+			
+			eventResizeStart: function(event, jsEvent, ui, view) {
+				console.log('RESIZE START ' + event.title);
+				console.log(this);
+			},
+			eventResizeStop: function(event, jsEvent, ui, view) {
+				console.log('RESIZE STOP ' + event.title);
+				console.log(this);
+			},
+			eventResize: function(event, dayDelta, minuteDelta, jsEvent, ui, view) {
+				console.log('RESIZE!! ' + event.title);
+				console.log(dayDelta + ' days');
+				console.log(minuteDelta + ' minutes');
+				console.log(jsEvent);
+				console.log(ui);
+				console.log(view.title);
+				console.log(this);
+			},
+			
+			events: [
+				{
+					id: 555,
+					title: "Rejected Event",
+					start: new Date(y, m, 5)
+				},
+				{
+					id: 666,
+					title: "Homemade Elm Event",
+					start: new Date(y, m, 6)
+				},
+				{
+					id: 1,
+					title: "Long Event",
+					start: new Date(y, m, 6),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 2)
+				},
+				{
+					id: 2,
+					title: "Repeating",
+					start: new Date(y, m, 9),
+					end: new Date(y, m, 10)
+				},
+				{
+					id: 3,
+					title: "Meeting",
+					start: new Date(y, m, 20, 9, 0),
+					end: new Date(y, m, 20, 10, 0),
+					allDay: false
+				},
+				{
+					id: 4,
+					title: "Click for Facebook",
+					start: new Date(y, m, 27),
+					end: new Date(y, m, 28),
+					url: "http://facebook.com/"
+				},
+				{
+					id: 5,
+					title: "timed event1",
+					start: new Date (y, m, 31, 17, 30),
+					allDay: false
+				},
+				{
+					id: 6,
+					title: "timed event1",
+					start: new Date (y, m+1, 2, 14, 15),
+					allDay: false
+				},
+				{
+					id: 7,
+					title: "timed event1",
+					start: new Date (y, m+1, 4, 15, 00),
+					end: new Date(y, m+1, 4, 17, 00),
+					allDay: false
+				}
+			]
+		});
+	});
+
+</script>
+</head>
+<body style='font-size:12px'>
+<div id='calendar' style='width:75%;margin:20px auto 0;font-family:arial'></div>
+</body>
+</html>