tui-calendar
Version:
TOAST UI Calendar
290 lines (245 loc) • 9.15 kB
JavaScript
/**
* @fileoverview Module for Time.Creation effect while dragging.
* @author NHN FE Development Lab <dl_javascript@nhn.com>
*/
'use strict';
var common = require('../../common/common');
var datetime = require('../../common/datetime');
var config = require('../../config');
var domutil = require('../../common/domutil');
var reqAnimFrame = require('../../common/reqAnimFrame');
var ratio = require('../../common/common').ratio;
var TZDate = require('../../common/timezone').Date;
var MIN60 = (datetime.MILLISECONDS_PER_MINUTES * 60);
/**
* Class for Time.Creation dragging effect.
* @constructor
* @param {TimeCreation} timeCreation - instance of TimeCreation.
*/
function TimeCreationGuide(timeCreation) {
/**
* Guide element for creation effect.
* @type {HTMLElement}
*/
this.guideElement = global.document.createElement('div');
/**
* @type {HTMLDivElement}
*/
this.guideTimeElement = domutil.appendHTMLElement(
'span',
this.guideElement,
config.classname('time-guide-creation-label')
);
domutil.addClass(this.guideElement, config.classname('time-guide-creation'));
/**
* @type {TimeCreation}
*/
this.timeCreation = timeCreation;
/**
* @type {array}
*/
this._styleUnit = null;
/**
* @type {array}
*/
this._styleStart = null;
/**
* @type {function}
*/
this._styleFunc = null;
timeCreation.on({
timeCreationDragstart: this._createGuideElement,
timeCreationDrag: this._onDrag,
timeCreationClick: this._createGuideElement
}, this);
this.applyTheme(timeCreation.baseController.theme);
}
/**
* Destroy method.
*/
TimeCreationGuide.prototype.destroy = function() {
this.clearGuideElement();
this.timeCreation.off(this);
this.timeCreation = this._styleUnit = this._styleStart =
this._styleFunc = this.guideElement = this.guideTimeElement = null;
};
/**
* Clear guide element.
*/
TimeCreationGuide.prototype.clearGuideElement = function() {
var guideElement = this.guideElement,
timeElement = this.guideTimeElement;
domutil.remove(guideElement);
reqAnimFrame.requestAnimFrame(function() {
guideElement.style.display = 'none';
guideElement.style.top = '';
guideElement.style.height = '';
timeElement.innerHTML = '';
});
};
/**
* Refresh guide element
* @param {number} top - The number of guide element's style top
* @param {number} height - The number of guide element's style height
* @param {TZDate} start - start time of schedule to create
* @param {TZDate} end - end time of schedule to create
* @param {boolean} bottomLabel - is label need to render bottom of guide element?
*/
TimeCreationGuide.prototype._refreshGuideElement = function(top, height, start, end, bottomLabel) {
var guideElement = this.guideElement;
var timeElement = this.guideTimeElement;
guideElement.style.top = top + 'px';
guideElement.style.height = height + 'px';
guideElement.style.display = 'block';
timeElement.innerHTML = datetime.format(start, 'HH:mm') +
' - ' + datetime.format(end, 'HH:mm');
if (bottomLabel) {
domutil.removeClass(timeElement, config.classname('time-guide-bottom'));
} else {
domutil.addClass(timeElement, config.classname('time-guide-bottom'));
}
};
/**
* Get unit data of calculating new style of guide element by user interaction
* @param {Time} relatedView - time view instance related with schedule
* @returns {array} unit data.
*/
TimeCreationGuide.prototype._getUnitData = function(relatedView) {
var viewOpt = relatedView.options,
viewHeight = relatedView.getViewBound().height,
hourLength = viewOpt.hourEnd - viewOpt.hourStart,
todayStart = datetime.parse(viewOpt.ymd),
todayEnd = datetime.getStartOfNextDay(todayStart);
todayStart.setHours(0, 0, 0, 0);
todayStart.setHours(viewOpt.hourStart);
// [0] height of view
// [1] hour length of view
// [2] start time of view
// [3] end time of view
// [4] height of view for one hour
return [
viewHeight,
hourLength,
todayStart,
todayEnd,
viewHeight / hourLength
];
};
/**
* Applying limitation to supplied data and return it.
* @param {number} top - top pixel of guide element
* @param {number} height - height pixel of guide element
* @param {TZDate} start - relative time value of dragstart point
* @param {TZDate} end - relative time value of dragend point
* @returns {array} limited style data
*/
TimeCreationGuide.prototype._limitStyleData = function(top, height, start, end) {
var unitData = this._styleUnit;
top = common.limit(top, [0], [unitData[0]]);
height = common.limit(top + height, [0], [unitData[0]]) - top;
start = common.limitDate(start, unitData[2], unitData[3]);
end = common.limitDate(end, unitData[2], unitData[3]);
return [top, height, start, end];
};
/**
* Get function to calculate guide element UI data from supplied units
* @param {number} viewHeight - total height of view's container element
* @param {number} hourLength - hour length that rendered in time view
* @param {TZDate} todayStart - time for view's start date
* @returns {function} UI data calculator function
*/
TimeCreationGuide.prototype._getStyleDataFunc = function(viewHeight, hourLength, todayStart) {
var todayStartTime = todayStart;
var todayEndTime = datetime.end(todayStart);
/**
* Get top, time value from schedule data
* @param {object} scheduleData - schedule data object
* @returns {number[]} top, time
*/
function getStyleData(scheduleData) {
var minMinutes = 30;
var gridY = scheduleData.nearestGridY,
gridTimeY = scheduleData.nearestGridTimeY,
gridEndTimeY = scheduleData.nearestGridEndTimeY || new TZDate(gridTimeY).addMinutes(minMinutes),
top, startTime, endTime;
top = common.limit(ratio(hourLength, viewHeight, gridY), [0], [viewHeight]);
startTime = common.limitDate(gridTimeY, todayStartTime, todayEndTime);
endTime = common.limitDate(gridEndTimeY, todayStartTime, todayEndTime);
return [top, startTime, endTime];
}
return getStyleData;
};
/**
* DragStart event handler
* @param {object} dragStartEventData - dragStart schedule data.
*/
TimeCreationGuide.prototype._createGuideElement = function(dragStartEventData) {
var relatedView = dragStartEventData.relatedView,
hourStart = datetime.millisecondsFrom('hour', dragStartEventData.hourStart) || 0,
unitData, styleFunc, styleData, result, top, height, start, end;
unitData = this._styleUnit = this._getUnitData(relatedView);
styleFunc = this._styleFunc = this._getStyleDataFunc.apply(this, unitData);
styleData = this._styleStart = styleFunc(dragStartEventData);
start = new TZDate(styleData[1]).addMinutes(datetime.minutesFromHours(hourStart));
end = new TZDate(styleData[2]).addMinutes(datetime.minutesFromHours(hourStart));
top = styleData[0];
height = (unitData[4] * (end - start) / MIN60);
result = this._limitStyleData(
top,
height,
start,
end
);
this._refreshGuideElement.apply(this, result);
relatedView.container.appendChild(this.guideElement);
};
/**
* Drag event handler
* @param {object} dragEventData - drag schedule data.
*/
TimeCreationGuide.prototype._onDrag = function(dragEventData) {
var minutes30 = 30;
var styleFunc = this._styleFunc,
unitData = this._styleUnit,
startStyle = this._styleStart,
refreshGuideElement = this._refreshGuideElement.bind(this),
heightOfHalfHour,
endStyle,
result;
if (!styleFunc || !unitData || !startStyle) {
return;
}
heightOfHalfHour = (unitData[4] / 2);
endStyle = styleFunc(dragEventData);
if (endStyle[0] > startStyle[0]) {
result = this._limitStyleData(
startStyle[0],
(endStyle[0] - startStyle[0]) + heightOfHalfHour,
startStyle[1],
new TZDate(endStyle[1]).addMinutes(minutes30)
);
} else {
result = this._limitStyleData(
endStyle[0],
(startStyle[0] - endStyle[0]) + heightOfHalfHour,
endStyle[1],
new TZDate(startStyle[1]).addMinutes(minutes30)
);
result.push(true);
}
reqAnimFrame.requestAnimFrame(function() {
refreshGuideElement.apply(null, result);
});
};
TimeCreationGuide.prototype.applyTheme = function(theme) {
var style = this.guideElement.style;
var timeStyle = this.guideTimeElement.style;
// block
style.backgroundColor = theme.common.creationGuide.backgroundColor;
style.border = theme.common.creationGuide.border;
// label
timeStyle.color = theme.week.creationGuide.color;
timeStyle.fontSize = theme.week.creationGuide.fontSize;
timeStyle.fontWeight = theme.week.creationGuide.fontWeight;
};
module.exports = TimeCreationGuide;