/* Date Math -----------------------------------------------------------------------------*/ var DAY_MS = 86400000, HOUR_MS = 3600000; function addYears(d, n, keepTime) { d.setFullYear(d.getFullYear() + n); if (!keepTime) { clearTime(d); } return d; } function addMonths(d, n, keepTime) { // prevents day overflow/underflow if (+d) { // prevent infinite looping on invalid dates var m = d.getMonth() + n, check = cloneDate(d); check.setDate(1); check.setMonth(m); d.setMonth(m); if (!keepTime) { clearTime(d); } while (d.getMonth() != check.getMonth()) { d.setDate(d.getDate() + (d < check ? 1 : -1)); } } return d; } function addDays(d, n, keepTime) { // deals with daylight savings if (+d) { // prevent infinite looping on invalid dates var dd = d.getDate() + n, check = cloneDate(d); check.setHours(12); // set to middle of day check.setDate(dd); d.setDate(dd); if (!keepTime) { clearTime(d); } while (d.getDate() != check.getDate()) { d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS); } } return d; } function addMinutes(d, n) { d.setMinutes(d.getMinutes() + n); return d; } function clearTime(d) { d.setHours(0); d.setMinutes(0); d.setSeconds(0); d.setMilliseconds(0); return d; } function cloneDate(d, dontKeepTime) { if (dontKeepTime) { return clearTime(new Date(+d)); } return new Date(+d); } /* Date Parsing -----------------------------------------------------------------------------*/ var parseDate = fc.parseDate = function(s) { if (typeof s == 'object') { // already a Date object return s; } if (typeof s == 'number') { // a UNIX timestamp return new Date(s * 1000); } if (typeof s == 'string') { if (s.match(/^\d+$/)) { // a UNIX timestamp return new Date(parseInt(s) * 1000); } return parseISO8601(s, true) || new Date(s) || null; } return null; } var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) { // derived from http://delete.me.uk/2005/03/iso8601.html var d = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/); if (!d) return null; var offset = 0; var date = new Date(d[1], 0, 1); if (d[3]) { date.setMonth(d[3] - 1); } if (d[5]) { date.setDate(d[5]); } if (d[7]) { date.setHours(d[7]); } if (d[8]) { date.setMinutes(d[8]); } if (d[10]) { date.setSeconds(d[10]); } if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } if (!ignoreTimezone) { if (d[14]) { offset = (Number(d[16]) * 60) + Number(d[17]); offset *= ((d[15] == '-') ? 1 : -1); } offset -= date.getTimezoneOffset(); } return new Date(Number(date) + (offset * 60 * 1000)); } /* Date Formatting -----------------------------------------------------------------------------*/ var formatDate = fc.formatDate = function(date, format, options) { return formatDates(date, null, format, options); } var formatDates = fc.formatDates = function(date1, date2, format, options) { options = options || defaults; var date = date1, otherDate = date2, i, len = format.length, c, i2, formatter, res = ''; for (i=0; ii; i2--) { if (formatter = dateFormatters[format.substring(i, i2)]) { if (date) { res += formatter(date, options); } i = i2 - 1; break; } } if (i2 == i) { if (date) { res += c; } } } } return res; } var dateFormatters = { s : function(d) { return d.getSeconds() }, ss : function(d) { return zeroPad(d.getSeconds()) }, m : function(d) { return d.getMinutes() }, mm : function(d) { return zeroPad(d.getMinutes()) }, h : function(d) { return d.getHours() % 12 || 12 }, hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, H : function(d) { return d.getHours() }, HH : function(d) { return zeroPad(d.getHours()) }, d : function(d) { return d.getDate() }, dd : function(d) { return zeroPad(d.getDate()) }, ddd : function(d,o) { return o.dayNamesShort[d.getDay()] }, dddd: function(d,o) { return o.dayNames[d.getDay()] }, M : function(d) { return d.getMonth() + 1 }, MM : function(d) { return zeroPad(d.getMonth() + 1) }, MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] }, MMMM: function(d,o) { return o.monthNames[d.getMonth()] }, yy : function(d) { return (d.getFullYear()+'').substring(2) }, yyyy: function(d) { return d.getFullYear() }, t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }, u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") }, S : function(d) { var date = d.getDate(); if (date > 10 && date < 20) return 'th'; return ['st', 'nd', 'rd'][date%10-1] || 'th'; } }; /* Element Dimensions -----------------------------------------------------------------------------*/ function setOuterWidth(element, width, includeMargins) { element.each(function() { var e = $(this); var w = width - ( (parseInt(e.css('border-left-width')) || 0) + (parseInt(e.css('padding-left')) || 0) + (parseInt(e.css('padding-right')) || 0) + (parseInt(e.css('border-right-width')) || 0)); if (includeMargins) { w -= (parseInt(e.css('margin-left')) || 0) + (parseInt(e.css('margin-right')) || 0); } e.width(w); }); } function setOuterHeight(element, height, includeMargins) { element.each(function() { var e = $(this); var h = height - ( (parseInt(e.css('border-top-width')) || 0) + (parseInt(e.css('padding-top')) || 0) + (parseInt(e.css('padding-bottom')) || 0) + (parseInt(e.css('border-bottom-width')) || 0)); if (includeMargins) { h -= (parseInt(e.css('margin-top')) || 0) + (parseInt(e.css('margin-bottom')) || 0); } e.height(h); }); } /* Hover Matrix -----------------------------------------------------------------------------*/ function HoverMatrix(changeCallback) { var tops=[], lefts=[], prevRowE, prevColE, origRow, origCol, currRow, currCol; this.row = function(e, topBug) { prevRowE = $(e); tops.push(prevRowE.offset().top + (topBug ? prevRowE.parent().position().top : 0)); }; this.col = function(e) { prevColE = $(e); lefts.push(prevColE.offset().left); }; this.mouse = function(x, y) { if (origRow == undefined) { tops.push(tops[tops.length-1] + prevRowE.outerHeight()); lefts.push(lefts[lefts.length-1] + prevColE.outerWidth()); currRow = currCol = -1; } var r, c; for (r=0; r=tops[r]; r++) ; for (c=0; c=lefts[c]; c++) ; r = r >= tops.length ? -1 : r - 1; c = c >= lefts.length ? -1 : c - 1; if (r != currRow || c != currCol) { currRow = r; currCol = c; if (r == -1 || c == -1) { this.cell = null; }else{ if (origRow == undefined) { origRow = r; origCol = c; } this.cell = { row: r, col: c, top: tops[r], left: lefts[c], width: lefts[c+1] - lefts[c], height: tops[r+1] - tops[r], isOrig: r==origRow && c==origCol, rowDelta: r-origRow, colDelta: c-origCol }; } changeCallback(this.cell); } }; } /* Misc Utils -----------------------------------------------------------------------------*/ var undefined, dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; function zeroPad(n) { return (n < 10 ? '0' : '') + n; } function strProp(s, prop) { return typeof s == 'string' ? s : s[prop]; }