UNPKG

tui-calendar

Version:
469 lines (390 loc) 10.9 kB
/* eslint complexity: 0 */ /** * @fileoverview Model of schedule. * @author NHN FE Development Lab <dl_javascript@nhn.com> */ 'use strict'; var util = require('tui-code-snippet'); var tz = require('../common/timezone'); var datetime = require('../common/datetime'); var dirty = require('../common/dirty'); var model = require('../common/model'); var TZDate = tz.Date; var MIN_TO_MS = 60 * 1000; var SCHEDULE_MIN_DURATION = datetime.MILLISECONDS_SCHEDULE_MIN_DURATION; /** * Schedule category * @readonly * @enum {string} */ var SCHEDULE_CATEGORY = { /** milestone */ MILESTONE: 'milestone', /** task */ TASK: 'task', /** all-day schedule */ ALLDAY: 'allday', /** normal schedule */ TIME: 'time' }; /** * Get duration by primary timezone * @param {Date} start render start date * @param {Date} end render end date * @returns {number} duration */ function getDurationByPrimaryTimezone(start, end) { var checkOffset = tz.isDifferentOffsetStartAndEndTime(start.getTime(), end.getTime()); var isOffsetChanged = checkOffset.isOffsetChanged; var duration = end - start; if (isOffsetChanged !== 0) { duration += checkOffset.offsetDiff * MIN_TO_MS; } return duration; } /** * Get duration by native timezone * @param {TZDate} start render start date * @param {TZDate} end render end date * @returns {number} duration */ function getDurationByNativeTimezone(start, end) { var startOffset = start.toDate().getTimezoneOffset(); var endOffset = end.toDate().getTimezoneOffset(); return (end - start) + ((endOffset - startOffset) * MIN_TO_MS); } /** * The model of calendar schedules. * @constructor * @mixes dirty * @mixes model */ function Schedule() { /** * `Optional` unique id for various use. * @type {string} */ this.id = ''; /** * title for schedule. * @type {string} */ this.title = ''; /** * body for schedule. * @type {string} */ this.body = ''; /** * is schedule is all day schedule? * @type {boolean} */ this.isAllDay = false; /** * schedule start * @type {TZDate} */ this.start = null; /** * schedule end * @type {TZDate} */ this.end = null; /** * schedule text color * @type {string} */ this.color = '#000'; /** * schedule block visibility * @type {boolean} */ this.isVisible = true; /** * schedule background color * @type {string} */ this.bgColor = '#a1b56c'; /** * schedule background color when dragging it * @type {string} */ this.dragBgColor = '#a1b56c'; /** * schedule left border color * @type {string} */ this.borderColor = '#000'; /** * calendar ID * @type {string} */ this.calendarId = ''; /** * Schedule category(milestone, task, allday, time) * @type {string} */ this.category = ''; /** * Classification of work schedules (before work, before lunch, before work) * @type {string} */ this.dueDateClass = ''; /** * Custom style for schedule element * @type {string} */ this.customStyle = ''; /** * in progress flag to do something * @type {boolean} */ this.isPending = false; /** * focused schedule flag * @type {boolean} */ this.isFocused = false; /** * read-only schedule flag * @type {boolean} */ this.isReadOnly = false; /** * private schedule * @type {boolean} */ this.isPrivate = false; /** * location * @type {string} */ this.location = ''; /** * attendees * @type {Array.<string>} */ this.attendees = []; /** * recurrence rule * @type {any} */ this.recurrenceRule = ''; /** * state. 'Busy' is default. * @type {string} */ this.state = ''; /** * travelTime: going-Duration minutes * @type {number} */ this.goingDuration = 0; /** * travelTime: coming-Duration minutes * @type {number} */ this.comingDuration = 0; /** * Separate data storage space independent of rendering. * @type {object} */ this.raw = null; // initialize model id util.stamp(this); } /********** * static props **********/ Schedule.schema = { required: ['title'], dateRange: ['start', 'end'] }; /** * create schedule model from json(object) data. * @param {object} data object for model. * @returns {Schedule} Schedule model instance. */ Schedule.create = function(data) { var inst = new Schedule(); inst.init(data); return inst; }; /********** * prototype props **********/ /** * Initialize schedule instance. * @param {object} options options. */ Schedule.prototype.init = function(options) { options = util.extend({}, options); if (options.category === SCHEDULE_CATEGORY.ALLDAY) { options.isAllDay = true; } this.id = options.id || ''; this.title = options.title || ''; this.body = options.body || ''; this.isAllDay = util.isExisty(options.isAllDay) ? options.isAllDay : false; this.isVisible = util.isExisty(options.isVisible) ? options.isVisible : true; this.color = options.color || this.color; this.bgColor = options.bgColor || this.bgColor; this.dragBgColor = options.dragBgColor || this.dragBgColor; this.borderColor = options.borderColor || this.borderColor; this.calendarId = options.calendarId || ''; this.category = options.category || ''; this.dueDateClass = options.dueDateClass || ''; this.customStyle = options.customStyle || ''; this.location = options.location || ''; this.attendees = options.attendees || []; this.recurrenceRule = options.recurrenceRule || ''; this.isPrivate = options.isPrivate || false; this.isPending = options.isPending || false; this.isFocused = options.isFocused || false; this.isReadOnly = options.isReadOnly || false; this.goingDuration = options.goingDuration || 0; this.comingDuration = options.comingDuration || 0; this.state = options.state || ''; if (this.isAllDay) { this.setAllDayPeriod(options.start, options.end); } else { this.setTimePeriod(options.start, options.end); } this.raw = options.raw || null; }; Schedule.prototype.setAllDayPeriod = function(start, end) { // If it is an all-day schedule, only the date information of the string is used. if (util.isString(start) && start.length === 10) { start = datetime.parse(start); } else { start = new TZDate(start || Date.now()); } if (util.isString(end) && end.length === 10) { end = datetime.parse(end); end.setHours(23, 59, 59); } else { end = new TZDate(end || start); } this.start = datetime.start(start); this.end = datetime.renderEnd(start, end); }; Schedule.prototype.setTimePeriod = function(start, end) { this.start = new TZDate(start || Date.now()); this.end = new TZDate(end || this.start); if (!end) { this.end.setMinutes(this.end.getMinutes() + 30); } }; /** * @returns {Date} render start date. */ Schedule.prototype.getStarts = function() { return this.start; }; /** * @returns {Date} render end date. */ Schedule.prototype.getEnds = function() { return this.end; }; /** * @returns {number} instance unique id. */ Schedule.prototype.cid = function() { return util.stamp(this); }; /** * Check two schedule are equals (means title, isAllDay, start, end are same) * @param {Schedule} schedule Schedule model instance to compare. * @returns {boolean} Return false when not same. */ Schedule.prototype.equals = function(schedule) { if (this.id !== schedule.id) { return false; } if (this.title !== schedule.title) { return false; } if (this.body !== schedule.body) { return false; } if (this.isAllDay !== schedule.isAllDay) { return false; } if (datetime.compare(this.getStarts(), schedule.getStarts()) !== 0) { return false; } if (datetime.compare(this.getEnds(), schedule.getEnds()) !== 0) { return false; } if (this.color !== schedule.color) { return false; } if (this.bgColor !== schedule.bgColor) { return false; } if (this.dragBgColor !== schedule.dragBgColor) { return false; } if (this.borderColor !== schedule.borderColor) { return false; } return true; }; /** * return duration between start and end. * @returns {Date} duration (UTC) */ Schedule.prototype.duration = function() { var start = this.getStarts(), end = this.getEnds(), duration; var hasPrimaryTimezoneCustomSetting = tz.hasPrimaryTimezoneCustomSetting(); if (this.isAllDay) { duration = datetime.end(end) - datetime.start(start); } else if (hasPrimaryTimezoneCustomSetting && tz.isPrimaryUsingDSTTimezone()) { duration = getDurationByPrimaryTimezone(start, end); } else if (hasPrimaryTimezoneCustomSetting && tz.isNativeOsUsingDSTTimezone()) { duration = getDurationByNativeTimezone(start, end); } else { duration = end - start; } return duration; }; /** * Returns true if the given Schedule coincides with the same time as the * calling Schedule. * @param {Schedule} schedule The other schedule to compare with this Schedule. * @returns {boolean} If the other schedule occurs within the same time as the first object. */ Schedule.prototype.collidesWith = function(schedule) { var ownStarts = this.getStarts(), ownEnds = this.getEnds(), start = schedule.getStarts(), end = schedule.getEnds(); var ownGoingDuration = datetime.millisecondsFrom('minutes', this.goingDuration), ownComingDuration = datetime.millisecondsFrom('minutes', this.comingDuration), goingDuration = datetime.millisecondsFrom('minutes', schedule.goingDuration), comingDuration = datetime.millisecondsFrom('minutes', schedule.comingDuration); if (Math.abs(ownEnds - ownStarts) < SCHEDULE_MIN_DURATION) { ownEnds += SCHEDULE_MIN_DURATION; } if (Math.abs(end - start) < SCHEDULE_MIN_DURATION) { end += SCHEDULE_MIN_DURATION; } ownStarts -= ownGoingDuration; ownEnds += ownComingDuration; start -= goingDuration; end += comingDuration; if ( (start > ownStarts && start < ownEnds) || (end > ownStarts && end < ownEnds) || (start <= ownStarts && end >= ownEnds) ) { return true; } return false; }; model.mixin(Schedule.prototype); dirty.mixin(Schedule.prototype); module.exports = Schedule;