ngx-kit 1.0.0 → 2.0.1
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/dialog/README.md +169 -0
- package/fesm2022/{ngx-input-angle-selector.mjs → ngx-kit-angle-selector.mjs} +16 -16
- package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -0
- package/fesm2022/{ngx-input-box-shadow.mjs → ngx-kit-box-shadow.mjs} +10 -10
- package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -0
- package/fesm2022/{ngx-input-color-picker.mjs → ngx-kit-color-picker.mjs} +30 -14
- package/fesm2022/ngx-kit-color-picker.mjs.map +1 -0
- package/fesm2022/ngx-kit-date-picker.mjs +2280 -0
- package/fesm2022/ngx-kit-date-picker.mjs.map +1 -0
- package/fesm2022/ngx-kit-dialog.mjs +378 -0
- package/fesm2022/ngx-kit-dialog.mjs.map +1 -0
- package/fesm2022/{ngx-input-gradient-picker.mjs → ngx-kit-gradient-picker.mjs} +11 -11
- package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -0
- package/fesm2022/ngx-kit-menu.mjs +229 -0
- package/fesm2022/ngx-kit-menu.mjs.map +1 -0
- package/fesm2022/ngx-kit-notify.mjs +292 -0
- package/fesm2022/ngx-kit-notify.mjs.map +1 -0
- package/fesm2022/{ngx-input-shared.mjs → ngx-kit-shared.mjs} +267 -162
- package/fesm2022/ngx-kit-shared.mjs.map +1 -0
- package/fesm2022/{ngx-input.mjs → ngx-kit.mjs} +1 -1
- package/fesm2022/ngx-kit.mjs.map +1 -0
- package/package.json +31 -15
- package/styles/all.css +22 -0
- package/styles/overlay.css +22 -0
- package/types/{ngx-input-angle-selector.d.ts → ngx-kit-angle-selector.d.ts} +6 -5
- package/types/{ngx-input-box-shadow.d.ts → ngx-kit-box-shadow.d.ts} +7 -7
- package/types/{ngx-input-color-picker.d.ts → ngx-kit-color-picker.d.ts} +7 -7
- package/types/ngx-kit-date-picker.d.ts +294 -0
- package/types/ngx-kit-dialog.d.ts +139 -0
- package/types/{ngx-input-gradient-picker.d.ts → ngx-kit-gradient-picker.d.ts} +7 -7
- package/types/ngx-kit-menu.d.ts +69 -0
- package/types/ngx-kit-notify.d.ts +60 -0
- package/types/{ngx-input-shared.d.ts → ngx-kit-shared.d.ts} +87 -40
- package/fesm2022/ngx-input-angle-selector.mjs.map +0 -1
- package/fesm2022/ngx-input-box-shadow.mjs.map +0 -1
- package/fesm2022/ngx-input-color-picker.mjs.map +0 -1
- package/fesm2022/ngx-input-gradient-picker.mjs.map +0 -1
- package/fesm2022/ngx-input-shared.mjs.map +0 -1
- package/fesm2022/ngx-input.mjs.map +0 -1
- /package/types/{ngx-input.d.ts → ngx-kit.d.ts} +0 -0
|
@@ -0,0 +1,2280 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, Injectable, EventEmitter, forwardRef, Output, Input, Component, input, ViewContainerRef, Renderer2, HostListener, Directive, viewChild } from '@angular/core';
|
|
3
|
+
import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
|
|
4
|
+
import * as i1 from '@angular/common';
|
|
5
|
+
import { CommonModule } from '@angular/common';
|
|
6
|
+
import { BrowserService, OverlayService } from 'ngx-kit/shared';
|
|
7
|
+
|
|
8
|
+
class NgxDatePickerConfig {
|
|
9
|
+
previousButtonTemplate;
|
|
10
|
+
nextButtonTemplate;
|
|
11
|
+
caretDownIconTemplate;
|
|
12
|
+
todayButton = true;
|
|
13
|
+
clearButton = true;
|
|
14
|
+
clearButtonText = 'Clear';
|
|
15
|
+
todayButtonText = 'Today';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Matches strings that have the form of a valid RFC 3339 string
|
|
20
|
+
* (https://tools.ietf.org/html/rfc3339). Note that the string may not actually be a valid date
|
|
21
|
+
* because the regex will match strings an with out of bounds month, date, etc.
|
|
22
|
+
*/
|
|
23
|
+
const ISO_8601_REGEX = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))?)?$/;
|
|
24
|
+
function deserialize(value) {
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
if (!value) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// The `Date` constructor accepts formats other than ISO 8601, so we need to make sure the
|
|
30
|
+
// string is the right format first.
|
|
31
|
+
if (ISO_8601_REGEX.test(value)) {
|
|
32
|
+
let date = new Date(value);
|
|
33
|
+
if (isValid(date)) {
|
|
34
|
+
return date;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (isValid(value)) {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isValid(obj) {
|
|
46
|
+
return obj instanceof Date && !isNaN(obj.getTime());
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Checks if two dates are equal.
|
|
50
|
+
* @param first The first date to check.
|
|
51
|
+
* @param second The second date to check.
|
|
52
|
+
* @returns Whether the two dates are equal.
|
|
53
|
+
* Null dates are considered equal to other null dates.
|
|
54
|
+
*/
|
|
55
|
+
function sameDate(first, second) {
|
|
56
|
+
if (first && second) {
|
|
57
|
+
let firstValid = isValid(first);
|
|
58
|
+
let secondValid = isValid(second);
|
|
59
|
+
if (firstValid && secondValid) {
|
|
60
|
+
return !compareDate(first, second);
|
|
61
|
+
}
|
|
62
|
+
return firstValid == secondValid;
|
|
63
|
+
}
|
|
64
|
+
return first == second;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Compares two dates.
|
|
68
|
+
* @param first The first date to compare.
|
|
69
|
+
* @param second The second date to compare.
|
|
70
|
+
* @returns 0 if the dates are equal, a number less than 0 if the first date is earlier,
|
|
71
|
+
* a number greater than 0 if the first date is later.
|
|
72
|
+
*/
|
|
73
|
+
function compareDate(first, second) {
|
|
74
|
+
if (!first || !second)
|
|
75
|
+
return 0;
|
|
76
|
+
return (first.getFullYear() - second.getFullYear() ||
|
|
77
|
+
first.getMonth() - second.getMonth() ||
|
|
78
|
+
first.getDate() - second.getDate());
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Clamp the given date between min and max dates.
|
|
82
|
+
* @param date The date to clamp.
|
|
83
|
+
* @param min The minimum value to allow. If null or omitted no min is enforced.
|
|
84
|
+
* @param max The maximum value to allow. If null or omitted no max is enforced.
|
|
85
|
+
* @returns `min` if `date` is less than `min`, `max` if date is greater than `max`,
|
|
86
|
+
* otherwise `date`.
|
|
87
|
+
*/
|
|
88
|
+
function clampDate(date, min, max) {
|
|
89
|
+
if (min && compareDate(date, min) < 0) {
|
|
90
|
+
return -1;
|
|
91
|
+
}
|
|
92
|
+
if (max && compareDate(date, max) > 0) {
|
|
93
|
+
return 1;
|
|
94
|
+
}
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
//------------------------------------------------------------------------------------------------------------
|
|
98
|
+
/**
|
|
99
|
+
* check only year and month
|
|
100
|
+
*/
|
|
101
|
+
function compareMonth(first, second) {
|
|
102
|
+
return first.getFullYear() - second.getFullYear() || first.getMonth() - second.getMonth();
|
|
103
|
+
}
|
|
104
|
+
function clampMonth(date, min, max) {
|
|
105
|
+
if (min && compareMonth(date, min) < 0) {
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
if (max && compareMonth(date, max) > 0) {
|
|
109
|
+
return 1;
|
|
110
|
+
}
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
//------------------------------------------------------------------------------------------------------------
|
|
114
|
+
/**
|
|
115
|
+
* check only year
|
|
116
|
+
*/
|
|
117
|
+
function compareYear(first, second) {
|
|
118
|
+
return first.getFullYear() - second.getFullYear();
|
|
119
|
+
}
|
|
120
|
+
function clampYear(date, min, max) {
|
|
121
|
+
if (min && compareYear(date, min) < 0) {
|
|
122
|
+
return -1;
|
|
123
|
+
}
|
|
124
|
+
if (max && compareYear(date, max) > 0) {
|
|
125
|
+
return 1;
|
|
126
|
+
}
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Date and Time Patterns
|
|
131
|
+
// yy = 2-digit year; yyyy = full year
|
|
132
|
+
// M = digit month; MM = 2-digit month; MMM = short month name; MMMM = full month name
|
|
133
|
+
// EEEE = full weekday name; EEE = short weekday name
|
|
134
|
+
// d = digit day; dd = 2-digit day
|
|
135
|
+
// h = hours am/pm; hh = 2-digit hours am/pm; H = hours; HH = 2-digit hours
|
|
136
|
+
// m = minutes; mm = 2-digit minutes; aaa = AM/PM
|
|
137
|
+
// s = seconds; ss = 2-digit seconds
|
|
138
|
+
// S = miliseconds
|
|
139
|
+
function genFormatDate(date, pattern = 'M/d/yyyy', monthNames, dayNames) {
|
|
140
|
+
if (!date) {
|
|
141
|
+
return '';
|
|
142
|
+
}
|
|
143
|
+
const day = date.day ?? 0;
|
|
144
|
+
const month = date.month ?? 0;
|
|
145
|
+
const year = date.year ?? 0;
|
|
146
|
+
const hour24 = date.hours ?? 0;
|
|
147
|
+
const minute = date.minutes ?? 0;
|
|
148
|
+
const second = date.seconds ?? 0;
|
|
149
|
+
const ms = date.milliseconds ?? 0;
|
|
150
|
+
const dayOfWeek = date.dayOfWeek ?? 0;
|
|
151
|
+
const hour12 = hour24 % 12 || 12;
|
|
152
|
+
const tokens = {
|
|
153
|
+
yyyy: year.toString(),
|
|
154
|
+
yy: year.toString().slice(-2),
|
|
155
|
+
MMMM: monthNames[month] ?? '',
|
|
156
|
+
MMM: (monthNames[month] ?? '').substring(0, 3),
|
|
157
|
+
MM: twoDigitPad(month + 1),
|
|
158
|
+
M: (month + 1).toString(),
|
|
159
|
+
EEEE: dayNames[dayOfWeek] ?? '',
|
|
160
|
+
EEE: (dayNames[dayOfWeek] ?? '').substring(0, 3),
|
|
161
|
+
dd: twoDigitPad(day),
|
|
162
|
+
d: day.toString(),
|
|
163
|
+
HH: twoDigitPad(hour24),
|
|
164
|
+
H: hour24.toString(),
|
|
165
|
+
hh: twoDigitPad(hour12),
|
|
166
|
+
h: hour12.toString(),
|
|
167
|
+
mm: twoDigitPad(minute),
|
|
168
|
+
m: minute.toString(),
|
|
169
|
+
ss: twoDigitPad(second),
|
|
170
|
+
s: second.toString(),
|
|
171
|
+
S: ms.toString().padStart(3, '0'),
|
|
172
|
+
aaa: hour24 < 12 ? 'AM' : 'PM',
|
|
173
|
+
};
|
|
174
|
+
return pattern.replace(/yyyy|yy|MMMM|MMM|MM|M|EEEE|EEE|dd|d|HH|H|hh|h|mm|m|ss|s|S|aaa/g, (token) => tokens[token]);
|
|
175
|
+
}
|
|
176
|
+
function twoDigitPad(num) {
|
|
177
|
+
return num.toString().padStart(2, '0');
|
|
178
|
+
}
|
|
179
|
+
// console.log(formatDate(new Date())); // 12/19/2022
|
|
180
|
+
// console.log(formatDate(new Date(), 'dd-MMM-yyyy')); //OP's request 19-Dec-2022
|
|
181
|
+
// console.log(formatDate(new Date(), 'EEEE, MMMM d, yyyy HH:mm:ss.S aaa')); // Monday, December 19, 2022 10:44:35.437 AM
|
|
182
|
+
// console.log(formatDate(new Date(), 'EEE, MMM d, yyyy HH:mm')); //Mon, Dec 19, 2022 10:44
|
|
183
|
+
// console.log(formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss.S')); //2022-12-19 10:44:35.438
|
|
184
|
+
// console.log(formatDate(new Date(), 'M/dd/yyyy h:mmaaa')); //12/19/2022 10:44AM
|
|
185
|
+
|
|
186
|
+
class GregorianAdapter {
|
|
187
|
+
startOfWeek = 0;
|
|
188
|
+
get longMonths() {
|
|
189
|
+
return [
|
|
190
|
+
'January',
|
|
191
|
+
'February',
|
|
192
|
+
'March',
|
|
193
|
+
'April',
|
|
194
|
+
'May',
|
|
195
|
+
'June',
|
|
196
|
+
'July',
|
|
197
|
+
'August',
|
|
198
|
+
'September',
|
|
199
|
+
'October',
|
|
200
|
+
'November',
|
|
201
|
+
'December',
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
get narrowDays() {
|
|
205
|
+
return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
206
|
+
}
|
|
207
|
+
get shortDays() {
|
|
208
|
+
return ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
|
209
|
+
}
|
|
210
|
+
get longDays() {
|
|
211
|
+
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
|
212
|
+
}
|
|
213
|
+
toLocale(date) {
|
|
214
|
+
const d = date;
|
|
215
|
+
return {
|
|
216
|
+
locale: 'en',
|
|
217
|
+
day: d.getDate(),
|
|
218
|
+
month: d.getMonth(),
|
|
219
|
+
year: d.getFullYear(),
|
|
220
|
+
date: d,
|
|
221
|
+
hours: date.getHours(),
|
|
222
|
+
minutes: date.getMinutes(),
|
|
223
|
+
seconds: date.getSeconds(),
|
|
224
|
+
milliseconds: date.getMilliseconds(),
|
|
225
|
+
dayOfWeek: date.getDay(),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
today() {
|
|
229
|
+
return this.toLocale(new Date());
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* getting first day of month
|
|
233
|
+
*/
|
|
234
|
+
firstDayofMonth(year, month) {
|
|
235
|
+
return new Date(year, month, 1).getDay();
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* getting last date of month
|
|
239
|
+
*/
|
|
240
|
+
lastDateofMonth(year, month) {
|
|
241
|
+
return new Date(year, month + 1, 0).getDate();
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* getting last day of month
|
|
245
|
+
*/
|
|
246
|
+
lastDayofMonth(year, month) {
|
|
247
|
+
return new Date(year, month, this.lastDateofMonth(year, month)).getDay();
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* getting last date of previous month
|
|
251
|
+
*/
|
|
252
|
+
lastDateofLastMonth(year, month) {
|
|
253
|
+
return new Date(year, month, 0).getDate();
|
|
254
|
+
}
|
|
255
|
+
// TODO
|
|
256
|
+
/**
|
|
257
|
+
* month start with zero
|
|
258
|
+
* @param date
|
|
259
|
+
* @returns
|
|
260
|
+
*/
|
|
261
|
+
getDate(date) {
|
|
262
|
+
let str = date.year + '-' + (date.month ? date.month + 1 : 1) + '-' + (date.day ?? 1);
|
|
263
|
+
str = str
|
|
264
|
+
.split('-')
|
|
265
|
+
.map((i) => {
|
|
266
|
+
return i.length < 2 ? '0' + i : i;
|
|
267
|
+
})
|
|
268
|
+
.join('-');
|
|
269
|
+
if (date.hours || date.minutes || date.seconds || date.milliseconds) {
|
|
270
|
+
str +=
|
|
271
|
+
' ' +
|
|
272
|
+
(date.hours ?? 0) +
|
|
273
|
+
':' +
|
|
274
|
+
(date.minutes ?? 0) +
|
|
275
|
+
':' +
|
|
276
|
+
(date.seconds ?? 0) +
|
|
277
|
+
':' +
|
|
278
|
+
(date.milliseconds ?? 0);
|
|
279
|
+
}
|
|
280
|
+
return new Date(str);
|
|
281
|
+
}
|
|
282
|
+
formatDate(date, format) {
|
|
283
|
+
if (!date) {
|
|
284
|
+
return '';
|
|
285
|
+
}
|
|
286
|
+
// let option: Intl.DateTimeFormatOptions = {
|
|
287
|
+
// year: 'numeric',
|
|
288
|
+
// month: '2-digit',
|
|
289
|
+
// day: '2-digit'
|
|
290
|
+
// };
|
|
291
|
+
// if (format === 'full') {
|
|
292
|
+
// option = {
|
|
293
|
+
// year: 'numeric',
|
|
294
|
+
// month: 'long',
|
|
295
|
+
// day: '2-digit',
|
|
296
|
+
// weekday: 'long'
|
|
297
|
+
// };
|
|
298
|
+
// }
|
|
299
|
+
// return new Date(date).toLocaleDateString('en-US', option);
|
|
300
|
+
return genFormatDate(date, format, this.longMonths, this.longDays);
|
|
301
|
+
}
|
|
302
|
+
getStartOf(date, t) {
|
|
303
|
+
if (!date) {
|
|
304
|
+
return date;
|
|
305
|
+
}
|
|
306
|
+
switch (t) {
|
|
307
|
+
case 'year':
|
|
308
|
+
return new Date(date.getFullYear(), 1, 1);
|
|
309
|
+
case 'month':
|
|
310
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
311
|
+
case 'day':
|
|
312
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
getLastOf(date, t) {
|
|
316
|
+
if (!date) {
|
|
317
|
+
return date;
|
|
318
|
+
}
|
|
319
|
+
switch (t) {
|
|
320
|
+
case 'year':
|
|
321
|
+
return new Date(date.getFullYear(), 12, 0);
|
|
322
|
+
case 'month':
|
|
323
|
+
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
|
|
324
|
+
case 'day':
|
|
325
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
var Jalali;
|
|
331
|
+
(function (Jalali) {
|
|
332
|
+
/*
|
|
333
|
+
Jalaali years starting the 33-year rule.
|
|
334
|
+
*/
|
|
335
|
+
Jalali.breaks = [-61, 9, 38, 199, 426, 686, 756, 818, 1111, 1181, 1210,
|
|
336
|
+
1635, 2060, 2097, 2192, 2262, 2324, 2394, 2456, 3178
|
|
337
|
+
];
|
|
338
|
+
/*
|
|
339
|
+
Converts a Gregorian date to Jalaali.
|
|
340
|
+
*/
|
|
341
|
+
function toJalaali(date) {
|
|
342
|
+
// if (Object.prototype.toString.call(date) === '[object Date]') {
|
|
343
|
+
let gd = date.getDate();
|
|
344
|
+
let gm = date.getMonth() + 1;
|
|
345
|
+
let gy = date.getFullYear();
|
|
346
|
+
return d2j(g2d(gy, gm, gd));
|
|
347
|
+
// }
|
|
348
|
+
// return null;
|
|
349
|
+
}
|
|
350
|
+
Jalali.toJalaali = toJalaali;
|
|
351
|
+
/*
|
|
352
|
+
Converts a Jalaali date to Gregorian.
|
|
353
|
+
*/
|
|
354
|
+
function toGregorian(jy, jm, jd) {
|
|
355
|
+
return d2g(j2d(jy, jm, jd));
|
|
356
|
+
}
|
|
357
|
+
Jalali.toGregorian = toGregorian;
|
|
358
|
+
/*
|
|
359
|
+
Checks whether a Jalaali date is valid or not.
|
|
360
|
+
*/
|
|
361
|
+
function isValidJalaaliDate(jy, jm, jd) {
|
|
362
|
+
return jy >= -61 && jy <= 3177 &&
|
|
363
|
+
jm >= 1 && jm <= 12 &&
|
|
364
|
+
jd >= 1 && jd <= jalaaliMonthLength(jy, jm);
|
|
365
|
+
}
|
|
366
|
+
Jalali.isValidJalaaliDate = isValidJalaaliDate;
|
|
367
|
+
/*
|
|
368
|
+
Is this a leap year or not?
|
|
369
|
+
*/
|
|
370
|
+
function isLeapJalaaliYear(jy) {
|
|
371
|
+
return jalCalLeap(jy) === 0;
|
|
372
|
+
}
|
|
373
|
+
Jalali.isLeapJalaaliYear = isLeapJalaaliYear;
|
|
374
|
+
/*
|
|
375
|
+
Number of days in a given month in a Jalaali year.
|
|
376
|
+
*/
|
|
377
|
+
function jalaaliMonthLength(jy, jm) {
|
|
378
|
+
if (jm <= 6)
|
|
379
|
+
return 31;
|
|
380
|
+
if (jm <= 11)
|
|
381
|
+
return 30;
|
|
382
|
+
if (isLeapJalaaliYear(jy))
|
|
383
|
+
return 30;
|
|
384
|
+
return 29;
|
|
385
|
+
}
|
|
386
|
+
Jalali.jalaaliMonthLength = jalaaliMonthLength;
|
|
387
|
+
/*
|
|
388
|
+
This function determines if the Jalaali (Persian) year is
|
|
389
|
+
leap (366-day long) or is the common year (365 days)
|
|
390
|
+
@param jy Jalaali calendar year (-61 to 3177)
|
|
391
|
+
@returns number of years since the last leap year (0 to 4)
|
|
392
|
+
*/
|
|
393
|
+
function jalCalLeap(jy) {
|
|
394
|
+
var bl = Jalali.breaks.length, jp = Jalali.breaks[0], jm, jump = 0, leap, n, i;
|
|
395
|
+
if (jy < jp || jy >= Jalali.breaks[bl - 1])
|
|
396
|
+
throw new Error('Invalid Jalaali year ' + jy);
|
|
397
|
+
for (i = 1; i < bl; i += 1) {
|
|
398
|
+
jm = Jalali.breaks[i];
|
|
399
|
+
jump = jm - jp;
|
|
400
|
+
if (jy < jm)
|
|
401
|
+
break;
|
|
402
|
+
jp = jm;
|
|
403
|
+
}
|
|
404
|
+
n = jy - jp;
|
|
405
|
+
if (jump - n < 6)
|
|
406
|
+
n = n - jump + div(jump + 4, 33) * 33;
|
|
407
|
+
leap = mod(mod(n + 1, 33) - 1, 4);
|
|
408
|
+
if (leap === -1) {
|
|
409
|
+
leap = 4;
|
|
410
|
+
}
|
|
411
|
+
return leap;
|
|
412
|
+
}
|
|
413
|
+
Jalali.jalCalLeap = jalCalLeap;
|
|
414
|
+
/*
|
|
415
|
+
This function determines if the Jalaali (Persian) year is
|
|
416
|
+
leap (366-day long) or is the common year (365 days), and
|
|
417
|
+
finds the day in March (Gregorian calendar) of the first
|
|
418
|
+
day of the Jalaali year (jy).
|
|
419
|
+
@param jy Jalaali calendar year (-61 to 3177)
|
|
420
|
+
@param withoutLeap when don't need leap (true or false) default is false
|
|
421
|
+
@return
|
|
422
|
+
leap: number of years since the last leap year (0 to 4)
|
|
423
|
+
gy: Gregorian year of the beginning of Jalaali year
|
|
424
|
+
march: the March day of Farvardin the 1st (1st day of jy)
|
|
425
|
+
@see: http://www.astro.uni.torun.pl/~kb/Papers/EMP/PersianC-EMP.htm
|
|
426
|
+
@see: http://www.fourmilab.ch/documents/calendar/
|
|
427
|
+
*/
|
|
428
|
+
function jalCal(jy, withoutLeap) {
|
|
429
|
+
var bl = Jalali.breaks.length, gy = jy + 621, leapJ = -14, jp = Jalali.breaks[0], jm, jump = 0, leap, leapG, march, n, i;
|
|
430
|
+
if (jy < jp || jy >= Jalali.breaks[bl - 1])
|
|
431
|
+
throw new Error('Invalid Jalaali year ' + jy);
|
|
432
|
+
// Find the limiting years for the Jalaali year jy.
|
|
433
|
+
for (i = 1; i < bl; i += 1) {
|
|
434
|
+
jm = Jalali.breaks[i];
|
|
435
|
+
jump = jm - jp;
|
|
436
|
+
if (jy < jm)
|
|
437
|
+
break;
|
|
438
|
+
leapJ = leapJ + div(jump, 33) * 8 + div(mod(jump, 33), 4);
|
|
439
|
+
jp = jm;
|
|
440
|
+
}
|
|
441
|
+
n = jy - jp;
|
|
442
|
+
// Find the number of leap years from AD 621 to the beginning
|
|
443
|
+
// of the current Jalaali year in the Persian calendar.
|
|
444
|
+
leapJ = leapJ + div(n, 33) * 8 + div(mod(n, 33) + 3, 4);
|
|
445
|
+
if (mod(jump, 33) === 4 && jump - n === 4)
|
|
446
|
+
leapJ += 1;
|
|
447
|
+
// And the same in the Gregorian calendar (until the year gy).
|
|
448
|
+
leapG = div(gy, 4) - div((div(gy, 100) + 1) * 3, 4) - 150;
|
|
449
|
+
// Determine the Gregorian date of Farvardin the 1st.
|
|
450
|
+
march = 20 + leapJ - leapG;
|
|
451
|
+
// return with gy and march when we don't need leap
|
|
452
|
+
if (withoutLeap)
|
|
453
|
+
return { gy: gy, march: march };
|
|
454
|
+
// Find how many years have passed since the last leap year.
|
|
455
|
+
if (jump - n < 6)
|
|
456
|
+
n = n - jump + div(jump + 4, 33) * 33;
|
|
457
|
+
leap = mod(mod(n + 1, 33) - 1, 4);
|
|
458
|
+
if (leap === -1) {
|
|
459
|
+
leap = 4;
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
leap: leap,
|
|
463
|
+
gy: gy,
|
|
464
|
+
march: march
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
Jalali.jalCal = jalCal;
|
|
468
|
+
/*
|
|
469
|
+
Converts a date of the Jalaali calendar to the Julian Day number.
|
|
470
|
+
@param jy Jalaali year (1 to 3100)
|
|
471
|
+
@param jm Jalaali month (1 to 12)
|
|
472
|
+
@param jd Jalaali day (1 to 29/31)
|
|
473
|
+
@return Julian Day number
|
|
474
|
+
*/
|
|
475
|
+
function j2d(jy, jm, jd) {
|
|
476
|
+
var r = jalCal(jy, true);
|
|
477
|
+
return g2d(r.gy, 3, r.march) + (jm - 1) * 31 - div(jm, 7) * (jm - 7) + jd - 1;
|
|
478
|
+
}
|
|
479
|
+
Jalali.j2d = j2d;
|
|
480
|
+
/*
|
|
481
|
+
Converts the Julian Day number to a date in the Jalaali calendar.
|
|
482
|
+
@param jdn Julian Day number
|
|
483
|
+
@return
|
|
484
|
+
jy: Jalaali year (1 to 3100)
|
|
485
|
+
jm: Jalaali month (1 to 12)
|
|
486
|
+
jd: Jalaali day (1 to 29/31)
|
|
487
|
+
*/
|
|
488
|
+
function d2j(jdn) {
|
|
489
|
+
var gy = d2g(jdn).gy // Calculate Gregorian year (gy).
|
|
490
|
+
, jy = gy - 621, r = jalCal(jy, false), jdn1f = g2d(gy, 3, r.march), jd, jm, k;
|
|
491
|
+
// Find number of days that passed since 1 Farvardin.
|
|
492
|
+
k = jdn - jdn1f;
|
|
493
|
+
if (k >= 0) {
|
|
494
|
+
if (k <= 185) {
|
|
495
|
+
// The first 6 months.
|
|
496
|
+
jm = 1 + div(k, 31);
|
|
497
|
+
jd = mod(k, 31) + 1;
|
|
498
|
+
return {
|
|
499
|
+
jy: jy,
|
|
500
|
+
jm: jm,
|
|
501
|
+
jd: jd
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
// The remaining months.
|
|
506
|
+
k -= 186;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
// Previous Jalaali year.
|
|
511
|
+
jy -= 1;
|
|
512
|
+
k += 179;
|
|
513
|
+
if (r.leap === 1)
|
|
514
|
+
k += 1;
|
|
515
|
+
}
|
|
516
|
+
jm = 7 + div(k, 30);
|
|
517
|
+
jd = mod(k, 30) + 1;
|
|
518
|
+
return {
|
|
519
|
+
jy: jy,
|
|
520
|
+
jm: jm,
|
|
521
|
+
jd: jd
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
Jalali.d2j = d2j;
|
|
525
|
+
/*
|
|
526
|
+
Calculates the Julian Day number from Gregorian or Julian
|
|
527
|
+
calendar dates. This integer number corresponds to the noon of
|
|
528
|
+
the date (i.e. 12 hours of Universal Time).
|
|
529
|
+
The procedure was tested to be good since 1 March, -100100 (of both
|
|
530
|
+
calendars) up to a few million years into the future.
|
|
531
|
+
@param gy Calendar year (years BC numbered 0, -1, -2, ...)
|
|
532
|
+
@param gm Calendar month (1 to 12)
|
|
533
|
+
@param gd Calendar day of the month (1 to 28/29/30/31)
|
|
534
|
+
@return Julian Day number
|
|
535
|
+
*/
|
|
536
|
+
function g2d(gy, gm, gd) {
|
|
537
|
+
var d = div((gy + div(gm - 8, 6) + 100100) * 1461, 4)
|
|
538
|
+
+ div(153 * mod(gm + 9, 12) + 2, 5)
|
|
539
|
+
+ gd - 34840408;
|
|
540
|
+
d = d - div(div(gy + 100100 + div(gm - 8, 6), 100) * 3, 4) + 752;
|
|
541
|
+
return d;
|
|
542
|
+
}
|
|
543
|
+
Jalali.g2d = g2d;
|
|
544
|
+
/*
|
|
545
|
+
Calculates Gregorian and Julian calendar dates from the Julian Day number
|
|
546
|
+
(jdn) for the period since jdn=-34839655 (i.e. the year -100100 of both
|
|
547
|
+
calendars) to some millions years ahead of the present.
|
|
548
|
+
@param jdn Julian Day number
|
|
549
|
+
@return
|
|
550
|
+
gy: Calendar year (years BC numbered 0, -1, -2, ...)
|
|
551
|
+
gm: Calendar month (1 to 12)
|
|
552
|
+
gd: Calendar day of the month M (1 to 28/29/30/31)
|
|
553
|
+
*/
|
|
554
|
+
function d2g(jdn) {
|
|
555
|
+
var j, i, gd, gm, gy;
|
|
556
|
+
j = 4 * jdn + 139361631;
|
|
557
|
+
j = j + div(div(4 * jdn + 183187720, 146097) * 3, 4) * 4 - 3908;
|
|
558
|
+
i = div(mod(j, 1461), 4) * 5 + 308;
|
|
559
|
+
gd = div(mod(i, 153), 5) + 1;
|
|
560
|
+
gm = mod(div(i, 153), 12) + 1;
|
|
561
|
+
gy = div(j, 1461) - 100100 + div(8 - gm, 6);
|
|
562
|
+
return {
|
|
563
|
+
gy: gy,
|
|
564
|
+
gm: gm,
|
|
565
|
+
gd: gd
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
Jalali.d2g = d2g;
|
|
569
|
+
/**
|
|
570
|
+
* Return Saturday and Friday day of current week(week start in Saturday)
|
|
571
|
+
* @param {number} jy jalaali year
|
|
572
|
+
* @param {number} jm jalaali month
|
|
573
|
+
* @param {number} jd jalaali day
|
|
574
|
+
* @returns Saturday and Friday of current week
|
|
575
|
+
*/
|
|
576
|
+
function jalaaliWeek(jy, jm, jd) {
|
|
577
|
+
var dayOfWeek = jalaaliToDateObject(jy, jm, jd).getDay();
|
|
578
|
+
var startDayDifference = dayOfWeek == 6 ? 0 : -(dayOfWeek + 1);
|
|
579
|
+
var endDayDifference = 6 + startDayDifference;
|
|
580
|
+
return {
|
|
581
|
+
saturday: d2j(j2d(jy, jm, jd + startDayDifference)),
|
|
582
|
+
friday: d2j(j2d(jy, jm, jd + endDayDifference))
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
Jalali.jalaaliWeek = jalaaliWeek;
|
|
586
|
+
/**
|
|
587
|
+
* Convert Jalaali calendar dates to javascript Date object
|
|
588
|
+
* @param {number} jy jalaali year
|
|
589
|
+
* @param {number} jm jalaali month
|
|
590
|
+
* @param {number} jd jalaali day
|
|
591
|
+
* @param {number} [h] hours
|
|
592
|
+
* @param {number} [m] minutes
|
|
593
|
+
* @param {number} [s] seconds
|
|
594
|
+
* @param {number} [ms] milliseconds
|
|
595
|
+
* @returns Date object of the jalaali calendar dates
|
|
596
|
+
*/
|
|
597
|
+
function jalaaliToDateObject(jy, jm, jd, h, m, s, ms) {
|
|
598
|
+
var gregorianCalenderDate = toGregorian(jy, jm, jd);
|
|
599
|
+
return new Date(gregorianCalenderDate.gy, gregorianCalenderDate.gm - 1, gregorianCalenderDate.gd, h || 3, m || 30, s || 0, ms || 0);
|
|
600
|
+
}
|
|
601
|
+
Jalali.jalaaliToDateObject = jalaaliToDateObject;
|
|
602
|
+
/*
|
|
603
|
+
Utility helper functions.
|
|
604
|
+
*/
|
|
605
|
+
function div(a, b) {
|
|
606
|
+
return ~~(a / b);
|
|
607
|
+
}
|
|
608
|
+
Jalali.div = div;
|
|
609
|
+
function mod(a, b) {
|
|
610
|
+
return a - ~~(a / b) * b;
|
|
611
|
+
}
|
|
612
|
+
Jalali.mod = mod;
|
|
613
|
+
})(Jalali || (Jalali = {}));
|
|
614
|
+
|
|
615
|
+
class JalaliAdapter {
|
|
616
|
+
// shanbeh
|
|
617
|
+
startOfWeek = 1;
|
|
618
|
+
dariMonth = false;
|
|
619
|
+
get longMonths() {
|
|
620
|
+
return [
|
|
621
|
+
'فروردین',
|
|
622
|
+
'اردیبهشت',
|
|
623
|
+
'خرداد',
|
|
624
|
+
'تیر',
|
|
625
|
+
'مرداد',
|
|
626
|
+
'شهریور',
|
|
627
|
+
'مهر',
|
|
628
|
+
'آبان',
|
|
629
|
+
'آذر',
|
|
630
|
+
'دی',
|
|
631
|
+
'بهمن',
|
|
632
|
+
'اسفند',
|
|
633
|
+
];
|
|
634
|
+
}
|
|
635
|
+
get narrowDays() {
|
|
636
|
+
return ['شنبه', 'یک', 'دو', 'سه', 'چهار', 'پنج', 'جمعه'];
|
|
637
|
+
}
|
|
638
|
+
get shortDays() {
|
|
639
|
+
return ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'];
|
|
640
|
+
}
|
|
641
|
+
get longDays() {
|
|
642
|
+
return ['شنبه', 'یک شنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنج شنبه', 'جمعه'];
|
|
643
|
+
}
|
|
644
|
+
constructor() { }
|
|
645
|
+
toLocale(date) {
|
|
646
|
+
let jd = Jalali.toJalaali(date);
|
|
647
|
+
return {
|
|
648
|
+
locale: 'fa',
|
|
649
|
+
day: jd.jd,
|
|
650
|
+
month: jd.jm - 1,
|
|
651
|
+
year: jd.jy,
|
|
652
|
+
date,
|
|
653
|
+
hours: date.getHours(),
|
|
654
|
+
minutes: date.getMinutes(),
|
|
655
|
+
seconds: date.getSeconds(),
|
|
656
|
+
milliseconds: date.getMilliseconds(),
|
|
657
|
+
dayOfWeek: date.getDay() + this.startOfWeek,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
today() {
|
|
661
|
+
return this.toLocale(new Date());
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* getting first day of month
|
|
665
|
+
*/
|
|
666
|
+
firstDayofMonth(year, month) {
|
|
667
|
+
let gDate = Jalali.jalaaliToDateObject(year, month + 1, 1);
|
|
668
|
+
let day = gDate.getDay() + this.startOfWeek;
|
|
669
|
+
return day > 6 ? 0 : day;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* getting last date of month
|
|
673
|
+
*/
|
|
674
|
+
lastDateofMonth(year, month) {
|
|
675
|
+
const monthLengths = [
|
|
676
|
+
31,
|
|
677
|
+
31,
|
|
678
|
+
31,
|
|
679
|
+
31,
|
|
680
|
+
31,
|
|
681
|
+
31,
|
|
682
|
+
30,
|
|
683
|
+
30,
|
|
684
|
+
30,
|
|
685
|
+
30,
|
|
686
|
+
30,
|
|
687
|
+
(year - 1095) % 4 != 0 ? 29 : 30,
|
|
688
|
+
];
|
|
689
|
+
return monthLengths[month];
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* getting last day of month
|
|
693
|
+
*/
|
|
694
|
+
lastDayofMonth(year, month) {
|
|
695
|
+
let gDate = Jalali.jalaaliToDateObject(year, month + 1, this.lastDateofMonth(year, month));
|
|
696
|
+
let day = gDate.getDay() + this.startOfWeek;
|
|
697
|
+
return day > 6 ? 0 : day;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* getting last date of previous month
|
|
701
|
+
*/
|
|
702
|
+
lastDateofLastMonth(year, month) {
|
|
703
|
+
month--;
|
|
704
|
+
if (month < 0) {
|
|
705
|
+
month = 11;
|
|
706
|
+
year--;
|
|
707
|
+
}
|
|
708
|
+
const monthLengths = [
|
|
709
|
+
31,
|
|
710
|
+
31,
|
|
711
|
+
31,
|
|
712
|
+
31,
|
|
713
|
+
31,
|
|
714
|
+
31,
|
|
715
|
+
30,
|
|
716
|
+
30,
|
|
717
|
+
30,
|
|
718
|
+
30,
|
|
719
|
+
30,
|
|
720
|
+
(year - 1095) % 4 != 0 ? 29 : 30,
|
|
721
|
+
];
|
|
722
|
+
return monthLengths[month];
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* تبدیل تاریخ جلالی به میلادی برای نمایش
|
|
726
|
+
* month start with zero
|
|
727
|
+
* @param date
|
|
728
|
+
* @returns
|
|
729
|
+
*/
|
|
730
|
+
getDate(date) {
|
|
731
|
+
let d = Jalali.jalaaliToDateObject(date.year, date.month ? date.month + 1 : 1, date.day ?? 1, date.hours ?? 0, date.minutes ?? 0, date.seconds ?? 0, date.milliseconds ?? 0);
|
|
732
|
+
// {
|
|
733
|
+
// locale: 'fa',
|
|
734
|
+
// year: d.getFullYear(),
|
|
735
|
+
// month: d.getMonth(),
|
|
736
|
+
// day: d.getDate(),
|
|
737
|
+
// hours: d.getHours(),
|
|
738
|
+
// minutes: d.getMinutes(),
|
|
739
|
+
// seconds: d.getSeconds(),
|
|
740
|
+
// milliseconds: d.getMilliseconds(),
|
|
741
|
+
// dayOfWeek: d.getDay() + this.startOfWeek,
|
|
742
|
+
// }
|
|
743
|
+
return d;
|
|
744
|
+
}
|
|
745
|
+
formatDate(date, format) {
|
|
746
|
+
if (!date) {
|
|
747
|
+
return '';
|
|
748
|
+
}
|
|
749
|
+
// let option: Intl.DateTimeFormatOptions = {
|
|
750
|
+
// year: 'numeric',
|
|
751
|
+
// month: '2-digit',
|
|
752
|
+
// day: '2-digit'
|
|
753
|
+
// };
|
|
754
|
+
// if (format === 'full') {
|
|
755
|
+
// option = {
|
|
756
|
+
// year: 'numeric',
|
|
757
|
+
// month: 'long',
|
|
758
|
+
// day: '2-digit',
|
|
759
|
+
// weekday: 'long'
|
|
760
|
+
// };
|
|
761
|
+
// }
|
|
762
|
+
// return new Date(date).toLocaleDateString('fa-IR-u-nu-latn', option);
|
|
763
|
+
return genFormatDate(date, format, this.longMonths, this.longDays);
|
|
764
|
+
}
|
|
765
|
+
// _______________________________________________________________________________________
|
|
766
|
+
getStartOf(date, t) {
|
|
767
|
+
if (!date) {
|
|
768
|
+
return date;
|
|
769
|
+
}
|
|
770
|
+
let jDate = Jalali.toJalaali(date);
|
|
771
|
+
switch (t) {
|
|
772
|
+
case 'year':
|
|
773
|
+
return Jalali.jalaaliToDateObject(jDate.jy, 1, 1);
|
|
774
|
+
case 'month':
|
|
775
|
+
// console.log(jDate.jy, '-', jDate.jm, '-', 1);
|
|
776
|
+
return Jalali.jalaaliToDateObject(jDate.jy, jDate.jm, 1);
|
|
777
|
+
case 'day':
|
|
778
|
+
return Jalali.jalaaliToDateObject(jDate.jy, jDate.jm, jDate.jd);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
getLastOf(date, t) {
|
|
782
|
+
if (!date) {
|
|
783
|
+
return date;
|
|
784
|
+
}
|
|
785
|
+
let jDate = Jalali.toJalaali(date);
|
|
786
|
+
switch (t) {
|
|
787
|
+
case 'year':
|
|
788
|
+
return Jalali.jalaaliToDateObject(jDate.jy, 12, 0);
|
|
789
|
+
case 'month':
|
|
790
|
+
// console.log(jDate.jy, '-', jDate.jm, '-', this.lastDateofMonth(jDate.jy, jDate.jm));
|
|
791
|
+
return Jalali.jalaaliToDateObject(jDate.jy, jDate.jm, this.lastDateofMonth(jDate.jy, jDate.jm));
|
|
792
|
+
case 'day':
|
|
793
|
+
return Jalali.jalaaliToDateObject(jDate.jy, jDate.jm, jDate.jd);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/**
|
|
799
|
+
* منطق تبدیل تاریخ هجری قمری (Umm al-Qura) <-> میلادی
|
|
800
|
+
* جدا از آداپتر، تا قابل تست و استفادهی مستقل باشد.
|
|
801
|
+
*/
|
|
802
|
+
const HIJRI_LOCALE = 'ar-SA-u-ca-islamic-umalqura';
|
|
803
|
+
const ONE_DAY_MS = 86400000;
|
|
804
|
+
var HijriConverter;
|
|
805
|
+
(function (HijriConverter) {
|
|
806
|
+
const parser = new Intl.DateTimeFormat(HIJRI_LOCALE, {
|
|
807
|
+
day: 'numeric',
|
|
808
|
+
month: 'numeric',
|
|
809
|
+
year: 'numeric',
|
|
810
|
+
});
|
|
811
|
+
/** تبدیل اعداد عربی/فارسی به لاتین */
|
|
812
|
+
function toLatinDigits(str) {
|
|
813
|
+
return str
|
|
814
|
+
.replace(/[٠١٢٣٤٥٦٧٨٩]/g, (d) => '0123456789'['٠١٢٣٤٥٦٧٨٩'.indexOf(d)])
|
|
815
|
+
.replace(/[۰۱۲۳۴۵۶۷۸۹]/g, (d) => '0123456789'['۰۱۲۳۴۵۶۷۸۹'.indexOf(d)]);
|
|
816
|
+
}
|
|
817
|
+
/** استخراج تاریخ هجری از یک Date میلادی */
|
|
818
|
+
function parse(date) {
|
|
819
|
+
const parts = parser.formatToParts(date);
|
|
820
|
+
return {
|
|
821
|
+
day: parseInt(toLatinDigits(parts.find((p) => p.type === 'day').value), 10),
|
|
822
|
+
month: parseInt(toLatinDigits(parts.find((p) => p.type === 'month').value), 10) - 1,
|
|
823
|
+
year: parseInt(toLatinDigits(parts.find((p) => p.type === 'year').value), 10),
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
HijriConverter.parse = parse;
|
|
827
|
+
/**
|
|
828
|
+
* پیدا کردن آخرین «روز اول ماه هجری» که در همان روز seed یا
|
|
829
|
+
* قبل از آن باشد (جستجوی فقط روبهعقب، حداکثر 35 روز).
|
|
830
|
+
*
|
|
831
|
+
* نکتهی مهم: این جستجو باید فقط روبهعقب باشد، نه «نزدیکترین
|
|
832
|
+
* در هر دو جهت». جستجوی دوجهته باعث میشد وقتی الگوریتم میخواهد
|
|
833
|
+
* یک قدم به عقب برود (-5 روز)، چون فاصلهی جلو هنوز کمتر بود،
|
|
834
|
+
* دوباره به همان ماهِ قبلی برگردد و لوپ هیچوقت واقعاً عقب نرود.
|
|
835
|
+
*/
|
|
836
|
+
function firstOfMonthAtOrBefore(seed) {
|
|
837
|
+
for (let i = 0; i <= 35; i++) {
|
|
838
|
+
const test = new Date(seed);
|
|
839
|
+
test.setDate(test.getDate() - i);
|
|
840
|
+
if (parse(test).day === 1) {
|
|
841
|
+
return test;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
// عملاً نباید به اینجا برسیم
|
|
845
|
+
return seed;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* پیدا کردن JS Date معادل «روز اول» یک ماه هجری دلخواه.
|
|
849
|
+
*
|
|
850
|
+
* بهجای تکیه به یک فرمولِ تخمینیِ سال میلادی (که میتواند تا یک
|
|
851
|
+
* سال کامل خطا داشته باشد و جستجوی محدودِ ±35 روزه را شکست بدهد —
|
|
852
|
+
* همان باگی که باعث میشد lastDateofMonth عدد ۳۱ بهجای ۲۹ بدهد)،
|
|
853
|
+
* از «امروز» -که همیشه با Intl بهدرستی قابلخواندن است- بهعنوان
|
|
854
|
+
* لنگر شروع میکنیم و ماهبهماه جلو/عقب میرویم. هر قدم (چه
|
|
855
|
+
* `+30` چه `-5`) probe را به داخلِ بدنهی ماهِ هدف میبرد (نه قبل
|
|
856
|
+
* از آن)، پس جستجوی «آخرین day1 در همان روز یا قبلتر» همیشه
|
|
857
|
+
* دقیقاً day1 همان ماه هدف را پیدا میکند.
|
|
858
|
+
*/
|
|
859
|
+
function firstDayOfMonth(year, month) {
|
|
860
|
+
let anchorDate = firstOfMonthAtOrBefore(new Date());
|
|
861
|
+
let h = parse(anchorDate);
|
|
862
|
+
// سقف ایمنی برای جلوگیری از لوپ بینهایت (≈ 100 سال هجری)
|
|
863
|
+
let guard = 0;
|
|
864
|
+
while ((h.year !== year || h.month !== month) && guard < 1200) {
|
|
865
|
+
const targetIsLater = year > h.year || (year === h.year && month > h.month);
|
|
866
|
+
const probe = new Date(anchorDate);
|
|
867
|
+
// طول هر ماه هجری 29 یا 30 روز است؛ +30 همیشه به داخل ماه
|
|
868
|
+
// بعد میرسد و -5 همیشه داخل بدنهی ماه قبل میماند.
|
|
869
|
+
probe.setDate(probe.getDate() + (targetIsLater ? 30 : -5));
|
|
870
|
+
anchorDate = firstOfMonthAtOrBefore(probe);
|
|
871
|
+
h = parse(anchorDate);
|
|
872
|
+
guard++;
|
|
873
|
+
}
|
|
874
|
+
return anchorDate;
|
|
875
|
+
}
|
|
876
|
+
HijriConverter.firstDayOfMonth = firstDayOfMonth;
|
|
877
|
+
/** تبدیل سال/ماه/روز هجری به Date میلادی */
|
|
878
|
+
function toGregorian(year, month, day) {
|
|
879
|
+
const first = firstDayOfMonth(year, month);
|
|
880
|
+
const result = new Date(first);
|
|
881
|
+
result.setDate(result.getDate() + (day - 1));
|
|
882
|
+
return result;
|
|
883
|
+
}
|
|
884
|
+
HijriConverter.toGregorian = toGregorian;
|
|
885
|
+
/**
|
|
886
|
+
* تعداد واقعیِ روزهای یک ماه هجری.
|
|
887
|
+
*
|
|
888
|
+
* نکتهی مهم (باگ قبلی): نباید از `Date.getDate()` روی «روز قبل از
|
|
889
|
+
* شروع ماه بعد» استفاده کرد، چون آن عدد، شمارهی روز در تقویم
|
|
890
|
+
* میلادیِ همان Date است، نه طول ماه هجری.
|
|
891
|
+
* روش درست: فاصلهی روزها بین «اول این ماه» و «اول ماه بعد».
|
|
892
|
+
*/
|
|
893
|
+
function daysInMonth(year, month) {
|
|
894
|
+
const nextMonth = (month + 1) % 12;
|
|
895
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
896
|
+
const first = firstDayOfMonth(year, month);
|
|
897
|
+
const nextFirst = firstDayOfMonth(nextYear, nextMonth);
|
|
898
|
+
const diffMs = nextFirst.getTime() - first.getTime();
|
|
899
|
+
return Math.round(diffMs / ONE_DAY_MS);
|
|
900
|
+
}
|
|
901
|
+
HijriConverter.daysInMonth = daysInMonth;
|
|
902
|
+
})(HijriConverter || (HijriConverter = {}));
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* تقویم هجری قمری - Umm al-Qura (تقویم رسمی عربستان)
|
|
906
|
+
* نیاز به ICU ≥ 56 دارد (تمام مرورگرهای مدرن)
|
|
907
|
+
*
|
|
908
|
+
* منطق تبدیل تاریخ در HijriConverter (helpers/hijri-converter.helper.ts) است.
|
|
909
|
+
*/
|
|
910
|
+
class HijriAdapter {
|
|
911
|
+
/** یکشنبه = 0 (همخوان با تقویم میلادی برای سادگی) */
|
|
912
|
+
startOfWeek = 0;
|
|
913
|
+
get longMonths() {
|
|
914
|
+
return [
|
|
915
|
+
'محرم',
|
|
916
|
+
'صفر',
|
|
917
|
+
'ربيع الأول',
|
|
918
|
+
'ربيع الثاني',
|
|
919
|
+
'جمادى الأولى',
|
|
920
|
+
'جمادى الثانية',
|
|
921
|
+
'رجب',
|
|
922
|
+
'شعبان',
|
|
923
|
+
'رمضان',
|
|
924
|
+
'شوال',
|
|
925
|
+
'ذو القعدة',
|
|
926
|
+
'ذو الحجة',
|
|
927
|
+
];
|
|
928
|
+
}
|
|
929
|
+
get narrowDays() {
|
|
930
|
+
return ['أحد', 'إثن', 'ثلا', 'أرب', 'خمي', 'جمع', 'سبت'];
|
|
931
|
+
}
|
|
932
|
+
get shortDays() {
|
|
933
|
+
return ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'];
|
|
934
|
+
}
|
|
935
|
+
get longDays() {
|
|
936
|
+
return ['الأحد', 'الإثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'];
|
|
937
|
+
}
|
|
938
|
+
toLocale(date) {
|
|
939
|
+
const h = HijriConverter.parse(date);
|
|
940
|
+
return {
|
|
941
|
+
locale: 'ar',
|
|
942
|
+
day: h.day,
|
|
943
|
+
month: h.month,
|
|
944
|
+
year: h.year,
|
|
945
|
+
date,
|
|
946
|
+
hours: date.getHours(),
|
|
947
|
+
minutes: date.getMinutes(),
|
|
948
|
+
seconds: date.getSeconds(),
|
|
949
|
+
milliseconds: date.getMilliseconds(),
|
|
950
|
+
dayOfWeek: date.getDay(),
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
today() {
|
|
954
|
+
return this.toLocale(new Date());
|
|
955
|
+
}
|
|
956
|
+
firstDayofMonth(year, month) {
|
|
957
|
+
return HijriConverter.firstDayOfMonth(year, month).getDay();
|
|
958
|
+
}
|
|
959
|
+
lastDateofMonth(year, month) {
|
|
960
|
+
return HijriConverter.daysInMonth(year, month);
|
|
961
|
+
}
|
|
962
|
+
lastDayofMonth(year, month) {
|
|
963
|
+
const lastDate = this.lastDateofMonth(year, month);
|
|
964
|
+
return HijriConverter.toGregorian(year, month, lastDate).getDay();
|
|
965
|
+
}
|
|
966
|
+
lastDateofLastMonth(year, month) {
|
|
967
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
968
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
969
|
+
return this.lastDateofMonth(prevYear, prevMonth);
|
|
970
|
+
}
|
|
971
|
+
/** month start with zero */
|
|
972
|
+
getDate(date) {
|
|
973
|
+
const jsDate = HijriConverter.toGregorian(date.year, date.month ?? 0, date.day ?? 1);
|
|
974
|
+
if (date.hours !== undefined)
|
|
975
|
+
jsDate.setHours(date.hours);
|
|
976
|
+
if (date.minutes !== undefined)
|
|
977
|
+
jsDate.setMinutes(date.minutes);
|
|
978
|
+
if (date.seconds !== undefined)
|
|
979
|
+
jsDate.setSeconds(date.seconds);
|
|
980
|
+
if (date.milliseconds !== undefined)
|
|
981
|
+
jsDate.setMilliseconds(date.milliseconds);
|
|
982
|
+
return jsDate;
|
|
983
|
+
}
|
|
984
|
+
formatDate(date, format) {
|
|
985
|
+
if (!date)
|
|
986
|
+
return null;
|
|
987
|
+
const jsDate = this.getDate(date);
|
|
988
|
+
const options = {
|
|
989
|
+
year: 'numeric',
|
|
990
|
+
month: 'long',
|
|
991
|
+
day: 'numeric',
|
|
992
|
+
};
|
|
993
|
+
if (format === 'full') {
|
|
994
|
+
options.weekday = 'long';
|
|
995
|
+
}
|
|
996
|
+
return new Intl.DateTimeFormat('ar-SA-u-ca-islamic-umalqura', options).format(jsDate);
|
|
997
|
+
}
|
|
998
|
+
getStartOf(date, t) {
|
|
999
|
+
if (!date)
|
|
1000
|
+
return date;
|
|
1001
|
+
const h = HijriConverter.parse(date);
|
|
1002
|
+
switch (t) {
|
|
1003
|
+
case 'year':
|
|
1004
|
+
return HijriConverter.toGregorian(h.year, 0, 1);
|
|
1005
|
+
case 'month':
|
|
1006
|
+
return HijriConverter.toGregorian(h.year, h.month, 1);
|
|
1007
|
+
case 'day':
|
|
1008
|
+
return HijriConverter.toGregorian(h.year, h.month, h.day);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
getLastOf(date, t) {
|
|
1012
|
+
if (!date)
|
|
1013
|
+
return date;
|
|
1014
|
+
const h = HijriConverter.parse(date);
|
|
1015
|
+
switch (t) {
|
|
1016
|
+
case 'year':
|
|
1017
|
+
return HijriConverter.toGregorian(h.year, 11, HijriConverter.daysInMonth(h.year, 11));
|
|
1018
|
+
case 'month':
|
|
1019
|
+
return HijriConverter.toGregorian(h.year, h.month, HijriConverter.daysInMonth(h.year, h.month));
|
|
1020
|
+
case 'day':
|
|
1021
|
+
return HijriConverter.toGregorian(h.year, h.month, h.day);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/**
|
|
1027
|
+
* منطق تبدیل تاریخ سنتی چینی (农历) <-> میلادی
|
|
1028
|
+
* جدا از آداپتر، تا قابل تست و استفادهی مستقل باشد.
|
|
1029
|
+
*
|
|
1030
|
+
* ⚠️ محدودیت شناختهشده: ماههای کبیسه (闰)
|
|
1031
|
+
* در تقویم چینی، یک ماه کبیسه همان شمارهی ماه عادیِ قبل از خودش را
|
|
1032
|
+
* دارد (مثلاً «闰七月» هم month=6 میشود، دقیقاً مثل «七月» عادی).
|
|
1033
|
+
* چون CalendarDate در این پروژه فیلدی برای isLeapMonth ندارد، این
|
|
1034
|
+
* پیادهسازی -مثل نسخهی قبلی- در سالهای کبیسه، ماه کبیسه را به ماه
|
|
1035
|
+
* عادیِ همنام نگاشت میکند و کاربر نمیتواند مستقیماً وارد ماه کبیسه
|
|
1036
|
+
* شود. این یک محدودیتِ آگاهانه است، نه باگ سهوی؛ برای رفع کامل باید
|
|
1037
|
+
* فیلد isLeapMonth به CalendarDate اضافه و در همهجا (toLocale,
|
|
1038
|
+
*/
|
|
1039
|
+
const CHINESE_LOCALE = 'zh-CN-u-ca-chinese';
|
|
1040
|
+
/**
|
|
1041
|
+
* نام ماه چینی -> شماره (صفر-پایه)
|
|
1042
|
+
* ماههای عادی: 正月(0) .. 腊月(11)
|
|
1043
|
+
*
|
|
1044
|
+
* نکتهی مهمِ این باگ: Intl برای ماه یازدهم رشتهی «十一月» را
|
|
1045
|
+
* برمیگرداند، نه «冬月» (که فقط یک نام جایگزینِ ادبی/سنتی است و
|
|
1046
|
+
* توسط Intl.DateTimeFormat تولید نمیشود). نسخهی قبلی این نقشه
|
|
1047
|
+
* فقط «冬月» را داشت، پس برای هر آذر/دیماهی mismatch رخ میداد و
|
|
1048
|
+
* شمارهی ماه بهاشتباه با مقدار پیشفرض `?? 0` صفر میشد. همین
|
|
1049
|
+
* باعث میشد طول ماههای اطراف آن بازه کاملاً غلط محاسبه شود.
|
|
1050
|
+
*
|
|
1051
|
+
* ماههای کبیسه روی همان شمارهی ماه عادیِ همنام نگاشت میشوند
|
|
1052
|
+
* (به توضیح بالای فایل مراجعه کنید).
|
|
1053
|
+
*/
|
|
1054
|
+
const CHINESE_MONTH_MAP = {
|
|
1055
|
+
正月: 0,
|
|
1056
|
+
二月: 1,
|
|
1057
|
+
三月: 2,
|
|
1058
|
+
四月: 3,
|
|
1059
|
+
五月: 4,
|
|
1060
|
+
六月: 5,
|
|
1061
|
+
七月: 6,
|
|
1062
|
+
八月: 7,
|
|
1063
|
+
九月: 8,
|
|
1064
|
+
十月: 9,
|
|
1065
|
+
十一月: 10,
|
|
1066
|
+
腊月: 11,
|
|
1067
|
+
闰正月: 0,
|
|
1068
|
+
闰二月: 1,
|
|
1069
|
+
闰三月: 2,
|
|
1070
|
+
闰四月: 3,
|
|
1071
|
+
闰五月: 4,
|
|
1072
|
+
闰六月: 5,
|
|
1073
|
+
闰七月: 6,
|
|
1074
|
+
闰八月: 7,
|
|
1075
|
+
闰九月: 8,
|
|
1076
|
+
闰十月: 9,
|
|
1077
|
+
闰十一月: 10,
|
|
1078
|
+
闰腊月: 11,
|
|
1079
|
+
};
|
|
1080
|
+
var ChineseConverter;
|
|
1081
|
+
(function (ChineseConverter) {
|
|
1082
|
+
const parser = new Intl.DateTimeFormat(CHINESE_LOCALE, {
|
|
1083
|
+
day: 'numeric',
|
|
1084
|
+
month: 'numeric',
|
|
1085
|
+
year: 'numeric',
|
|
1086
|
+
});
|
|
1087
|
+
/** تبدیل ارقام تمامعرض/فولویدث به لاتین */
|
|
1088
|
+
function toLatinDigits(str) {
|
|
1089
|
+
return str.replace(/[0-9]/g, (d) => String.fromCharCode(d.charCodeAt(0) - 0xfee0));
|
|
1090
|
+
}
|
|
1091
|
+
/** استخراج تاریخ چینی از یک Date میلادی - با تشخیص ماه کبیسه */
|
|
1092
|
+
function parse(date) {
|
|
1093
|
+
const parts = parser.formatToParts(date);
|
|
1094
|
+
const dayPart = parts.find((p) => p.type === 'day');
|
|
1095
|
+
const monthPart = parts.find((p) => p.type === 'month');
|
|
1096
|
+
const yearPart = parts.find((p) => p.type === 'year' || p.type === 'relatedYear');
|
|
1097
|
+
const day = parseInt(toLatinDigits(dayPart.value), 10);
|
|
1098
|
+
const isLeapMonth = monthPart.value.includes('闰');
|
|
1099
|
+
const month = CHINESE_MONTH_MAP[monthPart.value] ?? 0;
|
|
1100
|
+
const year = parseInt(toLatinDigits(yearPart.value), 10);
|
|
1101
|
+
return { day, month, year, isLeapMonth };
|
|
1102
|
+
}
|
|
1103
|
+
ChineseConverter.parse = parse;
|
|
1104
|
+
/**
|
|
1105
|
+
* پیدا کردن آخرین «روز اول ماهِ چینیِ غیرکبیسه» که در همان روز
|
|
1106
|
+
* seed یا قبل از آن باشد (جستجوی فقط روبهعقب، حداکثر 45 روز).
|
|
1107
|
+
*
|
|
1108
|
+
* نکتهی مهم: این جستجو باید فقط روبهعقب باشد، نه «نزدیکترین
|
|
1109
|
+
* در هر دو جهت». نسخهی قبلی نزدیکترین day1 را در هر دو جهت
|
|
1110
|
+
* برمیگرداند که باعث میشد وقتی الگوریتم میخواهد یک قدم به
|
|
1111
|
+
* عقب برود (-5 روز)، چون فاصلهی جلو هنوز کمتر بود، دوباره به
|
|
1112
|
+
* همان ماهِ قبلی برگردد و لوپ هیچوقت واقعاً عقب نرود (لوپ
|
|
1113
|
+
* بینهایت/گیر کردن روی یک ماه ثابت).
|
|
1114
|
+
*/
|
|
1115
|
+
function firstOfMonthAtOrBefore(seed) {
|
|
1116
|
+
for (let i = 0; i <= 65; i++) {
|
|
1117
|
+
const test = new Date(seed);
|
|
1118
|
+
test.setDate(test.getDate() - i);
|
|
1119
|
+
const c = parse(test);
|
|
1120
|
+
if (c.day === 1 && !c.isLeapMonth) {
|
|
1121
|
+
return test;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
// عملاً نباید به اینجا برسیم
|
|
1125
|
+
return seed;
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* پیدا کردن JS Date معادل «روز اول» یک ماه چینیِ غیرکبیسهی دلخواه.
|
|
1129
|
+
*
|
|
1130
|
+
* نسخهی قبلی فرض میکرد فیلد `year` بازگشتی از Intl برای
|
|
1131
|
+
* `zh-CN-u-ca-chinese` همان شمارهی سال در دورهی ۶۰ساله است
|
|
1132
|
+
* (epoch هوانگدی)، در حالیکه در عمل همان سال میلادی برمیگردد
|
|
1133
|
+
* (مثلاً 2026). با فرمول `year - 2697` این عدد منفی و کاملاً
|
|
1134
|
+
* نادرست میشد (مثلاً -671) و جستجوی ±45 روزه همیشه شکست
|
|
1135
|
+
* میخورد و روی fallback (یک تاریخ کاملاً غلط) میافتاد —
|
|
1136
|
+
* همان باگی که باعث میشد طول ماه فقط چند روز نمایش داده شود.
|
|
1137
|
+
*
|
|
1138
|
+
* راهحل: مثل آداپتر هجری، از «امروز» -که همیشه با Intl بهدرستی
|
|
1139
|
+
* قابلخواندن است- بهعنوان لنگر شروع میکنیم و ماهبهماه
|
|
1140
|
+
* جلو/عقب میرویم.
|
|
1141
|
+
*
|
|
1142
|
+
* نکتهی اضافیِ مخصوص تقویم چینی: بر خلاف هجری، اینجا «ماه
|
|
1143
|
+
* کبیسه» هم وجود دارد. وقتی دقیقاً بین دو ماهِ عادیِ متوالی یک
|
|
1144
|
+
* ماه کبیسه فاصله افتاده باشد (مثلاً 五月 عادی -> 闰五月 -> 五月
|
|
1145
|
+
* بعدی، یعنی واقعاً ماه پنجم بعدی)، فاصلهی واقعی حدود 59 روز
|
|
1146
|
+
* میشود نه ~30 روز، و یک قدمِ ثابتِ `+30` فقط وسطِ همان ماه
|
|
1147
|
+
* کبیسه میافتد؛ چون جستجوی عقب ماه کبیسه را نادیده میگیرد،
|
|
1148
|
+
* به همان ماهِ عادیِ قبلی برمیگردد و پیشرفتی حاصل نمیشود.
|
|
1149
|
+
* برای همین، اگر یک قدم هیچ پیشرفتی نداشت (anchor عوض نشد)،
|
|
1150
|
+
* قدم را بزرگتر میکنیم تا از روی ماه کبیسهی احتمالی بپرد.
|
|
1151
|
+
*/
|
|
1152
|
+
function firstDayOfMonth(year, month) {
|
|
1153
|
+
let anchorDate = firstOfMonthAtOrBefore(new Date());
|
|
1154
|
+
let c = parse(anchorDate);
|
|
1155
|
+
// سقف ایمنی برای جلوگیری از لوپ بینهایت (≈ 100 سال چینی)
|
|
1156
|
+
let guard = 0;
|
|
1157
|
+
while ((c.year !== year || c.month !== month) && guard < 1300) {
|
|
1158
|
+
const targetIsLater = year > c.year || (year === c.year && month > c.month);
|
|
1159
|
+
let newAnchor = anchorDate;
|
|
1160
|
+
// طول هر ماه عادی 29 یا 30 روز است؛ اما اگر بینِ این ماه و
|
|
1161
|
+
// ماهِ بعد/قبل یک ماه کبیسه فاصله افتاده باشد، باید قدم را
|
|
1162
|
+
// بزرگتر کنیم (به اندازهی حداکثر یک ماهِ کبیسهی اضافه).
|
|
1163
|
+
for (const step of targetIsLater ? [30, 60, 90] : [-5, -35, -65]) {
|
|
1164
|
+
const probe = new Date(anchorDate);
|
|
1165
|
+
probe.setDate(probe.getDate() + step);
|
|
1166
|
+
newAnchor = firstOfMonthAtOrBefore(probe);
|
|
1167
|
+
if (newAnchor.getTime() !== anchorDate.getTime()) {
|
|
1168
|
+
break;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
anchorDate = newAnchor;
|
|
1172
|
+
c = parse(anchorDate);
|
|
1173
|
+
guard++;
|
|
1174
|
+
}
|
|
1175
|
+
return anchorDate;
|
|
1176
|
+
}
|
|
1177
|
+
ChineseConverter.firstDayOfMonth = firstDayOfMonth;
|
|
1178
|
+
/** تبدیل سال/ماه/روز چینی به Date میلادی */
|
|
1179
|
+
function toGregorian(year, month, day) {
|
|
1180
|
+
const first = firstDayOfMonth(year, month);
|
|
1181
|
+
const result = new Date(first);
|
|
1182
|
+
result.setDate(result.getDate() + (day - 1));
|
|
1183
|
+
return result;
|
|
1184
|
+
}
|
|
1185
|
+
ChineseConverter.toGregorian = toGregorian;
|
|
1186
|
+
/**
|
|
1187
|
+
* تعداد واقعیِ روزهای یک ماه چینی (۲۹ یا ۳۰).
|
|
1188
|
+
*
|
|
1189
|
+
* نکته: بر خلاف نسخهی هجری، اینجا از شمارهی روزِ خروجیِ خودِ
|
|
1190
|
+
* تقویم چینی (`parse(test).day`) استفاده میکنیم نه از
|
|
1191
|
+
* `Date.getDate()` میلادی، چون آن مقدار به اشتباه طول ماه را
|
|
1192
|
+
* بر اساس تقویم میلادی محاسبه میکرد.
|
|
1193
|
+
*/
|
|
1194
|
+
function daysInMonth(year, month) {
|
|
1195
|
+
const first = firstDayOfMonth(year, month);
|
|
1196
|
+
for (let i = 1; i <= 31; i++) {
|
|
1197
|
+
const test = new Date(first);
|
|
1198
|
+
test.setDate(test.getDate() + i);
|
|
1199
|
+
const c = parse(test);
|
|
1200
|
+
if (c.year !== year || c.month !== month || c.isLeapMonth) {
|
|
1201
|
+
const last = new Date(test);
|
|
1202
|
+
last.setDate(last.getDate() - 1);
|
|
1203
|
+
return parse(last).day;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return 29; // fallback ایمن
|
|
1207
|
+
}
|
|
1208
|
+
ChineseConverter.daysInMonth = daysInMonth;
|
|
1209
|
+
})(ChineseConverter || (ChineseConverter = {}));
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* تقویم سنتی چینی (农历)
|
|
1213
|
+
* منطق تبدیل تاریخ در ChineseConverter (helpers/chinese-converter.helper.ts) است.
|
|
1214
|
+
*
|
|
1215
|
+
* ⚠️ محدودیت شناختهشده: ماههای کبیسه (闰) فعلاً به ماه عادیِ همنام
|
|
1216
|
+
* نگاشت میشوند؛ جزئیات در chinese-converter.helper.ts.
|
|
1217
|
+
*/
|
|
1218
|
+
class ChineseAdapter {
|
|
1219
|
+
/** یکشنبه = 0 */
|
|
1220
|
+
startOfWeek = 0;
|
|
1221
|
+
get longMonths() {
|
|
1222
|
+
return [
|
|
1223
|
+
'正月',
|
|
1224
|
+
'二月',
|
|
1225
|
+
'三月',
|
|
1226
|
+
'四月',
|
|
1227
|
+
'五月',
|
|
1228
|
+
'六月',
|
|
1229
|
+
'七月',
|
|
1230
|
+
'八月',
|
|
1231
|
+
'九月',
|
|
1232
|
+
'十月',
|
|
1233
|
+
'冬月',
|
|
1234
|
+
'腊月',
|
|
1235
|
+
];
|
|
1236
|
+
}
|
|
1237
|
+
get narrowDays() {
|
|
1238
|
+
return ['日', '一', '二', '三', '四', '五', '六'];
|
|
1239
|
+
}
|
|
1240
|
+
get shortDays() {
|
|
1241
|
+
return ['日', '一', '二', '三', '四', '五', '六'];
|
|
1242
|
+
}
|
|
1243
|
+
get longDays() {
|
|
1244
|
+
return ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
1245
|
+
}
|
|
1246
|
+
toLocale(date) {
|
|
1247
|
+
const c = ChineseConverter.parse(date);
|
|
1248
|
+
return {
|
|
1249
|
+
locale: 'zh',
|
|
1250
|
+
day: c.day,
|
|
1251
|
+
month: c.month,
|
|
1252
|
+
year: c.year,
|
|
1253
|
+
date,
|
|
1254
|
+
hours: date.getHours(),
|
|
1255
|
+
minutes: date.getMinutes(),
|
|
1256
|
+
seconds: date.getSeconds(),
|
|
1257
|
+
milliseconds: date.getMilliseconds(),
|
|
1258
|
+
dayOfWeek: date.getDay(),
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
today() {
|
|
1262
|
+
return this.toLocale(new Date());
|
|
1263
|
+
}
|
|
1264
|
+
firstDayofMonth(year, month) {
|
|
1265
|
+
return ChineseConverter.firstDayOfMonth(year, month).getDay();
|
|
1266
|
+
}
|
|
1267
|
+
lastDateofMonth(year, month) {
|
|
1268
|
+
return ChineseConverter.daysInMonth(year, month);
|
|
1269
|
+
}
|
|
1270
|
+
lastDayofMonth(year, month) {
|
|
1271
|
+
const lastDate = this.lastDateofMonth(year, month);
|
|
1272
|
+
return ChineseConverter.toGregorian(year, month, lastDate).getDay();
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* روز آخر ماه قبل - با یک ترفند ساده:
|
|
1276
|
+
* روز قبل از روز اول ماه فعلی، حتماً آخرین روز ماه قبل است.
|
|
1277
|
+
*/
|
|
1278
|
+
lastDateofLastMonth(year, month) {
|
|
1279
|
+
const firstOfThis = ChineseConverter.firstDayOfMonth(year, month);
|
|
1280
|
+
const lastOfPrev = new Date(firstOfThis);
|
|
1281
|
+
lastOfPrev.setDate(lastOfPrev.getDate() - 1);
|
|
1282
|
+
return ChineseConverter.parse(lastOfPrev).day;
|
|
1283
|
+
}
|
|
1284
|
+
/** month start with zero */
|
|
1285
|
+
getDate(date) {
|
|
1286
|
+
const jsDate = ChineseConverter.toGregorian(date.year, date.month ?? 0, date.day ?? 1);
|
|
1287
|
+
if (date.hours !== undefined)
|
|
1288
|
+
jsDate.setHours(date.hours);
|
|
1289
|
+
if (date.minutes !== undefined)
|
|
1290
|
+
jsDate.setMinutes(date.minutes);
|
|
1291
|
+
if (date.seconds !== undefined)
|
|
1292
|
+
jsDate.setSeconds(date.seconds);
|
|
1293
|
+
if (date.milliseconds !== undefined)
|
|
1294
|
+
jsDate.setMilliseconds(date.milliseconds);
|
|
1295
|
+
return jsDate;
|
|
1296
|
+
}
|
|
1297
|
+
formatDate(date, format) {
|
|
1298
|
+
if (!date)
|
|
1299
|
+
return null;
|
|
1300
|
+
const jsDate = this.getDate(date);
|
|
1301
|
+
const options = {
|
|
1302
|
+
year: 'numeric',
|
|
1303
|
+
month: 'long',
|
|
1304
|
+
day: 'numeric',
|
|
1305
|
+
};
|
|
1306
|
+
if (format === 'full') {
|
|
1307
|
+
options.weekday = 'long';
|
|
1308
|
+
}
|
|
1309
|
+
return new Intl.DateTimeFormat('zh-CN-u-ca-chinese', options).format(jsDate);
|
|
1310
|
+
}
|
|
1311
|
+
getStartOf(date, t) {
|
|
1312
|
+
if (!date)
|
|
1313
|
+
return date;
|
|
1314
|
+
const c = ChineseConverter.parse(date);
|
|
1315
|
+
switch (t) {
|
|
1316
|
+
case 'year':
|
|
1317
|
+
return ChineseConverter.firstDayOfMonth(c.year, 0);
|
|
1318
|
+
case 'month':
|
|
1319
|
+
return ChineseConverter.firstDayOfMonth(c.year, c.month);
|
|
1320
|
+
case 'day':
|
|
1321
|
+
return ChineseConverter.toGregorian(c.year, c.month, c.day);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
getLastOf(date, t) {
|
|
1325
|
+
if (!date)
|
|
1326
|
+
return date;
|
|
1327
|
+
const c = ChineseConverter.parse(date);
|
|
1328
|
+
switch (t) {
|
|
1329
|
+
case 'year':
|
|
1330
|
+
return ChineseConverter.toGregorian(c.year, 11, ChineseConverter.daysInMonth(c.year, 11));
|
|
1331
|
+
case 'month':
|
|
1332
|
+
return ChineseConverter.toGregorian(c.year, c.month, ChineseConverter.daysInMonth(c.year, c.month));
|
|
1333
|
+
case 'day':
|
|
1334
|
+
return ChineseConverter.toGregorian(c.year, c.month, c.day);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
const DATE_ADAPTERS = new InjectionToken('DATE_ADAPTERS');
|
|
1340
|
+
const DEFAULT_DATE_ADAPTERS = Object.freeze([
|
|
1341
|
+
{ locale: 'en', useClass: GregorianAdapter },
|
|
1342
|
+
{ locale: 'fa', useClass: JalaliAdapter },
|
|
1343
|
+
{ locale: 'hi', useClass: HijriAdapter },
|
|
1344
|
+
{ locale: 'zh', useClass: ChineseAdapter },
|
|
1345
|
+
]);
|
|
1346
|
+
function getLocals() {
|
|
1347
|
+
const adapters = inject(DATE_ADAPTERS);
|
|
1348
|
+
return adapters.map((m) => m.locale);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
class DateAdapterRegistry {
|
|
1352
|
+
adapters = inject(DATE_ADAPTERS);
|
|
1353
|
+
resolve(locale) {
|
|
1354
|
+
const type = this.adapters?.find((x) => x.locale == locale)?.useClass;
|
|
1355
|
+
if (!type) {
|
|
1356
|
+
console.warn(`Date adapter "${locale}" not registred!`);
|
|
1357
|
+
return new GregorianAdapter();
|
|
1358
|
+
}
|
|
1359
|
+
else {
|
|
1360
|
+
return new type();
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DateAdapterRegistry, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1364
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DateAdapterRegistry });
|
|
1365
|
+
}
|
|
1366
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DateAdapterRegistry, decorators: [{
|
|
1367
|
+
type: Injectable
|
|
1368
|
+
}] });
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* convert 300s to 5:00
|
|
1372
|
+
*/
|
|
1373
|
+
function convertSecondsToTime(givenSeconds) {
|
|
1374
|
+
const dateObj = new Date(givenSeconds * 1000);
|
|
1375
|
+
const hours = dateObj.getUTCHours();
|
|
1376
|
+
const minutes = dateObj.getUTCMinutes();
|
|
1377
|
+
const seconds = dateObj.getSeconds();
|
|
1378
|
+
const h = hours > 0 ? hours.toString().padStart(2, '0') + ':' : '';
|
|
1379
|
+
const timeString = h + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
|
|
1380
|
+
return timeString;
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* convert 0 to 00:00 , 1 to 01:00 , 1.5 => 01:30
|
|
1384
|
+
*/
|
|
1385
|
+
function convertNumberToTime(num) {
|
|
1386
|
+
const hour = Math.floor(num);
|
|
1387
|
+
const min = 60 * (num - hour);
|
|
1388
|
+
const t = `${hour.toString().padStart(2, '0')}:${min.toString().padStart(2, '0')}`;
|
|
1389
|
+
return t;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
class NgxDatePickerBase {
|
|
1393
|
+
_locale = 'en';
|
|
1394
|
+
dateAdapterRegistry = inject(DateAdapterRegistry);
|
|
1395
|
+
adapter = this.dateAdapterRegistry.resolve(this._locale);
|
|
1396
|
+
currYear;
|
|
1397
|
+
currMonth;
|
|
1398
|
+
currentWeek;
|
|
1399
|
+
months = [];
|
|
1400
|
+
weeks = [];
|
|
1401
|
+
viewDays = [];
|
|
1402
|
+
viewMonths = [];
|
|
1403
|
+
viewYears = [];
|
|
1404
|
+
viewWeeks = [];
|
|
1405
|
+
displayMonth = '';
|
|
1406
|
+
minDate = null;
|
|
1407
|
+
maxDate = null;
|
|
1408
|
+
renderCalendar(view, selected, events, callback) {
|
|
1409
|
+
switch (view) {
|
|
1410
|
+
case 'day':
|
|
1411
|
+
this.renderDay(selected, events);
|
|
1412
|
+
break;
|
|
1413
|
+
case 'month':
|
|
1414
|
+
this.renderMonth();
|
|
1415
|
+
break;
|
|
1416
|
+
case 'year':
|
|
1417
|
+
this.renderYear();
|
|
1418
|
+
break;
|
|
1419
|
+
case 'week':
|
|
1420
|
+
this.renderWeek();
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1423
|
+
this.displayMonth = this.months[this.currMonth];
|
|
1424
|
+
if (callback) {
|
|
1425
|
+
callback();
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
renderYear() {
|
|
1429
|
+
this.viewYears = [];
|
|
1430
|
+
const s = this.currYear - 10;
|
|
1431
|
+
const e = this.currYear + 10;
|
|
1432
|
+
for (let i = s; i < e; i++) {
|
|
1433
|
+
this.viewYears.push({
|
|
1434
|
+
year: i,
|
|
1435
|
+
selected: i === this.currYear,
|
|
1436
|
+
active: this.checkActiveYear(i),
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
renderMonth() {
|
|
1441
|
+
this.viewMonths = [];
|
|
1442
|
+
for (let i = 0; i < this.months.length; i++) {
|
|
1443
|
+
this.viewMonths.push({
|
|
1444
|
+
month: i,
|
|
1445
|
+
displayMonth: this.months[i],
|
|
1446
|
+
selected: i === this.currMonth,
|
|
1447
|
+
active: this.checkActiveMonth(this.currYear, i),
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
/** only in calendar view */
|
|
1452
|
+
renderWeek() {
|
|
1453
|
+
this.viewWeeks = [];
|
|
1454
|
+
for (let t = 0; t <= 24; t = t + 0.5) {
|
|
1455
|
+
this.viewWeeks.push({
|
|
1456
|
+
time: t,
|
|
1457
|
+
displayTime: convertNumberToTime(t),
|
|
1458
|
+
weeks: this.weeks,
|
|
1459
|
+
active: true,
|
|
1460
|
+
selected: false,
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
renderDay(selected, _events) {
|
|
1465
|
+
this.viewDays = [];
|
|
1466
|
+
let firstDayofMonth = this.adapter.firstDayofMonth(this.currYear, this.currMonth);
|
|
1467
|
+
let lastDateofMonth = this.adapter.lastDateofMonth(this.currYear, this.currMonth);
|
|
1468
|
+
let lastDayofMonth = this.adapter.lastDayofMonth(this.currYear, this.currMonth);
|
|
1469
|
+
let lastDateofLastMonth = this.adapter.lastDateofLastMonth(this.currYear, this.currMonth);
|
|
1470
|
+
for (let i = firstDayofMonth; i > 0; i--) {
|
|
1471
|
+
const d = lastDateofLastMonth - i + 1;
|
|
1472
|
+
const date = this.adapter.getDate({
|
|
1473
|
+
locale: this._locale,
|
|
1474
|
+
year: this.currYear,
|
|
1475
|
+
month: this.currMonth - 1,
|
|
1476
|
+
day: d,
|
|
1477
|
+
});
|
|
1478
|
+
this.viewDays.push({
|
|
1479
|
+
day: d,
|
|
1480
|
+
active: false,
|
|
1481
|
+
isToday: false,
|
|
1482
|
+
selected: false,
|
|
1483
|
+
date,
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
// console.log('selected', this.selected);
|
|
1487
|
+
for (let i = 1; i <= lastDateofMonth; i++) {
|
|
1488
|
+
let today = this.adapter.today();
|
|
1489
|
+
let isToday = i === today.day && this.currMonth === today.month && this.currYear === today.year;
|
|
1490
|
+
const date = this.adapter.getDate({
|
|
1491
|
+
locale: this._locale,
|
|
1492
|
+
year: this.currYear,
|
|
1493
|
+
month: this.currMonth,
|
|
1494
|
+
day: i,
|
|
1495
|
+
});
|
|
1496
|
+
const events = this.getEvents(date, _events);
|
|
1497
|
+
this.viewDays.push({
|
|
1498
|
+
day: i,
|
|
1499
|
+
active: this.checkActiveDate(date),
|
|
1500
|
+
isToday: isToday,
|
|
1501
|
+
selected: i === selected?.day &&
|
|
1502
|
+
selected.month === this.currMonth &&
|
|
1503
|
+
selected.year === this.currYear,
|
|
1504
|
+
date,
|
|
1505
|
+
events,
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
for (let i = lastDayofMonth; i < 6; i++) {
|
|
1509
|
+
const d = i - lastDayofMonth + 1;
|
|
1510
|
+
const date = this.adapter.getDate({
|
|
1511
|
+
locale: this._locale,
|
|
1512
|
+
year: this.currYear,
|
|
1513
|
+
month: this.currMonth + 1,
|
|
1514
|
+
day: d,
|
|
1515
|
+
});
|
|
1516
|
+
this.viewDays.push({
|
|
1517
|
+
day: d,
|
|
1518
|
+
active: false,
|
|
1519
|
+
isToday: false,
|
|
1520
|
+
selected: false,
|
|
1521
|
+
date,
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
checkActiveDate(date) {
|
|
1526
|
+
let c = clampDate(date, this.minDate, this.maxDate);
|
|
1527
|
+
if (c < 0) {
|
|
1528
|
+
return false;
|
|
1529
|
+
}
|
|
1530
|
+
else if (c > 0) {
|
|
1531
|
+
return false;
|
|
1532
|
+
}
|
|
1533
|
+
return true;
|
|
1534
|
+
}
|
|
1535
|
+
checkActiveMonth(year, month) {
|
|
1536
|
+
let fd = this.adapter.getDate({ locale: this._locale, year, month, day: 1 });
|
|
1537
|
+
let ld = this.adapter.getDate({
|
|
1538
|
+
locale: this._locale,
|
|
1539
|
+
year,
|
|
1540
|
+
month,
|
|
1541
|
+
day: this.adapter.lastDateofMonth(year, month),
|
|
1542
|
+
});
|
|
1543
|
+
let min = this.adapter.getStartOf(this.minDate, 'month');
|
|
1544
|
+
let max = this.adapter.getLastOf(this.maxDate, 'month');
|
|
1545
|
+
return clampMonth(fd, min, max) === 0 && clampMonth(ld, min, max) === 0;
|
|
1546
|
+
}
|
|
1547
|
+
// g(d: Date | null) {
|
|
1548
|
+
// if (d)
|
|
1549
|
+
// return d.getFullYear() + '/' + d.getMonth() + '/' + d.getDate();
|
|
1550
|
+
// else return '';
|
|
1551
|
+
// }
|
|
1552
|
+
checkActiveYear(year) {
|
|
1553
|
+
const d = this.adapter.getDate({ locale: this._locale, year, month: 1, day: 1 });
|
|
1554
|
+
let c = clampYear(d, this.minDate, this.maxDate);
|
|
1555
|
+
if (c < 0) {
|
|
1556
|
+
return false;
|
|
1557
|
+
}
|
|
1558
|
+
else if (c > 0) {
|
|
1559
|
+
return false;
|
|
1560
|
+
}
|
|
1561
|
+
return true;
|
|
1562
|
+
}
|
|
1563
|
+
getEvents(date, events) {
|
|
1564
|
+
if (!events || events.length == 0)
|
|
1565
|
+
return [];
|
|
1566
|
+
let eventList = [];
|
|
1567
|
+
eventList = events.filter((x) => {
|
|
1568
|
+
let s = compareDate(date, x.start);
|
|
1569
|
+
let e = x.end ? compareDate(date, x.end) : s;
|
|
1570
|
+
// console.info('compare', date, '<=>', x.start, 's', s, e);
|
|
1571
|
+
if (s >= 0 && e <= 0)
|
|
1572
|
+
return true;
|
|
1573
|
+
else
|
|
1574
|
+
return false;
|
|
1575
|
+
});
|
|
1576
|
+
// console.log('event', date, eventList);
|
|
1577
|
+
return eventList;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
class NgxInputDatePickerComponent extends NgxDatePickerBase {
|
|
1582
|
+
browserService = inject(BrowserService);
|
|
1583
|
+
theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
|
|
1584
|
+
set setTheme(val) {
|
|
1585
|
+
if (!val || val == 'auto') {
|
|
1586
|
+
this.theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
|
|
1587
|
+
}
|
|
1588
|
+
else {
|
|
1589
|
+
this.theme = val;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
config = new NgxDatePickerConfig();
|
|
1593
|
+
set setConfig(val) {
|
|
1594
|
+
this.config = { ...new NgxDatePickerConfig(), ...val };
|
|
1595
|
+
}
|
|
1596
|
+
set locale(val) {
|
|
1597
|
+
this._locale = val;
|
|
1598
|
+
this.adapter = this.dateAdapterRegistry.resolve(this._locale);
|
|
1599
|
+
this.init();
|
|
1600
|
+
}
|
|
1601
|
+
/** The minimum valid date. */
|
|
1602
|
+
set setMin(value) {
|
|
1603
|
+
const validValue = deserialize(value);
|
|
1604
|
+
if (!sameDate(validValue, this.minDate)) {
|
|
1605
|
+
this.minDate = validValue;
|
|
1606
|
+
this._validatorOnChange();
|
|
1607
|
+
this.init();
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
/** The maximum valid date. */
|
|
1611
|
+
set setMax(value) {
|
|
1612
|
+
const validValue = deserialize(value);
|
|
1613
|
+
if (!sameDate(validValue, this.maxDate)) {
|
|
1614
|
+
this.maxDate = validValue;
|
|
1615
|
+
this._validatorOnChange();
|
|
1616
|
+
this.init();
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
view = 'day';
|
|
1620
|
+
change = new EventEmitter();
|
|
1621
|
+
wrapperWidth = 40 * 7 + 20;
|
|
1622
|
+
selected;
|
|
1623
|
+
calendarHeader = '';
|
|
1624
|
+
isDisabled = false;
|
|
1625
|
+
weekDays = [];
|
|
1626
|
+
_onChange = (value) => { };
|
|
1627
|
+
_onTouched = () => { };
|
|
1628
|
+
_validatorOnChange = () => { };
|
|
1629
|
+
constructor() {
|
|
1630
|
+
super();
|
|
1631
|
+
}
|
|
1632
|
+
ngOnInit() {
|
|
1633
|
+
this.init();
|
|
1634
|
+
}
|
|
1635
|
+
updateConfig(val) {
|
|
1636
|
+
this.config = { ...new NgxDatePickerConfig(), ...val };
|
|
1637
|
+
}
|
|
1638
|
+
init() {
|
|
1639
|
+
this.months = this.adapter.longMonths;
|
|
1640
|
+
let sDays = this.adapter.shortDays;
|
|
1641
|
+
let lDays = this.adapter.longDays;
|
|
1642
|
+
this.weekDays = sDays.map((m, i) => ({ min: m, name: lDays[i] }));
|
|
1643
|
+
if (!this.selected?.date) {
|
|
1644
|
+
this.gotoToday();
|
|
1645
|
+
}
|
|
1646
|
+
else {
|
|
1647
|
+
let l = this.adapter.toLocale(this.selected.date);
|
|
1648
|
+
this.currYear = l.year;
|
|
1649
|
+
this.currMonth = l.month ?? 1;
|
|
1650
|
+
this.renderCalendar(this.view);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
writeValue(value) {
|
|
1654
|
+
const validValue = deserialize(value);
|
|
1655
|
+
if (validValue) {
|
|
1656
|
+
this.selected = this.adapter.toLocale(validValue);
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
this.selected = undefined;
|
|
1660
|
+
}
|
|
1661
|
+
this.init();
|
|
1662
|
+
}
|
|
1663
|
+
validate(control) {
|
|
1664
|
+
if (this.selected?.date) {
|
|
1665
|
+
if (!isValid(this.selected.date)) {
|
|
1666
|
+
return {
|
|
1667
|
+
invalid: true,
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
let c = clampDate(this.selected?.date, this.minDate, this.maxDate);
|
|
1671
|
+
if (c < 0) {
|
|
1672
|
+
return {
|
|
1673
|
+
invalid: true,
|
|
1674
|
+
min: this.minDate,
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
else if (c > 0) {
|
|
1678
|
+
return {
|
|
1679
|
+
invalid: true,
|
|
1680
|
+
max: this.maxDate,
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return null;
|
|
1685
|
+
}
|
|
1686
|
+
registerOnChange(fn) {
|
|
1687
|
+
this._onChange = fn;
|
|
1688
|
+
}
|
|
1689
|
+
registerOnTouched(fn) {
|
|
1690
|
+
this._onTouched = fn;
|
|
1691
|
+
}
|
|
1692
|
+
registerOnValidatorChange(fn) {
|
|
1693
|
+
this._validatorOnChange = fn;
|
|
1694
|
+
}
|
|
1695
|
+
setDisabledState(disabled) {
|
|
1696
|
+
this.isDisabled = disabled;
|
|
1697
|
+
}
|
|
1698
|
+
renderCalendar(view) {
|
|
1699
|
+
super.renderCalendar(view, this.selected, [], () => {
|
|
1700
|
+
let d = this.selected?.date;
|
|
1701
|
+
this.calendarHeader =
|
|
1702
|
+
(d && this.adapter.formatDate(this.adapter.toLocale(d), 'EEEE - d MMMM, yyyy')) ?? '';
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
gotoToday() {
|
|
1706
|
+
let today = this.adapter.today();
|
|
1707
|
+
this.selected = today;
|
|
1708
|
+
this.currYear = today.year;
|
|
1709
|
+
this.currMonth = today.month ?? 1;
|
|
1710
|
+
this.calendarHeader = this.adapter.formatDate(today, 'EEEE, d MMMM, yyyy') ?? '';
|
|
1711
|
+
this.changeView('day');
|
|
1712
|
+
}
|
|
1713
|
+
changeView(v) {
|
|
1714
|
+
this.view = v;
|
|
1715
|
+
this.renderCalendar(this.view);
|
|
1716
|
+
}
|
|
1717
|
+
next() {
|
|
1718
|
+
if (this.view === 'year') {
|
|
1719
|
+
this.currYear += 20;
|
|
1720
|
+
}
|
|
1721
|
+
else if (this.view === 'month') {
|
|
1722
|
+
this.currYear++;
|
|
1723
|
+
}
|
|
1724
|
+
else {
|
|
1725
|
+
this.currMonth++;
|
|
1726
|
+
}
|
|
1727
|
+
if (this.currMonth < 0 || this.currMonth > 11) {
|
|
1728
|
+
let date = new Date(this.currYear, this.currMonth);
|
|
1729
|
+
this.currYear = date.getFullYear();
|
|
1730
|
+
this.currMonth = date.getMonth();
|
|
1731
|
+
}
|
|
1732
|
+
this.renderCalendar(this.view);
|
|
1733
|
+
}
|
|
1734
|
+
previous() {
|
|
1735
|
+
if (this.view === 'year') {
|
|
1736
|
+
this.currYear -= 20;
|
|
1737
|
+
}
|
|
1738
|
+
else if (this.view === 'month') {
|
|
1739
|
+
this.currYear--;
|
|
1740
|
+
}
|
|
1741
|
+
else {
|
|
1742
|
+
this.currMonth--;
|
|
1743
|
+
}
|
|
1744
|
+
if (this.currMonth < 0 || this.currMonth > 11) {
|
|
1745
|
+
let date = new Date(this.currYear, this.currMonth);
|
|
1746
|
+
this.currYear = date.getFullYear();
|
|
1747
|
+
this.currMonth = date.getMonth();
|
|
1748
|
+
}
|
|
1749
|
+
this.renderCalendar(this.view);
|
|
1750
|
+
}
|
|
1751
|
+
selectDay(ev, item) {
|
|
1752
|
+
ev.stopPropagation();
|
|
1753
|
+
if (item.active) {
|
|
1754
|
+
this.selected = {
|
|
1755
|
+
locale: this._locale,
|
|
1756
|
+
year: this.currYear,
|
|
1757
|
+
month: this.currMonth,
|
|
1758
|
+
day: item.day,
|
|
1759
|
+
date: item.date,
|
|
1760
|
+
};
|
|
1761
|
+
this.change.emit(this.selected.date);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
selectMonth(ev, item) {
|
|
1765
|
+
ev.stopPropagation();
|
|
1766
|
+
if (item.active) {
|
|
1767
|
+
this.currMonth = item.month;
|
|
1768
|
+
this.changeView('day');
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
selectYear(ev, item) {
|
|
1772
|
+
ev.stopPropagation();
|
|
1773
|
+
if (item.active) {
|
|
1774
|
+
this.currYear = item.year;
|
|
1775
|
+
this.changeView('month');
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
clear() {
|
|
1779
|
+
this.selected = undefined;
|
|
1780
|
+
this.change.emit(null);
|
|
1781
|
+
}
|
|
1782
|
+
stopPagination(ev) {
|
|
1783
|
+
ev.stopPropagation();
|
|
1784
|
+
}
|
|
1785
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1786
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxInputDatePickerComponent, isStandalone: true, selector: "ngx-datepicker", inputs: { setTheme: ["theme", "setTheme"], setConfig: ["config", "setConfig"], locale: "locale", setMin: ["min", "setMin"], setMax: ["max", "setMax"], view: "view" }, outputs: { change: "change" }, host: { properties: { "class.dark": "theme==\"dark\"" } }, providers: [
|
|
1787
|
+
DateAdapterRegistry,
|
|
1788
|
+
{
|
|
1789
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1790
|
+
useExisting: forwardRef(() => NgxInputDatePickerComponent),
|
|
1791
|
+
multi: true,
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
provide: NG_VALIDATORS,
|
|
1795
|
+
useExisting: forwardRef(() => NgxInputDatePickerComponent),
|
|
1796
|
+
multi: true,
|
|
1797
|
+
},
|
|
1798
|
+
], usesInheritance: true, ngImport: i0, template: "<div\n class=\"wrapper\"\n #datepickerWrapper\n [style.width.px]=\"wrapperWidth\"\n (click)=\"stopPagination($event)\">\n <div class=\"header\">\n {{ calendarHeader }}\n </div>\n <div class=\"sub-header\">\n <div class=\"icons\">\n <span id=\"prev\" class=\"material-symbols-rounded\" (click)=\"previous()\">\n <ng-template\n [ngTemplateOutlet]=\"\n config.previousButtonTemplate || defaultPreviousBTNTemplate\n \"></ng-template>\n </span>\n </div>\n <span class=\"current-date\">\n <span (click)=\"changeView('year')\">\n {{ currYear }}\n <ng-template\n [ngTemplateOutlet]=\"config.caretDownIconTemplate || defaultCaretDownIcon\"></ng-template>\n </span>\n <span (click)=\"changeView('month')\">\n {{ displayMonth }}\n <ng-template\n [ngTemplateOutlet]=\"config.caretDownIconTemplate || defaultCaretDownIcon\"></ng-template>\n </span>\n </span>\n <div class=\"icons\">\n <span id=\"next\" class=\"material-symbols-rounded\" (click)=\"next()\">\n <ng-template\n [ngTemplateOutlet]=\"config.nextButtonTemplate || defaultNextBTNTemplate\"></ng-template>\n </span>\n </div>\n </div>\n <div class=\"calendar\">\n @if (view === 'day') {\n <ul class=\"weeks\">\n @for (w of weekDays; track $index) {\n <li [title]=\"w.name\">\n {{ w.min }}\n </li>\n }\n </ul>\n <ul class=\"days\">\n @for (item of viewDays; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectDay($event, item)\">\n {{ item.day }}\n </li>\n }\n </ul>\n } @else if (view === 'month') {\n <ul class=\"months\">\n @for (item of viewMonths; track $index; let i = $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectMonth($event, item)\">\n {{ i + 1 }}.{{ item.displayMonth }}\n </li>\n }\n </ul>\n } @else if (view === 'year') {\n <ul class=\"years\">\n @for (item of viewYears; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectYear($event, item)\">\n {{ item.year }}\n </li>\n }\n </ul>\n }\n <!-- <pre>\n currYear={{currYear}}\n currMonth={{currMonth}}\n {{selected|json}}\n </pre> -->\n <div class=\"calendar-footer\">\n @if (config.clearButton) {\n <button class=\"today dtp-btn\" (click)=\"clear()\">\n {{ config.clearButtonText }}\n </button>\n }\n @if (config.todayButton) {\n <button class=\"today dtp-btn\" (click)=\"gotoToday()\">\n {{ config.todayButtonText }}\n </button>\n }\n </div>\n </div>\n</div>\n\n<ng-template #defaultPreviousBTNTemplate>\n <svg width=\"15px\" height=\"40px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M224 480c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25l192-192c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L77.25 256l169.4 169.4c12.5 12.5 12.5 32.75 0 45.25C240.4 476.9 232.2 480 224 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultNextBTNTemplate>\n <svg width=\"15px\" height=\"40px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultCaretDownIcon>\n <svg width=\"10px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z\" />\n </svg>\n</ng-template>\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000;--ngx-border-color: #c0c0c0;--ngx-datepicker-header-bg: #6200ee;--ngx-datepicker-header-text: #fff;--ngx-datepicker-subheader-bg: #e0d5ef;--ngx-datepicker-subheader-text: #272727}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff;--ngx-border-color: #c0c0c0;--ngx-datepicker-header-bg: #6200ee;--ngx-datepicker-header-text: #fff;--ngx-datepicker-subheader-bg: #8e819e;--ngx-datepicker-subheader-text: #272727}.wrapper{background:var(--ngx-color-bg);box-shadow:0 15px 40px #0000001f;color:var(--ngx-color-text);border-radius:6px;overflow:hidden}.wrapper .header{display:block;padding:15px 15px 10px;background-color:var(--ngx-datepicker-header-bg);color:var(--ngx-datepicker-header-text);font-size:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.wrapper .sub-header{display:flex;align-items:center;padding:5px 10px;background-color:var(--ngx-datepicker-subheader-bg);color:var(--ngx-datepicker-subheader-text)}.wrapper .sub-header .current-date{font-size:1rem;font-weight:800;flex:auto;display:flex;align-items:center}.wrapper .sub-header .current-date span{flex:auto;text-align:center}.wrapper .sub-header .icons{display:flex}.wrapper .sub-header .icons span{height:38px;width:38px;margin:0 1px;cursor:pointer;color:#878787;text-align:center;line-height:38px;font-size:1.9rem;-webkit-user-select:none;user-select:none;border-radius:50%}.wrapper .sub-header .icons span:hover{background:#f2f2f272}.wrapper .calendar-footer{display:flex;justify-content:space-between;gap:5px}.wrapper .calendar-footer .dtp-btn{background:none;color:inherit;border:1px rgba(159,159,159,.5450980392) solid;border-radius:3px;padding:3px 15px;box-shadow:0 0 4px #0003;transition:all .3s}.wrapper .calendar-footer .dtp-btn:not([disabled]):hover{cursor:pointer;background:#87879e}.calendar{padding:10px}.calendar ul{display:flex;flex-wrap:wrap;list-style:none;text-align:center;padding:0;margin:0}.calendar .days{margin-bottom:20px}.calendar .days li{height:40px;width:40px}.calendar .months{margin-bottom:20px}.calendar .months li{height:40px;width:33%}.calendar .years{margin-bottom:20px}.calendar .years li{height:40px;width:25%}.calendar li{z-index:1;cursor:pointer;position:relative;color:#333;font-size:12px;border-radius:50px;display:flex;align-items:center;justify-content:center;border:1px transparent solid;transition:all .3s;color:inherit}.calendar li:not(.active):hover{background:#dfdfdf68}.calendar li.de-active{opacity:.2}.calendar li.selected{border:1px #1216fa solid}.calendar li.today{background-color:#9b59b6}.calendar .weeks{border-bottom:1px rgba(231,231,231,.3450980392) solid;margin-bottom:10px;padding-bottom:5px}.calendar .weeks li{font-weight:500;cursor:default;flex:auto;flex-wrap:nowrap}.calendar .weeks li:hover{background:none}::ng-deep body[dir=rtl] .wrapper .sub-header .icons #next,::ng-deep body[dir=rtl] .wrapper .sub-header .icons #prev,::ng-deep html[dir=rtl] .wrapper .sub-header .icons #next,::ng-deep html[dir=rtl] .wrapper .sub-header .icons #prev{transform:rotate(180deg)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
1799
|
+
}
|
|
1800
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputDatePickerComponent, decorators: [{
|
|
1801
|
+
type: Component,
|
|
1802
|
+
args: [{ selector: 'ngx-datepicker', imports: [CommonModule], providers: [
|
|
1803
|
+
DateAdapterRegistry,
|
|
1804
|
+
{
|
|
1805
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1806
|
+
useExisting: forwardRef(() => NgxInputDatePickerComponent),
|
|
1807
|
+
multi: true,
|
|
1808
|
+
},
|
|
1809
|
+
{
|
|
1810
|
+
provide: NG_VALIDATORS,
|
|
1811
|
+
useExisting: forwardRef(() => NgxInputDatePickerComponent),
|
|
1812
|
+
multi: true,
|
|
1813
|
+
},
|
|
1814
|
+
], host: {
|
|
1815
|
+
'[class.dark]': 'theme=="dark"',
|
|
1816
|
+
}, template: "<div\n class=\"wrapper\"\n #datepickerWrapper\n [style.width.px]=\"wrapperWidth\"\n (click)=\"stopPagination($event)\">\n <div class=\"header\">\n {{ calendarHeader }}\n </div>\n <div class=\"sub-header\">\n <div class=\"icons\">\n <span id=\"prev\" class=\"material-symbols-rounded\" (click)=\"previous()\">\n <ng-template\n [ngTemplateOutlet]=\"\n config.previousButtonTemplate || defaultPreviousBTNTemplate\n \"></ng-template>\n </span>\n </div>\n <span class=\"current-date\">\n <span (click)=\"changeView('year')\">\n {{ currYear }}\n <ng-template\n [ngTemplateOutlet]=\"config.caretDownIconTemplate || defaultCaretDownIcon\"></ng-template>\n </span>\n <span (click)=\"changeView('month')\">\n {{ displayMonth }}\n <ng-template\n [ngTemplateOutlet]=\"config.caretDownIconTemplate || defaultCaretDownIcon\"></ng-template>\n </span>\n </span>\n <div class=\"icons\">\n <span id=\"next\" class=\"material-symbols-rounded\" (click)=\"next()\">\n <ng-template\n [ngTemplateOutlet]=\"config.nextButtonTemplate || defaultNextBTNTemplate\"></ng-template>\n </span>\n </div>\n </div>\n <div class=\"calendar\">\n @if (view === 'day') {\n <ul class=\"weeks\">\n @for (w of weekDays; track $index) {\n <li [title]=\"w.name\">\n {{ w.min }}\n </li>\n }\n </ul>\n <ul class=\"days\">\n @for (item of viewDays; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectDay($event, item)\">\n {{ item.day }}\n </li>\n }\n </ul>\n } @else if (view === 'month') {\n <ul class=\"months\">\n @for (item of viewMonths; track $index; let i = $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectMonth($event, item)\">\n {{ i + 1 }}.{{ item.displayMonth }}\n </li>\n }\n </ul>\n } @else if (view === 'year') {\n <ul class=\"years\">\n @for (item of viewYears; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectYear($event, item)\">\n {{ item.year }}\n </li>\n }\n </ul>\n }\n <!-- <pre>\n currYear={{currYear}}\n currMonth={{currMonth}}\n {{selected|json}}\n </pre> -->\n <div class=\"calendar-footer\">\n @if (config.clearButton) {\n <button class=\"today dtp-btn\" (click)=\"clear()\">\n {{ config.clearButtonText }}\n </button>\n }\n @if (config.todayButton) {\n <button class=\"today dtp-btn\" (click)=\"gotoToday()\">\n {{ config.todayButtonText }}\n </button>\n }\n </div>\n </div>\n</div>\n\n<ng-template #defaultPreviousBTNTemplate>\n <svg width=\"15px\" height=\"40px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M224 480c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25l192-192c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L77.25 256l169.4 169.4c12.5 12.5 12.5 32.75 0 45.25C240.4 476.9 232.2 480 224 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultNextBTNTemplate>\n <svg width=\"15px\" height=\"40px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultCaretDownIcon>\n <svg width=\"10px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z\" />\n </svg>\n</ng-template>\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000;--ngx-border-color: #c0c0c0;--ngx-datepicker-header-bg: #6200ee;--ngx-datepicker-header-text: #fff;--ngx-datepicker-subheader-bg: #e0d5ef;--ngx-datepicker-subheader-text: #272727}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff;--ngx-border-color: #c0c0c0;--ngx-datepicker-header-bg: #6200ee;--ngx-datepicker-header-text: #fff;--ngx-datepicker-subheader-bg: #8e819e;--ngx-datepicker-subheader-text: #272727}.wrapper{background:var(--ngx-color-bg);box-shadow:0 15px 40px #0000001f;color:var(--ngx-color-text);border-radius:6px;overflow:hidden}.wrapper .header{display:block;padding:15px 15px 10px;background-color:var(--ngx-datepicker-header-bg);color:var(--ngx-datepicker-header-text);font-size:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center}.wrapper .sub-header{display:flex;align-items:center;padding:5px 10px;background-color:var(--ngx-datepicker-subheader-bg);color:var(--ngx-datepicker-subheader-text)}.wrapper .sub-header .current-date{font-size:1rem;font-weight:800;flex:auto;display:flex;align-items:center}.wrapper .sub-header .current-date span{flex:auto;text-align:center}.wrapper .sub-header .icons{display:flex}.wrapper .sub-header .icons span{height:38px;width:38px;margin:0 1px;cursor:pointer;color:#878787;text-align:center;line-height:38px;font-size:1.9rem;-webkit-user-select:none;user-select:none;border-radius:50%}.wrapper .sub-header .icons span:hover{background:#f2f2f272}.wrapper .calendar-footer{display:flex;justify-content:space-between;gap:5px}.wrapper .calendar-footer .dtp-btn{background:none;color:inherit;border:1px rgba(159,159,159,.5450980392) solid;border-radius:3px;padding:3px 15px;box-shadow:0 0 4px #0003;transition:all .3s}.wrapper .calendar-footer .dtp-btn:not([disabled]):hover{cursor:pointer;background:#87879e}.calendar{padding:10px}.calendar ul{display:flex;flex-wrap:wrap;list-style:none;text-align:center;padding:0;margin:0}.calendar .days{margin-bottom:20px}.calendar .days li{height:40px;width:40px}.calendar .months{margin-bottom:20px}.calendar .months li{height:40px;width:33%}.calendar .years{margin-bottom:20px}.calendar .years li{height:40px;width:25%}.calendar li{z-index:1;cursor:pointer;position:relative;color:#333;font-size:12px;border-radius:50px;display:flex;align-items:center;justify-content:center;border:1px transparent solid;transition:all .3s;color:inherit}.calendar li:not(.active):hover{background:#dfdfdf68}.calendar li.de-active{opacity:.2}.calendar li.selected{border:1px #1216fa solid}.calendar li.today{background-color:#9b59b6}.calendar .weeks{border-bottom:1px rgba(231,231,231,.3450980392) solid;margin-bottom:10px;padding-bottom:5px}.calendar .weeks li{font-weight:500;cursor:default;flex:auto;flex-wrap:nowrap}.calendar .weeks li:hover{background:none}::ng-deep body[dir=rtl] .wrapper .sub-header .icons #next,::ng-deep body[dir=rtl] .wrapper .sub-header .icons #prev,::ng-deep html[dir=rtl] .wrapper .sub-header .icons #next,::ng-deep html[dir=rtl] .wrapper .sub-header .icons #prev{transform:rotate(180deg)}\n"] }]
|
|
1817
|
+
}], ctorParameters: () => [], propDecorators: { setTheme: [{
|
|
1818
|
+
type: Input,
|
|
1819
|
+
args: ['theme']
|
|
1820
|
+
}], setConfig: [{
|
|
1821
|
+
type: Input,
|
|
1822
|
+
args: ['config']
|
|
1823
|
+
}], locale: [{
|
|
1824
|
+
type: Input
|
|
1825
|
+
}], setMin: [{
|
|
1826
|
+
type: Input,
|
|
1827
|
+
args: ['min']
|
|
1828
|
+
}], setMax: [{
|
|
1829
|
+
type: Input,
|
|
1830
|
+
args: ['max']
|
|
1831
|
+
}], view: [{
|
|
1832
|
+
type: Input
|
|
1833
|
+
}], change: [{
|
|
1834
|
+
type: Output
|
|
1835
|
+
}] } });
|
|
1836
|
+
|
|
1837
|
+
class NgxInputDatePicker {
|
|
1838
|
+
el;
|
|
1839
|
+
dateAdapterRegistry = inject(DateAdapterRegistry);
|
|
1840
|
+
theme = 'auto';
|
|
1841
|
+
openOnCLick = input(true, /* @ts-ignore */
|
|
1842
|
+
...(ngDevMode ? [{ debugName: "openOnCLick" }] : /* istanbul ignore next */ []));
|
|
1843
|
+
change = new EventEmitter();
|
|
1844
|
+
value;
|
|
1845
|
+
pickerRef;
|
|
1846
|
+
adapter;
|
|
1847
|
+
_locale = 'en';
|
|
1848
|
+
set locale(val) {
|
|
1849
|
+
this._locale = val;
|
|
1850
|
+
this.adapter = this.dateAdapterRegistry.resolve(this._locale);
|
|
1851
|
+
}
|
|
1852
|
+
_onChange = (value) => { };
|
|
1853
|
+
_onTouched = () => { };
|
|
1854
|
+
_validatorOnChange = () => { };
|
|
1855
|
+
/**
|
|
1856
|
+
* display format in input
|
|
1857
|
+
*/
|
|
1858
|
+
displayFormat = 'yyyy/MM/dd';
|
|
1859
|
+
min = null;
|
|
1860
|
+
/** The minimum valid date. */
|
|
1861
|
+
set setMin(value) {
|
|
1862
|
+
const validValue = deserialize(value);
|
|
1863
|
+
if (!sameDate(validValue, this.min)) {
|
|
1864
|
+
this.min = validValue;
|
|
1865
|
+
this._validatorOnChange();
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
max = null;
|
|
1869
|
+
/** The maximum valid date. */
|
|
1870
|
+
set setMax(value) {
|
|
1871
|
+
const validValue = deserialize(value);
|
|
1872
|
+
if (!sameDate(validValue, this.max)) {
|
|
1873
|
+
this.max = validValue;
|
|
1874
|
+
this._validatorOnChange();
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
config = new NgxDatePickerConfig();
|
|
1878
|
+
set setConfig(val) {
|
|
1879
|
+
this.config = { ...new NgxDatePickerConfig(), ...val };
|
|
1880
|
+
}
|
|
1881
|
+
isDisabled = false;
|
|
1882
|
+
overlayService = inject(OverlayService);
|
|
1883
|
+
viewContainerRef = inject(ViewContainerRef);
|
|
1884
|
+
renderer = inject(Renderer2);
|
|
1885
|
+
constructor(el) {
|
|
1886
|
+
this.el = el;
|
|
1887
|
+
}
|
|
1888
|
+
updateConfig(val) {
|
|
1889
|
+
this.config = { ...new NgxDatePickerConfig(), ...val };
|
|
1890
|
+
if (this.pickerRef && this.pickerRef.componentRef) {
|
|
1891
|
+
this.pickerRef.componentRef.instance.updateConfig(this.config);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
ngOnDestroy() {
|
|
1895
|
+
this.destroyDatePicker();
|
|
1896
|
+
}
|
|
1897
|
+
onClick(ev) {
|
|
1898
|
+
if (this.openOnCLick() && !this.isDisabled) {
|
|
1899
|
+
ev.stopPropagation();
|
|
1900
|
+
ev.preventDefault();
|
|
1901
|
+
this.toggle();
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
onInput(event) {
|
|
1905
|
+
const input = event.target;
|
|
1906
|
+
const validValue = deserialize(input.value);
|
|
1907
|
+
this.value = validValue;
|
|
1908
|
+
this._formatValue(this.value);
|
|
1909
|
+
this._onChange(this.value);
|
|
1910
|
+
}
|
|
1911
|
+
onBlur() {
|
|
1912
|
+
this._onTouched();
|
|
1913
|
+
}
|
|
1914
|
+
writeValue(value) {
|
|
1915
|
+
const validValue = deserialize(value);
|
|
1916
|
+
this.value = validValue;
|
|
1917
|
+
this._formatValue(this.value);
|
|
1918
|
+
}
|
|
1919
|
+
registerOnChange(fn) {
|
|
1920
|
+
this._onChange = fn;
|
|
1921
|
+
}
|
|
1922
|
+
registerOnTouched(fn) {
|
|
1923
|
+
this._onTouched = fn;
|
|
1924
|
+
}
|
|
1925
|
+
registerOnValidatorChange(fn) {
|
|
1926
|
+
this._validatorOnChange = fn;
|
|
1927
|
+
}
|
|
1928
|
+
setDisabledState(disabled) {
|
|
1929
|
+
this.isDisabled = disabled;
|
|
1930
|
+
if (disabled) {
|
|
1931
|
+
this.renderer.setProperty(this.el.nativeElement, 'disabled', disabled);
|
|
1932
|
+
}
|
|
1933
|
+
else {
|
|
1934
|
+
this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
toggle() {
|
|
1938
|
+
if (this.pickerRef || this.isDisabled) {
|
|
1939
|
+
this.destroyDatePicker();
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
this.pickerRef = this.overlayService.open({
|
|
1943
|
+
anchor: this.el.nativeElement,
|
|
1944
|
+
component: NgxInputDatePickerComponent,
|
|
1945
|
+
viewContainerRef: this.viewContainerRef,
|
|
1946
|
+
alignment: 'center',
|
|
1947
|
+
placement: 'bottom',
|
|
1948
|
+
margin: 2,
|
|
1949
|
+
configure: (instance, ref) => {
|
|
1950
|
+
instance.locale = this._locale;
|
|
1951
|
+
instance.minDate = this.min;
|
|
1952
|
+
instance.maxDate = this.max;
|
|
1953
|
+
instance.setTheme = this.theme;
|
|
1954
|
+
instance.updateConfig(this.config);
|
|
1955
|
+
instance.writeValue(this.value);
|
|
1956
|
+
instance.change.subscribe((c) => {
|
|
1957
|
+
this.value = c;
|
|
1958
|
+
this.emitChange(c);
|
|
1959
|
+
this.destroyDatePicker();
|
|
1960
|
+
});
|
|
1961
|
+
// instance.closed.subscribe(() => ref.close());
|
|
1962
|
+
},
|
|
1963
|
+
onClosed: () => {
|
|
1964
|
+
this.pickerRef = undefined;
|
|
1965
|
+
},
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
destroyDatePicker() {
|
|
1969
|
+
this.pickerRef?.close();
|
|
1970
|
+
this.pickerRef = undefined;
|
|
1971
|
+
}
|
|
1972
|
+
async emitChange(c) {
|
|
1973
|
+
this._formatValue(c);
|
|
1974
|
+
this._onChange(c);
|
|
1975
|
+
this.change.emit(c);
|
|
1976
|
+
this._onTouched();
|
|
1977
|
+
}
|
|
1978
|
+
validate(control) {
|
|
1979
|
+
if (this.value) {
|
|
1980
|
+
if (!isValid(this.value)) {
|
|
1981
|
+
return {
|
|
1982
|
+
invalid: true,
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
let c = clampDate(this.value, this.min, this.max);
|
|
1986
|
+
if (c < 0) {
|
|
1987
|
+
return {
|
|
1988
|
+
invalid: true,
|
|
1989
|
+
min: this.min,
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
else if (c > 0) {
|
|
1993
|
+
return {
|
|
1994
|
+
invalid: true,
|
|
1995
|
+
max: this.max,
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
return null;
|
|
2000
|
+
}
|
|
2001
|
+
/** Formats a value and sets it on the input element. */
|
|
2002
|
+
_formatValue(value, setChange = false) {
|
|
2003
|
+
let val = '';
|
|
2004
|
+
if (value && this.adapter) {
|
|
2005
|
+
let o = this.adapter.toLocale(value);
|
|
2006
|
+
val = (value && this.adapter.formatDate(o, this.displayFormat)) ?? '';
|
|
2007
|
+
}
|
|
2008
|
+
this.renderer.setProperty(this.el.nativeElement, 'value', val);
|
|
2009
|
+
if (setChange) {
|
|
2010
|
+
this._onChange(this.value);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputDatePicker, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
2014
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxInputDatePicker, isStandalone: true, selector: "[ngxInputDatePicker]", inputs: { theme: { classPropertyName: "theme", publicName: "theme", isSignal: false, isRequired: false, transformFunction: null }, openOnCLick: { classPropertyName: "openOnCLick", publicName: "openOnCLick", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: false, isRequired: false, transformFunction: null }, displayFormat: { classPropertyName: "displayFormat", publicName: "displayFormat", isSignal: false, isRequired: false, transformFunction: null }, setMin: { classPropertyName: "setMin", publicName: "min", isSignal: false, isRequired: false, transformFunction: null }, setMax: { classPropertyName: "setMax", publicName: "max", isSignal: false, isRequired: false, transformFunction: null }, setConfig: { classPropertyName: "setConfig", publicName: "config", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { change: "change" }, host: { listeners: { "click": "onClick($event)", "input": "onInput($event)", "blur": "onBlur()" }, properties: { "attr.readOnly": "true" }, classAttribute: "ngx-datepicker-input" }, providers: [
|
|
2015
|
+
DateAdapterRegistry,
|
|
2016
|
+
{
|
|
2017
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2018
|
+
useExisting: forwardRef(() => NgxInputDatePicker),
|
|
2019
|
+
multi: true,
|
|
2020
|
+
},
|
|
2021
|
+
{
|
|
2022
|
+
provide: NG_VALIDATORS,
|
|
2023
|
+
useExisting: forwardRef(() => NgxInputDatePicker),
|
|
2024
|
+
multi: true,
|
|
2025
|
+
},
|
|
2026
|
+
], exportAs: ["ngxInputDatePicker"], ngImport: i0 });
|
|
2027
|
+
}
|
|
2028
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputDatePicker, decorators: [{
|
|
2029
|
+
type: Directive,
|
|
2030
|
+
args: [{
|
|
2031
|
+
selector: '[ngxInputDatePicker]',
|
|
2032
|
+
exportAs: 'ngxInputDatePicker',
|
|
2033
|
+
host: {
|
|
2034
|
+
class: 'ngx-datepicker-input',
|
|
2035
|
+
'[attr.readOnly]': 'true',
|
|
2036
|
+
},
|
|
2037
|
+
providers: [
|
|
2038
|
+
DateAdapterRegistry,
|
|
2039
|
+
{
|
|
2040
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2041
|
+
useExisting: forwardRef(() => NgxInputDatePicker),
|
|
2042
|
+
multi: true,
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
provide: NG_VALIDATORS,
|
|
2046
|
+
useExisting: forwardRef(() => NgxInputDatePicker),
|
|
2047
|
+
multi: true,
|
|
2048
|
+
},
|
|
2049
|
+
],
|
|
2050
|
+
}]
|
|
2051
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { theme: [{
|
|
2052
|
+
type: Input
|
|
2053
|
+
}], openOnCLick: [{ type: i0.Input, args: [{ isSignal: true, alias: "openOnCLick", required: false }] }], change: [{
|
|
2054
|
+
type: Output
|
|
2055
|
+
}], locale: [{
|
|
2056
|
+
type: Input
|
|
2057
|
+
}], displayFormat: [{
|
|
2058
|
+
type: Input
|
|
2059
|
+
}], setMin: [{
|
|
2060
|
+
type: Input,
|
|
2061
|
+
args: ['min']
|
|
2062
|
+
}], setMax: [{
|
|
2063
|
+
type: Input,
|
|
2064
|
+
args: ['max']
|
|
2065
|
+
}], setConfig: [{
|
|
2066
|
+
type: Input,
|
|
2067
|
+
args: ['config']
|
|
2068
|
+
}], onClick: [{
|
|
2069
|
+
type: HostListener,
|
|
2070
|
+
args: ['click', ['$event']]
|
|
2071
|
+
}], onInput: [{
|
|
2072
|
+
type: HostListener,
|
|
2073
|
+
args: ['input', ['$event']]
|
|
2074
|
+
}], onBlur: [{
|
|
2075
|
+
type: HostListener,
|
|
2076
|
+
args: ['blur']
|
|
2077
|
+
}] } });
|
|
2078
|
+
|
|
2079
|
+
class NgxCalendarComponent extends NgxDatePickerBase {
|
|
2080
|
+
browserService = inject(BrowserService);
|
|
2081
|
+
theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
|
|
2082
|
+
set setTheme(val) {
|
|
2083
|
+
if (!val || val == 'auto') {
|
|
2084
|
+
this.theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
|
|
2085
|
+
}
|
|
2086
|
+
else {
|
|
2087
|
+
this.theme = val;
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
_config = new NgxDatePickerConfig();
|
|
2091
|
+
set config(val) {
|
|
2092
|
+
this._config = { ...new NgxDatePickerConfig(), ...val };
|
|
2093
|
+
}
|
|
2094
|
+
set locale(val) {
|
|
2095
|
+
this._locale = val;
|
|
2096
|
+
this.adapter = this.dateAdapterRegistry.resolve(this._locale);
|
|
2097
|
+
this.ngOnInit();
|
|
2098
|
+
}
|
|
2099
|
+
/** The minimum valid date. */
|
|
2100
|
+
set setMin(value) {
|
|
2101
|
+
const validValue = deserialize(value);
|
|
2102
|
+
if (!sameDate(validValue, this.minDate)) {
|
|
2103
|
+
this.minDate = validValue;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
/** The maximum valid date. */
|
|
2107
|
+
set setMax(value) {
|
|
2108
|
+
const validValue = deserialize(value);
|
|
2109
|
+
if (!sameDate(validValue, this.maxDate)) {
|
|
2110
|
+
this.maxDate = validValue;
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
view = 'day';
|
|
2114
|
+
_events = [];
|
|
2115
|
+
set events(val) {
|
|
2116
|
+
if (val && Array.isArray(val)) {
|
|
2117
|
+
this._events = val;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
dateChange = new EventEmitter();
|
|
2121
|
+
selectEvent = new EventEmitter();
|
|
2122
|
+
defaultHeight = 600;
|
|
2123
|
+
minHeight = this.defaultHeight;
|
|
2124
|
+
selected;
|
|
2125
|
+
calendarWrapper = viewChild('calendarWrapper', /* @ts-ignore */
|
|
2126
|
+
...(ngDevMode ? [{ debugName: "calendarWrapper" }] : /* istanbul ignore next */ []));
|
|
2127
|
+
constructor() {
|
|
2128
|
+
super();
|
|
2129
|
+
}
|
|
2130
|
+
ngOnInit() {
|
|
2131
|
+
this.months = this.adapter.longMonths;
|
|
2132
|
+
this.weeks = this.adapter.longDays;
|
|
2133
|
+
if (this.selected) {
|
|
2134
|
+
let converted = this.adapter.toLocale(this.selected);
|
|
2135
|
+
this.currYear = converted.year;
|
|
2136
|
+
this.currMonth = converted.month;
|
|
2137
|
+
this.renderCalendar(this.view);
|
|
2138
|
+
}
|
|
2139
|
+
else {
|
|
2140
|
+
this.gotoToday();
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
ngAfterViewInit() {
|
|
2144
|
+
this.calcCellSize();
|
|
2145
|
+
}
|
|
2146
|
+
onResize(ev) {
|
|
2147
|
+
this.calcCellSize();
|
|
2148
|
+
}
|
|
2149
|
+
calcCellSize() {
|
|
2150
|
+
const fullWidth = this.calendarWrapper()?.nativeElement?.clientWidth ?? 0;
|
|
2151
|
+
const cellHeight = fullWidth / 6;
|
|
2152
|
+
this.minHeight = fullWidth > this.defaultHeight ? this.defaultHeight : fullWidth;
|
|
2153
|
+
if (fullWidth <= 500) {
|
|
2154
|
+
this.weeks = this.adapter.shortDays;
|
|
2155
|
+
}
|
|
2156
|
+
else if (fullWidth > 500) {
|
|
2157
|
+
this.weeks = this.adapter.longDays;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
renderCalendar(view) {
|
|
2161
|
+
// console.log('_events', this._events);
|
|
2162
|
+
super.renderCalendar(view, undefined, this._events, () => { });
|
|
2163
|
+
}
|
|
2164
|
+
changeView(v) {
|
|
2165
|
+
this.view = v;
|
|
2166
|
+
this.renderCalendar(this.view);
|
|
2167
|
+
}
|
|
2168
|
+
gotoToday() {
|
|
2169
|
+
let today = this.adapter.today();
|
|
2170
|
+
this.selected = this.adapter.getDate(today);
|
|
2171
|
+
this.currYear = today.year;
|
|
2172
|
+
this.currMonth = today.month ?? 1;
|
|
2173
|
+
this.changeView(this.view);
|
|
2174
|
+
}
|
|
2175
|
+
selectDay(ev, item) {
|
|
2176
|
+
ev.stopPropagation();
|
|
2177
|
+
if (item.active) {
|
|
2178
|
+
this.dateChange.emit(item);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
selectMonth(ev, item) {
|
|
2182
|
+
ev.stopPropagation();
|
|
2183
|
+
if (item.active) {
|
|
2184
|
+
this.currMonth = item.month;
|
|
2185
|
+
this.changeView('day');
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
selectYear(ev, item) {
|
|
2189
|
+
ev.stopPropagation();
|
|
2190
|
+
if (item.active) {
|
|
2191
|
+
this.currYear = item.year;
|
|
2192
|
+
this.changeView('month');
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
next() {
|
|
2196
|
+
if (this.view === 'month' || this.view == 'event') {
|
|
2197
|
+
this.currMonth++;
|
|
2198
|
+
}
|
|
2199
|
+
else if (this.view == 'day' || this.view == 'week') {
|
|
2200
|
+
this.currentWeek++;
|
|
2201
|
+
}
|
|
2202
|
+
if (this.currMonth < 0 || this.currMonth > 11) {
|
|
2203
|
+
let date = new Date(this.currYear, this.currMonth);
|
|
2204
|
+
this.currYear = date.getFullYear();
|
|
2205
|
+
this.currMonth = date.getMonth();
|
|
2206
|
+
}
|
|
2207
|
+
this.renderCalendar(this.view);
|
|
2208
|
+
}
|
|
2209
|
+
previous() {
|
|
2210
|
+
if (this.view === 'month' || this.view == 'event') {
|
|
2211
|
+
this.currMonth--;
|
|
2212
|
+
}
|
|
2213
|
+
else if (this.view == 'day' || this.view == 'week') {
|
|
2214
|
+
this.currentWeek--;
|
|
2215
|
+
}
|
|
2216
|
+
if (this.currMonth < 0 || this.currMonth > 11) {
|
|
2217
|
+
let date = new Date(this.currYear, this.currMonth);
|
|
2218
|
+
this.currYear = date.getFullYear();
|
|
2219
|
+
this.currMonth = date.getMonth();
|
|
2220
|
+
}
|
|
2221
|
+
this.renderCalendar(this.view);
|
|
2222
|
+
}
|
|
2223
|
+
onclickEvent(item, event) {
|
|
2224
|
+
this.selectEvent.emit({
|
|
2225
|
+
date: item.date,
|
|
2226
|
+
event: event,
|
|
2227
|
+
});
|
|
2228
|
+
}
|
|
2229
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2230
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxCalendarComponent, isStandalone: true, selector: "ngx-calendar", inputs: { setTheme: ["theme", "setTheme"], config: "config", locale: "locale", setMin: ["min", "setMin"], setMax: ["max", "setMax"], view: "view", events: "events" }, outputs: { dateChange: "dateChange", selectEvent: "selectEvent" }, host: { listeners: { "window:resize": "onResize($event)" }, properties: { "class.dark": "theme==\"dark\"" } }, providers: [DateAdapterRegistry], viewQueries: [{ propertyName: "calendarWrapper", first: true, predicate: ["calendarWrapper"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"wrapper\" #datepickerWrapper>\n <div class=\"header\">\n <div class=\"nxt-prv-buttons\">\n <button id=\"prev\" class=\"previous dtp-btn\" (click)=\"previous()\" title=\"Previous\">\n <ng-template\n [ngTemplateOutlet]=\"\n _config.previousButtonTemplate || defaultPreviousBTNTemplate\n \"></ng-template>\n </button>\n @if (_config.todayButton) {\n <button class=\"today dtp-btn\" (click)=\"gotoToday()\">\n {{ _config.todayButtonText }}\n </button>\n }\n <button id=\"next\" class=\"next dtp-btn\" (click)=\"next()\" title=\"Next\">\n <ng-template\n [ngTemplateOutlet]=\"_config.nextButtonTemplate || defaultNextBTNTemplate\"></ng-template>\n </button>\n </div>\n <div class=\"current-date\">\n <span>\n {{ currYear }}\n </span>\n <span>\n {{ displayMonth }}\n </span>\n </div>\n <div class=\"view-mode\">\n {{ view }}\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('day')\"\n [class.active]=\"view == 'day'\"\n title=\"Month View\">\n Month\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('week')\"\n [class.active]=\"view == 'week'\"\n title=\"Week View\">\n Week\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('day')\"\n [class.active]=\"view == 'day'\"\n title=\"Day View\">\n Day\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('event')\"\n [class.active]=\"view == 'event'\"\n title=\"Day View\">\n Event\n </button>\n </div>\n </div>\n <div class=\"calendar\" #calendarWrapper>\n @if (view === 'day') {\n <ul class=\"weeks\">\n @for (w of weeks; track $index) {\n <li>\n {{ w }}\n </li>\n }\n </ul>\n <ul class=\"days\" [style.minHeight.px]=\"minHeight\">\n @for (item of viewDays; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectDay($event, item)\">\n <div>{{ item.day }}</div>\n @if (item.events) {\n <div class=\"ms-day-events\">\n @for (event of item.events; track $index) {\n <a\n tabindex=\"0\"\n class=\"ms-day-event\"\n [title]=\"event.title\"\n (click)=\"onclickEvent(item, event)\">\n {{ event.title }}\n </a>\n }\n </div>\n }\n </li>\n }\n </ul>\n } @else if (view == 'week' || view == 'month') {\n <table>\n <thead>\n <tr>\n <th></th>\n @for (w of weeks; track $index) {\n <th>{{ w }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of viewWeeks; track $index; let i = $index) {\n <tr>\n <td [title]=\"item.displayTime\">{{ item.time % 1 == 0 ? item.time : '' }}</td>\n @for (w of item.weeks; track $index) {\n <td></td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else if (view == 'event') {\n not implemented\n }\n </div>\n</div>\n\n<ng-template #defaultPreviousBTNTemplate>\n <svg width=\"15px\" height=\"30px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M224 480c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25l192-192c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L77.25 256l169.4 169.4c12.5 12.5 12.5 32.75 0 45.25C240.4 476.9 232.2 480 224 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultNextBTNTemplate>\n <svg width=\"15px\" height=\"30px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultCaretDownIcon>\n <svg width=\"10px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z\" />\n </svg>\n</ng-template>\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000;--ngx-border-color: #c0c0c0}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff;--ngx-border-color: #c0c0c0}.wrapper{background-color:var(--ngx-color-bg);color:var(--ngx-color-text);border-radius:5px}.wrapper .dtp-btn{background:none;border:none;color:inherit;border-radius:3px;padding:3px 15px;box-shadow:0 0 4px #0003;transition:all .3s;display:inline-flex;align-items:center}.wrapper .dtp-btn:not([disabled]):hover{cursor:pointer;background:#87879e}.wrapper .dtp-btn.active{background:#87879e}.wrapper .dtp-btn svg{fill:var(--ngx-color-text)}.wrapper .header{display:flex;align-items:center;justify-content:space-between;padding:10px 10px 0}.wrapper .header .current-date{text-align:center;flex:auto}.wrapper .nxt-prv-buttons{display:flex;align-items:center}.wrapper .nxt-prv-buttons .dtp-btn{border-radius:0}.wrapper .nxt-prv-buttons .dtp-btn:first-child{border-radius:5px 0 0 5px}.wrapper .nxt-prv-buttons .dtp-btn:last-child{border-radius:0 5px 5px 0}.calendar{padding:10px}.calendar ul{display:flex;flex-wrap:wrap;list-style:none;padding:0;margin:0;border:1px var(--ngx-border-color) solid;border-bottom:none}.calendar .days{margin-bottom:20px}.calendar .days li{width:14.2857142857%;text-align:end;max-height:300px;overflow:auto}.calendar .months{margin-bottom:20px}.calendar .months li{height:40px;width:33%}.calendar .years{margin-bottom:20px}.calendar .years li{height:40px;width:25%}.calendar li{position:relative;border-right:1px var(--ngx-border-color) solid;border-bottom:1px var(--ngx-border-color) solid;padding:4px}.calendar li.de-active{color:#cbcbcb}.calendar li.selected{border:1px #1216fa solid}.calendar li.today{background-color:#ff9d0130}.calendar .weeks li{cursor:default;width:14.2857142857%;text-align:center;font-weight:700}.calendar .weeks li:hover{background:none}.ms-day-events .ms-day-event{color:#3f51b5;background:var(--ngx-color-bg);border:1px rgba(63,81,181,.1215686275) solid;border-radius:4px;min-height:25px;padding:4px;margin:4px 0;text-decoration:none;display:block}::ng-deep html[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:first-child,::ng-deep body[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:first-child{border-radius:0 5px 5px 0!important}::ng-deep html[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:last-child,::ng-deep body[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:last-child{border-radius:5px 0 0 5px!important}::ng-deep html[dir=rtl] .wrapper .wrapper .dtp-btn.next,::ng-deep html[dir=rtl] .wrapper .wrapper .dtp-btn.previous,::ng-deep body[dir=rtl] .wrapper .wrapper .dtp-btn.next,::ng-deep body[dir=rtl] .wrapper .wrapper .dtp-btn.previous{transform:rotate(180deg)}table{width:100%;border-collapse:collapse}table td,table th{border:1px rgb(158,158,158) solid;padding:5px;height:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
2231
|
+
}
|
|
2232
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxCalendarComponent, decorators: [{
|
|
2233
|
+
type: Component,
|
|
2234
|
+
args: [{ selector: 'ngx-calendar', imports: [CommonModule], providers: [DateAdapterRegistry], host: {
|
|
2235
|
+
'[class.dark]': 'theme=="dark"',
|
|
2236
|
+
}, template: "<div class=\"wrapper\" #datepickerWrapper>\n <div class=\"header\">\n <div class=\"nxt-prv-buttons\">\n <button id=\"prev\" class=\"previous dtp-btn\" (click)=\"previous()\" title=\"Previous\">\n <ng-template\n [ngTemplateOutlet]=\"\n _config.previousButtonTemplate || defaultPreviousBTNTemplate\n \"></ng-template>\n </button>\n @if (_config.todayButton) {\n <button class=\"today dtp-btn\" (click)=\"gotoToday()\">\n {{ _config.todayButtonText }}\n </button>\n }\n <button id=\"next\" class=\"next dtp-btn\" (click)=\"next()\" title=\"Next\">\n <ng-template\n [ngTemplateOutlet]=\"_config.nextButtonTemplate || defaultNextBTNTemplate\"></ng-template>\n </button>\n </div>\n <div class=\"current-date\">\n <span>\n {{ currYear }}\n </span>\n <span>\n {{ displayMonth }}\n </span>\n </div>\n <div class=\"view-mode\">\n {{ view }}\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('day')\"\n [class.active]=\"view == 'day'\"\n title=\"Month View\">\n Month\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('week')\"\n [class.active]=\"view == 'week'\"\n title=\"Week View\">\n Week\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('day')\"\n [class.active]=\"view == 'day'\"\n title=\"Day View\">\n Day\n </button>\n <button\n class=\"dayview dtp-btn\"\n (click)=\"changeView('event')\"\n [class.active]=\"view == 'event'\"\n title=\"Day View\">\n Event\n </button>\n </div>\n </div>\n <div class=\"calendar\" #calendarWrapper>\n @if (view === 'day') {\n <ul class=\"weeks\">\n @for (w of weeks; track $index) {\n <li>\n {{ w }}\n </li>\n }\n </ul>\n <ul class=\"days\" [style.minHeight.px]=\"minHeight\">\n @for (item of viewDays; track $index) {\n <li\n [class.de-active]=\"!item.active\"\n [class.today]=\"item.isToday\"\n [class.selected]=\"item.selected\"\n (click)=\"selectDay($event, item)\">\n <div>{{ item.day }}</div>\n @if (item.events) {\n <div class=\"ms-day-events\">\n @for (event of item.events; track $index) {\n <a\n tabindex=\"0\"\n class=\"ms-day-event\"\n [title]=\"event.title\"\n (click)=\"onclickEvent(item, event)\">\n {{ event.title }}\n </a>\n }\n </div>\n }\n </li>\n }\n </ul>\n } @else if (view == 'week' || view == 'month') {\n <table>\n <thead>\n <tr>\n <th></th>\n @for (w of weeks; track $index) {\n <th>{{ w }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (item of viewWeeks; track $index; let i = $index) {\n <tr>\n <td [title]=\"item.displayTime\">{{ item.time % 1 == 0 ? item.time : '' }}</td>\n @for (w of item.weeks; track $index) {\n <td></td>\n }\n </tr>\n }\n </tbody>\n </table>\n } @else if (view == 'event') {\n not implemented\n }\n </div>\n</div>\n\n<ng-template #defaultPreviousBTNTemplate>\n <svg width=\"15px\" height=\"30px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M224 480c-8.188 0-16.38-3.125-22.62-9.375l-192-192c-12.5-12.5-12.5-32.75 0-45.25l192-192c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L77.25 256l169.4 169.4c12.5 12.5 12.5 32.75 0 45.25C240.4 476.9 232.2 480 224 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultNextBTNTemplate>\n <svg width=\"15px\" height=\"30px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M96 480c-8.188 0-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L242.8 256L73.38 86.63c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l192 192c12.5 12.5 12.5 32.75 0 45.25l-192 192C112.4 476.9 104.2 480 96 480z\" />\n </svg>\n</ng-template>\n\n<ng-template #defaultCaretDownIcon>\n <svg width=\"10px\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 320 512\">\n <path\n class=\"fa-secondary\"\n d=\"M310.6 246.6l-127.1 128C176.4 380.9 168.2 384 160 384s-16.38-3.125-22.63-9.375l-127.1-128C.2244 237.5-2.516 223.7 2.438 211.8S19.07 192 32 192h255.1c12.94 0 24.62 7.781 29.58 19.75S319.8 237.5 310.6 246.6z\" />\n </svg>\n</ng-template>\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000;--ngx-border-color: #c0c0c0}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff;--ngx-border-color: #c0c0c0}.wrapper{background-color:var(--ngx-color-bg);color:var(--ngx-color-text);border-radius:5px}.wrapper .dtp-btn{background:none;border:none;color:inherit;border-radius:3px;padding:3px 15px;box-shadow:0 0 4px #0003;transition:all .3s;display:inline-flex;align-items:center}.wrapper .dtp-btn:not([disabled]):hover{cursor:pointer;background:#87879e}.wrapper .dtp-btn.active{background:#87879e}.wrapper .dtp-btn svg{fill:var(--ngx-color-text)}.wrapper .header{display:flex;align-items:center;justify-content:space-between;padding:10px 10px 0}.wrapper .header .current-date{text-align:center;flex:auto}.wrapper .nxt-prv-buttons{display:flex;align-items:center}.wrapper .nxt-prv-buttons .dtp-btn{border-radius:0}.wrapper .nxt-prv-buttons .dtp-btn:first-child{border-radius:5px 0 0 5px}.wrapper .nxt-prv-buttons .dtp-btn:last-child{border-radius:0 5px 5px 0}.calendar{padding:10px}.calendar ul{display:flex;flex-wrap:wrap;list-style:none;padding:0;margin:0;border:1px var(--ngx-border-color) solid;border-bottom:none}.calendar .days{margin-bottom:20px}.calendar .days li{width:14.2857142857%;text-align:end;max-height:300px;overflow:auto}.calendar .months{margin-bottom:20px}.calendar .months li{height:40px;width:33%}.calendar .years{margin-bottom:20px}.calendar .years li{height:40px;width:25%}.calendar li{position:relative;border-right:1px var(--ngx-border-color) solid;border-bottom:1px var(--ngx-border-color) solid;padding:4px}.calendar li.de-active{color:#cbcbcb}.calendar li.selected{border:1px #1216fa solid}.calendar li.today{background-color:#ff9d0130}.calendar .weeks li{cursor:default;width:14.2857142857%;text-align:center;font-weight:700}.calendar .weeks li:hover{background:none}.ms-day-events .ms-day-event{color:#3f51b5;background:var(--ngx-color-bg);border:1px rgba(63,81,181,.1215686275) solid;border-radius:4px;min-height:25px;padding:4px;margin:4px 0;text-decoration:none;display:block}::ng-deep html[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:first-child,::ng-deep body[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:first-child{border-radius:0 5px 5px 0!important}::ng-deep html[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:last-child,::ng-deep body[dir=rtl] .wrapper .nxt-prv-buttons .dtp-btn:last-child{border-radius:5px 0 0 5px!important}::ng-deep html[dir=rtl] .wrapper .wrapper .dtp-btn.next,::ng-deep html[dir=rtl] .wrapper .wrapper .dtp-btn.previous,::ng-deep body[dir=rtl] .wrapper .wrapper .dtp-btn.next,::ng-deep body[dir=rtl] .wrapper .wrapper .dtp-btn.previous{transform:rotate(180deg)}table{width:100%;border-collapse:collapse}table td,table th{border:1px rgb(158,158,158) solid;padding:5px;height:1.5em}\n"] }]
|
|
2237
|
+
}], ctorParameters: () => [], propDecorators: { setTheme: [{
|
|
2238
|
+
type: Input,
|
|
2239
|
+
args: ['theme']
|
|
2240
|
+
}], config: [{
|
|
2241
|
+
type: Input
|
|
2242
|
+
}], locale: [{
|
|
2243
|
+
type: Input
|
|
2244
|
+
}], setMin: [{
|
|
2245
|
+
type: Input,
|
|
2246
|
+
args: ['min']
|
|
2247
|
+
}], setMax: [{
|
|
2248
|
+
type: Input,
|
|
2249
|
+
args: ['max']
|
|
2250
|
+
}], view: [{
|
|
2251
|
+
type: Input
|
|
2252
|
+
}], events: [{
|
|
2253
|
+
type: Input
|
|
2254
|
+
}], dateChange: [{
|
|
2255
|
+
type: Output
|
|
2256
|
+
}], selectEvent: [{
|
|
2257
|
+
type: Output
|
|
2258
|
+
}], calendarWrapper: [{ type: i0.ViewChild, args: ['calendarWrapper', { isSignal: true }] }], onResize: [{
|
|
2259
|
+
type: HostListener,
|
|
2260
|
+
args: ['window:resize', ['$event']]
|
|
2261
|
+
}] } });
|
|
2262
|
+
|
|
2263
|
+
function dedupeAdapters(adapters) {
|
|
2264
|
+
return Array.from(new Map(adapters.map((a) => [a.locale, a])).values());
|
|
2265
|
+
}
|
|
2266
|
+
function provideDateAdapters(...additional) {
|
|
2267
|
+
const all = dedupeAdapters([...DEFAULT_DATE_ADAPTERS, ...additional]);
|
|
2268
|
+
return all.map((adapter) => ({
|
|
2269
|
+
provide: DATE_ADAPTERS,
|
|
2270
|
+
multi: true,
|
|
2271
|
+
useValue: adapter,
|
|
2272
|
+
}));
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
/**
|
|
2276
|
+
* Generated bundle index. Do not edit.
|
|
2277
|
+
*/
|
|
2278
|
+
|
|
2279
|
+
export { DATE_ADAPTERS, DEFAULT_DATE_ADAPTERS, NgxCalendarComponent, NgxDatePickerConfig, NgxInputDatePicker, NgxInputDatePickerComponent, getLocals, provideDateAdapters };
|
|
2280
|
+
//# sourceMappingURL=ngx-kit-date-picker.mjs.map
|