devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
369 lines (367 loc) • 15.9 kB
JavaScript
/**
* DevExtreme (cjs/__internal/scheduler/appointment_popup/m_popup.js)
* Version: 25.2.7
* Build date: Tue May 05 2026
*
* Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AppointmentPopup = exports.APPOINTMENT_POPUP_CLASS = void 0;
var _visibility_change = require("../../../common/core/events/visibility_change");
var _message = _interopRequireDefault(require("../../../common/core/localization/message"));
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _date = _interopRequireDefault(require("../../../core/utils/date"));
var _deferred = require("../../../core/utils/deferred");
var _extend = require("../../../core/utils/extend");
var _size = require("../../../core/utils/size");
var _window = require("../../../core/utils/window");
var _ui = _interopRequireDefault(require("../../../ui/popup/ui.popup"));
var _themes = require("../../../ui/themes");
var _m_loading = require("../m_loading");
var _appointment_adapter = require("../utils/appointment_adapter/appointment_adapter");
var _appointment_groups_utils = require("../utils/resource_manager/appointment_groups_utils");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const APPOINTMENT_POPUP_CLASS = exports.APPOINTMENT_POPUP_CLASS = "dx-scheduler-appointment-popup";
const POPUP_FULL_SCREEN_MODE_WINDOW_WIDTH_THRESHOLD = 485;
class AppointmentPopup {
get popup() {
return this._popup
}
get visible() {
var _this$_popup;
return Boolean(null === (_this$_popup = this._popup) || void 0 === _this$_popup ? void 0 : _this$_popup.option("visible"))
}
constructor(scheduler, form) {
this.config = {
onSave: () => Promise.resolve(),
title: "",
readOnly: false
};
this.scheduler = scheduler;
this.form = form;
this.state = {
saveChangesLocker: false,
appointment: {
data: null
}
}
}
show(appointment, config) {
this.state.appointment.data = appointment;
this.config = config;
this.disposePopup();
const popupConfig = this.createPopupConfig();
this.createPopup(popupConfig);
this._popup.show()
}
hide() {
var _this$_popup2;
null === (_this$_popup2 = this._popup) || void 0 === _this$_popup2 || _this$_popup2.hide()
}
dispose() {
this.disposePopup()
}
disposePopup() {
if (this._popup) {
const $element = this._popup.$element();
this.form.dispose();
this._popup.dispose();
$element.remove();
this._popup = void 0
}
}
createPopup(options) {
const popupElement = (0, _renderer.default)("<div>").addClass(APPOINTMENT_POPUP_CLASS).appendTo(this.scheduler.getElement());
this.scheduler.createComponent(popupElement, _ui.default, options)
}
createPopupConfig() {
const editingConfig = this.scheduler.getEditingConfig();
const customPopupOptions = (null === editingConfig || void 0 === editingConfig ? void 0 : editingConfig.popup) ?? {};
this.customPopupOptions = customPopupOptions;
const defaultPopupConfig = {
height: "auto",
maxHeight: "90%",
showCloseButton: false,
showTitle: false,
preventScrollEvents: false,
enableBodyScroll: false,
_ignorePreventScrollEventsDeprecation: true,
onInitialized: e => {
var _customPopupOptions$o;
this._popup = e.component;
null === customPopupOptions || void 0 === customPopupOptions || null === (_customPopupOptions$o = customPopupOptions.onInitialized) || void 0 === _customPopupOptions$o || _customPopupOptions$o.call(customPopupOptions, e)
},
onHiding: e => {
var _customPopupOptions$o2;
this.scheduler.focus();
null === customPopupOptions || void 0 === customPopupOptions || null === (_customPopupOptions$o2 = customPopupOptions.onHiding) || void 0 === _customPopupOptions$o2 || _customPopupOptions$o2.call(customPopupOptions, e)
},
contentTemplate: () => {
this.form.create({
dxPopup: this.popup,
updateToolbarForMainGroup: () => this.updateToolbarForMainGroup(),
updateToolbarForRecurrenceGroup: () => this.updateToolbarForRecurrenceGroup()
});
return this.form.dxForm.$element()
},
onShowing: e => {
var _customPopupOptions$o3;
this.onShowing(e);
null === customPopupOptions || void 0 === customPopupOptions || null === (_customPopupOptions$o3 = customPopupOptions.onShowing) || void 0 === _customPopupOptions$o3 || _customPopupOptions$o3.call(customPopupOptions, e)
},
wrapperAttr: {
class: APPOINTMENT_POPUP_CLASS
}
};
return (0, _extend.extend)(true, {}, defaultPopupConfig, customPopupOptions, {
onInitialized: defaultPopupConfig.onInitialized,
onHiding: defaultPopupConfig.onHiding,
onShowing: defaultPopupConfig.onShowing
})
}
onShowing(e) {
this.updateForm();
e.component.$overlayContent().attr("aria-label", _message.default.format("dxScheduler-ariaEditForm"));
const arg = {
form: this.form.dxForm,
popup: this.popup,
appointmentData: this.state.appointment.data,
cancel: false
};
this.scheduler.getAppointmentFormOpening()(arg);
this.scheduler.processActionResult(arg, canceled => {
if (canceled) {
e.cancel = true
} else {
this.updatePopupFullScreenMode()
}
})
}
createAppointmentAdapter(rawAppointment) {
return new _appointment_adapter.AppointmentAdapter(rawAppointment, this.scheduler.getDataAccessors())
}
updateForm() {
const rawAppointment = this.state.appointment.data;
const appointmentAdapter = this.createAppointmentAdapter(rawAppointment).clone().calculateDates(this.scheduler.getTimeZoneCalculator(), "toAppointment");
const formData = this.createFormData(appointmentAdapter);
this.form.readOnly = this.config.readOnly;
this.form.formData = formData;
this.form.showMainGroup()
}
createFormData(appointmentAdapter) {
const {
resources: resources
} = this.scheduler.getResourceManager();
const groupValues = (0, _appointment_groups_utils.getRawAppointmentGroupValues)(appointmentAdapter.source, resources);
const {
allDayExpr: allDayExpr,
recurrenceRuleExpr: recurrenceRuleExpr
} = this.scheduler.getDataAccessors().expr;
return Object.assign({}, appointmentAdapter.source, groupValues, {
[allDayExpr]: Boolean(appointmentAdapter.allDay),
[recurrenceRuleExpr]: appointmentAdapter.recurrenceRule
})
}
triggerResize() {
var _this$popup;
if (null !== (_this$popup = this.popup) && void 0 !== _this$popup && _this$popup.$element()) {
(0, _visibility_change.triggerResizeEvent)(this.popup.$element())
}
}
getMaxWidth() {
var _this$customPopupOpti, _this$customPopupOpti2;
if (void 0 !== (null === (_this$customPopupOpti = this.customPopupOptions) || void 0 === _this$customPopupOpti ? void 0 : _this$customPopupOpti.maxWidth)) {
return this.customPopupOptions.maxWidth
}
if (void 0 !== (null === (_this$customPopupOpti2 = this.customPopupOptions) || void 0 === _this$customPopupOpti2 ? void 0 : _this$customPopupOpti2.width)) {
return this.customPopupOptions.width
}
return (0, _themes.isFluent)((0, _themes.current)()) ? 380 : 420
}
updatePopupFullScreenMode() {
if (this.visible) {
var _this$customPopupOpti3;
const isPopupFullScreenNeeded = () => {
const window = (0, _window.getWindow)();
const width = window && (0, _size.getWidth)(window);
return width < 485
};
const isFullScreen = isPopupFullScreenNeeded();
this.popup.option("fullScreen", isFullScreen);
if (void 0 !== (null === (_this$customPopupOpti3 = this.customPopupOptions) || void 0 === _this$customPopupOpti3 ? void 0 : _this$customPopupOpti3.width)) {
this.popup.option("width", this.customPopupOptions.width)
}
const maxWidth = this.getMaxWidth();
this.popup.option("maxWidth", isFullScreen ? "100%" : maxWidth)
}
}
saveChangesAsync(isShowLoadPanel) {
this.form.saveRecurrenceValue();
const deferred = new _deferred.Deferred;
const validation = this.form.dxForm.validate();
isShowLoadPanel && this.showLoadPanel();
(0, _deferred.when)((null === validation || void 0 === validation ? void 0 : validation.complete) ?? validation).done(validation => {
if (validation && !validation.isValid) {
(0, _m_loading.hide)();
deferred.resolve(false);
return
}
const adapter = this.createAppointmentAdapter(this.form.formData);
const clonedAdapter = adapter.clone().calculateDates(this.scheduler.getTimeZoneCalculator(), "fromAppointment");
this.addMissingDSTTime(adapter, clonedAdapter);
const appointment = clonedAdapter.source;
(0, _deferred.when)(this.config.onSave(appointment)).done(deferred.resolve);
deferred.done(() => {
(0, _m_loading.hide)()
})
});
return deferred.promise()
}
saveButtonClickHandler(e) {
e.cancel = true;
this.saveEditDataAsync()
}
saveEditDataAsync() {
const deferred = new _deferred.Deferred;
if (this.tryLockSaveChanges()) {
(0, _deferred.when)(this.saveChangesAsync(true)).done(() => {
this.unlockSaveChanges();
deferred.resolve()
})
}
return deferred.promise()
}
showLoadPanel() {
const container = this.popup.$overlayContent();
(0, _m_loading.show)({
container: container,
position: {
of: container
}
})
}
tryLockSaveChanges() {
if (false === this.state.saveChangesLocker) {
this.state.saveChangesLocker = true;
return true
}
return false
}
unlockSaveChanges() {
this.state.saveChangesLocker = false
}
addMissingDSTTime(formAppointmentAdapter, clonedAppointmentAdapter) {
const timeZoneCalculator = this.scheduler.getTimeZoneCalculator();
clonedAppointmentAdapter.startDate = this.addMissingDSTShiftToDate(timeZoneCalculator, formAppointmentAdapter.startDate, clonedAppointmentAdapter.startDate);
if (clonedAppointmentAdapter.endDate) {
clonedAppointmentAdapter.endDate = this.addMissingDSTShiftToDate(timeZoneCalculator, formAppointmentAdapter.endDate, clonedAppointmentAdapter.endDate)
}
}
addMissingDSTShiftToDate(timeZoneCalculator, originFormDate, clonedDate) {
var _timeZoneCalculator$g, _timeZoneCalculator$g2;
const originTimezoneShift = null === (_timeZoneCalculator$g = timeZoneCalculator.getOffsets(originFormDate)) || void 0 === _timeZoneCalculator$g ? void 0 : _timeZoneCalculator$g.common;
const clonedTimezoneShift = null === (_timeZoneCalculator$g2 = timeZoneCalculator.getOffsets(clonedDate)) || void 0 === _timeZoneCalculator$g2 ? void 0 : _timeZoneCalculator$g2.common;
const shiftDifference = originTimezoneShift - clonedTimezoneShift;
return shiftDifference ? new Date(clonedDate.getTime() + shiftDifference * _date.default.dateToMilliseconds("hour")) : clonedDate
}
tryApplyCustomToolbarItems() {
var _this$customPopupOpti4;
if (null !== (_this$customPopupOpti4 = this.customPopupOptions) && void 0 !== _this$customPopupOpti4 && _this$customPopupOpti4.toolbarItems) {
this.popup.option("toolbarItems", this.customPopupOptions.toolbarItems);
return true
}
return false
}
updateToolbarForMainGroup() {
if (this.tryApplyCustomToolbarItems()) {
return
}
const toolbarItems = [{
toolbar: "top",
location: "before",
text: this.config.title,
cssClass: "dx-toolbar-label"
}];
const canSave = !this.form.readOnly;
if (canSave) {
toolbarItems.push({
toolbar: "top",
location: "after",
options: {
onClick: e => this.saveButtonClickHandler(e),
stylingMode: "contained",
type: "default",
text: _message.default.format("dxScheduler-editPopupSaveButtonText")
},
shortcut: "done"
})
}
toolbarItems.push({
toolbar: "top",
location: "after",
shortcut: "cancel",
options: {
stylingMode: "outlined"
}
});
this.popup.option("toolbarItems", toolbarItems)
}
updateToolbarForRecurrenceGroup() {
if (this.tryApplyCustomToolbarItems()) {
return
}
const toolbarItems = [{
toolbar: "top",
location: "before",
widget: "dxButton",
options: {
icon: "arrowleft",
stylingMode: "text",
elementAttr: {
"aria-label": _message.default.format("Back")
},
onClick: () => {
this.form.saveRecurrenceValue();
this.form.showMainGroup()
}
}
}, {
toolbar: "top",
location: "before",
text: _message.default.format("dxScheduler-editorLabelRecurrence"),
cssClass: "dx-toolbar-label"
}];
const canSave = !this.form.readOnly;
if (canSave) {
toolbarItems.push({
toolbar: "top",
location: "after",
options: {
onClick: e => this.saveButtonClickHandler(e),
stylingMode: "contained",
type: "default",
text: _message.default.format("dxScheduler-editPopupSaveButtonText")
},
shortcut: "done"
})
}
toolbarItems.push({
toolbar: "top",
location: "after",
shortcut: "cancel",
options: {
stylingMode: "outlined"
}
});
this.popup.option("toolbarItems", toolbarItems)
}
}
exports.AppointmentPopup = AppointmentPopup;