/* 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) { var dd = d.getDate() + n, check = cloneDate(d); check.setHours(9); // set to middle of day check.setDate(dd); d.setDate(dd); if (!keepTime) { clearTime(d); } fixDate(d, check); } return d; } fc.addDays = addDays; function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes if (+d) { // prevent infinite looping on invalid dates while (d.getDate() != check.getDate()) { d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS); } } } 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); } fc.cloneDate = cloneDate; 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() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) { addDays(date, inc); } return date; } function dayDiff(d1, d2) { // d1 - d2 return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS); } function setYMD(date, y, m, d) { if (y !== undefined && y != date.getFullYear()) { date.setDate(1); date.setMonth(0); date.setFullYear(y); } if (m !== undefined && m != date.getMonth()) { date.setDate(1); date.setMonth(m); } if (d !== undefined) { date.setDate(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) || (s ? new Date(s) : null); } // TODO: never return invalid dates (like from new Date()), return null instead return null; }; var parseISO8601 = fc.parseISO8601 = function(s, ignoreTimezone) { // derived from http://delete.me.uk/2005/03/iso8601.html // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html var m = 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 (!m) { return null; } var date = new Date(m[1], 0, 1), check = new Date(m[1], 0, 1, 9, 0), offset = 0; if (m[3]) { date.setMonth(m[3] - 1); check.setMonth(m[3] - 1); } if (m[5]) { date.setDate(m[5]); check.setDate(m[5]); } fixDate(date, check); if (m[7]) { date.setHours(m[7]); } if (m[8]) { date.setMinutes(m[8]); } if (m[10]) { date.setSeconds(m[10]); } if (m[12]) { date.setMilliseconds(Number("0." + m[12]) * 1000); } fixDate(date, check); if (!ignoreTimezone) { if (m[14]) { offset = Number(m[16]) * 60 + Number(m[17]); offset *= m[15] == '-' ? 1 : -1; } offset -= date.getTimezoneOffset(); } return new Date(+date + (offset * 60 * 1000)); }; var parseTime = fc.parseTime = function(s) { // returns minutes since start of day if (typeof s == 'number') { // an hour return s * 60; } if (typeof s == 'object') { // a Date object return s.getHours() * 60 + s.getMinutes(); } var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/); if (m) { var h = parseInt(m[1]); if (m[3]) { h %= 12; if (m[3].toLowerCase().charAt(0) == 'p') { h += 12; } } return h * 60 + (m[2] ? parseInt(m[2]) : 0); } }; /* 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(i, _element) { _element.style.width = width - hsides(_element, includeMargins) + 'px'; }); } function setOuterHeight(element, height, includeMargins) { element.each(function(i, _element) { _element.style.height = height - vsides(_element, includeMargins) + 'px'; }); } function hsides(_element, includeMargins) { return (parseFloat(jQuery.curCSS(_element, 'paddingLeft', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'paddingRight', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'borderLeftWidth', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'borderRightWidth', true)) || 0) + (includeMargins ? hmargins(_element) : 0); } function hmargins(_element) { return (parseFloat(jQuery.curCSS(_element, 'marginLeft', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'marginRight', true)) || 0); } function vsides(_element, includeMargins) { return (parseFloat(jQuery.curCSS(_element, 'paddingTop', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'paddingBottom', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'borderTopWidth', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'borderBottomWidth', true)) || 0) + (includeMargins ? vmargins(_element) : 0); } function vmargins(_element) { return (parseFloat(jQuery.curCSS(_element, 'marginTop', true)) || 0) + (parseFloat(jQuery.curCSS(_element, 'marginBottom', true)) || 0); } function setMinHeight(element, h) { h = typeof h == 'number' ? h + 'px' : h; element[0].style.cssText += ';min-height:' + h + ';_height:' + h; } /* Position Calculation -----------------------------------------------------------------------------*/ // nasty bugs in opera 9.25 // position()'s top returning incorrectly with TR/TD or elements within TD var topBug; function topCorrect(tr) { // tr/th/td or anything else if (topBug !== false) { var cell; if (tr.is('th,td')) { tr = (cell = tr).parent(); } if (topBug === undefined && tr.is('tr')) { topBug = tr.position().top != tr.children().position().top; } if (topBug) { return tr.parent().position().top + (cell ? tr.position().top - cell.position().top : 0); } } return 0; } /* Coordinate Grid -----------------------------------------------------------------------------*/ function CoordinateGrid(buildFunc) { var t = this; var rows; var cols; t.build = function() { rows = []; cols = []; buildFunc(rows, cols); }; t.cell = function(x, y) { var rowCnt = rows.length; var colCnt = cols.length; var i, r=-1, c=-1; for (i=0; i= rows[i][0] && y < rows[i][1]) { r = i; break; } } for (i=0; i= cols[i][0] && x < cols[i][1]) { c = i; break; } } return (r>=0 && c>=0) ? { row:r, col:c } : null; }; t.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive var origin = originElement.offset(); return { top: rows[row0][0] - origin.top, left: cols[col0][0] - origin.left, width: cols[col1][1] - cols[col0][0], height: rows[row1][1] - rows[row0][0] }; }; } /* Hover Listener -----------------------------------------------------------------------------*/ function HoverListener(coordinateGrid) { var t = this; var bindType; var change; var firstCell; var cell; t.start = function(_change, ev, _bindType) { change = _change; firstCell = cell = null; coordinateGrid.build(); mouse(ev); bindType = _bindType || 'mousemove'; $(document).bind(bindType, mouse); }; function mouse(ev) { var newCell = coordinateGrid.cell(ev.pageX, ev.pageY); if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) { if (newCell) { if (!firstCell) { firstCell = newCell; } change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col); }else{ change(newCell, firstCell); } cell = newCell; } } t.stop = function() { $(document).unbind(bindType, mouse); return cell; }; } /* Misc Utils -----------------------------------------------------------------------------*/ var 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 of an object 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['']; } function htmlEscape(s) { return s.replace(/&/g, '&') .replace(//g, '>') .replace(/'/g, ''') .replace(/"/g, '"') .replace(/\n/g, '
'); } function HorizontalPositionCache(getElement) { var t = this, elements = {}, lefts = {}, rights = {}; function e(i) { return elements[i] = elements[i] || getElement(i); } t.left = function(i) { return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i]; }; t.right = function(i) { return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i]; }; t.clear = function() { elements = {}; lefts = {}; rights = {}; }; } function cssKey(_element) { return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, ''); } function cmp(a, b) { return a - b; } function exclEndDay(event) { if (event.end) { return _exclEndDay(event.end, event.allDay); }else{ return addDays(cloneDate(event.start), 1); } } function _exclEndDay(end, allDay) { end = cloneDate(end); return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end); } function disableTextSelection(element) { element .attr('unselectable', 'on') .css('MozUserSelect', 'none') .bind('selectstart.ui', function() { return false; }); } /* function enableTextSelection(element) { element .attr('unselectable', 'off') .css('MozUserSelect', '') .unbind('selectstart.ui'); } */