diff --git a/angular.json b/angular.json
index b2f58c0..5c080b6 100644
--- a/angular.json
+++ b/angular.json
@@ -30,7 +30,10 @@
"styles": [
"src/styles.less"
],
- "scripts": []
+ "scripts": [
+ "node_modules/uikit/dist/js/uikit.min.js",
+ "node_modules/uikit/dist/js/uikit-icons.min.js"
+ ]
},
"configurations": {
"production": {
@@ -103,5 +106,8 @@
}
}
}
+ },
+ "cli": {
+ "analytics": false
}
}
diff --git a/package.json b/package.json
index 3633fa7..56149d6 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "0.0.0",
"scripts": {
"ng": "ng",
- "start": "ng serve",
+ "start": "ng serve --disable-host-check --host 0.0.0.0 --port 5100",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 38c9891..3a97107 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -6,6 +6,9 @@ import { AppComponent } from './app.component';
import { TopmenuComponent } from './shared/topmenu/topmenu.component';
import { SidebarComponent } from './shared/sidebar/sidebar.component';
import { SingleRecordValidatorComponent } from './pages/single-record-validator/single-record-validator.component';
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {HttpClient, HttpClientModule} from "@angular/common/http";
+import {InputModule} from "./shared/utils/input/input.module";
@NgModule({
declarations: [
@@ -16,7 +19,11 @@ import { SingleRecordValidatorComponent } from './pages/single-record-validator/
],
imports: [
BrowserModule,
- AppRoutingModule
+ AppRoutingModule,
+ FormsModule,
+ ReactiveFormsModule,
+ HttpClientModule,
+ InputModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/src/app/pages/single-record-validator/single-record-validator.component.html b/src/app/pages/single-record-validator/single-record-validator.component.html
index 18e49ef..175d97b 100644
--- a/src/app/pages/single-record-validator/single-record-validator.component.html
+++ b/src/app/pages/single-record-validator/single-record-validator.component.html
@@ -1,50 +1,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/app/pages/single-record-validator/single-record-validator.component.ts b/src/app/pages/single-record-validator/single-record-validator.component.ts
index b1e265e..ec77763 100644
--- a/src/app/pages/single-record-validator/single-record-validator.component.ts
+++ b/src/app/pages/single-record-validator/single-record-validator.component.ts
@@ -1,4 +1,7 @@
import { Component, OnInit } from '@angular/core';
+import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
+import {SingleRecordValidatorService} from "./single-record-validator.service";
+import {Option} from "../../shared/utils/input/input.component";
@Component({
selector: 'app-single-record-validator',
@@ -6,10 +9,28 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./single-record-validator.component.less']
})
export class SingleRecordValidatorComponent implements OnInit {
+ public options: Option[] = [
+ {label: 'Data Archive Guidelines V2 Profile', value: 'dataArchiveGuidelinesV2Profile'},
+ {label: 'Literature Guidelines V3 Profile', value: 'literatureGuidelinesV3Profile'},
+ {label: 'Literature Guidelines V4 Profile', value: 'literatureGuidelinesV4Profile'}
+ ];
+ public form: UntypedFormGroup;
+ public result: any;
- constructor() { }
-
- ngOnInit(): void {
+ constructor(private fb: UntypedFormBuilder, private validator: SingleRecordValidatorService) {
+ this.form = this.fb.group({
+ guidelines: this.fb.control("", Validators.required),
+ xml: this.fb.control('', Validators.required)
+ });
}
+ ngOnInit(): void {}
+
+ public validate() {
+ this.validator.validateRecord(this.form.get('xml')?.getRawValue(), this.form.get('guidelines')?.getRawValue()).subscribe(
+ result => {
+ this.result = result;
+ }
+ )
+ }
}
diff --git a/src/app/pages/single-record-validator/single-record-validator.service.ts b/src/app/pages/single-record-validator/single-record-validator.service.ts
new file mode 100644
index 0000000..e68cecc
--- /dev/null
+++ b/src/app/pages/single-record-validator/single-record-validator.service.ts
@@ -0,0 +1,18 @@
+import {Injectable} from "@angular/core";
+import {HttpClient, HttpHeaders} from "@angular/common/http";
+import {Observable} from "rxjs";
+import {environment} from "../../../environments/environment";
+
+@Injectable({
+ providedIn: "root"
+})
+export class SingleRecordValidatorService {
+
+ constructor(private http: HttpClient) {}
+
+ validateRecord(xml: string, guidelinesName: string): Observable
{
+ let url = environment.validatorAPI + "validate?guidelines="+guidelinesName;
+ let headers = new HttpHeaders({'Content-Type': 'application/json', 'accept': 'application/json'});
+ return this.http.post(url, xml, {headers: headers});
+ }
+}
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
new file mode 100644
index 0000000..e536a08
--- /dev/null
+++ b/src/app/shared/utils/click/click-outside-or-esc.directive.ts
@@ -0,0 +1,33 @@
+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
new file mode 100644
index 0000000..4283a1e
--- /dev/null
+++ b/src/app/shared/utils/click/click.module.ts
@@ -0,0 +1,14 @@
+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
new file mode 100644
index 0000000..bc8b095
--- /dev/null
+++ b/src/app/shared/utils/click/long-click.directive.ts
@@ -0,0 +1,72 @@
+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/input/input.component.ts b/src/app/shared/utils/input/input.component.ts
new file mode 100644
index 0000000..a01a66f
--- /dev/null
+++ b/src/app/shared/utils/input/input.component.ts
@@ -0,0 +1,626 @@
+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: `
+
+
+
0 && opened" #optionBox
+ uk-dropdown="pos: bottom-justify; mode: none; offset: 15; boundary-align: true;" [attr.boundary]="'#' + id">
+
+
+
+
+ {{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
new file mode 100644
index 0000000..29a0622
--- /dev/null
+++ b/src/app/shared/utils/input/input.module.ts
@@ -0,0 +1,24 @@
+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/assets/common-assets b/src/assets/common-assets
index c645362..936fac2 160000
--- a/src/assets/common-assets
+++ b/src/assets/common-assets
@@ -1 +1 @@
-Subproject commit c645362896b10ae00563f38337aa0011c640cb20
+Subproject commit 936fac297322fa252af930cab3c0e69efe57c1a5
diff --git a/src/assets/openaire-theme b/src/assets/openaire-theme
index 8b8db18..8bb758b 160000
--- a/src/assets/openaire-theme
+++ b/src/assets/openaire-theme
@@ -1 +1 @@
-Subproject commit 8b8db18d0b34ed61d76936f0e44ef856a5f6df5c
+Subproject commit 8bb758b340d05b50b65da48863ff7ed69fdc122b
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index f56ff47..558a791 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -3,7 +3,8 @@
// The list of file replacements can be found in `angular.json`.
export const environment = {
- production: false
+ production: false,
+ validatorAPI: "http://duffy.di.uoa.gr:8080/uoa-validator-api/"
};
/*
diff --git a/tsconfig.json b/tsconfig.json
index ff06eae..9da5caf 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,9 +5,9 @@
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
- "strict": true,
+ "strict": false,
"noImplicitOverride": true,
- "noPropertyAccessFromIndexSignature": true,
+ "noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
@@ -27,6 +27,6 @@
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
- "strictTemplates": true
+ "strictTemplates": false
}
}