add keybaord shortcuts on array for choices

This commit is contained in:
tykayn 2020-11-06 14:33:20 +01:00
parent d3042b3723
commit 4769ecefc3
5 changed files with 187 additions and 10 deletions

View File

@ -65,6 +65,34 @@
<fieldset class="date-kind">
<!-- choix spécialement pour les dates-->
</fieldset>
<button
(click)="showDateInterval = !showDateInterval"
[ngClass]="{ active: showDateInterval }"
class="btn btn--primary"
id="toggle_interval_button"
>
<i class="fa fa-clock-o" aria-hidden="true"></i>
{{ 'dates.add_interval' | translate }}
</button>
<section *ngIf="showDateInterval" class="date-interval form-row">
<h2>{{ 'dates.add_interval' | translate }}</h2>
<p>
{{ 'dates.interval_propose' | translate }}
<input (change)="countDays()" formControlName="startDateInterval" type="date" />
{{ 'dates.interval_span' | translate }}
<input (change)="countDays()" formControlName="endDateInterval" type="date" />
<br />
</p>
<button (click)="addIntervalOfDates()" class="btn btn-block btn--primary">
<i class="fa fa-plus" aria-hidden="true"></i>
{{ 'dates.interval_button' | translate }}
{{ intervalDays }}
{{ 'dates.interval_button_dates' | translate }}
</button>
<hr />
</section>
<div class="form-field">
<h2>
{{ 'choices.title' | translate }}
@ -94,6 +122,9 @@
</span>
</span>
<p class="hint">
{{ 'creation.choices_hint' | translate }}
</p>
<span *ngFor="let choice of choices.controls; let i = index">
<div class="form-row" [formGroup]="choice">
<div class="columns">
@ -104,11 +135,23 @@
{{ i * 1 + 1 }})
</div>
<div class="column">
<label for="label" class="hidden">label</label>
<input formControlName="label" id="label" placeholder="Enter a choice description" />
<label [for]="'choice_label_' + i" class="hidden">label</label>
<input
formControlName="label"
[id]="'choice_label_' + i"
placeholder="Enter a choice description"
(keyup)="keyOnChoice($event, i)"
(keyup.backspace)="deleteChoiceField(i)"
/>
<br />
<label for="imageUrl" class="hidden">image Url</label>
<input formControlName="imageUrl" id="imageUrl" placeholder="URL de l' image" />
<label [for]="'image_url_' + i" class="hidden">image Url</label>
<input
formControlName="imageUrl"
[id]="'image_url_' + i"
placeholder="URL de l' image"
(keyup)="keyOnChoice($event, i)"
(keyup.backspace)="deleteChoiceField(i)"
/>
</div>
</div>
</div>

View File

@ -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.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();
}
}
}
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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",