forked from tykayn/funky-framadate-front
add keybaord shortcuts on array for choices
This commit is contained in:
parent
d3042b3723
commit
4769ecefc3
@ -65,6 +65,34 @@
|
|||||||
<fieldset class="date-kind">
|
<fieldset class="date-kind">
|
||||||
<!-- choix spécialement pour les dates-->
|
<!-- choix spécialement pour les dates-->
|
||||||
</fieldset>
|
</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">
|
<div class="form-field">
|
||||||
<h2>
|
<h2>
|
||||||
{{ 'choices.title' | translate }}
|
{{ 'choices.title' | translate }}
|
||||||
@ -94,6 +122,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<p class="hint">
|
||||||
|
{{ 'creation.choices_hint' | translate }}
|
||||||
|
</p>
|
||||||
<span *ngFor="let choice of choices.controls; let i = index">
|
<span *ngFor="let choice of choices.controls; let i = index">
|
||||||
<div class="form-row" [formGroup]="choice">
|
<div class="form-row" [formGroup]="choice">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
@ -104,11 +135,23 @@
|
|||||||
{{ i * 1 + 1 }})
|
{{ i * 1 + 1 }})
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<label for="label" class="hidden">label</label>
|
<label [for]="'choice_label_' + i" class="hidden">label</label>
|
||||||
<input formControlName="label" id="label" placeholder="Enter a choice description" />
|
<input
|
||||||
|
formControlName="label"
|
||||||
|
[id]="'choice_label_' + i"
|
||||||
|
placeholder="Enter a choice description"
|
||||||
|
(keyup)="keyOnChoice($event, i)"
|
||||||
|
(keyup.backspace)="deleteChoiceField(i)"
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<label for="imageUrl" class="hidden">image Url</label>
|
<label [for]="'image_url_' + i" class="hidden">image Url</label>
|
||||||
<input formControlName="imageUrl" id="imageUrl" placeholder="URL de l' image" />
|
<input
|
||||||
|
formControlName="imageUrl"
|
||||||
|
[id]="'image_url_' + i"
|
||||||
|
placeholder="URL de l' image"
|
||||||
|
(keyup)="keyOnChoice($event, i)"
|
||||||
|
(keyup.backspace)="deleteChoiceField(i)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 { Poll } from '../../../core/models/poll.model';
|
||||||
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { UuidService } from '../../../core/services/uuid.service';
|
import { UuidService } from '../../../core/services/uuid.service';
|
||||||
import { ApiService } from '../../../core/services/api.service';
|
import { ApiService } from '../../../core/services/api.service';
|
||||||
import { ToastService } from '../../../core/services/toast.service';
|
import { ToastService } from '../../../core/services/toast.service';
|
||||||
import { PollService } from '../../../core/services/poll.service';
|
import { PollService } from '../../../core/services/poll.service';
|
||||||
|
import { DateUtilities } from '../../old-stuff/config/DateUtilities';
|
||||||
|
import { DOCUMENT } from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-admin-form',
|
selector: 'app-admin-form',
|
||||||
@ -18,13 +20,22 @@ export class FormComponent implements OnInit {
|
|||||||
|
|
||||||
public urlPrefix: string = window.location.origin + '/participation/';
|
public urlPrefix: string = window.location.origin + '/participation/';
|
||||||
public advancedDisplayEnabled = false;
|
public advancedDisplayEnabled = false;
|
||||||
|
public showDateInterval = true;
|
||||||
|
startDateInterval: any;
|
||||||
|
intervalDays: any;
|
||||||
|
intervalDaysDefault = 7;
|
||||||
|
endDateInterval: any;
|
||||||
|
dateList: any[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
|
private cd: ChangeDetectorRef,
|
||||||
private uuidService: UuidService,
|
private uuidService: UuidService,
|
||||||
private toastService: ToastService,
|
private toastService: ToastService,
|
||||||
private pollService: PollService,
|
private pollService: PollService,
|
||||||
private apiService: ApiService
|
public dateUtilities: DateUtilities,
|
||||||
|
private apiService: ApiService,
|
||||||
|
@Inject(DOCUMENT) private document: any
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@ -61,6 +72,13 @@ export class FormComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.choices.push(newControlGroup);
|
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 {
|
deleteChoiceField(index: number): void {
|
||||||
@ -73,7 +91,7 @@ export class FormComponent implements OnInit {
|
|||||||
this.choices.setValue([]);
|
this.choices.setValue([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
initFormDefault(): void {
|
initFormDefault(showDemoValues = true): void {
|
||||||
this.form = this.fb.group({
|
this.form = this.fb.group({
|
||||||
title: ['', [Validators.required, Validators.minLength(12)]],
|
title: ['', [Validators.required, Validators.minLength(12)]],
|
||||||
creatorPseudo: ['', [Validators.required]],
|
creatorPseudo: ['', [Validators.required]],
|
||||||
@ -82,6 +100,8 @@ export class FormComponent implements OnInit {
|
|||||||
description: ['', [Validators.required]],
|
description: ['', [Validators.required]],
|
||||||
choices: new FormArray([]),
|
choices: new FormArray([]),
|
||||||
isAboutDate: [true, [Validators.required]],
|
isAboutDate: [true, [Validators.required]],
|
||||||
|
startDateInterval: ['', [Validators.required]],
|
||||||
|
endDateInterval: ['', [Validators.required]],
|
||||||
isProtectedByPassword: [false, [Validators.required]],
|
isProtectedByPassword: [false, [Validators.required]],
|
||||||
isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]],
|
isOwnerNotifiedByEmailOnNewVote: [false, [Validators.required]],
|
||||||
isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]],
|
isOwnerNotifiedByEmailOnNewComment: [false, [Validators.required]],
|
||||||
@ -90,9 +110,33 @@ export class FormComponent implements OnInit {
|
|||||||
expiracyNumberOfDays: [60, [Validators.required, Validators.min(0)]],
|
expiracyNumberOfDays: [60, [Validators.required, Validators.min(0)]],
|
||||||
});
|
});
|
||||||
console.log('this.form ', this.form);
|
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 {
|
setDemoValues(): void {
|
||||||
this.addChoice('orange');
|
this.addChoice('orange');
|
||||||
this.addChoice('raisin');
|
this.addChoice('raisin');
|
||||||
@ -116,7 +160,88 @@ export class FormComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
askInitFormDefault(): void {
|
askInitFormDefault(): void {
|
||||||
this.initFormDefault();
|
this.initFormDefault(false);
|
||||||
this.toastService.display('formulaire réinitialisé');
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,4 +60,12 @@ export class DateUtilities {
|
|||||||
getDoubleDigits(str) {
|
getDoubleDigits(str) {
|
||||||
return ('00' + str).slice(-2);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export class DatesComponent extends BaseComponent implements OnInit {
|
|||||||
date_object: new Date(),
|
date_object: new Date(),
|
||||||
timeList: [],
|
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();
|
this.cd.detectChanges();
|
||||||
const elem = this.document.querySelector(selector);
|
const elem = this.document.querySelector(selector);
|
||||||
if (elem) {
|
if (elem) {
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
},
|
},
|
||||||
"choose_title": "Dont le titre sera",
|
"choose_title": "Dont le titre sera",
|
||||||
"choose_title_placeholder": "titre",
|
"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": "Je peux aussi préciser mon nom si je le souhaite",
|
||||||
"name_placeholder": "mon nom",
|
"name_placeholder": "mon nom",
|
||||||
"description": "et la description serait",
|
"description": "et la description serait",
|
||||||
|
Loading…
Reference in New Issue
Block a user