diff --git a/src/app/openaire-library b/src/app/openaire-library index 27f644a..6ecde00 160000 --- a/src/app/openaire-library +++ b/src/app/openaire-library @@ -1 +1 @@ -Subproject commit 27f644aad1f4568a03bafbbd3d1640568a725957 +Subproject commit 6ecde003afe2cc7f4917b1d0f616d8c4b6355346 diff --git a/src/app/shared/utils/breadcrumbs/breadcrumbs.component.ts b/src/app/shared/utils/breadcrumbs/breadcrumbs.component.ts deleted file mode 100644 index 6c9803e..0000000 --- a/src/app/shared/utils/breadcrumbs/breadcrumbs.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Component, Input} from "@angular/core"; - -export interface Breadcrumb { - name: string; - route?: string; - keepFormat?: boolean -} - -@Component({ - selector: 'breadcrumbs', - template: ` - ` -}) -export class BreadcrumbsComponent { - - @Input() public light: boolean = false; - @Input() public breadcrumbs: Breadcrumb[] = []; - @Input() public addClass = ""; -} diff --git a/src/app/shared/utils/breadcrumbs/breadcrumbs.module.ts b/src/app/shared/utils/breadcrumbs/breadcrumbs.module.ts deleted file mode 100644 index 47b8b56..0000000 --- a/src/app/shared/utils/breadcrumbs/breadcrumbs.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {NgModule} from "@angular/core"; -import {CommonModule} from "@angular/common"; -import {BreadcrumbsComponent} from "./breadcrumbs.component"; -import {RouterModule} from "@angular/router"; - -@NgModule({ - imports: [CommonModule, RouterModule], - declarations: [BreadcrumbsComponent], - exports: [BreadcrumbsComponent] -}) -export class BreadcrumbsModule {} \ No newline at end of file diff --git a/src/app/shared/utils/click/click-outside-or-esc.directive.ts b/src/app/shared/utils/click/click-outside-or-esc.directive.ts deleted file mode 100644 index e536a08..0000000 --- a/src/app/shared/utils/click/click-outside-or-esc.directive.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {Directive, ElementRef, EventEmitter, HostListener, Output} from '@angular/core'; - -export interface ClickEvent { - event: any, - clicked: boolean; -} - -@Directive({ - selector: '[click-outside-or-esc]' -}) -export class ClickOutsideOrEsc { - @Output('clickOutside') clickOutside: EventEmitter = new EventEmitter(); - - constructor(private elementRef: ElementRef) {} - - @HostListener('document:click', ['$event']) - click(event) { - if(event.isTrusted) { - this.clickOutside.emit({ - event: event, - clicked: !(this.elementRef && this.elementRef.nativeElement.contains(event.target)) - }); - } - } - - @HostListener('window:keydown.escape', ['$event']) - esc(event: KeyboardEvent) { - this.clickOutside.emit({ - event: event, - clicked: true - }); - } -} diff --git a/src/app/shared/utils/click/click.module.ts b/src/app/shared/utils/click/click.module.ts deleted file mode 100644 index 4283a1e..0000000 --- a/src/app/shared/utils/click/click.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {NgModule} from "@angular/core"; -import {ClickOutsideOrEsc} from "./click-outside-or-esc.directive"; -import {LongClick} from "./long-click.directive"; - -@NgModule({ - imports: [], - declarations: [ - ClickOutsideOrEsc, LongClick - ], - exports: [ - ClickOutsideOrEsc, LongClick - ] -}) -export class ClickModule {} diff --git a/src/app/shared/utils/click/long-click.directive.ts b/src/app/shared/utils/click/long-click.directive.ts deleted file mode 100644 index bc8b095..0000000 --- a/src/app/shared/utils/click/long-click.directive.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {Directive, EventEmitter, HostListener, Input, Output} from '@angular/core'; - -@Directive({ - selector: '[long-click]' -}) - -export class LongClick { - - @Input() duration: number = 500; - - @Output() onLongPress: EventEmitter = new EventEmitter(); - @Output() onLongPressing: EventEmitter = new EventEmitter(); - @Output() onLongPressEnd: EventEmitter = new EventEmitter(); - - private pressing: boolean; - private longPressing: boolean; - private timeout: any; - private mouseX: number = 0; - private mouseY: number = 0; - - @HostListener('mousedown', ['$event']) - onMouseDown(event) { - // don't do right/middle clicks - if (event.which !== 1) return; - - this.mouseX = event.clientX; - this.mouseY = event.clientY; - - this.pressing = true; - this.longPressing = false; - - this.timeout = setTimeout(() => { - this.longPressing = true; - this.onLongPress.emit(event); - this.loop(event); - }, this.duration); - - this.loop(event); - } - - @HostListener('mousemove', ['$event']) - onMouseMove(event) { - if (this.pressing && !this.longPressing) { - const xThres = (event.clientX - this.mouseX) > 10; - const yThres = (event.clientY - this.mouseY) > 10; - if (xThres || yThres) { - this.endPress(); - } - } - } - - loop(event) { - if (this.longPressing) { - this.timeout = setTimeout(() => { - this.onLongPressing.emit(event); - this.loop(event); - }, 50); - } - } - - endPress() { - clearTimeout(this.timeout); - this.longPressing = false; - this.pressing = false; - this.onLongPressEnd.emit(true); - } - - @HostListener('mouseup') - onMouseUp() { - this.endPress(); - } -} diff --git a/src/app/shared/utils/icons/icons-preview/icons-preview.component.ts b/src/app/shared/utils/icons/icons-preview/icons-preview.component.ts deleted file mode 100644 index deb26a9..0000000 --- a/src/app/shared/utils/icons/icons-preview/icons-preview.component.ts +++ /dev/null @@ -1,97 +0,0 @@ -import {Component} from "@angular/core"; - -@Component({ - selector: 'icons-preview', - template: ` -
-

Icons

-
-
- -
book
-
-
- -
database
-
-
- -
cog
-
-
- -
earth
-
-
- -
incognito
-
-
- -
restricted
-
-
- -
graph
-
-
- -
orcid_add
-
-
- -
orcid_bin
-
-
- -
link
-
-
- -
quotes
-
-
- -
mining
-
-
-
-

Usage

-
    -
  • 1. Import IconsModule
  • -
  • 2. Add this to your module with these icons you will need
    -
    -
    constructor(private iconsService: IconsService) {{ "{" }}
    -   this.iconsService.registerIcons([edit]);
    -{{ "}" }}
    -
    -
  • -
  • 3. Use an icon with icon tag. Add parameter ratio to scale this icon. Default size 20x20 (ratio: 1)
    -
    -
    {{'<'}}icon name="edit"{{'><'}}/icon{{'>'}}
    -
    -
  • -
  • 4. Add a color class in parent of icon to give your icon a color.
    -
    -
    {{'<'}}div class="uk-text-secondary"{{'>'}}
    -  {{'<'}}icon name="edit"{{'><'}}/icon{{'>'}}
    -{{'<'}}/div{{'>'}}
    -
    -
  • -
-
-
-

Add a new icon

-
    -
  • 1. Go to Material Icons
  • -
  • 2. Find your icon and download it as svg.
  • -
  • 3. Open svg file with an editor and change width and height to 20
  • -
  • 4. Create an entry on icons file with your new icon.
  • -
-
-
- ` -}) -export class IconsPreviewComponent { - -} diff --git a/src/app/shared/utils/icons/icons-preview/icons-preview.module.ts b/src/app/shared/utils/icons/icons-preview/icons-preview.module.ts deleted file mode 100644 index 5ce06c3..0000000 --- a/src/app/shared/utils/icons/icons-preview/icons-preview.module.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {NgModule} from "@angular/core"; -import {CommonModule} from "@angular/common"; -import {RouterModule} from "@angular/router"; -import {IconsPreviewComponent} from "./icons-preview.component"; -import {IconsService} from "../icons.service"; -import {IconsModule} from "../icons.module"; -import { - book, - cog, - database, - earth, - filters, - graph, - incognito, link, mining, - orcid_add, - orcid_bin, - quotes, - restricted -} from "../icons"; - -@NgModule({ - imports: [CommonModule, RouterModule.forChild([ - {path: '', component: IconsPreviewComponent} - ]), IconsModule], - declarations: [IconsPreviewComponent], - exports: [IconsPreviewComponent] -}) -export class IconsPreviewModule { - constructor(private iconsService: IconsService) { - this.iconsService.registerIcons([book, database, cog, earth, incognito, restricted, graph, filters, orcid_add, orcid_bin, link, quotes, mining]) - } -} diff --git a/src/app/shared/utils/icons/icons.component.ts b/src/app/shared/utils/icons/icons.component.ts deleted file mode 100644 index e44a146..0000000 --- a/src/app/shared/utils/icons/icons.component.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - ElementRef, - Input, - OnChanges, - SimpleChanges, - ViewChild -} from "@angular/core"; -import {IconsService} from "./icons.service"; - -export interface StopRule { - class: string, - offset: number -} - -/** - * By default, this component uses Material Icons Library to render an icon with - * a specific @name. For custom icons you should: - * - * - Add your icon in icons.ts and register it to Icon registry, by adding this to your component Module. - * - * e.g export class ExampleModule { - * constructor(private iconsService: IconsService) { - * this.iconsService.registerIcons([arrow_right]) - * } - * } - * - * If the name of your icon is the same with a Material Icon name, yours will be used instead of the default. - * - * - Custom SVG Icon. Define a variable in your component with an SVG and give it as Input @svg. - * - * In case of SVGs, there is an opportunity to add gradient color by define at least a start and end stop-color rules - * and an id to support them. This option is enabled by giving id as input in @gradient (Optional @degrees for gradient direction) - * - * e.g #gradient .start { - * stop-color: red; - * } - * - * e.g #gradient .end { - * stop-color: orange; - * } - * - * */ -@Component({ - selector: 'icon', - template: ` - - - {{iconName}} - - {{visuallyHidden}} - ` -}) -export class IconsComponent implements AfterViewInit, OnChanges { - private static DEFAULT_ICON_SIZE = 20; - public iconName: string; - public style; - /** - * Custom icon as SVG - */ - @Input() - public svg; - @Input() - public defaultSize = false; - /** - * True if this icon should have display flex (Optional, Default: false) - * - * */ - @Input() - public flex = false; - /** - * - * Add custom class(es)(Optional) - * */ - @Input() - public customClass = ''; - /** - * Color of svg (Optional) - * */ - @Input() - public fill; - /** - * Color of svg stroke (Optional) - * */ - @Input() - public stroke; - /** - * Size of icon (Default: 1) - * - * Disabled if defaultSize = true - * */ - @Input() - public ratio = 1; - /** - * In case of Material icon only. Type of icon (Optional) - * */ - @Input() - public type: "outlined" | "round" | "sharp" | "two-tone" | null = null; - /** - * Name of icon in registry (Required) - * */ - @Input() - set name(iconName: string) { - this.iconName = iconName; - this.svg = this.iconsService.getIcon(iconName); - } - /** - * Set visually hidden name for accessibility - * */ - @Input() - public visuallyHidden: string = null; - /** - * Gradient rules - * Available only for SVG! - * - * Define your css rules for stop-colors - * */ - @Input() - public gradient: string = null; - @Input() - public degrees: number = 0; - @Input() - public stopRules: StopRule[]= [{class: 'start', offset: 0}, {class: 'end', offset: 100}]; - @ViewChild("icon") - public icon: ElementRef; - - constructor(private iconsService: IconsService, - private cdr: ChangeDetectorRef) {} - - ngAfterViewInit() { - this.initIcon(); - } - - ngOnChanges(changes: SimpleChanges) { - this.initIcon(); - } - - initIcon() { - if(this.svg && this.icon) { - this.cdr.detectChanges(); - let svg: Element = this.icon.nativeElement.getElementsByTagName('svg').item(0); - if(!this.defaultSize && svg) { - svg.setAttribute("width", (this.ratio * IconsComponent.DEFAULT_ICON_SIZE).toString()); - svg.setAttribute("height", (this.ratio * IconsComponent.DEFAULT_ICON_SIZE).toString()); - } - if(this.gradient && svg) { - this.addGradient(svg); - } else { - this.style = { - fill: this.fill, - stroke: this.stroke - }; - } - } else { - this.style = { - "font-size.px": this.ratio*IconsComponent.DEFAULT_ICON_SIZE - }; - } - this.cdr.detectChanges(); - } - - addGradient(svg: Element) { - if(svg.children.length > 0 && typeof document !== "undefined") { - let gradientDefinition = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'); - gradientDefinition.setAttribute('id', this.gradient); - if(this.degrees !== 0) { - let angle = (this.degrees) * (Math.PI / 180); - gradientDefinition.setAttribute('x1', Math.round(50 + Math.sin(angle + Math.PI) * 50) + '%'); - gradientDefinition.setAttribute('y1', Math.round(50 + Math.cos(angle + Math.PI) * 50) + '%'); - gradientDefinition.setAttribute('x2', Math.round(50 + Math.sin(angle) * 50) + '%'); - gradientDefinition.setAttribute('y2', Math.round(50 + Math.cos(angle) * 50) + '%'); - } - for(let rule of this.stopRules) { - let item = document.createElementNS('http://www.w3.org/2000/svg','stop'); - item.setAttribute('class', rule.class); - item.setAttribute('offset', rule.offset + '%'); - gradientDefinition.appendChild(item); - } - let defs = document.createElementNS('http://www.w3.org/2000/svg','defs'); - defs.appendChild(gradientDefinition); - for(let i = 0; i < svg.children.length; i++) { - let item = svg.children.item(i); - if(!item.hasAttribute('fill')) { - item.setAttribute('fill', "url('#" + this.gradient + "')"); - } - } - svg.insertBefore(defs, svg.childNodes[0]); - } - } -} diff --git a/src/app/shared/utils/icons/icons.module.ts b/src/app/shared/utils/icons/icons.module.ts deleted file mode 100644 index bdbd84f..0000000 --- a/src/app/shared/utils/icons/icons.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {NgModule} from "@angular/core"; -import {CommonModule} from "@angular/common"; -import {IconsComponent} from "./icons.component"; - -@NgModule({ - imports: [CommonModule], - declarations: [IconsComponent], - exports: [IconsComponent] -}) -export class IconsModule {} diff --git a/src/app/shared/utils/icons/icons.service.ts b/src/app/shared/utils/icons/icons.service.ts deleted file mode 100644 index 151fc64..0000000 --- a/src/app/shared/utils/icons/icons.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {Injectable} from "@angular/core"; -import {Icon} from "./icons"; - -@Injectable({ - providedIn: 'root' -}) -export class IconsService { - - private registry = new Map(); - - public registerIcons(icons: any[]): void { - icons.forEach((icon: Icon) => this.registry.set(icon.name, icon.data)); - } - - public getIcon(iconName: string): string | undefined { - return this.registry.get(iconName); - } -} diff --git a/src/app/shared/utils/icons/icons.ts b/src/app/shared/utils/icons/icons.ts deleted file mode 100644 index 1a6447d..0000000 --- a/src/app/shared/utils/icons/icons.ts +++ /dev/null @@ -1,226 +0,0 @@ -export interface Icon { - name: string, - data: string -} - -/** @deprecated */ -export const arrow_left: Icon = { - name: 'arrow_left', - data: '' -} - -/** @deprecated */ -export const arrow_right: Icon = { - name: 'arrow_right', - data: '' -}; - -/** @deprecated */ -export const arrow_up: Icon = { - name: 'arrow_up', - data: '' -} - -/** @deprecated */ -export const arrow_down: Icon = { - name: 'arrow_down', - data: '' -} - -export const book: Icon = { - name: 'book', - data: '' -}; - -export const database: Icon = { - name: 'database', - data: '' -}; - -export const cog: Icon = { - name: 'cog', - data: '' -}; - -export const earth: Icon = { - name: 'earth', - data: '' -} - -/** @deprecated */ -export const edit: Icon = { - name: 'edit', - data: '' -} - -/** @deprecated - * - * Use delete - * */ -export const remove: Icon = { - name: 'remove', - data: '' -} - -/** @deprecated - * Use visibility - * */ -export const preview: Icon = { - name: 'preview', - data: '' -} - -/** @deprecated */ -export const bullet: Icon = { - name: 'bullet', - data: '' -} - -/** @deprecated */ -export const remove_circle = { - name: 'remove_circle', - data: '' -} - -/** @deprecated */ -export const remove_circle_outline = { - name: 'remove_circle_outline', - data: '' -} - -/** @deprecated */ -export const person_add = { - name: 'person_add', - data: '' -} - -/** @deprecated */ -export const cloud_upload = { - name: 'cloud_upload', - data: '' -} - -/** @deprecated */ -export const add = { - name: 'add', - data: '' -} - -/** @deprecated */ -export const group = { - name: 'group', - data: '' -} - -/** @deprecated */ -export const lock = { - name: 'lock', - data: '' -} - -/** @deprecated */ -export const search = { - name: 'search', - data: '' -} - -/** @deprecated */ -export const refresh = { - name: 'refresh', - data: '' -} - -/** @deprecated */ -export const close = { - name: 'close', - data: '' -} - -/** @deprecated */ -export const done = { - name: 'done', - data: '' -} - -/** @deprecated */ -export const mail = { - name: 'mail', - data: '' -} - -/** @deprecated */ -export const photo = { - name: 'photo', - data: '' -} - -/** @deprecated */ -export const check_circle_outlined = { - name: 'check_circle_outlined', - data: '' -} - -/** @deprecated */ -export const reset = { - name: 'reset', - data: '' -} - -/** @deprecated */ -export const send = { - name: 'send', - data: '' -} - -/** @deprecated */ -export const print = { - name: 'print', - data: '' -} - -export const incognito = { - name: 'incognito', - data: '' -} - -export const restricted = { - name: 'restricted', - data: '' -} - -export const graph = { - name: 'graph', - data: '' -} - -export const filters = { - name: 'filters', - data: '' -} - -export const orcid_add = { - name: 'orcid_add', - data: '' -} - -export const orcid_bin = { - name: 'orcid_bin', - data: '' -} - -export const link = { - name: 'link', - data: '' -} - -export const quotes = { - name: 'quotes', - data: '' -} - -export const mining = { - name: 'mining', - data: '' -} - -/** Add new icon under this line to be sure that it will be added on preview */ diff --git a/src/app/shared/utils/input/input.component.ts b/src/app/shared/utils/input/input.component.ts deleted file mode 100644 index a01a66f..0000000 --- a/src/app/shared/utils/input/input.component.ts +++ /dev/null @@ -1,626 +0,0 @@ -import { - AfterViewInit, - ChangeDetectorRef, - Component, - ElementRef, - EventEmitter, - HostListener, - Input, - OnChanges, - OnDestroy, - OnInit, - Output, - SimpleChanges, - ViewChild -} from "@angular/core"; -import {AbstractControl, UntypedFormArray, UntypedFormControl, ValidatorFn} from "@angular/forms"; -// import {HelperFunctions} from "../../utils/HelperFunctions.class"; -import {Subscription} from "rxjs"; -import {ClickEvent} from "../click/click-outside-or-esc.directive"; -// import {EnvProperties} from "../../utils/properties/env-properties"; -// import {properties} from "../../../../environments/environment"; - -export type InputType = 'text' | 'URL' | 'logoURL' | 'autocomplete' | 'autocomplete_soft' | 'textarea' | 'select' | 'chips'; - -export interface Option { - icon?: string, - iconClass?: string, - value: any, - label: string, - tooltip?: string, - disabled?: boolean, - hidden?: boolean -} - -export interface Placeholder { - label: string, - static?: boolean -} - -declare var UIkit; - -/** - * WARNING! dashboard-input selector is @deprecated, use input instead - * - * Autocomplete soft allows values that are not listed in options list. In order to work as expected - * avoid providing options with different label and value. - * - * */ -@Component({ - selector: '[dashboard-input], [input]', - template: ` -
-
-
-
- -
-
- - - - - - - - -
{{placeholderInfo.label}}
-
{{getLabel(formControl.value)}}
-
- -
{{noValueSelected}}
-
{{getLabel(formControl.value)}}
-
-
- - -
{{getLabel(formAsControl.value)}}
- -
{{noValueSelected}}
-
{{getLabel(formControl.value)}}
-
-
- - - - -
-
-
- {{getLabel(chip.value)}} - -
-
-
- -
-
- + {{(formAsArray.length - 1)}} more -
-
-
-
- - - - - - - -
-
-
- -
-
-
- -
- - {{formControl.errors.error}} - Please provide a valid URL (e.g. https://example.com) - - - - - - - - Note: Prefer urls like "https://example.com/my-secure-image.png" - instead of "http://example.com/my-image.png". - Browsers may not load non secure content. - - - - - - ` -}) -export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChanges { - private static INPUT_COUNTER: number = 0; - /** Deprecated options*/ - /** @deprecated */ - @Input('label') label: string; - /** @deprecated */ - @Input() extraLeft: boolean = true; - /** @deprecated */ - @Input() gridSmall: boolean = false; - /** @deprecated */ - @Input() hideControl: boolean = false; - /** @deprecated */ - @Input() flex: 'middle' | 'top' | 'bottom' = 'middle'; - /** @deprecated */ - @Input() iconLeft: boolean = false; - /** @deprecated */ - @Input() removable: boolean = true; - /** @deprecated */ - @Input() smallChip: boolean = false; - /** @deprecated */ - @Input() panelWidth: number = 300; - /** @deprecated */ - @Input() panelClass: string = null; - /** Basic information */ - @Input('formInput') formControl: AbstractControl; - @Input('type') type: InputType = 'text'; - @Input() validators: ValidatorFn[] | ValidatorFn; - @Input() disabled: boolean = false; - @Input() disabledIcon: string = 'lock'; - @Input() value: any | any[]; - @Output() valueChange = new EventEmitter(); - @Input() hint: string; - @Input() tooltip: boolean = false; - @Input() searchable: boolean = false; - /** Text */ - @ViewChild('input') input: ElementRef; - /** Textarea options */ - @ViewChild('textArea') textArea: ElementRef; - @Input('rows') rows: number = 3; - /** Select | Autocomplete | chips available options */ - @Input() selectArrow: string = 'arrow_drop_down'; - @Input() selectedIndex: number = 0; - @Input() selectable: boolean = false; - @Input() noValueSelected: string = 'No option selected'; - /** Chips && Autocomplete*/ - public filteredOptions: Option[] = []; - public searchControl: UntypedFormControl; - /** Use modifier's class(es) to change view of your Input */ - @Input() inputClass: string = 'inner'; - /** Icon on the input */ - @Input() icon: string = null; - /** Chip options */ - @Input() addExtraChips: boolean = false; - @Input() showOptionsOnEmpty: boolean = true; - @Output() focusEmitter: EventEmitter = new EventEmitter(); - /** LogoUrl information */ - public secure: boolean = true; - /** Internal basic information */ - public id: string; - public placeholderInfo: Placeholder = {label: '', static: true}; - public required: boolean = false; - public focused: boolean = false; - public opened: boolean = false; - private initValue: any; - private optionsArray: Option[] = []; - private optionsBreakpoint: number = 6; - private subscriptions: any[] = []; - @ViewChild('inputBox') inputBox: ElementRef; - @ViewChild('optionBox') optionBox: ElementRef; - @ViewChild('searchInput') searchInput: ElementRef; - - @Input() - set placeholder(placeholder: string | Placeholder) { - if (typeof placeholder === 'string') { - this.placeholderInfo = {label: placeholder, static: false}; - } else { - if (placeholder.static && (this.type === 'autocomplete' || this.type === 'chips' || this.hint)) { - placeholder.static = false; - console.debug('Static placeholder is not available in this type of input and if hint is available.'); - } - this.placeholderInfo = placeholder; - } - } - - @Input() - set options(options: (Option | string | number) []) { - this.optionsArray = options.map(option => { - if (typeof option === 'string' || typeof option === 'number') { - return { - label: option.toString(), - value: option - }; - } else { - return option; - } - }); - if(!this.tooltip) { - this.tooltip = this.optionsArray.length > 0; - } - if(this.type === "select") { - if (this.optionsArray.length > this.optionsBreakpoint) { - this.type = 'autocomplete'; - this.showOptionsOnEmpty = true; - this.icon = this.selectArrow; - } - this.selectable = true; - } - } - - constructor(private elementRef: ElementRef, private cdr: ChangeDetectorRef) {} - - @HostListener('window:keydown.arrowUp', ['$event']) - arrowUp(event: KeyboardEvent) { - if (this.opened) { - event.preventDefault(); - if (this.selectedIndex > 0) { - this.selectedIndex--; - this.optionBox.nativeElement.scrollBy(0, -34); - } - } - } - - @HostListener('window:keydown.arrowDown', ['$event']) - arrowDown(event: KeyboardEvent) { - if (this.opened) { - event.preventDefault(); - if (this.selectedIndex < (this.filteredOptions.length - 1)) { - this.selectedIndex++; - this.optionBox.nativeElement.scrollBy(0, 34); - } - } - } - - @HostListener('window:keydown.enter', ['$event']) - enter(event: KeyboardEvent) { - if (this.opened && this.optionBox) { - event.preventDefault(); - if (this.filteredOptions[this.selectedIndex]) { - this.selectOption(this.filteredOptions[this.selectedIndex], event); - } - this.open(false); - event.stopPropagation(); - } else { - this.focus(false, event); - } - } - - click(event: ClickEvent) { - this.focus(!event.clicked, event); - } - - ngOnInit() { - InputComponent.INPUT_COUNTER++; - this.id = 'input-' + InputComponent.INPUT_COUNTER; - if (!this.formControl) { - if (Array.isArray(this.value)) { - this.formControl = new UntypedFormArray([]); - this.value.forEach(value => { - this.formAsArray.push(new UntypedFormControl(value, this.validators)); - }); - } else { - this.formControl = new UntypedFormControl(this.value); - this.formControl.setValidators(this.validators); - } - if (this.disabled) { - this.formControl.disable(); - } - } - } - - ngAfterViewInit() { - this.reset(); - } - - ngOnChanges(changes: SimpleChanges) { - if (this.formControl) { - if (changes.value) { - this.formControl.setValue(this.value); - } - if (changes.formControl || changes.validators || changes.options) { - this.reset(); - } - if (changes.disabled) { - if (this.disabled) { - this.formControl.disable(); - } else { - this.formControl.enable(); - } - } - } - } - - ngOnDestroy(): void { - this.unsubscribe(); - } - - get formAsControl(): UntypedFormControl { - if (this.formControl instanceof UntypedFormControl) { - return this.formControl; - } else { - return null; - } - } - - get formAsArray(): UntypedFormArray { - if (this.formControl instanceof UntypedFormArray) { - return this.formControl; - } else { - return null; - } - } - - reset() { - this.secure = true; - this.unsubscribe(); - this.initValue = this.copy(this.formControl.value); - if (this.type === 'logoURL') { - this.secure = (!this.initValue || this.initValue.includes('https://')); - } - if (this.optionsArray) { - this.filteredOptions = this.filter(''); - this.cdr.detectChanges(); - } - if (this.type === 'chips' || this.type === 'autocomplete') { - if (!this.searchControl) { - this.searchControl = new UntypedFormControl('', this.validators); - } - this.subscriptions.push(this.searchControl.valueChanges.subscribe(value => { - this.filteredOptions = this.filter(value); - this.cdr.detectChanges(); - if (this.focused) { - this.open(true); - setTimeout(() => { - this.searchInput.nativeElement.focus(); - this.searchInput.nativeElement.value = value; - }, 0); - } - })); - } - if (this.formControl.validator) { - let validator = this.formControl.validator({} as AbstractControl); - this.required = (validator && validator.required); - } - this.subscriptions.push(this.formControl.valueChanges.subscribe(value => { - if (this.formControl.enabled) { - value = (value === '') ? null : value; - if (this.type === 'logoURL') { - this.secure = (!value || value.includes('https://')); - } - if (this.initValue === value || (this.initValue === '' && value === null)) { - this.formControl.markAsPristine(); - } else { - this.formControl.markAsDirty(); - } - if (this.type === 'autocomplete_soft') { - this.filteredOptions = this.filter(value); - this.cdr.detectChanges(); - if (this.focused) { - this.open(true); - } - } - if ((this.value && value && this.value !== value) || (!this.value && value) || this.value && !value) { - this.valueChange.emit(this.formControl.value); - } - } - })); - if (this.input) { - this.input.nativeElement.disabled = this.formControl.disabled; - } - } - - unsubscribe() { - this.subscriptions.forEach(subscription => { - if (subscription instanceof Subscription) { - subscription.unsubscribe(); - } - }); - } - - remove(index: number, event) { - if (this.focused) { - this.formAsArray.removeAt(index); - this.formAsArray.markAsDirty(); - this.focus(true); - this.searchControl.setValue(''); - event.stopPropagation(); - } - } - - private filter(value: string): Option[] { - let options = this.optionsArray.filter(option => !option.hidden); - if (this.type === "chips") { - options = options.filter(option => !this.formAsArray.value.find(value => this.equals(option.value, value))); - } - if ((!value || value.length == 0)) { - this.selectedIndex = 0; - return (this.showOptionsOnEmpty) ? options : []; - } - const filterValue = value.toString().toLowerCase(); - options = options.filter(option => option.label.toLowerCase().indexOf(filterValue) != -1); - this.selectedIndex = options.findIndex(option => option.value === this.formControl.value); - if (this.selectedIndex === -1) { - this.selectedIndex = 0; - } - return options; - } - - add(event) { - if (this.addExtraChips && this.searchControl.value && this.searchControl.valid) { - if (event && event.stopPropagation) { - event.stopPropagation(); - } - this.formAsArray.push(new UntypedFormControl(this.searchControl.value, this.validators)); - this.formAsArray.markAsDirty(); - } - this.searchControl.setValue(''); - } - - getLabel(value: any): string { - let option = this.optionsArray.find(option => this.equals(option.value, value)); - return (option) ? option.label : (value); - } - - getTooltip(value: any): string { - let option = this.optionsArray.find(option => this.equals(option.value, value)); - return (option) ? (option.tooltip ? option.tooltip : option.label) : (value); - } - - focus(value: boolean, event = null) { - if (this.focused) { - this.formControl.markAsTouched(); - } - this.focused = value; - this.cdr.detectChanges(); - if (this.focused) { - if (this.input) { - this.input.nativeElement.focus(); - } else if (this.textArea) { - this.textArea.nativeElement.focus(); - } else if (this.searchInput) { - this.searchInput.nativeElement.focus(); - } - if (this.selectArrow) { - this.open(!this.opened); - } else if (this.type !== 'autocomplete' || this.showOptionsOnEmpty || !this.formControl.value) { - this.open(true); - } - } else { - this.open(false); - if (this.input) { - this.input.nativeElement.blur(); - } else if (this.textArea) { - this.textArea.nativeElement.blur(); - } else if (this.searchInput) { - this.searchInput.nativeElement.blur(); - } - if (this.searchControl) { - this.add(event); - } - } - this.focusEmitter.emit(this.focused); - } - - open(value: boolean) { - this.opened = value && this.formControl.enabled; - this.cdr.detectChanges(); - if (this.optionBox && this.opened) { - this.selectedIndex = this.filteredOptions.findIndex(option => option.value === this.formControl.value); - if (this.selectedIndex === -1 && this.type !== 'autocomplete_soft') { - this.selectedIndex = 0; - } - UIkit.dropdown(this.optionBox.nativeElement).show(); - } else { - if (this.optionBox) { - UIkit.dropdown(this.optionBox.nativeElement).hide(); - this.focused = false; - } - } - } - - resetSearch(event: any) { - event.stopPropagation(); - this.searchControl.setValue(''); - this.focus(true, event); - } - - resetValue(event: any) { - event.stopPropagation(); - this.formControl.setValue(''); - this.focus(true, event); - } - - selectOption(option: Option, event) { - if (this.formControl.enabled) { - if (this.formAsControl) { - this.formAsControl.setValue(option.value); - } else if (this.formAsArray) { - this.formAsArray.push(new UntypedFormControl(option.value)); - this.formAsArray.markAsDirty(); - event.stopPropagation(); - this.focus(true); - this.searchControl.setValue(''); - } - } - } - - - - // External Helper Methods - public equals(object1, object2) { - return object1 === object2 || JSON.stringify(object1) === JSON.stringify(object2); - } - - public copy(obj: any): any { - let copy; - - // Handle the 3 simple types, and null or undefined - if (null == obj || "object" != typeof obj) return obj; - - // Handle Date - if (obj instanceof Date) { - copy = new Date(); - copy.setTime(obj.getTime()); - return copy; - } - - // Handle Array - if (obj instanceof Array) { - copy = []; - for (let i = 0, len = obj.length; i < len; i++) { - copy[i] = this.copy(obj[i]); - } - return copy; - } - - // Handle Map - if (obj instanceof Map) { - return new Map(obj.entries()); - } - - // Handle Object - if (obj instanceof Object) { - copy = {}; - for (let attr in obj) { - if (obj.hasOwnProperty(attr)) { - copy[attr] = this.copy(obj[attr]); - } - } - return copy; - } - throw new Error("Unable to copy obj! Its type isn't supported."); - } -} diff --git a/src/app/shared/utils/input/input.module.ts b/src/app/shared/utils/input/input.module.ts deleted file mode 100644 index 29a0622..0000000 --- a/src/app/shared/utils/input/input.module.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {NgModule} from '@angular/core'; -import {InputComponent} from "./input.component"; -import {CommonModule} from "@angular/common"; -import {RouterModule} from "@angular/router"; -import {FormsModule, ReactiveFormsModule} from "@angular/forms"; -import {ClickModule} from "../click/click.module"; - -@NgModule({ - imports: [ - CommonModule, - RouterModule, - FormsModule, - ReactiveFormsModule, - ClickModule - ], - exports: [ - InputComponent - ], - declarations: [ - InputComponent - ] -}) -export class InputModule { -} diff --git a/src/app/shared/utils/modal/alert.ts b/src/app/shared/utils/modal/alert.ts deleted file mode 100644 index f9599ca..0000000 --- a/src/app/shared/utils/modal/alert.ts +++ /dev/null @@ -1,191 +0,0 @@ -import {Component, ElementRef, EventEmitter, Input, Output, ViewChild, ViewEncapsulation} from '@angular/core'; - -declare var UIkit: any; - -@Component({ - selector: 'modal-alert', - template: ` -
-
-
-
-
{{alertTitle}}
-
- -
-
-
- -
- -
-
- `, - encapsulation: ViewEncapsulation.None, -}) -/** - * API to an open alert window. - */ -export class AlertModal { - private static MODAL_COUNTER: number = 0; - - id: string = "modal"; - @Input() classTitle: string = "uk-background-primary-opacity"; - @Input() classBody: string = ""; - @Input() large: boolean = false; - @Input() overflowBody: boolean = true; - /** - * Caption for the title. - */ - public alertTitle: string; - /** - * Describes if the alert contains Ok Button. - * The default Ok button will close the alert and emit the callback. - * Defaults to true. - */ - public okButton: boolean = true; - /** - * Caption for the OK button. - * Default: Ok - */ - public okButtonText: string = 'OK'; - /** - * Describes if the alert contains cancel Button. - * The default Cancelbutton will close the alert. - * Defaults to true. - */ - public cancelButton: boolean = true; - /** - * Caption for the Cancel button. - * Default: Cancel - */ - public cancelButtonText: string = 'Cancel'; - /** - * if the alertMessage is true it will show the contentString inside alert body. - */ - public alertMessage: boolean = true; - /** - * Some message/content can be set in message which will be shown in alert body. - */ - public message: string; - /** - * if the value is true alert footer will be visible or else it will be hidden. - */ - public alertFooter: boolean = true; - /** - * shows alert header if the value is true. - */ - public alertHeader: boolean = true; - /** - * if the value is true ok button align on the left, else on the right - */ - public okButtonLeft: boolean = true; - - /** - * if the value is true ok button is disabled - */ - @Input() - public okDisabled: boolean = false; - - /** - * If the value is true, a checkbox option will be appeared on the right side of footer - */ - @Input() - public choice: boolean = false; - - /** - * if the value is true then on ok clicked, modal will stay open. - */ - public stayOpen: boolean = false; - - /** - * Value will be emitted if @choice is true - */ - public select: boolean = true; - /** - * Emitted when ok button was clicked - * or when Ok method is called. - */ - @Output() public alertOutput: EventEmitter = new EventEmitter(); - /** - * Emitted when cancel button was clicked - * or when cancel method is called. - */ - @Output() public cancelOutput: EventEmitter = new EventEmitter(); - - @ViewChild('element') element: ElementRef; - - constructor() { - } - - ngOnInit() { - AlertModal.MODAL_COUNTER++; - this.id = 'modal-' + AlertModal.MODAL_COUNTER; - } - - ngOnDestroy() { - if(typeof document !== "undefined") { - const element = document.getElementById("modal-container"); - for (let i = element.childNodes.length - 1; i >= 0; --i) { - let child: ChildNode = element.childNodes[i]; - if (child['id'] == this.id) { - child.remove(); - } - } - } - } - - /** - * Opens an alert window creating backdrop. - */ - open() { - UIkit.modal(this.element.nativeElement).show(); - } - - /** - * ok method closes the modal and emits modalOutput. - */ - ok() { - if (!this.stayOpen) { - UIkit.modal(this.element.nativeElement).hide(); - } - if (!this.choice) { - this.alertOutput.emit(true); - } else { - this.alertOutput.emit({ - value: true, - choice: this.select - }); - } - } - - /** - * cancel method closes the modal. - */ - cancel() { - UIkit.modal(this.element.nativeElement).hide(); - this.cancelOutput.emit(true); - } -} diff --git a/src/app/shared/utils/modal/alertModal.module.ts b/src/app/shared/utils/modal/alertModal.module.ts deleted file mode 100644 index bf0d941..0000000 --- a/src/app/shared/utils/modal/alertModal.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; - -import {AlertModal} from './alert'; -import {ModalModule} from './modal.module'; -import {IconsModule} from "../icons/icons.module"; - -@NgModule({ - imports: [CommonModule, FormsModule, ModalModule, IconsModule], - declarations: [ - AlertModal - ], - exports: [ - AlertModal - ] -}) -export class AlertModalModule { } diff --git a/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.component.ts b/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.component.ts deleted file mode 100644 index 750286a..0000000 --- a/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.component.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { - AfterViewInit, ChangeDetectorRef, - Component, - ElementRef, - EventEmitter, HostListener, - Input, - OnDestroy, - OnInit, - Output, - ViewChild -} from "@angular/core"; -import {fromEvent, Subscription} from 'rxjs'; -import {delay} from "rxjs/operators"; -import {HelperFunctions} from "../../HelperFunctions.class"; - -declare var UIkit; -declare var ResizeObserver; - -@Component({ - selector: 'fs-modal', - template: ` -
-
-
-
- -
-
-

{{title}}

-
-
- - -
-
-
-
- -
-
-
-
- ` -}) -export class FullScreenModalComponent implements AfterViewInit, OnDestroy { - private static FS_MODAL_COUNTER: number = 0; - - id: string = "fs-modal"; - @Input() classTitle: string = "uk-background-primary uk-light"; - @Input() classBody: string = 'uk-container-large'; - back: boolean = false; - title: string; - okButton: boolean = false; - okButtonText = 'OK'; - @Input() - okButtonDisabled = false; - @Output() - okEmitter: EventEmitter = new EventEmitter(); - @Output() - cancelEmitter: EventEmitter = new EventEmitter(); - @ViewChild('modal') modal: ElementRef; - @ViewChild('header') header: ElementRef; - @ViewChild('body') body: ElementRef; - observer: any; - headerHeight: number; - bodyHeight: number; - - constructor(private cdr: ChangeDetectorRef) { - } - - @HostListener('window:resize', ['$event']) - onResize() { - this.changeHeight(); - } - - ngOnInit() { - FullScreenModalComponent.FS_MODAL_COUNTER++; - this.id = 'fs-modal-' + FullScreenModalComponent.FS_MODAL_COUNTER; - } - - ngAfterViewInit() { - if(typeof window !== "undefined") { - this.observer = new ResizeObserver(entries => { - for (let entry of entries) { - this.changeHeight(); - } - }); - this.observer.observe(this.header.nativeElement); - } - } - - /* Height = Viewport - header - (Body padding) */ - changeHeight() { - if(typeof window !== "undefined" && this.header) { - this.bodyHeight = window.innerHeight - this.header.nativeElement.clientHeight - 80; - this.cdr.detectChanges(); - } - } - - ngOnDestroy() { - if(this.observer && this.observer instanceof ResizeObserver) { - this.observer.disconnect(); - } - if(typeof document !== "undefined") { - const element = document.getElementById("modal-container"); - for (let i = element.childNodes.length - 1; i >= 0; --i) { - let child: ChildNode = element.childNodes[i]; - if (child['id'] == this.id) { - child.remove(); - } - } - } - - } - - get isOpen() { - return this.modal && UIkit.modal(this.modal.nativeElement).isToggled(); - } - - open() { - UIkit.modal(this.modal.nativeElement).show(); - HelperFunctions.scroll(); - } - - cancel() { - UIkit.modal(this.modal.nativeElement).hide(); - HelperFunctions.scroll(); - this.cancelEmitter.emit(); - } - - ok() { - UIkit.modal(this.modal.nativeElement).hide(); - HelperFunctions.scroll(); - this.okEmitter.emit(true); - } -} diff --git a/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.module.ts b/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.module.ts deleted file mode 100644 index ab5537d..0000000 --- a/src/app/shared/utils/modal/full-screen-modal/full-screen-modal.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {NgModule} from "@angular/core"; -import {CommonModule} from "@angular/common"; -import {FullScreenModalComponent} from "./full-screen-modal.component"; -import {IconsModule} from "../../icons/icons.module"; - -@NgModule({ - imports: [CommonModule, IconsModule], - declarations: [FullScreenModalComponent], - exports: [FullScreenModalComponent] -}) -export class FullScreenModalModule { -} diff --git a/src/app/shared/utils/modal/loading.component.ts b/src/app/shared/utils/modal/loading.component.ts deleted file mode 100644 index 81c84c2..0000000 --- a/src/app/shared/utils/modal/loading.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {Component, ViewEncapsulation, ComponentRef, ElementRef, Input, EventEmitter, Output} from '@angular/core'; - -@Component({ - selector: 'modal-loading', - template: ` - -
-
- - -
-
-

{{message}}

- - - - -
-
- -
- -
- - `, - encapsulation: ViewEncapsulation.None, -}) -/** - * API to an open alert window. - */ -export class ModalLoading{ - -@Input() public message:string ="Loading"; - - /** - * if the value is true alert will be visible or else it will be hidden. - */ - public isOpen:boolean=false; - /** - * Emitted when a ok button was clicked - * or when Ok method is called. - */ - @Output() public alertOutput:EventEmitter = new EventEmitter(); - constructor( public _elementRef: ElementRef){} - /** - * Opens a alert window creating backdrop. - */ - open(){ - this.isOpen= true; - } - - close(){ - this.isOpen = false; - } -} diff --git a/src/app/shared/utils/modal/loadingModal.module.ts b/src/app/shared/utils/modal/loadingModal.module.ts deleted file mode 100644 index 6edf5c4..0000000 --- a/src/app/shared/utils/modal/loadingModal.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; - - import {ModalLoading} from './loading.component'; -import {ModalModule} from './modal.module'; - -//helpers - -@NgModule({ - imports: [ CommonModule, FormsModule,ModalModule ], - declarations: [ - ModalLoading - ], - exports: [ - ModalLoading - ] -}) -export class LoadingModalModule { } diff --git a/src/app/shared/utils/modal/modal.module.ts b/src/app/shared/utils/modal/modal.module.ts deleted file mode 100644 index 6b76d1a..0000000 --- a/src/app/shared/utils/modal/modal.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* common components of modal components */ -import {NgModule} from '@angular/core'; -import {Open} from './open.component'; - -@NgModule({ - imports: [], - declarations: [ - Open - ], - exports: [ - Open - ] -}) -export class ModalModule { -} diff --git a/src/app/shared/utils/modal/open.component.ts b/src/app/shared/utils/modal/open.component.ts deleted file mode 100644 index fb9f011..0000000 --- a/src/app/shared/utils/modal/open.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -import {Directive, Input, HostBinding} from '@angular/core'; - -// todo: add animate -// todo: add init and on change -@Directive({selector: '[open]'}) -export class Open { - @HostBinding('style.display') - public display:string; - @HostBinding('class.in') - @HostBinding('attr.aria-expanded') - public isExpanded:boolean = true; - - @Input() - public set open(value:boolean) { - this.isExpanded = value; - this.toggle(); - } - - public get open():boolean { - return this.isExpanded; - } - - constructor() { - } - init() { - this.isExpanded = false; - this.display = 'none'; - } - toggle() { - if (this.isExpanded) { - this.hide(); - } else { - this.show(); - } - } - - hide() { - this.isExpanded = false; - this.display = 'none'; - if (typeof document !== 'undefined') { - let backDrop = document.getElementsByClassName("modal-backdrop"); - if(backDrop.length>0){ - document.body.removeChild(backDrop[0]); - } - } - } - - show() { - if (typeof document !== 'undefined') { - // let backDrop = document.createElement('div'); - // backDrop.className="modal-backdrop fade in"; - // document.body.appendChild(backDrop); - } - this.isExpanded = true; - this.display = 'block'; - } -} diff --git a/src/app/shared/utils/string-utils.class.ts b/src/app/shared/utils/string-utils.class.ts deleted file mode 100644 index 8eb8ab1..0000000 --- a/src/app/shared/utils/string-utils.class.ts +++ /dev/null @@ -1,455 +0,0 @@ -import {UrlSegment} from '@angular/router'; -import {AbstractControl, UntypedFormGroup, ValidationErrors, ValidatorFn, Validators} from "@angular/forms"; - -export class Dates { - public static yearMin = 1800; - public static yearMax = (new Date().getFullYear()) + 10; - public static currentYear = (new Date().getFullYear()); - - public static isValidYear(yearString, yearMin = this.yearMin, yearMax = this.yearMax) { - // First check for the pattern - if (!/^\d{4}$/.test(yearString)) - return false; - var year = parseInt(yearString, 10); - - // Check the ranges of month and year - return !(year < yearMin || year > yearMax); - } - - //format YYYY-MM-DD - public static isValidDate(dateString: string) { - // First check for the pattern - if (!/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(dateString)) - return false; - - // Parse the date parts to integers - var parts = dateString.split("-"); - var day = parseInt(parts[2], 10); - var month = parseInt(parts[1], 10); - var year = parseInt(parts[0], 10); - if (!this.isValidYear(parts[0])) { - return false; - } - - // Check the ranges of month and year - if (month == 0 || month > 12) - return false; - - var monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - - // Adjust for leap years - if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) - monthLength[1] = 29; - - // Check the range of the day - return day > 0 && day <= monthLength[month - 1]; - - } - - public static getDateToday(): Date { - var myDate = new Date(); - return myDate; - - } - - public static getDateToString(myDate: Date): string { - var date: string = myDate.getFullYear() + "-"; - date += ((myDate.getMonth() + 1) < 10) ? "0" + (myDate.getMonth() + 1) : (myDate.getMonth() + 1); - date += "-"; - date += (myDate.getDate() < 10) ? "0" + myDate.getDate() : myDate.getDate(); - return date; - - } - - public static getDateXMonthsAgo(x: number): Date { - var myDate = new Date(); - myDate.setMonth(myDate.getMonth() - x); - return myDate; - - } - - public static getDateXYearsAgo(x: number): Date { - var myDate = new Date(); - myDate.setFullYear(myDate.getFullYear() - x); - return myDate; - - } - - public static getDateFromString(date: string): Date { - - var myDate = new Date(); - myDate.setFullYear(+date.substring(0, 4)); - myDate.setMonth(((date.length > 5) ? (+date.substring(5, 7) - 1) : (0))); - myDate.setDate(((date.length > 8) ? (+date.substring(8, 11)) : (1))); - return myDate; - - } - - public static getDate(dateString: string): Date { - let date = new Date(dateString); - if (Object.prototype.toString.call(date) === "[object Date]") { - if (isNaN(date.getTime())) { - return null; - } else { - return date; - } - } else { - return null; - } - } - - public static timeSince(date: Date) { - - let seconds = Math.floor((new Date().getTime() - new Date(date).getTime()) / 1000); - - let interval = seconds / (365*24*60*60); - - if (interval > 1) { - let years = Math.floor(interval); - return (years > 1?(years + ' years ago'):'a year ago'); - } - interval = seconds / (7*24*60*60); - if (interval > 1) { - let weeks = Math.floor(interval); - return (weeks > 1?(weeks + ' weeks ago'):'a week ago'); - } - interval = seconds / (24*60*60); - if (interval > 1) { - let days = Math.floor(interval); - return (days > 1?(days + ' days ago'):'a day ago'); - } - interval = seconds / (60*60); - if (interval > 1) { - let hours = Math.floor(interval); - return (hours > 1?(hours + ' hours ago'):'an hour ago'); - } - interval = seconds / 60; - if (interval > 1) { - let minutes = Math.floor(interval); - return (minutes > 1?(minutes + ' minutes ago'):'a minute ago'); - } - seconds = Math.floor(interval); - return (seconds > 1?(seconds + ' seconds ago'):' just now'); - } -} - -export class DOI { - - public static getDOIsFromString(str: string): string[] { - return Identifier.getDOIsFromString(str); - } - - public static isValidDOI(str: string): boolean { - return Identifier.isValidDOI(str); - } -} - -export class Identifier { - class: "doi" | "pmc" | "pmid" | "handle" | "ORCID" | "re3data" = null; - id: string; - - public static getDOIsFromString(str: string): string[] { - var DOIs: string[] = []; - var words: string[] = str.split(" "); - - for (var i = 0; i < words.length; i++) { - let id = words[i]; - if (DOI.isValidDOI(id) ) { - id = Identifier.getRawDOIValue(id); - if( DOIs.indexOf(id) == -1){ - DOIs.push(id); - } - } - } - return DOIs; - } - public static getRawDOIValue(id: string): string { - if(id.indexOf("doi.org")!=-1 && id.split("doi.org/").length > 1){ - id = id.split("doi.org/")[1]; - } - return id; - } - public static getIdentifiersFromString(str: string): Identifier[] { - let identifiers: Identifier[] = []; - let words: string[] = str.split(" "); - - for (let id of words) { - if (id.length > 0) { - let identifier: Identifier = this.getIdentifierFromString(id); - if (identifier) { - identifiers.push(identifier); - } - } - } - return identifiers; - } - - public static getIdentifierFromString(pid: string,strict:boolean = true): Identifier { - if (Identifier.isValidDOI(pid)) { - pid = Identifier.getRawDOIValue(pid); - return {"class": "doi", "id": pid}; - } else if (Identifier.isValidORCID(pid)) { - return {"class": "ORCID", "id": pid}; - } else if (Identifier.isValidPMCID(pid)) { - return {"class": "pmc", "id": pid}; - } else if (Identifier.isValidPMID(pid)) { - return {"class": "pmid", "id": pid}; - } else if (Identifier.isValidHANDLE(pid)) { - return {"class": "handle", "id": pid}; - } else if (Identifier.isValidRe3Data(pid)) { - return {"class": "re3data", "id": pid}; - } - //set it as a doi, to catch the case that doi has not valid format - return (strict?null:{"class": "doi", "id": pid}); - } - - public static getPIDFromIdentifiers(identifiers: Map): Identifier { - let classes:string [] = ["doi", "handle", "pmc", "pmid", "re3data"]; - if(identifiers) { - for (let cl of classes) { - if (identifiers.get(cl)) { - for (let pid of identifiers.get(cl)) { - let identifier = Identifier.getIdentifierFromString(pid); - if (identifier) { - return identifier; - } - } - } - } - } - return null; - } - - public static isValidDOI(str: string): boolean { - //keep only exp3? - let exp1 = /\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])\S)+)\b/g; - let exp2 = /\b(10[.][0-9]{4,}(?:[.][0-9]+)*\/(?:(?!["&\'<>])[[:graph:]])+)\b/g; - let exp3 = /\b(10[.]*)\b/g; - return (str.match(exp1) != null || str.match(exp2) != null || str.match(exp3) != null); - } - - public static isValidORCID(str: string): boolean { - let exp = /\b\d{4}-\d{4}-\d{4}-(\d{3}X|\d{4})\b/g; - return str.match(exp) != null; - } - - public static isValidPMID(str: string): boolean { - let exp = /^\d*$/g; - return str.match(exp) != null; - - } - - public static isValidPMCID(str: string): boolean { - let exp = /^(PMC\d{7})$/g; - return str.match(exp) != null; - } - - public static isValidHANDLE(str: string): boolean { - let exp = /^[0-9a-zA-Z-]*\/[0-9a-zA-Z-]*$/g; - return str.match(exp) != null; - } - - public static isValidRe3Data(str: string): boolean { - let exp = /(r3d[1-9]\d{0,8})/g; - return str.match(exp) != null; - } -} - -export class StringUtils { - - public static urlRegex = 'https?:\\/\\/(?:www(2?)\\.|(?!www(2?)))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www(2?)\\.' + - '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?:\\/\\/(?:www(2?)\\.|(?!www(2?)))[a-zA-Z0-9]+\\.[^\\s]{2,}|www(2?)\\.' + - '[a-zA-Z0-9]+\\.[^\\s]{2,}'; - - public static routeRegex = '^[a-zA-Z0-9\/][a-zA-Z0-9\/-]*$'; - - public static jsonRegex = /^[\],:{}\s]*$/; - - public static urlPrefix(url: string): string { - if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("//")) { - return ""; - } else { - return "//"; - } - } - - public static quote(params: string): string { - return '"' + params + '"'; - } - - public static unquote(params: string): string { - if (params.length > 2 && (params[0] == '"' && params[params.length - 1] == '"') || (params[0] == "'" && params[params.length - 1] == "'")) { - params = params.substring(1, params.length - 1); - } - return params; - } - - public static URIEncode(params: string): string { - return encodeURIComponent(params); - } - - public static URIDecode(params: string): string { - return decodeURIComponent(params); - } - - public static validateEmails(emails: string): boolean { - return (emails.split(',') - .map(email => Validators.email({value: email.trim()})) - .find(_ => _ !== null) === undefined); - } - - public static b64DecodeUnicode(str) { - return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); - } - - private emailValidator(email: any): boolean { - return !!email.match("^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$"); - } - - public static isValidUrl(url: string): boolean { - return new RegExp(this.urlRegex).test(url); - } - - public static urlValidator(): ValidatorFn { - return Validators.pattern(StringUtils.urlRegex); - } - - public static jsonValidator(error: string = ''): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - if(control.value) { - let test = control.getRawValue().replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''); - if(!new RegExp(this.jsonRegex).test(test)) { - return {error: 'Please provide a valid JSON.' + error} - } - } - return null; - }; - } - - public static validatorType(options: string[]): ValidatorFn { - return (control: AbstractControl): { [key: string]: boolean } | null => { - if (options.filter(type => type === control.value).length === 0) { - return {'type': false}; - } - return null; - } - } - - public static validRoute(pages: any[], field: string, initial: string = null): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - if(control.value) { - if(!new RegExp(this.routeRegex).test(control.value)) { - return {error: 'Route should contain only letters or numbers, e.g /route or route'} - } - if(pages && pages.length > 0 && control.value !== initial) { - const forbidden = pages.filter(page => page[field].replace('/', '') === control.value.replace('/', '')).length > 0; - return forbidden ? {error: 'This route is used by an other page'} : null; - } - } - return null; - }; - } - - public static sliceString(mystr, size: number): string { - const sliced = String(mystr).substr(0, size); - return sliced + (String(mystr).length > size ? '...' : ''); - } - - /** - * Splits a text to words base on a list of separators. Returns the words of the text including the separators. - * DO NOT TOUCH, IT WORKS - * - * @param text - * @param separators - */ - public static split(text: string, separators: string[]): string[] { - let words: (string | string[])[] = [text]; - separators.forEach(separator => { - words.forEach((word, index) => { - if (typeof word === "string" && separators.indexOf(word) === -1) { - let tokens: string[] = word.split(separator).filter(value => value !== ''); - if (tokens.length > 1) { - words[index] = []; - tokens.forEach((token, i) => { - ((words[index])).push(token); - if (i !== (tokens.length - 1)) { - ((words[index])).push(separator); - } - }); - } - } - }); - words = [].concat.apply([], words); - }); - return words; - } - - public static capitalize(value: string): string { - return value.charAt(0).toUpperCase() + value.slice(1); - } - - /** - * Checks if a text contains a word - */ - public static containsWord(text: string, word: string): boolean { - return (text && text.toLowerCase().includes(word)); - } - - public static URLSegmentsToPath(segments: UrlSegment[]): string { - let path = ''; - segments.forEach(route => { - path += '/' + route.path; - }) - return path; - } - - public static isEuropeanCountry(country: string) { - let countries = ["Albania", "Andorra", "Armenia", "Austria", "Azerbaijan", "Belarus", "Belgium", "Bosnia and Herzegovina", - "Bulgaria", "Croatia", "Cyprus", "Czech Republic", "Denmark", "Estonia", "Finland", "France", "Georgia", "Germany", "Greece", "Hungary", "Iceland", "Ireland", - "Italy", "Kosovo", "Latvia", "Liechtenstein", "Lithuania", "Luxembourg", "Macedonia", "Malta", "Moldova", "Monaco", "Montenegro", "The Netherlands", "Norway", "Poland", - "Portugal", "Romania", "Russia", "San Marino", "Serbia", "Slovakia", "Slovenia", "Spain", "Sweden", "Switzerland", "Turkey", "Ukraine", "United Kingdom", "Vatican City", - ]; - return (country && countries.indexOf(country) != -1); - } - - public static isOpenAIREID(id: string) { - if (id && id.length == 46) { - let exp1 = /^.{12}::([0-9a-z]{32})$/g; - return (id.match(exp1) != null); - } - return false; - } - public static HTMLToString( html:string){ - try { - html = html.replace(/ /g, ' '); - html = html.replace(/(\r\n|\n|\r| +(?= ))|\s\s+/gm, " "); - html = html.replace(/<[^>]*>/g, ''); - }catch( e){ - } - return html; - } - - public static inValidYearValidator(minYear, maxYear): ValidatorFn { - return (control: AbstractControl): {[key: string]: any} | null => { - return ((control.value && !Dates.isValidYear(control.value, minYear, maxYear)) ? - {error: 'Year must be between ' + minYear + ' and ' + maxYear + '.'} : null); - }; - } - - public static fromYearAfterToYearValidator: ValidatorFn = (control: UntypedFormGroup): ValidationErrors | null => { - const yearFrom = control.get('yearFrom'); - const yearTo = control.get('yearTo'); - return ((yearFrom && yearTo && (parseInt(yearFrom.value, 10) > parseInt(yearTo.value, 10))) ? - {error: 'Starting year must be greater than or equal to ending year.' } : null); - } - - public static rangeRequired( enabled:boolean): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - const yearFrom = control.get('yearFrom'); - const yearTo = control.get('yearTo'); - return ((yearFrom && yearTo && enabled && (yearFrom.value == "" || yearTo.value == "")) ? { error: 'Both starting and ending year are required' } : null); - }; - } -}