/**
- Copyright 2008 Google Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
*/
/**
// Namespace to protect this library from conflicting with external
var calvis = calvis || {};
// Constant strings for month labels
calvis.MONTHS = [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto',
'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ];
// Constant strings for day labels
calvis.DAYS = [ 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom' ];
// CSS IDs
calvis.monthViewButtonId = 'monthViewButton';
calvis.weekViewButtonId = 'weekViewButton';
calvis.todayButtonId = 'todayButton';
calvis.prevWeekButtonId = 'prevWeek';
calvis.nextWeekButtonId = 'nextWeek';
calvis.prevMonthButtonId = 'prevMonth';
calvis.nextMonthButtonId = 'nextMonth';
calvis.yearChooserId = 'yearChooser';
calvis.weekDurationId = 'weekDuration';
calvis.yearHolderId = 'yearHolder';
calvis.monthHolderId = 'monthHolder';
calvis.loginLinkId = 'loginLink';
// CSS classes
calvis.columnHeadingClass = 'columnHeading';
calvis.weekViewCellClass = 'weekViewCell';
calvis.monthViewCellClass = 'monthViewCell';
calvis.contentCellClass = 'contentCell';
calvis.eventClass = 'eventItem';
// string labels
calvis.AppStringLabel = 'Generic-Calendar-Container-1.0';
calvis.loginLabel = 'Log in';
calvis.logoutLabel = 'Log out';
calvis.monthViewButtonLabel = 'Mese';
calvis.weekViewButtonLabel = 'Settimana';
calvis.todayButtonLabel = 'Giorno';
calvis.prevWeekButtonLabel = '<<';
calvis.nextWeekButtonLabel = '>>';
calvis.prevMonthButtonLabel = '<<';
calvis.nextMonthButtonLabel = '>>';
calvis.loadingLabel = ' loading... ';
calvis.moreLabel = 'more';
/**
-
Constructor to create an instance of the Calendar Container
*/
calvis.Calendar = function() {
// Fix quarks for IE
calvis.fixIE();
// Create an instance of the Google Data service object
this.calendarService = new google.gdata.calendar.CalendarService(
calvis.AppStringLabel);
// CSS IDs to position key container components
this.calendarBodyId = null;
this.navControlId = null;
this.viewControlId = null;
this.loginControlId = null;
this.statusControlId = null;
this.eventDisplayId = null;
// The callback method to be invoked when event is triggered to be displayed
this.eventCallback = null;
// The calendar ID(s) to be displayed from this container
this.calIds = null;
// The visibility of this calendar, private or public
this.visibility = null;
// The pivot date for the current navigation view
this.currentPivotDate = new Date();
// The current view mode of the container
this.currentViewMode = null;
// Cache todays date
this.currentDateCellID = [ new Date().getFullYear(),
calvis.padZero(new Date().getMonth() + 1),
calvis.padZero(new Date().getDate()) ].join('');
};
/**
- Set the CSS ID for the calendar body. Calendar body is the grid that
- represents where the date cells are contained.
- @param {string}
-
cssId The CSS ID of the calendar body.
*/
calvis.Calendar.prototype.setCalendarBody = function(cssId) {
this.calendarBodyId = cssId;
};
/**
- Set the CSS ID for the navigation control. Navgivation control allows the
- user to navigate through the calendar
- @param {string}
-
cssId The CSS ID of the navigation control.
*/
calvis.Calendar.prototype.setNavControl = function(cssId) {
this.navControlId = cssId;
};
/**
- Set the CSS ID for the view control. View control allows the user to switch
- between calendar views (month or week)
- @param {string}
-
cssId The CSS ID of the view control.
*/
calvis.Calendar.prototype.setViewControl = function(cssId) {
this.viewControlId = cssId;
};
/**
- Set the CSS ID for the status control. Status control is where the calendar
- status such as "loading" or error messages are displayed
- @param {string}
-
cssId The CSS ID of the status control.
*/
calvis.Calendar.prototype.setStatusControl = function(cssId) {
this.statusControlId = cssId;
};
/**
- Set the method that will be invoked when a trigger (click or mouseover)
- occurs.
- @param {string}
-
trigger The event that triggers the callback, can be "click" or
-
- @param {Function}
-
callback This callback will be invoked when the trigger occurs.
-
The callback will be passed one argument of type
-
"google.gdata.calendar.CalendarEventEntry", documentation -
-
http://code.google.com/apis/gdata/jsdoc/1.1/google/gdata/calendar/CalendarEventEntry.html.
-
This callback should use this event object and access its details
-
*/
calvis.Calendar.prototype.setEventCallback = function(trigger, callback) {
this.eventTrigger = trigger;
this.eventCallback = callback;
};
/**
- Set the array of Google Calendar IDs of one or more public calendars.
- @param {string}
-
calId The ID of a public Google Calendar.
*/
calvis.Calendar.prototype.setPublicCalendars = function(calIds) {
this.visibility = 'public';
this.calIds = calIds;
};
/**
-
This method should be called after all the CSS IDs and other properties are
-
set and ready to be displayed.
*/
calvis.Calendar.prototype.render = function() {
var calendar = this;
calendar.createFittingSpan();
// global init
// default view is month view
calendar.initViewControl();
if (!calendar.currentViewMode) {
calendar.setDefaultView('month');
}
calendar.currentViewMode();
};
/**
- Set the default view for CalVis initial rendering.
- @param {string}
-
view The View setting, either "month" or "week".
*/
calvis.Calendar.prototype.setDefaultView = function(view) {
switch (view) {
case 'week':
this.currentViewMode = this.initWeekView;
break;
case 'month':
this.currentViewMode = this.initMonthView;
break;
}
};
/**
- Retrieve the feed URL(s) that will be used for token request and also for
- data request of your calendar(s).
*/
calvis.Calendar.prototype.getFeedUrls = function() {
var feedUrlArray = new Array();
calIds = this.calIds;
for ( var i = 0; i < calIds.length; i++) {
feedUrlArray[i] = [ 'http://www.google.com/calendar/feeds/', calIds[i],
'/public/full' ].join('');
}
return feedUrlArray;
};
/**
-
Initialize the view control.
*/
calvis.Calendar.prototype.initViewControl = function() {
var calendar = this;
var viewControlHtml = [];
viewControlHtml.push('');
viewControlHtml.push(' ');
viewControlHtml.push('');
jQuery('#' + this.viewControlId).empty();
jQuery('#' + this.viewControlId).html(viewControlHtml.join(''));
// append click handler to view control buttons
jQuery('#' + calvis.monthViewButtonId).click(function() {
calendar.currentViewMode = calendar.initMonthView;
calendar.currentViewMode();
});
jQuery('#' + calvis.weekViewButtonId).click(function() {
calendar.currentViewMode = calendar.initWeekView;
calendar.currentViewMode();
});
};
/**
-
Update the week duration display of the Navigation control.
*/
calvis.Calendar.prototype.updateWeekDuration = function() {
var weekStart = calvis.getFirstDateOfWeek(this.currentPivotDate);
var weekEnd = new Date(weekStart);
weekEnd.setDate(weekEnd.getDate() + 6);
var durationString = [];
durationString.push(calvis.monthString(weekStart.getMonth()));
durationString.push(' ');
durationString.push(weekStart.getDate());
durationString.push(' - ');
durationString.push(calvis.monthString(weekEnd.getMonth()));
durationString.push(' ');
durationString.push(weekEnd.getDate());
durationString.push(' ');
durationString.push(weekEnd.getFullYear());
jQuery('#' + calvis.weekDurationId).empty();
jQuery('#' + calvis.weekDurationId).html(durationString.join(''));
};
/**
- Initialize week view.
*/
calvis.Calendar.prototype.initWeekView = function() {
this.initWeekNavControl();
this.updateWeekView();
};
/**
-
Initialize week view navigation control.
*/
calvis.Calendar.prototype.initWeekNavControl = function() {
var calendar = this;
var navControlHtml = [];
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
jQuery('#' + calendar.navControlId).empty();
jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));
calendar.updateWeekDuration();
jQuery('#' + calvis.todayButtonId).click(function() {
calendar.currentPivotDate = new Date();
calendar.currentViewMode();
});
jQuery('#' + calvis.prevWeekButtonId).click(
function() {
calendar.currentPivotDate.setDate(calendar.currentPivotDate
.getDate() - 7);
calendar.updateWeekView();
});
jQuery('#' + calvis.nextWeekButtonId).click(
function() {
calendar.currentPivotDate.setDate(calendar.currentPivotDate
.getDate() + 7);
calendar.updateWeekView();
});
};
/**
-
Update the current week view base on the current pivot date.
*/
calvis.Calendar.prototype.updateWeekView = function() {
this.updateWeekDuration();
var firstDate = calvis.getFirstDateOfWeek(this.currentPivotDate);
var lastDate = new Date(firstDate);
lastDate.setDate(firstDate.getDate() + 6);
var weekViewHtml = [];
weekViewHtml.push('
');weekViewHtml.push('
');var dateHolder = new Date(firstDate);
for ( var i = 0; i < 7; i++) {
var weekDateHeading = [ dateHolder.getFullYear(), '-',
calvis.padZero(dateHolder.getMonth() + 1), '-',
calvis.padZero(dateHolder.getDate()) ].join('');
var weekDateHeading = [];
weekDateHeading.push(calvis.dayString(dateHolder.getDay()));
weekDateHeading.push(' ');
weekDateHeading.push(dateHolder.getMonth() + 1);
weekDateHeading.push('/');
weekDateHeading.push(dateHolder.getDate());
weekViewHtml.push('<td class="');
weekViewHtml.push(calvis.columnHeadingClass);
weekViewHtml.push('">');
weekViewHtml.push(weekDateHeading.join(''));
weekViewHtml.push('</td>');
dateHolder.setDate(dateHolder.getDate() + 1);
}
weekViewHtml.push('
');var dateHolder = new Date(firstDate);
weekViewHtml.push('
');
for ( var i = 0; i < 7; i++) {
var dateCellId = [ dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');
var dateContentId = [ 'content', dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');weekViewHtml.push('<td>');
var dateHtml = [];
dateHtml.push('<div class="');
// add a class to todays date cell
if (dateCellId == this.currentDateCellID)
dateHtml.push(calvis.weekViewCellClass + ' today');
else
dateHtml.push(calvis.weekViewCellClass);
dateHtml.push('" id=');
dateHtml.push(dateCellId);
dateHtml.push('>');
// dateHtml.push(calvis.dayString(i));
dateHtml.push('<div class="');
dateHtml.push(calvis.contentCellClass);
dateHtml.push('" id=');
dateHtml.push(dateContentId);
dateHtml.push('>');
dateHtml.push('</div>');
dateHtml.push('</div>');
weekViewHtml.push(dateHtml.join(''));
weekViewHtml.push('</td>');
dateHolder.setDate(dateHolder.getDate() + 1);
}
weekViewHtml.push('
');
weekViewHtml.push('');
jQuery('#' + this.calendarBodyId).empty();
jQuery('#' + this.calendarBodyId).html(weekViewHtml.join(''));
var feedUriArray = this.getFeedUrls();
calendar = this;
for ( var i = 0; i < feedUriArray.length; i++) {
calendar.overlayGData(firstDate, lastDate, feedUriArray[i], i);
}
};
calvis.Calendar.prototype.setYearChooser = function(year) {
var options = jQuery('#' + calvis.yearChooserId).get(0).options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
if (option.value == year) {
jQuery('#' + calvis.yearChooserId).get(0).selectedIndex = i;
break;
}
}
};
/**
-
Populate the options for year chooser of month view.
*/
calvis.Calendar.prototype.createYearChooser = function() {
var calendar = this;
var year = 2000;
var html = [];
html.push('');
for ( var i = 0; i < 20; i++) {
var now = new Date();
if (year == now.getFullYear()) {
html.push('<option selected="yes" value="');
} else {
html.push('<option value="');
}
html.push(year);
html.push('">');
html.push(year);
html.push('</option>');
year++;
}
html.push('');
html = html.join('');
var element = jQuery(html).change(
function() {
calendar.currentPivotDate.setFullYear($(this).get(0).options[$(
this).get(0).selectedIndex].value);
calendar.updateMonthView();
});
return element;
};
/**
- Initialize the month view.
*/
calvis.Calendar.prototype.initMonthView = function() {
this.initMonthNavControl();
this.updateMonthView();
};
/**
-
Initialize the month view navigation control.
*/
calvis.Calendar.prototype.initMonthNavControl = function() {
var calendar = this;
var navControlHtml = [];
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(calvis.monthString(this.currentPivotDate.getMonth()));
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
jQuery('#' + calendar.navControlId).empty();
jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));
jQuery('#' + calvis.yearHolderId).html(this.createYearChooser());
jQuery('#' + calvis.todayButtonId).click(function() {
calendar.currentPivotDate = new Date();
calendar.currentViewMode();
});
jQuery('#' + calvis.prevMonthButtonId).click(function() {
var currentMonth = calendar.currentPivotDate.getMonth();
calendar.currentPivotDate.setMonth(currentMonth - 1);
calendar.currentPivotDate.setDate(1);
calendar.updateMonthView();
});
jQuery('#' + calvis.nextMonthButtonId).click(function() {
var currentMonth = calendar.currentPivotDate.getMonth();
calendar.currentPivotDate.setMonth(currentMonth + 1);
calendar.currentPivotDate.setDate(1);
calendar.updateMonthView();
});
};
/**
- Update the month view navigation control relative to the current pivot date.
*/
calvis.Calendar.prototype.updateMonthNavControl = function() {
this.setYearChooser(this.currentPivotDate.getFullYear());
jQuery('#' + calvis.monthHolderId).empty();
jQuery('#' + calvis.monthHolderId).html(
calvis.monthString(this.currentPivotDate.getMonth()));
};
/**
-
Initialize the month view grid. The month view grid is the grid rectangular
-
boxes that represents the dates of a given month.
*/
calvis.Calendar.prototype.initMonthGrid = function() {
var monthViewHtml = [];
monthViewHtml.push('
');
monthViewHtml.push('');
for ( var i = 0; i < 7; i++) {
monthViewHtml.push('');var index = 0;
for ( var i = 0; i < 6; i++) {
monthViewHtml.push('
');
for ( var j = 0; j < 7; j++) {
monthViewHtml.push('');
index++;
}
monthViewHtml.push('');
}monthViewHtml.push('
');
monthViewHtml.push(calvis.dayString(i));
monthViewHtml.push('</td>');
}
monthViewHtml.push(' |
');
// monthViewHtml.push(' '); Allow empty rows to collapse
monthViewHtml.push(' |
');
jQuery('#' + this.calendarBodyId).empty();
jQuery('#' + this.calendarBodyId).html(monthViewHtml.join(''));
};
/**
-
Update month view relative to the current pivot date.
*/
calvis.Calendar.prototype.updateMonthView = function() {
this.initMonthGrid();
this.updateMonthNavControl();
// fill the month dates
var firstDate = (new Date(this.currentPivotDate));
firstDate.setDate(1);
var daysInMonth = calvis.getDaysInMonth(firstDate);
var dateHolder = new Date(firstDate);
var startIndex = firstDate.getDay();
for ( var i = 0; i < daysInMonth; i++) {
var dateCellId = [ dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');
var dateContentId = [ 'content', dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');
var dateHtml = [];
dateHtml.push('<div class="');
// add a class to todays date cell
if (dateCellId == this.currentDateCellID)
dateHtml.push(calvis.monthViewCellClass + ' today');
else
dateHtml.push(calvis.monthViewCellClass);
dateHtml.push('" id=');
dateHtml.push(dateCellId);
dateHtml.push('>');
dateHtml.push('<div class="');
dateHtml.push(calvis.contentCellClass);
dateHtml.push('" id=');
dateHtml.push(dateContentId);
dateHtml.push('>');
dateHtml.push(dateHolder.getDate());
dateHtml.push('</div>');
dateHtml.push('</div>');
jQuery('#date' + startIndex).html(dateHtml.join(''));
dateHolder.setDate(dateHolder.getDate() + 1);
startIndex++;
}
var lastDate = new Date(firstDate);
lastDate.setDate(daysInMonth);
var feedUriArray = this.getFeedUrls();
calendar = this;
for ( var i = 0; i < feedUriArray.length; i++) {
calendar.overlayGData(firstDate, lastDate, feedUriArray[i], i);
}
};
/**
-
This is an internal callback that is invoked when the JavaScript client
-
library returns the event data. It will then display the event title on its
-
corresponding date cell.
-
@param {string}
-
-
@param {google.gdata.calendar.CalendarEventEntry}
-
A Google Data calendar event object.
-
@param {string}
-
label A div ID identifying so that each calendar may have a
-
different style attached to its events
-
*/
calvis.Calendar.prototype.appendEvent = function(id, event, label) {
var eventTime = /T(\d\d):(\d\d)/.exec(event.gd$when[0].startTime);
var eTime = '';
if (eventTime) {
if (eventTime[1] > 12) {
eTime = (eventTime[1] - 12);
if ('00' != eventTime[2]) {
eTime += ':' + eventTime[2] + 'p ';
} else {
eTime += 'p ';
}
} else {
eTime = eventTime[1];
if ('00' != eventTime[2]) {
eTime += ':' + eventTime[2] + ' ';
} else {
eTime += ' ';
}
}
}
var calendar = this;
var title = event.getTitle().getText();
var eventId = event.getId().getValue();
var cell = jQuery('#' + id);
// special case, this is a date element that doesn't exist in the current
// view. This is most likely that an event that spans across
// two months. This script currently doesn't handle multi-day events yet.
if (cell.length == 0) {
return;
}
var cellHeight = cell.parent().height();
var cellWidth = cell.width();
var contentFontHeight = parseInt(cell.css('font-size'));
var currentContentHeight = cell.height();
var bottomMargin = 5;
if (cellHeight < currentContentHeight + contentFontHeight + bottomMargin) {
if (cell.get(0).lastChild != null
&& cell.get(0).lastChild.innerHTML == calvis.moreLabel) {
// Can return right away, there is already a "more" link
return;
}
jQuery(cell.get(0).lastChild).empty();
jQuery(cell.get(0).lastChild).remove();
var moreHtml = [];
moreHtml.push('<div align="right" class="');
moreHtml.push(calvis.eventClass + ' more');
moreHtml.push('">');
moreHtml.push(calvis.moreLabel);
moreHtml.push('</div>');
var moreDiv = jQuery(moreHtml.join(''));
moreDiv.bind('click', function() {
calendar.currentPivotDate = event.getTimes()[0].getStartTime()
.getDate();
calendar.currentControlView = calendar.initWeekView;
calendar.initWeekView();
});
cell.append(moreDiv);
} else {
// if greater than a single day then copy into next cell
var times = event.getTimes();
for (i = 0; i < times.length; i++) {
var days = Math.floor(times[i].getEndTime().getDate()
- times[i].getStartTime().getDate())
/ (1000 * 60 * 60 * 24);
for (j = 0; j < days; j++) {
var date = times[i].getStartTime().getDate();
date.setDate(date.getDate() + j);
var id = [];
id.push('content');
id.push(date.getFullYear());
id.push(calvis.padZero(date.getMonth() + 1));
id.push(calvis.padZero(date.getDate()));
id = id.join('');
var cell = jQuery('#' + id);
var eventHtml = [];
eventHtml.push('<div id="');
eventHtml.push('cal' + label); // Eamonn 'eventId'
eventHtml.push('" class="');
if (days > 1) {
if (j == 0)
eventHtml.push(calvis.eventClass + ' first');
else if (j == days - 1)
eventHtml.push(calvis.eventClass + ' last');
else
eventHtml.push(calvis.eventClass + ' middle');
} else {
eventHtml.push(calvis.eventClass);
}
eventHtml.push('">');
eventHtml.push(calendar.fitText(' ' + eTime + title,
cellWidth));
eventHtml.push('</div>');
var eventDiv = jQuery(eventHtml.join(''));
eventDiv.bind(this.eventTrigger, function() {
if (calendar.eventCallback) {
calendar.eventCallback(event);
} else {
calendar.defaultEventCallback(event);
}
});
cell.append(eventDiv);
}
}
}
};
/**
-
When the date cell is overflowed because of too many events for a particular
-
date, a "more" link is created.
-
@param {string}
-
id The date cell ID which this more link belongs to.
*/
calvis.Calendar.prototype.createMoreMenu = function(id) {
var calendar = this;
var moreHtml = [];
moreHtml.push('');
moreHtml.push('');
var moreDiv = jQuery(moreHtml.join(''));
moreDiv.bind('change', function() {
if (calendar.eventCallback) {
calendar.eventCallback(event);
} else {
calendar.defaultEventCallback(event);
}
});
return moreDiv;
};
/**
- This creates a dummy span that is used to calculate whether a date cell is
- overflowing.
*/
calvis.Calendar.prototype.createFittingSpan = function() {
var span = jQuery('');
span.addClass(calvis.contentCellClass);
span.css( {
'visibility' : 'hidden'
});
jQuery(document.body).append(span);
this.fittingSpan = span;
};
/**
-
This method overlays the event data between two dates and append these events
-
on their appropriate date cells.
-
@param {Date}
-
startDate The start date that will be used for data query.
-
@param {Date}
-
endDate The end date that will be used for data query.
-
@param {string}
-
label An identifer used to style events per calendar
*/
calvis.Calendar.prototype.overlayGData = function(startDate, endDate, feedUri,
label) {
var calendar = this;
// if it is a private account and doesn't have a valid token
if (calendar.visibility == 'private' && !calendar.hasValidToken(feedUri)) {
jQuery('#' + this.statusControlId).html(
'you must log in to access private calendar');
return;
}
endDate.setDate(endDate.getDate() + 1);
var startDateTime = new google.gdata.DateTime(startDate, true);
var endDateTime = new google.gdata.DateTime(endDate, true);
var query = new google.gdata.calendar.CalendarEventQuery(feedUri);
query.setMinimumStartTime(startDateTime);
query.setMaximumStartTime(endDateTime);
query.setMaxResults(500);
query.setOrderBy('starttime');
query.setSortOrder('a');
query.setSingleEvents(true);
var callback = function(root) {
var eventEntries = root.feed.getEntries();
for ( var i = 0; i < eventEntries.length; i++) {
var event = eventEntries[i];
for ( var j = 0; j < event.getTimes().length; j++) {
var status = event.getEventStatus();
if (status == google.gdata.EventStatus.VALUE_CANCELED)
continue;
var when = event.getTimes()[j];
var datetime = when.getStartTime();
var date = datetime.getDate();
var id = [];
id.push('content');
id.push(date.getFullYear());
id.push(calvis.padZero(date.getMonth() + 1));
id.push(calvis.padZero(date.getDate()));
id = id.join('');
calendar.appendEvent(id, event, label);
}
}
jQuery('#' + calendar.statusControlId).html('');
};
jQuery('#' + calendar.statusControlId).html(calvis.loadingLabel);
calendar.calendarService.getEventsFeed(query, callback, calvis.handleError);
};
/**
- A helper function that gets the string representation of a day of the week
- @param {number}
-
offset An index between 0 and 6
*/
calvis.dayString = function(offset) {
return calvis.DAYS[offset];
};
/**
- A helper function that gets the string representation of a month of the year
- @param {number}
-
offset An index between 0 and 11
*/
calvis.monthString = function(offset) {
return calvis.MONTHS[offset];
};
/**
- A helper function that derives the number of days within a month.
- @param {Date}
-
pivotDate The current pivot date to locate the current month.
*/
calvis.getDaysInMonth = function(pivotDate) {
var year = pivotDate.getFullYear();
var month = pivotDate.getMonth();
return 32 - (new Date(year, month, 32)).getDate();
};
/**
- A helper function that derives the first date of a week.
- @param {Date}
-
pivotDate The current pivot date to locate the current week.
*/
calvis.getFirstDateOfWeek = function(pivotDate) {
var dayOffset = pivotDate.getDay();
return new Date(pivotDate.getFullYear(), pivotDate.getMonth(), pivotDate
.getDate()
- dayOffset);
};
/**
-
This function fits the event title to the width of a date cell, it truncates
-
the title and replaced with "...", if necessary.
-
@param {string}
-
text The text that is examined to fit it width to date cell.
-
@param {number}
-
limit The maximum number of characters that is permitted.
*/
calvis.Calendar.prototype.fitText = function(text, limit) {
this.fittingSpan.html(text);
var currentWidth = this.fittingSpan.width();
while (currentWidth > limit) {
text = text.replace(/.$/, '');
this.fittingSpan.html(text);
currentWidth = this.fittingSpan.width();
}
return text;
};
/**
-
The is the error handler that display the error message to the status
-
control. Callback function for the Google data JS client library to call when
-
an error occurs during the retrieval of the feed.
-
@param {Object}
-
*/
calvis.handleError = function(e) {
google.accounts.user.logout();
jQuery('#' + calvis.loginLinkId).html(calvis.loginLabel)
if (e instanceof Error) {
/* alert with the error line number, file and message /
jQuery('#' + this.statusControlId).html(
'Error at line ' + e.lineNumber + ' in ' + e.fileName + '\n'
+ 'Message: ' + e.message + '.
');
/ if available, output HTTP error code and status text */
if (e.cause) {
var status = e.cause.status;
var statusText = e.cause.statusText;
jQuery('#' + this.statusControlId).append(
'Root cause: HTTP error ' + status
+ ' with status text of: ' + statusText);
}
}
};
/**
- Debug method that display at the token information.
*/
calvis.getTokenInfo = function() {
google.accounts.user.getInfo(function(data) {
console.log(data.currentTarget.responseText);
var target = eval(data.currentTarget.responseText);
console.log(target);
});
};
/**
- A helper functions that makes sure a number is represeted in two digits by
- padding zero in front if necessary.
- @param {number}
-
number The number that will be padded.
*/
calvis.padZero = function(number) {
if (number < 10) {
number = 0 + '' + number;
}
return number;
};
/**
-
This method fixes IE specific issues
*/
calvis.fixIE = function() {
if (!Array.indexOf) {
Array.prototype.indexOf = function(arg) {
var index = -1;
for ( var i = 0; i < this.length; i++) {
var value = this[i];
if (value == arg) {
index = i;
break;
}
}
return index;
};
}
// inject "console.log" to emulate Firefox firebug.
// For debugging purpose
if (!window.console) {
window.console = {};
window.console.log = function(message) {
var body = document.getElementsByTagName('body')[0];
var messageDiv = document.createElement('div');
messageDiv.innerHTML = message;
body.insertBefore(messageDiv, body.lastChild);
};
}
};
/**
*/
/**
*/
// Namespace to protect this library from conflicting with external
var calvis = calvis || {};
// Constant strings for month labels
calvis.MONTHS = [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto',
'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ];
// Constant strings for day labels
calvis.DAYS = [ 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom' ];
// CSS IDs
calvis.monthViewButtonId = 'monthViewButton';
calvis.weekViewButtonId = 'weekViewButton';
calvis.todayButtonId = 'todayButton';
calvis.prevWeekButtonId = 'prevWeek';
calvis.nextWeekButtonId = 'nextWeek';
calvis.prevMonthButtonId = 'prevMonth';
calvis.nextMonthButtonId = 'nextMonth';
calvis.yearChooserId = 'yearChooser';
calvis.weekDurationId = 'weekDuration';
calvis.yearHolderId = 'yearHolder';
calvis.monthHolderId = 'monthHolder';
calvis.loginLinkId = 'loginLink';
// CSS classes
calvis.columnHeadingClass = 'columnHeading';
calvis.weekViewCellClass = 'weekViewCell';
calvis.monthViewCellClass = 'monthViewCell';
calvis.contentCellClass = 'contentCell';
calvis.eventClass = 'eventItem';
// string labels
calvis.AppStringLabel = 'Generic-Calendar-Container-1.0';
calvis.loginLabel = 'Log in';
calvis.logoutLabel = 'Log out';
calvis.monthViewButtonLabel = 'Mese';
calvis.weekViewButtonLabel = 'Settimana';
calvis.todayButtonLabel = 'Giorno';
calvis.prevWeekButtonLabel = '<<';
calvis.nextWeekButtonLabel = '>>';
calvis.prevMonthButtonLabel = '<<';
calvis.nextMonthButtonLabel = '>>';
calvis.loadingLabel = ' loading... ';
calvis.moreLabel = 'more';
/**
Constructor to create an instance of the Calendar Container
*/
calvis.Calendar = function() {
// Fix quarks for IE
calvis.fixIE();
// Create an instance of the Google Data service object
this.calendarService = new google.gdata.calendar.CalendarService(
calvis.AppStringLabel);
// CSS IDs to position key container components
this.calendarBodyId = null;
this.navControlId = null;
this.viewControlId = null;
this.loginControlId = null;
this.statusControlId = null;
this.eventDisplayId = null;
// The callback method to be invoked when event is triggered to be displayed
this.eventCallback = null;
// The calendar ID(s) to be displayed from this container
this.calIds = null;
// The visibility of this calendar, private or public
this.visibility = null;
// The pivot date for the current navigation view
this.currentPivotDate = new Date();
// The current view mode of the container
this.currentViewMode = null;
// Cache todays date
this.currentDateCellID = [ new Date().getFullYear(),
calvis.padZero(new Date().getMonth() + 1),
calvis.padZero(new Date().getDate()) ].join('');
};
/**
calvis.Calendar.prototype.setCalendarBody = function(cssId) {
this.calendarBodyId = cssId;
};
/**
calvis.Calendar.prototype.setNavControl = function(cssId) {
this.navControlId = cssId;
};
/**
calvis.Calendar.prototype.setViewControl = function(cssId) {
this.viewControlId = cssId;
};
/**
calvis.Calendar.prototype.setStatusControl = function(cssId) {
this.statusControlId = cssId;
};
/**
calvis.Calendar.prototype.setEventCallback = function(trigger, callback) {
this.eventTrigger = trigger;
this.eventCallback = callback;
};
/**
calvis.Calendar.prototype.setPublicCalendars = function(calIds) {
this.visibility = 'public';
this.calIds = calIds;
};
/**
This method should be called after all the CSS IDs and other properties are
set and ready to be displayed.
*/
calvis.Calendar.prototype.render = function() {
var calendar = this;
calendar.createFittingSpan();
// global init
// default view is month view
calendar.initViewControl();
if (!calendar.currentViewMode) {
calendar.setDefaultView('month');
}
calendar.currentViewMode();
};
/**
calvis.Calendar.prototype.setDefaultView = function(view) {
switch (view) {
case 'week':
this.currentViewMode = this.initWeekView;
break;
case 'month':
this.currentViewMode = this.initMonthView;
break;
}
};
/**
*/
calvis.Calendar.prototype.getFeedUrls = function() {
var feedUrlArray = new Array();
calIds = this.calIds;
for ( var i = 0; i < calIds.length; i++) {
feedUrlArray[i] = [ 'http://www.google.com/calendar/feeds/', calIds[i],
'/public/full' ].join('');
}
return feedUrlArray;
};
/**
Initialize the view control.
*/
calvis.Calendar.prototype.initViewControl = function() {
var calendar = this;
var viewControlHtml = [];
viewControlHtml.push('');
viewControlHtml.push(' ');
viewControlHtml.push('');
jQuery('#' + this.viewControlId).empty();
jQuery('#' + this.viewControlId).html(viewControlHtml.join(''));
// append click handler to view control buttons
jQuery('#' + calvis.monthViewButtonId).click(function() {
calendar.currentViewMode = calendar.initMonthView;
calendar.currentViewMode();
});
jQuery('#' + calvis.weekViewButtonId).click(function() {
calendar.currentViewMode = calendar.initWeekView;
calendar.currentViewMode();
});
};
/**
Update the week duration display of the Navigation control.
*/
calvis.Calendar.prototype.updateWeekDuration = function() {
var weekStart = calvis.getFirstDateOfWeek(this.currentPivotDate);
var weekEnd = new Date(weekStart);
weekEnd.setDate(weekEnd.getDate() + 6);
var durationString = [];
durationString.push(calvis.monthString(weekStart.getMonth()));
durationString.push(' ');
durationString.push(weekStart.getDate());
durationString.push(' - ');
durationString.push(calvis.monthString(weekEnd.getMonth()));
durationString.push(' ');
durationString.push(weekEnd.getDate());
durationString.push(' ');
durationString.push(weekEnd.getFullYear());
jQuery('#' + calvis.weekDurationId).empty();
jQuery('#' + calvis.weekDurationId).html(durationString.join(''));
};
/**
*/
calvis.Calendar.prototype.initWeekView = function() {
this.initWeekNavControl();
this.updateWeekView();
};
/**
Initialize week view navigation control.
*/
calvis.Calendar.prototype.initWeekNavControl = function() {
var calendar = this;
var navControlHtml = [];
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
jQuery('#' + calendar.navControlId).empty();
jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));
calendar.updateWeekDuration();
jQuery('#' + calvis.todayButtonId).click(function() {
calendar.currentPivotDate = new Date();
calendar.currentViewMode();
});
jQuery('#' + calvis.prevWeekButtonId).click(
function() {
calendar.currentPivotDate.setDate(calendar.currentPivotDate
.getDate() - 7);
calendar.updateWeekView();
});
jQuery('#' + calvis.nextWeekButtonId).click(
function() {
calendar.currentPivotDate.setDate(calendar.currentPivotDate
.getDate() + 7);
calendar.updateWeekView();
});
};
/**
Update the current week view base on the current pivot date.
*/
calvis.Calendar.prototype.updateWeekView = function() {
this.updateWeekDuration();
var firstDate = calvis.getFirstDateOfWeek(this.currentPivotDate);
var lastDate = new Date(firstDate);
lastDate.setDate(firstDate.getDate() + 6);
var weekViewHtml = [];
weekViewHtml.push('
');weekViewHtml.push('
');var dateHolder = new Date(firstDate);
for ( var i = 0; i < 7; i++) {
}
');weekViewHtml.push('
var dateHolder = new Date(firstDate);
weekViewHtml.push('
');for ( var i = 0; i < 7; i++) {
var dateCellId = [ dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');
var dateContentId = [ 'content', dateHolder.getFullYear(),
calvis.padZero(dateHolder.getMonth() + 1),
calvis.padZero(dateHolder.getDate()) ].join('');
}
weekViewHtml.push('
');weekViewHtml.push('
jQuery('#' + this.calendarBodyId).empty();
jQuery('#' + this.calendarBodyId).html(weekViewHtml.join(''));
var feedUriArray = this.getFeedUrls();
calendar = this;
for ( var i = 0; i < feedUriArray.length; i++) {
calendar.overlayGData(firstDate, lastDate, feedUriArray[i], i);
}
};
calvis.Calendar.prototype.setYearChooser = function(year) {
};
/**
Populate the options for year chooser of month view.
*/
calvis.Calendar.prototype.createYearChooser = function() {
var calendar = this;
var year = 2000;
var html = [];
html.push(''); for ( var i = 0; i < 20; i++) { var now = new Date(); if (year == now.getFullYear()) { html.push('<option selected="yes" value="'); } else { html.push('<option value="'); } html.push(year); html.push('">'); html.push(year); html.push('</option>'); year++; } html.push('');
html = html.join('');
var element = jQuery(html).change($(this).get(0).options[$ (
function() {
calendar.currentPivotDate.setFullYear(
this).get(0).selectedIndex].value);
calendar.updateMonthView();
});
return element;
};
/**
*/
calvis.Calendar.prototype.initMonthView = function() {
this.initMonthNavControl();
this.updateMonthView();
};
/**
Initialize the month view navigation control.
*/
calvis.Calendar.prototype.initMonthNavControl = function() {
var calendar = this;
var navControlHtml = [];
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
navControlHtml.push(calvis.monthString(this.currentPivotDate.getMonth()));
navControlHtml.push('');
navControlHtml.push(' ');
navControlHtml.push('');
jQuery('#' + calendar.navControlId).empty();
jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));
jQuery('#' + calvis.yearHolderId).html(this.createYearChooser());
jQuery('#' + calvis.todayButtonId).click(function() {
calendar.currentPivotDate = new Date();
calendar.currentViewMode();
});
jQuery('#' + calvis.prevMonthButtonId).click(function() {
});
jQuery('#' + calvis.nextMonthButtonId).click(function() {
});
};
/**
*/
calvis.Calendar.prototype.updateMonthNavControl = function() {
this.setYearChooser(this.currentPivotDate.getFullYear());
jQuery('#' + calvis.monthHolderId).empty();
jQuery('#' + calvis.monthHolderId).html(
calvis.monthString(this.currentPivotDate.getMonth()));
};
/**
Initialize the month view grid. The month view grid is the grid rectangular
boxes that represents the dates of a given month.
*/
calvis.Calendar.prototype.initMonthGrid = function() {
var monthViewHtml = [];
monthViewHtml.push('
');monthViewHtml.push('');
for ( var i = 0; i < 7; i++) {
monthViewHtml.push('');
var index = 0;
for ( var i = 0; i < 6; i++) {
');monthViewHtml.push('
for ( var j = 0; j < 7; j++) {
monthViewHtml.push('');
index++;
}
monthViewHtml.push('');
}
monthViewHtml.push('
}
monthViewHtml.push('
// monthViewHtml.push(' '); Allow empty rows to collapse
monthViewHtml.push('
jQuery('#' + this.calendarBodyId).empty();
jQuery('#' + this.calendarBodyId).html(monthViewHtml.join(''));
};
/**
Update month view relative to the current pivot date.
*/
calvis.Calendar.prototype.updateMonthView = function() {
this.initMonthGrid();
this.updateMonthNavControl();
// fill the month dates
var firstDate = (new Date(this.currentPivotDate));
firstDate.setDate(1);
var daysInMonth = calvis.getDaysInMonth(firstDate);
var dateHolder = new Date(firstDate);
var startIndex = firstDate.getDay();
for ( var i = 0; i < daysInMonth; i++) {
}
var lastDate = new Date(firstDate);
lastDate.setDate(daysInMonth);
var feedUriArray = this.getFeedUrls();
calendar = this;
for ( var i = 0; i < feedUriArray.length; i++) {
calendar.overlayGData(firstDate, lastDate, feedUriArray[i], i);
}
};
/**
This is an internal callback that is invoked when the JavaScript client
library returns the event data. It will then display the event title on its
corresponding date cell.
@param {string}
@param {google.gdata.calendar.CalendarEventEntry}
@param {string}
*/
calvis.Calendar.prototype.appendEvent = function(id, event, label) {
var eventTime = /T(\d\d):(\d\d)/.exec(event.gd$when[0].startTime);
var eTime = '';
if (eventTime) {
if (eventTime[1] > 12) {
eTime = (eventTime[1] - 12);
if ('00' != eventTime[2]) {
eTime += ':' + eventTime[2] + 'p ';
} else {
eTime += 'p ';
}
} else {
eTime = eventTime[1];
if ('00' != eventTime[2]) {
eTime += ':' + eventTime[2] + ' ';
} else {
eTime += ' ';
}
}
}
var calendar = this;
var title = event.getTitle().getText();
var eventId = event.getId().getValue();
var cell = jQuery('#' + id);
// special case, this is a date element that doesn't exist in the current
// view. This is most likely that an event that spans across
// two months. This script currently doesn't handle multi-day events yet.
if (cell.length == 0) {
return;
}
var cellHeight = cell.parent().height();
var cellWidth = cell.width();
var contentFontHeight = parseInt(cell.css('font-size'));
var currentContentHeight = cell.height();
var bottomMargin = 5;
if (cellHeight < currentContentHeight + contentFontHeight + bottomMargin) {
if (cell.get(0).lastChild != null
&& cell.get(0).lastChild.innerHTML == calvis.moreLabel) {
// Can return right away, there is already a "more" link
return;
}
} else {
}
};
/**
When the date cell is overflowed because of too many events for a particular
date, a "more" link is created.
@param {string}
*/
calvis.Calendar.prototype.createMoreMenu = function(id) {
var calendar = this;
var moreHtml = [];
moreHtml.push(''); moreHtml.push('');
var moreDiv = jQuery(moreHtml.join(''));
moreDiv.bind('change', function() {
if (calendar.eventCallback) {
calendar.eventCallback(event);
} else {
calendar.defaultEventCallback(event);
}
});
return moreDiv;
};
/**
*/
calvis.Calendar.prototype.createFittingSpan = function() {
var span = jQuery('');
span.addClass(calvis.contentCellClass);
span.css( {
'visibility' : 'hidden'
});
jQuery(document.body).append(span);
this.fittingSpan = span;
};
/**
This method overlays the event data between two dates and append these events
on their appropriate date cells.
@param {Date}
@param {Date}
@param {string}
*/
calvis.Calendar.prototype.overlayGData = function(startDate, endDate, feedUri,
label) {
var calendar = this;
// if it is a private account and doesn't have a valid token
if (calendar.visibility == 'private' && !calendar.hasValidToken(feedUri)) {
jQuery('#' + this.statusControlId).html(
'you must log in to access private calendar');
return;
}
endDate.setDate(endDate.getDate() + 1);
var startDateTime = new google.gdata.DateTime(startDate, true);
var endDateTime = new google.gdata.DateTime(endDate, true);
var query = new google.gdata.calendar.CalendarEventQuery(feedUri);
query.setMinimumStartTime(startDateTime);
query.setMaximumStartTime(endDateTime);
query.setMaxResults(500);
query.setOrderBy('starttime');
query.setSortOrder('a');
query.setSingleEvents(true);
var callback = function(root) {
};
jQuery('#' + calendar.statusControlId).html(calvis.loadingLabel);
calendar.calendarService.getEventsFeed(query, callback, calvis.handleError);
};
/**
calvis.dayString = function(offset) {
return calvis.DAYS[offset];
};
/**
calvis.monthString = function(offset) {
return calvis.MONTHS[offset];
};
/**
calvis.getDaysInMonth = function(pivotDate) {
var year = pivotDate.getFullYear();
var month = pivotDate.getMonth();
return 32 - (new Date(year, month, 32)).getDate();
};
/**
calvis.getFirstDateOfWeek = function(pivotDate) {
var dayOffset = pivotDate.getDay();
return new Date(pivotDate.getFullYear(), pivotDate.getMonth(), pivotDate
.getDate()
- dayOffset);
};
/**
This function fits the event title to the width of a date cell, it truncates
the title and replaced with "...", if necessary.
@param {string}
@param {number}
*/
calvis.Calendar.prototype.fitText = function(text, limit) {
this.fittingSpan.html(text);
var currentWidth = this.fittingSpan.width();
while (currentWidth > limit) {
text = text.replace(/.$/, '');
this.fittingSpan.html(text);
currentWidth = this.fittingSpan.width();
}
return text;
};
/**
The is the error handler that display the error message to the status
control. Callback function for the Google data JS client library to call when
an error occurs during the retrieval of the feed.
@param {Object}
*/
calvis.handleError = function(e) {
google.accounts.user.logout();
jQuery('#' + calvis.loginLinkId).html(calvis.loginLabel)
if (e instanceof Error) {
/* alert with the error line number, file and message /
jQuery('#' + this.statusControlId).html(
'Error at line ' + e.lineNumber + ' in ' + e.fileName + '\n'
+ 'Message: ' + e.message + '.
');
/ if available, output HTTP error code and status text */
if (e.cause) {
var status = e.cause.status;
var statusText = e.cause.statusText;
jQuery('#' + this.statusControlId).append(
'Root cause: HTTP error ' + status
+ ' with status text of: ' + statusText);
}
}
};
/**
*/
calvis.getTokenInfo = function() {
google.accounts.user.getInfo(function(data) {
console.log(data.currentTarget.responseText);
var target = eval(data.currentTarget.responseText);
console.log(target);
});
};
/**
calvis.padZero = function(number) {
if (number < 10) {
number = 0 + '' + number;
}
return number;
};
/**
This method fixes IE specific issues
*/
calvis.fixIE = function() {
if (!Array.indexOf) {
Array.prototype.indexOf = function(arg) {
}
// inject "console.log" to emulate Firefox firebug.
// For debugging purpose
if (!window.console) {
window.console = {};
window.console.log = function(message) {
var body = document.getElementsByTagName('body')[0];
var messageDiv = document.createElement('div');
messageDiv.innerHTML = message;
body.insertBefore(messageDiv, body.lastChild);
};
}
};