@keenthemes/ktui 1.0.29 → 1.1.0
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.
- package/README.md +27 -0
- package/dist/ktui.js +8780 -6199
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +2744 -1367
- package/lib/cjs/components/alert/alert.js +1025 -0
- package/lib/cjs/components/alert/alert.js.map +1 -0
- package/lib/cjs/components/alert/index.js +20 -0
- package/lib/cjs/components/alert/index.js.map +1 -0
- package/lib/cjs/components/alert/templates.js +120 -0
- package/lib/cjs/components/alert/templates.js.map +1 -0
- package/lib/cjs/components/alert/types.js +7 -0
- package/lib/cjs/components/alert/types.js.map +1 -0
- package/lib/cjs/components/datepicker/config/config.js +42 -0
- package/lib/cjs/components/datepicker/config/config.js.map +1 -0
- package/lib/cjs/components/datepicker/config/index.js +24 -0
- package/lib/cjs/components/datepicker/config/index.js.map +1 -0
- package/lib/cjs/components/datepicker/config/interfaces.js +7 -0
- package/lib/cjs/components/datepicker/config/interfaces.js.map +1 -0
- package/lib/cjs/components/datepicker/config/types.js +7 -0
- package/lib/cjs/components/datepicker/config/types.js.map +1 -0
- package/lib/cjs/components/datepicker/core/event-manager.js +135 -0
- package/lib/cjs/components/datepicker/core/event-manager.js.map +1 -0
- package/lib/cjs/components/datepicker/core/focus-manager.js +167 -0
- package/lib/cjs/components/datepicker/core/focus-manager.js.map +1 -0
- package/lib/cjs/components/datepicker/core/helpers.js +219 -0
- package/lib/cjs/components/datepicker/core/helpers.js.map +1 -0
- package/lib/cjs/components/datepicker/core/index.js +25 -0
- package/lib/cjs/components/datepicker/core/index.js.map +1 -0
- package/lib/cjs/components/datepicker/core/unified-state-manager.js +394 -0
- package/lib/cjs/components/datepicker/core/unified-state-manager.js.map +1 -0
- package/lib/cjs/components/datepicker/datepicker.js +2066 -763
- package/lib/cjs/components/datepicker/datepicker.js.map +1 -1
- package/lib/cjs/components/datepicker/index.js +19 -8
- package/lib/cjs/components/datepicker/index.js.map +1 -1
- package/lib/cjs/components/datepicker/ui/index.js +23 -0
- package/lib/cjs/components/datepicker/ui/index.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/input/dropdown.js +489 -0
- package/lib/cjs/components/datepicker/ui/input/dropdown.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/input/index.js +23 -0
- package/lib/cjs/components/datepicker/ui/input/index.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/input/segmented-input.js +640 -0
- package/lib/cjs/components/datepicker/ui/input/segmented-input.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/renderers/calendar.js +446 -0
- package/lib/cjs/components/datepicker/ui/renderers/calendar.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/renderers/footer.js +42 -0
- package/lib/cjs/components/datepicker/ui/renderers/footer.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/renderers/header.js +32 -0
- package/lib/cjs/components/datepicker/ui/renderers/header.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/renderers/index.js +25 -0
- package/lib/cjs/components/datepicker/ui/renderers/index.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/renderers/time-picker.js +384 -0
- package/lib/cjs/components/datepicker/ui/renderers/time-picker.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/templates/index.js +22 -0
- package/lib/cjs/components/datepicker/ui/templates/index.js.map +1 -0
- package/lib/cjs/components/datepicker/ui/templates/templates.js +253 -0
- package/lib/cjs/components/datepicker/ui/templates/templates.js.map +1 -0
- package/lib/cjs/components/datepicker/utils/date-formatters.js +88 -0
- package/lib/cjs/components/datepicker/utils/date-formatters.js.map +1 -0
- package/lib/cjs/components/datepicker/utils/date-utils.js +194 -0
- package/lib/cjs/components/datepicker/utils/date-utils.js.map +1 -0
- package/lib/cjs/components/datepicker/utils/index.js +24 -0
- package/lib/cjs/components/datepicker/utils/index.js.map +1 -0
- package/lib/cjs/components/datepicker/utils/time-utils.js +213 -0
- package/lib/cjs/components/datepicker/utils/time-utils.js.map +1 -0
- package/lib/cjs/index.js +6 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/components/alert/alert.js +1022 -0
- package/lib/esm/components/alert/alert.js.map +1 -0
- package/lib/esm/components/alert/index.js +4 -0
- package/lib/esm/components/alert/index.js.map +1 -0
- package/lib/esm/components/alert/templates.js +112 -0
- package/lib/esm/components/alert/templates.js.map +1 -0
- package/lib/esm/components/alert/types.js +6 -0
- package/lib/esm/components/alert/types.js.map +1 -0
- package/lib/esm/components/datepicker/config/config.js +39 -0
- package/lib/esm/components/datepicker/config/config.js.map +1 -0
- package/lib/esm/components/datepicker/config/index.js +8 -0
- package/lib/esm/components/datepicker/config/index.js.map +1 -0
- package/lib/esm/components/datepicker/config/interfaces.js +6 -0
- package/lib/esm/components/datepicker/config/interfaces.js.map +1 -0
- package/lib/esm/components/datepicker/config/types.js +6 -0
- package/lib/esm/components/datepicker/config/types.js.map +1 -0
- package/lib/esm/components/datepicker/core/event-manager.js +133 -0
- package/lib/esm/components/datepicker/core/event-manager.js.map +1 -0
- package/lib/esm/components/datepicker/core/focus-manager.js +164 -0
- package/lib/esm/components/datepicker/core/focus-manager.js.map +1 -0
- package/lib/esm/components/datepicker/core/helpers.js +211 -0
- package/lib/esm/components/datepicker/core/helpers.js.map +1 -0
- package/lib/esm/components/datepicker/core/index.js +9 -0
- package/lib/esm/components/datepicker/core/index.js.map +1 -0
- package/lib/esm/components/datepicker/core/unified-state-manager.js +391 -0
- package/lib/esm/components/datepicker/core/unified-state-manager.js.map +1 -0
- package/lib/esm/components/datepicker/datepicker.js +2065 -763
- package/lib/esm/components/datepicker/datepicker.js.map +1 -1
- package/lib/esm/components/datepicker/index.js +6 -8
- package/lib/esm/components/datepicker/index.js.map +1 -1
- package/lib/esm/components/datepicker/ui/index.js +7 -0
- package/lib/esm/components/datepicker/ui/index.js.map +1 -0
- package/lib/esm/components/datepicker/ui/input/dropdown.js +486 -0
- package/lib/esm/components/datepicker/ui/input/dropdown.js.map +1 -0
- package/lib/esm/components/datepicker/ui/input/index.js +7 -0
- package/lib/esm/components/datepicker/ui/input/index.js.map +1 -0
- package/lib/esm/components/datepicker/ui/input/segmented-input.js +637 -0
- package/lib/esm/components/datepicker/ui/input/segmented-input.js.map +1 -0
- package/lib/esm/components/datepicker/ui/renderers/calendar.js +443 -0
- package/lib/esm/components/datepicker/ui/renderers/calendar.js.map +1 -0
- package/lib/esm/components/datepicker/ui/renderers/footer.js +39 -0
- package/lib/esm/components/datepicker/ui/renderers/footer.js.map +1 -0
- package/lib/esm/components/datepicker/ui/renderers/header.js +29 -0
- package/lib/esm/components/datepicker/ui/renderers/header.js.map +1 -0
- package/lib/esm/components/datepicker/ui/renderers/index.js +9 -0
- package/lib/esm/components/datepicker/ui/renderers/index.js.map +1 -0
- package/lib/esm/components/datepicker/ui/renderers/time-picker.js +381 -0
- package/lib/esm/components/datepicker/ui/renderers/time-picker.js.map +1 -0
- package/lib/esm/components/datepicker/ui/templates/index.js +6 -0
- package/lib/esm/components/datepicker/ui/templates/index.js.map +1 -0
- package/lib/esm/components/datepicker/ui/templates/templates.js +242 -0
- package/lib/esm/components/datepicker/ui/templates/templates.js.map +1 -0
- package/lib/esm/components/datepicker/utils/date-formatters.js +83 -0
- package/lib/esm/components/datepicker/utils/date-formatters.js.map +1 -0
- package/lib/esm/components/datepicker/utils/date-utils.js +184 -0
- package/lib/esm/components/datepicker/utils/date-utils.js.map +1 -0
- package/lib/esm/components/datepicker/utils/index.js +8 -0
- package/lib/esm/components/datepicker/utils/index.js.map +1 -0
- package/lib/esm/components/datepicker/utils/time-utils.js +201 -0
- package/lib/esm/components/datepicker/utils/time-utils.js.map +1 -0
- package/lib/esm/index.js +4 -0
- package/lib/esm/index.js.map +1 -1
- package/package.json +12 -3
- package/src/components/alert/alert.css +429 -188
- package/src/components/alert/alert.ts +990 -0
- package/src/components/alert/index.ts +4 -0
- package/src/components/alert/templates.ts +110 -0
- package/src/components/alert/tests/accessibility/aria-roles.test.ts +19 -0
- package/src/components/alert/tests/accessibility/focus-management.test.ts +19 -0
- package/src/components/alert/tests/accessibility/keyboard-nav.test.ts +22 -0
- package/src/components/alert/tests/actions/confirm-cancel.test.ts +122 -0
- package/src/components/alert/tests/actions/input-field.test.ts +180 -0
- package/src/components/alert/tests/alert.basic.test.ts +126 -0
- package/src/components/alert/tests/alert.config.test.ts +75 -0
- package/src/components/alert/tests/alert.templates.test.ts +17 -0
- package/src/components/alert/tests/config/attribute-config.test.ts +94 -0
- package/src/components/alert/tests/config/json-config.test.ts +119 -0
- package/src/components/alert/tests/config/merging.test.ts +89 -0
- package/src/components/alert/tests/dismissal/auto-dismiss.test.ts +96 -0
- package/src/components/alert/tests/dismissal/escape-key-dismiss.test.ts +105 -0
- package/src/components/alert/tests/dismissal/manual-dismiss.test.ts +90 -0
- package/src/components/alert/tests/dismissal/outside-click-dismiss.test.ts +91 -0
- package/src/components/alert/tests/edge-cases/invalid-config.test.ts +19 -0
- package/src/components/alert/tests/edge-cases/multiple-alerts.test.ts +19 -0
- package/src/components/alert/tests/rendering/custom-content.test.ts +81 -0
- package/src/components/alert/tests/rendering/info-alert.test.ts +84 -0
- package/src/components/alert/tests/rendering/success-alert.test.ts +100 -0
- package/src/components/alert/tests/templates/default-templates.test.ts +16 -0
- package/src/components/alert/tests/templates/user-templates.test.ts +16 -0
- package/src/components/alert/types.ts +145 -0
- package/src/components/datepicker/__tests__/datepicker-events.test.ts +356 -0
- package/src/components/datepicker/__tests__/datepicker-init.test.ts +343 -0
- package/src/components/datepicker/__tests__/datepicker-integration.test.ts +435 -0
- package/src/components/datepicker/__tests__/datepicker-timezone.test.ts +220 -0
- package/src/components/datepicker/__tests__/segmented-input-focus.test.ts +380 -0
- package/src/components/datepicker/__tests__/selective-state-updates.test.ts +400 -0
- package/src/components/datepicker/__tests__/state-manager.test.ts +421 -0
- package/src/components/datepicker/__tests__/time-preservation.test.ts +387 -0
- package/src/components/datepicker/config/config.ts +40 -0
- package/src/components/datepicker/config/index.ts +8 -0
- package/src/components/datepicker/config/interfaces.ts +82 -0
- package/src/components/datepicker/config/types.ts +188 -0
- package/src/components/datepicker/core/event-manager.ts +159 -0
- package/src/components/datepicker/core/focus-manager.ts +201 -0
- package/src/components/datepicker/core/helpers.ts +231 -0
- package/src/components/datepicker/core/index.ts +9 -0
- package/src/components/datepicker/core/unified-state-manager.ts +459 -0
- package/src/components/datepicker/datepicker.css +429 -1
- package/src/components/datepicker/datepicker.ts +2538 -1277
- package/src/components/datepicker/index.ts +6 -8
- package/src/components/datepicker/ui/index.ts +7 -0
- package/src/components/datepicker/ui/input/dropdown.ts +552 -0
- package/src/components/datepicker/ui/input/index.ts +7 -0
- package/src/components/datepicker/ui/input/segmented-input.ts +638 -0
- package/src/components/datepicker/ui/renderers/__tests__/calendar-optimizations.test.ts +611 -0
- package/src/components/datepicker/ui/renderers/calendar.ts +530 -0
- package/src/components/datepicker/ui/renderers/footer.ts +43 -0
- package/src/components/datepicker/ui/renderers/header.ts +33 -0
- package/src/components/datepicker/ui/renderers/index.ts +9 -0
- package/src/components/datepicker/ui/renderers/time-picker.ts +438 -0
- package/src/components/datepicker/ui/templates/index.ts +6 -0
- package/src/components/datepicker/ui/templates/templates.ts +306 -0
- package/src/components/datepicker/utils/__tests__/date-formatters.test.ts +160 -0
- package/src/components/datepicker/utils/__tests__/date-utils-keys.test.ts +86 -0
- package/src/components/datepicker/utils/__tests__/date-utils-timezone.test.ts +215 -0
- package/src/components/datepicker/utils/date-formatters.ts +85 -0
- package/src/components/datepicker/utils/date-utils.ts +172 -0
- package/src/components/datepicker/utils/index.ts +8 -0
- package/src/components/datepicker/utils/time-utils.ts +221 -0
- package/src/index.ts +7 -1
- package/lib/cjs/components/datepicker/calendar.js +0 -1061
- package/lib/cjs/components/datepicker/calendar.js.map +0 -1
- package/lib/cjs/components/datepicker/config.js +0 -332
- package/lib/cjs/components/datepicker/config.js.map +0 -1
- package/lib/cjs/components/datepicker/dropdown.js +0 -635
- package/lib/cjs/components/datepicker/dropdown.js.map +0 -1
- package/lib/cjs/components/datepicker/events.js +0 -129
- package/lib/cjs/components/datepicker/events.js.map +0 -1
- package/lib/cjs/components/datepicker/keyboard.js +0 -536
- package/lib/cjs/components/datepicker/keyboard.js.map +0 -1
- package/lib/cjs/components/datepicker/locales.js +0 -78
- package/lib/cjs/components/datepicker/locales.js.map +0 -1
- package/lib/cjs/components/datepicker/templates.js +0 -403
- package/lib/cjs/components/datepicker/templates.js.map +0 -1
- package/lib/cjs/components/datepicker/types.js +0 -23
- package/lib/cjs/components/datepicker/types.js.map +0 -1
- package/lib/cjs/components/datepicker/utils.js +0 -524
- package/lib/cjs/components/datepicker/utils.js.map +0 -1
- package/lib/esm/components/datepicker/calendar.js +0 -1058
- package/lib/esm/components/datepicker/calendar.js.map +0 -1
- package/lib/esm/components/datepicker/config.js +0 -329
- package/lib/esm/components/datepicker/config.js.map +0 -1
- package/lib/esm/components/datepicker/dropdown.js +0 -632
- package/lib/esm/components/datepicker/dropdown.js.map +0 -1
- package/lib/esm/components/datepicker/events.js +0 -126
- package/lib/esm/components/datepicker/events.js.map +0 -1
- package/lib/esm/components/datepicker/keyboard.js +0 -533
- package/lib/esm/components/datepicker/keyboard.js.map +0 -1
- package/lib/esm/components/datepicker/locales.js +0 -74
- package/lib/esm/components/datepicker/locales.js.map +0 -1
- package/lib/esm/components/datepicker/templates.js +0 -390
- package/lib/esm/components/datepicker/templates.js.map +0 -1
- package/lib/esm/components/datepicker/types.js +0 -20
- package/lib/esm/components/datepicker/types.js.map +0 -1
- package/lib/esm/components/datepicker/utils.js +0 -508
- package/lib/esm/components/datepicker/utils.js.map +0 -1
- package/src/components/datepicker/calendar.ts +0 -1397
- package/src/components/datepicker/config.ts +0 -368
- package/src/components/datepicker/dropdown.ts +0 -757
- package/src/components/datepicker/events.ts +0 -149
- package/src/components/datepicker/keyboard.ts +0 -646
- package/src/components/datepicker/locales.ts +0 -80
- package/src/components/datepicker/templates.ts +0 -792
- package/src/components/datepicker/types.ts +0 -154
- package/src/components/datepicker/utils.ts +0 -631
- package/src/components/select/variants.css +0 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
/*
|
|
3
|
+
* datepicker.ts - Main implementation for KTDatepicker component
|
|
4
|
+
* Provides single, range, and multi-date selection with segmented input UI.
|
|
5
|
+
* Modular rendering and state helpers are imported from datepicker-helpers.ts.
|
|
5
6
|
*/
|
|
6
7
|
var __extends = (this && this.__extends) || (function () {
|
|
7
8
|
var extendStatics = function (d, b) {
|
|
@@ -18,932 +19,2234 @@ var __extends = (this && this.__extends) || (function () {
|
|
|
18
19
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
19
20
|
};
|
|
20
21
|
})();
|
|
22
|
+
var __assign = (this && this.__assign) || function () {
|
|
23
|
+
__assign = Object.assign || function(t) {
|
|
24
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
25
|
+
s = arguments[i];
|
|
26
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
27
|
+
t[p] = s[p];
|
|
28
|
+
}
|
|
29
|
+
return t;
|
|
30
|
+
};
|
|
31
|
+
return __assign.apply(this, arguments);
|
|
32
|
+
};
|
|
33
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
34
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
35
|
+
if (ar || !(i in from)) {
|
|
36
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
37
|
+
ar[i] = from[i];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
41
|
+
};
|
|
21
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
43
|
exports.KTDatepicker = void 0;
|
|
44
|
+
exports.initDatepickers = initDatepickers;
|
|
23
45
|
var component_1 = require("../component");
|
|
24
|
-
var
|
|
25
|
-
var config_1 = require("./config");
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
var templates_1 = require("./ui/templates/templates");
|
|
47
|
+
var config_1 = require("./config/config");
|
|
48
|
+
var header_1 = require("./ui/renderers/header");
|
|
49
|
+
var calendar_1 = require("./ui/renderers/calendar");
|
|
50
|
+
var footer_1 = require("./ui/renderers/footer");
|
|
51
|
+
var time_picker_1 = require("./ui/renderers/time-picker");
|
|
52
|
+
var event_manager_1 = require("./core/event-manager");
|
|
53
|
+
var focus_manager_1 = require("./core/focus-manager");
|
|
54
|
+
var dropdown_1 = require("./ui/input/dropdown");
|
|
55
|
+
var unified_state_manager_1 = require("./core/unified-state-manager");
|
|
56
|
+
var date_utils_1 = require("./utils/date-utils");
|
|
57
|
+
var date_formatters_1 = require("./utils/date-formatters");
|
|
58
|
+
var time_utils_1 = require("./utils/time-utils");
|
|
59
|
+
var helpers_1 = require("./core/helpers");
|
|
36
60
|
/**
|
|
37
|
-
* KTDatepicker
|
|
38
|
-
*
|
|
61
|
+
* KTDatepicker
|
|
62
|
+
*
|
|
63
|
+
* Datepicker component for selecting single, range, or multiple dates.
|
|
64
|
+
*
|
|
65
|
+
* Features:
|
|
66
|
+
* - Opens on input focus or calendar button click (configurable)
|
|
67
|
+
* - Supports single, range, and multi-date modes
|
|
68
|
+
* - Customizable via templates and data attributes
|
|
69
|
+
* - Keyboard navigation and accessibility support
|
|
39
70
|
*/
|
|
40
71
|
var KTDatepicker = /** @class */ (function (_super) {
|
|
41
72
|
__extends(KTDatepicker, _super);
|
|
42
73
|
/**
|
|
43
|
-
* Constructor
|
|
74
|
+
* Constructor: Initializes the datepicker component
|
|
44
75
|
*/
|
|
45
76
|
function KTDatepicker(element, config) {
|
|
46
77
|
var _this = _super.call(this) || this;
|
|
47
78
|
_this._name = 'datepicker';
|
|
48
|
-
_this.
|
|
49
|
-
_this.
|
|
50
|
-
_this.
|
|
51
|
-
_this.
|
|
52
|
-
_this.
|
|
53
|
-
_this.
|
|
54
|
-
_this.
|
|
55
|
-
_this.
|
|
56
|
-
|
|
57
|
-
_this.
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
_this._defaultConfig = config_1.defaultDatepickerConfig;
|
|
80
|
+
_this._config = config_1.defaultDatepickerConfig;
|
|
81
|
+
_this._userTemplates = {};
|
|
82
|
+
_this._input = null;
|
|
83
|
+
_this._focusManager = null;
|
|
84
|
+
_this._dropdownModule = null;
|
|
85
|
+
_this._timePickerRenderer = null;
|
|
86
|
+
_this._unsubscribeFromState = null;
|
|
87
|
+
// Dynamic element detection
|
|
88
|
+
_this._elementObserver = null;
|
|
89
|
+
// DOM element cache for performance optimization
|
|
90
|
+
_this._cachedElements = {
|
|
91
|
+
calendarElement: null,
|
|
92
|
+
timePickerElement: null,
|
|
93
|
+
startContainer: null,
|
|
94
|
+
endContainer: null,
|
|
95
|
+
yearElement: null,
|
|
96
|
+
monthElement: null,
|
|
97
|
+
dayElement: null,
|
|
98
|
+
hourElement: null,
|
|
99
|
+
minuteElement: null,
|
|
100
|
+
secondElement: null,
|
|
101
|
+
ampmElement: null,
|
|
102
|
+
monthYearElement: null,
|
|
103
|
+
timeDisplay: null
|
|
104
|
+
};
|
|
105
|
+
/** Handler for Apply button in multi-date mode */
|
|
106
|
+
_this._onApplyMultiDate = function (e) {
|
|
107
|
+
// Apply button clicked in multi-date mode
|
|
108
|
+
};
|
|
109
|
+
_this._onToday = function (e) {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
var today = new Date();
|
|
112
|
+
_this.setDate(today);
|
|
113
|
+
};
|
|
114
|
+
// Stub for _onClear (to be implemented next)
|
|
115
|
+
_this._onClear = function (e) {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
// Clear all selection states using unified state manager
|
|
118
|
+
_this._unifiedStateManager.updateState({
|
|
119
|
+
selectedDate: null,
|
|
120
|
+
selectedRange: { start: null, end: null },
|
|
121
|
+
selectedDates: [],
|
|
122
|
+
selectedTime: null
|
|
123
|
+
}, 'clear');
|
|
124
|
+
if (_this._input) {
|
|
125
|
+
var evt = new Event('change', { bubbles: true });
|
|
126
|
+
_this._input.dispatchEvent(evt);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Handler for Apply button - confirms selection and closes dropdown
|
|
131
|
+
* Used in range and multi-date modes
|
|
132
|
+
*/
|
|
133
|
+
_this._onApply = function (e) {
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
var currentState = _this._unifiedStateManager.getState();
|
|
137
|
+
// Ensure input value is updated with current selection
|
|
138
|
+
_this._updateInput(currentState);
|
|
139
|
+
// Fire onChange event if there's a selection
|
|
140
|
+
if (_this._config.range && currentState.selectedRange) {
|
|
141
|
+
if (currentState.selectedRange.start || currentState.selectedRange.end) {
|
|
142
|
+
_this._fireDatepickerEvent('onChange', currentState.selectedRange, _this);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else if (_this._config.multiDate && currentState.selectedDates.length > 0) {
|
|
146
|
+
_this._fireDatepickerEvent('onChange', currentState.selectedDates, _this);
|
|
147
|
+
}
|
|
148
|
+
else if (currentState.selectedDate) {
|
|
149
|
+
_this._fireDatepickerEvent('onChange', currentState.selectedDate, _this);
|
|
150
|
+
}
|
|
151
|
+
// Trigger input change event
|
|
152
|
+
if (_this._input) {
|
|
153
|
+
var evt = new Event('change', { bubbles: true });
|
|
154
|
+
_this._input.dispatchEvent(evt);
|
|
155
|
+
}
|
|
156
|
+
// Close the dropdown
|
|
157
|
+
_this._unifiedStateManager.setDropdownOpen(false, 'apply-button');
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Centralized keyboard event handler for all datepicker keyboard interactions.
|
|
161
|
+
* Handles navigation, selection, and closing for input, calendar, and popover.
|
|
162
|
+
* Covers: Tab, Shift+Tab, Arrow keys, Enter, Space, Escape, Home, End, PageUp, PageDown.
|
|
163
|
+
*/
|
|
164
|
+
_this._onKeyDown = function (e) {
|
|
165
|
+
var _a;
|
|
166
|
+
if (!_this._unifiedStateManager.isDropdownOpen())
|
|
167
|
+
return;
|
|
168
|
+
var target = e.target;
|
|
169
|
+
// Check if segmented input is focused - let it handle its own keyboard events
|
|
170
|
+
if (target.closest('[data-segment]')) {
|
|
171
|
+
return; // Let segmented input handle its own keyboard events
|
|
172
|
+
}
|
|
173
|
+
// Handle Escape key
|
|
174
|
+
if (e.key === 'Escape') {
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Handle Tab/Shift+Tab: allow normal tabbing, but trap focus within dropdown if needed
|
|
179
|
+
if (e.key === 'Tab') {
|
|
180
|
+
// Optionally implement focus trap if required
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Handle Arrow keys, Home/End, PageUp/PageDown for calendar grid navigation
|
|
184
|
+
var isCalendarGrid = target.closest('[data-kt-datepicker-calendar-grid]');
|
|
185
|
+
if (isCalendarGrid) {
|
|
186
|
+
// Find all day buttons
|
|
187
|
+
var dayButtons = Array.from(isCalendarGrid.querySelectorAll('button[data-day]'));
|
|
188
|
+
var currentIndex = dayButtons.findIndex(function (btn) { return btn === target; });
|
|
189
|
+
var nextIndex_1 = currentIndex;
|
|
190
|
+
if (e.key === 'ArrowRight')
|
|
191
|
+
nextIndex_1 = Math.min(dayButtons.length - 1, currentIndex + 1);
|
|
192
|
+
if (e.key === 'ArrowLeft')
|
|
193
|
+
nextIndex_1 = Math.max(0, currentIndex - 1);
|
|
194
|
+
if (e.key === 'ArrowDown')
|
|
195
|
+
nextIndex_1 = Math.min(dayButtons.length - 1, currentIndex + 7);
|
|
196
|
+
if (e.key === 'ArrowUp')
|
|
197
|
+
nextIndex_1 = Math.max(0, currentIndex - 7);
|
|
198
|
+
if (e.key === 'Home')
|
|
199
|
+
nextIndex_1 = Math.floor(currentIndex / 7) * 7;
|
|
200
|
+
if (e.key === 'End')
|
|
201
|
+
nextIndex_1 = Math.min(dayButtons.length - 1, Math.floor(currentIndex / 7) * 7 + 6);
|
|
202
|
+
if (e.key === 'PageUp' || e.key === 'PageDown') {
|
|
203
|
+
// Change month and focus first day
|
|
204
|
+
_this._changeMonth(e.key === 'PageUp' ? -1 : 1);
|
|
205
|
+
setTimeout(function () {
|
|
206
|
+
var newGrid = _this._element.querySelector('[data-kt-datepicker-calendar-grid]');
|
|
207
|
+
if (newGrid) {
|
|
208
|
+
var newButtons = Array.from(newGrid.querySelectorAll('button[data-day]'));
|
|
209
|
+
if (newButtons.length > 0) {
|
|
210
|
+
// Set roving tabindex
|
|
211
|
+
newButtons.forEach(function (btn, idx) { return btn.tabIndex = idx === 0 ? 0 : -1; });
|
|
212
|
+
newButtons[0].focus();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}, 0);
|
|
216
|
+
e.preventDefault();
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (nextIndex_1 !== currentIndex && dayButtons[nextIndex_1]) {
|
|
220
|
+
// Set roving tabindex
|
|
221
|
+
dayButtons.forEach(function (btn, idx) { return btn.tabIndex = idx === nextIndex_1 ? 0 : -1; });
|
|
222
|
+
dayButtons[nextIndex_1].focus();
|
|
223
|
+
e.preventDefault();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
// Enter/Space: select date
|
|
227
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
228
|
+
(_a = dayButtons[currentIndex]) === null || _a === void 0 ? void 0 : _a.click();
|
|
229
|
+
// Optionally announce selection to screen reader
|
|
230
|
+
var liveRegion = _this._element.querySelector('[data-kt-datepicker-live]');
|
|
231
|
+
if (liveRegion && dayButtons[currentIndex]) {
|
|
232
|
+
liveRegion.textContent = "Selected ".concat(dayButtons[currentIndex].getAttribute('aria-label'));
|
|
233
|
+
}
|
|
234
|
+
e.preventDefault();
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Handle navigation for header buttons (prev/next month)
|
|
239
|
+
if (target.hasAttribute('data-kt-datepicker-prev') || target.hasAttribute('data-kt-datepicker-next')) {
|
|
240
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
241
|
+
target.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
242
|
+
// Optionally announce navigation to screen reader
|
|
243
|
+
var liveRegion = _this._element.querySelector('[data-kt-datepicker-live]');
|
|
244
|
+
if (liveRegion) {
|
|
245
|
+
liveRegion.textContent = target.hasAttribute('data-kt-datepicker-prev') ? 'Previous month' : 'Next month';
|
|
246
|
+
}
|
|
247
|
+
e.preventDefault();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Handle footer buttons (today, clear, apply)
|
|
252
|
+
if (target.hasAttribute('data-kt-datepicker-today') || target.hasAttribute('data-kt-datepicker-clear') || target.hasAttribute('data-kt-datepicker-apply')) {
|
|
253
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
254
|
+
target.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
255
|
+
// Optionally announce action to screen reader
|
|
256
|
+
var liveRegion = _this._element.querySelector('[data-kt-datepicker-live]');
|
|
257
|
+
if (liveRegion) {
|
|
258
|
+
if (target.hasAttribute('data-kt-datepicker-today'))
|
|
259
|
+
liveRegion.textContent = 'Today selected';
|
|
260
|
+
if (target.hasAttribute('data-kt-datepicker-clear'))
|
|
261
|
+
liveRegion.textContent = 'Selection cleared';
|
|
262
|
+
if (target.hasAttribute('data-kt-datepicker-apply'))
|
|
263
|
+
liveRegion.textContent = 'Selection applied';
|
|
264
|
+
}
|
|
265
|
+
e.preventDefault();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Handler for input focus event, opens the datepicker if showOnFocus is true and input is not disabled/readonly
|
|
272
|
+
*/
|
|
273
|
+
_this._onInputFocus = function (e) {
|
|
274
|
+
if (!_this._input)
|
|
275
|
+
return;
|
|
276
|
+
if (_this._input.hasAttribute('disabled') || _this._input.hasAttribute('readonly'))
|
|
277
|
+
return;
|
|
278
|
+
if (_this._config.showOnFocus) {
|
|
279
|
+
_this.open();
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* Handler for document click event, closes the datepicker if click is outside the component
|
|
284
|
+
*/
|
|
285
|
+
_this._handleDocumentClick = function (e) {
|
|
286
|
+
// Skip if click-outside is disabled
|
|
287
|
+
if (!_this._config.closeOnOutsideClick)
|
|
288
|
+
return;
|
|
289
|
+
// Skip if dropdown is not open
|
|
290
|
+
if (!_this._unifiedStateManager.isDropdownOpen())
|
|
291
|
+
return;
|
|
292
|
+
var targetElement = e.target;
|
|
293
|
+
// Find the dropdown element (it's rendered in body, not inside _element)
|
|
294
|
+
var dropdownElement = document.querySelector("[data-kt-datepicker-dropdown][data-kt-datepicker-instance-id=\"".concat(_this._instanceId, "\"]"));
|
|
295
|
+
// Check if click is outside both the datepicker element and the dropdown
|
|
296
|
+
var isInsideDatepicker = _this._element.contains(targetElement);
|
|
297
|
+
var isInsideDropdown = dropdownElement && dropdownElement.contains(targetElement);
|
|
298
|
+
if (!isInsideDatepicker && !isInsideDropdown) {
|
|
299
|
+
_this.close();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
// Generate unique instance ID
|
|
303
|
+
_this._instanceId = "datepicker-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
|
|
304
|
+
// Add instance ID to element for debugging
|
|
305
|
+
element.setAttribute('data-kt-datepicker-instance-id', _this._instanceId);
|
|
63
306
|
_this._init(element);
|
|
64
|
-
// Build
|
|
307
|
+
// Build config using the standard KTComponent approach
|
|
65
308
|
_this._buildConfig(config);
|
|
66
|
-
|
|
309
|
+
_this._templateSet = (0, templates_1.getTemplateStrings)(_this._config);
|
|
310
|
+
_this._templateRenderer = (0, templates_1.createTemplateRenderer)(_this._templateSet);
|
|
311
|
+
// Initialize unified state manager
|
|
312
|
+
_this._unifiedStateManager = new unified_state_manager_1.KTDatepickerUnifiedStateManager({
|
|
313
|
+
enableValidation: true,
|
|
314
|
+
enableDebugging: _this._config.debug || false,
|
|
315
|
+
enableUpdateBatching: true,
|
|
316
|
+
batchDelay: 16
|
|
317
|
+
});
|
|
318
|
+
// Subscribe to state changes
|
|
319
|
+
_this._unsubscribeFromState = _this._unifiedStateManager.subscribe(_this);
|
|
320
|
+
// Set placeholder from config if available
|
|
321
|
+
if (_this._input && _this._config.placeholder) {
|
|
322
|
+
_this._input.setAttribute('placeholder', _this._config.placeholder);
|
|
323
|
+
}
|
|
324
|
+
// Set disabled state from config if available
|
|
325
|
+
if (_this._input && _this._config.disabled) {
|
|
326
|
+
_this._input.setAttribute('disabled', 'true');
|
|
327
|
+
// Also set disabled state in unified state manager
|
|
328
|
+
_this._unifiedStateManager.setDropdownDisabled(true, 'config');
|
|
329
|
+
}
|
|
330
|
+
// --- Time initialization ---
|
|
331
|
+
if (_this._config.enableTime) {
|
|
332
|
+
_this._unifiedStateManager.updateState({
|
|
333
|
+
timeGranularity: _this._config.timeGranularity || 'minute'
|
|
334
|
+
}, 'config');
|
|
335
|
+
// Initialize time from selected date or current time
|
|
336
|
+
var baseDate = _this._unifiedStateManager.getState().selectedDate || _this._unifiedStateManager.getState().currentDate || new Date();
|
|
337
|
+
_this._unifiedStateManager.setSelectedTime((0, time_utils_1.dateToTimeState)(baseDate), 'config');
|
|
338
|
+
}
|
|
339
|
+
// --- Mode-specific initialization ---
|
|
340
|
+
if (_this._config.range && _this._config.valueRange) {
|
|
341
|
+
_this._initRangeFromConfig();
|
|
342
|
+
}
|
|
343
|
+
else if (_this._config.multiDate && Array.isArray(_this._config.values)) {
|
|
344
|
+
_this._initMultiDateFromConfig();
|
|
345
|
+
}
|
|
346
|
+
else if (_this._config.value) {
|
|
347
|
+
_this._initSingleDateFromConfig();
|
|
348
|
+
}
|
|
349
|
+
// --- Input focus event for showOnFocus ---
|
|
350
|
+
if (_this._input) {
|
|
351
|
+
_this._eventManager.addListener(_this._input, 'focus', _this._onInputFocus);
|
|
352
|
+
}
|
|
353
|
+
// --- Document click event for outside click detection ---
|
|
354
|
+
_this._eventManager.addListener(document, 'click', _this._handleDocumentClick);
|
|
67
355
|
element.instance = _this;
|
|
68
|
-
|
|
69
|
-
_this._element.setAttribute('tabindex', '0');
|
|
70
|
-
_this._element.classList.add('kt-datepicker', 'relative', 'focus:outline-none');
|
|
71
|
-
// Mark as initialized
|
|
72
|
-
_this._element.setAttribute('data-kt-datepicker-initialized', 'true');
|
|
73
|
-
// Find input elements
|
|
74
|
-
_this._initializeInputElements();
|
|
75
|
-
// Create display element if needed
|
|
76
|
-
_this._createDisplayElement();
|
|
77
|
-
// Create state manager first
|
|
78
|
-
_this._state = new config_1.KTDatepickerStateManager(_this._element, _this._config);
|
|
79
|
-
_this._config = _this._state.getConfig();
|
|
80
|
-
// Initialize the calendar and keyboard after creating the state manager
|
|
81
|
-
_this._calendar = new calendar_1.KTDatepickerCalendar(_this._element, _this._state);
|
|
82
|
-
_this._keyboard = new keyboard_1.KTDatepickerKeyboard(_this._element, _this._state);
|
|
83
|
-
// Initialize event manager
|
|
84
|
-
_this._eventManager = _this._state.getEventManager();
|
|
85
|
-
// Set up event listeners
|
|
86
|
-
_this._setupEventListeners();
|
|
87
|
-
// Initialize with any default values
|
|
88
|
-
_this._initializeDefaultValues();
|
|
356
|
+
_this._render();
|
|
89
357
|
return _this;
|
|
90
358
|
}
|
|
91
359
|
/**
|
|
92
|
-
* Initialize
|
|
360
|
+
* Initialize the datepicker components after configuration is set
|
|
93
361
|
*/
|
|
94
|
-
KTDatepicker.prototype.
|
|
95
|
-
//
|
|
96
|
-
this.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.
|
|
362
|
+
KTDatepicker.prototype._initializeDatepicker = function () {
|
|
363
|
+
// Set up templates
|
|
364
|
+
this._templateSet = (0, templates_1.getTemplateStrings)(this._config);
|
|
365
|
+
this._templateRenderer = (0, templates_1.createTemplateRenderer)(this._templateSet);
|
|
366
|
+
// Initialize state manager
|
|
367
|
+
this._unifiedStateManager = new unified_state_manager_1.KTDatepickerUnifiedStateManager({
|
|
368
|
+
enableValidation: true,
|
|
369
|
+
enableDebugging: this._config.debug || false,
|
|
370
|
+
enableUpdateBatching: true,
|
|
371
|
+
batchDelay: 16
|
|
372
|
+
});
|
|
373
|
+
// Set initial state
|
|
374
|
+
this._unifiedStateManager.updateState(this._getInitialState(), 'initialization', true);
|
|
375
|
+
// Subscribe to state changes
|
|
376
|
+
this._unsubscribeFromState = this._unifiedStateManager.subscribe(this);
|
|
377
|
+
// Initialize event manager
|
|
378
|
+
this._eventManager = new event_manager_1.EventManager();
|
|
379
|
+
// Set up instance ID for debugging
|
|
380
|
+
this._instanceId = "datepicker-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
|
|
381
|
+
this._element.setAttribute('data-kt-datepicker-instance-id', this._instanceId);
|
|
382
|
+
// Set placeholder from config if available
|
|
383
|
+
if (this._input && this._config.placeholder) {
|
|
384
|
+
this._input.setAttribute('placeholder', this._config.placeholder);
|
|
385
|
+
}
|
|
386
|
+
// Set disabled state from config if available
|
|
387
|
+
if (this._input && this._config.disabled) {
|
|
388
|
+
this._input.setAttribute('disabled', 'true');
|
|
389
|
+
// Also set disabled state in unified state manager
|
|
390
|
+
this._unifiedStateManager.setDropdownDisabled(true, 'config');
|
|
391
|
+
}
|
|
392
|
+
// --- Time initialization ---
|
|
393
|
+
if (this._config.enableTime) {
|
|
394
|
+
this._unifiedStateManager.updateState({
|
|
395
|
+
timeGranularity: this._config.timeGranularity || 'minute'
|
|
396
|
+
}, 'config');
|
|
397
|
+
// Initialize time from selected date or current time
|
|
398
|
+
var baseDate = this._unifiedStateManager.getState().selectedDate || this._unifiedStateManager.getState().currentDate || new Date();
|
|
399
|
+
this._unifiedStateManager.setSelectedTime((0, time_utils_1.dateToTimeState)(baseDate), 'config');
|
|
400
|
+
}
|
|
401
|
+
// --- Mode-specific initialization ---
|
|
402
|
+
if (this._config.range && this._config.valueRange) {
|
|
403
|
+
this._initRangeFromConfig();
|
|
404
|
+
}
|
|
405
|
+
else if (this._config.multiDate && Array.isArray(this._config.values)) {
|
|
406
|
+
this._initMultiDateFromConfig();
|
|
102
407
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
408
|
+
else if (this._config.value) {
|
|
409
|
+
this._initSingleDateFromConfig();
|
|
410
|
+
}
|
|
411
|
+
// --- Input focus event for showOnFocus ---
|
|
412
|
+
if (this._input) {
|
|
413
|
+
this._eventManager.addListener(this._input, 'focus', this._onInputFocus);
|
|
414
|
+
}
|
|
415
|
+
// --- Document click event for outside click detection ---
|
|
416
|
+
this._eventManager.addListener(document, 'click', this._handleDocumentClick);
|
|
417
|
+
this._element.instance = this;
|
|
418
|
+
// Initial render
|
|
419
|
+
this._render();
|
|
112
420
|
};
|
|
113
421
|
/**
|
|
114
|
-
*
|
|
422
|
+
* Get the initial state for the datepicker
|
|
115
423
|
*/
|
|
116
|
-
KTDatepicker.prototype.
|
|
117
|
-
var
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
424
|
+
KTDatepicker.prototype._getInitialState = function () {
|
|
425
|
+
var now = new Date();
|
|
426
|
+
var selectedDate = this._config.value ? new Date(this._config.value) : null;
|
|
427
|
+
var selectedTime = selectedDate && this._config.enableTime ? (0, time_utils_1.dateToTimeState)(selectedDate) : null;
|
|
428
|
+
return {
|
|
429
|
+
currentDate: selectedDate || now,
|
|
430
|
+
selectedDate: selectedDate,
|
|
431
|
+
selectedRange: null,
|
|
432
|
+
selectedDates: [],
|
|
433
|
+
selectedTime: selectedTime,
|
|
434
|
+
timeGranularity: this._config.timeGranularity || 'minute',
|
|
435
|
+
viewMode: 'days',
|
|
436
|
+
isOpen: false,
|
|
437
|
+
isFocused: false,
|
|
438
|
+
isTransitioning: false,
|
|
439
|
+
isDisabled: !!this._config.disabled,
|
|
440
|
+
validationErrors: [],
|
|
441
|
+
isValid: true,
|
|
442
|
+
dropdownState: {
|
|
443
|
+
isOpen: false,
|
|
444
|
+
isTransitioning: false,
|
|
445
|
+
isDisabled: !!this._config.disabled,
|
|
446
|
+
isFocused: false,
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
};
|
|
450
|
+
/**
|
|
451
|
+
* Initialize DOM element cache for performance optimization
|
|
452
|
+
*/
|
|
453
|
+
KTDatepicker.prototype._initializeElementCache = function () {
|
|
454
|
+
var _a, _b;
|
|
455
|
+
// Cache main container elements
|
|
456
|
+
this._cachedElements.calendarElement = this._element.querySelector('[data-kt-datepicker-calendar-table]');
|
|
457
|
+
this._cachedElements.timePickerElement = this._element.querySelector('[data-kt-datepicker-time-container]');
|
|
458
|
+
// Cache range mode containers
|
|
459
|
+
this._cachedElements.startContainer = this._element.querySelector('[data-kt-datepicker-start-container]');
|
|
460
|
+
this._cachedElements.endContainer = this._element.querySelector('[data-kt-datepicker-end-container]');
|
|
461
|
+
// Cache segmented input elements
|
|
462
|
+
this._cachedElements.yearElement = this._element.querySelector('[data-segment="year"]');
|
|
463
|
+
this._cachedElements.monthElement = this._element.querySelector('[data-segment="month"]');
|
|
464
|
+
this._cachedElements.dayElement = this._element.querySelector('[data-segment="day"]');
|
|
465
|
+
this._cachedElements.hourElement = this._element.querySelector('[data-segment="hour"]');
|
|
466
|
+
this._cachedElements.minuteElement = this._element.querySelector('[data-segment="minute"]');
|
|
467
|
+
this._cachedElements.secondElement = this._element.querySelector('[data-segment="second"]');
|
|
468
|
+
this._cachedElements.ampmElement = this._element.querySelector('[data-segment="ampm"]');
|
|
469
|
+
// Cache navigation and display elements
|
|
470
|
+
this._cachedElements.monthYearElement = (_a = this._cachedElements.calendarElement) === null || _a === void 0 ? void 0 : _a.querySelector('[data-kt-datepicker-month-year]');
|
|
471
|
+
this._cachedElements.timeDisplay = (_b = this._cachedElements.timePickerElement) === null || _b === void 0 ? void 0 : _b.querySelector('[data-kt-datepicker-time-value]');
|
|
472
|
+
};
|
|
473
|
+
/**
|
|
474
|
+
* Refresh DOM element cache when structure changes
|
|
475
|
+
*/
|
|
476
|
+
KTDatepicker.prototype._refreshElementCache = function () {
|
|
477
|
+
this._initializeElementCache();
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* Update input field with current state
|
|
481
|
+
*/
|
|
482
|
+
KTDatepicker.prototype._updateInput = function (state) {
|
|
483
|
+
if (!this._input)
|
|
121
484
|
return;
|
|
485
|
+
// Update input value
|
|
486
|
+
var value = '';
|
|
487
|
+
if (this._config.range && state.selectedRange) {
|
|
488
|
+
value = this._formatRange(state.selectedRange.start, state.selectedRange.end);
|
|
122
489
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
// Create segmented display for better date part selection
|
|
136
|
-
var displayContainer = document.createElement('div');
|
|
137
|
-
displayContainer.className = 'kt-datepicker-display-element';
|
|
138
|
-
displayContainer.setAttribute('tabindex', '0');
|
|
139
|
-
displayContainer.setAttribute('role', 'textbox');
|
|
140
|
-
displayContainer.setAttribute('aria-label', placeholder);
|
|
141
|
-
displayContainer.setAttribute('data-kt-datepicker-display', '');
|
|
142
|
-
// Add segmented template based on range mode
|
|
143
|
-
if (this._config.range) {
|
|
144
|
-
displayContainer.innerHTML = (0, templates_1.segmentedDateRangeInputTemplate)(this._config.format || 'mm/dd/yyyy');
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
displayContainer.innerHTML = (0, templates_1.segmentedDateInputTemplate)(this._config.format || 'mm/dd/yyyy');
|
|
148
|
-
}
|
|
149
|
-
this._displayElement = displayContainer;
|
|
150
|
-
this._displayWrapper.appendChild(this._displayElement);
|
|
151
|
-
// Add click handlers for segments
|
|
152
|
-
var segments = this._displayElement.querySelectorAll('[data-segment]');
|
|
153
|
-
segments.forEach(function (segment) {
|
|
154
|
-
segment.addEventListener('click', function (e) {
|
|
155
|
-
e.stopPropagation();
|
|
156
|
-
var segmentType = segment.getAttribute('data-segment');
|
|
157
|
-
_this._handleSegmentClick(segmentType);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
490
|
+
else if (this._config.multiDate && state.selectedDates.length > 0) {
|
|
491
|
+
value = this._formatMultiDate(state.selectedDates);
|
|
492
|
+
}
|
|
493
|
+
else if (state.selectedDate) {
|
|
494
|
+
value = this._formatSingleDate(state.selectedDate);
|
|
495
|
+
}
|
|
496
|
+
if (this._input.value !== value) {
|
|
497
|
+
this._input.value = value;
|
|
498
|
+
}
|
|
499
|
+
// Update disabled state
|
|
500
|
+
if (state.isDisabled) {
|
|
501
|
+
this._input.setAttribute('disabled', 'true');
|
|
160
502
|
}
|
|
161
503
|
else {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
this._displayText = document.createElement('span');
|
|
172
|
-
this._displayText.className = 'kt-datepicker-display-text';
|
|
173
|
-
this._displayText.textContent = placeholder;
|
|
174
|
-
this._displayText.classList.add('text-gray-400');
|
|
175
|
-
this._displayElement.appendChild(this._displayText);
|
|
176
|
-
this._displayWrapper.appendChild(this._displayElement);
|
|
177
|
-
}
|
|
178
|
-
// Add click event to display element
|
|
179
|
-
this._displayElement.addEventListener('click', function (e) {
|
|
180
|
-
e.preventDefault();
|
|
181
|
-
if (!_this._state.getState().isOpen) {
|
|
182
|
-
_this._state.setOpen(true);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
// Enhanced keyboard event handling for display element
|
|
186
|
-
this._displayElement.addEventListener('keydown', function (e) {
|
|
187
|
-
if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
|
|
188
|
-
e.preventDefault();
|
|
189
|
-
e.stopPropagation();
|
|
190
|
-
// If not already open, open the dropdown
|
|
191
|
-
if (!_this._state.getState().isOpen) {
|
|
192
|
-
_this._state.setOpen(true);
|
|
193
|
-
// Dispatch a custom event to notify about the keyboard open
|
|
194
|
-
_this._eventManager.dispatchKeyboardOpenEvent();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
});
|
|
504
|
+
this._input.removeAttribute('disabled');
|
|
505
|
+
}
|
|
506
|
+
// Update placeholder
|
|
507
|
+
if (value) {
|
|
508
|
+
this._input.removeAttribute('placeholder');
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
this._input.setAttribute('placeholder', 'Select date...');
|
|
512
|
+
}
|
|
198
513
|
};
|
|
199
514
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
* @param segmentType - Type of segment clicked
|
|
515
|
+
* Update single date segmented input
|
|
203
516
|
*/
|
|
204
|
-
KTDatepicker.prototype.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
//
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (this._displayElement) {
|
|
213
|
-
var segment = this._displayElement.querySelector("[data-segment=\"".concat(segmentType, "\"]"));
|
|
214
|
-
if (segment) {
|
|
215
|
-
segment.classList.add('kt-datepicker-segment-focused');
|
|
216
|
-
}
|
|
517
|
+
KTDatepicker.prototype._updateSingleSegmentedInput = function (state) {
|
|
518
|
+
var dateToUse = state.selectedDate || state.currentDate;
|
|
519
|
+
if (dateToUse) {
|
|
520
|
+
this._updateDateSegments(dateToUse);
|
|
521
|
+
}
|
|
522
|
+
// Update time segments if time is enabled
|
|
523
|
+
if (state.selectedTime) {
|
|
524
|
+
this._updateTimeSegments(state.selectedTime);
|
|
217
525
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
526
|
+
};
|
|
527
|
+
/**
|
|
528
|
+
* Update date segments in a specific container
|
|
529
|
+
*/
|
|
530
|
+
KTDatepicker.prototype._updateDateSegmentsInContainer = function (date, container) {
|
|
531
|
+
// For range mode, we need to query within the specific container
|
|
532
|
+
var yearElement = container.querySelector('[data-segment="year"]');
|
|
533
|
+
var monthElement = container.querySelector('[data-segment="month"]');
|
|
534
|
+
var dayElement = container.querySelector('[data-segment="day"]');
|
|
535
|
+
if (yearElement) {
|
|
536
|
+
yearElement.textContent = date.getFullYear().toString();
|
|
223
537
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this._state.setViewMode('months');
|
|
227
|
-
this._state.setOpen(true);
|
|
538
|
+
if (monthElement) {
|
|
539
|
+
monthElement.textContent = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
228
540
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this._state.setViewMode('years');
|
|
232
|
-
this._state.setOpen(true);
|
|
541
|
+
if (dayElement) {
|
|
542
|
+
dayElement.textContent = date.getDate().toString().padStart(2, '0');
|
|
233
543
|
}
|
|
234
544
|
};
|
|
235
545
|
/**
|
|
236
|
-
*
|
|
546
|
+
* Update date segments (year, month, day)
|
|
237
547
|
*/
|
|
238
|
-
KTDatepicker.prototype.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
|
|
257
|
-
var state = _this._state.getState();
|
|
258
|
-
if (!state.isOpen) {
|
|
259
|
-
e.preventDefault();
|
|
260
|
-
_this._state.setOpen(true);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
// Add keyboard navigation for segments
|
|
265
|
-
if (this._displayElement && this._useSegmentedDisplay) {
|
|
266
|
-
this._displayElement.addEventListener('keydown', this._handleSegmentKeydown.bind(this));
|
|
548
|
+
KTDatepicker.prototype._updateDateSegments = function (date) {
|
|
549
|
+
this._updateDateSegmentsInContainer(date, this._element);
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Update time segments
|
|
553
|
+
*/
|
|
554
|
+
KTDatepicker.prototype._updateTimeSegments = function (time) {
|
|
555
|
+
if (this._cachedElements.hourElement) {
|
|
556
|
+
this._cachedElements.hourElement.textContent = time.hour.toString().padStart(2, '0');
|
|
557
|
+
}
|
|
558
|
+
if (this._cachedElements.minuteElement) {
|
|
559
|
+
this._cachedElements.minuteElement.textContent = time.minute.toString().padStart(2, '0');
|
|
560
|
+
}
|
|
561
|
+
if (this._cachedElements.secondElement) {
|
|
562
|
+
this._cachedElements.secondElement.textContent = time.second.toString().padStart(2, '0');
|
|
563
|
+
}
|
|
564
|
+
if (this._cachedElements.ampmElement) {
|
|
565
|
+
this._cachedElements.ampmElement.textContent = time.hour >= 12 ? 'PM' : 'AM';
|
|
267
566
|
}
|
|
268
567
|
};
|
|
269
568
|
/**
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* @param e - Keyboard event
|
|
569
|
+
* Update calendar display
|
|
273
570
|
*/
|
|
274
|
-
KTDatepicker.prototype.
|
|
275
|
-
|
|
276
|
-
|
|
571
|
+
KTDatepicker.prototype._updateCalendar = function (state) {
|
|
572
|
+
var _this = this;
|
|
573
|
+
// Try to find dropdown first
|
|
574
|
+
var dropdownEl = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
575
|
+
if (!dropdownEl && this._instanceId) {
|
|
576
|
+
dropdownEl = document.querySelector("[data-kt-datepicker-dropdown][data-kt-datepicker-instance-id=\"".concat(this._instanceId, "\"]"));
|
|
577
|
+
}
|
|
578
|
+
if (!dropdownEl) {
|
|
277
579
|
return;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
580
|
+
}
|
|
581
|
+
// Find ALL calendar tables (for multi-month view support)
|
|
582
|
+
var calendarElements = dropdownEl.querySelectorAll('[data-kt-datepicker-calendar-table]');
|
|
583
|
+
// If no calendars found, return early
|
|
584
|
+
if (calendarElements.length === 0) {
|
|
281
585
|
return;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
586
|
+
}
|
|
587
|
+
// Update cache with first calendar (for backward compatibility)
|
|
588
|
+
if (calendarElements.length > 0) {
|
|
589
|
+
this._cachedElements.calendarElement = calendarElements[0];
|
|
590
|
+
}
|
|
591
|
+
// Update range state on ALL calendar elements for hover handlers to access dynamically
|
|
592
|
+
if (this._config.range && state.selectedRange) {
|
|
593
|
+
calendarElements.forEach(function (calendar) {
|
|
594
|
+
if (state.selectedRange.start) {
|
|
595
|
+
calendar.setAttribute('data-kt-range-start', (0, date_utils_1.formatDateToLocalString)(state.selectedRange.start));
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
calendar.removeAttribute('data-kt-range-start');
|
|
599
|
+
}
|
|
600
|
+
if (state.selectedRange.end) {
|
|
601
|
+
calendar.setAttribute('data-kt-range-end', (0, date_utils_1.formatDateToLocalString)(state.selectedRange.end));
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
calendar.removeAttribute('data-kt-range-end');
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
else if (this._config.range) {
|
|
609
|
+
// No range selected, clear attributes from all calendars
|
|
610
|
+
calendarElements.forEach(function (calendar) {
|
|
611
|
+
calendar.removeAttribute('data-kt-range-start');
|
|
612
|
+
calendar.removeAttribute('data-kt-range-end');
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
// Update date selection highlighting for ALL calendars
|
|
616
|
+
calendarElements.forEach(function (calendarElement) {
|
|
617
|
+
_this._updateDateSelection(state, calendarElement);
|
|
618
|
+
});
|
|
619
|
+
// Update navigation (month/year display) - only update first calendar for navigation
|
|
620
|
+
if (calendarElements.length > 0) {
|
|
621
|
+
this._updateNavigation(state, calendarElements[0]);
|
|
305
622
|
}
|
|
306
623
|
};
|
|
307
624
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* @param direction - 'prev' or 'next'
|
|
311
|
-
* @param currentSegment - Current segment identifier
|
|
625
|
+
* Update date selection highlighting
|
|
312
626
|
*/
|
|
313
|
-
KTDatepicker.prototype.
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
//
|
|
317
|
-
var
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
627
|
+
KTDatepicker.prototype._updateDateSelection = function (state, calendarElement) {
|
|
628
|
+
var _this = this;
|
|
629
|
+
var _a, _b;
|
|
630
|
+
// Clear previous selections
|
|
631
|
+
var selectedCells = calendarElement.querySelectorAll('[data-kt-selected]');
|
|
632
|
+
selectedCells.forEach(function (cell) {
|
|
633
|
+
cell.removeAttribute('data-kt-selected');
|
|
634
|
+
cell.removeAttribute('aria-selected');
|
|
635
|
+
cell.classList.remove('active'); // Remove active class if present (legacy support)
|
|
636
|
+
});
|
|
637
|
+
// Clear previous range highlighting (only if range is complete, not during hover preview)
|
|
638
|
+
// Check if we're in hover preview mode by checking if range has start but no end
|
|
639
|
+
if (((_a = state.selectedRange) === null || _a === void 0 ? void 0 : _a.start) && ((_b = state.selectedRange) === null || _b === void 0 ? void 0 : _b.end)) {
|
|
640
|
+
// Range is complete, clear all hover-range attributes to re-apply for completed range
|
|
641
|
+
var hoverRangeCells = calendarElement.querySelectorAll('[data-kt-hover-range]');
|
|
642
|
+
hoverRangeCells.forEach(function (cell) {
|
|
643
|
+
cell.removeAttribute('data-kt-hover-range');
|
|
644
|
+
});
|
|
327
645
|
}
|
|
328
|
-
|
|
329
|
-
|
|
646
|
+
// Highlight selected date(s)
|
|
647
|
+
if (state.selectedDate) {
|
|
648
|
+
this._highlightDate(state.selectedDate, calendarElement);
|
|
330
649
|
}
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
return;
|
|
335
|
-
// Calculate new index
|
|
336
|
-
var newIndex;
|
|
337
|
-
if (direction === 'prev') {
|
|
338
|
-
newIndex = currentIndex === 0 ? segments.length - 1 : currentIndex - 1;
|
|
650
|
+
// Highlight range start/end dates and dates in between
|
|
651
|
+
if (state.selectedRange) {
|
|
652
|
+
this._highlightDateRange(state.selectedRange, calendarElement);
|
|
339
653
|
}
|
|
340
|
-
|
|
341
|
-
|
|
654
|
+
// Highlight multi-date selections
|
|
655
|
+
if (state.selectedDates.length > 0) {
|
|
656
|
+
state.selectedDates.forEach(function (date) { return _this._highlightDate(date, calendarElement); });
|
|
342
657
|
}
|
|
343
|
-
// Find new segment element
|
|
344
|
-
var newSegment = this._displayElement.querySelector("[data-segment=\"".concat(segments[newIndex], "\"]"));
|
|
345
|
-
if (!newSegment)
|
|
346
|
-
return;
|
|
347
|
-
// Update focus
|
|
348
|
-
newSegment.focus();
|
|
349
|
-
this._segmentFocused = segments[newIndex];
|
|
350
|
-
// Remove highlight from all segments
|
|
351
|
-
this._removeSegmentHighlights();
|
|
352
|
-
// Add highlight to new segment
|
|
353
|
-
newSegment.classList.add('segment-focused');
|
|
354
658
|
};
|
|
355
659
|
/**
|
|
356
|
-
*
|
|
660
|
+
* Highlight a specific date
|
|
661
|
+
* Uses data-kt-selected attribute (class="active" removed for consistency)
|
|
357
662
|
*/
|
|
358
|
-
KTDatepicker.prototype.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
663
|
+
KTDatepicker.prototype._highlightDate = function (date, calendarElement) {
|
|
664
|
+
var cell = this._findDayCell(date, calendarElement);
|
|
665
|
+
if (cell) {
|
|
666
|
+
cell.setAttribute('data-kt-selected', 'true');
|
|
667
|
+
cell.setAttribute('aria-selected', 'true');
|
|
668
|
+
// Note: class="active" is redundant - CSS already targets data-kt-selected
|
|
669
|
+
}
|
|
365
670
|
};
|
|
366
671
|
/**
|
|
367
|
-
*
|
|
672
|
+
* Highlight a date range
|
|
673
|
+
* Uses data-kt-hover-range for both hover preview and completed ranges (consolidated)
|
|
368
674
|
*/
|
|
369
|
-
KTDatepicker.prototype.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
var selectedDate = state.selectedDate;
|
|
375
|
-
var selectedDateRange = state.selectedDateRange;
|
|
376
|
-
if (this._useSegmentedDisplay) {
|
|
377
|
-
// Update segmented display elements
|
|
378
|
-
if (selectedDate) {
|
|
379
|
-
// Single date
|
|
380
|
-
var daySegment = this._displayElement.querySelector('[data-segment="day"]');
|
|
381
|
-
var monthSegment = this._displayElement.querySelector('[data-segment="month"]');
|
|
382
|
-
var yearSegment = this._displayElement.querySelector('[data-segment="year"]');
|
|
383
|
-
if (daySegment) {
|
|
384
|
-
daySegment.textContent = selectedDate
|
|
385
|
-
.getDate()
|
|
386
|
-
.toString()
|
|
387
|
-
.padStart(2, '0');
|
|
388
|
-
}
|
|
389
|
-
if (monthSegment) {
|
|
390
|
-
monthSegment.textContent = (selectedDate.getMonth() + 1)
|
|
391
|
-
.toString()
|
|
392
|
-
.padStart(2, '0');
|
|
393
|
-
}
|
|
394
|
-
if (yearSegment) {
|
|
395
|
-
yearSegment.textContent = selectedDate.getFullYear().toString();
|
|
396
|
-
}
|
|
675
|
+
KTDatepicker.prototype._highlightDateRange = function (range, calendarElement) {
|
|
676
|
+
if (!range.start || !range.end) {
|
|
677
|
+
// If only start or end is set, just highlight that date (hover preview handles the rest)
|
|
678
|
+
if (range.start) {
|
|
679
|
+
this._highlightDate(range.start, calendarElement);
|
|
397
680
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
var startDay = this._displayElement.querySelector('[data-segment="start-day"]');
|
|
401
|
-
var startMonth = this._displayElement.querySelector('[data-segment="start-month"]');
|
|
402
|
-
var startYear = this._displayElement.querySelector('[data-segment="start-year"]');
|
|
403
|
-
if (startDay) {
|
|
404
|
-
startDay.textContent = selectedDateRange.startDate
|
|
405
|
-
.getDate()
|
|
406
|
-
.toString()
|
|
407
|
-
.padStart(2, '0');
|
|
408
|
-
}
|
|
409
|
-
if (startMonth) {
|
|
410
|
-
startMonth.textContent = (selectedDateRange.startDate.getMonth() + 1)
|
|
411
|
-
.toString()
|
|
412
|
-
.padStart(2, '0');
|
|
413
|
-
}
|
|
414
|
-
if (startYear) {
|
|
415
|
-
startYear.textContent = selectedDateRange.startDate
|
|
416
|
-
.getFullYear()
|
|
417
|
-
.toString();
|
|
418
|
-
}
|
|
419
|
-
if (selectedDateRange.endDate) {
|
|
420
|
-
var endDay = this._displayElement.querySelector('[data-segment="end-day"]');
|
|
421
|
-
var endMonth = this._displayElement.querySelector('[data-segment="end-month"]');
|
|
422
|
-
var endYear = this._displayElement.querySelector('[data-segment="end-year"]');
|
|
423
|
-
if (endDay) {
|
|
424
|
-
endDay.textContent = selectedDateRange.endDate
|
|
425
|
-
.getDate()
|
|
426
|
-
.toString()
|
|
427
|
-
.padStart(2, '0');
|
|
428
|
-
}
|
|
429
|
-
if (endMonth) {
|
|
430
|
-
endMonth.textContent = (selectedDateRange.endDate.getMonth() + 1)
|
|
431
|
-
.toString()
|
|
432
|
-
.padStart(2, '0');
|
|
433
|
-
}
|
|
434
|
-
if (endYear) {
|
|
435
|
-
endYear.textContent = selectedDateRange.endDate
|
|
436
|
-
.getFullYear()
|
|
437
|
-
.toString();
|
|
438
|
-
}
|
|
439
|
-
}
|
|
681
|
+
if (range.end) {
|
|
682
|
+
this._highlightDate(range.end, calendarElement);
|
|
440
683
|
}
|
|
684
|
+
return;
|
|
441
685
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
686
|
+
// Normalize dates to local midnight for accurate comparison
|
|
687
|
+
var start = new Date(range.start);
|
|
688
|
+
start.setHours(0, 0, 0, 0);
|
|
689
|
+
var end = new Date(range.end);
|
|
690
|
+
end.setHours(0, 0, 0, 0);
|
|
691
|
+
// Determine actual start and end (handle backward selection)
|
|
692
|
+
var actualStart = start <= end ? start : end;
|
|
693
|
+
var actualEnd = start <= end ? end : start;
|
|
694
|
+
// Highlight start and end dates
|
|
695
|
+
this._highlightDate(actualStart, calendarElement);
|
|
696
|
+
this._highlightDate(actualEnd, calendarElement);
|
|
697
|
+
// Find all calendars in multi-month view to highlight range across all visible months
|
|
698
|
+
var dropdownEl = calendarElement.closest('[data-kt-datepicker-dropdown]');
|
|
699
|
+
var allCalendars = dropdownEl
|
|
700
|
+
? Array.from(dropdownEl.querySelectorAll('[data-kt-datepicker-calendar-table]'))
|
|
701
|
+
: [calendarElement];
|
|
702
|
+
// Highlight all dates in between using data-kt-hover-range (same as hover preview)
|
|
703
|
+
var current = new Date(actualStart);
|
|
704
|
+
current.setDate(current.getDate() + 1); // Start from day after start
|
|
705
|
+
while (current < actualEnd) {
|
|
706
|
+
var dateLocal = (0, date_utils_1.formatDateToLocalString)(current);
|
|
707
|
+
// Search across all calendars to find the cell
|
|
708
|
+
for (var _i = 0, allCalendars_1 = allCalendars; _i < allCalendars_1.length; _i++) {
|
|
709
|
+
var calendar = allCalendars_1[_i];
|
|
710
|
+
var cell = calendar.querySelector("td[data-kt-datepicker-day][data-date=\"".concat(dateLocal, "\"]"));
|
|
711
|
+
if (cell) {
|
|
712
|
+
// Use data-kt-hover-range for completed ranges (consolidated with hover preview)
|
|
713
|
+
cell.setAttribute('data-kt-hover-range', 'true');
|
|
714
|
+
break; // Found in this calendar, no need to search others
|
|
456
715
|
}
|
|
457
716
|
}
|
|
458
|
-
|
|
459
|
-
// No date selected, show format as placeholder
|
|
460
|
-
var placeholder = ((_a = this._displayElement) === null || _a === void 0 ? void 0 : _a.getAttribute('data-placeholder')) ||
|
|
461
|
-
this._config.format;
|
|
462
|
-
this._displayText.textContent = placeholder;
|
|
463
|
-
this._displayText.classList.add('placeholder');
|
|
464
|
-
}
|
|
717
|
+
current.setDate(current.getDate() + 1);
|
|
465
718
|
}
|
|
466
719
|
};
|
|
467
720
|
/**
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
721
|
+
* Find day cell for a specific date
|
|
722
|
+
* Uses data-date attribute (YYYY-MM-DD format) for accurate date matching across months
|
|
723
|
+
* Searches within the provided calendar element, or across all calendars in multi-month view
|
|
471
724
|
*/
|
|
472
|
-
KTDatepicker.prototype.
|
|
473
|
-
var
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
displayValue = (0, utils_1.formatDate)(startDate, this._config.format, this._config);
|
|
497
|
-
if (endDate) {
|
|
498
|
-
var endFormatted = (0, utils_1.formatDate)(endDate, this._config.format, this._config);
|
|
499
|
-
displayValue += "".concat(this._config.rangeSeparator).concat(endFormatted);
|
|
725
|
+
KTDatepicker.prototype._findDayCell = function (date, calendarElement) {
|
|
726
|
+
var dateLocal = (0, date_utils_1.formatDateToLocalString)(date); // Use local timezone date string for accurate matching (YYYY-MM-DD)
|
|
727
|
+
// First, try to find in the provided calendar element
|
|
728
|
+
var cells = calendarElement.querySelectorAll('td[data-kt-datepicker-day]');
|
|
729
|
+
for (var _i = 0, _a = Array.from(cells); _i < _a.length; _i++) {
|
|
730
|
+
var cell = _a[_i];
|
|
731
|
+
var cellDate = cell.getAttribute('data-date');
|
|
732
|
+
if (cellDate === dateLocal) {
|
|
733
|
+
return cell;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
// If not found in provided calendar, search across all calendars in multi-month view
|
|
737
|
+
// This handles cases where the date might be in a different visible month
|
|
738
|
+
var dropdownEl = calendarElement.closest('[data-kt-datepicker-dropdown]');
|
|
739
|
+
if (dropdownEl) {
|
|
740
|
+
var allCalendars = dropdownEl.querySelectorAll('[data-kt-datepicker-calendar-table]');
|
|
741
|
+
for (var _b = 0, _c = Array.from(allCalendars); _b < _c.length; _b++) {
|
|
742
|
+
var calendar = _c[_b];
|
|
743
|
+
var allCells = calendar.querySelectorAll('td[data-kt-datepicker-day]');
|
|
744
|
+
for (var _d = 0, _e = Array.from(allCells); _d < _e.length; _d++) {
|
|
745
|
+
var cell = _e[_d];
|
|
746
|
+
var cellDate = cell.getAttribute('data-date');
|
|
747
|
+
if (cellDate === dateLocal) {
|
|
748
|
+
return cell;
|
|
500
749
|
}
|
|
501
750
|
}
|
|
502
|
-
this._dateInputElement.value = displayValue;
|
|
503
|
-
// Dispatch change event on input
|
|
504
|
-
this._dateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
505
751
|
}
|
|
506
|
-
// Update individual start/end inputs if they exist
|
|
507
|
-
if (this._startDateInputElement && startDate) {
|
|
508
|
-
this._startDateInputElement.value = (0, utils_1.formatDate)(startDate, this._config.format, this._config);
|
|
509
|
-
this._startDateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
510
|
-
}
|
|
511
|
-
if (this._endDateInputElement && endDate) {
|
|
512
|
-
this._endDateInputElement.value = (0, utils_1.formatDate)(endDate, this._config.format, this._config);
|
|
513
|
-
this._endDateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
514
|
-
}
|
|
515
|
-
// Update display element for range
|
|
516
|
-
this._updateRangeDisplayElement(startDate, endDate);
|
|
517
752
|
}
|
|
753
|
+
// No fallback - if date not found by data-date, it's not in any visible calendar view
|
|
754
|
+
// This prevents incorrect matches (e.g., matching Oct 20 when looking for Nov 20)
|
|
755
|
+
return null;
|
|
518
756
|
};
|
|
519
757
|
/**
|
|
520
|
-
* Update
|
|
521
|
-
*
|
|
522
|
-
* @param date - The date to display
|
|
758
|
+
* Update navigation display
|
|
523
759
|
*/
|
|
524
|
-
KTDatepicker.prototype.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
760
|
+
KTDatepicker.prototype._updateNavigation = function (state, calendarElement) {
|
|
761
|
+
if (this._cachedElements.monthYearElement) {
|
|
762
|
+
var month = state.currentDate.toLocaleDateString('en-US', { month: 'long' });
|
|
763
|
+
var year = state.currentDate.getFullYear();
|
|
764
|
+
this._cachedElements.monthYearElement.textContent = "".concat(month, " ").concat(year);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
/**
|
|
768
|
+
* Update time picker display
|
|
769
|
+
*/
|
|
770
|
+
KTDatepicker.prototype._updateTimePicker = function (state) {
|
|
771
|
+
if (!this._cachedElements.timePickerElement || !state.selectedTime)
|
|
532
772
|
return;
|
|
773
|
+
if (this._cachedElements.timeDisplay) {
|
|
774
|
+
var timeString = "".concat(state.selectedTime.hour.toString().padStart(2, '0'), ":").concat(state.selectedTime.minute.toString().padStart(2, '0'), ":").concat(state.selectedTime.second.toString().padStart(2, '0'));
|
|
775
|
+
this._cachedElements.timeDisplay.textContent = timeString;
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* Fire events based on state changes using the centralized event system
|
|
780
|
+
*/
|
|
781
|
+
KTDatepicker.prototype._fireEvents = function (newState, oldState) {
|
|
782
|
+
var _a, _b, _c, _d;
|
|
783
|
+
// Fire onChange when selected date changes
|
|
784
|
+
if (newState.selectedDate !== oldState.selectedDate ||
|
|
785
|
+
((_a = newState.selectedRange) === null || _a === void 0 ? void 0 : _a.start) !== ((_b = oldState.selectedRange) === null || _b === void 0 ? void 0 : _b.start) ||
|
|
786
|
+
((_c = newState.selectedRange) === null || _c === void 0 ? void 0 : _c.end) !== ((_d = oldState.selectedRange) === null || _d === void 0 ? void 0 : _d.end) ||
|
|
787
|
+
JSON.stringify(newState.selectedDates) !== JSON.stringify(oldState.selectedDates)) {
|
|
788
|
+
var selectedValue = null;
|
|
789
|
+
if (this._config.range && newState.selectedRange) {
|
|
790
|
+
// For range mode, pass the end date if both are selected, otherwise null
|
|
791
|
+
selectedValue = newState.selectedRange.end || newState.selectedRange.start;
|
|
792
|
+
}
|
|
793
|
+
else if (this._config.multiDate && newState.selectedDates.length > 0) {
|
|
794
|
+
// For multi-date mode, pass the last selected date
|
|
795
|
+
selectedValue = newState.selectedDates[newState.selectedDates.length - 1];
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
// For single date mode
|
|
799
|
+
selectedValue = newState.selectedDate;
|
|
800
|
+
}
|
|
801
|
+
this._fireDatepickerEvent('onChange', selectedValue, this);
|
|
533
802
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
var month = date.getMonth() + 1;
|
|
538
|
-
var year = date.getFullYear();
|
|
539
|
-
var daySegment = this._displayElement.querySelector('[data-segment="day"]');
|
|
540
|
-
var monthSegment = this._displayElement.querySelector('[data-segment="month"]');
|
|
541
|
-
var yearSegment = this._displayElement.querySelector('[data-segment="year"]');
|
|
542
|
-
if (daySegment)
|
|
543
|
-
daySegment.textContent = day < 10 ? "0".concat(day) : "".concat(day);
|
|
544
|
-
if (monthSegment)
|
|
545
|
-
monthSegment.textContent = month < 10 ? "0".concat(month) : "".concat(month);
|
|
546
|
-
if (yearSegment)
|
|
547
|
-
yearSegment.textContent = "".concat(year);
|
|
803
|
+
// Fire onOpen when dropdown opens
|
|
804
|
+
if (newState.isOpen && !oldState.isOpen) {
|
|
805
|
+
this._fireDatepickerEvent('onOpen', this);
|
|
548
806
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
this.
|
|
807
|
+
// Fire onClose when dropdown closes
|
|
808
|
+
if (!newState.isOpen && oldState.isOpen) {
|
|
809
|
+
this._fireDatepickerEvent('onClose', this);
|
|
552
810
|
}
|
|
553
811
|
};
|
|
554
812
|
/**
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
* @param startDate - The start date of the range
|
|
558
|
-
* @param endDate - The end date of the range
|
|
813
|
+
* Centralized event firing system - safely dispatches events with error handling
|
|
559
814
|
*/
|
|
560
|
-
KTDatepicker.prototype.
|
|
561
|
-
var
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
if (!startDate) {
|
|
565
|
-
// If no date, show placeholder
|
|
566
|
-
var placeholder = ((_a = this._dateInputElement) === null || _a === void 0 ? void 0 : _a.getAttribute('placeholder')) ||
|
|
567
|
-
'Select date range';
|
|
568
|
-
this._displayElement.innerHTML = (0, templates_1.placeholderTemplate)(placeholder);
|
|
569
|
-
return;
|
|
815
|
+
KTDatepicker.prototype._fireDatepickerEvent = function (eventName) {
|
|
816
|
+
var args = [];
|
|
817
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
818
|
+
args[_i - 1] = arguments[_i];
|
|
570
819
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
var startMonth = this._displayElement.querySelector('[data-segment="start-month"]');
|
|
576
|
-
var startYear = this._displayElement.querySelector('[data-segment="start-year"]');
|
|
577
|
-
if (startDay)
|
|
578
|
-
startDay.textContent =
|
|
579
|
-
startDate.getDate() < 10
|
|
580
|
-
? "0".concat(startDate.getDate())
|
|
581
|
-
: "".concat(startDate.getDate());
|
|
582
|
-
if (startMonth)
|
|
583
|
-
startMonth.textContent =
|
|
584
|
-
startDate.getMonth() + 1 < 10
|
|
585
|
-
? "0".concat(startDate.getMonth() + 1)
|
|
586
|
-
: "".concat(startDate.getMonth() + 1);
|
|
587
|
-
if (startYear)
|
|
588
|
-
startYear.textContent = "".concat(startDate.getFullYear());
|
|
589
|
-
// End date segments
|
|
590
|
-
if (endDate) {
|
|
591
|
-
var endDay = this._displayElement.querySelector('[data-segment="end-day"]');
|
|
592
|
-
var endMonth = this._displayElement.querySelector('[data-segment="end-month"]');
|
|
593
|
-
var endYear = this._displayElement.querySelector('[data-segment="end-year"]');
|
|
594
|
-
if (endDay)
|
|
595
|
-
endDay.textContent =
|
|
596
|
-
endDate.getDate() < 10
|
|
597
|
-
? "0".concat(endDate.getDate())
|
|
598
|
-
: "".concat(endDate.getDate());
|
|
599
|
-
if (endMonth)
|
|
600
|
-
endMonth.textContent =
|
|
601
|
-
endDate.getMonth() + 1 < 10
|
|
602
|
-
? "0".concat(endDate.getMonth() + 1)
|
|
603
|
-
: "".concat(endDate.getMonth() + 1);
|
|
604
|
-
if (endYear)
|
|
605
|
-
endYear.textContent = "".concat(endDate.getFullYear());
|
|
820
|
+
try {
|
|
821
|
+
var eventHandler = this._config[eventName];
|
|
822
|
+
if (typeof eventHandler === 'function') {
|
|
823
|
+
eventHandler.apply(void 0, args);
|
|
606
824
|
}
|
|
607
825
|
}
|
|
608
|
-
|
|
609
|
-
//
|
|
610
|
-
var displayText = (0, utils_1.formatDate)(startDate, this._config.format, this._config);
|
|
611
|
-
if (endDate) {
|
|
612
|
-
var endFormatted = (0, utils_1.formatDate)(endDate, this._config.format, this._config);
|
|
613
|
-
displayText += "".concat(this._config.rangeSeparator).concat(endFormatted);
|
|
614
|
-
}
|
|
615
|
-
this._displayElement.textContent = displayText;
|
|
826
|
+
catch (error) {
|
|
827
|
+
// Don't let event handler errors break the datepicker
|
|
616
828
|
}
|
|
617
829
|
};
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
var inputValue = input.value.trim();
|
|
626
|
-
if (!inputValue) {
|
|
627
|
-
// Clear selection if input is empty
|
|
628
|
-
this._state.setSelectedDate(null);
|
|
629
|
-
return;
|
|
830
|
+
// --- Mode-specific helpers ---
|
|
831
|
+
/** Initialize single date from config */
|
|
832
|
+
KTDatepicker.prototype._initSingleDateFromConfig = function () {
|
|
833
|
+
if (this._config.value) {
|
|
834
|
+
var date = new Date(this._config.value);
|
|
835
|
+
this._unifiedStateManager.setSelectedDate(date, 'config');
|
|
836
|
+
this._unifiedStateManager.setCurrentDate(date, 'config');
|
|
630
837
|
}
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
838
|
+
};
|
|
839
|
+
/** Initialize range from config */
|
|
840
|
+
KTDatepicker.prototype._initRangeFromConfig = function () {
|
|
841
|
+
if (this._config.valueRange) {
|
|
842
|
+
var start = this._config.valueRange.start ? new Date(this._config.valueRange.start) : null;
|
|
843
|
+
var end = this._config.valueRange.end ? new Date(this._config.valueRange.end) : null;
|
|
844
|
+
this._unifiedStateManager.setSelectedRange({ start: start, end: end }, 'config');
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
/** Initialize multi-date from config */
|
|
848
|
+
KTDatepicker.prototype._initMultiDateFromConfig = function () {
|
|
849
|
+
if (Array.isArray(this._config.values)) {
|
|
850
|
+
var dates = this._config.values.map(function (v) { return new Date(v); });
|
|
851
|
+
this._unifiedStateManager.setSelectedDates(dates, 'config');
|
|
852
|
+
}
|
|
853
|
+
};
|
|
854
|
+
/** Format single date for input */
|
|
855
|
+
KTDatepicker.prototype._formatSingleDate = function (date) {
|
|
856
|
+
if (!date)
|
|
857
|
+
return '';
|
|
858
|
+
// If time is enabled, include time in the format
|
|
859
|
+
if (this._config.enableTime) {
|
|
860
|
+
if (this._config.format && typeof this._config.format === 'string') {
|
|
861
|
+
// Check if format already includes time tokens
|
|
862
|
+
var hasTimeTokens = /[Hhms]/.test(this._config.format);
|
|
863
|
+
if (hasTimeTokens) {
|
|
864
|
+
return (0, date_formatters_1.formatDate)(date, this._config.format);
|
|
645
865
|
}
|
|
646
|
-
|
|
647
|
-
|
|
866
|
+
else {
|
|
867
|
+
// Add time format based on granularity and format
|
|
868
|
+
var timeFormat = this._getTimeFormat();
|
|
869
|
+
var dateFormat = this._config.format;
|
|
870
|
+
return (0, date_formatters_1.formatDate)(date, "".concat(dateFormat, " ").concat(timeFormat));
|
|
648
871
|
}
|
|
649
872
|
}
|
|
650
|
-
else
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
console.log('Date from input is outside allowed range:', singleDate.toISOString());
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
if (singleDate) {
|
|
658
|
-
this.setDateRange(singleDate, null);
|
|
659
|
-
}
|
|
873
|
+
else {
|
|
874
|
+
// Default format with time
|
|
875
|
+
var timeFormat = this._getTimeFormat();
|
|
876
|
+
return "".concat(date.toLocaleDateString(this._config.locale || 'en-US'), " ").concat((0, date_formatters_1.formatDate)(date, timeFormat));
|
|
660
877
|
}
|
|
661
878
|
}
|
|
662
879
|
else {
|
|
663
|
-
//
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (parsedDate && (0, utils_1.isDateDisabled)(parsedDate, this._config)) {
|
|
667
|
-
console.log('Date from input is outside allowed range:', parsedDate.toISOString());
|
|
668
|
-
return;
|
|
880
|
+
// Time not enabled, use original logic
|
|
881
|
+
if (this._config.format && typeof this._config.format === 'string') {
|
|
882
|
+
return (0, date_formatters_1.formatDate)(date, this._config.format);
|
|
669
883
|
}
|
|
670
|
-
if (
|
|
671
|
-
this.
|
|
884
|
+
else if (this._config.locale) {
|
|
885
|
+
return date.toLocaleDateString(this._config.locale);
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
return date.toLocaleDateString();
|
|
672
889
|
}
|
|
673
890
|
}
|
|
674
891
|
};
|
|
675
892
|
/**
|
|
676
|
-
*
|
|
893
|
+
* Get time format string based on granularity and time format
|
|
894
|
+
* @returns Time format string
|
|
677
895
|
*/
|
|
678
|
-
KTDatepicker.prototype.
|
|
679
|
-
|
|
680
|
-
var
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
896
|
+
KTDatepicker.prototype._getTimeFormat = function () {
|
|
897
|
+
var granularity = this._unifiedStateManager.getState().timeGranularity || 'minute';
|
|
898
|
+
var timeFormat = this._config.timeFormat || '24h';
|
|
899
|
+
switch (granularity) {
|
|
900
|
+
case 'hour':
|
|
901
|
+
return timeFormat === '12h' ? 'HH a' : 'HH';
|
|
902
|
+
case 'minute':
|
|
903
|
+
return timeFormat === '12h' ? 'HH:mm a' : 'HH:mm';
|
|
904
|
+
case 'second':
|
|
905
|
+
return timeFormat === '12h' ? 'HH:mm:ss a' : 'HH:mm:ss';
|
|
906
|
+
default:
|
|
907
|
+
return timeFormat === '12h' ? 'HH:mm a' : 'HH:mm';
|
|
687
908
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
909
|
+
};
|
|
910
|
+
/** Format range for input */
|
|
911
|
+
KTDatepicker.prototype._formatRange = function (start, end) {
|
|
912
|
+
if (start && end) {
|
|
913
|
+
return "".concat(this._formatSingleDate(start), " \u2013 ").concat(this._formatSingleDate(end));
|
|
693
914
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
this._handleInputChange({
|
|
697
|
-
target: this._dateInputElement,
|
|
698
|
-
});
|
|
915
|
+
else if (start) {
|
|
916
|
+
return this._formatSingleDate(start);
|
|
699
917
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
918
|
+
return '';
|
|
919
|
+
};
|
|
920
|
+
/** Format multi-date for input */
|
|
921
|
+
KTDatepicker.prototype._formatMultiDate = function (dates) {
|
|
922
|
+
var _this = this;
|
|
923
|
+
return dates.map(function (d) { return _this._formatSingleDate(d); }).join(', ');
|
|
924
|
+
};
|
|
925
|
+
/** Select a single date */
|
|
926
|
+
KTDatepicker.prototype._selectSingleDate = function (date) {
|
|
927
|
+
// Preserve time if time is enabled
|
|
928
|
+
if (this._config.enableTime) {
|
|
929
|
+
var timeToUse = this._unifiedStateManager.getState().selectedTime;
|
|
930
|
+
// If no selectedTime, try to extract from current selectedDate
|
|
931
|
+
if (!timeToUse) {
|
|
932
|
+
var currentSelectedDate = this._unifiedStateManager.getState().selectedDate;
|
|
933
|
+
if (currentSelectedDate) {
|
|
934
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(currentSelectedDate);
|
|
935
|
+
}
|
|
708
936
|
}
|
|
709
|
-
|
|
710
|
-
|
|
937
|
+
// If still no time, default to current time
|
|
938
|
+
if (!timeToUse) {
|
|
939
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(new Date());
|
|
711
940
|
}
|
|
941
|
+
var dateWithTime = (0, time_utils_1.applyTimeToDate)(date, timeToUse);
|
|
942
|
+
this._unifiedStateManager.setSelectedDate(dateWithTime, 'calendar');
|
|
943
|
+
}
|
|
944
|
+
else {
|
|
945
|
+
this._unifiedStateManager.setSelectedDate(date, 'calendar');
|
|
946
|
+
}
|
|
947
|
+
// Dispatch change event
|
|
948
|
+
if (this._input) {
|
|
949
|
+
var evt = new Event('change', { bubbles: true });
|
|
950
|
+
this._input.dispatchEvent(evt);
|
|
712
951
|
}
|
|
713
952
|
};
|
|
714
953
|
/**
|
|
715
|
-
*
|
|
716
|
-
*
|
|
717
|
-
* ========================================================================
|
|
718
|
-
*/
|
|
719
|
-
/**
|
|
720
|
-
* Get the currently selected date
|
|
721
|
-
*
|
|
722
|
-
* @returns Selected date, null if no selection, or date range object
|
|
954
|
+
* Select a range date (calendar click or segmented input change)
|
|
955
|
+
* Updates both segmented inputs and internal state.
|
|
723
956
|
*/
|
|
724
|
-
KTDatepicker.prototype.
|
|
725
|
-
var
|
|
726
|
-
var
|
|
727
|
-
|
|
728
|
-
|
|
957
|
+
KTDatepicker.prototype._selectRangeDate = function (date) {
|
|
958
|
+
var _a;
|
|
959
|
+
var currentState = this._unifiedStateManager.getState();
|
|
960
|
+
// First, let updateRangeSelection handle the date logic (it normalizes to midnight for comparison)
|
|
961
|
+
var newRange = (0, helpers_1.updateRangeSelection)(currentState.selectedRange, date);
|
|
962
|
+
// Then, if time is enabled, apply time to both start and end dates
|
|
963
|
+
if (this._config.enableTime) {
|
|
964
|
+
var timeToUse = currentState.selectedTime;
|
|
965
|
+
// If no selectedTime, try to extract from current selectedDate or range dates
|
|
966
|
+
if (!timeToUse) {
|
|
967
|
+
// Check if we have a start date with time
|
|
968
|
+
if ((_a = currentState.selectedRange) === null || _a === void 0 ? void 0 : _a.start) {
|
|
969
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(currentState.selectedRange.start);
|
|
970
|
+
}
|
|
971
|
+
else if (currentState.selectedDate) {
|
|
972
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(currentState.selectedDate);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
// If still no time, default to current time
|
|
976
|
+
if (!timeToUse) {
|
|
977
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(new Date());
|
|
978
|
+
}
|
|
979
|
+
// Apply time to both start and end dates
|
|
980
|
+
var rangeWithTime = {
|
|
981
|
+
start: newRange.start ? (0, time_utils_1.applyTimeToDate)(newRange.start, timeToUse) : null,
|
|
982
|
+
end: newRange.end ? (0, time_utils_1.applyTimeToDate)(newRange.end, timeToUse) : null
|
|
983
|
+
};
|
|
984
|
+
this._unifiedStateManager.setSelectedRange(rangeWithTime, 'calendar');
|
|
729
985
|
}
|
|
730
986
|
else {
|
|
731
|
-
|
|
987
|
+
this._unifiedStateManager.setSelectedRange(newRange, 'calendar');
|
|
988
|
+
}
|
|
989
|
+
if (this._input) {
|
|
990
|
+
var evt = new Event('change', { bubbles: true });
|
|
991
|
+
this._input.dispatchEvent(evt);
|
|
732
992
|
}
|
|
733
993
|
};
|
|
734
|
-
/**
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
994
|
+
/** Select a multi-date */
|
|
995
|
+
KTDatepicker.prototype._selectMultiDate = function (date) {
|
|
996
|
+
var currentState = this._unifiedStateManager.getState();
|
|
997
|
+
var currentDates = currentState.selectedDates || [];
|
|
998
|
+
// Preserve time if time is enabled
|
|
999
|
+
var dateToSelect = date;
|
|
1000
|
+
if (this._config.enableTime) {
|
|
1001
|
+
var timeToUse = currentState.selectedTime;
|
|
1002
|
+
// If no selectedTime, try to extract from existing selected dates
|
|
1003
|
+
if (!timeToUse && currentDates.length > 0) {
|
|
1004
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(currentDates[0]);
|
|
1005
|
+
}
|
|
1006
|
+
else if (!timeToUse && currentState.selectedDate) {
|
|
1007
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(currentState.selectedDate);
|
|
1008
|
+
}
|
|
1009
|
+
// If still no time, default to current time
|
|
1010
|
+
if (!timeToUse) {
|
|
1011
|
+
timeToUse = (0, time_utils_1.dateToTimeState)(new Date());
|
|
1012
|
+
}
|
|
1013
|
+
dateToSelect = (0, time_utils_1.applyTimeToDate)(date, timeToUse);
|
|
744
1014
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1015
|
+
var exists = currentDates.some(function (d) { return d.getTime() === dateToSelect.getTime(); });
|
|
1016
|
+
var newDates;
|
|
1017
|
+
if (exists) {
|
|
1018
|
+
newDates = currentDates.filter(function (d) { return d.getTime() !== dateToSelect.getTime(); });
|
|
748
1019
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
// Update hidden input
|
|
752
|
-
if (this._dateInputElement && date) {
|
|
753
|
-
this._dateInputElement.value = (0, utils_1.formatDate)(date, this._config.format, this._config);
|
|
754
|
-
this._dateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1020
|
+
else {
|
|
1021
|
+
newDates = __spreadArray(__spreadArray([], currentDates, true), [dateToSelect], false);
|
|
755
1022
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1023
|
+
this._unifiedStateManager.setSelectedDates(newDates, 'calendar');
|
|
1024
|
+
if (this._input) {
|
|
1025
|
+
var evt = new Event('change', { bubbles: true });
|
|
1026
|
+
this._input.dispatchEvent(evt);
|
|
759
1027
|
}
|
|
760
1028
|
};
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1029
|
+
KTDatepicker.prototype._init = function (element) {
|
|
1030
|
+
this._element = element;
|
|
1031
|
+
// Find or assign the input
|
|
1032
|
+
this._input = this._element.querySelector('input[data-kt-datepicker-input]');
|
|
1033
|
+
if (!this._input) {
|
|
1034
|
+
// Fallback: find the first input and add the attribute
|
|
1035
|
+
var firstInput = this._element.querySelector('input');
|
|
1036
|
+
if (firstInput) {
|
|
1037
|
+
firstInput.setAttribute('data-kt-datepicker-input', '');
|
|
1038
|
+
this._input = firstInput;
|
|
1039
|
+
}
|
|
1040
|
+
else {
|
|
1041
|
+
// If no input exists, create one and append
|
|
1042
|
+
var newInput = document.createElement('input');
|
|
1043
|
+
newInput.setAttribute('data-kt-datepicker-input', '');
|
|
1044
|
+
this._element.appendChild(newInput);
|
|
1045
|
+
this._input = newInput;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
769
1048
|
};
|
|
770
1049
|
/**
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
* @param start - Start date of the range
|
|
774
|
-
* @param end - End date of the range
|
|
1050
|
+
* Build config by merging defaults and user config
|
|
775
1051
|
*/
|
|
776
|
-
KTDatepicker.prototype.
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
//
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
1052
|
+
KTDatepicker.prototype._buildConfig = function (config) {
|
|
1053
|
+
// First call parent to read data attributes
|
|
1054
|
+
_super.prototype._buildConfig.call(this, config);
|
|
1055
|
+
// Merge templates separately to ensure correct type
|
|
1056
|
+
var mergedTemplates = __assign(__assign(__assign({}, templates_1.defaultTemplates), (this._config.templates || {})), (this._userTemplates || {}));
|
|
1057
|
+
// Determine closeOnSelect default based on mode and requirements
|
|
1058
|
+
var closeOnSelect;
|
|
1059
|
+
if (typeof this._config.closeOnSelect !== 'undefined') {
|
|
1060
|
+
// User explicitly set closeOnSelect, respect their choice
|
|
1061
|
+
closeOnSelect = this._config.closeOnSelect;
|
|
783
1062
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
return;
|
|
1063
|
+
else if (this._config.enableTime) {
|
|
1064
|
+
// Time-enabled: never close on date selection
|
|
1065
|
+
closeOnSelect = false;
|
|
788
1066
|
}
|
|
789
|
-
if (
|
|
790
|
-
|
|
791
|
-
|
|
1067
|
+
else if (this._config.range) {
|
|
1068
|
+
// Range mode: handle clicks inside dropdown
|
|
1069
|
+
closeOnSelect = false;
|
|
1070
|
+
}
|
|
1071
|
+
else if (this._config.multiDate) {
|
|
1072
|
+
// Multi-date mode: don't close on individual selections
|
|
1073
|
+
closeOnSelect = false;
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
// Single date only: close on date click
|
|
1077
|
+
closeOnSelect = true;
|
|
1078
|
+
}
|
|
1079
|
+
// Merge with data attributes and passed config
|
|
1080
|
+
// Important: data attributes (this._config) must come after defaults to override them
|
|
1081
|
+
this._config = __assign(__assign(__assign(__assign({}, config_1.defaultDatepickerConfig), this._config), (config || {})), { templates: mergedTemplates, closeOnSelect: closeOnSelect });
|
|
1082
|
+
// Initialize event manager
|
|
1083
|
+
this._eventManager = new event_manager_1.EventManager();
|
|
1084
|
+
// Initialize focus manager for keyboard navigation
|
|
1085
|
+
this._focusManager = new focus_manager_1.FocusManager({
|
|
1086
|
+
enableFocusTrapping: true,
|
|
1087
|
+
enableFocusRestoration: true,
|
|
1088
|
+
enableKeyboardNavigation: true,
|
|
1089
|
+
enableDebugging: this._config.debug || false
|
|
1090
|
+
});
|
|
1091
|
+
};
|
|
1092
|
+
/**
|
|
1093
|
+
* Public method to set/override templates at runtime (supports string or function)
|
|
1094
|
+
*/
|
|
1095
|
+
KTDatepicker.prototype.setTemplates = function (templates) {
|
|
1096
|
+
this._userTemplates = __assign(__assign({}, this._userTemplates), templates);
|
|
1097
|
+
this._templateSet = (0, templates_1.getTemplateStrings)(this._config);
|
|
1098
|
+
this._templateRenderer.updateTemplates(this._templateSet);
|
|
1099
|
+
this._render();
|
|
1100
|
+
};
|
|
1101
|
+
/**
|
|
1102
|
+
* Render the main container and set this._container
|
|
1103
|
+
*/
|
|
1104
|
+
KTDatepicker.prototype._renderContainer = function () {
|
|
1105
|
+
var containerEl = this._templateRenderer.renderTemplateToElement({
|
|
1106
|
+
templateKey: 'container',
|
|
1107
|
+
data: {},
|
|
1108
|
+
configClasses: this._config.classes
|
|
1109
|
+
});
|
|
1110
|
+
this._container = containerEl;
|
|
1111
|
+
return containerEl;
|
|
1112
|
+
};
|
|
1113
|
+
/**
|
|
1114
|
+
* Render the input wrapper and calendar button, move/create input element
|
|
1115
|
+
* In range mode, renders two segmented inputs (start/end) using the segmentedDateRangeInput template.
|
|
1116
|
+
*/
|
|
1117
|
+
KTDatepicker.prototype._renderInputWrapper = function (calendarButtonHtml) {
|
|
1118
|
+
var _this = this;
|
|
1119
|
+
var inputWrapperTpl = this._templateSet.inputWrapper || templates_1.defaultTemplates.inputWrapper;
|
|
1120
|
+
// Set input to hidden instead of removing it, so it remains in DOM for form submission
|
|
1121
|
+
if (this._input) {
|
|
1122
|
+
this._input.type = 'hidden';
|
|
1123
|
+
// Remove any visible styling classes that might interfere
|
|
1124
|
+
this._input.classList.remove('hidden');
|
|
1125
|
+
}
|
|
1126
|
+
if (this._config.range) {
|
|
1127
|
+
var rangeTpl = this._templateSet.segmentedDateRangeInput || templates_1.defaultTemplates.segmentedDateRangeInput;
|
|
1128
|
+
var _a = (0, helpers_1.renderRangeSegmentedInputUI)(inputWrapperTpl, rangeTpl, calendarButtonHtml, this._config), inputWrapperEl_1 = _a.inputWrapperEl, startContainer = _a.startContainer, endContainer = _a.endContainer;
|
|
1129
|
+
(0, helpers_1.instantiateRangeSegmentedInputs)(startContainer, endContainer, this._unifiedStateManager.getState(), this._config, function (date) {
|
|
1130
|
+
var _a;
|
|
1131
|
+
var end = ((_a = _this._unifiedStateManager.getState().selectedRange) === null || _a === void 0 ? void 0 : _a.end) || null;
|
|
1132
|
+
var newEnd = end;
|
|
1133
|
+
if (end && date > end)
|
|
1134
|
+
newEnd = null;
|
|
1135
|
+
_this._unifiedStateManager.updateState({ selectedRange: { start: date, end: newEnd } }, 'range-selection');
|
|
1136
|
+
_this._render();
|
|
1137
|
+
}, function (date) {
|
|
1138
|
+
var _a;
|
|
1139
|
+
var start = ((_a = _this._unifiedStateManager.getState().selectedRange) === null || _a === void 0 ? void 0 : _a.start) || null;
|
|
1140
|
+
var newStart = start;
|
|
1141
|
+
if (start && date < start)
|
|
1142
|
+
newStart = null;
|
|
1143
|
+
_this._unifiedStateManager.updateState({ selectedRange: { start: newStart, end: date } }, 'range-selection');
|
|
1144
|
+
_this._render();
|
|
1145
|
+
});
|
|
1146
|
+
return inputWrapperEl_1;
|
|
1147
|
+
}
|
|
1148
|
+
// Single-date mode
|
|
1149
|
+
var inputWrapperEl = (0, helpers_1.renderSingleSegmentedInputUI)(inputWrapperTpl, calendarButtonHtml, this._config);
|
|
1150
|
+
// Find the segmented input container that was rendered by the template system
|
|
1151
|
+
var segmentedInputContainer = inputWrapperEl.querySelector('[data-kt-datepicker-segmented-input]');
|
|
1152
|
+
(0, helpers_1.instantiateSingleSegmentedInput)(segmentedInputContainer, this._unifiedStateManager.getState(), this._config, function (date) {
|
|
1153
|
+
_this.setDate(date);
|
|
1154
|
+
});
|
|
1155
|
+
return inputWrapperEl;
|
|
1156
|
+
};
|
|
1157
|
+
/**
|
|
1158
|
+
* Bind event listener to the calendar button and input wrapper
|
|
1159
|
+
*/
|
|
1160
|
+
KTDatepicker.prototype._bindCalendarButtonEvent = function (inputWrapperEl) {
|
|
1161
|
+
var _this = this;
|
|
1162
|
+
var buttonEl = inputWrapperEl.querySelector('button[data-kt-datepicker-calendar-btn]');
|
|
1163
|
+
if (buttonEl && buttonEl instanceof HTMLButtonElement) {
|
|
1164
|
+
buttonEl.type = 'button';
|
|
1165
|
+
buttonEl.setAttribute('aria-label', this._config.calendarButtonAriaLabel || 'Open calendar');
|
|
1166
|
+
buttonEl.addEventListener('click', function (e) {
|
|
1167
|
+
e.preventDefault();
|
|
1168
|
+
e.stopPropagation();
|
|
1169
|
+
if (_this._config.disabled || buttonEl.hasAttribute('disabled')) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
_this.toggle();
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
// Add click handler to entire input wrapper for better UX
|
|
1176
|
+
inputWrapperEl.addEventListener('click', function (e) {
|
|
1177
|
+
// Don't handle if disabled
|
|
1178
|
+
if (_this._config.disabled) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
// Don't handle if target is a focusable input element (segmented input)
|
|
1182
|
+
var target = e.target;
|
|
1183
|
+
if (target.hasAttribute('contenteditable') || target.hasAttribute('data-segment')) {
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
// Don't handle if already handled by button click
|
|
1187
|
+
if (target === buttonEl || (buttonEl === null || buttonEl === void 0 ? void 0 : buttonEl.contains(target))) {
|
|
1188
|
+
return;
|
|
1189
|
+
}
|
|
1190
|
+
// Open the datepicker
|
|
1191
|
+
_this.open();
|
|
1192
|
+
});
|
|
1193
|
+
};
|
|
1194
|
+
/**
|
|
1195
|
+
* Render the dropdown container from template
|
|
1196
|
+
*/
|
|
1197
|
+
KTDatepicker.prototype._renderDropdown = function () {
|
|
1198
|
+
var dropdownEl = this._templateRenderer.renderTemplateToElement({
|
|
1199
|
+
templateKey: 'dropdown',
|
|
1200
|
+
data: {},
|
|
1201
|
+
configClasses: this._config.classes
|
|
1202
|
+
});
|
|
1203
|
+
dropdownEl.setAttribute('data-kt-datepicker-dropdown', '');
|
|
1204
|
+
// Add instance association for better identification
|
|
1205
|
+
if (this._instanceId) {
|
|
1206
|
+
dropdownEl.setAttribute('data-kt-datepicker-instance-id', this._instanceId);
|
|
1207
|
+
}
|
|
1208
|
+
if (!this._unifiedStateManager.isDropdownOpen()) {
|
|
1209
|
+
dropdownEl.classList.add('hidden');
|
|
1210
|
+
}
|
|
1211
|
+
return dropdownEl;
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* Render header, calendar, and footer into the dropdown element
|
|
1215
|
+
*/
|
|
1216
|
+
KTDatepicker.prototype._renderDropdownContent = function (dropdownEl) {
|
|
1217
|
+
var _this = this;
|
|
1218
|
+
var _a;
|
|
1219
|
+
var visibleMonths = (_a = this._config.visibleMonths) !== null && _a !== void 0 ? _a : 1;
|
|
1220
|
+
if (visibleMonths === 1) {
|
|
1221
|
+
this._renderSingleMonth(dropdownEl);
|
|
1222
|
+
}
|
|
1223
|
+
else {
|
|
1224
|
+
this._renderMultiMonth(dropdownEl, visibleMonths);
|
|
1225
|
+
}
|
|
1226
|
+
// --- Render footer using template-driven buttons (conditional by mode) ---
|
|
1227
|
+
var isRange = !!this._config.range;
|
|
1228
|
+
var isMultiDate = !!this._config.multiDate;
|
|
1229
|
+
var showFooter = isRange || isMultiDate;
|
|
1230
|
+
if (showFooter) {
|
|
1231
|
+
var todayButtonHtml = undefined;
|
|
1232
|
+
var clearButtonHtml = undefined;
|
|
1233
|
+
var applyButtonHtml = undefined;
|
|
1234
|
+
var todayButtonTpl = this._templateSet.todayButton || templates_1.defaultTemplates.todayButton;
|
|
1235
|
+
var clearButtonTpl = this._templateSet.clearButton || templates_1.defaultTemplates.clearButton;
|
|
1236
|
+
var applyButtonTpl = this._templateSet.applyButton || templates_1.defaultTemplates.applyButton;
|
|
1237
|
+
// Only show Today/Clear if explicitly enabled in config/templates
|
|
1238
|
+
if (this._config.showTodayButton) {
|
|
1239
|
+
todayButtonHtml = typeof todayButtonTpl === 'function' ? todayButtonTpl({}) : todayButtonTpl;
|
|
1240
|
+
}
|
|
1241
|
+
if (this._config.showClearButton) {
|
|
1242
|
+
clearButtonHtml = typeof clearButtonTpl === 'function' ? clearButtonTpl({}) : clearButtonTpl;
|
|
1243
|
+
}
|
|
1244
|
+
// Always show Apply in range/multi-date mode
|
|
1245
|
+
applyButtonHtml = typeof applyButtonTpl === 'function' ? applyButtonTpl({}) : applyButtonTpl;
|
|
1246
|
+
var footer = (0, footer_1.renderFooter)(this._templateSet.footer, { todayButton: todayButtonHtml, clearButton: clearButtonHtml, applyButton: applyButtonHtml }, this._onToday, this._onClear, this._onApply);
|
|
1247
|
+
dropdownEl.appendChild(footer);
|
|
1248
|
+
}
|
|
1249
|
+
// --- Render time picker if enabled ---
|
|
1250
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1251
|
+
if (this._config.enableTime && currentState.selectedTime) {
|
|
1252
|
+
var timePickerContainer = this._templateRenderer.renderTemplateToElement({
|
|
1253
|
+
templateKey: 'timePickerWrapper',
|
|
1254
|
+
data: {},
|
|
1255
|
+
configClasses: this._config.classes
|
|
1256
|
+
});
|
|
1257
|
+
timePickerContainer.setAttribute('data-kt-datepicker-time-container', '');
|
|
1258
|
+
// Store the time picker renderer result
|
|
1259
|
+
this._timePickerRenderer = (0, time_picker_1.renderTimePicker)(timePickerContainer, {
|
|
1260
|
+
time: currentState.selectedTime,
|
|
1261
|
+
granularity: currentState.timeGranularity,
|
|
1262
|
+
format: this._config.timeFormat || '24h',
|
|
1263
|
+
minTime: this._config.minTime,
|
|
1264
|
+
maxTime: this._config.maxTime,
|
|
1265
|
+
timeStep: this._config.timeStep || 1,
|
|
1266
|
+
disabled: !!this._config.disabled,
|
|
1267
|
+
onChange: function (newTime) {
|
|
1268
|
+
// Update unified state manager
|
|
1269
|
+
_this._unifiedStateManager.updateState({
|
|
1270
|
+
selectedTime: newTime
|
|
1271
|
+
}, 'time-picker');
|
|
1272
|
+
// Apply time to selected date if exists
|
|
1273
|
+
var updatedState = _this._unifiedStateManager.getState();
|
|
1274
|
+
if (updatedState.selectedDate) {
|
|
1275
|
+
var dateWithTime = (0, time_utils_1.applyTimeToDate)(updatedState.selectedDate, newTime);
|
|
1276
|
+
_this._unifiedStateManager.updateState({
|
|
1277
|
+
selectedDate: dateWithTime
|
|
1278
|
+
}, 'time-picker');
|
|
1279
|
+
}
|
|
1280
|
+
// Update the time picker renderer with the new state
|
|
1281
|
+
if (_this._timePickerRenderer) {
|
|
1282
|
+
_this._timePickerRenderer.update(newTime);
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
templates: this._templateSet
|
|
1286
|
+
});
|
|
1287
|
+
dropdownEl.appendChild(timePickerContainer);
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
/**
|
|
1291
|
+
* Render single month calendar
|
|
1292
|
+
*/
|
|
1293
|
+
KTDatepicker.prototype._renderSingleMonth = function (dropdownEl) {
|
|
1294
|
+
var _this = this;
|
|
1295
|
+
var prevButtonHtml;
|
|
1296
|
+
var nextButtonHtml;
|
|
1297
|
+
var prevButtonTpl = this._templateSet.prevButton || templates_1.defaultTemplates.prevButton;
|
|
1298
|
+
var nextButtonTpl = this._templateSet.nextButton || templates_1.defaultTemplates.nextButton;
|
|
1299
|
+
prevButtonHtml = typeof prevButtonTpl === 'function' ? prevButtonTpl({}) : prevButtonTpl;
|
|
1300
|
+
nextButtonHtml = typeof nextButtonTpl === 'function' ? nextButtonTpl({}) : nextButtonTpl;
|
|
1301
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1302
|
+
var header = (0, header_1.renderHeader)(this._templateSet.header, {
|
|
1303
|
+
month: currentState.currentDate.toLocaleString(this._config.locale, { month: 'long' }),
|
|
1304
|
+
year: currentState.currentDate.getFullYear(),
|
|
1305
|
+
prevButton: prevButtonHtml,
|
|
1306
|
+
nextButton: nextButtonHtml,
|
|
1307
|
+
}, function (e) { e.stopPropagation(); _this._changeMonth(-1); }, function (e) { e.stopPropagation(); _this._changeMonth(1); });
|
|
1308
|
+
dropdownEl.appendChild(header);
|
|
1309
|
+
var dayClickHandler = function (day) {
|
|
1310
|
+
_this.setDate(day);
|
|
1311
|
+
};
|
|
1312
|
+
var calendar = (0, calendar_1.renderCalendar)(this._templateSet.dayCell, this._getCalendarDays(currentState.currentDate), currentState.currentDate, currentState.selectedDate, dayClickHandler, this._config.locale, this._config.range ? currentState.selectedRange : undefined, this._config.multiDate ? currentState.selectedDates : undefined);
|
|
1313
|
+
dropdownEl.appendChild(calendar);
|
|
1314
|
+
};
|
|
1315
|
+
/**
|
|
1316
|
+
* Get array of dates for multi-month display
|
|
1317
|
+
* @param baseDate - The base date to calculate months from
|
|
1318
|
+
* @param count - Number of months to generate
|
|
1319
|
+
* @returns Array of dates representing the first day of each month
|
|
1320
|
+
*/
|
|
1321
|
+
KTDatepicker.prototype._getMultiMonthDates = function (baseDate, count) {
|
|
1322
|
+
var dates = [];
|
|
1323
|
+
for (var i = 0; i < count; i++) {
|
|
1324
|
+
var monthDate = new Date(baseDate.getFullYear(), baseDate.getMonth() + i, 1);
|
|
1325
|
+
dates.push(monthDate);
|
|
1326
|
+
}
|
|
1327
|
+
return dates;
|
|
1328
|
+
};
|
|
1329
|
+
/**
|
|
1330
|
+
* Render a single calendar month for multi-month display
|
|
1331
|
+
* @param monthDate - The date representing the month to render
|
|
1332
|
+
* @param index - Index of this month in the multi-month display
|
|
1333
|
+
* @param totalMonths - Total number of months being displayed
|
|
1334
|
+
* @returns HTMLElement containing the rendered month
|
|
1335
|
+
*/
|
|
1336
|
+
KTDatepicker.prototype._renderMultiMonthCalendar = function (monthDate, index, totalMonths) {
|
|
1337
|
+
var _this = this;
|
|
1338
|
+
// Navigation buttons: only first gets prev, only last gets next
|
|
1339
|
+
var prevButtonHtml = '';
|
|
1340
|
+
var nextButtonHtml = '';
|
|
1341
|
+
if (index === 0) {
|
|
1342
|
+
var prevButtonTpl = this._templateSet.prevButton || templates_1.defaultTemplates.prevButton;
|
|
1343
|
+
prevButtonHtml = typeof prevButtonTpl === 'function' ? prevButtonTpl({}) : prevButtonTpl;
|
|
1344
|
+
}
|
|
1345
|
+
if (index === totalMonths - 1) {
|
|
1346
|
+
var nextButtonTpl = this._templateSet.nextButton || templates_1.defaultTemplates.nextButton;
|
|
1347
|
+
nextButtonHtml = typeof nextButtonTpl === 'function' ? nextButtonTpl({}) : nextButtonTpl;
|
|
1348
|
+
}
|
|
1349
|
+
var header = (0, header_1.renderHeader)(this._templateSet.header, {
|
|
1350
|
+
month: monthDate.toLocaleString(this._config.locale, { month: 'long' }),
|
|
1351
|
+
year: monthDate.getFullYear(),
|
|
1352
|
+
prevButton: prevButtonHtml,
|
|
1353
|
+
nextButton: nextButtonHtml,
|
|
1354
|
+
}, function (e) { e.stopPropagation(); _this._changeMonth(-1); }, function (e) { e.stopPropagation(); _this._changeMonth(1); });
|
|
1355
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1356
|
+
var calendar = (0, calendar_1.renderCalendar)(this._templateSet.dayCell, this._getCalendarDays(monthDate), monthDate, currentState.selectedDate, function (day) { _this.setDate(day); }, this._config.locale, this._config.range ? currentState.selectedRange : undefined, this._config.multiDate ? currentState.selectedDates : undefined);
|
|
1357
|
+
// Create panel element and append header + calendar directly to preserve event listeners
|
|
1358
|
+
// Instead of converting to HTML strings which lose event listeners
|
|
1359
|
+
var panel = document.createElement('div');
|
|
1360
|
+
panel.setAttribute('data-kt-datepicker-panel', '');
|
|
1361
|
+
// Apply default panel styling (flex flex-col gap-1.5 from CSS)
|
|
1362
|
+
panel.className = 'flex flex-col gap-1.5';
|
|
1363
|
+
// Append header and calendar directly (preserves event listeners)
|
|
1364
|
+
panel.appendChild(header);
|
|
1365
|
+
panel.appendChild(calendar);
|
|
1366
|
+
return panel;
|
|
1367
|
+
};
|
|
1368
|
+
/**
|
|
1369
|
+
* Render multi-month calendar
|
|
1370
|
+
*/
|
|
1371
|
+
KTDatepicker.prototype._renderMultiMonth = function (dropdownEl, visibleMonths) {
|
|
1372
|
+
var _this = this;
|
|
1373
|
+
var _a;
|
|
1374
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1375
|
+
var baseDate = new Date(currentState.currentDate);
|
|
1376
|
+
// Get all month dates for multi-month display
|
|
1377
|
+
var monthDates = this._getMultiMonthDates(baseDate, visibleMonths);
|
|
1378
|
+
// Create multi-month container element
|
|
1379
|
+
var multiMonthContainer = document.createElement('div');
|
|
1380
|
+
multiMonthContainer.setAttribute('data-kt-datepicker-multimonth-container', '');
|
|
1381
|
+
// Apply classes: flex flex-col md:flex-row gap-4
|
|
1382
|
+
multiMonthContainer.className = 'flex flex-col md:flex-row gap-4';
|
|
1383
|
+
if ((_a = this._config.classes) === null || _a === void 0 ? void 0 : _a.multiMonthContainer) {
|
|
1384
|
+
multiMonthContainer.className += ' ' + this._config.classes.multiMonthContainer;
|
|
1385
|
+
}
|
|
1386
|
+
// Render each month panel and append directly (preserves event listeners)
|
|
1387
|
+
monthDates.forEach(function (monthDate, index) {
|
|
1388
|
+
var panel = _this._renderMultiMonthCalendar(monthDate, index, visibleMonths);
|
|
1389
|
+
multiMonthContainer.appendChild(panel);
|
|
1390
|
+
});
|
|
1391
|
+
dropdownEl.appendChild(multiMonthContainer);
|
|
1392
|
+
};
|
|
1393
|
+
/**
|
|
1394
|
+
* Render the datepicker UI using templates
|
|
1395
|
+
*/
|
|
1396
|
+
KTDatepicker.prototype._render = function () {
|
|
1397
|
+
var _this = this;
|
|
1398
|
+
// Performance marker: Start render
|
|
1399
|
+
if (typeof performance !== 'undefined' && this._config.debug) {
|
|
1400
|
+
performance.mark('datepicker-render-start');
|
|
1401
|
+
}
|
|
1402
|
+
// Store current state before rendering
|
|
1403
|
+
var wasOpen = this._unifiedStateManager.isDropdownOpen();
|
|
1404
|
+
var selectedDate = this._unifiedStateManager.getState().selectedDate;
|
|
1405
|
+
var selectedRange = this._unifiedStateManager.getState().selectedRange;
|
|
1406
|
+
var selectedDates = this._unifiedStateManager.getState().selectedDates;
|
|
1407
|
+
// Remove any previous container
|
|
1408
|
+
if (this._container && this._container.parentNode) {
|
|
1409
|
+
this._container.parentNode.removeChild(this._container);
|
|
1410
|
+
}
|
|
1411
|
+
// Render main container from template
|
|
1412
|
+
var containerEl = this._renderContainer();
|
|
1413
|
+
// Remove any previous input wrapper
|
|
1414
|
+
var existingWrapper = this._element.querySelector('[data-kt-datepicker-input-wrapper]');
|
|
1415
|
+
if (existingWrapper && existingWrapper.parentNode) {
|
|
1416
|
+
existingWrapper.parentNode.removeChild(existingWrapper);
|
|
1417
|
+
}
|
|
1418
|
+
// Render calendar button from template
|
|
1419
|
+
var calendarButtonTpl = this._templateSet.calendarButton || templates_1.defaultTemplates.calendarButton;
|
|
1420
|
+
var calendarButtonHtml;
|
|
1421
|
+
if (typeof calendarButtonTpl === 'function') {
|
|
1422
|
+
var classData = (0, templates_1.mergeClassData)('calendarButton', { ariaLabel: this._config.calendarButtonAriaLabel || 'Open calendar' }, this._config.classes);
|
|
1423
|
+
calendarButtonHtml = calendarButtonTpl(classData);
|
|
1424
|
+
}
|
|
1425
|
+
else {
|
|
1426
|
+
var classData = (0, templates_1.mergeClassData)('calendarButton', { ariaLabel: this._config.calendarButtonAriaLabel || 'Open calendar' }, this._config.classes);
|
|
1427
|
+
calendarButtonHtml = (0, templates_1.renderTemplateString)(calendarButtonTpl, classData);
|
|
1428
|
+
}
|
|
1429
|
+
// Render input wrapper and calendar button from template
|
|
1430
|
+
var inputWrapperEl = this._renderInputWrapper(calendarButtonHtml);
|
|
1431
|
+
// Attach calendar button event listener
|
|
1432
|
+
this._bindCalendarButtonEvent(inputWrapperEl);
|
|
1433
|
+
// Insert wrapper at the start of the element
|
|
1434
|
+
this._element.insertBefore(inputWrapperEl, this._element.firstChild);
|
|
1435
|
+
// --- Dropdown rendering and attachment ---
|
|
1436
|
+
// Remove any previous dropdown
|
|
1437
|
+
var existingDropdown = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
1438
|
+
if (existingDropdown && existingDropdown.parentNode) {
|
|
1439
|
+
existingDropdown.parentNode.removeChild(existingDropdown);
|
|
1440
|
+
}
|
|
1441
|
+
// Render dropdown from template system (never inline)
|
|
1442
|
+
var dropdownEl = this._renderDropdown();
|
|
1443
|
+
this._renderDropdownContent(dropdownEl);
|
|
1444
|
+
this._attachDropdown(inputWrapperEl, dropdownEl);
|
|
1445
|
+
// Restore state
|
|
1446
|
+
this._unifiedStateManager.updateState({
|
|
1447
|
+
selectedDate: selectedDate,
|
|
1448
|
+
selectedRange: selectedRange,
|
|
1449
|
+
selectedDates: selectedDates
|
|
1450
|
+
}, 'render-restore');
|
|
1451
|
+
// Restore open state
|
|
1452
|
+
if (wasOpen) {
|
|
1453
|
+
this._unifiedStateManager.setDropdownOpen(true, 'render-restore');
|
|
1454
|
+
// The dropdown module will automatically open via observer pattern
|
|
1455
|
+
}
|
|
1456
|
+
this._updatePlaceholder();
|
|
1457
|
+
this._updateDisabledState();
|
|
1458
|
+
// Enforce min/max dates after rendering
|
|
1459
|
+
// Use requestAnimationFrame to align with browser render cycle
|
|
1460
|
+
requestAnimationFrame(function () {
|
|
1461
|
+
_this._enforceMinMaxDates();
|
|
1462
|
+
});
|
|
1463
|
+
// Attach keyboard event listeners
|
|
1464
|
+
if (this._input) {
|
|
1465
|
+
this._eventManager.removeListener(this._input, 'keydown', this._onKeyDown);
|
|
1466
|
+
this._eventManager.addListener(this._input, 'keydown', this._onKeyDown);
|
|
1467
|
+
}
|
|
1468
|
+
if (dropdownEl) {
|
|
1469
|
+
this._eventManager.removeListener(dropdownEl, 'keydown', this._onKeyDown);
|
|
1470
|
+
this._eventManager.addListener(dropdownEl, 'keydown', this._onKeyDown);
|
|
1471
|
+
}
|
|
1472
|
+
// Ensure live region exists
|
|
1473
|
+
var liveRegion = this._element.querySelector('[data-kt-datepicker-live]');
|
|
1474
|
+
if (!liveRegion) {
|
|
1475
|
+
liveRegion = this._templateRenderer.renderTemplateToElement({
|
|
1476
|
+
templateKey: 'liveRegion',
|
|
1477
|
+
data: {},
|
|
1478
|
+
configClasses: this._config.classes
|
|
1479
|
+
});
|
|
1480
|
+
this._element.appendChild(liveRegion);
|
|
1481
|
+
}
|
|
1482
|
+
// Initialize DOM element cache after rendering
|
|
1483
|
+
this._initializeElementCache();
|
|
1484
|
+
// Performance marker: End render
|
|
1485
|
+
if (typeof performance !== 'undefined' && this._config.debug) {
|
|
1486
|
+
performance.mark('datepicker-render-end');
|
|
1487
|
+
performance.measure('datepicker-render', 'datepicker-render-start', 'datepicker-render-end');
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
/**
|
|
1491
|
+
* Attach the dropdown after the input wrapper
|
|
1492
|
+
*/
|
|
1493
|
+
KTDatepicker.prototype._attachDropdown = function (inputWrapperEl, dropdownEl) {
|
|
1494
|
+
// Clean up existing dropdown module
|
|
1495
|
+
if (this._dropdownModule) {
|
|
1496
|
+
this._dropdownModule.dispose();
|
|
1497
|
+
}
|
|
1498
|
+
// Always attach dropdown element to DOM first
|
|
1499
|
+
if (inputWrapperEl.nextSibling) {
|
|
1500
|
+
this._element.insertBefore(dropdownEl, inputWrapperEl.nextSibling);
|
|
1501
|
+
}
|
|
1502
|
+
else {
|
|
1503
|
+
this._element.appendChild(dropdownEl);
|
|
1504
|
+
}
|
|
1505
|
+
// Find the toggle element (calendar button)
|
|
1506
|
+
var toggleElement = this._element.querySelector('button[data-kt-datepicker-calendar-btn]');
|
|
1507
|
+
if (toggleElement) {
|
|
1508
|
+
// Create new dropdown module
|
|
1509
|
+
this._dropdownModule = new dropdown_1.KTDatepickerDropdown(this._element, toggleElement, dropdownEl, this._config);
|
|
1510
|
+
// Connect dropdown module to unified state manager
|
|
1511
|
+
if (this._dropdownModule) {
|
|
1512
|
+
this._dropdownModule.setUnifiedStateManager(this._unifiedStateManager);
|
|
1513
|
+
this._unifiedStateManager.subscribe(this._dropdownModule);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
KTDatepicker.prototype._getCalendarDays = function (date) {
|
|
1518
|
+
var year = date.getFullYear();
|
|
1519
|
+
var month = date.getMonth();
|
|
1520
|
+
var firstDay = new Date(year, month, 1);
|
|
1521
|
+
var lastDay = new Date(year, month + 1, 0);
|
|
1522
|
+
var days = [];
|
|
1523
|
+
// Start from Sunday of the first week
|
|
1524
|
+
var start = new Date(firstDay);
|
|
1525
|
+
start.setDate(firstDay.getDate() - firstDay.getDay());
|
|
1526
|
+
// End at Saturday of the last week
|
|
1527
|
+
var end = new Date(lastDay);
|
|
1528
|
+
end.setDate(lastDay.getDate() + (6 - lastDay.getDay()));
|
|
1529
|
+
// Reuse date object by incrementing instead of creating new ones
|
|
1530
|
+
var currentDate = new Date(start);
|
|
1531
|
+
while (currentDate <= end) {
|
|
1532
|
+
days.push(new Date(currentDate)); // Create new Date instance for each day to avoid mutation issues
|
|
1533
|
+
currentDate.setDate(currentDate.getDate() + 1);
|
|
792
1534
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
1535
|
+
return days;
|
|
1536
|
+
};
|
|
1537
|
+
KTDatepicker.prototype._changeMonth = function (offset) {
|
|
1538
|
+
var _this = this;
|
|
1539
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1540
|
+
var d = new Date(currentState.currentDate);
|
|
1541
|
+
d.setMonth(d.getMonth() + offset);
|
|
1542
|
+
// Update the unified state manager and wait for state to propagate
|
|
1543
|
+
this._unifiedStateManager.updateState({
|
|
1544
|
+
currentDate: d
|
|
1545
|
+
}, 'month-navigation');
|
|
1546
|
+
// Ensure state is fully updated before proceeding
|
|
1547
|
+
setTimeout(function () {
|
|
1548
|
+
// Force a state refresh to ensure we have the latest state
|
|
1549
|
+
var updatedState = _this._unifiedStateManager.getState();
|
|
1550
|
+
// Check if the state actually changed
|
|
1551
|
+
if (updatedState.currentDate.getMonth() === d.getMonth()) {
|
|
1552
|
+
// Use multi-month update if multiple months are visible
|
|
1553
|
+
if (_this._config.visibleMonths && _this._config.visibleMonths > 1) {
|
|
1554
|
+
_this._updateMultiMonthCalendarContent();
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
_this._updateCalendarContent();
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
else {
|
|
1561
|
+
// Wait a bit more for state to propagate
|
|
1562
|
+
setTimeout(function () {
|
|
1563
|
+
if (_this._config.visibleMonths && _this._config.visibleMonths > 1) {
|
|
1564
|
+
_this._updateMultiMonthCalendarContent();
|
|
1565
|
+
}
|
|
1566
|
+
else {
|
|
1567
|
+
_this._updateCalendarContent();
|
|
1568
|
+
}
|
|
1569
|
+
}, 50);
|
|
799
1570
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
1571
|
+
}, 10);
|
|
1572
|
+
};
|
|
1573
|
+
/**
|
|
1574
|
+
* Update only the calendar content without recreating the dropdown
|
|
1575
|
+
* This preserves the dropdown state while updating the month view
|
|
1576
|
+
*/
|
|
1577
|
+
KTDatepicker.prototype._updateCalendarContent = function () {
|
|
1578
|
+
var _this = this;
|
|
1579
|
+
// Performance marker: Start incremental update
|
|
1580
|
+
if (typeof performance !== 'undefined' && this._config.debug) {
|
|
1581
|
+
performance.mark('datepicker-incremental-update-start');
|
|
1582
|
+
}
|
|
1583
|
+
// Instance-scoped dropdown element selection strategy
|
|
1584
|
+
var dropdownEl = null;
|
|
1585
|
+
// First priority: find dropdown within current datepicker instance
|
|
1586
|
+
dropdownEl = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
1587
|
+
// Second priority: if instance ID is available, find by instance ID
|
|
1588
|
+
if (!dropdownEl && this._instanceId) {
|
|
1589
|
+
dropdownEl = document.querySelector("[data-kt-datepicker-dropdown][data-kt-datepicker-instance-id=\"".concat(this._instanceId, "\"]"));
|
|
1590
|
+
}
|
|
1591
|
+
// Third priority: check dropdown module reference
|
|
1592
|
+
if (!dropdownEl && this._dropdownModule) {
|
|
1593
|
+
var dropdownModuleElement = this._dropdownModule._dropdownElement;
|
|
1594
|
+
if (dropdownModuleElement) {
|
|
1595
|
+
dropdownEl = dropdownModuleElement;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
// Final fallback: global search with warnings (only if no other instances exist)
|
|
1599
|
+
if (!dropdownEl) {
|
|
1600
|
+
var allDropdowns = document.querySelectorAll('[data-kt-datepicker-dropdown]');
|
|
1601
|
+
if (allDropdowns.length === 1) {
|
|
1602
|
+
// Only one dropdown exists globally, safe to use
|
|
1603
|
+
dropdownEl = allDropdowns[0];
|
|
1604
|
+
}
|
|
1605
|
+
else if (allDropdowns.length > 1) {
|
|
1606
|
+
// Multiple dropdowns exist - this could cause cross-instance issues
|
|
1607
|
+
this._render();
|
|
1608
|
+
return;
|
|
805
1609
|
}
|
|
806
1610
|
else {
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
if (
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1611
|
+
this._render();
|
|
1612
|
+
return;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
if (!dropdownEl) {
|
|
1616
|
+
// Fallback to full render if dropdown doesn't exist (should be rare)
|
|
1617
|
+
this._render();
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
// Clear existing calendar content and update only the calendar
|
|
1621
|
+
var calendarEl = dropdownEl.querySelector('[data-kt-datepicker-calendar-table]');
|
|
1622
|
+
if (calendarEl) {
|
|
1623
|
+
// Remove the old calendar
|
|
1624
|
+
calendarEl.remove();
|
|
1625
|
+
// Get current state - ensure we have the most up-to-date state
|
|
1626
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1627
|
+
// Update the month/year display in the header with multiple selector strategies
|
|
1628
|
+
var monthYearEl = dropdownEl.querySelector('[data-kt-datepicker-month-year]');
|
|
1629
|
+
// Fallback selectors if primary selector fails
|
|
1630
|
+
if (!monthYearEl) {
|
|
1631
|
+
monthYearEl = dropdownEl.querySelector('[data-kt-datepicker-month]');
|
|
1632
|
+
}
|
|
1633
|
+
// Additional fallback: look for span containing month and year
|
|
1634
|
+
if (!monthYearEl) {
|
|
1635
|
+
var spans = dropdownEl.querySelectorAll('span');
|
|
1636
|
+
monthYearEl = Array.from(spans).find(function (span) {
|
|
1637
|
+
return span.textContent && span.textContent.match(/[A-Za-z]+ \d{4}/);
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
// Final fallback: any span in header
|
|
1641
|
+
if (!monthYearEl) {
|
|
1642
|
+
var headerEl_1 = dropdownEl.querySelector('[data-kt-datepicker-header]');
|
|
1643
|
+
if (headerEl_1) {
|
|
1644
|
+
monthYearEl = headerEl_1.querySelector('span');
|
|
816
1645
|
}
|
|
817
|
-
this._dateInputElement.value = inputValue;
|
|
818
|
-
this._dateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
819
1646
|
}
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
|
|
1647
|
+
if (monthYearEl) {
|
|
1648
|
+
var newMonthYear = "".concat(currentState.currentDate.toLocaleString(this._config.locale, { month: 'long' }), " ").concat(currentState.currentDate.getFullYear());
|
|
1649
|
+
monthYearEl.textContent = newMonthYear;
|
|
1650
|
+
}
|
|
1651
|
+
// Render only the new calendar
|
|
1652
|
+
var dayClickHandler = function (day) {
|
|
1653
|
+
_this.setDate(day);
|
|
1654
|
+
};
|
|
1655
|
+
var newCalendar = (0, calendar_1.renderCalendar)(this._templateSet.dayCell, this._getCalendarDays(currentState.currentDate), currentState.currentDate, currentState.selectedDate, dayClickHandler, this._config.locale, this._config.range ? currentState.selectedRange : undefined, this._config.multiDate ? currentState.selectedDates : undefined);
|
|
1656
|
+
// Insert the new calendar after the header
|
|
1657
|
+
var headerEl = dropdownEl.querySelector('[data-kt-datepicker-header]');
|
|
1658
|
+
if (headerEl) {
|
|
1659
|
+
headerEl.insertAdjacentElement('afterend', newCalendar);
|
|
823
1660
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
1661
|
+
else {
|
|
1662
|
+
// Fallback: append to dropdown
|
|
1663
|
+
dropdownEl.appendChild(newCalendar);
|
|
827
1664
|
}
|
|
828
|
-
|
|
829
|
-
|
|
1665
|
+
// Refresh cache with the new calendar element
|
|
1666
|
+
this._cachedElements.calendarElement = newCalendar;
|
|
1667
|
+
// Enforce min/max dates after calendar update
|
|
1668
|
+
this._enforceMinMaxDates();
|
|
1669
|
+
// Performance marker: End incremental update
|
|
1670
|
+
if (typeof performance !== 'undefined' && this._config.debug) {
|
|
1671
|
+
performance.mark('datepicker-incremental-update-end');
|
|
1672
|
+
performance.measure('datepicker-incremental-update', 'datepicker-incremental-update-start', 'datepicker-incremental-update-end');
|
|
830
1673
|
}
|
|
831
|
-
// Dispatch change event
|
|
832
|
-
this._eventManager.dispatchEvent(events_1.KTDatepickerEventName.DATE_CHANGE, {
|
|
833
|
-
selectedDateRange: state.selectedDateRange,
|
|
834
|
-
});
|
|
835
1674
|
}
|
|
836
1675
|
else {
|
|
837
|
-
//
|
|
838
|
-
this.
|
|
839
|
-
// Clear display
|
|
840
|
-
if (this._displayElement) {
|
|
841
|
-
var placeholder = ((_a = this._dateInputElement) === null || _a === void 0 ? void 0 : _a.getAttribute('placeholder')) ||
|
|
842
|
-
'Select date range';
|
|
843
|
-
this._displayElement.innerHTML = (0, templates_1.placeholderTemplate)(placeholder);
|
|
844
|
-
}
|
|
845
|
-
// Clear inputs
|
|
846
|
-
if (this._dateInputElement) {
|
|
847
|
-
this._dateInputElement.value = '';
|
|
848
|
-
this._dateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
849
|
-
}
|
|
850
|
-
if (this._startDateInputElement) {
|
|
851
|
-
this._startDateInputElement.value = '';
|
|
852
|
-
this._startDateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
853
|
-
}
|
|
854
|
-
if (this._endDateInputElement) {
|
|
855
|
-
this._endDateInputElement.value = '';
|
|
856
|
-
this._endDateInputElement.dispatchEvent(new Event('change', { bubbles: true }));
|
|
857
|
-
}
|
|
858
|
-
this._eventManager.dispatchEvent(events_1.KTDatepickerEventName.DATE_CHANGE, {
|
|
859
|
-
selectedDateRange: null,
|
|
860
|
-
});
|
|
1676
|
+
// If calendar element not found, fallback to full render
|
|
1677
|
+
this._render();
|
|
861
1678
|
}
|
|
862
1679
|
};
|
|
863
1680
|
/**
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
* @param minDate - Minimum date or null to remove constraint
|
|
1681
|
+
* Update multi-month calendar content without recreating the dropdown
|
|
1682
|
+
* This preserves the dropdown state while updating all visible months
|
|
867
1683
|
*/
|
|
868
|
-
KTDatepicker.prototype.
|
|
869
|
-
|
|
870
|
-
//
|
|
871
|
-
|
|
1684
|
+
KTDatepicker.prototype._updateMultiMonthCalendarContent = function () {
|
|
1685
|
+
var _this = this;
|
|
1686
|
+
// Instance-scoped dropdown element selection strategy
|
|
1687
|
+
var dropdownEl = null;
|
|
1688
|
+
// First priority: find dropdown within current datepicker instance
|
|
1689
|
+
dropdownEl = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
1690
|
+
// Second priority: if instance ID is available, find by instance ID
|
|
1691
|
+
if (!dropdownEl && this._instanceId) {
|
|
1692
|
+
dropdownEl = document.querySelector("[data-kt-datepicker-dropdown][data-kt-datepicker-instance-id=\"".concat(this._instanceId, "\"]"));
|
|
1693
|
+
}
|
|
1694
|
+
// Third priority: check dropdown module reference
|
|
1695
|
+
if (!dropdownEl && this._dropdownModule) {
|
|
1696
|
+
var dropdownModuleElement = this._dropdownModule._dropdownElement;
|
|
1697
|
+
if (dropdownModuleElement) {
|
|
1698
|
+
dropdownEl = dropdownModuleElement;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
// Final fallback: global search with warnings (only if no other instances exist)
|
|
1702
|
+
if (!dropdownEl) {
|
|
1703
|
+
var allDropdowns = document.querySelectorAll('[data-kt-datepicker-dropdown]');
|
|
1704
|
+
if (allDropdowns.length === 1) {
|
|
1705
|
+
// Only one dropdown exists globally, safe to use
|
|
1706
|
+
dropdownEl = allDropdowns[0];
|
|
1707
|
+
}
|
|
1708
|
+
else if (allDropdowns.length > 1) {
|
|
1709
|
+
// Multiple dropdowns exist - this could cause cross-instance issues
|
|
1710
|
+
this._render();
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
else {
|
|
1714
|
+
this._render();
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
if (!dropdownEl) {
|
|
1719
|
+
// Fallback to full render if dropdown doesn't exist (should be rare)
|
|
1720
|
+
this._render();
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
// Get current state - ensure we have the most up-to-date state
|
|
1724
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1725
|
+
var visibleMonths = this._config.visibleMonths || 1;
|
|
1726
|
+
// Find the multi-month container
|
|
1727
|
+
var multiMonthContainer = dropdownEl.querySelector('[data-kt-datepicker-multimonth-container]');
|
|
1728
|
+
if (!multiMonthContainer) {
|
|
1729
|
+
// Multi-month container not found, fallback to full render
|
|
1730
|
+
this._render();
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
// Clear existing multi-month content
|
|
1734
|
+
multiMonthContainer.innerHTML = '';
|
|
1735
|
+
// Get all month dates for multi-month display
|
|
1736
|
+
var monthDates = this._getMultiMonthDates(currentState.currentDate, visibleMonths);
|
|
1737
|
+
// Re-render each month using the helper method
|
|
1738
|
+
monthDates.forEach(function (monthDate, index) {
|
|
1739
|
+
var panel = _this._renderMultiMonthCalendar(monthDate, index, visibleMonths);
|
|
1740
|
+
multiMonthContainer.appendChild(panel);
|
|
1741
|
+
});
|
|
1742
|
+
// Enforce min/max dates after multi-month calendar update
|
|
1743
|
+
this._enforceMinMaxDates();
|
|
1744
|
+
console.log('[KTDatepicker] Multi-month calendar content updated successfully');
|
|
872
1745
|
};
|
|
873
1746
|
/**
|
|
874
|
-
* Set the
|
|
875
|
-
*
|
|
876
|
-
* @param maxDate - Maximum date or null to remove constraint
|
|
1747
|
+
* Set the selected date (single, range, or multi-date)
|
|
1748
|
+
* @param date - The date to select
|
|
877
1749
|
*/
|
|
878
|
-
KTDatepicker.prototype.
|
|
879
|
-
|
|
880
|
-
//
|
|
881
|
-
this.
|
|
1750
|
+
KTDatepicker.prototype.setDate = function (date) {
|
|
1751
|
+
console.log('🗓️ [KTDatepicker] setDate called with:', date);
|
|
1752
|
+
// Prevent selection if date is outside min/max
|
|
1753
|
+
if (this._config.minDate && date < new Date(this._config.minDate)) {
|
|
1754
|
+
console.log('🗓️ [KTDatepicker] setDate blocked: date is before minDate');
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
if (this._config.maxDate && date > new Date(this._config.maxDate)) {
|
|
1758
|
+
console.log('🗓️ [KTDatepicker] setDate blocked: date is after maxDate');
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
// Validate time constraints if time is enabled
|
|
1762
|
+
if (this._config.enableTime) {
|
|
1763
|
+
var timeState = (0, time_utils_1.dateToTimeState)(date);
|
|
1764
|
+
var validation = (0, time_utils_1.validateTime)(timeState, this._config.minTime, this._config.maxTime);
|
|
1765
|
+
if (!validation.isValid) {
|
|
1766
|
+
console.log('🗓️ [KTDatepicker] setDate blocked: time validation failed:', validation.error);
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
if (this._config.multiDate) {
|
|
1771
|
+
this._selectMultiDate(date);
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
if (this._config.range) {
|
|
1775
|
+
this._selectRangeDate(date);
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
this._selectSingleDate(date);
|
|
1779
|
+
};
|
|
1780
|
+
/**
|
|
1781
|
+
* Get the selected date
|
|
1782
|
+
*/
|
|
1783
|
+
KTDatepicker.prototype.getDate = function () {
|
|
1784
|
+
return this._unifiedStateManager.getState().selectedDate;
|
|
882
1785
|
};
|
|
883
1786
|
/**
|
|
884
|
-
* Update the datepicker (
|
|
1787
|
+
* Update the datepicker (re-render)
|
|
885
1788
|
*/
|
|
886
1789
|
KTDatepicker.prototype.update = function () {
|
|
887
|
-
|
|
888
|
-
this._eventManager.dispatchEvent(events_1.KTDatepickerEventName.UPDATE);
|
|
1790
|
+
this._render();
|
|
889
1791
|
};
|
|
890
1792
|
/**
|
|
891
|
-
*
|
|
1793
|
+
* Clean up event listeners and DOM on destroy
|
|
892
1794
|
*/
|
|
893
1795
|
KTDatepicker.prototype.destroy = function () {
|
|
894
|
-
|
|
895
|
-
this.
|
|
896
|
-
|
|
897
|
-
|
|
1796
|
+
console.log('🗓️ [KTDatepicker] destroy() called');
|
|
1797
|
+
if (this._container && this._container.parentNode) {
|
|
1798
|
+
this._container.parentNode.removeChild(this._container);
|
|
1799
|
+
}
|
|
1800
|
+
// Clean up event manager
|
|
1801
|
+
this._eventManager.removeListener(document, 'click', this._handleDocumentClick);
|
|
1802
|
+
if (this._input) {
|
|
1803
|
+
this._eventManager.removeAllListeners(this._input);
|
|
1804
|
+
}
|
|
1805
|
+
// Clean up focus manager
|
|
1806
|
+
if (this._focusManager) {
|
|
1807
|
+
this._focusManager.dispose();
|
|
1808
|
+
}
|
|
1809
|
+
// Clean up dropdown module
|
|
1810
|
+
if (this._dropdownModule) {
|
|
1811
|
+
this._dropdownModule.dispose();
|
|
1812
|
+
}
|
|
1813
|
+
// Clean up unified state manager
|
|
1814
|
+
if (this._unsubscribeFromState) {
|
|
1815
|
+
this._unsubscribeFromState();
|
|
1816
|
+
this._unsubscribeFromState = null;
|
|
1817
|
+
}
|
|
1818
|
+
if (this._unifiedStateManager) {
|
|
1819
|
+
this._unifiedStateManager.dispose();
|
|
1820
|
+
}
|
|
1821
|
+
// Clean up element observer
|
|
1822
|
+
if (this._elementObserver) {
|
|
1823
|
+
this._elementObserver.disconnect();
|
|
1824
|
+
this._elementObserver = null;
|
|
1825
|
+
}
|
|
1826
|
+
// Clean up time picker renderer
|
|
1827
|
+
if (this._timePickerRenderer) {
|
|
1828
|
+
this._timePickerRenderer.cleanup();
|
|
1829
|
+
this._timePickerRenderer = null;
|
|
1830
|
+
}
|
|
1831
|
+
// Clear DOM element cache
|
|
1832
|
+
this._cachedElements = {
|
|
1833
|
+
calendarElement: null,
|
|
1834
|
+
timePickerElement: null,
|
|
1835
|
+
startContainer: null,
|
|
1836
|
+
endContainer: null,
|
|
1837
|
+
yearElement: null,
|
|
1838
|
+
monthElement: null,
|
|
1839
|
+
dayElement: null,
|
|
1840
|
+
hourElement: null,
|
|
1841
|
+
minuteElement: null,
|
|
1842
|
+
secondElement: null,
|
|
1843
|
+
ampmElement: null,
|
|
1844
|
+
monthYearElement: null,
|
|
1845
|
+
timeDisplay: null
|
|
1846
|
+
};
|
|
1847
|
+
this._element.instance = null;
|
|
1848
|
+
console.log('🗓️ [KTDatepicker] destroy() completed');
|
|
1849
|
+
};
|
|
1850
|
+
/**
|
|
1851
|
+
* Start observing for dynamic element creation
|
|
1852
|
+
*/
|
|
1853
|
+
KTDatepicker.prototype._startElementObservation = function () {
|
|
1854
|
+
if (this._elementObserver) {
|
|
1855
|
+
this._elementObserver.disconnect();
|
|
898
1856
|
}
|
|
899
|
-
|
|
900
|
-
|
|
1857
|
+
this._elementObserver = new MutationObserver(function (mutations) {
|
|
1858
|
+
mutations.forEach(function (mutation) {
|
|
1859
|
+
if (mutation.type === 'childList') {
|
|
1860
|
+
mutation.addedNodes.forEach(function (node) {
|
|
1861
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
1862
|
+
var element = node;
|
|
1863
|
+
// Segmented input elements are now handled by direct UI updates
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
this._elementObserver.observe(this._element, {
|
|
1870
|
+
childList: true,
|
|
1871
|
+
subtree: true
|
|
1872
|
+
});
|
|
1873
|
+
};
|
|
1874
|
+
/**
|
|
1875
|
+
* Update the input placeholder if no date is selected
|
|
1876
|
+
*/
|
|
1877
|
+
KTDatepicker.prototype._updatePlaceholder = function () {
|
|
1878
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1879
|
+
if (this._input && !currentState.selectedDate && this._config.placeholder) {
|
|
1880
|
+
this._input.setAttribute('placeholder', this._config.placeholder);
|
|
1881
|
+
console.log('🗓️ [KTDatepicker] _render: Placeholder set to:', this._config.placeholder);
|
|
901
1882
|
}
|
|
902
|
-
// Remove instance from element
|
|
903
|
-
this._element.removeAttribute('data-kt-datepicker-initialized');
|
|
904
|
-
delete this._element.instance;
|
|
905
|
-
// Remove initialized class
|
|
906
|
-
this._element.classList.remove('relative');
|
|
907
|
-
// Remove from instances map
|
|
908
|
-
KTDatepicker._instances.delete(this._element);
|
|
909
1883
|
};
|
|
910
1884
|
/**
|
|
911
|
-
*
|
|
1885
|
+
* Update the disabled state of the input and calendar button
|
|
912
1886
|
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
1887
|
+
* Accessibility rationale:
|
|
1888
|
+
* - When disabling the calendar button, set:
|
|
1889
|
+
* - disabled attribute (removes from tab order, blocks interaction)
|
|
1890
|
+
* - aria-disabled="true" (announces as disabled to screen readers)
|
|
1891
|
+
* - tabindex="-1" (removes from tab order for extra safety)
|
|
1892
|
+
* - When enabling, remove these attributes.
|
|
1893
|
+
* This matches accessibility best practices and ensures the button is properly announced and not focusable when disabled.
|
|
915
1894
|
*/
|
|
916
|
-
KTDatepicker.prototype.
|
|
917
|
-
this.
|
|
1895
|
+
KTDatepicker.prototype._updateDisabledState = function () {
|
|
1896
|
+
var calendarButton = this._element.querySelector('button[data-kt-datepicker-calendar-btn]');
|
|
1897
|
+
if (this._input && this._config.disabled) {
|
|
1898
|
+
this._input.setAttribute('disabled', 'true');
|
|
1899
|
+
if (calendarButton) {
|
|
1900
|
+
// Set disabled attribute
|
|
1901
|
+
calendarButton.setAttribute('disabled', 'true');
|
|
1902
|
+
// Set aria-disabled for screen readers
|
|
1903
|
+
calendarButton.setAttribute('aria-disabled', 'true');
|
|
1904
|
+
// Remove from tab order
|
|
1905
|
+
calendarButton.setAttribute('tabindex', '-1');
|
|
1906
|
+
}
|
|
1907
|
+
console.log('🗓️ [KTDatepicker] _render: Input and calendar button disabled');
|
|
1908
|
+
}
|
|
1909
|
+
else if (this._input) {
|
|
1910
|
+
this._input.removeAttribute('disabled');
|
|
1911
|
+
if (calendarButton) {
|
|
1912
|
+
// Remove disabled attribute
|
|
1913
|
+
calendarButton.removeAttribute('disabled');
|
|
1914
|
+
// Remove aria-disabled attribute
|
|
1915
|
+
calendarButton.removeAttribute('aria-disabled');
|
|
1916
|
+
// Restore tab order (remove tabindex)
|
|
1917
|
+
calendarButton.removeAttribute('tabindex');
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
918
1920
|
};
|
|
919
1921
|
/**
|
|
920
|
-
*
|
|
1922
|
+
* Update the segmented input UI to reflect current state
|
|
921
1923
|
*/
|
|
922
|
-
KTDatepicker.
|
|
1924
|
+
KTDatepicker.prototype._updateSegmentedInput = function (state) {
|
|
923
1925
|
var _this = this;
|
|
924
|
-
var
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1926
|
+
var segmentedContainer = this._element.querySelector('[data-kt-datepicker-segmented-input]');
|
|
1927
|
+
if (!segmentedContainer)
|
|
1928
|
+
return;
|
|
1929
|
+
// Re-instantiate the segmented input with the current state
|
|
1930
|
+
// This will update the display without recreating the entire UI
|
|
1931
|
+
(0, helpers_1.instantiateSingleSegmentedInput)(segmentedContainer, state, this._config, function (date) { return _this._handleSegmentedInputChange(date); });
|
|
1932
|
+
};
|
|
1933
|
+
/**
|
|
1934
|
+
* Update the range segmented inputs UI to reflect current state
|
|
1935
|
+
*/
|
|
1936
|
+
KTDatepicker.prototype._updateRangeSegmentedInput = function (state) {
|
|
1937
|
+
var _this = this;
|
|
1938
|
+
var startContainer = this._element.querySelector('[data-kt-datepicker-start-container]');
|
|
1939
|
+
var endContainer = this._element.querySelector('[data-kt-datepicker-end-container]');
|
|
1940
|
+
if (!startContainer || !endContainer)
|
|
1941
|
+
return;
|
|
1942
|
+
// Re-instantiate the range segmented inputs with the current state
|
|
1943
|
+
// This will update the display without recreating the entire UI
|
|
1944
|
+
(0, helpers_1.instantiateRangeSegmentedInputs)(startContainer, endContainer, state, this._config, function (date) {
|
|
1945
|
+
var _a;
|
|
1946
|
+
var end = ((_a = state.selectedRange) === null || _a === void 0 ? void 0 : _a.end) || null;
|
|
1947
|
+
var newEnd = end;
|
|
1948
|
+
if (end && date > end)
|
|
1949
|
+
newEnd = null;
|
|
1950
|
+
_this._unifiedStateManager.updateState({ selectedRange: { start: date, end: newEnd } }, 'range-selection');
|
|
1951
|
+
_this._updateCalendarContent();
|
|
1952
|
+
}, function (date) {
|
|
1953
|
+
var _a;
|
|
1954
|
+
var start = ((_a = state.selectedRange) === null || _a === void 0 ? void 0 : _a.start) || null;
|
|
1955
|
+
var newStart = start;
|
|
1956
|
+
if (start && date < start)
|
|
1957
|
+
newStart = null;
|
|
1958
|
+
_this._unifiedStateManager.updateState({ selectedRange: { start: newStart, end: date } }, 'range-selection');
|
|
1959
|
+
_this._updateCalendarContent();
|
|
1960
|
+
});
|
|
1961
|
+
};
|
|
1962
|
+
/**
|
|
1963
|
+
* Handle changes from the segmented input
|
|
1964
|
+
*/
|
|
1965
|
+
KTDatepicker.prototype._handleSegmentedInputChange = function (date) {
|
|
1966
|
+
console.log('🗓️ [KTDatepicker] Segmented input change:', date);
|
|
1967
|
+
// When date changes from segmented input, also update the calendar view to show the selected date's month/year
|
|
1968
|
+
var currentState = this._unifiedStateManager.getState();
|
|
1969
|
+
var newCurrentDate = new Date(date.getFullYear(), date.getMonth(), 1); // First day of selected date's month
|
|
1970
|
+
// Prepare state updates
|
|
1971
|
+
var stateUpdates = {
|
|
1972
|
+
selectedDate: date,
|
|
1973
|
+
currentDate: newCurrentDate
|
|
1974
|
+
};
|
|
1975
|
+
// Update selectedTime if time is enabled
|
|
1976
|
+
if (this._config.enableTime) {
|
|
1977
|
+
stateUpdates.selectedTime = (0, time_utils_1.dateToTimeState)(date);
|
|
1978
|
+
}
|
|
1979
|
+
// Update both selectedDate and currentDate to sync the calendar view
|
|
1980
|
+
// Use immediate update to ensure events fire synchronously
|
|
1981
|
+
this._unifiedStateManager.updateState(stateUpdates, 'segmented-input', true);
|
|
1982
|
+
// Update calendar content to sync dropdown even when closed
|
|
1983
|
+
this._updateCalendarContent();
|
|
1984
|
+
// Fire onChange event
|
|
1985
|
+
this._fireDatepickerEvent('onChange', date, this);
|
|
1986
|
+
};
|
|
1987
|
+
/**
|
|
1988
|
+
* Normalize a date to midnight for date-only comparison (removes time component)
|
|
1989
|
+
*/
|
|
1990
|
+
/**
|
|
1991
|
+
* Disable day buttons outside min/max date range
|
|
1992
|
+
*/
|
|
1993
|
+
KTDatepicker.prototype._enforceMinMaxDates = function () {
|
|
1994
|
+
if (this._config.minDate || this._config.maxDate) {
|
|
1995
|
+
// Normalize min/max dates to midnight for date-only comparison
|
|
1996
|
+
var minDate_1 = this._config.minDate ? (0, date_formatters_1.normalizeDateToMidnight)(new Date(this._config.minDate)) : null;
|
|
1997
|
+
var maxDate_1 = this._config.maxDate ? (0, date_formatters_1.normalizeDateToMidnight)(new Date(this._config.maxDate)) : null;
|
|
1998
|
+
// Find calendar element - try multiple strategies
|
|
1999
|
+
var calendarElement = this._cachedElements.calendarElement;
|
|
2000
|
+
if (!calendarElement || !calendarElement.isConnected) {
|
|
2001
|
+
// Try to find dropdown first
|
|
2002
|
+
var dropdownEl = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
2003
|
+
if (!dropdownEl && this._instanceId) {
|
|
2004
|
+
dropdownEl = document.querySelector("[data-kt-datepicker-dropdown][data-kt-datepicker-instance-id=\"".concat(this._instanceId, "\"]"));
|
|
2005
|
+
}
|
|
2006
|
+
if (dropdownEl) {
|
|
2007
|
+
calendarElement = dropdownEl.querySelector('[data-kt-datepicker-calendar-table]');
|
|
2008
|
+
}
|
|
931
2009
|
}
|
|
2010
|
+
if (!calendarElement)
|
|
2011
|
+
return;
|
|
2012
|
+
// Get all day cells using the calendar element scope
|
|
2013
|
+
var dayCells = calendarElement.querySelectorAll('td[data-kt-datepicker-day]');
|
|
2014
|
+
dayCells.forEach(function (td) {
|
|
2015
|
+
// Get the actual date from the data-date attribute (stored as ISO string)
|
|
2016
|
+
var dateISO = td.getAttribute('data-date');
|
|
2017
|
+
if (!dateISO)
|
|
2018
|
+
return;
|
|
2019
|
+
// Parse the ISO date and normalize to midnight for comparison
|
|
2020
|
+
var cellDate = (0, date_formatters_1.normalizeDateToMidnight)(new Date(dateISO));
|
|
2021
|
+
var btn = td.querySelector('button[data-day]');
|
|
2022
|
+
if (!btn)
|
|
2023
|
+
return;
|
|
2024
|
+
var disabled = false;
|
|
2025
|
+
// Compare dates (normalized to midnight) for proper date-only comparison
|
|
2026
|
+
if (minDate_1 && cellDate < minDate_1)
|
|
2027
|
+
disabled = true;
|
|
2028
|
+
if (maxDate_1 && cellDate > maxDate_1)
|
|
2029
|
+
disabled = true;
|
|
2030
|
+
if (disabled) {
|
|
2031
|
+
btn.setAttribute('disabled', 'true');
|
|
2032
|
+
td.setAttribute('data-out-of-range', 'true');
|
|
2033
|
+
}
|
|
2034
|
+
else {
|
|
2035
|
+
btn.removeAttribute('disabled');
|
|
2036
|
+
td.removeAttribute('data-out-of-range');
|
|
2037
|
+
}
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
/**
|
|
2042
|
+
* Opens the datepicker dropdown.
|
|
2043
|
+
*/
|
|
2044
|
+
KTDatepicker.prototype.open = function () {
|
|
2045
|
+
if (this._unifiedStateManager.isDropdownOpen()) {
|
|
2046
|
+
console.log('🗓️ [KTDatepicker] open() skipped: already open');
|
|
2047
|
+
return;
|
|
2048
|
+
}
|
|
2049
|
+
if (this._config.disabled) {
|
|
2050
|
+
console.log('🗓️ [KTDatepicker] open() blocked: datepicker is disabled');
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
console.log('🗓️ [KTDatepicker] open() called, attempting to open dropdown');
|
|
2054
|
+
// Use unified state management
|
|
2055
|
+
var success = this._unifiedStateManager.setDropdownOpen(true, 'datepicker-open');
|
|
2056
|
+
if (!success) {
|
|
2057
|
+
console.log('🗓️ [KTDatepicker] open() blocked by state validation');
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
console.log('🗓️ [KTDatepicker] State manager open() successful, dropdown module:', this._dropdownModule);
|
|
2061
|
+
// Ensure dropdown content is rendered before opening
|
|
2062
|
+
var dropdownEl = this._element.querySelector('[data-kt-datepicker-dropdown]');
|
|
2063
|
+
if (dropdownEl) {
|
|
2064
|
+
// Always render dropdown content to ensure it's up to date
|
|
2065
|
+
console.log('🗓️ [KTDatepicker] Rendering dropdown content before opening');
|
|
2066
|
+
this._renderDropdownContent(dropdownEl);
|
|
2067
|
+
}
|
|
2068
|
+
// Use dropdown module if available
|
|
2069
|
+
if (this._dropdownModule) {
|
|
2070
|
+
console.log('🗓️ [KTDatepicker] Dropdown module available, state change will trigger open');
|
|
2071
|
+
// The dropdown module will automatically open via observer pattern
|
|
2072
|
+
}
|
|
2073
|
+
else {
|
|
2074
|
+
console.log('🗓️ [KTDatepicker] No dropdown module, using fallback');
|
|
2075
|
+
}
|
|
2076
|
+
// Don't call _render() here as it recreates the dropdown module
|
|
2077
|
+
// The dropdown module handles its own visibility
|
|
2078
|
+
};
|
|
2079
|
+
/**
|
|
2080
|
+
* Closes the datepicker dropdown.
|
|
2081
|
+
*/
|
|
2082
|
+
KTDatepicker.prototype.close = function () {
|
|
2083
|
+
var _a;
|
|
2084
|
+
console.log('🗓️ [KTDatepicker] close() called, current state:', {
|
|
2085
|
+
stateManagerOpen: this._unifiedStateManager.isDropdownOpen(),
|
|
2086
|
+
dropdownModuleOpen: (_a = this._dropdownModule) === null || _a === void 0 ? void 0 : _a.isOpen(),
|
|
2087
|
+
stateManagerState: this._unifiedStateManager.getDropdownState()
|
|
932
2088
|
});
|
|
2089
|
+
if (!this._unifiedStateManager.isDropdownOpen()) {
|
|
2090
|
+
console.log('🗓️ [KTDatepicker] close() skipped: already closed');
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
// Debug log with stack trace
|
|
2094
|
+
console.log('[KTDatepicker] close() called. Dropdown will close. Stack trace:', new Error().stack);
|
|
2095
|
+
// Use unified state management
|
|
2096
|
+
var success = this._unifiedStateManager.setDropdownOpen(false, 'datepicker-close');
|
|
2097
|
+
if (!success) {
|
|
2098
|
+
console.log('🗓️ [KTDatepicker] close() blocked by state validation');
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
console.log('🗓️ [KTDatepicker] State manager close() successful');
|
|
2102
|
+
// Use dropdown module if available
|
|
2103
|
+
if (this._dropdownModule) {
|
|
2104
|
+
console.log('🗓️ [KTDatepicker] Dropdown module available, state change will trigger close');
|
|
2105
|
+
// The dropdown module will automatically close via observer pattern
|
|
2106
|
+
}
|
|
2107
|
+
else {
|
|
2108
|
+
console.log('🗓️ [KTDatepicker] No dropdown module, using fallback');
|
|
2109
|
+
}
|
|
2110
|
+
// Don't call _render() here as it recreates the dropdown module
|
|
2111
|
+
// The dropdown module handles its own visibility
|
|
2112
|
+
};
|
|
2113
|
+
KTDatepicker.prototype.toggle = function () {
|
|
2114
|
+
if (this._unifiedStateManager.isDropdownOpen()) {
|
|
2115
|
+
this.close();
|
|
2116
|
+
}
|
|
2117
|
+
else {
|
|
2118
|
+
this.open();
|
|
2119
|
+
}
|
|
933
2120
|
};
|
|
934
2121
|
/**
|
|
935
|
-
*
|
|
2122
|
+
* Returns whether the datepicker dropdown is currently open.
|
|
936
2123
|
*/
|
|
937
|
-
KTDatepicker.
|
|
938
|
-
|
|
2124
|
+
KTDatepicker.prototype.isOpen = function () {
|
|
2125
|
+
return this._unifiedStateManager.isDropdownOpen();
|
|
939
2126
|
};
|
|
940
2127
|
/**
|
|
941
|
-
*
|
|
942
|
-
* Static instances
|
|
943
|
-
* ========================================================================
|
|
2128
|
+
* Returns the current state of the datepicker component.
|
|
944
2129
|
*/
|
|
945
|
-
KTDatepicker.
|
|
2130
|
+
KTDatepicker.prototype.getState = function () {
|
|
2131
|
+
return __assign({}, this._unifiedStateManager.getState());
|
|
2132
|
+
};
|
|
2133
|
+
/**
|
|
2134
|
+
* Returns the current dropdown state.
|
|
2135
|
+
*/
|
|
2136
|
+
KTDatepicker.prototype.getDropdownState = function () {
|
|
2137
|
+
return this._unifiedStateManager.getDropdownState();
|
|
2138
|
+
};
|
|
2139
|
+
/**
|
|
2140
|
+
* StateObserver implementation: Called when state changes
|
|
2141
|
+
*/
|
|
2142
|
+
/**
|
|
2143
|
+
* StateObserver implementation: Returns update priority (lower = higher priority)
|
|
2144
|
+
*/
|
|
2145
|
+
KTDatepicker.prototype.getUpdatePriority = function () {
|
|
2146
|
+
return 10; // Medium priority
|
|
2147
|
+
};
|
|
2148
|
+
/**
|
|
2149
|
+
* StateObserver implementation: Handle state changes from unified state manager
|
|
2150
|
+
*/
|
|
2151
|
+
KTDatepicker.prototype.onStateChange = function (newState, oldState) {
|
|
2152
|
+
this._handleStateChange(newState, oldState);
|
|
2153
|
+
};
|
|
2154
|
+
/**
|
|
2155
|
+
* Handle state changes from the unified state manager
|
|
2156
|
+
*/
|
|
2157
|
+
KTDatepicker.prototype._handleStateChange = function (newState, oldState) {
|
|
2158
|
+
console.log('🗓️ [KTDatepicker] _handleStateChange called:', { newState: newState, oldState: oldState });
|
|
2159
|
+
// Skip UI updates if this is from segmented input arrow navigation
|
|
2160
|
+
if (typeof window !== 'undefined' && window.__ktui_segmented_input_arrow_navigation) {
|
|
2161
|
+
console.log('🗓️ [KTDatepicker] Skipping UI update due to segmented input navigation');
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
// Get changed properties for selective updates
|
|
2165
|
+
var changedProperties = this._unifiedStateManager.getLastChangedProperties();
|
|
2166
|
+
// Get the source of the last state update
|
|
2167
|
+
var lastUpdateSource = this._unifiedStateManager.getLastUpdateSource();
|
|
2168
|
+
// Update dropdown state if open/closed changed
|
|
2169
|
+
if (changedProperties.has('isOpen') && newState.isOpen !== oldState.isOpen) {
|
|
2170
|
+
if (this._dropdownModule) {
|
|
2171
|
+
console.log('🗓️ [KTDatepicker] Dropdown module available, state change will trigger open');
|
|
2172
|
+
// The dropdown module will automatically open via observer pattern
|
|
2173
|
+
}
|
|
2174
|
+
else {
|
|
2175
|
+
console.log('🗓️ [KTDatepicker] No dropdown module, using fallback');
|
|
2176
|
+
}
|
|
2177
|
+
// Don't call _render() here as it recreates the dropdown module
|
|
2178
|
+
// The dropdown module handles its own visibility
|
|
2179
|
+
}
|
|
2180
|
+
// Update disabled state only if it changed
|
|
2181
|
+
if (changedProperties.has('isDisabled') && newState.isDisabled !== oldState.isDisabled) {
|
|
2182
|
+
this._updateDisabledState();
|
|
2183
|
+
}
|
|
2184
|
+
// Selective UI updates based on changed properties
|
|
2185
|
+
// Update input field only if selection-related properties changed
|
|
2186
|
+
if (changedProperties.has('selectedDate') ||
|
|
2187
|
+
changedProperties.has('selectedRange') ||
|
|
2188
|
+
changedProperties.has('selectedDates') ||
|
|
2189
|
+
changedProperties.has('selectedRange.start') ||
|
|
2190
|
+
changedProperties.has('selectedRange.end')) {
|
|
2191
|
+
this._updateInput(newState);
|
|
2192
|
+
}
|
|
2193
|
+
// Update segmented input only if selectedDate changed (and not from segmented input itself)
|
|
2194
|
+
if (this._config.range) {
|
|
2195
|
+
if ((changedProperties.has('selectedRange') ||
|
|
2196
|
+
changedProperties.has('selectedRange.start') ||
|
|
2197
|
+
changedProperties.has('selectedRange.end')) &&
|
|
2198
|
+
lastUpdateSource !== 'range-selection') {
|
|
2199
|
+
this._updateRangeSegmentedInput(newState);
|
|
2200
|
+
}
|
|
2201
|
+
else if (lastUpdateSource === 'range-selection') {
|
|
2202
|
+
console.log('🗓️ [KTDatepicker] Skipping _updateRangeSegmentedInput to preserve focus during typing');
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
else {
|
|
2206
|
+
if (changedProperties.has('selectedDate') && lastUpdateSource !== 'segmented-input') {
|
|
2207
|
+
this._updateSegmentedInput(newState);
|
|
2208
|
+
}
|
|
2209
|
+
else if (lastUpdateSource === 'segmented-input') {
|
|
2210
|
+
console.log('🗓️ [KTDatepicker] Skipping _updateSegmentedInput to preserve focus during typing');
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
// Update calendar highlighting only if selection state changed
|
|
2214
|
+
if (changedProperties.has('selectedDate') ||
|
|
2215
|
+
changedProperties.has('selectedRange') ||
|
|
2216
|
+
changedProperties.has('selectedRange.start') ||
|
|
2217
|
+
changedProperties.has('selectedRange.end') ||
|
|
2218
|
+
changedProperties.has('selectedDates') ||
|
|
2219
|
+
changedProperties.has('currentDate')) {
|
|
2220
|
+
this._updateCalendar(newState);
|
|
2221
|
+
}
|
|
2222
|
+
// Update time picker only if selectedTime changed
|
|
2223
|
+
if (changedProperties.has('selectedTime')) {
|
|
2224
|
+
this._updateTimePicker(newState);
|
|
2225
|
+
}
|
|
2226
|
+
// Fire events based on state changes
|
|
2227
|
+
this._fireEvents(newState, oldState);
|
|
2228
|
+
// Start observing for dynamic element creation
|
|
2229
|
+
this._startElementObservation();
|
|
2230
|
+
};
|
|
2231
|
+
// Static init method for auto-initialization
|
|
2232
|
+
KTDatepicker.init = function () {
|
|
2233
|
+
var elements = document.querySelectorAll('[data-kt-datepicker]');
|
|
2234
|
+
elements.forEach(function (el) {
|
|
2235
|
+
if (!el.instance) {
|
|
2236
|
+
new KTDatepicker(el);
|
|
2237
|
+
}
|
|
2238
|
+
});
|
|
2239
|
+
};
|
|
946
2240
|
return KTDatepicker;
|
|
947
2241
|
}(component_1.default));
|
|
948
2242
|
exports.KTDatepicker = KTDatepicker;
|
|
2243
|
+
// Optionally, export a static init method for auto-initialization
|
|
2244
|
+
function initDatepickers() {
|
|
2245
|
+
var elements = document.querySelectorAll('[data-kt-datepicker]');
|
|
2246
|
+
elements.forEach(function (el) {
|
|
2247
|
+
if (!el.instance) {
|
|
2248
|
+
new KTDatepicker(el);
|
|
2249
|
+
}
|
|
2250
|
+
});
|
|
2251
|
+
}
|
|
949
2252
|
//# sourceMappingURL=datepicker.js.map
|