Subversion Repositories eFlore/Applications.cel

Rev

Rev 3325 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3318 idir 1
function UtilsLg() {
2
	// this.infosUtilisateur = null;
3
	this.langue = $( 'body' ).data( 'lang' );
4
	this.urlRacine = window.location.origin;
5
	// système de traduction minimaliste
6
	this.msgs = {
7
		fr: {
8
			'arbre'                             : 'Arbre',
9
			'dupliquer'                         : 'Dupliquer',
10
			'saisir-lichens'                    : 'Saisir les lichens',
11
			'format-non-supporte'               : 'Le format de fichier n\'est pas supporté, les formats acceptés sont',
12
			'image-deja-chargee'                : 'Cette image a déjà été utilisée',
13
			'date-incomplete'                   : 'Format : jj/mm/aaaa.',
14
			'observations-transmises'           : 'observations transmises',
15
			'supprimer-observation-liste'       : 'Supprimer cette observation de la liste à transmettre',
16
			'milieu'                            : 'Milieu',
17
			'commentaires'                      : 'Commentaires',
18
			'non-lie-au-ref'                    : 'non lié au référentiel',
19
			'obs-le'                            : 'le',
20
			'non-connexion'                     : 'Veuillez entrer votre login et votre mot de passe',
21
			'obs-numero'                        : 'Observation n°',
22
			'erreur'                            : 'Erreur',
23
			'erreur-inconnue'                   : 'Erreur inconnue',
24
			'erreur-image'                      : 'Erreur lors du chargement des images',
25
			'erreur-ajax'                       : 'Erreur Ajax',
26
			'erreur-chargement'                 : 'Erreur lors du chargement de l\'observation',
27
			'erreur-chargement-obs-utilisateur' : 'Erreur lors du chargement des observations de cet utilisateur',
28
			'erreur-formulaire'                 : 'Erreur: impossible de charger le formulaire',
29
			'lieu-obs'                          : 'observé à',
30
			'lieu-dit'                          : 'Lieu-dit',
31
			'station'                           : 'Station',
32
			'date-rue'                          : 'Un releve existe dejà à cette date pour cette rue.',
33
			'rechargement-page'                 : 'Êtes vous sûr de vouloir quiter la page?\nLes observations saisies mais non transmises seront perdues.'
34
		},
35
		en: {
36
			'arbre'                             : 'Tree',
37
			'dupliquer'                         : 'Duplicate',
38
			'saisir-lichens'                    : 'Enter the lichens',
39
			'format-non-supporte'               : 'The file format is not supported, the accepted formats are',
40
			'image-deja-chargee'                : 'This image has already been used',
41
			'date-incomplete'                   : 'Format: dd/mm/yyyy.',
42
			'observations-transmises'           : 'observations transmitted',
43
			'supprimer-observation-liste'       : 'Delete this observation from the list to be transmitted',
44
			'milieu'                            : 'Environment',
45
			'commentaires'                      : 'Comments',
46
			'non-lie-au-ref'                    : 'unrelated to the referencial ',
47
			'obs-le'                            : 'the',
48
			'non-connexion'                     : 'Please enter your login and password',
49
			'obs-numero'                        : 'Observation number ',
50
			'erreur'                            : 'Error',
51
			'erreur-inconnue'                   : 'Unknown error',
52
			'erreur-image'                      : 'Error loading the images',
53
			'erreur-ajax'                       : 'Ajax Error',
54
			'erreur-chargement'                 : 'Error loading the observation',
55
			'erreur-chargement-obs-utilisateur' : 'Error loading this user\'s observations',
56
			'erreur-formulaire'                 : 'Error: couldn\'t load form',
57
			'lieu-obs'                          : 'observed at',
58
			'lieu-dit'                          : 'Locality',
59
			'station'                           : 'Place',
60
			'date-rue'                          : 'A record already exists on this date for this street',
61
			'rechargement-page'                 : 'Are you sure you want to leave the page?\nAll untransmitted observations will be lost.'
62
		}
63
	};
64
}
65
 
66
 
67
UtilsLg.prototype.chargerForm = function( nomSquelette, lgFormObj ) {
68
	const lthis = this;
69
	var urlSqueletteArbres = this.urlRacine + '/widget:cel:lg?squelette=' + nomSquelette;
70
 
71
	$.ajax({
72
		url: urlSqueletteArbres,
73
		type: 'get',
74
		success: function( squelette ) {
75
			if ( lthis.valOk( squelette ) ) {
76
				lgFormObj.chargerSquelette( squelette, nomSquelette );
77
			}
78
		},
79
		error: function() {
80
			$( '#charger-form' ).html( lthis.msgTraduction( 'erreur-formulaire' ) );
81
		}
82
	});
83
};
84
 
85
UtilsLg.prototype.chargerFormLichens = function( squelette, nomSquelette ) {
86
	if ( this.valOk( $( '#releve-data' ).val() ) ) {
87
		$( '#charger-form' ).html( squelette );
88
		const releveDatas = $.parseJSON( $( '#releve-data' ).val() );
89
		const nbArbres    = releveDatas.length -1;
90
 
91
		for ( var i = 1; i <= nbArbres ; i++ ) {
92
			$( '#choisir-arbre' ).append(
93
				'<option value="' + i + '">'+
94
					this.msgTraduction( 'arbre' ) + ' ' + i +
95
				'</option>'
96
			);
97
		}
98
	}
99
};
100
 
101
/**
102
 * Stocke en Json les valeurs du relevé dans en value d'un input hidden
103
 */
104
UtilsLg.prototype.formaterReleveData = function( releveDatas ) {
105
	var releve  = [],
106
		obs  = releveDatas.obs,
107
		obsE = releveDatas.obsE;
108
 
109
	releve[0] = {
110
		utilisateur        : obs.ce_utilisateur,
111
		date               : obs.date_observation,
112
		rue                : obsE.rue,
113
		'commune-nom'      : obs.zone_geo,
114
		'commune-insee'    : obs.ce_zone_geo,
115
		pays               : obs.pays,
116
		latitude           : obs.latitude,
117
		longitude          : obs.longitude,
118
		altitude           : obs.altitude,
119
		commentaires       : obs.commentaire
120
	};
121
	return releve;
122
};
123
 
124
/**
125
 * Stocke en Json les valeurs d'une obs
126
 */
127
UtilsLg.prototype.formaterArbreData = function( arbresDatas ) {
128
	var retour = {},
129
		obs          = arbresDatas.obs,
130
		obsE         = arbresDatas.obsE,
131
		miniatureImg = [];
132
	if( this.valOk( obs['miniature-img'] ) ) {
133
		miniatureImg = obs['miniature-img'];
134
	} else if ( this.valOk( obsE['miniature-img'] ) ) {
135
		miniatureImg = $.parseJSON( obsE['miniature-img'] );
136
	}
137
 
138
	retour = {
139
		'date_rue_commune'      : obs.date_observation + obsE.rue + obs.zone_geo,
140
		'num-arbre'             : obsE.num_arbre,
141
		'id_observation'        : obs.id_observation,
142
		'taxon'                 : {
143
			'numNomSel' : obs.nom_sel_nn,
144
			'value'     : obs.nom_sel,
145
			'nomRet'    : obs.nom_ret,
146
			'numNomRet' : obs.nom_ret_nn,
147
			'nt'        : obs.nt,
148
			'famille'   : obs.famille,
149
		},
150
		'miniature-img'         : miniatureImg,
151
		'referentiel'           : obs.nom_referentiel,
152
		'certitude'             : obs.certitude,
3325 idir 153
		'rue-arbres'            : obsE['rue-arbres'],
3318 idir 154
		'latitude-arbres'       : obsE['latitude-arbres'],
155
		'longitude-arbres'      : obsE['longitude-arbres'],
156
		'altitude-arbres'       : obsE['altitude-arbres'],
157
		'circonference'         : obsE.circonference,
158
		'face-ombre'            : obsE['face-ombre'],
159
		'com-arbres'            : obsE['com-arbres']
160
	};
161
	return retour;
162
};
163
 
164
UtilsLg.prototype.fournirDate = function( dateObs ) {
165
	if ( /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/.test( dateObs ) ) {
166
		return dateObs;
167
	} else if ( /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test( dateObs ) ) {
168
		var dateArray = dateObs.split( '-' );
169
		return dateArray[2] + '/' + dateArray[1] + '/' + dateArray[0]
170
	} else {
171
		console.log( 'erreur date : ' + dateObs )
172
	}
173
};
174
 
175
/**
176
 * Si la langue est définie dans this.langue, et si des messages sont définis
177
 * dans this.msgs, tente de trouver le message dont la clé est [cle] dans la
178
 * langue en cours. S'il n'est pas trouvé, retourne la version française (par
179
 * défaut); si celle-ci n'exite pas, retourne "N/A".
180
 */
181
UtilsLg.prototype.msgTraduction = function( cle ) {
182
	var msg = 'N/A';
183
 
184
	if ( this.msgs ) {
185
		if ( this.langue in this.msgs && cle in this.msgs[this.langue] ) {
186
			msg = this.msgs[this.langue][cle];
187
		} else if ( cle in this.msgs['fr'] ) {
188
			msg = this.msgs['fr'][cle];
189
		}
190
	}
191
	return msg;
192
};
193
 
194
/**
195
* Permet à la fois de vérifier qu'une valeur ou objet existe et n'est pas vide
196
* et de comparer à une autre valeur :
197
* Vérifie qu'une variable ou objet n'est pas : vide, null, undefined, NaN
198
* Si comparer est défini on le compare à valeur en fonction de sensComparaison
199
* Un booléen est une variable valide : on retourne true
200
* @param { string || number || object || undefined } valeur
201
* @param { boolean } sensComparaison : true = rechercher, false = refuser
202
* @param { string || number || object || undefined || boolean } comparer :valeur à comparer
203
* @returns {boolean}
204
*/
205
UtilsLg.prototype.valOk = function( valeur, sensComparaison = true, comparer = undefined ) {
206
	var retour = true;
207
	if ( 'boolean' !== typeof valeur ) {
208
		switch( typeof valeur ) {
209
			case 'string' :
210
				retour = ( '' !== valeur );
211
			 break;
212
			case 'number' :
213
					retour = ( NaN !== valeur );
214
				break;
215
			case 'object' :
216
					retour = ( null !== valeur && undefined !== valeur && !$.isEmptyObject( valeur ) );
217
					if (  null !== valeur && undefined !== valeur.length ) {
218
						retour = ( retour  && 0 < valeur.length );
219
					}
220
				break;
221
			case 'undefined' :
222
			default :
223
				retour = false;
224
		}
225
		if ( retour && comparer !== undefined ) {
226
			var resultComparaison = ( comparer === valeur );
227
			retour = ( sensComparaison ) ? resultComparaison : !resultComparaison ;
228
		}
229
 
230
		return retour;
231
	} else {
232
		// Un booléen est une valeur valable
233
		return true;
234
	}
235
}
236
 
237
// Lib hors objet
238
 
239
/*************************************
240
 *  Fonctions de Style et Affichage  *
241
 *      des éléments "spéciaux"      *
242
 *************************************/
243
 
244
// Logique d'affichage pour le input type=file
245
function inputFile() {
246
  // Initialisation des variables
247
  var $fileInput  = $( '.input-file' ),
248
      $button     = $( '.label-file' );
249
  // Action lorsque la "barre d'espace" ou "Entrée" est pressée
250
  $( '#charger-form' ).on( 'keydown', '.label-file', function( event ) {
251
    if ( event.keyCode == 13 || event.keyCode == 32 ) {
252
      $( '#' + $( this ).attr( 'for' ) + '.input-file' ).click();
253
    }
254
  });
255
}
256
 
257
// Style et affichage des list-checkboxes
258
function inputListCheckbox() {
259
  // On écoute le click sur une list-checkbox ('.selectBox')
260
  // à tout moment de son insertion dans le dom
261
  // _ S'assurer de bien viser la bonne list-checkbox
262
  // _ Au click sur un autre champ remballer la list-checkbox
263
  $( document ).click( function( event ) {
264
    var target = event.target;
265
 
266
    if ( !$( target ).is( '.overSelect' ) && 0 === $( target ).closest( '.checkboxes' ).length ) {
267
      $( '.checkboxes' ).each( function () {
268
        $( this ).addClass( 'hidden' );
269
      });
270
      $( '.selectBox select.focus', '#zone-appli' ).each( function() {
271
        $( this ).removeClass( 'focus' );
272
      });
273
    }
274
  });
275
  $( '#zone-appli' ).on( 'click' , '.selectBox' , function() {
276
    // afficher/cacher le volet des checkboxes et focus
277
    $( this ).next().toggleClass( 'hidden' );
278
    $( this ).find( 'select' ).toggleClass( 'focus' );
279
 
280
    // Cacher le volet des autres checkboxes et retirer leur focus
281
    var $checkboxes = $( this ).next(),
282
        count = $( '.checkboxes' ).length;
283
 
284
    for ( var i = 0; i < count; i++ ) {
285
      if ( $( '.checkboxes' )[i] !== $checkboxes[0] && !$checkboxes.hasClass( 'hidden' ) ) {
286
        var $otherListCheckboxes = $( '.checkboxes' )[i];
287
        if ( !$otherListCheckboxes.classList.contains( 'hidden' ) ) {
288
          $otherListCheckboxes.classList.add( 'hidden' );
289
        }
290
        if( $otherListCheckboxes.previousElementSibling.firstElementChild.classList.contains( 'focus' ) ) {
291
          $otherListCheckboxes.previousElementSibling.firstElementChild.classList.remove( 'focus' );
292
        }
293
      }
294
    }
295
  });
296
}
297
 
298
// Style et affichage des input type="range"
299
function inputRangeDisplayNumber() {
300
  $( 'input[type="range"]','#charger-form' ).each( function() {
301
    $( this ).siblings( '.range-live-value' ).text( $( this ).val() );
302
  });
303
  $( '#top' ).on( 'input' , 'input[type="range"]' , function () {
304
    $( this ).siblings( '.range-live-value' ).text( $( this ).val() );
305
  });
306
  $( '#top' ).on( 'click', '#ajouter-obs', function() {
307
    $( '.range-live-value' ).each( function() {
308
      var $this = $( this );
309
      $this.text( '' );
310
    });
311
  });
312
}
313
 
314
// Activation/Desactivation et contenu de la modale Bootstrap
315
// https://getbootstrap.com/docs/3.3/javascript/#modals
316
function newFieldsHelpModal() {
317
  $( '#zone-appli' ).on( 'click' , '.help-button' , function ( event ) {
318
    var thisFieldKey = $( this ).data( 'key' ),
319
        fileMimeType = $( this ).data( 'mime-type' );
320
 
321
    // Titre
322
    $( '#help-modal-label' ).text( 'Aide pour : ' +  $( this ).data( 'name' ) );
323
    if( fileMimeType.match( 'image' ) ) {
324
      var extention = fileMimeType.replace( /(?:imag)?e\/?/g , '' );
325
      // var extention = 'jpg';
326
      $( '#print_content' ).append( '<img src="' + CHEMIN_FICHIERS + thisFieldKey + '.' + extention + '" style="max-width:100%" alt="' + thisFieldKey + '" />' );
327
    }
328
    // Sortie avec la touche escape
329
    $( '#help-modal' ).modal( { keyboard : true } );
330
    // Affichage
331
    $( '#help-modal' ).modal({ show: true });
332
    // Remplacer l'autofocus qui ne fonctionne plus en HTML5
333
    // Message dans la doc de bootstrap :
334
    // Due to how HTML5 defines its semantics,
335
    // the autofocus HTML attribute has no effect in Bootstrap modals.
336
    // To achieve the same effect, use some custom JavaScript
337
    $( '#help-modal' ).on( 'shown.bs.modal' , function () {
338
      $( '#myInput' ).trigger( 'focus' );
339
    })
340
    // Réinitialisation
341
    $( '#help-modal' ).on( 'hidden.bs.modal' , function () {
342
      $( '#help-modal-label' ).text();
343
      $( '#print_content' ).empty();
344
    })
345
  });
346
}
347
 
348
// Activation/Desactivation et contenu de la modale Bootstrap
349
// https://getbootstrap.com/docs/3.3/javascript/#modals
350
function projetHelpModale() {
351
  $( '#top' ).on ( 'click', '#info-button', function ( event ) {
352
    var fileMimeType = $( this ).data( 'mime-info' );
353
 
354
    // Titre
355
    $( '#help-modal-label' ).text( 'Aide du projet : ' +  $( '#titre-projet' ).text() );
356
    if( fileMimeType.match( 'image' ) ) {
357
      var extention = fileMimeType.replace( /(?:imag)?e\/?/g , '' );
358
      $( '#print_content' ).append( '<img src="' + CHEMIN_FICHIERS + 'info.' + extention + '" style="max-width:100%" alt="info projet" />' );
359
    }
360
    // Sortie avec la touche escape
361
    $( '#help-modal' ).modal( { keyboard : true } );
362
    // Affichage
363
    $( '#help-modal' ).modal({ show: true });
364
    // Remplacer l'autofocus qui ne fonctionne plus en HTML5
365
    // Message dans la doc de bootstrap :
366
    // Due to how HTML5 defines its semantics,
367
    // the autofocus HTML attribute has no effect in Bootstrap modals.
368
    // To achieve the same effect, use some custom JavaScript
369
    $( '#help-modal' ).on( 'shown.bs.modal' , function () {
370
      $( '#myInput' ).trigger( 'focus' );
371
    })
372
    // Réinitialisation
373
    $( '#help-modal' ).on( 'hidden.bs.modal' , function () {
374
      $( '#help-modal-label' ).text();
375
      $( '#print_content' ).empty();
376
    });
377
 
378
  });
379
}
380
 
381
// Faire apparaitre un champ text "Autre"
382
function onOtherOption() {
383
  const PREFIX = 'collect-other-';
384
 
385
  // Ajouter un champ texte pour "Autre"
386
  function optionAdd( otherId, $target, element, dataName ) {
387
    $target.after(
388
      '<div class="control-group">'+
389
        '<label'+
390
          ' for="' + otherId + '"'+
391
          ' class="' + otherId + '"'+
392
        '>'+
393
          'Autre option :'+
394
        '</label>'+
395
        '<input'+
396
          ' type="text"'+
397
          ' id="' + otherId + '"'+
398
          ' name="' + otherId + '"'+
399
          ' class="collect-other form-control"'+
400
          ' data-name="' + dataName + '"'+
401
          ' data-element="' + element + '"'+
402
        '>'+
403
      '</div>'
404
    );
405
    $( '#' + otherId ).focus();
406
  }
407
 
408
  // Supprimer un champ texte pour "Autre"
409
  function optionRemove( otherId ) {
410
    $( '.' + otherId + ', #' + otherId ).remove();
411
  }
412
 
413
  $( '.other', '#form-arbre' ).each( function() {
414
    if( $( this ).hasClass( 'is-select' ) ) {
415
      var dataName = $( this ).data( 'name' ),
416
          otherId  = PREFIX + dataName;
417
 
418
      // Insertion du champ "Autre" après les boutons
419
      optionAdd( otherId, $( this ).parent( '.add-field-select' ), 'select', dataName );
420
    } else if ( $( this ).is( ':checked' ) ) {
421
      var dataName = $( this ).data( 'name' ),
422
          otherId  = PREFIX + dataName,
423
          element = $( this ).data( 'element' );
424
      // Insertion du champ "Autre" après les boutons
425
      optionAdd( otherId, $( this ).parent( 'label' ), element, dataName );
426
    }
427
  });
428
 
429
  $( '#charger-form' ).on( 'change', '.select', function () {
430
    var dataName = $( this ).data( 'name' ),
431
        otherId  = PREFIX + dataName;
432
 
433
    if( 'other' === $( this ).val() ) {
434
        // Insertion du champ "Autre" après les boutons
435
        optionAdd( otherId, $( this ).parent( '.add-field-select' ), 'select', dataName );
436
      } else {
437
        // Suppression du champ autre
438
        optionRemove( otherId );
439
        $( this ).find( '.other' ).val( 'other' );
440
      }
441
  });
442
 
443
  $( '#charger-form' ).on( 'change', 'input[type=radio]', function () {
444
    var dataName = $( this ).data( 'name' ),
445
        otherId  = PREFIX + dataName;
446
 
447
    if( 'other' === $( this ).val() ) {
448
      // Insertion du champ "Autre" après les boutons
449
      optionAdd( otherId, $( this ).parent( 'label' ), 'radio', dataName );
450
    } else {
451
      // Suppression du champ autre
452
      optionRemove( otherId );
453
      $( this ).closest( '.radio' ).find( '.other' ).val( 'other' );
454
    }
455
  });
456
 
457
  $( '#charger-form' ).on( 'click', '.list-checkbox .other,.checkbox .other', function () {
458
    var dataName = $( this ).data( 'name' ),
459
        otherId  = PREFIX + dataName,
460
        element = $( this ).data( 'element' );
461
 
462
    if( $( this ).is( ':checked' ) ) {
463
        // Insertion du champ "Autre" après les boutons
464
        optionAdd( otherId, $( this ).parent( 'label' ), element, dataName );
465
      } else {
466
        // Suppression du champ autre
467
        optionRemove( otherId );
468
        $( this ).val( 'other' );
469
      }
470
  });
471
}
472
 
473
function collectOtherOption() {
474
  $( '#charger-form' ).on( 'change', '.collect-other', function () {
475
    var otherIdSuffix = $( this ).data( 'name' ).replace( '[]', '' );
476
    var element = $( this ).data( 'element' );
477
 
478
    if ( '' === $( this ).val() ){
479
      if ( 'select' === element ) {
480
        $( '#' + otherIdSuffix ).find( '.other' ).prop( 'selected', false ).val( 'other' );
481
      } else {
482
        $( '#other-' + otherIdSuffix ).prop( 'checked', false ).val( 'other' );
483
      }
484
      $( 'label.collect-other-' + otherIdSuffix ).remove();
485
      $( this ).remove();
486
    } else {
487
      if ( 'select' === element ) {
488
        $( '#' +  otherIdSuffix ).find( '.other' ).val( $( this ).val() );
489
        $( '#' +  otherIdSuffix ).val( $( this ).val() );
490
        $( '#' +  otherIdSuffix + ' option').not( '.other' ).prop( 'selected', false );
491
        $( '#' +  otherIdSuffix ).find( '.other' ).prop( 'selected', true );
492
      } else {
493
        if ( 'radio' === element ) {
494
          $( 'input[name=' + otherIdSuffix + ']' ).not( '#other-' + otherIdSuffix ).prop( 'checked', false );
495
        }
496
        $( '#other-' + otherIdSuffix ).val( $( this ).val() );
497
        $( '#other-' + otherIdSuffix ).prop( 'checked', true );
498
      }
499
    }
500
  });
501
}
502
 
503
/***************************
504
 *  Lancement des scripts  *
505
 ***************************/
506
const CHEMIN_FICHIERS = $( '#zone-appli' ).data('url-fichiers');
507
 
508
jQuery( document ).ready( function() {
509
  // Modale "aide" du projet
510
  projetHelpModale();
511
  // Affichage input file
512
  inputFile();
513
  // Affichage des List-checkbox
514
  inputListCheckbox();
515
  // Affichage des Range
516
  inputRangeDisplayNumber()
517
  // Modale "aide"
518
  newFieldsHelpModal();
519
  // Ajout/suppression d'un champ texte "Autre"
520
  onOtherOption();
521
  // Récupérer les données entrées dans "Autre"
522
  collectOtherOption();
523
});