getting closer to 1.4
This commit is contained in:
parent
8e0312a750
commit
20208deb66
8 changed files with 870 additions and 786 deletions
802
src/agenda.js
802
src/agenda.js
File diff suppressed because it is too large
Load diff
|
@ -11,7 +11,6 @@
|
|||
|
||||
.fc .fc-axis {
|
||||
width: 50px;
|
||||
height: 1.6em;
|
||||
padding: 0 4px 0 0;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
|
@ -28,7 +27,7 @@
|
|||
}
|
||||
|
||||
.fc-agenda-head tr.fc-all-day th {
|
||||
height: 2em;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.fc-agenda tr.fc-first th,
|
||||
|
@ -47,6 +46,10 @@
|
|||
.fc .fc-agenda-body td {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.fc .fc-agenda-body td div {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -57,15 +60,34 @@
|
|||
}
|
||||
|
||||
|
||||
|
||||
.fc .fc-divider th {
|
||||
height: 3px;
|
||||
border-bottom-width: 1px;
|
||||
|
||||
.fc .fc-divider div {
|
||||
font-size: 1px; /* for IE6/7 */
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.fc .fc-divider .fc-state-default {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.fc-agenda-head tr.fc-last th {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.fc-agenda .fc-day-content {
|
||||
padding: 2px 2px 0;
|
||||
}
|
||||
|
||||
.fc-agenda-head .fc-day-content {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -205,6 +227,7 @@
|
|||
_white-space: normal;
|
||||
overflow: hidden;
|
||||
font-size: 10px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.fc-event-vert span.fc-event-title {
|
||||
|
|
|
@ -224,6 +224,7 @@ table.fc-header {
|
|||
------------------------------------------------------------------------*/
|
||||
|
||||
.fc-event,
|
||||
.fc-agenda .fc-event-time,
|
||||
.fc-event a {
|
||||
border-style: solid;
|
||||
border-color: #36c; /* default BORDER color (probably the same as background-color) */
|
||||
|
|
103
src/grid.js
103
src/grid.js
|
@ -18,7 +18,7 @@ views.month = function(element, options) {
|
|||
this.title = formatDates(
|
||||
start,
|
||||
addDays(cloneDate(this.end = addMonths(cloneDate(start), 1)), -1),
|
||||
strProp(options.titleFormat, 'month'),
|
||||
this.option('titleFormat'),
|
||||
options
|
||||
);
|
||||
addDays(this.visStart = cloneDate(start), -((start.getDay() - options.firstDay + 7) % 7));
|
||||
|
@ -28,7 +28,7 @@ views.month = function(element, options) {
|
|||
addDays(this.visEnd, (6 - rowCnt) * 7);
|
||||
rowCnt = 6;
|
||||
}
|
||||
this.renderGrid(rowCnt, 7, strProp(options.columnFormat, 'month'), true, fetchEvents);
|
||||
this.renderGrid(rowCnt, 7, this.option('columnFormat'), true, fetchEvents);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ views.basicWeek = function(element, options) {
|
|||
this.title = formatDates(
|
||||
this.start = this.visStart = addDays(cloneDate(date), -((date.getDay() - options.firstDay + 7) % 7)),
|
||||
addDays(cloneDate(this.end = this.visEnd = addDays(cloneDate(this.start), 7)), -1),
|
||||
strProp(options.titleFormat, 'week'),
|
||||
this.option('titleFormat'),
|
||||
options
|
||||
);
|
||||
this.renderGrid(1, 7, strProp(options.columnFormat, 'week'), false, fetchEvents);
|
||||
this.renderGrid(1, 7, this.option('columnFormat'), false, fetchEvents);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -56,10 +56,10 @@ views.basicDay = function(element, options) {
|
|||
if (delta) {
|
||||
addDays(date, delta);
|
||||
}
|
||||
this.title = formatDate(date, strProp(options.titleFormat, 'day'), options);
|
||||
this.title = formatDate(date, this.option('titleFormat'), options);
|
||||
this.start = this.visStart = cloneDate(date, true);
|
||||
this.end = this.visEnd = addDays(cloneDate(this.start), 1);
|
||||
this.renderGrid(1, 1, strProp(options.columnFormat, 'day'), false, fetchEvents);
|
||||
this.renderGrid(1, 1, this.option('columnFormat'), false, fetchEvents);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -326,10 +326,11 @@ function Grid(element, options, methods) {
|
|||
|
||||
|
||||
function compileSegs(events) {
|
||||
var d1 = cloneDate(view.visStart);
|
||||
var d2 = addDays(cloneDate(d1), colCnt);
|
||||
var rows = [];
|
||||
for (var i=0; i<rowCnt; i++) {
|
||||
var d1 = cloneDate(view.visStart),
|
||||
d2 = addDays(cloneDate(d1), colCnt),
|
||||
rows = [],
|
||||
i=0;
|
||||
for (; i<rowCnt; i++) {
|
||||
rows.push(stackSegs(view.sliceSegs(events, d1, d2)));
|
||||
addDays(d1, 7);
|
||||
addDays(d2, 7);
|
||||
|
@ -350,7 +351,7 @@ function Grid(element, options, methods) {
|
|||
event,
|
||||
eventClasses,
|
||||
startElm, endElm,
|
||||
left1, left2,
|
||||
left, right,
|
||||
eventElement, eventAnchor,
|
||||
triggerRes;
|
||||
for (i=0; i<len; i++) {
|
||||
|
@ -387,14 +388,14 @@ function Grid(element, options, methods) {
|
|||
}
|
||||
eventClasses.push('fc-event', 'fc-event-hori');
|
||||
startElm = seg.isStart ?
|
||||
tr.find('td:eq('+((seg.start.getDay()-firstDay+colCnt)%colCnt)+') div.fc-day-content div') :
|
||||
tr.find('td:eq('+((seg.start.getDay()-firstDay+colCnt)%colCnt)+') div div') :
|
||||
tbody;
|
||||
endElm = seg.isEnd ?
|
||||
tr.find('td:eq('+((seg.end.getDay()-firstDay+colCnt-1)%colCnt)+') div.fc-day-content div') :
|
||||
tr.find('td:eq('+((seg.end.getDay()-firstDay+colCnt-1)%colCnt)+') div div') :
|
||||
tbody;
|
||||
if (rtl) {
|
||||
left1 = endElm.position().left;
|
||||
left2 = startElm.position().left + startElm.width();
|
||||
left = endElm.position().left;
|
||||
right = startElm.position().left + startElm.width();
|
||||
if (seg.isStart) {
|
||||
eventClasses.push('fc-corner-right');
|
||||
}
|
||||
|
@ -402,8 +403,8 @@ function Grid(element, options, methods) {
|
|||
eventClasses.push('fc-corner-left');
|
||||
}
|
||||
}else{
|
||||
left1 = startElm.position().left;
|
||||
left2 = endElm.position().left + endElm.width();
|
||||
left = startElm.position().left;
|
||||
right = endElm.position().left + endElm.width();
|
||||
if (seg.isStart) {
|
||||
eventClasses.push('fc-corner-left');
|
||||
}
|
||||
|
@ -415,7 +416,7 @@ function Grid(element, options, methods) {
|
|||
.append(eventAnchor = $("<a/>")
|
||||
.append(event.allDay || !seg.isStart ? null :
|
||||
$("<span class='fc-event-time'/>")
|
||||
.html(formatDates(event.start, event.end, options.timeFormat, options)))
|
||||
.html(formatDates(event.start, event.end, view.option('timeFormat'), options)))
|
||||
.append($("<span class='fc-event-title'/>")
|
||||
.text(event.title)));
|
||||
if (event.url) {
|
||||
|
@ -430,23 +431,23 @@ function Grid(element, options, methods) {
|
|||
.css({
|
||||
position: 'absolute',
|
||||
top: top,
|
||||
left: left1 + (rtlLeftDiff||0),
|
||||
zIndex: 2
|
||||
left: left + (rtlLeftDiff||0),
|
||||
zIndex: 8
|
||||
})
|
||||
.appendTo(element);
|
||||
setOuterWidth(eventElement, left2-left1, true);
|
||||
setOuterWidth(eventElement, right-left, true);
|
||||
if (rtl && rtlLeftDiff == undefined) {
|
||||
// bug in IE6 where offsets are miscalculated with direction:rtl
|
||||
rtlLeftDiff = left1 - eventElement.position().left;
|
||||
rtlLeftDiff = left - eventElement.position().left;
|
||||
if (rtlLeftDiff) {
|
||||
eventElement.css('left', left1 + rtlLeftDiff);
|
||||
eventElement.css('left', left + rtlLeftDiff);
|
||||
}
|
||||
}
|
||||
eventElementHandlers(event, eventElement);
|
||||
if (event.editable || event.editable == undefined && options.editable) {
|
||||
draggableEvent(event, eventElement);
|
||||
if (seg.isEnd) {
|
||||
resizableEvent(event, eventElement);
|
||||
view.resizableDayEvent(event, eventElement, colWidth);
|
||||
}
|
||||
}
|
||||
view.reportEventElement(event, eventElement);
|
||||
|
@ -479,7 +480,7 @@ function Grid(element, options, methods) {
|
|||
|
||||
|
||||
|
||||
/* Draggable
|
||||
/* Event Dragging
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
@ -487,9 +488,9 @@ function Grid(element, options, methods) {
|
|||
if (!options.disableDragging && eventElement.draggable) {
|
||||
var matrix;
|
||||
eventElement.draggable({
|
||||
zIndex: 3,
|
||||
zIndex: 9,
|
||||
delay: 50,
|
||||
opacity: options.dragOpacity,
|
||||
opacity: view.option('dragOpacity'),
|
||||
revertDuration: options.dragRevertDuration,
|
||||
start: function(ev, ui) {
|
||||
matrix = new HoverMatrix(function(cell) {
|
||||
|
@ -518,20 +519,17 @@ function Grid(element, options, methods) {
|
|||
matrix.mouse(ev.pageX, ev.pageY);
|
||||
},
|
||||
stop: function(ev, ui) {
|
||||
if ($.browser.msie) {
|
||||
eventElement.css('filter', ''); // clear IE opacity side-effects
|
||||
}
|
||||
view.hideOverlay();
|
||||
view.trigger('eventDragStop', eventElement, event, ev, ui);
|
||||
var cell = matrix.cell;
|
||||
if (!cell || !cell.rowDelta && !cell.colDelta) {
|
||||
view.showEvents(event, eventElement);
|
||||
}else{
|
||||
var dayDelta = cell.rowDelta*7 + cell.colDelta*dis;
|
||||
view.moveEvent(event, dayDelta);
|
||||
view.trigger('eventDrop', this, event, dayDelta, 0, function() {
|
||||
view.moveEvent(event, -dayDelta);
|
||||
rerenderEvents();
|
||||
}, ev, ui);
|
||||
eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link
|
||||
rerenderEvents();
|
||||
view.eventDrop(this, event, cell.rowDelta*7+cell.colDelta*dis, 0, event.allDay, ev, ui);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -539,42 +537,7 @@ function Grid(element, options, methods) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/* Resizable
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
function resizableEvent(event, eventElement) {
|
||||
if (!options.disableResizing && eventElement.resizable) {
|
||||
eventElement.resizable({
|
||||
handles: rtl ? 'w' : 'e',
|
||||
grid: colWidth,
|
||||
minWidth: colWidth/2, // need this or else IE throws errors when too small
|
||||
containment: element,
|
||||
start: function(ev, ui) {
|
||||
eventElement.css('z-index', 3);
|
||||
view.hideEvents(event, eventElement);
|
||||
view.trigger('eventResizeStart', this, event, ev, ui);
|
||||
},
|
||||
stop: function(ev, ui) {
|
||||
view.trigger('eventResizeStop', this, event, ev, ui);
|
||||
// ui.size.width wasn't working with grid correctly, use .width()
|
||||
var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
|
||||
if (dayDelta) {
|
||||
view.resizeEvent(event, dayDelta);
|
||||
view.trigger('eventResize', this, event, dayDelta, 0, function() {
|
||||
view.resizeEvent(event, -dayDelta);
|
||||
rerenderEvents();
|
||||
}, ev, ui);
|
||||
rerenderEvents();
|
||||
}else{
|
||||
view.showEvents(event, eventElement);
|
||||
}
|
||||
eventElement.css('z-index', 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// event resizing w/ 'view' methods...
|
||||
|
||||
};
|
||||
|
||||
|
|
64
src/main.js
64
src/main.js
|
@ -30,7 +30,6 @@ var defaults = {
|
|||
cacheParam: '_',
|
||||
|
||||
// time formats
|
||||
timeFormat: 'h(:mm)t', // for events
|
||||
titleFormat: {
|
||||
month: 'MMMM yyyy',
|
||||
week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}",
|
||||
|
@ -41,6 +40,9 @@ var defaults = {
|
|||
week: 'ddd M/d',
|
||||
day: 'dddd M/d'
|
||||
},
|
||||
timeFormat: { // for event elements
|
||||
'': 'h(:mm)t' // default
|
||||
},
|
||||
|
||||
// locale
|
||||
isRTL: false,
|
||||
|
@ -166,7 +168,7 @@ $.fn.fullCalendar = function(options) {
|
|||
|
||||
function changeView(v) {
|
||||
if (v != viewName) {
|
||||
lockContentSize();
|
||||
fixContentSize();
|
||||
if (view) {
|
||||
if (view.eventsChanged) {
|
||||
eventsDirtyExcept(view);
|
||||
|
@ -188,14 +190,14 @@ $.fn.fullCalendar = function(options) {
|
|||
}
|
||||
view.name = viewName = v;
|
||||
render();
|
||||
unlockContentSize();
|
||||
unfixContentSize();
|
||||
}
|
||||
}
|
||||
|
||||
function render(inc) {
|
||||
if (_element.offsetWidth !== 0) { // visible on the screen
|
||||
if (inc || !view.date || +view.date != +date) { // !view.date means it hasn't been rendered yet
|
||||
ignoreWindowResizes = true;
|
||||
fixContentSize();
|
||||
view.render(date, inc || 0, function(callback) {
|
||||
// dont refetch if new view contains the same events (or a subset)
|
||||
if (!eventStart || view.visStart < eventStart || view.visEnd > eventEnd) {
|
||||
|
@ -204,7 +206,7 @@ $.fn.fullCalendar = function(options) {
|
|||
callback(events); // no refetching
|
||||
}
|
||||
});
|
||||
ignoreWindowResizes = false;
|
||||
unfixContentSize();
|
||||
view.date = cloneDate(date);
|
||||
if (header) {
|
||||
// enable/disable 'today' button
|
||||
|
@ -620,35 +622,47 @@ $.fn.fullCalendar = function(options) {
|
|||
/* Resizing
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
function lockContentSize() {
|
||||
content.css({
|
||||
overflow: 'hidden',
|
||||
height: Math.round(content.width() / options.aspectRatio)
|
||||
});
|
||||
}
|
||||
|
||||
function unlockContentSize() {
|
||||
content.css({
|
||||
overflow: '',
|
||||
height: ($.browser.msie && $.browser.version == '6.0') ? 1 : ''
|
||||
});
|
||||
}
|
||||
|
||||
var elementWidth,
|
||||
ignoreWindowResizes = false,
|
||||
contentSizeFixed = false,
|
||||
resizeCnt = 0;
|
||||
|
||||
function fixContentSize() {
|
||||
if (!contentSizeFixed) {
|
||||
contentSizeFixed = true;
|
||||
content.css({
|
||||
overflow: 'hidden',
|
||||
height: Math.round(content.width() / options.aspectRatio)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function unfixContentSize() {
|
||||
if (contentSizeFixed) {
|
||||
content.css({
|
||||
overflow: 'visible',
|
||||
height: ''
|
||||
});
|
||||
if ($.browser.msie && ($.browser.version=='6.0' || $.browser.version=='7.0')) {
|
||||
// in IE6/7 the inside of the content div was invisible
|
||||
// bizarre hack to get this work... need both lines
|
||||
content[0].clientHeight;
|
||||
content.hide().show();
|
||||
}
|
||||
contentSizeFixed = false;
|
||||
}
|
||||
}
|
||||
|
||||
$(window).resize(function() {
|
||||
if (!ignoreWindowResizes && view.date) { // view.date means the view has been rendered
|
||||
if (!contentSizeFixed && view.date) { // view.date means the view has been rendered
|
||||
var rcnt = ++resizeCnt; // add a delay
|
||||
setTimeout(function() {
|
||||
if (rcnt == resizeCnt && !ignoreWindowResizes) {
|
||||
if (rcnt == resizeCnt && !contentSizeFixed) {
|
||||
var newWidth = element.width();
|
||||
if (newWidth != elementWidth) {
|
||||
elementWidth = newWidth;
|
||||
lockContentSize();
|
||||
fixContentSize();
|
||||
view.updateSize();
|
||||
unlockContentSize();
|
||||
unfixContentSize();
|
||||
view.rerenderEvents(true);
|
||||
sizesDirtyExcept(view);
|
||||
view.trigger('windowResize', _element);
|
||||
|
@ -686,7 +700,7 @@ function normalizeEvent(event, options) {
|
|||
}
|
||||
event._start = cloneDate(event.start = parseDate(event.start));
|
||||
event.end = parseDate(event.end);
|
||||
if (event.end && event.end < event.start) {
|
||||
if (event.end && event.end <= event.start) {
|
||||
event.end = null;
|
||||
}
|
||||
event._end = event.end ? cloneDate(event.end) : null;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
-----------------------------------------------------------------------------*/
|
||||
|
||||
var DAY_MS = 86400000,
|
||||
HOUR_MS = 3600000;
|
||||
HOUR_MS = 3600000,
|
||||
MINUTE_MS = 60000;
|
||||
|
||||
function addYears(d, n, keepTime) {
|
||||
d.setFullYear(d.getFullYear() + n);
|
||||
|
@ -340,7 +341,3 @@ function zeroPad(n) {
|
|||
return (n < 10 ? '0' : '') + n;
|
||||
}
|
||||
|
||||
function strProp(s, prop) {
|
||||
return typeof s == 'string' ? s : s[prop];
|
||||
}
|
||||
|
||||
|
|
610
src/view.js
610
src/view.js
|
@ -1,264 +1,346 @@
|
|||
|
||||
/* Methods & Utilities for All Views
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
var viewMethods = {
|
||||
|
||||
/*
|
||||
* Objects inheriting these methods must implement the following properties/methods:
|
||||
* - title
|
||||
* - start
|
||||
* - end
|
||||
* - visStart
|
||||
* - visEnd
|
||||
* - defaultEventEnd(event)
|
||||
* - visEventEnd(event)
|
||||
* - render(events)
|
||||
* - rerenderEvents()
|
||||
*
|
||||
*
|
||||
* z-index reservations:
|
||||
* 1. day-overlay
|
||||
* 2. events
|
||||
* 3. dragging/resizing events
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
init: function(element, options) {
|
||||
this.element = element;
|
||||
this.options = options;
|
||||
this.cachedEvents = [];
|
||||
this.eventsByID = {};
|
||||
this.eventElements = [];
|
||||
this.eventElementsByID = {};
|
||||
},
|
||||
|
||||
|
||||
|
||||
// triggers an event handler, always append view as last arg
|
||||
|
||||
trigger: function(name, thisObj) {
|
||||
if (this.options[name]) {
|
||||
return this.options[name].apply(thisObj || this, Array.prototype.slice.call(arguments, 2).concat([this]));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// returns a Date object for an event's end
|
||||
|
||||
eventEnd: function(event) {
|
||||
return event.end || this.defaultEventEnd(event);
|
||||
},
|
||||
|
||||
|
||||
|
||||
// report when view receives new events
|
||||
|
||||
reportEvents: function(events) { // events are already normalized at this point
|
||||
var i, len=events.length, event,
|
||||
eventsByID = this.eventsByID = {},
|
||||
cachedEvents = this.cachedEvents = [];
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
if (eventsByID[event._id]) {
|
||||
eventsByID[event._id].push(event);
|
||||
}else{
|
||||
eventsByID[event._id] = [event];
|
||||
}
|
||||
cachedEvents.push(event);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// report when view creates an element for an event
|
||||
|
||||
reportEventElement: function(event, element) {
|
||||
this.eventElements.push(element);
|
||||
var eventElementsByID = this.eventElementsByID;
|
||||
if (eventElementsByID[event._id]) {
|
||||
eventElementsByID[event._id].push(element);
|
||||
}else{
|
||||
eventElementsByID[event._id] = [element];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event element manipulation
|
||||
|
||||
clearEvents: function() { // only remove ELEMENTS
|
||||
$.each(this.eventElements, function() {
|
||||
this.remove();
|
||||
});
|
||||
this.eventElements = [];
|
||||
this.eventElementsByID = {};
|
||||
},
|
||||
|
||||
showEvents: function(event, exceptElement) {
|
||||
this._eee(event, exceptElement, 'show');
|
||||
},
|
||||
|
||||
hideEvents: function(event, exceptElement) {
|
||||
this._eee(event, exceptElement, 'hide');
|
||||
},
|
||||
|
||||
_eee: function(event, exceptElement, funcName) { // event-element-each
|
||||
var elements = this.eventElementsByID[event._id],
|
||||
i, len = elements.length;
|
||||
for (i=0; i<len; i++) {
|
||||
if (elements[i] != exceptElement) {
|
||||
elements[i][funcName]();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event modification reporting
|
||||
|
||||
moveEvent: function(event, days, minutes) { // actually DO the date changes
|
||||
minutes = minutes || 0;
|
||||
var events = this.eventsByID[event._id],
|
||||
i, len=events.length, e;
|
||||
for (i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
e.allDay = event.allDay;
|
||||
addMinutes(addDays(e.start, days, true), minutes);
|
||||
if (e.end) {
|
||||
e.end = addMinutes(addDays(e.end, days, true), minutes);
|
||||
}
|
||||
normalizeEvent(e, this.options);
|
||||
}
|
||||
this.eventsChanged = true;
|
||||
},
|
||||
|
||||
resizeEvent: function(event, days, minutes) { // actually DO the date changes
|
||||
minutes = minutes || 0;
|
||||
var events = this.eventsByID[event._id],
|
||||
i, len=events.length, e;
|
||||
for (i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
e.end = addMinutes(addDays(this.eventEnd(e), days, true), minutes);
|
||||
normalizeEvent(e, this.options);
|
||||
}
|
||||
this.eventsChanged = true;
|
||||
},
|
||||
|
||||
|
||||
|
||||
// semi-transparent overlay (while dragging)
|
||||
|
||||
showOverlay: function(props) {
|
||||
if (!this.dayOverlay) {
|
||||
this.dayOverlay = $("<div class='fc-cell-overlay' style='position:absolute;z-index:1;display:none'/>")
|
||||
.appendTo(this.element);
|
||||
}
|
||||
var o = this.element.offset();
|
||||
this.dayOverlay
|
||||
.css({
|
||||
top: props.top - o.top,
|
||||
left: props.left - o.left,
|
||||
width: props.width,
|
||||
height: props.height
|
||||
})
|
||||
.show();
|
||||
},
|
||||
|
||||
hideOverlay: function() {
|
||||
if (this.dayOverlay) {
|
||||
this.dayOverlay.hide();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event rendering utilities
|
||||
|
||||
sliceSegs: function(events, start, end) {
|
||||
var segs = [],
|
||||
i, len=events.length, event,
|
||||
eventStart, eventEnd,
|
||||
segStart, segEnd,
|
||||
isStart, isEnd;
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
eventStart = event.start;
|
||||
eventEnd = this.visEventEnd(event);
|
||||
if (eventEnd > start && eventStart < end) {
|
||||
if (eventStart < start) {
|
||||
segStart = cloneDate(start);
|
||||
isStart = false;
|
||||
}else{
|
||||
segStart = eventStart;
|
||||
isStart = true;
|
||||
}
|
||||
if (eventEnd > end) {
|
||||
segEnd = cloneDate(end);
|
||||
isEnd = false;
|
||||
}else{
|
||||
segEnd = eventEnd;
|
||||
isEnd = true;
|
||||
}
|
||||
segs.push({
|
||||
event: event,
|
||||
start: segStart,
|
||||
end: segEnd,
|
||||
isStart: isStart,
|
||||
isEnd: isEnd,
|
||||
msLength: segEnd - segStart
|
||||
});
|
||||
}
|
||||
}
|
||||
return segs.sort(segCmp);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// more event rendering utilities
|
||||
|
||||
function stackSegs(segs) {
|
||||
var levels = [],
|
||||
i, len = segs.length, seg,
|
||||
j, collide, k;
|
||||
for (i=0; i<len; i++) {
|
||||
seg = segs[i];
|
||||
j = 0; // the level index where seg should belong
|
||||
while (true) {
|
||||
collide = false;
|
||||
if (levels[j]) {
|
||||
for (k=0; k<levels[j].length; k++) {
|
||||
if (segsCollide(levels[j][k], seg)) {
|
||||
collide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collide) {
|
||||
j++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (levels[j]) {
|
||||
levels[j].push(seg);
|
||||
}else{
|
||||
levels[j] = [seg];
|
||||
}
|
||||
//seg.after = 0;
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
function segCmp(a, b) {
|
||||
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
|
||||
}
|
||||
|
||||
function segsCollide(seg1, seg2) {
|
||||
return seg1.end > seg2.start && seg1.start < seg2.end;
|
||||
}
|
||||
|
||||
|
||||
/* Methods & Utilities for All Views
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
var viewMethods = {
|
||||
|
||||
// TODO: maybe change the 'vis' variables to 'excl'
|
||||
|
||||
/*
|
||||
* Objects inheriting these methods must implement the following properties/methods:
|
||||
* - title
|
||||
* - start
|
||||
* - end
|
||||
* - visStart
|
||||
* - visEnd
|
||||
* - defaultEventEnd(event)
|
||||
* - visEventEnd(event)
|
||||
* - render(events)
|
||||
* - rerenderEvents()
|
||||
*
|
||||
*
|
||||
* z-index reservations:
|
||||
* 3 - day-overlay
|
||||
* 8 - events
|
||||
* 9 - dragging/resizing events
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
init: function(element, options) {
|
||||
this.element = element;
|
||||
this.options = options;
|
||||
this.cachedEvents = [];
|
||||
this.eventsByID = {};
|
||||
this.eventElements = [];
|
||||
this.eventElementsByID = {};
|
||||
},
|
||||
|
||||
|
||||
|
||||
// triggers an event handler, always append view as last arg
|
||||
|
||||
trigger: function(name, thisObj) {
|
||||
if (this.options[name]) {
|
||||
return this.options[name].apply(thisObj || this, Array.prototype.slice.call(arguments, 2).concat([this]));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// returns a Date object for an event's end
|
||||
|
||||
eventEnd: function(event) {
|
||||
return event.end ? cloneDate(event.end) : this.defaultEventEnd(event); // TODO: make sure always using copies
|
||||
},
|
||||
|
||||
|
||||
|
||||
// report when view receives new events
|
||||
|
||||
reportEvents: function(events) { // events are already normalized at this point
|
||||
var i, len=events.length, event,
|
||||
eventsByID = this.eventsByID = {},
|
||||
cachedEvents = this.cachedEvents = [];
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
if (eventsByID[event._id]) {
|
||||
eventsByID[event._id].push(event);
|
||||
}else{
|
||||
eventsByID[event._id] = [event];
|
||||
}
|
||||
cachedEvents.push(event);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// report when view creates an element for an event
|
||||
|
||||
reportEventElement: function(event, element) {
|
||||
this.eventElements.push(element);
|
||||
var eventElementsByID = this.eventElementsByID;
|
||||
if (eventElementsByID[event._id]) {
|
||||
eventElementsByID[event._id].push(element);
|
||||
}else{
|
||||
eventElementsByID[event._id] = [element];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event element manipulation
|
||||
|
||||
clearEvents: function() { // only remove ELEMENTS
|
||||
$.each(this.eventElements, function() {
|
||||
this.remove();
|
||||
});
|
||||
this.eventElements = [];
|
||||
this.eventElementsByID = {};
|
||||
},
|
||||
|
||||
showEvents: function(event, exceptElement) {
|
||||
this._eee(event, exceptElement, 'show');
|
||||
},
|
||||
|
||||
hideEvents: function(event, exceptElement) {
|
||||
this._eee(event, exceptElement, 'hide');
|
||||
},
|
||||
|
||||
_eee: function(event, exceptElement, funcName) { // event-element-each
|
||||
var elements = this.eventElementsByID[event._id],
|
||||
i, len = elements.length;
|
||||
for (i=0; i<len; i++) {
|
||||
if (elements[i] != exceptElement) {
|
||||
elements[i][funcName]();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event modification reporting
|
||||
|
||||
eventDrop: function(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
|
||||
var view = this,
|
||||
oldAllDay = event.allDay;
|
||||
view.moveEvents(view.eventsByID[event._id], dayDelta, minuteDelta, allDay);
|
||||
view.trigger('eventDrop', e, event, dayDelta, minuteDelta, allDay, function() { // TODO: change docs
|
||||
// TODO: investigate cases where this inverse technique might not work
|
||||
view.moveEvents(view.eventsByID[event._id], -dayDelta, -minuteDelta, oldAllDay);
|
||||
view.rerenderEvents();
|
||||
}, ev, ui);
|
||||
view.eventsChanged = true;
|
||||
view.rerenderEvents();
|
||||
},
|
||||
|
||||
eventResize: function(e, event, dayDelta, minuteDelta, ev, ui) {
|
||||
var view = this;
|
||||
view.elongateEvents(view.eventsByID[event._id], dayDelta, minuteDelta);
|
||||
view.trigger('eventResize', e, event, dayDelta, minuteDelta, function() {
|
||||
// TODO: investigate cases where this inverse technique might not work
|
||||
view.elongateEvents(view.eventsByID[event._id], -dayDelta, -minuteDelta);
|
||||
view.rerenderEvents();
|
||||
}, ev, ui);
|
||||
view.eventsChanged = true;
|
||||
view.rerenderEvents();
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event modification
|
||||
|
||||
moveEvents: function(events, dayDelta, minuteDelta, allDay) {
|
||||
minuteDelta = minuteDelta || 0;
|
||||
for (var e, len=events.length, i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
if (allDay != undefined) {
|
||||
e.allDay = allDay;
|
||||
}
|
||||
addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
|
||||
if (e.end) {
|
||||
e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
|
||||
}
|
||||
normalizeEvent(e, this.options);
|
||||
}
|
||||
},
|
||||
|
||||
elongateEvents: function(events, dayDelta, minuteDelta) {
|
||||
minuteDelta = minuteDelta || 0;
|
||||
for (var e, len=events.length, i=0; i<len; i++) {
|
||||
e = events[i];
|
||||
e.end = addMinutes(addDays(this.eventEnd(e), dayDelta, true), minuteDelta);
|
||||
normalizeEvent(e, this.options);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// semi-transparent overlay (while dragging)
|
||||
|
||||
showOverlay: function(props) {
|
||||
if (!this.dayOverlay) {
|
||||
this.dayOverlay = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3;display:none'/>")
|
||||
.appendTo(this.element);
|
||||
}
|
||||
var o = this.element.offset();
|
||||
this.dayOverlay
|
||||
.css({
|
||||
top: props.top - o.top,
|
||||
left: props.left - o.left,
|
||||
width: props.width,
|
||||
height: props.height
|
||||
})
|
||||
.show();
|
||||
},
|
||||
|
||||
hideOverlay: function() {
|
||||
if (this.dayOverlay) {
|
||||
this.dayOverlay.hide();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// common horizontal event resizing
|
||||
|
||||
resizableDayEvent: function(event, eventElement, colWidth) {
|
||||
var view = this;
|
||||
if (!view.options.disableResizing && eventElement.resizable) {
|
||||
eventElement.resizable({
|
||||
handles: view.options.isRTL ? 'w' : 'e',
|
||||
grid: colWidth,
|
||||
minWidth: colWidth/2, // need this or else IE throws errors when too small
|
||||
containment: view.element,
|
||||
start: function(ev, ui) {
|
||||
eventElement.css('z-index', 9);
|
||||
view.hideEvents(event, eventElement);
|
||||
view.trigger('eventResizeStart', this, event, ev, ui);
|
||||
},
|
||||
stop: function(ev, ui) {
|
||||
view.trigger('eventResizeStop', this, event, ev, ui);
|
||||
// ui.size.width wasn't working with grid correctly, use .width()
|
||||
var dayDelta = Math.round((eventElement.width() - ui.originalSize.width) / colWidth);
|
||||
if (dayDelta) {
|
||||
view.eventResize(this, event, dayDelta, 0, ev, ui);
|
||||
}else{
|
||||
eventElement.css('z-index', 8);
|
||||
view.showEvents(event, eventElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// get a property from the 'options' object, using smart view naming
|
||||
|
||||
option: function(name) {
|
||||
var v = this.options[name];
|
||||
if (typeof v == 'object') {
|
||||
var parts = this.name.split(/(?=[A-Z])/),
|
||||
i=parts.length-1, res;
|
||||
for (; i>=0; i--) {
|
||||
res = v[parts[i].toLowerCase()];
|
||||
if (res != undefined) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return v[''];
|
||||
}
|
||||
return v;
|
||||
},
|
||||
|
||||
|
||||
|
||||
// event rendering utilities
|
||||
|
||||
sliceSegs: function(events, start, end) {
|
||||
var segs = [],
|
||||
i, len=events.length, event,
|
||||
eventStart, eventEnd,
|
||||
segStart, segEnd,
|
||||
isStart, isEnd;
|
||||
for (i=0; i<len; i++) {
|
||||
event = events[i];
|
||||
eventStart = event.start;
|
||||
eventEnd = this.visEventEnd(event);
|
||||
if (eventEnd > start && eventStart < end) {
|
||||
if (eventStart < start) {
|
||||
segStart = cloneDate(start);
|
||||
isStart = false;
|
||||
}else{
|
||||
segStart = eventStart;
|
||||
isStart = true;
|
||||
}
|
||||
if (eventEnd > end) {
|
||||
segEnd = cloneDate(end);
|
||||
isEnd = false;
|
||||
}else{
|
||||
segEnd = eventEnd;
|
||||
isEnd = true;
|
||||
}
|
||||
segs.push({
|
||||
event: event,
|
||||
start: segStart,
|
||||
end: segEnd,
|
||||
isStart: isStart,
|
||||
isEnd: isEnd,
|
||||
msLength: segEnd - segStart
|
||||
});
|
||||
}
|
||||
}
|
||||
return segs.sort(segCmp);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// event rendering calculation utilities
|
||||
|
||||
function stackSegs(segs) {
|
||||
var levels = [],
|
||||
i, len = segs.length, seg,
|
||||
j, collide, k;
|
||||
for (i=0; i<len; i++) {
|
||||
seg = segs[i];
|
||||
j = 0; // the level index where seg should belong
|
||||
while (true) {
|
||||
collide = false;
|
||||
if (levels[j]) {
|
||||
for (k=0; k<levels[j].length; k++) {
|
||||
if (segsCollide(levels[j][k], seg)) {
|
||||
collide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (collide) {
|
||||
j++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (levels[j]) {
|
||||
levels[j].push(seg);
|
||||
}else{
|
||||
levels[j] = [seg];
|
||||
}
|
||||
//seg.after = 0;
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
function segCmp(a, b) {
|
||||
return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
|
||||
}
|
||||
|
||||
function segsCollide(seg1, seg2) {
|
||||
return seg1.end > seg2.start && seg1.start < seg2.end;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,14 @@
|
|||
var m = d.getMonth();
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
slotMinutes: 30,
|
||||
//allDayHeader: false,
|
||||
//weekMode: 'variable',
|
||||
theme: true,
|
||||
//theme: true,
|
||||
//firstDay: 1,
|
||||
//isRTL: true,
|
||||
editable: true,
|
||||
//dragOpacity: .5,
|
||||
defaultView: 'agendaWeek',
|
||||
header: {
|
||||
left: 'prev,next today',
|
||||
|
@ -27,20 +31,26 @@
|
|||
id: 1,
|
||||
title: "Long Event",
|
||||
start: new Date(y, m, 6, 14, 0),
|
||||
end: new Date(y, m, 11),
|
||||
end: new Date(y, m, 11)
|
||||
//allDay: false
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Repeating Event111",
|
||||
start: new Date(y, m, 8),
|
||||
allDay: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Repeating Event222",
|
||||
start: new Date(y, m, 9, 5, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Repeating Event",
|
||||
start: new Date(y, m, 2),
|
||||
allDay: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Repeating Event",
|
||||
start: new Date(y, m, 9),
|
||||
allDay: true
|
||||
id: 345,
|
||||
title: "Hey Hey",
|
||||
start: new Date(y, m, 9, 4, 0),
|
||||
allDay: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
|
|
Loading…
Reference in a new issue