Quellcode durchsuchen

better timezone support for Google Calendar plugin

can request events when timezone has spaces (like "America/New York").
url of Event Objects will have gcal page with correct timezone.
Adam Shaw vor 11 Jahren
Ursprung
Commit
f17264f6e9
2 geänderte Dateien mit 84 neuen und 17 gelöschten Zeilen
  1. 25 2
      src/gcal/gcal.js
  2. 59 15
      tests/automated/events-gcal.js

+ 25 - 2
src/gcal/gcal.js

@@ -73,6 +73,7 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
 	var apiKey = sourceOptions.googleCalendarApiKey || calendar.options.googleCalendarApiKey;
 	var success = sourceOptions.success;
 	var data;
+	var timezoneArg; // populated when a specific timezone. escaped to Google's liking
 
 	function reportError(message, apiErrorObjs) {
 		var errorObjs = apiErrorObjs || [ { message: message } ]; // to be passed into error handlers
@@ -105,10 +106,16 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
 		end = end.clone().utc().add(1, 'day');
 	}
 
+	// when sending timezone names to Google, only accepts underscores, not spaces
+	if (timezone && timezone != 'local') {
+		timezoneArg = timezone.replace(' ', '_');
+	}
+
 	data = $.extend({}, sourceOptions.data || {}, {
 		key: apiKey,
 		timeMin: start.format(),
 		timeMax: end.format(),
+		timeZone: timezoneArg,
 		singleEvents: true,
 		maxResults: 9999
 	});
@@ -117,9 +124,9 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
 		googleCalendarId: null, // prevents source-normalizing from happening again
 		url: url,
 		data: data,
-		timezoneParam: 'timeZone',
 		startParam: false, // `false` omits this parameter. we already included it above
 		endParam: false, // same
+		timezoneParam: false, // same
 		success: function(data) {
 			var events = [];
 			var successArgs;
@@ -130,12 +137,19 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
 			}
 			else if (data.items) {
 				$.each(data.items, function(i, entry) {
+					var url = entry.htmlLink;
+
+					// make the URLs for each event show times in the correct timezone
+					if (timezoneArg) {
+						url = injectQsComponent(url, 'ctz=' + timezoneArg);
+					}
+
 					events.push({
 						id: entry.id,
 						title: entry.summary,
 						start: entry.start.dateTime || entry.start.date, // try timed. will fall back to all-day
 						end: entry.end.dateTime || entry.end.date, // same
-						url: entry.htmlLink,
+						url: url,
 						location: entry.location,
 						description: entry.description
 					});
@@ -155,4 +169,13 @@ function transformOptions(sourceOptions, start, end, timezone, calendar) {
 }
 
 
+// Injects a string like "arg=value" into the querystring of a URL
+function injectQsComponent(url, component) {
+	// inject it after the querystring but before the fragment
+	return url.replace(/(\?.*?)?(#|$)/, function(whole, qs, hash) {
+		return (qs ? qs + '&' : '?') + component + hash;
+	});
+}
+
+
 });

+ 59 - 15
tests/automated/events-gcal.js

@@ -44,48 +44,92 @@ describe('Google Calendar plugin', function() {
 		console.warn = oldConsoleWarn;
 	});
 
-	it('sends request correctly when local timezone', function() {
+	it('request/receives correctly when local timezone', function(done) {
 		options.googleCalendarApiKey = API_KEY;
 		options.events = { googleCalendarId: '[email protected]' };
 		options.timezone = 'local';
+		options.eventAfterAllRender = function() {
+			var events = $('#cal').fullCalendar('clientEvents');
+			var i;
+
+			expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
+			expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
+			expect(currentRequest.data.timeZone).toBeUndefined();
+
+			expect(events.length).toBe(4);
+			for (i = 0; i < events.length; i++) {
+				expect(events[i].url).not.toMatch('ctz=');
+			}
+
+			done();
+		};
 		$('#cal').fullCalendar(options);
-		expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
-		expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
-		expect(currentRequest.data.timeZone).toBeUndefined();
 	});
 
-	it('sends request correctly when UTC timezone', function() {
+	it('request/receives correctly when UTC timezone', function(done) {
 		options.googleCalendarApiKey = API_KEY;
 		options.events = { googleCalendarId: '[email protected]' };
 		options.timezone = 'UTC';
+		options.eventAfterAllRender = function() {
+			var events = $('#cal').fullCalendar('clientEvents');
+			var i;
+
+			expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
+			expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
+			expect(currentRequest.data.timeZone).toEqual('UTC');
+
+			expect(events.length).toBe(4);
+			for (i = 0; i < events.length; i++) {
+				expect(events[i].url).toMatch('ctz=UTC');
+			}
+
+			done();
+		};
 		$('#cal').fullCalendar(options);
-		expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
-		expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
-		expect(currentRequest.data.timeZone).toEqual('UTC');
 	});
 
-	it('sends request correctly when custom timezone', function() {
+	it('request/receives correctly when custom timezone', function(done) {
 		options.googleCalendarApiKey = API_KEY;
 		options.events = { googleCalendarId: '[email protected]' };
-		options.timezone = 'America/Chicago';
+		options.timezone = 'America/New York';
+		options.eventAfterAllRender = function() {
+			var events = $('#cal').fullCalendar('clientEvents');
+			var i;
+
+			expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
+			expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
+			expect(currentRequest.data.timeZone).toEqual('America/New_York'); // space should be escaped
+
+			expect(events.length).toBe(4);
+			for (i = 0; i < events.length; i++) {
+				expect(events[i].url).toMatch('ctz=America/New_York');
+			}
+
+			done();
+		};
 		$('#cal').fullCalendar(options);
-		expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
-		expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
-		expect(currentRequest.data.timeZone).toEqual('America/Chicago');
 	});
 
-	it('fetches events correctly when no timezone, defaults to not editable', function(done) {
+	it('requests/receives correctly when no timezone, defaults to not editable', function(done) {
 		options.googleCalendarApiKey = API_KEY;
 		options.events = { googleCalendarId: '[email protected]' };
 		options.eventAfterAllRender = function() {
 			var events = $('#cal').fullCalendar('clientEvents');
 			var eventEls = $('.fc-event');
-			expect(events.length).toBe(4); // 4 holidays in November 2014
+			var i;
+
 			expect(currentRequest.data.timeMin).toEqual('2014-10-25T00:00:00+00:00'); // one day before, by design
 			expect(currentRequest.data.timeMax).toEqual('2014-12-08T00:00:00+00:00'); // one day after, by design
 			expect(currentRequest.data.timeZone).toBeUndefined();
+
+			expect(events.length).toBe(4); // 4 holidays in November 2014
+			for (i = 0; i < events.length; i++) {
+				expect(events[i].url).not.toMatch('ctz=');
+			}
+
 			expect(eventEls.length).toBe(4);
 			expect(eventEls.find('.fc-resizer').length).toBe(0); // not editable
+
 			done();
 		};
 		$('#cal').fullCalendar(options);