angular-hijri-gregorian-date-time-picker 1.5.0 → 1.5.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/README.md +249 -236
- package/{fesm2020 → fesm2022}/angular-hijri-gregorian-date-time-picker.mjs +1438 -1438
- package/fesm2022/angular-hijri-gregorian-date-time-picker.mjs.map +1 -0
- package/index.d.ts +347 -5
- package/package.json +7 -15
- package/_interfaces/calendar-model.d.ts +0 -28
- package/_interfaces/styles-config.model.d.ts +0 -13
- package/_services/date-utilities.service.d.ts +0 -49
- package/esm2020/_data/dictionary.json +0 -1
- package/esm2020/_interfaces/calendar-model.mjs +0 -2
- package/esm2020/_interfaces/styles-config.model.mjs +0 -2
- package/esm2020/_services/date-utilities.service.mjs +0 -375
- package/esm2020/angular-hijri-gregorian-date-time-picker.mjs +0 -5
- package/esm2020/lib/hijri-gregorian-datepicker.component.mjs +0 -1058
- package/esm2020/lib/hijri-gregorian-datepicker.module.mjs +0 -19
- package/esm2020/public-api.mjs +0 -8
- package/esm2020/themes/themes.json +0 -152
- package/fesm2015/angular-hijri-gregorian-date-time-picker.mjs +0 -28995
- package/fesm2015/angular-hijri-gregorian-date-time-picker.mjs.map +0 -1
- package/fesm2020/angular-hijri-gregorian-date-time-picker.mjs.map +0 -1
- package/lib/hijri-gregorian-datepicker.component.d.ts +0 -238
- package/lib/hijri-gregorian-datepicker.module.d.ts +0 -9
- package/public-api.d.ts +0 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, EventEmitter,
|
|
2
|
+
import { Injectable, EventEmitter, HostBinding, Output, Input, Component, NgModule } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
5
5
|
import * as i3 from '@angular/common';
|
|
@@ -27378,377 +27378,377 @@ var dictionary = {
|
|
|
27378
27378
|
}
|
|
27379
27379
|
};
|
|
27380
27380
|
|
|
27381
|
-
class DateUtilitiesService {
|
|
27382
|
-
constructor() {
|
|
27383
|
-
this.calendarData = dictionary; //prod
|
|
27384
|
-
// this.calendarData = datesDictionary; //debug
|
|
27385
|
-
}
|
|
27386
|
-
parseDate(dateStr) {
|
|
27387
|
-
if (!dateStr) {
|
|
27388
|
-
return null;
|
|
27389
|
-
}
|
|
27390
|
-
const parts = dateStr?.split('/');
|
|
27391
|
-
if (parts.length !== 3) {
|
|
27392
|
-
return null;
|
|
27393
|
-
}
|
|
27394
|
-
const [day, month, year] = parts.map(Number);
|
|
27395
|
-
if (isNaN(day) ||
|
|
27396
|
-
isNaN(month) ||
|
|
27397
|
-
isNaN(year) ||
|
|
27398
|
-
day < 1 ||
|
|
27399
|
-
day > 31 ||
|
|
27400
|
-
month < 1 ||
|
|
27401
|
-
month > 12 ||
|
|
27402
|
-
year < 1) {
|
|
27403
|
-
return null;
|
|
27404
|
-
}
|
|
27405
|
-
return new Date(year, month - 1, day);
|
|
27406
|
-
}
|
|
27407
|
-
formatDate(date) {
|
|
27408
|
-
const day = String(date.getDate()).padStart(2, '0');
|
|
27409
|
-
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
27410
|
-
const year = date.getFullYear();
|
|
27411
|
-
return `${day}/${month}/${year}`;
|
|
27412
|
-
}
|
|
27413
|
-
getDayShortHand(date) {
|
|
27414
|
-
return date.toLocaleString('en-US', { weekday: 'short' });
|
|
27415
|
-
}
|
|
27416
|
-
generateDates(fD, lD, uC) {
|
|
27417
|
-
const startDate = this.parseDate(fD?.gD);
|
|
27418
|
-
const endDate = this.parseDate(lD?.gD);
|
|
27419
|
-
const daysInMonth = [];
|
|
27420
|
-
let currentGregorianDate = new Date(startDate);
|
|
27421
|
-
let currentUmmAlQuraDay = parseInt(fD?.uD?.split('/')[0]);
|
|
27422
|
-
let currentUmmAlQuraMonth = parseInt(fD?.uD?.split('/')[1]);
|
|
27423
|
-
let currentUmmAlQuraYear = parseInt(fD?.uD?.split('/')[2]);
|
|
27424
|
-
let daysInCurrentUmmAlQuraMonth = uC;
|
|
27425
|
-
while (currentGregorianDate <= endDate) {
|
|
27426
|
-
const ummAlQuraDate = `${currentUmmAlQuraDay
|
|
27427
|
-
.toString()
|
|
27428
|
-
.padStart(2, '0')}/${currentUmmAlQuraMonth
|
|
27429
|
-
.toString()
|
|
27430
|
-
.padStart(2, '0')}/${currentUmmAlQuraYear}`;
|
|
27431
|
-
daysInMonth.push({
|
|
27432
|
-
gD: this.formatDate(currentGregorianDate),
|
|
27433
|
-
uD: ummAlQuraDate,
|
|
27434
|
-
dN: this.getDayShortHand(currentGregorianDate),
|
|
27435
|
-
uC: 0,
|
|
27436
|
-
});
|
|
27437
|
-
currentGregorianDate.setDate(currentGregorianDate.getDate() + 1);
|
|
27438
|
-
currentUmmAlQuraDay += 1;
|
|
27439
|
-
if (currentUmmAlQuraDay > daysInCurrentUmmAlQuraMonth) {
|
|
27440
|
-
currentUmmAlQuraDay = 1;
|
|
27441
|
-
currentUmmAlQuraMonth += 1;
|
|
27442
|
-
if (currentUmmAlQuraMonth > 12) {
|
|
27443
|
-
currentUmmAlQuraMonth = 1;
|
|
27444
|
-
currentUmmAlQuraYear += 1;
|
|
27445
|
-
}
|
|
27446
|
-
const nextMonthData = this.calendarData[currentUmmAlQuraYear.toString()]?.[currentUmmAlQuraMonth.toString()];
|
|
27447
|
-
daysInCurrentUmmAlQuraMonth = nextMonthData ? nextMonthData.fD.uC : 30;
|
|
27448
|
-
}
|
|
27449
|
-
}
|
|
27450
|
-
return daysInMonth;
|
|
27451
|
-
}
|
|
27452
|
-
convertDate(dateStr, isGregorian) {
|
|
27453
|
-
if (!dateStr)
|
|
27454
|
-
return null;
|
|
27455
|
-
if (isGregorian) {
|
|
27456
|
-
// Preprocess Gregorian date
|
|
27457
|
-
const gregorianDate = this.parseDate(dateStr);
|
|
27458
|
-
if (!gregorianDate)
|
|
27459
|
-
return null;
|
|
27460
|
-
const formattedDate = this.formatDate(gregorianDate);
|
|
27461
|
-
for (const yearKey in this.calendarData) {
|
|
27462
|
-
for (const monthKey in this.calendarData[yearKey]) {
|
|
27463
|
-
const monthData = this.calendarData[yearKey][monthKey];
|
|
27464
|
-
if (this.isDateInMonthRange(formattedDate, monthData.fD?.gD, monthData.lD?.gD)) {
|
|
27465
|
-
const daysInMonth = this.generateDates(monthData.fD, monthData.lD, monthData.fD?.uC);
|
|
27466
|
-
const dayMatch = daysInMonth.find((d) => d.gD === formattedDate);
|
|
27467
|
-
if (dayMatch)
|
|
27468
|
-
return dayMatch;
|
|
27469
|
-
}
|
|
27470
|
-
}
|
|
27471
|
-
}
|
|
27472
|
-
}
|
|
27473
|
-
else {
|
|
27474
|
-
const [day, month, year] = dateStr.split('/').map(Number);
|
|
27475
|
-
if (isNaN(day) || isNaN(month) || isNaN(year))
|
|
27476
|
-
return null;
|
|
27477
|
-
for (const yearKey in this.calendarData) {
|
|
27478
|
-
for (const monthKey in this.calendarData[yearKey]) {
|
|
27479
|
-
const monthData = this.calendarData[yearKey][monthKey];
|
|
27480
|
-
if (this.isDateInMonthRange(`${day}/${month}/${year}`, monthData.fD?.uD, monthData.lD?.uD)) {
|
|
27481
|
-
const daysInMonth = this.generateDates(monthData.fD, monthData.lD, monthData.fD?.uC);
|
|
27482
|
-
const dayMatch = daysInMonth.find((d) => {
|
|
27483
|
-
const [uDay, uMonth, uYear] = d?.uD?.split('/').map(Number);
|
|
27484
|
-
return uDay === day && uMonth === month && uYear === year;
|
|
27485
|
-
});
|
|
27486
|
-
if (dayMatch)
|
|
27487
|
-
return dayMatch;
|
|
27488
|
-
}
|
|
27489
|
-
}
|
|
27490
|
-
}
|
|
27491
|
-
}
|
|
27492
|
-
return null;
|
|
27493
|
-
}
|
|
27494
|
-
isDateInMonthRange(dateToCheck, monthStartDate, monthEndDate) {
|
|
27495
|
-
if (!monthStartDate || !monthEndDate)
|
|
27496
|
-
return false;
|
|
27497
|
-
const checkDate = this.parseDate(dateToCheck);
|
|
27498
|
-
const startDate = this.parseDate(monthStartDate);
|
|
27499
|
-
const endDate = this.parseDate(monthEndDate);
|
|
27500
|
-
if (!checkDate || !startDate || !endDate)
|
|
27501
|
-
return false;
|
|
27502
|
-
return checkDate >= startDate && checkDate <= endDate;
|
|
27503
|
-
}
|
|
27504
|
-
getMonthData(inputDate, type) {
|
|
27505
|
-
const [day, month, year] = inputDate?.split('/').map(Number);
|
|
27506
|
-
let isGregorian;
|
|
27507
|
-
if (type == 'greg') {
|
|
27508
|
-
isGregorian = true;
|
|
27509
|
-
}
|
|
27510
|
-
else {
|
|
27511
|
-
isGregorian = false;
|
|
27512
|
-
}
|
|
27513
|
-
if (isGregorian) {
|
|
27514
|
-
return this.getGregorianMonthData(day, month, year);
|
|
27515
|
-
}
|
|
27516
|
-
else {
|
|
27517
|
-
return this.getUmAlQurraMonthData(day, month, year);
|
|
27518
|
-
}
|
|
27519
|
-
}
|
|
27520
|
-
getGregorianMonthData(day, month, year) {
|
|
27521
|
-
const yearData = this.calendarData[year];
|
|
27522
|
-
if (!yearData)
|
|
27523
|
-
return null;
|
|
27524
|
-
const monthData = yearData[month];
|
|
27525
|
-
if (!monthData)
|
|
27526
|
-
return null;
|
|
27527
|
-
const monthArray = [];
|
|
27528
|
-
const endDate = new Date(year, month, 0);
|
|
27529
|
-
for (let d = 1; d <= endDate.getDate(); d++) {
|
|
27530
|
-
const offset = d - 1;
|
|
27531
|
-
monthArray.push({
|
|
27532
|
-
gD: `${d.toString().padStart(2, '0')}/${month
|
|
27533
|
-
.toString()
|
|
27534
|
-
.padStart(2, '0')}/${year}`,
|
|
27535
|
-
uD: this.calculateUmAlQurraDate(monthData.fD.uD, offset, monthData.fD.uC),
|
|
27536
|
-
dN: this.getDayName(new Date(year, month - 1, d).getDay()),
|
|
27537
|
-
uC: monthData.fD.uC,
|
|
27538
|
-
});
|
|
27539
|
-
}
|
|
27540
|
-
return monthArray;
|
|
27541
|
-
}
|
|
27542
|
-
getUmAlQurraMonthData(day, month, year) {
|
|
27543
|
-
for (const gregorianYear in this.calendarData) {
|
|
27544
|
-
const yearData = this.calendarData[parseInt(gregorianYear)];
|
|
27545
|
-
for (const monthIndex in yearData) {
|
|
27546
|
-
const monthData = yearData[parseInt(monthIndex)];
|
|
27547
|
-
const [fDay, fMonth, fYear] = monthData?.fD?.uD?.split('/').map(Number);
|
|
27548
|
-
if (fYear === year && fMonth === month) {
|
|
27549
|
-
const totalDays = monthData.fD.uC;
|
|
27550
|
-
const monthArray = [];
|
|
27551
|
-
const umAlQurraStartDate = `01/${month
|
|
27552
|
-
.toString()
|
|
27553
|
-
.padStart(2, '0')}/${year}`;
|
|
27554
|
-
const dayDifference = fDay - 1;
|
|
27555
|
-
const startGregorianDate = this.calculateGregorianDate(monthData.fD.gD, -dayDifference);
|
|
27556
|
-
for (let i = 0; i < totalDays; i++) {
|
|
27557
|
-
const uDate = this.calculateUmAlQurraDate(umAlQurraStartDate, i, totalDays);
|
|
27558
|
-
const gDate = this.calculateGregorianDate(startGregorianDate, i);
|
|
27559
|
-
const [gDay, gMonth, gYear] = gDate?.split('/').map(Number);
|
|
27560
|
-
const dayName = this.getDayName(new Date(gYear, gMonth - 1, gDay).getDay());
|
|
27561
|
-
monthArray.push({
|
|
27562
|
-
gD: gDate,
|
|
27563
|
-
uD: uDate,
|
|
27564
|
-
dN: dayName,
|
|
27565
|
-
uC: totalDays,
|
|
27566
|
-
});
|
|
27567
|
-
}
|
|
27568
|
-
return monthArray;
|
|
27569
|
-
}
|
|
27570
|
-
}
|
|
27571
|
-
}
|
|
27572
|
-
return null;
|
|
27573
|
-
}
|
|
27574
|
-
calculateGregorianDate(startGDate, offset) {
|
|
27575
|
-
const [day, month, year] = startGDate?.split('/').map(Number);
|
|
27576
|
-
const newDate = new Date(year, month - 1, day + offset);
|
|
27577
|
-
return `${newDate.getDate().toString().padStart(2, '0')}/${(newDate.getMonth() + 1)
|
|
27578
|
-
.toString()
|
|
27579
|
-
.padStart(2, '0')}/${newDate.getFullYear()}`;
|
|
27580
|
-
}
|
|
27581
|
-
calculateUmAlQurraDate(startUDate, offset, uC) {
|
|
27582
|
-
const [day, month, year] = startUDate?.split('/').map(Number);
|
|
27583
|
-
let newDay = day + offset;
|
|
27584
|
-
let newMonth = month;
|
|
27585
|
-
let newYear = year;
|
|
27586
|
-
while (newDay > uC) {
|
|
27587
|
-
newDay -= uC;
|
|
27588
|
-
newMonth += 1;
|
|
27589
|
-
}
|
|
27590
|
-
while (newMonth > 12) {
|
|
27591
|
-
newMonth = 1;
|
|
27592
|
-
newYear += 1;
|
|
27593
|
-
}
|
|
27594
|
-
return `${newDay.toString().padStart(2, '0')}/${newMonth
|
|
27595
|
-
.toString()
|
|
27596
|
-
.padStart(2, '0')}/${newYear}`;
|
|
27597
|
-
}
|
|
27598
|
-
getDayName(dayIndex) {
|
|
27599
|
-
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
27600
|
-
return days[dayIndex];
|
|
27601
|
-
}
|
|
27602
|
-
/// Check date is it in past or future
|
|
27603
|
-
checkPastOrFuture(inputDate, targetDate) {
|
|
27604
|
-
if (inputDate) {
|
|
27605
|
-
const [day, month, year] = inputDate?.split('/').map(Number);
|
|
27606
|
-
const dateToCheck = new Date(year, month - 1, day);
|
|
27607
|
-
const today = targetDate;
|
|
27608
|
-
today.setHours(0, 0, 0, 0);
|
|
27609
|
-
if (dateToCheck > today) {
|
|
27610
|
-
return 'Future';
|
|
27611
|
-
}
|
|
27612
|
-
else if (dateToCheck < today) {
|
|
27613
|
-
return 'Past';
|
|
27614
|
-
}
|
|
27615
|
-
else {
|
|
27616
|
-
return 'Today';
|
|
27617
|
-
}
|
|
27618
|
-
}
|
|
27619
|
-
}
|
|
27620
|
-
/// Convert english numbers to arabic equivalent
|
|
27621
|
-
parseEnglish(englishNum) {
|
|
27622
|
-
if (!englishNum)
|
|
27623
|
-
return englishNum;
|
|
27624
|
-
const numStr = String(englishNum);
|
|
27625
|
-
const arabicNumbers = [
|
|
27626
|
-
'\u0660',
|
|
27627
|
-
'\u0661',
|
|
27628
|
-
'\u0662',
|
|
27629
|
-
'\u0663',
|
|
27630
|
-
'\u0664',
|
|
27631
|
-
'\u0665',
|
|
27632
|
-
'\u0666',
|
|
27633
|
-
'\u0667',
|
|
27634
|
-
'\u0668',
|
|
27635
|
-
'\u0669',
|
|
27636
|
-
];
|
|
27637
|
-
return numStr.replace(/[0-9]/g, (digit) => {
|
|
27638
|
-
return arabicNumbers[Number(digit)] || digit;
|
|
27639
|
-
});
|
|
27640
|
-
}
|
|
27641
|
-
/// Convert arabic numbers to english equivalent
|
|
27642
|
-
parseArabic(arabicNum) {
|
|
27643
|
-
return arabicNum.replace(/[٠١٢٣٤٥٦٧٨٩]/g, function (d) {
|
|
27644
|
-
return d.charCodeAt(0) - 1632;
|
|
27645
|
-
});
|
|
27646
|
-
}
|
|
27647
|
-
///
|
|
27648
|
-
convertDateNumerals(date, targetLang) {
|
|
27649
|
-
const arabicNumbers = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
|
27650
|
-
const englishNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
27651
|
-
const toArabic = (value) => value
|
|
27652
|
-
.split('')
|
|
27653
|
-
.map((char) => (/\d/.test(char) ? arabicNumbers[+char] : char))
|
|
27654
|
-
.join('');
|
|
27655
|
-
const toEnglish = (value) => value
|
|
27656
|
-
.split('')
|
|
27657
|
-
.map((char) => {
|
|
27658
|
-
const index = arabicNumbers.indexOf(char);
|
|
27659
|
-
return index > -1 ? englishNumbers[index] : char;
|
|
27660
|
-
})
|
|
27661
|
-
.join('');
|
|
27662
|
-
if (targetLang === 'ar') {
|
|
27663
|
-
const [day, month, year] = date.split('/');
|
|
27664
|
-
return `${toArabic(year)}/${toArabic(month)}/${toArabic(day)}`;
|
|
27665
|
-
}
|
|
27666
|
-
else {
|
|
27667
|
-
const [year, month, day] = date.split('/');
|
|
27668
|
-
return `${toEnglish(day)}/${toEnglish(month)}/${toEnglish(year)}`;
|
|
27669
|
-
}
|
|
27670
|
-
}
|
|
27671
|
-
/**
|
|
27672
|
-
* Normalize input date to DD/MM/YYYY string format (Gregorian)
|
|
27673
|
-
* Accepts Date object or DD/MM/YYYY string
|
|
27674
|
-
*/
|
|
27675
|
-
normalizeDateToString(date) {
|
|
27676
|
-
if (!date)
|
|
27677
|
-
return null;
|
|
27678
|
-
if (date instanceof Date) {
|
|
27679
|
-
return this.formatDate(date);
|
|
27680
|
-
}
|
|
27681
|
-
// Already a string - validate format
|
|
27682
|
-
const parsed = this.parseDate(date);
|
|
27683
|
-
return parsed ? this.formatDate(parsed) : null;
|
|
27684
|
-
}
|
|
27685
|
-
/**
|
|
27686
|
-
* Compare two dates (Gregorian format DD/MM/YYYY)
|
|
27687
|
-
* Returns: -1 if date1 < date2, 0 if equal, 1 if date1 > date2
|
|
27688
|
-
*/
|
|
27689
|
-
compareDates(date1Str, date2Str) {
|
|
27690
|
-
const d1 = this.parseDate(date1Str);
|
|
27691
|
-
const d2 = this.parseDate(date2Str);
|
|
27692
|
-
if (!d1 || !d2)
|
|
27693
|
-
return 0;
|
|
27694
|
-
if (d1 < d2)
|
|
27695
|
-
return -1;
|
|
27696
|
-
if (d1 > d2)
|
|
27697
|
-
return 1;
|
|
27698
|
-
return 0;
|
|
27699
|
-
}
|
|
27700
|
-
/**
|
|
27701
|
-
* Compare two Hijri dates (UM format DD/MM/YYYY)
|
|
27702
|
-
* Converts to Gregorian for comparison
|
|
27703
|
-
*/
|
|
27704
|
-
compareHijriDates(hijri1, hijri2) {
|
|
27705
|
-
const day1 = this.convertDate(hijri1, false);
|
|
27706
|
-
const day2 = this.convertDate(hijri2, false);
|
|
27707
|
-
if (!day1?.gD || !day2?.gD)
|
|
27708
|
-
return 0;
|
|
27709
|
-
return this.compareDates(day1.gD, day2.gD);
|
|
27710
|
-
}
|
|
27711
|
-
/**
|
|
27712
|
-
* Check if a date is within the specified range (inclusive)
|
|
27713
|
-
* All dates in Gregorian DD/MM/YYYY format
|
|
27714
|
-
*/
|
|
27715
|
-
isDateInRange(dateStr, minDateStr, maxDateStr) {
|
|
27716
|
-
if (!dateStr)
|
|
27717
|
-
return false;
|
|
27718
|
-
// If no constraints, date is valid
|
|
27719
|
-
if (!minDateStr && !maxDateStr)
|
|
27720
|
-
return true;
|
|
27721
|
-
// Check minimum constraint
|
|
27722
|
-
if (minDateStr && this.compareDates(dateStr, minDateStr) < 0) {
|
|
27723
|
-
return false;
|
|
27724
|
-
}
|
|
27725
|
-
// Check maximum constraint
|
|
27726
|
-
if (maxDateStr && this.compareDates(dateStr, maxDateStr) > 0) {
|
|
27727
|
-
return false;
|
|
27728
|
-
}
|
|
27729
|
-
return true;
|
|
27730
|
-
}
|
|
27731
|
-
/**
|
|
27732
|
-
* Check if a Hijri date is within the specified range
|
|
27733
|
-
* Converts to Gregorian for comparison
|
|
27734
|
-
*/
|
|
27735
|
-
isHijriDateInRange(hijriDateStr, minDateStr, maxDateStr) {
|
|
27736
|
-
if (!hijriDateStr)
|
|
27737
|
-
return false;
|
|
27738
|
-
const dayInfo = this.convertDate(hijriDateStr, false);
|
|
27739
|
-
if (!dayInfo?.gD)
|
|
27740
|
-
return false;
|
|
27741
|
-
return this.isDateInRange(dayInfo.gD, minDateStr, maxDateStr);
|
|
27742
|
-
}
|
|
27743
|
-
}
|
|
27744
|
-
|
|
27745
|
-
|
|
27746
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
27747
|
-
type: Injectable,
|
|
27748
|
-
args: [{
|
|
27749
|
-
providedIn: 'root',
|
|
27750
|
-
}]
|
|
27751
|
-
}], ctorParameters:
|
|
27381
|
+
class DateUtilitiesService {
|
|
27382
|
+
constructor() {
|
|
27383
|
+
this.calendarData = dictionary; //prod
|
|
27384
|
+
// this.calendarData = datesDictionary; //debug
|
|
27385
|
+
}
|
|
27386
|
+
parseDate(dateStr) {
|
|
27387
|
+
if (!dateStr) {
|
|
27388
|
+
return null;
|
|
27389
|
+
}
|
|
27390
|
+
const parts = dateStr?.split('/');
|
|
27391
|
+
if (parts.length !== 3) {
|
|
27392
|
+
return null;
|
|
27393
|
+
}
|
|
27394
|
+
const [day, month, year] = parts.map(Number);
|
|
27395
|
+
if (isNaN(day) ||
|
|
27396
|
+
isNaN(month) ||
|
|
27397
|
+
isNaN(year) ||
|
|
27398
|
+
day < 1 ||
|
|
27399
|
+
day > 31 ||
|
|
27400
|
+
month < 1 ||
|
|
27401
|
+
month > 12 ||
|
|
27402
|
+
year < 1) {
|
|
27403
|
+
return null;
|
|
27404
|
+
}
|
|
27405
|
+
return new Date(year, month - 1, day);
|
|
27406
|
+
}
|
|
27407
|
+
formatDate(date) {
|
|
27408
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
27409
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
27410
|
+
const year = date.getFullYear();
|
|
27411
|
+
return `${day}/${month}/${year}`;
|
|
27412
|
+
}
|
|
27413
|
+
getDayShortHand(date) {
|
|
27414
|
+
return date.toLocaleString('en-US', { weekday: 'short' });
|
|
27415
|
+
}
|
|
27416
|
+
generateDates(fD, lD, uC) {
|
|
27417
|
+
const startDate = this.parseDate(fD?.gD);
|
|
27418
|
+
const endDate = this.parseDate(lD?.gD);
|
|
27419
|
+
const daysInMonth = [];
|
|
27420
|
+
let currentGregorianDate = new Date(startDate);
|
|
27421
|
+
let currentUmmAlQuraDay = parseInt(fD?.uD?.split('/')[0]);
|
|
27422
|
+
let currentUmmAlQuraMonth = parseInt(fD?.uD?.split('/')[1]);
|
|
27423
|
+
let currentUmmAlQuraYear = parseInt(fD?.uD?.split('/')[2]);
|
|
27424
|
+
let daysInCurrentUmmAlQuraMonth = uC;
|
|
27425
|
+
while (currentGregorianDate <= endDate) {
|
|
27426
|
+
const ummAlQuraDate = `${currentUmmAlQuraDay
|
|
27427
|
+
.toString()
|
|
27428
|
+
.padStart(2, '0')}/${currentUmmAlQuraMonth
|
|
27429
|
+
.toString()
|
|
27430
|
+
.padStart(2, '0')}/${currentUmmAlQuraYear}`;
|
|
27431
|
+
daysInMonth.push({
|
|
27432
|
+
gD: this.formatDate(currentGregorianDate),
|
|
27433
|
+
uD: ummAlQuraDate,
|
|
27434
|
+
dN: this.getDayShortHand(currentGregorianDate),
|
|
27435
|
+
uC: 0,
|
|
27436
|
+
});
|
|
27437
|
+
currentGregorianDate.setDate(currentGregorianDate.getDate() + 1);
|
|
27438
|
+
currentUmmAlQuraDay += 1;
|
|
27439
|
+
if (currentUmmAlQuraDay > daysInCurrentUmmAlQuraMonth) {
|
|
27440
|
+
currentUmmAlQuraDay = 1;
|
|
27441
|
+
currentUmmAlQuraMonth += 1;
|
|
27442
|
+
if (currentUmmAlQuraMonth > 12) {
|
|
27443
|
+
currentUmmAlQuraMonth = 1;
|
|
27444
|
+
currentUmmAlQuraYear += 1;
|
|
27445
|
+
}
|
|
27446
|
+
const nextMonthData = this.calendarData[currentUmmAlQuraYear.toString()]?.[currentUmmAlQuraMonth.toString()];
|
|
27447
|
+
daysInCurrentUmmAlQuraMonth = nextMonthData ? nextMonthData.fD.uC : 30;
|
|
27448
|
+
}
|
|
27449
|
+
}
|
|
27450
|
+
return daysInMonth;
|
|
27451
|
+
}
|
|
27452
|
+
convertDate(dateStr, isGregorian) {
|
|
27453
|
+
if (!dateStr)
|
|
27454
|
+
return null;
|
|
27455
|
+
if (isGregorian) {
|
|
27456
|
+
// Preprocess Gregorian date
|
|
27457
|
+
const gregorianDate = this.parseDate(dateStr);
|
|
27458
|
+
if (!gregorianDate)
|
|
27459
|
+
return null;
|
|
27460
|
+
const formattedDate = this.formatDate(gregorianDate);
|
|
27461
|
+
for (const yearKey in this.calendarData) {
|
|
27462
|
+
for (const monthKey in this.calendarData[yearKey]) {
|
|
27463
|
+
const monthData = this.calendarData[yearKey][monthKey];
|
|
27464
|
+
if (this.isDateInMonthRange(formattedDate, monthData.fD?.gD, monthData.lD?.gD)) {
|
|
27465
|
+
const daysInMonth = this.generateDates(monthData.fD, monthData.lD, monthData.fD?.uC);
|
|
27466
|
+
const dayMatch = daysInMonth.find((d) => d.gD === formattedDate);
|
|
27467
|
+
if (dayMatch)
|
|
27468
|
+
return dayMatch;
|
|
27469
|
+
}
|
|
27470
|
+
}
|
|
27471
|
+
}
|
|
27472
|
+
}
|
|
27473
|
+
else {
|
|
27474
|
+
const [day, month, year] = dateStr.split('/').map(Number);
|
|
27475
|
+
if (isNaN(day) || isNaN(month) || isNaN(year))
|
|
27476
|
+
return null;
|
|
27477
|
+
for (const yearKey in this.calendarData) {
|
|
27478
|
+
for (const monthKey in this.calendarData[yearKey]) {
|
|
27479
|
+
const monthData = this.calendarData[yearKey][monthKey];
|
|
27480
|
+
if (this.isDateInMonthRange(`${day}/${month}/${year}`, monthData.fD?.uD, monthData.lD?.uD)) {
|
|
27481
|
+
const daysInMonth = this.generateDates(monthData.fD, monthData.lD, monthData.fD?.uC);
|
|
27482
|
+
const dayMatch = daysInMonth.find((d) => {
|
|
27483
|
+
const [uDay, uMonth, uYear] = d?.uD?.split('/').map(Number);
|
|
27484
|
+
return uDay === day && uMonth === month && uYear === year;
|
|
27485
|
+
});
|
|
27486
|
+
if (dayMatch)
|
|
27487
|
+
return dayMatch;
|
|
27488
|
+
}
|
|
27489
|
+
}
|
|
27490
|
+
}
|
|
27491
|
+
}
|
|
27492
|
+
return null;
|
|
27493
|
+
}
|
|
27494
|
+
isDateInMonthRange(dateToCheck, monthStartDate, monthEndDate) {
|
|
27495
|
+
if (!monthStartDate || !monthEndDate)
|
|
27496
|
+
return false;
|
|
27497
|
+
const checkDate = this.parseDate(dateToCheck);
|
|
27498
|
+
const startDate = this.parseDate(monthStartDate);
|
|
27499
|
+
const endDate = this.parseDate(monthEndDate);
|
|
27500
|
+
if (!checkDate || !startDate || !endDate)
|
|
27501
|
+
return false;
|
|
27502
|
+
return checkDate >= startDate && checkDate <= endDate;
|
|
27503
|
+
}
|
|
27504
|
+
getMonthData(inputDate, type) {
|
|
27505
|
+
const [day, month, year] = inputDate?.split('/').map(Number);
|
|
27506
|
+
let isGregorian;
|
|
27507
|
+
if (type == 'greg') {
|
|
27508
|
+
isGregorian = true;
|
|
27509
|
+
}
|
|
27510
|
+
else {
|
|
27511
|
+
isGregorian = false;
|
|
27512
|
+
}
|
|
27513
|
+
if (isGregorian) {
|
|
27514
|
+
return this.getGregorianMonthData(day, month, year);
|
|
27515
|
+
}
|
|
27516
|
+
else {
|
|
27517
|
+
return this.getUmAlQurraMonthData(day, month, year);
|
|
27518
|
+
}
|
|
27519
|
+
}
|
|
27520
|
+
getGregorianMonthData(day, month, year) {
|
|
27521
|
+
const yearData = this.calendarData[year];
|
|
27522
|
+
if (!yearData)
|
|
27523
|
+
return null;
|
|
27524
|
+
const monthData = yearData[month];
|
|
27525
|
+
if (!monthData)
|
|
27526
|
+
return null;
|
|
27527
|
+
const monthArray = [];
|
|
27528
|
+
const endDate = new Date(year, month, 0);
|
|
27529
|
+
for (let d = 1; d <= endDate.getDate(); d++) {
|
|
27530
|
+
const offset = d - 1;
|
|
27531
|
+
monthArray.push({
|
|
27532
|
+
gD: `${d.toString().padStart(2, '0')}/${month
|
|
27533
|
+
.toString()
|
|
27534
|
+
.padStart(2, '0')}/${year}`,
|
|
27535
|
+
uD: this.calculateUmAlQurraDate(monthData.fD.uD, offset, monthData.fD.uC),
|
|
27536
|
+
dN: this.getDayName(new Date(year, month - 1, d).getDay()),
|
|
27537
|
+
uC: monthData.fD.uC,
|
|
27538
|
+
});
|
|
27539
|
+
}
|
|
27540
|
+
return monthArray;
|
|
27541
|
+
}
|
|
27542
|
+
getUmAlQurraMonthData(day, month, year) {
|
|
27543
|
+
for (const gregorianYear in this.calendarData) {
|
|
27544
|
+
const yearData = this.calendarData[parseInt(gregorianYear)];
|
|
27545
|
+
for (const monthIndex in yearData) {
|
|
27546
|
+
const monthData = yearData[parseInt(monthIndex)];
|
|
27547
|
+
const [fDay, fMonth, fYear] = monthData?.fD?.uD?.split('/').map(Number);
|
|
27548
|
+
if (fYear === year && fMonth === month) {
|
|
27549
|
+
const totalDays = monthData.fD.uC;
|
|
27550
|
+
const monthArray = [];
|
|
27551
|
+
const umAlQurraStartDate = `01/${month
|
|
27552
|
+
.toString()
|
|
27553
|
+
.padStart(2, '0')}/${year}`;
|
|
27554
|
+
const dayDifference = fDay - 1;
|
|
27555
|
+
const startGregorianDate = this.calculateGregorianDate(monthData.fD.gD, -dayDifference);
|
|
27556
|
+
for (let i = 0; i < totalDays; i++) {
|
|
27557
|
+
const uDate = this.calculateUmAlQurraDate(umAlQurraStartDate, i, totalDays);
|
|
27558
|
+
const gDate = this.calculateGregorianDate(startGregorianDate, i);
|
|
27559
|
+
const [gDay, gMonth, gYear] = gDate?.split('/').map(Number);
|
|
27560
|
+
const dayName = this.getDayName(new Date(gYear, gMonth - 1, gDay).getDay());
|
|
27561
|
+
monthArray.push({
|
|
27562
|
+
gD: gDate,
|
|
27563
|
+
uD: uDate,
|
|
27564
|
+
dN: dayName,
|
|
27565
|
+
uC: totalDays,
|
|
27566
|
+
});
|
|
27567
|
+
}
|
|
27568
|
+
return monthArray;
|
|
27569
|
+
}
|
|
27570
|
+
}
|
|
27571
|
+
}
|
|
27572
|
+
return null;
|
|
27573
|
+
}
|
|
27574
|
+
calculateGregorianDate(startGDate, offset) {
|
|
27575
|
+
const [day, month, year] = startGDate?.split('/').map(Number);
|
|
27576
|
+
const newDate = new Date(year, month - 1, day + offset);
|
|
27577
|
+
return `${newDate.getDate().toString().padStart(2, '0')}/${(newDate.getMonth() + 1)
|
|
27578
|
+
.toString()
|
|
27579
|
+
.padStart(2, '0')}/${newDate.getFullYear()}`;
|
|
27580
|
+
}
|
|
27581
|
+
calculateUmAlQurraDate(startUDate, offset, uC) {
|
|
27582
|
+
const [day, month, year] = startUDate?.split('/').map(Number);
|
|
27583
|
+
let newDay = day + offset;
|
|
27584
|
+
let newMonth = month;
|
|
27585
|
+
let newYear = year;
|
|
27586
|
+
while (newDay > uC) {
|
|
27587
|
+
newDay -= uC;
|
|
27588
|
+
newMonth += 1;
|
|
27589
|
+
}
|
|
27590
|
+
while (newMonth > 12) {
|
|
27591
|
+
newMonth = 1;
|
|
27592
|
+
newYear += 1;
|
|
27593
|
+
}
|
|
27594
|
+
return `${newDay.toString().padStart(2, '0')}/${newMonth
|
|
27595
|
+
.toString()
|
|
27596
|
+
.padStart(2, '0')}/${newYear}`;
|
|
27597
|
+
}
|
|
27598
|
+
getDayName(dayIndex) {
|
|
27599
|
+
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
27600
|
+
return days[dayIndex];
|
|
27601
|
+
}
|
|
27602
|
+
/// Check date is it in past or future
|
|
27603
|
+
checkPastOrFuture(inputDate, targetDate) {
|
|
27604
|
+
if (inputDate) {
|
|
27605
|
+
const [day, month, year] = inputDate?.split('/').map(Number);
|
|
27606
|
+
const dateToCheck = new Date(year, month - 1, day);
|
|
27607
|
+
const today = targetDate;
|
|
27608
|
+
today.setHours(0, 0, 0, 0);
|
|
27609
|
+
if (dateToCheck > today) {
|
|
27610
|
+
return 'Future';
|
|
27611
|
+
}
|
|
27612
|
+
else if (dateToCheck < today) {
|
|
27613
|
+
return 'Past';
|
|
27614
|
+
}
|
|
27615
|
+
else {
|
|
27616
|
+
return 'Today';
|
|
27617
|
+
}
|
|
27618
|
+
}
|
|
27619
|
+
}
|
|
27620
|
+
/// Convert english numbers to arabic equivalent
|
|
27621
|
+
parseEnglish(englishNum) {
|
|
27622
|
+
if (!englishNum)
|
|
27623
|
+
return englishNum;
|
|
27624
|
+
const numStr = String(englishNum);
|
|
27625
|
+
const arabicNumbers = [
|
|
27626
|
+
'\u0660',
|
|
27627
|
+
'\u0661',
|
|
27628
|
+
'\u0662',
|
|
27629
|
+
'\u0663',
|
|
27630
|
+
'\u0664',
|
|
27631
|
+
'\u0665',
|
|
27632
|
+
'\u0666',
|
|
27633
|
+
'\u0667',
|
|
27634
|
+
'\u0668',
|
|
27635
|
+
'\u0669',
|
|
27636
|
+
];
|
|
27637
|
+
return numStr.replace(/[0-9]/g, (digit) => {
|
|
27638
|
+
return arabicNumbers[Number(digit)] || digit;
|
|
27639
|
+
});
|
|
27640
|
+
}
|
|
27641
|
+
/// Convert arabic numbers to english equivalent
|
|
27642
|
+
parseArabic(arabicNum) {
|
|
27643
|
+
return arabicNum.replace(/[٠١٢٣٤٥٦٧٨٩]/g, function (d) {
|
|
27644
|
+
return d.charCodeAt(0) - 1632;
|
|
27645
|
+
});
|
|
27646
|
+
}
|
|
27647
|
+
///
|
|
27648
|
+
convertDateNumerals(date, targetLang) {
|
|
27649
|
+
const arabicNumbers = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
|
27650
|
+
const englishNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
|
27651
|
+
const toArabic = (value) => value
|
|
27652
|
+
.split('')
|
|
27653
|
+
.map((char) => (/\d/.test(char) ? arabicNumbers[+char] : char))
|
|
27654
|
+
.join('');
|
|
27655
|
+
const toEnglish = (value) => value
|
|
27656
|
+
.split('')
|
|
27657
|
+
.map((char) => {
|
|
27658
|
+
const index = arabicNumbers.indexOf(char);
|
|
27659
|
+
return index > -1 ? englishNumbers[index] : char;
|
|
27660
|
+
})
|
|
27661
|
+
.join('');
|
|
27662
|
+
if (targetLang === 'ar') {
|
|
27663
|
+
const [day, month, year] = date.split('/');
|
|
27664
|
+
return `${toArabic(year)}/${toArabic(month)}/${toArabic(day)}`;
|
|
27665
|
+
}
|
|
27666
|
+
else {
|
|
27667
|
+
const [year, month, day] = date.split('/');
|
|
27668
|
+
return `${toEnglish(day)}/${toEnglish(month)}/${toEnglish(year)}`;
|
|
27669
|
+
}
|
|
27670
|
+
}
|
|
27671
|
+
/**
|
|
27672
|
+
* Normalize input date to DD/MM/YYYY string format (Gregorian)
|
|
27673
|
+
* Accepts Date object or DD/MM/YYYY string
|
|
27674
|
+
*/
|
|
27675
|
+
normalizeDateToString(date) {
|
|
27676
|
+
if (!date)
|
|
27677
|
+
return null;
|
|
27678
|
+
if (date instanceof Date) {
|
|
27679
|
+
return this.formatDate(date);
|
|
27680
|
+
}
|
|
27681
|
+
// Already a string - validate format
|
|
27682
|
+
const parsed = this.parseDate(date);
|
|
27683
|
+
return parsed ? this.formatDate(parsed) : null;
|
|
27684
|
+
}
|
|
27685
|
+
/**
|
|
27686
|
+
* Compare two dates (Gregorian format DD/MM/YYYY)
|
|
27687
|
+
* Returns: -1 if date1 < date2, 0 if equal, 1 if date1 > date2
|
|
27688
|
+
*/
|
|
27689
|
+
compareDates(date1Str, date2Str) {
|
|
27690
|
+
const d1 = this.parseDate(date1Str);
|
|
27691
|
+
const d2 = this.parseDate(date2Str);
|
|
27692
|
+
if (!d1 || !d2)
|
|
27693
|
+
return 0;
|
|
27694
|
+
if (d1 < d2)
|
|
27695
|
+
return -1;
|
|
27696
|
+
if (d1 > d2)
|
|
27697
|
+
return 1;
|
|
27698
|
+
return 0;
|
|
27699
|
+
}
|
|
27700
|
+
/**
|
|
27701
|
+
* Compare two Hijri dates (UM format DD/MM/YYYY)
|
|
27702
|
+
* Converts to Gregorian for comparison
|
|
27703
|
+
*/
|
|
27704
|
+
compareHijriDates(hijri1, hijri2) {
|
|
27705
|
+
const day1 = this.convertDate(hijri1, false);
|
|
27706
|
+
const day2 = this.convertDate(hijri2, false);
|
|
27707
|
+
if (!day1?.gD || !day2?.gD)
|
|
27708
|
+
return 0;
|
|
27709
|
+
return this.compareDates(day1.gD, day2.gD);
|
|
27710
|
+
}
|
|
27711
|
+
/**
|
|
27712
|
+
* Check if a date is within the specified range (inclusive)
|
|
27713
|
+
* All dates in Gregorian DD/MM/YYYY format
|
|
27714
|
+
*/
|
|
27715
|
+
isDateInRange(dateStr, minDateStr, maxDateStr) {
|
|
27716
|
+
if (!dateStr)
|
|
27717
|
+
return false;
|
|
27718
|
+
// If no constraints, date is valid
|
|
27719
|
+
if (!minDateStr && !maxDateStr)
|
|
27720
|
+
return true;
|
|
27721
|
+
// Check minimum constraint
|
|
27722
|
+
if (minDateStr && this.compareDates(dateStr, minDateStr) < 0) {
|
|
27723
|
+
return false;
|
|
27724
|
+
}
|
|
27725
|
+
// Check maximum constraint
|
|
27726
|
+
if (maxDateStr && this.compareDates(dateStr, maxDateStr) > 0) {
|
|
27727
|
+
return false;
|
|
27728
|
+
}
|
|
27729
|
+
return true;
|
|
27730
|
+
}
|
|
27731
|
+
/**
|
|
27732
|
+
* Check if a Hijri date is within the specified range
|
|
27733
|
+
* Converts to Gregorian for comparison
|
|
27734
|
+
*/
|
|
27735
|
+
isHijriDateInRange(hijriDateStr, minDateStr, maxDateStr) {
|
|
27736
|
+
if (!hijriDateStr)
|
|
27737
|
+
return false;
|
|
27738
|
+
const dayInfo = this.convertDate(hijriDateStr, false);
|
|
27739
|
+
if (!dayInfo?.gD)
|
|
27740
|
+
return false;
|
|
27741
|
+
return this.isDateInRange(dayInfo.gD, minDateStr, maxDateStr);
|
|
27742
|
+
}
|
|
27743
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DateUtilitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
27744
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DateUtilitiesService, providedIn: 'root' }); }
|
|
27745
|
+
}
|
|
27746
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DateUtilitiesService, decorators: [{
|
|
27747
|
+
type: Injectable,
|
|
27748
|
+
args: [{
|
|
27749
|
+
providedIn: 'root',
|
|
27750
|
+
}]
|
|
27751
|
+
}], ctorParameters: () => [] });
|
|
27752
27752
|
|
|
27753
27753
|
var themes = [
|
|
27754
27754
|
{
|
|
@@ -27908,1078 +27908,1078 @@ var themesConfig = /*#__PURE__*/Object.freeze({
|
|
|
27908
27908
|
default: themes
|
|
27909
27909
|
});
|
|
27910
27910
|
|
|
27911
|
-
class HijriGregorianDatepickerComponent {
|
|
27912
|
-
constructor(formBuilder, _dateUtilsService) {
|
|
27913
|
-
this.formBuilder = formBuilder;
|
|
27914
|
-
this._dateUtilsService = _dateUtilsService;
|
|
27915
|
-
/// Inputs
|
|
27916
|
-
this.markToday = true;
|
|
27917
|
-
this.canChangeMode = true;
|
|
27918
|
-
this.todaysDateSection = true;
|
|
27919
|
-
this.futureValidation = true;
|
|
27920
|
-
this.disableYearPicker = false;
|
|
27921
|
-
this.disableMonthPicker = false;
|
|
27922
|
-
this.disableDayPicker = false;
|
|
27923
|
-
this.multiple = false;
|
|
27924
|
-
this.isRequired = false;
|
|
27925
|
-
this.showConfirmButton = true;
|
|
27926
|
-
this.futureValidationMessage = false;
|
|
27927
|
-
this.arabicLayout = false;
|
|
27928
|
-
this.mode = 'greg';
|
|
27929
|
-
this.dir = 'ltr';
|
|
27930
|
-
this.locale = 'en';
|
|
27931
|
-
this.submitTextButton = 'Confirm';
|
|
27932
|
-
this.todaysDateText = "Today's Date";
|
|
27933
|
-
this.ummAlQuraDateText = 'Hijri Date';
|
|
27934
|
-
this.monthSelectLabel = 'Month';
|
|
27935
|
-
this.yearSelectLabel = 'Year';
|
|
27936
|
-
this.theme = '';
|
|
27937
|
-
this.pastYearsLimit = 90;
|
|
27938
|
-
this.futureYearsLimit = 0;
|
|
27939
|
-
this.styles = {};
|
|
27940
|
-
// New inputs for extended functionality
|
|
27941
|
-
this.enableTime = false; // Enable time picker (hours & minutes)
|
|
27942
|
-
// BACKWARD COMPATIBILITY: Default to false (24-hour format)
|
|
27943
|
-
// When true, displays 12-hour format with AM/PM toggle
|
|
27944
|
-
this.useMeridian = false; // Enable 12-hour format with AM/PM
|
|
27945
|
-
// BACKWARD COMPATIBILITY: Default to 'single' (existing behavior)
|
|
27946
|
-
// 'range' enables range selection mode (first click = start, second click = end)
|
|
27947
|
-
this.selectionMode = 'single';
|
|
27948
|
-
/// Outputs
|
|
27949
|
-
this.onSubmit = new EventEmitter();
|
|
27950
|
-
this.onDaySelect = new EventEmitter();
|
|
27951
|
-
this.onMonthChange = new EventEmitter();
|
|
27952
|
-
this.onYearChange = new EventEmitter();
|
|
27953
|
-
/// Variables
|
|
27954
|
-
this.ummAlQuraMonths = [
|
|
27955
|
-
{ labelAr: 'محرم', labelEn: 'Muharram', value: 1 },
|
|
27956
|
-
{ labelAr: 'صفر', labelEn: 'Safar', value: 2 },
|
|
27957
|
-
{ labelAr: 'ربيع الأول', labelEn: 'Rabi al-Awwal', value: 3 },
|
|
27958
|
-
{ labelAr: 'ربيع الثاني', labelEn: 'Rabi al-Thani', value: 4 },
|
|
27959
|
-
{ labelAr: 'جمادى الأولى', labelEn: 'Jumada al-Awwal', value: 5 },
|
|
27960
|
-
{ labelAr: 'جمادى الآخرة', labelEn: 'Jumada al-Thani', value: 6 },
|
|
27961
|
-
{ labelAr: 'رجب', labelEn: 'Rajab', value: 7 },
|
|
27962
|
-
{ labelAr: 'شعبان', labelEn: 'Shaban', value: 8 },
|
|
27963
|
-
{ labelAr: 'رمضان', labelEn: 'Ramadan', value: 9 },
|
|
27964
|
-
{ labelAr: 'شوال', labelEn: 'Shawwal', value: 10 },
|
|
27965
|
-
{ labelAr: 'ذو القعدة', labelEn: 'Dhu al-Qadah', value: 11 },
|
|
27966
|
-
{ labelAr: 'ذو الحجة', labelEn: 'Dhu al-Hijjah', value: 12 },
|
|
27967
|
-
];
|
|
27968
|
-
this.gregMonths = [
|
|
27969
|
-
{ labelAr: 'يناير', labelEn: 'January', value: 1 },
|
|
27970
|
-
{ labelAr: 'فبراير', labelEn: 'February', value: 2 },
|
|
27971
|
-
{ labelAr: 'مارس', labelEn: 'March', value: 3 },
|
|
27972
|
-
{ labelAr: 'ابريل', labelEn: 'April', value: 4 },
|
|
27973
|
-
{ labelAr: 'مايو', labelEn: 'May', value: 5 },
|
|
27974
|
-
{ labelAr: 'يونيو', labelEn: 'June', value: 6 },
|
|
27975
|
-
{ labelAr: 'يوليو', labelEn: 'July', value: 7 },
|
|
27976
|
-
{ labelAr: 'اغسطس', labelEn: 'August', value: 8 },
|
|
27977
|
-
{ labelAr: 'سبتمبر', labelEn: 'September', value: 9 },
|
|
27978
|
-
{ labelAr: 'اكتوبر', labelEn: 'October', value: 10 },
|
|
27979
|
-
{ labelAr: 'نوفمبر', labelEn: 'November', value: 11 },
|
|
27980
|
-
{ labelAr: 'ديسمبر', labelEn: 'December', value: 12 },
|
|
27981
|
-
];
|
|
27982
|
-
this.weekdaysEn = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
27983
|
-
this.weekdaysAr = ['سبت', 'جمعة', 'خميس', 'أربعاء', 'ثلاثاء', 'اثنين', 'أحد'];
|
|
27984
|
-
// weekdaysAr = ['س', 'ج', 'خ', 'أر', 'ث', 'إث', 'أح'];
|
|
27985
|
-
this.todaysDate = {};
|
|
27986
|
-
this.multipleSelectedDates = [];
|
|
27987
|
-
this.themes = [];
|
|
27988
|
-
// Time picker variables
|
|
27989
|
-
// BACKWARD COMPATIBILITY: selectedTime defaults to 0:0 to preserve existing behavior when enableTime=false
|
|
27990
|
-
// When enableTime=true, this will be initialized to current system time in ngOnInit
|
|
27991
|
-
this.selectedTime = { hour: 0, minute: 0 };
|
|
27992
|
-
// Track if time has been initialized to avoid re-initializing at midnight
|
|
27993
|
-
this.timeInitialized = false;
|
|
27994
|
-
// BACKWARD COMPATIBILITY: Meridian only used when useMeridian=true
|
|
27995
|
-
// Tracks AM/PM state for 12-hour format
|
|
27996
|
-
this.meridian = 'AM';
|
|
27997
|
-
// Range selection state
|
|
27998
|
-
// BACKWARD COMPATIBILITY: These are only used when selectionMode='range'
|
|
27999
|
-
// They do not affect single or multiple selection modes
|
|
28000
|
-
this.rangeStart = undefined;
|
|
28001
|
-
this.rangeEnd = undefined;
|
|
28002
|
-
}
|
|
28003
|
-
ngOnInit() {
|
|
28004
|
-
this.initTheme();
|
|
28005
|
-
this.initializeForm();
|
|
28006
|
-
this.getTodaysDateInfo();
|
|
28007
|
-
this.initializeYearsAndMonths();
|
|
28008
|
-
// Initialize time from current system time or initialDate
|
|
28009
|
-
// BACKWARD COMPATIBILITY: This only runs when enableTime=true
|
|
28010
|
-
if (this.enableTime) {
|
|
28011
|
-
this.initializeTime();
|
|
28012
|
-
}
|
|
28013
|
-
}
|
|
28014
|
-
ngAfterViewInit() {
|
|
28015
|
-
// Double-check time initialization after view is ready
|
|
28016
|
-
// This handles cases where enableTime might be set after ngOnInit
|
|
28017
|
-
if (this.enableTime && !this.timeInitialized) {
|
|
28018
|
-
this.initializeTime();
|
|
28019
|
-
}
|
|
28020
|
-
}
|
|
28021
|
-
ngOnChanges(changes) {
|
|
28022
|
-
if (!changes['mode'].isFirstChange()) {
|
|
28023
|
-
this.changeCalendarMode();
|
|
28024
|
-
}
|
|
28025
|
-
}
|
|
28026
|
-
initTheme() {
|
|
28027
|
-
if (this.theme != '') {
|
|
28028
|
-
this.themes = themesConfig;
|
|
28029
|
-
for (const themeItem of this.themes['default']) {
|
|
28030
|
-
if (themeItem.name == this.theme) {
|
|
28031
|
-
this.styles = themeItem.stylesConfig;
|
|
28032
|
-
break;
|
|
28033
|
-
}
|
|
28034
|
-
}
|
|
28035
|
-
}
|
|
28036
|
-
this.fontFamilyStyle = this.styles.fontFamily;
|
|
28037
|
-
}
|
|
28038
|
-
/// Initialize form control for month and year select
|
|
28039
|
-
initializeForm() {
|
|
28040
|
-
this.periodForm = this.formBuilder.group({
|
|
28041
|
-
year: [{ value: '', disabled: this.disableYearPicker }, []],
|
|
28042
|
-
month: [{ value: '', disabled: this.disableMonthPicker }, []],
|
|
28043
|
-
});
|
|
28044
|
-
}
|
|
28045
|
-
// Initialize years and months for calendar
|
|
28046
|
-
initializeYearsAndMonths() {
|
|
28047
|
-
this.years = [];
|
|
28048
|
-
this.months = [];
|
|
28049
|
-
// Determine the date to use for initialization (initialDate or today)
|
|
28050
|
-
let referenceDate;
|
|
28051
|
-
if (this.initialDate) {
|
|
28052
|
-
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28053
|
-
if (normalizedInitialDate) {
|
|
28054
|
-
if (this.mode == 'greg') {
|
|
28055
|
-
referenceDate = normalizedInitialDate;
|
|
28056
|
-
}
|
|
28057
|
-
else {
|
|
28058
|
-
const hijriDate = this._dateUtilsService.convertDate(normalizedInitialDate, true);
|
|
28059
|
-
referenceDate = hijriDate?.uD || this.todaysDate.ummAlQura;
|
|
28060
|
-
}
|
|
28061
|
-
}
|
|
28062
|
-
else {
|
|
28063
|
-
referenceDate =
|
|
28064
|
-
this.mode == 'greg'
|
|
28065
|
-
? this.todaysDate.gregorian
|
|
28066
|
-
: this.todaysDate.ummAlQura;
|
|
28067
|
-
}
|
|
28068
|
-
}
|
|
28069
|
-
else {
|
|
28070
|
-
referenceDate =
|
|
28071
|
-
this.mode == 'greg'
|
|
28072
|
-
? this.todaysDate.gregorian
|
|
28073
|
-
: this.todaysDate.ummAlQura;
|
|
28074
|
-
}
|
|
28075
|
-
if (this.mode == 'greg') {
|
|
28076
|
-
this.gregYear =
|
|
28077
|
-
this.futureYearsLimit == 0
|
|
28078
|
-
? Number(referenceDate?.split('/')[2])
|
|
28079
|
-
: Number(referenceDate?.split('/')[2]) + this.futureYearsLimit;
|
|
28080
|
-
for (let i = 0; i < this.gregYear; i++) {
|
|
28081
|
-
if (i < this.pastYearsLimit) {
|
|
28082
|
-
let val = this.gregYear--;
|
|
28083
|
-
this.years.push(val);
|
|
28084
|
-
}
|
|
28085
|
-
else {
|
|
28086
|
-
break;
|
|
28087
|
-
}
|
|
28088
|
-
}
|
|
28089
|
-
this.months = this.gregMonths;
|
|
28090
|
-
}
|
|
28091
|
-
else {
|
|
28092
|
-
this.ummAlQuraYear =
|
|
28093
|
-
this.futureYearsLimit == 0
|
|
28094
|
-
? Number(referenceDate?.split('/')[2])
|
|
28095
|
-
: Number(referenceDate?.split('/')[2]) + this.futureYearsLimit;
|
|
28096
|
-
for (let i = 0; i < this.ummAlQuraYear; i++) {
|
|
28097
|
-
if (i < this.pastYearsLimit) {
|
|
28098
|
-
let val = this.ummAlQuraYear--;
|
|
28099
|
-
this.years.push(val);
|
|
28100
|
-
}
|
|
28101
|
-
else {
|
|
28102
|
-
break;
|
|
28103
|
-
}
|
|
28104
|
-
}
|
|
28105
|
-
this.months = this.ummAlQuraMonths;
|
|
28106
|
-
}
|
|
28107
|
-
this.years.map((year) => {
|
|
28108
|
-
if (year == referenceDate?.split('/')[2]) {
|
|
28109
|
-
this.periodForm.controls['year'].setValue(year);
|
|
28110
|
-
}
|
|
28111
|
-
});
|
|
28112
|
-
this.months.map((month) => {
|
|
28113
|
-
if (month.value == referenceDate?.split('/')[1]) {
|
|
28114
|
-
this.periodForm.controls['month'].setValue(month.value);
|
|
28115
|
-
}
|
|
28116
|
-
});
|
|
28117
|
-
}
|
|
28118
|
-
/// On change event of years and months
|
|
28119
|
-
onPeriodChange(type) {
|
|
28120
|
-
if (type == 'year') {
|
|
28121
|
-
this.onYearChange.emit(this.periodForm.controls['year'].value);
|
|
28122
|
-
}
|
|
28123
|
-
else {
|
|
28124
|
-
this.onMonthChange.emit(this.periodForm.controls['month'].value);
|
|
28125
|
-
}
|
|
28126
|
-
const days = this._dateUtilsService.getMonthData('01/' +
|
|
28127
|
-
this.periodForm.controls['month'].value +
|
|
28128
|
-
'/' +
|
|
28129
|
-
this.periodForm.controls['year'].value, this.mode);
|
|
28130
|
-
this.weeks = this.generateWeeksArray(days);
|
|
28131
|
-
}
|
|
28132
|
-
/// Get todays(greg and umm al qura) date info
|
|
28133
|
-
getTodaysDateInfo() {
|
|
28134
|
-
this.todaysDate.gregorian = this._dateUtilsService.formatDate(new Date());
|
|
28135
|
-
this.todaysDate.ummAlQura = this._dateUtilsService.convertDate(this.todaysDate.gregorian, true)?.uD;
|
|
28136
|
-
// Use initialDate if provided, otherwise use today's date
|
|
28137
|
-
let dateToNavigate;
|
|
28138
|
-
if (this.initialDate) {
|
|
28139
|
-
// Normalize initialDate to DD/MM/YYYY format
|
|
28140
|
-
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28141
|
-
if (normalizedInitialDate) {
|
|
28142
|
-
if (this.mode == 'greg') {
|
|
28143
|
-
dateToNavigate = normalizedInitialDate;
|
|
28144
|
-
}
|
|
28145
|
-
else {
|
|
28146
|
-
// Convert to Hijri for ummAlQura mode
|
|
28147
|
-
const hijriDate = this._dateUtilsService.convertDate(normalizedInitialDate, true);
|
|
28148
|
-
dateToNavigate = hijriDate?.uD || this.todaysDate.ummAlQura;
|
|
28149
|
-
}
|
|
28150
|
-
}
|
|
28151
|
-
else {
|
|
28152
|
-
// Invalid initialDate, fall back to today
|
|
28153
|
-
dateToNavigate =
|
|
28154
|
-
this.mode == 'greg'
|
|
28155
|
-
? this.todaysDate.gregorian
|
|
28156
|
-
: this.todaysDate.ummAlQura;
|
|
28157
|
-
}
|
|
28158
|
-
}
|
|
28159
|
-
else {
|
|
28160
|
-
// No initialDate provided, use today
|
|
28161
|
-
dateToNavigate =
|
|
28162
|
-
this.mode == 'greg'
|
|
28163
|
-
? this.todaysDate.gregorian
|
|
28164
|
-
: this.todaysDate.ummAlQura;
|
|
28165
|
-
}
|
|
28166
|
-
this.generatetMonthData(dateToNavigate);
|
|
28167
|
-
// Highlight initialDate or initialRange if provided
|
|
28168
|
-
if (this.selectionMode === 'range' && (this.initialRangeStart || this.initialRangeEnd)) {
|
|
28169
|
-
this.highlightInitialRange();
|
|
28170
|
-
}
|
|
28171
|
-
else if (this.initialDate) {
|
|
28172
|
-
this.highlightInitialDate();
|
|
28173
|
-
}
|
|
28174
|
-
}
|
|
28175
|
-
/// Generate month days from JSON
|
|
28176
|
-
generatetMonthData(date) {
|
|
28177
|
-
const days = this._dateUtilsService.getMonthData(date, this.mode);
|
|
28178
|
-
this.weeks = this.generateWeeksArray(days);
|
|
28179
|
-
}
|
|
28180
|
-
/// Highlight initialDate on the calendar
|
|
28181
|
-
highlightInitialDate() {
|
|
28182
|
-
if (!this.initialDate) {
|
|
28183
|
-
return;
|
|
28184
|
-
}
|
|
28185
|
-
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28186
|
-
if (!normalizedInitialDate) {
|
|
28187
|
-
return;
|
|
28188
|
-
}
|
|
28189
|
-
// Find the day in the weeks array that matches initialDate
|
|
28190
|
-
for (const week of this.weeks) {
|
|
28191
|
-
for (const day of week) {
|
|
28192
|
-
if (day && day.gD === normalizedInitialDate) {
|
|
28193
|
-
// Don't select if date is disabled
|
|
28194
|
-
if (!this.isDateDisabled(day)) {
|
|
28195
|
-
// Mark as selected without triggering events
|
|
28196
|
-
day.selected = true;
|
|
28197
|
-
// Set as selectedDay based on selection mode
|
|
28198
|
-
if (this.selectionMode === 'range') {
|
|
28199
|
-
this.rangeStart = day;
|
|
28200
|
-
}
|
|
28201
|
-
else if (this.multiple) {
|
|
28202
|
-
this.multipleSelectedDates = [day];
|
|
28203
|
-
}
|
|
28204
|
-
else {
|
|
28205
|
-
this.selectedDay = day;
|
|
28206
|
-
}
|
|
28207
|
-
// Initialize time if enableTime is active
|
|
28208
|
-
if (this.enableTime && !this.timeInitialized) {
|
|
28209
|
-
this.initializeTime();
|
|
28210
|
-
}
|
|
28211
|
-
// Attach time to the day if it's a Date object with time
|
|
28212
|
-
if (this.enableTime && this.initialDate instanceof Date) {
|
|
28213
|
-
day.time = {
|
|
28214
|
-
hour: this.initialDate.getHours(),
|
|
28215
|
-
minute: this.initialDate.getMinutes()
|
|
28216
|
-
};
|
|
28217
|
-
}
|
|
28218
|
-
}
|
|
28219
|
-
return;
|
|
28220
|
-
}
|
|
28221
|
-
}
|
|
28222
|
-
}
|
|
28223
|
-
}
|
|
28224
|
-
/// Highlight initial range (start and end dates) on the calendar
|
|
28225
|
-
highlightInitialRange() {
|
|
28226
|
-
if (!this.initialRangeStart && !this.initialRangeEnd) {
|
|
28227
|
-
return;
|
|
28228
|
-
}
|
|
28229
|
-
const normalizedStartDate = this.initialRangeStart
|
|
28230
|
-
? this._dateUtilsService.normalizeDateToString(this.initialRangeStart)
|
|
28231
|
-
: null;
|
|
28232
|
-
const normalizedEndDate = this.initialRangeEnd
|
|
28233
|
-
? this._dateUtilsService.normalizeDateToString(this.initialRangeEnd)
|
|
28234
|
-
: null;
|
|
28235
|
-
let startDay = null;
|
|
28236
|
-
let endDay = null;
|
|
28237
|
-
// Find both start and end dates in the weeks array
|
|
28238
|
-
for (const week of this.weeks) {
|
|
28239
|
-
for (const day of week) {
|
|
28240
|
-
if (day && normalizedStartDate && day.gD === normalizedStartDate) {
|
|
28241
|
-
if (!this.isDateDisabled(day)) {
|
|
28242
|
-
startDay = day;
|
|
28243
|
-
}
|
|
28244
|
-
}
|
|
28245
|
-
if (day && normalizedEndDate && day.gD === normalizedEndDate) {
|
|
28246
|
-
if (!this.isDateDisabled(day)) {
|
|
28247
|
-
endDay = day;
|
|
28248
|
-
}
|
|
28249
|
-
}
|
|
28250
|
-
}
|
|
28251
|
-
}
|
|
28252
|
-
// Set range start
|
|
28253
|
-
if (startDay) {
|
|
28254
|
-
startDay.selected = true;
|
|
28255
|
-
this.rangeStart = startDay;
|
|
28256
|
-
this.selectedDay = startDay;
|
|
28257
|
-
// Initialize and attach time to start date
|
|
28258
|
-
if (this.enableTime) {
|
|
28259
|
-
if (!this.timeInitialized) {
|
|
28260
|
-
this.initializeTime();
|
|
28261
|
-
}
|
|
28262
|
-
if (this.initialRangeStart instanceof Date) {
|
|
28263
|
-
startDay.time = {
|
|
28264
|
-
hour: this.initialRangeStart.getHours(),
|
|
28265
|
-
minute: this.initialRangeStart.getMinutes()
|
|
28266
|
-
};
|
|
28267
|
-
}
|
|
28268
|
-
else {
|
|
28269
|
-
startDay.time = { ...this.selectedTime };
|
|
28270
|
-
}
|
|
28271
|
-
}
|
|
28272
|
-
}
|
|
28273
|
-
// Set range end if provided
|
|
28274
|
-
if (endDay && startDay) {
|
|
28275
|
-
// Swap if end is before start
|
|
28276
|
-
const startDate = this.parseDateString(startDay.gD);
|
|
28277
|
-
const endDate = this.parseDateString(endDay.gD);
|
|
28278
|
-
if (endDate && startDate && endDate < startDate) {
|
|
28279
|
-
// Swap
|
|
28280
|
-
this.rangeEnd = startDay;
|
|
28281
|
-
this.rangeStart = endDay;
|
|
28282
|
-
endDay.selected = true;
|
|
28283
|
-
}
|
|
28284
|
-
else {
|
|
28285
|
-
this.rangeEnd = endDay;
|
|
28286
|
-
}
|
|
28287
|
-
// Attach time to end date (inherit from start)
|
|
28288
|
-
if (this.enableTime) {
|
|
28289
|
-
const timeToUse = this.rangeStart.time || { ...this.selectedTime };
|
|
28290
|
-
if (this.initialRangeEnd instanceof Date) {
|
|
28291
|
-
this.rangeEnd.time = {
|
|
28292
|
-
hour: this.initialRangeEnd.getHours(),
|
|
28293
|
-
minute: this.initialRangeEnd.getMinutes()
|
|
28294
|
-
};
|
|
28295
|
-
}
|
|
28296
|
-
else {
|
|
28297
|
-
this.rangeEnd.time = { ...timeToUse };
|
|
28298
|
-
}
|
|
28299
|
-
// Ensure start also has time
|
|
28300
|
-
this.rangeStart.time = { ...timeToUse };
|
|
28301
|
-
}
|
|
28302
|
-
// Highlight the range
|
|
28303
|
-
this.highlightRange();
|
|
28304
|
-
this.selectedDay = this.rangeEnd;
|
|
28305
|
-
}
|
|
28306
|
-
}
|
|
28307
|
-
/// Generate month weeks
|
|
28308
|
-
generateWeeksArray(daysArray) {
|
|
28309
|
-
const firstDayName = daysArray[0]?.dN;
|
|
28310
|
-
const startIndex = this.weekdaysEn.indexOf(firstDayName);
|
|
28311
|
-
const weeks = [[]];
|
|
28312
|
-
let currentWeek = 0;
|
|
28313
|
-
let currentDayIndex = startIndex;
|
|
28314
|
-
daysArray?.forEach((day) => {
|
|
28315
|
-
if (!weeks[currentWeek]) {
|
|
28316
|
-
weeks[currentWeek] = [];
|
|
28317
|
-
}
|
|
28318
|
-
weeks[currentWeek][currentDayIndex] = day;
|
|
28319
|
-
currentDayIndex++;
|
|
28320
|
-
if (currentDayIndex === 7) {
|
|
28321
|
-
currentDayIndex = 0;
|
|
28322
|
-
currentWeek++;
|
|
28323
|
-
}
|
|
28324
|
-
});
|
|
28325
|
-
weeks.forEach((week) => {
|
|
28326
|
-
while (week.length < 7) {
|
|
28327
|
-
week.push({});
|
|
28328
|
-
}
|
|
28329
|
-
});
|
|
28330
|
-
return weeks;
|
|
28331
|
-
}
|
|
28332
|
-
/// Change calendar mode 'greg' or 'ummAlQura'
|
|
28333
|
-
changeCalendarMode() {
|
|
28334
|
-
this.mode = this.mode == 'greg' ? 'ummAlQura' : 'greg';
|
|
28335
|
-
this.initializeYearsAndMonths();
|
|
28336
|
-
this.generatetMonthData('01/' +
|
|
28337
|
-
this.periodForm.controls['month'].value +
|
|
28338
|
-
'/' +
|
|
28339
|
-
this.periodForm.controls['year'].value);
|
|
28340
|
-
}
|
|
28341
|
-
/// On day clicked handler
|
|
28342
|
-
onDayClicked(day) {
|
|
28343
|
-
if (day && day?.gD) {
|
|
28344
|
-
// Check if day is disabled by min/max constraints
|
|
28345
|
-
if (this.isDateDisabled(day)) {
|
|
28346
|
-
return; // Don't allow selection of disabled dates
|
|
28347
|
-
}
|
|
28348
|
-
if (this.futureValidation) {
|
|
28349
|
-
if (this.checkFutureValidation(day)) {
|
|
28350
|
-
this.futureValidationMessage = true;
|
|
28351
|
-
}
|
|
28352
|
-
else {
|
|
28353
|
-
this.futureValidationMessage = false;
|
|
28354
|
-
this.markDaySelected(day);
|
|
28355
|
-
}
|
|
28356
|
-
}
|
|
28357
|
-
else {
|
|
28358
|
-
this.markDaySelected(day);
|
|
28359
|
-
}
|
|
28360
|
-
}
|
|
28361
|
-
}
|
|
28362
|
-
/// Mark day as selected
|
|
28363
|
-
markDaySelected(dayInfo) {
|
|
28364
|
-
// BACKWARD COMPATIBILITY: Range selection only when selectionMode='range'
|
|
28365
|
-
if (this.selectionMode === 'range') {
|
|
28366
|
-
this.handleRangeSelection(dayInfo);
|
|
28367
|
-
return;
|
|
28368
|
-
}
|
|
28369
|
-
// BACKWARD COMPATIBILITY: Original behavior for single/multiple selection
|
|
28370
|
-
if (dayInfo.selected) {
|
|
28371
|
-
dayInfo.selected = false;
|
|
28372
|
-
this.multipleSelectedDates = this.multipleSelectedDates.filter((day) => day !== dayInfo);
|
|
28373
|
-
if (!this.multiple) {
|
|
28374
|
-
this.selectedDay = undefined;
|
|
28375
|
-
}
|
|
28376
|
-
}
|
|
28377
|
-
else {
|
|
28378
|
-
if (!this.multiple) {
|
|
28379
|
-
this.weeks.forEach((week) => {
|
|
28380
|
-
week.forEach((day) => {
|
|
28381
|
-
day.selected = false;
|
|
28382
|
-
});
|
|
28383
|
-
});
|
|
28384
|
-
dayInfo.selected = true;
|
|
28385
|
-
this.selectedDay = dayInfo;
|
|
28386
|
-
this.multipleSelectedDates = [dayInfo];
|
|
28387
|
-
// Attach current time if enableTime is active
|
|
28388
|
-
if (this.enableTime) {
|
|
28389
|
-
// Ensure time is initialized before attaching
|
|
28390
|
-
if (!this.timeInitialized) {
|
|
28391
|
-
this.initializeTime();
|
|
28392
|
-
}
|
|
28393
|
-
dayInfo.time = { ...this.selectedTime };
|
|
28394
|
-
}
|
|
28395
|
-
this.onDaySelect.emit(dayInfo);
|
|
28396
|
-
}
|
|
28397
|
-
else {
|
|
28398
|
-
dayInfo.selected = true;
|
|
28399
|
-
// Attach current time if enableTime is active
|
|
28400
|
-
if (this.enableTime) {
|
|
28401
|
-
// Ensure time is initialized before attaching
|
|
28402
|
-
if (!this.timeInitialized) {
|
|
28403
|
-
this.initializeTime();
|
|
28404
|
-
}
|
|
28405
|
-
dayInfo.time = { ...this.selectedTime };
|
|
28406
|
-
}
|
|
28407
|
-
this.onDaySelect.emit(dayInfo);
|
|
28408
|
-
if (!this.multipleSelectedDates.includes(dayInfo)) {
|
|
28409
|
-
this.multipleSelectedDates.push(dayInfo);
|
|
28410
|
-
}
|
|
28411
|
-
}
|
|
28412
|
-
}
|
|
28413
|
-
}
|
|
28414
|
-
/**
|
|
28415
|
-
* Handle range selection logic
|
|
28416
|
-
* BACKWARD COMPATIBILITY: Only called when selectionMode='range'
|
|
28417
|
-
*
|
|
28418
|
-
* Range selection lifecycle:
|
|
28419
|
-
* 1. First click → Sets rangeStart
|
|
28420
|
-
* 2. Second click → Sets rangeEnd, highlights range
|
|
28421
|
-
* 3. Third click → Resets range, starts new selection
|
|
28422
|
-
*/
|
|
28423
|
-
handleRangeSelection(dayInfo) {
|
|
28424
|
-
// First click or resetting range
|
|
28425
|
-
if (!this.rangeStart || (this.rangeStart && this.rangeEnd)) {
|
|
28426
|
-
this.resetRange();
|
|
28427
|
-
this.rangeStart = dayInfo;
|
|
28428
|
-
dayInfo.selected = true;
|
|
28429
|
-
this.selectedDay = dayInfo;
|
|
28430
|
-
// Attach current time if enableTime is active
|
|
28431
|
-
if (this.enableTime) {
|
|
28432
|
-
// Ensure selectedTime is initialized
|
|
28433
|
-
// If time hasn't been initialized yet, initialize it now
|
|
28434
|
-
if (!this.timeInitialized) {
|
|
28435
|
-
this.initializeTime();
|
|
28436
|
-
}
|
|
28437
|
-
dayInfo.time = { ...this.selectedTime };
|
|
28438
|
-
}
|
|
28439
|
-
this.onDaySelect.emit({ start: dayInfo, end: null });
|
|
28440
|
-
}
|
|
28441
|
-
// Second click - complete the range
|
|
28442
|
-
else if (this.rangeStart && !this.rangeEnd) {
|
|
28443
|
-
const startDate = this.parseDateString(this.rangeStart.gD);
|
|
28444
|
-
const endDate = this.parseDateString(dayInfo.gD);
|
|
28445
|
-
// Swap if end is before start
|
|
28446
|
-
if (endDate && startDate && endDate < startDate) {
|
|
28447
|
-
this.rangeEnd = this.rangeStart;
|
|
28448
|
-
this.rangeStart = dayInfo;
|
|
28449
|
-
}
|
|
28450
|
-
else {
|
|
28451
|
-
this.rangeEnd = dayInfo;
|
|
28452
|
-
}
|
|
28453
|
-
// Attach time if enableTime is active
|
|
28454
|
-
// IMPORTANT: Range end inherits time from range start (not current selectedTime)
|
|
28455
|
-
if (this.enableTime) {
|
|
28456
|
-
// Use rangeStart's time if it exists, otherwise use current selectedTime
|
|
28457
|
-
const timeToUse = this.rangeStart.time || { ...this.selectedTime };
|
|
28458
|
-
this.rangeStart.time = { ...timeToUse };
|
|
28459
|
-
this.rangeEnd.time = { ...timeToUse };
|
|
28460
|
-
}
|
|
28461
|
-
this.highlightRange();
|
|
28462
|
-
this.selectedDay = this.rangeEnd;
|
|
28463
|
-
this.onDaySelect.emit({ start: this.rangeStart, end: this.rangeEnd });
|
|
28464
|
-
}
|
|
28465
|
-
}
|
|
28466
|
-
/// On confirm button clicked
|
|
28467
|
-
onConfirmClicked() {
|
|
28468
|
-
// BACKWARD COMPATIBILITY: Range selection output when selectionMode='range'
|
|
28469
|
-
if (this.selectionMode === 'range') {
|
|
28470
|
-
if (this.rangeStart && this.rangeEnd) {
|
|
28471
|
-
// Collect all dates in range
|
|
28472
|
-
const rangeDates = [];
|
|
28473
|
-
this.weeks.forEach((week) => {
|
|
28474
|
-
week.forEach((day) => {
|
|
28475
|
-
if (day && day.gD && (this.isInRange(day) || this.isRangeStart(day) || this.isRangeEnd(day))) {
|
|
28476
|
-
// Attach current time if enableTime is active
|
|
28477
|
-
if (this.enableTime && !day.time) {
|
|
28478
|
-
day.time = { ...this.selectedTime };
|
|
28479
|
-
}
|
|
28480
|
-
rangeDates.push(day);
|
|
28481
|
-
}
|
|
28482
|
-
});
|
|
28483
|
-
});
|
|
28484
|
-
this.onSubmit.emit({
|
|
28485
|
-
start: this.rangeStart,
|
|
28486
|
-
end: this.rangeEnd,
|
|
28487
|
-
dates: rangeDates
|
|
28488
|
-
});
|
|
28489
|
-
}
|
|
28490
|
-
else {
|
|
28491
|
-
// Incomplete range
|
|
28492
|
-
this.onSubmit.emit({ start: this.rangeStart, end: null, dates: [] });
|
|
28493
|
-
}
|
|
28494
|
-
return;
|
|
28495
|
-
}
|
|
28496
|
-
// BACKWARD COMPATIBILITY: Original behavior for multiple/single selection
|
|
28497
|
-
if (this.multiple) {
|
|
28498
|
-
// For multiple dates, attach time to each if enableTime is active
|
|
28499
|
-
if (this.enableTime) {
|
|
28500
|
-
this.multipleSelectedDates.forEach((day) => {
|
|
28501
|
-
if (!day.time) {
|
|
28502
|
-
day.time = { ...this.selectedTime };
|
|
28503
|
-
}
|
|
28504
|
-
});
|
|
28505
|
-
}
|
|
28506
|
-
this.onSubmit.emit(this.multipleSelectedDates);
|
|
28507
|
-
}
|
|
28508
|
-
else {
|
|
28509
|
-
// For single date, attach time if enableTime is active
|
|
28510
|
-
if (this.enableTime && this.selectedDay) {
|
|
28511
|
-
this.selectedDay.time = { ...this.selectedTime };
|
|
28512
|
-
}
|
|
28513
|
-
this.onSubmit.emit(this.selectedDay);
|
|
28514
|
-
}
|
|
28515
|
-
}
|
|
28516
|
-
/// Check if date from future
|
|
28517
|
-
checkFutureValidation(day) {
|
|
28518
|
-
if (this._dateUtilsService.checkPastOrFuture(day?.gD, new Date()) == 'Future') {
|
|
28519
|
-
return true;
|
|
28520
|
-
}
|
|
28521
|
-
}
|
|
28522
|
-
/// Check if passed day is today or not
|
|
28523
|
-
checkTodaysDate(day) {
|
|
28524
|
-
return (this.todaysDate?.gregorian == day?.gD ||
|
|
28525
|
-
this.todaysDate?.ummAlQura == day?.uD);
|
|
28526
|
-
}
|
|
28527
|
-
/**
|
|
28528
|
-
* Check if a day is disabled based on min/max date constraints
|
|
28529
|
-
* Works for both Gregorian and Hijri modes
|
|
28530
|
-
*/
|
|
28531
|
-
isDateDisabled(day) {
|
|
28532
|
-
if (!day || !day.gD)
|
|
28533
|
-
return true;
|
|
28534
|
-
// Normalize min/max dates to Gregorian DD/MM/YYYY format
|
|
28535
|
-
const minDateStr = this.minDate
|
|
28536
|
-
? this._dateUtilsService.normalizeDateToString(this.minDate)
|
|
28537
|
-
: null;
|
|
28538
|
-
const maxDateStr = this.maxDate
|
|
28539
|
-
? this._dateUtilsService.normalizeDateToString(this.maxDate)
|
|
28540
|
-
: null;
|
|
28541
|
-
// Check if the day's Gregorian date is within range
|
|
28542
|
-
return !this._dateUtilsService.isDateInRange(day.gD, minDateStr, maxDateStr);
|
|
28543
|
-
}
|
|
28544
|
-
/**
|
|
28545
|
-
* Initialize time from current system time or initialDate
|
|
28546
|
-
* BACKWARD COMPATIBILITY: Only called when enableTime=true
|
|
28547
|
-
*
|
|
28548
|
-
* Priority:
|
|
28549
|
-
* 1. If initialDate has time, use that
|
|
28550
|
-
* 2. If selectedDay has time, use that
|
|
28551
|
-
* 3. Otherwise, use current system time
|
|
28552
|
-
*/
|
|
28553
|
-
initializeTime() {
|
|
28554
|
-
let timeSet = false;
|
|
28555
|
-
// Check if initialDate has time information
|
|
28556
|
-
if (this.initialDate && this.initialDate instanceof Date) {
|
|
28557
|
-
this.selectedTime = {
|
|
28558
|
-
hour: this.initialDate.getHours(),
|
|
28559
|
-
minute: this.initialDate.getMinutes(),
|
|
28560
|
-
};
|
|
28561
|
-
timeSet = true;
|
|
28562
|
-
}
|
|
28563
|
-
// If no time from initialDate, use current system time
|
|
28564
|
-
if (!timeSet) {
|
|
28565
|
-
const now = new Date();
|
|
28566
|
-
this.selectedTime = {
|
|
28567
|
-
hour: now.getHours(),
|
|
28568
|
-
minute: now.getMinutes(),
|
|
28569
|
-
};
|
|
28570
|
-
}
|
|
28571
|
-
// Mark that time has been initialized
|
|
28572
|
-
this.timeInitialized = true;
|
|
28573
|
-
// BACKWARD COMPATIBILITY: Only set meridian when useMeridian=true
|
|
28574
|
-
if (this.useMeridian) {
|
|
28575
|
-
this.meridian = this.selectedTime.hour >= 12 ? 'PM' : 'AM';
|
|
28576
|
-
}
|
|
28577
|
-
}
|
|
28578
|
-
/**
|
|
28579
|
-
* Increment hour value with wraparound (0-23)
|
|
28580
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28581
|
-
*/
|
|
28582
|
-
incrementHour() {
|
|
28583
|
-
this.selectedTime.hour = (this.selectedTime.hour + 1) % 24;
|
|
28584
|
-
this.updateSelectedDayTime();
|
|
28585
|
-
}
|
|
28586
|
-
/**
|
|
28587
|
-
* Decrement hour value with wraparound (0-23)
|
|
28588
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28589
|
-
*/
|
|
28590
|
-
decrementHour() {
|
|
28591
|
-
this.selectedTime.hour = (this.selectedTime.hour - 1 + 24) % 24;
|
|
28592
|
-
this.updateSelectedDayTime();
|
|
28593
|
-
}
|
|
28594
|
-
/**
|
|
28595
|
-
* Increment minute value with wraparound (0-59)
|
|
28596
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28597
|
-
*/
|
|
28598
|
-
incrementMinute() {
|
|
28599
|
-
this.selectedTime.minute = (this.selectedTime.minute + 1) % 60;
|
|
28600
|
-
this.updateSelectedDayTime();
|
|
28601
|
-
}
|
|
28602
|
-
/**
|
|
28603
|
-
* Decrement minute value with wraparound (0-59)
|
|
28604
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28605
|
-
*/
|
|
28606
|
-
decrementMinute() {
|
|
28607
|
-
this.selectedTime.minute = (this.selectedTime.minute - 1 + 60) % 60;
|
|
28608
|
-
this.updateSelectedDayTime();
|
|
28609
|
-
}
|
|
28610
|
-
/**
|
|
28611
|
-
* Handle keyboard input for hours
|
|
28612
|
-
* Validates and clamps to 0-23 range
|
|
28613
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28614
|
-
*/
|
|
28615
|
-
onHourInputChange(event) {
|
|
28616
|
-
let value = parseInt(event.target.value, 10);
|
|
28617
|
-
if (isNaN(value) || value < 0) {
|
|
28618
|
-
value = 0;
|
|
28619
|
-
}
|
|
28620
|
-
else if (value > 23) {
|
|
28621
|
-
value = 23;
|
|
28622
|
-
}
|
|
28623
|
-
this.selectedTime.hour = value;
|
|
28624
|
-
event.target.value = value;
|
|
28625
|
-
this.updateSelectedDayTime();
|
|
28626
|
-
}
|
|
28627
|
-
/**
|
|
28628
|
-
* Handle keyboard input for minutes
|
|
28629
|
-
* Validates and clamps to 0-59 range
|
|
28630
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28631
|
-
*/
|
|
28632
|
-
onMinuteInputChange(event) {
|
|
28633
|
-
let value = parseInt(event.target.value, 10);
|
|
28634
|
-
if (isNaN(value) || value < 0) {
|
|
28635
|
-
value = 0;
|
|
28636
|
-
}
|
|
28637
|
-
else if (value > 59) {
|
|
28638
|
-
value = 59;
|
|
28639
|
-
}
|
|
28640
|
-
this.selectedTime.minute = value;
|
|
28641
|
-
event.target.value = value;
|
|
28642
|
-
this.updateSelectedDayTime();
|
|
28643
|
-
}
|
|
28644
|
-
/**
|
|
28645
|
-
* Handle keyboard arrow keys for hour/minute input
|
|
28646
|
-
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28647
|
-
*/
|
|
28648
|
-
onTimeKeydown(event, type) {
|
|
28649
|
-
if (event.key === 'ArrowUp') {
|
|
28650
|
-
event.preventDefault();
|
|
28651
|
-
if (type === 'hour') {
|
|
28652
|
-
this.incrementHour();
|
|
28653
|
-
}
|
|
28654
|
-
else {
|
|
28655
|
-
this.incrementMinute();
|
|
28656
|
-
}
|
|
28657
|
-
}
|
|
28658
|
-
else if (event.key === 'ArrowDown') {
|
|
28659
|
-
event.preventDefault();
|
|
28660
|
-
if (type === 'hour') {
|
|
28661
|
-
this.decrementHour();
|
|
28662
|
-
}
|
|
28663
|
-
else {
|
|
28664
|
-
this.decrementMinute();
|
|
28665
|
-
}
|
|
28666
|
-
}
|
|
28667
|
-
}
|
|
28668
|
-
/**
|
|
28669
|
-
* Update the selected day's time property when time changes
|
|
28670
|
-
* BACKWARD COMPATIBILITY: Only called when enableTime=true
|
|
28671
|
-
*/
|
|
28672
|
-
updateSelectedDayTime() {
|
|
28673
|
-
if (this.selectedDay) {
|
|
28674
|
-
this.selectedDay.time = { ...this.selectedTime };
|
|
28675
|
-
}
|
|
28676
|
-
}
|
|
28677
|
-
/**
|
|
28678
|
-
* Get display hour for 12-hour format
|
|
28679
|
-
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28680
|
-
*
|
|
28681
|
-
* Conversion:
|
|
28682
|
-
* - 0 (midnight) → 12 AM
|
|
28683
|
-
* - 1-11 (AM) → 1-11 AM
|
|
28684
|
-
* - 12 (noon) → 12 PM
|
|
28685
|
-
* - 13-23 (PM) → 1-11 PM
|
|
28686
|
-
*
|
|
28687
|
-
* IMPORTANT: Hour 0 is NEVER displayed as 0, always as 12
|
|
28688
|
-
*/
|
|
28689
|
-
getDisplayHour() {
|
|
28690
|
-
if (!this.useMeridian) {
|
|
28691
|
-
return this.selectedTime.hour;
|
|
28692
|
-
}
|
|
28693
|
-
const hour = this.selectedTime.hour;
|
|
28694
|
-
// Midnight (0) → 12
|
|
28695
|
-
if (hour === 0) {
|
|
28696
|
-
return 12;
|
|
28697
|
-
}
|
|
28698
|
-
// 1-12 → 1-12 (no change)
|
|
28699
|
-
else if (hour <= 12) {
|
|
28700
|
-
return hour;
|
|
28701
|
-
}
|
|
28702
|
-
// 13-23 → 1-11 (subtract 12)
|
|
28703
|
-
else {
|
|
28704
|
-
return hour - 12;
|
|
28705
|
-
}
|
|
28706
|
-
}
|
|
28707
|
-
/**
|
|
28708
|
-
* Toggle AM/PM meridian
|
|
28709
|
-
* BACKWARD COMPATIBILITY: Only available when useMeridian=true
|
|
28710
|
-
*
|
|
28711
|
-
* When toggling:
|
|
28712
|
-
* - Adds or subtracts 12 hours
|
|
28713
|
-
* - Maintains internal 24-hour format
|
|
28714
|
-
*/
|
|
28715
|
-
toggleMeridian() {
|
|
28716
|
-
if (this.meridian === 'AM') {
|
|
28717
|
-
this.meridian = 'PM';
|
|
28718
|
-
// Add 12 hours if not already in PM range
|
|
28719
|
-
if (this.selectedTime.hour < 12) {
|
|
28720
|
-
this.selectedTime.hour += 12;
|
|
28721
|
-
}
|
|
28722
|
-
}
|
|
28723
|
-
else {
|
|
28724
|
-
this.meridian = 'AM';
|
|
28725
|
-
// Subtract 12 hours if in PM range
|
|
28726
|
-
if (this.selectedTime.hour >= 12) {
|
|
28727
|
-
this.selectedTime.hour -= 12;
|
|
28728
|
-
}
|
|
28729
|
-
}
|
|
28730
|
-
this.updateSelectedDayTime();
|
|
28731
|
-
}
|
|
28732
|
-
/**
|
|
28733
|
-
* Increment hour in 12-hour mode
|
|
28734
|
-
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28735
|
-
*/
|
|
28736
|
-
incrementHour12() {
|
|
28737
|
-
let displayHour = this.getDisplayHour();
|
|
28738
|
-
displayHour = (displayHour % 12) + 1; // 1-12 cycle
|
|
28739
|
-
// Convert back to 24-hour format
|
|
28740
|
-
if (this.meridian === 'AM') {
|
|
28741
|
-
this.selectedTime.hour = displayHour === 12 ? 0 : displayHour;
|
|
28742
|
-
}
|
|
28743
|
-
else {
|
|
28744
|
-
this.selectedTime.hour = displayHour === 12 ? 12 : displayHour + 12;
|
|
28745
|
-
}
|
|
28746
|
-
this.updateSelectedDayTime();
|
|
28747
|
-
}
|
|
28748
|
-
/**
|
|
28749
|
-
* Decrement hour in 12-hour mode
|
|
28750
|
-
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28751
|
-
*/
|
|
28752
|
-
decrementHour12() {
|
|
28753
|
-
let displayHour = this.getDisplayHour();
|
|
28754
|
-
displayHour = displayHour === 1 ? 12 : displayHour - 1; // 1-12 cycle
|
|
28755
|
-
// Convert back to 24-hour format
|
|
28756
|
-
if (this.meridian === 'AM') {
|
|
28757
|
-
this.selectedTime.hour = displayHour === 12 ? 0 : displayHour;
|
|
28758
|
-
}
|
|
28759
|
-
else {
|
|
28760
|
-
this.selectedTime.hour = displayHour === 12 ? 12 : displayHour + 12;
|
|
28761
|
-
}
|
|
28762
|
-
this.updateSelectedDayTime();
|
|
28763
|
-
}
|
|
28764
|
-
/**
|
|
28765
|
-
* Handle 12-hour input change
|
|
28766
|
-
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28767
|
-
*
|
|
28768
|
-
* IMPORTANT: Input must be 1-12, never 0
|
|
28769
|
-
* - User types 0 → converted to 12
|
|
28770
|
-
* - User types > 12 → clamped to 12
|
|
28771
|
-
*/
|
|
28772
|
-
onHour12InputChange(event) {
|
|
28773
|
-
let value = parseInt(event.target.value, 10);
|
|
28774
|
-
// Validate 1-12 range (0 is not allowed in 12-hour format)
|
|
28775
|
-
if (isNaN(value) || value < 1 || value === 0) {
|
|
28776
|
-
value = 12; // Default to 12 if invalid or 0
|
|
28777
|
-
}
|
|
28778
|
-
else if (value > 12) {
|
|
28779
|
-
value = 12;
|
|
28780
|
-
}
|
|
28781
|
-
// Convert to 24-hour format
|
|
28782
|
-
if (this.meridian === 'AM') {
|
|
28783
|
-
this.selectedTime.hour = value === 12 ? 0 : value;
|
|
28784
|
-
}
|
|
28785
|
-
else {
|
|
28786
|
-
this.selectedTime.hour = value === 12 ? 12 : value + 12;
|
|
28787
|
-
}
|
|
28788
|
-
event.target.value = value;
|
|
28789
|
-
this.updateSelectedDayTime();
|
|
28790
|
-
}
|
|
28791
|
-
/**
|
|
28792
|
-
* Check if a date is within the current range
|
|
28793
|
-
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28794
|
-
*/
|
|
28795
|
-
isInRange(day) {
|
|
28796
|
-
if (this.selectionMode !== 'range' || !this.rangeStart || !this.rangeEnd || !day?.gD) {
|
|
28797
|
-
return false;
|
|
28798
|
-
}
|
|
28799
|
-
const dayDate = this.parseDateString(day.gD);
|
|
28800
|
-
const startDate = this.parseDateString(this.rangeStart.gD);
|
|
28801
|
-
const endDate = this.parseDateString(this.rangeEnd.gD);
|
|
28802
|
-
if (!dayDate || !startDate || !endDate) {
|
|
28803
|
-
return false;
|
|
28804
|
-
}
|
|
28805
|
-
return dayDate >= startDate && dayDate <= endDate;
|
|
28806
|
-
}
|
|
28807
|
-
/**
|
|
28808
|
-
* Check if a date is the range start
|
|
28809
|
-
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28810
|
-
*/
|
|
28811
|
-
isRangeStart(day) {
|
|
28812
|
-
return this.selectionMode === 'range' &&
|
|
28813
|
-
this.rangeStart?.gD === day?.gD;
|
|
28814
|
-
}
|
|
28815
|
-
/**
|
|
28816
|
-
* Check if a date is the range end
|
|
28817
|
-
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28818
|
-
*/
|
|
28819
|
-
isRangeEnd(day) {
|
|
28820
|
-
return this.selectionMode === 'range' &&
|
|
28821
|
-
this.rangeEnd?.gD === day?.gD;
|
|
28822
|
-
}
|
|
28823
|
-
/**
|
|
28824
|
-
* Reset range selection
|
|
28825
|
-
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28826
|
-
*/
|
|
28827
|
-
resetRange() {
|
|
28828
|
-
if (this.selectionMode !== 'range') {
|
|
28829
|
-
return;
|
|
28830
|
-
}
|
|
28831
|
-
// Clear range highlighting
|
|
28832
|
-
this.weeks.forEach((week) => {
|
|
28833
|
-
week.forEach((day) => {
|
|
28834
|
-
if (day && day.gD) {
|
|
28835
|
-
day.selected = false;
|
|
28836
|
-
}
|
|
28837
|
-
});
|
|
28838
|
-
});
|
|
28839
|
-
this.rangeStart = undefined;
|
|
28840
|
-
this.rangeEnd = undefined;
|
|
28841
|
-
this.selectedDay = undefined;
|
|
28842
|
-
}
|
|
28843
|
-
/**
|
|
28844
|
-
* Parse date string (DD/MM/YYYY) to Date object
|
|
28845
|
-
* Helper for range comparison
|
|
28846
|
-
*/
|
|
28847
|
-
parseDateString(dateStr) {
|
|
28848
|
-
if (!dateStr)
|
|
28849
|
-
return null;
|
|
28850
|
-
const parts = dateStr.split('/');
|
|
28851
|
-
if (parts.length !== 3)
|
|
28852
|
-
return null;
|
|
28853
|
-
const day = parseInt(parts[0], 10);
|
|
28854
|
-
const month = parseInt(parts[1], 10) - 1; // Month is 0-indexed
|
|
28855
|
-
const year = parseInt(parts[2], 10);
|
|
28856
|
-
return new Date(year, month, day);
|
|
28857
|
-
}
|
|
28858
|
-
/**
|
|
28859
|
-
* Highlight all dates in range
|
|
28860
|
-
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28861
|
-
*/
|
|
28862
|
-
highlightRange() {
|
|
28863
|
-
if (this.selectionMode !== 'range' || !this.rangeStart || !this.rangeEnd) {
|
|
28864
|
-
return;
|
|
28865
|
-
}
|
|
28866
|
-
this.weeks.forEach((week) => {
|
|
28867
|
-
week.forEach((day) => {
|
|
28868
|
-
if (day && day.gD) {
|
|
28869
|
-
day.selected = this.isInRange(day) ||
|
|
28870
|
-
this.isRangeStart(day) ||
|
|
28871
|
-
this.isRangeEnd(day);
|
|
28872
|
-
}
|
|
28873
|
-
});
|
|
28874
|
-
});
|
|
28875
|
-
}
|
|
28876
|
-
}
|
|
28877
|
-
HijriGregorianDatepickerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: HijriGregorianDatepickerComponent, deps: [{ token: i1.UntypedFormBuilder }, { token: DateUtilitiesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
28878
|
-
HijriGregorianDatepickerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: HijriGregorianDatepickerComponent, selector: "hijri-gregorian-datepicker", inputs: { markToday: "markToday", canChangeMode: "canChangeMode", todaysDateSection: "todaysDateSection", futureValidation: "futureValidation", disableYearPicker: "disableYearPicker", disableMonthPicker: "disableMonthPicker", disableDayPicker: "disableDayPicker", multiple: "multiple", isRequired: "isRequired", showConfirmButton: "showConfirmButton", futureValidationMessage: "futureValidationMessage", arabicLayout: "arabicLayout", mode: "mode", dir: "dir", locale: "locale", submitTextButton: "submitTextButton", todaysDateText: "todaysDateText", ummAlQuraDateText: "ummAlQuraDateText", monthSelectLabel: "monthSelectLabel", yearSelectLabel: "yearSelectLabel", futureValidationMessageEn: "futureValidationMessageEn", futureValidationMessageAr: "futureValidationMessageAr", theme: "theme", pastYearsLimit: "pastYearsLimit", futureYearsLimit: "futureYearsLimit", styles: "styles", enableTime: "enableTime", minDate: "minDate", maxDate: "maxDate", initialDate: "initialDate", initialRangeStart: "initialRangeStart", initialRangeEnd: "initialRangeEnd", useMeridian: "useMeridian", selectionMode: "selectionMode" }, outputs: { onSubmit: "onSubmit", onDaySelect: "onDaySelect", onMonthChange: "onMonthChange", onYearChange: "onYearChange" }, host: { properties: { "style.font-family": "this.fontFamilyStyle" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container\" [dir]=\"dir\" [attr.lang]=\"locale\">\n <div\n class=\"toggle-section\"\n [dir]=\"dir\"\n *ngIf=\"canChangeMode\"\n [ngStyle]=\"{ color: styles.primaryColor }\"\n >\n <span> {{ ummAlQuraDateText }} </span>\n <label class=\"switch\">\n <input\n type=\"checkbox\"\n [disabled]=\"!canChangeMode\"\n [checked]=\"mode === 'ummAlQura'\"\n (change)=\"changeCalendarMode()\"\n #calendarCheckbox\n />\n <span\n class=\"slider\"\n [ngStyle]=\"\n calendarCheckbox.checked\n ? { 'background-color': styles.primaryColor }\n : { 'background-color': styles.backgroundColor }\n \"\n ></span>\n </label>\n </div>\n\n <div\n class=\"todays-date-section\"\n *ngIf=\"todaysDateSection\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n color: styles.primaryColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <div\n class=\"text-info\"\n [ngClass]=\"{\n order: dir == 'rtl'\n }\"\n >\n <p>{{ todaysDateText }}</p>\n </div>\n\n <div\n class=\"data\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n 'background-color': styles.todaysDateBgColor,\n color: styles.todaysDateTextColor\n }\"\n >\n <p *ngIf=\"mode == 'ummAlQura'\">\n <!-- {{todaysDate.ummAlQura}} -->\n {{\n locale == \"ar\"\n ? _dateUtilsService.convertDateNumerals(todaysDate.ummAlQura, \"ar\")\n : todaysDate.ummAlQura\n }}\n </p>\n <p *ngIf=\"mode == 'greg'\">\n {{\n locale == \"ar\"\n ? _dateUtilsService.convertDateNumerals(todaysDate.gregorian, \"ar\")\n : todaysDate.gregorian\n }}\n </p>\n </div>\n </div>\n\n <div class=\"period-container\">\n <form [formGroup]=\"periodForm\" class=\"period-form\">\n <div\n class=\"select-item\"\n [ngClass]=\"{\n order: dir == 'ltr'\n }\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <label *ngIf=\"!periodForm.controls['year'].value\">{{\n yearSelectLabel\n }}</label>\n\n <select\n formControlName=\"year\"\n class=\"{{ 'icon-' + dir }}\"\n placeholder=\"\u0627\u0644\u0633\u0646\u0629\"\n (change)=\"onPeriodChange('year')\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n color: styles.primaryColor,\n 'font-family': styles.fontFamily\n }\"\n >\n <option *ngFor=\"let year of years\" [ngValue]=\"year\">\n {{ locale == \"ar\" ? _dateUtilsService.parseEnglish(year) : year }}\n </option>\n </select>\n </div>\n\n <div\n class=\"select-item\"\n [ngClass]=\"{\n order: dir == 'rtl'\n }\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <label *ngIf=\"!periodForm.controls['month'].value\">{{\n monthSelectLabel\n }}</label>\n <select\n class=\"{{ 'icon-' + dir }}\"\n formControlName=\"month\"\n (change)=\"onPeriodChange('month')\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n color: styles.primaryColor,\n 'font-family': styles.fontFamily\n }\"\n >\n <option *ngFor=\"let month of months\" [ngValue]=\"month.value\">\n {{ locale == \"ar\" ? month?.labelAr : month?.labelEn }}\n </option>\n </select>\n </div>\n </form>\n </div>\n\n <div\n class=\"calendar-layout\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <div class=\"week-days\">\n <div\n class=\"week-day\"\n [ngStyle]=\"{ color: styles.dayNameColor }\"\n *ngFor=\"let date of locale == 'ar' ? weekdaysAr : weekdaysEn\"\n >\n {{ date }}\n </div>\n </div>\n\n <div [dir]=\"dir\">\n <div class=\"week\" *ngFor=\"let week of weeks\">\n <div\n class=\"day\"\n *ngFor=\"let day of week\"\n (click)=\"disableDayPicker == false ? onDayClicked(day) : ''\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n color: styles.dayColor\n }\"\n >\n <div\n id=\"greg-day\"\n [ngClass]=\"{\n 'todays-date': checkTodaysDate(day),\n 'selected-date': day?.selected == true\n }\"\n [ngStyle]=\"{\n border:\n markToday && checkTodaysDate(day)\n ? '1px solid ' + styles.secondaryColor\n : '',\n 'background-color':\n day?.selected == true ? styles.secondaryColor : '',\n color:\n (day?.selected == true ? styles.todaysDateTextColor : '') ||\n (checkFutureValidation(day) && futureValidation\n ? styles.disabledDayColor\n : '') ||\n (isDateDisabled(day) ? styles.disabledDayColor : ''),\n opacity: isDateDisabled(day) ? '0.4' : '1',\n cursor: isDateDisabled(day) ? 'not-allowed' : 'pointer'\n }\"\n >\n <span *ngIf=\"mode == 'greg'\">{{\n locale == \"ar\"\n ? _dateUtilsService.parseEnglish(\n day?.gD?.split(\"/\")[0] | number\n )\n : (day?.gD?.split(\"/\")[0] | number)\n }}</span>\n\n <span id=\"ummAlQura-day\" *ngIf=\"mode == 'ummAlQura'\">{{\n locale == \"ar\"\n ? _dateUtilsService.parseEnglish(\n day?.uD?.split(\"/\")[0] | number\n )\n : (day?.uD?.split(\"/\")[0] | number)\n }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"future-validation\" dir=\"auto\" *ngIf=\"futureValidationMessage\">\n <span *ngIf=\"locale == 'ar'\">\n {{ futureValidationMessageAr }}\n </span>\n <span *ngIf=\"locale == 'en'\">\n {{ futureValidationMessageEn }}\n </span>\n </div>\n\n <!-- Time Picker Section -->\n <!-- BACKWARD COMPATIBILITY: This section only renders when enableTime=true -->\n <div class=\"time-picker-section\" *ngIf=\"enableTime\" [dir]=\"'ltr'\">\n <div class=\"time-picker-wrapper\">\n <!-- Hour Input with Arrows -->\n <div class=\"time-input-container\">\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-up\"\n (click)=\"useMeridian ? incrementHour12() : incrementHour()\"\n tabindex=\"-1\"\n aria-label=\"Increment hour\"\n >\n <i class=\"ri-arrow-drop-up-line\"></i>\n </button>\n <input\n type=\"number\"\n class=\"time-field\"\n [value]=\"getDisplayHour().toString().padStart(2, '0')\"\n (input)=\"\n useMeridian\n ? onHour12InputChange($event)\n : onHourInputChange($event)\n \"\n (keydown)=\"onTimeKeydown($event, 'hour')\"\n [min]=\"useMeridian ? 1 : 0\"\n [max]=\"useMeridian ? 12 : 23\"\n aria-label=\"Hour\"\n />\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-down\"\n (click)=\"useMeridian ? decrementHour12() : decrementHour()\"\n tabindex=\"-1\"\n aria-label=\"Decrement hour\"\n >\n <i class=\"ri-arrow-drop-down-line\"></i>\n </button>\n </div>\n\n <!-- Colon Separator -->\n <span class=\"time-colon\">:</span>\n\n <!-- Minute Input with Arrows -->\n <div class=\"time-input-container\">\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-up\"\n (click)=\"incrementMinute()\"\n tabindex=\"-1\"\n aria-label=\"Increment minute\"\n >\n <i class=\"ri-arrow-drop-up-line\"></i>\n </button>\n <input\n type=\"number\"\n class=\"time-field\"\n [value]=\"selectedTime.minute.toString().padStart(2, '0')\"\n (input)=\"onMinuteInputChange($event)\"\n (keydown)=\"onTimeKeydown($event, 'minute')\"\n min=\"0\"\n max=\"59\"\n aria-label=\"Minute\"\n />\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-down\"\n (click)=\"decrementMinute()\"\n tabindex=\"-1\"\n aria-label=\"Decrement minute\"\n >\n <i class=\"ri-arrow-drop-down-line\"></i>\n </button>\n </div>\n\n <!-- AM/PM Button Group (only when useMeridian=true) -->\n <!-- BACKWARD COMPATIBILITY: This only renders when useMeridian=true -->\n <div class=\"meridian-toggle-group\" *ngIf=\"useMeridian\">\n <button\n type=\"button\"\n class=\"meridian-btn\"\n [class.active]=\"meridian === 'AM'\"\n (click)=\"meridian !== 'AM' && toggleMeridian()\"\n aria-label=\"Select AM\"\n >\n AM\n </button>\n <button\n type=\"button\"\n class=\"meridian-btn\"\n [class.active]=\"meridian === 'PM'\"\n (click)=\"meridian !== 'PM' && toggleMeridian()\"\n aria-label=\"Select PM\"\n >\n PM\n </button>\n </div>\n </div>\n </div>\n\n <div>\n <button\n type=\"button\"\n class=\"confirm-btn\"\n [disabled]=\"\n isRequired &&\n ((!selectedDay && !multiple) ||\n (!multipleSelectedDates.length && multiple))\n \"\n (click)=\"onConfirmClicked()\"\n *ngIf=\"showConfirmButton\"\n [ngStyle]=\"{\n 'background-color': styles.secondaryColor,\n color: styles.confirmBtnTextColor,\n 'font-family': styles.fontFamily,\n 'border-radius': styles.borderRadius\n }\"\n >\n {{ submitTextButton }}\n </button>\n </div>\n</div>\n", styles: [".calendar-container{margin:auto;display:block;border-radius:20px;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-weight:400}.calendar-container[dir=rtl],.calendar-container[lang=ar]{font-family:Zain,Arabic Typesetting,Tahoma,sans-serif;font-weight:300;letter-spacing:0;line-height:1.7}.calendar-container .todays-date-section{border-radius:4px;margin-top:12px;display:flex;align-items:center;justify-content:space-between;padding-left:10px;padding-right:10px}.calendar-container .todays-date-section .text-info{display:flex;align-items:center}.calendar-container .todays-date-section .text-info p{font-size:17px;font-weight:500;letter-spacing:.02em}[dir=rtl] .calendar-container .todays-date-section .text-info p,[lang=ar] .calendar-container .todays-date-section .text-info p{font-weight:400;letter-spacing:0}[dir=rtl] .calendar-container .todays-date-section .data p,[lang=ar] .calendar-container .todays-date-section .data p{font-weight:300}.calendar-container .todays-date-section .data{border-radius:8px}.calendar-container .todays-date-section .data p{font-size:14px;font-weight:400;margin:5px 10px}.calendar-container .period-container{display:flex;justify-content:space-between;margin-top:8px}.calendar-container .period-container .period-form{width:100%;display:flex;justify-content:space-between}.calendar-container .period-container .period-form .select-item{width:42.5%;border-radius:4px;height:50px;padding-left:10px;padding-right:10px}.calendar-container .period-container .period-form label{margin-right:10px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-container .period-container .period-form label,[lang=ar] .calendar-container .period-container .period-form label{font-weight:400}.calendar-container .period-container .period-form select{width:100%;height:50px;border:none;font-size:16px;font-weight:500;display:block;margin:auto;background:url(\"data:image/svg+xml;utf8,<svg viewBox='0 0 140 140' width='15' height='15' xmlns='http://www.w3.org/2000/svg'><g><path d='m121.3,34.6c-1.6-1.6-4.2-1.6-5.8,0l-51,51.1-51.1-51.1c-1.6-1.6-4.2-1.6-5.8,0-1.6,1.6-1.6,4.2 0,5.8l53.9,53.9c0.8,0.8 1.8,1.2 2.9,1.2 1,0 2.1-0.4 2.9-1.2l53.9-53.9c1.7-1.6 1.7-4.2 0.1-5.8z' fill='black'/></g></svg>\") no-repeat 95% 50%;-webkit-appearance:none;appearance:none;cursor:pointer}.calendar-container .period-container .period-form select option,.calendar-container [dir=rtl] .period-container select{font-weight:400}.calendar-container [dir=rtl] .period-container select option{font-weight:300}.icon-ltr{background-position:right}.icon-rtl{background-position:left!important}select:focus{outline:none}.calendar-layout{border-radius:4px;margin:8px auto auto;display:block;padding-bottom:5px}.calendar-layout .week-days{text-align:center;margin-top:5px;display:flex;justify-content:space-evenly}.calendar-layout .week-days .week-day{display:inline-block;width:13%;text-align:center;padding:15px 0 10px;font-weight:600;font-size:13px;text-transform:uppercase;letter-spacing:.05em}[dir=rtl] .calendar-layout .week-days{flex-direction:row-reverse!important}[dir=rtl] .calendar-layout .week-days .week-day{font-weight:700;letter-spacing:0;text-transform:none;font-size:14px}.calendar-layout .week{text-align:center;display:flex;justify-content:space-evenly}.calendar-layout .day{display:inline-flex;width:13%;height:5.5vh;justify-content:center;align-items:center;cursor:pointer;font-weight:500;transition:all .2s ease;border-radius:4px}.calendar-layout .day:hover:not(.disabled-day){transform:scale(1.05)}[dir=rtl] .calendar-layout .day{font-weight:400}.calendar-layout #greg-day{position:relative;min-width:20px}.calendar-layout #greg-day span{font-size:14px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #greg-day span,[lang=ar] .calendar-layout #greg-day span{font-weight:400}.calendar-layout #ummAlQura-day{font-size:11px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #ummAlQura-day,[lang=ar] .calendar-layout #ummAlQura-day{font-weight:400}.calendar-layout .todays-date,.calendar-layout .selected-date{padding:10px;border-radius:5px}.confirm-btn{height:50px;width:100%;border:none;font-size:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;margin:8px auto 0;box-shadow:none!important;cursor:pointer;transition:all .2s ease;border-radius:8px}.confirm-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 4px 12px #00000026!important}.confirm-btn:disabled{opacity:.5;cursor:not-allowed}[dir=rtl] .confirm-btn{font-weight:700;letter-spacing:0;text-transform:none;font-size:17px}.toggle-section{display:flex;align-items:center;justify-content:space-between}.toggle-section label{text-align:right;font-size:19px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .toggle-section label,[lang=ar] .toggle-section label{font-weight:400}.toggle-section .switch{position:relative;display:inline-block;width:50px;height:24px}.toggle-section .switch input{opacity:0;width:0;height:0}.toggle-section .slider{position:absolute;cursor:pointer;inset:0;background-color:#ccc;transition:.4s;border-radius:24px}.toggle-section .slider:before{content:\"\";position:absolute;height:18px;width:18px;left:3px;bottom:3px;background-color:#fff;transition:.4s;border-radius:50%}.toggle-section input:checked+.slider:before{transform:translate(26px)}.order{order:1}.future-validation{text-align:center;color:#eb445a;margin-top:8px;font-size:13px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .future-validation,[lang=ar] .future-validation{font-weight:400;line-height:1.8}.time-picker-section{padding:10px;background:transparent;border-radius:0;font-family:Poppins,sans-serif}.time-picker-section .time-picker-wrapper{display:flex;align-items:center;justify-content:center;gap:8px}.time-picker-section .time-picker-wrapper .time-input-container{position:relative;display:inline-flex;flex-direction:column;align-items:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{width:100%;height:20px;border:1px solid #ddd;background:#ffffff;color:#5b479c;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s ease;padding:0;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow i{font-size:20px;line-height:1;pointer-events:none;opacity:.7;transition:opacity .2s ease;display:flex;align-items:center;justify-content:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:hover i{opacity:1}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:active{background:#e9ecef}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:focus{outline:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-up{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-down{border-radius:0 0 4px 4px;border-top:none}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:25px;border:1px solid #ddd;border-top:none;border-bottom:none;background:#ffffff;font-size:18px;font-weight:600;color:#333;text-align:center;padding:0;margin:0;transition:all .2s ease;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;-webkit-appearance:textfield;appearance:textfield}[dir=rtl] .time-picker-section .time-picker-wrapper .time-input-container .time-field,[lang=ar] .time-picker-section .time-picker-wrapper .time-input-container .time-field{font-weight:700}.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-outer-spin-button,.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-field:focus{outline:none;box-shadow:0 0 0 2px #5b479c1a;z-index:1}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px;font-weight:600;color:#5b479c;padding:0 4px;-webkit-user-select:none;user-select:none;line-height:1;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .time-colon,[lang=ar] .time-picker-section .time-picker-wrapper .time-colon{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group{display:flex;flex-direction:column;gap:0;margin-left:8px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:25px;border:1px solid #ddd;background:#ffffff;color:#666;font-size:13px;font-weight:600;text-align:center;padding:0;cursor:pointer;transition:all .2s ease;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn,[lang=ar] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:first-child{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:last-child{border-radius:0 0 4px 4px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:hover:not(.active){background:#f8f9fa;border-color:#00ace4;color:#00ace4}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:active{transform:scale(.98)}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:focus{outline:none;border-color:#00ace4;box-shadow:0 0 0 2px #00ace41a;z-index:1}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn.active{background:rgb(0,77,97);border-color:#004d61;color:#fff;cursor:default}@media (max-width: 480px){.time-picker-section{padding:12px}.time-picker-section .time-picker-wrapper{gap:6px}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{height:18px}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:36px;font-size:20px}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px}.time-picker-section .time-picker-wrapper .meridian-toggle-group{margin-left:6px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:27px;font-size:12px}}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.DecimalPipe, name: "number" }] });
|
|
28879
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
28880
|
-
type: Component,
|
|
28881
|
-
args: [{ selector: 'hijri-gregorian-datepicker', template: "<div class=\"calendar-container\" [dir]=\"dir\" [attr.lang]=\"locale\">\n <div\n class=\"toggle-section\"\n [dir]=\"dir\"\n *ngIf=\"canChangeMode\"\n [ngStyle]=\"{ color: styles.primaryColor }\"\n >\n <span> {{ ummAlQuraDateText }} </span>\n <label class=\"switch\">\n <input\n type=\"checkbox\"\n [disabled]=\"!canChangeMode\"\n [checked]=\"mode === 'ummAlQura'\"\n (change)=\"changeCalendarMode()\"\n #calendarCheckbox\n />\n <span\n class=\"slider\"\n [ngStyle]=\"\n calendarCheckbox.checked\n ? { 'background-color': styles.primaryColor }\n : { 'background-color': styles.backgroundColor }\n \"\n ></span>\n </label>\n </div>\n\n <div\n class=\"todays-date-section\"\n *ngIf=\"todaysDateSection\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n color: styles.primaryColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <div\n class=\"text-info\"\n [ngClass]=\"{\n order: dir == 'rtl'\n }\"\n >\n <p>{{ todaysDateText }}</p>\n </div>\n\n <div\n class=\"data\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n 'background-color': styles.todaysDateBgColor,\n color: styles.todaysDateTextColor\n }\"\n >\n <p *ngIf=\"mode == 'ummAlQura'\">\n <!-- {{todaysDate.ummAlQura}} -->\n {{\n locale == \"ar\"\n ? _dateUtilsService.convertDateNumerals(todaysDate.ummAlQura, \"ar\")\n : todaysDate.ummAlQura\n }}\n </p>\n <p *ngIf=\"mode == 'greg'\">\n {{\n locale == \"ar\"\n ? _dateUtilsService.convertDateNumerals(todaysDate.gregorian, \"ar\")\n : todaysDate.gregorian\n }}\n </p>\n </div>\n </div>\n\n <div class=\"period-container\">\n <form [formGroup]=\"periodForm\" class=\"period-form\">\n <div\n class=\"select-item\"\n [ngClass]=\"{\n order: dir == 'ltr'\n }\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <label *ngIf=\"!periodForm.controls['year'].value\">{{\n yearSelectLabel\n }}</label>\n\n <select\n formControlName=\"year\"\n class=\"{{ 'icon-' + dir }}\"\n placeholder=\"\u0627\u0644\u0633\u0646\u0629\"\n (change)=\"onPeriodChange('year')\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n color: styles.primaryColor,\n 'font-family': styles.fontFamily\n }\"\n >\n <option *ngFor=\"let year of years\" [ngValue]=\"year\">\n {{ locale == \"ar\" ? _dateUtilsService.parseEnglish(year) : year }}\n </option>\n </select>\n </div>\n\n <div\n class=\"select-item\"\n [ngClass]=\"{\n order: dir == 'rtl'\n }\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <label *ngIf=\"!periodForm.controls['month'].value\">{{\n monthSelectLabel\n }}</label>\n <select\n class=\"{{ 'icon-' + dir }}\"\n formControlName=\"month\"\n (change)=\"onPeriodChange('month')\"\n [dir]=\"dir\"\n [ngStyle]=\"{\n color: styles.primaryColor,\n 'font-family': styles.fontFamily\n }\"\n >\n <option *ngFor=\"let month of months\" [ngValue]=\"month.value\">\n {{ locale == \"ar\" ? month?.labelAr : month?.labelEn }}\n </option>\n </select>\n </div>\n </form>\n </div>\n\n <div\n class=\"calendar-layout\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n 'border-radius': styles.borderRadius\n }\"\n >\n <div class=\"week-days\">\n <div\n class=\"week-day\"\n [ngStyle]=\"{ color: styles.dayNameColor }\"\n *ngFor=\"let date of locale == 'ar' ? weekdaysAr : weekdaysEn\"\n >\n {{ date }}\n </div>\n </div>\n\n <div [dir]=\"dir\">\n <div class=\"week\" *ngFor=\"let week of weeks\">\n <div\n class=\"day\"\n *ngFor=\"let day of week\"\n (click)=\"disableDayPicker == false ? onDayClicked(day) : ''\"\n [ngStyle]=\"{\n 'background-color': styles.backgroundColor,\n color: styles.dayColor\n }\"\n >\n <div\n id=\"greg-day\"\n [ngClass]=\"{\n 'todays-date': checkTodaysDate(day),\n 'selected-date': day?.selected == true\n }\"\n [ngStyle]=\"{\n border:\n markToday && checkTodaysDate(day)\n ? '1px solid ' + styles.secondaryColor\n : '',\n 'background-color':\n day?.selected == true ? styles.secondaryColor : '',\n color:\n (day?.selected == true ? styles.todaysDateTextColor : '') ||\n (checkFutureValidation(day) && futureValidation\n ? styles.disabledDayColor\n : '') ||\n (isDateDisabled(day) ? styles.disabledDayColor : ''),\n opacity: isDateDisabled(day) ? '0.4' : '1',\n cursor: isDateDisabled(day) ? 'not-allowed' : 'pointer'\n }\"\n >\n <span *ngIf=\"mode == 'greg'\">{{\n locale == \"ar\"\n ? _dateUtilsService.parseEnglish(\n day?.gD?.split(\"/\")[0] | number\n )\n : (day?.gD?.split(\"/\")[0] | number)\n }}</span>\n\n <span id=\"ummAlQura-day\" *ngIf=\"mode == 'ummAlQura'\">{{\n locale == \"ar\"\n ? _dateUtilsService.parseEnglish(\n day?.uD?.split(\"/\")[0] | number\n )\n : (day?.uD?.split(\"/\")[0] | number)\n }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"future-validation\" dir=\"auto\" *ngIf=\"futureValidationMessage\">\n <span *ngIf=\"locale == 'ar'\">\n {{ futureValidationMessageAr }}\n </span>\n <span *ngIf=\"locale == 'en'\">\n {{ futureValidationMessageEn }}\n </span>\n </div>\n\n <!-- Time Picker Section -->\n <!-- BACKWARD COMPATIBILITY: This section only renders when enableTime=true -->\n <div class=\"time-picker-section\" *ngIf=\"enableTime\" [dir]=\"'ltr'\">\n <div class=\"time-picker-wrapper\">\n <!-- Hour Input with Arrows -->\n <div class=\"time-input-container\">\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-up\"\n (click)=\"useMeridian ? incrementHour12() : incrementHour()\"\n tabindex=\"-1\"\n aria-label=\"Increment hour\"\n >\n <i class=\"ri-arrow-drop-up-line\"></i>\n </button>\n <input\n type=\"number\"\n class=\"time-field\"\n [value]=\"getDisplayHour().toString().padStart(2, '0')\"\n (input)=\"\n useMeridian\n ? onHour12InputChange($event)\n : onHourInputChange($event)\n \"\n (keydown)=\"onTimeKeydown($event, 'hour')\"\n [min]=\"useMeridian ? 1 : 0\"\n [max]=\"useMeridian ? 12 : 23\"\n aria-label=\"Hour\"\n />\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-down\"\n (click)=\"useMeridian ? decrementHour12() : decrementHour()\"\n tabindex=\"-1\"\n aria-label=\"Decrement hour\"\n >\n <i class=\"ri-arrow-drop-down-line\"></i>\n </button>\n </div>\n\n <!-- Colon Separator -->\n <span class=\"time-colon\">:</span>\n\n <!-- Minute Input with Arrows -->\n <div class=\"time-input-container\">\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-up\"\n (click)=\"incrementMinute()\"\n tabindex=\"-1\"\n aria-label=\"Increment minute\"\n >\n <i class=\"ri-arrow-drop-up-line\"></i>\n </button>\n <input\n type=\"number\"\n class=\"time-field\"\n [value]=\"selectedTime.minute.toString().padStart(2, '0')\"\n (input)=\"onMinuteInputChange($event)\"\n (keydown)=\"onTimeKeydown($event, 'minute')\"\n min=\"0\"\n max=\"59\"\n aria-label=\"Minute\"\n />\n <button\n type=\"button\"\n class=\"time-arrow time-arrow-down\"\n (click)=\"decrementMinute()\"\n tabindex=\"-1\"\n aria-label=\"Decrement minute\"\n >\n <i class=\"ri-arrow-drop-down-line\"></i>\n </button>\n </div>\n\n <!-- AM/PM Button Group (only when useMeridian=true) -->\n <!-- BACKWARD COMPATIBILITY: This only renders when useMeridian=true -->\n <div class=\"meridian-toggle-group\" *ngIf=\"useMeridian\">\n <button\n type=\"button\"\n class=\"meridian-btn\"\n [class.active]=\"meridian === 'AM'\"\n (click)=\"meridian !== 'AM' && toggleMeridian()\"\n aria-label=\"Select AM\"\n >\n AM\n </button>\n <button\n type=\"button\"\n class=\"meridian-btn\"\n [class.active]=\"meridian === 'PM'\"\n (click)=\"meridian !== 'PM' && toggleMeridian()\"\n aria-label=\"Select PM\"\n >\n PM\n </button>\n </div>\n </div>\n </div>\n\n <div>\n <button\n type=\"button\"\n class=\"confirm-btn\"\n [disabled]=\"\n isRequired &&\n ((!selectedDay && !multiple) ||\n (!multipleSelectedDates.length && multiple))\n \"\n (click)=\"onConfirmClicked()\"\n *ngIf=\"showConfirmButton\"\n [ngStyle]=\"{\n 'background-color': styles.secondaryColor,\n color: styles.confirmBtnTextColor,\n 'font-family': styles.fontFamily,\n 'border-radius': styles.borderRadius\n }\"\n >\n {{ submitTextButton }}\n </button>\n </div>\n</div>\n", styles: [".calendar-container{margin:auto;display:block;border-radius:20px;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-weight:400}.calendar-container[dir=rtl],.calendar-container[lang=ar]{font-family:Zain,Arabic Typesetting,Tahoma,sans-serif;font-weight:300;letter-spacing:0;line-height:1.7}.calendar-container .todays-date-section{border-radius:4px;margin-top:12px;display:flex;align-items:center;justify-content:space-between;padding-left:10px;padding-right:10px}.calendar-container .todays-date-section .text-info{display:flex;align-items:center}.calendar-container .todays-date-section .text-info p{font-size:17px;font-weight:500;letter-spacing:.02em}[dir=rtl] .calendar-container .todays-date-section .text-info p,[lang=ar] .calendar-container .todays-date-section .text-info p{font-weight:400;letter-spacing:0}[dir=rtl] .calendar-container .todays-date-section .data p,[lang=ar] .calendar-container .todays-date-section .data p{font-weight:300}.calendar-container .todays-date-section .data{border-radius:8px}.calendar-container .todays-date-section .data p{font-size:14px;font-weight:400;margin:5px 10px}.calendar-container .period-container{display:flex;justify-content:space-between;margin-top:8px}.calendar-container .period-container .period-form{width:100%;display:flex;justify-content:space-between}.calendar-container .period-container .period-form .select-item{width:42.5%;border-radius:4px;height:50px;padding-left:10px;padding-right:10px}.calendar-container .period-container .period-form label{margin-right:10px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-container .period-container .period-form label,[lang=ar] .calendar-container .period-container .period-form label{font-weight:400}.calendar-container .period-container .period-form select{width:100%;height:50px;border:none;font-size:16px;font-weight:500;display:block;margin:auto;background:url(\"data:image/svg+xml;utf8,<svg viewBox='0 0 140 140' width='15' height='15' xmlns='http://www.w3.org/2000/svg'><g><path d='m121.3,34.6c-1.6-1.6-4.2-1.6-5.8,0l-51,51.1-51.1-51.1c-1.6-1.6-4.2-1.6-5.8,0-1.6,1.6-1.6,4.2 0,5.8l53.9,53.9c0.8,0.8 1.8,1.2 2.9,1.2 1,0 2.1-0.4 2.9-1.2l53.9-53.9c1.7-1.6 1.7-4.2 0.1-5.8z' fill='black'/></g></svg>\") no-repeat 95% 50%;-webkit-appearance:none;appearance:none;cursor:pointer}.calendar-container .period-container .period-form select option,.calendar-container [dir=rtl] .period-container select{font-weight:400}.calendar-container [dir=rtl] .period-container select option{font-weight:300}.icon-ltr{background-position:right}.icon-rtl{background-position:left!important}select:focus{outline:none}.calendar-layout{border-radius:4px;margin:8px auto auto;display:block;padding-bottom:5px}.calendar-layout .week-days{text-align:center;margin-top:5px;display:flex;justify-content:space-evenly}.calendar-layout .week-days .week-day{display:inline-block;width:13%;text-align:center;padding:15px 0 10px;font-weight:600;font-size:13px;text-transform:uppercase;letter-spacing:.05em}[dir=rtl] .calendar-layout .week-days{flex-direction:row-reverse!important}[dir=rtl] .calendar-layout .week-days .week-day{font-weight:700;letter-spacing:0;text-transform:none;font-size:14px}.calendar-layout .week{text-align:center;display:flex;justify-content:space-evenly}.calendar-layout .day{display:inline-flex;width:13%;height:5.5vh;justify-content:center;align-items:center;cursor:pointer;font-weight:500;transition:all .2s ease;border-radius:4px}.calendar-layout .day:hover:not(.disabled-day){transform:scale(1.05)}[dir=rtl] .calendar-layout .day{font-weight:400}.calendar-layout #greg-day{position:relative;min-width:20px}.calendar-layout #greg-day span{font-size:14px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #greg-day span,[lang=ar] .calendar-layout #greg-day span{font-weight:400}.calendar-layout #ummAlQura-day{font-size:11px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #ummAlQura-day,[lang=ar] .calendar-layout #ummAlQura-day{font-weight:400}.calendar-layout .todays-date,.calendar-layout .selected-date{padding:10px;border-radius:5px}.confirm-btn{height:50px;width:100%;border:none;font-size:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;margin:8px auto 0;box-shadow:none!important;cursor:pointer;transition:all .2s ease;border-radius:8px}.confirm-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 4px 12px #00000026!important}.confirm-btn:disabled{opacity:.5;cursor:not-allowed}[dir=rtl] .confirm-btn{font-weight:700;letter-spacing:0;text-transform:none;font-size:17px}.toggle-section{display:flex;align-items:center;justify-content:space-between}.toggle-section label{text-align:right;font-size:19px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .toggle-section label,[lang=ar] .toggle-section label{font-weight:400}.toggle-section .switch{position:relative;display:inline-block;width:50px;height:24px}.toggle-section .switch input{opacity:0;width:0;height:0}.toggle-section .slider{position:absolute;cursor:pointer;inset:0;background-color:#ccc;transition:.4s;border-radius:24px}.toggle-section .slider:before{content:\"\";position:absolute;height:18px;width:18px;left:3px;bottom:3px;background-color:#fff;transition:.4s;border-radius:50%}.toggle-section input:checked+.slider:before{transform:translate(26px)}.order{order:1}.future-validation{text-align:center;color:#eb445a;margin-top:8px;font-size:13px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .future-validation,[lang=ar] .future-validation{font-weight:400;line-height:1.8}.time-picker-section{padding:10px;background:transparent;border-radius:0;font-family:Poppins,sans-serif}.time-picker-section .time-picker-wrapper{display:flex;align-items:center;justify-content:center;gap:8px}.time-picker-section .time-picker-wrapper .time-input-container{position:relative;display:inline-flex;flex-direction:column;align-items:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{width:100%;height:20px;border:1px solid #ddd;background:#ffffff;color:#5b479c;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s ease;padding:0;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow i{font-size:20px;line-height:1;pointer-events:none;opacity:.7;transition:opacity .2s ease;display:flex;align-items:center;justify-content:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:hover i{opacity:1}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:active{background:#e9ecef}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:focus{outline:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-up{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-down{border-radius:0 0 4px 4px;border-top:none}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:25px;border:1px solid #ddd;border-top:none;border-bottom:none;background:#ffffff;font-size:18px;font-weight:600;color:#333;text-align:center;padding:0;margin:0;transition:all .2s ease;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;-webkit-appearance:textfield;appearance:textfield}[dir=rtl] .time-picker-section .time-picker-wrapper .time-input-container .time-field,[lang=ar] .time-picker-section .time-picker-wrapper .time-input-container .time-field{font-weight:700}.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-outer-spin-button,.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-field:focus{outline:none;box-shadow:0 0 0 2px #5b479c1a;z-index:1}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px;font-weight:600;color:#5b479c;padding:0 4px;-webkit-user-select:none;user-select:none;line-height:1;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .time-colon,[lang=ar] .time-picker-section .time-picker-wrapper .time-colon{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group{display:flex;flex-direction:column;gap:0;margin-left:8px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:25px;border:1px solid #ddd;background:#ffffff;color:#666;font-size:13px;font-weight:600;text-align:center;padding:0;cursor:pointer;transition:all .2s ease;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn,[lang=ar] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:first-child{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:last-child{border-radius:0 0 4px 4px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:hover:not(.active){background:#f8f9fa;border-color:#00ace4;color:#00ace4}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:active{transform:scale(.98)}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:focus{outline:none;border-color:#00ace4;box-shadow:0 0 0 2px #00ace41a;z-index:1}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn.active{background:rgb(0,77,97);border-color:#004d61;color:#fff;cursor:default}@media (max-width: 480px){.time-picker-section{padding:12px}.time-picker-section .time-picker-wrapper{gap:6px}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{height:18px}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:36px;font-size:20px}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px}.time-picker-section .time-picker-wrapper .meridian-toggle-group{margin-left:6px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:27px;font-size:12px}}\n"] }]
|
|
28882
|
-
}], ctorParameters:
|
|
28883
|
-
type: Input
|
|
28884
|
-
}], canChangeMode: [{
|
|
28885
|
-
type: Input
|
|
28886
|
-
}], todaysDateSection: [{
|
|
28887
|
-
type: Input
|
|
28888
|
-
}], futureValidation: [{
|
|
28889
|
-
type: Input
|
|
28890
|
-
}], disableYearPicker: [{
|
|
28891
|
-
type: Input
|
|
28892
|
-
}], disableMonthPicker: [{
|
|
28893
|
-
type: Input
|
|
28894
|
-
}], disableDayPicker: [{
|
|
28895
|
-
type: Input
|
|
28896
|
-
}], multiple: [{
|
|
28897
|
-
type: Input
|
|
28898
|
-
}], isRequired: [{
|
|
28899
|
-
type: Input
|
|
28900
|
-
}], showConfirmButton: [{
|
|
28901
|
-
type: Input
|
|
28902
|
-
}], futureValidationMessage: [{
|
|
28903
|
-
type: Input
|
|
28904
|
-
}], arabicLayout: [{
|
|
28905
|
-
type: Input
|
|
28906
|
-
}], mode: [{
|
|
28907
|
-
type: Input
|
|
28908
|
-
}], dir: [{
|
|
28909
|
-
type: Input
|
|
28910
|
-
}], locale: [{
|
|
28911
|
-
type: Input
|
|
28912
|
-
}], submitTextButton: [{
|
|
28913
|
-
type: Input
|
|
28914
|
-
}], todaysDateText: [{
|
|
28915
|
-
type: Input
|
|
28916
|
-
}], ummAlQuraDateText: [{
|
|
28917
|
-
type: Input
|
|
28918
|
-
}], monthSelectLabel: [{
|
|
28919
|
-
type: Input
|
|
28920
|
-
}], yearSelectLabel: [{
|
|
28921
|
-
type: Input
|
|
28922
|
-
}], futureValidationMessageEn: [{
|
|
28923
|
-
type: Input
|
|
28924
|
-
}], futureValidationMessageAr: [{
|
|
28925
|
-
type: Input
|
|
28926
|
-
}], theme: [{
|
|
28927
|
-
type: Input
|
|
28928
|
-
}], pastYearsLimit: [{
|
|
28929
|
-
type: Input
|
|
28930
|
-
}], futureYearsLimit: [{
|
|
28931
|
-
type: Input
|
|
28932
|
-
}], styles: [{
|
|
28933
|
-
type: Input
|
|
28934
|
-
}], enableTime: [{
|
|
28935
|
-
type: Input
|
|
28936
|
-
}], minDate: [{
|
|
28937
|
-
type: Input
|
|
28938
|
-
}], maxDate: [{
|
|
28939
|
-
type: Input
|
|
28940
|
-
}], initialDate: [{
|
|
28941
|
-
type: Input
|
|
28942
|
-
}], initialRangeStart: [{
|
|
28943
|
-
type: Input
|
|
28944
|
-
}], initialRangeEnd: [{
|
|
28945
|
-
type: Input
|
|
28946
|
-
}], useMeridian: [{
|
|
28947
|
-
type: Input
|
|
28948
|
-
}], selectionMode: [{
|
|
28949
|
-
type: Input
|
|
28950
|
-
}], onSubmit: [{
|
|
28951
|
-
type: Output
|
|
28952
|
-
}], onDaySelect: [{
|
|
28953
|
-
type: Output
|
|
28954
|
-
}], onMonthChange: [{
|
|
28955
|
-
type: Output
|
|
28956
|
-
}], onYearChange: [{
|
|
28957
|
-
type: Output
|
|
28958
|
-
}], fontFamilyStyle: [{
|
|
28959
|
-
type: HostBinding,
|
|
28960
|
-
args: ['style.font-family']
|
|
27911
|
+
class HijriGregorianDatepickerComponent {
|
|
27912
|
+
constructor(formBuilder, _dateUtilsService) {
|
|
27913
|
+
this.formBuilder = formBuilder;
|
|
27914
|
+
this._dateUtilsService = _dateUtilsService;
|
|
27915
|
+
/// Inputs
|
|
27916
|
+
this.markToday = true;
|
|
27917
|
+
this.canChangeMode = true;
|
|
27918
|
+
this.todaysDateSection = true;
|
|
27919
|
+
this.futureValidation = true;
|
|
27920
|
+
this.disableYearPicker = false;
|
|
27921
|
+
this.disableMonthPicker = false;
|
|
27922
|
+
this.disableDayPicker = false;
|
|
27923
|
+
this.multiple = false;
|
|
27924
|
+
this.isRequired = false;
|
|
27925
|
+
this.showConfirmButton = true;
|
|
27926
|
+
this.futureValidationMessage = false;
|
|
27927
|
+
this.arabicLayout = false;
|
|
27928
|
+
this.mode = 'greg';
|
|
27929
|
+
this.dir = 'ltr';
|
|
27930
|
+
this.locale = 'en';
|
|
27931
|
+
this.submitTextButton = 'Confirm';
|
|
27932
|
+
this.todaysDateText = "Today's Date";
|
|
27933
|
+
this.ummAlQuraDateText = 'Hijri Date';
|
|
27934
|
+
this.monthSelectLabel = 'Month';
|
|
27935
|
+
this.yearSelectLabel = 'Year';
|
|
27936
|
+
this.theme = '';
|
|
27937
|
+
this.pastYearsLimit = 90;
|
|
27938
|
+
this.futureYearsLimit = 0;
|
|
27939
|
+
this.styles = {};
|
|
27940
|
+
// New inputs for extended functionality
|
|
27941
|
+
this.enableTime = false; // Enable time picker (hours & minutes)
|
|
27942
|
+
// BACKWARD COMPATIBILITY: Default to false (24-hour format)
|
|
27943
|
+
// When true, displays 12-hour format with AM/PM toggle
|
|
27944
|
+
this.useMeridian = false; // Enable 12-hour format with AM/PM
|
|
27945
|
+
// BACKWARD COMPATIBILITY: Default to 'single' (existing behavior)
|
|
27946
|
+
// 'range' enables range selection mode (first click = start, second click = end)
|
|
27947
|
+
this.selectionMode = 'single';
|
|
27948
|
+
/// Outputs
|
|
27949
|
+
this.onSubmit = new EventEmitter();
|
|
27950
|
+
this.onDaySelect = new EventEmitter();
|
|
27951
|
+
this.onMonthChange = new EventEmitter();
|
|
27952
|
+
this.onYearChange = new EventEmitter();
|
|
27953
|
+
/// Variables
|
|
27954
|
+
this.ummAlQuraMonths = [
|
|
27955
|
+
{ labelAr: 'محرم', labelEn: 'Muharram', value: 1 },
|
|
27956
|
+
{ labelAr: 'صفر', labelEn: 'Safar', value: 2 },
|
|
27957
|
+
{ labelAr: 'ربيع الأول', labelEn: 'Rabi al-Awwal', value: 3 },
|
|
27958
|
+
{ labelAr: 'ربيع الثاني', labelEn: 'Rabi al-Thani', value: 4 },
|
|
27959
|
+
{ labelAr: 'جمادى الأولى', labelEn: 'Jumada al-Awwal', value: 5 },
|
|
27960
|
+
{ labelAr: 'جمادى الآخرة', labelEn: 'Jumada al-Thani', value: 6 },
|
|
27961
|
+
{ labelAr: 'رجب', labelEn: 'Rajab', value: 7 },
|
|
27962
|
+
{ labelAr: 'شعبان', labelEn: 'Shaban', value: 8 },
|
|
27963
|
+
{ labelAr: 'رمضان', labelEn: 'Ramadan', value: 9 },
|
|
27964
|
+
{ labelAr: 'شوال', labelEn: 'Shawwal', value: 10 },
|
|
27965
|
+
{ labelAr: 'ذو القعدة', labelEn: 'Dhu al-Qadah', value: 11 },
|
|
27966
|
+
{ labelAr: 'ذو الحجة', labelEn: 'Dhu al-Hijjah', value: 12 },
|
|
27967
|
+
];
|
|
27968
|
+
this.gregMonths = [
|
|
27969
|
+
{ labelAr: 'يناير', labelEn: 'January', value: 1 },
|
|
27970
|
+
{ labelAr: 'فبراير', labelEn: 'February', value: 2 },
|
|
27971
|
+
{ labelAr: 'مارس', labelEn: 'March', value: 3 },
|
|
27972
|
+
{ labelAr: 'ابريل', labelEn: 'April', value: 4 },
|
|
27973
|
+
{ labelAr: 'مايو', labelEn: 'May', value: 5 },
|
|
27974
|
+
{ labelAr: 'يونيو', labelEn: 'June', value: 6 },
|
|
27975
|
+
{ labelAr: 'يوليو', labelEn: 'July', value: 7 },
|
|
27976
|
+
{ labelAr: 'اغسطس', labelEn: 'August', value: 8 },
|
|
27977
|
+
{ labelAr: 'سبتمبر', labelEn: 'September', value: 9 },
|
|
27978
|
+
{ labelAr: 'اكتوبر', labelEn: 'October', value: 10 },
|
|
27979
|
+
{ labelAr: 'نوفمبر', labelEn: 'November', value: 11 },
|
|
27980
|
+
{ labelAr: 'ديسمبر', labelEn: 'December', value: 12 },
|
|
27981
|
+
];
|
|
27982
|
+
this.weekdaysEn = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
27983
|
+
this.weekdaysAr = ['سبت', 'جمعة', 'خميس', 'أربعاء', 'ثلاثاء', 'اثنين', 'أحد'];
|
|
27984
|
+
// weekdaysAr = ['س', 'ج', 'خ', 'أر', 'ث', 'إث', 'أح'];
|
|
27985
|
+
this.todaysDate = {};
|
|
27986
|
+
this.multipleSelectedDates = [];
|
|
27987
|
+
this.themes = [];
|
|
27988
|
+
// Time picker variables
|
|
27989
|
+
// BACKWARD COMPATIBILITY: selectedTime defaults to 0:0 to preserve existing behavior when enableTime=false
|
|
27990
|
+
// When enableTime=true, this will be initialized to current system time in ngOnInit
|
|
27991
|
+
this.selectedTime = { hour: 0, minute: 0 };
|
|
27992
|
+
// Track if time has been initialized to avoid re-initializing at midnight
|
|
27993
|
+
this.timeInitialized = false;
|
|
27994
|
+
// BACKWARD COMPATIBILITY: Meridian only used when useMeridian=true
|
|
27995
|
+
// Tracks AM/PM state for 12-hour format
|
|
27996
|
+
this.meridian = 'AM';
|
|
27997
|
+
// Range selection state
|
|
27998
|
+
// BACKWARD COMPATIBILITY: These are only used when selectionMode='range'
|
|
27999
|
+
// They do not affect single or multiple selection modes
|
|
28000
|
+
this.rangeStart = undefined;
|
|
28001
|
+
this.rangeEnd = undefined;
|
|
28002
|
+
}
|
|
28003
|
+
ngOnInit() {
|
|
28004
|
+
this.initTheme();
|
|
28005
|
+
this.initializeForm();
|
|
28006
|
+
this.getTodaysDateInfo();
|
|
28007
|
+
this.initializeYearsAndMonths();
|
|
28008
|
+
// Initialize time from current system time or initialDate
|
|
28009
|
+
// BACKWARD COMPATIBILITY: This only runs when enableTime=true
|
|
28010
|
+
if (this.enableTime) {
|
|
28011
|
+
this.initializeTime();
|
|
28012
|
+
}
|
|
28013
|
+
}
|
|
28014
|
+
ngAfterViewInit() {
|
|
28015
|
+
// Double-check time initialization after view is ready
|
|
28016
|
+
// This handles cases where enableTime might be set after ngOnInit
|
|
28017
|
+
if (this.enableTime && !this.timeInitialized) {
|
|
28018
|
+
this.initializeTime();
|
|
28019
|
+
}
|
|
28020
|
+
}
|
|
28021
|
+
ngOnChanges(changes) {
|
|
28022
|
+
if (!changes['mode'].isFirstChange()) {
|
|
28023
|
+
this.changeCalendarMode();
|
|
28024
|
+
}
|
|
28025
|
+
}
|
|
28026
|
+
initTheme() {
|
|
28027
|
+
if (this.theme != '') {
|
|
28028
|
+
this.themes = themesConfig;
|
|
28029
|
+
for (const themeItem of this.themes['default']) {
|
|
28030
|
+
if (themeItem.name == this.theme) {
|
|
28031
|
+
this.styles = themeItem.stylesConfig;
|
|
28032
|
+
break;
|
|
28033
|
+
}
|
|
28034
|
+
}
|
|
28035
|
+
}
|
|
28036
|
+
this.fontFamilyStyle = this.styles.fontFamily;
|
|
28037
|
+
}
|
|
28038
|
+
/// Initialize form control for month and year select
|
|
28039
|
+
initializeForm() {
|
|
28040
|
+
this.periodForm = this.formBuilder.group({
|
|
28041
|
+
year: [{ value: '', disabled: this.disableYearPicker }, []],
|
|
28042
|
+
month: [{ value: '', disabled: this.disableMonthPicker }, []],
|
|
28043
|
+
});
|
|
28044
|
+
}
|
|
28045
|
+
// Initialize years and months for calendar
|
|
28046
|
+
initializeYearsAndMonths() {
|
|
28047
|
+
this.years = [];
|
|
28048
|
+
this.months = [];
|
|
28049
|
+
// Determine the date to use for initialization (initialDate or today)
|
|
28050
|
+
let referenceDate;
|
|
28051
|
+
if (this.initialDate) {
|
|
28052
|
+
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28053
|
+
if (normalizedInitialDate) {
|
|
28054
|
+
if (this.mode == 'greg') {
|
|
28055
|
+
referenceDate = normalizedInitialDate;
|
|
28056
|
+
}
|
|
28057
|
+
else {
|
|
28058
|
+
const hijriDate = this._dateUtilsService.convertDate(normalizedInitialDate, true);
|
|
28059
|
+
referenceDate = hijriDate?.uD || this.todaysDate.ummAlQura;
|
|
28060
|
+
}
|
|
28061
|
+
}
|
|
28062
|
+
else {
|
|
28063
|
+
referenceDate =
|
|
28064
|
+
this.mode == 'greg'
|
|
28065
|
+
? this.todaysDate.gregorian
|
|
28066
|
+
: this.todaysDate.ummAlQura;
|
|
28067
|
+
}
|
|
28068
|
+
}
|
|
28069
|
+
else {
|
|
28070
|
+
referenceDate =
|
|
28071
|
+
this.mode == 'greg'
|
|
28072
|
+
? this.todaysDate.gregorian
|
|
28073
|
+
: this.todaysDate.ummAlQura;
|
|
28074
|
+
}
|
|
28075
|
+
if (this.mode == 'greg') {
|
|
28076
|
+
this.gregYear =
|
|
28077
|
+
this.futureYearsLimit == 0
|
|
28078
|
+
? Number(referenceDate?.split('/')[2])
|
|
28079
|
+
: Number(referenceDate?.split('/')[2]) + this.futureYearsLimit;
|
|
28080
|
+
for (let i = 0; i < this.gregYear; i++) {
|
|
28081
|
+
if (i < this.pastYearsLimit) {
|
|
28082
|
+
let val = this.gregYear--;
|
|
28083
|
+
this.years.push(val);
|
|
28084
|
+
}
|
|
28085
|
+
else {
|
|
28086
|
+
break;
|
|
28087
|
+
}
|
|
28088
|
+
}
|
|
28089
|
+
this.months = this.gregMonths;
|
|
28090
|
+
}
|
|
28091
|
+
else {
|
|
28092
|
+
this.ummAlQuraYear =
|
|
28093
|
+
this.futureYearsLimit == 0
|
|
28094
|
+
? Number(referenceDate?.split('/')[2])
|
|
28095
|
+
: Number(referenceDate?.split('/')[2]) + this.futureYearsLimit;
|
|
28096
|
+
for (let i = 0; i < this.ummAlQuraYear; i++) {
|
|
28097
|
+
if (i < this.pastYearsLimit) {
|
|
28098
|
+
let val = this.ummAlQuraYear--;
|
|
28099
|
+
this.years.push(val);
|
|
28100
|
+
}
|
|
28101
|
+
else {
|
|
28102
|
+
break;
|
|
28103
|
+
}
|
|
28104
|
+
}
|
|
28105
|
+
this.months = this.ummAlQuraMonths;
|
|
28106
|
+
}
|
|
28107
|
+
this.years.map((year) => {
|
|
28108
|
+
if (year == referenceDate?.split('/')[2]) {
|
|
28109
|
+
this.periodForm.controls['year'].setValue(year);
|
|
28110
|
+
}
|
|
28111
|
+
});
|
|
28112
|
+
this.months.map((month) => {
|
|
28113
|
+
if (month.value == referenceDate?.split('/')[1]) {
|
|
28114
|
+
this.periodForm.controls['month'].setValue(month.value);
|
|
28115
|
+
}
|
|
28116
|
+
});
|
|
28117
|
+
}
|
|
28118
|
+
/// On change event of years and months
|
|
28119
|
+
onPeriodChange(type) {
|
|
28120
|
+
if (type == 'year') {
|
|
28121
|
+
this.onYearChange.emit(this.periodForm.controls['year'].value);
|
|
28122
|
+
}
|
|
28123
|
+
else {
|
|
28124
|
+
this.onMonthChange.emit(this.periodForm.controls['month'].value);
|
|
28125
|
+
}
|
|
28126
|
+
const days = this._dateUtilsService.getMonthData('01/' +
|
|
28127
|
+
this.periodForm.controls['month'].value +
|
|
28128
|
+
'/' +
|
|
28129
|
+
this.periodForm.controls['year'].value, this.mode);
|
|
28130
|
+
this.weeks = this.generateWeeksArray(days);
|
|
28131
|
+
}
|
|
28132
|
+
/// Get todays(greg and umm al qura) date info
|
|
28133
|
+
getTodaysDateInfo() {
|
|
28134
|
+
this.todaysDate.gregorian = this._dateUtilsService.formatDate(new Date());
|
|
28135
|
+
this.todaysDate.ummAlQura = this._dateUtilsService.convertDate(this.todaysDate.gregorian, true)?.uD;
|
|
28136
|
+
// Use initialDate if provided, otherwise use today's date
|
|
28137
|
+
let dateToNavigate;
|
|
28138
|
+
if (this.initialDate) {
|
|
28139
|
+
// Normalize initialDate to DD/MM/YYYY format
|
|
28140
|
+
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28141
|
+
if (normalizedInitialDate) {
|
|
28142
|
+
if (this.mode == 'greg') {
|
|
28143
|
+
dateToNavigate = normalizedInitialDate;
|
|
28144
|
+
}
|
|
28145
|
+
else {
|
|
28146
|
+
// Convert to Hijri for ummAlQura mode
|
|
28147
|
+
const hijriDate = this._dateUtilsService.convertDate(normalizedInitialDate, true);
|
|
28148
|
+
dateToNavigate = hijriDate?.uD || this.todaysDate.ummAlQura;
|
|
28149
|
+
}
|
|
28150
|
+
}
|
|
28151
|
+
else {
|
|
28152
|
+
// Invalid initialDate, fall back to today
|
|
28153
|
+
dateToNavigate =
|
|
28154
|
+
this.mode == 'greg'
|
|
28155
|
+
? this.todaysDate.gregorian
|
|
28156
|
+
: this.todaysDate.ummAlQura;
|
|
28157
|
+
}
|
|
28158
|
+
}
|
|
28159
|
+
else {
|
|
28160
|
+
// No initialDate provided, use today
|
|
28161
|
+
dateToNavigate =
|
|
28162
|
+
this.mode == 'greg'
|
|
28163
|
+
? this.todaysDate.gregorian
|
|
28164
|
+
: this.todaysDate.ummAlQura;
|
|
28165
|
+
}
|
|
28166
|
+
this.generatetMonthData(dateToNavigate);
|
|
28167
|
+
// Highlight initialDate or initialRange if provided
|
|
28168
|
+
if (this.selectionMode === 'range' && (this.initialRangeStart || this.initialRangeEnd)) {
|
|
28169
|
+
this.highlightInitialRange();
|
|
28170
|
+
}
|
|
28171
|
+
else if (this.initialDate) {
|
|
28172
|
+
this.highlightInitialDate();
|
|
28173
|
+
}
|
|
28174
|
+
}
|
|
28175
|
+
/// Generate month days from JSON
|
|
28176
|
+
generatetMonthData(date) {
|
|
28177
|
+
const days = this._dateUtilsService.getMonthData(date, this.mode);
|
|
28178
|
+
this.weeks = this.generateWeeksArray(days);
|
|
28179
|
+
}
|
|
28180
|
+
/// Highlight initialDate on the calendar
|
|
28181
|
+
highlightInitialDate() {
|
|
28182
|
+
if (!this.initialDate) {
|
|
28183
|
+
return;
|
|
28184
|
+
}
|
|
28185
|
+
const normalizedInitialDate = this._dateUtilsService.normalizeDateToString(this.initialDate);
|
|
28186
|
+
if (!normalizedInitialDate) {
|
|
28187
|
+
return;
|
|
28188
|
+
}
|
|
28189
|
+
// Find the day in the weeks array that matches initialDate
|
|
28190
|
+
for (const week of this.weeks) {
|
|
28191
|
+
for (const day of week) {
|
|
28192
|
+
if (day && day.gD === normalizedInitialDate) {
|
|
28193
|
+
// Don't select if date is disabled
|
|
28194
|
+
if (!this.isDateDisabled(day)) {
|
|
28195
|
+
// Mark as selected without triggering events
|
|
28196
|
+
day.selected = true;
|
|
28197
|
+
// Set as selectedDay based on selection mode
|
|
28198
|
+
if (this.selectionMode === 'range') {
|
|
28199
|
+
this.rangeStart = day;
|
|
28200
|
+
}
|
|
28201
|
+
else if (this.multiple) {
|
|
28202
|
+
this.multipleSelectedDates = [day];
|
|
28203
|
+
}
|
|
28204
|
+
else {
|
|
28205
|
+
this.selectedDay = day;
|
|
28206
|
+
}
|
|
28207
|
+
// Initialize time if enableTime is active
|
|
28208
|
+
if (this.enableTime && !this.timeInitialized) {
|
|
28209
|
+
this.initializeTime();
|
|
28210
|
+
}
|
|
28211
|
+
// Attach time to the day if it's a Date object with time
|
|
28212
|
+
if (this.enableTime && this.initialDate instanceof Date) {
|
|
28213
|
+
day.time = {
|
|
28214
|
+
hour: this.initialDate.getHours(),
|
|
28215
|
+
minute: this.initialDate.getMinutes()
|
|
28216
|
+
};
|
|
28217
|
+
}
|
|
28218
|
+
}
|
|
28219
|
+
return;
|
|
28220
|
+
}
|
|
28221
|
+
}
|
|
28222
|
+
}
|
|
28223
|
+
}
|
|
28224
|
+
/// Highlight initial range (start and end dates) on the calendar
|
|
28225
|
+
highlightInitialRange() {
|
|
28226
|
+
if (!this.initialRangeStart && !this.initialRangeEnd) {
|
|
28227
|
+
return;
|
|
28228
|
+
}
|
|
28229
|
+
const normalizedStartDate = this.initialRangeStart
|
|
28230
|
+
? this._dateUtilsService.normalizeDateToString(this.initialRangeStart)
|
|
28231
|
+
: null;
|
|
28232
|
+
const normalizedEndDate = this.initialRangeEnd
|
|
28233
|
+
? this._dateUtilsService.normalizeDateToString(this.initialRangeEnd)
|
|
28234
|
+
: null;
|
|
28235
|
+
let startDay = null;
|
|
28236
|
+
let endDay = null;
|
|
28237
|
+
// Find both start and end dates in the weeks array
|
|
28238
|
+
for (const week of this.weeks) {
|
|
28239
|
+
for (const day of week) {
|
|
28240
|
+
if (day && normalizedStartDate && day.gD === normalizedStartDate) {
|
|
28241
|
+
if (!this.isDateDisabled(day)) {
|
|
28242
|
+
startDay = day;
|
|
28243
|
+
}
|
|
28244
|
+
}
|
|
28245
|
+
if (day && normalizedEndDate && day.gD === normalizedEndDate) {
|
|
28246
|
+
if (!this.isDateDisabled(day)) {
|
|
28247
|
+
endDay = day;
|
|
28248
|
+
}
|
|
28249
|
+
}
|
|
28250
|
+
}
|
|
28251
|
+
}
|
|
28252
|
+
// Set range start
|
|
28253
|
+
if (startDay) {
|
|
28254
|
+
startDay.selected = true;
|
|
28255
|
+
this.rangeStart = startDay;
|
|
28256
|
+
this.selectedDay = startDay;
|
|
28257
|
+
// Initialize and attach time to start date
|
|
28258
|
+
if (this.enableTime) {
|
|
28259
|
+
if (!this.timeInitialized) {
|
|
28260
|
+
this.initializeTime();
|
|
28261
|
+
}
|
|
28262
|
+
if (this.initialRangeStart instanceof Date) {
|
|
28263
|
+
startDay.time = {
|
|
28264
|
+
hour: this.initialRangeStart.getHours(),
|
|
28265
|
+
minute: this.initialRangeStart.getMinutes()
|
|
28266
|
+
};
|
|
28267
|
+
}
|
|
28268
|
+
else {
|
|
28269
|
+
startDay.time = { ...this.selectedTime };
|
|
28270
|
+
}
|
|
28271
|
+
}
|
|
28272
|
+
}
|
|
28273
|
+
// Set range end if provided
|
|
28274
|
+
if (endDay && startDay) {
|
|
28275
|
+
// Swap if end is before start
|
|
28276
|
+
const startDate = this.parseDateString(startDay.gD);
|
|
28277
|
+
const endDate = this.parseDateString(endDay.gD);
|
|
28278
|
+
if (endDate && startDate && endDate < startDate) {
|
|
28279
|
+
// Swap
|
|
28280
|
+
this.rangeEnd = startDay;
|
|
28281
|
+
this.rangeStart = endDay;
|
|
28282
|
+
endDay.selected = true;
|
|
28283
|
+
}
|
|
28284
|
+
else {
|
|
28285
|
+
this.rangeEnd = endDay;
|
|
28286
|
+
}
|
|
28287
|
+
// Attach time to end date (inherit from start)
|
|
28288
|
+
if (this.enableTime) {
|
|
28289
|
+
const timeToUse = this.rangeStart.time || { ...this.selectedTime };
|
|
28290
|
+
if (this.initialRangeEnd instanceof Date) {
|
|
28291
|
+
this.rangeEnd.time = {
|
|
28292
|
+
hour: this.initialRangeEnd.getHours(),
|
|
28293
|
+
minute: this.initialRangeEnd.getMinutes()
|
|
28294
|
+
};
|
|
28295
|
+
}
|
|
28296
|
+
else {
|
|
28297
|
+
this.rangeEnd.time = { ...timeToUse };
|
|
28298
|
+
}
|
|
28299
|
+
// Ensure start also has time
|
|
28300
|
+
this.rangeStart.time = { ...timeToUse };
|
|
28301
|
+
}
|
|
28302
|
+
// Highlight the range
|
|
28303
|
+
this.highlightRange();
|
|
28304
|
+
this.selectedDay = this.rangeEnd;
|
|
28305
|
+
}
|
|
28306
|
+
}
|
|
28307
|
+
/// Generate month weeks
|
|
28308
|
+
generateWeeksArray(daysArray) {
|
|
28309
|
+
const firstDayName = daysArray[0]?.dN;
|
|
28310
|
+
const startIndex = this.weekdaysEn.indexOf(firstDayName);
|
|
28311
|
+
const weeks = [[]];
|
|
28312
|
+
let currentWeek = 0;
|
|
28313
|
+
let currentDayIndex = startIndex;
|
|
28314
|
+
daysArray?.forEach((day) => {
|
|
28315
|
+
if (!weeks[currentWeek]) {
|
|
28316
|
+
weeks[currentWeek] = [];
|
|
28317
|
+
}
|
|
28318
|
+
weeks[currentWeek][currentDayIndex] = day;
|
|
28319
|
+
currentDayIndex++;
|
|
28320
|
+
if (currentDayIndex === 7) {
|
|
28321
|
+
currentDayIndex = 0;
|
|
28322
|
+
currentWeek++;
|
|
28323
|
+
}
|
|
28324
|
+
});
|
|
28325
|
+
weeks.forEach((week) => {
|
|
28326
|
+
while (week.length < 7) {
|
|
28327
|
+
week.push({});
|
|
28328
|
+
}
|
|
28329
|
+
});
|
|
28330
|
+
return weeks;
|
|
28331
|
+
}
|
|
28332
|
+
/// Change calendar mode 'greg' or 'ummAlQura'
|
|
28333
|
+
changeCalendarMode() {
|
|
28334
|
+
this.mode = this.mode == 'greg' ? 'ummAlQura' : 'greg';
|
|
28335
|
+
this.initializeYearsAndMonths();
|
|
28336
|
+
this.generatetMonthData('01/' +
|
|
28337
|
+
this.periodForm.controls['month'].value +
|
|
28338
|
+
'/' +
|
|
28339
|
+
this.periodForm.controls['year'].value);
|
|
28340
|
+
}
|
|
28341
|
+
/// On day clicked handler
|
|
28342
|
+
onDayClicked(day) {
|
|
28343
|
+
if (day && day?.gD) {
|
|
28344
|
+
// Check if day is disabled by min/max constraints
|
|
28345
|
+
if (this.isDateDisabled(day)) {
|
|
28346
|
+
return; // Don't allow selection of disabled dates
|
|
28347
|
+
}
|
|
28348
|
+
if (this.futureValidation) {
|
|
28349
|
+
if (this.checkFutureValidation(day)) {
|
|
28350
|
+
this.futureValidationMessage = true;
|
|
28351
|
+
}
|
|
28352
|
+
else {
|
|
28353
|
+
this.futureValidationMessage = false;
|
|
28354
|
+
this.markDaySelected(day);
|
|
28355
|
+
}
|
|
28356
|
+
}
|
|
28357
|
+
else {
|
|
28358
|
+
this.markDaySelected(day);
|
|
28359
|
+
}
|
|
28360
|
+
}
|
|
28361
|
+
}
|
|
28362
|
+
/// Mark day as selected
|
|
28363
|
+
markDaySelected(dayInfo) {
|
|
28364
|
+
// BACKWARD COMPATIBILITY: Range selection only when selectionMode='range'
|
|
28365
|
+
if (this.selectionMode === 'range') {
|
|
28366
|
+
this.handleRangeSelection(dayInfo);
|
|
28367
|
+
return;
|
|
28368
|
+
}
|
|
28369
|
+
// BACKWARD COMPATIBILITY: Original behavior for single/multiple selection
|
|
28370
|
+
if (dayInfo.selected) {
|
|
28371
|
+
dayInfo.selected = false;
|
|
28372
|
+
this.multipleSelectedDates = this.multipleSelectedDates.filter((day) => day !== dayInfo);
|
|
28373
|
+
if (!this.multiple) {
|
|
28374
|
+
this.selectedDay = undefined;
|
|
28375
|
+
}
|
|
28376
|
+
}
|
|
28377
|
+
else {
|
|
28378
|
+
if (!this.multiple) {
|
|
28379
|
+
this.weeks.forEach((week) => {
|
|
28380
|
+
week.forEach((day) => {
|
|
28381
|
+
day.selected = false;
|
|
28382
|
+
});
|
|
28383
|
+
});
|
|
28384
|
+
dayInfo.selected = true;
|
|
28385
|
+
this.selectedDay = dayInfo;
|
|
28386
|
+
this.multipleSelectedDates = [dayInfo];
|
|
28387
|
+
// Attach current time if enableTime is active
|
|
28388
|
+
if (this.enableTime) {
|
|
28389
|
+
// Ensure time is initialized before attaching
|
|
28390
|
+
if (!this.timeInitialized) {
|
|
28391
|
+
this.initializeTime();
|
|
28392
|
+
}
|
|
28393
|
+
dayInfo.time = { ...this.selectedTime };
|
|
28394
|
+
}
|
|
28395
|
+
this.onDaySelect.emit(dayInfo);
|
|
28396
|
+
}
|
|
28397
|
+
else {
|
|
28398
|
+
dayInfo.selected = true;
|
|
28399
|
+
// Attach current time if enableTime is active
|
|
28400
|
+
if (this.enableTime) {
|
|
28401
|
+
// Ensure time is initialized before attaching
|
|
28402
|
+
if (!this.timeInitialized) {
|
|
28403
|
+
this.initializeTime();
|
|
28404
|
+
}
|
|
28405
|
+
dayInfo.time = { ...this.selectedTime };
|
|
28406
|
+
}
|
|
28407
|
+
this.onDaySelect.emit(dayInfo);
|
|
28408
|
+
if (!this.multipleSelectedDates.includes(dayInfo)) {
|
|
28409
|
+
this.multipleSelectedDates.push(dayInfo);
|
|
28410
|
+
}
|
|
28411
|
+
}
|
|
28412
|
+
}
|
|
28413
|
+
}
|
|
28414
|
+
/**
|
|
28415
|
+
* Handle range selection logic
|
|
28416
|
+
* BACKWARD COMPATIBILITY: Only called when selectionMode='range'
|
|
28417
|
+
*
|
|
28418
|
+
* Range selection lifecycle:
|
|
28419
|
+
* 1. First click → Sets rangeStart
|
|
28420
|
+
* 2. Second click → Sets rangeEnd, highlights range
|
|
28421
|
+
* 3. Third click → Resets range, starts new selection
|
|
28422
|
+
*/
|
|
28423
|
+
handleRangeSelection(dayInfo) {
|
|
28424
|
+
// First click or resetting range
|
|
28425
|
+
if (!this.rangeStart || (this.rangeStart && this.rangeEnd)) {
|
|
28426
|
+
this.resetRange();
|
|
28427
|
+
this.rangeStart = dayInfo;
|
|
28428
|
+
dayInfo.selected = true;
|
|
28429
|
+
this.selectedDay = dayInfo;
|
|
28430
|
+
// Attach current time if enableTime is active
|
|
28431
|
+
if (this.enableTime) {
|
|
28432
|
+
// Ensure selectedTime is initialized
|
|
28433
|
+
// If time hasn't been initialized yet, initialize it now
|
|
28434
|
+
if (!this.timeInitialized) {
|
|
28435
|
+
this.initializeTime();
|
|
28436
|
+
}
|
|
28437
|
+
dayInfo.time = { ...this.selectedTime };
|
|
28438
|
+
}
|
|
28439
|
+
this.onDaySelect.emit({ start: dayInfo, end: null });
|
|
28440
|
+
}
|
|
28441
|
+
// Second click - complete the range
|
|
28442
|
+
else if (this.rangeStart && !this.rangeEnd) {
|
|
28443
|
+
const startDate = this.parseDateString(this.rangeStart.gD);
|
|
28444
|
+
const endDate = this.parseDateString(dayInfo.gD);
|
|
28445
|
+
// Swap if end is before start
|
|
28446
|
+
if (endDate && startDate && endDate < startDate) {
|
|
28447
|
+
this.rangeEnd = this.rangeStart;
|
|
28448
|
+
this.rangeStart = dayInfo;
|
|
28449
|
+
}
|
|
28450
|
+
else {
|
|
28451
|
+
this.rangeEnd = dayInfo;
|
|
28452
|
+
}
|
|
28453
|
+
// Attach time if enableTime is active
|
|
28454
|
+
// IMPORTANT: Range end inherits time from range start (not current selectedTime)
|
|
28455
|
+
if (this.enableTime) {
|
|
28456
|
+
// Use rangeStart's time if it exists, otherwise use current selectedTime
|
|
28457
|
+
const timeToUse = this.rangeStart.time || { ...this.selectedTime };
|
|
28458
|
+
this.rangeStart.time = { ...timeToUse };
|
|
28459
|
+
this.rangeEnd.time = { ...timeToUse };
|
|
28460
|
+
}
|
|
28461
|
+
this.highlightRange();
|
|
28462
|
+
this.selectedDay = this.rangeEnd;
|
|
28463
|
+
this.onDaySelect.emit({ start: this.rangeStart, end: this.rangeEnd });
|
|
28464
|
+
}
|
|
28465
|
+
}
|
|
28466
|
+
/// On confirm button clicked
|
|
28467
|
+
onConfirmClicked() {
|
|
28468
|
+
// BACKWARD COMPATIBILITY: Range selection output when selectionMode='range'
|
|
28469
|
+
if (this.selectionMode === 'range') {
|
|
28470
|
+
if (this.rangeStart && this.rangeEnd) {
|
|
28471
|
+
// Collect all dates in range
|
|
28472
|
+
const rangeDates = [];
|
|
28473
|
+
this.weeks.forEach((week) => {
|
|
28474
|
+
week.forEach((day) => {
|
|
28475
|
+
if (day && day.gD && (this.isInRange(day) || this.isRangeStart(day) || this.isRangeEnd(day))) {
|
|
28476
|
+
// Attach current time if enableTime is active
|
|
28477
|
+
if (this.enableTime && !day.time) {
|
|
28478
|
+
day.time = { ...this.selectedTime };
|
|
28479
|
+
}
|
|
28480
|
+
rangeDates.push(day);
|
|
28481
|
+
}
|
|
28482
|
+
});
|
|
28483
|
+
});
|
|
28484
|
+
this.onSubmit.emit({
|
|
28485
|
+
start: this.rangeStart,
|
|
28486
|
+
end: this.rangeEnd,
|
|
28487
|
+
dates: rangeDates
|
|
28488
|
+
});
|
|
28489
|
+
}
|
|
28490
|
+
else {
|
|
28491
|
+
// Incomplete range
|
|
28492
|
+
this.onSubmit.emit({ start: this.rangeStart, end: null, dates: [] });
|
|
28493
|
+
}
|
|
28494
|
+
return;
|
|
28495
|
+
}
|
|
28496
|
+
// BACKWARD COMPATIBILITY: Original behavior for multiple/single selection
|
|
28497
|
+
if (this.multiple) {
|
|
28498
|
+
// For multiple dates, attach time to each if enableTime is active
|
|
28499
|
+
if (this.enableTime) {
|
|
28500
|
+
this.multipleSelectedDates.forEach((day) => {
|
|
28501
|
+
if (!day.time) {
|
|
28502
|
+
day.time = { ...this.selectedTime };
|
|
28503
|
+
}
|
|
28504
|
+
});
|
|
28505
|
+
}
|
|
28506
|
+
this.onSubmit.emit(this.multipleSelectedDates);
|
|
28507
|
+
}
|
|
28508
|
+
else {
|
|
28509
|
+
// For single date, attach time if enableTime is active
|
|
28510
|
+
if (this.enableTime && this.selectedDay) {
|
|
28511
|
+
this.selectedDay.time = { ...this.selectedTime };
|
|
28512
|
+
}
|
|
28513
|
+
this.onSubmit.emit(this.selectedDay);
|
|
28514
|
+
}
|
|
28515
|
+
}
|
|
28516
|
+
/// Check if date from future
|
|
28517
|
+
checkFutureValidation(day) {
|
|
28518
|
+
if (this._dateUtilsService.checkPastOrFuture(day?.gD, new Date()) == 'Future') {
|
|
28519
|
+
return true;
|
|
28520
|
+
}
|
|
28521
|
+
}
|
|
28522
|
+
/// Check if passed day is today or not
|
|
28523
|
+
checkTodaysDate(day) {
|
|
28524
|
+
return (this.todaysDate?.gregorian == day?.gD ||
|
|
28525
|
+
this.todaysDate?.ummAlQura == day?.uD);
|
|
28526
|
+
}
|
|
28527
|
+
/**
|
|
28528
|
+
* Check if a day is disabled based on min/max date constraints
|
|
28529
|
+
* Works for both Gregorian and Hijri modes
|
|
28530
|
+
*/
|
|
28531
|
+
isDateDisabled(day) {
|
|
28532
|
+
if (!day || !day.gD)
|
|
28533
|
+
return true;
|
|
28534
|
+
// Normalize min/max dates to Gregorian DD/MM/YYYY format
|
|
28535
|
+
const minDateStr = this.minDate
|
|
28536
|
+
? this._dateUtilsService.normalizeDateToString(this.minDate)
|
|
28537
|
+
: null;
|
|
28538
|
+
const maxDateStr = this.maxDate
|
|
28539
|
+
? this._dateUtilsService.normalizeDateToString(this.maxDate)
|
|
28540
|
+
: null;
|
|
28541
|
+
// Check if the day's Gregorian date is within range
|
|
28542
|
+
return !this._dateUtilsService.isDateInRange(day.gD, minDateStr, maxDateStr);
|
|
28543
|
+
}
|
|
28544
|
+
/**
|
|
28545
|
+
* Initialize time from current system time or initialDate
|
|
28546
|
+
* BACKWARD COMPATIBILITY: Only called when enableTime=true
|
|
28547
|
+
*
|
|
28548
|
+
* Priority:
|
|
28549
|
+
* 1. If initialDate has time, use that
|
|
28550
|
+
* 2. If selectedDay has time, use that
|
|
28551
|
+
* 3. Otherwise, use current system time
|
|
28552
|
+
*/
|
|
28553
|
+
initializeTime() {
|
|
28554
|
+
let timeSet = false;
|
|
28555
|
+
// Check if initialDate has time information
|
|
28556
|
+
if (this.initialDate && this.initialDate instanceof Date) {
|
|
28557
|
+
this.selectedTime = {
|
|
28558
|
+
hour: this.initialDate.getHours(),
|
|
28559
|
+
minute: this.initialDate.getMinutes(),
|
|
28560
|
+
};
|
|
28561
|
+
timeSet = true;
|
|
28562
|
+
}
|
|
28563
|
+
// If no time from initialDate, use current system time
|
|
28564
|
+
if (!timeSet) {
|
|
28565
|
+
const now = new Date();
|
|
28566
|
+
this.selectedTime = {
|
|
28567
|
+
hour: now.getHours(),
|
|
28568
|
+
minute: now.getMinutes(),
|
|
28569
|
+
};
|
|
28570
|
+
}
|
|
28571
|
+
// Mark that time has been initialized
|
|
28572
|
+
this.timeInitialized = true;
|
|
28573
|
+
// BACKWARD COMPATIBILITY: Only set meridian when useMeridian=true
|
|
28574
|
+
if (this.useMeridian) {
|
|
28575
|
+
this.meridian = this.selectedTime.hour >= 12 ? 'PM' : 'AM';
|
|
28576
|
+
}
|
|
28577
|
+
}
|
|
28578
|
+
/**
|
|
28579
|
+
* Increment hour value with wraparound (0-23)
|
|
28580
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28581
|
+
*/
|
|
28582
|
+
incrementHour() {
|
|
28583
|
+
this.selectedTime.hour = (this.selectedTime.hour + 1) % 24;
|
|
28584
|
+
this.updateSelectedDayTime();
|
|
28585
|
+
}
|
|
28586
|
+
/**
|
|
28587
|
+
* Decrement hour value with wraparound (0-23)
|
|
28588
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28589
|
+
*/
|
|
28590
|
+
decrementHour() {
|
|
28591
|
+
this.selectedTime.hour = (this.selectedTime.hour - 1 + 24) % 24;
|
|
28592
|
+
this.updateSelectedDayTime();
|
|
28593
|
+
}
|
|
28594
|
+
/**
|
|
28595
|
+
* Increment minute value with wraparound (0-59)
|
|
28596
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28597
|
+
*/
|
|
28598
|
+
incrementMinute() {
|
|
28599
|
+
this.selectedTime.minute = (this.selectedTime.minute + 1) % 60;
|
|
28600
|
+
this.updateSelectedDayTime();
|
|
28601
|
+
}
|
|
28602
|
+
/**
|
|
28603
|
+
* Decrement minute value with wraparound (0-59)
|
|
28604
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28605
|
+
*/
|
|
28606
|
+
decrementMinute() {
|
|
28607
|
+
this.selectedTime.minute = (this.selectedTime.minute - 1 + 60) % 60;
|
|
28608
|
+
this.updateSelectedDayTime();
|
|
28609
|
+
}
|
|
28610
|
+
/**
|
|
28611
|
+
* Handle keyboard input for hours
|
|
28612
|
+
* Validates and clamps to 0-23 range
|
|
28613
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28614
|
+
*/
|
|
28615
|
+
onHourInputChange(event) {
|
|
28616
|
+
let value = parseInt(event.target.value, 10);
|
|
28617
|
+
if (isNaN(value) || value < 0) {
|
|
28618
|
+
value = 0;
|
|
28619
|
+
}
|
|
28620
|
+
else if (value > 23) {
|
|
28621
|
+
value = 23;
|
|
28622
|
+
}
|
|
28623
|
+
this.selectedTime.hour = value;
|
|
28624
|
+
event.target.value = value;
|
|
28625
|
+
this.updateSelectedDayTime();
|
|
28626
|
+
}
|
|
28627
|
+
/**
|
|
28628
|
+
* Handle keyboard input for minutes
|
|
28629
|
+
* Validates and clamps to 0-59 range
|
|
28630
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28631
|
+
*/
|
|
28632
|
+
onMinuteInputChange(event) {
|
|
28633
|
+
let value = parseInt(event.target.value, 10);
|
|
28634
|
+
if (isNaN(value) || value < 0) {
|
|
28635
|
+
value = 0;
|
|
28636
|
+
}
|
|
28637
|
+
else if (value > 59) {
|
|
28638
|
+
value = 59;
|
|
28639
|
+
}
|
|
28640
|
+
this.selectedTime.minute = value;
|
|
28641
|
+
event.target.value = value;
|
|
28642
|
+
this.updateSelectedDayTime();
|
|
28643
|
+
}
|
|
28644
|
+
/**
|
|
28645
|
+
* Handle keyboard arrow keys for hour/minute input
|
|
28646
|
+
* BACKWARD COMPATIBILITY: Only available when enableTime=true
|
|
28647
|
+
*/
|
|
28648
|
+
onTimeKeydown(event, type) {
|
|
28649
|
+
if (event.key === 'ArrowUp') {
|
|
28650
|
+
event.preventDefault();
|
|
28651
|
+
if (type === 'hour') {
|
|
28652
|
+
this.incrementHour();
|
|
28653
|
+
}
|
|
28654
|
+
else {
|
|
28655
|
+
this.incrementMinute();
|
|
28656
|
+
}
|
|
28657
|
+
}
|
|
28658
|
+
else if (event.key === 'ArrowDown') {
|
|
28659
|
+
event.preventDefault();
|
|
28660
|
+
if (type === 'hour') {
|
|
28661
|
+
this.decrementHour();
|
|
28662
|
+
}
|
|
28663
|
+
else {
|
|
28664
|
+
this.decrementMinute();
|
|
28665
|
+
}
|
|
28666
|
+
}
|
|
28667
|
+
}
|
|
28668
|
+
/**
|
|
28669
|
+
* Update the selected day's time property when time changes
|
|
28670
|
+
* BACKWARD COMPATIBILITY: Only called when enableTime=true
|
|
28671
|
+
*/
|
|
28672
|
+
updateSelectedDayTime() {
|
|
28673
|
+
if (this.selectedDay) {
|
|
28674
|
+
this.selectedDay.time = { ...this.selectedTime };
|
|
28675
|
+
}
|
|
28676
|
+
}
|
|
28677
|
+
/**
|
|
28678
|
+
* Get display hour for 12-hour format
|
|
28679
|
+
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28680
|
+
*
|
|
28681
|
+
* Conversion:
|
|
28682
|
+
* - 0 (midnight) → 12 AM
|
|
28683
|
+
* - 1-11 (AM) → 1-11 AM
|
|
28684
|
+
* - 12 (noon) → 12 PM
|
|
28685
|
+
* - 13-23 (PM) → 1-11 PM
|
|
28686
|
+
*
|
|
28687
|
+
* IMPORTANT: Hour 0 is NEVER displayed as 0, always as 12
|
|
28688
|
+
*/
|
|
28689
|
+
getDisplayHour() {
|
|
28690
|
+
if (!this.useMeridian) {
|
|
28691
|
+
return this.selectedTime.hour;
|
|
28692
|
+
}
|
|
28693
|
+
const hour = this.selectedTime.hour;
|
|
28694
|
+
// Midnight (0) → 12
|
|
28695
|
+
if (hour === 0) {
|
|
28696
|
+
return 12;
|
|
28697
|
+
}
|
|
28698
|
+
// 1-12 → 1-12 (no change)
|
|
28699
|
+
else if (hour <= 12) {
|
|
28700
|
+
return hour;
|
|
28701
|
+
}
|
|
28702
|
+
// 13-23 → 1-11 (subtract 12)
|
|
28703
|
+
else {
|
|
28704
|
+
return hour - 12;
|
|
28705
|
+
}
|
|
28706
|
+
}
|
|
28707
|
+
/**
|
|
28708
|
+
* Toggle AM/PM meridian
|
|
28709
|
+
* BACKWARD COMPATIBILITY: Only available when useMeridian=true
|
|
28710
|
+
*
|
|
28711
|
+
* When toggling:
|
|
28712
|
+
* - Adds or subtracts 12 hours
|
|
28713
|
+
* - Maintains internal 24-hour format
|
|
28714
|
+
*/
|
|
28715
|
+
toggleMeridian() {
|
|
28716
|
+
if (this.meridian === 'AM') {
|
|
28717
|
+
this.meridian = 'PM';
|
|
28718
|
+
// Add 12 hours if not already in PM range
|
|
28719
|
+
if (this.selectedTime.hour < 12) {
|
|
28720
|
+
this.selectedTime.hour += 12;
|
|
28721
|
+
}
|
|
28722
|
+
}
|
|
28723
|
+
else {
|
|
28724
|
+
this.meridian = 'AM';
|
|
28725
|
+
// Subtract 12 hours if in PM range
|
|
28726
|
+
if (this.selectedTime.hour >= 12) {
|
|
28727
|
+
this.selectedTime.hour -= 12;
|
|
28728
|
+
}
|
|
28729
|
+
}
|
|
28730
|
+
this.updateSelectedDayTime();
|
|
28731
|
+
}
|
|
28732
|
+
/**
|
|
28733
|
+
* Increment hour in 12-hour mode
|
|
28734
|
+
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28735
|
+
*/
|
|
28736
|
+
incrementHour12() {
|
|
28737
|
+
let displayHour = this.getDisplayHour();
|
|
28738
|
+
displayHour = (displayHour % 12) + 1; // 1-12 cycle
|
|
28739
|
+
// Convert back to 24-hour format
|
|
28740
|
+
if (this.meridian === 'AM') {
|
|
28741
|
+
this.selectedTime.hour = displayHour === 12 ? 0 : displayHour;
|
|
28742
|
+
}
|
|
28743
|
+
else {
|
|
28744
|
+
this.selectedTime.hour = displayHour === 12 ? 12 : displayHour + 12;
|
|
28745
|
+
}
|
|
28746
|
+
this.updateSelectedDayTime();
|
|
28747
|
+
}
|
|
28748
|
+
/**
|
|
28749
|
+
* Decrement hour in 12-hour mode
|
|
28750
|
+
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28751
|
+
*/
|
|
28752
|
+
decrementHour12() {
|
|
28753
|
+
let displayHour = this.getDisplayHour();
|
|
28754
|
+
displayHour = displayHour === 1 ? 12 : displayHour - 1; // 1-12 cycle
|
|
28755
|
+
// Convert back to 24-hour format
|
|
28756
|
+
if (this.meridian === 'AM') {
|
|
28757
|
+
this.selectedTime.hour = displayHour === 12 ? 0 : displayHour;
|
|
28758
|
+
}
|
|
28759
|
+
else {
|
|
28760
|
+
this.selectedTime.hour = displayHour === 12 ? 12 : displayHour + 12;
|
|
28761
|
+
}
|
|
28762
|
+
this.updateSelectedDayTime();
|
|
28763
|
+
}
|
|
28764
|
+
/**
|
|
28765
|
+
* Handle 12-hour input change
|
|
28766
|
+
* BACKWARD COMPATIBILITY: Only used when useMeridian=true
|
|
28767
|
+
*
|
|
28768
|
+
* IMPORTANT: Input must be 1-12, never 0
|
|
28769
|
+
* - User types 0 → converted to 12
|
|
28770
|
+
* - User types > 12 → clamped to 12
|
|
28771
|
+
*/
|
|
28772
|
+
onHour12InputChange(event) {
|
|
28773
|
+
let value = parseInt(event.target.value, 10);
|
|
28774
|
+
// Validate 1-12 range (0 is not allowed in 12-hour format)
|
|
28775
|
+
if (isNaN(value) || value < 1 || value === 0) {
|
|
28776
|
+
value = 12; // Default to 12 if invalid or 0
|
|
28777
|
+
}
|
|
28778
|
+
else if (value > 12) {
|
|
28779
|
+
value = 12;
|
|
28780
|
+
}
|
|
28781
|
+
// Convert to 24-hour format
|
|
28782
|
+
if (this.meridian === 'AM') {
|
|
28783
|
+
this.selectedTime.hour = value === 12 ? 0 : value;
|
|
28784
|
+
}
|
|
28785
|
+
else {
|
|
28786
|
+
this.selectedTime.hour = value === 12 ? 12 : value + 12;
|
|
28787
|
+
}
|
|
28788
|
+
event.target.value = value;
|
|
28789
|
+
this.updateSelectedDayTime();
|
|
28790
|
+
}
|
|
28791
|
+
/**
|
|
28792
|
+
* Check if a date is within the current range
|
|
28793
|
+
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28794
|
+
*/
|
|
28795
|
+
isInRange(day) {
|
|
28796
|
+
if (this.selectionMode !== 'range' || !this.rangeStart || !this.rangeEnd || !day?.gD) {
|
|
28797
|
+
return false;
|
|
28798
|
+
}
|
|
28799
|
+
const dayDate = this.parseDateString(day.gD);
|
|
28800
|
+
const startDate = this.parseDateString(this.rangeStart.gD);
|
|
28801
|
+
const endDate = this.parseDateString(this.rangeEnd.gD);
|
|
28802
|
+
if (!dayDate || !startDate || !endDate) {
|
|
28803
|
+
return false;
|
|
28804
|
+
}
|
|
28805
|
+
return dayDate >= startDate && dayDate <= endDate;
|
|
28806
|
+
}
|
|
28807
|
+
/**
|
|
28808
|
+
* Check if a date is the range start
|
|
28809
|
+
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28810
|
+
*/
|
|
28811
|
+
isRangeStart(day) {
|
|
28812
|
+
return this.selectionMode === 'range' &&
|
|
28813
|
+
this.rangeStart?.gD === day?.gD;
|
|
28814
|
+
}
|
|
28815
|
+
/**
|
|
28816
|
+
* Check if a date is the range end
|
|
28817
|
+
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28818
|
+
*/
|
|
28819
|
+
isRangeEnd(day) {
|
|
28820
|
+
return this.selectionMode === 'range' &&
|
|
28821
|
+
this.rangeEnd?.gD === day?.gD;
|
|
28822
|
+
}
|
|
28823
|
+
/**
|
|
28824
|
+
* Reset range selection
|
|
28825
|
+
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28826
|
+
*/
|
|
28827
|
+
resetRange() {
|
|
28828
|
+
if (this.selectionMode !== 'range') {
|
|
28829
|
+
return;
|
|
28830
|
+
}
|
|
28831
|
+
// Clear range highlighting
|
|
28832
|
+
this.weeks.forEach((week) => {
|
|
28833
|
+
week.forEach((day) => {
|
|
28834
|
+
if (day && day.gD) {
|
|
28835
|
+
day.selected = false;
|
|
28836
|
+
}
|
|
28837
|
+
});
|
|
28838
|
+
});
|
|
28839
|
+
this.rangeStart = undefined;
|
|
28840
|
+
this.rangeEnd = undefined;
|
|
28841
|
+
this.selectedDay = undefined;
|
|
28842
|
+
}
|
|
28843
|
+
/**
|
|
28844
|
+
* Parse date string (DD/MM/YYYY) to Date object
|
|
28845
|
+
* Helper for range comparison
|
|
28846
|
+
*/
|
|
28847
|
+
parseDateString(dateStr) {
|
|
28848
|
+
if (!dateStr)
|
|
28849
|
+
return null;
|
|
28850
|
+
const parts = dateStr.split('/');
|
|
28851
|
+
if (parts.length !== 3)
|
|
28852
|
+
return null;
|
|
28853
|
+
const day = parseInt(parts[0], 10);
|
|
28854
|
+
const month = parseInt(parts[1], 10) - 1; // Month is 0-indexed
|
|
28855
|
+
const year = parseInt(parts[2], 10);
|
|
28856
|
+
return new Date(year, month, day);
|
|
28857
|
+
}
|
|
28858
|
+
/**
|
|
28859
|
+
* Highlight all dates in range
|
|
28860
|
+
* BACKWARD COMPATIBILITY: Only used when selectionMode='range'
|
|
28861
|
+
*/
|
|
28862
|
+
highlightRange() {
|
|
28863
|
+
if (this.selectionMode !== 'range' || !this.rangeStart || !this.rangeEnd) {
|
|
28864
|
+
return;
|
|
28865
|
+
}
|
|
28866
|
+
this.weeks.forEach((week) => {
|
|
28867
|
+
week.forEach((day) => {
|
|
28868
|
+
if (day && day.gD) {
|
|
28869
|
+
day.selected = this.isInRange(day) ||
|
|
28870
|
+
this.isRangeStart(day) ||
|
|
28871
|
+
this.isRangeEnd(day);
|
|
28872
|
+
}
|
|
28873
|
+
});
|
|
28874
|
+
});
|
|
28875
|
+
}
|
|
28876
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerComponent, deps: [{ token: i1.UntypedFormBuilder }, { token: DateUtilitiesService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
28877
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: HijriGregorianDatepickerComponent, isStandalone: false, selector: "hijri-gregorian-datepicker", inputs: { markToday: "markToday", canChangeMode: "canChangeMode", todaysDateSection: "todaysDateSection", futureValidation: "futureValidation", disableYearPicker: "disableYearPicker", disableMonthPicker: "disableMonthPicker", disableDayPicker: "disableDayPicker", multiple: "multiple", isRequired: "isRequired", showConfirmButton: "showConfirmButton", futureValidationMessage: "futureValidationMessage", arabicLayout: "arabicLayout", mode: "mode", dir: "dir", locale: "locale", submitTextButton: "submitTextButton", todaysDateText: "todaysDateText", ummAlQuraDateText: "ummAlQuraDateText", monthSelectLabel: "monthSelectLabel", yearSelectLabel: "yearSelectLabel", futureValidationMessageEn: "futureValidationMessageEn", futureValidationMessageAr: "futureValidationMessageAr", theme: "theme", pastYearsLimit: "pastYearsLimit", futureYearsLimit: "futureYearsLimit", styles: "styles", enableTime: "enableTime", minDate: "minDate", maxDate: "maxDate", initialDate: "initialDate", initialRangeStart: "initialRangeStart", initialRangeEnd: "initialRangeEnd", useMeridian: "useMeridian", selectionMode: "selectionMode" }, outputs: { onSubmit: "onSubmit", onDaySelect: "onDaySelect", onMonthChange: "onMonthChange", onYearChange: "onYearChange" }, host: { properties: { "style.font-family": "this.fontFamilyStyle" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"calendar-container\" [dir]=\"dir\" [attr.lang]=\"locale\">\r\n <div\r\n class=\"toggle-section\"\r\n [dir]=\"dir\"\r\n *ngIf=\"canChangeMode\"\r\n [ngStyle]=\"{ color: styles.primaryColor }\"\r\n >\r\n <span> {{ ummAlQuraDateText }} </span>\r\n <label class=\"switch\">\r\n <input\r\n type=\"checkbox\"\r\n [disabled]=\"!canChangeMode\"\r\n [checked]=\"mode === 'ummAlQura'\"\r\n (change)=\"changeCalendarMode()\"\r\n #calendarCheckbox\r\n />\r\n <span\r\n class=\"slider\"\r\n [ngStyle]=\"\r\n calendarCheckbox.checked\r\n ? { 'background-color': styles.primaryColor }\r\n : { 'background-color': styles.backgroundColor }\r\n \"\r\n ></span>\r\n </label>\r\n </div>\r\n\r\n <div\r\n class=\"todays-date-section\"\r\n *ngIf=\"todaysDateSection\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n color: styles.primaryColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <div\r\n class=\"text-info\"\r\n [ngClass]=\"{\r\n order: dir == 'rtl'\r\n }\"\r\n >\r\n <p>{{ todaysDateText }}</p>\r\n </div>\r\n\r\n <div\r\n class=\"data\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.todaysDateBgColor,\r\n color: styles.todaysDateTextColor\r\n }\"\r\n >\r\n <p *ngIf=\"mode == 'ummAlQura'\">\r\n <!-- {{todaysDate.ummAlQura}} -->\r\n {{\r\n locale == \"ar\"\r\n ? _dateUtilsService.convertDateNumerals(todaysDate.ummAlQura, \"ar\")\r\n : todaysDate.ummAlQura\r\n }}\r\n </p>\r\n <p *ngIf=\"mode == 'greg'\">\r\n {{\r\n locale == \"ar\"\r\n ? _dateUtilsService.convertDateNumerals(todaysDate.gregorian, \"ar\")\r\n : todaysDate.gregorian\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"period-container\">\r\n <form [formGroup]=\"periodForm\" class=\"period-form\">\r\n <div\r\n class=\"select-item\"\r\n [ngClass]=\"{\r\n order: dir == 'ltr'\r\n }\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <label *ngIf=\"!periodForm.controls['year'].value\">{{\r\n yearSelectLabel\r\n }}</label>\r\n\r\n <select\r\n formControlName=\"year\"\r\n class=\"{{ 'icon-' + dir }}\"\r\n placeholder=\"\u0627\u0644\u0633\u0646\u0629\"\r\n (change)=\"onPeriodChange('year')\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n color: styles.primaryColor,\r\n 'font-family': styles.fontFamily\r\n }\"\r\n >\r\n <option *ngFor=\"let year of years\" [ngValue]=\"year\">\r\n {{ locale == \"ar\" ? _dateUtilsService.parseEnglish(year) : year }}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n <div\r\n class=\"select-item\"\r\n [ngClass]=\"{\r\n order: dir == 'rtl'\r\n }\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <label *ngIf=\"!periodForm.controls['month'].value\">{{\r\n monthSelectLabel\r\n }}</label>\r\n <select\r\n class=\"{{ 'icon-' + dir }}\"\r\n formControlName=\"month\"\r\n (change)=\"onPeriodChange('month')\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n color: styles.primaryColor,\r\n 'font-family': styles.fontFamily\r\n }\"\r\n >\r\n <option *ngFor=\"let month of months\" [ngValue]=\"month.value\">\r\n {{ locale == \"ar\" ? month?.labelAr : month?.labelEn }}\r\n </option>\r\n </select>\r\n </div>\r\n </form>\r\n </div>\r\n\r\n <div\r\n class=\"calendar-layout\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <div class=\"week-days\">\r\n <div\r\n class=\"week-day\"\r\n [ngStyle]=\"{ color: styles.dayNameColor }\"\r\n *ngFor=\"let date of locale == 'ar' ? weekdaysAr : weekdaysEn\"\r\n >\r\n {{ date }}\r\n </div>\r\n </div>\r\n\r\n <div [dir]=\"dir\">\r\n <div class=\"week\" *ngFor=\"let week of weeks\">\r\n <div\r\n class=\"day\"\r\n *ngFor=\"let day of week\"\r\n (click)=\"disableDayPicker == false ? onDayClicked(day) : ''\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n color: styles.dayColor\r\n }\"\r\n >\r\n <div\r\n id=\"greg-day\"\r\n [ngClass]=\"{\r\n 'todays-date': checkTodaysDate(day),\r\n 'selected-date': day?.selected == true\r\n }\"\r\n [ngStyle]=\"{\r\n border:\r\n markToday && checkTodaysDate(day)\r\n ? '1px solid ' + styles.secondaryColor\r\n : '',\r\n 'background-color':\r\n day?.selected == true ? styles.secondaryColor : '',\r\n color:\r\n (day?.selected == true ? styles.todaysDateTextColor : '') ||\r\n (checkFutureValidation(day) && futureValidation\r\n ? styles.disabledDayColor\r\n : '') ||\r\n (isDateDisabled(day) ? styles.disabledDayColor : ''),\r\n opacity: isDateDisabled(day) ? '0.4' : '1',\r\n cursor: isDateDisabled(day) ? 'not-allowed' : 'pointer'\r\n }\"\r\n >\r\n <span *ngIf=\"mode == 'greg'\">{{\r\n locale == \"ar\"\r\n ? _dateUtilsService.parseEnglish(\r\n day?.gD?.split(\"/\")[0] | number\r\n )\r\n : (day?.gD?.split(\"/\")[0] | number)\r\n }}</span>\r\n\r\n <span id=\"ummAlQura-day\" *ngIf=\"mode == 'ummAlQura'\">{{\r\n locale == \"ar\"\r\n ? _dateUtilsService.parseEnglish(\r\n day?.uD?.split(\"/\")[0] | number\r\n )\r\n : (day?.uD?.split(\"/\")[0] | number)\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"future-validation\" dir=\"auto\" *ngIf=\"futureValidationMessage\">\r\n <span *ngIf=\"locale == 'ar'\">\r\n {{ futureValidationMessageAr }}\r\n </span>\r\n <span *ngIf=\"locale == 'en'\">\r\n {{ futureValidationMessageEn }}\r\n </span>\r\n </div>\r\n\r\n <!-- Time Picker Section -->\r\n <!-- BACKWARD COMPATIBILITY: This section only renders when enableTime=true -->\r\n <div class=\"time-picker-section\" *ngIf=\"enableTime\" [dir]=\"'ltr'\">\r\n <div class=\"time-picker-wrapper\">\r\n <!-- Hour Input with Arrows -->\r\n <div class=\"time-input-container\">\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-up\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"useMeridian ? incrementHour12() : incrementHour()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Increment hour\"\r\n >\r\n <i class=\"ri-arrow-drop-up-line\"></i>\r\n </button>\r\n <input\r\n type=\"number\"\r\n class=\"time-field\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerTextColor || '#333'\r\n }\"\r\n [value]=\"getDisplayHour().toString().padStart(2, '0')\"\r\n (input)=\"\r\n useMeridian\r\n ? onHour12InputChange($event)\r\n : onHourInputChange($event)\r\n \"\r\n (keydown)=\"onTimeKeydown($event, 'hour')\"\r\n [min]=\"useMeridian ? 1 : 0\"\r\n [max]=\"useMeridian ? 12 : 23\"\r\n aria-label=\"Hour\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-down\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"useMeridian ? decrementHour12() : decrementHour()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Decrement hour\"\r\n >\r\n <i class=\"ri-arrow-drop-down-line\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Colon Separator -->\r\n <span\r\n class=\"time-colon\"\r\n [ngStyle]=\"{\r\n color: styles.timePickerColonColor || '#5b479c'\r\n }\"\r\n >:</span\r\n >\r\n\r\n <!-- Minute Input with Arrows -->\r\n <div class=\"time-input-container\">\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-up\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"incrementMinute()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Increment minute\"\r\n >\r\n <i class=\"ri-arrow-drop-up-line\"></i>\r\n </button>\r\n <input\r\n type=\"number\"\r\n class=\"time-field\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerTextColor || '#333'\r\n }\"\r\n [value]=\"selectedTime.minute.toString().padStart(2, '0')\"\r\n (input)=\"onMinuteInputChange($event)\"\r\n (keydown)=\"onTimeKeydown($event, 'minute')\"\r\n min=\"0\"\r\n max=\"59\"\r\n aria-label=\"Minute\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-down\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"decrementMinute()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Decrement minute\"\r\n >\r\n <i class=\"ri-arrow-drop-down-line\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- AM/PM Button Group (only when useMeridian=true) -->\r\n <!-- BACKWARD COMPATIBILITY: This only renders when useMeridian=true -->\r\n <div class=\"meridian-toggle-group\" *ngIf=\"useMeridian\">\r\n <button\r\n type=\"button\"\r\n class=\"meridian-btn\"\r\n [class.active]=\"meridian === 'AM'\"\r\n [ngStyle]=\"\r\n meridian === 'AM'\r\n ? {\r\n 'background-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n 'border-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n color: styles.meridianActiveTextColor || '#ffffff'\r\n }\r\n : {\r\n 'background-color': styles.meridianBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.meridianTextColor || '#666'\r\n }\r\n \"\r\n (click)=\"meridian !== 'AM' && toggleMeridian()\"\r\n aria-label=\"Select AM\"\r\n >\r\n AM\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"meridian-btn\"\r\n [class.active]=\"meridian === 'PM'\"\r\n [ngStyle]=\"\r\n meridian === 'PM'\r\n ? {\r\n 'background-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n 'border-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n color: styles.meridianActiveTextColor || '#ffffff'\r\n }\r\n : {\r\n 'background-color': styles.meridianBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.meridianTextColor || '#666'\r\n }\r\n \"\r\n (click)=\"meridian !== 'PM' && toggleMeridian()\"\r\n aria-label=\"Select PM\"\r\n >\r\n PM\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"confirm-btn\"\r\n [disabled]=\"\r\n isRequired &&\r\n ((!selectedDay && !multiple) ||\r\n (!multipleSelectedDates.length && multiple))\r\n \"\r\n (click)=\"onConfirmClicked()\"\r\n *ngIf=\"showConfirmButton\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.secondaryColor,\r\n color: styles.confirmBtnTextColor,\r\n 'font-family': styles.fontFamily,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n {{ submitTextButton }}\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".calendar-container{margin:auto;display:block;border-radius:20px;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-weight:400}.calendar-container[dir=rtl],.calendar-container[lang=ar]{font-family:Zain,Arabic Typesetting,Tahoma,sans-serif;font-weight:300;letter-spacing:0;line-height:1.7}.calendar-container .todays-date-section{border-radius:4px;margin-top:12px;display:flex;align-items:center;justify-content:space-between;padding-left:10px;padding-right:10px}.calendar-container .todays-date-section .text-info{display:flex;align-items:center}.calendar-container .todays-date-section .text-info p{font-size:17px;font-weight:500;letter-spacing:.02em}[dir=rtl] .calendar-container .todays-date-section .text-info p,[lang=ar] .calendar-container .todays-date-section .text-info p{font-weight:400;letter-spacing:0}[dir=rtl] .calendar-container .todays-date-section .data p,[lang=ar] .calendar-container .todays-date-section .data p{font-weight:300}.calendar-container .todays-date-section .data{border-radius:8px}.calendar-container .todays-date-section .data p{font-size:14px;font-weight:400;margin:5px 10px}.calendar-container .period-container{display:flex;justify-content:space-between;margin-top:8px}.calendar-container .period-container .period-form{width:100%;display:flex;justify-content:space-between}.calendar-container .period-container .period-form .select-item{width:42.5%;border-radius:4px;height:50px;padding-left:10px;padding-right:10px}.calendar-container .period-container .period-form label{margin-right:10px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-container .period-container .period-form label,[lang=ar] .calendar-container .period-container .period-form label{font-weight:400}.calendar-container .period-container .period-form select{width:100%;height:50px;border:none;font-size:16px;font-weight:500;display:block;margin:auto;background:url(\"data:image/svg+xml;utf8,<svg viewBox='0 0 140 140' width='15' height='15' xmlns='http://www.w3.org/2000/svg'><g><path d='m121.3,34.6c-1.6-1.6-4.2-1.6-5.8,0l-51,51.1-51.1-51.1c-1.6-1.6-4.2-1.6-5.8,0-1.6,1.6-1.6,4.2 0,5.8l53.9,53.9c0.8,0.8 1.8,1.2 2.9,1.2 1,0 2.1-0.4 2.9-1.2l53.9-53.9c1.7-1.6 1.7-4.2 0.1-5.8z' fill='black'/></g></svg>\") no-repeat 95% 50%;-moz-appearance:none;-webkit-appearance:none;appearance:none;cursor:pointer}.calendar-container .period-container .period-form select option,.calendar-container [dir=rtl] .period-container select{font-weight:400}.calendar-container [dir=rtl] .period-container select option{font-weight:300}.icon-ltr{background-position:right}.icon-rtl{background-position:left!important}select:focus{outline:none}.calendar-layout{border-radius:4px;margin:8px auto auto;display:block;padding-bottom:5px}.calendar-layout .week-days{text-align:center;margin-top:5px;display:flex;justify-content:space-evenly}.calendar-layout .week-days .week-day{display:inline-block;width:13%;text-align:center;padding:15px 0 10px;font-weight:600;font-size:13px;text-transform:uppercase;letter-spacing:.05em}[dir=rtl] .calendar-layout .week-days{flex-direction:row-reverse!important}[dir=rtl] .calendar-layout .week-days .week-day{font-weight:700;letter-spacing:0;text-transform:none;font-size:14px}.calendar-layout .week{text-align:center;display:flex;justify-content:space-evenly}.calendar-layout .day{display:inline-flex;width:13%;height:5.5vh;justify-content:center;align-items:center;cursor:pointer;font-weight:500;transition:all .2s ease;border-radius:4px}.calendar-layout .day:hover:not(.disabled-day){transform:scale(1.05)}[dir=rtl] .calendar-layout .day{font-weight:400}.calendar-layout #greg-day{position:relative;min-width:20px}.calendar-layout #greg-day span{font-size:14px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #greg-day span,[lang=ar] .calendar-layout #greg-day span{font-weight:400}.calendar-layout #ummAlQura-day{font-size:11px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #ummAlQura-day,[lang=ar] .calendar-layout #ummAlQura-day{font-weight:400}.calendar-layout .todays-date,.calendar-layout .selected-date{padding:10px;border-radius:5px}.confirm-btn{height:50px;width:100%;border:none;font-size:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;margin:8px auto 0;box-shadow:none!important;cursor:pointer;transition:all .2s ease;border-radius:8px}.confirm-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 4px 12px #00000026!important}.confirm-btn:disabled{opacity:.5;cursor:not-allowed}[dir=rtl] .confirm-btn{font-weight:700;letter-spacing:0;text-transform:none;font-size:17px}.toggle-section{display:flex;align-items:center;justify-content:space-between}.toggle-section label{text-align:right;font-size:19px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .toggle-section label,[lang=ar] .toggle-section label{font-weight:400}.toggle-section .switch{position:relative;display:inline-block;width:50px;height:24px}.toggle-section .switch input{opacity:0;width:0;height:0}.toggle-section .slider{position:absolute;cursor:pointer;inset:0;background-color:#ccc;transition:.4s;border-radius:24px}.toggle-section .slider:before{content:\"\";position:absolute;height:18px;width:18px;left:3px;bottom:3px;background-color:#fff;transition:.4s;border-radius:50%}.toggle-section input:checked+.slider:before{transform:translate(26px)}.order{order:1}.future-validation{text-align:center;color:#eb445a;margin-top:8px;font-size:13px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .future-validation,[lang=ar] .future-validation{font-weight:400;line-height:1.8}.time-picker-section{padding:10px;background:transparent;border-radius:0;font-family:Poppins,sans-serif}.time-picker-section .time-picker-wrapper{display:flex;align-items:center;justify-content:center;gap:8px}.time-picker-section .time-picker-wrapper .time-input-container{position:relative;display:inline-flex;flex-direction:column;align-items:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{width:100%;height:20px;border:1px solid #ddd;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s ease;padding:0;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow i{font-size:20px;line-height:1;pointer-events:none;opacity:.7;transition:opacity .2s ease;display:flex;align-items:center;justify-content:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:hover i{opacity:1}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:active{background:#e9ecef}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:focus{outline:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-up{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-down{border-radius:0 0 4px 4px;border-top:none}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:25px;border:1px solid #ddd;border-top:none;border-bottom:none;background:#fff;font-size:18px;font-weight:600;color:#333;text-align:center;padding:0;margin:0;transition:all .2s ease;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;-moz-appearance:textfield;appearance:textfield}[dir=rtl] .time-picker-section .time-picker-wrapper .time-input-container .time-field,[lang=ar] .time-picker-section .time-picker-wrapper .time-input-container .time-field{font-weight:700}.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-outer-spin-button,.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-field:focus{outline:none;box-shadow:0 0 0 2px #5b479c1a;z-index:1}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px;font-weight:600;color:#5b479c;padding:0 4px;-webkit-user-select:none;user-select:none;line-height:1;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .time-colon,[lang=ar] .time-picker-section .time-picker-wrapper .time-colon{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group{display:flex;flex-direction:column;gap:0;margin-left:8px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:25px;border:1px solid #ddd;background:#fff;color:#666;font-size:13px;font-weight:600;text-align:center;padding:0;cursor:pointer;transition:all .2s ease;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn,[lang=ar] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:first-child{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:last-child{border-radius:0 0 4px 4px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:hover:not(.active){background:#f8f9fa;border-color:#00ace4;color:#00ace4}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:active{transform:scale(.98)}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:focus{outline:none;border-color:#00ace4;box-shadow:0 0 0 2px #00ace41a;z-index:1}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn.active{background:#004d61;border-color:#004d61;color:#fff;cursor:default}@media (max-width: 480px){.time-picker-section{padding:12px}.time-picker-section .time-picker-wrapper{gap:6px}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{height:18px}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:36px;font-size:20px}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px}.time-picker-section .time-picker-wrapper .meridian-toggle-group{margin-left:6px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:27px;font-size:12px}}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.DecimalPipe, name: "number" }] }); }
|
|
28878
|
+
}
|
|
28879
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerComponent, decorators: [{
|
|
28880
|
+
type: Component,
|
|
28881
|
+
args: [{ standalone: false, selector: 'hijri-gregorian-datepicker', template: "<div class=\"calendar-container\" [dir]=\"dir\" [attr.lang]=\"locale\">\r\n <div\r\n class=\"toggle-section\"\r\n [dir]=\"dir\"\r\n *ngIf=\"canChangeMode\"\r\n [ngStyle]=\"{ color: styles.primaryColor }\"\r\n >\r\n <span> {{ ummAlQuraDateText }} </span>\r\n <label class=\"switch\">\r\n <input\r\n type=\"checkbox\"\r\n [disabled]=\"!canChangeMode\"\r\n [checked]=\"mode === 'ummAlQura'\"\r\n (change)=\"changeCalendarMode()\"\r\n #calendarCheckbox\r\n />\r\n <span\r\n class=\"slider\"\r\n [ngStyle]=\"\r\n calendarCheckbox.checked\r\n ? { 'background-color': styles.primaryColor }\r\n : { 'background-color': styles.backgroundColor }\r\n \"\r\n ></span>\r\n </label>\r\n </div>\r\n\r\n <div\r\n class=\"todays-date-section\"\r\n *ngIf=\"todaysDateSection\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n color: styles.primaryColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <div\r\n class=\"text-info\"\r\n [ngClass]=\"{\r\n order: dir == 'rtl'\r\n }\"\r\n >\r\n <p>{{ todaysDateText }}</p>\r\n </div>\r\n\r\n <div\r\n class=\"data\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.todaysDateBgColor,\r\n color: styles.todaysDateTextColor\r\n }\"\r\n >\r\n <p *ngIf=\"mode == 'ummAlQura'\">\r\n <!-- {{todaysDate.ummAlQura}} -->\r\n {{\r\n locale == \"ar\"\r\n ? _dateUtilsService.convertDateNumerals(todaysDate.ummAlQura, \"ar\")\r\n : todaysDate.ummAlQura\r\n }}\r\n </p>\r\n <p *ngIf=\"mode == 'greg'\">\r\n {{\r\n locale == \"ar\"\r\n ? _dateUtilsService.convertDateNumerals(todaysDate.gregorian, \"ar\")\r\n : todaysDate.gregorian\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n <div class=\"period-container\">\r\n <form [formGroup]=\"periodForm\" class=\"period-form\">\r\n <div\r\n class=\"select-item\"\r\n [ngClass]=\"{\r\n order: dir == 'ltr'\r\n }\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <label *ngIf=\"!periodForm.controls['year'].value\">{{\r\n yearSelectLabel\r\n }}</label>\r\n\r\n <select\r\n formControlName=\"year\"\r\n class=\"{{ 'icon-' + dir }}\"\r\n placeholder=\"\u0627\u0644\u0633\u0646\u0629\"\r\n (change)=\"onPeriodChange('year')\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n color: styles.primaryColor,\r\n 'font-family': styles.fontFamily\r\n }\"\r\n >\r\n <option *ngFor=\"let year of years\" [ngValue]=\"year\">\r\n {{ locale == \"ar\" ? _dateUtilsService.parseEnglish(year) : year }}\r\n </option>\r\n </select>\r\n </div>\r\n\r\n <div\r\n class=\"select-item\"\r\n [ngClass]=\"{\r\n order: dir == 'rtl'\r\n }\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <label *ngIf=\"!periodForm.controls['month'].value\">{{\r\n monthSelectLabel\r\n }}</label>\r\n <select\r\n class=\"{{ 'icon-' + dir }}\"\r\n formControlName=\"month\"\r\n (change)=\"onPeriodChange('month')\"\r\n [dir]=\"dir\"\r\n [ngStyle]=\"{\r\n color: styles.primaryColor,\r\n 'font-family': styles.fontFamily\r\n }\"\r\n >\r\n <option *ngFor=\"let month of months\" [ngValue]=\"month.value\">\r\n {{ locale == \"ar\" ? month?.labelAr : month?.labelEn }}\r\n </option>\r\n </select>\r\n </div>\r\n </form>\r\n </div>\r\n\r\n <div\r\n class=\"calendar-layout\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n <div class=\"week-days\">\r\n <div\r\n class=\"week-day\"\r\n [ngStyle]=\"{ color: styles.dayNameColor }\"\r\n *ngFor=\"let date of locale == 'ar' ? weekdaysAr : weekdaysEn\"\r\n >\r\n {{ date }}\r\n </div>\r\n </div>\r\n\r\n <div [dir]=\"dir\">\r\n <div class=\"week\" *ngFor=\"let week of weeks\">\r\n <div\r\n class=\"day\"\r\n *ngFor=\"let day of week\"\r\n (click)=\"disableDayPicker == false ? onDayClicked(day) : ''\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.backgroundColor,\r\n color: styles.dayColor\r\n }\"\r\n >\r\n <div\r\n id=\"greg-day\"\r\n [ngClass]=\"{\r\n 'todays-date': checkTodaysDate(day),\r\n 'selected-date': day?.selected == true\r\n }\"\r\n [ngStyle]=\"{\r\n border:\r\n markToday && checkTodaysDate(day)\r\n ? '1px solid ' + styles.secondaryColor\r\n : '',\r\n 'background-color':\r\n day?.selected == true ? styles.secondaryColor : '',\r\n color:\r\n (day?.selected == true ? styles.todaysDateTextColor : '') ||\r\n (checkFutureValidation(day) && futureValidation\r\n ? styles.disabledDayColor\r\n : '') ||\r\n (isDateDisabled(day) ? styles.disabledDayColor : ''),\r\n opacity: isDateDisabled(day) ? '0.4' : '1',\r\n cursor: isDateDisabled(day) ? 'not-allowed' : 'pointer'\r\n }\"\r\n >\r\n <span *ngIf=\"mode == 'greg'\">{{\r\n locale == \"ar\"\r\n ? _dateUtilsService.parseEnglish(\r\n day?.gD?.split(\"/\")[0] | number\r\n )\r\n : (day?.gD?.split(\"/\")[0] | number)\r\n }}</span>\r\n\r\n <span id=\"ummAlQura-day\" *ngIf=\"mode == 'ummAlQura'\">{{\r\n locale == \"ar\"\r\n ? _dateUtilsService.parseEnglish(\r\n day?.uD?.split(\"/\")[0] | number\r\n )\r\n : (day?.uD?.split(\"/\")[0] | number)\r\n }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"future-validation\" dir=\"auto\" *ngIf=\"futureValidationMessage\">\r\n <span *ngIf=\"locale == 'ar'\">\r\n {{ futureValidationMessageAr }}\r\n </span>\r\n <span *ngIf=\"locale == 'en'\">\r\n {{ futureValidationMessageEn }}\r\n </span>\r\n </div>\r\n\r\n <!-- Time Picker Section -->\r\n <!-- BACKWARD COMPATIBILITY: This section only renders when enableTime=true -->\r\n <div class=\"time-picker-section\" *ngIf=\"enableTime\" [dir]=\"'ltr'\">\r\n <div class=\"time-picker-wrapper\">\r\n <!-- Hour Input with Arrows -->\r\n <div class=\"time-input-container\">\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-up\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"useMeridian ? incrementHour12() : incrementHour()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Increment hour\"\r\n >\r\n <i class=\"ri-arrow-drop-up-line\"></i>\r\n </button>\r\n <input\r\n type=\"number\"\r\n class=\"time-field\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerTextColor || '#333'\r\n }\"\r\n [value]=\"getDisplayHour().toString().padStart(2, '0')\"\r\n (input)=\"\r\n useMeridian\r\n ? onHour12InputChange($event)\r\n : onHourInputChange($event)\r\n \"\r\n (keydown)=\"onTimeKeydown($event, 'hour')\"\r\n [min]=\"useMeridian ? 1 : 0\"\r\n [max]=\"useMeridian ? 12 : 23\"\r\n aria-label=\"Hour\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-down\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"useMeridian ? decrementHour12() : decrementHour()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Decrement hour\"\r\n >\r\n <i class=\"ri-arrow-drop-down-line\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Colon Separator -->\r\n <span\r\n class=\"time-colon\"\r\n [ngStyle]=\"{\r\n color: styles.timePickerColonColor || '#5b479c'\r\n }\"\r\n >:</span\r\n >\r\n\r\n <!-- Minute Input with Arrows -->\r\n <div class=\"time-input-container\">\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-up\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"incrementMinute()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Increment minute\"\r\n >\r\n <i class=\"ri-arrow-drop-up-line\"></i>\r\n </button>\r\n <input\r\n type=\"number\"\r\n class=\"time-field\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerTextColor || '#333'\r\n }\"\r\n [value]=\"selectedTime.minute.toString().padStart(2, '0')\"\r\n (input)=\"onMinuteInputChange($event)\"\r\n (keydown)=\"onTimeKeydown($event, 'minute')\"\r\n min=\"0\"\r\n max=\"59\"\r\n aria-label=\"Minute\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"time-arrow time-arrow-down\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.timePickerBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.timePickerArrowColor || '#5b479c'\r\n }\"\r\n (click)=\"decrementMinute()\"\r\n tabindex=\"-1\"\r\n aria-label=\"Decrement minute\"\r\n >\r\n <i class=\"ri-arrow-drop-down-line\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- AM/PM Button Group (only when useMeridian=true) -->\r\n <!-- BACKWARD COMPATIBILITY: This only renders when useMeridian=true -->\r\n <div class=\"meridian-toggle-group\" *ngIf=\"useMeridian\">\r\n <button\r\n type=\"button\"\r\n class=\"meridian-btn\"\r\n [class.active]=\"meridian === 'AM'\"\r\n [ngStyle]=\"\r\n meridian === 'AM'\r\n ? {\r\n 'background-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n 'border-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n color: styles.meridianActiveTextColor || '#ffffff'\r\n }\r\n : {\r\n 'background-color': styles.meridianBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.meridianTextColor || '#666'\r\n }\r\n \"\r\n (click)=\"meridian !== 'AM' && toggleMeridian()\"\r\n aria-label=\"Select AM\"\r\n >\r\n AM\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"meridian-btn\"\r\n [class.active]=\"meridian === 'PM'\"\r\n [ngStyle]=\"\r\n meridian === 'PM'\r\n ? {\r\n 'background-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n 'border-color':\r\n styles.meridianActiveBgColor || 'rgb(0, 77, 97)',\r\n color: styles.meridianActiveTextColor || '#ffffff'\r\n }\r\n : {\r\n 'background-color': styles.meridianBgColor || '#ffffff',\r\n 'border-color': styles.timePickerBorderColor || '#ddd',\r\n color: styles.meridianTextColor || '#666'\r\n }\r\n \"\r\n (click)=\"meridian !== 'PM' && toggleMeridian()\"\r\n aria-label=\"Select PM\"\r\n >\r\n PM\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"confirm-btn\"\r\n [disabled]=\"\r\n isRequired &&\r\n ((!selectedDay && !multiple) ||\r\n (!multipleSelectedDates.length && multiple))\r\n \"\r\n (click)=\"onConfirmClicked()\"\r\n *ngIf=\"showConfirmButton\"\r\n [ngStyle]=\"{\r\n 'background-color': styles.secondaryColor,\r\n color: styles.confirmBtnTextColor,\r\n 'font-family': styles.fontFamily,\r\n 'border-radius': styles.borderRadius\r\n }\"\r\n >\r\n {{ submitTextButton }}\r\n </button>\r\n </div>\r\n</div>\r\n", styles: [".calendar-container{margin:auto;display:block;border-radius:20px;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-weight:400}.calendar-container[dir=rtl],.calendar-container[lang=ar]{font-family:Zain,Arabic Typesetting,Tahoma,sans-serif;font-weight:300;letter-spacing:0;line-height:1.7}.calendar-container .todays-date-section{border-radius:4px;margin-top:12px;display:flex;align-items:center;justify-content:space-between;padding-left:10px;padding-right:10px}.calendar-container .todays-date-section .text-info{display:flex;align-items:center}.calendar-container .todays-date-section .text-info p{font-size:17px;font-weight:500;letter-spacing:.02em}[dir=rtl] .calendar-container .todays-date-section .text-info p,[lang=ar] .calendar-container .todays-date-section .text-info p{font-weight:400;letter-spacing:0}[dir=rtl] .calendar-container .todays-date-section .data p,[lang=ar] .calendar-container .todays-date-section .data p{font-weight:300}.calendar-container .todays-date-section .data{border-radius:8px}.calendar-container .todays-date-section .data p{font-size:14px;font-weight:400;margin:5px 10px}.calendar-container .period-container{display:flex;justify-content:space-between;margin-top:8px}.calendar-container .period-container .period-form{width:100%;display:flex;justify-content:space-between}.calendar-container .period-container .period-form .select-item{width:42.5%;border-radius:4px;height:50px;padding-left:10px;padding-right:10px}.calendar-container .period-container .period-form label{margin-right:10px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-container .period-container .period-form label,[lang=ar] .calendar-container .period-container .period-form label{font-weight:400}.calendar-container .period-container .period-form select{width:100%;height:50px;border:none;font-size:16px;font-weight:500;display:block;margin:auto;background:url(\"data:image/svg+xml;utf8,<svg viewBox='0 0 140 140' width='15' height='15' xmlns='http://www.w3.org/2000/svg'><g><path d='m121.3,34.6c-1.6-1.6-4.2-1.6-5.8,0l-51,51.1-51.1-51.1c-1.6-1.6-4.2-1.6-5.8,0-1.6,1.6-1.6,4.2 0,5.8l53.9,53.9c0.8,0.8 1.8,1.2 2.9,1.2 1,0 2.1-0.4 2.9-1.2l53.9-53.9c1.7-1.6 1.7-4.2 0.1-5.8z' fill='black'/></g></svg>\") no-repeat 95% 50%;-moz-appearance:none;-webkit-appearance:none;appearance:none;cursor:pointer}.calendar-container .period-container .period-form select option,.calendar-container [dir=rtl] .period-container select{font-weight:400}.calendar-container [dir=rtl] .period-container select option{font-weight:300}.icon-ltr{background-position:right}.icon-rtl{background-position:left!important}select:focus{outline:none}.calendar-layout{border-radius:4px;margin:8px auto auto;display:block;padding-bottom:5px}.calendar-layout .week-days{text-align:center;margin-top:5px;display:flex;justify-content:space-evenly}.calendar-layout .week-days .week-day{display:inline-block;width:13%;text-align:center;padding:15px 0 10px;font-weight:600;font-size:13px;text-transform:uppercase;letter-spacing:.05em}[dir=rtl] .calendar-layout .week-days{flex-direction:row-reverse!important}[dir=rtl] .calendar-layout .week-days .week-day{font-weight:700;letter-spacing:0;text-transform:none;font-size:14px}.calendar-layout .week{text-align:center;display:flex;justify-content:space-evenly}.calendar-layout .day{display:inline-flex;width:13%;height:5.5vh;justify-content:center;align-items:center;cursor:pointer;font-weight:500;transition:all .2s ease;border-radius:4px}.calendar-layout .day:hover:not(.disabled-day){transform:scale(1.05)}[dir=rtl] .calendar-layout .day{font-weight:400}.calendar-layout #greg-day{position:relative;min-width:20px}.calendar-layout #greg-day span{font-size:14px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #greg-day span,[lang=ar] .calendar-layout #greg-day span{font-weight:400}.calendar-layout #ummAlQura-day{font-size:11px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .calendar-layout #ummAlQura-day,[lang=ar] .calendar-layout #ummAlQura-day{font-weight:400}.calendar-layout .todays-date,.calendar-layout .selected-date{padding:10px;border-radius:5px}.confirm-btn{height:50px;width:100%;border:none;font-size:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;margin:8px auto 0;box-shadow:none!important;cursor:pointer;transition:all .2s ease;border-radius:8px}.confirm-btn:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 4px 12px #00000026!important}.confirm-btn:disabled{opacity:.5;cursor:not-allowed}[dir=rtl] .confirm-btn{font-weight:700;letter-spacing:0;text-transform:none;font-size:17px}.toggle-section{display:flex;align-items:center;justify-content:space-between}.toggle-section label{text-align:right;font-size:19px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .toggle-section label,[lang=ar] .toggle-section label{font-weight:400}.toggle-section .switch{position:relative;display:inline-block;width:50px;height:24px}.toggle-section .switch input{opacity:0;width:0;height:0}.toggle-section .slider{position:absolute;cursor:pointer;inset:0;background-color:#ccc;transition:.4s;border-radius:24px}.toggle-section .slider:before{content:\"\";position:absolute;height:18px;width:18px;left:3px;bottom:3px;background-color:#fff;transition:.4s;border-radius:50%}.toggle-section input:checked+.slider:before{transform:translate(26px)}.order{order:1}.future-validation{text-align:center;color:#eb445a;margin-top:8px;font-size:13px;font-family:Poppins,sans-serif;font-weight:500}[dir=rtl] .future-validation,[lang=ar] .future-validation{font-weight:400;line-height:1.8}.time-picker-section{padding:10px;background:transparent;border-radius:0;font-family:Poppins,sans-serif}.time-picker-section .time-picker-wrapper{display:flex;align-items:center;justify-content:center;gap:8px}.time-picker-section .time-picker-wrapper .time-input-container{position:relative;display:inline-flex;flex-direction:column;align-items:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{width:100%;height:20px;border:1px solid #ddd;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s ease;padding:0;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow i{font-size:20px;line-height:1;pointer-events:none;opacity:.7;transition:opacity .2s ease;display:flex;align-items:center;justify-content:center}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:hover i{opacity:1}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:active{background:#e9ecef}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow:focus{outline:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-up{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow.time-arrow-down{border-radius:0 0 4px 4px;border-top:none}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:25px;border:1px solid #ddd;border-top:none;border-bottom:none;background:#fff;font-size:18px;font-weight:600;color:#333;text-align:center;padding:0;margin:0;transition:all .2s ease;font-family:Poppins,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;-moz-appearance:textfield;appearance:textfield}[dir=rtl] .time-picker-section .time-picker-wrapper .time-input-container .time-field,[lang=ar] .time-picker-section .time-picker-wrapper .time-input-container .time-field{font-weight:700}.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-outer-spin-button,.time-picker-section .time-picker-wrapper .time-input-container .time-field::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}.time-picker-section .time-picker-wrapper .time-input-container .time-field:focus{outline:none;box-shadow:0 0 0 2px #5b479c1a;z-index:1}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px;font-weight:600;color:#5b479c;padding:0 4px;-webkit-user-select:none;user-select:none;line-height:1;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .time-colon,[lang=ar] .time-picker-section .time-picker-wrapper .time-colon{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group{display:flex;flex-direction:column;gap:0;margin-left:8px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:25px;border:1px solid #ddd;background:#fff;color:#666;font-size:13px;font-weight:600;text-align:center;padding:0;cursor:pointer;transition:all .2s ease;font-family:Poppins,sans-serif}[dir=rtl] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn,[lang=ar] .time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{font-weight:700}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:first-child{border-radius:4px 4px 0 0;border-bottom:none}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:last-child{border-radius:0 0 4px 4px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:hover:not(.active){background:#f8f9fa;border-color:#00ace4;color:#00ace4}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:active{transform:scale(.98)}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn:focus{outline:none;border-color:#00ace4;box-shadow:0 0 0 2px #00ace41a;z-index:1}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn.active{background:#004d61;border-color:#004d61;color:#fff;cursor:default}@media (max-width: 480px){.time-picker-section{padding:12px}.time-picker-section .time-picker-wrapper{gap:6px}.time-picker-section .time-picker-wrapper .time-input-container .time-arrow{height:18px}.time-picker-section .time-picker-wrapper .time-input-container .time-field{width:50px;height:36px;font-size:20px}.time-picker-section .time-picker-wrapper .time-colon{font-size:24px}.time-picker-section .time-picker-wrapper .meridian-toggle-group{margin-left:6px}.time-picker-section .time-picker-wrapper .meridian-toggle-group .meridian-btn{width:45px;height:27px;font-size:12px}}\n"] }]
|
|
28882
|
+
}], ctorParameters: () => [{ type: i1.UntypedFormBuilder }, { type: DateUtilitiesService }], propDecorators: { markToday: [{
|
|
28883
|
+
type: Input
|
|
28884
|
+
}], canChangeMode: [{
|
|
28885
|
+
type: Input
|
|
28886
|
+
}], todaysDateSection: [{
|
|
28887
|
+
type: Input
|
|
28888
|
+
}], futureValidation: [{
|
|
28889
|
+
type: Input
|
|
28890
|
+
}], disableYearPicker: [{
|
|
28891
|
+
type: Input
|
|
28892
|
+
}], disableMonthPicker: [{
|
|
28893
|
+
type: Input
|
|
28894
|
+
}], disableDayPicker: [{
|
|
28895
|
+
type: Input
|
|
28896
|
+
}], multiple: [{
|
|
28897
|
+
type: Input
|
|
28898
|
+
}], isRequired: [{
|
|
28899
|
+
type: Input
|
|
28900
|
+
}], showConfirmButton: [{
|
|
28901
|
+
type: Input
|
|
28902
|
+
}], futureValidationMessage: [{
|
|
28903
|
+
type: Input
|
|
28904
|
+
}], arabicLayout: [{
|
|
28905
|
+
type: Input
|
|
28906
|
+
}], mode: [{
|
|
28907
|
+
type: Input
|
|
28908
|
+
}], dir: [{
|
|
28909
|
+
type: Input
|
|
28910
|
+
}], locale: [{
|
|
28911
|
+
type: Input
|
|
28912
|
+
}], submitTextButton: [{
|
|
28913
|
+
type: Input
|
|
28914
|
+
}], todaysDateText: [{
|
|
28915
|
+
type: Input
|
|
28916
|
+
}], ummAlQuraDateText: [{
|
|
28917
|
+
type: Input
|
|
28918
|
+
}], monthSelectLabel: [{
|
|
28919
|
+
type: Input
|
|
28920
|
+
}], yearSelectLabel: [{
|
|
28921
|
+
type: Input
|
|
28922
|
+
}], futureValidationMessageEn: [{
|
|
28923
|
+
type: Input
|
|
28924
|
+
}], futureValidationMessageAr: [{
|
|
28925
|
+
type: Input
|
|
28926
|
+
}], theme: [{
|
|
28927
|
+
type: Input
|
|
28928
|
+
}], pastYearsLimit: [{
|
|
28929
|
+
type: Input
|
|
28930
|
+
}], futureYearsLimit: [{
|
|
28931
|
+
type: Input
|
|
28932
|
+
}], styles: [{
|
|
28933
|
+
type: Input
|
|
28934
|
+
}], enableTime: [{
|
|
28935
|
+
type: Input
|
|
28936
|
+
}], minDate: [{
|
|
28937
|
+
type: Input
|
|
28938
|
+
}], maxDate: [{
|
|
28939
|
+
type: Input
|
|
28940
|
+
}], initialDate: [{
|
|
28941
|
+
type: Input
|
|
28942
|
+
}], initialRangeStart: [{
|
|
28943
|
+
type: Input
|
|
28944
|
+
}], initialRangeEnd: [{
|
|
28945
|
+
type: Input
|
|
28946
|
+
}], useMeridian: [{
|
|
28947
|
+
type: Input
|
|
28948
|
+
}], selectionMode: [{
|
|
28949
|
+
type: Input
|
|
28950
|
+
}], onSubmit: [{
|
|
28951
|
+
type: Output
|
|
28952
|
+
}], onDaySelect: [{
|
|
28953
|
+
type: Output
|
|
28954
|
+
}], onMonthChange: [{
|
|
28955
|
+
type: Output
|
|
28956
|
+
}], onYearChange: [{
|
|
28957
|
+
type: Output
|
|
28958
|
+
}], fontFamilyStyle: [{
|
|
28959
|
+
type: HostBinding,
|
|
28960
|
+
args: ['style.font-family']
|
|
28961
28961
|
}] } });
|
|
28962
28962
|
|
|
28963
|
-
class HijriGregorianDatepickerModule {
|
|
28964
|
-
}
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
28969
|
-
type: NgModule,
|
|
28970
|
-
args: [{
|
|
28971
|
-
declarations: [HijriGregorianDatepickerComponent],
|
|
28972
|
-
imports: [FormsModule, ReactiveFormsModule, CommonModule],
|
|
28973
|
-
exports: [HijriGregorianDatepickerComponent],
|
|
28974
|
-
}]
|
|
28963
|
+
class HijriGregorianDatepickerModule {
|
|
28964
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
28965
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerModule, declarations: [HijriGregorianDatepickerComponent], imports: [FormsModule, ReactiveFormsModule, CommonModule], exports: [HijriGregorianDatepickerComponent] }); }
|
|
28966
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerModule, imports: [FormsModule, ReactiveFormsModule, CommonModule] }); }
|
|
28967
|
+
}
|
|
28968
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HijriGregorianDatepickerModule, decorators: [{
|
|
28969
|
+
type: NgModule,
|
|
28970
|
+
args: [{
|
|
28971
|
+
declarations: [HijriGregorianDatepickerComponent],
|
|
28972
|
+
imports: [FormsModule, ReactiveFormsModule, CommonModule],
|
|
28973
|
+
exports: [HijriGregorianDatepickerComponent],
|
|
28974
|
+
}]
|
|
28975
28975
|
}] });
|
|
28976
28976
|
|
|
28977
|
-
/*
|
|
28978
|
-
* Public API Surface of hijri-gregorian-datepicker
|
|
28977
|
+
/*
|
|
28978
|
+
* Public API Surface of hijri-gregorian-datepicker
|
|
28979
28979
|
*/
|
|
28980
28980
|
|
|
28981
|
-
/**
|
|
28982
|
-
* Generated bundle index. Do not edit.
|
|
28981
|
+
/**
|
|
28982
|
+
* Generated bundle index. Do not edit.
|
|
28983
28983
|
*/
|
|
28984
28984
|
|
|
28985
28985
|
export { DateUtilitiesService, HijriGregorianDatepickerComponent, HijriGregorianDatepickerModule };
|