@dcsl/flex-ui 0.0.31 → 0.0.33
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/fesm2022/dcsl-flex-ui.mjs +277 -125
- package/fesm2022/dcsl-flex-ui.mjs.map +1 -1
- package/index.d.ts +61 -5
- package/package.json +1 -2
|
@@ -5,11 +5,9 @@ import { CommonModule } from '@angular/common';
|
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
6
6
|
import { FormsModule } from '@angular/forms';
|
|
7
7
|
import dayjs from 'dayjs';
|
|
8
|
-
import calendarSystems from '@calidy/dayjs-calendarsystems';
|
|
9
|
-
import PersianCalendarSystem from '@calidy/dayjs-calendarsystems/calendarSystems/PersianCalendarSystem';
|
|
10
|
-
import HijriCalendarSystem from '@calidy/dayjs-calendarsystems/calendarSystems/HijriCalendarSystem';
|
|
11
8
|
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
12
9
|
import utc from 'dayjs/plugin/utc';
|
|
10
|
+
import { hijriToGregorian, gregorianToHijri } from '@tabby_ai/hijri-converter';
|
|
13
11
|
import { autoUpdate, computePosition, offset, flip, shift } from '@floating-ui/dom';
|
|
14
12
|
|
|
15
13
|
class FlexPanelComponent {
|
|
@@ -669,67 +667,64 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
669
667
|
}] } });
|
|
670
668
|
|
|
671
669
|
dayjs.extend(utc);
|
|
672
|
-
// Extend Day.js with calendar systems support
|
|
673
|
-
dayjs.extend(calendarSystems);
|
|
674
670
|
dayjs.extend(customParseFormat);
|
|
675
|
-
// Register the Persian calendar
|
|
676
|
-
dayjs.registerCalendarSystem('persian', new PersianCalendarSystem());
|
|
677
|
-
dayjs.registerCalendarSystem('islamic', new HijriCalendarSystem());
|
|
678
671
|
class DateServiceService {
|
|
679
672
|
constructor() {
|
|
680
673
|
}
|
|
674
|
+
//month will start from 1
|
|
675
|
+
convertToGregorian(date) {
|
|
676
|
+
var grego = hijriToGregorian({
|
|
677
|
+
day: date.day,
|
|
678
|
+
month: date.month,
|
|
679
|
+
year: date.year
|
|
680
|
+
});
|
|
681
|
+
return {
|
|
682
|
+
day: grego.day,
|
|
683
|
+
month: grego.month,
|
|
684
|
+
year: grego.year
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
//month will start from 1
|
|
688
|
+
convertToHijri(date) {
|
|
689
|
+
var hijri = gregorianToHijri({
|
|
690
|
+
day: date.day,
|
|
691
|
+
month: date.month,
|
|
692
|
+
year: date.year
|
|
693
|
+
});
|
|
694
|
+
return {
|
|
695
|
+
day: hijri.day,
|
|
696
|
+
month: hijri.month,
|
|
697
|
+
year: hijri.year
|
|
698
|
+
};
|
|
699
|
+
}
|
|
681
700
|
parse(dateString, calendar, format) {
|
|
682
701
|
//Step 1: User will input gregorian or islamic(hijri) date. for this we will use customParseFormat
|
|
683
702
|
//in the control we will specify the format using binding.
|
|
684
703
|
var parsedUtcDate = dayjs.utc(dateString, format, true);
|
|
685
|
-
console.log("Parsed string provided by User as Utc Iso: ", parsedUtcDate.toISOString());
|
|
686
704
|
if (!parsedUtcDate.isValid()) {
|
|
687
|
-
console.log("entered date string is invalid: ", dateString);
|
|
688
705
|
return null;
|
|
689
706
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
//to show islamic date, we have to tell the dayjs to use islamic calender
|
|
701
|
-
var customDateString = customDate.format('YYYY-MM-DD');
|
|
702
|
-
const d2 = dayjs.utc(customDateString);
|
|
703
|
-
// console.log("utc", d2.toISOString());
|
|
704
|
-
return d2.toDate();
|
|
705
|
-
}
|
|
706
|
-
// parse2(dateString: string, calendar: FlexCalendarSystem, format: string): Date | null {
|
|
707
|
-
// const d = dayjs.utc(dateString, format, true);
|
|
708
|
-
// if (!d.isValid()) return null;
|
|
709
|
-
// let gYear = d.year();
|
|
710
|
-
// let gMonth = d.month();
|
|
711
|
-
// let gDay = d.date();
|
|
712
|
-
// if (calendar === "islamic") {
|
|
713
|
-
// const hijri = { hijriYear: d.year(), hijriMonth: d.month(), hijriDay: d.date() };
|
|
714
|
-
// const greg = hijriToGregorian({
|
|
715
|
-
// year: hijri.hijriYear,
|
|
716
|
-
// month: hijri.hijriMonth,
|
|
717
|
-
// day: hijri.hijriDay as number
|
|
718
|
-
// });
|
|
719
|
-
// gYear = greg.year;
|
|
720
|
-
// gMonth = greg.month;
|
|
721
|
-
// gDay = greg.day;
|
|
722
|
-
// }
|
|
723
|
-
// // construct a pure UTC date
|
|
724
|
-
// const fixed = dayjs.utc(new Date(gYear, gMonth, gDay as number));
|
|
725
|
-
// return fixed.toDate();
|
|
726
|
-
// }
|
|
707
|
+
if (calendar == "islamic") {
|
|
708
|
+
var grego = hijriToGregorian({
|
|
709
|
+
day: parsedUtcDate.date(),
|
|
710
|
+
month: parsedUtcDate.month() + 1,
|
|
711
|
+
year: parsedUtcDate.year()
|
|
712
|
+
});
|
|
713
|
+
parsedUtcDate = dayjs.utc(`${grego.year}-${grego.month}-${grego.day}`);
|
|
714
|
+
}
|
|
715
|
+
return parsedUtcDate.toDate();
|
|
716
|
+
}
|
|
727
717
|
format(date, calendar, format) {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
718
|
+
var day = dayjs.utc(`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`);
|
|
719
|
+
if (calendar == "islamic") {
|
|
720
|
+
var hijri = gregorianToHijri({
|
|
721
|
+
day: date.getDate(),
|
|
722
|
+
month: date.getMonth() + 1,
|
|
723
|
+
year: date.getFullYear()
|
|
724
|
+
});
|
|
725
|
+
day = dayjs.utc(`${hijri.year}-${hijri.month}-${hijri.day}`);
|
|
726
|
+
}
|
|
727
|
+
return day.format(format);
|
|
733
728
|
}
|
|
734
729
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
735
730
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: DateServiceService, providedIn: 'root' });
|
|
@@ -912,6 +907,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
912
907
|
args: ['window:resize']
|
|
913
908
|
}] } });
|
|
914
909
|
|
|
910
|
+
const MinGregorianDate = new Date(1937, 0, 1).getTime();
|
|
911
|
+
const MaxGregorianDate = new Date(2076, 11, 31).getTime();
|
|
915
912
|
// ✅ Intl formatters
|
|
916
913
|
const hijriFmt = new Intl.DateTimeFormat('en-u-ca-islamic-umalqura-nu-latn', {
|
|
917
914
|
day: 'numeric',
|
|
@@ -939,12 +936,17 @@ const gregMonthNamesAr = [
|
|
|
939
936
|
const weekDaysEn = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
|
940
937
|
const weekDaysAr = ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'];
|
|
941
938
|
function hijriFromGregorian(g) {
|
|
942
|
-
const parts = hijriFmt.formatToParts(g);
|
|
943
|
-
const map = {};
|
|
944
|
-
for (const p of parts)
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
939
|
+
// const parts = hijriFmt.formatToParts(g);
|
|
940
|
+
// const map: Record<string, string> = {};
|
|
941
|
+
// for (const p of parts) map[p.type] = p.value;
|
|
942
|
+
// const n = (k: string) => parseInt(map[k] ?? '0', 10);
|
|
943
|
+
// return { hy: n('year'), hm: n('month'), hd: n('day') };
|
|
944
|
+
var hijri = gregorianToHijri({
|
|
945
|
+
day: g.getDate(),
|
|
946
|
+
month: g.getMonth() + 1,
|
|
947
|
+
year: g.getFullYear()
|
|
948
|
+
});
|
|
949
|
+
return { hy: hijri.year, hm: hijri.month, hd: hijri.day };
|
|
948
950
|
}
|
|
949
951
|
function compareHijri(a, b) {
|
|
950
952
|
if (a.hy !== b.hy)
|
|
@@ -954,43 +956,60 @@ function compareHijri(a, b) {
|
|
|
954
956
|
return a.hd - b.hd;
|
|
955
957
|
}
|
|
956
958
|
function findGregorianForHijri(target) {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
959
|
+
console.log(target);
|
|
960
|
+
console.log("findGregorianForHijri => ", target.hm, "M");
|
|
961
|
+
console.log(typeof target.hm);
|
|
962
|
+
console.log(typeof target.hy);
|
|
963
|
+
var month = parseInt(target.hm.toString());
|
|
964
|
+
//var year = parseInt(target.hy.toString());
|
|
965
|
+
// console.log(month);
|
|
966
|
+
var grego = hijriToGregorian({
|
|
967
|
+
day: 1,
|
|
968
|
+
month: month,
|
|
969
|
+
year: target.hy
|
|
970
|
+
});
|
|
971
|
+
console.log("findGregorianForHijri Greg => ", grego.month, "M");
|
|
972
|
+
return new Date(grego.year, grego.month - 1, grego.day);
|
|
973
|
+
// let lo = new Date(1937, 0, 1).getTime();
|
|
974
|
+
// let hi = new Date(2076, 11, 31).getTime();
|
|
975
|
+
// const dayMs = 86400000;
|
|
976
|
+
// while (lo <= hi) {
|
|
977
|
+
// const mid = Math.floor((lo + hi) / 2);
|
|
978
|
+
// const h = hijriFromGregorian(new Date(mid));
|
|
979
|
+
// compareHijri(h, target) < 0 ? (lo = mid + dayMs) : (hi = mid - dayMs);
|
|
980
|
+
// }
|
|
981
|
+
// let d = new Date(lo);
|
|
982
|
+
// while (true) {
|
|
983
|
+
// const h = hijriFromGregorian(d);
|
|
984
|
+
// const cmp = compareHijri(h, target);
|
|
985
|
+
// if (cmp === 0) {
|
|
986
|
+
// console.log(d);
|
|
987
|
+
// return d;
|
|
988
|
+
// }
|
|
989
|
+
// if (cmp > 0) throw new Error('Hijri date out of supported range');
|
|
990
|
+
// d = new Date(d.getTime() + dayMs);
|
|
991
|
+
// }
|
|
975
992
|
}
|
|
976
993
|
function stripTime(d) {
|
|
977
|
-
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
994
|
+
//return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
995
|
+
return d;
|
|
978
996
|
}
|
|
997
|
+
|
|
979
998
|
class FlexDualCalendarComponent {
|
|
980
999
|
/** Two-way bound selected date (Gregorian) */
|
|
981
|
-
value;
|
|
982
|
-
valueChange = new EventEmitter();
|
|
1000
|
+
value = model(new Date(), ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1001
|
+
// @Output() valueChange = new EventEmitter<Date>();
|
|
983
1002
|
/** Optional min/max (Gregorian) */
|
|
984
1003
|
minDate;
|
|
985
1004
|
maxDate;
|
|
986
1005
|
/** Month/weekday language */
|
|
987
1006
|
monthLang = 'en';
|
|
988
1007
|
/** Start mode, default Hijri */
|
|
989
|
-
startMode = 'gregory';
|
|
1008
|
+
//@Input() startMode: FlexCalendarSystem = 'gregory';
|
|
990
1009
|
// This will be injected by FloatingUiService
|
|
991
1010
|
close;
|
|
992
1011
|
/** Current mode (hijri | gregory) */
|
|
993
|
-
mode =
|
|
1012
|
+
mode = model('gregory', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
994
1013
|
/** Hijri view state */
|
|
995
1014
|
hy = signal(0, ...(ngDevMode ? [{ debugName: "hy" }] : []));
|
|
996
1015
|
hm = signal(0, ...(ngDevMode ? [{ debugName: "hm" }] : []));
|
|
@@ -1016,6 +1035,7 @@ class FlexDualCalendarComponent {
|
|
|
1016
1035
|
? this.hijriMonths[this.selectedMonth - 1]
|
|
1017
1036
|
: this.gregMonths[this.selectedMonth - 1];
|
|
1018
1037
|
}
|
|
1038
|
+
ignoreDropdownSync = false;
|
|
1019
1039
|
constructor() {
|
|
1020
1040
|
const today = new Date();
|
|
1021
1041
|
const h = hijriFromGregorian(today);
|
|
@@ -1024,7 +1044,7 @@ class FlexDualCalendarComponent {
|
|
|
1024
1044
|
this.gy.set(today.getFullYear());
|
|
1025
1045
|
this.gm.set(today.getMonth() + 1);
|
|
1026
1046
|
// initialize selectors with start mode
|
|
1027
|
-
this.mode.set(this.startMode);
|
|
1047
|
+
//this.mode.set(this.startMode);
|
|
1028
1048
|
if (this.mode() === 'islamic') {
|
|
1029
1049
|
this.selectedYear = this.hy();
|
|
1030
1050
|
this.selectedMonth = this.hm();
|
|
@@ -1033,14 +1053,13 @@ class FlexDualCalendarComponent {
|
|
|
1033
1053
|
this.selectedYear = this.gy();
|
|
1034
1054
|
this.selectedMonth = this.gm();
|
|
1035
1055
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
const g = stripTime(this.value);
|
|
1056
|
+
effect((() => {
|
|
1057
|
+
if (this.ignoreDropdownSync)
|
|
1058
|
+
return;
|
|
1059
|
+
const v = this.value();
|
|
1060
|
+
if (!v)
|
|
1061
|
+
return;
|
|
1062
|
+
const g = stripTime(this.value());
|
|
1044
1063
|
const h = hijriFromGregorian(g);
|
|
1045
1064
|
this.gy.set(g.getFullYear());
|
|
1046
1065
|
this.gm.set(g.getMonth() + 1);
|
|
@@ -1055,7 +1074,29 @@ class FlexDualCalendarComponent {
|
|
|
1055
1074
|
this.selectedYear = this.gy();
|
|
1056
1075
|
this.selectedMonth = this.gm();
|
|
1057
1076
|
}
|
|
1058
|
-
}
|
|
1077
|
+
}));
|
|
1078
|
+
}
|
|
1079
|
+
ngOnInit() {
|
|
1080
|
+
this.buildYearRange();
|
|
1081
|
+
}
|
|
1082
|
+
ngOnChanges(changes) {
|
|
1083
|
+
// If value changed from outside, update both calendars
|
|
1084
|
+
// if (changes['value'] && this.value() instanceof Date) {
|
|
1085
|
+
// const g = stripTime(this.value());
|
|
1086
|
+
// const h = hijriFromGregorian(g);
|
|
1087
|
+
// this.gy.set(g.getFullYear());
|
|
1088
|
+
// this.gm.set(g.getMonth() + 1);
|
|
1089
|
+
// this.hy.set(h.hy);
|
|
1090
|
+
// this.hm.set(h.hm);
|
|
1091
|
+
// // Update dropdowns based on current mode
|
|
1092
|
+
// if (this.mode() === 'islamic') {
|
|
1093
|
+
// this.selectedYear = this.hy();
|
|
1094
|
+
// this.selectedMonth = this.hm();
|
|
1095
|
+
// } else {
|
|
1096
|
+
// this.selectedYear = this.gy();
|
|
1097
|
+
// this.selectedMonth = this.gm();
|
|
1098
|
+
// }
|
|
1099
|
+
// }
|
|
1059
1100
|
// Rebuild year range if min/max changed
|
|
1060
1101
|
if (changes['minDate'] || changes['maxDate'] || changes['value']) {
|
|
1061
1102
|
this.buildYearRange();
|
|
@@ -1080,7 +1121,7 @@ class FlexDualCalendarComponent {
|
|
|
1080
1121
|
}
|
|
1081
1122
|
// 🔁 Mode switch (SYNCED view — keep same instant)
|
|
1082
1123
|
switchMode(value) {
|
|
1083
|
-
const pivot = this.value
|
|
1124
|
+
const pivot = this.value(); // use selected date or current view start
|
|
1084
1125
|
if (value === 'gregory') {
|
|
1085
1126
|
// To Gregorian mode
|
|
1086
1127
|
const g = stripTime(pivot);
|
|
@@ -1103,6 +1144,7 @@ class FlexDualCalendarComponent {
|
|
|
1103
1144
|
}
|
|
1104
1145
|
// called when dropdowns change
|
|
1105
1146
|
onMonthYearChange() {
|
|
1147
|
+
this.ignoreDropdownSync = true;
|
|
1106
1148
|
if (this.mode() === 'islamic') {
|
|
1107
1149
|
this.hy.set(this.selectedYear);
|
|
1108
1150
|
this.hm.set(this.selectedMonth);
|
|
@@ -1111,10 +1153,12 @@ class FlexDualCalendarComponent {
|
|
|
1111
1153
|
this.gy.set(this.selectedYear);
|
|
1112
1154
|
this.gm.set(this.selectedMonth);
|
|
1113
1155
|
}
|
|
1156
|
+
setTimeout(() => (this.ignoreDropdownSync = false));
|
|
1114
1157
|
}
|
|
1115
1158
|
// Start of visible month (Gregorian date)
|
|
1116
1159
|
firstOfMonth() {
|
|
1117
1160
|
if (this.mode() === 'islamic') {
|
|
1161
|
+
//console.log("firstOfMonth function: ", this.hm());
|
|
1118
1162
|
return findGregorianForHijri({ hy: this.hy(), hm: this.hm(), hd: 1 });
|
|
1119
1163
|
}
|
|
1120
1164
|
return new Date(this.gy(), this.gm() - 1, 1);
|
|
@@ -1131,6 +1175,7 @@ class FlexDualCalendarComponent {
|
|
|
1131
1175
|
const g = new Date(start);
|
|
1132
1176
|
g.setDate(start.getDate() + i);
|
|
1133
1177
|
const h = hijriFromGregorian(g);
|
|
1178
|
+
//console.log("month:", h.hm);
|
|
1134
1179
|
let disabled = false;
|
|
1135
1180
|
if (this.minDate && g < stripTime(this.minDate))
|
|
1136
1181
|
disabled = true;
|
|
@@ -1146,6 +1191,7 @@ class FlexDualCalendarComponent {
|
|
|
1146
1191
|
prevMonth() {
|
|
1147
1192
|
if (!this.canPrev())
|
|
1148
1193
|
return;
|
|
1194
|
+
this.ignoreDropdownSync = true;
|
|
1149
1195
|
if (this.mode() === 'islamic') {
|
|
1150
1196
|
let m = this.hm(), y = this.hy();
|
|
1151
1197
|
if (--m < 1) {
|
|
@@ -1168,10 +1214,12 @@ class FlexDualCalendarComponent {
|
|
|
1168
1214
|
this.selectedYear = y;
|
|
1169
1215
|
this.selectedMonth = m;
|
|
1170
1216
|
}
|
|
1217
|
+
setTimeout(() => (this.ignoreDropdownSync = false));
|
|
1171
1218
|
}
|
|
1172
1219
|
nextMonth() {
|
|
1173
1220
|
if (!this.canNext())
|
|
1174
1221
|
return;
|
|
1222
|
+
this.ignoreDropdownSync = true;
|
|
1175
1223
|
if (this.mode() === 'islamic') {
|
|
1176
1224
|
let m = this.hm(), y = this.hy();
|
|
1177
1225
|
if (++m > 12) {
|
|
@@ -1194,6 +1242,7 @@ class FlexDualCalendarComponent {
|
|
|
1194
1242
|
this.selectedYear = y;
|
|
1195
1243
|
this.selectedMonth = m;
|
|
1196
1244
|
}
|
|
1245
|
+
setTimeout(() => (this.ignoreDropdownSync = false));
|
|
1197
1246
|
}
|
|
1198
1247
|
canPrev() {
|
|
1199
1248
|
if (!this.minDate)
|
|
@@ -1221,22 +1270,27 @@ class FlexDualCalendarComponent {
|
|
|
1221
1270
|
&& g.getDate() === t.getDate();
|
|
1222
1271
|
}
|
|
1223
1272
|
isSelected(g) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1273
|
+
const v = this.value();
|
|
1274
|
+
if (!v)
|
|
1275
|
+
return false;
|
|
1276
|
+
return !!this.value() &&
|
|
1277
|
+
g.getFullYear() === v.getFullYear() &&
|
|
1278
|
+
g.getMonth() === v.getMonth() &&
|
|
1279
|
+
g.getDate() === v.getDate();
|
|
1228
1280
|
}
|
|
1229
1281
|
select(c) {
|
|
1230
1282
|
if (c.disabled)
|
|
1231
1283
|
return;
|
|
1232
|
-
|
|
1233
|
-
|
|
1284
|
+
var g = c.g;
|
|
1285
|
+
var st = stripTime(c.g);
|
|
1286
|
+
this.value.set(st);
|
|
1287
|
+
//this.valueChange.emit(this.value);
|
|
1234
1288
|
// keep both views in sync after selection
|
|
1235
|
-
const h = hijriFromGregorian(this.value);
|
|
1289
|
+
const h = hijriFromGregorian(this.value());
|
|
1236
1290
|
this.hy.set(h.hy);
|
|
1237
1291
|
this.hm.set(h.hm);
|
|
1238
|
-
this.gy.set(this.value.getFullYear());
|
|
1239
|
-
this.gm.set(this.value.getMonth() + 1);
|
|
1292
|
+
this.gy.set(this.value().getFullYear());
|
|
1293
|
+
this.gm.set(this.value().getMonth() + 1);
|
|
1240
1294
|
if (this.mode() === 'islamic') {
|
|
1241
1295
|
this.selectedYear = this.hy();
|
|
1242
1296
|
this.selectedMonth = this.hm();
|
|
@@ -1245,26 +1299,20 @@ class FlexDualCalendarComponent {
|
|
|
1245
1299
|
this.selectedYear = this.gy();
|
|
1246
1300
|
this.selectedMonth = this.gm();
|
|
1247
1301
|
}
|
|
1248
|
-
this.close(this.value);
|
|
1302
|
+
this.close(this.value());
|
|
1249
1303
|
}
|
|
1250
1304
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1251
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualCalendarComponent, isStandalone: true, selector: "flex-dual-calendar", inputs: { value: "value", minDate: "minDate", maxDate: "maxDate", monthLang: "monthLang",
|
|
1305
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualCalendarComponent, isStandalone: true, selector: "flex-dual-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: false, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: false, isRequired: false, transformFunction: null }, monthLang: { classPropertyName: "monthLang", publicName: "monthLang", isSignal: false, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", mode: "modeChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100 rounded-0\" [class.muted]=\"!c.inCurrentMonth\" [class.fw-bold]=\"isToday(c.g)\"\r\n [class.btn-info]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'gregory'\" type=\"button\"\r\n (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'islamic'\" type=\"button\"\r\n (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell>.muted{opacity:.5;color:#aaa}.cell>.today{background-color:#647998}.cell>.selected{background-color:#0d6efd;color:#fff}.cell>.btn:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
1252
1306
|
}
|
|
1253
1307
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualCalendarComponent, decorators: [{
|
|
1254
1308
|
type: Component,
|
|
1255
|
-
args: [{ selector: 'flex-dual-calendar', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\"
|
|
1256
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
1257
|
-
type: Input
|
|
1258
|
-
}], valueChange: [{
|
|
1259
|
-
type: Output
|
|
1260
|
-
}], minDate: [{
|
|
1309
|
+
args: [{ selector: 'flex-dual-calendar', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"card\">\r\n <div class=\"card-header p-1\">\r\n <div class=\"d-flex gap-1\">\r\n\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"prevMonth()\" [disabled]=\"!canPrev()\"><i\r\n class=\"bi bi-caret-left-fill\"></i></button>\r\n </div>\r\n <div class=\"flex-grow-1\">\r\n <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedMonth\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @if (mode() === 'islamic') {\r\n @for (m of hijriMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{ hijriMonths[$index] }}-{{$index + 1}}</option>\r\n }\r\n } @else {\r\n @for (m of gregMonths; track $index) {\r\n <option [value]=\"$index + 1\">{{$index + 1}}-{{ gregMonths[$index] }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n <div> <select class=\"form-select form-select-sm\" [(ngModel)]=\"selectedYear\"\r\n (ngModelChange)=\"onMonthYearChange()\">\r\n @for (y of yearRange; track y) {\r\n <option [value]=\"y\">{{ y }}</option>\r\n }\r\n </select></div>\r\n <div>\r\n <button class=\"btn btn-sm w-100 \" (click)=\"nextMonth()\" [disabled]=\"!canNext()\"><i\r\n class=\"bi bi-caret-right-fill\"></i></button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"card-body p-0\">\r\n <!-- Weekday labels -->\r\n <div class=\"grid\">\r\n @for (w of weekDays; track $index) {\r\n <div class=\"col fw-bold border pb-1\">{{ w }}</div>\r\n }\r\n </div>\r\n\r\n <!-- Calendar cells -->\r\n <div class=\"grid\">\r\n @for (c of cells(); track $index) {\r\n <div class=\"cell\">\r\n <button class=\"btn w-100 rounded-0\" [class.muted]=\"!c.inCurrentMonth\" [class.fw-bold]=\"isToday(c.g)\"\r\n [class.btn-info]=\"isSelected(c.g)\" [disabled]=\"c.disabled\" (click)=\"select(c)\">\r\n <!-- show Hijri day in Hijri mode, otherwise Gregorian -->\r\n @if(mode() === 'islamic'){\r\n {{ c.h.hd }}\r\n }\r\n @else{\r\n {{ c.g.getDate() }}\r\n }\r\n </button>\r\n </div>\r\n }\r\n\r\n </div>\r\n </div>\r\n <div class=\"card-footer px-0 py-1\">\r\n <div class=\"d-flex justify-content-center\">\r\n <div class=\"btn-group\" role=\"group\" aria-label=\"Basic example\">\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'gregory'\" type=\"button\"\r\n (click)=\"switchMode('gregory')\">\r\n Gregorian\r\n </button>\r\n <button class=\"btn btn-sm btn-outline-secondary\" [class.btn-info]=\"mode() == 'islamic'\" type=\"button\"\r\n (click)=\"switchMode('islamic')\">\r\n \u0647\u062C\u0631\u064A\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: [".grid{display:grid;grid-template-columns:repeat(7,1fr)}.cell{border:1px solid #ddd}.cell>.muted{opacity:.5;color:#aaa}.cell>.today{background-color:#647998}.cell>.selected{background-color:#0d6efd;color:#fff}.cell>.btn:disabled{background-color:#f8f9fa;color:#aaa;cursor:not-allowed}.col{text-align:center}.btn{font-size:90%;--bs-btn-padding-x: .5rem;--bs-btn-padding-y: .25rem}.btn:hover{background-color:azure}\n"] }]
|
|
1310
|
+
}], ctorParameters: () => [], propDecorators: { minDate: [{
|
|
1261
1311
|
type: Input
|
|
1262
1312
|
}], maxDate: [{
|
|
1263
1313
|
type: Input
|
|
1264
1314
|
}], monthLang: [{
|
|
1265
1315
|
type: Input
|
|
1266
|
-
}], startMode: [{
|
|
1267
|
-
type: Input
|
|
1268
1316
|
}] } });
|
|
1269
1317
|
|
|
1270
1318
|
class DeviceDetectorService {
|
|
@@ -1404,7 +1452,6 @@ class FlexDualDatepickerComponent {
|
|
|
1404
1452
|
calendarDropdown;
|
|
1405
1453
|
inputDiv;
|
|
1406
1454
|
modalDiv;
|
|
1407
|
-
// @ViewChild("menu") popupDiv?: ElementRef;
|
|
1408
1455
|
value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
|
|
1409
1456
|
enabled = input(true, ...(ngDevMode ? [{ debugName: "enabled" }] : []));
|
|
1410
1457
|
cssClass = input(...(ngDevMode ? [undefined, { debugName: "cssClass" }] : []));
|
|
@@ -1413,8 +1460,8 @@ class FlexDualDatepickerComponent {
|
|
|
1413
1460
|
calendarSwitchPosition = input("title", ...(ngDevMode ? [{ debugName: "calendarSwitchPosition" }] : []));
|
|
1414
1461
|
//selectedDate is needed to keep the current data for process
|
|
1415
1462
|
selectedDate;
|
|
1416
|
-
calendar =
|
|
1417
|
-
_calendar = "gregory";
|
|
1463
|
+
calendar = model("gregory", ...(ngDevMode ? [{ debugName: "calendar" }] : []));
|
|
1464
|
+
// protected _calendar: FlexCalendarSystem = "gregory";
|
|
1418
1465
|
inputDate = "";
|
|
1419
1466
|
isMobile = false;
|
|
1420
1467
|
constructor(dateService, deviceDetector, floating) {
|
|
@@ -1423,7 +1470,7 @@ class FlexDualDatepickerComponent {
|
|
|
1423
1470
|
this.floating = floating;
|
|
1424
1471
|
this.isMobile = deviceDetector.isMobile();
|
|
1425
1472
|
effect(() => {
|
|
1426
|
-
this._calendar = this.calendar();
|
|
1473
|
+
//this._calendar = this.calendar();
|
|
1427
1474
|
if (!this.selectedDate)
|
|
1428
1475
|
return;
|
|
1429
1476
|
this.inputDate = this.formatDate(this.selectedDate);
|
|
@@ -1431,7 +1478,7 @@ class FlexDualDatepickerComponent {
|
|
|
1431
1478
|
effect(() => {
|
|
1432
1479
|
const iso = this.value();
|
|
1433
1480
|
if (iso) {
|
|
1434
|
-
const date = dayjs(iso);
|
|
1481
|
+
const date = dayjs.utc(iso);
|
|
1435
1482
|
if (date.isValid()) {
|
|
1436
1483
|
this.selectedDate = date.toDate();
|
|
1437
1484
|
this.inputDate = this.formatDate(this.selectedDate);
|
|
@@ -1443,11 +1490,13 @@ class FlexDualDatepickerComponent {
|
|
|
1443
1490
|
});
|
|
1444
1491
|
}
|
|
1445
1492
|
switchCalendar() {
|
|
1446
|
-
if (this.
|
|
1447
|
-
this._calendar = "islamic";
|
|
1493
|
+
if (this.calendar() == "gregory") {
|
|
1494
|
+
// this._calendar = "islamic";
|
|
1495
|
+
this.calendar.set("islamic");
|
|
1448
1496
|
}
|
|
1449
1497
|
else {
|
|
1450
|
-
this._calendar = "gregory";
|
|
1498
|
+
//this._calendar = "gregory";
|
|
1499
|
+
this.calendar.set("gregory");
|
|
1451
1500
|
}
|
|
1452
1501
|
this.inputDate = this.formatDate(this.selectedDate);
|
|
1453
1502
|
}
|
|
@@ -1476,7 +1525,7 @@ class FlexDualDatepickerComponent {
|
|
|
1476
1525
|
this.value.set(d);
|
|
1477
1526
|
}
|
|
1478
1527
|
formatDate(date) {
|
|
1479
|
-
return this.dateService.format(date, this.
|
|
1528
|
+
return this.dateService.format(date, this.calendar(), this.format());
|
|
1480
1529
|
}
|
|
1481
1530
|
parseInputDate(str) {
|
|
1482
1531
|
/*if the user clear the text in input box then we must accept as the user
|
|
@@ -1490,7 +1539,7 @@ class FlexDualDatepickerComponent {
|
|
|
1490
1539
|
so we will should not show null or empty value, instead we will
|
|
1491
1540
|
return current date or last selected date
|
|
1492
1541
|
*/
|
|
1493
|
-
var parsedDate = this.dateService.parse(str, this.
|
|
1542
|
+
var parsedDate = this.dateService.parse(str, this.calendar(), this.format());
|
|
1494
1543
|
if (parsedDate)
|
|
1495
1544
|
return parsedDate;
|
|
1496
1545
|
//if parseDate is null this means user entered wrong date, in this case we will return
|
|
@@ -1513,10 +1562,12 @@ class FlexDualDatepickerComponent {
|
|
|
1513
1562
|
async openCalendar() {
|
|
1514
1563
|
const button = this.calendarButton?.nativeElement;
|
|
1515
1564
|
const result = await this.floating.open(button, FlexDualCalendarComponent, {
|
|
1516
|
-
placement: 'bottom
|
|
1565
|
+
placement: 'bottom',
|
|
1517
1566
|
inputs: {
|
|
1518
1567
|
// You can pass any props here
|
|
1519
1568
|
initialDate: this.selectedDate,
|
|
1569
|
+
mode: this.calendar,
|
|
1570
|
+
value: this.value
|
|
1520
1571
|
},
|
|
1521
1572
|
});
|
|
1522
1573
|
if (result) {
|
|
@@ -1526,11 +1577,11 @@ class FlexDualDatepickerComponent {
|
|
|
1526
1577
|
}
|
|
1527
1578
|
isOpen = false;
|
|
1528
1579
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualDatepickerComponent, deps: [{ token: DateServiceService }, { token: DeviceDetectorService }, { token: FloatingUiService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1529
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualDatepickerComponent, isStandalone: true, selector: "flex-dual-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, cssClass: { classPropertyName: "cssClass", publicName: "cssClass", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, calendarSwitchPosition: { classPropertyName: "calendarSwitchPosition", publicName: "calendarSwitchPosition", isSignal: true, isRequired: false, transformFunction: null }, calendar: { classPropertyName: "calendar", publicName: "calendar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "calendarButton", first: true, predicate: ["calendarButton"], descendants: true }, { propertyName: "calendarDropdown", first: true, predicate: ["calendarDropdown"], descendants: true }, { propertyName: "inputDiv", first: true, predicate: ["inputDiv"], descendants: true }, { propertyName: "modalDiv", first: true, predicate: ["modalDiv"], descendants: true }], ngImport: i0, template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(
|
|
1580
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexDualDatepickerComponent, isStandalone: true, selector: "flex-dual-datepicker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, enabled: { classPropertyName: "enabled", publicName: "enabled", isSignal: true, isRequired: false, transformFunction: null }, cssClass: { classPropertyName: "cssClass", publicName: "cssClass", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, calendarSwitchPosition: { classPropertyName: "calendarSwitchPosition", publicName: "calendarSwitchPosition", isSignal: true, isRequired: false, transformFunction: null }, calendar: { classPropertyName: "calendar", publicName: "calendar", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", calendar: "calendarChange" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "calendarButton", first: true, predicate: ["calendarButton"], descendants: true }, { propertyName: "calendarDropdown", first: true, predicate: ["calendarDropdown"], descendants: true }, { propertyName: "inputDiv", first: true, predicate: ["inputDiv"], descendants: true }, { propertyName: "modalDiv", first: true, predicate: ["modalDiv"], descendants: true }], ngImport: i0, template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(calendar() == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(calendar() == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n</div>", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
1530
1581
|
}
|
|
1531
1582
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexDualDatepickerComponent, decorators: [{
|
|
1532
1583
|
type: Component,
|
|
1533
|
-
args: [{ selector: 'flex-dual-datepicker', imports: [CommonModule, FormsModule], template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(
|
|
1584
|
+
args: [{ selector: 'flex-dual-datepicker', imports: [CommonModule, FormsModule], template: "@if(calendarSwitchPosition() == 'title'){\r\n<div class=\"d-flex align-items-center gap-1\">\r\n <label>{{ title() }}</label>\r\n <button type=\"button\" class=\"btn btn-sm btn-light\" style=\"cursor: pointer; padding-bottom: 1px; padding-top: 1px;\"\r\n (click)=\"switchCalendar()\">\r\n @if(calendar() == 'gregory') {G}\r\n @else{H}\r\n </button>\r\n</div>\r\n}\r\n<div class=\"input-group flex-nowrap\" #inputDiv>\r\n @if(calendarSwitchPosition() == 'inline'){\r\n <span class=\"input-group-text\" style=\"cursor: pointer;\" (click)=\"switchCalendar()\"> @if(calendar() == 'gregory') {G}\r\n @else{H}</span>\r\n }\r\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"inputDate\" (blur)=\"onManualDateEntered()\"\r\n [disabled]=\"!enabled()\" [placeholder]=\"format()\" (keyup.enter)=\"onManualDateEntered()\">\r\n <button #calendarButton class=\"btn btn-outline-secondary\" (click)=\"openCalendar()\" [disabled]=\"!enabled()\">\r\n <i class=\"bi bi-calendar3\"></i>\r\n </button>\r\n</div>", styles: [".dropdown-menu{--bs-dropdown-padding-y: 0}.card-body{padding:0!important}.dropdown-panel{position:fixed;border-radius:4px;z-index:9999}.calendar-dropdown{width:max-content;position:absolute;top:0;left:0;visibility:hidden;z-index:\"1080\",}\n"] }]
|
|
1534
1585
|
}], ctorParameters: () => [{ type: DateServiceService }, { type: DeviceDetectorService }, { type: FloatingUiService }], propDecorators: { calendarButton: [{
|
|
1535
1586
|
type: ViewChild,
|
|
1536
1587
|
args: ['calendarButton']
|
|
@@ -1548,6 +1599,107 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
1548
1599
|
args: ['document:click', ['$event']]
|
|
1549
1600
|
}] } });
|
|
1550
1601
|
|
|
1602
|
+
class FlexTablePagingComponent {
|
|
1603
|
+
pageIndex = 1; // current page
|
|
1604
|
+
pageSize = 10; // selected page size
|
|
1605
|
+
totalCount = 0; // total items
|
|
1606
|
+
pageSizes = [10, 50, 100, 200];
|
|
1607
|
+
pageIndexChange = new EventEmitter();
|
|
1608
|
+
pageSizeChange = new EventEmitter();
|
|
1609
|
+
// detect external changes
|
|
1610
|
+
ngOnChanges(changes) {
|
|
1611
|
+
if (changes['totalCount'] && !changes['totalCount'].firstChange) {
|
|
1612
|
+
// Reset to page 1 if totalCount decreased or changed
|
|
1613
|
+
this.pageIndex = 1;
|
|
1614
|
+
this.pageIndexChange.emit(1);
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
get totalPages() {
|
|
1618
|
+
return Math.max(1, Math.ceil(this.totalCount / this.pageSize));
|
|
1619
|
+
}
|
|
1620
|
+
get pages() {
|
|
1621
|
+
return Array.from({ length: this.totalPages }, (_, i) => i + 1);
|
|
1622
|
+
}
|
|
1623
|
+
onPageChange(e) {
|
|
1624
|
+
this.pageIndex = +e.target.value;
|
|
1625
|
+
this.pageIndexChange.emit(this.pageIndex);
|
|
1626
|
+
}
|
|
1627
|
+
onPageSizeChange(e) {
|
|
1628
|
+
this.pageSize = +e.target.value;
|
|
1629
|
+
this.pageSizeChange.emit(this.pageSize);
|
|
1630
|
+
// reset to page 1 when size changes
|
|
1631
|
+
this.pageIndex = 1;
|
|
1632
|
+
this.pageIndexChange.emit(this.pageIndex);
|
|
1633
|
+
}
|
|
1634
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTablePagingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1635
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.1", type: FlexTablePagingComponent, isStandalone: true, selector: "flex-table-paging", inputs: { pageIndex: "pageIndex", pageSize: "pageSize", totalCount: "totalCount", pageSizes: "pageSizes" }, outputs: { pageIndexChange: "pageIndexChange", pageSizeChange: "pageSizeChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"border-top\">\r\n <div class=\"d-flex align-items-center gap-2 p-2 small\">\r\n\r\n <div>Page No</div>\r\n\r\n <select class=\"form-select w-auto\" [ngModel]=\"pageIndex\" (change)=\"onPageChange($event)\">\r\n <option *ngFor=\"let p of pages\" [value]=\"p\">{{ p }}</option>\r\n </select>\r\n\r\n <div>Page Size</div>\r\n\r\n <select class=\"form-select w-auto\" [ngModel]=\"pageSize\" (change)=\"onPageSizeChange($event)\">\r\n <option *ngFor=\"let size of pageSizes\" [value]=\"size\">{{ size }}</option>\r\n </select>\r\n\r\n <div class=\"ms-auto\">\r\n Total Rows : <strong>{{ totalCount }}</strong>\r\n </div>\r\n </div>\r\n</div>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
|
|
1636
|
+
}
|
|
1637
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTablePagingComponent, decorators: [{
|
|
1638
|
+
type: Component,
|
|
1639
|
+
args: [{ selector: 'flex-table-paging', imports: [CommonModule, FormsModule], template: "<div class=\"border-top\">\r\n <div class=\"d-flex align-items-center gap-2 p-2 small\">\r\n\r\n <div>Page No</div>\r\n\r\n <select class=\"form-select w-auto\" [ngModel]=\"pageIndex\" (change)=\"onPageChange($event)\">\r\n <option *ngFor=\"let p of pages\" [value]=\"p\">{{ p }}</option>\r\n </select>\r\n\r\n <div>Page Size</div>\r\n\r\n <select class=\"form-select w-auto\" [ngModel]=\"pageSize\" (change)=\"onPageSizeChange($event)\">\r\n <option *ngFor=\"let size of pageSizes\" [value]=\"size\">{{ size }}</option>\r\n </select>\r\n\r\n <div class=\"ms-auto\">\r\n Total Rows : <strong>{{ totalCount }}</strong>\r\n </div>\r\n </div>\r\n</div>" }]
|
|
1640
|
+
}], propDecorators: { pageIndex: [{
|
|
1641
|
+
type: Input
|
|
1642
|
+
}], pageSize: [{
|
|
1643
|
+
type: Input
|
|
1644
|
+
}], totalCount: [{
|
|
1645
|
+
type: Input
|
|
1646
|
+
}], pageSizes: [{
|
|
1647
|
+
type: Input
|
|
1648
|
+
}], pageIndexChange: [{
|
|
1649
|
+
type: Output
|
|
1650
|
+
}], pageSizeChange: [{
|
|
1651
|
+
type: Output
|
|
1652
|
+
}] } });
|
|
1653
|
+
|
|
1654
|
+
class FlexTableComponent {
|
|
1655
|
+
columns = Array.from({ length: 50 }, (_, index) => `Item ${index + 1}`);
|
|
1656
|
+
items = Array.from({ length: 50 }, (_, index) => `Item ${index + 1}`);
|
|
1657
|
+
enablePaging = input(false, ...(ngDevMode ? [{ debugName: "enablePaging" }] : []));
|
|
1658
|
+
totalDataCount = input(0, ...(ngDevMode ? [{ debugName: "totalDataCount" }] : []));
|
|
1659
|
+
pageChange = output();
|
|
1660
|
+
currentPage = 1;
|
|
1661
|
+
pageSize = 50;
|
|
1662
|
+
selectedIndex = -1;
|
|
1663
|
+
gridColumns;
|
|
1664
|
+
tableHeader;
|
|
1665
|
+
dataSource = input([], ...(ngDevMode ? [{ debugName: "dataSource" }] : []));
|
|
1666
|
+
rowClicked = output();
|
|
1667
|
+
rowDblClicked = output();
|
|
1668
|
+
syncScroll(e) {
|
|
1669
|
+
const body = e.target;
|
|
1670
|
+
const header = this.tableHeader?.nativeElement; //document.querySelector('.grid-header');
|
|
1671
|
+
if (header)
|
|
1672
|
+
header.scrollLeft = body.scrollLeft;
|
|
1673
|
+
}
|
|
1674
|
+
onRowDblClick(index, data) {
|
|
1675
|
+
this.selectedIndex = index;
|
|
1676
|
+
// console.log(index);
|
|
1677
|
+
this.rowDblClicked.emit({ index: index, data: data });
|
|
1678
|
+
}
|
|
1679
|
+
onRowClick(index, data) {
|
|
1680
|
+
this.selectedIndex = index;
|
|
1681
|
+
// console.log(index);
|
|
1682
|
+
this.rowClicked.emit({ index: index, data: data });
|
|
1683
|
+
}
|
|
1684
|
+
pageSizes = [50, 100, 200, 500];
|
|
1685
|
+
selectedPageSize;
|
|
1686
|
+
onPageSizeChange($event) {
|
|
1687
|
+
throw new Error('Method not implemented.');
|
|
1688
|
+
}
|
|
1689
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1690
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.1", type: FlexTableComponent, isStandalone: true, selector: "flex-table", inputs: { enablePaging: { classPropertyName: "enablePaging", publicName: "enablePaging", isSignal: true, isRequired: false, transformFunction: null }, totalDataCount: { classPropertyName: "totalDataCount", publicName: "totalDataCount", isSignal: true, isRequired: false, transformFunction: null }, dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pageChange: "pageChange", rowClicked: "rowClicked", rowDblClicked: "rowDblClicked" }, queries: [{ propertyName: "gridColumns", first: true, predicate: FlexColumnsComponent, descendants: true }], viewQueries: [{ propertyName: "tableHeader", first: true, predicate: ["tableHeader"], descendants: true }], ngImport: i0, template: "<div class=\"table-layout\">\r\n <div style=\"overflow-x: hidden; padding-right: 15px;\" #tableHeader>\r\n <table class=\"table table-bordered mb-0 table-header\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <th class=\"text-truncate\">\r\n @if (col.headerTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.headerTemplate\"></ng-container>\r\n }\r\n @else {\r\n <!-- <ng-template #defaultHeader><span [textContent]=\"col.field\"></span></ng-template> -->\r\n <!-- <span [textContent]=\"col.field\"></span> -->\r\n {{ col.headerText() }}\r\n }\r\n </th>\r\n }\r\n\r\n <!-- <th style=\"width: 20px;\"></th> -->\r\n </tr>\r\n </thead>\r\n </table>\r\n </div>\r\n\r\n <div class=\"content-area\" (scroll)=\"syncScroll($event)\">\r\n <table class=\"table table-bordered\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <tbody>\r\n @for (row of dataSource(); track $index; let i = $index) {\r\n <tr [class.table-active]=\"$index === selectedIndex\" (click)=\"onRowClick($index, row)\"\r\n (dblclick)=\"onRowDblClick($index, row)\">\r\n @for (col of gridColumns?.columns; track $index) {\r\n <td>\r\n @if (col.cellTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.cellTemplate\" [ngTemplateOutletContext]=\"{ $implicit: row,\r\n rowIndex: (currentPage - 1) * pageSize + i,\r\n localIndex: i }\">\r\n </ng-container>\r\n } @else {\r\n <!-- {{ row[col.field] }} -->\r\n <span [textContent]=\"row[col.field]\"></span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if(enablePaging()){\r\n <flex-table-paging [totalCount]=\"totalDataCount()\"></flex-table-paging>\r\n }\r\n\r\n</div>", styles: [":host{display:block;height:100%;min-height:0;background:var(--bg);color:var(--text)}.table-layout{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0}.content-area{overflow-x:auto;overflow-y:auto;min-height:0;background:var(--scroll-bg)}table{border-collapse:collapse;white-space:nowrap;min-width:max-content}.table-header{--bs-table-bg: #f9f9f9}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: FlexTablePagingComponent, selector: "flex-table-paging", inputs: ["pageIndex", "pageSize", "totalCount", "pageSizes"], outputs: ["pageIndexChange", "pageSizeChange"] }] });
|
|
1691
|
+
}
|
|
1692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImport: i0, type: FlexTableComponent, decorators: [{
|
|
1693
|
+
type: Component,
|
|
1694
|
+
args: [{ selector: 'flex-table', imports: [CommonModule, FlexTablePagingComponent], template: "<div class=\"table-layout\">\r\n <div style=\"overflow-x: hidden; padding-right: 15px;\" #tableHeader>\r\n <table class=\"table table-bordered mb-0 table-header\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <thead>\r\n <tr>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <th class=\"text-truncate\">\r\n @if (col.headerTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.headerTemplate\"></ng-container>\r\n }\r\n @else {\r\n <!-- <ng-template #defaultHeader><span [textContent]=\"col.field\"></span></ng-template> -->\r\n <!-- <span [textContent]=\"col.field\"></span> -->\r\n {{ col.headerText() }}\r\n }\r\n </th>\r\n }\r\n\r\n <!-- <th style=\"width: 20px;\"></th> -->\r\n </tr>\r\n </thead>\r\n </table>\r\n </div>\r\n\r\n <div class=\"content-area\" (scroll)=\"syncScroll($event)\">\r\n <table class=\"table table-bordered\">\r\n <colgroup>\r\n @for (col of gridColumns?.columns; track $index) {\r\n <col [style.width.px]=\"col.width\" [style.maxWidth.px]=\"col.width\">\r\n }\r\n </colgroup>\r\n <tbody>\r\n @for (row of dataSource(); track $index; let i = $index) {\r\n <tr [class.table-active]=\"$index === selectedIndex\" (click)=\"onRowClick($index, row)\"\r\n (dblclick)=\"onRowDblClick($index, row)\">\r\n @for (col of gridColumns?.columns; track $index) {\r\n <td>\r\n @if (col.cellTemplate) {\r\n <ng-container [ngTemplateOutlet]=\"col.cellTemplate\" [ngTemplateOutletContext]=\"{ $implicit: row,\r\n rowIndex: (currentPage - 1) * pageSize + i,\r\n localIndex: i }\">\r\n </ng-container>\r\n } @else {\r\n <!-- {{ row[col.field] }} -->\r\n <span [textContent]=\"row[col.field]\"></span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </div>\r\n @if(enablePaging()){\r\n <flex-table-paging [totalCount]=\"totalDataCount()\"></flex-table-paging>\r\n }\r\n\r\n</div>", styles: [":host{display:block;height:100%;min-height:0;background:var(--bg);color:var(--text)}.table-layout{display:grid;grid-template-rows:auto 1fr auto;height:100%;min-height:0}.content-area{overflow-x:auto;overflow-y:auto;min-height:0;background:var(--scroll-bg)}table{border-collapse:collapse;white-space:nowrap;min-width:max-content}.table-header{--bs-table-bg: #f9f9f9}\n"] }]
|
|
1695
|
+
}], propDecorators: { gridColumns: [{
|
|
1696
|
+
type: ContentChild,
|
|
1697
|
+
args: [FlexColumnsComponent]
|
|
1698
|
+
}], tableHeader: [{
|
|
1699
|
+
type: ViewChild,
|
|
1700
|
+
args: ["tableHeader"]
|
|
1701
|
+
}] } });
|
|
1702
|
+
|
|
1551
1703
|
/*
|
|
1552
1704
|
* Public API Surface of flex-ui-controls
|
|
1553
1705
|
*/
|
|
@@ -1556,5 +1708,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.1", ngImpor
|
|
|
1556
1708
|
* Generated bundle index. Do not edit.
|
|
1557
1709
|
*/
|
|
1558
1710
|
|
|
1559
|
-
export { ComboDatePickerComponent, FlexColumnComponent, FlexColumnsComponent, FlexContainerComponent, FlexDualDatepickerComponent, FlexGridComponent, FlexPaginationComponent, FlexPanelComponent, HijriDatepickerComponent };
|
|
1711
|
+
export { ComboDatePickerComponent, FlexColumnComponent, FlexColumnsComponent, FlexContainerComponent, FlexDualDatepickerComponent, FlexGridComponent, FlexPaginationComponent, FlexPanelComponent, FlexTableComponent, FlexTablePagingComponent, HijriDatepickerComponent };
|
|
1560
1712
|
//# sourceMappingURL=dcsl-flex-ui.mjs.map
|