@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
298 lines (249 loc) • 8.8 kB
text/typescript
/*
* Deepkit Framework
* Copyright (C) 2021 Deepkit UG, Marc J. Schmidt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the MIT License.
*
* You should have received a copy of the MIT License along with this program.
*/
import {
AfterViewInit,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
HostBinding,
Injector,
Input,
Output,
SkipSelf,
ViewChild,
} from '@angular/core';
import { ngValueAccessor, ValueAccessorBase } from '../../core/form';
import { detectChangesNextFrame } from '../app';
import { DatePipe } from '@angular/common';
const dateTimeTypes: string[] = ['time', 'date', 'datetime', 'datetime-local'];
export class InputComponent extends ValueAccessorBase<any> implements AfterViewInit {
type: string = 'text';
step: number = 1;
placeholder: string = '';
icon: string = '';
min?: number;
max?: number;
maxLength?: number;
minLength?: number;
iconSize: number = 17;
/**
* Focuses this element once created (AfterViewInit).
*/
focus: boolean | '' = false;
/**
* Uses a more decent focus border.
*/
lightFocus: boolean | '' = false;
/**
* Disables input controls (like for type=number the arrow buttons)
*/
noControls: boolean | '' = false;
/**
* Appears a little bit transparent. Perfect for blurry background.
*/
semiTransparent: boolean | '' = false;
esc = new EventEmitter<KeyboardEvent>();
enter = new EventEmitter<KeyboardEvent>();
keyDown = new EventEmitter<KeyboardEvent>();
keyUp = new EventEmitter<KeyboardEvent>();
input?: ElementRef<HTMLInputElement | HTMLTextAreaElement>;
textured: boolean | '' = false;
readonly: boolean | '' = false;
focusChange = new EventEmitter<boolean>();
get isTextured() {
return false !== this.textured;
}
get isFocused() {
if ('undefined' === typeof document) return false;
return this.input ? document.activeElement === this.input!.nativeElement : false;
}
get isFilled() {
return !!this.innerValue;
}
round: boolean | '' = false;
get isRound() {
return false !== this.round;
}
clearer: boolean | '' = false;
get hasClearer() {
return false !== this.clearer;
}
get hasIcon() {
return !!this.icon;
}
constructor(
protected injector: Injector,
public readonly cd: ChangeDetectorRef,
public readonly cdParent: ChangeDetectorRef,
private datePipe : DatePipe,
) {
super(injector, cd, cdParent);
}
onBlur() {
this.cdParent.detectChanges();
this.focusChange.next(false);
}
onFocus() {
this.cdParent.detectChanges();
this.focusChange.next(true);
}
public async clear() {
this.innerValue = '';
}
/**
* From <input>
*/
setInnerValue(value: any) {
if (this.type === 'file') return;
this.innerValue = value;
}
get innerValue(): any {
if (this.type === 'text') {
} else if (this.type === 'number') {
} else if (dateTimeTypes.includes(this.type)) {
if (super.innerValue instanceof Date) {
if (this.type === 'date') return this.datePipe.transform(super.innerValue, `yyyy-MM-dd`);
return this.datePipe.transform(super.innerValue, 'yyyy-MM-ddThh:mm:ss.SSS');
} else if ('string' === typeof super.innerValue) {
return this.datePipe.transform(new Date(super.innerValue), 'yyyy-MM-ddThh:mm:ss.SSS');
}
}
return super.innerValue;
}
set innerValue(value: any | undefined) {
if (this.type === 'text') {
} else if (this.type === 'number') {
if (value && 'number' !== typeof value) {
value = parseFloat(value);
}
} else if (dateTimeTypes.includes(this.type)) {
if ('string' === typeof value) {
value = new Date(value);
}
}
super.innerValue = value;
}
writeValue(value?: any) {
if (this.type === 'file' && !value && this.input) {
//we need to manually reset the field, since writing to it via ngModel is not supported.
this.input!.nativeElement.value = '';
}
super.writeValue(value);
}
onKeyDown(event: KeyboardEvent) {
this.touch();
this.keyDown.emit(event);
}
onKeyUp(event: KeyboardEvent) {
if (event.key.toLowerCase() === 'enter' && this.type !== 'textarea') {
this.enter.emit(event);
}
if (event.key.toLowerCase() === 'esc' || event.key.toLowerCase() === 'escape') {
this.esc.emit(event);
}
this.keyUp.emit(event);
}
focusInput() {
setTimeout(() => {
this.input!.nativeElement.focus();
});
}
ngAfterViewInit() {
if (this.focus !== false && this.input) {
setTimeout(() => {
this.input!.nativeElement.focus();
detectChangesNextFrame(this.cd);
});
}
}
public async handleFileInput(event: any) {
const files = event.target.files;
this.touch();
const readFile = (file: File): Promise<ArrayBuffer | undefined> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result) {
if (reader.result instanceof ArrayBuffer) {
resolve(reader.result);
} else {
resolve(undefined);
}
}
};
reader.onerror = (error) => {
console.log('Error: ', error);
reject();
};
reader.readAsArrayBuffer(file);
});
};
if (files) {
if (files.length > 1) {
const value: any[] = [];
for (let i = 0; i < files.length; i++) {
const file = files.item(i);
if (file) {
value.push(await readFile(file));
}
}
this.innerValue = value;
} else if (files.length === 1) {
this.innerValue = await readFile(files.item(0));
}
}
}
}