UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,075 lines • 79.5 kB
/** * DevExtreme (ui/scheduler/ui.scheduler.js) * Version: 18.1.3 * Build date: Tue May 15 2018 * * Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var $ = require("../../core/renderer"), Callbacks = require("../../core/utils/callbacks"), translator = require("../../animation/translator"), errors = require("../widget/ui.errors"), dialog = require("../dialog"), recurrenceUtils = require("./utils.recurrence"), domUtils = require("../../core/utils/dom"), dateUtils = require("../../core/utils/date"), each = require("../../core/utils/iterator").each, extend = require("../../core/utils/extend").extend, inArray = require("../../core/utils/array").inArray, noop = require("../../core/utils/common").noop, typeUtils = require("../../core/utils/type"), devices = require("../../core/devices"), config = require("../../core/config"), registerComponent = require("../../core/component_registrator"), messageLocalization = require("../../localization/message"), dateSerialization = require("../../core/utils/date_serialization"), Widget = require("../widget/ui.widget"), subscribes = require("./ui.scheduler.subscribes"), FunctionTemplate = require("../widget/function_template"), appointmentTooltip = require("./ui.scheduler.appointment_tooltip"), SchedulerHeader = require("./ui.scheduler.header"), SchedulerWorkSpaceDay = require("./ui.scheduler.work_space_day"), SchedulerWorkSpaceWeek = require("./ui.scheduler.work_space_week"), SchedulerWorkSpaceWorkWeek = require("./ui.scheduler.work_space_work_week"), SchedulerWorkSpaceMonth = require("./ui.scheduler.work_space_month"), SchedulerTimelineDay = require("./ui.scheduler.timeline_day"), SchedulerTimelineWeek = require("./ui.scheduler.timeline_week"), SchedulerTimelineWorkWeek = require("./ui.scheduler.timeline_work_week"), SchedulerTimelineMonth = require("./ui.scheduler.timeline_month"), SchedulerAgenda = require("./ui.scheduler.agenda"), SchedulerResourceManager = require("./ui.scheduler.resource_manager"), SchedulerAppointmentModel = require("./ui.scheduler.appointment_model"), SchedulerAppointments = require("./ui.scheduler.appointments"), SchedulerLayoutManager = require("./ui.scheduler.appointments.layout_manager"), DropDownAppointments = require("./ui.scheduler.appointments.drop_down"), SchedulerTimezones = require("./ui.scheduler.timezones"), DataHelperMixin = require("../../data_helper"), loading = require("./ui.loading"), AppointmentForm = require("./ui.scheduler.appointment_form"), Popup = require("../popup"), deferredUtils = require("../../core/utils/deferred"), when = deferredUtils.when, Deferred = deferredUtils.Deferred, EmptyTemplate = require("../widget/empty_template"), BindableTemplate = require("../widget/bindable_template"), themes = require("../themes"); var WIDGET_CLASS = "dx-scheduler", WIDGET_SMALL_CLASS = "dx-scheduler-small", WIDGET_READONLY_CLASS = "dx-scheduler-readonly", APPOINTMENT_POPUP_CLASS = "dx-scheduler-appointment-popup", RECURRENCE_EDITOR_ITEM_CLASS = "dx-scheduler-recurrence-rule-item", RECURRENCE_EDITOR_OPENED_ITEM_CLASS = "dx-scheduler-recurrence-rule-item-opened", WIDGET_SMALL_WIDTH = 400, APPOINTEMENT_POPUP_WIDTH = 610; var VIEWS_CONFIG = { day: { workSpace: SchedulerWorkSpaceDay, renderingStrategy: "vertical" }, week: { workSpace: SchedulerWorkSpaceWeek, renderingStrategy: "vertical" }, workWeek: { workSpace: SchedulerWorkSpaceWorkWeek, renderingStrategy: "vertical" }, month: { workSpace: SchedulerWorkSpaceMonth, renderingStrategy: "horizontalMonth" }, timelineDay: { workSpace: SchedulerTimelineDay, renderingStrategy: "horizontal" }, timelineWeek: { workSpace: SchedulerTimelineWeek, renderingStrategy: "horizontal" }, timelineWorkWeek: { workSpace: SchedulerTimelineWorkWeek, renderingStrategy: "horizontal" }, timelineMonth: { workSpace: SchedulerTimelineMonth, renderingStrategy: "horizontalMonthLine" }, agenda: { workSpace: SchedulerAgenda, renderingStrategy: "agenda" } }; var Scheduler = Widget.inherit({ _getDefaultOptions: function() { return extend(this.callBase(), { views: ["day", "week"], currentView: "day", currentDate: dateUtils.trimTime(new Date), min: void 0, max: void 0, dateSerializationFormat: void 0, firstDayOfWeek: void 0, groups: [], resources: [], dataSource: null, appointmentTemplate: "item", dropDownAppointmentTemplate: "dropDownAppointment", dataCellTemplate: null, timeCellTemplate: null, resourceCellTemplate: null, dateCellTemplate: null, startDayHour: 0, endDayHour: 24, editing: { allowAdding: true, allowDeleting: true, allowDragging: true, allowResizing: true, allowUpdating: true }, showAllDayPanel: true, showCurrentTimeIndicator: true, shadeUntilCurrentTime: false, indicatorUpdateInterval: 3e5, indicatorTime: void 0, recurrenceEditMode: "dialog", cellDuration: 30, maxAppointmentsPerCell: "auto", selectedCellData: [], onAppointmentRendered: null, onAppointmentClick: null, onAppointmentDblClick: null, onAppointmentContextMenu: null, onCellClick: null, onCellContextMenu: null, onAppointmentAdding: null, onAppointmentAdded: null, onAppointmentUpdating: null, onAppointmentUpdated: null, onAppointmentDeleting: null, onAppointmentDeleted: null, onAppointmentFormCreated: null, appointmentTooltipTemplate: "appointmentTooltip", appointmentPopupTemplate: "appointmentPopup", crossScrollingEnabled: false, useDropDownViewSwitcher: false, startDateExpr: "startDate", endDateExpr: "endDate", textExpr: "text", descriptionExpr: "description", allDayExpr: "allDay", recurrenceRuleExpr: "recurrenceRule", recurrenceExceptionExpr: "recurrenceException", remoteFiltering: false, timeZone: "", startDateTimeZoneExpr: "startDateTimeZone", endDateTimeZoneExpr: "endDateTimeZone", noDataText: messageLocalization.format("dxCollectionWidget-noDataText"), allowMultipleCellSelection: true, _appointmentTooltipOffset: { x: 0, y: 0 }, _appointmentTooltipButtonsPosition: "bottom", _appointmentTooltipCloseButton: false, _useAppointmentColorForTooltip: false, _appointmentTooltipOpenButtonText: messageLocalization.format("dxScheduler-openAppointment"), _appointmentTooltipOpenButtonIcon: "", _dropDownButtonIcon: "overflow", _appointmentCountPerCell: 2, _appointmentGroupButtonOffset: 0, _appointmentOffset: 26 }) }, _defaultOptionsRules: function() { return this.callBase().concat([{ device: function() { return "desktop" === devices.real().deviceType && !devices.isSimulator() }, options: { focusStateEnabled: true } }, { device: function() { return !devices.current().generic }, options: { useDropDownViewSwitcher: true, editing: { allowDragging: false, allowResizing: false } } }, { device: function() { return themes.isMaterial() }, options: { useDropDownViewSwitcher: true, dateCellTemplate: function(data, index, element) { var text = data.text; text.split(" ").forEach(function(text, index) { var span = $("<span>").text(text).addClass("dx-scheduler-header-panel-cell-date"); $(element).append(span); if (!index) { $(element).append(" ") } }) }, _appointmentTooltipOffset: { x: 0, y: 11 }, _appointmentTooltipButtonsPosition: "top", _appointmentTooltipCloseButton: true, _useAppointmentColorForTooltip: true, _appointmentTooltipOpenButtonText: null, _appointmentTooltipOpenButtonIcon: "edit", _dropDownButtonIcon: "chevrondown", _appointmentCountPerCell: 1, _appointmentGroupButtonOffset: 20, _appointmentOffset: 30 } }]) }, _optionChanged: function(args) { var value = args.value, name = args.name; switch (args.name) { case "firstDayOfWeek": this._updateOption("workSpace", name, value); this._updateOption("header", name, value); break; case "currentDate": value = this._dateOption(name); value = dateUtils.trimTime(new Date(value)); this._workSpace.option(name, value); this._header.option(name, this._workSpace._getViewStartByOptions()); this._appointments.option("items", []); this._filterAppointmentsByDate(); this._reloadDataSource(); break; case "dataSource": this._initDataSource(); this._customizeStoreLoadOptions(); this._appointmentModel.setDataSource(this._dataSource); this._loadResources().done(function() { this._filterAppointmentsByDate(); this._updateOption("workSpace", "showAllDayPanel", this.option("showAllDayPanel")); this._reloadDataSource() }.bind(this)); break; case "min": case "max": value = this._dateOption(name); this._updateOption("header", name, new Date(value)); this._updateOption("workSpace", name, new Date(value)); break; case "views": this._processCurrentView(); if (!!this._getCurrentViewOptions()) { this.repaint() } else { this._header.option(name, value) } break; case "useDropDownViewSwitcher": this._header.option(name, value); break; case "currentView": this._processCurrentView(); this.option("selectedCellData", []); var viewCountConfig = this._getViewCountConfig(); this._appointments.option({ items: [], allowDrag: this._allowDragging(), allowResize: this._allowResizing(), itemTemplate: this._getAppointmentTemplate("appointmentTemplate") }); this._header.option("intervalCount", viewCountConfig.intervalCount); this._header.option("startDate", viewCountConfig.startDate || new Date(this.option("currentDate"))); this._header.option("min", this._dateOption("min")); this._header.option("max", this._dateOption("max")); this._header.option("currentDate", this._dateOption("currentDate")); this._header.option("firstDayOfWeek", this._getCurrentViewOption("firstDayOfWeek")); this._header.option("currentView", this._currentView); this._loadResources().done(function(resources) { this.getLayoutManager().initRenderingStrategy(this._getAppointmentsRenderingStrategy()); this._refreshWorkSpace(resources); this._filterAppointmentsByDate(); this._appointments.option("allowAllDayResize", "day" !== value); this._reloadDataSource() }.bind(this)); break; case "appointmentTemplate": this._appointments.option("itemTemplate", value); break; case "dateCellTemplate": case "resourceCellTemplate": case "dataCellTemplate": case "timeCellTemplate": this._updateOption("workSpace", name, value); this.repaint(); break; case "groups": this._loadResources().done(function(resources) { this._refreshWorkSpace(resources); this._filterAppointmentsByDate(); this._reloadDataSource() }.bind(this)); break; case "resources": this._resourcesManager.setResources(this.option("resources")); this._appointmentModel.setDataAccessors(this._combineDataAccessors()); this._loadResources().done(function(resources) { this._appointments.option("items", []); this._refreshWorkSpace(resources); this._filterAppointmentsByDate(); this._reloadDataSource() }.bind(this)); break; case "startDayHour": case "endDayHour": this._appointments.option("items", []); this._updateOption("workSpace", name, value); this._appointments.repaint(); this._filterAppointmentsByDate(); this._reloadDataSource(); break; case "onAppointmentAdding": case "onAppointmentAdded": case "onAppointmentUpdating": case "onAppointmentUpdated": case "onAppointmentDeleting": case "onAppointmentDeleted": case "onAppointmentFormCreated": this._actions[name] = this._createActionByOption(name); break; case "onAppointmentRendered": this._appointments.option("onItemRendered", this._getAppointmentRenderedAction()); break; case "onAppointmentClick": this._appointments.option("onItemClick", this._createActionByOption(name)); break; case "onAppointmentDblClick": this._appointments.option(name, this._createActionByOption(name)); break; case "onAppointmentContextMenu": this._appointments.option("onItemContextMenu", this._createActionByOption(name)); break; case "noDataText": case "allowMultipleCellSelection": case "selectedCellData": case "accessKey": case "onCellClick": this._workSpace.option(name, value); break; case "onCellContextMenu": this._workSpace.option(name, value); break; case "crossScrollingEnabled": this._loadResources().done(function(resources) { this._appointments.option("items", []); this._refreshWorkSpace(resources); if (this._readyToRenderAppointments) { this._appointments.option("items", this._getAppointmentsToRepaint()) } }.bind(this)); break; case "cellDuration": this._appointments.option("items", []); if (this._readyToRenderAppointments) { this._updateOption("workSpace", "hoursInterval", value / 60); this._appointments.option("items", this._getAppointmentsToRepaint()) } break; case "tabIndex": case "focusStateEnabled": this._updateOption("header", name, value); this._updateOption("workSpace", name, value); this._appointments.option(name, value); this.callBase(args); break; case "width": this._updateOption("header", name, value); if (this.option("crossScrollingEnabled")) { this._updateOption("workSpace", "width", value) } this.callBase(args); this._dimensionChanged(); break; case "height": this.callBase(args); this._dimensionChanged(); break; case "editing": this._initEditing(); var editing = this._editing; this._bringEditingModeToAppointments(editing); this.hideAppointmentTooltip(); this._cleanPopup(); break; case "showAllDayPanel": this._loadResources().done(function() { this._filterAppointmentsByDate(); this._updateOption("workSpace", "allDayExpanded", value); this._updateOption("workSpace", name, value); this._reloadDataSource() }.bind(this)); break; case "showCurrentTimeIndicator": case "indicatorTime": case "indicatorUpdateInterval": case "shadeUntilCurrentTime": this._updateOption("workSpace", name, value); this.repaint(); break; case "appointmentTooltipTemplate": case "appointmentPopupTemplate": case "recurrenceEditMode": case "remoteFiltering": case "timeZone": case "dropDownAppointmentTemplate": case "_appointmentTooltipOffset": case "_appointmentTooltipButtonsPosition": case "_appointmentTooltipCloseButton": case "_useAppointmentColorForTooltip": case "_appointmentTooltipOpenButtonText": case "_appointmentTooltipOpenButtonIcon": case "_dropDownButtonIcon": case "_appointmentCountPerCell": case "_appointmentGroupButtonOffset": case "_appointmentOffset": this.repaint(); break; case "dateSerializationFormat": break; case "maxAppointmentsPerCell": break; case "startDateExpr": case "endDateExpr": case "startDateTimeZoneExpr": case "endDateTimeZoneExpr": case "textExpr": case "descriptionExpr": case "allDayExpr": case "recurrenceRuleExpr": case "recurrenceExceptionExpr": this._updateExpression(name, value); this._initAppointmentTemplate(); this.repaint(); break; default: this.callBase(args) } }, _dateOption: function(optionName) { var optionValue = this._getCurrentViewOption(optionName); return dateSerialization.deserializeDate(optionValue) }, _getSerializationFormat: function(optionName) { var value = this._getCurrentViewOption(optionName); if ("number" === typeof value) { return "number" } if (!typeUtils.isString(value)) { return } return dateSerialization.getDateSerializationFormat(value) }, _bringEditingModeToAppointments: function(editing) { var editingConfig = { allowDelete: editing.allowUpdating && editing.allowDeleting }; if (!this._isAgenda()) { editingConfig.allowDrag = editing.allowDragging; editingConfig.allowResize = editing.allowResizing; editingConfig.allowAllDayResize = editing.allowResizing && this._supportAllDayResizing() } this._appointments.option(editingConfig); this._dropDownAppointments.repaintExisting(this.$element()) }, _isAgenda: function() { return "agenda" === this._getAppointmentsRenderingStrategy() }, _allowDragging: function() { return this._editing.allowDragging && !this._isAgenda() }, _allowResizing: function() { return this._editing.allowResizing && !this._isAgenda() }, _allowAllDayResizing: function() { return this._editing.allowResizing && this._supportAllDayResizing() }, _supportAllDayResizing: function() { return "day" !== this._getCurrentViewType() || this._currentView.intervalCount > 1 }, _isAllDayExpanded: function(items) { return this.option("showAllDayPanel") && this._appointmentModel.hasAllDayAppointments(items, this._getCurrentViewOption("startDayHour"), this._getCurrentViewOption("endDayHour")) }, _getTimezoneOffsetByOption: function(date) { return this._calculateTimezoneByValue(this.option("timeZone"), date) }, _calculateTimezoneByValue: function(timezone, date) { var result = timezone; if ("string" === typeof timezone) { date = date || new Date; result = SchedulerTimezones.getTimezoneOffsetById(timezone, Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes())) } return result }, _filterAppointmentsByDate: function() { var dateRange = this._workSpace.getDateRange(); this._appointmentModel.filterByDate(dateRange[0], dateRange[1], this.option("remoteFiltering"), this.option("dateSerializationFormat")) }, _loadResources: function() { var groups = this._getCurrentViewOption("groups"), result = new Deferred; this._resourcesManager.loadResources(groups).done(function(resources) { this._loadedResources = resources; result.resolve(resources) }.bind(this)); return result.promise() }, _dataSourceLoadedCallback: Callbacks(), _reloadDataSource: function() { if (this._dataSource) { this._dataSource.load().done(function() { loading.hide(); this._fireContentReadyAction() }.bind(this)).fail(function() { loading.hide() }); this._dataSource.isLoading() && loading.show({ container: this.$element(), position: { of: this.$element() } }) } }, _dimensionChanged: function() { var filteredItems = this.getFilteredItems(); this._toggleSmallClass(); if (!this._isAgenda() && filteredItems && this._isVisible()) { this._workSpace._cleanAllowedPositions(); this._workSpace.option("allDayExpanded", this._isAllDayExpanded(filteredItems)); var appointments = this._layoutManager.createAppointmentsMap(filteredItems); this._appointments.option("items", appointments) } this.hideAppointmentTooltip() }, _clean: function() { this._cleanPopup(); this.callBase() }, _toggleSmallClass: function() { var width = this.$element().get(0).getBoundingClientRect().width; this.$element().toggleClass(WIDGET_SMALL_CLASS, width < WIDGET_SMALL_WIDTH) }, _visibilityChanged: function(visible) { visible && this._dimensionChanged() }, _dataSourceOptions: function() { return { paginate: false } }, _init: function() { this._initExpressions({ startDate: this.option("startDateExpr"), endDate: this.option("endDateExpr"), startDateTimeZone: this.option("startDateTimeZoneExpr"), endDateTimeZone: this.option("endDateTimeZoneExpr"), allDay: this.option("allDayExpr"), text: this.option("textExpr"), description: this.option("descriptionExpr"), recurrenceRule: this.option("recurrenceRuleExpr"), recurrenceException: this.option("recurrenceExceptionExpr") }); this.callBase(); this._initDataSource(); this._loadedResources = []; this._proxiedCustomizeStoreLoadOptionsHandler = this._customizeStoreLoadOptionsHandler.bind(this); this._customizeStoreLoadOptions(); this.$element().addClass(WIDGET_CLASS); this._initEditing(); this._resourcesManager = new SchedulerResourceManager(this.option("resources")); var combinedDataAccessors = this._combineDataAccessors(); this._appointmentModel = new SchedulerAppointmentModel(this._dataSource, { startDateExpr: this.option("startDateExpr"), endDateExpr: this.option("endDateExpr"), allDayExpr: this.option("allDayExpr"), recurrenceRuleExpr: this.option("recurrenceRuleExpr"), recurrenceExceptionExpr: this.option("recurrenceExceptionExpr") }, combinedDataAccessors); this._initActions(); this._dropDownAppointments = new DropDownAppointments; this._subscribes = subscribes }, _initTemplates: function() { this.callBase(); this._initAppointmentTemplate(); this._defaultTemplates.appointmentTooltip = new EmptyTemplate(this); this._defaultTemplates.appointmentPopup = new EmptyTemplate(this); this._defaultTemplates.dropDownAppointment = new EmptyTemplate(this) }, _initAppointmentTemplate: function() { var that = this; this._defaultTemplates.item = new BindableTemplate(function($container, data, model) { var appointmentsInst = that.getAppointmentsInstance(); appointmentsInst._renderAppointmentTemplate.call(appointmentsInst, $container, data, model) }, ["html", "text", "startDate", "endDate", "allDay", "description", "recurrenceRule", "recurrenceException", "startDateTimeZone", "endDateTimeZone"], this.option("integrationOptions.watchMethod"), { text: this._dataAccessors.getter.text, startDate: this._dataAccessors.getter.startDate, endDate: this._dataAccessors.getter.endDate, startDateTimeZone: this._dataAccessors.getter.startDateTimeZone, endDateTimeZone: this._dataAccessors.getter.endDateTimeZone, allDay: this._dataAccessors.getter.allDay, recurrenceRule: this._dataAccessors.getter.recurrenceRule }) }, _combineDataAccessors: function() { var resourcesDataAccessors = this._resourcesManager._dataAccessors, result = extend(true, {}, this._dataAccessors); each(resourcesDataAccessors, function(type, accessor) { result[type].resources = accessor }.bind(this)); return result }, _renderContent: function() { this._renderContentImpl() }, _dataSourceChangedHandler: function(result) { this._workSpaceRecalculation.done(function() { this._filteredItems = this.fire("prerenderFilter"); this._workSpace.option("allDayExpanded", this._isAllDayExpanded(this._filteredItems)); if (this._isAgenda()) { this.getRenderingStrategyInstance().calculateRows(this._filteredItems, 7, this.option("currentDate"), true) } if (this._filteredItems.length && this._isVisible()) { this._appointments.option("items", this._getAppointmentsToRepaint()); delete this.instance._updatedAppointment } else { this._appointments.option("items", []) } if (this._isAgenda()) { this._workSpace._renderView(); this._dataSourceLoadedCallback.fireWith(this, [result]) } }.bind(this)) }, _getAppointmentsToRepaint: function() { var appointments = this._layoutManager.createAppointmentsMap(this._filteredItems); return this._layoutManager.markRepaintedAppointments(appointments, this.getAppointmentsInstance().option("items")) }, _initExpressions: function(fields) { var dataCoreUtils = require("../../core/utils/data"), isDateField = function(field) { return "startDate" === field || "endDate" === field }; if (!this._dataAccessors) { this._dataAccessors = { getter: {}, setter: {} } } each(fields, function(name, expr) { if (!!expr) { var getter = dataCoreUtils.compileGetter(expr), setter = dataCoreUtils.compileSetter(expr); var dateGetter, dateSetter; if (isDateField(name)) { var that = this; dateGetter = function() { var value = getter.apply(this, arguments); if (config().forceIsoDateParsing) { if (!that.option("dateSerializationFormat")) { var format = dateSerialization.getDateSerializationFormat(value); if (format) { that.option("dateSerializationFormat", format) } } value = dateSerialization.deserializeDate(value) } return value }; dateSetter = function(object, value) { if (config().forceIsoDateParsing || that.option("dateSerializationFormat")) { value = dateSerialization.serializeDate(value, that.option("dateSerializationFormat")) } setter.call(this, object, value) } } this._dataAccessors.getter[name] = dateGetter || getter; this._dataAccessors.setter[name] = dateSetter || setter } else { delete this._dataAccessors.getter[name]; delete this._dataAccessors.setter[name] } }.bind(this)) }, _updateExpression: function(name, value) { var exprObj = {}; exprObj[name.replace("Expr", "")] = value; this._initExpressions(exprObj) }, _initEditing: function() { var editing = this.option("editing"); this._editing = { allowAdding: !!editing, allowUpdating: !!editing, allowDeleting: !!editing, allowResizing: !!editing, allowDragging: !!editing }; if (typeUtils.isObject(editing)) { this._editing = extend(this._editing, editing) } this._editing.allowDragging = this._editing.allowDragging && this._editing.allowUpdating; this._editing.allowResizing = this._editing.allowResizing && this._editing.allowUpdating; this.$element().toggleClass(WIDGET_READONLY_CLASS, this._isReadOnly()) }, _isReadOnly: function() { var result = true, editing = this._editing; for (var prop in editing) { if (editing.hasOwnProperty(prop)) { result = result && !editing[prop] } } return result }, _customizeStoreLoadOptions: function() { this._dataSource && this._dataSource.on("customizeStoreLoadOptions", this._proxiedCustomizeStoreLoadOptionsHandler) }, _dispose: function() { this.hideAppointmentPopup(); this.hideAppointmentTooltip(); clearTimeout(this._repaintTimer); this._dataSource && this._dataSource.off("customizeStoreLoadOptions", this._proxiedCustomizeStoreLoadOptionsHandler); this.callBase() }, _customizeStoreLoadOptionsHandler: function(options) { options.storeLoadOptions.dxScheduler = { startDate: this.getStartViewDate(), endDate: this.getEndViewDate(), resources: this.option("resources") } }, _initActions: function() { this._actions = { onAppointmentAdding: this._createActionByOption("onAppointmentAdding"), onAppointmentAdded: this._createActionByOption("onAppointmentAdded"), onAppointmentUpdating: this._createActionByOption("onAppointmentUpdating"), onAppointmentUpdated: this._createActionByOption("onAppointmentUpdated"), onAppointmentDeleting: this._createActionByOption("onAppointmentDeleting"), onAppointmentDeleted: this._createActionByOption("onAppointmentDeleted"), onAppointmentFormCreated: this._createActionByOption("onAppointmentFormCreated") } }, _getAppointmentRenderedAction: function() { return this._createActionByOption("onAppointmentRendered", { excludeValidators: ["designMode", "disabled", "readOnly"] }) }, _renderFocusTarget: noop, _initMarkup: function() { this.callBase(); this._processCurrentView(); this._renderHeader(); this._layoutManager = new SchedulerLayoutManager(this, this._getAppointmentsRenderingStrategy()); this._appointments = this._createComponent("<div>", SchedulerAppointments, this._appointmentsConfig()); this._appointments.option("itemTemplate", this._getAppointmentTemplate("appointmentTemplate")); this._loadResources().done(function(resources) { this._renderWorkSpace(resources); var $fixedContainer = this._workSpace.getFixedContainer(), $allDayContainer = this._workSpace.getAllDayContainer(); this._appointments.option({ fixedContainer: $fixedContainer, allDayContainer: $allDayContainer }); this._filterAppointmentsByDate(); this._reloadDataSource() }.bind(this)); this._readyToRenderAppointments = false }, _render: function() { this.callBase(); this._toggleSmallClass(); this._readyToRenderAppointments = true; this._workSpaceRecalculation && this._workSpaceRecalculation.resolve() }, _renderHeader: function() { var $header = $("<div>").appendTo(this.$element()); this._header = this._createComponent($header, SchedulerHeader, this._headerConfig()) }, _headerConfig: function() { var result, currentViewOptions = this._getCurrentViewOptions(), countConfig = this._getViewCountConfig(); result = extend({ firstDayOfWeek: this.option("firstDayOfWeek"), currentView: this._currentView, tabIndex: this.option("tabIndex"), focusStateEnabled: this.option("focusStateEnabled"), width: this.option("width"), rtlEnabled: this.option("rtlEnabled"), useDropDownViewSwitcher: this.option("useDropDownViewSwitcher"), _dropDownButtonIcon: this.option("_dropDownButtonIcon") }, currentViewOptions); result.observer = this; result.intervalCount = countConfig.intervalCount; result.views = this.option("views"); result.min = new Date(this._dateOption("min")); result.max = new Date(this._dateOption("max")); result.currentDate = dateUtils.trimTime(new Date(this._dateOption("currentDate"))); return result }, _appointmentsConfig: function() { var that = this; var config = { observer: this, onItemRendered: this._getAppointmentRenderedAction(), onItemClick: this._createActionByOption("onAppointmentClick"), onItemContextMenu: this._createActionByOption("onAppointmentContextMenu"), onAppointmentDblClick: this._createActionByOption("onAppointmentDblClick"), tabIndex: this.option("tabIndex"), focusStateEnabled: this.option("focusStateEnabled"), allowDrag: this._allowDragging(), allowDelete: this._editing.allowUpdating && this._editing.allowDeleting, allowResize: this._allowResizing(), allowAllDayResize: this._allowAllDayResizing(), rtlEnabled: this.option("rtlEnabled"), _appointmentGroupButtonOffset: this.option("_appointmentGroupButtonOffset"), onContentReady: function() { that._workSpace && that._workSpace.option("allDayExpanded", that._isAllDayExpanded(that.getFilteredItems())) } }; return config }, getAppointmentDurationInMinutes: function() { return this._getCurrentViewOption("cellDuration") }, _processCurrentView: function() { var views = this.option("views"), currentView = this.option("currentView"), that = this; this._currentView = currentView; each(views, function(_, view) { var isViewIsObject = typeUtils.isObject(view), viewName = isViewIsObject ? view.name : view, viewType = view.type; if (currentView === viewName || currentView === viewType) { that._currentView = view; return false } }) }, _getCurrentViewType: function() { return this._currentView.type || this._currentView }, _getAppointmentsRenderingStrategy: function() { return VIEWS_CONFIG[this._getCurrentViewType()].renderingStrategy }, _getDayDuration: function() { return this._getCurrentViewOption("endDayHour") - this._getCurrentViewOption("startDayHour") }, _renderWorkSpace: function(groups) { var $workSpace = $("<div>").appendTo(this.$element()); var countConfig = this._getViewCountConfig(); this._workSpace = this._createComponent($workSpace, VIEWS_CONFIG[this._getCurrentViewType()].workSpace, this._workSpaceConfig(groups, countConfig)); this._workSpace.getWorkArea().append(this._appointments.$element()); this._recalculateWorkspace(); countConfig.startDate && this._header && this._header.option("currentDate", this._workSpace.getStartViewDate()) }, _getViewCountConfig: function() { var currentView = this.option("currentView"); var view = this._getViewByName(currentView), viewCount = view && view.intervalCount || 1, startDate = view && view.startDate || null; return { intervalCount: viewCount, startDate: startDate } }, _getViewByName: function(name) { var views = this.option("views"); for (var i = 0; i < views.length; i++) { if (views[i].name === name || views[i].type === name || views[i] === name) { return views[i] } } }, _recalculateWorkspace: function() { this._workSpaceRecalculation = new Deferred; domUtils.triggerResizeEvent(this._workSpace.$element()); this._workSpace._refreshDateTimeIndication() }, _workSpaceConfig: function(groups, countConfig) { var _this = this; var result, currentViewOptions = this._getCurrentViewOptions(); result = extend({ noDataText: this.option("noDataText"), firstDayOfWeek: this.option("firstDayOfWeek"), startDayHour: this.option("startDayHour"), endDayHour: this.option("endDayHour"), tabIndex: this.option("tabIndex"), accessKey: this.option("accessKey"), focusStateEnabled: this.option("focusStateEnabled"), cellDuration: this.option("cellDuration"), showAllDayPanel: this.option("showAllDayPanel"), showCurrentTimeIndicator: this.option("showCurrentTimeIndicator"), indicatorTime: this.option("indicatorTime"), indicatorUpdateInterval: this.option("indicatorUpdateInterval"), shadeUntilCurrentTime: this.option("shadeUntilCurrentTime"), allDayExpanded: this._appointments.option("items"), crossScrollingEnabled: this.option("crossScrollingEnabled"), dataCellTemplate: this.option("dataCellTemplate"), timeCellTemplate: this.option("timeCellTemplate"), resourceCellTemplate: this.option("resourceCellTemplate"), dateCellTemplate: this.option("dateCellTemplate"), allowMultipleCellSelection: this.option("allowMultipleCellSelection"), selectedCellData: this.option("selectedCellData"), onSelectionChanged: function(args) { _this.option("selectedCellData", args.selectedCellData) } }, currentViewOptions); result.observer = this; result.intervalCount = countConfig.intervalCount; result.startDate = countConfig.startDate; result.groups = groups; result.onCellClick = this._createActionByOption("onCellClick"); result.onCellContextMenu = this._createActionByOption("onCellContextMenu"); result.min = new Date(this._dateOption("min")); result.max = new Date(this._dateOption("max")); result.currentDate = dateUtils.trimTime(new Date(this._dateOption("currentDate"))); result.hoursInterval = result.cellDuration / 60; result.allDayExpanded = this._isAllDayExpanded(this.getFilteredItems()); result.dataCellTemplate = result.dataCellTemplate ? this._getTemplate(result.dataCellTemplate) : null; result.timeCellTemplate = result.timeCellTemplate ? this._getTemplate(result.timeCellTemplate) : null; result.resourceCellTemplate = result.resourceCellTemplate ? this._getTemplate(result.resourceCellTemplate) : null; result.dateCellTemplate = result.dateCellTemplate ? this._getTemplate(result.dateCellTemplate) : null; return result }, _getCurrentViewOptions: function() { return this._currentView }, _getCurrentViewOption: function(optionName) { var currentViewOptions = this._getCurrentViewOptions(); if (currentViewOptions && void 0 !== currentViewOptions[optionName]) { return currentViewOptions[optionName] } return this.option(optionName) }, _getAppointmentTemplate: function(optionName) { var currentViewOptions = this._getCurrentViewOptions(); if (currentViewOptions && currentViewOptions[optionName]) { return this._getTemplate(currentViewOptions[optionName]) } return this._getTemplateByOption(optionName) }, _updateOption: function(viewName, optionName, value) { var currentViewOptions = this._getCurrentViewOptions(); if (!currentViewOptions || !typeUtils.isDefined(currentViewOptions[optionName])) { this["_" + viewName].option(optionName, value) } }, _refreshWorkSpace: function(groups) { this._appointments.$element().detach(); this._workSpace._dispose(); this._workSpace.$element().remove(); delete this._workSpace; this._renderWorkSpace(groups); if (this._readyToRenderAppointments) { this._workSpaceRecalculation.resolve(); this._appointments.option({ fixedContainer: this._workSpace.getFixedContainer(), allDayContainer: this._workSpace.getAllDayContainer() }) } }, getWorkSpaceScrollable: function() { return this._workSpace.getScrollable() }, getWorkSpaceScrollableScrollTop: function(allDay) { return this._workSpace.getGroupedScrollableScrollTop(allDay) }, getWorkSpaceScrollableScrollLeft: function() { return this._workSpace.getScrollableScrollLeft() }, getWorkSpaceScrollableContainer: function() { return this._workSpace.getScrollableContainer() }, getWorkSpaceAllDayHeight: function() { return this._workSpace.getAllDayHeight() }, getWorkSpaceAllDayOffset: function() { return this._workSpace.getAllDayOffset() }, getWorkSpaceHeaderPanelHeight: function() { return this._workSpace.getHeaderPanelHeight() }, getWorkSpaceDateTableOffset: function() { return !this.option("crossScrollingEnabled") || this.option("rtlEnabled") ? this._workSpace.getWorkSpaceLeftOffset() : 0 }, getWorkSpace: function() { return this._workSpace }, getHeader: function() { return this._header }, getMaxAppointmentsPerCell: function() { return this._getCurrentViewOption("maxAppointmentsPerCell") }, _createPopup: function(appointmentData, processTimeZone) { this._$popup = $("<div>").addClass(APPOINTMENT_POPUP_CLASS).appendTo(this.$element()); this._initDynamicPopupTemplate(appointmentData, processTimeZone); this._popup = this._createComponent(this._$popup, Popup, this._popupConfig(appointmentData)) }, _popupContent: function(appointmentData, processTimeZone) { var $popupContent = this._popup.$content(); this._createAppointmentForm(appointmentData, $popupContent, processTimeZone); return $popupContent }, _createAppointmentForm: function(appointmentData, $content, processTimeZone) { var allDay = this.fire("getField", "allDay", appointmentData), resources = this.option("resources"), startDate = this.fire("getField", "startDate", appointmentData), endDate = this.fire("getField", "endDate", appointmentData); each(this._resourcesManager.getResourcesFromItem(appointmentData, true) || {}, function(resourceName, resourceValue) { appointmentData[resourceName] = resourceValue }); var formData = extend(true, {}, appointmentData); if (processTimeZone) { startDate = this.fire("convertDateByTimezone", startDate); endDate = this.fire("convertDateByTimezone", endDate); this.fire("setField", "startDate", formData, startDate); this.fire("setField", "endDate", formData, endDate) } if (this._appointmentForm) { var startDateExpr = this.option("startDateExpr"), endDateExpr = this.option("endDateExpr"); this._appointmentForm.option("formData", formData); this._appointmentForm.option("readOnly", this._editAppointmentData ? !this._editing.allowUpdating : false); AppointmentForm.checkEditorsType(this._appointmentForm, startDateExpr, endDateExpr, allDay) } else { AppointmentForm.prepareAppointmentFormEditors(allDay, { textExpr: this.option("textExpr"), allDayExpr: this.option("allDayExpr"), startDateExpr: this.option("startDateExpr"), endDateExpr: this.option("endDateExpr"), descriptionExpr: this.option("descriptionExpr"), recurrenceRuleExpr: this.option("recurrenceRuleExpr"), startDateTimeZoneExpr: this.option("startDateTimeZoneExpr"), endDateTimeZoneExpr: this.option("endDateTimeZoneExpr") }, this); if (resources && resources.length) { this._resourcesManager.setResources(this.option("resources")); AppointmentForm.concatResources(this._resourcesManager.getEditors()) } this._appointmentForm = AppointmentForm.create(this._createComponent.bind(this), $content, this._editAppointmentData ? !this._editing.allowUpdating : false, formData) } var recurrenceRuleExpr = this.option("recurrenceRuleExpr"), recurrentEditorItem = recurrenceRuleExpr ? this._appointmentForm.itemOption(recurrenceRuleExpr) : null; if (r