From afadc63b78cb0a94eb781e77e0a09b060a6e54c5 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Sat, 19 Feb 2011 15:47:23 -0800 Subject: [PATCH] restructured HTML/CSS of event elements. solves issues 327 and 395 --- src/agenda/AgendaEventRenderer.js | 549 +++++++++++++++--------------- src/agenda/AgendaView.js | 7 +- src/basic/BasicEventRenderer.js | 88 ++--- src/common/DayEventRenderer.js | 220 +++++++----- src/common/View.js | 25 ++ src/common/common.css | 27 +- src/common/print.css | 4 +- src/main.css | 1 + tests/sources_new.html | 12 +- 9 files changed, 504 insertions(+), 429 deletions(-) diff --git a/src/agenda/AgendaEventRenderer.js b/src/agenda/AgendaEventRenderer.js index 72e233d..423d14c 100644 --- a/src/agenda/AgendaEventRenderer.js +++ b/src/agenda/AgendaEventRenderer.js @@ -15,6 +15,9 @@ function AgendaEventRenderer() { DayEventRenderer.call(t); var opt = t.opt; var trigger = t.trigger; + //var setOverflowHidden = t.setOverflowHidden; + var isEventDraggable = t.isEventDraggable; + var isEventResizable = t.isEventResizable; var eventEnd = t.eventEnd; var reportEvents = t.reportEvents; var reportEventClear = t.reportEventClear; @@ -171,13 +174,6 @@ function AgendaEventRenderer() { for (i=0; i" + - "" + - "
" + - "
" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "
" + - "
" + - "
" + - "
" + - htmlEscape(event.title) + - "
" + - "
" + - "
" + - "
" + - ((seg.isEnd && - isEventEditable(event) && - !opt('disableResizing') && // TODO: make like other source properties - $.fn.resizable) - ? - "
=
" - : - '' - ) + - ""; + var classes = ['fc-event', 'fc-event-skin', 'fc-event-vert']; + if (isEventDraggable(event)) { + classes.push('fc-event-draggable'); + } + if (seg.isStart) { + classes.push('fc-corner-top'); + } + if (seg.isEnd) { + classes.push('fc-corner-bottom'); + } + classes = classes.concat(event.className, event.source.className); + if (url) { + html += "a href='" + htmlEscape(event.url) + "'"; + }else{ + html += "div"; + } + html += + " class='" + classes.join(' ') + "'" + + " style='position:absolute;z-index:8;top:" + seg.top + "px;left:" + seg.left + "px;" + skinCss + "'" + + ">" + + "
" + + "
" + + "
" + + htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + + "
" + + "
" + + "
" + + "
" + + htmlEscape(event.title) + + "
" + + "
" + + "
" + + "
"; // close inner + if (seg.isEnd && isEventResizable(event)) { + html += + "
=
"; + } + html += + ""; + return html; } function bindDaySeg(event, eventElement, seg) { - eventElementHandlers(event, eventElement); - if (isEventEditable(event)) { + if (isEventDraggable(event)) { 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) { - eventElementHandlers(event, eventElement); - if (isEventEditable(event)) { - var timeElement = eventElement.find('span.fc-event-time'); + var timeElement = eventElement.find('span.fc-event-time'); + if (isEventDraggable(event)) { draggableSlotEvent(event, eventElement, timeElement); - if (seg.isEnd) { - resizableSlotEvent(event, eventElement, timeElement); - } } - } - - - function isEventEditable(event) { - return firstDefined(event.editable, event.source.editable, opt('editable')); + if (seg.isEnd && isEventResizable(event)) { + resizableSlotEvent(event, eventElement, timeElement); + } + eventElementHandlers(event, eventElement); } @@ -347,101 +353,98 @@ function AgendaEventRenderer() { // 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) { - if (!opt('disableDragging') && eventElement.draggable) { - var origWidth; - var revert; - var allDay=true; - var dayDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - var minMinute = getMinMinute(); - eventElement.draggable({ - zIndex: 9, - opacity: opt('dragOpacity', 'month'), // use whatever the month view was using - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origWidth = eventElement.width(); - 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(); + var origWidth; + var revert; + var allDay=true; + var dayDelta; + var dis = opt('isRTL') ? -1 : 1; + var hoverListener = getHoverListener(); + var colWidth = getColWidth(); + var slotHeight = getSlotHeight(); + var minMinute = getMinMinute(); + eventElement.draggable({ + zIndex: 9, + opacity: opt('dragOpacity', 'month'), // use whatever the month view was using + revertDuration: opt('dragRevertDuration'), + start: function(ev, ui) { + trigger('eventDragStart', eventElement, event, ev, ui); + hideEvents(event, eventElement); + origWidth = eventElement.width(); + hoverListener.start(function(cell, origCell, rowDelta, colDelta) { 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 + if (cell) { + //setOverflowHidden(true); + 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; + } } - showEvents(event, eventElement); + revert = revert || (allDay && !dayDelta); }else{ - // changed! - eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link - 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); + resetElement(); + //setOverflowHidden(false); + revert = true; } + 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); } - }); - function resetElement() { - if (!allDay) { - eventElement - .width(origWidth) - .height('') - .draggable('option', 'grid', null); - allDay = true; - } + //setOverflowHidden(false); + } + }); + function resetElement() { + if (!allDay) { + eventElement + .width(origWidth) + .height('') + .draggable('option', 'grid', null); + allDay = true; } } } @@ -450,102 +453,100 @@ function AgendaEventRenderer() { // when event starts out IN TIMESLOTS function draggableSlotEvent(event, eventElement, timeElement) { - if (!opt('disableDragging') && eventElement.draggable) { - var origPosition; - var allDay=false; - var dayDelta; - var minuteDelta; - var prevMinuteDelta; - var dis = opt('isRTL') ? -1 : 1; - var hoverListener = getHoverListener(); - var colCnt = getColCnt(); - var colWidth = getColWidth(); - var slotHeight = getSlotHeight(); - eventElement.draggable({ - zIndex: 9, - scroll: false, - grid: [colWidth, slotHeight], - axis: colCnt==1 ? 'y' : false, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - if ($.browser.msie) { - eventElement.find('div.fc-event-bg').hide(); // nested opacities mess up in IE, just hide - } - origPosition = eventElement.position(); - minuteDelta = prevMinuteDelta = 0; - hoverListener.start(function(cell, origCell, rowDelta, colDelta) { - 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(); + var origPosition; + var allDay=false; + var dayDelta; + var minuteDelta; + var prevMinuteDelta; + var dis = opt('isRTL') ? -1 : 1; + var hoverListener = getHoverListener(); + var colCnt = getColCnt(); + var colWidth = getColWidth(); + var slotHeight = getSlotHeight(); + eventElement.draggable({ + zIndex: 9, + scroll: false, + grid: [colWidth, slotHeight], + axis: colCnt==1 ? 'y' : false, + opacity: opt('dragOpacity'), + revertDuration: opt('dragRevertDuration'), + start: function(ev, ui) { + trigger('eventDragStart', eventElement, event, ev, ui); + hideEvents(event, eventElement); + if ($.browser.msie) { + eventElement.find('div.fc-event-bg').hide(); // nested opacities mess up in IE, just hide + } + origPosition = eventElement.position(); + minuteDelta = prevMinuteDelta = 0; + hoverListener.start(function(cell, origCell, rowDelta, colDelta) { + eventElement.draggable('option', 'revert', !cell); clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - 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(); + 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(); } - 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) { - var newStart = addMinutes(cloneDate(event.start), minuteDelta); - var newEnd; - if (event.end) { - newEnd = addMinutes(cloneDate(event.end), minuteDelta); + }, + stop: function(ev, ui) { + var cell = hoverListener.stop(); + clearOverlays(); + trigger('eventDragStop', eventElement, event, ev, ui); + 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 - if (allDay) { - timeElement.css('display', ''); // show() was causing display=inline - eventElement.draggable('option', 'grid', [colWidth, slotHeight]); - allDay = false; - } + }); + function updateTimeText(minuteDelta) { + var newStart = addMinutes(cloneDate(event.start), minuteDelta); + var newEnd; + if (event.end) { + 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) { - if (!opt('disableResizing') && eventElement.resizable) { - var slotDelta, prevSlotDelta; - var slotHeight = getSlotHeight(); - eventElement.resizable({ - handles: { - s: 'div.ui-resizable-s' - }, - grid: slotHeight, - start: function(ev, ui) { - slotDelta = prevSlotDelta = 0; - hideEvents(event, eventElement); - if ($.browser.msie && $.browser.version == '6.0') { - 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 - } + var slotDelta, prevSlotDelta; + var slotHeight = getSlotHeight(); + eventElement.resizable({ + handles: { + s: 'div.ui-resizable-s' + }, + grid: slotHeight, + start: function(ev, ui) { + slotDelta = prevSlotDelta = 0; + hideEvents(event, eventElement); + if ($.browser.msie && $.browser.version == '6.0') { + 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 + } + } + }); } diff --git a/src/agenda/AgendaView.js b/src/agenda/AgendaView.js index 952f060..67b2201 100644 --- a/src/agenda/AgendaView.js +++ b/src/agenda/AgendaView.js @@ -695,6 +695,8 @@ function AgendaView(element, calendar, viewName) { .appendTo(slotContent); } }else{ + rect.isStart = true; // conside rect a "seg" now + rect.isEnd = true; // selectionHelper = $(slotSegHtml( { title: '', @@ -704,11 +706,10 @@ function AgendaView(element, calendar, viewName) { editable: false, source: {} }, - rect, - ['fc-event', 'fc-event-vert', 'fc-corner-top', 'fc-corner-bottom'] + rect )); 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')); } diff --git a/src/basic/BasicEventRenderer.js b/src/basic/BasicEventRenderer.js index 555c726..e7a211b 100644 --- a/src/basic/BasicEventRenderer.js +++ b/src/basic/BasicEventRenderer.js @@ -14,6 +14,9 @@ function BasicEventRenderer() { DayEventRenderer.call(t); var opt = t.opt; var trigger = t.trigger; + //var setOverflowHidden = t.setOverflowHidden; + var isEventDraggable = t.isEventDraggable; + var isEventResizable = t.isEventResizable; var reportEvents = t.reportEvents; var reportEventClear = t.reportEventClear; var eventElementHandlers = t.eventElementHandlers; @@ -76,13 +79,14 @@ function BasicEventRenderer() { function bindDaySeg(event, eventElement, seg) { - eventElementHandlers(event, eventElement); - if (firstDefined(event.editable, event.source.editable, opt('editable'))) { + if (isEventDraggable(event)) { 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) { - if (!opt('disableDragging') && eventElement.draggable) { - var hoverListener = getHoverListener(); - var dayDelta; - eventElement.draggable({ - zIndex: 9, - delay: 50, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - hoverListener.start(function(cell, origCell, 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(); + var hoverListener = getHoverListener(); + var dayDelta; + eventElement.draggable({ + zIndex: 9, + delay: 50, + opacity: opt('dragOpacity'), + revertDuration: opt('dragRevertDuration'), + start: function(ev, ui) { + trigger('eventDragStart', eventElement, event, ev, ui); + hideEvents(event, eventElement); + hoverListener.start(function(cell, origCell, rowDelta, colDelta) { + eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta); clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (dayDelta) { - eventElement.find('a').removeAttr('href'); // prevents safari from visiting the link - eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui); + if (cell) { + //setOverflowHidden(true); + dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1); + renderDayOverlay( + addDays(cloneDate(event.start), dayDelta), + addDays(exclEndDay(event), dayDelta) + ); }else{ - if ($.browser.msie) { - eventElement.css('filter', ''); // clear IE opacity side-effects - } - showEvents(event, eventElement); + //setOverflowHidden(false); + dayDelta = 0; } + }, 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); + } + }); } diff --git a/src/common/DayEventRenderer.js b/src/common/DayEventRenderer.js index 1cfac94..15a9ce6 100644 --- a/src/common/DayEventRenderer.js +++ b/src/common/DayEventRenderer.js @@ -11,6 +11,8 @@ function DayEventRenderer() { // imports var opt = t.opt; var trigger = t.trigger; + var isEventDraggable = t.isEventDraggable; + var isEventResizable = t.isEventResizable; var eventEnd = t.eventEnd; var reportEventElement = t.reportEventElement; var showEvents = t.showEvents; @@ -119,6 +121,7 @@ function DayEventRenderer() { var segCnt=segs.length; var seg; var event; + var url; var classes; var bounds = allDayBounds(); var minLeft = bounds.left; @@ -132,7 +135,10 @@ function DayEventRenderer() { for (i=0; i" + - "" + - (!event.allDay && seg.isStart ? - "" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "" - :'') + - "" + htmlEscape(event.title) + "" + - "" + - ((seg.isEnd && - firstDefined(event.editable, event.source.editable, opt('editable')) && - !opt('disableResizing')) // TODO: make this like the other source options - ? - "
" - : - '' - ) + + " class='" + classes.join(' ') + "'" + + " style='position:absolute;z-index:8;left:"+left+"px;" + skinCss + "'" + + ">" + + ""; + if (!event.allDay && seg.isStart) { + html += + "" + + htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + + ""; + } + html += + "" + htmlEscape(event.title) + "" + ""; + if (seg.isEnd && isEventResizable(event)) { + html += + "
"; + } + html += + ""; seg.left = 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.endCol = cols[1] + 1; } @@ -368,78 +379,99 @@ function DayEventRenderer() { function resizableDayEvent(event, element, seg) { - if (!opt('disableResizing') && seg.isEnd) { - var rtl = opt('isRTL'); - var direction = rtl ? 'w' : 'e'; - var handle = element.find('div.ui-resizable-' + direction); - handle.mousedown(function(ev) { - if (ev.which != 1) { - return; // needs to be left mouse button - } - 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', '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 + var rtl = opt('isRTL'); + var direction = rtl ? 'w' : 'e'; + var handle = element.find('div.ui-resizable-' + direction); + var isResizing = false; + + // TODO: look into using jquery-ui mouse widget for this stuff + disableTextSelection(element); // prevent native selection for IE + element + .mousedown(function(ev) { // prevent native selection for others + ev.preventDefault(); + }) + .click(function(ev) { + if (isResizing) { + ev.preventDefault(); // prevent link from being visited (only method that worked in IE6) + ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called + // (eventElementHandlers needs to be bound after resizableDayEvent) } }); - } + + 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); + } + + }); } diff --git a/src/common/View.js b/src/common/View.js index b65baae..b9bb0e0 100644 --- a/src/common/View.js +++ b/src/common/View.js @@ -10,6 +10,9 @@ function View(element, calendar, viewName) { t.name = viewName; t.opt = opt; t.trigger = trigger; + //t.setOverflowHidden = setOverflowHidden; + t.isEventDraggable = isEventDraggable; + t.isEventResizable = isEventResizable; t.reportEvents = reportEvents; t.eventEnd = eventEnd; 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 ------------------------------------------------------------------------------*/ diff --git a/src/common/common.css b/src/common/common.css index 2f3cfe1..4ee1b54 100644 --- a/src/common/common.css +++ b/src/common/common.css @@ -133,34 +133,39 @@ /* 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 { border-style: solid; border-width: 0; font-size: .85em; + cursor: default; + } + +a.fc-event, +.fc-event-draggable { + cursor: pointer; + } + +a.fc-event { + text-decoration: none; } .fc-rtl .fc-event { 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 { position: relative; - display: block; /* might be an tag */ width: 100%; height: 100%; border-style: solid; border-width: 0; - text-decoration: none; - cursor: pointer; } .fc-event-time, diff --git a/src/common/print.css b/src/common/print.css index e33eeb8..9ec3ac1 100644 --- a/src/common/print.css +++ b/src/common/print.css @@ -13,9 +13,7 @@ /* Events -----------------------------------------------------*/ -.fc-event, -.fc-event-inner, -.fc-event-head { +.fc-event-skin { background: none !important; color: #000 !important; } diff --git a/src/main.css b/src/main.css index 80c11c7..f5e156d 100644 --- a/src/main.css +++ b/src/main.css @@ -110,6 +110,7 @@ html .fc, .fc-view { width: 100%; /* needed for view switching (when view is absolute) */ + overflow: hidden; } diff --git a/tests/sources_new.html b/tests/sources_new.html index efd0ba5..1ba3453 100644 --- a/tests/sources_new.html +++ b/tests/sources_new.html @@ -56,8 +56,11 @@ $(document).ready(function() { right: 'month,agendaWeek,basicWeek,agendaDay,basicDay' }, editable: true, + //disableResizing: true, + //disableDragging: true, selectable: true, selectHelper: true, + dragOpacity: .5, eventSources: [ { @@ -67,6 +70,7 @@ $(document).ready(function() { success: function(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; + } }); });