UNPKG

devexpress-reporting

Version:

DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.

176 lines (175 loc) 8.46 kB
/** * DevExpress HTML/JS Reporting (viewer\widgets\dateRange\dateRangeEditor.viewmodel.js) * Version: 25.2.3 * Build date: Dec 15, 2025 * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * License: https://www.devexpress.com/Support/EULAs/universal.xml */ import { createViewModelGenerator } from '@devexpress/analytics-core/analytics-serializer-native'; import { getLocalization, getParentContainer, $dx, KeyboardEnum, guid, $unwrap, calculateWithZoomFactor } from '@devexpress/analytics-core/analytics-internal-native'; import { predefinedDateRanges, predefinedDateRangesModel, predefinedTimeRanges } from './dateRangeEditor.ranges'; import dxButton from 'devextreme/ui/button'; import { getTemplate } from '@devexpress/analytics-core/analytics-utils-native'; const predefinedDateRangesDefaultGroupCount = 4; const predefinedDateRangesGroupItemsCount = 3; function getPredefinedTimeRangeItemElement(item, id) { const element = document.createElement('div'); element.id = id; element.classList.add(...['dxrv-predefined-timerange', 'dx-accessibility-timerange-item']); new dxButton(element, { template: function (data, container) { const rootElement = $unwrap(container); rootElement.classList.add('dxrv-predefined-timerange-button'); const icon = document.createElement('span'); icon.classList.add('dxrv-predefined-timerange-button-icon'); icon.innerHTML = getTemplate(item.iconTemplate); const text = document.createElement('div'); text.classList.add('dxrv-predefined-timerange-text'); text.innerText = data.text; rootElement.appendChild(icon); rootElement.appendChild(text); }, text: item.displayName, width: '140px', hint: item.displayName }); return element; } export function createPredefinedGroupedItemsViewModel(editor) { const items = (editor.isTimeOnlyType ? predefinedTimeRanges : predefinedDateRanges).map(x => { const timeRangeItemId = `dxrv-timerange-${x.displayName.replace(/\s+/g, '')}-${guid()}`; return createViewModelGenerator({ ...x, click: () => editor.applyDate(x.range(), true), template: editor.isTimeOnlyType ? getPredefinedTimeRangeItemElement(x, timeRangeItemId) : undefined, id: timeRangeItemId, ratio: 1, }) .generateProperty('selected', editor._isSelected(x)) .getViewModel(); }); const itemsInGroup = 3; const groupedItems = []; for (let i = 0; i < items.length; i += itemsInGroup) { const group = items.slice(i, i + itemsInGroup); if (group.length == 2) group[1].ratio = 2; groupedItems.push(group); } return groupedItems; } export function createDateRangeEditorViewModel(baseViewModel) { let popupSettings = null; const inRange = (date) => { const _end = new Date(viewModel.endRange.value.getTime()); const _start = new Date(viewModel.startRange.value.getTime()); return date <= new Date(_end.setHours(0, 0, 0, 0)) && date >= new Date(_start.setHours(0, 0, 0, 0)); }; const timeRangeItemEnterEvent = (e, item, dialogKeyboardHelper) => { if (e.key == KeyboardEnum.Enter || e.key == KeyboardEnum.Space) { item.itemData.click(); dialogKeyboardHelper.changeSelections(item.itemData); } else if (e.key == KeyboardEnum.Esc) { dialogKeyboardHelper?.itemHandleEscKey(e); } }; const createPredefinedItemsViewModel = () => (this.isTimeOnlyType ? predefinedTimeRanges : predefinedDateRanges).map(x => { return createViewModelGenerator({ ...x, click: () => this.applyDate(x.range(), true) }) .generateProperty('selected', this._isSelected(x)) .getViewModel(); }); const viewModel = createViewModelGenerator({ ...baseViewModel, showPopup: () => this._showPopup(), popupTemplate: this.popupTemplate, items: this.items, cacheElement: ($element) => this._$element = $dx($element), scrollViewOptions: { showScrollbar: 'always', direction: 'horizontal', useNative: false, onInitialized: function (e) { e.component.option('useKeyboard', false); } }, _editorInputId: this._editorInputId, _displayName: this._displayName }) .generateProperty('getPopupSettings', (isTimeOnly) => { if (!popupSettings) { const timeOnlyRangePopupMaxHeight = 260 + 35 * (Math.ceil(predefinedTimeRanges.length / predefinedDateRangesGroupItemsCount) - predefinedDateRangesDefaultGroupCount); popupSettings = createViewModelGenerator({ width: isTimeOnly ? '490px' : 'max-content', maxHeight: isTimeOnly ? `${timeOnlyRangePopupMaxHeight}px` : '350px', height: calculateWithZoomFactor(362), wrapperAttr: { class: 'dxrv-daterange-editor-popup-wrapper' }, elementAttr: { class: isTimeOnly ? 'dx-accessibility-timerange-item' : '' }, position: { my: 'right top', at: 'right bottom', of: this._$element[0], collision: 'fit fit', offset: '1 -1' }, container: getParentContainer(this._$element[0]), showTitle: false, showCloseButton: false, hideOnOutsideClick: true, onHidden: (e) => this._popupVisible = false, animation: {}, shading: false, }) .generateProperty('visible', this._popupVisible) .getViewModel(); } return popupSettings; }) .generateProperty('onRangeItemsRendered', (item) => { $unwrap(item.itemElement)?.addEventListener('keydown', (e) => timeRangeItemEnterEvent(e, item, this.dialogKeyboardHelper)); }) .generateProperty('onRangeItemClick', (item) => { item.itemData.click(); this.dialogKeyboardHelper?.changeSelections(item.itemData); }) .generateProperty('dialogKeyboardHelper', this.dialogKeyboardHelper) .generateProperty('predefinedDateRanges', createViewModelGenerator({ attr: { 'aria-label': getLocalization('Predefined periods', 'ASPxReportsStringId.WebDocumentViewer_AriaLabelPredefinedPeriods') }, accessibilityKeyboardHelper: !this.isTimeOnlyType ? this.dialogKeyboardHelper.predefinedDateRangesKeyboardHelper : undefined, scrollViewOptions: { showScrollbar: 'onHover', scrollByContent: false, bounceEnabled: false, useNative: false, scrollByThumb: true, onInitialized: function (e) { e.component.option('useKeyboard', false); } } }) .generateProperty('items', createPredefinedItemsViewModel()) .generateProperty('groupedItems', createPredefinedGroupedItemsViewModel(this)) .getViewModel()) .generateProperty('startRange', createViewModelGenerator({ height: this.calendarHeight, inRange: (date) => inRange(date), onValueChanged: (e) => this.startDate = e.value }) .generateProperty('value', this.startDate) .getViewModel()) .generateProperty('endRange', createViewModelGenerator({ height: this.calendarHeight, inRange: (date) => inRange(date), onValueChanged: (e) => this.endDate = e.value }) .generateProperty('value', this.endDate) .generateProperty('min', this.startDate) .getViewModel()) .generateProperty('disabled', this.disabled) .generateProperty('visible', this.visible) .generateProperty('displayValue', this._displayText) .generateProperty('type', this.type) .getViewModel(); this.addDisposable(predefinedDateRangesModel.events.on('dateRangesChanged', (e) => { viewModel.predefinedDateRanges.items = createPredefinedItemsViewModel(); })); this.addDisposable(predefinedDateRangesModel.events.on('timeRangesChanged', (e) => { viewModel.predefinedDateRanges.groupedItems = createPredefinedGroupedItemsViewModel(this); })); viewModel.popupModel = this['_options'].isMobile ? this.popupModel.getViewModel() : viewModel; return viewModel; }