Merge pull request #253 from paperless-ngx/feature-better-date-keyboard-input

Improve date keyboard input
This commit is contained in:
shamoon 2022-03-11 10:27:56 -08:00 committed by GitHub
commit 440f4729ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 54 deletions

View File

@ -20,8 +20,8 @@
</div>
<div class="input-group input-group-sm">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()"
[(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker">
<button class="btn btn-outline-secondary" (click)="dateAfterPicker.toggle()" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>
@ -43,8 +43,8 @@
</div>
<div class="input-group input-group-sm">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()"
[(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker">
<input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)"
maxlength="10" [(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker">
<button class="btn btn-outline-secondary" (click)="dateBeforePicker.toggle()" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>

View File

@ -120,4 +120,10 @@ export class DateDropdownComponent implements OnInit, OnDestroy {
this.onChange()
}
// prevent chars other than numbers and separators
onKeyPress(event: KeyboardEvent) {
if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) {
event.preventDefault()
}
}
}

View File

@ -1,8 +1,9 @@
<div class="mb-3">
<label class="form-label" [for]="inputId">{{title}}</label>
<div class="input-group" [class.is-invalid]="error">
<input class="form-control" [class.is-invalid]="error" [placeholder]="placeholder" [id]="inputId" (dateSelect)="onChange(value)" (change)="onChange(value)"
name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel">
<input class="form-control" [class.is-invalid]="error" [placeholder]="placeholder" [id]="inputId" maxlength="10"
(dateSelect)="onChange(value)" (change)="onChange(value)" (keypress)="onKeyPress($event)"
name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel">
<button class="btn btn-outline-secondary calendar" (click)="datePicker.toggle()" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16">
<path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/>

View File

@ -1,8 +1,6 @@
import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgbDateAdapter, NgbDateParserFormatter, NgbDatepickerContent } from '@ng-bootstrap/ng-bootstrap';
import { Component, forwardRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { SettingsService } from 'src/app/services/settings.service';
import { v4 as uuidv4 } from 'uuid';
import { AbstractInputComponent } from '../abstract-input';
@ -29,4 +27,10 @@ export class DateComponent extends AbstractInputComponent<string> implements OnI
placeholder: string
// prevent chars other than numbers and separators
onKeyPress(event: KeyboardEvent) {
if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) {
event.preventDefault()
}
}
}

View File

@ -4,6 +4,7 @@ import { SettingsService } from "../services/settings.service"
@Injectable()
export class LocalizedDateParserFormatter extends NgbDateParserFormatter {
private separatorRegExp: RegExp = /[\.,\/-]+/
constructor(private settings: SettingsService) {
super()
@ -35,59 +36,36 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter {
* have it expanded to 10.03.2022, in the case of the German format.
* (All other formats are also supported)
*
* It also replaces commas with the date separator.
* This allows quick entry of the date on the numpad.
* It also strips any separators before running formatting and pads
* any parts of the string, e.g. allowing for 1/2/22,
* which allows quick entry of the date on the numpad.
*/
private preformatDateInput(value: string): string {
let inputFormat = this.getDateInputFormat()
let dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0)
value = value.replace(/,/g, dateSeparator)
if (value.includes(dateSeparator)) { return value }
const inputFormat = this.getDateInputFormat()
const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0)
if (this.separatorRegExp.test(value)) {
// split on separator, pad & re-join without separator
value = value.split(this.separatorRegExp).map(segment => segment.padStart(2,'0')).join('')
}
if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') {
return value.substring(0, 2)
+ dateSeparator
+ value.substring(2, 4)
+ dateSeparator
+ new Date().getFullYear()
}
else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') {
return new Date().getFullYear()
+ dateSeparator
+ value.substring(0, 2)
+ dateSeparator
+ value.substring(2, 4)
}
else if (value.length == 6) {
return value.substring(0, 2)
+ dateSeparator
+ value.substring(2, 4)
+ dateSeparator
+ value.substring(4, 6)
}
else if (value.length == 8 && inputFormat.substring(0, 4) != 'yyyy') {
return value.substring(0, 2)
+ dateSeparator
+ value.substring(2, 4)
+ dateSeparator
+ value.substring(4, 8)
}
else if (value.length == 8 && inputFormat.substring(0, 4) == 'yyyy') {
return value.substring(0, 4)
+ dateSeparator
+ value.substring(4, 6)
+ dateSeparator
+ value.substring(6, 8)
}
else {
return [value.substring(0, 2), value.substring(2, 4), new Date().getFullYear()].join(dateSeparator)
} else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') {
return [new Date().getFullYear(), value.substring(0, 2), value.substring(2, 4)].join(dateSeparator)
} else if (value.length == 6) {
return [value.substring(0, 2), value.substring(2, 4), value.substring(4, 6)].join(dateSeparator)
} else if (value.length == 8 && inputFormat.substring(0, 4) != 'yyyy') {
return [value.substring(0, 2), value.substring(2, 4), value.substring(4, 8)].join(dateSeparator)
} else if (value.length == 8 && inputFormat.substring(0, 4) == 'yyyy') {
return [value.substring(0, 4), value.substring(4, 6), value.substring(6, 8)].join(dateSeparator)
} else {
return value
}
}
parse(value: string): NgbDateStruct | null {
value = this.preformatDateInput(value);
value = this.preformatDateInput(value)
let match = this.getDateParseRegex().exec(value)
if (match) {
let dateStruct = {