mirror of
https://github.com/wassname/fullcalendar.git
synced 2026-09-09 11:22:41 +08:00
fix bug with agenda event grid snapping, landing on wrong day (from PR#55)
This commit is contained in:
@@ -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) {
|
||||
var origDate = cellToDate(0, origCell.col);
|
||||
var date = cellToDate(0, cell.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);
|
||||
|
||||
// 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 col = origCell.col + colDelta;
|
||||
col = Math.max(0, col);
|
||||
col = Math.min(colCnt-1, col);
|
||||
var date = cellToDate(0, col);
|
||||
dayDelta = dayDiff(date, origDate);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ function AgendaView(element, calendar, viewName) {
|
||||
t.timePosition = timePosition;
|
||||
t.getIsCellAllDay = getIsCellAllDay;
|
||||
t.allDayRow = getAllDayRow;
|
||||
t.getCoordinateGrid = function() { return coordinateGrid }; // specifically for AgendaEventRenderer
|
||||
t.getHoverListener = function() { return hoverListener };
|
||||
t.colLeft = colLeft;
|
||||
t.colRight = colRight;
|
||||
|
||||
Reference in New Issue
Block a user