mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge pull request #253 from paperless-ngx/feature-better-date-keyboard-input
Improve date keyboard input
This commit is contained in:
		| @@ -20,8 +20,8 @@ | |||||||
|           </div> |           </div> | ||||||
|  |  | ||||||
|           <div class="input-group input-group-sm"> |           <div class="input-group input-group-sm"> | ||||||
|             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" |             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" | ||||||
|                     [(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker"> |                     maxlength="10" [(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker"> | ||||||
|             <button class="btn btn-outline-secondary" (click)="dateAfterPicker.toggle()" type="button"> |             <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"> |               <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"/> |                 <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> | ||||||
|  |  | ||||||
|           <div class="input-group input-group-sm"> |           <div class="input-group input-group-sm"> | ||||||
|             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" |             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" (keypress)="onKeyPress($event)" | ||||||
|                     [(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker"> |                     maxlength="10" [(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker"> | ||||||
|             <button class="btn btn-outline-secondary" (click)="dateBeforePicker.toggle()" type="button"> |             <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"> |               <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"/> |                 <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"/> | ||||||
|   | |||||||
| @@ -120,4 +120,10 @@ export class DateDropdownComponent implements OnInit, OnDestroy { | |||||||
|     this.onChange() |     this.onChange() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // prevent chars other than numbers and separators | ||||||
|  |   onKeyPress(event: KeyboardEvent) { | ||||||
|  |     if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) { | ||||||
|  |       event.preventDefault() | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| <div class="mb-3"> | <div class="mb-3"> | ||||||
|   <label class="form-label" [for]="inputId">{{title}}</label> |   <label class="form-label" [for]="inputId">{{title}}</label> | ||||||
|   <div class="input-group" [class.is-invalid]="error"> |   <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)" |     <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"> |           name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel"> | ||||||
|     <button class="btn btn-outline-secondary calendar" (click)="datePicker.toggle()" type="button"> |     <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"> |       <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16"> | ||||||
|   | |||||||
| @@ -1,8 +1,6 @@ | |||||||
| import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; | import { Component, forwardRef, OnInit } from '@angular/core'; | ||||||
| import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | import { NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||||
| import { NgbDateAdapter, NgbDateParserFormatter, NgbDatepickerContent } from '@ng-bootstrap/ng-bootstrap'; |  | ||||||
| import { SettingsService } from 'src/app/services/settings.service'; | import { SettingsService } from 'src/app/services/settings.service'; | ||||||
| import { v4 as uuidv4 } from 'uuid'; |  | ||||||
| import { AbstractInputComponent } from '../abstract-input'; | import { AbstractInputComponent } from '../abstract-input'; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -29,4 +27,10 @@ export class DateComponent extends AbstractInputComponent<string> implements OnI | |||||||
|  |  | ||||||
|   placeholder: string |   placeholder: string | ||||||
|  |  | ||||||
|  |   // prevent chars other than numbers and separators | ||||||
|  |   onKeyPress(event: KeyboardEvent) { | ||||||
|  |     if ('Enter' !== event.key && !/[0-9,\.\/-]+/.test(event.key)) { | ||||||
|  |       event.preventDefault() | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import { SettingsService } from "../services/settings.service" | |||||||
|  |  | ||||||
| @Injectable() | @Injectable() | ||||||
| export class LocalizedDateParserFormatter extends NgbDateParserFormatter { | export class LocalizedDateParserFormatter extends NgbDateParserFormatter { | ||||||
|  |   private separatorRegExp: RegExp = /[\.,\/-]+/ | ||||||
|  |  | ||||||
|   constructor(private settings: SettingsService) { |   constructor(private settings: SettingsService) { | ||||||
|     super() |     super() | ||||||
| @@ -35,59 +36,36 @@ export class LocalizedDateParserFormatter extends NgbDateParserFormatter { | |||||||
|    * have it expanded to 10.03.2022, in the case of the German format. |    * have it expanded to 10.03.2022, in the case of the German format. | ||||||
|    * (All other formats are also supported) |    * (All other formats are also supported) | ||||||
|    *  |    *  | ||||||
|    * It also replaces commas with the date separator.  |    * It also strips any separators before running formatting and pads | ||||||
|    * This allows quick entry of the date on the numpad.  |    * 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 { |   private preformatDateInput(value: string): string { | ||||||
|     let inputFormat = this.getDateInputFormat() |     const inputFormat = this.getDateInputFormat() | ||||||
|     let dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) |     const dateSeparator = inputFormat.replace(/[dmy]/gi, '').charAt(0) | ||||||
|      |      | ||||||
|     value = value.replace(/,/g, dateSeparator) |     if (this.separatorRegExp.test(value)) { | ||||||
|  |       // split on separator, pad & re-join without separator | ||||||
|     if (value.includes(dateSeparator)) { return value } |       value = value.split(this.separatorRegExp).map(segment => segment.padStart(2,'0')).join('') | ||||||
|  |     }     | ||||||
|  |  | ||||||
|     if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { |     if (value.length == 4 && inputFormat.substring(0, 4) != 'yyyy') { | ||||||
|       return value.substring(0, 2) |       return [value.substring(0, 2), value.substring(2, 4), new Date().getFullYear()].join(dateSeparator) | ||||||
|         + dateSeparator |     } else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') { | ||||||
|         + value.substring(2, 4) |       return [new Date().getFullYear(), value.substring(0, 2), value.substring(2, 4)].join(dateSeparator) | ||||||
|         + dateSeparator |     } else if (value.length == 6) { | ||||||
|         + new Date().getFullYear() |       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') { | ||||||
|     else if (value.length == 4 && inputFormat.substring(0, 4) == 'yyyy') { |       return [value.substring(0, 2), value.substring(2, 4), value.substring(4, 8)].join(dateSeparator) | ||||||
|       return new Date().getFullYear() |     } else if (value.length == 8 && inputFormat.substring(0, 4) == 'yyyy') { | ||||||
|         + dateSeparator |       return [value.substring(0, 4), value.substring(4, 6), value.substring(6, 8)].join(dateSeparator) | ||||||
|         + value.substring(0, 2) |     } else { | ||||||
|         + 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 |       return value | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   parse(value: string): NgbDateStruct | null { |   parse(value: string): NgbDateStruct | null { | ||||||
|     value = this.preformatDateInput(value); |     value = this.preformatDateInput(value) | ||||||
|     let match = this.getDateParseRegex().exec(value) |     let match = this.getDateParseRegex().exec(value) | ||||||
|     if (match) { |     if (match) { | ||||||
|       let dateStruct = { |       let dateStruct = { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon