ng-material-date-range-picker
Version:
This library provides the date range selection with two views.
329 lines • 65.3 kB
JavaScript
/**
* @(#)ng-date-picker.component.ts Sept 05, 2023
*
* @author Aakash Kumar
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, ElementRef, EventEmitter, inject, Input, Output, signal, } from '@angular/core';
import { DateRange } from '@angular/material/datepicker';
import { DATE_OPTION_TYPE } from './constant/date-filter-const';
import { DEFAULT_DATE_OPTIONS } from './data/default-date-options';
import { getClone, getDateString, getDateWithOffset, getDaysInMonth, getFormattedDateString, resetOptionSelection, selectCustomOption, } from './utils/date-picker-utilities';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/material/input";
import * as i3 from "@angular/material/form-field";
import * as i4 from "@angular/cdk/overlay";
import * as i5 from "@angular/material/icon";
import * as i6 from "@angular/material/button";
import * as i7 from "@angular/material/list";
import * as i8 from "@angular/material/tooltip";
import * as i9 from "./calendar/calendar.component";
export class NgDatePickerComponent {
constructor() {
this.isDateOptionList = false;
this.isCustomRange = false;
this.inputLabel = 'Date Range';
this.staticOptionId = 'static-options';
this.dynamicOptionId = 'dynamic-options';
this.calendarId = 'custom-calendar';
this.enableDefaultOptions = true;
this.dateFormat = 'dd/MM/yyyy';
this.isShowStaticDefaultOptions = false;
this.hideDefaultOptions = false;
this.cdkConnectedOverlayOffsetX = 0;
this.cdkConnectedOverlayOffsetY = 0;
this.listCdkConnectedOverlayOffsetY = 0;
this.listCdkConnectedOverlayOffsetX = 0;
this.selectedOptionIndex = 3;
this.displaySelectedLabel = false;
this.cdkConnectedOverlayPush = true;
this.cdkConnectedOverlayPositions = [];
// default min date is current date - 10 years.
this.minDate = getDateWithOffset(-10);
// default max date is current date + 10 years.
this.maxDate = getDateWithOffset(10);
this.onDateSelectionChanged = new EventEmitter();
this.dateListOptions = new EventEmitter();
this.cdref = inject(ChangeDetectorRef);
this.el = inject(ElementRef);
this._dateOptions = signal([]);
this.visibleOptions = computed(() => this._dateOptions().filter((op) => op.isVisible));
}
set dateDropDownOptions(defaultDateList) {
const options = [
...(this.enableDefaultOptions ? getClone(DEFAULT_DATE_OPTIONS) : []),
...(defaultDateList ?? []),
];
this._dateOptions.set(options);
}
get dateDropDownOptions() {
return this._dateOptions() ?? [];
}
ngOnInit() {
if (this.isDefaultInitRequired()) {
this.initDefaultOptions();
}
this.dateListOptions.emit(this.dateDropDownOptions);
}
ngAfterViewInit() {
this.updateDefaultDatesValues();
}
/**
* Toggles the visibility of the default date option list.
* If the custom option is selected, toggles the custom date range view instead.
*
* @param event Optional MouseEvent triggering the toggle.
*/
toggleDateOptionSelectionList(event) {
event?.preventDefault();
event?.stopImmediatePropagation();
const isCustomSelected = this.dateDropDownOptions.find((option) => option.isSelected)
?.optionType === DATE_OPTION_TYPE.CUSTOM;
if (isCustomSelected) {
this.toggleCustomDateRangeView();
return;
}
this.isDateOptionList = !this.isDateOptionList;
}
/**
* Updates the custom date range selection from the input.
*
* @param input The HTML input element associated with the date picker.
* @param selectedDates The selected date range.
*/
updateCustomRange(input, selectedDates) {
if (this.isCustomRange) {
resetOptionSelection(this.dateDropDownOptions);
selectCustomOption(this.dateDropDownOptions);
this.isCustomRange = false;
}
const start = selectedDates?.start ?? new Date();
const end = selectedDates?.end ?? new Date();
this.updateSelectedDates(input, start, end, null);
}
/**
* Updates the selection when a specific date option is clicked.
*
* @param option The selected date option.
* @param input The HTML input element to update with selected dates.
*/
updateSelection(option, input) {
this.isDateOptionList = false;
this.isCustomRange = option.optionType === DATE_OPTION_TYPE.CUSTOM;
if (!this.isCustomRange) {
resetOptionSelection(this.dateDropDownOptions, option);
this.updateDateOnOptionSelect(option, input);
}
this.cdref.markForCheck();
}
/**
* Toggles the custom date range selection view visibility.
*/
toggleCustomDateRangeView() {
this.isCustomRange = !this.isCustomRange;
}
/**
* Clears the currently selected dates and resets all related properties.
*
* @param event The MouseEvent triggering the clear action.
*/
clearSelection(event) {
event?.stopImmediatePropagation();
this.minDate = getDateWithOffset(-10);
this.maxDate = getDateWithOffset(10);
this.selectedDates = null;
resetOptionSelection(this.dateDropDownOptions);
this.clearDateInput();
this.cdref.markForCheck();
const selectedDateEventData = {
range: null,
selectedOption: null,
};
this.onDateSelectionChanged.emit(selectedDateEventData);
}
/**
* Clears the input field value for the date picker.
*/
clearDateInput() {
const dateInputField = this.el.nativeElement.querySelector('#date-input-field');
if (dateInputField) {
dateInputField.value = '';
}
}
/**
* Updates selected dates based on a selected option and input element.
*
* @param option The selected date option.
* @param input The HTML input element to update.
*/
updateDateOnOptionSelect(option, input) {
// If there is a callback function, use it to get the date range
if (option?.callBackFunction) {
const dateRange = option.callBackFunction();
if (dateRange?.start && dateRange?.end) {
this.updateSelectedDates(input, dateRange.start, dateRange.end, option);
return;
}
}
this.updateDateWithSelectedOption(option, input);
}
/**
* Calculates and updates the start and end dates based on the selected option.
*
* @param option The selected date option.
* @param input The HTML input element to update.
*/
updateDateWithSelectedOption(option, input) {
const currDate = new Date();
let startDate = new Date();
let lastDate = new Date();
// Determine the date range based on the option key
switch (option.optionType) {
case DATE_OPTION_TYPE.DATE_DIFF:
startDate.setDate(startDate.getDate() + (option.dateDiff ?? 0));
break;
case DATE_OPTION_TYPE.LAST_MONTH:
currDate.setMonth(currDate.getMonth() - 1);
startDate = new Date(currDate.getFullYear(), currDate.getMonth(), 1);
lastDate = new Date(currDate.getFullYear(), currDate.getMonth(), getDaysInMonth(currDate));
break;
case DATE_OPTION_TYPE.THIS_MONTH:
startDate = new Date(currDate.getFullYear(), currDate.getMonth(), 1);
lastDate = new Date(currDate.getFullYear(), currDate.getMonth(), getDaysInMonth(currDate));
break;
case DATE_OPTION_TYPE.YEAR_TO_DATE:
startDate = new Date(currDate.getFullYear(), 0, 1);
break;
case DATE_OPTION_TYPE.MONTH_TO_DATE:
startDate = new Date(currDate.getFullYear(), currDate.getMonth(), 1);
break;
default:
break;
}
// Update the selected dates
this.updateSelectedDates(input, startDate, lastDate, option);
}
/**
* Updates the date range and input display.
*
* @param input The HTML input element.
* @param start Start date of the range.
* @param end End date of the range.
* @param opt Optional selected date option.
*/
updateSelectedDates(input, start, end, opt) {
const range = new DateRange(start, end);
this.selectedDates = range;
const label = this.displaySelectedLabel ? opt?.optionLabel : null;
const rangeLabel = `${getDateString(start, this.dateFormat)} - ${getDateString(end, this.dateFormat)}`;
input.value = label ?? rangeLabel;
this.onDateSelectionChanged.emit({
range,
selectedOption: this.dateDropDownOptions.find((o) => o.isSelected) ?? null,
});
this.cdref.markForCheck();
}
/**
* Updates the input and internal state with default dates on initialization.
*/
updateDefaultDatesValues() {
const input = this.el.nativeElement.querySelector('#date-input-field');
if (this.selectedDates?.start && this.selectedDates?.end) {
this._dateOptions().find((option) => option.optionType === DATE_OPTION_TYPE.CUSTOM).isSelected = true;
input.value = getFormattedDateString(this.selectedDates, this.dateFormat);
this.cdref.detectChanges();
return;
}
const selectedOptions = this._dateOptions().find((option) => option.isSelected);
if (selectedOptions &&
selectedOptions.optionType !== DATE_OPTION_TYPE.CUSTOM) {
this.updatedFromListValueSelection(selectedOptions, input);
this.cdref.detectChanges();
}
}
/**
* Updates the input and selected dates based on a selected option from the list.
*
* @param selectedOption The selected date option.
* @param input The HTML input element to update.
*/
updatedFromListValueSelection(selectedOption, input) {
// This will update value if option is selected from default list.
if (!selectedOption['callBackFunction']) {
this.updateDateOnOptionSelect(selectedOption, input);
return;
}
// This will update value if option is selected from provided custom list.
const dateRange = selectedOption.callBackFunction();
this.updateSelectedDates(input, dateRange.start ?? new Date(), dateRange.end ?? new Date(), selectedOption);
}
/**
* Checks whether default initialization of options is required.
*
* @returns True if default options need to be initialized, otherwise false.
*/
isDefaultInitRequired() {
return this.enableDefaultOptions && !this._dateOptions.length;
}
/**
* Initializes the default date options with the selected index.
*/
initDefaultOptions() {
const options = getClone(DEFAULT_DATE_OPTIONS).map((opt, idx) => ({
...opt,
isSelected: idx === this.selectedOptionIndex,
}));
this._dateOptions.set(options);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgDatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: NgDatePickerComponent, selector: "ng-date-range-picker", inputs: { inputLabel: "inputLabel", staticOptionId: "staticOptionId", dynamicOptionId: "dynamicOptionId", calendarId: "calendarId", enableDefaultOptions: "enableDefaultOptions", selectedDates: "selectedDates", dateFormat: "dateFormat", isShowStaticDefaultOptions: "isShowStaticDefaultOptions", hideDefaultOptions: "hideDefaultOptions", cdkConnectedOverlayOffsetX: "cdkConnectedOverlayOffsetX", cdkConnectedOverlayOffsetY: "cdkConnectedOverlayOffsetY", listCdkConnectedOverlayOffsetY: "listCdkConnectedOverlayOffsetY", listCdkConnectedOverlayOffsetX: "listCdkConnectedOverlayOffsetX", selectedOptionIndex: "selectedOptionIndex", displaySelectedLabel: "displaySelectedLabel", cdkConnectedOverlayPush: "cdkConnectedOverlayPush", cdkConnectedOverlayPositions: "cdkConnectedOverlayPositions", minDate: "minDate", maxDate: "maxDate", dateDropDownOptions: "dateDropDownOptions" }, outputs: { onDateSelectionChanged: "onDateSelectionChanged", dateListOptions: "dateListOptions" }, ngImport: i0, template: "<!--**\r\n * @(#)ng-date-picker.component.html Sept 05, 2023\r\n\r\n * @author Aakash Kumar\r\n *-->\r\n<div class=\"date-picker-main\" cdkOverlayOrigin #trigger>\r\n <mat-form-field class=\"w-full\" [class]=\"{'display-hidden':isShowStaticDefaultOptions}\" (click)=\"toggleDateOptionSelectionList($event)\">\r\n <mat-label (click)=\"toggleDateOptionSelectionList($event)\">{{inputLabel}}</mat-label>\r\n <input matInput readonly=\"readonly\" #dateInput class=\"cursor-pointer\" id=\"date-input-field\">\r\n <button mat-icon-button matSuffix class=\"cursor-pointer pe-0 ps-0\" matTooltip=\"Clear\" *ngIf=\"!!dateInput.value\"\r\n (click)=\"clearSelection($event)\"><mat-icon>clear</mat-icon></button>\r\n <button mat-icon-button matSuffix class=\"cursor-pointer\"> <mat-icon>date_range</mat-icon></button>\r\n </mat-form-field>\r\n\r\n @if(dateDropDownOptions.length && isShowStaticDefaultOptions) {\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput,\r\n optionId: staticOptionId, className:'w-full custom-ckd-container range-input'\r\n }\"></ng-container>\r\n }\r\n\r\n <ng-template cdkConnectedOverlay [cdkConnectedOverlayHasBackdrop]=\"false\" [cdkConnectedOverlayOrigin]=\"trigger\"\r\n [cdkConnectedOverlayOpen]=\"isDateOptionList\" [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\r\n [cdkConnectedOverlayOffsetX]=\"listCdkConnectedOverlayOffsetX\" [cdkConnectedOverlayOffsetY]=\"listCdkConnectedOverlayOffsetY\"\r\n (overlayOutsideClick)=\"!isShowStaticDefaultOptions && toggleDateOptionSelectionList()\">\r\n\r\n @if(dateDropDownOptions.length && !isShowStaticDefaultOptions) {\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput,\r\n optionId: dynamicOptionId, className:'w-full custom-ckd-container range-input'\r\n }\"></ng-container>\r\n }\r\n </ng-template>\r\n\r\n <ng-template cdkConnectedOverlay [cdkConnectedOverlayHasBackdrop]=\"false\" [cdkConnectedOverlayOrigin]=\"trigger\"\r\n [cdkConnectedOverlayOpen]=\"isCustomRange\" [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\r\n [cdkConnectedOverlayPositions]=\"cdkConnectedOverlayPositions\" [cdkConnectedOverlayOffsetX]=\"cdkConnectedOverlayOffsetX\"\r\n [cdkConnectedOverlayOffsetY]=\"cdkConnectedOverlayOffsetY\" (overlayOutsideClick)=\"toggleCustomDateRangeView()\">\r\n <div class=\"custom-ckd-container custom-calendar-container\" [class]=\"{'without-default-opt':hideDefaultOptions}\">\r\n <div class=\"row-1\">\r\n <div class=\"pt-custom br-right column-1\" *ngIf=\"!hideDefaultOptions\">\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput}\"></ng-container>\r\n </div>\r\n <div class=\"mt-2 column-2\"><lib-calendar [selectedDates]=\"selectedDates\" #calendar [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"></lib-calendar></div>\r\n </div>\r\n <div class=\"row-2 br-top\">\r\n <div class=\"text-end my-2 w-full\">\r\n <div class=\"footer-content\">\r\n <span id=\"range-label-text\">\r\n {{calendar?.selectedDates?.start | date: dateFormat}}\r\n @if (calendar?.selectedDates?.end) {\r\n <span> - {{calendar.selectedDates?.end | date:\r\n dateFormat}} </span>\r\n }\r\n </span>\r\n <div class=\"d-inline buttons\">\r\n <button mat-button mat-raised-button class=\"p-3 mx-2\" (click)=\"isCustomRange=false;\">Cancel</button>\r\n <button mat-button mat-raised-button color=\"primary\" class=\"ms-2 p-3\"\r\n [class.disabled]=\"!(calendar?.selectedDates?.start && calendar?.selectedDates?.end)\"\r\n (click)=\"updateCustomRange(dateInput,calendar.selectedDates);\"> Apply </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n</div>\r\n\r\n<ng-template #dateOptionList let-options let-input=\"dateInput\" let-optionId=\"optionId\" let-className=\"className\">\r\n <mat-action-list [ngClass]=\"className\" [id]=\"optionId\">\r\n @for (option of options; track option.optionLabel) {\r\n <mat-list-item [activated]=\"option.isSelected\" (click)=\"updateSelection(option, input)\">\r\n {{option.optionLabel}}\r\n </mat-list-item>\r\n }\r\n </mat-action-list>\r\n</ng-template>\r\n", styles: ["::ng-deep .cdk-overlay-dark-backdrop{background:none}mat-list-item{height:35px}::ng-deep .cdk-overlay-pane:has(.custom-ckd-container){width:100%;background-color:var(--bg-color, white);max-height:100vh;overflow-y:auto;overflow-x:hidden;max-width:700px;margin-top:-22px;border:1px solid var(--border-color, #ddd)}::ng-deep .cdk-overlay-pane:has(.range-input){max-width:250px}.br-top{border-top:1px solid var(--border-color, #ddd)}.br-right{border-right:1px solid var(--border-color, #ddd)}.disabled{pointer-events:none;opacity:.5}.mat-button,.mdc-button{font-family:var(--mdc-list-list-item-label-text-font);line-height:var(--mdc-list-list-item-label-text-line-height);font-size:var(--mdc-list-list-item-label-text-size);font-weight:var(--mdc-list-list-item-label-text-weight);letter-spacing:var(--mdc-list-list-item-label-text-tracking)}.w-full{width:100%}.display-hidden{display:none}.custom-calendar-container,.row-1,.row-2{width:100%;display:block;float:left}.row-2{padding:.7rem}.footer-content{width:100%;align-items:center;display:flex;text-align:right;justify-content:end;gap:10px;margin-right:2rem;text-overflow:ellipsis}.buttons{margin-right:1.5rem;display:flex;gap:10px}.column-1{width:25%;display:block;float:left}.column-2{width:73%;display:block;float:left}@media (max-width: 400px){.footer-content{display:block}#range-label-text{margin-right:1.5rem}.buttons{float:right;margin-top:20px}}@media (max-width: 650px){.column-1,.column-2{width:100%}}@media (min-width: 650px){.column-1{width:25%}.column-2{width:74%}}.without-default-opt .column-1{display:none}.without-default-opt .column-2{width:100%;display:block;float:left}.pe-0{padding-right:0}.ps-0{padding-left:0}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i4.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i4.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i6.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: i7.MatActionList, selector: "mat-action-list", exportAs: ["matActionList"] }, { kind: "component", type: i7.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: i9.CalendarComponent, selector: "lib-calendar", inputs: ["minDate", "maxDate", "selectedDates"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgDatePickerComponent, decorators: [{
type: Component,
args: [{ selector: 'ng-date-range-picker', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--**\r\n * @(#)ng-date-picker.component.html Sept 05, 2023\r\n\r\n * @author Aakash Kumar\r\n *-->\r\n<div class=\"date-picker-main\" cdkOverlayOrigin #trigger>\r\n <mat-form-field class=\"w-full\" [class]=\"{'display-hidden':isShowStaticDefaultOptions}\" (click)=\"toggleDateOptionSelectionList($event)\">\r\n <mat-label (click)=\"toggleDateOptionSelectionList($event)\">{{inputLabel}}</mat-label>\r\n <input matInput readonly=\"readonly\" #dateInput class=\"cursor-pointer\" id=\"date-input-field\">\r\n <button mat-icon-button matSuffix class=\"cursor-pointer pe-0 ps-0\" matTooltip=\"Clear\" *ngIf=\"!!dateInput.value\"\r\n (click)=\"clearSelection($event)\"><mat-icon>clear</mat-icon></button>\r\n <button mat-icon-button matSuffix class=\"cursor-pointer\"> <mat-icon>date_range</mat-icon></button>\r\n </mat-form-field>\r\n\r\n @if(dateDropDownOptions.length && isShowStaticDefaultOptions) {\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput,\r\n optionId: staticOptionId, className:'w-full custom-ckd-container range-input'\r\n }\"></ng-container>\r\n }\r\n\r\n <ng-template cdkConnectedOverlay [cdkConnectedOverlayHasBackdrop]=\"false\" [cdkConnectedOverlayOrigin]=\"trigger\"\r\n [cdkConnectedOverlayOpen]=\"isDateOptionList\" [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\r\n [cdkConnectedOverlayOffsetX]=\"listCdkConnectedOverlayOffsetX\" [cdkConnectedOverlayOffsetY]=\"listCdkConnectedOverlayOffsetY\"\r\n (overlayOutsideClick)=\"!isShowStaticDefaultOptions && toggleDateOptionSelectionList()\">\r\n\r\n @if(dateDropDownOptions.length && !isShowStaticDefaultOptions) {\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput,\r\n optionId: dynamicOptionId, className:'w-full custom-ckd-container range-input'\r\n }\"></ng-container>\r\n }\r\n </ng-template>\r\n\r\n <ng-template cdkConnectedOverlay [cdkConnectedOverlayHasBackdrop]=\"false\" [cdkConnectedOverlayOrigin]=\"trigger\"\r\n [cdkConnectedOverlayOpen]=\"isCustomRange\" [cdkConnectedOverlayPush]=\"cdkConnectedOverlayPush\"\r\n [cdkConnectedOverlayPositions]=\"cdkConnectedOverlayPositions\" [cdkConnectedOverlayOffsetX]=\"cdkConnectedOverlayOffsetX\"\r\n [cdkConnectedOverlayOffsetY]=\"cdkConnectedOverlayOffsetY\" (overlayOutsideClick)=\"toggleCustomDateRangeView()\">\r\n <div class=\"custom-ckd-container custom-calendar-container\" [class]=\"{'without-default-opt':hideDefaultOptions}\">\r\n <div class=\"row-1\">\r\n <div class=\"pt-custom br-right column-1\" *ngIf=\"!hideDefaultOptions\">\r\n <ng-container *ngTemplateOutlet=\"dateOptionList; context: { $implicit: visibleOptions(), dateInput: dateInput}\"></ng-container>\r\n </div>\r\n <div class=\"mt-2 column-2\"><lib-calendar [selectedDates]=\"selectedDates\" #calendar [minDate]=\"minDate\"\r\n [maxDate]=\"maxDate\"></lib-calendar></div>\r\n </div>\r\n <div class=\"row-2 br-top\">\r\n <div class=\"text-end my-2 w-full\">\r\n <div class=\"footer-content\">\r\n <span id=\"range-label-text\">\r\n {{calendar?.selectedDates?.start | date: dateFormat}}\r\n @if (calendar?.selectedDates?.end) {\r\n <span> - {{calendar.selectedDates?.end | date:\r\n dateFormat}} </span>\r\n }\r\n </span>\r\n <div class=\"d-inline buttons\">\r\n <button mat-button mat-raised-button class=\"p-3 mx-2\" (click)=\"isCustomRange=false;\">Cancel</button>\r\n <button mat-button mat-raised-button color=\"primary\" class=\"ms-2 p-3\"\r\n [class.disabled]=\"!(calendar?.selectedDates?.start && calendar?.selectedDates?.end)\"\r\n (click)=\"updateCustomRange(dateInput,calendar.selectedDates);\"> Apply </button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </ng-template>\r\n</div>\r\n\r\n<ng-template #dateOptionList let-options let-input=\"dateInput\" let-optionId=\"optionId\" let-className=\"className\">\r\n <mat-action-list [ngClass]=\"className\" [id]=\"optionId\">\r\n @for (option of options; track option.optionLabel) {\r\n <mat-list-item [activated]=\"option.isSelected\" (click)=\"updateSelection(option, input)\">\r\n {{option.optionLabel}}\r\n </mat-list-item>\r\n }\r\n </mat-action-list>\r\n</ng-template>\r\n", styles: ["::ng-deep .cdk-overlay-dark-backdrop{background:none}mat-list-item{height:35px}::ng-deep .cdk-overlay-pane:has(.custom-ckd-container){width:100%;background-color:var(--bg-color, white);max-height:100vh;overflow-y:auto;overflow-x:hidden;max-width:700px;margin-top:-22px;border:1px solid var(--border-color, #ddd)}::ng-deep .cdk-overlay-pane:has(.range-input){max-width:250px}.br-top{border-top:1px solid var(--border-color, #ddd)}.br-right{border-right:1px solid var(--border-color, #ddd)}.disabled{pointer-events:none;opacity:.5}.mat-button,.mdc-button{font-family:var(--mdc-list-list-item-label-text-font);line-height:var(--mdc-list-list-item-label-text-line-height);font-size:var(--mdc-list-list-item-label-text-size);font-weight:var(--mdc-list-list-item-label-text-weight);letter-spacing:var(--mdc-list-list-item-label-text-tracking)}.w-full{width:100%}.display-hidden{display:none}.custom-calendar-container,.row-1,.row-2{width:100%;display:block;float:left}.row-2{padding:.7rem}.footer-content{width:100%;align-items:center;display:flex;text-align:right;justify-content:end;gap:10px;margin-right:2rem;text-overflow:ellipsis}.buttons{margin-right:1.5rem;display:flex;gap:10px}.column-1{width:25%;display:block;float:left}.column-2{width:73%;display:block;float:left}@media (max-width: 400px){.footer-content{display:block}#range-label-text{margin-right:1.5rem}.buttons{float:right;margin-top:20px}}@media (max-width: 650px){.column-1,.column-2{width:100%}}@media (min-width: 650px){.column-1{width:25%}.column-2{width:74%}}.without-default-opt .column-1{display:none}.without-default-opt .column-2{width:100%;display:block;float:left}.pe-0{padding-right:0}.ps-0{padding-left:0}\n"] }]
}], ctorParameters: () => [], propDecorators: { inputLabel: [{
type: Input
}], staticOptionId: [{
type: Input
}], dynamicOptionId: [{
type: Input
}], calendarId: [{
type: Input
}], enableDefaultOptions: [{
type: Input
}], selectedDates: [{
type: Input
}], dateFormat: [{
type: Input
}], isShowStaticDefaultOptions: [{
type: Input
}], hideDefaultOptions: [{
type: Input
}], cdkConnectedOverlayOffsetX: [{
type: Input
}], cdkConnectedOverlayOffsetY: [{
type: Input
}], listCdkConnectedOverlayOffsetY: [{
type: Input
}], listCdkConnectedOverlayOffsetX: [{
type: Input
}], selectedOptionIndex: [{
type: Input
}], displaySelectedLabel: [{
type: Input
}], cdkConnectedOverlayPush: [{
type: Input
}], cdkConnectedOverlayPositions: [{
type: Input
}], minDate: [{
type: Input
}], maxDate: [{
type: Input
}], onDateSelectionChanged: [{
type: Output
}], dateListOptions: [{
type: Output
}], dateDropDownOptions: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctZGF0ZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctZGF0ZS1waWNrZXIvc3JjL2xpYi9uZy1kYXRlLXBpY2tlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1kYXRlLXBpY2tlci9zcmMvbGliL25nLWRhdGUtcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsUUFBUSxFQUNSLFVBQVUsRUFDVixZQUFZLEVBQ1osTUFBTSxFQUNOLEtBQUssRUFFTCxNQUFNLEVBRU4sTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUVuRSxPQUFPLEVBQ0wsUUFBUSxFQUNSLGFBQWEsRUFDYixpQkFBaUIsRUFDakIsY0FBYyxFQUNkLHNCQUFzQixFQUN0QixvQkFBb0IsRUFDcEIsa0JBQWtCLEdBQ25CLE1BQU0sK0JBQStCLENBQUM7Ozs7Ozs7Ozs7O0FBUXZDLE1BQU0sT0FBTyxxQkFBcUI7SUFvQ2hDO1FBbkNPLHFCQUFnQixHQUFZLEtBQUssQ0FBQztRQUNsQyxrQkFBYSxHQUFZLEtBQUssQ0FBQztRQUM3QixlQUFVLEdBQVcsWUFBWSxDQUFDO1FBQ2xDLG1CQUFjLEdBQUcsZ0JBQWdCLENBQUM7UUFDbEMsb0JBQWUsR0FBRyxpQkFBaUIsQ0FBQztRQUNwQyxlQUFVLEdBQVcsaUJBQWlCLENBQUM7UUFDdkMseUJBQW9CLEdBQVksSUFBSSxDQUFDO1FBRXJDLGVBQVUsR0FBVyxZ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c0JBQWxCLEtBQUs7Z0JBQ0csY0FBYztzQkFBdEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csb0JBQW9CO3NCQUE1QixLQUFLO2dCQUNHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRywwQkFBMEI7c0JBQWxDLEtBQUs7Z0JBQ0csa0JBQWtCO3NCQUExQixLQUFLO2dCQUNHLDBCQUEwQjtzQkFBbEMsS0FBSztnQkFDRywwQkFBMEI7c0JBQWxDLEtBQUs7Z0JBQ0csOEJBQThCO3NCQUF0QyxLQUFLO2dCQUNHLDhCQUE4QjtzQkFBdEMsS0FBSztnQkFDRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBQ0csb0JBQW9CO3NCQUE1QixLQUFLO2dCQUNHLHVCQUF1QjtzQkFBL0IsS0FBSztnQkFDRyw0QkFBNEI7c0JBQXBDLEtBQUs7Z0JBR0csT0FBTztzQkFBZixLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFSSxzQkFBc0I7c0JBQS9CLE1BQU07Z0JBQ0csZUFBZTtzQkFBeEIsTUFBTTtnQkFZSCxtQkFBbUI7c0JBRHRCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogQCgjKW5nLWRhdGUtcGlja2VyLmNvbXBvbmVudC50cyBTZXB0IDA1LCAyMDIzXHJcbiAqXHJcbiAqIEBhdXRob3IgQWFrYXNoIEt1bWFyXHJcbiAqL1xyXG5pbXBvcnQge1xyXG4gIEFmdGVyVmlld0luaXQsXHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXHJcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXHJcbiAgQ29tcG9uZW50LFxyXG4gIGNvbXB1dGVkLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIGluamVjdCxcclxuICBJbnB1dCxcclxuICBPbkluaXQsXHJcbiAgT3V0cHV0LFxyXG4gIFNpZ25hbCxcclxuICBzaWduYWwsXHJcbiAgV3JpdGFibGVTaWduYWwsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IERhdGVSYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2RhdGVwaWNrZXInO1xyXG5pbXBvcnQgeyBTZWxlY3RlZERhdGVFdmVudCB9IGZyb20gJy4uL3B1YmxpYy1hcGknO1xyXG5pbXBvcnQgeyBEQVRFX09QVElPTl9UWVBFIH0gZnJvbSAnLi9jb25zdGFudC9kYXRlLWZpbHRlci1jb25zdCc7XHJcbmltcG9ydCB7IERFRkFVTFRfREFURV9PUFRJT05TIH0gZnJvbSAnLi9kYXRhL2RlZmF1bHQtZGF0ZS1vcHRpb25zJztcclxuaW1wb3J0IHsgSVNlbGVjdERhdGVPcHRpb24gfSBmcm9tICcuL21vZGVsL3NlbGVjdC1kYXRlLW9wdGlvbi5tb2RlbCc7XHJcbmltcG9ydCB7XHJcbiAgZ2V0Q2xvbmUsXHJcbiAgZ2V0RGF0ZVN0cmluZyxcclxuICBnZXREYXRlV2l0aE9mZnNldCxcclxuICBnZXREYXlzSW5Nb250aCxcclxuICBnZXRGb3JtYXR0ZWREYXRlU3RyaW5nLFxyXG4gIHJlc2V0T3B0aW9uU2VsZWN0aW9uLFxyXG4gIHNlbGVjdEN1c3RvbU9wdGlvbixcclxufSBmcm9tICcuL3V0aWxzL2RhdGUtcGlja2VyLXV0aWxpdGllcyc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25nLWRhdGUtcmFuZ2UtcGlja2VyJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vbmctZGF0ZS1waWNrZXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL25nLWRhdGUtcGlja2VyLmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOZ0RhdGVQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQge1xyXG4gIHB1YmxpYyBpc0RhdGVPcHRpb25MaXN0OiBib29sZWFuID0gZmFsc2U7XHJcbiAgcHVibGljIGlzQ3VzdG9tUmFuZ2U6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBpbnB1dExhYmVsOiBzdHJpbmcgPSAnRGF0ZSBSYW5nZSc7XHJcbiAgQElucHV0KCkgc3RhdGljT3B0aW9uSWQgPSAnc3RhdGljLW9wdGlvbnMnO1xyXG4gIEBJbnB1dCgpIGR5bmFtaWNPcHRpb25JZCA9ICdkeW5hbWljLW9wdGlvbnMnO1xyXG4gIEBJbnB1dCgpIGNhbGVuZGFySWQ6IHN0cmluZyA9ICdjdXN0b20tY2FsZW5kYXInO1xyXG4gIEBJbnB1dCgpIGVuYWJsZURlZmF1bHRPcHRpb25zOiBib29sZWFuID0gdHJ1ZTtcclxuICBASW5wdXQoKSBzZWxlY3RlZERhdGVzITogRGF0ZVJhbmdlPERhdGU+IHwgbnVsbDtcclxuICBASW5wdXQoKSBkYXRlRm9ybWF0OiBzdHJpbmcgPSAnZGQvTU0veXl5eSc7XHJcbiAgQElucHV0KCkgaXNTaG93U3RhdGljRGVmYXVsdE9wdGlvbnM6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBoaWRlRGVmYXVsdE9wdGlvbnM6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBASW5wdXQoKSBjZGtDb25uZWN0ZWRPdmVybGF5T2Zmc2V0WCA9IDA7XHJcbiAgQElucHV0KCkgY2RrQ29ubmVjdGVkT3ZlcmxheU9mZnNldFkgPSAwO1xyXG4gIEBJbnB1dCgpIGxpc3RDZGtDb25uZWN0ZWRPdmVybGF5T2Zmc2V0WSA9IDA7XHJcbiAgQElucHV0KCkgbGlzdENka0Nvbm5lY3RlZE92ZXJsYXlPZmZzZXRYID0gMDtcclxuICBASW5wdXQoKSBzZWxlY3RlZE9wdGlvbkluZGV4ID0gMztcclxuICBASW5wdXQoKSBkaXNwbGF5U2VsZWN0ZWRMYWJlbCA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIGNka0Nvbm5lY3RlZE92ZXJsYXlQdXNoID0gdHJ1ZTtcclxuICBASW5wdXQoKSBjZGtDb25uZWN0ZWRPdmVybGF5UG9zaXRpb25zID0gW107XHJcblxyXG4gIC8vIGRlZmF1bHQgbWluIGRhdGUgaXMgY3VycmVudCBkYXRlIC0gMTAgeWVhcnMuXHJcbiAgQElucHV0KCkgbWluRGF0ZSA9IGdldERhdGVXaXRoT2Zmc2V0KC0xMCk7XHJcbiAgLy8gZGVmYXVsdCBtYXggZGF0ZSBpcyBjdXJyZW50IGRhdGUgKyAxMCB5ZWFycy5cclxuICBASW5wdXQoKSBtYXhEYXRlID0gZ2V0RGF0ZVdpdGhPZmZzZXQoMTApO1xyXG5cclxuICBAT3V0cHV0KCkgb25EYXRlU2VsZWN0aW9uQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8U2VsZWN0ZWREYXRlRXZlbnQ+KCk7XHJcbiAgQE91dHB1dCgpIGRhdGVMaXN0T3B0aW9ucyA9IG5ldyBFdmVudEVtaXR0ZXI8SVNlbGVjdERhdGVPcHRpb25bXT4oKTtcclxuXHJcbiAgcHJpdmF0ZSBjZHJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xyXG4gIHByaXZhdGUgZWw6IEVsZW1lbnRSZWYgPSBpbmplY3QoRWxlbWVudFJlZik7XHJcblxyXG4gIHByaXZhdGUgX2RhdGVPcHRpb25zOiBXcml0YWJsZVNpZ25hbDxJU2VsZWN0RGF0ZU9wdGlvbltdPiA9IHNpZ25hbChbXSk7XHJcbiAgdmlzaWJsZU9wdGlvbnMgPSBjb21wdXRlZCgoKSA9PlxyXG4gICAgdGhpcy5fZGF0ZU9wdGlvbnMoKS5maWx0ZXIoKG9wKSA9PiBvcC5pc1Zpc2libGUpXHJcbiAgKTtcclxuICBjb25zdHJ1Y3RvcigpIHt9XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgc2V0IGRhdGVEcm9wRG93bk9wdGlvbnMoZGVmYXVsdERhdGVMaXN0OiBJU2VsZWN0RGF0ZU9wdGlvbltdKSB7XHJcbiAgICBjb25zdCBvcHRpb25zID0gW1xyXG4gICAgICAuLi4odGhpcy5lbmFibGVEZWZhdWx0T3B0aW9ucyA/IGdldENsb25lKERFRkFVTFRfREFURV9PUFRJT05TKSA6IFtdKSxcclxuICAgICAgLi4uKGRlZmF1bHREYXRlTGlzdCA/PyBbXSksXHJcbiAgICBdO1xyXG4gICAgdGhpcy5fZGF0ZU9wdGlvbnMuc2V0KG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGRhdGVEcm9wRG93bk9wdGlvbnMoKTogSVNlbGVjdERhdGVPcHRpb25bXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fZGF0ZU9wdGlvbnMoKSA/PyBbXTtcclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuaXNEZWZhdWx0SW5pdFJlcXVpcmVkKCkpIHtcclxuICAgICAgdGhpcy5pbml0RGVmYXVsdE9wdGlvbnMoKTtcclxuICAgIH1cclxuICAgIHRoaXMuZGF0ZUxpc3RPcHRpb25zLmVtaXQodGhpcy5kYXRlRHJvcERvd25PcHRpb25zKTtcclxuICB9XHJcblxyXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcclxuICAgIHRoaXMudXBkYXRlRGVmYXVsdERhdGVzVmFsdWVzKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUb2dnbGVzIHRoZSB2aXNpYmlsaXR5IG9mIHRoZSBkZWZhdWx0IGRhdGUgb3B0aW9uIGxpc3QuXHJcbiAgICogSWYgdGhlIGN1c3RvbSBvcHRpb24gaXMgc2VsZWN0ZWQsIHRvZ2dsZXMgdGhlIGN1c3RvbSBkYXRlIHJhbmdlIHZpZXcgaW5zdGVhZC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBldmVudCBPcHRpb25hbCBNb3VzZUV2ZW50IHRyaWdnZXJpbmcgdGhlIHRvZ2dsZS5cclxuICAgKi9cclxuICB0b2dnbGVEYXRlT3B0aW9uU2VsZWN0aW9uTGlzdChldmVudD86IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50Py5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgZXZlbnQ/LnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xyXG4gICAgY29uc3QgaXNDdXN0b21TZWxlY3RlZCA9XHJcbiAgICAgIHRoaXMuZGF0ZURyb3BEb3duT3B0aW9ucy5maW5kKChvcHRpb24pID0+IG9wdGlvbi5pc1NlbGVjdGVkKVxyXG4gICAgICAgID8ub3B0aW9uVHlwZSA9PT0gREFURV9PUFRJT05fVFlQRS5DVVNUT007XHJcblxyXG4gICAgaWYgKGlzQ3VzdG9tU2VsZWN0ZWQpIHtcclxuICAgICAgdGhpcy50b2dnbGVDdXN0b21EYXRlUmFuZ2VWaWV3KCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHRoaXMuaXNEYXRlT3B0aW9uTGlzdCA9ICF0aGlzLmlzRGF0ZU9wdGlvbkxpc3Q7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBVcGRhdGVzIHRoZSBjdXN0b20gZGF0ZSByYW5nZSBzZWxlY3Rpb24gZnJvbSB0aGUgaW5wdXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0gaW5wdXQgVGhlIEhUTUwgaW5wdXQgZWxlbWVudCBhc3NvY2lhdGVkIHdpdGggdGhlIGRhdGUgcGlja2VyLlxyXG4gICAqIEBwYXJhbSBzZWxlY3RlZERhdGVzIFRoZSBzZWxlY3RlZCBkYXRlIHJhbmdlLlxyXG4gICAqL1xyXG4gIHVwZGF0ZUN1c3RvbVJhbmdlKFxyXG4gICAgaW5wdXQ6IEhUTUxJbnB1dEVsZW1lbnQsXHJcbiAgICBzZWxlY3RlZERhdGVzOiBEYXRlUmFuZ2U8RGF0ZT4gfCBudWxsXHJcbiAgKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMuaXNDdXN0b21SYW5nZSkge1xyXG4gICAgICByZXNldE9wdGlvblNlbGVjdGlvbih0aGlzLmRhdGVEcm9wRG93bk9wdGlvbnMpO1xyXG4gICAgICBzZWxlY3RDdXN0b21PcHRpb24odGhpcy5kYXRlRHJvcERvd25PcHRpb25zKTtcclxuICAgICAgdGhpcy5pc0N1c3RvbVJhbmdlID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3Qgc3RhcnQgPSBzZWxlY3RlZERhdGVzPy5zdGFydCA/PyBuZXcgRGF0ZSgpO1xyXG4gICAgY29uc3QgZW5kID0gc2VsZWN0ZWREYXRlcz8uZW5kID8/IG5ldyBEYXRlKCk7XHJcbiAgICB0aGlzLnVwZGF0ZVNlbGVjdGVkRGF0ZXMoaW5wdXQsIHN0YXJ0LCBlbmQsIG51bGwpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVXBkYXRlcyB0aGUgc2VsZWN0aW9uIHdoZW4gYSBzcGVjaWZpYyBkYXRlIG9wdGlvbiBpcyBjbGlja2VkLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIG9wdGlvbiBUaGUgc2VsZWN0ZWQgZGF0ZSBvcHRpb24uXHJcbiAgICogQHBhcmFtIGlucHV0IFRoZSBIVE1MIGlucHV0IGVsZW1lbnQgdG8gdXBkYXRlIHdpdGggc2VsZWN0ZWQgZGF0ZXMuXHJcbiAgICovXHJcbiAgdXBkYXRlU2VsZWN0aW9uKG9wdGlvbjogSVNlbGVjdERhdGVPcHRpb24sIGlucHV0OiBIVE1MSW5wdXRFbGVtZW50KTogdm9pZCB7XHJcbiAgICB0aGlzLmlzRGF0ZU9wdGlvbkxpc3QgPSBmYWxzZTtcclxuICAgIHRoaXMuaXNDdXN0b21SYW5nZSA9IG9wdGlvbi5vcHRpb25UeXBlID09PSBEQVRFX09QVElPTl9UWVBFLkNVU1RPTTtcclxuICAgIGlmICghdGhpcy5pc0N1c3RvbVJhbmdlKSB7XHJcbiAgICAgIHJlc2V0T3B0aW9uU2VsZWN0aW9uKHRoaXMuZGF0ZURyb3BEb3duT3B0aW9ucywgb3B0aW9uKTtcclxuICAgICAgdGhpcy51cGRhdGVEYXRlT25PcHRpb25TZWxlY3Qob3B0aW9uLCBpbnB1dCk7XHJcbiAgICB9XHJcbiAgICB0aGlzLmNkcmVmLm1hcmtGb3JDaGVjaygpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVG9nZ2xlcyB0aGUgY3VzdG9tIGRhdGUgcmFuZ2Ugc2VsZWN0aW9uIHZpZXcgdmlzaWJpbGl0eS5cclxuICAgKi9cclxuICB0b2dnbGVDdXN0b21EYXRlUmFuZ2VWaWV3KCk6IHZvaWQge1xyXG4gICAgdGhpcy5pc0N1c3RvbVJhbmdlID0gIXRoaXMuaXNDdXN0b21SYW5nZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENsZWFycyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGRhdGVzIGFuZCByZXNldHMgYWxsIHJlbGF0ZWQgcHJvcGVydGllcy5cclxuICAgKlxyXG4gICAqIEBwYXJhbSBldmVudCBUaGUgTW91c2VFdmVudCB0cml