UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

478 lines (367 loc) • 18.4 kB
"use strict"; var Class = require("../../core/class"), config = require("../../core/config"), iteratorUtils = require("../../core/utils/iterator"), dateSerialization = require("../../core/utils/date_serialization"), recurrenceUtils = require("./utils.recurrence"), dateUtils = require("../../core/utils/date"), commonUtils = require("../../core/utils/common"), typeUtils = require("../../core/utils/type"), inArray = require("../../core/utils/array").inArray, extend = require("../../core/utils/extend").extend, arrayUtils = require("../../core/utils/array"), query = require("../../data/query"); var DATE_FILTER_POSITION = 0, USER_FILTER_POSITION = 1; var FilterMaker = Class.inherit({ ctor: function ctor(dataExpressions, dataAccessors) { this._filterRegistry = null; this._dataAccessors = dataAccessors; this._dataExpressions = dataExpressions; }, isRegistered: function isRegistered() { return !!this._filterRegistry; }, clearRegistry: function clearRegistry() { delete this._filterRegistry; }, make: function make(type, args) { if (!this._filterRegistry) { this._filterRegistry = {}; } this._make[type].apply(this, args); }, _make: { "date": function date(min, max, useAccessors) { var startDate = useAccessors ? this._dataAccessors.getter.startDate : this._dataExpressions.startDateExpr, endDate = useAccessors ? this._dataAccessors.getter.endDate : this._dataExpressions.endDateExpr, recurrenceRule = this._dataExpressions.recurrenceRuleExpr; this._filterRegistry.date = [[[endDate, ">", min], [startDate, "<", max]], "or", [recurrenceRule, "startswith", "freq"], "or", [[endDate, min], [startDate, min]]]; if (!recurrenceRule) { this._filterRegistry.date.splice(1, 2); } }, "user": function user(userFilter) { this._filterRegistry.user = userFilter; } }, combine: function combine() { var filter = []; this._filterRegistry.date && filter.push(this._filterRegistry.date); this._filterRegistry.user && filter.push(this._filterRegistry.user); return filter; }, dateFilter: function dateFilter() { return this._filterRegistry.date; } }); var AppointmentModel = Class.inherit({ _createFilter: function _createFilter(min, max, remoteFiltering, dateSerializationFormat) { this._filterMaker.make("date", [min, max]); var userFilterPosition = this._excessFiltering() ? this._dataSource.filter()[USER_FILTER_POSITION] : this._dataSource.filter(); this._filterMaker.make("user", [userFilterPosition]); if (remoteFiltering) { this._dataSource.filter(this._combineRemoteFilter(dateSerializationFormat)); } }, _excessFiltering: function _excessFiltering() { var dateFilter = this._filterMaker.dateFilter(), dataSourceFilter = this._dataSource.filter(); return dataSourceFilter && (commonUtils.equalByValue(dataSourceFilter, dateFilter) || dataSourceFilter.length && commonUtils.equalByValue(dataSourceFilter[DATE_FILTER_POSITION], dateFilter)); }, _combineFilter: function _combineFilter() { return this._filterMaker.combine(); }, _getStoreKey: function _getStoreKey(target) { var store = this._dataSource.store(); return store.keyOf(target); }, _filterAppointmentByResources: function _filterAppointmentByResources(appointment, resources) { var result = false; function checkAppointmentResourceValues() { var resourceGetter = this._dataAccessors.getter.resources[resourceName], resource; if (typeUtils.isFunction(resourceGetter)) { resource = resourceGetter(appointment); } var appointmentResourceValues = arrayUtils.wrapToArray(resource), resourceData = iteratorUtils.map(resources[i].items, function (item) { return item.id; }); for (var j = 0, itemDataCount = appointmentResourceValues.length; j < itemDataCount; j++) { if (inArray(appointmentResourceValues[j], resourceData) > -1) { return true; } } return false; } for (var i = 0, len = resources.length; i < len; i++) { var resourceName = resources[i].name; result = checkAppointmentResourceValues.call(this); if (!result) { return false; } } return result; }, _filterAppointmentByRRule: function _filterAppointmentByRRule(appointment, min, max, startDayHour, endDayHour) { var recurrenceRule = appointment.recurrenceRule, recurrenceException = appointment.recurrenceException, allDay = appointment.allDay, result = true, appointmentStartDate = appointment.startDate, appointmentEndDate = appointment.endDate; if (allDay || this._appointmentPartInInterval(appointmentStartDate, appointmentEndDate, startDayHour, endDayHour)) { var trimmedDates = this._trimDates(min, max); min = trimmedDates.min; max = new Date(trimmedDates.max.getTime() - 60000); } if (recurrenceRule && !recurrenceUtils.getRecurrenceRule(recurrenceRule).isValid) { result = appointmentEndDate > min && appointmentStartDate <= max; } if (result && recurrenceUtils.getRecurrenceRule(recurrenceRule).isValid) { result = recurrenceUtils.dateInRecurrenceRange({ rule: recurrenceRule, exception: recurrenceException, start: appointmentStartDate, end: appointmentEndDate, min: min, max: max }); } return result; }, _appointmentPartInInterval: function _appointmentPartInInterval(startDate, endDate, startDayHour, endDayHour) { var apptStartDayHour = startDate.getHours(), apptEndDayHour = endDate.getHours(); return apptStartDayHour <= startDayHour && apptEndDayHour <= endDayHour && apptEndDayHour >= startDayHour || apptEndDayHour >= endDayHour && apptStartDayHour <= endDayHour && apptStartDayHour >= startDayHour; }, _createCombinedFilter: function _createCombinedFilter(filterOptions, timeZoneProcessor) { var dataAccessors = this._dataAccessors, startDayHour = filterOptions.startDayHour, endDayHour = filterOptions.endDayHour, min = new Date(filterOptions.min), max = new Date(filterOptions.max), resources = filterOptions.resources, that = this; return [[function (appointment) { var result = true, startDate = new Date(dataAccessors.getter.startDate(appointment)), endDate = new Date(dataAccessors.getter.endDate(appointment)), appointmentTakesAllDay = that.appointmentTakesAllDay(appointment, startDayHour, endDayHour), isAllDay = dataAccessors.getter.allDay(appointment), apptStartHour = startDate.getHours(), hiddenInterval = (24 - endDayHour + startDayHour) * 3600000, apptDuration = endDate.getTime() - startDate.getTime(), delta = (hiddenInterval - apptDuration) / (1000 * 60 * 60), useRecurrence = typeUtils.isDefined(dataAccessors.getter.recurrenceRule), recurrenceRule; if (useRecurrence) { recurrenceRule = dataAccessors.getter.recurrenceRule(appointment); } if (resources && resources.length) { result = that._filterAppointmentByResources(appointment, resources); } if (appointmentTakesAllDay && filterOptions.allDay === false) { result = false; } if (result && useRecurrence) { result = that._filterAppointmentByRRule({ startDate: startDate, endDate: endDate, recurrenceRule: recurrenceRule, recurrenceException: dataAccessors.getter.recurrenceException(appointment), allDay: appointmentTakesAllDay }, min, max, startDayHour, endDayHour); } var startDateTimeZone = dataAccessors.getter.startDateTimeZone(appointment), endDateTimeZone = dataAccessors.getter.endDateTimeZone(appointment), comparableStartDate = timeZoneProcessor(startDate, startDateTimeZone), comparableEndDate = timeZoneProcessor(endDate, endDateTimeZone); if (result && startDayHour !== undefined) { result = comparableStartDate.getHours() >= startDayHour || comparableEndDate.getHours() >= startDayHour || appointmentTakesAllDay; } if (result && endDayHour !== undefined) { result = comparableStartDate.getHours() < endDayHour || appointmentTakesAllDay && comparableStartDate <= max; if (apptDuration < hiddenInterval) { if (apptStartHour > endDayHour && delta <= apptStartHour - endDayHour) { result = false; } } } if (result && useRecurrence && !recurrenceRule) { if (comparableEndDate < min && !isAllDay) { result = false; } } return result; }]]; }, ctor: function ctor(dataSource, dataExpressions, dataAccessors) { this._dataExpressions = dataExpressions; this.setDataSource(dataSource); this._filterMaker = new FilterMaker(dataExpressions, dataAccessors); this.setDataAccessors(dataAccessors); }, setDataSource: function setDataSource(dataSource) { this._dataSource = dataSource; this._filterMaker && this._filterMaker.clearRegistry(); }, setDataAccessors: function setDataAccessors(dataAccessors) { this._dataAccessors = dataAccessors; }, filterByDate: function filterByDate(min, max, remoteFiltering, dateSerializationFormat) { if (!this._dataSource) { return; } var trimmedDates = this._trimDates(min, max); if (!this._filterMaker.isRegistered()) { this._createFilter(trimmedDates.min, trimmedDates.max, remoteFiltering, dateSerializationFormat); } else { this._filterMaker.make("date", [trimmedDates.min, trimmedDates.max]); if (this._dataSource.filter() && this._dataSource.filter().length > 1) { this._filterMaker.make("user", [this._dataSource.filter()[1]]); } if (remoteFiltering) { this._dataSource.filter(this._combineRemoteFilter(dateSerializationFormat)); } } }, _combineRemoteFilter: function _combineRemoteFilter(dateSerializationFormat) { var combinedFilter = this._filterMaker.combine(); return this._serializeRemoteFilter(combinedFilter, dateSerializationFormat); }, _serializeRemoteFilter: function _serializeRemoteFilter(filter, dateSerializationFormat) { var that = this; if (!Array.isArray(filter)) return filter; filter = extend([], filter); var startDate = that._dataExpressions.startDateExpr, endDate = that._dataExpressions.endDateExpr; if (typeUtils.isString(filter[0])) { if (config().forceIsoDateParsing && filter.length > 1) { if (filter[0] === startDate || filter[0] === endDate) { filter[filter.length - 1] = dateSerialization.serializeDate(filter[filter.length - 1], dateSerializationFormat); } } } for (var i = 0; i < filter.length; i++) { filter[i] = that._serializeRemoteFilter(filter[i], dateSerializationFormat); } return filter; }, filterLoadedAppointments: function filterLoadedAppointments(filterOptions, timeZoneProcessor) { if (!typeUtils.isFunction(timeZoneProcessor)) { timeZoneProcessor = function timeZoneProcessor(date) { return date; }; } var combinedFilter = this._createCombinedFilter(filterOptions, timeZoneProcessor); if (this._filterMaker.isRegistered()) { var trimmedDates = this._trimDates(filterOptions.min, filterOptions.max); this._filterMaker.make("date", [trimmedDates.min, trimmedDates.max, true]); var dateFilter = this.customizeDateFilter(this._filterMaker.combine(), timeZoneProcessor); combinedFilter.push([dateFilter]); } return query(this._dataSource.items()).filter(combinedFilter).toArray(); }, _trimDates: function _trimDates(min, max) { var minCopy = dateUtils.trimTime(new Date(min)), maxCopy = dateUtils.trimTime(new Date(max)); maxCopy.setDate(maxCopy.getDate() + 1); return { min: minCopy, max: maxCopy }; }, hasAllDayAppointments: function hasAllDayAppointments(items, startDayHour, endDayHour) { if (!items) { return false; } var that = this; var result = false; iteratorUtils.each(items, function (index, item) { if (that.appointmentTakesAllDay(item, startDayHour, endDayHour)) { result = true; return false; } }); return result; }, appointmentTakesAllDay: function appointmentTakesAllDay(appointment, startDayHour, endDayHour) { var dataAccessors = this._dataAccessors, startDate = dataAccessors.getter.startDate(appointment), endDate = dataAccessors.getter.endDate(appointment), allDay = dataAccessors.getter.allDay(appointment); return allDay || this._appointmentHasAllDayDuration(startDate, endDate, startDayHour, endDayHour); }, _appointmentHasAllDayDuration: function _appointmentHasAllDayDuration(startDate, endDate, startDayHour, endDayHour) { startDate = new Date(startDate); endDate = new Date(endDate); var dayDuration = 24, appointmentDurationInHours = this._getAppointmentDurationInHours(startDate, endDate); return appointmentDurationInHours >= dayDuration || this._appointmentHasShortDayDuration(startDate, endDate, startDayHour, endDayHour); }, _appointmentHasShortDayDuration: function _appointmentHasShortDayDuration(startDate, endDate, startDayHour, endDayHour) { var appointmentDurationInHours = this._getAppointmentDurationInHours(startDate, endDate), shortDayDurationInHours = endDayHour - startDayHour; return appointmentDurationInHours >= shortDayDurationInHours && startDate.getHours() === startDayHour && endDate.getHours() === endDayHour; }, _getAppointmentDurationInHours: function _getAppointmentDurationInHours(startDate, endDate) { return (endDate.getTime() - startDate.getTime()) / 3600000; }, appointmentTakesSeveralDays: function appointmentTakesSeveralDays(appointment) { var dataAccessors = this._dataAccessors, startDate = dataAccessors.getter.startDate(appointment), endDate = dataAccessors.getter.endDate(appointment); var startDateCopy = dateUtils.trimTime(new Date(startDate)), endDateCopy = dateUtils.trimTime(new Date(endDate)); return startDateCopy.getTime() !== endDateCopy.getTime(); }, _mapDateFieldsDependOnTZ: function _mapDateFieldsDependOnTZ(appointment, tz) { function convert(date) { date = dateUtils.makeDate(date); var tzDiff = tz.value * 3600000 + tz.clientOffset; return new Date(date.getTime() - tzDiff); } var startDate = this._dataAccessors.getter.startDate(appointment), endDate = this._dataAccessors.getter.endDate(appointment); this._dataAccessors.setter.startDate(appointment, convert(startDate)); this._dataAccessors.setter.endDate(appointment, convert(endDate)); }, customizeDateFilter: function customizeDateFilter(dateFilter, timeZoneProcessor) { var currentFilter = extend(true, [], dateFilter); return function (appointment) { appointment = extend(true, {}, appointment); var startDate = this._dataAccessors.getter.startDate(appointment), endDate = this._dataAccessors.getter.endDate(appointment), startDateTimeZone = this._dataAccessors.getter.startDateTimeZone(appointment), endDateTimeZone = this._dataAccessors.getter.endDateTimeZone(appointment); var comparableStartDate = timeZoneProcessor(startDate, startDateTimeZone), comparableEndDate = timeZoneProcessor(endDate, endDateTimeZone); this._dataAccessors.setter.startDate(appointment, comparableStartDate); this._dataAccessors.setter.endDate(appointment, comparableEndDate); return query([appointment]).filter(currentFilter).toArray().length > 0; }.bind(this); }, add: function add(data, tz) { if (tz && tz.value !== undefined) { this._mapDateFieldsDependOnTZ(data, tz); } return this._dataSource.store().insert(data).done(function () { this._dataSource.load(); }.bind(this)); }, update: function update(target, data) { var key = this._getStoreKey(target); return this._dataSource.store().update(key, data).done(function () { this._dataSource.load(); }.bind(this)); }, remove: function remove(target) { var key = this._getStoreKey(target); return this._dataSource.store().remove(key).done(function () { this._dataSource.load(); }.bind(this)); } }); module.exports = AppointmentModel;