restructured HTML/CSS of event elements. solves issues 327 and 395

This commit is contained in:
Adam Shaw 2011-02-19 15:47:23 -08:00
parent a2e1de5d3d
commit afadc63b78
9 changed files with 504 additions and 429 deletions

View file

@ -15,6 +15,9 @@ function AgendaEventRenderer() {
DayEventRenderer.call(t); DayEventRenderer.call(t);
var opt = t.opt; var opt = t.opt;
var trigger = t.trigger; var trigger = t.trigger;
//var setOverflowHidden = t.setOverflowHidden;
var isEventDraggable = t.isEventDraggable;
var isEventResizable = t.isEventResizable;
var eventEnd = t.eventEnd; var eventEnd = t.eventEnd;
var reportEvents = t.reportEvents; var reportEvents = t.reportEvents;
var reportEventClear = t.reportEventClear; var reportEventClear = t.reportEventClear;
@ -171,13 +174,6 @@ function AgendaEventRenderer() {
for (i=0; i<segCnt; i++) { for (i=0; i<segCnt; i++) {
seg = segs[i]; seg = segs[i];
event = seg.event; event = seg.event;
classes = ['fc-event', 'fc-event-vert'];
if (seg.isStart) {
classes.push('fc-corner-top');
}
if (seg.isEnd) {
classes.push('fc-corner-bottom');
}
top = timePosition(seg.start, seg.start); top = timePosition(seg.start, seg.start);
bottom = timePosition(seg.start, seg.end); bottom = timePosition(seg.start, seg.end);
colI = seg.col; colI = seg.col;
@ -205,7 +201,7 @@ function AgendaEventRenderer() {
seg.left = left; seg.left = left;
seg.outerWidth = outerWidth; seg.outerWidth = outerWidth;
seg.outerHeight = bottom - top; seg.outerHeight = bottom - top;
html += slotSegHtml(event, seg, classes); html += slotSegHtml(event, seg);
} }
slotSegmentContainer[0].innerHTML = html; // faster than html() slotSegmentContainer[0].innerHTML = html; // faster than html()
eventElements = slotSegmentContainer.children(); eventElements = slotSegmentContainer.children();
@ -278,65 +274,75 @@ function AgendaEventRenderer() {
} }
function slotSegHtml(event, seg, classes) { function slotSegHtml(event, seg) {
classes = classes.concat(event.className, event.source.className); var html = "<";
var url = event.url;
var skinCss = getSkinCss(event, opt); var skinCss = getSkinCss(event, opt);
var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : ''); var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
return "<div class='" + classes.join(' ') + "' style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'>" + var classes = ['fc-event', 'fc-event-skin', 'fc-event-vert'];
"<a class='fc-event-inner'" + if (isEventDraggable(event)) {
(event.url ? " href='" + htmlEscape(event.url) + "'" : '') + // good for escaping quotes? classes.push('fc-event-draggable');
skinCssAttr + }
">" + if (seg.isStart) {
"<div class='fc-event-head'" + skinCssAttr + ">" + classes.push('fc-corner-top');
"<div class='fc-event-time'>" + }
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + if (seg.isEnd) {
"</div>" + classes.push('fc-corner-bottom');
"</div>" + }
"<div class='fc-event-content'>" + classes = classes.concat(event.className, event.source.className);
"<div class='fc-event-title'>" + if (url) {
htmlEscape(event.title) + html += "a href='" + htmlEscape(event.url) + "'";
"</div>" + }else{
"</div>" + html += "div";
"<div class='fc-event-bg'></div>" + }
"</a>" + html +=
((seg.isEnd && " class='" + classes.join(' ') + "'" +
isEventEditable(event) && " style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" +
!opt('disableResizing') && // TODO: make like other source properties ">" +
$.fn.resizable) "<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
? "<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
"<div class='ui-resizable-handle ui-resizable-s'>=</div>" "<div class='fc-event-time'>" +
: htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
'' "</div>" +
) + "</div>" +
"</div>"; "<div class='fc-event-content'>" +
"<div class='fc-event-title'>" +
htmlEscape(event.title) +
"</div>" +
"</div>" +
"<div class='fc-event-bg'></div>" +
"</div>"; // close inner
if (seg.isEnd && isEventResizable(event)) {
html +=
"<div class='ui-resizable-handle ui-resizable-s'>=</div>";
}
html +=
"</" + (url ? "a" : "div") + ">";
return html;
} }
function bindDaySeg(event, eventElement, seg) { function bindDaySeg(event, eventElement, seg) {
eventElementHandlers(event, eventElement); if (isEventDraggable(event)) {
if (isEventEditable(event)) {
draggableDayEvent(event, eventElement, seg.isStart); draggableDayEvent(event, eventElement, seg.isStart);
if (seg.isEnd) {
resizableDayEvent(event, eventElement, seg);
}
} }
if (seg.isEnd && isEventResizable(event)) {
resizableDayEvent(event, eventElement, seg);
}
eventElementHandlers(event, eventElement);
// needs to be after, because resizableDayEvent might stopImmediatePropagation on click
} }
function bindSlotSeg(event, eventElement, seg) { function bindSlotSeg(event, eventElement, seg) {
eventElementHandlers(event, eventElement); var timeElement = eventElement.find('span.fc-event-time');
if (isEventEditable(event)) { if (isEventDraggable(event)) {
var timeElement = eventElement.find('span.fc-event-time');
draggableSlotEvent(event, eventElement, timeElement); draggableSlotEvent(event, eventElement, timeElement);
if (seg.isEnd) {
resizableSlotEvent(event, eventElement, timeElement);
}
} }
} if (seg.isEnd && isEventResizable(event)) {
resizableSlotEvent(event, eventElement, timeElement);
}
function isEventEditable(event) { eventElementHandlers(event, eventElement);
return firstDefined(event.editable, event.source.editable, opt('editable'));
} }
@ -347,101 +353,98 @@ function AgendaEventRenderer() {
// when event starts out FULL-DAY // when event starts out FULL-DAY
// TODO: bug when dragging an event that occupies first day, but is not the event's start (no rounded left side)
// TODO: bug when dragging from day to slot, outer container doesn't seem to change height
function draggableDayEvent(event, eventElement, isStart) { function draggableDayEvent(event, eventElement, isStart) {
if (!opt('disableDragging') && eventElement.draggable) { var origWidth;
var origWidth; var revert;
var revert; var allDay=true;
var allDay=true; var dayDelta;
var dayDelta; var dis = opt('isRTL') ? -1 : 1;
var dis = opt('isRTL') ? -1 : 1; var hoverListener = getHoverListener();
var hoverListener = getHoverListener(); var colWidth = getColWidth();
var colWidth = getColWidth(); var slotHeight = getSlotHeight();
var slotHeight = getSlotHeight(); var minMinute = getMinMinute();
var minMinute = getMinMinute(); eventElement.draggable({
eventElement.draggable({ zIndex: 9,
zIndex: 9, opacity: opt('dragOpacity', 'month'), // use whatever the month view was using
opacity: opt('dragOpacity', 'month'), // use whatever the month view was using revertDuration: opt('dragRevertDuration'),
revertDuration: opt('dragRevertDuration'), start: function(ev, ui) {
start: function(ev, ui) { trigger('eventDragStart', eventElement, event, ev, ui);
trigger('eventDragStart', eventElement, event, ev, ui); hideEvents(event, eventElement);
hideEvents(event, eventElement); origWidth = eventElement.width();
origWidth = eventElement.width(); hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
clearOverlays();
if (cell) {
revert = false;
dayDelta = colDelta * dis;
if (!cell.row) {
// on full-days
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
);
resetElement();
}else{
// mouse is over bottom slots
if (isStart) {
if (allDay) {
// convert event to temporary slot-event
eventElement.width(colWidth - 10); // don't use entire width
setOuterHeight(
eventElement,
slotHeight * Math.round(
(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
/ opt('slotMinutes')
)
);
eventElement.draggable('option', 'grid', [colWidth, 1]);
allDay = false;
}
}else{
revert = true;
}
}
revert = revert || (allDay && !dayDelta);
}else{
revert = true;
}
eventElement.draggable('option', 'revert', revert);
}, ev, 'drag');
},
stop: function(ev, ui) {
hoverListener.stop();
clearOverlays(); clearOverlays();
trigger('eventDragStop', eventElement, event, ev, ui); if (cell) {
if (revert) { //setOverflowHidden(true);
// hasn't moved or is out of bounds (draggable has already reverted) revert = false;
resetElement(); dayDelta = colDelta * dis;
if ($.browser.msie) { if (!cell.row) {
eventElement.css('filter', ''); // clear IE opacity side-effects // on full-days
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
);
resetElement();
}else{
// mouse is over bottom slots
if (isStart) {
if (allDay) {
// convert event to temporary slot-event
eventElement.width(colWidth - 10); // don't use entire width
setOuterHeight(
eventElement,
slotHeight * Math.round(
(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
/ opt('slotMinutes')
)
);
eventElement.draggable('option', 'grid', [colWidth, 1]);
allDay = false;
}
}else{
revert = true;
}
} }
showEvents(event, eventElement); revert = revert || (allDay && !dayDelta);
}else{ }else{
// changed! resetElement();
eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link //setOverflowHidden(false);
var minuteDelta = 0; revert = true;
if (!allDay) {
minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)
* opt('slotMinutes')
+ minMinute
- (event.start.getHours() * 60 + event.start.getMinutes());
}
eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
} }
eventElement.draggable('option', 'revert', revert);
}, ev, 'drag');
},
stop: function(ev, ui) {
hoverListener.stop();
clearOverlays();
trigger('eventDragStop', eventElement, event, ev, ui);
if (revert) {
// hasn't moved or is out of bounds (draggable has already reverted)
resetElement();
if ($.browser.msie) {
eventElement.css('filter', ''); // clear IE opacity side-effects
}
showEvents(event, eventElement);
}else{
// changed!
var minuteDelta = 0;
if (!allDay) {
minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)
* opt('slotMinutes')
+ minMinute
- (event.start.getHours() * 60 + event.start.getMinutes());
}
eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
} }
}); //setOverflowHidden(false);
function resetElement() { }
if (!allDay) { });
eventElement function resetElement() {
.width(origWidth) if (!allDay) {
.height('') eventElement
.draggable('option', 'grid', null); .width(origWidth)
allDay = true; .height('')
} .draggable('option', 'grid', null);
allDay = true;
} }
} }
} }
@ -450,102 +453,100 @@ function AgendaEventRenderer() {
// when event starts out IN TIMESLOTS // when event starts out IN TIMESLOTS
function draggableSlotEvent(event, eventElement, timeElement) { function draggableSlotEvent(event, eventElement, timeElement) {
if (!opt('disableDragging') && eventElement.draggable) { var origPosition;
var origPosition; var allDay=false;
var allDay=false; var dayDelta;
var dayDelta; var minuteDelta;
var minuteDelta; var prevMinuteDelta;
var prevMinuteDelta; var dis = opt('isRTL') ? -1 : 1;
var dis = opt('isRTL') ? -1 : 1; var hoverListener = getHoverListener();
var hoverListener = getHoverListener(); var colCnt = getColCnt();
var colCnt = getColCnt(); var colWidth = getColWidth();
var colWidth = getColWidth(); var slotHeight = getSlotHeight();
var slotHeight = getSlotHeight(); eventElement.draggable({
eventElement.draggable({ zIndex: 9,
zIndex: 9, scroll: false,
scroll: false, grid: [colWidth, slotHeight],
grid: [colWidth, slotHeight], axis: colCnt==1 ? 'y' : false,
axis: colCnt==1 ? 'y' : false, opacity: opt('dragOpacity'),
opacity: opt('dragOpacity'), revertDuration: opt('dragRevertDuration'),
revertDuration: opt('dragRevertDuration'), start: function(ev, ui) {
start: function(ev, ui) { trigger('eventDragStart', eventElement, event, ev, ui);
trigger('eventDragStart', eventElement, event, ev, ui); hideEvents(event, eventElement);
hideEvents(event, eventElement); if ($.browser.msie) {
if ($.browser.msie) { eventElement.find('div.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
eventElement.find('div.fc-event-bg').hide(); // nested opacities mess up in IE, just hide }
} origPosition = eventElement.position();
origPosition = eventElement.position(); minuteDelta = prevMinuteDelta = 0;
minuteDelta = prevMinuteDelta = 0; hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
hoverListener.start(function(cell, origCell, rowDelta, colDelta) { eventElement.draggable('option', 'revert', !cell);
eventElement.draggable('option', 'revert', !cell);
clearOverlays();
if (cell) {
dayDelta = colDelta * dis;
if (opt('allDaySlot') && !cell.row) {
// over full days
if (!allDay) {
// convert to temporary all-day event
allDay = true;
timeElement.hide();
eventElement.draggable('option', 'grid', null);
}
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
);
}else{
// on slots
resetElement();
}
}
}, ev, 'drag');
},
drag: function(ev, ui) {
minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');
if (minuteDelta != prevMinuteDelta) {
if (!allDay) {
updateTimeText(minuteDelta);
}
prevMinuteDelta = minuteDelta;
}
},
stop: function(ev, ui) {
var cell = hoverListener.stop();
clearOverlays(); clearOverlays();
trigger('eventDragStop', eventElement, event, ev, ui); if (cell) {
if (cell && (dayDelta || minuteDelta || allDay)) { dayDelta = colDelta * dis;
// changed! if (opt('allDaySlot') && !cell.row) {
eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui); // over full days
}else{ if (!allDay) {
// either no change or out-of-bounds (draggable has already reverted) // convert to temporary all-day event
resetElement(); allDay = true;
eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position timeElement.hide();
updateTimeText(0); eventElement.draggable('option', 'grid', null);
if ($.browser.msie) { // TODO: dont use browser detection. base off of the presence of filter }
eventElement renderDayOverlay(
.css('filter', '') // clear IE opacity side-effects addDays(cloneDate(event.start), dayDelta),
.find('div.fc-event-bg') addDays(exclEndDay(event), dayDelta)
.show(); );
}else{
// on slots
resetElement();
} }
showEvents(event, eventElement);
} }
}, ev, 'drag');
},
drag: function(ev, ui) {
minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');
if (minuteDelta != prevMinuteDelta) {
if (!allDay) {
updateTimeText(minuteDelta);
}
prevMinuteDelta = minuteDelta;
} }
}); },
function updateTimeText(minuteDelta) { stop: function(ev, ui) {
var newStart = addMinutes(cloneDate(event.start), minuteDelta); var cell = hoverListener.stop();
var newEnd; clearOverlays();
if (event.end) { trigger('eventDragStop', eventElement, event, ev, ui);
newEnd = addMinutes(cloneDate(event.end), minuteDelta); if (cell && (dayDelta || minuteDelta || allDay)) {
// changed!
eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
}else{
// either no change or out-of-bounds (draggable has already reverted)
resetElement();
eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
updateTimeText(0);
if ($.browser.msie) { // TODO: dont use browser detection. base off of the presence of filter
eventElement
.css('filter', '') // clear IE opacity side-effects
.find('div.fc-event-bg')
.show();
}
showEvents(event, eventElement);
} }
timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
} }
function resetElement() { });
// convert back to original slot-event function updateTimeText(minuteDelta) {
if (allDay) { var newStart = addMinutes(cloneDate(event.start), minuteDelta);
timeElement.css('display', ''); // show() was causing display=inline var newEnd;
eventElement.draggable('option', 'grid', [colWidth, slotHeight]); if (event.end) {
allDay = false; newEnd = addMinutes(cloneDate(event.end), minuteDelta);
} }
timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')));
}
function resetElement() {
// convert back to original slot-event
if (allDay) {
timeElement.css('display', ''); // show() was causing display=inline
eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
allDay = false;
} }
} }
} }
@ -557,50 +558,48 @@ function AgendaEventRenderer() {
function resizableSlotEvent(event, eventElement, timeElement) { function resizableSlotEvent(event, eventElement, timeElement) {
if (!opt('disableResizing') && eventElement.resizable) { var slotDelta, prevSlotDelta;
var slotDelta, prevSlotDelta; var slotHeight = getSlotHeight();
var slotHeight = getSlotHeight(); eventElement.resizable({
eventElement.resizable({ handles: {
handles: { s: 'div.ui-resizable-s'
s: 'div.ui-resizable-s' },
}, grid: slotHeight,
grid: slotHeight, start: function(ev, ui) {
start: function(ev, ui) { slotDelta = prevSlotDelta = 0;
slotDelta = prevSlotDelta = 0; hideEvents(event, eventElement);
hideEvents(event, eventElement); if ($.browser.msie && $.browser.version == '6.0') {
if ($.browser.msie && $.browser.version == '6.0') { eventElement.css('overflow', 'hidden');
eventElement.css('overflow', 'hidden');
}
eventElement.css('z-index', 9);
trigger('eventResizeStart', this, event, ev, ui);
},
resize: function(ev, ui) {
// don't rely on ui.size.height, doesn't take grid into account
slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
if (slotDelta != prevSlotDelta) {
timeElement.text(
formatDates(
event.start,
(!slotDelta && !event.end) ? null : // no change, so don't display time range
addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
opt('timeFormat')
)
);
prevSlotDelta = slotDelta;
}
},
stop: function(ev, ui) {
trigger('eventResizeStop', this, event, ev, ui);
if (slotDelta) {
eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);
}else{
eventElement.css('z-index', 8);
showEvents(event, eventElement);
// BUG: if event was really short, need to put title back in span
}
} }
}); eventElement.css('z-index', 9);
} trigger('eventResizeStart', this, event, ev, ui);
},
resize: function(ev, ui) {
// don't rely on ui.size.height, doesn't take grid into account
slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
if (slotDelta != prevSlotDelta) {
timeElement.text(
formatDates(
event.start,
(!slotDelta && !event.end) ? null : // no change, so don't display time range
addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
opt('timeFormat')
)
);
prevSlotDelta = slotDelta;
}
},
stop: function(ev, ui) {
trigger('eventResizeStop', this, event, ev, ui);
if (slotDelta) {
eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);
}else{
eventElement.css('z-index', 8);
showEvents(event, eventElement);
// BUG: if event was really short, need to put title back in span
}
}
});
} }

View file

@ -695,6 +695,8 @@ function AgendaView(element, calendar, viewName) {
.appendTo(slotContent); .appendTo(slotContent);
} }
}else{ }else{
rect.isStart = true; // conside rect a "seg" now
rect.isEnd = true; //
selectionHelper = $(slotSegHtml( selectionHelper = $(slotSegHtml(
{ {
title: '', title: '',
@ -704,11 +706,10 @@ function AgendaView(element, calendar, viewName) {
editable: false, editable: false,
source: {} source: {}
}, },
rect, rect
['fc-event', 'fc-event-vert', 'fc-corner-top', 'fc-corner-bottom']
)); ));
if ($.browser.msie) { if ($.browser.msie) {
selectionHelper.find('span.fc-event-bg').hide(); // nested opacities mess up in IE, just hide selectionHelper.find('div.fc-event-bg').hide(); // nested opacities mess up in IE, just hide
} }
selectionHelper.css('opacity', opt('dragOpacity')); selectionHelper.css('opacity', opt('dragOpacity'));
} }

View file

@ -14,6 +14,9 @@ function BasicEventRenderer() {
DayEventRenderer.call(t); DayEventRenderer.call(t);
var opt = t.opt; var opt = t.opt;
var trigger = t.trigger; var trigger = t.trigger;
//var setOverflowHidden = t.setOverflowHidden;
var isEventDraggable = t.isEventDraggable;
var isEventResizable = t.isEventResizable;
var reportEvents = t.reportEvents; var reportEvents = t.reportEvents;
var reportEventClear = t.reportEventClear; var reportEventClear = t.reportEventClear;
var eventElementHandlers = t.eventElementHandlers; var eventElementHandlers = t.eventElementHandlers;
@ -76,13 +79,14 @@ function BasicEventRenderer() {
function bindDaySeg(event, eventElement, seg) { function bindDaySeg(event, eventElement, seg) {
eventElementHandlers(event, eventElement); if (isEventDraggable(event)) {
if (firstDefined(event.editable, event.source.editable, opt('editable'))) {
draggableDayEvent(event, eventElement); draggableDayEvent(event, eventElement);
if (seg.isEnd) {
resizableDayEvent(event, eventElement, seg);
}
} }
if (seg.isEnd && isEventResizable(event)) {
resizableDayEvent(event, eventElement, seg);
}
eventElementHandlers(event, eventElement);
// needs to be after, because resizableDayEvent might stopImmediatePropagation on click
} }
@ -92,47 +96,47 @@ function BasicEventRenderer() {
function draggableDayEvent(event, eventElement) { function draggableDayEvent(event, eventElement) {
if (!opt('disableDragging') && eventElement.draggable) { var hoverListener = getHoverListener();
var hoverListener = getHoverListener(); var dayDelta;
var dayDelta; eventElement.draggable({
eventElement.draggable({ zIndex: 9,
zIndex: 9, delay: 50,
delay: 50, opacity: opt('dragOpacity'),
opacity: opt('dragOpacity'), revertDuration: opt('dragRevertDuration'),
revertDuration: opt('dragRevertDuration'), start: function(ev, ui) {
start: function(ev, ui) { trigger('eventDragStart', eventElement, event, ev, ui);
trigger('eventDragStart', eventElement, event, ev, ui); hideEvents(event, eventElement);
hideEvents(event, eventElement); hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
hoverListener.start(function(cell, origCell, rowDelta, colDelta) { eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
clearOverlays();
if (cell) {
dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
);
}else{
dayDelta = 0;
}
}, ev, 'drag');
},
stop: function(ev, ui) {
hoverListener.stop();
clearOverlays(); clearOverlays();
trigger('eventDragStop', eventElement, event, ev, ui); if (cell) {
if (dayDelta) { //setOverflowHidden(true);
eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui); renderDayOverlay(
addDays(cloneDate(event.start), dayDelta),
addDays(exclEndDay(event), dayDelta)
);
}else{ }else{
if ($.browser.msie) { //setOverflowHidden(false);
eventElement.css('filter', ''); // clear IE opacity side-effects dayDelta = 0;
}
showEvents(event, eventElement);
} }
}, ev, 'drag');
},
stop: function(ev, ui) {
hoverListener.stop();
clearOverlays();
trigger('eventDragStop', eventElement, event, ev, ui);
if (dayDelta) {
eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);
}else{
if ($.browser.msie) {
eventElement.css('filter', ''); // clear IE opacity side-effects
}
showEvents(event, eventElement);
} }
}); //setOverflowHidden(false);
} }
});
} }

View file

@ -11,6 +11,8 @@ function DayEventRenderer() {
// imports // imports
var opt = t.opt; var opt = t.opt;
var trigger = t.trigger; var trigger = t.trigger;
var isEventDraggable = t.isEventDraggable;
var isEventResizable = t.isEventResizable;
var eventEnd = t.eventEnd; var eventEnd = t.eventEnd;
var reportEventElement = t.reportEventElement; var reportEventElement = t.reportEventElement;
var showEvents = t.showEvents; var showEvents = t.showEvents;
@ -119,6 +121,7 @@ function DayEventRenderer() {
var segCnt=segs.length; var segCnt=segs.length;
var seg; var seg;
var event; var event;
var url;
var classes; var classes;
var bounds = allDayBounds(); var bounds = allDayBounds();
var minLeft = bounds.left; var minLeft = bounds.left;
@ -132,7 +135,10 @@ function DayEventRenderer() {
for (i=0; i<segCnt; i++) { for (i=0; i<segCnt; i++) {
seg = segs[i]; seg = segs[i];
event = seg.event; event = seg.event;
classes = ['fc-event', 'fc-event-hori']; classes = ['fc-event', 'fc-event-skin', 'fc-event-hori'];
if (isEventDraggable(event)) {
classes.push('fc-event-draggable');
}
if (rtl) { if (rtl) {
if (seg.isStart) { if (seg.isStart) {
classes.push('fc-corner-right'); classes.push('fc-corner-right');
@ -157,34 +163,39 @@ function DayEventRenderer() {
right = seg.isEnd ? colContentRight(cols[1]) : maxLeft; right = seg.isEnd ? colContentRight(cols[1]) : maxLeft;
} }
classes = classes.concat(event.className, event.source.className); classes = classes.concat(event.className, event.source.className);
url = event.url;
skinCss = getSkinCss(event, opt); skinCss = getSkinCss(event, opt);
if (url) {
html += "<a href='" + htmlEscape(url) + "'";
}else{
html += "<div";
}
html += html +=
"<div class='" + classes.join(' ') + "' " + " class='" + classes.join(' ') + "'" +
"style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" + " style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" +
">" + ">" +
"<a class='fc-event-inner'" + "<div" +
(event.url ? " href='" + htmlEscape(event.url) + "'" : '') + " class='fc-event-inner fc-event-skin'" +
(skinCss ? " style='" + skinCss + "'" : '') + (skinCss ? " style='" + skinCss + "'" : '') +
">" + ">";
(!event.allDay && seg.isStart ? if (!event.allDay && seg.isStart) {
"<span class='fc-event-time'>" + html +=
htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + "<span class='fc-event-time'>" +
"</span>" htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
:'') + "</span>";
"<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" + }
"</a>" + html +=
((seg.isEnd && "<span class='fc-event-title'>" + htmlEscape(event.title) + "</span>" +
firstDefined(event.editable, event.source.editable, opt('editable')) &&
!opt('disableResizing')) // TODO: make this like the other source options
?
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>"
:
''
) +
"</div>"; "</div>";
if (seg.isEnd && isEventResizable(event)) {
html +=
"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'></div>";
}
html +=
"</" + (url ? "a" : "div" ) + ">";
seg.left = left; seg.left = left;
seg.outerWidth = right - left; seg.outerWidth = right - left;
cols.sort(cmp); cols.sort(cmp); // is this still needed now that cols are always left-to-right?
seg.startCol = cols[0]; seg.startCol = cols[0];
seg.endCol = cols[1] + 1; seg.endCol = cols[1] + 1;
} }
@ -368,78 +379,99 @@ function DayEventRenderer() {
function resizableDayEvent(event, element, seg) { function resizableDayEvent(event, element, seg) {
if (!opt('disableResizing') && seg.isEnd) { var rtl = opt('isRTL');
var rtl = opt('isRTL'); var direction = rtl ? 'w' : 'e';
var direction = rtl ? 'w' : 'e'; var handle = element.find('div.ui-resizable-' + direction);
var handle = element.find('div.ui-resizable-' + direction); var isResizing = false;
handle.mousedown(function(ev) {
if (ev.which != 1) { // TODO: look into using jquery-ui mouse widget for this stuff
return; // needs to be left mouse button disableTextSelection(element); // prevent native <a> selection for IE
} element
var hoverListener = t.getHoverListener(); .mousedown(function(ev) { // prevent native <a> selection for others
var rowCnt = getRowCnt(); ev.preventDefault();
var colCnt = getColCnt(); })
var dis = rtl ? -1 : 1; .click(function(ev) {
var dit = rtl ? colCnt : 0; if (isResizing) {
var elementTop = element.css('top'); ev.preventDefault(); // prevent link from being visited (only method that worked in IE6)
var dayDelta; ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called
var helpers; // (eventElementHandlers needs to be bound after resizableDayEvent)
var eventCopy = $.extend({}, event);
var minCell = dateCell(event.start);
clearSelection();
$('body')
.css('cursor', direction + '-resize')
.one('mouseup', mouseup);
trigger('eventResizeStart', this, event, ev);
hoverListener.start(function(cell, origCell) {
if (cell) {
var r = Math.max(minCell.row, cell.row);
var c = cell.col;
if (rowCnt == 1) {
r = 0; // hack for all-day area in agenda views
}
if (r == minCell.row) {
if (rtl) {
c = Math.min(minCell.col, c);
}else{
c = Math.max(minCell.col, c);
}
}
dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);
var newEnd = addDays(eventEnd(event), dayDelta, true);
if (dayDelta) {
eventCopy.end = newEnd;
var oldHelpers = helpers;
helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);
helpers.find('*').css('cursor', direction + '-resize');
if (oldHelpers) {
oldHelpers.remove();
}
hideEvents(event);
}else{
if (helpers) {
showEvents(event);
helpers.remove();
helpers = null;
}
}
clearOverlays();
renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
}
}, ev);
function mouseup(ev) {
trigger('eventResizeStop', this, event, ev);
$('body').css('cursor', 'auto');
hoverListener.stop();
clearOverlays();
if (dayDelta) {
eventResize(this, event, dayDelta, 0, ev);
// event redraw will clear helpers
}
// otherwise, the drag handler already restored the old events
} }
}); });
}
handle.mousedown(function(ev) {
if (ev.which != 1) {
return; // needs to be left mouse button
}
isResizing = true;
var hoverListener = t.getHoverListener();
var rowCnt = getRowCnt();
var colCnt = getColCnt();
var dis = rtl ? -1 : 1;
var dit = rtl ? colCnt : 0;
var elementTop = element.css('top');
var dayDelta;
var helpers;
var eventCopy = $.extend({}, event);
var minCell = dateCell(event.start);
clearSelection();
$('body')
.css('cursor', direction + '-resize')
.one('mouseup', mouseup);
trigger('eventResizeStart', this, event, ev);
hoverListener.start(function(cell, origCell) {
if (cell) {
var r = Math.max(minCell.row, cell.row);
var c = cell.col;
if (rowCnt == 1) {
r = 0; // hack for all-day area in agenda views
}
if (r == minCell.row) {
if (rtl) {
c = Math.min(minCell.col, c);
}else{
c = Math.max(minCell.col, c);
}
}
dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);
var newEnd = addDays(eventEnd(event), dayDelta, true);
if (dayDelta) {
eventCopy.end = newEnd;
var oldHelpers = helpers;
helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);
helpers.find('*').css('cursor', direction + '-resize');
if (oldHelpers) {
oldHelpers.remove();
}
hideEvents(event);
}else{
if (helpers) {
showEvents(event);
helpers.remove();
helpers = null;
}
}
clearOverlays();
renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
}
}, ev);
function mouseup(ev) {
trigger('eventResizeStop', this, event, ev);
$('body').css('cursor', '');
hoverListener.stop();
clearOverlays();
if (dayDelta) {
eventResize(this, event, dayDelta, 0, ev);
// event redraw will clear helpers
}
// otherwise, the drag handler already restored the old events
setTimeout(function() { // make this happen after the element's click event
isResizing = false;
},0);
}
});
} }

View file

@ -10,6 +10,9 @@ function View(element, calendar, viewName) {
t.name = viewName; t.name = viewName;
t.opt = opt; t.opt = opt;
t.trigger = trigger; t.trigger = trigger;
//t.setOverflowHidden = setOverflowHidden;
t.isEventDraggable = isEventDraggable;
t.isEventResizable = isEventResizable;
t.reportEvents = reportEvents; t.reportEvents = reportEvents;
t.eventEnd = eventEnd; t.eventEnd = eventEnd;
t.reportEventElement = reportEventElement; t.reportEventElement = reportEventElement;
@ -55,6 +58,28 @@ function View(element, calendar, viewName) {
} }
/*
function setOverflowHidden(bool) {
element.css('overflow', bool ? 'hidden' : '');
}
*/
function isEventDraggable(event) {
return isEventEditable(event) && !opt('disableDragging');
}
function isEventResizable(event) { // but also need to make sure the seg.isEnd == true
return isEventEditable(event) && !opt('disableResizing');
}
function isEventEditable(event) {
return firstDefined(event.editable, event.source.editable, opt('editable'));
}
/* Event Data /* Event Data
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/

View file

@ -134,33 +134,38 @@
/* Global Event Styles /* Global Event Styles
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
.fc-event, /* TODO: change this to a fc-event-skin class (and change print.css) */
.fc-event-inner,
.fc-event-head {
border-color: #36c; /* default BORDER color */
background-color: #36c; /* default BACKGROUND color */
color: #fff; /* default TEXT color */
}
.fc-event { .fc-event {
border-style: solid; border-style: solid;
border-width: 0; border-width: 0;
font-size: .85em; font-size: .85em;
cursor: default;
}
a.fc-event,
.fc-event-draggable {
cursor: pointer;
}
a.fc-event {
text-decoration: none;
} }
.fc-rtl .fc-event { .fc-rtl .fc-event {
text-align: right; text-align: right;
} }
.fc-event-skin {
border-color: #36c; /* default BORDER color */
background-color: #36c; /* default BACKGROUND color */
color: #fff; /* default TEXT color */
}
.fc-event-inner { .fc-event-inner {
position: relative; position: relative;
display: block; /* might be an <a> tag */
width: 100%; width: 100%;
height: 100%; height: 100%;
border-style: solid; border-style: solid;
border-width: 0; border-width: 0;
text-decoration: none;
cursor: pointer;
} }
.fc-event-time, .fc-event-time,

View file

@ -13,9 +13,7 @@
/* Events /* Events
-----------------------------------------------------*/ -----------------------------------------------------*/
.fc-event, .fc-event-skin {
.fc-event-inner,
.fc-event-head {
background: none !important; background: none !important;
color: #000 !important; color: #000 !important;
} }

View file

@ -110,6 +110,7 @@ html .fc,
.fc-view { .fc-view {
width: 100%; /* needed for view switching (when view is absolute) */ width: 100%; /* needed for view switching (when view is absolute) */
overflow: hidden;
} }

View file

@ -56,8 +56,11 @@ $(document).ready(function() {
right: 'month,agendaWeek,basicWeek,agendaDay,basicDay' right: 'month,agendaWeek,basicWeek,agendaDay,basicDay'
}, },
editable: true, editable: true,
//disableResizing: true,
//disableDragging: true,
selectable: true, selectable: true,
selectHelper: true, selectHelper: true,
dragOpacity: .5,
eventSources: [ eventSources: [
{ {
@ -67,6 +70,7 @@ $(document).ready(function() {
success: function(events) { success: function(events) {
console.log('successfully loaded gcal event data!', events); console.log('successfully loaded gcal event data!', events);
}, },
editable: true
}, },
/* /*
@ -143,7 +147,13 @@ $(document).ready(function() {
] ]
} }
] ],
eventClick: function(event) {
if (event.url) {
window.open(event.url);
}
return false;
}
}); });
}); });