From 4769ecefc3b6b59887baec2625bd5e35f23f6554 Mon Sep 17 00:00:00 2001 From: tykayn <15d65f2f-0b14-4f70-bf34-e130180ed62b@users.tedomum.net> Date: Fri, 6 Nov 2020 14:33:20 +0100 Subject: [PATCH] add keybaord shortcuts on array for choices --- .../administration/form/form.component.html | 51 ++++++- .../administration/form/form.component.ts | 135 +++++++++++++++++- .../old-stuff/config/DateUtilities.ts | 8 ++ .../old-stuff/pages/dates/dates.component.ts | 2 +- src/assets/i18n/FR.json | 1 + 5 files changed, 187 insertions(+), 10 deletions(-) diff --git a/src/app/features/administration/form/form.component.html b/src/app/features/administration/form/form.component.html index 8c76d5ae..ed0098b8 100644 --- a/src/app/features/administration/form/form.component.html +++ b/src/app/features/administration/form/form.component.html @@ -65,6 +65,34 @@
+ + +
+

{{ 'dates.add_interval' | translate }}

+

+ {{ 'dates.interval_propose' | translate }} + + {{ 'dates.interval_span' | translate }} + +
+

+ +
+
+

{{ 'choices.title' | translate }} @@ -94,6 +122,9 @@ +

+ {{ 'creation.choices_hint' | translate }} +

@@ -104,11 +135,23 @@ {{ i * 1 + 1 }})
- - + +
- - + +

diff --git a/src/app/features/administration/form/form.component.ts b/src/app/features/administration/form/form.component.ts index b5217e7e..8b024dc9 100644 --- a/src/app/features/administration/form/form.component.ts +++ b/src/app/features/administration/form/form.component.ts @@ -1,10 +1,12 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; import { Poll } from '../../../core/models/poll.model'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { UuidService } from '../../../core/services/uuid.service'; import { ApiService } from '../../../core/services/api.service'; import { ToastService } from '../../../core/services/toast.service'; import { PollService } from '../../../core/services/poll.service'; +import { DateUtilities } from '../../old-stuff/config/DateUtilities'; +import { DOCUMENT } from '@angular/common'; @Component({ selector: 'app-admin-form', @@ -18,13 +20,22 @@ export class FormComponent implements OnInit { public urlPrefix: string = window.location.origin + '/participation/'; public advancedDisplayEnabled = false; + public showDateInterval = true; + startDateInterval: any; + intervalDays: any; + intervalDaysDefault = 7; + endDateInterval: any; + dateList: any[]; constructor( private fb: FormBuilder, + private cd: ChangeDetectorRef, private uuidService: UuidService, private toastService: ToastService, private pollService: PollService, - private apiService: ApiService + public dateUtilities: DateUtilities, + private apiService: ApiService, + @Inject(DOCUMENT) private document: any ) {} ngOnInit(): void { @@ -61,6 +72,13 @@ export class FormComponent implements OnInit { }); } this.choices.push(newControlGroup); + this.cd.detectChanges(); + console.log('this.choices.length', this.choices.length); + const selector = '#choice_label_' + (this.choices.length - 1); + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } } deleteChoiceField(index: number): void { @@ -73,7 +91,7 @@ export class FormComponent implements OnInit { this.choices.setValue([]); } - initFormDefault(): void { + initFormDefault(showDemoValues = true): void { this.form = this.fb.group({ title: ['', [Validators.required, Validators.minLength(12)]], creatorPseudo: ['', [Validators.required]], @@ -82,6 +100,8 @@ export class FormComponent implements OnInit { description: ['', [Validators.required]], choices: new FormArray([]), isAboutDate: [true, [Validators.required]], + startDateInterval: ['', [Validators.required]], + endDateInterval: ['', [Validators.required]], isProtectedByPassword: [false, [Validators.required]], isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]], isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]], @@ -90,9 +110,33 @@ export class FormComponent implements OnInit { expiracyNumberOfDays: [60, [Validators.required, Validators.min(0)]], }); console.log('this.form ', this.form); - this.setDemoValues(); + this.setDefaultDatesForInterval(); + + if (showDemoValues) { + this.setDemoValues(); + } } + /** + * default interval of dates proposed is from today to 7 days more + */ + setDefaultDatesForInterval(): void { + const dateCurrent = new Date(); + const dateJson = dateCurrent.toISOString(); + this.startDateInterval = dateJson.substring(0, 10); + this.endDateInterval = this.dateUtilities + .addDaysToDate(this.intervalDaysDefault, dateCurrent) + .toISOString() + .substring(0, 10); + this.form.patchValue({ + startDateInterval: this.startDateInterval, + endDateInterval: this.endDateInterval, + }); + } + + /** + * add example values to the form + */ setDemoValues(): void { this.addChoice('orange'); this.addChoice('raisin'); @@ -116,7 +160,88 @@ export class FormComponent implements OnInit { } askInitFormDefault(): void { - this.initFormDefault(); + this.initFormDefault(false); this.toastService.display('formulaire réinitialisé'); } + + countDays(): void { + this.intervalDays = this.dateUtilities.countDays(this.startDateInterval, this.endDateInterval); + } + + /** + * add all the dates between the start and end dates in the interval section + */ + addIntervalOfDates(): void { + const newIntervalArray = this.dateUtilities.getDatesInRange(this.startDateInterval, this.endDateInterval, 1); + + const converted = []; + newIntervalArray.forEach((element) => { + converted.push({ + literal: element.literal, + date_object: element.date_object, + timeList: [], + }); + }); + this.dateList = [...new Set(converted)]; + // add only dates that are not already present with a Set of unique items + console.log('this.dateList', this.dateList); + this.showDateInterval = false; + + this.toastService.display(`les dates ont été ajoutées aux réponses possibles.`); + } + + /** + * handle keyboard shortcuts + * @param $event + */ + keyOnChoice($event: KeyboardEvent, choice_number: number): void { + $event.preventDefault(); + + console.log('this.choices.length', this.choices.length); + console.log('choice_number', choice_number); + const lastChoice = this.choices.length - 1 === choice_number; + // reset field with Ctrl + D + // add a field with Ctrl + N + // go to previous choice with arrow up + // go to next choice with arrow down + console.log('$event', $event); + + if ($event.key == 'ArrowUp' && choice_number > 0) { + const selector = '#choice_label_' + (choice_number - 1); + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } + } + if ($event.key == 'ArrowDown') { + // add a field if we are on the last choice + if (lastChoice) { + this.addChoice(); + this.toastService.display('choix ajouté par raccourci "flèche bas"'); + } else { + const selector = '#choice_label_' + (choice_number + 1); + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } + } + } + if ($event.ctrlKey && $event.key == 'Backspace') { + this.deleteChoiceField(choice_number); + this.toastService.display('choix supprimé par raccourci "Ctrl + retour"'); + this.cd.detectChanges(); + const selector = '#choice_label_' + Math.min(choice_number - 1, 0); + const elem = this.document.querySelector(selector); + if (elem) { + elem.focus(); + } + } + if ($event.ctrlKey && $event.key == 'Enter') { + // go to other fields + const elem = this.document.querySelector('#creatorEmail'); + if (elem) { + elem.focus(); + } + } + } } diff --git a/src/app/features/old-stuff/config/DateUtilities.ts b/src/app/features/old-stuff/config/DateUtilities.ts index 6e60ca21..eec4d518 100644 --- a/src/app/features/old-stuff/config/DateUtilities.ts +++ b/src/app/features/old-stuff/config/DateUtilities.ts @@ -60,4 +60,12 @@ export class DateUtilities { getDoubleDigits(str) { return ('00' + str).slice(-2); } + + countDays(startDateInterval: Date, endDateInterval: Date): number { + // compute the number of days in the date interval + if (endDateInterval && startDateInterval) { + return this.dayDiff(endDateInterval, startDateInterval); + } + return 0; + } } diff --git a/src/app/features/old-stuff/pages/dates/dates.component.ts b/src/app/features/old-stuff/pages/dates/dates.component.ts index 31458e4d..1caed356 100644 --- a/src/app/features/old-stuff/pages/dates/dates.component.ts +++ b/src/app/features/old-stuff/pages/dates/dates.component.ts @@ -55,7 +55,7 @@ export class DatesComponent extends BaseComponent implements OnInit { date_object: new Date(), timeList: [], }); - const selector = '[ng-reflect-choice_label="dateChoices_' + (this.config.dateList.length - 1) + '"]'; + const selector = '["choice_label_' + (this.config.dateList.length - 1) + '"]'; this.cd.detectChanges(); const elem = this.document.querySelector(selector); if (elem) { diff --git a/src/assets/i18n/FR.json b/src/assets/i18n/FR.json index 89808c4b..2b885653 100644 --- a/src/assets/i18n/FR.json +++ b/src/assets/i18n/FR.json @@ -35,6 +35,7 @@ }, "choose_title": "Dont le titre sera", "choose_title_placeholder": "titre", + "choices_hint": "Utilisez les flèches haut ⬆️ et bas ⬇️ pour passer d'un choix à un autre", "name": "Je peux aussi préciser mon nom si je le souhaite", "name_placeholder": "mon nom", "description": "et la description serait",