dhtmlx-scheduler 7.2.11 → 7.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  })(this, function(exports2) {
4
4
  "use strict";/** @license
5
5
 
6
- dhtmlxScheduler v.7.2.11 Standard
6
+ dhtmlxScheduler v.7.2.13 Standard
7
7
 
8
8
  To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product), please obtain Commercial/Enterprise or Ultimate license on our site https://dhtmlx.com/docs/products/dhtmlxScheduler/#licensing or contact us at sales@dhtmlx.com
9
9
 
@@ -1301,7 +1301,7 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
1301
1301
  if (scheduler2._dp && scheduler2._dp._in_progress[event2.id]) {
1302
1302
  return;
1303
1303
  }
1304
- if (type === "add-event") {
1304
+ if (type === "add-event" && scheduler2._dp) {
1305
1305
  for (const id in scheduler2._dp._in_progress) {
1306
1306
  if (scheduler2._dp.getState(id) === "inserted") {
1307
1307
  scheduler2._dp.attachEvent("onFullSync", function() {
@@ -1340,9 +1340,13 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
1340
1340
  console.warn(`Event with ID ${eventData.id} already exists. Skipping add.`);
1341
1341
  return;
1342
1342
  }
1343
- eventData.start_date = scheduler2.templates.parse_date(eventData.start_date);
1344
- eventData.end_date = scheduler2.templates.parse_date(eventData.end_date);
1345
- if (eventData.original_start) {
1343
+ if (typeof eventData.start_date === "string") {
1344
+ eventData.start_date = scheduler2.templates.parse_date(eventData.start_date);
1345
+ }
1346
+ if (typeof eventData.end_date === "string") {
1347
+ eventData.end_date = scheduler2.templates.parse_date(eventData.end_date);
1348
+ }
1349
+ if (eventData.original_start && typeof eventData.original_start === "string") {
1346
1350
  eventData.original_start = scheduler2.templates.parse_date(eventData.original_start);
1347
1351
  }
1348
1352
  ignore(() => {
@@ -1362,10 +1366,14 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
1362
1366
  existingEvent[key] = eventData[key];
1363
1367
  }
1364
1368
  }
1365
- existingEvent.start_date = scheduler2.templates.parse_date(eventData.start_date);
1366
- existingEvent.end_date = scheduler2.templates.parse_date(eventData.end_date);
1367
- if (eventData.original_start) {
1368
- eventData.original_start = scheduler2.templates.parse_date(eventData.original_start);
1369
+ if (typeof eventData.start_date === "string") {
1370
+ existingEvent.start_date = scheduler2.templates.parse_date(eventData.start_date);
1371
+ }
1372
+ if (typeof eventData.end_date === "string") {
1373
+ existingEvent.end_date = scheduler2.templates.parse_date(eventData.end_date);
1374
+ }
1375
+ if (eventData.original_start && typeof eventData.original_start === "string") {
1376
+ existingEvent.original_start = scheduler2.templates.parse_date(eventData.original_start);
1369
1377
  }
1370
1378
  scheduler2.callEvent("onEventChanged", [sid, existingEvent]);
1371
1379
  scheduler2.updateEvent(sid);
@@ -2095,18 +2103,21 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
2095
2103
  });
2096
2104
  return views.concat(date).concat(nav);
2097
2105
  }
2106
+ scheduler2._getInitialState = function(provided) {
2107
+ const initialDate = provided.date || this._currentDate();
2108
+ const initialView = provided.mode || "week";
2109
+ return { date: initialDate, mode: initialView };
2110
+ };
2098
2111
  scheduler2.init = function(id, date, mode) {
2099
2112
  if (this.$destroyed) {
2100
2113
  return;
2101
2114
  }
2102
- date = date || scheduler2._currentDate();
2103
- mode = mode || "week";
2104
- if (this._obj) {
2105
- this.unset_actions();
2106
- }
2107
2115
  this._obj = typeof id == "string" ? document.getElementById(id) : id;
2108
2116
  this.$container = this._obj;
2109
2117
  this.$root = this._obj;
2118
+ if (this._obj) {
2119
+ this.unset_actions();
2120
+ }
2110
2121
  if (!this.$container.offsetHeight && this.$container.offsetWidth && this.$container.style.height === "100%") {
2111
2122
  window.console.error(scheduler2._commonErrorMessages.collapsedContainer(), this.$container);
2112
2123
  }
@@ -2144,9 +2155,12 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
2144
2155
  this._init_once();
2145
2156
  this._init_touch_events();
2146
2157
  this.set_sizes();
2158
+ const initialState = scheduler2._getInitialState({ date, mode });
2159
+ const initialDate = initialState.date;
2160
+ const initialMode = initialState.mode;
2147
2161
  scheduler2.callEvent("onSchedulerReady", []);
2148
2162
  scheduler2.$initialized = true;
2149
- this.setCurrentView(date, mode);
2163
+ this.setCurrentView(initialDate, initialMode);
2150
2164
  };
2151
2165
  scheduler2.xy = { min_event_height: 20, bar_height: 24, scale_width: 50, scroll_width: 18, scale_height: 20, month_scale_height: 20, menu_width: 25, margin_top: 0, margin_left: 0, editor_width: 140, month_head_height: 22, event_header_height: 14 };
2152
2166
  scheduler2.keys = { edit_save: 13, edit_cancel: 27 };
@@ -9257,7 +9271,7 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
9257
9271
  }
9258
9272
  }
9259
9273
  function factoryMethod(extensionManager) {
9260
- const scheduler2 = { version: "7.2.11" };
9274
+ const scheduler2 = { version: "7.2.13" };
9261
9275
  scheduler2.$stateProvider = StateService();
9262
9276
  scheduler2.getState = scheduler2.$stateProvider.getState;
9263
9277
  extend$n(scheduler2);
@@ -10309,74 +10323,95 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
10309
10323
  }
10310
10324
  }
10311
10325
  function cookie(scheduler2) {
10312
- function setCookie(name, cookie_param, value) {
10313
- const str = `${name}=${value}${cookie_param ? `; ${cookie_param}` : ""}`;
10314
- document.cookie = `${str}; Secure`;
10315
- }
10316
- function getCookie(name) {
10317
- var search = name + "=";
10318
- if (document.cookie.length > 0) {
10319
- var offset = document.cookie.indexOf(search);
10320
- if (offset != -1) {
10321
- offset += search.length;
10322
- var end = document.cookie.indexOf(";", offset);
10323
- if (end == -1)
10324
- end = document.cookie.length;
10325
- return document.cookie.substring(offset, end);
10326
- }
10326
+ function getStorageKey() {
10327
+ return (scheduler2._obj.id || "scheduler") + "_settings";
10328
+ }
10329
+ const dateToString = scheduler2.date.date_to_str("%Y-%m-%d %H:%i");
10330
+ const stringToDate = scheduler2.date.str_to_date("%Y-%m-%d %H:%i");
10331
+ function safeLocalStorageGet(key) {
10332
+ try {
10333
+ return window.localStorage.getItem(key);
10334
+ } catch (e) {
10335
+ return null;
10327
10336
  }
10328
- return "";
10329
10337
  }
10330
- function getCookieName(scheduler3) {
10331
- return (scheduler3._obj.id || "scheduler") + "_settings";
10338
+ function safeLocalStorageSet(key, value) {
10339
+ try {
10340
+ window.localStorage.setItem(key, value);
10341
+ return true;
10342
+ } catch (e) {
10343
+ return false;
10344
+ }
10332
10345
  }
10333
- var first = true;
10334
- scheduler2.attachEvent("onBeforeViewChange", function(oldMode, oldDate, mode, date) {
10335
- if (first && scheduler2._get_url_nav) {
10336
- var urlNavigationPlugin = scheduler2._get_url_nav();
10337
- if (urlNavigationPlugin.date || urlNavigationPlugin.mode || urlNavigationPlugin.event) {
10338
- first = false;
10346
+ function readStoredState() {
10347
+ const storageKey = getStorageKey();
10348
+ const raw = safeLocalStorageGet(storageKey);
10349
+ if (!raw) {
10350
+ return { date: null, mode: null };
10351
+ }
10352
+ let parsed;
10353
+ try {
10354
+ parsed = JSON.parse(raw);
10355
+ } catch (e) {
10356
+ return { date: null, mode: null };
10357
+ }
10358
+ if (!parsed || typeof parsed !== "object") {
10359
+ return { date: null, mode: null };
10360
+ }
10361
+ let parsedDate = null;
10362
+ if (typeof parsed.date === "string" && parsed.date.length > 0) {
10363
+ try {
10364
+ parsedDate = stringToDate(parsed.date);
10365
+ if (isNaN(+parsedDate)) {
10366
+ parsedDate = null;
10367
+ }
10368
+ } catch (e) {
10369
+ parsedDate = null;
10339
10370
  }
10340
10371
  }
10341
- var cookie2 = getCookieName(scheduler2);
10342
- if (first) {
10343
- first = false;
10344
- var schedulerCookie = getCookie(cookie2);
10345
- if (schedulerCookie) {
10346
- if (!scheduler2._min_date) {
10347
- scheduler2._min_date = date;
10372
+ const parsedMode = typeof parsed.mode === "string" ? parsed.mode : null;
10373
+ return { date: parsedDate, mode: parsedMode };
10374
+ }
10375
+ function urlHasExplicitNavigation() {
10376
+ if (!scheduler2._get_url_nav) {
10377
+ return false;
10378
+ }
10379
+ const urlState = scheduler2._get_url_nav();
10380
+ if (!urlState) {
10381
+ return false;
10382
+ }
10383
+ if (urlState.date || urlState.mode || urlState.event) {
10384
+ return true;
10385
+ }
10386
+ return false;
10387
+ }
10388
+ const originalGetInitialState = scheduler2._getInitialState;
10389
+ scheduler2._getInitialState = function(provided) {
10390
+ const baseState = originalGetInitialState.call(this, provided);
10391
+ if (urlHasExplicitNavigation()) {
10392
+ return baseState;
10393
+ }
10394
+ const storedState = readStoredState();
10395
+ const nextState = { date: baseState.date, mode: baseState.mode };
10396
+ if (storedState.date) {
10397
+ nextState.date = storedState.date;
10398
+ }
10399
+ if (storedState.mode) {
10400
+ try {
10401
+ if (this.isViewExists(storedState.mode)) {
10402
+ nextState.mode = storedState.mode;
10348
10403
  }
10349
- schedulerCookie = unescape(schedulerCookie).split("@");
10350
- schedulerCookie[0] = this._helpers.parseDate(schedulerCookie[0]);
10351
- var view = this.isViewExists(schedulerCookie[1]) ? schedulerCookie[1] : mode, date = !isNaN(+schedulerCookie[0]) ? schedulerCookie[0] : date;
10352
- window.setTimeout(function() {
10353
- if (scheduler2.$destroyed) {
10354
- return;
10355
- }
10356
- scheduler2.setCurrentView(date, view);
10357
- }, 1);
10358
- return false;
10404
+ } catch (e) {
10359
10405
  }
10360
10406
  }
10361
- return true;
10362
- });
10407
+ return nextState;
10408
+ };
10363
10409
  scheduler2.attachEvent("onViewChange", function(newMode, newDate) {
10364
- var cookie2 = getCookieName(scheduler2);
10365
- var text = escape(this._helpers.formatDate(newDate) + "@" + newMode);
10366
- setCookie(cookie2, "expires=Sun, 31 Jan 9999 22:00:00 GMT", text);
10410
+ const storageKey = getStorageKey();
10411
+ const payload = { date: dateToString(newDate), mode: newMode };
10412
+ safeLocalStorageSet(storageKey, JSON.stringify(payload));
10413
+ return true;
10367
10414
  });
10368
- var old_load = scheduler2._load;
10369
- scheduler2._load = function() {
10370
- var args = arguments;
10371
- if (!scheduler2._date) {
10372
- var that = this;
10373
- window.setTimeout(function() {
10374
- old_load.apply(that, args);
10375
- }, 1);
10376
- } else {
10377
- old_load.apply(this, args);
10378
- }
10379
- };
10380
10415
  }
10381
10416
  const notImplemented = { alert: (extension, assert2) => {
10382
10417
  assert2(false, `The ${extension} extension is not included in this version of dhtmlxScheduler.<br>
@@ -15442,41 +15477,39 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
15442
15477
  scheduler2.hideQuickInfo();
15443
15478
  };
15444
15479
  scheduler2._init_quick_info = function() {
15445
- if (!this._quick_info_box) {
15446
- var qi = this._quick_info_box = document.createElement("div");
15447
- this._waiAria.quickInfoAttr(qi);
15448
- qi.className = "dhx_cal_quick_info";
15449
- if (scheduler2.$testmode)
15450
- qi.className += " dhx_no_animate";
15451
- if (scheduler2.config.rtl)
15452
- qi.className += " dhx_quick_info_rtl";
15453
- var ariaAttr = this._waiAria.quickInfoHeaderAttrString();
15454
- var html = `
15455
- <div class="dhx_cal_qi_tcontrols">
15456
- <a class="dhx_cal_qi_close_btn scheduler_icon close"></a>
15480
+ let qi = this._quick_info_box = document.createElement("div");
15481
+ this._waiAria.quickInfoAttr(qi);
15482
+ qi.className = "dhx_cal_quick_info";
15483
+ if (scheduler2.$testmode)
15484
+ qi.className += " dhx_no_animate";
15485
+ if (scheduler2.config.rtl)
15486
+ qi.className += " dhx_quick_info_rtl";
15487
+ let ariaAttr = this._waiAria.quickInfoHeaderAttrString();
15488
+ let html = `
15489
+ <div class="dhx_cal_qi_tcontrols">
15490
+ <a class="dhx_cal_qi_close_btn scheduler_icon close"></a>
15491
+ </div>
15492
+ <div class="dhx_cal_qi_title" ${ariaAttr}>
15493
+
15494
+ <div class="dhx_cal_qi_tcontent"></div>
15495
+ <div class="dhx_cal_qi_tdate"></div>
15457
15496
  </div>
15458
- <div class="dhx_cal_qi_title" ${ariaAttr}>
15459
-
15460
- <div class="dhx_cal_qi_tcontent"></div>
15461
- <div class="dhx_cal_qi_tdate"></div>
15462
- </div>
15463
- <div class="dhx_cal_qi_content"></div>`;
15464
- html += '<div class="dhx_cal_qi_controls">';
15465
- var buttons = scheduler2.config.icons_select;
15466
- for (var i = 0; i < buttons.length; i++) {
15467
- var ariaAttr = this._waiAria.quickInfoButtonAttrString(this.locale.labels[buttons[i]]);
15468
- html += `<div ${ariaAttr} class="dhx_qi_big_icon ${buttons[i]}" title="${scheduler2.locale.labels[buttons[i]]}">
15469
- <div class='dhx_menu_icon ${buttons[i]}'></div><div>${scheduler2.locale.labels[buttons[i]]}</div></div>`;
15470
- }
15471
- html += "</div>";
15472
- qi.innerHTML = html;
15473
- scheduler2.event(qi, "click", function(ev) {
15474
- scheduler2._qi_button_click(ev.target || ev.srcElement);
15475
- });
15476
- if (scheduler2.config.quick_info_detached) {
15477
- scheduler2._detachDomEvent(scheduler2._els["dhx_cal_data"][0], "scroll", scheduler2._quick_info_onscroll_handler);
15478
- scheduler2.event(scheduler2._els["dhx_cal_data"][0], "scroll", scheduler2._quick_info_onscroll_handler);
15479
- }
15497
+ <div class="dhx_cal_qi_content"></div>`;
15498
+ html += '<div class="dhx_cal_qi_controls">';
15499
+ let buttons = scheduler2.config.icons_select;
15500
+ for (let i = 0; i < buttons.length; i++) {
15501
+ let ariaAttr2 = this._waiAria.quickInfoButtonAttrString(this.locale.labels[buttons[i]]);
15502
+ html += `<div ${ariaAttr2} class="dhx_qi_big_icon ${buttons[i]}" title="${scheduler2.locale.labels[buttons[i]]}">
15503
+ <div class='dhx_menu_icon ${buttons[i]}'></div><div>${scheduler2.locale.labels[buttons[i]]}</div></div>`;
15504
+ }
15505
+ html += "</div>";
15506
+ qi.innerHTML = html;
15507
+ scheduler2.event(qi, "click", function(ev) {
15508
+ scheduler2._qi_button_click(ev.target || ev.srcElement);
15509
+ });
15510
+ if (scheduler2.config.quick_info_detached) {
15511
+ scheduler2._detachDomEvent(scheduler2._els["dhx_cal_data"][0], "scroll", scheduler2._quick_info_onscroll_handler);
15512
+ scheduler2.event(scheduler2._els["dhx_cal_data"][0], "scroll", scheduler2._quick_info_onscroll_handler);
15480
15513
  }
15481
15514
  return this._quick_info_box;
15482
15515
  };
@@ -18210,6 +18243,73 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18210
18243
  return "".concat(header).concat(dateString);
18211
18244
  }
18212
18245
  function recurring(scheduler2) {
18246
+ scheduler2.ext.recurring = { confirm: function(context) {
18247
+ }, confirmDefault: function showRecurringConfirmModal(context) {
18248
+ const labels = context.labels || {};
18249
+ const options = Array.isArray(context.options) ? context.options : [];
18250
+ if (options.length === 0) {
18251
+ return Promise.resolve(null);
18252
+ }
18253
+ if (options.length === 1) {
18254
+ return Promise.resolve(options[0]);
18255
+ }
18256
+ const modalOptions = options.map((decision, index) => ({ value: decision, label: labelForDecision(decision, labels), checked: index === 0 }));
18257
+ return new Promise((resolve) => {
18258
+ scheduler2.modalbox({ text: `<div class="dhx_edit_recurrence_options">
18259
+ ${modalOptions.map((option) => `<label class="dhx_styled_radio">
18260
+ <input type="radio" value="${option.value}" name="option" ${option.checked ? "checked" : ""}>
18261
+ ${option.label}
18262
+ </label>`).join("")}
18263
+ </div>`, type: "recurring_mode", title: labels.title || scheduler2.locale.labels.confirm_recurring, width: "auto", position: "middle", buttons: [{ label: labels.ok || scheduler2.locale.labels.message_ok, value: "ok", css: "rec_ok" }, { label: labels.cancel || scheduler2.locale.labels.message_cancel, value: "cancel" }], callback: function onModalClose(value, event2) {
18264
+ if (value === "cancel") {
18265
+ resolve(null);
18266
+ return;
18267
+ }
18268
+ const box = event2.target.closest(".scheduler_modal_box");
18269
+ const checked = box && box.querySelector("input[type='radio']:checked");
18270
+ const selected = checked ? checked.value : null;
18271
+ if (!selected) {
18272
+ resolve(null);
18273
+ return;
18274
+ }
18275
+ resolve(selected);
18276
+ } });
18277
+ });
18278
+ }, _getDecision: async function _getDecision(context) {
18279
+ const confirmHandler = scheduler2.ext.recurring.confirm;
18280
+ let decision;
18281
+ if (typeof confirmHandler === "function") {
18282
+ decision = await confirmHandler(context);
18283
+ } else {
18284
+ decision = void 0;
18285
+ }
18286
+ if (decision === void 0) {
18287
+ decision = await scheduler2.ext.recurring.confirmDefault(context);
18288
+ }
18289
+ if (decision === null) {
18290
+ return null;
18291
+ }
18292
+ if (context.options && context.options.length > 0) {
18293
+ if (context.options.indexOf(decision) === -1) {
18294
+ console.warning(`[recurring extension] - the custom confirm handler returned a value ("${decision}") which is not in the allowed options list. The allowed options are: [${context.options.join(", ")}]. The operation will be cancelled.`);
18295
+ return null;
18296
+ }
18297
+ }
18298
+ return decision;
18299
+ } };
18300
+ scheduler2.ext.recurring.confirm = scheduler2.ext.recurring.confirmDefault;
18301
+ function labelForDecision(decision, labels) {
18302
+ if (decision === "occurrence") {
18303
+ return labels.occurrence || scheduler2.locale.labels.button_edit_occurrence;
18304
+ }
18305
+ if (decision === "following") {
18306
+ return labels.following || scheduler2.locale.labels.button_edit_occurrence_and_following;
18307
+ }
18308
+ if (decision === "series") {
18309
+ return labels.series || scheduler2.locale.labels.button_edit_series;
18310
+ }
18311
+ return decision;
18312
+ }
18213
18313
  function clearMilliseconds(date) {
18214
18314
  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0);
18215
18315
  }
@@ -18249,10 +18349,14 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18249
18349
  if (ev.rrule.includes(";UNTIL=")) {
18250
18350
  ev.rrule = ev.rrule.split(";UNTIL=")[0];
18251
18351
  }
18252
- let parsedRRule = rrulestr(`RRULE:${ev.rrule};UNTIL=${toIcalString(setUTCPartsToDate(ev._end_date || ev.end_date))}`, { dtstart: ev.start_date });
18253
- let newRRULE = new RRule(parsedRRule.origOptions).toString().replace("RRULE:", "");
18254
- newRRULE = newRRULE.split("\n")[1];
18255
- ev.rrule = newRRULE;
18352
+ let parsedRRule;
18353
+ if (ev.rrule.includes(";COUNT=")) {
18354
+ parsedRRule = rrulestr(`RRULE:${ev.rrule};UNTIL=${toIcalString(setUTCPartsToDate(ev._shorten_end_date))}`, { dtstart: ev.start_date });
18355
+ delete parsedRRule.origOptions.count;
18356
+ } else {
18357
+ parsedRRule = rrulestr(`RRULE:${ev.rrule};UNTIL=${toIcalString(setUTCPartsToDate(ev._end_date || ev.end_date))}`, { dtstart: ev.start_date });
18358
+ }
18359
+ ev.rrule = new RRule(parsedRRule.origOptions).toString().replace("RRULE:", "").split("\n")[1];
18256
18360
  }
18257
18361
  function updateFollowingRRULE(id, ev) {
18258
18362
  if (!ev) {
@@ -18260,6 +18364,7 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18260
18364
  }
18261
18365
  let rruleStringparts = ev.rrule.split(";");
18262
18366
  let updatedRRULE = [];
18367
+ let interval;
18263
18368
  for (let i = 0; i < rruleStringparts.length; i++) {
18264
18369
  let splited = rruleStringparts[i].split("=");
18265
18370
  let code = splited[0];
@@ -18276,6 +18381,17 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18276
18381
  ev._end_date = ev.end_date;
18277
18382
  }
18278
18383
  }
18384
+ if (code === "INTERVAL") {
18385
+ interval = Number(name);
18386
+ }
18387
+ if (code === "COUNT") {
18388
+ if (ev._shorten_end_date) {
18389
+ const start = scheduler2.date.date_part(new Date(ev._start_date));
18390
+ const end = scheduler2.date.date_part(new Date(ev._shorten_end_date));
18391
+ const days = Math.floor((end - start) / (1e3 * 60 * 60 * 24 * interval)) + 1;
18392
+ name = name - days;
18393
+ }
18394
+ }
18279
18395
  updatedRRULE.push(code);
18280
18396
  updatedRRULE.push("=");
18281
18397
  updatedRRULE.push(name);
@@ -18415,8 +18531,10 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18415
18531
  for (let i in scheduler2._events) {
18416
18532
  let tev = scheduler2._events[i];
18417
18533
  if (tev.recurring_event_id == id || scheduler2._is_virtual_event(tev.id) && tev.id.split("#")[0] == id) {
18418
- tev.text = data.text;
18419
- scheduler2.updateEvent(tev.id);
18534
+ if (tev.start_date.valueOf() >= data.start_date.valueOf()) {
18535
+ tev.text = data.text;
18536
+ scheduler2.updateEvent(tev.id);
18537
+ }
18420
18538
  }
18421
18539
  }
18422
18540
  }
@@ -18534,7 +18652,7 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18534
18652
  scheduler2.attachEvent("onRecurringEventSave", function(id, data, is_new_event) {
18535
18653
  let ev = this.getEvent(id);
18536
18654
  let tempEvent = scheduler2._lame_clone(ev);
18537
- let tempDataRRULE = data.rrule;
18655
+ let tempData = scheduler2._lame_clone(data);
18538
18656
  if (ev && isSeries(ev)) {
18539
18657
  if (!is_new_event && this._isFollowing(id)) {
18540
18658
  if (ev._removeFollowing) {
@@ -18590,10 +18708,8 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18590
18708
  ev._shorten = true;
18591
18709
  updateFollowingRRULEOnSave(ev);
18592
18710
  scheduler2.callEvent("onEventChanged", [ev.id, ev]);
18593
- let followingEv = { ...tempEvent };
18594
- followingEv.text = data.text;
18595
- followingEv.duration = data.duration;
18596
- followingEv.rrule = tempDataRRULE;
18711
+ let followingEv = { ...tempData };
18712
+ followingEv._end_date = tempEvent._end_date;
18597
18713
  followingEv._start_date = null;
18598
18714
  followingEv.id = scheduler2.uid();
18599
18715
  scheduler2.addEvent(followingEv.start_date, followingEv.end_date, followingEv.text, followingEv.id, followingEv);
@@ -18761,43 +18877,28 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18761
18877
  return this.showLightbox_rec(id);
18762
18878
  }
18763
18879
  if (formSetting === "ask") {
18764
- const locale2 = scheduler2.locale;
18765
- showModalbox([{ value: "Occurrence", label: locale2.labels.button_edit_occurrence, checked: true, callback: () => showRequiredLightbox(id, "Occurrence") }, { value: "Following", label: locale2.labels.button_edit_occurrence_and_following, callback: () => showRequiredLightbox(id, "Following") }, { value: "AllEvents", label: locale2.labels.button_edit_series, callback: () => showRequiredLightbox(id, "AllEvents") }]);
18766
- }
18767
- };
18768
- function showModalbox(options, callback) {
18769
- const locale = scheduler2.locale;
18770
- const haveChecked = options.find((o) => o.checked);
18771
- if (!haveChecked) {
18772
- options[0].checked = true;
18880
+ showRecurringScopeConfirmForLightbox(id, pid);
18773
18881
  }
18774
- const callbacks = options.reduce((result, o) => {
18775
- result[o.value] = o.callback;
18776
- return result;
18777
- }, {});
18778
- scheduler2.modalbox({ text: `<div class="dhx_edit_recurrence_options">
18779
- ${options.map((option) => `<label class="dhx_styled_radio">
18780
- <input type="radio" value="${option.value}" name="option" ${option.checked ? "checked" : ""}>
18781
- ${option.label}
18782
- </label>`).join("")}
18783
- </div>`, type: "recurring_mode", title: locale.labels.confirm_recurring, width: "auto", position: "middle", buttons: [{ label: locale.labels.message_ok, value: "ok", css: "rec_ok" }, { label: locale.labels.message_cancel, value: "cancel" }], callback: function(value, e) {
18784
- if (callback) {
18785
- callback(value, e);
18786
- }
18787
- if (value === "cancel") {
18882
+ async function showRecurringScopeConfirmForLightbox(id2, pid2) {
18883
+ const locale2 = scheduler2.locale;
18884
+ const occurrence = scheduler2.getEvent(id2);
18885
+ const seriesEvent = scheduler2.getEvent(pid2);
18886
+ const context = { origin: "lightbox", occurrence, series: seriesEvent, labels: { title: locale2.labels.confirm_recurring, ok: locale2.labels.message_ok, cancel: locale2.labels.message_cancel, occurrence: locale2.labels.button_edit_occurrence, following: locale2.labels.button_edit_occurrence_and_following, series: locale2.labels.button_edit_series }, options: ["occurrence", "following", "series"] };
18887
+ const decision = await scheduler2.ext.recurring._getDecision(context);
18888
+ if (decision === null) {
18788
18889
  return;
18789
18890
  }
18790
- const box = e.target.closest(".scheduler_modal_box");
18791
- const checked = box.querySelector("input[type='radio']:checked");
18792
- let selectedOption;
18793
- if (checked) {
18794
- selectedOption = checked.value;
18891
+ if (decision === "occurrence") {
18892
+ return showRequiredLightbox(id2, "Occurrence");
18795
18893
  }
18796
- if (selectedOption) {
18797
- callbacks[selectedOption]();
18894
+ if (decision === "following") {
18895
+ return showRequiredLightbox(id2, "Following");
18798
18896
  }
18799
- } });
18800
- }
18897
+ if (decision === "series") {
18898
+ return showRequiredLightbox(id2, "AllEvents");
18899
+ }
18900
+ }
18901
+ };
18801
18902
  scheduler2._showRequiredModalBox = function(id, type) {
18802
18903
  let buttons;
18803
18904
  const locale = scheduler2.locale;
@@ -18919,17 +19020,30 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
18919
19020
  }
18920
19021
  }
18921
19022
  };
18922
- const btnAll = { value: "AllEvents", label: locale.labels.button_edit_series, callback: () => handleAllEvents(occurrence) };
18923
- const btnFollowing = { value: "Following", label: locale.labels.button_edit_occurrence_and_following, callback: () => handleFollowing(occurrence) };
18924
- const btnOccurrence = { value: "Occurrence", label: locale.labels.button_edit_occurrence, callback: () => handleOccurrence(occurrence), checked: true };
18925
19023
  if (type === "ask") {
18926
- buttons = [btnOccurrence, btnFollowing, btnAll];
19024
+ buttons = ["occurrence", "following", "series"];
18927
19025
  } else {
18928
- buttons = [btnOccurrence, btnFollowing];
19026
+ buttons = ["occurrence", "following"];
18929
19027
  }
18930
- showModalbox(buttons, (result) => {
18931
- if (result === "cancel") {
19028
+ const context = { origin: "dnd", occurrence, series: event2, labels: { title: locale.labels.confirm_recurring, ok: locale.labels.message_ok, cancel: locale.labels.message_cancel, occurrence: locale.labels.button_edit_occurrence, following: locale.labels.button_edit_occurrence_and_following, series: locale.labels.button_edit_series }, options: buttons };
19029
+ Promise.resolve(scheduler2.ext.recurring._getDecision(context)).then((decision) => {
19030
+ if (!decision) {
18932
19031
  removeTempDraggedEvent();
19032
+ return;
19033
+ }
19034
+ switch (decision) {
19035
+ case "occurrence":
19036
+ handleOccurrence(occurrence);
19037
+ break;
19038
+ case "following":
19039
+ handleFollowing(occurrence);
19040
+ break;
19041
+ case "series":
19042
+ handleAllEvents(occurrence);
19043
+ break;
19044
+ default:
19045
+ removeTempDraggedEvent();
19046
+ return;
18933
19047
  }
18934
19048
  });
18935
19049
  };
@@ -20981,73 +21095,103 @@ To use dhtmlxScheduler in non-GPL projects (and get Pro version of the product),
20981
21095
  notImplemented.alert("Units", scheduler2.assert);
20982
21096
  }
20983
21097
  function url(scheduler2) {
20984
- scheduler2._get_url_nav = function() {
20985
- var p = {};
20986
- var data = (document.location.hash || "").replace("#", "").split(",");
20987
- for (var i = 0; i < data.length; i++) {
20988
- var s = data[i].split("=");
20989
- if (s.length == 2)
20990
- p[s[0]] = s[1];
21098
+ function parseHashParameters() {
21099
+ const parameters = {};
21100
+ const raw = (document.location.hash || "").replace("#", "");
21101
+ if (!raw) {
21102
+ return parameters;
21103
+ }
21104
+ const pairs = raw.split(",");
21105
+ for (let i = 0; i < pairs.length; i++) {
21106
+ const parts = pairs[i].split("=");
21107
+ if (parts.length === 2) {
21108
+ parameters[parts[0]] = parts[1];
21109
+ }
20991
21110
  }
20992
- return p;
21111
+ return parameters;
21112
+ }
21113
+ scheduler2._get_url_nav = function() {
21114
+ return parseHashParameters();
20993
21115
  };
20994
- scheduler2.attachEvent("onTemplatesReady", function() {
20995
- var first = true;
20996
- var s2d = scheduler2.date.str_to_date("%Y-%m-%d");
20997
- var d2s = scheduler2.date.date_to_str("%Y-%m-%d");
20998
- var select_event = scheduler2._get_url_nav().event || null;
20999
- scheduler2.attachEvent("onAfterEventDisplay", function(ev) {
21000
- select_event = null;
21001
- return true;
21002
- });
21003
- scheduler2.attachEvent("onBeforeViewChange", function(om, od, m, d) {
21004
- if (first) {
21005
- first = false;
21006
- var p = scheduler2._get_url_nav();
21007
- if (p.event) {
21008
- try {
21009
- if (scheduler2.getEvent(p.event)) {
21010
- setTimeout(function() {
21011
- showEvent(p.event);
21012
- });
21013
- return false;
21014
- } else {
21015
- var handler = scheduler2.attachEvent("onXLE", function() {
21016
- setTimeout(function() {
21017
- showEvent(p.event);
21018
- });
21019
- scheduler2.detachEvent(handler);
21020
- });
21021
- }
21022
- } catch (e) {
21023
- }
21024
- }
21025
- if (p.date || p.mode) {
21026
- try {
21027
- this.setCurrentView(p.date ? s2d(p.date) : null, p.mode || null);
21028
- } catch (e) {
21029
- this.setCurrentView(p.date ? s2d(p.date) : null, m);
21030
- }
21031
- return false;
21116
+ const dateToString = scheduler2.date.date_to_str("%Y-%m-%d");
21117
+ const originalGetInitialState = scheduler2._getInitialState;
21118
+ scheduler2._getInitialState = function(provided) {
21119
+ const baseState = originalGetInitialState.call(this, provided);
21120
+ const url2 = scheduler2._get_url_nav ? scheduler2._get_url_nav() : null;
21121
+ if (!url2) {
21122
+ return baseState;
21123
+ }
21124
+ const nextState = { date: baseState.date, mode: baseState.mode };
21125
+ if (url2.date) {
21126
+ const stringToDate = scheduler2.date.str_to_date("%Y-%m-%d");
21127
+ try {
21128
+ const parsed = stringToDate(url2.date);
21129
+ if (!isNaN(+parsed)) {
21130
+ nextState.date = parsed;
21032
21131
  }
21132
+ } catch (e) {
21033
21133
  }
21034
- var values = ["date=" + d2s(d || od), "mode=" + (m || om)];
21035
- if (select_event) {
21036
- values.push("event=" + select_event);
21134
+ }
21135
+ if (url2.mode) {
21136
+ try {
21137
+ if (this.isViewExists(url2.mode)) {
21138
+ nextState.mode = url2.mode;
21139
+ }
21140
+ } catch (e) {
21037
21141
  }
21038
- var text = "#" + values.join(",");
21039
- document.location.hash = text;
21040
- return true;
21041
- });
21042
- function showEvent(e) {
21142
+ }
21143
+ return nextState;
21144
+ };
21145
+ function updateHashFromState(optionalSelectedEventId) {
21146
+ const currentDate = scheduler2._date || scheduler2.getState().date;
21147
+ const currentMode = scheduler2.getState().mode;
21148
+ const values = ["date=" + dateToString(currentDate), "mode=" + currentMode];
21149
+ if (optionalSelectedEventId) {
21150
+ values.push("event=" + optionalSelectedEventId);
21151
+ }
21152
+ document.location.hash = "#" + values.join(",");
21153
+ }
21154
+ function showEventWhenPossible(eventId) {
21155
+ if (!eventId) {
21156
+ return;
21157
+ }
21158
+ const tryShowNow = function() {
21043
21159
  if (scheduler2.$destroyed) {
21044
- return true;
21160
+ return;
21045
21161
  }
21046
- select_event = e;
21047
- if (scheduler2.getEvent(e)) {
21048
- scheduler2.showEvent(e);
21162
+ if (scheduler2.getEvent(eventId)) {
21163
+ scheduler2.showEvent(eventId);
21164
+ return true;
21049
21165
  }
21166
+ return false;
21167
+ };
21168
+ if (tryShowNow()) {
21169
+ return;
21050
21170
  }
21171
+ const onLoadedId = scheduler2.attachEvent("onParse", function() {
21172
+ tryShowNow();
21173
+ scheduler2.detachEvent(onLoadedId);
21174
+ return true;
21175
+ });
21176
+ }
21177
+ let pendingSelectedEventId = null;
21178
+ scheduler2.attachEvent("onSchedulerReady", function() {
21179
+ const initialState = scheduler2._get_url_nav();
21180
+ if (initialState.event) {
21181
+ pendingSelectedEventId = initialState.event;
21182
+ showEventWhenPossible(initialState.event);
21183
+ }
21184
+ updateHashFromState(pendingSelectedEventId);
21185
+ return true;
21186
+ });
21187
+ scheduler2.attachEvent("onAfterEventDisplay", function() {
21188
+ pendingSelectedEventId = null;
21189
+ updateHashFromState(null);
21190
+ return true;
21191
+ });
21192
+ scheduler2.attachEvent("onViewChange", function() {
21193
+ updateHashFromState(pendingSelectedEventId);
21194
+ return true;
21051
21195
  });
21052
21196
  }
21053
21197
  function week_agenda_restricted(scheduler2) {