Compare commits

...

1 commit

Author SHA1 Message Date
Adam Shaw
409cf6d404 using new MightyDate library 2011-05-08 01:49:19 -07:00
20 changed files with 1065 additions and 526 deletions

View file

@ -22,8 +22,8 @@ function Calendar(element, options, eventSources) {
t.today = today;
t.gotoDate = gotoDate;
t.incrementDate = incrementDate;
t.formatDate = function(format, date) { return formatDate(format, date, options) };
t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) };
t.formatDate = function(date, format) { return date.toString(format, options) };
t.formatDates = function(date1, date2, format) { return date1.toString(date2, format, options) };
t.getDate = getDate;
t.getView = getView;
t.option = option;
@ -49,7 +49,7 @@ function Calendar(element, options, eventSources) {
var absoluteViewElement;
var resizeUID = 0;
var ignoreWindowResize = 0;
var date = new Date();
var date = new MightyDate();
var events = [];
var _dragElement;
@ -59,7 +59,13 @@ function Calendar(element, options, eventSources) {
-----------------------------------------------------------------------------*/
setYMD(date, options.year, options.month, options.date);
if (options.year) {
date = new MightyDate(
options.year,
options.month || 0,
options.date || 1
);
}
function render(inc) {
@ -198,7 +204,9 @@ function Calendar(element, options, eventSources) {
}
var forceEventRender = false;
if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {
if (
!currentView.start || inc || date.before(currentView.start) || !date.before(currentView.end)
) {
// view must render an entire new date range (and refetch/render events)
currentView.render(date, inc || 0); // responsible for clearing events
setSize(true);
@ -221,8 +229,8 @@ function Calendar(element, options, eventSources) {
elementOuterWidth = element.outerWidth();
header.updateTitle(currentView.title);
var today = new Date();
if (today >= currentView.start && today < currentView.end) {
var today = new MightyDate();
if (!today.before(currentView.start) && today.before(currentView.end)) { // within range
header.disableButton('today');
}else{
header.enableButton('today');
@ -391,28 +399,32 @@ function Calendar(element, options, eventSources) {
function prevYear() {
addYears(date, -1);
date.addYears(-1, true);
renderView();
}
function nextYear() {
addYears(date, 1);
date.addYears(1, true);
renderView();
}
function today() {
date = new Date();
date = new MightyDate();
renderView();
}
function gotoDate(year, month, dateOfMonth) {
if (year instanceof Date) {
date = cloneDate(year); // provided 1 argument, a Date
if (typeof year == 'object') {
date = new MightyDate(year); // provided 1 argument, a Date or MightyDate
}else{
setYMD(date, year, month, dateOfMonth);
date = new MightyDate(
year,
month || 0,
dateOfMonth || 1
);
}
renderView();
}
@ -420,20 +432,20 @@ function Calendar(element, options, eventSources) {
function incrementDate(years, months, days) {
if (years !== undefined) {
addYears(date, years);
date.addYears(years, true);
}
if (months !== undefined) {
addMonths(date, months);
date.addMonths(months, true);
}
if (days !== undefined) {
addDays(date, days);
date.addDays(days);
}
renderView();
}
function getDate() {
return cloneDate(date);
return date.clone();
}

View file

@ -53,7 +53,7 @@ function EventManager(options, _sources) {
function isFetchNeeded(start, end) {
return !rangeStart || start < rangeStart || end > rangeEnd;
return !rangeStart || start.before(rangeStart) || end.after(rangeEnd);
}
@ -94,7 +94,7 @@ function EventManager(options, _sources) {
var fetchers = fc.sourceFetchers;
var res;
for (i=0; i<fetchers.length; i++) {
res = fetchers[i](source, rangeStart, rangeEnd, callback);
res = fetchers[i](source, rangeStart.clone(), rangeEnd.clone(), callback);
if (res === true) {
// the fetcher is in charge. made its own async request
return;
@ -109,7 +109,7 @@ function EventManager(options, _sources) {
if (events) {
if ($.isFunction(events)) {
pushLoading();
events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
events(rangeStart.clone(), rangeEnd.clone(), function(events) {
callback(events);
popLoading();
});
@ -208,22 +208,23 @@ function EventManager(options, _sources) {
-----------------------------------------------------------------------------*/
function updateEvent(event) { // update an existing event
function updateEvent(event) { // update an existing event // TODO: test thoroughly
var i, len = cache.length, e,
defaultEventEnd = getView().defaultEventEnd, // getView???
startDelta = event.start - event._start,
endDelta = event.end ?
(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end
: 0; // was null and event was just resized
startDelta = event._start.diffMilliseconds(event.start),
endDelta =
event.end ?
(event._end || defaultEventEnd(event)).diffMilliseconds(event.end) : // event._end would be null if event.end
0; // was null and event was just resized
for (i=0; i<len; i++) {
e = cache[i];
if (e._id == event._id && e != event) {
e.start = new Date(+e.start + startDelta);
e.start.addMilliseconds(startDelta);
if (event.end) {
if (e.end) {
e.end = new Date(+e.end + endDelta);
e.end.addMilliseconds(endDelta);
}else{
e.end = new Date(+defaultEventEnd(e) + endDelta);
e.end = defaultEventEnd(e).addMilliseconds(endDelta);
}
}else{
e.end = null;
@ -334,12 +335,12 @@ function EventManager(options, _sources) {
}
delete event.date;
}
event._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));
event._start = (event.start = parseDate(event.start, ignoreTimezone)).clone();
event.end = parseDate(event.end, ignoreTimezone);
if (event.end && event.end <= event.start) {
if (event.end && !event.end.after(event.start)) {
event.end = null;
}
event._end = event.end ? cloneDate(event.end) : null;
event._end = event.end ? event.end.clone() : null;
if (event.allDay === undefined) {
event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);
}

View file

@ -42,7 +42,7 @@ js('main.js');
js('Calendar.js');
js('Header.js');
js('EventManager.js');
js('date_util.js');
js('mightydate.js');
js('util.js');
js('basic/MonthView.js');

View file

@ -19,13 +19,13 @@ function AgendaDayView(element, calendar) {
function render(date, delta) {
if (delta) {
addDays(date, delta);
date.addDays(delta);
if (!opt('weekends')) {
skipWeekend(date, delta < 0 ? -1 : 1);
}
}
var start = cloneDate(date, true);
var end = addDays(cloneDate(start), 1);
var start = date.clone().clearTime();
var end = start.clone().addDays(1);
t.title = formatDate(date, opt('titleFormat'));
t.start = t.visStart = start;
t.end = t.visEnd = end;

View file

@ -103,14 +103,14 @@ function AgendaEventRenderer() {
var colCnt = getColCnt(),
minMinute = getMinMinute(),
maxMinute = getMaxMinute(),
d = addMinutes(cloneDate(t.visStart), minMinute),
d = t.visStart.clone().addMinutes(minMinute),
visEventEnds = $.map(events, slotEventEnd),
i, col,
j, level,
k, seg,
segs=[];
for (i=0; i<colCnt; i++) {
col = stackSegs(sliceSegs(events, visEventEnds, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
col = stackSegs(sliceSegs(events, visEventEnds, d, d.clone().addMinutes(maxMinute-minMinute)));
countForwardSegs(col);
for (j=0; j<col.length; j++) {
level = col[j];
@ -121,7 +121,7 @@ function AgendaEventRenderer() {
segs.push(seg);
}
}
addDays(d, 1, true);
d.addDays(1);
}
return segs;
}
@ -129,9 +129,9 @@ function AgendaEventRenderer() {
function slotEventEnd(event) {
if (event.end) {
return cloneDate(event.end);
return event.end.clone();
}else{
return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));
return event.start.clone().addMinutes(opt('defaultEventMinutes'));
}
}
@ -383,8 +383,8 @@ function AgendaEventRenderer() {
if (!cell.row) {
// on full-days
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
event.start.clone().addDays(dayDelta).clearTime(),
exclEndDay(event).addDays(dayDelta).clearTime()
);
resetElement();
}else{
@ -396,8 +396,7 @@ function AgendaEventRenderer() {
setOuterHeight(
eventElement,
slotHeight * Math.round(
(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
/ opt('slotMinutes')
(event.end ? event.start.diffMinutes(event.end) : opt('defaultEventMinutes')) / opt('slotMinutes')
)
);
eventElement.draggable('option', 'grid', [colWidth, 1]);
@ -490,8 +489,8 @@ function AgendaEventRenderer() {
eventElement.draggable('option', 'grid', null);
}
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
event.start.clone().addDays(dayDelta).clearTime(),
exclEndDay(event).addDays(dayDelta).clearTime()
);
}else{
// on slots
@ -527,10 +526,10 @@ function AgendaEventRenderer() {
}
});
function updateTimeText(minuteDelta) {
var newStart = addMinutes(cloneDate(event.start), minuteDelta);
var newStart = event.start.clone().addMinutes(minuteDelta);
var newEnd;
if (event.end) {
newEnd = addMinutes(cloneDate(event.end), minuteDelta);
newEnd = event.end.clone().addMinutes(minuteDelta);
}
timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
}
@ -572,7 +571,7 @@ function AgendaEventRenderer() {
formatDates(
event.start,
(!slotDelta && !event.end) ? null : // no change, so don't display time range
addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
eventEnd(event).addMinutes(opt('slotMinutes')*slotDelta),
opt('timeFormat')
)
);

View file

@ -273,11 +273,11 @@ function AgendaView(element, calendar, viewName) {
s =
"<table class='fc-agenda-slots' style='width:100%' cellspacing='0'>" +
"<tbody>";
d = zeroDate();
maxd = addMinutes(cloneDate(d), maxMinute);
addMinutes(d, minMinute);
d = t.visStart.clone();
maxd = d.clone().addMinutes(maxMinute);
d.addMinutes(minMinute);
slotCnt = 0;
for (i=0; d < maxd; i++) {
for (i=0; d.before(maxd); i++) {
minutes = d.getMinutes();
s +=
"<tr class='fc-slot" + i + ' ' + (!minutes ? '' : 'fc-minor') + "'>" +
@ -288,7 +288,7 @@ function AgendaView(element, calendar, viewName) {
"<div style='position:relative'>&nbsp;</div>" +
"</td>" +
"</tr>";
addMinutes(d, opt('slotMinutes'));
d.addMinutes(opt('slotMinutes'));
slotCnt++;
}
s +=
@ -309,13 +309,13 @@ function AgendaView(element, calendar, viewName) {
var headCell;
var bodyCell;
var date;
var today = clearTime(new Date());
var today = new MightyDate().clearTime();
for (i=0; i<colCnt; i++) {
date = colDate(i);
headCell = dayHeadCells.eq(i);
headCell.html(formatDate(date, colFormat));
bodyCell = dayBodyCells.eq(i);
if (+date == +today) {
if (date.equals(today)) {
bodyCell.addClass(tm + '-state-highlight fc-today');
}else{
bodyCell.removeClass(tm + '-state-highlight fc-today');
@ -394,8 +394,8 @@ function AgendaView(element, calendar, viewName) {
function resetScroll() {
var d0 = zeroDate();
var scrollDate = cloneDate(d0);
var d0 = t.visStart.clone();
var scrollDate = d0.clone();
scrollDate.setHours(opt('firstHour'));
var top = timePosition(d0, scrollDate) + 1; // +1 for the border
function scroll() {
@ -457,17 +457,18 @@ function AgendaView(element, calendar, viewName) {
function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusive
// TODO: get straight whether caller needs to do clearTime or not
if (refreshCoordinateGrid) {
coordinateGrid.build();
}
var visStart = cloneDate(t.visStart);
var visStart = t.visStart;
var startCol, endCol;
if (rtl) {
startCol = dayDiff(endDate, visStart)*dis+dit+1;
endCol = dayDiff(startDate, visStart)*dis+dit+1;
startCol = visStart.diffDays(endDate)*dis+dit+1;
endCol = visStart.diffDays(startDate)*dis+dit+1;
}else{
startCol = dayDiff(startDate, visStart);
endCol = dayDiff(endDate, visStart);
startCol = visStart.diffDays(startDate);
endCol = visStart.diffDays(endDate);
}
startCol = Math.max(0, startCol);
endCol = Math.min(colCnt, endCol);
@ -486,12 +487,12 @@ function AgendaView(element, calendar, viewName) {
function renderSlotOverlay(overlayStart, overlayEnd) {
var dayStart = cloneDate(t.visStart);
var dayEnd = addDays(cloneDate(dayStart), 1);
var dayStart = t.visStart.clone();
var dayEnd = dayStart.clone().addDays(1);
for (var i=0; i<colCnt; i++) {
var stretchStart = new Date(Math.max(dayStart, overlayStart));
var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));
if (stretchStart < stretchEnd) {
var stretchStart = overlayStart.before(dayStart) ? dayStart : overlayStart;
var stretchEnd = overlayEnd.after(dayEnd) ? dayEnd : overlayEnd;
if (stretchStart.before(stretchEnd)) {
var col = i*dis+dit;
var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only use it for horizontal coords
var top = timePosition(dayStart, stretchStart);
@ -502,8 +503,8 @@ function AgendaView(element, calendar, viewName) {
renderOverlay(rect, slotContent)
);
}
addDays(dayStart, 1);
addDays(dayEnd, 1);
dayStart.addDays(1);
dayEnd.addDays(1);
}
}
@ -567,7 +568,7 @@ function AgendaView(element, calendar, viewName) {
function dateCell(date) { // "cell" terminology is now confusing
return {
row: Math.floor(dayDiff(date, t.visStart) / 7),
row: t.visStart.diffWeeks(date),
col: dayOfWeekCol(date.getDay())
};
}
@ -580,14 +581,14 @@ function AgendaView(element, calendar, viewName) {
slotIndex--;
}
if (slotIndex >= 0) {
addMinutes(d, minMinute + slotIndex * opt('slotMinutes'));
d.addMinutes(minMinute + slotIndex * opt('slotMinutes'));
}
return d;
}
function colDate(col) { // returns dates with 00:00:00
return addDays(cloneDate(t.visStart), col*dis+dit);
return t.visStart.clone().addDays(col*dis+dit);
}
@ -605,11 +606,11 @@ function AgendaView(element, calendar, viewName) {
// get the Y coordinate of the given time on the given day (both Date objects)
function timePosition(day, time) { // both date objects. day holds 00:00 of current day
day = cloneDate(day, true);
if (time < addMinutes(cloneDate(day), minMinute)) {
day = day.clone().clearTime();
if (time.before(day.clone().addMinutes(minMinute))) {
return 0;
}
if (time >= addMinutes(cloneDate(day), maxMinute)) {
if (!time.before(day.clone().addMinutes(maxMinute))) {
return slotTable.height();
}
var slotMinutes = opt('slotMinutes'),
@ -639,11 +640,11 @@ function AgendaView(element, calendar, viewName) {
function defaultEventEnd(event) {
var start = cloneDate(event.start);
var start = event.start.clone();
if (event.allDay) {
return start;
}
return addMinutes(start, opt('defaultEventMinutes'));
return start.addMinutes(opt('defaultEventMinutes'));
}
@ -654,16 +655,20 @@ function AgendaView(element, calendar, viewName) {
function defaultSelectionEnd(startDate, allDay) {
if (allDay) {
return cloneDate(startDate);
return startDate.clone();
}
return addMinutes(cloneDate(startDate), opt('slotMinutes'));
return startDate.clone().addMinutes(opt('slotMinutes'));
}
function renderSelection(startDate, endDate, allDay) { // only for all-day
if (allDay) {
if (opt('allDaySlot')) {
renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);
renderDayOverlay(
startDate.clone().clearTime(),
endDate.clone().addDays(1).clearTime(), // TODO: use util
true
);
}
}else{
renderSlotSelection(startDate, endDate);
@ -675,7 +680,7 @@ function AgendaView(element, calendar, viewName) {
var helperOption = opt('selectHelper');
coordinateGrid.build();
if (helperOption) {
var col = dayDiff(startDate, t.visStart) * dis + dit;
var col = t.visStart.diffDays(startDate) * dis + dit;
if (col >= 0 && col < colCnt) { // only works when times are on same day
var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords
var top = timePosition(startDate, startDate);
@ -743,9 +748,9 @@ function AgendaView(element, calendar, viewName) {
var d2 = cellDate(cell);
dates = [
d1,
addMinutes(cloneDate(d1), opt('slotMinutes')),
d1.clone().addMinutes(opt('slotMinutes')),
d2,
addMinutes(cloneDate(d2), opt('slotMinutes'))
d2.clone().addMinutes(opt('slotMinutes'))
].sort(cmp);
renderSlotSelection(dates[0], dates[3]);
}else{
@ -755,7 +760,7 @@ function AgendaView(element, calendar, viewName) {
$(document).one('mouseup', function(ev) {
hoverListener.stop();
if (dates) {
if (+dates[0] == +dates[1]) {
if (dates[0].equals(dates[1])) {
reportDayClick(dates[0], false, ev);
}
reportSelection(dates[0], dates[3], false, ev);
@ -766,7 +771,7 @@ function AgendaView(element, calendar, viewName) {
function reportDayClick(date, allDay, ev) {
trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev);
trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date.clone(), allDay, ev);
}
@ -783,7 +788,7 @@ function AgendaView(element, calendar, viewName) {
renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
}else{
var d1 = cellDate(cell);
var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));
var d2 = d1.clone().addMinutes(opt('defaultEventMinutes'));
renderSlotOverlay(d1, d2);
}
}

View file

@ -19,12 +19,12 @@ function AgendaWeekView(element, calendar) {
function render(date, delta) {
if (delta) {
addDays(date, delta * 7);
date.addWeeks(delta);
}
var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
var end = addDays(cloneDate(start), 7);
var visStart = cloneDate(start);
var visEnd = cloneDate(end);
var start = date.clone().clearTime().addDays(-((date.getDay() - opt('firstDay') + 7) % 7));
var end = start.clone().addWeeks(1);
var visStart = start.clone();
var visEnd = end.clone();
var weekends = opt('weekends');
if (!weekends) {
skipWeekend(visStart);
@ -32,7 +32,7 @@ function AgendaWeekView(element, calendar) {
}
t.title = formatDates(
visStart,
addDays(cloneDate(visEnd), -1),
visEnd.clone().addDays(-1),
opt('titleFormat')
);
t.start = start;

View file

@ -22,14 +22,14 @@ function BasicDayView(element, calendar) {
function render(date, delta) {
if (delta) {
addDays(date, delta);
date.addDays(delta);
if (!opt('weekends')) {
skipWeekend(date, delta < 0 ? -1 : 1);
}
}
t.title = formatDate(date, opt('titleFormat'));
t.start = t.visStart = cloneDate(date, true);
t.end = t.visEnd = addDays(cloneDate(t.start), 1);
t.start = t.visStart = date.clone().clearTime();
t.end = t.visEnd = t.start.clone().addDays(1);
renderBasic(1, 1, 1, false);
}

View file

@ -53,8 +53,8 @@ function BasicEventRenderer() {
function compileSegs(events) {
var rowCnt = getRowCnt(),
colCnt = getColCnt(),
d1 = cloneDate(t.visStart),
d2 = addDays(cloneDate(d1), colCnt),
d1 = t.visStart.clone(),
d2 = d1.clone().addDays(colCnt),
visEventsEnds = $.map(events, exclEndDay),
i, row,
j, level,
@ -71,8 +71,8 @@ function BasicEventRenderer() {
segs.push(seg);
}
}
addDays(d1, 7);
addDays(d2, 7);
d1.addWeeks(1);
d2.addWeeks(1);
}
return segs;
}
@ -113,8 +113,8 @@ function BasicEventRenderer() {
//setOverflowHidden(true);
dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
event.start.clone().addDays(dayDelta).clearTime(),
exclEndDay(event).addDays(dayDelta).clearTime()
);
}else{
//setOverflowHidden(false);

View file

@ -184,7 +184,7 @@ function BasicView(element, calendar, viewName) {
function updateCells(firstTime) {
var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating?
var month = t.start.getMonth();
var today = clearTime(new Date());
var today = new MightyDate().clearTime();
var cell;
var date;
var row;
@ -206,7 +206,7 @@ function BasicView(element, calendar, viewName) {
}else{
cell.addClass('fc-other-month');
}
if (+date == +today) {
if (date.equals(today)) {
cell.addClass(tm + '-state-highlight fc-today');
}else{
cell.removeClass(tm + '-state-highlight fc-today');
@ -296,29 +296,30 @@ function BasicView(element, calendar, viewName) {
function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive
// TODO: get straight whether caller needs to do clearTime or not
if (refreshCoordinateGrid) {
coordinateGrid.build();
}
var rowStart = cloneDate(t.visStart);
var rowEnd = addDays(cloneDate(rowStart), colCnt);
var rowStart = t.visStart.clone();
var rowEnd = rowStart.clone().addDays(colCnt);
for (var i=0; i<rowCnt; i++) {
var stretchStart = new Date(Math.max(rowStart, overlayStart));
var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));
if (stretchStart < stretchEnd) {
var stretchStart = overlayStart.before(rowStart) ? rowStart : overlayStart;
var stretchEnd = overlayEnd.after(rowEnd) ? rowEnd : overlayEnd;
if (stretchStart.before(stretchEnd)) {
var colStart, colEnd;
if (rtl) {
colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;
colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;
colStart = rowStart.diffDays(stretchEnd)*dis+dit+1;
colEnd = rowStart.diffDays(stretchStart)*dis+dit+1;
}else{
colStart = dayDiff(stretchStart, rowStart);
colEnd = dayDiff(stretchEnd, rowStart);
colStart = rowStart.diffDays(stretchStart);
colEnd = rowStart.diffDays(stretchEnd);
}
dayBind(
renderCellOverlay(i, colStart, i, colEnd-1)
);
}
addDays(rowStart, 7);
addDays(rowEnd, 7);
rowStart.addWeeks(1);
rowEnd.addWeeks(1);
}
}
@ -335,12 +336,16 @@ function BasicView(element, calendar, viewName) {
function defaultSelectionEnd(startDate, allDay) {
return cloneDate(startDate);
return startDate.clone();
}
function renderSelection(startDate, endDate, allDay) {
renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???
renderDayOverlay(
startDate.clone().clearTime(),
endDate.clone().addDays(1).clearTime(), // TODO: use util
true // rebuild every time???
);
}
@ -352,7 +357,7 @@ function BasicView(element, calendar, viewName) {
function reportDayClick(date, allDay, ev) {
var cell = dateCell(date);
var _element = bodyCells[cell.row*colCnt + cell.col];
trigger('dayClick', _element, date, allDay, ev);
trigger('dayClick', _element, date.clone(), allDay, ev);
}
@ -387,7 +392,7 @@ function BasicView(element, calendar, viewName) {
function defaultEventEnd(event) {
return cloneDate(event.start);
return event.start.clone();
}
@ -440,7 +445,7 @@ function BasicView(element, calendar, viewName) {
function dateCell(date) {
return {
row: Math.floor(dayDiff(date, t.visStart) / 7),
row: t.visStart.diffWeeks(date),
col: dayOfWeekCol(date.getDay())
};
}
@ -452,7 +457,7 @@ function BasicView(element, calendar, viewName) {
function _cellDate(row, col) {
return addDays(cloneDate(t.visStart), row*7 + col*dis+dit);
return t.visStart.clone().addDays(row*7 + col*dis+dit);
// what about weekends in middle of week?
}

View file

@ -19,12 +19,12 @@ function BasicWeekView(element, calendar) {
function render(date, delta) {
if (delta) {
addDays(date, delta * 7);
date.addWeeks(delta);
}
var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
var end = addDays(cloneDate(start), 7);
var visStart = cloneDate(start);
var visEnd = cloneDate(end);
var start = date.clone().clearTime().addDays(-((date.getDay() - opt('firstDay') + 7) % 7));
var end = start.clone().addWeeks(1);
var visStart = start.clone();
var visEnd = end.clone();
var weekends = opt('weekends');
if (!weekends) {
skipWeekend(visStart);
@ -32,7 +32,7 @@ function BasicWeekView(element, calendar) {
}
t.title = formatDates(
visStart,
addDays(cloneDate(visEnd), -1),
visEnd.clone().addDays(-1),
opt('titleFormat')
);
t.start = start;

View file

@ -19,25 +19,23 @@ function MonthView(element, calendar) {
function render(date, delta) {
if (delta) {
addMonths(date, delta);
date.setDate(1);
date.setDate(1).addMonths(delta);
}
var start = cloneDate(date, true);
start.setDate(1);
var end = addMonths(cloneDate(start), 1);
var visStart = cloneDate(start);
var visEnd = cloneDate(end);
var start = date.clone().setDate(1).clearTime();
var end = start.clone().addMonths(1);
var visStart = start.clone();
var visEnd = end.clone();
var firstDay = opt('firstDay');
var nwe = opt('weekends') ? 0 : 1;
if (nwe) {
skipWeekend(visStart);
skipWeekend(visEnd, -1, true);
}
addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));
addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);
var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
visStart.addDays(-((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));
visEnd.addDays((7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);
var rowCnt = visStart.diffWeeks(visEnd);
if (opt('weekMode') == 'fixed') {
addDays(visEnd, (6 - rowCnt) * 7);
visEnd.addWeeks(6 - rowCnt);
rowCnt = 6;
}
t.title = formatDate(start, opt('titleFormat'));

View file

@ -438,7 +438,7 @@ function DayEventRenderer() {
}
}
dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);
var newEnd = addDays(eventEnd(event), dayDelta, true);
var newEnd = eventEnd(event).addDays(dayDelta);
if (dayDelta) {
eventCopy.end = newEnd;
var oldHelpers = helpers;
@ -456,7 +456,11 @@ function DayEventRenderer() {
}
}
clearOverlays();
renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
renderDayOverlay(
event.start.clone().clearTime(),
newEnd.clone().addDays(1).clearTime() // TODO: use util
);
// coordinate grid already rebuild at hoverListener.start
}
}, ev);

View file

@ -60,7 +60,7 @@ function SelectionManager() {
function reportSelection(startDate, endDate, allDay, ev) {
selected = true;
trigger('select', null, startDate, endDate, allDay, ev);
trigger('select', null, startDate.clone(), endDate.clone(), allDay, ev);
}
@ -85,7 +85,7 @@ function SelectionManager() {
$(document).one('mouseup', function(ev) {
hoverListener.stop();
if (dates) {
if (+dates[0] == +dates[1]) {
if (dates[0].equals(dates[1])) {
reportDayClick(dates[0], true, ev);
}
reportSelection(dates[0], dates[1], true, ev);

View file

@ -102,7 +102,7 @@ function View(element, calendar, viewName) {
// returns a Date object for an event's end
function eventEnd(event) {
return event.end ? cloneDate(event.end) : defaultEventEnd(event);
return event.end ? event.end.clone() : defaultEventEnd(event);
}
@ -232,9 +232,9 @@ function View(element, calendar, viewName) {
if (allDay !== undefined) {
e.allDay = allDay;
}
addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
e.start.addDays(dayDelta).addMinutes(minuteDelta);
if (e.end) {
e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
e.end.addDays(dayDelta).addMinutes(minuteDelta);
}
normalizeEvent(e, options);
}
@ -245,7 +245,7 @@ function View(element, calendar, viewName) {
minuteDelta = minuteDelta || 0;
for (var e, len=events.length, i=0; i<len; i++) {
e = events[i];
e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);
e.end = eventEnd(e).addDays(dayDelta).addMinutes(minuteDelta);
normalizeEvent(e, options);
}
}

View file

@ -1,357 +0,0 @@
fc.addDays = addDays;
fc.cloneDate = cloneDate;
fc.parseDate = parseDate;
fc.parseISO8601 = parseISO8601;
fc.parseTime = parseTime;
fc.formatDate = formatDate;
fc.formatDates = formatDates;
/* Date Math
-----------------------------------------------------------------------------*/
var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
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;
}
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);
}
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
-----------------------------------------------------------------------------*/
function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
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+(\.\d+)?$/)) { // a UNIX timestamp
return new Date(parseFloat(s) * 1000);
}
if (ignoreTimezone === undefined) {
ignoreTimezone = true;
}
return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);
}
// TODO: never return invalid dates (like from new Date(<string>)), return null instead
return null;
}
function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false
// 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);
if (ignoreTimezone || !m[14]) {
var check = new Date(m[1], 0, 1, 9, 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);
}else{
date.setUTCFullYear(
m[1],
m[3] ? m[3] - 1 : 0,
m[5] || 1
);
date.setUTCHours(
m[7] || 0,
m[8] || 0,
m[10] || 0,
m[12] ? Number("0." + m[12]) * 1000 : 0
);
var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);
offset *= m[15] == '-' ? 1 : -1;
date = new Date(+date + (offset * 60 * 1000));
}
return date;
}
function parseTime(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], 10);
if (m[3]) {
h %= 12;
if (m[3].toLowerCase().charAt(0) == 'p') {
h += 12;
}
}
return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);
}
}
/* Date Formatting
-----------------------------------------------------------------------------*/
// TODO: use same function formatDate(date, [date2], format, [options])
function formatDate(date, format, options) {
return formatDates(date, null, format, options);
}
function formatDates(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/, ''), 10)) {
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';
}
};

View file

@ -42,10 +42,6 @@ var defaults = {
// locale
isRTL: false,
firstDay: 0,
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
buttonText: {
prev: '&nbsp;&#9668;&nbsp;',
next: '&nbsp;&#9658;&nbsp;',

View file

@ -13,9 +13,7 @@
var fc = $.fullCalendar;
var formatDate = fc.formatDate;
var parseISO8601 = fc.parseISO8601;
var addDays = fc.addDays;
var parseDate = fc.parseDate;
var applyAll = fc.applyAll;
@ -42,8 +40,8 @@ function transformOptions(sourceOptions, start, end) {
var success = sourceOptions.success;
var data = $.extend({}, sourceOptions.data || {}, {
'start-min': formatDate(start, 'u'),
'start-max': formatDate(end, 'u'),
'start-min': start.toString('u'),
'start-max': end.toString('u'),
'singleevents': true,
'max-results': 9999
});
@ -64,8 +62,8 @@ function transformOptions(sourceOptions, start, end) {
if (data.feed.entry) {
$.each(data.feed.entry, function(i, entry) {
var startStr = entry['gd$when'][0]['startTime'];
var start = parseISO8601(startStr, true);
var end = parseISO8601(entry['gd$when'][0]['endTime'], true);
var start = parseDate(startStr, true); // true for ignoreTimezone
var end = parseDate(entry['gd$when'][0]['endTime'], true); // true for ignoreTimezone
var allDay = startStr.indexOf('T') == -1;
var url;
$.each(entry.link, function(i, link) {
@ -77,7 +75,7 @@ function transformOptions(sourceOptions, start, end) {
}
});
if (allDay) {
addDays(end, -1); // make inclusive
end.addDays(-1); // make inclusive
}
events.push({
id: entry['gCal$uid']['value'],

795
src/mightydate.js Normal file
View file

@ -0,0 +1,795 @@
/**
* @preserve MightyDate v0.4
* http://github.com/arshaw/mightydate
*
* Copyright 2011, Adam Shaw
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Date: Sun May 8 00:19:07 2011 -0700
*/
var MightyDate = (function(Date, undefined) {
/** @const */ var FULLYEAR_INDEX = 0;
/** @const */ var MONTH_INDEX = 1;
/** @const */ var DATE_INDEX = 2;
/** @const */ var HOURS_INDEX = 3;
/** @const */ var MINUTES_INDEX = 4;
/** @const */ var SECONDS_INDEX = 5;
/** @const */ var MILLISECONDS_INDEX = 6;
/** @const */ var DAY_INDEX = 7;
/** @const */ var YEAR_INDEX = 8;
/** @const */ var WEEK_INDEX = 9;
/** @const */ var DAY_MS = 86400000;
var methodSubjects = [
'FullYear', // 0
'Month', // 1
'Date', // 2
'Hours', // 3
'Minutes', // 4
'Seconds', // 5
'Milliseconds', // 6
'Day', // 7
'Year' // 8
];
var subjectPlurals = [
'Years', // 0
'Months', // 1
'Days' // 2
];
var otherGetters = [
'getTimezoneOffset',
'getTime',
'valueOf',
'toDateString',
'toTimeString',
'toLocaleString',
'toLocaleDateString',
'toLocaleTimeString',
'toJSON'
];
var formatStringRE = new RegExp(
"(" + // 1
"\\((" + "('.*?'|\\(.*?\\)|.)*?" + ")\\)" + "|" + // 2 3
"\\{(" + "('.*?'|.)*?" + ")\\}" + "|" + // 4 5
"\\[(" + "('.*?'|.)*?" + ")\\]" + "|" + // 6 7
"'(.*?)'" + "|" + // 8
"(.[^({[']*)" + // 9
")" +
"(.*)" // 10
);
var UTC = Date.UTC;
var proto = MightyDate.prototype;
var i;
var noopSignal = {};
/* Constructor
------------------------------------------------------------------------------*/
function MightyDate() {
if (!(this instanceof MightyDate)) {
// when MightyDate is called as a method. TODO: write test
return init(new MightyDate(noopSignal), arguments);
}
init(this, arguments);
}
function init(mightyDate, args) {
var len = args.length;
if (!len) {
// set to now
setLocalDate(mightyDate, new Date());
}
else if (len == 1) {
var arg = args[0];
if (isNumber(arg)) {
setLocalDate(mightyDate, new Date(arg));
}
else if (isString(arg)) {
_setUniversalDate(mightyDate, new Date(0));
parse(mightyDate, arg);
}
else if (arg instanceof Date) {
setLocalDate(mightyDate, new Date(+arg));
}
else if (arg instanceof MightyDate) {
_setUniversalDate(mightyDate, new Date(+getUniversalDate(arg)));
}
else if (arg != noopSignal) {
_setUniversalDate(mightyDate, NaN); // make it an Invalid Date. TODO: write test
}
}
else {
_setUniversalDate(mightyDate, new Date(UTC.apply(Date, args)));
}
return mightyDate;
}
/* Standard Methods + Adding/Diffing Methods
-----------------------------------------------------------------------------*/
for (i=0; i<WEEK_INDEX; i++) (function(subject, i) { // TODO: rename i to fieldIndex
if (i != YEAR_INDEX) { // there is no getUTCYear
// getFullYear
// getMonth
// getDate
// getHours
// getMinutes
// getSeconds
// getMilliseconds
// getDay
proto['get' + subject] = function() {
return getUniversalDate(this)['getUTC' + subject]();
};
}
// getFullYear
// getMonth
// getDate
// getHours
// getMinutes
// getSeconds
// getMilliseconds
// getDay
// getYear
proto['getUTC' + subject] = function() {
return getLocalDate(this)['getUTC' + subject]();
};
if (i != DAY_INDEX) { // there is no setDay or setUTCDay methods
// setFullYear
// setMonth
// setDate
// setHours
// setMinutes
// setSeconds
// setMilliseconds
// setYear
proto['set' + subject] = function(value, preventOverflow) {
value = parseInt(value); // TODO: write tests
var month = i == MONTH_INDEX ? value % 12 : this.getMonth();
var args = arguments;
if (args.length == 2 && (isBoolean(preventOverflow) || preventOverflow === undefined)) {
args = [value];
}
getUniversalDate(this)['setUTC' + subject].apply(
getUniversalDate(this),
args
);
clearLocalDate(this);
// TODO: write tests for year overflow
if (i < DATE_INDEX && preventOverflow === true && this.getMonth() != month) { // fullyear or month
this.addMonths(-1)
.setDate(
getDaysInMonth(this.getFullYear(), this.getMonth())
);
}
return this; // for chaining
};
if (i != YEAR_INDEX) { // there is no setUTCYear method
// setUTCFullYear
// setUTCMonth
// setUTCDate
// setUTCHours
// setUTCMinutes
// setUTCMilliseconds
proto['setUTC' + subject] = function() {
var localDate = getLocalDate(this);
localDate['setUTC' + subject].apply(
localDate,
arguments
);
setUniversalDate(this, localToUniversal(localDate));
return this; // for chaining
};
}
}
if (i < DAY_INDEX) { // not day and not year
// addYears
// addMonths
// addDays
// addHours
// addMinutes
// addSeconds
// addMilliseconds
proto['add' + (subjectPlurals[i] || subject)] = function(delta, preventOverflow) {
delta = parseInt(delta);
this['set' + subject](
this['get' + subject]() + delta,
preventOverflow
);
return this; // for chaining
};
// diffYears
// diffMonths
// diffDays
// diffHours
// diffMinutes
// diffSeconds
// diffMilliseconds
proto['diff' + (subjectPlurals[i] || subject)] = function(otherDate, exact) {
return diff(i, this, otherDate, exact);
};
}
})(methodSubjects[i], i);
for (i=0; i<otherGetters.length; i++) (function(getter) {
proto[getter] = function() {
return getLocalDate(this)[getter]();
};
})(otherGetters[i]);
proto.getYear = function() {
return getUniversalDate(this).getUTCFullYear() - 1900;
};
proto.setTime = function(t) {
setLocalDate(this, new Date(t));
};
function diff(fieldIndex, date, otherDate, exact) { // TODO: write tests
var d1 = getUniversalDate(date);
var d2 = extractUniversalDate(otherDate);
var v;
if (fieldIndex < DATE_INDEX) { // fullyear or month
v = (d2.getUTCFullYear() * 12 + d2.getUTCMonth()) -
(d1.getUTCFullYear() * 12 + d1.getUTCMonth()) +
((d2 - UTC(d2.getUTCFullYear(), d2.getUTCMonth(), 1)) -
(d1 - UTC(d1.getUTCFullYear(), d1.getUTCMonth(), 1))) / DAY_MS / 31;
if (fieldIndex == FULLYEAR_INDEX) {
v /= 12;
}
}else{
v = (d2 - d1) / [ // milliseconds in a...
DAY_MS, // day
3600000, // hour
60000, // minute
1000, // second
1, // millisecond
0,
0,
DAY_MS * 7 // week
][fieldIndex - 2];
}
if (!exact) {
v = Math.floor(v);
}
return v;
}
/* Week (TODO: write tests)
----------------------------------------------------------------------------*/
proto.diffWeeks = function(otherDate, exact) {
return diff(WEEK_INDEX, this, otherDate, exact);
};
proto.addWeeks = function(delta) {
return this.addDays(delta * 7);
};
proto.getWeek = function(d) {
return _getWeek(this.getFullYear(), this.getMonth(), this.getDate());
};
proto.getUTCWeek = function(d) {
return _getWeek(this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDate());
};
function _getWeek(year, month, date) {
var d = new Date(UTC(year, month, date));
var currentWeek1 = getWeek1(year);
var week1 = currentWeek1;
if (d < currentWeek1) {
week1 = getWeek1(year-1);
}else{
var nextWeek1 = getWeek1(year+1);
if (d >= nextWeek1) {
week1 = nextWeek1;
}
}
return Math.floor(Math.round((d - week1) / DAY_MS) / 7) + 1;
}
function getWeek1(year) {
var d = new Date(UTC(year, 0, 4));
d.setUTCDate(d.getUTCDate() - (d.getUTCDay() + 6) % 7);
return d;
}
/* Non-Standard Methods
-----------------------------------------------------------------------------*/
proto.equals = function(date) {
return +getUniversalDate(this) == +extractUniversalDate(date);
};
proto.before = function(date) {
return getUniversalDate(this) < extractUniversalDate(date);
};
proto.after = function(date) {
return getUniversalDate(this) > extractUniversalDate(date);
};
proto.valid = function() {
return !isNaN(+getUniversalDate(this));
};
proto.clearTime = function() {
return this.setHours(0, 0, 0, 0);
};
proto.clone = function() {
return new MightyDate(this);
};
proto.toDate = function() {
return new Date(+this);
};
/* Parsing
-----------------------------------------------------------------------------*/
MightyDate.parsers = [
parseISO
];
MightyDate.parse = function(str) {
return +new MightyDate(''+str);
};
function parse(date, str) {
var parsers = MightyDate.parsers;
for (var i=0; i<parsers.length; i++) {
if (parsers[i](date, str)) {
return;
}
}
setLocalDate(date, new Date(str));
}
function parseISO(date, str) {
var m = str.match(/^(\d{4})(-(\d{2})(-(\d{2})([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d+))?)?(Z|(([-+])(\d{2})(:?(\d{2}))?))?)?)?)?$/);
if (!m) {
return false;
}
var args1 = [
m[1],
m[3] ? m[3] - 1 : 0,
m[5] || 1
];
var args2 = [
m[7] || 0,
m[8] || 0,
m[10] || 0,
m[12] ? Number('0.' + m[12]) * 1000 : 0
];
if (m[14]) {
date.setUTCFullYear.apply(date, args1);
date.setUTCHours.apply(date, args2);
var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);
offset *= m[15] == '-' ? 1 : -1;
date.addMinutes(offset);
}else{
date.setFullYear.apply(date, args1);
date.setHours.apply(date, args2);
}
return true;
}
/* Formatting
---------------------------------------------------------------------------------------*/
MightyDate.defaultLocale = '';
MightyDate.locales = {
'': {
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
amDesignator: 'AM',
pmDesignator: 'PM'
}
};
MightyDate.formatters = {
i: "yyyy-MM-dd'T'HH:mm:ss",
u: "yyyy-MM-dd'T'HH:mm:ssK"
};
proto.toString = function(otherDate, formatString, settings) {
if (!arguments.length || !this.valid()) {
return getLocalDate(this).toString();
}
return format(false, this, otherDate, formatString, settings);
};
proto.toUTCString = proto.toGMTString = function(otherDate, formatString, settings) {
if (!arguments.length || !this.valid()) {
return getLocalDate(this).toUTCString();
}
return format(true, this, otherDate, formatString, settings);
};
function format(isUTC, date, otherDate, formatString, settings) {
if (isString(otherDate)) {
settings = formatString;
formatString = otherDate;
otherDate = null;
}
var locales = MightyDate.locales;
var localeSettings = locales[MightyDate.defaultLocale] || {};
if (isString(settings)) {
localeSettings = locales[settings] || localeSettings;
settings = {};
}else{
settings = settings || {};
}
function getSetting(name) {
return settings[name] || localeSettings[name];
}
return _format(isUTC, date, otherDate, formatString, getSetting);
}
function _format(isUTC, date, otherDate, formatString, getSetting, uniqueness) {
var match;
var tokenReplacement;
var subOutput;
var output = '';
var _getField = isUTC ? getUTCField : getLocalField;
function getField(i) {
if (uniqueness) {
for (var j=i; j>=0; j--) {
uniqueness.push(_getField(date, j));
}
}
return _getField(date, i);
}
while (formatString) {
match = formatStringRE.exec(formatString);
if (match[9] !== undefined) {
// tokens
var tokenSoup = match[9];
var tokenSoupLength = tokenSoup.length;
var tokenStart = 0;
var tokenEnd = tokenSoupLength;
while (tokenStart < tokenSoupLength) {
tokenReplacement = undefined;
// find the longest formatter starting at tokenStart
while (tokenEnd > tokenStart) {
tokenReplacement = getTokenReplacement(
tokenSoup.substring(tokenStart, tokenEnd), // the potential token
isUTC, date, getField, getSetting, uniqueness
);
if (tokenReplacement !== undefined) {
output += tokenReplacement;
tokenStart = tokenEnd; // continue looking after
break;
}
tokenEnd--;
}
if (tokenReplacement === undefined) {
// swallow single character and continue after
output += formatString.charAt(tokenStart);
tokenStart++;
}
tokenEnd = tokenSoupLength;
}
}
else if (match[2] !== undefined) {
// only if non-zero
subOutput = _format(isUTC, date, otherDate, match[2], getSetting);
if (Number(subOutput.replace(/\D/g, ''))) {
output += subOutput;
}
}
else if (match[4] !== undefined) {
// switch to other date
if (otherDate) {
output += _format(isUTC, otherDate, date, match[4], getSetting);
}
}
else if (match[6] !== undefined) {
// only if different
var otherSubUniqueness = [];
var otherSubOutput = _format(isUTC, otherDate, date, match[6], getSetting, otherSubUniqueness);
var subUniqueness = [];
subOutput = _format(isUTC, date, otherDate, match[6], getSetting, subUniqueness);
if (subOutput != otherSubOutput || subUniqueness.join() != otherSubUniqueness.join()) {
output += subOutput;
}
}
else if (match[8] !== undefined) {
if (match[8]) {
output += match[8]; // quoted text
}else{
output += "'"; // escaped quote
}
}
formatString = match[10];
}
return output;
}
function getTokenReplacement(token, isUTC, date, getField, getSetting, uniqueness) {
var formatter = MightyDate.formatters[token];
if (formatter) {
if (isString(formatter)) {
return _format(isUTC, date, null, formatter, getSetting, uniqueness);
}
return formatter(date, getSetting, isUTC);
}
switch (token) {
case 's' : return getField(SECONDS_INDEX);
case 'ss' : return zeroPad(getField(SECONDS_INDEX));
case 'm' : return getField(MINUTES_INDEX);
case 'mm' : return zeroPad(getField(MINUTES_INDEX));
case 'h' : return getField(HOURS_INDEX) % 12 || 12;
case 'hh' : return zeroPad(getField(HOURS_INDEX) % 12 || 12);
case 'H' : return getField(HOURS_INDEX);
case 'HH' : return zeroPad(getField(HOURS_INDEX));
case 'd' : return getField(DATE_INDEX);
case 'dd' : return zeroPad(getField(DATE_INDEX));
case 'ddd' : return getSetting('dayNamesShort')[getField(DAY_INDEX)];
case 'dddd' : return getSetting('dayNames')[getField(DAY_INDEX)];
case 'M' : return getField(MONTH_INDEX) + 1;
case 'MM' : return zeroPad(getField(MONTH_INDEX) + 1);
case 'MMM' : return getSetting('monthNamesShort')[getField(MONTH_INDEX)];
case 'MMMM' : return getSetting('monthNames')[getField(MONTH_INDEX)];
case 'yy' : return (getField(FULLYEAR_INDEX)+'').substring(2);
case 'yyyy' : return getField(FULLYEAR_INDEX);
case 't' :
case 'tt' :
case 'T' :
case 'TT' :
var s = getField(HOURS_INDEX) < 12 ? getSetting('amDesignator') : getSetting('pmDesignator');
if (token.length == 1) s = s.substr(0, 1);
if (token > 'TT') s = s.toLowerCase(); // token == 't' || token == 'tt'
return s;
case 'K' : if (isUTC) return 'Z';
case 'z' :
case 'zz' :
case 'zzz' :
var tzo = date.getTimezoneOffset();
var sign = tzo < 0 ? '+' : '-';
var hours = Math.floor((tzo = Math.abs(tzo)) / 60);
var minutes = tzo % 60;
return sign +
(token == 'z' ? hours : zeroPad(hours)) +
((token == 'z' || token == 'zz') ? '' : ':' + zeroPad(minutes));
case 'S' :
var d = getField(DATE_INDEX);
if (d > 10 && d < 20) return 'th';
return ['st', 'nd', 'rd'][d % 10 - 1] || 'th';
case 'W' :
return _getWeek(
getField(FULLYEAR_INDEX),
getField(MONTH_INDEX),
getField(DATE_INDEX)
);
case 'WW' :
return zeroPad(
_getWeek(
getField(FULLYEAR_INDEX),
getField(MONTH_INDEX),
getField(DATE_INDEX)
)
);
}
}
function getLocalField(date, i) {
return date['get' + methodSubjects[i]]();
}
function getUTCField(date, i) {
return date['getUTC' + methodSubjects[i]]();
}
/* Misc Class Methods
-----------------------------------------------------------------------------*/
MightyDate.now = Date.now;
MightyDate.UTC = UTC;
MightyDate.getDaysInMonth = getDaysInMonth;
/* Date Utilities
--------------------------------------------------------------------------------*/
function getDaysInMonth(year, month) {
return 32 - new Date(Date.UTC(year, month, 32)).getUTCDate();
}
function extractUniversalDate(date) {
if (date instanceof MightyDate) {
return getUniversalDate(date);
}
else if (date instanceof Date) {
return localToUniversal(date);
}
return getUniversalDate(new MightyDate(date));
}
function localToUniversal(localDate) {
return new Date(UTC(
localDate.getFullYear(),
localDate.getMonth(),
localDate.getDate(),
localDate.getHours(),
localDate.getMinutes(),
localDate.getSeconds(),
localDate.getMilliseconds()
));
}
function universalToLocal(universalDate) {
return new Date(
universalDate.getUTCFullYear(),
universalDate.getUTCMonth(),
universalDate.getUTCDate(),
universalDate.getUTCHours(),
universalDate.getUTCMinutes(),
universalDate.getUTCSeconds(),
universalDate.getUTCMilliseconds()
);
}
/* General Utilities
--------------------------------------------------------------------------------*/
function zeroPad(n) {
return (n < 10 ? '0' : '') + n;
}
function isString(x) {
return typeof x == 'string';
}
function isNumber(x) {
return typeof x == 'number';
}
function isBoolean(x) {
return typeof x == 'boolean';
}
/* Internal Utilities
---------------------------------------------------------------------------------*/
// _ is universal date
// $ is local date
function getUniversalDate(mightyDate) {
return mightyDate._;
}
function setUniversalDate(mightyDate, universalDate) {
_setUniversalDate(mightyDate, universalDate);
clearLocalDate(mightyDate);
}
function _setUniversalDate(mightyDate, universalDate) {
mightyDate._ = universalDate;
}
function getLocalDate(mightyDate) {
if (mightyDate.$ === undefined) {
mightyDate.$ = universalToLocal(mightyDate._);
}
return mightyDate.$;
}
function setLocalDate(mightyDate, localDate) {
mightyDate.$ = localDate;
mightyDate._ = localToUniversal(localDate);
}
function clearLocalDate(mightyDate) {
delete mightyDate.$;
}
return MightyDate;
})(Date);

View file

@ -1,5 +1,85 @@
fc.applyAll = applyAll;
fc.Date = MightyDate;
fc.parseDate = parseDate;
fc.parseISO8601 = parseISO8601;
fc.formatDate = formatDate;
fc.formatDates = formatDates;
var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
/* Date
--------------------------------------------------------------------------------*/
function skipWeekend(date, inc, excl) {
inc = inc || 1;
while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
date.addDays(inc);
}
return date;
}
function parseTime(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], 10);
if (m[3]) {
h %= 12;
if (m[3].toLowerCase().charAt(0) == 'p') {
h += 12;
}
}
return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);
}
}
// TODO: change ignoreTimezone default
function parseDate(input, ignoreTimezone) { // ignoreTimezone DEFAULTS TO TRUE!!! :(
// handles more than just strings
if (ignoreTimezone === undefined) {
ignoreTimezone = true;
}
if (ignoreTimezone && typeof input == 'string') {
input = stripTimezone(input);
}
return new MightyDate(input);
}
// TODO: deprecate
function parseISO8601(input, ignoreTimezone) { // ignoreTimezone DEFAULTS TO FALSE
if (ignoreTimezone === undefined) {
ignoreTimezone = false;
}
return parseDate(input, ignoreTimezone);
}
function stripTimezone(s) {
return s.replace(/^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d+)?)(.*)$/, '$1');
}
function formatDate(date, formatString, settings) {
return new MightyDate(date).toString(formatString, settings);
}
function formatDates(date1, date2, formatString, settings) {
return new MightyDate(date1).toString(date2, formatString, settings);
}
/* Event Date Math
@ -10,24 +90,27 @@ function exclEndDay(event) {
if (event.end) {
return _exclEndDay(event.end, event.allDay);
}else{
return addDays(cloneDate(event.start), 1);
return event.start.clone().addDays(1).clearTime();
}
}
function _exclEndDay(end, allDay) {
end = cloneDate(end);
return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
end = end.clone();
if (allDay || end.getHours() || end.getMinutes()) {
end.addDays(1);
}
return end.clearTime();
}
function segCmp(a, b) {
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
return (b.msLength - a.msLength) * 100 + b.event.start.diffMilliseconds(a.event.start);
}
function segsCollide(seg1, seg2) {
return seg1.end > seg2.start && seg1.start < seg2.end;
return seg1.end.after(seg2.start) && seg1.start.before(seg2.end);
}
@ -47,16 +130,16 @@ function sliceSegs(events, visEventEnds, start, end) {
event = events[i];
eventStart = event.start;
eventEnd = visEventEnds[i];
if (eventEnd > start && eventStart < end) {
if (eventStart < start) {
segStart = cloneDate(start);
if (eventEnd.after(start) && eventStart.before(end)) {
if (eventStart.before(start)) {
segStart = start.clone();
isStart = false;
}else{
segStart = eventStart;
isStart = true;
}
if (eventEnd > end) {
segEnd = cloneDate(end);
if (eventEnd.after(end)) {
segEnd = end.clone();
isEnd = false;
}else{
segEnd = eventEnd;
@ -68,7 +151,7 @@ function sliceSegs(events, visEventEnds, start, end) {
end: segEnd,
isStart: isStart,
isEnd: isEnd,
msLength: segEnd - segStart
msLength: segStart.diffMilliseconds(segEnd)
});
}
}