@energycap/components 0.46.8 → 0.46.9-esm-luxon.20260514-2148
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.
|
@@ -16,8 +16,8 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
|
|
16
16
|
import { ClipboardService } from 'ngx-clipboard';
|
|
17
17
|
import { Subject, of, lastValueFrom, forkJoin, merge, fromEvent, EMPTY, timer, interval, race, ReplaySubject } from 'rxjs';
|
|
18
18
|
import { takeUntil, switchMap, delay, distinctUntilChanged, filter, take, debounceTime, skipUntil, tap, pluck, map, catchError, skipWhile } from 'rxjs/operators';
|
|
19
|
-
import
|
|
20
|
-
import { range, cloneDeep, isEqual, uniqueId, sortBy, orderBy, get, upperFirst } from 'lodash';
|
|
19
|
+
import { DateTime, Info } from 'luxon';
|
|
20
|
+
import { range, cloneDeep, isEqual, uniqueId, sortBy, orderBy, get, upperFirst } from 'lodash-es';
|
|
21
21
|
import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
|
|
22
22
|
import Popper from 'popper.js';
|
|
23
23
|
|
|
@@ -480,7 +480,7 @@ class DateTimeHelper {
|
|
|
480
480
|
/** 3000-01-01 */
|
|
481
481
|
static { this.endOfTime = new Date(3000, 0, 1); }
|
|
482
482
|
/** 3000-01-01 UTC */
|
|
483
|
-
static { this.endOfTimeUTC =
|
|
483
|
+
static { this.endOfTimeUTC = DateTime.fromISO('3000-01-01', { zone: 'utc' }).toJSDate(); }
|
|
484
484
|
/** Default effective date for new AccountMeter relationships: 2010-01-01 */
|
|
485
485
|
static { this.defaultAccountMeterEffectiveDate = new Date(2010, 0, 1); }
|
|
486
486
|
/** The default date that a newly created account becomes effective: 2010-01-01 */
|
|
@@ -522,20 +522,19 @@ class DateTimeHelper {
|
|
|
522
522
|
"yyyyMMdd"
|
|
523
523
|
]; }
|
|
524
524
|
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
'
|
|
532
|
-
'
|
|
533
|
-
'
|
|
534
|
-
'
|
|
535
|
-
'
|
|
536
|
-
'
|
|
537
|
-
'
|
|
538
|
-
'MM-DD-YYYY'
|
|
525
|
+
* Luxon parse formats for the month-first preference. Separator characters
|
|
526
|
+
* in the input are normalized to a hyphen before matching (see {@link parseWithFormats}),
|
|
527
|
+
* so the formats below intentionally use a single separator.
|
|
528
|
+
*/
|
|
529
|
+
static { this.luxonMonthFirstParseFormats = [
|
|
530
|
+
'M-d',
|
|
531
|
+
'MM-dd',
|
|
532
|
+
'M-d-yy',
|
|
533
|
+
'MM-dd-yy',
|
|
534
|
+
'MMddyyyy',
|
|
535
|
+
'yyyyMMdd',
|
|
536
|
+
'yyyy-MM-dd',
|
|
537
|
+
'MM-dd-yyyy'
|
|
539
538
|
]; }
|
|
540
539
|
/**
|
|
541
540
|
* User input formats that we will parse into a date
|
|
@@ -559,44 +558,48 @@ class DateTimeHelper {
|
|
|
559
558
|
"yyyyDDmm"
|
|
560
559
|
]; }
|
|
561
560
|
/**
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
'
|
|
569
|
-
'
|
|
570
|
-
'
|
|
571
|
-
'
|
|
572
|
-
'
|
|
573
|
-
'
|
|
574
|
-
'YYYY-MM-DD',
|
|
575
|
-
'DD-MM-YYYY'
|
|
561
|
+
* Luxon parse formats for the day-first preference. Separator characters
|
|
562
|
+
* in the input are normalized to a hyphen before matching (see {@link parseWithFormats}).
|
|
563
|
+
*/
|
|
564
|
+
static { this.luxonDateFirstParseFormats = [
|
|
565
|
+
'd-M',
|
|
566
|
+
'dd-MM',
|
|
567
|
+
'd-M-yy',
|
|
568
|
+
'dd-MM-yy',
|
|
569
|
+
'ddMMyyyy',
|
|
570
|
+
'yyyyMMdd',
|
|
571
|
+
'yyyy-MM-dd',
|
|
572
|
+
'dd-MM-yyyy'
|
|
576
573
|
]; }
|
|
577
574
|
/**
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
'
|
|
585
|
-
'MMM
|
|
586
|
-
'
|
|
587
|
-
'
|
|
588
|
-
'
|
|
589
|
-
'MMM
|
|
590
|
-
'MMM
|
|
591
|
-
'MMM
|
|
592
|
-
'
|
|
593
|
-
'MMMM
|
|
594
|
-
'
|
|
595
|
-
'MMM
|
|
596
|
-
'
|
|
597
|
-
'MMM,
|
|
598
|
-
'
|
|
599
|
-
'MMMM,
|
|
575
|
+
* Luxon parse formats for medium/long date strings (e.g. "Jan 5, 2024").
|
|
576
|
+
* Shared by date-first and month-first preferences because the month is
|
|
577
|
+
* not numeric, so the order is unambiguous.
|
|
578
|
+
*/
|
|
579
|
+
static { this.luxonMedAndLongDateFormats = [
|
|
580
|
+
// Moment was forgiving with leading zeros (`DD` matched both `9` and `09`);
|
|
581
|
+
// Luxon's `dd` is strict, so single-digit `d` variants are listed explicitly.
|
|
582
|
+
'd MMM',
|
|
583
|
+
'dd MMM',
|
|
584
|
+
'MMM d',
|
|
585
|
+
'MMM dd',
|
|
586
|
+
'd MMM yy',
|
|
587
|
+
'dd MMM yy',
|
|
588
|
+
'd MMM yyyy',
|
|
589
|
+
'dd MMM yyyy',
|
|
590
|
+
'd MMMM yyyy',
|
|
591
|
+
'dd MMMM yyyy',
|
|
592
|
+
'MMM d, yy',
|
|
593
|
+
'MMM d, yyyy',
|
|
594
|
+
'MMM dd, yyyy',
|
|
595
|
+
'MMMM d, yyyy',
|
|
596
|
+
'MMMM dd, yyyy',
|
|
597
|
+
'MMM yy',
|
|
598
|
+
'MMM yyyy',
|
|
599
|
+
'MMMM yyyy',
|
|
600
|
+
'MMM, yy',
|
|
601
|
+
'MMM, yyyy',
|
|
602
|
+
'MMMM, yyyy',
|
|
600
603
|
]; }
|
|
601
604
|
/**
|
|
602
605
|
* Format to display the time portion of a datetime
|
|
@@ -605,6 +608,99 @@ class DateTimeHelper {
|
|
|
605
608
|
///////////////////////////////////////////////////////
|
|
606
609
|
// METHODS
|
|
607
610
|
///////////////////////////////////////////////////////
|
|
611
|
+
/**
|
|
612
|
+
* Convert any date-like value into a Luxon {@link DateTime}. Strings are parsed
|
|
613
|
+
* as ISO 8601; numbers are treated as epoch milliseconds. Returns an invalid
|
|
614
|
+
* DateTime when the input is null/undefined.
|
|
615
|
+
*/
|
|
616
|
+
static toDateTime(value) {
|
|
617
|
+
if (value === null || value === undefined) {
|
|
618
|
+
return DateTime.invalid('null or undefined');
|
|
619
|
+
}
|
|
620
|
+
if (DateTime.isDateTime(value)) {
|
|
621
|
+
return value;
|
|
622
|
+
}
|
|
623
|
+
if (value instanceof Date) {
|
|
624
|
+
return DateTime.fromJSDate(value);
|
|
625
|
+
}
|
|
626
|
+
if (typeof value === 'number') {
|
|
627
|
+
return DateTime.fromMillis(value);
|
|
628
|
+
}
|
|
629
|
+
return DateTime.fromISO(value);
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Translate a moment-style format string (e.g. `MM/DD/YYYY HH:mm:ss A`) into
|
|
633
|
+
* the Luxon equivalent (`MM/dd/yyyy HH:mm:ss a`). Use this when format strings
|
|
634
|
+
* originate from external sources (such as user preferences) that still use
|
|
635
|
+
* moment tokens.
|
|
636
|
+
*
|
|
637
|
+
* Only the tokens currently in use across this library are translated:
|
|
638
|
+
* `Y`→`y`, `D`→`d`, `A`→`a`. `M`, `H`, `h`, `m`, `s` are identical between
|
|
639
|
+
* the two libraries.
|
|
640
|
+
*/
|
|
641
|
+
static momentToLuxonFormat(format) {
|
|
642
|
+
return format
|
|
643
|
+
.replace(/Y/g, 'y')
|
|
644
|
+
.replace(/D/g, 'd')
|
|
645
|
+
.replace(/A/g, 'a');
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Format a date-like value using a moment-style format string. The format
|
|
649
|
+
* string is automatically translated to Luxon tokens, so callers can keep
|
|
650
|
+
* passing the same preference strings (e.g. `MM/DD/YYYY HH:mm:ss`).
|
|
651
|
+
*
|
|
652
|
+
* When `displayInUTC` is true, string inputs without zone info are parsed
|
|
653
|
+
* as UTC (matching `moment.utc(str)`), and all other inputs are shifted to
|
|
654
|
+
* the UTC zone for display. Returns an empty string for invalid input.
|
|
655
|
+
*
|
|
656
|
+
* Moment's lowercase `a` token produces lowercase `am`/`pm`, but Luxon's
|
|
657
|
+
* `a` is locale-aware and emits uppercase `AM`/`PM` in en-US. When the
|
|
658
|
+
* incoming format uses lowercase `a` (and not uppercase `A`), the meridiem
|
|
659
|
+
* in the output is lowercased to preserve the moment contract for user
|
|
660
|
+
* preferences like `h:mm:ss a` that are stored externally.
|
|
661
|
+
*/
|
|
662
|
+
static formatDate(date, momentFormat, displayInUTC = false) {
|
|
663
|
+
let dt;
|
|
664
|
+
if (displayInUTC && typeof date === 'string') {
|
|
665
|
+
dt = DateTime.fromISO(date, { zone: 'utc' });
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
668
|
+
dt = this.toDateTime(date);
|
|
669
|
+
if (displayInUTC) {
|
|
670
|
+
dt = dt.setZone('utc');
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (!dt.isValid)
|
|
674
|
+
return '';
|
|
675
|
+
let result = dt.toFormat(this.momentToLuxonFormat(momentFormat));
|
|
676
|
+
if (momentFormat.includes('a') && !momentFormat.includes('A')) {
|
|
677
|
+
result = result.replace(/AM|PM/g, m => m.toLowerCase());
|
|
678
|
+
}
|
|
679
|
+
return result;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Parse a string against a list of format patterns. Returns the first
|
|
683
|
+
* successful parse as a {@link DateTime} (which may be invalid if none match).
|
|
684
|
+
*
|
|
685
|
+
* Format strings may use either Luxon or moment tokens — each pattern is
|
|
686
|
+
* run through {@link momentToLuxonFormat} before matching, so callers can
|
|
687
|
+
* keep passing arrays like `['M/D/YYYY']` from previously moment-based code.
|
|
688
|
+
*
|
|
689
|
+
* Mirrors moment's behavior of ignoring separator characters by normalizing
|
|
690
|
+
* `/`, `.` and `-` in both input and patterns before matching.
|
|
691
|
+
*/
|
|
692
|
+
static parseWithFormats(value, formats) {
|
|
693
|
+
const normalize = (s) => s.replace(/[\/.\-]/g, '-');
|
|
694
|
+
const normalizedValue = normalize(value);
|
|
695
|
+
for (const format of formats) {
|
|
696
|
+
const luxonFormat = this.momentToLuxonFormat(format);
|
|
697
|
+
const dt = DateTime.fromFormat(normalizedValue, normalize(luxonFormat));
|
|
698
|
+
if (dt.isValid) {
|
|
699
|
+
return dt;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return DateTime.invalid('no matching format');
|
|
703
|
+
}
|
|
608
704
|
/**
|
|
609
705
|
* Return true if @see date is equal to the @see endOfTime
|
|
610
706
|
*/
|
|
@@ -616,7 +712,7 @@ class DateTimeHelper {
|
|
|
616
712
|
* Compare two dates and return true if they represent the same year, month, and day (time is ignored).
|
|
617
713
|
*/
|
|
618
714
|
static isSameDay(date1, date2) {
|
|
619
|
-
return
|
|
715
|
+
return this.toDateTime(date1).hasSame(this.toDateTime(date2), 'day');
|
|
620
716
|
}
|
|
621
717
|
/**
|
|
622
718
|
* Get the parse formats based on the given date format. If no date format is
|
|
@@ -635,19 +731,19 @@ class DateTimeHelper {
|
|
|
635
731
|
return dateFormat ? map[dateFormat] : this.monthFirstParseFormats;
|
|
636
732
|
}
|
|
637
733
|
/**
|
|
638
|
-
* Get the
|
|
734
|
+
* Get the Luxon parse formats based on the given date format. If no date format is
|
|
639
735
|
* given, or we don't recognize the format, return the month first parse formats.
|
|
640
736
|
*/
|
|
641
|
-
static
|
|
737
|
+
static getLuxonParseFormats(dateFormat) {
|
|
642
738
|
let map = {
|
|
643
|
-
'MM/DD/YYYY': [...this.
|
|
644
|
-
'MM-DD-YYYY': [...this.
|
|
645
|
-
'DD/MM/YYYY': [...this.
|
|
646
|
-
'DD-MM-YYYY': [...this.
|
|
647
|
-
'YYYY/MM/DD': [...this.
|
|
648
|
-
'YYYY-MM-DD': [...this.
|
|
739
|
+
'MM/DD/YYYY': [...this.luxonMonthFirstParseFormats, ...this.luxonMedAndLongDateFormats],
|
|
740
|
+
'MM-DD-YYYY': [...this.luxonMonthFirstParseFormats, ...this.luxonMedAndLongDateFormats],
|
|
741
|
+
'DD/MM/YYYY': [...this.luxonDateFirstParseFormats, ...this.luxonMedAndLongDateFormats],
|
|
742
|
+
'DD-MM-YYYY': [...this.luxonDateFirstParseFormats, ...this.luxonMedAndLongDateFormats],
|
|
743
|
+
'YYYY/MM/DD': [...this.luxonMonthFirstParseFormats, ...this.luxonMedAndLongDateFormats],
|
|
744
|
+
'YYYY-MM-DD': [...this.luxonMonthFirstParseFormats, ...this.luxonMedAndLongDateFormats]
|
|
649
745
|
};
|
|
650
|
-
return dateFormat ? map[dateFormat] : this.
|
|
746
|
+
return dateFormat ? map[dateFormat] : this.luxonMonthFirstParseFormats;
|
|
651
747
|
}
|
|
652
748
|
/**
|
|
653
749
|
* Get relationship start date (favoring date in partialFormState if exists)
|
|
@@ -670,28 +766,23 @@ class DateTimeHelper {
|
|
|
670
766
|
return null;
|
|
671
767
|
}
|
|
672
768
|
static isDateBetween(date, startDate, endDate, includeStart, includeEnd) {
|
|
673
|
-
let inclusivity = '()';
|
|
674
|
-
if (includeStart && includeEnd) {
|
|
675
|
-
inclusivity = '[]';
|
|
676
|
-
}
|
|
677
|
-
else if (includeStart) {
|
|
678
|
-
inclusivity = '[)';
|
|
679
|
-
}
|
|
680
|
-
else if (includeEnd) {
|
|
681
|
-
inclusivity = '(]';
|
|
682
|
-
}
|
|
683
769
|
// If a start date is not provide, we'll use our beginning of time instead
|
|
684
770
|
startDate = startDate || this.beginningOfTime;
|
|
685
771
|
// If an end date is not provided, we'll use our end of time instead
|
|
686
772
|
endDate = endDate || this.endOfTime;
|
|
687
|
-
|
|
773
|
+
const d = this.toDateTime(date).startOf('day');
|
|
774
|
+
const s = this.toDateTime(startDate).startOf('day');
|
|
775
|
+
const e = this.toDateTime(endDate).startOf('day');
|
|
776
|
+
const afterStart = includeStart ? d >= s : d > s;
|
|
777
|
+
const beforeEnd = includeEnd ? d <= e : d < e;
|
|
778
|
+
return afterStart && beforeEnd;
|
|
688
779
|
}
|
|
689
780
|
static stringToDate(dateString) {
|
|
690
781
|
if (dateString === null || dateString === undefined) {
|
|
691
782
|
return dateString;
|
|
692
783
|
}
|
|
693
784
|
else {
|
|
694
|
-
return
|
|
785
|
+
return DateTime.fromISO(dateString).toJSDate();
|
|
695
786
|
}
|
|
696
787
|
}
|
|
697
788
|
}
|
|
@@ -705,15 +796,15 @@ class DateInputSelectionStrategyBase {
|
|
|
705
796
|
if (!value) {
|
|
706
797
|
return null;
|
|
707
798
|
}
|
|
708
|
-
|
|
709
|
-
if (date.isValid
|
|
799
|
+
let date = DateTimeHelper.parseWithFormats(value, parseFormats);
|
|
800
|
+
if (date.isValid) {
|
|
710
801
|
// If we're in a temporary state (when the user is typing in a textbox), we need to set the year to the current year if it's before the min year
|
|
711
802
|
// This prevents the calendars from showing unhelpful dates that are in the distant past before the user finishes typing in the date.
|
|
712
803
|
// We don't do this modification when the real selection happens on textbox blur.
|
|
713
|
-
if (opts?.shiftToCurrentYearIfBelow && date.
|
|
714
|
-
date.set(
|
|
804
|
+
if (opts?.shiftToCurrentYearIfBelow && date < DateTime.fromJSDate(opts.shiftToCurrentYearIfBelow)) {
|
|
805
|
+
date = date.set({ year: DateTime.now().year });
|
|
715
806
|
}
|
|
716
|
-
return date.
|
|
807
|
+
return date.toJSDate();
|
|
717
808
|
}
|
|
718
809
|
return null;
|
|
719
810
|
}
|
|
@@ -795,7 +886,7 @@ class DaySelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
795
886
|
getNextSelection(selection) {
|
|
796
887
|
// Add a single day to the selection
|
|
797
888
|
if (DateInput.isSelectionSingleDate(selection)) {
|
|
798
|
-
return
|
|
889
|
+
return DateTime.fromJSDate(selection).plus({ days: 1 }).toJSDate();
|
|
799
890
|
}
|
|
800
891
|
// This shouldn't happen based on current date input flows, but if it does just return the selection as-is.
|
|
801
892
|
return selection;
|
|
@@ -803,7 +894,7 @@ class DaySelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
803
894
|
getPreviousSelection(selection) {
|
|
804
895
|
// Subtract a single day from the selection
|
|
805
896
|
if (DateInput.isSelectionSingleDate(selection)) {
|
|
806
|
-
return
|
|
897
|
+
return DateTime.fromJSDate(selection).minus({ days: 1 }).toJSDate();
|
|
807
898
|
}
|
|
808
899
|
// This shouldn't happen based on current date input flows, but if it does just return the selection as-is.
|
|
809
900
|
return selection;
|
|
@@ -834,19 +925,19 @@ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
834
925
|
// Update the start and end dates to match a 28-day range, keying off the end date if parseFromEnd is true
|
|
835
926
|
// parseFromEnd is true when a date is being entered from the end date textbox
|
|
836
927
|
if (opts?.parseFromEnd) {
|
|
837
|
-
start =
|
|
928
|
+
start = DateTime.fromJSDate(end).minus({ days: 27 }).toJSDate();
|
|
838
929
|
}
|
|
839
930
|
else {
|
|
840
|
-
end =
|
|
931
|
+
end = DateTime.fromJSDate(start).plus({ days: 27 }).toJSDate();
|
|
841
932
|
}
|
|
842
933
|
}
|
|
843
934
|
// If the start date is not provided, we'll use the end date to calculate the start date
|
|
844
935
|
if (!start && end && !opts?.preventAutoComplete) {
|
|
845
|
-
start =
|
|
936
|
+
start = DateTime.fromJSDate(end).minus({ days: 27 }).toJSDate();
|
|
846
937
|
}
|
|
847
938
|
// If the end date is not provided, we'll use the start date to calculate the end date
|
|
848
939
|
if (!end && start && !opts?.preventAutoComplete) {
|
|
849
|
-
end =
|
|
940
|
+
end = DateTime.fromJSDate(start).plus({ days: 27 }).toJSDate();
|
|
850
941
|
}
|
|
851
942
|
if (!start && !end) {
|
|
852
943
|
return null;
|
|
@@ -857,7 +948,7 @@ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
857
948
|
}
|
|
858
949
|
getSelectionFromDate(date) {
|
|
859
950
|
return {
|
|
860
|
-
start:
|
|
951
|
+
start: DateTime.fromJSDate(date).minus({ days: 27 }).toJSDate(),
|
|
861
952
|
end: date
|
|
862
953
|
};
|
|
863
954
|
}
|
|
@@ -867,7 +958,7 @@ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
867
958
|
if (!previousSelection.end && previousSelection.start) {
|
|
868
959
|
return {
|
|
869
960
|
start: previousSelection.start,
|
|
870
|
-
end:
|
|
961
|
+
end: DateTime.fromJSDate(previousSelection.start).plus({ days: 27 }).toJSDate()
|
|
871
962
|
};
|
|
872
963
|
// If the range only has an end date, make the 28-day range end on that date
|
|
873
964
|
}
|
|
@@ -884,9 +975,10 @@ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
884
975
|
getNextSelection(selection) {
|
|
885
976
|
// Move the selection to the next 28 days
|
|
886
977
|
if (DateInput.isSelectionRange(selection) && selection.end) {
|
|
978
|
+
const end = DateTime.fromJSDate(selection.end);
|
|
887
979
|
return {
|
|
888
|
-
start:
|
|
889
|
-
end:
|
|
980
|
+
start: end.plus({ days: 1 }).toJSDate(),
|
|
981
|
+
end: end.plus({ days: 28 }).toJSDate()
|
|
890
982
|
};
|
|
891
983
|
}
|
|
892
984
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
@@ -896,9 +988,10 @@ class Last28DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
896
988
|
getPreviousSelection(selection) {
|
|
897
989
|
// Move the selection to the previous 28 days
|
|
898
990
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
991
|
+
const start = DateTime.fromJSDate(selection.start);
|
|
899
992
|
return {
|
|
900
|
-
start:
|
|
901
|
-
end:
|
|
993
|
+
start: start.minus({ days: 28 }).toJSDate(),
|
|
994
|
+
end: start.minus({ days: 1 }).toJSDate()
|
|
902
995
|
};
|
|
903
996
|
}
|
|
904
997
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
@@ -931,19 +1024,19 @@ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
931
1024
|
// Update the start and end dates to match a 7-day range, keying off the end date if parseFromEnd is true
|
|
932
1025
|
// parseFromEnd is true when a date is being entered from the end date textbox
|
|
933
1026
|
if (opts?.parseFromEnd) {
|
|
934
|
-
start =
|
|
1027
|
+
start = DateTime.fromJSDate(end).minus({ days: 6 }).toJSDate();
|
|
935
1028
|
}
|
|
936
1029
|
else {
|
|
937
|
-
end =
|
|
1030
|
+
end = DateTime.fromJSDate(start).plus({ days: 6 }).toJSDate();
|
|
938
1031
|
}
|
|
939
1032
|
}
|
|
940
1033
|
// If the start date is not provided, we'll use the end date to calculate the start date
|
|
941
1034
|
if (!start && end && !opts?.preventAutoComplete) {
|
|
942
|
-
start =
|
|
1035
|
+
start = DateTime.fromJSDate(end).minus({ days: 6 }).toJSDate();
|
|
943
1036
|
}
|
|
944
1037
|
// If the end date is not provided, we'll use the start date to calculate the end date
|
|
945
1038
|
if (!end && start && !opts?.preventAutoComplete) {
|
|
946
|
-
end =
|
|
1039
|
+
end = DateTime.fromJSDate(start).plus({ days: 6 }).toJSDate();
|
|
947
1040
|
}
|
|
948
1041
|
if (!start && !end) {
|
|
949
1042
|
return null;
|
|
@@ -955,7 +1048,7 @@ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
955
1048
|
getSelectionFromDate(date) {
|
|
956
1049
|
// Base the selection on the given date, moving back 6 days
|
|
957
1050
|
return {
|
|
958
|
-
start:
|
|
1051
|
+
start: DateTime.fromJSDate(date).minus({ days: 6 }).toJSDate(),
|
|
959
1052
|
end: date
|
|
960
1053
|
};
|
|
961
1054
|
}
|
|
@@ -965,7 +1058,7 @@ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
965
1058
|
if (!previousSelection.end && previousSelection.start) {
|
|
966
1059
|
return {
|
|
967
1060
|
start: previousSelection.start,
|
|
968
|
-
end:
|
|
1061
|
+
end: DateTime.fromJSDate(previousSelection.start).plus({ days: 6 }).toJSDate()
|
|
969
1062
|
};
|
|
970
1063
|
// Otherwise, create the new selection based on the end date backwards
|
|
971
1064
|
}
|
|
@@ -982,9 +1075,10 @@ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
982
1075
|
getNextSelection(selection) {
|
|
983
1076
|
// Shift the range forward by 7 days
|
|
984
1077
|
if (DateInput.isSelectionRange(selection) && selection.end) {
|
|
1078
|
+
const end = DateTime.fromJSDate(selection.end);
|
|
985
1079
|
return {
|
|
986
|
-
start:
|
|
987
|
-
end:
|
|
1080
|
+
start: end.plus({ days: 1 }).toJSDate(),
|
|
1081
|
+
end: end.plus({ days: 7 }).toJSDate()
|
|
988
1082
|
};
|
|
989
1083
|
}
|
|
990
1084
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
@@ -994,9 +1088,10 @@ class Last7DaysSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
994
1088
|
getPreviousSelection(selection) {
|
|
995
1089
|
// Shift the range back 7 days
|
|
996
1090
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1091
|
+
const start = DateTime.fromJSDate(selection.start);
|
|
997
1092
|
return {
|
|
998
|
-
start:
|
|
999
|
-
end:
|
|
1093
|
+
start: start.minus({ days: 7 }).toJSDate(),
|
|
1094
|
+
end: start.minus({ days: 1 }).toJSDate()
|
|
1000
1095
|
};
|
|
1001
1096
|
}
|
|
1002
1097
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
@@ -1024,7 +1119,7 @@ class MonthSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1024
1119
|
// A single date selection shouldn't happen in this mode but it's simple enough to handle
|
|
1025
1120
|
const date = DateInput.isSelectionRange(selection) ? selection.start : selection;
|
|
1026
1121
|
return {
|
|
1027
|
-
textbox:
|
|
1122
|
+
textbox: date ? DateTime.fromJSDate(date).toFormat('MMM, yyyy') : null,
|
|
1028
1123
|
textbox2: null
|
|
1029
1124
|
};
|
|
1030
1125
|
}
|
|
@@ -1037,9 +1132,10 @@ class MonthSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1037
1132
|
return this.getSelectionFromDate(date);
|
|
1038
1133
|
}
|
|
1039
1134
|
getSelectionFromDate(date) {
|
|
1135
|
+
const dt = DateTime.fromJSDate(date);
|
|
1040
1136
|
return {
|
|
1041
|
-
start:
|
|
1042
|
-
end:
|
|
1137
|
+
start: dt.startOf('month').toJSDate(),
|
|
1138
|
+
end: dt.endOf('month').toJSDate()
|
|
1043
1139
|
};
|
|
1044
1140
|
}
|
|
1045
1141
|
getNewSelectionFromExisting(previousSelection) {
|
|
@@ -1059,8 +1155,8 @@ class MonthSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1059
1155
|
getNextSelection(selection) {
|
|
1060
1156
|
// Move the selection to the next month
|
|
1061
1157
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1062
|
-
const date =
|
|
1063
|
-
return this.getSelectionFromDate(date.
|
|
1158
|
+
const date = DateTime.fromJSDate(selection.start).plus({ months: 1 });
|
|
1159
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1064
1160
|
}
|
|
1065
1161
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
1066
1162
|
// If it does, just return the selection as-is.
|
|
@@ -1069,8 +1165,8 @@ class MonthSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1069
1165
|
getPreviousSelection(selection) {
|
|
1070
1166
|
// Move the selection to the previous month
|
|
1071
1167
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1072
|
-
const date =
|
|
1073
|
-
return this.getSelectionFromDate(date.
|
|
1168
|
+
const date = DateTime.fromJSDate(selection.start).minus({ months: 1 });
|
|
1169
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1074
1170
|
}
|
|
1075
1171
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
1076
1172
|
// If it does, just return the selection as-is.
|
|
@@ -1093,9 +1189,9 @@ class QuarterSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1093
1189
|
// Format the the quarter range as "MMM–MMM, YYYY"
|
|
1094
1190
|
// We only have one textbox in this mode
|
|
1095
1191
|
if (DateInput.isSelectionRange(selection)) {
|
|
1096
|
-
const start =
|
|
1097
|
-
const end =
|
|
1098
|
-
const year =
|
|
1192
|
+
const start = selection.start ? DateTime.fromJSDate(selection.start).toFormat('MMM') : '';
|
|
1193
|
+
const end = selection.end ? DateTime.fromJSDate(selection.end).toFormat('MMM') : '';
|
|
1194
|
+
const year = selection.end ? DateTime.fromJSDate(selection.end).toFormat('yyyy') : '';
|
|
1099
1195
|
return {
|
|
1100
1196
|
textbox: `${start}–${end}, ${year}`,
|
|
1101
1197
|
textbox2: null
|
|
@@ -1113,9 +1209,10 @@ class QuarterSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1113
1209
|
return this.getSelectionFromDate(date);
|
|
1114
1210
|
}
|
|
1115
1211
|
getSelectionFromDate(date) {
|
|
1212
|
+
const dt = DateTime.fromJSDate(date);
|
|
1116
1213
|
return {
|
|
1117
|
-
start:
|
|
1118
|
-
end:
|
|
1214
|
+
start: dt.startOf('quarter').toJSDate(),
|
|
1215
|
+
end: dt.endOf('quarter').toJSDate()
|
|
1119
1216
|
};
|
|
1120
1217
|
}
|
|
1121
1218
|
getNewSelectionFromExisting(previousSelection) {
|
|
@@ -1135,8 +1232,8 @@ class QuarterSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1135
1232
|
getNextSelection(selection) {
|
|
1136
1233
|
// Move the selection to the next quarter
|
|
1137
1234
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1138
|
-
const date =
|
|
1139
|
-
return this.getSelectionFromDate(date.
|
|
1235
|
+
const date = DateTime.fromJSDate(selection.start).plus({ quarters: 1 });
|
|
1236
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1140
1237
|
}
|
|
1141
1238
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
1142
1239
|
// If it does, just return the selection as-is.
|
|
@@ -1145,8 +1242,8 @@ class QuarterSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1145
1242
|
getPreviousSelection(selection) {
|
|
1146
1243
|
// Move the selection to the previous quarter
|
|
1147
1244
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1148
|
-
const date =
|
|
1149
|
-
return this.getSelectionFromDate(date.
|
|
1245
|
+
const date = DateTime.fromJSDate(selection.start).minus({ quarters: 1 });
|
|
1246
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1150
1247
|
}
|
|
1151
1248
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
1152
1249
|
// If it does, just return the selection as-is.
|
|
@@ -1169,13 +1266,13 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1169
1266
|
if (!selection) {
|
|
1170
1267
|
return { textbox: null, textbox2: null };
|
|
1171
1268
|
}
|
|
1172
|
-
// We use
|
|
1269
|
+
// We use Luxon's DATE_MED preset here (equivalent to moment's 'll') so the formatted date follows the user's locale
|
|
1173
1270
|
if (DateInput.isSelectionSingleDate(selection)) {
|
|
1174
|
-
return { textbox:
|
|
1271
|
+
return { textbox: DateTime.fromJSDate(selection).toLocaleString(DateTime.DATE_MED), textbox2: null };
|
|
1175
1272
|
}
|
|
1176
1273
|
else {
|
|
1177
|
-
const start = selection.start ?
|
|
1178
|
-
const end = selection.end ?
|
|
1274
|
+
const start = selection.start ? DateTime.fromJSDate(selection.start).toLocaleString(DateTime.DATE_MED) : null;
|
|
1275
|
+
const end = selection.end ? DateTime.fromJSDate(selection.end).toLocaleString(DateTime.DATE_MED) : null;
|
|
1179
1276
|
return { textbox: start, textbox2: end };
|
|
1180
1277
|
}
|
|
1181
1278
|
}
|
|
@@ -1186,7 +1283,7 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1186
1283
|
// because we don't have a fixed range to automatically adjust the dates to. If the user is changing the begin date or end date and ends
|
|
1187
1284
|
// up crossing the other date, we should clear out the date that's not being changed so that the user can enter a valid range using the
|
|
1188
1285
|
// begin/end date they just entered.
|
|
1189
|
-
if (start && end &&
|
|
1286
|
+
if (start && end && DateTime.fromJSDate(start) > DateTime.fromJSDate(end)) {
|
|
1190
1287
|
if (opts?.parseFromEnd) {
|
|
1191
1288
|
start = null;
|
|
1192
1289
|
}
|
|
@@ -1204,18 +1301,19 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1204
1301
|
getSelectionFromDate(date, existingSelection) {
|
|
1205
1302
|
if (DateInput.isSelectionRange(existingSelection)) {
|
|
1206
1303
|
const { start, end } = existingSelection;
|
|
1304
|
+
const dDt = DateTime.fromJSDate(date);
|
|
1207
1305
|
if (start && !end) {
|
|
1208
1306
|
// If the selected date is before the existing start date, set it as the new start date and use the existing start date as the end date
|
|
1209
|
-
return
|
|
1307
|
+
return dDt < DateTime.fromJSDate(start) ? { start: date, end: start } : { start, end: date };
|
|
1210
1308
|
}
|
|
1211
1309
|
if (end && !start) {
|
|
1212
1310
|
// If the selected date is after the existing end date, set it as the new end date and use the existing end date as the start date
|
|
1213
|
-
return
|
|
1311
|
+
return dDt < DateTime.fromJSDate(end) ? { start: date, end } : { start: end, end: date };
|
|
1214
1312
|
}
|
|
1215
1313
|
}
|
|
1216
1314
|
else if (DateInput.isSelectionSingleDate(existingSelection)) {
|
|
1217
1315
|
// If the selected date is before the existing date, set it as the new start date and use the existing date as the end date
|
|
1218
|
-
return
|
|
1316
|
+
return DateTime.fromJSDate(date) < DateTime.fromJSDate(existingSelection) ? { start: date, end: existingSelection } : { start: existingSelection, end: date };
|
|
1219
1317
|
}
|
|
1220
1318
|
// If no selection exists or we already have a complete selection, start a new one with the selected date as the start date.
|
|
1221
1319
|
return { start: date, end: null };
|
|
@@ -1236,9 +1334,9 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1236
1334
|
// If we have a valid range, we'll shift the range to the date provided, using it as the end date
|
|
1237
1335
|
// The new selection will have the same length as the previous.
|
|
1238
1336
|
if (DateInput.isSelectionRange(existingSelection) && existingSelection.start && existingSelection.end) {
|
|
1239
|
-
const length =
|
|
1337
|
+
const length = Math.floor(DateTime.fromJSDate(existingSelection.end).diff(DateTime.fromJSDate(existingSelection.start), 'days').days);
|
|
1240
1338
|
return {
|
|
1241
|
-
start:
|
|
1339
|
+
start: DateTime.fromJSDate(date).minus({ days: length }).toJSDate(),
|
|
1242
1340
|
end: date
|
|
1243
1341
|
};
|
|
1244
1342
|
}
|
|
@@ -1250,10 +1348,11 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1250
1348
|
// We can only determine the next selection if we have a valid range
|
|
1251
1349
|
if (DateInput.isSelectionRange(selection) && selection.start && selection.end) {
|
|
1252
1350
|
// Shift the range forward by the number of days between the start and end dates
|
|
1253
|
-
const
|
|
1351
|
+
const end = DateTime.fromJSDate(selection.end);
|
|
1352
|
+
const length = Math.floor(end.diff(DateTime.fromJSDate(selection.start), 'days').days);
|
|
1254
1353
|
return {
|
|
1255
|
-
start:
|
|
1256
|
-
end:
|
|
1354
|
+
start: end.plus({ days: 1 }).toJSDate(),
|
|
1355
|
+
end: end.plus({ days: 1 + length }).toJSDate()
|
|
1257
1356
|
};
|
|
1258
1357
|
}
|
|
1259
1358
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
@@ -1264,10 +1363,11 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1264
1363
|
// We can only determine the previous selection if we have a valid range
|
|
1265
1364
|
if (DateInput.isSelectionRange(selection) && selection.start && selection.end) {
|
|
1266
1365
|
// Shift the range back by the number of days between the start and end dates
|
|
1267
|
-
const
|
|
1366
|
+
const start = DateTime.fromJSDate(selection.start);
|
|
1367
|
+
const length = Math.floor(DateTime.fromJSDate(selection.end).diff(start, 'days').days);
|
|
1268
1368
|
return {
|
|
1269
|
-
start:
|
|
1270
|
-
end:
|
|
1369
|
+
start: start.minus({ days: 1 + length }).toJSDate(),
|
|
1370
|
+
end: start.minus({ days: 1 }).toJSDate()
|
|
1271
1371
|
};
|
|
1272
1372
|
}
|
|
1273
1373
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
@@ -1277,31 +1377,33 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1277
1377
|
getPrimaryCalendarView(selection, minDate, maxDate, currentView) {
|
|
1278
1378
|
let viewDate;
|
|
1279
1379
|
if (DateInput.isSelectionRange(selection)) {
|
|
1280
|
-
|
|
1281
|
-
|
|
1380
|
+
const start = selection.start ? DateTime.fromJSDate(selection.start) : null;
|
|
1381
|
+
const end = selection.end ? DateTime.fromJSDate(selection.end) : null;
|
|
1382
|
+
const minDt = DateTime.fromJSDate(minDate);
|
|
1383
|
+
const maxDt = DateTime.fromJSDate(maxDate);
|
|
1282
1384
|
// Since we're in range mode, the primary calendar is mostly concerned with the start date
|
|
1283
1385
|
if (start) {
|
|
1284
1386
|
// If we have a start date in the selection and it's before the min date, shift the view to the min date.
|
|
1285
|
-
if (start.
|
|
1387
|
+
if (start.startOf('month') < minDt.startOf('month')) {
|
|
1286
1388
|
viewDate = minDate;
|
|
1287
1389
|
// If the start is after the max date, shift the view to the max date.
|
|
1288
1390
|
}
|
|
1289
|
-
else if (start.
|
|
1391
|
+
else if (start.startOf('month') >= maxDt.startOf('month')) {
|
|
1290
1392
|
// the secondary calendar will show the max date month.
|
|
1291
1393
|
// The primary calendar will show the month before the max date.
|
|
1292
|
-
viewDate =
|
|
1394
|
+
viewDate = maxDt.minus({ months: 1 }).toJSDate();
|
|
1293
1395
|
}
|
|
1294
1396
|
else {
|
|
1295
|
-
viewDate = start.
|
|
1397
|
+
viewDate = start.toJSDate();
|
|
1296
1398
|
}
|
|
1297
1399
|
}
|
|
1298
|
-
else if (end && end.
|
|
1400
|
+
else if (end && end.startOf('month') <= minDt.startOf('month')) {
|
|
1299
1401
|
// If we don't have a start date, and the end date is the same month or before the min date, shift the view to the min date.
|
|
1300
1402
|
viewDate = minDate;
|
|
1301
1403
|
}
|
|
1302
|
-
else if (end && end.
|
|
1404
|
+
else if (end && end.startOf('month') <= DateTime.now().startOf('month')) {
|
|
1303
1405
|
// If we don't have a start date, and the end date is the same month or before the current month, shift the view to the month before the end
|
|
1304
|
-
viewDate =
|
|
1406
|
+
viewDate = end.minus({ months: 1 }).toJSDate();
|
|
1305
1407
|
}
|
|
1306
1408
|
else {
|
|
1307
1409
|
// Otherwise, show the current month.
|
|
@@ -1319,32 +1421,34 @@ class RangeSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1319
1421
|
getSecondaryCalendarView(selection, minDate, maxDate, currentView) {
|
|
1320
1422
|
let viewDate;
|
|
1321
1423
|
if (DateInput.isSelectionRange(selection)) {
|
|
1322
|
-
|
|
1323
|
-
|
|
1424
|
+
const start = selection.start ? DateTime.fromJSDate(selection.start) : null;
|
|
1425
|
+
const end = selection.end ? DateTime.fromJSDate(selection.end) : null;
|
|
1426
|
+
const minDt = DateTime.fromJSDate(minDate);
|
|
1427
|
+
const maxDt = DateTime.fromJSDate(maxDate);
|
|
1324
1428
|
// The secondary calendar is primarily concerned with the end date in the selection.
|
|
1325
1429
|
if (end) {
|
|
1326
|
-
if (end.
|
|
1430
|
+
if (end.startOf('month') > maxDt.startOf('month')) {
|
|
1327
1431
|
// If the end date is after the max date, shift the view to the max date.
|
|
1328
1432
|
viewDate = maxDate;
|
|
1329
1433
|
}
|
|
1330
|
-
else if (end.
|
|
1434
|
+
else if (end.startOf('month') <= minDt.startOf('month')) {
|
|
1331
1435
|
// If the end date is the same month or before the min date, shift the view to show
|
|
1332
1436
|
// the month after the min date. The primary calendar will show the min date month.
|
|
1333
|
-
viewDate =
|
|
1437
|
+
viewDate = minDt.plus({ months: 1 }).toJSDate();
|
|
1334
1438
|
}
|
|
1335
1439
|
else {
|
|
1336
1440
|
// Otherwise, show the end date month.
|
|
1337
|
-
viewDate = end.
|
|
1441
|
+
viewDate = end.toJSDate();
|
|
1338
1442
|
}
|
|
1339
1443
|
}
|
|
1340
|
-
else if (start && start.
|
|
1444
|
+
else if (start && start.startOf('month') >= maxDt.startOf('month')) {
|
|
1341
1445
|
// If we don't have an end date, and the start date is after the max date, show the max date month
|
|
1342
1446
|
viewDate = maxDate;
|
|
1343
1447
|
}
|
|
1344
|
-
else if (start && start.
|
|
1448
|
+
else if (start && start.startOf('month') >= DateTime.now().startOf('month')) {
|
|
1345
1449
|
// If we don't have an end date, and the start date is on or after the current month,
|
|
1346
1450
|
// show the month after the start date.
|
|
1347
|
-
viewDate =
|
|
1451
|
+
viewDate = start.plus({ months: 1 }).toJSDate();
|
|
1348
1452
|
}
|
|
1349
1453
|
else {
|
|
1350
1454
|
// Otherwise, show the current month.
|
|
@@ -1379,12 +1483,12 @@ class YearSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1379
1483
|
// Only one date is needed for formatting since the ranges span a single year.
|
|
1380
1484
|
// There shouldn't be any case where there's only a single date but it's covered anyway.
|
|
1381
1485
|
const date = DateInput.isSelectionRange(selection) ? selection.start : selection;
|
|
1382
|
-
return { textbox:
|
|
1486
|
+
return { textbox: date ? DateTime.fromJSDate(date).toFormat('yyyy') : null, textbox2: null };
|
|
1383
1487
|
}
|
|
1384
1488
|
parseString(value, parseFormats, opts) {
|
|
1385
|
-
// Including '
|
|
1489
|
+
// Including 'yy' and 'yyyy' as valid formats for year input. These aren't included in the default parse
|
|
1386
1490
|
// formats because they cause issues with the default date parsing.
|
|
1387
|
-
return super.parseString(value, ['
|
|
1491
|
+
return super.parseString(value, ['yy', 'yyyy', ...parseFormats], opts);
|
|
1388
1492
|
}
|
|
1389
1493
|
parseTextboxValues(value, parseFormats, opts) {
|
|
1390
1494
|
// Only a single textbox is used in year mode
|
|
@@ -1395,9 +1499,10 @@ class YearSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1395
1499
|
return this.getSelectionFromDate(date);
|
|
1396
1500
|
}
|
|
1397
1501
|
getSelectionFromDate(date) {
|
|
1502
|
+
const dt = DateTime.fromJSDate(date);
|
|
1398
1503
|
return {
|
|
1399
|
-
start:
|
|
1400
|
-
end:
|
|
1504
|
+
start: dt.startOf('year').toJSDate(),
|
|
1505
|
+
end: dt.endOf('year').toJSDate()
|
|
1401
1506
|
};
|
|
1402
1507
|
}
|
|
1403
1508
|
getNewSelectionFromExisting(previousSelection) {
|
|
@@ -1420,8 +1525,8 @@ class YearSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1420
1525
|
getNextSelection(selection) {
|
|
1421
1526
|
// Move the selection to the next year
|
|
1422
1527
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1423
|
-
const date =
|
|
1424
|
-
return this.getSelectionFromDate(date.
|
|
1528
|
+
const date = DateTime.fromJSDate(selection.start).plus({ years: 1 });
|
|
1529
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1425
1530
|
}
|
|
1426
1531
|
// This shouldn't happen since the next stepper is disabled if the selection only has one date.
|
|
1427
1532
|
// If it does, just return the selection as-is.
|
|
@@ -1430,8 +1535,8 @@ class YearSelectionStrategy extends DateInputSelectionStrategyBase {
|
|
|
1430
1535
|
getPreviousSelection(selection) {
|
|
1431
1536
|
// Move the selection to the previous year
|
|
1432
1537
|
if (DateInput.isSelectionRange(selection) && selection.start) {
|
|
1433
|
-
const date =
|
|
1434
|
-
return this.getSelectionFromDate(date.
|
|
1538
|
+
const date = DateTime.fromJSDate(selection.start).minus({ years: 1 });
|
|
1539
|
+
return this.getSelectionFromDate(date.toJSDate());
|
|
1435
1540
|
}
|
|
1436
1541
|
// This shouldn't happen since the previous stepper is disabled if the selection only has one date.
|
|
1437
1542
|
// If it does, just return the selection as-is.
|
|
@@ -1470,10 +1575,10 @@ class DateDisplayPipe {
|
|
|
1470
1575
|
transform(date, showEndOfTime, showTime, showSeconds) {
|
|
1471
1576
|
let display = '';
|
|
1472
1577
|
let formatString = '';
|
|
1473
|
-
if (date &&
|
|
1578
|
+
if (date != null && DateTimeHelper.toDateTime(date).isValid && (showEndOfTime || !DateTimeHelper.isEndOfTime(date))) {
|
|
1474
1579
|
// use user-preferred formats
|
|
1475
1580
|
this.userPreferenceService.getPreferences().subscribe(result => {
|
|
1476
|
-
//if preferences exist then format date to users preference
|
|
1581
|
+
//if preferences exist then format date to users preference
|
|
1477
1582
|
//otherwise use the last user preference
|
|
1478
1583
|
if (result.preference) {
|
|
1479
1584
|
formatString = result.preference.dateFormat;
|
|
@@ -1487,7 +1592,7 @@ class DateDisplayPipe {
|
|
|
1487
1592
|
this.lastFormatString = formatString;
|
|
1488
1593
|
}
|
|
1489
1594
|
});
|
|
1490
|
-
display =
|
|
1595
|
+
display = DateTimeHelper.formatDate(date, this.lastFormatString);
|
|
1491
1596
|
}
|
|
1492
1597
|
return display;
|
|
1493
1598
|
}
|
|
@@ -1554,9 +1659,14 @@ class CalendarItemComponent {
|
|
|
1554
1659
|
this.today = false;
|
|
1555
1660
|
this.outsideActiveMonth = false;
|
|
1556
1661
|
}
|
|
1662
|
+
else if (this.item?.date) {
|
|
1663
|
+
const itemDt = DateTime.fromJSDate(this.item.date);
|
|
1664
|
+
this.today = itemDt.hasSame(DateTime.now(), 'day');
|
|
1665
|
+
this.outsideActiveMonth = !itemDt.hasSame(DateTime.fromJSDate(this.view.date), 'month');
|
|
1666
|
+
}
|
|
1557
1667
|
else {
|
|
1558
|
-
this.today =
|
|
1559
|
-
this.outsideActiveMonth =
|
|
1668
|
+
this.today = false;
|
|
1669
|
+
this.outsideActiveMonth = false;
|
|
1560
1670
|
}
|
|
1561
1671
|
if (this.item?.date) {
|
|
1562
1672
|
this.hidden = this.isHidden(this.item.date, this.minDate, this.maxDate, this.view.mode);
|
|
@@ -1570,24 +1680,30 @@ class CalendarItemComponent {
|
|
|
1570
1680
|
if (!date || !selection) {
|
|
1571
1681
|
return false;
|
|
1572
1682
|
}
|
|
1683
|
+
const unit = view ?? 'day';
|
|
1684
|
+
const dt = DateTime.fromJSDate(date);
|
|
1573
1685
|
if (DateInput.isSelectionSingleDate(selection)) {
|
|
1574
|
-
return
|
|
1686
|
+
return dt.hasSame(DateTime.fromJSDate(selection), unit);
|
|
1575
1687
|
}
|
|
1576
1688
|
else {
|
|
1577
1689
|
if (selection.start && !selection.end) {
|
|
1578
|
-
return
|
|
1690
|
+
return dt.hasSame(DateTime.fromJSDate(selection.start), unit);
|
|
1579
1691
|
}
|
|
1580
1692
|
else if (!selection.start && selection.end) {
|
|
1581
|
-
return
|
|
1693
|
+
return dt.hasSame(DateTime.fromJSDate(selection.end), unit);
|
|
1582
1694
|
}
|
|
1583
1695
|
else if (selection.start && selection.end) {
|
|
1584
|
-
|
|
1696
|
+
const d = dt.startOf(unit);
|
|
1697
|
+
const s = DateTime.fromJSDate(selection.start).startOf(unit);
|
|
1698
|
+
const e = DateTime.fromJSDate(selection.end).startOf(unit);
|
|
1699
|
+
return d >= s && d <= e;
|
|
1585
1700
|
}
|
|
1586
1701
|
}
|
|
1587
1702
|
return false;
|
|
1588
1703
|
}
|
|
1589
1704
|
isHidden(date, minDate, maxDate, view) {
|
|
1590
|
-
|
|
1705
|
+
const d = DateTime.fromJSDate(date).startOf(view);
|
|
1706
|
+
return d < DateTime.fromJSDate(minDate).startOf(view) || d > DateTime.fromJSDate(maxDate).startOf(view);
|
|
1591
1707
|
}
|
|
1592
1708
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: CalendarItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1593
1709
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.4", type: CalendarItemComponent, isStandalone: false, selector: "button[ec-calendar-item]", inputs: { item: "item", selection: "selection", view: "view", minDate: "minDate", maxDate: "maxDate" }, host: { properties: { "class.is-today": "this.today", "class.is-selected": "this.selected", "class.is-outside-active-month": "this.outsideActiveMonth", "class.is-hidden": "this.hidden", "attr.disabled": "this.disabled" } }, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{font-size:var(--ec-font-size-action);height:2rem;line-height:1.25rem;padding:.3125rem .5rem;border:0;border-radius:var(--ec-border-radius);display:flex;align-items:center;justify-content:center;cursor:pointer}:host .label{display:flex;align-items:center;justify-content:center;white-space:nowrap;flex:auto}:host .ec-icon{flex:none}:host .ec-icon+.label{flex:none;margin-left:.25rem}:host.has-badge{padding-right:.0625rem}:host:focus{outline:none;position:relative;z-index:1}:host:disabled{background-color:var(--ec-background-color-disabled);border:1px solid var(--ec-form-control-border-color-disabled);color:var(--ec-color-disabled-dark);opacity:var(--ec-form-control-opacity-disabled);cursor:default}:host:disabled .ec-icon{color:var(--ec-color-disabled-dark)}:host{background-color:transparent}:host:disabled{background-color:transparent;border-color:transparent;color:var(--ec-color-hint-dark);--ec-color-icon: var(--ec-color-hint-dark)}:host:hover:not(:disabled){background-color:var(--ec-background-color-hover)}:host:active:not(:disabled){background-color:var(--ec-background-color-selected);font-weight:700}:host:focus:not(:disabled){box-shadow:var(--ec-button-box-shadow-active, 0 0 0 2px var(--ec-border-color-focus))}:host.is-selected{background-color:var(--ec-background-color-selected);font-weight:700}:host{line-height:1.125rem}:host.is-selected,:host.is-selected:disabled{background-color:var(--ec-background-color-selected);font-weight:700}:host.is-today{position:relative}:host.is-today:after{content:\"\";position:absolute;top:50%;left:50%;width:1.75rem;height:1.75rem;transform:translate(-50%,-50%);border:1px solid;border-radius:50%;pointer-events:none}:host.is-outside-active-month{color:var(--ec-color-hint-dark)}:host.is-hidden{opacity:0!important}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
@@ -1636,8 +1752,12 @@ class CalendarComponent {
|
|
|
1636
1752
|
this.viewChange = new EventEmitter();
|
|
1637
1753
|
/** Array of calendar item rows to display in the calendar. */
|
|
1638
1754
|
this.calendarItems = [];
|
|
1639
|
-
/** Weekday labels to show at the top of the calendar in day view. */
|
|
1640
|
-
this.weekDays =
|
|
1755
|
+
/** Weekday labels to show at the top of the calendar in day view. Starts on Sunday to match the calendar grid layout. */
|
|
1756
|
+
this.weekDays = (() => {
|
|
1757
|
+
// Info.weekdays returns Monday-first; reorder so Sunday is first to match the calendar grid.
|
|
1758
|
+
const mondayFirst = Info.weekdays('short');
|
|
1759
|
+
return [mondayFirst[6], ...mondayFirst.slice(0, 6)].map(d => d.slice(0, 1));
|
|
1760
|
+
})();
|
|
1641
1761
|
this.disablePreviousButton = false;
|
|
1642
1762
|
this.disableNextButton = false;
|
|
1643
1763
|
// Trackby functions for ngFor loops. These reduce the number of DOM elements that need to be updated when the calendar is re-drawn.
|
|
@@ -1661,19 +1781,19 @@ class CalendarComponent {
|
|
|
1661
1781
|
onNextClick() {
|
|
1662
1782
|
// If we're in day view, we're incrementing by month
|
|
1663
1783
|
// In month, quarter, and year views we're incrementing by year\
|
|
1664
|
-
const unit = this.view.mode === 'day' ? '
|
|
1784
|
+
const unit = this.view.mode === 'day' ? 'months' : 'years';
|
|
1665
1785
|
// In year view, we're moving by 16 years at a time. Otherwise we're just moving by 1 month/year.
|
|
1666
1786
|
const count = this.view.mode === 'year' ? 16 : 1;
|
|
1667
|
-
const goToDate =
|
|
1787
|
+
const goToDate = DateTime.fromJSDate(this.view.date).plus({ [unit]: count }).toJSDate();
|
|
1668
1788
|
this.drawCalendar({ mode: this.view.mode, date: goToDate });
|
|
1669
1789
|
}
|
|
1670
1790
|
onPreviousClick() {
|
|
1671
1791
|
// If we're in day view, we're incrementing by month
|
|
1672
1792
|
// In month, quarter, and year views we're incrementing by year
|
|
1673
|
-
const unit = this.view.mode === 'day' ? '
|
|
1793
|
+
const unit = this.view.mode === 'day' ? 'months' : 'years';
|
|
1674
1794
|
// In year view, we're moving by 16 years at a time. Otherwise we're just moving by 1 month/year.
|
|
1675
1795
|
const count = this.view.mode === 'year' ? 16 : 1;
|
|
1676
|
-
const goToDate =
|
|
1796
|
+
const goToDate = DateTime.fromJSDate(this.view.date).minus({ [unit]: count }).toJSDate();
|
|
1677
1797
|
this.drawCalendar({ mode: this.view.mode, date: goToDate });
|
|
1678
1798
|
}
|
|
1679
1799
|
/** Switches the calendar to month view. */
|
|
@@ -1740,13 +1860,14 @@ class CalendarComponent {
|
|
|
1740
1860
|
this.view = view;
|
|
1741
1861
|
this.viewChange.emit(view);
|
|
1742
1862
|
}
|
|
1743
|
-
|
|
1744
|
-
this.
|
|
1863
|
+
const viewDt = DateTime.fromJSDate(this.view.date);
|
|
1864
|
+
this.month = viewDt.toFormat('MMM');
|
|
1865
|
+
this.year = viewDt.toFormat('yyyy');
|
|
1745
1866
|
this.calendarItems = this.getCalendarItems(this.view);
|
|
1746
1867
|
const startYear = this.calendarItems[0][0].date < this.minDate ? this.minDate : this.calendarItems[0][0].date;
|
|
1747
1868
|
const lastItem = this.getLastItem();
|
|
1748
1869
|
const endYear = lastItem.date > this.maxDate ? this.maxDate : lastItem.date;
|
|
1749
|
-
this.yearRange = `${
|
|
1870
|
+
this.yearRange = `${DateTime.fromJSDate(startYear).toFormat('yyyy')}–${DateTime.fromJSDate(endYear).toFormat('yyyy')}`;
|
|
1750
1871
|
this.updateNextPreviousStates();
|
|
1751
1872
|
}
|
|
1752
1873
|
getCalendarItems(view) {
|
|
@@ -1758,53 +1879,58 @@ class CalendarComponent {
|
|
|
1758
1879
|
}
|
|
1759
1880
|
}
|
|
1760
1881
|
getDayViewItems(activeDate) {
|
|
1761
|
-
// 6 rows of 7 days = 42 days
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1882
|
+
// 6 rows of 7 days = 42 days.
|
|
1883
|
+
// Use the start of the week of the first day of the month, anchored to Sunday to match the calendar grid.
|
|
1884
|
+
// Luxon's startOf('week') is Monday-based per ISO, so shift back to Sunday explicitly.
|
|
1885
|
+
const monthStart = DateTime.fromJSDate(activeDate).startOf('month');
|
|
1886
|
+
const sundayStart = monthStart.weekday === 7 ? monthStart : monthStart.startOf('week').minus({ days: 1 });
|
|
1887
|
+
return range(0, 6).map((r) => {
|
|
1888
|
+
return range(0, 7).map((d) => {
|
|
1889
|
+
const date = sundayStart.plus({ days: r * 7 + d });
|
|
1767
1890
|
return {
|
|
1768
|
-
date: date.
|
|
1769
|
-
label: date.
|
|
1891
|
+
date: date.toJSDate(),
|
|
1892
|
+
label: date.toFormat('d')
|
|
1770
1893
|
};
|
|
1771
1894
|
});
|
|
1772
1895
|
});
|
|
1773
1896
|
}
|
|
1774
1897
|
getMonthViewItems(activeDate) {
|
|
1775
1898
|
// 4 rows of 3 months = 12 months
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1899
|
+
const yearStart = DateTime.fromJSDate(activeDate).startOf('year');
|
|
1900
|
+
return range(0, 4).map((r) => {
|
|
1901
|
+
return range(0, 3).map((m) => {
|
|
1902
|
+
const date = yearStart.plus({ months: r * 3 + m });
|
|
1779
1903
|
return {
|
|
1780
|
-
date: date.
|
|
1781
|
-
label: date.
|
|
1904
|
+
date: date.toJSDate(),
|
|
1905
|
+
label: date.toFormat('MMM')
|
|
1782
1906
|
};
|
|
1783
1907
|
});
|
|
1784
1908
|
});
|
|
1785
1909
|
}
|
|
1786
1910
|
getQuarterViewItems(activeDate) {
|
|
1787
1911
|
// 2 rows of 2 quarters = 4 quarters
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
const
|
|
1912
|
+
const yearStart = DateTime.fromJSDate(activeDate).startOf('year');
|
|
1913
|
+
return range(0, 2).map((r) => {
|
|
1914
|
+
return range(0, 2).map((q) => {
|
|
1915
|
+
const date = yearStart.plus({ quarters: r * 2 + q });
|
|
1916
|
+
const endDate = date.endOf('quarter');
|
|
1792
1917
|
return {
|
|
1793
|
-
date: date.
|
|
1794
|
-
label: `${date.
|
|
1918
|
+
date: date.toJSDate(),
|
|
1919
|
+
label: `${date.toFormat('MMM')}–${endDate.toFormat('MMM')}`
|
|
1795
1920
|
};
|
|
1796
1921
|
});
|
|
1797
1922
|
});
|
|
1798
1923
|
}
|
|
1799
1924
|
getYearViewItems(activeDate) {
|
|
1800
1925
|
// 4 rows of 4 years = 16 years
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1926
|
+
// Subtracting 8 years to put the current active year at the beginning of the 3rd row.
|
|
1927
|
+
const yearStart = DateTime.fromJSDate(activeDate).startOf('year').minus({ years: 8 });
|
|
1928
|
+
return range(0, 4).map((r) => {
|
|
1929
|
+
return range(0, 4).map((y) => {
|
|
1930
|
+
const date = yearStart.plus({ years: r * 4 + y });
|
|
1805
1931
|
return {
|
|
1806
|
-
date: date.
|
|
1807
|
-
label: date.
|
|
1932
|
+
date: date.toJSDate(),
|
|
1933
|
+
label: date.toFormat('yyyy')
|
|
1808
1934
|
};
|
|
1809
1935
|
});
|
|
1810
1936
|
});
|
|
@@ -1814,24 +1940,20 @@ class CalendarComponent {
|
|
|
1814
1940
|
// We don't want to disable the next/previous buttons if the min or max date is within the
|
|
1815
1941
|
// next or previous view
|
|
1816
1942
|
const unit = this.view.mode === 'day' ? 'month' : 'year';
|
|
1943
|
+
const pluralUnit = this.view.mode === 'day' ? 'months' : 'years';
|
|
1944
|
+
const viewDt = DateTime.fromJSDate(this.view.date);
|
|
1817
1945
|
// When in year view, we need to subtract 9 years to determine if we're past the min date.
|
|
1818
1946
|
// The year view is 16 years long, and the current date is the 9th year in the view.
|
|
1819
1947
|
const subCount = this.view.mode === 'year' ? 9 : 1;
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
else {
|
|
1824
|
-
this.disablePreviousButton = false;
|
|
1825
|
-
}
|
|
1948
|
+
const prev = viewDt.minus({ [pluralUnit]: subCount }).startOf(unit);
|
|
1949
|
+
const minDt = DateTime.fromJSDate(this.minDate).startOf(unit);
|
|
1950
|
+
this.disablePreviousButton = prev < minDt;
|
|
1826
1951
|
// When in year view, we need to add 8 years to determine if we're past the max date.
|
|
1827
1952
|
// The year view is 16 years long, and the current date is the 9th year in the view.
|
|
1828
1953
|
const addCount = this.view.mode === 'year' ? 8 : 1;
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
else {
|
|
1833
|
-
this.disableNextButton = false;
|
|
1834
|
-
}
|
|
1954
|
+
const next = viewDt.plus({ [pluralUnit]: addCount }).startOf(unit);
|
|
1955
|
+
const maxDt = DateTime.fromJSDate(this.maxDate).startOf(unit);
|
|
1956
|
+
this.disableNextButton = next > maxDt;
|
|
1835
1957
|
}
|
|
1836
1958
|
getLastItem() {
|
|
1837
1959
|
const lastRow = this.calendarItems[this.calendarItems.length - 1];
|
|
@@ -5122,7 +5244,7 @@ class DateInputComponent extends FormControlBase {
|
|
|
5122
5244
|
* Date parsing formats for user-entered dates. Defaults to month-first formats, but is updated in onInit
|
|
5123
5245
|
* to use the user's preferred date format.
|
|
5124
5246
|
*/
|
|
5125
|
-
this.parseFormats = DateTimeHelper.
|
|
5247
|
+
this.parseFormats = DateTimeHelper.getLuxonParseFormats();
|
|
5126
5248
|
}
|
|
5127
5249
|
ngOnChanges(changes) {
|
|
5128
5250
|
if (changes.selectionMode && !changes.selectionMode.isFirstChange()) {
|
|
@@ -5239,7 +5361,7 @@ class DateInputComponent extends FormControlBase {
|
|
|
5239
5361
|
goToToday() {
|
|
5240
5362
|
// If both calendars are visible, show today in the secondary calendar and the month before in the primary calendar.
|
|
5241
5363
|
if (this.selectionStrategy.showSecondaryCalendar) {
|
|
5242
|
-
this.primaryCalendarView = { mode: 'day', date:
|
|
5364
|
+
this.primaryCalendarView = { mode: 'day', date: DateTime.now().minus({ months: 1 }).toJSDate() };
|
|
5243
5365
|
this.secondaryCalendarView = { mode: 'day', date: new Date() };
|
|
5244
5366
|
// If we're in a single date mode, show today in the primary calendar.
|
|
5245
5367
|
}
|
|
@@ -5372,7 +5494,7 @@ class DateInputComponent extends FormControlBase {
|
|
|
5372
5494
|
const { preference } = await lastValueFrom(this.userPreferenceService.getPreferences());
|
|
5373
5495
|
const dateFormat = preference?.dateFormat;
|
|
5374
5496
|
this.placeholder = dateFormat ?? this.placeholder;
|
|
5375
|
-
this.parseFormats = DateTimeHelper.
|
|
5497
|
+
this.parseFormats = DateTimeHelper.getLuxonParseFormats(dateFormat);
|
|
5376
5498
|
}
|
|
5377
5499
|
/** Focuses the date input. */
|
|
5378
5500
|
focusInput() {
|
|
@@ -5392,10 +5514,10 @@ class DateInputComponent extends FormControlBase {
|
|
|
5392
5514
|
// This would cause the dates in the other calendar to be unselectable if we were to
|
|
5393
5515
|
// update the min/max dates in these cases.
|
|
5394
5516
|
if (this.primaryCalendarView?.mode === 'day') {
|
|
5395
|
-
this.secondaryCalendarMinDate =
|
|
5517
|
+
this.secondaryCalendarMinDate = DateTime.fromJSDate(this.primaryCalendarView.date).plus({ months: 1 }).startOf('month').toJSDate();
|
|
5396
5518
|
}
|
|
5397
5519
|
if (this.secondaryCalendarView?.mode === 'day') {
|
|
5398
|
-
this.primaryCalendarMaxDate =
|
|
5520
|
+
this.primaryCalendarMaxDate = DateTime.fromJSDate(this.secondaryCalendarView.date).minus({ months: 1 }).endOf('month').toJSDate();
|
|
5399
5521
|
}
|
|
5400
5522
|
}
|
|
5401
5523
|
updateCalendars(selection) {
|
|
@@ -5411,8 +5533,10 @@ class DateInputComponent extends FormControlBase {
|
|
|
5411
5533
|
// However, it's possible that the new date is after the secondary calendar's date. In this case,
|
|
5412
5534
|
// We want to shift the secondary calendar so the calendars stay in order.
|
|
5413
5535
|
if (shiftSecondary && this.secondaryCalendarView) {
|
|
5414
|
-
|
|
5415
|
-
|
|
5536
|
+
const primaryDt = DateTime.fromJSDate(this.primaryCalendarView.date);
|
|
5537
|
+
const secondaryDt = DateTime.fromJSDate(this.secondaryCalendarView.date);
|
|
5538
|
+
if (primaryDt.startOf('month') >= secondaryDt.startOf('month')) {
|
|
5539
|
+
const newSecondaryDate = primaryDt.plus({ months: 1 }).toJSDate();
|
|
5416
5540
|
this.secondaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: newSecondaryDate };
|
|
5417
5541
|
}
|
|
5418
5542
|
}
|
|
@@ -5423,8 +5547,10 @@ class DateInputComponent extends FormControlBase {
|
|
|
5423
5547
|
// However, it's possible that the new date is before the primary calendar's date. In this case,
|
|
5424
5548
|
// We want to shift the primary calendar so the calendars stay in order.
|
|
5425
5549
|
if (shiftPrimary && this.primaryCalendarView) {
|
|
5426
|
-
|
|
5427
|
-
|
|
5550
|
+
const primaryDt = DateTime.fromJSDate(this.primaryCalendarView.date);
|
|
5551
|
+
const secondaryDt = DateTime.fromJSDate(this.secondaryCalendarView.date);
|
|
5552
|
+
if (primaryDt.startOf('month') >= secondaryDt.startOf('month')) {
|
|
5553
|
+
const newPrimaryDate = secondaryDt.minus({ months: 1 }).toJSDate();
|
|
5428
5554
|
this.primaryCalendarView = { mode: this.selectionStrategy.selectionViewMode, date: newPrimaryDate };
|
|
5429
5555
|
}
|
|
5430
5556
|
}
|
|
@@ -5474,10 +5600,12 @@ class DateInputComponent extends FormControlBase {
|
|
|
5474
5600
|
// We're using the view mode as the granularity. We don't want to invalidate
|
|
5475
5601
|
// the date in the case where you have a month/quarter/year selected and the min
|
|
5476
5602
|
// or max date is somewhere within that month/quarter/year.
|
|
5477
|
-
|
|
5603
|
+
const unit = this.selectionStrategy.selectionViewMode;
|
|
5604
|
+
const valueDt = DateTime.fromJSDate(value).startOf(unit);
|
|
5605
|
+
if (valueDt < DateTime.fromJSDate(this.minDate).startOf(unit)) {
|
|
5478
5606
|
return { minDate: { minValue: this.minDate } };
|
|
5479
5607
|
}
|
|
5480
|
-
else if (
|
|
5608
|
+
else if (valueDt > DateTime.fromJSDate(this.maxDate).startOf(unit)) {
|
|
5481
5609
|
return { maxDate: { maxValue: this.maxDate } };
|
|
5482
5610
|
}
|
|
5483
5611
|
}
|
|
@@ -11734,7 +11862,9 @@ class DateDisplayPipe2 {
|
|
|
11734
11862
|
}
|
|
11735
11863
|
async transform(date, options) {
|
|
11736
11864
|
const { showEndOfTime, showTime, showSeconds, displayInUTC } = options || {};
|
|
11737
|
-
if (
|
|
11865
|
+
if (date == null)
|
|
11866
|
+
return '';
|
|
11867
|
+
if (!DateTimeHelper.toDateTime(date).isValid || (!showEndOfTime && DateTimeHelper.isEndOfTime(date))) {
|
|
11738
11868
|
return '';
|
|
11739
11869
|
}
|
|
11740
11870
|
const { preference } = await lastValueFrom(this.userPrefs.getPreferences());
|
|
@@ -11746,8 +11876,7 @@ class DateDisplayPipe2 {
|
|
|
11746
11876
|
}
|
|
11747
11877
|
formatString += ` ${timeFormat}`;
|
|
11748
11878
|
}
|
|
11749
|
-
|
|
11750
|
-
return (displayInUTC ? moment.utc(date) : moment(date)).format(formatString);
|
|
11879
|
+
return DateTimeHelper.formatDate(date, formatString, displayInUTC);
|
|
11751
11880
|
}
|
|
11752
11881
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: DateDisplayPipe2, deps: [{ token: UserPreferenceService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
11753
11882
|
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.4", ngImport: i0, type: DateDisplayPipe2, isStandalone: false, name: "dateDisplay2" }); }
|
|
@@ -11760,6 +11889,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
11760
11889
|
}]
|
|
11761
11890
|
}], ctorParameters: () => [{ type: UserPreferenceService }] });
|
|
11762
11891
|
|
|
11892
|
+
/**
|
|
11893
|
+
* Same behavior as {@link DateDisplayPipe2}, but always appends the short named
|
|
11894
|
+
* timezone abbreviation (e.g. `EST`, `PDT`, `UTC`) to the output. Use this when
|
|
11895
|
+
* downstream consumers need to disambiguate the timezone of a rendered date.
|
|
11896
|
+
*
|
|
11897
|
+
* @example <span>{{ someDate | dateDisplay3 | async }}</span>
|
|
11898
|
+
*/
|
|
11899
|
+
class DateDisplayPipe3 {
|
|
11900
|
+
constructor(userPrefs) {
|
|
11901
|
+
this.userPrefs = userPrefs;
|
|
11902
|
+
}
|
|
11903
|
+
async transform(date, options) {
|
|
11904
|
+
const { showEndOfTime, showTime, showSeconds, displayInUTC } = options || {};
|
|
11905
|
+
if (date == null)
|
|
11906
|
+
return '';
|
|
11907
|
+
if (!DateTimeHelper.toDateTime(date).isValid || (!showEndOfTime && DateTimeHelper.isEndOfTime(date))) {
|
|
11908
|
+
return '';
|
|
11909
|
+
}
|
|
11910
|
+
const { preference } = await lastValueFrom(this.userPrefs.getPreferences());
|
|
11911
|
+
let formatString = preference?.dateFormat || 'MM/DD/YYYY';
|
|
11912
|
+
if (showTime) {
|
|
11913
|
+
let timeFormat = preference.timeFormat;
|
|
11914
|
+
if (!showSeconds) {
|
|
11915
|
+
timeFormat = timeFormat.replace(':ss', '');
|
|
11916
|
+
}
|
|
11917
|
+
formatString += ` ${timeFormat}`;
|
|
11918
|
+
}
|
|
11919
|
+
// Luxon's `ZZZZ` renders the short named offset (e.g. `EST`, `EDT`, `UTC`).
|
|
11920
|
+
// The token passes through `momentToLuxonFormat` unchanged.
|
|
11921
|
+
formatString += ' ZZZZ';
|
|
11922
|
+
return DateTimeHelper.formatDate(date, formatString, !!displayInUTC);
|
|
11923
|
+
}
|
|
11924
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: DateDisplayPipe3, deps: [{ token: UserPreferenceService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
11925
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.4", ngImport: i0, type: DateDisplayPipe3, isStandalone: false, name: "dateDisplay3" }); }
|
|
11926
|
+
}
|
|
11927
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: DateDisplayPipe3, decorators: [{
|
|
11928
|
+
type: Pipe,
|
|
11929
|
+
args: [{
|
|
11930
|
+
name: 'dateDisplay3',
|
|
11931
|
+
standalone: false
|
|
11932
|
+
}]
|
|
11933
|
+
}], ctorParameters: () => [{ type: UserPreferenceService }] });
|
|
11934
|
+
|
|
11763
11935
|
/**
|
|
11764
11936
|
* Format a time to the user's preference for display
|
|
11765
11937
|
*/
|
|
@@ -11772,11 +11944,10 @@ class TimeDisplayPipe {
|
|
|
11772
11944
|
* Format a time for display, accounting for user's display preferences.
|
|
11773
11945
|
*/
|
|
11774
11946
|
transform(time, showSeconds) {
|
|
11775
|
-
let display = '';
|
|
11776
11947
|
let formatString = '';
|
|
11777
11948
|
// use user-preferred formats
|
|
11778
11949
|
this.userPreferenceService.getPreferences().subscribe(result => {
|
|
11779
|
-
//if preferences exist then format time to users preference
|
|
11950
|
+
//if preferences exist then format time to users preference
|
|
11780
11951
|
//otherwise use the last user preference
|
|
11781
11952
|
if (result.preference) {
|
|
11782
11953
|
formatString = result.preference.timeFormat;
|
|
@@ -11786,8 +11957,7 @@ class TimeDisplayPipe {
|
|
|
11786
11957
|
this.lastFormatString = formatString;
|
|
11787
11958
|
}
|
|
11788
11959
|
});
|
|
11789
|
-
|
|
11790
|
-
return display;
|
|
11960
|
+
return DateTimeHelper.formatDate(time ?? null, this.lastFormatString);
|
|
11791
11961
|
}
|
|
11792
11962
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: TimeDisplayPipe, deps: [{ token: UserPreferenceService }], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
11793
11963
|
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.4", ngImport: i0, type: TimeDisplayPipe, isStandalone: false, name: "timeDisplay" }); }
|
|
@@ -11815,21 +11985,21 @@ class RelativeDatePipe {
|
|
|
11815
11985
|
* If any of todayLabel, yesterdayLabel is supplied, use the supplied label.
|
|
11816
11986
|
*/
|
|
11817
11987
|
transform(timeSelected, options) {
|
|
11818
|
-
const selected =
|
|
11819
|
-
const today =
|
|
11820
|
-
const yesterday =
|
|
11988
|
+
const selected = DateTime.fromISO(timeSelected);
|
|
11989
|
+
const today = DateTime.now();
|
|
11990
|
+
const yesterday = today.minus({ days: 1 });
|
|
11821
11991
|
const timeDisplay = options?.dateOnly ? `` : ` ${this.timeDisplayPipe.transform(timeSelected)}`;
|
|
11822
11992
|
let displayValue = null;
|
|
11823
11993
|
let prefixValue = '';
|
|
11824
|
-
if (selected.
|
|
11994
|
+
if (selected.hasSame(today, 'day') && !options?.showTimeForToday) {
|
|
11825
11995
|
displayValue = this.translateService.instant(options?.todayLabel ? options?.todayLabel : 'today');
|
|
11826
11996
|
prefixValue = options?.todayPrefix ?? '';
|
|
11827
11997
|
}
|
|
11828
|
-
else if (selected.
|
|
11998
|
+
else if (selected.hasSame(today, 'day') && options?.showTimeForToday && !timeDisplay) {
|
|
11829
11999
|
displayValue = this.timeDisplayPipe.transform(timeSelected);
|
|
11830
12000
|
prefixValue = options?.todayTimePrefix ?? '';
|
|
11831
12001
|
}
|
|
11832
|
-
else if (selected.
|
|
12002
|
+
else if (selected.hasSame(yesterday, 'day')) {
|
|
11833
12003
|
displayValue = this.translateService.instant(options?.yesterdayLabel ? options?.yesterdayLabel : 'yesterday');
|
|
11834
12004
|
prefixValue = options?.yesterdayPrefix ?? '';
|
|
11835
12005
|
}
|
|
@@ -12467,6 +12637,7 @@ class ComponentsModule {
|
|
|
12467
12637
|
DateInputComponent,
|
|
12468
12638
|
KeyboardNavContainerDirective,
|
|
12469
12639
|
DateDisplayPipe2,
|
|
12640
|
+
DateDisplayPipe3,
|
|
12470
12641
|
MultiselectComponent], imports: [CommonModule,
|
|
12471
12642
|
FormsModule,
|
|
12472
12643
|
ReactiveFormsModule,
|
|
@@ -12539,7 +12710,8 @@ class ComponentsModule {
|
|
|
12539
12710
|
CalendarComponent,
|
|
12540
12711
|
DateInputComponent,
|
|
12541
12712
|
KeyboardNavContainerDirective,
|
|
12542
|
-
DateDisplayPipe2
|
|
12713
|
+
DateDisplayPipe2,
|
|
12714
|
+
DateDisplayPipe3] }); }
|
|
12543
12715
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComponentsModule, providers: [
|
|
12544
12716
|
FormGroupHelper,
|
|
12545
12717
|
DialogService,
|
|
@@ -12549,7 +12721,8 @@ class ComponentsModule {
|
|
|
12549
12721
|
RowCountPipe,
|
|
12550
12722
|
RelativeDatePipe,
|
|
12551
12723
|
HighlightTextPipe,
|
|
12552
|
-
DateDisplayPipe2
|
|
12724
|
+
DateDisplayPipe2,
|
|
12725
|
+
DateDisplayPipe3
|
|
12553
12726
|
], imports: [CommonModule,
|
|
12554
12727
|
FormsModule,
|
|
12555
12728
|
ReactiveFormsModule,
|
|
@@ -12635,6 +12808,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
12635
12808
|
DateInputComponent,
|
|
12636
12809
|
KeyboardNavContainerDirective,
|
|
12637
12810
|
DateDisplayPipe2,
|
|
12811
|
+
DateDisplayPipe3,
|
|
12638
12812
|
MultiselectComponent
|
|
12639
12813
|
],
|
|
12640
12814
|
imports: [
|
|
@@ -12656,7 +12830,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
12656
12830
|
RowCountPipe,
|
|
12657
12831
|
RelativeDatePipe,
|
|
12658
12832
|
HighlightTextPipe,
|
|
12659
|
-
DateDisplayPipe2
|
|
12833
|
+
DateDisplayPipe2,
|
|
12834
|
+
DateDisplayPipe3
|
|
12660
12835
|
],
|
|
12661
12836
|
exports: [
|
|
12662
12837
|
ButtonComponent,
|
|
@@ -12724,7 +12899,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
12724
12899
|
CalendarComponent,
|
|
12725
12900
|
DateInputComponent,
|
|
12726
12901
|
KeyboardNavContainerDirective,
|
|
12727
|
-
DateDisplayPipe2
|
|
12902
|
+
DateDisplayPipe2,
|
|
12903
|
+
DateDisplayPipe3
|
|
12728
12904
|
]
|
|
12729
12905
|
}]
|
|
12730
12906
|
}] });
|
|
@@ -13720,5 +13896,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
13720
13896
|
* Generated bundle index. Do not edit.
|
|
13721
13897
|
*/
|
|
13722
13898
|
|
|
13723
|
-
export { AppBarComponent, AvatarComponent, BannerComponent, ButtonComponent, CacheService, CalendarComponent, CheckboxComponent, ClickAreaForDirective, CollapsibleToggleComponent, ComboboxComponent, ComponentsModule, ConfirmComponent, ConfirmDialogContext, CopyButtonBaseTestInjectorFactory, CopyButtonDirective, CopyTableButtonDirective, CustomValidators, DateDisplayPipe, DateDisplayPipe2, DateInput, DateInputComponent, DateTimeHelper, DialogCloseDuration, DialogCloseEvent, DialogCloseLatestEvent, DialogComponent, DialogEvent, DialogGroupComponent, DialogOpenDuration, DialogOpenEndEvent, DialogOpenStartEvent, DialogResult, DialogService, DropdownComponent, ErrorService, FileTypeExtensions, FileUploadComponent, FormControlBase, FormControlComponent, FormControlLabelComponent, FormGroupComponent, FormGroupHelper, HelpPopoverComponent, HierarchyBase, HierarchyBaseTestInjectorFactory, HierarchyItem, HierarchyMocks, HierarchyTreeComponent, HighlightTextPipe, IfViewportWidthDirective, ItemDisplayComponent, ItemPickerComponent, ItemPickerSelectableContext, JsonDisplayComponent, JsonHelper, KeyboardNavContainerDirective, LinkButtonComponent, MenuComponent, MockActivatedRoute, MockDateDisplayPipe, MockDialog, MockDialogContent, MockTranslateService, MockTranslationHelperService, MultiselectComponent, NavGroup, NavItemActiveDirective, NumericboxComponent, Overlay, PageBaseComponent, PageBaseComponentTestHelper, PageBaseComponentTestInjectorFactory, PageInitResult, PageStatus, PageStatuses, PageTitleComponent, PageViewComponent, PanelCloseDuration, PanelOpenDuration, PopoverComponent, PopupContainerDirective, RadioButtonComponent, RadioButtonOption, RelativeDatePipe, ResizableBase, ResizableColumnComponent, ResizableComponent, RouterHelper, RowCountPipe, ScrollService, SearchableTableComponent, SelectComponent, SpinnerComponent, SplashComponent, SplashService, SpyFactory, TableComponent, TableLockedColumnComponent, TableMasterHeaderRowComponent, TableMasterRowComponent, TablePaginationComponent, TableSelectableRowComponent, TableSelectableRowContext, TabsComponent, Tag, TagsComponent, TelemetryService, TelemetryTrackerService, TextboxComponent, TimeDisplayPipe, ToastComponent, ToastEvent, ToastService, ToasterComponent, TooltipComponent, TooltipDirective, TooltipService, TreeComponent, UnicodeStrings, UserPreferenceService, ValidationMessageService, ViewOverlayComponent, WindowService, WizardBaseComponent, WizardButtonsComponent, WizardProgressComponent, canadianPostalCodeRegex, clickEvent, dateInputFormatRegex, domainPattern, findAllSpacesPattern, forEachFormControl, getApiError, getControlValue, getDecimalPattern, handleKeyNavigate, integerPattern, isApiError, menuAnimationSpeed, mockRouterFactory, mockRouterHelperFactory, numericboxValidation, orderByIgnoreCase, otherZipCodeRegex, phoneNumberValidationPattern, sortByIgnoreCase, textboxValidation, unitedStatesZipCodeRegex, urlValidationPattern, validateFormGroupValuesAreUnique };
|
|
13899
|
+
export { AppBarComponent, AvatarComponent, BannerComponent, ButtonComponent, CacheService, CalendarComponent, CheckboxComponent, ClickAreaForDirective, CollapsibleToggleComponent, ComboboxComponent, ComponentsModule, ConfirmComponent, ConfirmDialogContext, CopyButtonBaseTestInjectorFactory, CopyButtonDirective, CopyTableButtonDirective, CustomValidators, DateDisplayPipe, DateDisplayPipe2, DateDisplayPipe3, DateInput, DateInputComponent, DateTimeHelper, DialogCloseDuration, DialogCloseEvent, DialogCloseLatestEvent, DialogComponent, DialogEvent, DialogGroupComponent, DialogOpenDuration, DialogOpenEndEvent, DialogOpenStartEvent, DialogResult, DialogService, DropdownComponent, ErrorService, FileTypeExtensions, FileUploadComponent, FormControlBase, FormControlComponent, FormControlLabelComponent, FormGroupComponent, FormGroupHelper, HelpPopoverComponent, HierarchyBase, HierarchyBaseTestInjectorFactory, HierarchyItem, HierarchyMocks, HierarchyTreeComponent, HighlightTextPipe, IfViewportWidthDirective, ItemDisplayComponent, ItemPickerComponent, ItemPickerSelectableContext, JsonDisplayComponent, JsonHelper, KeyboardNavContainerDirective, LinkButtonComponent, MenuComponent, MockActivatedRoute, MockDateDisplayPipe, MockDialog, MockDialogContent, MockTranslateService, MockTranslationHelperService, MultiselectComponent, NavGroup, NavItemActiveDirective, NumericboxComponent, Overlay, PageBaseComponent, PageBaseComponentTestHelper, PageBaseComponentTestInjectorFactory, PageInitResult, PageStatus, PageStatuses, PageTitleComponent, PageViewComponent, PanelCloseDuration, PanelOpenDuration, PopoverComponent, PopupContainerDirective, RadioButtonComponent, RadioButtonOption, RelativeDatePipe, ResizableBase, ResizableColumnComponent, ResizableComponent, RouterHelper, RowCountPipe, ScrollService, SearchableTableComponent, SelectComponent, SpinnerComponent, SplashComponent, SplashService, SpyFactory, TableComponent, TableLockedColumnComponent, TableMasterHeaderRowComponent, TableMasterRowComponent, TablePaginationComponent, TableSelectableRowComponent, TableSelectableRowContext, TabsComponent, Tag, TagsComponent, TelemetryService, TelemetryTrackerService, TextboxComponent, TimeDisplayPipe, ToastComponent, ToastEvent, ToastService, ToasterComponent, TooltipComponent, TooltipDirective, TooltipService, TreeComponent, UnicodeStrings, UserPreferenceService, ValidationMessageService, ViewOverlayComponent, WindowService, WizardBaseComponent, WizardButtonsComponent, WizardProgressComponent, canadianPostalCodeRegex, clickEvent, dateInputFormatRegex, domainPattern, findAllSpacesPattern, forEachFormControl, getApiError, getControlValue, getDecimalPattern, handleKeyNavigate, integerPattern, isApiError, menuAnimationSpeed, mockRouterFactory, mockRouterHelperFactory, numericboxValidation, orderByIgnoreCase, otherZipCodeRegex, phoneNumberValidationPattern, sortByIgnoreCase, textboxValidation, unitedStatesZipCodeRegex, urlValidationPattern, validateFormGroupValuesAreUnique };
|
|
13724
13900
|
//# sourceMappingURL=energycap-components.mjs.map
|