gentics-ui-core
Version:
This is the common core framework for the Gentics CMS and Mesh UI, and other Angular applications.
1 lines • 521 kB
Source Map (JSON)
{"version":3,"file":"gentics-ui-core.mjs","sources":["../../../src/module.config.ts","../../../src/components/modal/user-agent-ref.ts","../../../src/components/icon/icon.directive.ts","../../../src/components/breadcrumbs/breadcrumbs.component.ts","../../../src/components/breadcrumbs/breadcrumbs.tpl.html","../../../src/components/button/button.component.ts","../../../src/components/button/button.tpl.html","../../../src/common/keycodes.ts","../../../src/components/checkbox/checkbox.component.ts","../../../src/components/checkbox/checkbox.tpl.html","../../../src/components/contents-list-item/contents-list-item.component.ts","../../../src/components/contents-list-item/contents-list-item.tpl.html","../../../src/common/coerce-to-boolean.ts","../../../src/components/date-time-picker/date-time-picker-default-strings.ts","../../../src/components/date-time-picker/date-time-picker-format-provider.service.ts","../../../src/common/momentjs.import.ts","../../../src/common/rome.import.ts","../../../src/components/dropdown-list/dropdown-item.component.ts","../../../src/components/dropdown-list/dropdown-trigger.directive.ts","../../../src/components/dropdown-list/dropdown-content.component.ts","../../../src/components/overlay-host/overlay-host.service.ts","../../../src/components/dropdown-list/dropdown-content-wrapper.component.ts","../../../src/components/dropdown-list/scroll-mask.component.ts","../../../src/components/dropdown-list/dropdown-list.component.ts","../../../src/components/dropdown-list/dropdown-list.tpl.html","../../../src/components/select/option.component.ts","../../../src/components/select/select.component.ts","../../../src/components/select/select.tpl.html","../../../src/components/input/input.component.ts","../../../src/components/input/input.tpl.html","../../../src/components/date-time-picker/date-time-picker-controls.component.ts","../../../src/components/date-time-picker/date-time-picker-controls.tpl.html","../../../src/components/date-time-picker/date-time-picker-modal.component.ts","../../../src/components/date-time-picker/date-time-picker-modal.tpl.html","../../../src/components/modal/dynamic-modal-wrapper.component.ts","../../../src/components/modal/dynamic-modal-wrapper.tpl.html","../../../src/components/modal/modal-dialog.component.ts","../../../src/components/modal/modal-dialog.tpl.html","../../../src/components/modal/blank-modal.component.ts","../../../src/components/modal/modal.service.ts","../../../src/components/date-time-picker/date-time-picker.component.ts","../../../src/components/date-time-picker/date-time-picker.tpl.html","../../../src/components/file-drop-area/drag-drop-utils.ts","../../../src/components/file-drop-area/drag-state-tracker.service.ts","../../../src/components/file-drop-area/matches-mime-type.ts","../../../src/components/file-drop-area/page-file-drag-handler.service.ts","../../../src/components/file-drop-area/file-drop-area.directive.ts","../../../src/components/file-drop-area/matches-mime-type.pipe.ts","../../../src/components/file-drop-area/prevent-file-drop.directive.ts","../../../src/components/file-picker/file-picker.component.ts","../../../src/components/file-picker/file-picker.tpl.html","../../../src/components/grouped-tabs/tab-content.ts","../../../src/components/grouped-tabs/tab-label.ts","../../../src/components/grouped-tabs/tab-pane.component.ts","../../../src/components/grouped-tabs/tab-group.component.ts","../../../src/components/grouped-tabs/grouped-tabs.component.ts","../../../src/components/grouped-tabs/grouped-tabs.tpl.html","../../../src/components/menu-toggle-button/menu-toggle-button.component.ts","../../../src/components/notification/toast.component.ts","../../../src/components/notification/toast.tpl.html","../../../src/components/notification/notification.service.ts","../../../src/components/overlay-host/overlay-host.component.ts","../../../src/components/progress-bar/progress-bar.component.ts","../../../src/components/progress-bar/progress-bar.tpl.html","../../../src/components/radio-button/radio-button.component.ts","../../../src/components/radio-button/radio-button.tpl.html","../../../src/components/range/range.component.ts","../../../src/components/range/range.tpl.html","../../../src/components/search-bar/search-bar.component.ts","../../../src/components/search-bar/search-bar.tpl.html","../../../src/components/side-menu/side-menu.component.ts","../../../src/components/side-menu/side-menu.tpl.html","../../../src/components/sortable-list/sortable-list.component.ts","../../../src/components/sortable-list/sortable-list.tpl.html","../../../src/components/split-button/split-button-primary-action.component.ts","../../../src/directives/autofocus/autofocus.directive.ts","../../../src/components/split-button/split-button.component.ts","../../../src/components/split-button/split-button.tpl.html","../../../src/components/split-view-container/split-view-container.component.ts","../../../src/components/split-view-container/split-view-container.tpl.html","../../../src/components/tabs/tab.component.ts","../../../src/components/tabs/tabs.component.ts","../../../src/components/tabs/tabs.tpl.html","../../../src/components/textarea/textarea.component.ts","../../../src/components/textarea/textarea.tpl.html","../../../src/components/top-bar/top-bar.component.ts","../../../src/components/top-bar/top-bar.tpl.html","../../../src/module.ts","../../../src/index.ts","../../../src/gentics-ui-core.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\n/* Default values */\nexport const defaultConfig: Config = {\n dropDownPageMargin: 50,\n dropDownMaxHeight: 650\n}\n\nexport interface Config {\n dropDownPageMargin?: number;\n dropDownMaxHeight?: number;\n}\n\nexport type optionsConfig = Partial<Config>;\nexport const ConfigService: InjectionToken<Config> = new InjectionToken('ConfigService');\nexport const CustomConfig: InjectionToken<Config> = new InjectionToken('CustomConfig');\nexport const PredefinedConfig: InjectionToken<Config> = new InjectionToken('PredefinedConfig');\n\nexport function configFactory(\n initConfig: optionsConfig,\n configValue: optionsConfig | (() => optionsConfig)\n): optionsConfig {\n return configValue instanceof Function ? { ...initConfig, ...configValue() } : { ...initConfig, ...configValue };\n}","import { Injectable } from '@angular/core';\n\n@Injectable()\nexport class UserAgentRef {\n static _window: any = window;\n readonly isIE11: boolean;\n readonly isEdge: boolean;\n\n constructor() {\n const window = UserAgentRef._window;\n this.isIE11 = !!(window.MSInputMethodContext && window.document.documentMode);\n this.isEdge = !!(window.navigator.userAgent.indexOf('Edge') > -1);\n }\n}\n","import {Directive} from '@angular/core';\n\n@Directive({\n selector: 'icon'\n})\nexport class Icon {}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnDestroy,\n Output,\n QueryList,\n SimpleChanges,\n ViewChild,\n ViewChildren,\n ChangeDetectorRef,\n AfterViewInit\n} from '@angular/core';\nimport {RouterLinkWithHref} from '@angular/router';\nimport {BehaviorSubject, Subscription, timer} from 'rxjs';\nimport {debounceTime} from 'rxjs/operators';\n\nimport {UserAgentRef} from '../modal/user-agent-ref';\n\nexport interface IBreadcrumbLink {\n href?: string;\n route?: any;\n text: string;\n tooltip?: string;\n [key: string]: any;\n}\n\nexport interface IBreadcrumbRouterLink {\n route: any[];\n text: string;\n tooltip?: string;\n [key: string]: any;\n}\n\n/** The width configured in the .ellipsis CSS class. */\nconst ELLIPSIS_WIDTH = 13;\n\n/**\n * A Breadcrumbs navigation component.\n *\n * ```html\n * <gtx-breadcrumbs></gtx-breadcrumbs>\n * ```\n */\n@Component({\n selector: 'gtx-breadcrumbs',\n templateUrl: './breadcrumbs.tpl.html',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class Breadcrumbs implements OnChanges, OnDestroy, AfterViewInit {\n\n /**\n * A list of links to display\n */\n @Input() links: IBreadcrumbLink[];\n\n /**\n * A list of RouterLinks to display\n */\n @Input() routerLinks: IBreadcrumbRouterLink[];\n\n /**\n * A color that is used for collapsed state background.\n */\n @Input() collapsedColor: string;\n\n /**\n * If true the first folder and all the folder names from the end of the breadcrumbs, which fit into one line are shown\n * and an ellipsis in between.\n */\n @Input() get multiline(): boolean {\n return this.isMultiline;\n }\n set multiline(val: boolean) {\n this.isMultiline = val != undefined && val !== false;\n }\n\n /**\n * If true the breadcrumbs are always expanded\n */\n @Input() get multilineExpanded(): boolean {\n return this.isMultilineExpanded;\n }\n set multilineExpanded(val: boolean) {\n this.isMultilineExpanded = val != undefined && val !== false;\n }\n\n /**\n * Controls whether the navigation is disabled.\n */\n @Input() get disabled(): boolean {\n return this.isDisabled;\n }\n set disabled(val: boolean) {\n this.isDisabled = val != undefined && val !== false;\n }\n\n /**\n * Fires when a link is clicked\n */\n @Output() linkClick = new EventEmitter<IBreadcrumbLink | IBreadcrumbRouterLink>();\n\n /**\n * Fires when the expand button is clicked\n */\n @Output() multilineExpandedChange = new EventEmitter<boolean>();\n\n isMultiline: boolean = false;\n isMultilineExpanded: boolean = false;\n isDisabled: boolean = false;\n isOverflowing: boolean = false;\n\n showArrow: boolean = false;\n\n backLink: IBreadcrumbLink | IBreadcrumbRouterLink;\n @ViewChildren(RouterLinkWithHref) routerLinkChildren: QueryList<RouterLinkWithHref>;\n\n @ViewChild('navWrapper')\n navWrapper: ElementRef;\n\n @ViewChild('lastPart')\n lastPart: ElementRef;\n\n private subscriptions = new Subscription();\n private resizeEvents = new BehaviorSubject<void>(null);\n\n constructor(private changeDetector: ChangeDetectorRef,\n private elementRef: ElementRef,\n private userAgent: UserAgentRef) { }\n\n ngAfterViewInit(): void {\n let element: HTMLElement = this.elementRef.nativeElement;\n if (element) {\n // Listen in the \"capture\" phase to prevent routerLinks when disabled\n element.firstElementChild.addEventListener('click', this.preventClicksWhenDisabled, true);\n element.style.setProperty('--collapsedColor', this.collapsedColor);\n }\n\n const timerSub = timer(500, 500)\n .subscribe(() => this.resizeEvents.next());\n this.subscriptions.add(timerSub);\n this.setUpResizeSub();\n\n this.preventDisabledRouterLinks();\n this.routerLinkChildren.changes.subscribe(() => this.preventDisabledRouterLinks());\n this.resizeEvents.next(null);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['links'] || changes['routerLinks']) {\n let allLinks = (this.links || []).concat(this.routerLinks || []);\n this.backLink = allLinks[allLinks.length - 2];\n this.resizeEvents.next(null);\n }\n if (changes['multiline'] || changes['multilineExpanded']) {\n this.resizeEvents.next(null);\n }\n }\n\n ngOnDestroy(): void {\n let element: HTMLElement = this.elementRef.nativeElement;\n element.firstElementChild.removeEventListener('click', this.preventClicksWhenDisabled, true);\n this.subscriptions.unsubscribe();\n }\n\n onLinkClicked(link: IBreadcrumbLink | IBreadcrumbRouterLink, event: Event): void {\n if (this.isDisabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n } else {\n this.linkClick.emit(link);\n }\n }\n\n toggleMultilineExpanded(): void {\n this.multilineExpanded = !this.multilineExpanded;\n this.multilineExpandedChange.emit(this.multilineExpanded);\n this.resizeEvents.next(null);\n this.changeDetector.markForCheck();\n }\n\n private setUpResizeSub() {\n let prevLinks: IBreadcrumbLink[];\n let prevRouterLinks: IBreadcrumbRouterLink[];\n let prevIsExpanded: boolean;\n let prevNavWidth = -1;\n\n const resizeSub = this.resizeEvents\n .pipe(debounceTime(5))\n .subscribe(() => {\n if (!this.lastPart || !this.navWrapper) {\n return;\n }\n // If neither the links, nor isMultilineExpanded, nor the navWrapper element's clientWidth has changed, we don't need to do anything.\n const currNavWidth = this.navWrapper.nativeElement.clientWidth;\n if (prevLinks === this.links && prevRouterLinks === this.routerLinks && prevIsExpanded === this.isMultilineExpanded && prevNavWidth === currNavWidth) {\n return;\n }\n prevLinks = this.links;\n prevRouterLinks = this.routerLinks;\n prevIsExpanded = this.isMultilineExpanded;\n prevNavWidth = currNavWidth;\n\n const elements = this.lastPart.nativeElement.querySelectorAll('a.breadcrumb');\n if (elements.length > 0) {\n const firstOffsetBottom = elements[0].offsetTop + elements[0].offsetHeight;\n const lastOffsetBottom = elements[elements.length - 1].offsetTop + elements[elements.length - 1].offsetHeight;\n this.showArrow = firstOffsetBottom !== lastOffsetBottom;\n } else {\n this.showArrow = false;\n }\n this.shortenTexts();\n this.changeDetector.markForCheck();\n });\n\n this.subscriptions.add(resizeSub);\n }\n\n private shortenTexts() {\n const navWrapper = this.navWrapper.nativeElement as HTMLElement;\n const lastPart = this.lastPart.nativeElement as HTMLElement;\n const innerElements = lastPart.querySelectorAll('a.breadcrumb');\n const defaultElements = this.getCuttableBreadcrumbsTexts();\n\n this.isOverflowing = false;\n\n // Reset all elements to their default states.\n const offset = this.multilineExpanded ? 0 : 1;\n for (let i = 0; i < innerElements.length; i++) {\n const innerElement = innerElements[i];\n innerElement.classList.remove('without');\n innerElement.classList.remove('hidden');\n innerElement.textContent = defaultElements[i + offset];\n }\n\n if (this.multilineExpanded) {\n return;\n }\n\n for (let i = 0; i < innerElements.length; ++i) {\n const innerElement = innerElements[i];\n while (lastPart.offsetLeft + lastPart.scrollWidth + ELLIPSIS_WIDTH > navWrapper.clientWidth) {\n this.isOverflowing = true;\n if (innerElement.textContent.length === 0) {\n innerElement.classList.add('hidden');\n const nextInnerElement = innerElements[i + 1];\n if (nextInnerElement) {\n nextInnerElement.classList.add('without');\n }\n break;\n } else {\n innerElement.textContent = innerElement.textContent.substring(1);\n }\n }\n }\n }\n\n private getCuttableBreadcrumbsTexts(): string[] {\n let defaultBreadcrumbs: string[] = [];\n if (this.links) {\n for (let i = 0; i < this.links.length; i++) {\n defaultBreadcrumbs.push(this.links[i].text);\n }\n }\n if (this.routerLinks) {\n for (let i = 0; i < this.routerLinks.length; i++) {\n defaultBreadcrumbs.push(this.routerLinks[i].text);\n }\n }\n return defaultBreadcrumbs;\n }\n\n onResize(event: any): void {\n this.resizeEvents.next(null);\n }\n\n private preventClicksWhenDisabled = (ev: Event): void => {\n if (this.isDisabled) {\n let target = ev.target as HTMLElement;\n if (target.tagName.toLowerCase() === 'a' && target.classList.contains('breadcrumb')) {\n ev.preventDefault();\n ev.stopImmediatePropagation();\n }\n }\n }\n\n /**\n * Workaround/Hack for the native angular \"RouterLink\" having no way to disable navigation on click.\n */\n private preventDisabledRouterLinks(): void {\n const thisComponent = this;\n const createsCompileErrorIfRouterLinkAPIChanges: keyof RouterLinkWithHref = 'onClick';\n\n for (const link of this.routerLinkChildren.filter(link => !link.hasOwnProperty('onClick'))) {\n const originalOnClick = link.onClick;\n link.onClick = function interceptedOnClick(...args: any[]): boolean {\n if (thisComponent.isDisabled) {\n return true;\n } else {\n return originalOnClick.apply(this, args);\n }\n };\n }\n }\n}\n","<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","import { Component, Input, HostListener } from '@angular/core';\n\n/**\n * A Button component.\n *\n * ```html\n * <gtx-button>Click me</gtx-button>\n * <gtx-button size=\"large\">Buy Now!</gtx-button>\n * <gtx-button type=\"alert\">Delete all stuff</gtx-button>\n * <gtx-button icon>\n * <i class=\"material-icons\">settings</i>\n * </gtx-button>\n * ```\n */\n@Component({\n selector: 'gtx-button',\n templateUrl: './button.tpl.html'\n})\nexport class Button {\n /**\n * Sets the input field to be auto-focused. Handled by `AutofocusDirective`.\n */\n @Input() autofocus: boolean = false;\n\n /**\n * Specify the size of the button. Can be \"small\", \"regular\" or \"large\".\n */\n @Input() size: 'small' | 'regular' | 'large' = 'regular';\n\n /**\n * Type determines the style of the button. Can be \"default\", \"secondary\",\n * \"success\", \"warning\" or \"alert\".\n */\n @Input() type: 'default' | 'secondary' | 'success' | 'warning' | 'alert' = 'default';\n\n /**\n * Setting the \"flat\" attribute gives the button a transparent background\n * and only depth on hover.\n */\n @Input()\n get flat(): boolean {\n return this.isFlat;\n }\n set flat(val: boolean) {\n this.isFlat = val != null && val !== false;\n }\n\n /**\n * Setting the \"icon\" attribute turns the button into an \"icon button\", which is\n * like a flat button without a border, suitable for wrapping an icon.\n */\n @Input()\n get icon(): boolean {\n return this.isIcon;\n }\n set icon(val: boolean) {\n this.isIcon = val != null && val !== false;\n }\n\n /**\n * Controls whether the button is disabled.\n */\n @Input()\n get disabled(): boolean {\n return this.isDisabled;\n }\n set disabled(disabled: boolean) {\n this.isDisabled = (<any> disabled) === '' || !!disabled;\n }\n\n /**\n * Set button as a submit button.\n */\n @Input()\n set submit(value: boolean) {\n this.buttonType = (value != null && value !== false) ? 'submit' : 'button';\n }\n\n buttonType = 'button';\n isFlat: boolean = false;\n isIcon: boolean = false;\n isDisabled: boolean = false;\n\n // In some browsers, disabled elements don't fire mouse events, but bubble them up the DOM tree.\n // To not trigger actions when the button is disabled, we need to prevent them manually.\n @HostListener('click', ['$event'])\n preventDisabledClick(event: Event): void {\n if (event && this.isDisabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n event.stopPropagation();\n }\n }\n}\n","<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","export enum KeyCode {\n UpArrow = 38,\n DownArrow = 40,\n RightArrow = 39,\n LeftArrow = 37,\n PageUp = 33,\n PageDown = 34,\n Home = 36,\n End = 35,\n Enter = 13,\n Space = 32,\n Tab = 9,\n Escape = 27,\n Backspace = 8,\n Delete = 46\n}\n","import {\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n forwardRef,\n HostListener,\n Input,\n Output,\n ViewChild\n} from '@angular/core';\nimport {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';\nimport {KeyCode} from '../../common/keycodes';\n\nexport type CheckState = boolean | 'indeterminate';\n\nconst GTX_CHECKBOX_VALUE_ACCESSOR = {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => Checkbox),\n multi: true\n};\n\n/**\n * Checkbox wraps the native `<input type=\"checkbox\">` form element.\n *\n * ```html\n * <gtx-checkbox [(ngModel)]=\"isOkay\" label=\"Is it okay?\"></gtx-checkbox>\n * <gtx-checkbox [(ngModel)]=\"checkStates.B\" value=\"B\" label=\"B\"></gtx-checkbox>\n * ```\n *\n * ## Stateless Mode\n * By default, the Checkbox keeps track of its own internal checked state. This makes sense\n * for most use cases, such as when used in a form bound to NgControl.\n *\n * However, in some cases we want to explicitly set the state from outside. This is done by binding\n * to the <code>checked</code> attribute. When this attribute is bound, the checked state of the\n * Checkbox will *only* change when the value of the binding changes. Clicking on the Checkbox\n * will have no effect other than to emit an event which the parent can use to update the binding.\n *\n * Here is a basic example of a stateless checkbox where the parent component manages the state:\n *\n * ```html\n * <gtx-checkbox [checked]=\"isChecked\"\n * (change)=\"isChecked = $event\"></gtx-checkbox>\n * ```\n */\n@Component({\n selector: 'gtx-checkbox',\n templateUrl: './checkbox.tpl.html',\n providers: [GTX_CHECKBOX_VALUE_ACCESSOR]\n})\nexport class Checkbox implements ControlValueAccessor {\n /**\n * Sets the checkbox to be auto-focused. Handled by `AutofocusDirective`.\n */\n @Input() autofocus: boolean = false;\n\n /**\n * Checked state of the checkbox. When set, the Checkbox will be\n * in stateless mode.\n */\n @Input() get checked(): boolean {\n return this.checkState === true;\n }\n set checked(value: boolean) {\n this.statelessMode = true;\n let val: boolean | 'true' | '' | 'indeterminate' = <any> value;\n let nowChecked = val === true || <any> val === 'true' || <any> val === '';\n if (nowChecked != this.checkState) {\n this.onChange(this.checkState = nowChecked);\n this.changeDetector.markForCheck();\n }\n }\n\n /**\n * Set to \"indeterminate\" for an indeterminate state (-)\n */\n @Input() get indeterminate(): boolean {\n return this.checkState === 'indeterminate';\n }\n set indeterminate(val: boolean) {\n if (val != (this.checkState === 'indeterminate')) {\n this.checkState = val ? 'indeterminate' : false;\n this.change.emit(this.checkState);\n this.onChange(this.checkState);\n }\n }\n\n /**\n * Set the checkbox to its disabled state.\n */\n @Input() disabled: boolean = false;\n /**\n * Checkbox ID\n */\n @Input() id: string = randomID();\n /**\n * Label for the checkbox\n */\n @Input() label: string = '';\n /**\n * Form name for the checkbox\n */\n @Input() name: string;\n /**\n * Sets the required property\n */\n @Input() required: boolean = false;\n /**\n * The value of the checkbox\n */\n @Input() value: any = '';\n\n /**\n * Blur event\n */\n @Output() blur = new EventEmitter<CheckState>();\n /**\n * Focus event\n */\n @Output() focus = new EventEmitter<CheckState>();\n /**\n * Change event\n */\n @Output() change = new EventEmitter<CheckState>();\n\n checkState: CheckState = false;\n tabbedFocus: boolean = false;\n\n @ViewChild('labelElement', { static: true }) labelElement: ElementRef;\n\n /**\n * See note above on stateless mode.\n */\n private statelessMode: boolean = false;\n\n\n constructor(private changeDetector: ChangeDetectorRef) { }\n\n onBlur(): void {\n this.blur.emit(this.checkState);\n this.onTouched();\n this.tabbedFocus = false;\n }\n\n onFocus(): void {\n this.focus.emit(this.checkState);\n }\n\n @HostListener('keyup', ['$event'])\n focusHandler(e: KeyboardEvent): void {\n if (e.keyCode === KeyCode.Tab) {\n if (!this.tabbedFocus) {\n this.tabbedFocus = true;\n }\n }\n }\n\n writeValue(value: any): void {\n if (value !== this.checkState) {\n this.checkState = value;\n this.changeDetector.markForCheck();\n }\n }\n\n ngOnInit(): void {\n this.onChange(this.checkState);\n }\n\n ngAfterViewInit(): void {\n this.fixInitialAnimation();\n }\n\n onInputChanged(e: Event, input: HTMLInputElement): boolean {\n if (e) {\n e.stopPropagation();\n }\n let newState: CheckState = input.indeterminate ? 'indeterminate' : input.checked;\n if (this.statelessMode) {\n if (input.checked !== this.checkState) {\n input.checked = !!this.checkState;\n }\n this.change.emit(newState);\n return false;\n }\n if (newState != this.checkState) {\n this.checkState = newState;\n this.onChange(newState);\n this.change.emit(newState);\n return true;\n }\n }\n\n registerOnChange(fn: Function): void { this.onChange = fn; }\n registerOnTouched(fn: Function): void { this.onTouched = fn; }\n setDisabledState(disabled: boolean): void {\n this.disabled = disabled;\n this.changeDetector.markForCheck();\n }\n\n private onChange: Function = () => {};\n private onTouched: Function = () => {};\n\n /**\n * This is a hacky fix to prevent Materialize from animating ticked checkboxes which\n * kicks in when a checkbox is added to the dom with checked=false and immediately\n * set to checked=true.\n */\n private fixInitialAnimation(): void {\n if (this.labelElement && this.labelElement.nativeElement) {\n let label: HTMLLabelElement = this.labelElement.nativeElement;\n label.style.display = 'none';\n let ignored = label.offsetWidth;\n label.style.display = '';\n }\n }\n}\n\nfunction randomID(): string {\n return 'checkbox-' + Math.random().toString(36).substr(2);\n}\n","<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","import {Component} from '@angular/core';\n\n/**\n * A wrapper around items that appear in the list pane of the SplitViewComponent.\n *\n * Two component-specific classes can be used:\n *\n * * `.item-avatar`: The content of this element will be styled in a circular container.\n * * `.item-primary`: The primary content of the item, which will take up all the remaining space via `flex: 1`.\n * * `.show-on-hover`: Any element with this class will appear faded out until the user hovers the list item.\n *\n *\n * ```html\n * <gtx-contents-list-item *ngFor=\"let item of listItems\">\n * <!-- this will be styled as a circular icon -->\n * <div class=\"item-avatar\"><i class=\"material-icons\">{{ item.icon }}</i></div>\n * <!-- this will stretch to use all available space -->\n * <div class=\"item-primary\"><a [routerLink]=\"[item.route]\">{{ item.title }}</a></div>\n * <!-- these will use remaining space to the right -->\n * <i class=\"material-icons show-on-hover\">edit</i>\n * <i class=\"material-icons show-on-hover\">star</i>\n * </gtx-contents-list-item>\n * ```\n */\n@Component({\n selector: 'gtx-contents-list-item',\n templateUrl: './contents-list-item.tpl.html'\n})\nexport class ContentsListItem {}\n","<ng-content></ng-content>\n","/**\n * Components with boolean inputs may receive the value as an actual boolean (if data-bound `[prop]=\"false\"`) or as\n * a string representation of a boolean (if passed as a regular attribute `prop=\"false\"`).\n * In the latter case, we want to ensure that the string version is correctly coerced to its boolean counterpart.\n */\nexport function coerceToBoolean(val: any): boolean {\n return val === true || val === 'true' || val === '';\n}\n","import {DateTimePickerStrings} from './date-time-picker-strings';\n\nexport const defaultStrings: DateTimePickerStrings = {\n hours: 'Hours',\n minutes: 'Minutes',\n seconds: 'Seconds',\n okay: 'Okay',\n cancel: 'Cancel',\n months: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December'\n ],\n monthsShort: [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec'\n ],\n weekdays: [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday'\n ],\n weekdaysShort: [\n 'Sun',\n 'Mon',\n 'Tue',\n 'Wed',\n 'Thu',\n 'Fri',\n 'Sat'\n ],\n weekdaysMin: [\n 'Su',\n 'Mo',\n 'Tu',\n 'We',\n 'Th',\n 'Fr',\n 'Sa'\n ]\n};\n","import {Injectable} from '@angular/core';\nimport {NEVER, Observable} from 'rxjs';\n\nimport {defaultStrings} from './date-time-picker-default-strings';\nimport {DateTimePickerStrings} from './date-time-picker-strings';\n\n/**\n * A simplified subset of the Moment interface which we expose via the first arg of the\n * DateTimePickerFormatProvider.format() method.\n */\nexport interface MomentLike {\n format(format: string): string;\n format(): string;\n\n year(): number;\n quarter(): number;\n month(): number;\n day(): number;\n date(): number;\n hour(): number;\n hours(): number;\n minute(): number;\n minutes(): number;\n second(): number;\n seconds(): number;\n millisecond(): number;\n milliseconds(): number;\n weekday(): number;\n isoWeekday(): number;\n weekYear(): number;\n isoWeekYear(): number;\n week(): number;\n weeks(): number;\n isoWeek(): number;\n isoWeeks(): number;\n weeksInYear(): number;\n isoWeeksInYear(): number;\n dayOfYear(): number;\n\n toArray(): number[];\n toDate(): Date;\n toISOString(): string;\n toJSON(): string;\n unix(): number;\n\n isLeapYear(): boolean;\n zone(): number;\n utcOffset(): number;\n daysInMonth(): number;\n isDST(): boolean;\n}\n\n/**\n * Format provider to localize the DateTimePicker component.\n */\n@Injectable()\nexport class DateTimePickerFormatProvider {\n\n /** Texts uses by the DateTimePicker modal. */\n strings: DateTimePickerStrings = defaultStrings;\n\n /** May emit a value when the translations or the date format changed. */\n changed$: Observable<any> = NEVER;\n\n /** Formats a human-readable string to be displayed in the control input field. */\n format(date: MomentLike, displayTime: boolean, displaySeconds: boolean): string {\n let formatString = displayTime ? (displaySeconds ? 'L, LTS' : 'L, LT') : 'L';\n return date.format(formatString);\n }\n}\n","/**\n * This is a workaround for loading moment JS in TypeScript 3.2 and Angular 7.\n * This is based on https://github.com/rollup/rollup/issues/1267#issuecomment-446681320\n */\n\nimport * as moment_ from 'moment';\n\n/** The moment namespace and moment function. */\nexport const momentjs = (moment_ as any).default || moment_;\n\n/** The Moment class. This must be used as a type instead of momentjs.Moment. */\nexport type Moment = moment_.Moment;\n","import {momentjs} from './momentjs.import';\n\nimport * as rome_ from '@bevacqua/rome';\nimport * as momentum from '@bevacqua/rome/src/momentum';\n\n(window as any).moment = momentjs;\nrome_.use(momentjs);\ndelete (window as any).moment;\n\nif (momentum.moment === void 0) {\n throw new Error('rome depends on moment.js, you can get it at http://momentjs.com.');\n}\n\n/** The rome namespace and rome function. */\nexport const rome = (rome_ as any).default || rome_;","import {Component, HostBinding, Input} from '@angular/core';\nimport {coerceToBoolean} from '../../common/coerce-to-boolean';\n\n@Component({\n selector: 'gtx-dropdown-item',\n template: `<ng-content></ng-content>`\n})\nexport class DropdownItem {\n\n /**\n * If true, the DropdownItem cannot be clicked or selected. *Default: false*\n */\n @Input()\n get disabled(): boolean {\n return this.isDisabled;\n }\n set disabled(value: boolean) {\n this.isDisabled = coerceToBoolean(value);\n }\n\n @HostBinding('tabindex') tabIndex = 0;\n\n @HostBinding('class.disabled') isDisabled = false;\n}\n","import {Directive, ElementRef} from '@angular/core';\n\nexport const FOCUSABLE_SELECTOR = `gtx-dropdown-item, a[href], area[href], input:not([disabled]), select:not([disabled]), \n textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]`;\n\n@Directive({\n selector: 'gtx-dropdown-trigger'\n})\nexport class DropdownTriggerDirective {\n constructor(public elementRef: ElementRef) {}\n\n /**\n * Focus the first focusable descendant of this element.\n */\n focus(): void {\n const focusable = this.elementRef.nativeElement.querySelector(FOCUSABLE_SELECTOR);\n if (focusable && focusable.focus) {\n focusable.focus();\n }\n }\n}\n","import {Component, ContentChildren, HostListener, EventEmitter, forwardRef, QueryList, ElementRef, AfterContentInit} from '@angular/core';\nimport {DropdownItem} from './dropdown-item.component';\nimport {KeyCode} from '../../common/keycodes';\nimport {FOCUSABLE_SELECTOR} from './dropdown-trigger.directive';\n\n/**\n * Wraps the content and handles keyboard control (tabbing and focus) of the contents.\n */\n@Component({\n selector: 'gtx-dropdown-content',\n template: `<div class=\"scroller\"><ng-content></ng-content></div>`\n})\nexport class DropdownContent implements AfterContentInit {\n focusLost = new EventEmitter<boolean>();\n focusableItems: HTMLElement[] = [];\n\n @ContentChildren(forwardRef(() => DropdownItem), { read: ElementRef }) items: QueryList<ElementRef>;\n\n constructor(public elementRef: ElementRef) {}\n\n @HostListener('keydown', ['$event'])\n keyHandler(e: KeyboardEvent): void {\n if (e.keyCode === KeyCode.Tab) {\n if (e.shiftKey) {\n this.focusPrevious(e.target as HTMLElement, e);\n } else {\n this.focusNext(e.target as HTMLElement, e);\n }\n }\n }\n\n ngAfterContentInit(): void {\n this.focusableItems = Array.from<HTMLElement>(this.elementRef.nativeElement.querySelectorAll(FOCUSABLE_SELECTOR));\n }\n\n focusFirstItem(): void {\n const firstItem = this.focusableItems[0];\n if (firstItem && firstItem.focus) {\n firstItem.focus();\n }\n }\n\n focusNext(currentElement: HTMLElement, e: KeyboardEvent): void {\n const items = this.focusableItems;\n const index = this.getIndexOfElement(currentElement);\n if (index === items.length - 1) {\n e.preventDefault();\n this.focusLost.emit(true);\n }\n }\n\n focusPrevious(currentElement: HTMLElement, e: KeyboardEvent): void {\n const index = this.getIndexOfElement(currentElement);\n if (index === 0) {\n e.preventDefault();\n this.focusLost.emit(true);\n }\n }\n\n private getIndexOfElement(element: HTMLElement): number {\n return this.focusableItems.indexOf(element);\n }\n}\n","import {Injectable, ViewContainerRef, Optional, SkipSelf} from '@angular/core';\n\n/**\n * The OverlayHostService is used to get a reference to the ViewConainerRef of the\n * OverlayHost component, so that other components may insert components & elements\n * into the DOM at that point.\n */\n@Injectable()\nexport class OverlayHostService {\n\n public hostView: ViewContainerRef;\n public promiseResolveFns: Function[] = [];\n\n /**\n * The OverlayHostService expects to be used by the OverlayHostComponent in the root module of the app.\n * In the case that the GenticsUICore is imported into a lazy-loaded child module, this service may be\n * instantiated a second time. This second instance will not have been registered with the OverlayHostComponent,\n * so we need to check out the injector tree and grab the hostView from the parent OverlayHostService.\n */\n constructor(@Optional() @SkipSelf() private parentInstance?: OverlayHostService) {\n if (parentInstance) {\n this.hostView = parentInstance.hostView;\n this.promiseResolveFns = parentInstance.promiseResolveFns;\n }\n }\n\n /**\n * Used to pass in the ViewContainerRef from the OverlayHost component.\n * Should not be used by any other component.\n */\n registerHostView(viewContainerRef: ViewContainerRef): void {\n this.hostView = viewContainerRef;\n if (0 < this.promiseResolveFns.length) {\n this.resolveHostView();\n }\n }\n\n /**\n * Returns a promise which resolves to the ViewContainerRef of the OverlayHost\n * component. This can then be used to insert components and elements into the\n * DOM at that point.\n */\n getHostView(): Promise<ViewContainerRef> {\n return new Promise((resolve: Function) => {\n this.promiseResolveFns.push(resolve);\n if (this.hostView !== undefined) {\n this.resolveHostView();\n }\n });\n }\n\n private resolveHostView(): void {\n this.promiseResolveFns.forEach(resolve => resolve(this.hostView));\n this.promiseResolveFns = [];\n }\n}\n","import {\n Component,\n HostListener,\n TemplateRef,\n ElementRef,\n ChangeDetectorRef,\n EventEmitter,\n ChangeDetectionStrategy,\n Inject, OnDestroy, AfterViewInit\n} from '@angular/core';\nimport {KeyCode} from '../../common/keycodes';\nimport {DropdownAlignment, DropdownWidth} from './dropdown.model';\nimport {Config, ConfigService} from '../../module.config';\n\n@Component({\n selector: 'gtx-dropdown-content-wrapper',\n template: `<div class=\"dropdown-content-wrapper\"\n (click)=\"onContentClick()\"\n [ngStyle]=\"contentStyles\">\n <ng-template [ngTemplateOutlet]=\"content\"></ng-template>\n </div>`,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class DropdownContentWrapper implements AfterViewInit, OnDestroy {\n pageMargin: Config['dropDownPageMargin'];\n dropDownMaxHeight: Config['dropDownMaxHeight'];\n content: TemplateRef<any>;\n contentStyles: any = {\n position: 'absolute'\n };\n options = {\n alignment: 'left' as DropdownAlignment,\n width: 'contents' as DropdownWidth,\n belowTrigger: false\n };\n trigger: HTMLElement;\n id: string = 'dropdown-' + Math.random().toString(36).substr(2);\n clicked = new EventEmitter<any>();\n escapeKeyPressed = new EventEmitter<any>();\n private widthHasBeenAdjusted = false;\n\n constructor(private elementRef: ElementRef,\n private cd: ChangeDetectorRef,\n @Inject(ConfigService) private config: Config) {\n this.pageMargin = this.config.dropDownPageMargin;\n this.dropDownMaxHeight = this.config.dropDownMaxHeight;\n }\n\n ngAfterViewInit(): void {\n this.setPositionAndSize(true);\n }\n\n /**\n * Positions and resizes the dropdown contents container.\n */\n setPositionAndSize(initialOpening: boolean = false): void {\n const content = this.getDropdownContent();\n if (!content) {\n return;\n }\n if (initialOpening) {\n // When opening for the first time, some extra logic is required\n this.contentStyles.height = 0;\n this.contentStyles.opacity = 0;\n content.setAttribute('id', this.id);\n }\n\n const positionStyles = this.calculatePositionStyles();\n Object.assign(this.contentStyles, positionStyles);\n // const flowUpwards = parseInt(positionStyles.top, 10) < Math.floor(this.trigger.getBoundingClientRect().top);\n const contentHeight = this.innerHeight(this.elementRef.nativeElement.querySelector('gtx-dropdown-content'));\n\n // when flowing upwards, we animate the `top` property, so must remember the final value.\n const finalTop = parseInt(this.contentStyles.top);\n if (positionStyles.flowUpwards) {\n this.contentStyles.top = finalTop + Math.min(contentHeight, parseInt(positionStyles.maxHeight)) + 'px';\n }\n\n this.contentStyles.width = this.calculateContainerWidth() + 'px';\n this.cd.markForCheck();\n this.cd.detectChanges();\n\n // Show dropdown. Wrapped in a setTimeout to allow the contents of the dropdown\n // to re-flow (if needed) so that the true dimensions can then be re-calculated.\n setTimeout(() => {\n const maxHeightValue = parseInt(positionStyles.maxHeight);\n let contentHeight = this.innerHeight(content);\n if (maxHeightValue < contentHeight) {\n contentHeight = maxHeightValue;\n }\n content.style.maxHeight = Math.max(contentHeight, maxHeightValue) + 'px';\n\n this.contentStyles.height = contentHeight + 'px';\n this.contentStyles.width = this.calculateContainerWidth() + 'px';\n\n if (positionStyles.flowUpwards) {\n this.contentStyles.top = finalTop + 'px';\n }\n this.contentStyles.transform = `translateZ(0)`;\n this.contentStyles.opacity = 1;\n\n if (this.options.width === 'contents') {\n this.contentStyles.whiteSpace = 'nowrap';\n }\n this.widthHasBeenAdjusted = true;\n this.cd.markForCheck();\n }, 0);\n }\n\n @HostListener('keydown', ['$event'])\n clickHandler(e: KeyboardEvent): void {\n if (e.keyCode === KeyCode.Escape) {\n this.escapeKeyPressed.emit(true);\n }\n }\n\n ngOnDestroy(): void {\n const content = this.getDropdownContent();\n if (content) {\n content.style.maxHeight = 'none';\n }\n this.contentStyles.opacity = 0;\n this.contentStyles.maxHeight = 'none';\n }\n /**\n * Calculates the position of the dropdown based on the height, width. alignment and screen boundaries.\n */\n calculatePositionStyles(): { top: string, left: string, maxHeight: string, flowUpwards: boolean; } {\n const positionStyles: any = {\n flowUpwards: false,\n maxHeight: this.dropDownMaxHeight + 'px'\n };\n const content = this.getDropdownContent();\n const fullHeightContent = content && content.querySelector('.scroller') as HTMLElement;\n const contentHeight = this.innerHeight(fullHeightContent) + this.pageMargin;\n\n // Offscreen detection\n const windowHeight: number = window.innerHeight;\n const triggerHeight: number = this.innerHeight(this.trigger);\n const offset = this.offse