gentics-ui-core
Version:
This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.
945 lines (928 loc) • 363 kB
JavaScript
import 'hammerjs';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Directive, EventEmitter, Component, ChangeDetectionStrategy, Input, Output, ViewChildren, ViewChild, HostListener, forwardRef, HostBinding, ElementRef, ContentChildren, Inject, Optional, SkipSelf, TemplateRef, ContentChild, ViewContainerRef, Pipe, Self, Attribute, NgModule } from '@angular/core';
import * as i5 from '@angular/forms';
import { NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i3 from '@angular/router';
import { RouterLinkWithHref, RouterModule } from '@angular/router';
import * as i1$3 from 'ngx-autosize';
import { AutosizeModule } from 'ngx-autosize';
import { Subscription, BehaviorSubject, timer, NEVER, of, Subject, Observable, merge, combineLatest, ObjectUnsubscribedError } from 'rxjs';
import { debounceTime, take, concat, filter, mapTo, map, switchMap, startWith } from 'rxjs/operators';
import * as moment_ from 'moment';
import * as rome_ from '@bevacqua/rome';
import * as momentum from '@bevacqua/rome/src/momentum';
import * as i1$1 from '@angular/platform-browser';
import { HammerModule } from '@angular/platform-browser';
import * as i1$2 from '@angular/animations';
import { animate, keyframes, style, trigger, state, transition, query, animateChild } from '@angular/animations';
import * as Sortable from 'sortablejs';
/* Default values */
const defaultConfig = {
dropDownPageMargin: 50,
dropDownMaxHeight: 650
};
const ConfigService = new InjectionToken('ConfigService');
const CustomConfig = new InjectionToken('CustomConfig');
const PredefinedConfig = new InjectionToken('PredefinedConfig');
function configFactory(initConfig, configValue) {
return configValue instanceof Function ? Object.assign(Object.assign({}, initConfig), configValue()) : Object.assign(Object.assign({}, initConfig), configValue);
}
class UserAgentRef {
constructor() {
const window = UserAgentRef._window;
this.isIE11 = !!(window.MSInputMethodContext && window.document.documentMode);
this.isEdge = !!(window.navigator.userAgent.indexOf('Edge') > -1);
}
}
UserAgentRef._window = window;
/** @nocollapse */ UserAgentRef.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: UserAgentRef, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ UserAgentRef.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: UserAgentRef });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: UserAgentRef, decorators: [{
type: Injectable
}], ctorParameters: function () { return []; } });
class Icon {
}
/** @nocollapse */ Icon.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Icon, deps: [], target: i0.ɵɵFactoryTarget.Directive });
/** @nocollapse */ Icon.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: Icon, selector: "icon", ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Icon, decorators: [{
type: Directive,
args: [{
selector: 'icon'
}]
}] });
/** The width configured in the .ellipsis CSS class. */
const ELLIPSIS_WIDTH = 13;
/**
* A Breadcrumbs navigation component.
*
* ```html
* <gtx-breadcrumbs></gtx-breadcrumbs>
* ```
*/
class Breadcrumbs {
constructor(changeDetector, elementRef, userAgent) {
this.changeDetector = changeDetector;
this.elementRef = elementRef;
this.userAgent = userAgent;
/**
* Fires when a link is clicked
*/
this.linkClick = new EventEmitter();
/**
* Fires when the expand button is clicked
*/
this.multilineExpandedChange = new EventEmitter();
this.isMultiline = false;
this.isMultilineExpanded = false;
this.isDisabled = false;
this.isOverflowing = false;
this.showArrow = false;
this.subscriptions = new Subscription();
this.resizeEvents = new BehaviorSubject(null);
this.preventClicksWhenDisabled = (ev) => {
if (this.isDisabled) {
let target = ev.target;
if (target.tagName.toLowerCase() === 'a' && target.classList.contains('breadcrumb')) {
ev.preventDefault();
ev.stopImmediatePropagation();
}
}
};
}
/**
* If true the first folder and all the folder names from the end of the breadcrumbs, which fit into one line are shown
* and an ellipsis in between.
*/
get multiline() {
return this.isMultiline;
}
set multiline(val) {
this.isMultiline = val != undefined && val !== false;
}
/**
* If true the breadcrumbs are always expanded
*/
get multilineExpanded() {
return this.isMultilineExpanded;
}
set multilineExpanded(val) {
this.isMultilineExpanded = val != undefined && val !== false;
}
/**
* Controls whether the navigation is disabled.
*/
get disabled() {
return this.isDisabled;
}
set disabled(val) {
this.isDisabled = val != undefined && val !== false;
}
ngAfterViewInit() {
let element = this.elementRef.nativeElement;
if (element) {
// Listen in the "capture" phase to prevent routerLinks when disabled
element.firstElementChild.addEventListener('click', this.preventClicksWhenDisabled, true);
element.style.setProperty('--collapsedColor', this.collapsedColor);
}
const timerSub = timer(500, 500)
.subscribe(() => this.resizeEvents.next());
this.subscriptions.add(timerSub);
this.setUpResizeSub();
this.preventDisabledRouterLinks();
this.routerLinkChildren.changes.subscribe(() => this.preventDisabledRouterLinks());
this.resizeEvents.next(null);
}
ngOnChanges(changes) {
if (changes['links'] || changes['routerLinks']) {
let allLinks = (this.links || []).concat(this.routerLinks || []);
this.backLink = allLinks[allLinks.length - 2];
this.resizeEvents.next(null);
}
if (changes['multiline'] || changes['multilineExpanded']) {
this.resizeEvents.next(null);
}
}
ngOnDestroy() {
let element = this.elementRef.nativeElement;
element.firstElementChild.removeEventListener('click', this.preventClicksWhenDisabled, true);
this.subscriptions.unsubscribe();
}
onLinkClicked(link, event) {
if (this.isDisabled) {
event.preventDefault();
event.stopImmediatePropagation();
}
else {
this.linkClick.emit(link);
}
}
toggleMultilineExpanded() {
this.multilineExpanded = !this.multilineExpanded;
this.multilineExpandedChange.emit(this.multilineExpanded);
this.resizeEvents.next(null);
this.changeDetector.markForCheck();
}
setUpResizeSub() {
let prevLinks;
let prevRouterLinks;
let prevIsExpanded;
let prevNavWidth = -1;
const resizeSub = this.resizeEvents
.pipe(debounceTime(5))
.subscribe(() => {
if (!this.lastPart || !this.navWrapper) {
return;
}
// If neither the links, nor isMultilineExpanded, nor the navWrapper element's clientWidth has changed, we don't need to do anything.
const currNavWidth = this.navWrapper.nativeElement.clientWidth;
if (prevLinks === this.links && prevRouterLinks === this.routerLinks && prevIsExpanded === this.isMultilineExpanded && prevNavWidth === currNavWidth) {
return;
}
prevLinks = this.links;
prevRouterLinks = this.routerLinks;
prevIsExpanded = this.isMultilineExpanded;
prevNavWidth = currNavWidth;
const elements = this.lastPart.nativeElement.querySelectorAll('a.breadcrumb');
if (elements.length > 0) {
const firstOffsetBottom = elements[0].offsetTop + elements[0].offsetHeight;
const lastOffsetBottom = elements[elements.length - 1].offsetTop + elements[elements.length - 1].offsetHeight;
this.showArrow = firstOffsetBottom !== lastOffsetBottom;
}
else {
this.showArrow = false;
}
this.shortenTexts();
this.changeDetector.markForCheck();
});
this.subscriptions.add(resizeSub);
}
shortenTexts() {
const navWrapper = this.navWrapper.nativeElement;
const lastPart = this.lastPart.nativeElement;
const innerElements = lastPart.querySelectorAll('a.breadcrumb');
const defaultElements = this.getCuttableBreadcrumbsTexts();
this.isOverflowing = false;
// Reset all elements to their default states.
const offset = this.multilineExpanded ? 0 : 1;
for (let i = 0; i < innerElements.length; i++) {
const innerElement = innerElements[i];
innerElement.classList.remove('without');
innerElement.classList.remove('hidden');
innerElement.textContent = defaultElements[i + offset];
}
if (this.multilineExpanded) {
return;
}
for (let i = 0; i < innerElements.length; ++i) {
const innerElement = innerElements[i];
while (lastPart.offsetLeft + lastPart.scrollWidth + ELLIPSIS_WIDTH > navWrapper.clientWidth) {
this.isOverflowing = true;
if (innerElement.textContent.length === 0) {
innerElement.classList.add('hidden');
const nextInnerElement = innerElements[i + 1];
if (nextInnerElement) {
nextInnerElement.classList.add('without');
}
break;
}
else {
innerElement.textContent = innerElement.textContent.substring(1);
}
}
}
}
getCuttableBreadcrumbsTexts() {
let defaultBreadcrumbs = [];
if (this.links) {
for (let i = 0; i < this.links.length; i++) {
defaultBreadcrumbs.push(this.links[i].text);
}
}
if (this.routerLinks) {
for (let i = 0; i < this.routerLinks.length; i++) {
defaultBreadcrumbs.push(this.routerLinks[i].text);
}
}
return defaultBreadcrumbs;
}
onResize(event) {
this.resizeEvents.next(null);
}
/**
* Workaround/Hack for the native angular "RouterLink" having no way to disable navigation on click.
*/
preventDisabledRouterLinks() {
const thisComponent = this;
const createsCompileErrorIfRouterLinkAPIChanges = 'onClick';
for (const link of this.routerLinkChildren.filter(link => !link.hasOwnProperty('onClick'))) {
const originalOnClick = link.onClick;
link.onClick = function interceptedOnClick(...args) {
if (thisComponent.isDisabled) {
return true;
}
else {
return originalOnClick.apply(this, args);
}
};
}
}
}
/** @nocollapse */ Breadcrumbs.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Breadcrumbs, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: UserAgentRef }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ Breadcrumbs.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: Breadcrumbs, selector: "gtx-breadcrumbs", inputs: { links: "links", routerLinks: "routerLinks", collapsedColor: "collapsedColor", multiline: "multiline", multilineExpanded: "multilineExpanded", disabled: "disabled" }, outputs: { linkClick: "linkClick", multilineExpandedChange: "multilineExpandedChange" }, viewQueries: [{ propertyName: "navWrapper", first: true, predicate: ["navWrapper"], descendants: true }, { propertyName: "lastPart", first: true, predicate: ["lastPart"], descendants: true }, { propertyName: "routerLinkChildren", predicate: RouterLinkWithHref, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<nav [class.disabled]=\"isDisabled\" [class.multiline]=\"multiline\">\n <div #navWrapper class=\"nav-wrapper\" [class.is-overflowing]=\"isOverflowing\" [class.multilineExpanded]=\"multilineExpanded\" [class.multiline]=\"multiline\" (window:resize)=\"onResize($event)\">\n <div class=\"inner-wrapper\">\n <a class=\"back-button\" *ngIf=\"backLink && backLink.route\"\n (click)=\"onLinkClicked(backLink, $event)\"\n [routerLink]=\"backLink.route\"\n [title]=\"backLink.text\"></a>\n <a class=\"back-button\" *ngIf=\"backLink && !backLink.route\"\n (click)=\"onLinkClicked(backLink, $event)\"\n [attr.href]=\"isDisabled ? null : backLink?.href\"\n [title]=\"backLink.text\"></a>\n\n <div class=\"other-content\">\n <ng-content></ng-content>\n </div>\n\n <ng-template [ngIf]=\"links\">\n <a *ngIf=\"!multilineExpanded && links[0]\" class=\"breadcrumb\"\n [attr.href]=\"isDisabled ? null : links[0].href\"\n (click)=\"onLinkClicked(links[0], $event)\"\n [title]=\"links[0].tooltip || links[0].text\"\n >{{ links[0].text }}</a>\n <div class=\"ellipsis\" *ngIf=\"isOverflowing && !multilineExpanded\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n ...\n </div>\n <div #lastPart class=\"lastPart\">\n <ng-container *ngFor=\"let link of links; let i = index\">\n <a *ngIf=\"!multilineExpanded && i > 0\"\n class=\"breadcrumb last\"\n [attr.href]=\"isDisabled ? null : link?.href\"\n (click)=\"onLinkClicked(link, $event)\"\n [title]=\"link.tooltip || link.text\"\n >{{ link.text }}</a>\n <a *ngIf=\"multilineExpanded\"\n class=\"breadcrumb last\"\n [attr.href]=\"isDisabled ? null : link?.href\"\n (click)=\"onLinkClicked(link, $event)\"\n [title]=\"link.tooltip || link.text\"\n >{{ link.text }}\n </a>\n </ng-container>\n <span *ngIf=\"multiline && multilineExpanded && !isOverflowing && showArrow\" class=\"back_arrow\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n <icon>arrow_back</icon>\n </span>\n </div>\n </ng-template>\n\n <ng-template [ngIf]=\"routerLinks\">\n <a *ngIf=\"!multilineExpanded && routerLinks[0]\" class=\"breadcrumb\"\n [routerLink]=\"routerLinks[0].route\"\n (click)=\"onLinkClicked(routerLinks[0], $event)\"\n [title]=\"routerLinks[0].tooltip || routerLinks[0].text\"\n >{{ routerLinks[0].text }}</a>\n <div class=\"ellipsis\" *ngIf=\"isOverflowing && !multilineExpanded\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n ...\n </div>\n <div #lastPart class=\"lastPart\">\n <ng-container *ngFor=\"let routerLink of routerLinks; let i = index\">\n <a *ngIf=\"!multilineExpanded && i > 0\"\n class=\"breadcrumb last\"\n [routerLink]=\"routerLink.route\"\n (click)=\"onLinkClicked(routerLink, $event)\"\n [title]=\"routerLink.tooltip || routerLink.text\"\n >{{ routerLink.text }}</a>\n <a *ngIf=\"multilineExpanded\"\n class=\"breadcrumb last\"\n [routerLink]=\"routerLink.route\"\n (click)=\"onLinkClicked(routerLink, $event)\"\n [title]=\"routerLink.tooltip || routerLink.text\"\n >{{ routerLink.text }}\n </a>\n </ng-container>\n <span *ngIf=\"multiline && multilineExpanded && !isOverflowing && showArrow\" class=\"back_arrow\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n <icon>arrow_back</icon>\n </span>\n </div>\n </ng-template>\n </div>\n </div>\n</nav>\n", directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "preserveFragment", "skipLocationChange", "replaceUrl", "state", "relativeTo", "routerLink"] }, { type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: Icon, selector: "icon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Breadcrumbs, decorators: [{
type: Component,
args: [{ selector: 'gtx-breadcrumbs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav [class.disabled]=\"isDisabled\" [class.multiline]=\"multiline\">\n <div #navWrapper class=\"nav-wrapper\" [class.is-overflowing]=\"isOverflowing\" [class.multilineExpanded]=\"multilineExpanded\" [class.multiline]=\"multiline\" (window:resize)=\"onResize($event)\">\n <div class=\"inner-wrapper\">\n <a class=\"back-button\" *ngIf=\"backLink && backLink.route\"\n (click)=\"onLinkClicked(backLink, $event)\"\n [routerLink]=\"backLink.route\"\n [title]=\"backLink.text\"></a>\n <a class=\"back-button\" *ngIf=\"backLink && !backLink.route\"\n (click)=\"onLinkClicked(backLink, $event)\"\n [attr.href]=\"isDisabled ? null : backLink?.href\"\n [title]=\"backLink.text\"></a>\n\n <div class=\"other-content\">\n <ng-content></ng-content>\n </div>\n\n <ng-template [ngIf]=\"links\">\n <a *ngIf=\"!multilineExpanded && links[0]\" class=\"breadcrumb\"\n [attr.href]=\"isDisabled ? null : links[0].href\"\n (click)=\"onLinkClicked(links[0], $event)\"\n [title]=\"links[0].tooltip || links[0].text\"\n >{{ links[0].text }}</a>\n <div class=\"ellipsis\" *ngIf=\"isOverflowing && !multilineExpanded\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n ...\n </div>\n <div #lastPart class=\"lastPart\">\n <ng-container *ngFor=\"let link of links; let i = index\">\n <a *ngIf=\"!multilineExpanded && i > 0\"\n class=\"breadcrumb last\"\n [attr.href]=\"isDisabled ? null : link?.href\"\n (click)=\"onLinkClicked(link, $event)\"\n [title]=\"link.tooltip || link.text\"\n >{{ link.text }}</a>\n <a *ngIf=\"multilineExpanded\"\n class=\"breadcrumb last\"\n [attr.href]=\"isDisabled ? null : link?.href\"\n (click)=\"onLinkClicked(link, $event)\"\n [title]=\"link.tooltip || link.text\"\n >{{ link.text }}\n </a>\n </ng-container>\n <span *ngIf=\"multiline && multilineExpanded && !isOverflowing && showArrow\" class=\"back_arrow\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n <icon>arrow_back</icon>\n </span>\n </div>\n </ng-template>\n\n <ng-template [ngIf]=\"routerLinks\">\n <a *ngIf=\"!multilineExpanded && routerLinks[0]\" class=\"breadcrumb\"\n [routerLink]=\"routerLinks[0].route\"\n (click)=\"onLinkClicked(routerLinks[0], $event)\"\n [title]=\"routerLinks[0].tooltip || routerLinks[0].text\"\n >{{ routerLinks[0].text }}</a>\n <div class=\"ellipsis\" *ngIf=\"isOverflowing && !multilineExpanded\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n ...\n </div>\n <div #lastPart class=\"lastPart\">\n <ng-container *ngFor=\"let routerLink of routerLinks; let i = index\">\n <a *ngIf=\"!multilineExpanded && i > 0\"\n class=\"breadcrumb last\"\n [routerLink]=\"routerLink.route\"\n (click)=\"onLinkClicked(routerLink, $event)\"\n [title]=\"routerLink.tooltip || routerLink.text\"\n >{{ routerLink.text }}</a>\n <a *ngIf=\"multilineExpanded\"\n class=\"breadcrumb last\"\n [routerLink]=\"routerLink.route\"\n (click)=\"onLinkClicked(routerLink, $event)\"\n [title]=\"routerLink.tooltip || routerLink.text\"\n >{{ routerLink.text }}\n </a>\n </ng-container>\n <span *ngIf=\"multiline && multilineExpanded && !isOverflowing && showArrow\" class=\"back_arrow\" [class.multilineExpanded]=\"multilineExpanded\" (click)=\"toggleMultilineExpanded()\">\n <icon>arrow_back</icon>\n </span>\n </div>\n </ng-template>\n </div>\n </div>\n</nav>\n" }]
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: UserAgentRef }]; }, propDecorators: { links: [{
type: Input
}], routerLinks: [{
type: Input
}], collapsedColor: [{
type: Input
}], multiline: [{
type: Input
}], multilineExpanded: [{
type: Input
}], disabled: [{
type: Input
}], linkClick: [{
type: Output
}], multilineExpandedChange: [{
type: Output
}], routerLinkChildren: [{
type: ViewChildren,
args: [RouterLinkWithHref]
}], navWrapper: [{
type: ViewChild,
args: ['navWrapper']
}], lastPart: [{
type: ViewChild,
args: ['lastPart']
}] } });
/**
* A Button component.
*
* ```html
* <gtx-button>Click me</gtx-button>
* <gtx-button size="large">Buy Now!</gtx-button>
* <gtx-button type="alert">Delete all stuff</gtx-button>
* <gtx-button icon>
* <i class="material-icons">settings</i>
* </gtx-button>
* ```
*/
class Button {
constructor() {
/**
* Sets the input field to be auto-focused. Handled by `AutofocusDirective`.
*/
this.autofocus = false;
/**
* Specify the size of the button. Can be "small", "regular" or "large".
*/
this.size = 'regular';
/**
* Type determines the style of the button. Can be "default", "secondary",
* "success", "warning" or "alert".
*/
this.type = 'default';
this.buttonType = 'button';
this.isFlat = false;
this.isIcon = false;
this.isDisabled = false;
}
/**
* Setting the "flat" attribute gives the button a transparent background
* and only depth on hover.
*/
get flat() {
return this.isFlat;
}
set flat(val) {
this.isFlat = val != null && val !== false;
}
/**
* Setting the "icon" attribute turns the button into an "icon button", which is
* like a flat button without a border, suitable for wrapping an icon.
*/
get icon() {
return this.isIcon;
}
set icon(val) {
this.isIcon = val != null && val !== false;
}
/**
* Controls whether the button is disabled.
*/
get disabled() {
return this.isDisabled;
}
set disabled(disabled) {
this.isDisabled = disabled === '' || !!disabled;
}
/**
* Set button as a submit button.
*/
set submit(value) {
this.buttonType = (value != null && value !== false) ? 'submit' : 'button';
}
// In some browsers, disabled elements don't fire mouse events, but bubble them up the DOM tree.
// To not trigger actions when the button is disabled, we need to prevent them manually.
preventDisabledClick(event) {
if (event && this.isDisabled) {
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
}
}
}
/** @nocollapse */ Button.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Button, deps: [], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ Button.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: Button, selector: "gtx-button", inputs: { autofocus: "autofocus", size: "size", type: "type", flat: "flat", icon: "icon", disabled: "disabled", submit: "submit" }, host: { listeners: { "click": "preventDisabledClick($event)" } }, ngImport: i0, template: "<div class=\"button-event-wrapper\" (click)=\"preventDisabledClick($event)\">\n <button class=\"btn {{size}} {{type}}\"\n [type]=\"buttonType\"\n [disabled]=\"disabled\"\n [class.btn-flat]=\"flat || icon\"\n [class.btn-icon]=\"icon\"\n (click)=\"preventDisabledClick($event)\"\n ><ng-content></ng-content></button>\n</div>\n" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Button, decorators: [{
type: Component,
args: [{ selector: 'gtx-button', template: "<div class=\"button-event-wrapper\" (click)=\"preventDisabledClick($event)\">\n <button class=\"btn {{size}} {{type}}\"\n [type]=\"buttonType\"\n [disabled]=\"disabled\"\n [class.btn-flat]=\"flat || icon\"\n [class.btn-icon]=\"icon\"\n (click)=\"preventDisabledClick($event)\"\n ><ng-content></ng-content></button>\n</div>\n" }]
}], propDecorators: { autofocus: [{
type: Input
}], size: [{
type: Input
}], type: [{
type: Input
}], flat: [{
type: Input
}], icon: [{
type: Input
}], disabled: [{
type: Input
}], submit: [{
type: Input
}], preventDisabledClick: [{
type: HostListener,
args: ['click', ['$event']]
}] } });
var KeyCode;
(function (KeyCode) {
KeyCode[KeyCode["UpArrow"] = 38] = "UpArrow";
KeyCode[KeyCode["DownArrow"] = 40] = "DownArrow";
KeyCode[KeyCode["RightArrow"] = 39] = "RightArrow";
KeyCode[KeyCode["LeftArrow"] = 37] = "LeftArrow";
KeyCode[KeyCode["PageUp"] = 33] = "PageUp";
KeyCode[KeyCode["PageDown"] = 34] = "PageDown";
KeyCode[KeyCode["Home"] = 36] = "Home";
KeyCode[KeyCode["End"] = 35] = "End";
KeyCode[KeyCode["Enter"] = 13] = "Enter";
KeyCode[KeyCode["Space"] = 32] = "Space";
KeyCode[KeyCode["Tab"] = 9] = "Tab";
KeyCode[KeyCode["Escape"] = 27] = "Escape";
KeyCode[KeyCode["Backspace"] = 8] = "Backspace";
KeyCode[KeyCode["Delete"] = 46] = "Delete";
})(KeyCode || (KeyCode = {}));
const GTX_CHECKBOX_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Checkbox),
multi: true
};
/**
* Checkbox wraps the native `<input type="checkbox">` form element.
*
* ```html
* <gtx-checkbox [(ngModel)]="isOkay" label="Is it okay?"></gtx-checkbox>
* <gtx-checkbox [(ngModel)]="checkStates.B" value="B" label="B"></gtx-checkbox>
* ```
*
* ## Stateless Mode
* By default, the Checkbox keeps track of its own internal checked state. This makes sense
* for most use cases, such as when used in a form bound to NgControl.
*
* However, in some cases we want to explicitly set the state from outside. This is done by binding
* to the <code>checked</code> attribute. When this attribute is bound, the checked state of the
* Checkbox will *only* change when the value of the binding changes. Clicking on the Checkbox
* will have no effect other than to emit an event which the parent can use to update the binding.
*
* Here is a basic example of a stateless checkbox where the parent component manages the state:
*
* ```html
* <gtx-checkbox [checked]="isChecked"
* (change)="isChecked = $event"></gtx-checkbox>
* ```
*/
class Checkbox {
constructor(changeDetector) {
this.changeDetector = changeDetector;
/**
* Sets the checkbox to be auto-focused. Handled by `AutofocusDirective`.
*/
this.autofocus = false;
/**
* Set the checkbox to its disabled state.
*/
this.disabled = false;
/**
* Checkbox ID
*/
this.id = randomID$1();
/**
* Label for the checkbox
*/
this.label = '';
/**
* Sets the required property
*/
this.required = false;
/**
* The value of the checkbox
*/
this.value = '';
/**
* Blur event
*/
this.blur = new EventEmitter();
/**
* Focus event
*/
this.focus = new EventEmitter();
/**
* Change event
*/
this.change = new EventEmitter();
this.checkState = false;
this.tabbedFocus = false;
/**
* See note above on stateless mode.
*/
this.statelessMode = false;
this.onChange = () => { };
this.onTouched = () => { };
}
/**
* Checked state of the checkbox. When set, the Checkbox will be
* in stateless mode.
*/
get checked() {
return this.checkState === true;
}
set checked(value) {
this.statelessMode = true;
let val = value;
let nowChecked = val === true || val === 'true' || val === '';
if (nowChecked != this.checkState) {
this.onChange(this.checkState = nowChecked);
this.changeDetector.markForCheck();
}
}
/**
* Set to "indeterminate" for an indeterminate state (-)
*/
get indeterminate() {
return this.checkState === 'indeterminate';
}
set indeterminate(val) {
if (val != (this.checkState === 'indeterminate')) {
this.checkState = val ? 'indeterminate' : false;
this.change.emit(this.checkState);
this.onChange(this.checkState);
}
}
onBlur() {
this.blur.emit(this.checkState);
this.onTouched();
this.tabbedFocus = false;
}
onFocus() {
this.focus.emit(this.checkState);
}
focusHandler(e) {
if (e.keyCode === KeyCode.Tab) {
if (!this.tabbedFocus) {
this.tabbedFocus = true;
}
}
}
writeValue(value) {
if (value !== this.checkState) {
this.checkState = value;
this.changeDetector.markForCheck();
}
}
ngOnInit() {
this.onChange(this.checkState);
}
ngAfterViewInit() {
this.fixInitialAnimation();
}
onInputChanged(e, input) {
if (e) {
e.stopPropagation();
}
let newState = input.indeterminate ? 'indeterminate' : input.checked;
if (this.statelessMode) {
if (input.checked !== this.checkState) {
input.checked = !!this.checkState;
}
this.change.emit(newState);
return false;
}
if (newState != this.checkState) {
this.checkState = newState;
this.onChange(newState);
this.change.emit(newState);
return true;
}
}
registerOnChange(fn) { this.onChange = fn; }
registerOnTouched(fn) { this.onTouched = fn; }
setDisabledState(disabled) {
this.disabled = disabled;
this.changeDetector.markForCheck();
}
/**
* This is a hacky fix to prevent Materialize from animating ticked checkboxes which
* kicks in when a checkbox is added to the dom with checked=false and immediately
* set to checked=true.
*/
fixInitialAnimation() {
if (this.labelElement && this.labelElement.nativeElement) {
let label = this.labelElement.nativeElement;
label.style.display = 'none';
let ignored = label.offsetWidth;
label.style.display = '';
}
}
}
/** @nocollapse */ Checkbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Checkbox, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ Checkbox.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: Checkbox, selector: "gtx-checkbox", inputs: { autofocus: "autofocus", checked: "checked", indeterminate: "indeterminate", disabled: "disabled", id: "id", label: "label", name: "name", required: "required", value: "value" }, outputs: { blur: "blur", focus: "focus", change: "change" }, host: { listeners: { "keyup": "focusHandler($event)" } }, providers: [GTX_CHECKBOX_VALUE_ACCESSOR], viewQueries: [{ propertyName: "labelElement", first: true, predicate: ["labelElement"], descendants: true, static: true }], ngImport: i0, template: "<div>\n <input type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [checked]=\"checkState === true\"\n [indeterminate]=\"checkState === 'indeterminate'\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [value]=\"value\"\n\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (change)=\"onInputChanged($event, input)\"\n\n [class.tabbed]=\"tabbedFocus\"\n\n #input\n >\n <label [attr.for]=\"id\" #labelElement>{{ label }}</label>\n</div>\n" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: Checkbox, decorators: [{
type: Component,
args: [{ selector: 'gtx-checkbox', providers: [GTX_CHECKBOX_VALUE_ACCESSOR], template: "<div>\n <input type=\"checkbox\"\n [attr.id]=\"id\"\n [attr.name]=\"name\"\n [checked]=\"checkState === true\"\n [indeterminate]=\"checkState === 'indeterminate'\"\n [disabled]=\"disabled\"\n [required]=\"required\"\n [value]=\"value\"\n\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (change)=\"onInputChanged($event, input)\"\n\n [class.tabbed]=\"tabbedFocus\"\n\n #input\n >\n <label [attr.for]=\"id\" #labelElement>{{ label }}</label>\n</div>\n" }]
}], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { autofocus: [{
type: Input
}], checked: [{
type: Input
}], indeterminate: [{
type: Input
}], disabled: [{
type: Input
}], id: [{
type: Input
}], label: [{
type: Input
}], name: [{
type: Input
}], required: [{
type: Input
}], value: [{
type: Input
}], blur: [{
type: Output
}], focus: [{
type: Output
}], change: [{
type: Output
}], labelElement: [{
type: ViewChild,
args: ['labelElement', { static: true }]
}], focusHandler: [{
type: HostListener,
args: ['keyup', ['$event']]
}] } });
function randomID$1() {
return 'checkbox-' + Math.random().toString(36).substr(2);
}
/**
* A wrapper around items that appear in the list pane of the SplitViewComponent.
*
* Two component-specific classes can be used:
*
* * `.item-avatar`: The content of this element will be styled in a circular container.
* * `.item-primary`: The primary content of the item, which will take up all the remaining space via `flex: 1`.
* * `.show-on-hover`: Any element with this class will appear faded out until the user hovers the list item.
*
*
* ```html
* <gtx-contents-list-item *ngFor="let item of listItems">
* <!-- this will be styled as a circular icon -->
* <div class="item-avatar"><i class="material-icons">{{ item.icon }}</i></div>
* <!-- this will stretch to use all available space -->
* <div class="item-primary"><a [routerLink]="[item.route]">{{ item.title }}</a></div>
* <!-- these will use remaining space to the right -->
* <i class="material-icons show-on-hover">edit</i>
* <i class="material-icons show-on-hover">star</i>
* </gtx-contents-list-item>
* ```
*/
class ContentsListItem {
}
/** @nocollapse */ ContentsListItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ContentsListItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ ContentsListItem.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: ContentsListItem, selector: "gtx-contents-list-item", ngImport: i0, template: "<ng-content></ng-content>\n" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: ContentsListItem, decorators: [{
type: Component,
args: [{ selector: 'gtx-contents-list-item', template: "<ng-content></ng-content>\n" }]
}] });
/**
* Components with boolean inputs may receive the value as an actual boolean (if data-bound `[prop]="false"`) or as
* a string representation of a boolean (if passed as a regular attribute `prop="false"`).
* In the latter case, we want to ensure that the string version is correctly coerced to its boolean counterpart.
*/
function coerceToBoolean(val) {
return val === true || val === 'true' || val === '';
}
const defaultStrings = {
hours: 'Hours',
minutes: 'Minutes',
seconds: 'Seconds',
okay: 'Okay',
cancel: 'Cancel',
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
],
monthsShort: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
],
weekdays: [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
],
weekdaysShort: [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat'
],
weekdaysMin: [
'Su',
'Mo',
'Tu',
'We',
'Th',
'Fr',
'Sa'
]
};
/**
* Format provider to localize the DateTimePicker component.
*/
class DateTimePickerFormatProvider {
constructor() {
/** Texts uses by the DateTimePicker modal. */
this.strings = defaultStrings;
/** May emit a value when the translations or the date format changed. */
this.changed$ = NEVER;
}
/** Formats a human-readable string to be displayed in the control input field. */
format(date, displayTime, displaySeconds) {
let formatString = displayTime ? (displaySeconds ? 'L, LTS' : 'L, LT') : 'L';
return date.format(formatString);
}
}
/** @nocollapse */ DateTimePickerFormatProvider.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DateTimePickerFormatProvider, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
/** @nocollapse */ DateTimePickerFormatProvider.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DateTimePickerFormatProvider });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DateTimePickerFormatProvider, decorators: [{
type: Injectable
}] });
/**
* This is a workaround for loading moment JS in TypeScript 3.2 and Angular 7.
* This is based on https://github.com/rollup/rollup/issues/1267#issuecomment-446681320
*/
/** The moment namespace and moment function. */
const momentjs = moment_.default || moment_;
window.moment = momentjs;
rome_.use(momentjs);
delete window.moment;
if (momentum.moment === void 0) {
throw new Error('rome depends on moment.js, you can get it at http://momentjs.com.');
}
/** The rome namespace and rome function. */
const rome = rome_.default || rome_;
class DropdownItem {
constructor() {
this.tabIndex = 0;
this.isDisabled = false;
}
/**
* If true, the DropdownItem cannot be clicked or selected. *Default: false*
*/
get disabled() {
return this.isDisabled;
}
set disabled(value) {
this.isDisabled = coerceToBoolean(value);
}
}
/** @nocollapse */ DropdownItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ DropdownItem.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: DropdownItem, selector: "gtx-dropdown-item", inputs: { disabled: "disabled" }, host: { properties: { "tabindex": "this.tabIndex", "class.disabled": "this.isDisabled" } }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownItem, decorators: [{
type: Component,
args: [{
selector: 'gtx-dropdown-item',
template: `<ng-content></ng-content>`
}]
}], propDecorators: { disabled: [{
type: Input
}], tabIndex: [{
type: HostBinding,
args: ['tabindex']
}], isDisabled: [{
type: HostBinding,
args: ['class.disabled']
}] } });
const FOCUSABLE_SELECTOR = `gtx-dropdown-item, a[href], area[href], input:not([disabled]), select:not([disabled]),
textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]`;
class DropdownTriggerDirective {
constructor(elementRef) {
this.elementRef = elementRef;
}
/**
* Focus the first focusable descendant of this element.
*/
focus() {
const focusable = this.elementRef.nativeElement.querySelector(FOCUSABLE_SELECTOR);
if (focusable && focusable.focus) {
focusable.focus();
}
}
}
/** @nocollapse */ DropdownTriggerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownTriggerDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
/** @nocollapse */ DropdownTriggerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.3.8", type: DropdownTriggerDirective, selector: "gtx-dropdown-trigger", ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownTriggerDirective, decorators: [{
type: Directive,
args: [{
selector: 'gtx-dropdown-trigger'
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; } });
/**
* Wraps the content and handles keyboard control (tabbing and focus) of the contents.
*/
class DropdownContent {
constructor(elementRef) {
this.elementRef = elementRef;
this.focusLost = new EventEmitter();
this.focusableItems = [];
}
keyHandler(e) {
if (e.keyCode === KeyCode.Tab) {
if (e.shiftKey) {
this.focusPrevious(e.target, e);
}
else {
this.focusNext(e.target, e);
}
}
}
ngAfterContentInit() {
this.focusableItems = Array.from(this.elementRef.nativeElement.querySelectorAll(FOCUSABLE_SELECTOR));
}
focusFirstItem() {
const firstItem = this.focusableItems[0];
if (firstItem && firstItem.focus) {
firstItem.focus();
}
}
focusNext(currentElement, e) {
const items = this.focusableItems;
const index = this.getIndexOfElement(currentElement);
if (index === items.length - 1) {
e.preventDefault();
this.focusLost.emit(true);
}
}
focusPrevious(currentElement, e) {
const index = this.getIndexOfElement(currentElement);
if (index === 0) {
e.preventDefault();
this.focusLost.emit(true);
}
}
getIndexOfElement(element) {
return this.focusableItems.indexOf(element);
}
}
/** @nocollapse */ DropdownContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownContent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ DropdownContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.8", type: DropdownContent, selector: "gtx-dropdown-content", host: { listeners: { "keydown": "keyHandler($event)" } }, queries: [{ propertyName: "items", predicate: i0.forwardRef(function () { return DropdownItem; }), read: ElementRef }], ngImport: i0, template: `<div class="scroller"><ng-content></ng-content></div>`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.8", ngImport: i0, type: DropdownContent, decorators: [{
type: Component,
args: [{
selector: 'gtx-dropdown-content',
template: `<div class="scroller"><ng-content></ng-content></div>`
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { items: [{
type: ContentChildren,
args: [forwardRef(() => DropdownItem), { read: ElementRef }]
}], keyHandler: [{
type: HostListener,
args: ['keydown', ['$event']]
}] } });
class DropdownContentWrapper {
constructor(elementRef, cd, config) {
this.elementRef = elementRef;
this.cd = cd;
this.config = config;
this.contentStyles = {
position: 'absolute'
};
this.options = {
alignment: 'left',
width: 'contents',
belowTrigger: false
};
this.id = 'dropdown-' + Math.random().toString(36).substr(2);
this.clicked = new EventEmitter();
this.escapeKeyPressed = new EventEmitter();
this.widthHasBeenAdjusted = false;
this.pageMargin = this.config.dropDownPageMargin;
this.dropDownMaxHeight = this.config.dropDownMaxHeight;
}
ngAfterViewInit() {
this.setPositionAndSize(true);
}
/**
* Positions and resizes the dropdown contents container.
*/
setPositionAndSize(initialOpening = false) {
const content = this.getDropdownContent();
if (!content) {
return;
}
if (initialOpening) {
// When opening for the first time, some extra logic is required
this.contentStyles.height = 0;
this.contentStyles.opacity = 0;
content.setAttribute('id', this.id);
}
const positionStyles = this.calculatePositionStyles();
Object.assign(this.contentStyles, positionStyles);
// const flowUpwards = parseInt(positionStyles.top, 10) < Math.floor(this.trigger.getBoundingClientRect().top);
const contentHeight = this.innerHeight(this.elementRef.nativeElement.querySelector('gtx-dropdown-content'));
// when flowing upwards, we animate the `top` property, so must remember the final value.
const finalTop = parseInt(this.contentStyles.top);
if (positi