UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,327 lines (1,069 loc) • 83.2 kB
"use strict"; var $ = require("../../core/renderer"), domAdapter = require("../../core/dom_adapter"), eventsEngine = require("../../events/core/events_engine"), dataUtils = require("../../core/element_data"), dateUtils = require("../../core/utils/date"), typeUtils = require("../../core/utils/type"), windowUtils = require("../../core/utils/window"), getPublicElement = require("../../core/utils/dom").getPublicElement, extend = require("../../core/utils/extend").extend, each = require("../../core/utils/iterator").each, messageLocalization = require("../../localization/message"), dateLocalization = require("../../localization/date"), toMs = dateUtils.dateToMilliseconds, Widget = require("../widget/ui.widget"), abstract = Widget.abstract, noop = require("../../core/utils/common").noop, isDefined = require("../../core/utils/type").isDefined, publisherMixin = require("./ui.scheduler.publisher_mixin"), eventUtils = require("../../events/utils"), pointerEvents = require("../../events/pointer"), errors = require("../widget/ui.errors"), clickEvent = require("../../events/click"), contextMenuEvent = require("../../events/contextmenu"), dragEvents = require("../../events/drag"), Scrollable = require("../scroll_view/ui.scrollable"), HorizontalGroupedStrategy = require("./ui.scheduler.work_space.grouped.strategy.horizontal"), VerticalGroupedStrategy = require("./ui.scheduler.work_space.grouped.strategy.vertical"), tableCreator = require("./ui.scheduler.table_creator"), VerticalShader = require("./ui.scheduler.current_time_shader.vertical"); var COMPONENT_CLASS = "dx-scheduler-work-space", GROUPED_WORKSPACE_CLASS = "dx-scheduler-work-space-grouped", VERTICAL_GROUPED_WORKSPACE_CLASS = "dx-scheduler-work-space-vertical-grouped", WORKSPACE_HORIZONTAL_GROUP_TABLE_CLASS = "dx-scheduler-work-space-horizontal-group-table", WORKSPACE_WITH_BOTH_SCROLLS_CLASS = "dx-scheduler-work-space-both-scrollbar", WORKSPACE_WITH_COUNT_CLASS = "dx-scheduler-work-space-count", WORKSPACE_WITH_ODD_CELLS_CLASS = "dx-scheduler-work-space-odd-cells", WORKSPACE_WITH_OVERLAPPING_CLASS = "dx-scheduler-work-space-overlapping", TIME_PANEL_CLASS = "dx-scheduler-time-panel", TIME_PANEL_CELL_CLASS = "dx-scheduler-time-panel-cell", TIME_PANEL_ROW_CLASS = "dx-scheduler-time-panel-row", ALL_DAY_PANEL_CLASS = "dx-scheduler-all-day-panel", ALL_DAY_TABLE_CLASS = "dx-scheduler-all-day-table", FIXED_CONTAINER_CLASS = "dx-scheduler-fixed-appointments", ALL_DAY_CONTAINER_CLASS = "dx-scheduler-all-day-appointments", ALL_DAY_TITLE_CLASS = "dx-scheduler-all-day-title", ALL_DAY_TITLE_HIDDEN_CLASS = "dx-scheduler-all-day-title-hidden", ALL_DAY_TABLE_CELL_CLASS = "dx-scheduler-all-day-table-cell", ALL_DAY_TABLE_ROW_CLASS = "dx-scheduler-all-day-table-row", WORKSPACE_WITH_ALL_DAY_CLASS = "dx-scheduler-work-space-all-day", WORKSPACE_WITH_COLLAPSED_ALL_DAY_CLASS = "dx-scheduler-work-space-all-day-collapsed", WORKSPACE_WITH_MOUSE_SELECTION_CLASS = "dx-scheduler-work-space-mouse-selection", HORIZONTAL_SIZES_CLASS = "dx-scheduler-cell-sizes-horizontal", VERTICAL_SIZES_CLASS = "dx-scheduler-cell-sizes-vertical", HEADER_PANEL_CLASS = "dx-scheduler-header-panel", HEADER_PANEL_CELL_CLASS = "dx-scheduler-header-panel-cell", HEADER_ROW_CLASS = "dx-scheduler-header-row", GROUP_ROW_CLASS = "dx-scheduler-group-row", GROUP_HEADER_CLASS = "dx-scheduler-group-header", GROUP_HEADER_CONTENT_CLASS = "dx-scheduler-group-header-content", DATE_TABLE_CLASS = "dx-scheduler-date-table", DATE_TABLE_CELL_CLASS = "dx-scheduler-date-table-cell", DATE_TABLE_ROW_CLASS = "dx-scheduler-date-table-row", DATE_TABLE_FOCUSED_CELL_CLASS = "dx-scheduler-focused-cell", DATE_TABLE_DROPPABLE_CELL_CLASS = "dx-scheduler-date-table-droppable-cell", SCHEDULER_HEADER_SCROLLABLE_CLASS = "dx-scheduler-header-scrollable", SCHEDULER_SIDEBAR_SCROLLABLE_CLASS = "dx-scheduler-sidebar-scrollable", SCHEDULER_DATE_TABLE_SCROLLABLE_CLASS = "dx-scheduler-date-table-scrollable", SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME = eventUtils.addNamespace(pointerEvents.down, "dxSchedulerWorkSpace"), SCHEDULER_CELL_DXDRAGENTER_EVENT_NAME = eventUtils.addNamespace(dragEvents.enter, "dxSchedulerDateTable"), SCHEDULER_CELL_DXDROP_EVENT_NAME = eventUtils.addNamespace(dragEvents.drop, "dxSchedulerDateTable"), SCHEDULER_CELL_DXCLICK_EVENT_NAME = eventUtils.addNamespace(clickEvent.name, "dxSchedulerDateTable"), SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME = eventUtils.addNamespace(pointerEvents.down, "dxSchedulerDateTable"), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME = eventUtils.addNamespace(pointerEvents.up, "dxSchedulerDateTable"), SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME = eventUtils.addNamespace(pointerEvents.move, "dxSchedulerDateTable"), CELL_DATA = "dxCellData", DATE_TABLE_MIN_CELL_WIDTH = 75, DATE_TABLE_CELL_BORDER = 1, DAY_MS = toMs("day"), HOUR_MS = toMs("hour"); var formatWeekday = function formatWeekday(date) { return dateLocalization.getDayNames("abbreviated")[date.getDay()]; }; var SchedulerWorkSpace = Widget.inherit({ _supportedKeys: function _supportedKeys() { var clickHandler = function clickHandler(e) { e.preventDefault(); e.stopPropagation(); if (this._focusedCells && this._focusedCells.length) { var $itemElement = $(this.option("focusedElement")); e.target = this._focusedCells; this._showPopup = true; this._cellClickAction({ event: e, cellElement: $(this._focusedCells), cellData: this.getCellData($itemElement) }); } }, arrowPressHandler = function arrowPressHandler(e, cell) { e.preventDefault(); e.stopPropagation(); this._moveToCell(cell, e.shiftKey); }; return extend(this.callBase(), { enter: clickHandler, space: clickHandler, downArrow: function downArrow(e) { var $cell = this._getCellFromNextRow("next", e.shiftKey); arrowPressHandler.call(this, e, $cell); }, upArrow: function upArrow(e) { var $cell = this._getCellFromNextRow("prev", e.shiftKey); arrowPressHandler.call(this, e, $cell); }, rightArrow: function rightArrow(e) { var $rightCell = this._getRightCell(e.shiftKey); arrowPressHandler.call(this, e, $rightCell); }, leftArrow: function leftArrow(e) { var $leftCell = this._getLeftCell(e.shiftKey); arrowPressHandler.call(this, e, $leftCell); } }); }, _isRTL: function _isRTL() { return this.option("rtlEnabled"); }, _getFocusedCell: function _getFocusedCell() { return this._$focusedCell || this._$dateTable.find("." + DATE_TABLE_CELL_CLASS).eq(0); }, _getAllFocusedCells: function _getAllFocusedCells() { return this._focusedCells || this._$dateTable.find("." + DATE_TABLE_CELL_CLASS).eq(0); }, _getCellFromNextRow: function _getCellFromNextRow(direction) { var $currentCell = this._$focusedCell; if (isDefined($currentCell)) { var cellIndex = $currentCell.index(), $row = $currentCell.parent(), $cell = $row[direction]().children().eq(cellIndex); $cell = this._checkForViewBounds($cell); return $cell; } }, _checkForViewBounds: function _checkForViewBounds($item) { if (!$item.length) { $item = this._$focusedCell; } return $item; }, _getRightCell: function _getRightCell(isMultiSelection) { if (!isDefined(this._$focusedCell)) { return; } var $rightCell, $focusedCell = this._$focusedCell, groupCount = this._getGroupCount(), rowCellCount = isMultiSelection ? this._getCellCount() : this._getTotalCellCount(groupCount), lastIndexInRow = rowCellCount - 1, edgeCellIndex = this._isRTL() ? 0 : lastIndexInRow, currentIndex = $focusedCell.index(), direction = this._isRTL() ? "prev" : "next"; if (currentIndex === edgeCellIndex || isMultiSelection && this._isGroupEndCell($focusedCell)) { var $row = $focusedCell.parent(), sign = this._isRTL() ? 1 : -1; $rightCell = $row[direction]().children().eq(currentIndex + sign * lastIndexInRow); $rightCell = this._checkForViewBounds($rightCell); } else { $rightCell = $focusedCell[direction](); } return $rightCell; }, _isGroupEndCell: function _isGroupEndCell($cell) { var cellsInRow = this._getCellCount(), currentCellIndex = $cell.index(), result = currentCellIndex % cellsInRow; return this._isRTL() ? result === 0 : result === cellsInRow - 1; }, _getLeftCell: function _getLeftCell(isMultiSelection) { if (!isDefined(this._$focusedCell)) { return; } var $leftCell, $focusedCell = this._$focusedCell, groupCount = this._getGroupCount(), rowCellCount = isMultiSelection ? this._getCellCount() : this._getTotalCellCount(groupCount), lastIndexInRow = rowCellCount - 1, edgeCellIndex = this._isRTL() ? lastIndexInRow : 0, currentIndex = $focusedCell.index(), direction = this._isRTL() ? "next" : "prev"; if (currentIndex === edgeCellIndex || isMultiSelection && this._isGroupStartCell($focusedCell)) { var $row = $focusedCell.parent(), sign = this._isRTL() ? -1 : 1; $leftCell = $row[direction]().children().eq(currentIndex + sign * lastIndexInRow); $leftCell = this._checkForViewBounds($leftCell); } else { $leftCell = $focusedCell[direction](); } return $leftCell; }, _isGroupStartCell: function _isGroupStartCell($cell) { var cellsInRow = this._getCellCount(), currentCellIndex = $cell.index(), result = currentCellIndex % cellsInRow; return this._isRTL() ? result === cellsInRow - 1 : result === 0; }, _moveToCell: function _moveToCell($cell, isMultiSelection) { isMultiSelection = isMultiSelection && this.option("allowMultipleCellSelection"); this._setFocusedCell($cell, isMultiSelection); this._dateTableScrollable.scrollToElement($cell); }, _setFocusedCell: function _setFocusedCell($cell, isMultiSelection) { if (!isDefined($cell) || !$cell.length) { return; } this._releaseFocusedCell(); this._focusedCells = []; if (isMultiSelection) { $cell = this._correctCellForGroup($cell); var $targetCells = this._getCellsBetween($cell, this._$prevCell); this._focusedCells = $targetCells.toArray(); } else { this._focusedCells = [$cell.get(0)]; this._$prevCell = $cell; } var $focusedCells = $(this._focusedCells); this._toggleFocusClass(true, $focusedCells); this.setAria("label", "Add appointment", $focusedCells); this._toggleFocusedCellClass(true, $cell); this._$focusedCell = $cell; var selectedCellData = this.getFocusedCellData(); this.option("selectedCellData", selectedCellData); this._selectionChangedAction({ selectedCellData: selectedCellData }); }, _correctCellForGroup: function _correctCellForGroup($cell) { var $focusedCell = this._$focusedCell, cellGroupIndex = this._getGroupIndexByCell($cell), focusedCellGroupIndex = this._getGroupIndexByCell($focusedCell), isDifferentTables = this._hasAllDayClass($cell) !== this._hasAllDayClass($focusedCell); return focusedCellGroupIndex !== cellGroupIndex || isDifferentTables ? $focusedCell : $cell; }, _getCellsBetween: function _getCellsBetween($first, $last) { var isAllDayTable = this._hasAllDayClass($last), $cells = this._getCells(isAllDayTable), firstIndex = $cells.index($first), lastIndex = $cells.index($last); if (firstIndex > lastIndex) { var buffer = firstIndex; firstIndex = lastIndex; lastIndex = buffer; } $cells = $cells.slice(firstIndex, lastIndex + 1); if (this._getGroupCount() > 1) { var result = [], focusedGroupIndex = this._getGroupIndexByCell($first); each($cells, function (_, cell) { var groupIndex = this._getGroupIndexByCell($(cell)); if (focusedGroupIndex === groupIndex) { result.push(cell); } }.bind(this)); $cells = $(result); } return $cells; }, _hasAllDayClass: function _hasAllDayClass($cell) { return $cell.hasClass(ALL_DAY_TABLE_CELL_CLASS); }, _getGroupIndexByCell: function _getGroupIndexByCell($cell) { var cellsInRow = this._getCellCount(), currentCellIndex = $cell.index() + 1, groupIndex = Math.ceil(currentCellIndex / cellsInRow); return groupIndex; }, _toggleFocusedCellClass: function _toggleFocusedCellClass(isFocused, $element) { var $focusTarget = $element && $element.length ? $element : this._focusTarget(); $focusTarget.toggleClass(DATE_TABLE_FOCUSED_CELL_CLASS, isFocused); }, _releaseFocusedCell: function _releaseFocusedCell($cell) { $cell = $cell || $(this._focusedCells); if (isDefined($cell)) { this._toggleFocusClass(false, $cell); this._toggleFocusedCellClass(false, $cell); this.setAria("label", undefined, $cell); } this.option("selectedCellData", []); }, _focusInHandler: function _focusInHandler(e) { if ($(e.target).is(this._focusTarget()) && this._isCellClick !== false) { delete this._isCellClick; delete this._contextMenuHandled; this.callBase.apply(this, arguments); var $cell = this._getFocusedCell(); this._setFocusedCell($cell); } }, _focusOutHandler: function _focusOutHandler() { this.callBase.apply(this, arguments); if (!this._contextMenuHandled) { this._releaseFocusedCell(); } }, _focusTarget: function _focusTarget() { return this.$element(); }, _activeStateUnit: "." + DATE_TABLE_CELL_CLASS + ", ." + ALL_DAY_TABLE_CELL_CLASS, _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { currentDate: new Date(), intervalCount: 1, startDate: null, firstDayOfWeek: undefined, startDayHour: 0, endDayHour: 24, hoursInterval: 0.5, activeStateEnabled: true, hoverStateEnabled: true, groups: [], showAllDayPanel: true, allDayExpanded: false, onCellClick: null, crossScrollingEnabled: false, dataCellTemplate: null, timeCellTemplate: null, resourceCellTemplate: null, dateCellTemplate: null, allowMultipleCellSelection: true, indicatorTime: new Date(), indicatorUpdateInterval: 5 * toMs("minute"), shadeUntilCurrentTime: true, groupOrientation: "horizontal", selectedCellData: [] }); }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "dateCellTemplate": case "resourceCellTemplate": case "dataCellTemplate": case "timeCellTemplate": case "startDayHour": case "endDayHour": case "hoursInterval": case "firstDayOfWeek": case "currentDate": case "startDate": this._cleanWorkSpace(); break; case "groups": this._cleanView(); this._removeAllDayElements(); this._initGrouping(); this.repaint(); break; case "groupOrientation": this._initGroupedStrategy(); this._createAllDayPanelElements(); this._removeAllDayElements(); this._cleanWorkSpace(); break; case "showAllDayPanel": if (this._isVerticalGroupedWorkSpace()) { this._cleanView(); this._removeAllDayElements(); this._initGrouping(); this.repaint(); } else { this._toggleAllDayVisibility(); } break; case "allDayExpanded": this._changeAllDayVisibility(); this.notifyObserver("allDayPanelToggled"); this._attachTablesEvents(); this.headerPanelOffsetRecalculate(); this._updateScrollable(); break; case "onSelectionChanged": this._createSelectionChangedAction(); break; case "onCellClick": this._createCellClickAction(); break; case "onCellContextMenu": this._attachContextMenuEvent(); break; case "intervalCount": this._cleanWorkSpace(); this._toggleWorkSpaceCountClass(); this._toggleFixedScrollableClass(); break; case "crossScrollingEnabled": this._toggleHorizontalScrollClass(); this._dateTableScrollable.option(this._dateTableScrollableConfig()); break; case "width": this.callBase(args); this._dimensionChanged(); break; case "allowMultipleCellSelection": break; case "selectedCellData": break; default: this.callBase(args); } }, _cleanWorkSpace: function _cleanWorkSpace() { this._cleanView(); this._toggleGroupedClass(); this._toggleWorkSpaceWithOddCells(); this._renderView(); }, _init: function _init() { this.callBase(); this._initGrouping(); this._toggleHorizontalScrollClass(); this._toggleWorkSpaceCountClass(); this._toggleWorkSpaceWithOddCells(); this._toggleWorkSpaceOverlappingClass(); this.$element().addClass(COMPONENT_CLASS).addClass(this._getElementClass()); }, _initGrouping: function _initGrouping() { this._initGroupedStrategy(); this._toggleGroupingDirectionClass(); }, _initGroupedStrategy: function _initGroupedStrategy() { var strategyName = this.option("groups").length ? this.option("groupOrientation") : this._getDefaultGroupStrategy(); var Strategy = strategyName === "vertical" ? VerticalGroupedStrategy : HorizontalGroupedStrategy; this._groupedStrategy = new Strategy(this); }, _getDefaultGroupStrategy: function _getDefaultGroupStrategy() { return "horizontal"; }, _isVerticalGroupedWorkSpace: function _isVerticalGroupedWorkSpace() { return !!this.option("groups").length && this.option("groupOrientation") === "vertical"; }, _toggleHorizontalScrollClass: function _toggleHorizontalScrollClass() { this.$element().toggleClass(WORKSPACE_WITH_BOTH_SCROLLS_CLASS, this.option("crossScrollingEnabled")); }, _toggleWorkSpaceCountClass: function _toggleWorkSpaceCountClass() { this.$element().toggleClass(WORKSPACE_WITH_COUNT_CLASS, this._isWorkSpaceWithCount()); }, _isWorkSpaceWithCount: function _isWorkSpaceWithCount() { return this.option("intervalCount") > 1; }, _toggleWorkSpaceWithOddCells: function _toggleWorkSpaceWithOddCells() { this.$element().toggleClass(WORKSPACE_WITH_ODD_CELLS_CLASS, this._isWorkspaceWithOddCells()); }, _isWorkspaceWithOddCells: function _isWorkspaceWithOddCells() { return this.option("hoursInterval") === 0.5; }, _toggleWorkSpaceOverlappingClass: function _toggleWorkSpaceOverlappingClass() { this.$element().toggleClass(WORKSPACE_WITH_OVERLAPPING_CLASS, this._isWorkSpaceWithOverlapping()); }, _isWorkSpaceWithOverlapping: function _isWorkSpaceWithOverlapping() { return this.invoke("getMaxAppointmentsPerCell") !== null; }, _toggleGroupingDirectionClass: function _toggleGroupingDirectionClass() { this.$element().toggleClass(VERTICAL_GROUPED_WORKSPACE_CLASS, this._isVerticalGroupedWorkSpace()); }, _getRealGroupOrientation: function _getRealGroupOrientation() { return this._isVerticalGroupedWorkSpace() ? "vertical" : "horizontal"; }, _getTimePanelClass: function _getTimePanelClass() { return TIME_PANEL_CLASS; }, _getDateTableClass: function _getDateTableClass() { return DATE_TABLE_CLASS; }, _getDateTableRowClass: function _getDateTableRowClass() { return DATE_TABLE_ROW_CLASS; }, _getDateTableCellClass: function _getDateTableCellClass(i, j) { var cellClass = DATE_TABLE_CELL_CLASS + " " + HORIZONTAL_SIZES_CLASS + " " + VERTICAL_SIZES_CLASS; return this._needApplyLastGroupCellClass() ? this._groupedStrategy.addAdditionalGroupCellClasses(cellClass, j + 1, i, j) : cellClass; }, _needApplyLastGroupCellClass: function _needApplyLastGroupCellClass() { return true; }, _getGroupRowClass: function _getGroupRowClass() { return GROUP_ROW_CLASS; }, _getGroupHeaderClass: function _getGroupHeaderClass() { return GROUP_HEADER_CLASS; }, _getGroupHeaderContentClass: function _getGroupHeaderContentClass() { return GROUP_HEADER_CONTENT_CLASS; }, _initWorkSpaceUnits: function _initWorkSpaceUnits() { this._$headerPanel = $("<table>"); this._$thead = $("<thead>").appendTo(this._$headerPanel); this._$fixedContainer = $("<div>").addClass(FIXED_CONTAINER_CLASS); this._$allDayContainer = $("<div>").addClass(ALL_DAY_CONTAINER_CLASS); this._initAllDayPanelElements(); this._createAllDayPanelElements(); this._$timePanel = $("<table>").addClass(this._getTimePanelClass()); this._$dateTable = $("<table>"); this._$groupTable = $("<table>").addClass(WORKSPACE_HORIZONTAL_GROUP_TABLE_CLASS); }, _initAllDayPanelElements: function _initAllDayPanelElements() { this._allDayTitles = []; this._allDayTables = []; this._allDayPanels = []; }, _createAllDayPanelElements: function _createAllDayPanelElements() { var groupCount = this._getGroupCount(); if (this._isVerticalGroupedWorkSpace() && groupCount !== 0) { for (var i = 0; i < groupCount; i++) { var $allDayTitle = $("<div>").addClass(ALL_DAY_TITLE_CLASS).text(messageLocalization.format("dxScheduler-allDay")); this._allDayTitles.push($allDayTitle); this._$allDayTable = $("<table>"); this._allDayTables.push(this._$allDayTable); this._$allDayPanel = $("<div>").addClass(ALL_DAY_PANEL_CLASS).append(this._$allDayTable); this._allDayPanels.push(this._$allDayPanel); } } else { this._$allDayTitle = $("<div>").addClass(ALL_DAY_TITLE_CLASS).text(messageLocalization.format("dxScheduler-allDay")).appendTo(this.$element()); this._$allDayTable = $("<table>"); this._$allDayPanel = $("<div>").addClass(ALL_DAY_PANEL_CLASS).append(this._$allDayTable); } }, _initDateTableScrollable: function _initDateTableScrollable() { var $dateTableScrollable = $("<div>").addClass(SCHEDULER_DATE_TABLE_SCROLLABLE_CLASS); this._dateTableScrollable = this._createComponent($dateTableScrollable, Scrollable, this._dateTableScrollableConfig()); }, _dateTableScrollableConfig: function _dateTableScrollableConfig() { var config = { useKeyboard: false, useNative: false, bounceEnabled: false, updateManually: true, pushBackValue: 0 }; if (this._needCreateCrossScrolling()) { config = extend(config, this._createCrossScrollingConfig()); } return config; }, _createCrossScrollingConfig: function _createCrossScrollingConfig() { var config = {}, headerScrollableOnScroll, sidebarScrollableOnScroll; config.direction = "both"; config.onStart = function (e) { if (this._headerScrollable) { headerScrollableOnScroll = this._headerScrollable.option("onScroll"); this._headerScrollable.option("onScroll", undefined); } if (this._sidebarScrollable) { sidebarScrollableOnScroll = this._sidebarScrollable.option("onScroll"); this._sidebarScrollable.option("onScroll", undefined); } }.bind(this); config.onScroll = function (e) { this._sidebarScrollable && this._sidebarScrollable.scrollTo({ top: e.scrollOffset.top }); this._headerScrollable && this._headerScrollable.scrollTo({ left: e.scrollOffset.left }); }.bind(this); config.onEnd = function () { this.notifyObserver("updateResizableArea", {}); this._headerScrollable && this._headerScrollable.option("onScroll", headerScrollableOnScroll); this._sidebarScrollable && this._sidebarScrollable.option("onScroll", sidebarScrollableOnScroll); }.bind(this); return config; }, _createWorkSpaceElements: function _createWorkSpaceElements() { if (this.option("crossScrollingEnabled")) { this._createWorkSpaceScrollableElements(); } else { this._createWorkSpaceStaticElements(); } }, _createWorkSpaceStaticElements: function _createWorkSpaceStaticElements() { if (this._isVerticalGroupedWorkSpace()) { this._dateTableScrollable.$content().append(this._$allDayContainer, this._$groupTable, this._$timePanel, this._$dateTable); this.$element().append(this._$fixedContainer, this._$headerPanel, this._dateTableScrollable.$element()); } else { this._dateTableScrollable.$content().append(this._$timePanel, this._$dateTable); this.$element().append(this._$fixedContainer, this._$headerPanel, this._$allDayContainer, this._$allDayPanel, this._dateTableScrollable.$element()); } }, _createWorkSpaceScrollableElements: function _createWorkSpaceScrollableElements() { this.$element().append(this._$fixedContainer); this._createHeaderScrollable(); this._createSidebarScrollable(); this.$element().append(this._dateTableScrollable.$element()); this._headerScrollable.$content().append(this._$headerPanel); this._dateTableScrollable.$content().append(this._$dateTable); if (this._isVerticalGroupedWorkSpace()) { this._dateTableScrollable.$content().prepend(this._$allDayContainer); this._sidebarScrollable.$content().append(this._$groupTable, this._$timePanel); } else { this._headerScrollable.$content().append(this._$allDayContainer, this._$allDayPanel); } this._sidebarScrollable.$content().append(this._$timePanel); }, _createHeaderScrollable: function _createHeaderScrollable() { var dateTableScrollableOnScroll, $headerScrollable = $("<div>").addClass(SCHEDULER_HEADER_SCROLLABLE_CLASS).appendTo(this.$element()); this._headerScrollable = this._createComponent($headerScrollable, Scrollable, { useKeyboard: false, showScrollbar: false, direction: "horizontal", useNative: false, updateManually: true, bounceEnabled: false, pushBackValue: 0, onStart: function (e) { dateTableScrollableOnScroll = this._dateTableScrollable.option("onScroll"); this._dateTableScrollable.option("onScroll", undefined); }.bind(this), onScroll: function (e) { this._dateTableScrollable.scrollTo({ left: e.scrollOffset.left }); }.bind(this), onEnd: function (e) { this._dateTableScrollable.option("onScroll", dateTableScrollableOnScroll); }.bind(this) }); }, _createSidebarScrollable: function _createSidebarScrollable() { var dateTableScrollableOnScroll, $timePanelScrollable = $("<div>").addClass(SCHEDULER_SIDEBAR_SCROLLABLE_CLASS).appendTo(this.$element()); this._sidebarScrollable = this._createComponent($timePanelScrollable, Scrollable, { useKeyboard: false, showScrollbar: false, direction: "vertical", useNative: false, updateManually: true, bounceEnabled: false, pushBackValue: 0, onStart: function (e) { dateTableScrollableOnScroll = this._dateTableScrollable.option("onScroll"); this._dateTableScrollable.option("onScroll", undefined); }.bind(this), onScroll: function (e) { this._dateTableScrollable.scrollTo({ top: e.scrollOffset.top }); }.bind(this), onEnd: function (e) { this._dateTableScrollable.option("onScroll", dateTableScrollableOnScroll); }.bind(this) }); }, _visibilityChanged: function _visibilityChanged(visible) { if (visible && this._isVerticalGroupedWorkSpace()) { this._setHorizontalGroupHeaderCellsHeight(); } if (visible && this._needCreateCrossScrolling()) { this._setTableSizes(); } }, _attachTableClasses: function _attachTableClasses() { this._addTableClass(this._$dateTable, this._getDateTableClass()); if (this._isVerticalGroupedWorkSpace()) { var groupCount = this._getGroupCount(); for (var i = 0; i < groupCount; i++) { this._addTableClass(this._allDayTables[i], ALL_DAY_TABLE_CLASS); } } else { this._addTableClass(this._$allDayTable, ALL_DAY_TABLE_CLASS); } }, _attachHeaderTableClasses: function _attachHeaderTableClasses() { this._addTableClass(this._$headerPanel, HEADER_PANEL_CLASS); }, _addTableClass: function _addTableClass($el, className) { $el && !$el.hasClass(className) && $el.addClass(className); }, _setTableSizes: function _setTableSizes() { this._attachTableClasses(); var cellWidth = this.getCellWidth(); if (cellWidth < DATE_TABLE_MIN_CELL_WIDTH) { cellWidth = DATE_TABLE_MIN_CELL_WIDTH; } var minWidth = this._groupedStrategy.getWorkSpaceMinWidth(), $headerCells = this._$headerPanel.find("tr").last().find("th"); var width = cellWidth * $headerCells.length; if (width < minWidth) { width = minWidth; } this._$headerPanel.width(width); this._$dateTable.width(width); this._$allDayTable && this._$allDayTable.width(width); this._attachHeaderTableClasses(); if (this._isVerticalGroupedWorkSpace()) { this._setHorizontalGroupHeaderCellsHeight(); } }, _dimensionChanged: function _dimensionChanged() { if (this.option("crossScrollingEnabled")) { this._setTableSizes(); } this.headerPanelOffsetRecalculate(); this._cleanCellDataCache(); this._cleanAllowedPositions(); }, _needCreateCrossScrolling: function _needCreateCrossScrolling() { return this.option("crossScrollingEnabled"); }, _getElementClass: noop, _getRowCount: noop, _getCellCount: noop, _initMarkup: function _initMarkup() { this._initWorkSpaceUnits(); this._initDateTableScrollable(); this._createWorkSpaceElements(); this.callBase(); if (!this.option("crossScrollingEnabled")) { this._attachTableClasses(); this._attachHeaderTableClasses(); } this._toggleGroupedClass(); this._toggleFixedScrollableClass(); this._renderView(); this._attachEvents(); this._setFocusOnCellByOption(this.option("selectedCellData")); }, _render: function _render() { this.callBase(); this._renderDateTimeIndication(); this._setIndicationUpdateInterval(); }, _toggleGroupedClass: function _toggleGroupedClass() { this.$element().toggleClass(GROUPED_WORKSPACE_CLASS, this._getGroupCount() > 0); }, _toggleFixedScrollableClass: noop, _renderView: function _renderView() { this._setFirstViewDate(); this._applyCellTemplates(this._renderGroupHeader()); this._renderDateHeader(); this._renderTimePanel(); if (this._isVerticalGroupedWorkSpace()) { var groupCount = this._getGroupCount(); for (var i = 0; i < groupCount; i++) { this._renderAllDayPanel(i); } } this._renderAllDayPanel(); this._renderDateTable(); if (this._isVerticalGroupedWorkSpace() && windowUtils.hasWindow()) { this._setHorizontalGroupHeaderCellsHeight(); } this._shader = new VerticalShader(); }, _renderDateTimeIndication: noop, _setIndicationUpdateInterval: noop, _refreshDateTimeIndication: noop, _setFocusOnCellByOption: function _setFocusOnCellByOption(data) { var cells = []; this._releaseFocusedCell(); for (var i = 0; i < data.length; i++) { var groups = data[i].groups, groupIndex = groups ? this._getGroupIndexByResourceId(groups) : 0, allDay = !!data[i].allDay, coordinates = this.getCoordinatesByDate(data[i].startDate, groupIndex, allDay), $cell = this._getCellByCoordinates(coordinates, groupIndex); if (isDefined($cell)) { this._toggleFocusClass(true, $cell); cells.push($cell); } } this._focusedCells = cells; }, _getGroupIndexByResourceId: function _getGroupIndexByResourceId(id) { var groups = this.option("groups"), groupKey = Object.keys(id)[0], groupValue = id[groupKey], tree = this.invoke("createResourcesTree", groups), index = 0; for (var i = 0; i < tree.length; i++) { if (tree[i].name === groupKey && tree[i].value === groupValue) { index = tree[i].leafIndex; } } return index; }, _setFirstViewDate: function _setFirstViewDate() { var firstDayOfWeek = isDefined(this._firstDayOfWeek()) ? this._firstDayOfWeek() : dateLocalization.firstDayOfWeekIndex(); this._firstViewDate = dateUtils.getFirstWeekDate(this._getViewStartByOptions(), firstDayOfWeek); this._setStartDayHour(this._firstViewDate); }, _getViewStartByOptions: function _getViewStartByOptions() { if (!this.option("startDate")) { return this.option("currentDate"); } else { var startDate = dateUtils.trimTime(this._getStartViewDate()), currentDate = this.option("currentDate"), diff = startDate.getTime() <= currentDate.getTime() ? 1 : -1, endDate = new Date(startDate.getTime() + this._getIntervalDuration() * diff); while (!this._dateInRange(currentDate, startDate, endDate, diff)) { startDate = endDate; endDate = new Date(startDate.getTime() + this._getIntervalDuration() * diff); } return diff > 0 ? startDate : endDate; } }, _getStartViewDate: function _getStartViewDate() { return this.option("startDate"); }, _dateInRange: function _dateInRange(date, startDate, endDate, diff) { return diff > 0 ? dateUtils.dateInRange(date, startDate, new Date(endDate.getTime() - 1)) : dateUtils.dateInRange(date, endDate, startDate, "date"); }, _getIntervalDuration: function _getIntervalDuration() { return toMs("day") * this.option("intervalCount"); }, _setStartDayHour: function _setStartDayHour(date) { var startDayHour = this.option("startDayHour"); if (isDefined(startDayHour)) { date.setHours(startDayHour, startDayHour % 1 * 60, 0, 0); } }, _firstDayOfWeek: function _firstDayOfWeek() { return this.option("firstDayOfWeek"); }, _attachEvents: function _attachEvents() { this._createSelectionChangedAction(); this._attachClickEvent(); this._attachContextMenuEvent(); }, _attachClickEvent: function _attachClickEvent() { var that = this; var pointerDownAction = this._createAction(function (e) { that._pointerDownHandler(e.event); }); this._createCellClickAction(); var cellSelector = "." + DATE_TABLE_CELL_CLASS + ",." + ALL_DAY_TABLE_CELL_CLASS; var $element = this.$element(); eventsEngine.off($element, SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME); eventsEngine.off($element, SCHEDULER_CELL_DXCLICK_EVENT_NAME); eventsEngine.on($element, SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME, function (e) { if (eventUtils.isMouseEvent(e) && e.which > 1) { e.preventDefault(); return; } pointerDownAction({ event: e }); }); eventsEngine.on($element, SCHEDULER_CELL_DXCLICK_EVENT_NAME, cellSelector, function (e) { var $cell = $(e.target); that._cellClickAction({ event: e, cellElement: getPublicElement($cell), cellData: that.getCellData($cell) }); }); }, _createCellClickAction: function _createCellClickAction() { var that = this; this._cellClickAction = this._createActionByOption("onCellClick", { afterExecute: function afterExecute(e) { that._moveToClosestNonStub(e.args[0].event); } }); }, _createSelectionChangedAction: function _createSelectionChangedAction() { this._selectionChangedAction = this._createActionByOption("onSelectionChanged"); }, _moveToClosestNonStub: function _moveToClosestNonStub(e) { var $target = $(e.target); if (this._showPopup && this._hasFocusClass($target)) { delete this._showPopup; this._showAddAppointmentPopup($target); } }, _pointerDownHandler: function _pointerDownHandler(e) { var $target = $(e.target); if (!$target.hasClass(DATE_TABLE_CELL_CLASS) && !$target.hasClass(ALL_DAY_TABLE_CELL_CLASS)) { this._isCellClick = false; return; } this._isCellClick = true; if ($target.hasClass(DATE_TABLE_FOCUSED_CELL_CLASS)) { this._showPopup = true; } else { this._setFocusedCell($target); } }, _showAddAppointmentPopup: function _showAddAppointmentPopup($cell) { var firstCellData = this.getCellData($cell.first()), lastCellData = this.getCellData($cell.last()); var args = { startDate: firstCellData.startDate, endDate: lastCellData.endDate }; if (isDefined(lastCellData.allDay)) { args.allDay = lastCellData.allDay; } extend(args, lastCellData.groups); this.notifyObserver("showAddAppointmentPopup", args); }, _attachContextMenuEvent: function _attachContextMenuEvent() { this._createContextMenuAction(); var cellSelector = "." + DATE_TABLE_CELL_CLASS + ",." + ALL_DAY_TABLE_CELL_CLASS, $element = this.$element(), eventName = eventUtils.addNamespace(contextMenuEvent.name, this.NAME); eventsEngine.off($element, eventName, cellSelector); eventsEngine.on($element, eventName, cellSelector, this._contextMenuHandler.bind(this)); }, _contextMenuHandler: function _contextMenuHandler(e) { var $cell = $(e.target); this._contextMenuAction({ event: e, cellElement: getPublicElement($cell), cellData: this.getCellData($cell) }); this._contextMenuHandled = true; }, _createContextMenuAction: function _createContextMenuAction() { this._contextMenuAction = this._createActionByOption("onCellContextMenu"); }, _getGroupHeaderContainer: function _getGroupHeaderContainer() { if (this._isVerticalGroupedWorkSpace()) { return this._$groupTable; } return this._$thead; }, _getDateHeaderContainer: function _getDateHeaderContainer() { return this._$thead; }, _renderGroupHeader: function _renderGroupHeader() { var $container = this._getGroupHeaderContainer(), groupCount = this._getGroupCount(), cellTemplates = []; if (groupCount) { var groupRows = this._makeGroupRows(this.option("groups")); this._attachGroupCountAttr(groupCount, groupRows); $container.append(groupRows.elements); cellTemplates = groupRows.cellTemplates; } else { this._detachGroupCountAttr(); } return cellTemplates; }, _applyCellTemplates: function _applyCellTemplates(templates) { templates.forEach(function (template) { template(); }); }, _detachGroupCountAttr: function _detachGroupCountAttr() { var groupedAttr = this._groupedStrategy.getGroupCountAttr(); this.$element().removeAttr(groupedAttr.attr); }, _attachGroupCountAttr: function _attachGroupCountAttr(groupRowCount, groupRows) { var groupedAttr = this._groupedStrategy.getGroupCountAttr(groupRowCount, groupRows); this.$element().attr(groupedAttr.attr, groupedAttr.count); }, headerPanelOffsetRecalculate: function headerPanelOffsetRecalculate() { if (!this.option("resourceCellTemplate") && !this.option("dateCellTemplate")) { return; } var headerPanelHeight = this.getHeaderPanelHeight(), headerHeight = this.invoke("getHeaderHeight"), allDayPanelHeight = this.supportAllDayRow() && this.option("showAllDayPanel") ? this._groupedStrategy.getAllDayTableHeight() : 0; headerPanelHeight && this._headerScrollable && this._headerScrollable.$element().height(headerPanelHeight + allDayPanelHeight); headerPanelHeight && this._dateTableScrollable.$element().css({ "paddingBottom": allDayPanelHeight + headerPanelHeight + "px", "marginBottom": -1 * (parseInt(headerPanelHeight, 10) + allDayPanelHeight) + "px" }); headerPanelHeight && this._sidebarScrollable && this._sidebarScrollable.$element().css({ "paddingBottom": allDayPanelHeight + headerPanelHeight + "px", "marginBottom": -1 * (parseInt(headerPanelHeight, 10) + allDayPanelHeight) + "px" }); this._$allDayTitle && this._$allDayTitle.css("top", headerHeight + headerPanelHeight + "px"); }, _makeGroupRows: function _makeGroupRows(groups) { var tableCreatorStrategy = this._isVerticalGroupedWorkSpace() ? tableCreator.VERTICAL : tableCreator.HORIZONTAL; return tableCreator.makeGroupedTable(tableCreatorStrategy, groups, { groupRowClass: this._getGroupRowClass(), groupHeaderClass: this._getGroupHeaderClass(), groupHeaderContentClass: this._getGroupHeaderContentClass() }, this._getCellCount() || 1, this.option("resourceCellTemplate")); }, _getDateHeaderTemplate: function _getDateHeaderTemplate() { return this.option("dateCellTemplate"); }, _renderDateHeader: function _renderDateHeader() { var $container = this._getDateHeaderContainer(), $headerRow = $("<tr>").addClass(HEADER_ROW_CLASS), count = this._getCellCount(), cellTemplate = this._getDateHeaderTemplate(), repeatCount = this._calculateHeaderCellRepeatCount(), templateCallbacks = []; for (var j = 0; j < repeatCount; j++) { for (var i = 0; i < count; i++) { var text = this._getHeaderText(i), $cell = $("<th>").addClass(this._getHeaderPanelCellClass(i)).attr("title", text); if (cellTemplate && cellTemplate.render) { templateCallbacks.push(cellTemplate.render.bind(cellTemplate, { model: { text: text, date: this._getDateByIndex(i) }, index: j * repeatCount + i, container: getPublicElement($cell) })); } else { $cell.text(text); } $headerRow.append($cell); } } $container.append($headerRow); this._applyCellTemplates(templateCallbacks); return $headerRow; }, _getHeaderPanelCellClass: function _getHeaderPanelCellClass(i) { var cellClass = HEADER_PANEL_CELL_CLASS + " " + HORIZONTAL_SIZES_CLASS; return this._groupedStrategy.addAdditionalGroupCellClasses(cellClass, i + 1); }, _calculateHeaderCellRepeatCount: function _calculateHeaderCellRepeatCount() { return this._groupedStrategy.calculateHeaderCellRepeatCount(); }, _renderAllDayPanel: function _renderAllDayPanel(index) { var cellCount = this._getCellCount(); if (!this._isVerticalGroupedWorkSpace()) { cellCount *= this._getGroupCount() || 1; } var cellTemplates = this._renderTableBody({ container: this._allDayPanels.length ? getPublicElement(this._allDayTables[index]) : getPublicElement(this._$allDayTable), rowCount: 1, cellCount: cellCount, cellClass: this._getAllDayPanelCellClass.bind(this), rowClass: ALL_DAY_TABLE_ROW_CLASS, cellTemplate: this.option("dataCellTemplate"), getCellData: this._getAllDayCellData.bind(this), groupIndex: index }, true); this._toggleAllDayVisibility(); this._applyCellTemplates(cellTemplates); }, _getAllDayPanelCellClass: function _getAllDayPanelCellClass(i, j) { var cellClass = ALL_DAY_TABLE_CELL_CLASS + " " + HORIZONTAL_SIZES_CLASS; return this._groupedStrategy.addAdditionalGroupCellClasses(cellClass, j + 1); }, _getAllDayCellData: function _getAllDayCellData(cell, rowIndex, cellIndex, groupIndex) { var startDate = this._getDateByCellIndexes(rowIndex, cellIndex); startDate = dateUtils.trimTime(startDate); var data = { startDate: startDate, endDate: new Date(startDate.getTime() + DAY_MS), allDay: true }; var groups = this._getCellGroups(groupIndex || this._getGroupIndex(rowIndex, cellIndex)); if (groups.length) { data.groups = {}; } for (var i = 0; i < groups.length; i++) { data.groups[groups[i].name] = groups[i].id; } return { key: CELL_DATA, value: data }; }, _toggleAllDayVisibility: function _toggleAllDayVisibility() { var showAllDayPanel = this.option("showAllDayPanel"); this._$allDayPanel.toggle(showAllDayPanel); this._$allDayTitle && this._$allDayTitle.toggleClass(ALL_DAY_TITLE_HIDDEN_CLASS, !showAllDayPanel); this.$element().toggleClass(WORKSPACE_WITH_ALL_DAY_CLASS, showAllDayPanel); this._changeAllDayVisibility(); showAllDayPanel && this._updateScrollable(); }, _changeAllDayVisibility: function _changeAllDayVisibility() { this.$element().toggleClass(WORKSPACE_WITH_COLLAPSED_ALL_DAY_CLASS, !this.option("allDayExpanded") && this.option("showAllDayPanel")); }, _updateScrollable: function _updateScrollable() { this._dateTableScrollable.update(); this._headerScrollable && this._headerScrollable.update(); this._sidebarScrollable && this._sidebarScrollable.update(); }, _renderTimePanel: function _renderTimePanel() { var repeatCount = this._groupedStrategy.calculateTimeCellRepeatCount(); this._renderTableBody({ container: getPublicElement(this._$timePanel), rowCount: this._getTimePanelRowCou