UNPKG

@hxui/angular

Version:

This README includes the steps that are necessary to import the HxUi-angular into a project or to contribute with development.

1,473 lines (1,456 loc) 642 kB
import { Injectable, ElementRef, Directive, HostListener, NgModule, Component, EventEmitter, Output, Input, forwardRef, TemplateRef, ReflectiveInjector, NgZone, ComponentFactoryResolver, Injector, Renderer2, ViewContainerRef, HostBinding, Optional, Inject, ViewChild, IterableDiffers, ViewEncapsulation, Pipe, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule, NgControl } from '@angular/forms'; import { CommonModule, DOCUMENT } from '@angular/common'; import { filter, takeUntil, take, debounceTime, mergeMap, toArray } from 'rxjs/operators'; import { __decorate } from 'tslib'; import { FocusTrapFactory, A11yModule } from '@angular/cdk/a11y'; import { cloneDeep, isEqual } from 'lodash'; import sortBy from 'array-sort-by'; import { Subject, Observable, from } from 'rxjs'; import { ComponentPortal, PortalModule } from '@angular/cdk/portal'; import { Overlay, ScrollDispatcher, OverlayModule } from '@angular/cdk/overlay'; import { Directionality } from '@angular/cdk/bidi'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @copyright Valor Software * @copyright Angular ng-bootstrap team */ class Positioning { /** * @param {?} element * @param {?=} round * @return {?} */ position(element, round = true) { let /** @type {?} */ elPosition; let /** @type {?} */ parentOffset = { width: 0, height: 0, top: 0, bottom: 0, left: 0, right: 0 }; if (this.getStyle(element, 'position') === 'fixed') { elPosition = element.getBoundingClientRect(); } else { const /** @type {?} */ offsetParentEl = this.offsetParent(element); elPosition = this.offset(element, false); if (offsetParentEl !== document.documentElement) { parentOffset = this.offset(offsetParentEl, false); } parentOffset.top += offsetParentEl.clientTop; parentOffset.left += offsetParentEl.clientLeft; } elPosition.top -= parentOffset.top; elPosition.bottom -= parentOffset.top; elPosition.left -= parentOffset.left; elPosition.right -= parentOffset.left; if (round) { elPosition.top = Math.round(elPosition.top); elPosition.bottom = Math.round(elPosition.bottom); elPosition.left = Math.round(elPosition.left); elPosition.right = Math.round(elPosition.right); } return elPosition; } /** * @param {?} element * @param {?=} round * @return {?} */ offset(element, round = true) { const /** @type {?} */ elBcr = element.getBoundingClientRect(); const /** @type {?} */ viewportOffset = { top: window.pageYOffset - document.documentElement.clientTop, left: window.pageXOffset - document.documentElement.clientLeft }; let /** @type {?} */ elOffset = { height: elBcr.height || element.offsetHeight, width: elBcr.width || element.offsetWidth, top: elBcr.top + viewportOffset.top, bottom: elBcr.bottom + viewportOffset.top, left: elBcr.left + viewportOffset.left, right: elBcr.right + viewportOffset.left }; if (round) { elOffset.height = Math.round(elOffset.height); elOffset.width = Math.round(elOffset.width); elOffset.top = Math.round(elOffset.top); elOffset.bottom = Math.round(elOffset.bottom); elOffset.left = Math.round(elOffset.left); elOffset.right = Math.round(elOffset.right); } return elOffset; } /** * @param {?} hostElement * @param {?} targetElement * @param {?} placement * @param {?=} appendToBody * @return {?} */ positionElements(hostElement, targetElement, placement, appendToBody) { const /** @type {?} */ hostElPosition = appendToBody ? this.offset(hostElement, false) : this.position(hostElement, false); const /** @type {?} */ shiftWidth = { left: hostElPosition.left, center: hostElPosition.left + hostElPosition.width / 2 - targetElement.offsetWidth / 2, right: hostElPosition.left + hostElPosition.width }; const /** @type {?} */ shiftHeight = { top: hostElPosition.top, center: hostElPosition.top + hostElPosition.height / 2 - targetElement.offsetHeight / 2, bottom: hostElPosition.top + hostElPosition.height }; const /** @type {?} */ targetElBCR = targetElement.getBoundingClientRect(); const /** @type {?} */ placementPrimary = placement.split(' ')[0] || 'top'; const /** @type {?} */ placementSecondary = placement.split(' ')[1] || 'center'; let /** @type {?} */ targetElPosition = { height: targetElBCR.height || targetElement.offsetHeight, width: targetElBCR.width || targetElement.offsetWidth, top: 0, bottom: targetElBCR.height || targetElement.offsetHeight, left: 0, right: targetElBCR.width || targetElement.offsetWidth }; switch (placementPrimary) { case 'top': targetElPosition.top = hostElPosition.top - targetElement.offsetHeight; targetElPosition.bottom += hostElPosition.top - targetElement.offsetHeight; targetElPosition.left = shiftWidth[placementSecondary]; targetElPosition.right += shiftWidth[placementSecondary]; break; case 'bottom': targetElPosition.top = shiftHeight[placementPrimary]; targetElPosition.bottom += shiftHeight[placementPrimary]; targetElPosition.left = shiftWidth[placementSecondary]; targetElPosition.right += shiftWidth[placementSecondary]; break; case 'left': targetElPosition.top = shiftHeight[placementSecondary]; targetElPosition.bottom += shiftHeight[placementSecondary]; targetElPosition.left = hostElPosition.left - targetElement.offsetWidth; targetElPosition.right += hostElPosition.left - targetElement.offsetWidth; break; case 'right': targetElPosition.top = shiftHeight[placementSecondary]; targetElPosition.bottom += shiftHeight[placementSecondary]; targetElPosition.left = shiftWidth[placementPrimary]; targetElPosition.right += shiftWidth[placementPrimary]; break; } targetElPosition.top = Math.round(targetElPosition.top); targetElPosition.bottom = Math.round(targetElPosition.bottom); targetElPosition.left = Math.round(targetElPosition.left); targetElPosition.right = Math.round(targetElPosition.right); return targetElPosition; } /** * @param {?} element * @param {?} prop * @return {?} */ getStyle(element, prop) { return (/** @type {?} */ (window.getComputedStyle(element)))[prop]; } /** * @param {?} element * @return {?} */ isStaticPositioned(element) { return (this.getStyle(element, 'position') || 'static') === 'static'; } /** * @param {?} element * @return {?} */ offsetParent(element) { let /** @type {?} */ offsetParentEl = /** @type {?} */ (element.offsetParent) || document.documentElement; while (offsetParentEl && offsetParentEl !== document.documentElement && this.isStaticPositioned(offsetParentEl)) { offsetParentEl = /** @type {?} */ (offsetParentEl.offsetParent); } return offsetParentEl || document.documentElement; } } const /** @type {?} */ positionService = new Positioning(); /** * @param {?} hostElement * @param {?} targetElement * @param {?} placement * @param {?=} appendToBody * @return {?} */ function positionElements(hostElement, targetElement, placement, appendToBody) { const /** @type {?} */ pos = positionService.positionElements(hostElement, targetElement, placement, appendToBody); targetElement.style.top = `${pos.top}px`; targetElement.style.left = `${pos.left}px`; } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class PositioningService { /** * @param {?} options * @return {?} */ position(options) { const { element, target, attachment, appendToBody } = options; positionElements(this._getHtmlElement(target), this._getHtmlElement(element), /** @type {?} */ (attachment), appendToBody); } /** * @param {?} element * @return {?} */ isElementBelowTheFold(element) { const /** @type {?} */ rect = element.getBoundingClientRect(); return ((rect.top + rect.height) > document.body.clientHeight); } /** * @param {?} element * @return {?} */ _getHtmlElement(element) { // it means that we got a selector if (typeof element === 'string') { return /** @type {?} */ (document.querySelector(element)); } if (element instanceof ElementRef) { return element.nativeElement; } return /** @type {?} */ (element); } } PositioningService.decorators = [ { type: Injectable }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @abstract */ class PositioningOptions { } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class AutoGrowDirective { /** * @param {?} element */ constructor(element) { this.element = element; } /** * @return {?} */ onInput() { this.resize(); } /** * @return {?} */ ngAfterViewInit() { const /** @type {?} */ style = this.element.nativeElement.style; style.overflow = 'hidden'; style.height = 'auto'; } /** * @return {?} */ resize() { const /** @type {?} */ el = this.element.nativeElement; if (el.style.height === el.scrollHeight + 'px') { return; } el.style.overflow = 'hidden'; el.style.height = 'auto'; el.style.height = `${el.scrollHeight}px`; } } AutoGrowDirective.decorators = [ { type: Directive, args: [{ selector: 'textarea[autogrow]' },] }, ]; /** @nocollapse */ AutoGrowDirective.ctorParameters = () => [ { type: ElementRef, }, ]; AutoGrowDirective.propDecorators = { "onInput": [{ type: HostListener, args: ['input', ['$event.target'],] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class AutoGrowModule { /** * @return {?} */ static forRoot() { return { ngModule: AutoGrowModule, providers: [] }; } ; } AutoGrowModule.decorators = [ { type: NgModule, args: [{ declarations: [ AutoGrowDirective ], exports: [ AutoGrowDirective ] },] }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DatepickerComponent { /** * @param {?} hostElement * @param {?} positioningService */ constructor(hostElement, positioningService) { this.hostElement = hostElement; this.positioningService = positioningService; this.onDateSelected = new EventEmitter(); this.days = new Array(); this.week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; this.cellCount = 41; } /** * @return {?} */ renderCalendar() { for (let /** @type {?} */ i = 0; i <= this.cellCount; i++) { // date will be set to the first day of the month set in this.viewDate const /** @type {?} */ date = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth()); // Shifts the week to start from Monday, rather than Sunday, this causes the index to start at 1 const /** @type {?} */ dayOffset = date.getDay() === 0 ? 7 : date.getDay(); this.days[i] = new Date(date.setDate(2 - dayOffset + i)); } } /** * @return {?} */ positionCalendar() { const /** @type {?} */ rect = this.hostElement.nativeElement.getBoundingClientRect(); const /** @type {?} */ buffer = 10; if (this.positioningService.isElementBelowTheFold(this.hostElement.nativeElement)) { this.hostElement.nativeElement.style.top = (rect.top - (rect.top + rect.height + buffer)) + 'px'; } } /** * @return {?} */ previousMonth() { this.viewDate = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth() - 1); this.renderCalendar(); } /** * @return {?} */ nextMonth() { this.viewDate = new Date(this.viewDate.getFullYear(), this.viewDate.getMonth() + 1); this.renderCalendar(); } /** * @param {?} inputDate * @return {?} */ isCurrentMonth(inputDate) { return inputDate.getMonth() === this.viewDate.getMonth(); } /** * @param {?} inputDate * @return {?} */ isCurrentDay(inputDate) { return inputDate.getTime() === this.presentDate.getTime(); } /** * @param {?} inputDate * @return {?} */ isSelectedDay(inputDate) { if (this.selectedDate) { return inputDate.getTime() === this.selectedDate.getTime(); } return false; } /** * @param {?} inputDate * @return {?} */ isInvalidDay(inputDate) { return this.validators.map((fn) => fn(inputDate)).reduce((prev, next) => prev || next, false); } /** * @param {?} date * @return {?} */ setSelectedDate(date) { if (!this.isInvalidDay(date)) { this.selectedDate = date; this.onDateSelected.emit(date); } } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (!!changes["selectedDate"].currentValue) { this.viewDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth()); } } /** * @return {?} */ ngOnInit() { const /** @type {?} */ date = new Date(); this.presentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); this.viewDate = this.viewDate || new Date(date.getFullYear(), date.getMonth()); this.renderCalendar(); this.positionCalendar(); } } DatepickerComponent.decorators = [ { type: Component, args: [{ selector: 'hxa-datepicker', template: `<div class="hxui-reset"> <div class="hx-card hxa-datepicker-container"> <div class="hx-card-header hxa-datepicker-header"> <div class="hxa-datepicker-month"> <div class="hxa-datepicker-icon" title="Previous Month" (click)="previousMonth()"> <a class="hx-button is-transparent"><i class="hx-icon icon-angle-left"></i></a> </div> <div class="hxa-datepicker-month-title"> <span>{{viewDate.toLocaleString("en-au", { month: "long", year: "numeric" })}}</span></div> <div class="hxa-datepicker-icon" title="Next Month" (click)="nextMonth()"> <a class="hx-button is-transparent"><i class="hx-icon icon-angle-right"></i></a> </div> </div> <div class="hxa-datepicker-week"> <div class="hxa-datepicker-weekday" *ngFor="let weekday of week"> {{weekday | slice:0:3}} </div> </div> </div> <div class="hxa-datepicker-contents"> <div class="hxa-datepicker-day" *ngFor="let day of days" [ngClass]="{'hxa-datepicker-day-siblingmonth': !isCurrentMonth(day), 'hxa-datepicker-day-currentday': isCurrentDay(day), 'hxa-datepicker-day-selectedday': isSelectedDay(day), 'hxa-datepicker-day-invalidday': isInvalidDay(day)}" (click)="setSelectedDate(day)"> <a class="hx-button is-transparent">{{day.getDate()}}</a> </div> </div> </div> </div>`, styles: [`.hxa-datepicker-container{max-width:21em;width:21em;height:24em;display:flex;flex-direction:column;font-size:1rem}.hxa-datepicker-header{padding:1rem 1rem 0;flex-direction:column;align-items:initial;justify-content:space-around;font-weight:100}.hxa-datepicker-icon{cursor:pointer;display:flex;flex:1;flex-direction:column;justify-content:center;align-items:center}.hxa-datepicker-icon .hx-button{position:initial!important;top:initial!important}.hxa-datepicker-icon .hx-button.is-transparent:hover{color:#000}.hxa-datepicker-icon .hx-icon{font-size:2.3em;position:initial!important;top:initial!important;color:#0d4d78}.hxa-datepicker-month{display:flex;text-align:center;margin-bottom:1rem}.hxa-datepicker-month-title{font-size:1.5em;flex:3;display:flex;justify-content:center;align-items:center;color:#0d4d78}.hxa-datepicker-week{display:flex;width:100%;text-align:center}.hxa-datepicker-weekday{flex:1;color:#0d4d78}.hxa-datepicker-contents{padding:1rem;background-color:rgba(246,246,249,.5);display:flex;flex-flow:row wrap;flex:1;justify-content:space-around;align-content:space-around}.hxa-datepicker-day{flex:1 1 14%;height:16.666%;display:flex;justify-content:center;align-items:center}.hxa-datepicker-day .hx-button{position:initial;top:initial;flex:1;font-weight:400;height:100%;padding:0;color:#41b987}.hxa-datepicker-day-siblingmonth .hx-button{color:#3b3b3b;font-weight:100}.hxa-datepicker-day-selectedday .hx-button{color:#fff;background:#41b987}.hxa-datepicker-day-invalidday .hx-button{color:#e0e0e1!important;pointer-events:none}.hxa-datepicker-day-currentday .hx-button{border:2px solid #41b987}`] },] }, ]; /** @nocollapse */ DatepickerComponent.ctorParameters = () => [ { type: ElementRef, }, { type: PositioningService, }, ]; DatepickerComponent.propDecorators = { "selectedDate": [{ type: Input },], "validators": [{ type: Input },], "onDateSelected": [{ type: Output },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DatepickerFormComponent { /** * @param {?} element */ constructor(element) { this.element = element; this.disabled = false; this.readonly = false; this.required = false; this.defaultToPresentDate = true; this.allowPreviousDates = true; this.allowFutureDates = true; this.dateFormat = "dd/MM/y"; this.placeholder = "Date"; this.align = "bottom"; this.from = ''; this.to = ''; this.onDateChange = new EventEmitter(); this.visible = false; this.dateValidators = new Array(); this.onChanged = new Array(); this.onTouched = new Array(); } /** * @return {?} */ ngOnInit() { const /** @type {?} */ date = new Date(); this.presentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); if (this.defaultToPresentDate) { setTimeout(() => { this.setDate(this.presentDate); }); } // Close to the minimum and maxium possible dates, but still normalisable // http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1 const /** @type {?} */ from$$1 = this.parseDate(this.from) || new Date(-8630000000000000); const /** @type {?} */ to = this.parseDate(this.to) || new Date(8630000000000000); if (!!this.from || !!this.to) { this.validateDateRange = this.createDateRangeValidator(from$$1, to); this.dateValidators.push(this.validateDateRange.bind(this)); } if (!this.allowPreviousDates) this.dateValidators.push(this.validateIsNotBeforeDate.bind(this)); if (!this.allowFutureDates) this.dateValidators.push(this.validateIsNotAfterDate.bind(this)); } /** * @param {?} date * @return {?} */ setDate(date) { this.date = date; this.onDateChange.emit(date); this.propogateChange(date); } /** * @return {?} */ setVisible() { this.visible = true; } /** * @return {?} */ unsetVisible() { this.visible = false; } /** * @param {?} targetElement * @return {?} */ onClickOutsideComponent(targetElement) { if (!this.element.nativeElement.firstChild.contains(targetElement)) { this.unsetVisible(); } } /** * @param {?} inputDate * @return {?} */ onDateSelectEvent(inputDate) { this.unsetVisible(); this.setDate(inputDate); } /** * @param {?} inputDate * @return {?} */ onChange(inputDate) { const /** @type {?} */ date = this.parseDate(inputDate); if (inputDate == "") { this.setDate(null); } else if (!!date) { this.setDate(date); } else { this.propogateChange(inputDate); } } /** * @return {?} */ onFocus() { this.setVisible(); this.propogateTouched(); } /** * @param {?} inputDate * @return {?} */ onTab(inputDate) { this.onChange(inputDate); this.unsetVisible(); this.propogateTouched(); } /** * @param {?} inputDate * @return {?} */ parseDate(inputDate) { // Since Date.Parse() only acceps m/d/y dates, we have to swap the day and month let /** @type {?} */ dateArray = inputDate.split(/[.,\/ -]/); if (dateArray.length == 3 && dateArray[2].length != 0) { let /** @type {?} */ day = dateArray.shift(); dateArray.splice(1, 0, day); let /** @type {?} */ parseInput = Date.parse(dateArray.join("/")); if (!isNaN(parseInput)) { return new Date(parseInput); } } return null; } /** * @param {?} date * @return {?} */ validateIsNotBeforeDate(date) { const /** @type {?} */ normalisedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); return normalisedDate.getTime() < this.presentDate.getTime(); } /** * @param {?} date * @return {?} */ validateIsNotAfterDate(date) { const /** @type {?} */ normalisedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); return normalisedDate.getTime() > this.presentDate.getTime(); } /** * @param {?} from * @param {?} to * @return {?} */ createDateRangeValidator(from$$1, to) { const /** @type {?} */ normalisedFromDate = new Date(from$$1.getFullYear(), from$$1.getMonth(), from$$1.getDate()); const /** @type {?} */ normalisedToDate = new Date(to.getFullYear(), to.getMonth(), to.getDate()); return (date) => { const /** @type {?} */ normalisedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); return !(normalisedFromDate.getTime() <= normalisedDate.getTime() && normalisedDate.getTime() <= normalisedToDate.getTime()); }; } /** * @param {?} value * @return {?} */ writeValue(value) { this.setDate(value); } /** * @param {?} fn * @return {?} */ registerOnChange(fn) { this.onChanged.push(fn); } /** * @param {?} fn * @return {?} */ registerOnTouched(fn) { this.onTouched.push(fn); } /** * @return {?} */ propogateTouched() { this.onTouched.forEach(fn => fn()); } /** * @param {?} value * @return {?} */ propogateChange(value) { this.onChanged.forEach(fn => fn(value)); } /** * @param {?} control * @return {?} */ validate(control) { const /** @type {?} */ date = Date.parse(control.value); if (!this.required && (control.value === null || control.value === undefined)) { this.isValid = true; return null; } if (isNaN(date)) { this.isValid = false; return { dateParseError: { valid: false } }; } if (!this.allowPreviousDates && this.validateIsNotBeforeDate(this.date)) { this.isValid = false; return { previousDateError: { valid: false } }; } if (!this.allowFutureDates && this.validateIsNotAfterDate(this.date)) { this.isValid = false; return { futureDateError: { valid: false } }; } if (this.validateDateRange && this.validateDateRange(this.date)) { this.isValid = false; return { dateRangeError: { valid: false } }; } if (this.required && !this.date) { this.isValid = false; return { dateRequiredError: { valid: false } }; } this.isValid = true; return null; } } DatepickerFormComponent.decorators = [ { type: Component, args: [{ selector: 'hxa-datepicker-input, hxa-datepicker-form', template: `<div class="hx-input-group hxa-datepicker-form"> <div class="hx-input-control" [ngClass]="{'is-danger': !isValid && datePickerForm.touched}"> <input class="hx-input" type="text" #datePickerForm="ngModel" [required]="required ? true : null" [disabled]="disabled" [readonly]="readonly ? true : null" [ngModel]="date | date:dateFormat" (change)="onChange(datePickerForm.value)" (focus)="onFocus()" (keydown.Tab)="onTab(datePickerForm.value)"> <label class="hx-label" *ngIf="placeholder">{{placeholder}} <sup *ngIf="required">*</sup></label> <div class="hx-help"></div> <div class="hxa-datepicker-help">Please select a date</div> </div> <i class="hx-icon icon-calendar"></i> <hxa-datepicker class="hxa-datepicker-calendar" *ngIf="visible" [selectedDate]="date" [validators]="dateValidators" (onDateSelected)="onDateSelectEvent($event)" [ngClass]="{'hxa-datepicker-calendar-top': align == 'top', 'hxa-datepicker-calendar-bottom': align == 'bottom'}"></hxa-datepicker> </div> `, styles: [`.hxa-datepicker-form{position:relative;max-width:21rem}.hxa-datepicker-calendar{position:absolute;z-index:99;left:0}.hxa-datepicker-calendar-top{bottom:100%}.hxa-datepicker-calendar-bottom{top:70%}.hxa-datepicker-help{font-size:.75rem;margin-top:.25rem;color:#63605f}.hxa-datepicker-form input[readonly]~.hx-label{top:-.5rem;font-size:.75rem;color:#41b987}`], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DatepickerFormComponent), multi: true }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => DatepickerFormComponent), multi: true, }] },] }, ]; /** @nocollapse */ DatepickerFormComponent.ctorParameters = () => [ { type: ElementRef, }, ]; DatepickerFormComponent.propDecorators = { "disabled": [{ type: Input },], "readonly": [{ type: Input },], "required": [{ type: Input },], "defaultToPresentDate": [{ type: Input },], "allowPreviousDates": [{ type: Input },], "allowFutureDates": [{ type: Input },], "dateFormat": [{ type: Input },], "placeholder": [{ type: Input },], "align": [{ type: Input },], "from": [{ type: Input },], "to": [{ type: Input },], "onDateChange": [{ type: Output },], "onClickOutsideComponent": [{ type: HostListener, args: ['document:click', ['$event.target'],] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DatepickerModule { /** * @return {?} */ static forRoot() { return { ngModule: DatepickerModule, providers: [] }; } } DatepickerModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule, FormsModule], declarations: [DatepickerComponent, DatepickerFormComponent], exports: [DatepickerComponent, DatepickerFormComponent] },] }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * Default dropdown configuration */ class DropdownConfig { constructor() { /** * default dropdown auto closing behavior */ this.autoClose = true; } } DropdownConfig.decorators = [ { type: Injectable }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ContentRef { /** * @param {?} nodes * @param {?=} viewRef * @param {?=} componentRef */ constructor(nodes, viewRef, componentRef) { this.nodes = nodes; this.viewRef = viewRef; this.componentRef = componentRef; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @copyright Valor Software * @copyright Angular ng-bootstrap team */ class Trigger { /** * @param {?} open * @param {?=} close */ constructor(open, close) { this.open = open; this.close = close || open; } /** * @return {?} */ isManual() { return this.open === 'manual' || this.close === 'manual'; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ const /** @type {?} */ DEFAULT_ALIASES = { hover: ['mouseenter', 'mouseleave'], focus: ['focusin', 'focusout'] }; /** * @param {?} triggers * @param {?=} aliases * @return {?} */ function parseTriggers(triggers, aliases = DEFAULT_ALIASES) { const /** @type {?} */ trimmedTriggers = (triggers || '').trim(); if (trimmedTriggers.length === 0) { return []; } const /** @type {?} */ parsedTriggers = trimmedTriggers.split(/\s+/) .map((trigger) => trigger.split(':')) .map((triggerPair) => { const /** @type {?} */ alias = aliases[triggerPair[0]] || triggerPair; return new Trigger(alias[0], alias[1]); }); const /** @type {?} */ manualTriggers = parsedTriggers .filter((triggerPair) => triggerPair.isManual()); if (manualTriggers.length > 1) { throw new Error('Triggers parse error: only one manual trigger is allowed'); } if (manualTriggers.length === 1 && parsedTriggers.length > 1) { throw new Error('Triggers parse error: manual trigger can\'t be mixed with other triggers'); } return parsedTriggers; } /** * @param {?} renderer * @param {?} target * @param {?} triggers * @param {?} showFn * @param {?} hideFn * @param {?} toggleFn * @return {?} */ function listenToTriggers(renderer, target, triggers, showFn, hideFn, toggleFn) { const /** @type {?} */ parsedTriggers = parseTriggers(triggers); const /** @type {?} */ listeners = []; if (parsedTriggers.length === 1 && parsedTriggers[0].isManual()) { return Function.prototype; } parsedTriggers.forEach((trigger) => { if (trigger.open === trigger.close) { listeners.push(renderer.listen(target, trigger.open, toggleFn)); return; } listeners.push(renderer.listen(target, /** @type {?} */ (trigger.open), showFn), renderer.listen(target, /** @type {?} */ (trigger.close), hideFn)); }); return () => { listeners.forEach((unsubscribeFn) => /** @type {?} */ (unsubscribeFn())); }; } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @template T */ class ComponentLoader { /** * Do not use this directly, it should be instanced via * `ComponentLoadFactory.attach` * \@internal * @param {?} _viewContainerRef * @param {?} _renderer * @param {?} _elementRef * @param {?} _injector * @param {?} _componentFactoryResolver * @param {?} _ngZone * @param {?} _posService */ constructor(_viewContainerRef, _renderer, _elementRef, _injector, _componentFactoryResolver, _ngZone, _posService) { this.onBeforeShow = new EventEmitter(); this.onShown = new EventEmitter(); this.onBeforeHide = new EventEmitter(); this.onHidden = new EventEmitter(); this._providers = []; this._ngZone = _ngZone; this._injector = _injector; this._renderer = _renderer; this._elementRef = _elementRef; this._posService = _posService; this._viewContainerRef = _viewContainerRef; this._componentFactoryResolver = _componentFactoryResolver; } /** * @return {?} */ get isShown() { return !!this._componentRef; } ; /** * @param {?} compType * @return {?} */ attach(compType) { this._componentFactory = this._componentFactoryResolver .resolveComponentFactory(compType); return this; } /** * @param {?=} container * @return {?} */ to(container) { this.container = container || this.container; return this; } /** * @param {?=} opts * @return {?} */ position(opts) { this.attachment = opts.attachment || this.attachment; this._elementRef = /** @type {?} */ (opts.target) || this._elementRef; return this; } /** * @param {?} provider * @return {?} */ provide(provider) { this._providers.push(provider); return this; } /** * @param {?=} opts * @return {?} */ show(opts = {}) { this._subscribePositioning(); if (!this._componentRef) { this.onBeforeShow.emit(); this._contentRef = this._getContentRef(opts.content); const /** @type {?} */ injector = ReflectiveInjector.resolveAndCreate(this._providers, this._injector); this._componentRef = this._viewContainerRef .createComponent(this._componentFactory, 0, injector, this._contentRef.nodes); this.instance = this._componentRef.instance; Object.assign(this._componentRef.instance, opts); if (this.container === 'body' && typeof document !== 'undefined') { document.querySelector(/** @type {?} */ (this.container)) .appendChild(this._componentRef.location.nativeElement); } // we need to manually invoke change detection since events registered // via // Renderer::listen() are not picked up by change detection with the // OnPush strategy this._componentRef.changeDetectorRef.markForCheck(); this.onShown.emit(this._componentRef.instance); } return this._componentRef; } /** * @return {?} */ hide() { if (this._componentRef) { this.onBeforeHide.emit(this._componentRef.instance); this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._componentRef.hostView)); this._componentRef = null; if (this._contentRef.viewRef) { this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef)); this._contentRef = null; } this._componentRef = null; this.onHidden.emit(); } return this; } /** * @return {?} */ toggle() { if (this.isShown) { this.hide(); return; } this.show(); } /** * @return {?} */ dispose() { if (this.isShown) { this.hide(); } this._unsubscribePositioning(); if (this._unregisterListenersFn) { this._unregisterListenersFn(); } } /** * @param {?} listenOpts * @return {?} */ listen(listenOpts) { this.triggers = listenOpts.triggers || this.triggers; listenOpts.target = listenOpts.target || this._elementRef; listenOpts.show = listenOpts.show || (() => this.show()); listenOpts.hide = listenOpts.hide || (() => this.hide()); listenOpts.toggle = listenOpts.toggle || (() => this.isShown ? listenOpts.hide() : listenOpts.show()); this._unregisterListenersFn = listenToTriggers(this._renderer, listenOpts.target.nativeElement, this.triggers, listenOpts.show, listenOpts.hide, listenOpts.toggle); return this; } /** * @return {?} */ _subscribePositioning() { if (this._zoneSubscription || !this.attachment) { return; } this._zoneSubscription = this._ngZone .onStable.subscribe(() => { if (!this._componentRef) { return; } this._posService.position({ element: this._componentRef.location, target: this._elementRef, attachment: this.attachment, appendToBody: this.container === 'body' }); }); } /** * @return {?} */ _unsubscribePositioning() { if (!this._zoneSubscription) { return; } this._zoneSubscription.unsubscribe(); this._zoneSubscription = null; } /** * @param {?} content * @return {?} */ _getContentRef(content) { if (!content) { return new ContentRef([]); } if (content instanceof TemplateRef) { const /** @type {?} */ viewRef = this._viewContainerRef .createEmbeddedView(content); return new ContentRef([viewRef.rootNodes], viewRef); } return new ContentRef([[this._renderer.createText(`${content}`)]]); } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class ComponentLoaderFactory { /** * @param {?} componentFactoryResolver * @param {?} ngZone * @param {?} injector * @param {?} posService */ constructor(componentFactoryResolver, ngZone, injector, posService) { this._ngZone = ngZone; this._injector = injector; this._posService = posService; this._componentFactoryResolver = componentFactoryResolver; } /** * @template T * @param {?} _elementRef * @param {?} _viewContainerRef * @param {?} _renderer * @return {?} */ createLoader(_elementRef, _viewContainerRef, _renderer) { return new ComponentLoader(_viewContainerRef, _renderer, _elementRef, this._injector, this._componentFactoryResolver, this._ngZone, this._posService); } } ComponentLoaderFactory.decorators = [ { type: Injectable }, ]; /** @nocollapse */ ComponentLoaderFactory.ctorParameters = () => [ { type: ComponentFactoryResolver, }, { type: NgZone, }, { type: Injector, }, { type: PositioningService, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DropdownState { constructor() { this.direction = 'down'; this.isOpenChange = new EventEmitter(); this.isDisabledChange = new EventEmitter(); this.toggleClick = new EventEmitter(); this.dropdownMenu = new Promise((resolve) => { this.resolveDropdownMenu = resolve; }); this.isOpenChange.subscribe((value) => { this.isOpen = value; }); } } DropdownState.decorators = [ { type: Injectable }, ]; /** @nocollapse */ DropdownState.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DropdownContainerComponent { /** * @param {?} _state */ constructor(_state) { this._state = _state; this.isOpen = false; this._subscription = _state.isOpenChange.subscribe((value) => { this.isOpen = value; }); } /** * @return {?} */ get direction() { return this._state.direction; } /** * @return {?} */ ngOnDestroy() { this._subscription.unsubscribe(); } } DropdownContainerComponent.decorators = [ { type: Component, args: [{ selector: 'hx-dropdown-container', host: { style: 'display:block;position: absolute;' }, template: ` <div [class.is-dropup]="direction === 'up'" [class.is-dropdown]="direction === 'down'" [class.is-open]="isOpen"><ng-content></ng-content></div> ` },] }, ]; /** @nocollapse */ DropdownContainerComponent.ctorParameters = () => [ { type: DropdownState, }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class DropdownDirective { /** * @param {?} _elementRef * @param {?} _renderer * @param {?} _viewContainerRef * @param {?} _cis * @param {?} _config * @param {?} _state */ constructor(_elementRef, _renderer, _viewContainerRef, _cis, _config, _state) { this._elementRef = _elementRef; this._renderer = _renderer; this._viewContainerRef = _viewContainerRef; this._cis = _cis; this._config = _config; this._state = _state; this._isInlineOpen = false; this._isInlineRight = false; this._subscriptions = []; this._isInited = false; // create dropdown component loader this._dropdown = this._cis .createLoader(this._elementRef, this._viewContainerRef, this._renderer) .provide({ provide: DropdownState, useValue: this._state }); this.onShown = this._dropdown.onShown; this.onHidden = this._dropdown.onHidden; this.isOpenChange = this._state.isOpenChange; // set initial dropdown state from config this._state.autoClose = this._config.autoClose; } /** * Indicates that dropdown will be closed on item or document click, * and after pressing ESC * @param {?} value * @return {?} */ set autoClose(value) { if (typeof value === 'boolean') { this._state.autoClose = value; } } ; /** * @return {?} */ get autoClose() { return this._state.autoClose; } /** * Disables dropdown toggle and hides dropdown menu if opened * @param {?} value * @return {?} */ set isDisabled(value) { this._isDisabled = value; this._state.isDisabledChange.emit(value); if (value) { this.hide(); } } /** * @return {?} */ get isDisabled() { return this._isDisabled; } /** * Returns whether or not dropdown is position right of the toggle * @return {?} */ get isRight() { return this._isInlineRight; } /** * @param {?} value * @return {?} */ set isRight(value) { this._isInlineRight = value; } /** * Returns whether or not the dropdown is currently being shown * @return {?} */ get isOpen() { if (this._showInline) { return this._isInlineOpen; } return this._dropdown.isShown; } /** * @param {?} value * @return {?} */ set isOpen(value) { if (value) { this.show(); } else { this.hide(); } } /** * @return {?} */ ngOnInit() { // fix: seems there are an issue with `routerLinkActive` // which result in duplicated call ngOnInit without call to ngOnDestroy // read more: https://github.com/valor-software/ngx-bootstrap/issues/1885 if (this._isInited) { return; } this._isInited = true; this._showInline = !this.container; // attach DOM listeners this._dropdown.listen({ triggers: this.triggers, show: () => this.show() }); // toggle visibility on toggle element click this._subscriptions.push(this._state .toggleClick.subscribe((value) => this.toggle(value))); // hide dropdown if set disabled while opened this._subscriptions.push(this._state .isDisabledChange.pipe(filter((value) => value === true)).subscribe((value) => this.hide())); // attach dropdown menu inside of dropdown if (this._showInline) { this._state.dropdownMenu .then((dropdownMenu) => { this._inlinedMenu = dropdownMenu.viewContainer.createEmbeddedView(dropdownMenu.templateRef); }); } } /** * Opens an element’s popover. This is considered a “manual” triggering of * the popover. * @return {?} */ show() { if (this.isOpen || this.isDisabled) { return; } if (this._showInline) { this._isInlineOpen = true; this.onShown.emit(true); this._state.isOpenChange.emit(true); return; } this._state.dropdownMenu .then((dropdownMenu) => { // check direction in which dropdown should be opened const /** @type {?} */ _dropup = this.dropup === true || (typeof this.dropup !== 'undefined' && this.dropup !== false); this._state.direction = _dropup ? 'up' : 'down'; const /** @type {?} */ _placement = this.placement || (_dropup ? 'top left' : 'bottom left'); // show dropdown this._dropdown .attach(DropdownContainerComponent) .to(this.container) .position({ attachment: _placement }) .show({ content: dropdownMenu.templateRef, placement: _placement }); this._state.isOpenChange.emit(true); }); } /** * Closes an element’s popover. This is considered a “manual” triggering of * the popover. * @return {?} */ hide() { if (!this.isOpen) { return; } if (this._showInline) { this._isInlineOpen = false; this.onHidden.emit(true); } else { this._dropdown.hide(); } this._state.isOpenChange.emit(false); } /** * Toggles an element’s popover. This is considered a “manual” triggering of * the popover. * @param {?=} value * @return {?} */ toggle(value) { if (this.isOpen || value === false) { return this.hide(); } return this.show(); } /** * @return {?} */ ngOnDestroy() { // clean up subscriptions and destroy dropdown for (const /** @type {?} */ sub of this._subscriptions) { sub.unsubscribe(); } this._dropdown.dispose(); } } DropdownDirective.decorators = [ { type: Directive, args: [{ selector: '[hxDropdown],[dropdown]', exportAs: 'hx-dropdown', providers: [DropdownState], host: { '[class.is-dropup]': 'dropup', '[class.is-open]': 'isOpen', '[class.is-right]': 'isRight' } },] }, ]; /** @nocollapse */ DropdownDirective.ctorParameters = () => [ { type: ElementRef, }, { type: Renderer2, }, { type: ViewContainerRef, }, { type: ComponentLoaderFactory, }, { type: DropdownConfig, }, { type: DropdownState, }, ]; DropdownDirective