tui-calendar
Version:
TOAST UI Calendar
375 lines (322 loc) • 12.5 kB
JavaScript
/**
* @fileoverview Handling move schedules from drag handler and time grid view
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
'use strict';
var util = require('tui-code-snippet');
var config = require('../../config');
var datetime = require('../../common/datetime');
var domutil = require('../../common/domutil');
var domevent = require('../../common/domevent');
var TZDate = require('../../common/timezone').Date;
var timeCore = require('./core');
var TimeMoveGuide = require('./moveGuide');
/**
* @constructor
* @implements {Handler}
* @mixes timeCore
* @mixes util.CustomEvents
* @param {Drag} [dragHandler] - Drag handler instance.
* @param {TimeGrid} [timeGridView] - TimeGrid view instance.
* @param {Base} [baseController] - Base controller instance.
*/
function TimeMove(dragHandler, timeGridView, baseController) {
/**
* @type {Drag}
*/
this.dragHandler = dragHandler;
/**
* @type {TimeGrid}
*/
this.timeGridView = timeGridView;
/**
* @type {Base}
*/
this.baseController = baseController;
/**
* @type {function}
*/
this._getScheduleDataFunc = null;
/**
* @type {object}
*/
this._dragStart = null;
/**
* @type {TimeMoveGuide}
*/
this._guide = new TimeMoveGuide(this);
dragHandler.on('dragStart', this._onDragStart, this);
dragHandler.on('mousedown', this._onMouseDown, this);
}
/**
* Destroy method.
*/
TimeMove.prototype.destroy = function() {
this._guide.destroy();
this.dragHandler.off(this);
this.dragHandler = this.timeGridView = this.baseController =
this._getScheduleDataFunc = this._dragStart = this._guide = null;
};
/**
* Check target element is expected condition for activate this plugins.
* @param {HTMLElement} target - The element to check
* @returns {boolean|object} - return object when satiate condition.
*/
TimeMove.prototype.checkExpectCondition = function(target) {
if (!domutil.closest(target, config.classname('.time-schedule'))) {
return false;
}
return this._getTimeView(target);
};
/**
* Get Time view container from supplied element.
* @param {HTMLElement} target - element to find time view container.
* @returns {object|boolean} - return time view instance when finded.
*/
TimeMove.prototype._getTimeView = function(target) {
var container = domutil.closest(target, config.classname('.time-date')),
matches;
if (!container) {
return false;
}
matches = domutil.getClass(container).match(config.time.getViewIDRegExp);
if (!matches || matches.length < 2) {
return false;
}
return util.pick(this.timeGridView.children.items, Number(matches[1]));
};
/**
* @emits TimeMove#mousedown
* @param {object} mouseDownEventData - Drag#mousedown schedule data.
*/
TimeMove.prototype._onMouseDown = function(mouseDownEventData) {
var target = mouseDownEventData.target,
timeView = this.checkExpectCondition(target),
blockElement = domutil.closest(target, config.classname('.time-date-schedule-block'));
if (!timeView || !blockElement) {
return;
}
// EventTarget.target is not changed in mousemove event even if mouse is over the other element.
// It's different with other browsers(IE, Chrome, Safari)
if (util.browser.firefox) {
domevent.preventDefault(mouseDownEventData.originEvent);
}
};
/**
* @emits TimeMove#timeMoveDragstart
* @param {object} dragStartEventData - Drag#dragStart schedule data.
*/
TimeMove.prototype._onDragStart = function(dragStartEventData) {
var target = dragStartEventData.target,
timeView = this.checkExpectCondition(target),
blockElement = domutil.closest(target, config.classname('.time-date-schedule-block')),
getScheduleDataFunc,
scheduleData,
ctrl = this.baseController,
targetModelID,
targetModel;
if (!timeView || !blockElement) {
return;
}
targetModelID = domutil.getData(blockElement, 'id');
targetModel = ctrl.schedules.items[targetModelID];
if (targetModel.isReadOnly) {
return;
}
getScheduleDataFunc = this._getScheduleDataFunc = this._retriveScheduleData(timeView);
scheduleData = this._dragStart = getScheduleDataFunc(
dragStartEventData.originEvent, {
targetModelID: targetModelID,
model: targetModel
}
);
this.dragHandler.on({
drag: this._onDrag,
dragEnd: this._onDragEnd,
click: this._onClick
}, this);
/**
* @event TimeMove#timeMoveDragstart
* @type {object}
* @property {HTMLElement} target - current target in mouse event object.
* @property {Time} relatedView - time view instance related with mouse position.
* @property {MouseEvent} originEvent - mouse event object.
* @property {number} mouseY - mouse Y px mouse event.
* @property {number} gridY - grid Y index value related with mouseY value.
* @property {number} timeY - milliseconds value of mouseY points.
* @property {number} nearestGridY - nearest grid index related with mouseY value.
* @property {number} nearestGridTimeY - time value for nearestGridY.
* @property {string} targetModelID - The model unique id emitted move schedule.
* @property {Schedule} model - model instance
*/
this.fire('timeMoveDragstart', scheduleData);
};
/**
* @emits TimeMove#timeMoveDrag
* @param {MouseEvent} dragEventData - mousemove event object
* @param {string} [overrideEventName] - name of emitting event to override.
* @param {function} [revise] - supply function for revise schedule data before emit.
*/
TimeMove.prototype._onDrag = function(dragEventData, overrideEventName, revise) {
var getScheduleDataFunc = this._getScheduleDataFunc,
timeView = this._getTimeView(dragEventData.target),
dragStart = this._dragStart,
scheduleData;
if (!timeView || !getScheduleDataFunc || !dragStart) {
return;
}
scheduleData = getScheduleDataFunc(dragEventData.originEvent, {
currentView: timeView,
targetModelID: dragStart.targetModelID
});
if (revise) {
revise(scheduleData);
}
/**
* @event TimeMove#timeMoveDrag
* @type {object}
* @property {HTMLElement} target - current target in mouse event object.
* @property {Time} relatedView - time view instance related with drag start position.
* @property {MouseEvent} originEvent - mouse event object.
* @property {number} mouseY - mouse Y px mouse event.
* @property {number} gridY - grid Y index value related with mouseY value.
* @property {number} timeY - milliseconds value of mouseY points.
* @property {number} nearestGridY - nearest grid index related with mouseY value.
* @property {number} nearestGridTimeY - time value for nearestGridY.
* @property {Time} currentView - time view instance related with current mouse position.
* @property {string} targetModelID - The model unique id emitted move schedule.
*/
this.fire(overrideEventName || 'timeMoveDrag', scheduleData);
};
/**
* Update model instance by dragend event results.
* @fires TimeMove#beforeUpdateSchedule
* @param {object} scheduleData - schedule data from TimeMove#timeMoveDragend
*/
TimeMove.prototype._updateSchedule = function(scheduleData) {
var ctrl = this.baseController,
modelID = scheduleData.targetModelID,
range = scheduleData.nearestRange,
timeDiff = range[1] - range[0],
dateDiff = 0,
schedule = ctrl.schedules.items[modelID],
relatedView = scheduleData.relatedView,
currentView = scheduleData.currentView,
newStarts,
newEnds;
if (!schedule || !currentView) {
return;
}
timeDiff -= datetime.millisecondsFrom('minutes', 30);
newStarts = new TZDate(schedule.getStarts()).addMilliseconds(timeDiff);
newEnds = new TZDate(schedule.getEnds()).addMilliseconds(timeDiff);
if (currentView) {
dateDiff = currentView.getDate() - relatedView.getDate();
}
newStarts.addMilliseconds(dateDiff);
newEnds.addMilliseconds(dateDiff);
/**
* @event TimeMove#beforeUpdateSchedule
* @type {object}
* @property {Schedule} schedule - The original schedule instance
* @property {Date} start - Deprecated: start time to update
* @property {Date} end - Deprecated: end time to update
* @property {object} changes - start and end time to update
* @property {Date} start - start time to update
* @property {Date} end - end time to update
*/
this.fire('beforeUpdateSchedule', {
schedule: schedule,
changes: {
start: newStarts,
end: newEnds
},
start: newStarts,
end: newEnds
});
};
/**
* @emits TimeMove#timeMoveDragend
* @param {MouseEvent} dragEndEventData - mouseup mouse event object.
*/
TimeMove.prototype._onDragEnd = function(dragEndEventData) {
var getScheduleDataFunc = this._getScheduleDataFunc,
currentView = this._getTimeView(dragEndEventData.target),
dragStart = this._dragStart,
scheduleData;
this.dragHandler.off({
drag: this._onDrag,
dragEnd: this._onDragEnd,
click: this._onClick
}, this);
if (!getScheduleDataFunc || !dragStart) {
return;
}
scheduleData = getScheduleDataFunc(dragEndEventData.originEvent, {
currentView: currentView,
targetModelID: dragStart.targetModelID
});
scheduleData.range = [
dragStart.timeY,
new TZDate(scheduleData.timeY).addMinutes(30)
];
scheduleData.nearestRange = [
dragStart.nearestGridTimeY,
new TZDate(scheduleData.nearestGridTimeY).addMinutes(30)
];
this._updateSchedule(scheduleData);
/**
* @event TimeMove#timeMoveDragend
* @type {object}
* @property {HTMLElement} target - current target in mouse event object.
* @property {Time} relatedView - time view instance related with drag start position.
* @property {Time} currentView - time view instance related with current mouse position.
* @property {MouseEvent} originEvent - mouse event object.
* @property {number} mouseY - mouse Y px mouse event.
* @property {number} gridY - grid Y index value related with mouseY value.
* @property {number} timeY - milliseconds value of mouseY points.
* @property {number} nearestGridY - nearest grid index related with mouseY value.
* @property {number} nearestGridTimeY - time value for nearestGridY.
* @property {string} targetModelID - The model unique id emitted move schedule.
* @property {number[]} range - milliseconds range between drag start and end.
* @property {number[]} nearestRange - milliseconds range related with nearestGridY between start and end.
*/
this.fire('timeMoveDragend', scheduleData);
};
/**
* @emits TimeMove#timeMoveClick
* @param {MouseEvent} clickEventData - click mouse event object.
*/
TimeMove.prototype._onClick = function(clickEventData) {
var getScheduleDataFunc = this._getScheduleDataFunc,
dragStart = this._dragStart,
scheduleData;
this.dragHandler.off({
drag: this._onDrag,
dragEnd: this._onDragEnd,
click: this._onClick
}, this);
if (!getScheduleDataFunc || !dragStart) {
return;
}
scheduleData = getScheduleDataFunc(clickEventData.originEvent, {
targetModelID: dragStart.targetModelID
});
/**
* @event TimeMove#timeMoveClick
* @type {object}
* @property {HTMLElement} target - current target in mouse event object.
* @property {Time} relatedView - time view instance related with drag start position.
* @property {MouseEvent} originEvent - mouse event object.
* @property {number} mouseY - mouse Y px mouse event.
* @property {number} gridY - grid Y index value related with mouseY value.
* @property {number} timeY - milliseconds value of mouseY points.
* @property {number} nearestGridY - nearest grid index related with mouseY value.
* @property {number} nearestGridTimeY - time value for nearestGridY.
* @property {string} targetModelID - The model unique id emitted move schedule.
*/
this.fire('timeMoveClick', scheduleData);
};
timeCore.mixin(TimeMove);
util.CustomEvents.mixin(TimeMove);
module.exports = TimeMove;