devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
502 lines (500 loc) • 22.9 kB
JavaScript
/**
* DevExtreme (cjs/__internal/scheduler/appointment_popup/m_recurrence_form.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.RecurrenceForm = void 0;
var _message = _interopRequireDefault(require("../../../common/core/localization/message"));
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _extend = require("../../../core/utils/extend");
var _button = _interopRequireDefault(require("../../../ui/button"));
var _localized_items = require("./localized_items");
var _utils = require("./utils");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const CLASSES = {
groupWithIcon: "dx-scheduler-form-group-with-icon",
formIcon: "dx-scheduler-form-icon",
recurrenceGroup: "dx-scheduler-form-recurrence-group",
recurrenceHidden: "dx-scheduler-form-recurrence-group-hidden",
recurrenceStartDateEditor: "dx-scheduler-form-recurrence-start-date-editor",
frequencyEditor: "dx-scheduler-form-recurrence-frequency-editor",
byMonthEditor: "dx-scheduler-form-recurrence-by-month-editor",
dayOfMonthEditor: "dx-scheduler-form-day-of-month-editor",
countEditor: "dx-scheduler-form-recurrence-count-editor",
daysOfWeekButtons: "dx-scheduler-days-of-week-buttons",
dayOfMonthGroup: "dx-scheduler-form-day-of-month-group",
dayOfYearGroup: "dx-scheduler-form-day-of-year-group",
recurrenceEndGroup: "dx-scheduler-form-recurrence-end-group",
recurrenceEndEditors: "dx-scheduler-form-recurrence-end-editors",
recurrenceSettingsGroup: "dx-scheduler-form-recurrence-settings-group"
};
const FREQ = {
HOURLY: "hourly",
DAILY: "daily",
WEEKLY: "weekly",
MONTHLY: "monthly",
YEARLY: "yearly"
};
const EDITOR_NAMES = {
recurrenceStartDateEditor: "recurrenceStartDateEditor",
recurrenceCountEditor: "recurrenceCountEditor",
recurrencePeriodEditor: "recurrencePeriodEditor",
recurrenceDayOfYearMonthEditor: "recurrenceDayOfYearMonthEditor",
recurrenceDayOfMonthEditor: "recurrenceDayOfMonthEditor",
recurrenceDayOfYearDayEditor: "recurrenceDayOfYearDayEditor",
recurrenceEndEditor: "recurrenceEndEditor",
recurrenceRepeatEndEditor: "recurrenceRepeatEndEditor",
recurrenceEndUntilEditor: "recurrenceEndUntilEditor",
recurrenceEndCountEditor: "recurrenceEndCountEditor",
recurrenceEndSpacer: "recurrenceEndSpacer"
};
const GROUP_NAMES = {
recurrenceStartDateGroup: "recurrenceStartDateGroup",
recurrenceRuleGroup: "recurrenceRuleGroup",
recurrencePatternGroup: "recurrencePatternGroup",
recurrenceRuleRepeatGroup: "recurrenceRuleRepeatGroup",
recurrenceEndGroup: "recurrenceEndGroup",
recurrenceDaysOfWeekEditor: "recurrenceDaysOfWeekEditor",
recurrenceDayOfYearGroup: "recurrenceDayOfYearGroup",
recurrenceEndEditorsGroup: "recurrenceEndEditorsGroup"
};
const ICON_NAMES = {
recurrenceStartDateIcon: "recurrenceStartDateIcon",
recurrenceRuleIcon: "recurrenceRuleIcon",
recurrenceEndIcon: "recurrenceEndIcon"
};
const RECURRENCE_GROUP_NAME = "recurrenceGroup";
class RecurrenceForm {
constructor(scheduler) {
this.recurrenceRule = new _utils.RecurrenceRule("", new Date);
this.weekDayButtons = {};
this.readOnly = false;
this.scheduler = scheduler
}
createByMonthDayNumberBoxItem(name, labelVisible) {
return {
itemType: "simple",
name: name,
colSpan: 1,
editorType: "dxNumberBox",
cssClass: CLASSES.dayOfMonthEditor,
label: labelVisible ? {
text: _message.default.format("dxScheduler-recurrenceRepeatOn")
} : {
visible: false
},
editorOptions: Object.assign({}, labelVisible ? {} : {
labelMode: "hidden"
}, {
min: 1,
max: 31,
format: "#",
showSpinButtons: true,
useLargeSpinButtons: false,
onContentReady: e => {
e.component.option("value", this.recurrenceRule.byMonthDay ?? void 0)
},
onValueChanged: e => {
this.recurrenceRule.byMonthDay = e.value
}
})
}
}
get dxForm() {
return this.dxFormInstance
}
set dxForm(value) {
this.dxFormInstance = value
}
setReadOnly(value) {
this.readOnly = value
}
createRecurrenceFormGroup() {
return {
name: "recurrenceGroup",
itemType: "group",
cssClass: `${CLASSES.recurrenceGroup} ${CLASSES.recurrenceHidden}`,
colSpan: 1,
items: [this.createRecurrenceStartDateGroup(), this.createRecurrenceSettingsGroup(), this.createRecurrenceEndGroup()]
}
}
createRecurrenceStartDateGroup() {
return {
name: GROUP_NAMES.recurrenceStartDateGroup,
itemType: "group",
cssClass: CLASSES.groupWithIcon,
items: [{
name: ICON_NAMES.recurrenceStartDateIcon,
colSpan: 1,
cssClass: CLASSES.formIcon,
template: (0, _utils.createFormIconTemplate)("clock")
}, (0, _extend.extend)(true, (0, _utils.getStartDateCommonConfig)(this.scheduler.getFirstDayOfWeek()), {
name: EDITOR_NAMES.recurrenceStartDateEditor,
cssClass: CLASSES.recurrenceStartDateEditor,
label: {
text: _message.default.format("dxScheduler-editorLabelStartDate")
},
editorOptions: {
onContentReady: e => {
e.component.option("value", this.recurrenceRule.startDate)
},
onValueChanged: e => {
this.recurrenceRule.startDate = e.value
}
}
})]
}
}
createRecurrenceSettingsGroup() {
return {
itemType: "group",
name: GROUP_NAMES.recurrenceRuleGroup,
cssClass: `${CLASSES.recurrenceSettingsGroup} ${CLASSES.groupWithIcon}`,
items: [{
name: ICON_NAMES.recurrenceRuleIcon,
colSpan: 1,
cssClass: CLASSES.formIcon,
template: (0, _utils.createFormIconTemplate)("repeat")
}, {
itemType: "group",
name: GROUP_NAMES.recurrencePatternGroup,
colSpan: 1,
colCount: 1,
colCountByScreen: {
xs: 1
},
items: [this.createRecurrenceRuleGroup(), this.createDaysOfWeekGroup(), this.createDayOfMonthGroup(), this.createDayOfYearGroup()]
}]
}
}
createRecurrenceRuleGroup() {
let needRestoreFrequencyEditorFocus = false;
return {
itemType: "group",
name: GROUP_NAMES.recurrenceRuleRepeatGroup,
colSpan: 1,
colCount: 2,
colCountByScreen: {
xs: 2
},
items: [{
itemType: "simple",
name: EDITOR_NAMES.recurrenceCountEditor,
colSpan: 1,
editorType: "dxNumberBox",
label: {
text: _message.default.format("dxScheduler-recurrenceRepeatEvery")
},
editorOptions: {
format: "#",
min: 1,
showSpinButtons: true,
useLargeSpinButtons: false,
onContentReady: e => {
e.component.option("value", this.recurrenceRule.interval)
},
onValueChanged: e => {
this.recurrenceRule.interval = e.value
}
}
}, {
itemType: "simple",
name: EDITOR_NAMES.recurrencePeriodEditor,
cssClass: CLASSES.frequencyEditor,
colSpan: 1,
editorType: "dxSelectBox",
label: {
visible: false
},
editorOptions: {
labelMode: "hidden",
items: (0, _localized_items.getRecurrenceFrequencyItems)(),
valueExpr: "value",
displayExpr: "text",
onContentReady: e => {
e.component.option("value", this.recurrenceRule.frequency);
if (needRestoreFrequencyEditorFocus) {
setTimeout(() => {
e.component.focus();
needRestoreFrequencyEditorFocus = false
})
}
},
onValueChanged: e => {
const previousValue = this.recurrenceRule.frequency;
if (previousValue === e.value) {
return
}
if (e.event) {
needRestoreFrequencyEditorFocus = true
}
this.recurrenceRule.frequency = e.value;
this.updateDayEditorsVisibility()
}
}
}]
}
}
createDaysOfWeekGroup() {
return {
name: GROUP_NAMES.recurrenceDaysOfWeekEditor,
colSpan: 1,
cssClass: "dx-field-item-has-group",
label: {
visible: false
},
template: () => {
const $container = (0, _renderer.default)("<div>").addClass(CLASSES.daysOfWeekButtons);
const weekDayItems = (0, _localized_items.getRecurrenceWeekDayItems)(this.scheduler.getFirstDayOfWeek());
weekDayItems.forEach(item => {
var _this$weekDayButtons$;
const buttonContainer = (0, _renderer.default)("<div>").appendTo($container);
null === (_this$weekDayButtons$ = this.weekDayButtons[item.key]) || void 0 === _this$weekDayButtons$ || _this$weekDayButtons$.dispose();
this.weekDayButtons[item.key] = this.scheduler.createComponent(buttonContainer, _button.default, {
text: item.text,
disabled: this.readOnly,
onContentReady: e => {
(0, _renderer.default)(e.element).removeClass("dx-button-has-text");
const isSelected = this.recurrenceRule.byDay.includes(item.key);
e.component.option("stylingMode", isSelected ? "contained" : "outlined");
e.component.option("type", isSelected ? "default" : "normal")
},
onClick: e => {
const isSelected = this.recurrenceRule.byDay.includes(item.key);
if (isSelected) {
const index = this.recurrenceRule.byDay.indexOf(item.key);
this.recurrenceRule.byDay.splice(index, 1);
e.component.option("stylingMode", "outlined");
e.component.option("type", "normal")
} else {
this.recurrenceRule.byDay.push(item.key);
e.component.option("stylingMode", "contained");
e.component.option("type", "default")
}
}
})
});
return $container
}
}
}
createDayOfMonthGroup() {
return Object.assign({}, this.createByMonthDayNumberBoxItem(EDITOR_NAMES.recurrenceDayOfMonthEditor, true), {
cssClass: `${CLASSES.dayOfMonthEditor} ${CLASSES.dayOfMonthGroup}`
})
}
createDayOfYearGroup() {
return {
itemType: "group",
name: GROUP_NAMES.recurrenceDayOfYearGroup,
cssClass: CLASSES.dayOfYearGroup,
colCount: 2,
colCountByScreen: {
xs: 2
},
items: [{
itemType: "simple",
name: EDITOR_NAMES.recurrenceDayOfYearMonthEditor,
colSpan: 1,
cssClass: CLASSES.byMonthEditor,
editorType: "dxSelectBox",
label: {
text: _message.default.format("dxScheduler-recurrenceRepeatEvery")
},
editorOptions: {
items: (0, _localized_items.getRecurrenceMonthItems)(),
displayExpr: "text",
valueExpr: "value",
onContentReady: e => {
e.component.option("value", this.recurrenceRule.byMonth)
},
onValueChanged: e => {
this.recurrenceRule.byMonth = e.value
}
}
}, this.createByMonthDayNumberBoxItem(EDITOR_NAMES.recurrenceDayOfYearDayEditor, false)]
}
}
createRecurrenceEndGroup() {
return {
name: GROUP_NAMES.recurrenceEndGroup,
itemType: "group",
cssClass: `${CLASSES.groupWithIcon} ${CLASSES.recurrenceEndGroup}`,
items: [{
name: ICON_NAMES.recurrenceEndIcon,
colSpan: 1,
cssClass: CLASSES.formIcon,
template: (0, _utils.createFormIconTemplate)("description")
}, {
itemType: "group",
name: EDITOR_NAMES.recurrenceEndEditor,
colSpan: 1,
colCount: 2,
colCountByScreen: {
xs: 2
},
label: {
text: _message.default.format("dxScheduler-recurrenceEnd")
},
items: [this.createRecurrenceEndRadioGroup(), this.createRecurrenceEndEditors()]
}]
}
}
createRecurrenceEndRadioGroup() {
return {
itemType: "simple",
name: EDITOR_NAMES.recurrenceRepeatEndEditor,
colSpan: 1,
editorType: "dxRadioGroup",
label: {
visible: false
},
editorOptions: {
labelMode: "hidden",
valueExpr: "type",
items: [{
text: _message.default.format("dxScheduler-recurrenceNever"),
type: "never"
}, {
text: _message.default.format("dxScheduler-recurrenceOn"),
type: "until"
}, {
text: _message.default.format("dxScheduler-recurrenceAfter"),
type: "count"
}],
layout: "vertical",
onContentReady: e => {
e.component.option("value", this.recurrenceRule.repeatEnd)
},
onValueChanged: e => {
this.recurrenceRule.repeatEnd = e.value;
this.updateRepeatEndEditors()
}
}
}
}
createRecurrenceEndEditors() {
return {
itemType: "group",
name: GROUP_NAMES.recurrenceEndEditorsGroup,
cssClass: CLASSES.recurrenceEndEditors,
colSpan: 1,
items: [{
itemType: "empty",
name: EDITOR_NAMES.recurrenceEndSpacer
}, {
itemType: "simple",
name: EDITOR_NAMES.recurrenceEndUntilEditor,
label: {
visible: false
},
editorType: "dxDateBox",
editorOptions: {
labelMode: "hidden",
type: "date",
useMaskBehavior: true,
calendarOptions: {
firstDayOfWeek: this.scheduler.getFirstDayOfWeek()
},
inputAttr: {
"aria-label": _message.default.format("dxScheduler-recurrenceUntilDateLabel")
},
onContentReady: e => {
const repeatEndValue = this.recurrenceRule.repeatEnd;
e.component.option("value", this.recurrenceRule.until);
e.component.option("disabled", "until" !== repeatEndValue)
},
onValueChanged: e => {
this.recurrenceRule.until = e.value
}
}
}, {
itemType: "simple",
name: EDITOR_NAMES.recurrenceEndCountEditor,
cssClass: CLASSES.countEditor,
label: {
visible: false
},
editorType: "dxNumberBox",
editorOptions: {
labelMode: "hidden",
format: `# ${_message.default.format("dxScheduler-recurrenceRepeatCount")}`,
min: 1,
showSpinButtons: true,
useLargeSpinButtons: false,
inputAttr: {
"aria-label": _message.default.format("dxScheduler-recurrenceOccurrenceLabel")
},
onContentReady: e => {
const repeatEndValue = this.recurrenceRule.repeatEnd;
e.component.option("value", this.recurrenceRule.count ?? void 0);
e.component.option("disabled", "count" !== repeatEndValue)
},
onValueChanged: e => {
this.recurrenceRule.count = e.value
}
}
}]
}
}
updateRecurrenceFormValues(recurrenceRuleRaw, startDate) {
var _this$dxForm$getEdito, _this$dxForm$getEdito2, _this$dxForm$getEdito3, _this$dxForm$getEdito4, _this$dxForm$getEdito5, _this$dxForm$getEdito6;
this.recurrenceRule = this.createRecurrenceRule(recurrenceRuleRaw, startDate);
null === (_this$dxForm$getEdito = this.dxForm.getEditor(EDITOR_NAMES.recurrenceStartDateEditor)) || void 0 === _this$dxForm$getEdito || _this$dxForm$getEdito.option("value", this.recurrenceRule.startDate);
null === (_this$dxForm$getEdito2 = this.dxForm.getEditor(EDITOR_NAMES.recurrencePeriodEditor)) || void 0 === _this$dxForm$getEdito2 || _this$dxForm$getEdito2.option("value", this.recurrenceRule.frequency);
null === (_this$dxForm$getEdito3 = this.dxForm.getEditor(EDITOR_NAMES.recurrenceCountEditor)) || void 0 === _this$dxForm$getEdito3 || _this$dxForm$getEdito3.option("value", this.recurrenceRule.interval);
null === (_this$dxForm$getEdito4 = this.dxForm.getEditor(EDITOR_NAMES.recurrenceRepeatEndEditor)) || void 0 === _this$dxForm$getEdito4 || _this$dxForm$getEdito4.option("value", this.recurrenceRule.repeatEnd);
null === (_this$dxForm$getEdito5 = this.dxForm.getEditor(EDITOR_NAMES.recurrenceEndUntilEditor)) || void 0 === _this$dxForm$getEdito5 || _this$dxForm$getEdito5.option("value", this.recurrenceRule.until);
null === (_this$dxForm$getEdito6 = this.dxForm.getEditor(EDITOR_NAMES.recurrenceEndCountEditor)) || void 0 === _this$dxForm$getEdito6 || _this$dxForm$getEdito6.option("value", this.recurrenceRule.count);
this.updateRepeatEndEditors();
this.updateDayEditorsVisibility()
}
createRecurrenceRule(recurrenceRuleRaw, startDate) {
const recurrenceRule = new _utils.RecurrenceRule(recurrenceRuleRaw ?? "", startDate);
if (0 === recurrenceRule.byDay.length) {
const defaultByDay = [_localized_items.ICAL_WEEK_DAYS[(null === startDate || void 0 === startDate ? void 0 : startDate.getDay()) ?? this.scheduler.getFirstDayOfWeek()]];
recurrenceRule.byDay = defaultByDay
}
return recurrenceRule
}
updateRepeatEndEditors() {
const repeatEndValue = this.recurrenceRule.repeatEnd;
const untilEditor = this.dxForm.getEditor(EDITOR_NAMES.recurrenceEndUntilEditor);
const countEditor = this.dxForm.getEditor(EDITOR_NAMES.recurrenceEndCountEditor);
null === untilEditor || void 0 === untilEditor || untilEditor.option("disabled", "until" !== repeatEndValue);
null === countEditor || void 0 === countEditor || countEditor.option("disabled", "count" !== repeatEndValue)
}
updateDayEditorsVisibility() {
const recurrencePatternGroupPath = `recurrenceGroup.${GROUP_NAMES.recurrenceRuleGroup}.${GROUP_NAMES.recurrencePatternGroup}`;
const daysOfWeekGroup = `${recurrencePatternGroupPath}.${GROUP_NAMES.recurrenceDaysOfWeekEditor}`;
const dayOfMonthGroup = `${recurrencePatternGroupPath}.${EDITOR_NAMES.recurrenceDayOfMonthEditor}`;
const dayOfYearGroup = `${recurrencePatternGroupPath}.${GROUP_NAMES.recurrenceDayOfYearGroup}`;
this.dxForm.beginUpdate();
this.dxForm.itemOption(daysOfWeekGroup, "visible", false);
this.dxForm.itemOption(dayOfMonthGroup, "visible", false);
this.dxForm.itemOption(dayOfYearGroup, "visible", false);
switch (this.recurrenceRule.frequency) {
case FREQ.WEEKLY:
this.dxForm.itemOption(daysOfWeekGroup, "visible", true);
break;
case FREQ.MONTHLY:
this.dxForm.itemOption(dayOfMonthGroup, "visible", true);
break;
case FREQ.YEARLY:
this.dxForm.itemOption(dayOfYearGroup, "visible", true)
}
this.dxForm.endUpdate()
}
}
exports.RecurrenceForm = RecurrenceForm;