import { Directive, ElementRef, AfterViewInit, HostListener, Renderer2, Input } from '@angular/core';
import { AbstractControl, NgControl } from '@angular/forms';
import moment from 'moment-timezone';
@Directive({
selector: '[dateInputMaterialController]'
})
export class DateInputMaterialControllerDirective implements AfterViewInit {
constructor(
private el: ElementRef<HTMLInputElement>,
private control: NgControl,
private renderer: Renderer2) { }
@Input('dateInputMaterialController')
inputFormatDate: string;
formatDate: string = "DD/MM/YYYY HH:mm";
formControl: AbstractControl
nativeInput: any;
highlightedIndex = 0;
charEventIndex = 0;
highlightedOptions: {
[x: string]: any;
patternGroup: string;
amountName: "days" | "months" | "years" | "hours" | "minutes";
startIndex?: number;
endIndex?: number
}[] = [{
patternGroup: "DD",
amountName: "days",
setName: "date",
minValue: 1,
maxValue: 31,
startIndex: 0,
endIndex: 2,
},
{
patternGroup: "MM",
amountName: "months",
setName: "month",
offset: -1,
minValue: 0,
maxValue: 11,
startIndex: 3,
endIndex: 5,
},
{
patternGroup: "YYYY",
amountName: "years",
setName: "y",
minValue: 0,
maxValue: 9999,
startIndex: 6,
endIndex: 10,
},
{
patternGroup: "HH",
amountName: "hours",
setName: "hour",
minValue: 0,
maxValue: 23,
startIndex: 11,
endIndex: 13,
},
{
patternGroup: "mm",
amountName: "minutes",
setName: "minute",
minValue: 0,
maxValue: 59,
startIndex: 14,
endIndex: 16,
},
];
removeSelection() {
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
}/* else if (document?.selection) { // IE?
document?.selection?.empty();
}*/
}
createSelection(start, end) {
let field = this.nativeInput;
if (field.createTextRange) {
var selRange = field.createTextRange();
selRange.collapse(true);
selRange.moveStart('character', start);
selRange.moveEnd('character', end);
selRange.select();
} else if (field.setSelectionRange) {
field.setSelectionRange(start, end);
} else if (field.selectionStart) {
field.selectionStart = start;
field.selectionEnd = end;
}
field.focus();
}
@HostListener('focus')
onFocusDate() {
//console.log("focus")
//se la data non è valida setta con quella odierna e ore 00:00
let valueOfInput = moment(this.nativeInput.value, this.formatDate);
if(!valueOfInput.isValid()){
valueOfInput = moment();
valueOfInput.set({hour:0, minute:0});
this.formControl.setValue(valueOfInput);
}
this.highlightedIndex = 0;
this.charEventIndex = 0;
this.highlightGroup(this.highlightedIndex);
}
@HostListener('click')
onClickDate() {
//console.log("clicked")
let input: any = this.el.nativeElement;
if (input.selectionStart || input.selectionStart == '0') {
let carPos = input.selectionStart;
let h = 0;
for (let i = 0; i < this.highlightedOptions.length; i++) {
let g = this.highlightedOptions[i];
h = i;
if ((g.endIndex) >= carPos) {
break;
}
}
this.highlightedIndex = h;
this.charEventIndex = 0;
}
this.highlightGroup(this.highlightedIndex);
}
highlightGroup(index) {
let g = this.highlightedOptions[index];
this.createSelection(g.startIndex, g.endIndex);
}
@HostListener('keydown', ['$event'])
onkeyDownDate(event: KeyboardEvent) {
let nextPatternGroup = false;
// se premi tab vai al successivo gurppo
if (event.key == 'Tab') {
nextPatternGroup = true;
if (this.highlightedIndex == (this.highlightedOptions.length - 1)) { return; }
}
event.preventDefault();
const valueOfInput = moment((event.target as any).value, this.formatDate);
let g = this.highlightedOptions[this.highlightedIndex];
// in caso di numerici
if (event.key.match(/[0-9]/)) {
const isLastCharOfTheGroup = this.charEventIndex == (g.endIndex - g.startIndex) - 1;
// prendi la data dal input e sostituisci carattere indice charEventIndex
let dataGroup: any = valueOfInput.format(g.patternGroup);
let replaceIndex = this.charEventIndex; //<-- partiamo dalle cifre più significative (da destra a sinistra)
// se invece vuoi partire dalle cifre unitarie (da sinistra a destra) decommenta questo
//replaceIndex = g.endIndex-g.startIndex-this.charEventIndex-1;
dataGroup = parseInt(dataGroup.slice(0, replaceIndex) + "" + event.key + "" + dataGroup.slice(replaceIndex + 1)) + (g.offset ?? 0)
if (dataGroup < g.minValue) {
dataGroup = g.minValue
}
const maxVal = g.patternGroup == "DD" ? valueOfInput.daysInMonth() : g.maxValue ;
if (dataGroup > maxVal) {
if (isLastCharOfTheGroup) {
dataGroup = maxVal
} else {
//padding 0 a sinistra
dataGroup = dataGroup.toString();
let zeros = "0".repeat(g.endIndex - g.startIndex - this.charEventIndex - 1);
dataGroup = parseInt(zeros + "" + event.key + "") + (g.offset ?? 0)
//prossimo gruppo
this.charEventIndex = 0;
nextPatternGroup = true;
}
}
valueOfInput.set(g.setName, dataGroup);
//valueOfInput.date(dataGroup)
//console.log(valueOfInput.format(this.fomatDate));
this.formControl.setValue(valueOfInput);
if (isLastCharOfTheGroup) {
this.charEventIndex = 0;
nextPatternGroup = true;
} else {
this.charEventIndex++;
}
this.highlightGroup(this.highlightedIndex)
//return;
}
if (event.key === 'ArrowLeft' || event.key == 'Backspace') {
if (this.highlightedIndex > 0) {
this.charEventIndex = 0;
this.highlightGroup(--this.highlightedIndex)
}
} else if (event.key === 'ArrowRight' || nextPatternGroup) {
if (this.highlightedIndex < (this.highlightedOptions.length - 1)) {
this.charEventIndex = 0;
this.highlightGroup(++this.highlightedIndex)
}
} else if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
let momentVal = valueOfInput.add(event.key === 'ArrowUp' ? 1 : -1, g.amountName);
this.formControl.setValue(momentVal);
this.charEventIndex = 0;
this.highlightGroup(this.highlightedIndex)
}
}
ngAfterViewInit() {
this.formControl = this.control?.control;
this.nativeInput = this.el.nativeElement;
if (this.inputFormatDate) {
this.formatDate = this.inputFormatDate;
this.highlightedOptions.forEach(opt => {
opt.startIndex = this.formatDate.indexOf(opt.patternGroup);
opt.endIndex = opt.patternGroup.length + opt.startIndex
})
this.highlightedOptions = this.highlightedOptions.filter(opt => opt.startIndex != 1).sort((a, b) => a.startIndex - b.startIndex);
}
}
}