fullcalendar/src/util.js

401 lines
9.6 KiB
JavaScript
Executable File

/* Date Math
-----------------------------------------------------------------------------*/
var DAY_MS = 86400000,
HOUR_MS = 3600000,
MINUTE_MS = 60000;
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;
}
fc.addDays = addDays;
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);
}
function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
var i=0, d;
do {
d = new Date(1970, i++, 1);
} while (d.getHours() != 0);
return d;
}
function skipWeekend(date, inc, excl) {
inc = inc || 1;
while (date.getDay()==0 || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
addDays(date, inc);
}
return date;
}
/* 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; i<len; i++) {
c = format.charAt(i);
if (c == "'") {
for (i2=i+1; i2<len; i2++) {
if (format.charAt(i2) == "'") {
if (date) {
if (i2 == i+1) {
res += "'";
}else{
res += format.substring(i+1, i2);
}
i = i2;
}
break;
}
}
}
else if (c == '(') {
for (i2=i+1; i2<len; i2++) {
if (format.charAt(i2) == ')') {
var subres = formatDate(date, format.substring(i+1, i2), options);
if (parseInt(subres.replace(/\D/, ''))) {
res += subres;
}
i = i2;
break;
}
}
}
else if (c == '[') {
for (i2=i+1; i2<len; i2++) {
if (format.charAt(i2) == ']') {
var subformat = format.substring(i+1, i2);
var subres = formatDate(date, subformat, options);
if (subres != formatDate(otherDate, subformat, options)) {
res += subres;
}
i = i2;
break;
}
}
}
else if (c == '{') {
date = date2;
otherDate = date1;
}
else if (c == '}') {
date = date1;
otherDate = date2;
}
else {
for (i2=len; i2>i; 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);
});
}
/* Position Calculation
-----------------------------------------------------------------------------*/
// nasty bugs in opera 9.25
// position() returning relative to direct parent
var operaPositionBug;
function reportTBody(tbody) {
if (operaPositionBug == undefined) {
operaPositionBug = tbody.position().top != tbody.find('tr').position().top;
}
}
function safePosition(element, td, tr, tbody) {
var position = element.position();
if (operaPositionBug) {
position.top += tbody.position().top + tr.position().top - td.position().top;
}
return position;
}
/* 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 + (
(operaPositionBug && prevRowE.is('tr')) ? 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.length && y>=tops[r]; r++) ;
for (c=0; c<lefts.length && x>=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 smartProperty(obj, name) { // get a camel-cased/namespaced property
if (obj[name] != undefined) {
return obj[name];
}
var parts = name.split(/(?=[A-Z])/),
i=parts.length-1, res;
for (; i>=0; i--) {
res = obj[parts[i].toLowerCase()];
if (res != undefined) {
return res;
}
}
return obj[''];
}