|
|
@@ -26,6 +26,7 @@ function AgendaEventRenderer() {
|
|
|
var getMaxMinute = t.getMaxMinute;
|
|
|
var getMinMinute = t.getMinMinute;
|
|
|
var timePosition = t.timePosition;
|
|
|
+ var getIsCellAllDay = t.getIsCellAllDay;
|
|
|
var colContentLeft = t.colContentLeft;
|
|
|
var colContentRight = t.colContentRight;
|
|
|
var cellToDate = t.cellToDate;
|
|
|
@@ -472,80 +473,148 @@ function AgendaEventRenderer() {
|
|
|
// when event starts out IN TIMESLOTS
|
|
|
|
|
|
function draggableSlotEvent(event, eventElement, timeElement) {
|
|
|
- var origPosition;
|
|
|
- var allDay = false;
|
|
|
- var dayDelta;
|
|
|
- var minuteDelta;
|
|
|
- var prevMinuteDelta;
|
|
|
- var hoverListener = getHoverListener();
|
|
|
+ var coordinateGrid = t.getCoordinateGrid();
|
|
|
var colCnt = getColCnt();
|
|
|
var colWidth = getColWidth();
|
|
|
var snapHeight = getSnapHeight();
|
|
|
var snapMinutes = getSnapMinutes();
|
|
|
+
|
|
|
+ // states
|
|
|
+ var origPosition; // original position of the element, not the mouse
|
|
|
+ var origCell;
|
|
|
+ var isInBounds, prevIsInBounds;
|
|
|
+ var isAllDay, prevIsAllDay;
|
|
|
+ var colDelta, prevColDelta;
|
|
|
+ var dayDelta; // derived from colDelta
|
|
|
+ var minuteDelta, prevMinuteDelta;
|
|
|
+
|
|
|
eventElement.draggable({
|
|
|
zIndex: 9,
|
|
|
scroll: false,
|
|
|
- grid: [colWidth, snapHeight],
|
|
|
+ grid: [ colWidth, snapHeight ],
|
|
|
axis: colCnt==1 ? 'y' : false,
|
|
|
opacity: opt('dragOpacity'),
|
|
|
revertDuration: opt('dragRevertDuration'),
|
|
|
start: function(ev, ui) {
|
|
|
+
|
|
|
trigger('eventDragStart', eventElement, event, ev, ui);
|
|
|
hideEvents(event, eventElement);
|
|
|
+
|
|
|
+ coordinateGrid.build();
|
|
|
+
|
|
|
+ // initialize states
|
|
|
origPosition = eventElement.position();
|
|
|
+ origCell = coordinateGrid.cell(ev.pageX, ev.pageY);
|
|
|
+ isInBounds = prevIsInBounds = true;
|
|
|
+ isAllDay = prevIsAllDay = getIsCellAllDay(origCell);
|
|
|
+ colDelta = prevColDelta = 0;
|
|
|
+ dayDelta = 0;
|
|
|
minuteDelta = prevMinuteDelta = 0;
|
|
|
- hoverListener.start(function(cell, origCell) {
|
|
|
- eventElement.draggable('option', 'revert', !cell);
|
|
|
- clearOverlays();
|
|
|
- if (cell) {
|
|
|
+
|
|
|
+ },
|
|
|
+ drag: function(ev, ui) {
|
|
|
+
|
|
|
+ // NOTE: this `cell` value is only useful for determining in-bounds and all-day.
|
|
|
+ // Bad for anything else due to the discrepancy between the mouse position and the
|
|
|
+ // element position while snapping. (problem revealed in PR #55)
|
|
|
+ //
|
|
|
+ // PS- the problem exists for draggableDayEvent() when dragging an all-day event to a slot event.
|
|
|
+ // We should overhaul the dragging system and stop relying on jQuery UI.
|
|
|
+ var cell = coordinateGrid.cell(ev.pageX, ev.pageY);
|
|
|
+
|
|
|
+ // update states
|
|
|
+ isInBounds = !!cell;
|
|
|
+ if (isInBounds) {
|
|
|
+ isAllDay = getIsCellAllDay(cell);
|
|
|
+
|
|
|
+ // calculate column delta
|
|
|
+ colDelta = Math.round((ui.position.left - origPosition.left) / colWidth);
|
|
|
+ if (colDelta != prevColDelta) {
|
|
|
+ // calculate the day delta based off of the original clicked column and the column delta
|
|
|
var origDate = cellToDate(0, origCell.col);
|
|
|
- var date = cellToDate(0, cell.col);
|
|
|
+ var col = origCell.col + colDelta;
|
|
|
+ col = Math.max(0, col);
|
|
|
+ col = Math.min(colCnt-1, col);
|
|
|
+ var date = cellToDate(0, col);
|
|
|
dayDelta = dayDiff(date, origDate);
|
|
|
- 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) / snapHeight) * snapMinutes;
|
|
|
- if (minuteDelta != prevMinuteDelta) {
|
|
|
- if (!allDay) {
|
|
|
- updateTimeText(minuteDelta);
|
|
|
+
|
|
|
+ // calculate minute delta (only if over slots)
|
|
|
+ if (!isAllDay) {
|
|
|
+ minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ // any state changes?
|
|
|
+ if (
|
|
|
+ isInBounds != prevIsInBounds ||
|
|
|
+ isAllDay != prevIsAllDay ||
|
|
|
+ colDelta != prevColDelta ||
|
|
|
+ minuteDelta != prevMinuteDelta
|
|
|
+ ) {
|
|
|
+
|
|
|
+ updateUI();
|
|
|
+
|
|
|
+ // update previous states for next time
|
|
|
+ prevIsInBounds = isInBounds;
|
|
|
+ prevIsAllDay = isAllDay;
|
|
|
+ prevColDelta = colDelta;
|
|
|
prevMinuteDelta = minuteDelta;
|
|
|
}
|
|
|
+
|
|
|
+ // if out-of-bounds, revert when done, and vice versa.
|
|
|
+ eventElement.draggable('option', 'revert', !isInBounds);
|
|
|
+
|
|
|
},
|
|
|
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();
|
|
|
+
|
|
|
+ if (isInBounds && (isAllDay || dayDelta || minuteDelta)) { // changed!
|
|
|
+ eventDrop(this, event, dayDelta, isAllDay ? 0 : minuteDelta, isAllDay, ev, ui);
|
|
|
+ }
|
|
|
+ else { // either no change or out-of-bounds (draggable has already reverted)
|
|
|
+
|
|
|
+ // reset states for next time, and for updateUI()
|
|
|
+ isInBounds = true;
|
|
|
+ isAllDay = false;
|
|
|
+ colDelta = 0;
|
|
|
+ dayDelta = 0;
|
|
|
+ minuteDelta = 0;
|
|
|
+
|
|
|
+ updateUI();
|
|
|
eventElement.css('filter', ''); // clear IE opacity side-effects
|
|
|
- eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
|
|
|
- updateTimeText(0);
|
|
|
+
|
|
|
+ // sometimes fast drags make event revert to wrong position, so reset.
|
|
|
+ // also, if we dragged the element out of the area because of snapping,
|
|
|
+ // but the *mouse* is still in bounds, we need to reset the position.
|
|
|
+ eventElement.css(origPosition);
|
|
|
+
|
|
|
showEvents(event, eventElement);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
+ function updateUI() {
|
|
|
+ clearOverlays();
|
|
|
+ if (isInBounds) {
|
|
|
+ if (isAllDay) {
|
|
|
+ timeElement.hide();
|
|
|
+ eventElement.draggable('option', 'grid', null); // disable grid snapping
|
|
|
+ renderDayOverlay(
|
|
|
+ addDays(cloneDate(event.start), dayDelta),
|
|
|
+ addDays(exclEndDay(event), dayDelta)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ updateTimeText(minuteDelta);
|
|
|
+ timeElement.css('display', ''); // show() was causing display=inline
|
|
|
+ eventElement.draggable('option', 'grid', [colWidth, snapHeight]); // re-enable grid snapping
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
function updateTimeText(minuteDelta) {
|
|
|
var newStart = addMinutes(cloneDate(event.start), minuteDelta);
|
|
|
var newEnd;
|
|
|
@@ -554,14 +623,7 @@ function AgendaEventRenderer() {
|
|
|
}
|
|
|
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, snapHeight]);
|
|
|
- allDay = false;
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|