$(document).ready(function(){
	if($.urlParam('title')!=null){
	    window.parent.document.title = decodeURI($.urlParam('title'));
	}

	var page = $.page();
	page = page == '' ? 'index' : page;
	var init = 'init_'+page;
	init = init.replace(/[^a-z_0-9]/g,'_');

	init_components();

	if($.urlParam('module')==null){
		if(window[init]!=null) window[init]($.urlParam());
	} else {
		var mod = $.urlParam('module').replace(/[^a-z_0-9]/g,'_');
		var init = 'init_plugin_'+mod;
		if(window[init]!=null) window[init]($.urlParam());
	}

	//SHOW HTTP ERROR/NOTICE
	if ($.urlParam('error') != null) {
		$.message('error', decodeURIComponent($.urlParam('error')), 0);
		$.urlParam('error', false);
	}
	if ($.urlParam('info') != null) {
		$.message('info', decodeURIComponent($.urlParam('info')));
		$.urlParam('info', false);
	}
	if ($.urlParam('success') != null) {
		$.message('success', decodeURIComponent($.urlParam('success')));
		$.urlParam('success', false);
	}

    //Icône menu mobile
    $('#mainMenu > button').on('click', function(e){
    	$('.menu').toggleClass('open');
    });
    $('.navbar-toggler').on('click', function(e){
    	if($(e.target).closest('#mainMenu').length) return;
 		$('#navbarCollapse').collapse('hide');
 		$('.menu').removeClass('open');
    });

    //Positionnement nom de l'utilisateur
    if($(document).width() <= 767){
    	var userFullname = $('#loginHeader > .user-dropdown-menu .user-fullname').detach();
		$('#loginHeader > .user-dropdown-menu > button.dropdown-toggle').append(userFullname);
    }
});

//Changement positionnement nom de l'utilisateur 
//connecté au redimensionnement de la fenêtre
$(window).resize(function(event) {
	if($(document).width() > 767){
		var userFullname = $('#loginHeader > .user-dropdown-menu > button.dropdown-toggle > .user-fullname').detach();
		$('#loginHeader > .user-dropdown-menu > .dropdown-menu').prepend(userFullname);
	}
	if($(document).width() <= 767){
		var userFullname = $('#loginHeader > .user-dropdown-menu .user-fullname').detach();
		$('#loginHeader > .user-dropdown-menu > button.dropdown-toggle').append(userFullname);
	}
});

/* COMPOSANT */
function init_components(selector){
	var selected = selector ? $('[data-type]',selector) : '[data-type]';
	$(selected).each(function(i,input){
		var input = $(input);
		switch($(input).attr('data-type')){
			case 'date':
				input.date();
			break;
			/**
			 * data-step : L'intervalle entre 2 valeurs en minutes
			 */
			case 'hour':
				input.hour();
			break;
			case 'image':
				if(input.closest('.type-image-bloc').length!=0) break;
				input.wrap( "<div class='type-image-bloc'></div>");
				var src = ($(input).attr('value')!='') ? $(input).attr('value') : 'img/default-image.png';
				
				src += src.indexOf('?')!=-1 ? '&' : '?';
				src += 't='+(Math.random()*1000);
				var thumbnail = $('<img src="'+src+'" >');
				var deleteBtn = !input.attr('data-delete') ? '' : '<div class="btn btn-delete-img noPrint" onclick="'+input.attr('data-delete')+'"><i class="fas fa-times"></i></div>';
				input.before(thumbnail);
				if(thumbnail.attr('src').indexOf('default-') === -1) thumbnail.before(deleteBtn);
				input.addClass('noPrint');
				input.change(function(){
					var reader = new FileReader();
					reader.onload = function (e) {
						thumbnail.attr('src', e.target.result);
						thumbnail.before(deleteBtn);
					}
				   reader.readAsDataURL(input.get(0).files[0]);
				});
			break;

			//Selection de tag liés a un dictionnary
			case 'tag-list':
				var container;
				var picker;
				var pickerLi;
				
				if(!input.data("data-component")){
					container = $('<div class="'+input.attr('class')+' data-type-tag-list"><ul><li class="tag-picker-li"><input type="text"></li></ul></div>');
					input.before(container);
					input.data("data-component", container);
					if(input.attr("required")) container.attr("required","");
				} else {
					container = input.data("data-component");
				}
				picker =  container.find('input:eq(0)');
				pickerLi =  container.find('ul li.tag-picker-li');
				container.find('.tag-picker-tag').remove();
				pickerLi.show();
				var pickerFunctions = {
					//Récuperation des valeurs sélectionnées (objet et id) en fonction des tags visuels présents
					getValues : function( container){
						var tags =  container.find('ul .tag-picker-tag');
						var values = {object:[],id:[]};
						tags.each(function(i,element){
							if($(element).attr('data-id') == '') return;
							var object = $(element).data();
							values['object'].push(object);
							values['id'].push(object.id);
						});
						return values;
					},
					//Ajout d'un tag visuel et mise à jour de l'input brut en fonction de l'objet  fournis
					addTag : function( container,tag){
						pickerLi =  container.find('ul li.tag-picker-li');
						if( container.find('li[data-id="'+tag.id+'"]').length>0) return;
						var tag = $('<li class="tag-picker-tag" data-slug="'+tag.slug+'" data-id="'+tag.id+'"><div>'+tag.name+'<i class="fa fa-times"></i></div></li>');
						pickerLi.before(tag);
						var values = pickerFunctions.getValues( container);
						input.val(values['id'].join(','));
						input.data('values',values['object']);


						if((values['id'].length) == 1 && input.attr('data-multiple') == null){
							pickerLi.hide();
						}else{
							pickerLi.show();
						}

						tag.find('i').click(function(){
							$(this).closest('.tag-picker-tag').remove();
							var values = pickerFunctions.getValues( container);
							input.val(values['id'].join(','));
							input.data('values',values['object']);
							if((values['id'].length-1) ==1 && input.attr('data-multiple') == null){
								pickerLi.hide();
							}else{
								pickerLi.show();
							}
						});
					}
				}
				//Gestion des champs déja remplis au chargement de la page
				if(input.val() !=''){
					var id = input.val();
					 container.find('ul').append('<li class="tag-picker-loader"><i class="fas fa-hourglass-half fa-spin"></i> Chargement...</li>');
					picker.hide();
					$.action({
						action : 'tag_list_by_id',
						id : id
					},function(r){
						 container.find('.tag-picker-loader').remove();
						picker.show();
						for(var key in r.tags)
							pickerFunctions.addTag( container,r.tags[key]);
						
					});
				}
				//Sélectionne l'input d'auto-completion ou que l'on clique dans le composant
				 container.find('ul').click(function(e){
					picker.focus();
					e.stopPropagation();
				});
				//Selectionne l'item dropdown actif lors de l'appuis sur entré
				picker.keyup(function(e){
					if(e.keyCode!=13 || input.is('[readonly]')) return;
					var active = $('.tag-picker-li .dropdown-menu .active');
					if(active.length==0) return;
					active.trigger('click');
					input.val('');
				});

				
				//aucompletion sur le nom des tags
				picker.autocomplete({
					action : 'tag_list_autocomplete',
					data : {
						parent : input.attr('data-slug')
					},
					skin : function(item){
						var html = '';
						var re = new RegExp(picker.val(),"gi");

						name = item.name.replace(re, function (x) {
							return '<strong>'+x+'</strong>';
						});

						
						html += '<div class="tag-infos"><span>'+name+'</span>'; 
						html += '<div class="clear"></div>';
						
						
						return html;
					},
					highlight : function(item){
						return item;
					},
					onClick : function(selected,element){
						picker.val('');
						selected.label = selected.name;

						pickerFunctions.addTag(container,selected);
						input.trigger('click').trigger('change');
					},
					onBlur : function(selected){
						if(input.attr('data-force')!='false' && input.val() == '') picker.val('');
					}
				});
			break;
			
			case 'user':
				var userContainer;
				var userPicker;
				var pickerLi;

				if(!input.data("data-component")){
					userContainer = $('<div class="'+input.attr('class')+' data-type-user"><ul><li class="user-picker-li"><input type="text"></li></ul></div>');
					input.before(userContainer);
					input.data("data-component", userContainer);
					if(input.attr("required")) userContainer.attr("required","");
				} else {
					userContainer = input.data("data-component");
				}
				userPicker = userContainer.find('input:eq(0)');
				pickerLi = userContainer.find('ul li.user-picker-li');
				userContainer.find('.user-picker-tag').remove();
				pickerLi.show();
				var pickerFunctions = {
					//Récuperation des valeurs sélectionnées (objet et uid) en fonction des tags visuels présents
					getValues : function(userContainer){
						var tags = userContainer.find('ul .user-picker-tag');
						var values = {object:[],uid:[]};
						tags.each(function(i,element){
							if($(element).attr('data-uid') == '') return;
							var object = $(element).data();
							values['object'].push(object);
							values['uid'].push(object.uid);
						});
						return values;
					},
					//Ajout d'un tag visuel et mise à jour de l'input brut en fonction de l'objet user fournis
					addTag : function(userContainer,user){
						pickerLi = userContainer.find('ul li.user-picker-li');
						if(userContainer.find('li[data-uid="'+user.uid+'"]').length>0) return;
						var tag = $('<li class="user-picker-tag" data-entity="'+user.type+'"  data-fullname="'+user.fullname+'" data-uid="'+user.uid+'"><div title="'+(user.type=='rank'?'Rang':'Utilisateur')+'">'+user.fullname+'<i class="fa fa-times"></i></div></li>');
						pickerLi.before(tag);
						var values = pickerFunctions.getValues(userContainer);
						input.val(values['uid'].join(','));
						input.data('values',values['object']);


						if((values['uid'].length) == 1 && input.attr('data-multiple') == null){
							pickerLi.hide();
						}else{
							pickerLi.show();
						}

						tag.find('i').click(function(){
							$(this).closest('.user-picker-tag').remove();
							var values = pickerFunctions.getValues(userContainer);
							input.val(values['uid'].join(','));
							input.data('values',values['object']);
							if((values['uid'].length-1) ==1 && input.attr('data-multiple') == null){
								pickerLi.hide();
							}else{
								pickerLi.show();
							}
						});
					}
				}
				//Gestion des champs déja remplis au chargement de la page
				if(input.val() !=''){
					var login = input.val();
					userContainer.find('ul').append('<li class="user-picker-loader"><i class="fas fa-hourglass-half fa-spin"></i> Chargement...</li>');
					userPicker.hide();
					$.action({
						action : 'user_by_uid',
						login : login
					},function(r){
						userContainer.find('.user-picker-loader').remove();
						userPicker.show();
						for(var key in r.users)
							pickerFunctions.addTag(userContainer,r.users[key]);
						
					});
				}
				//Sélectionne l'input d'auto-completion ou que l'on clique dans le composant
				userContainer.find('ul').click(function(e){
					userPicker.focus();
					e.stopPropagation();
				});
				//Selectionne l'item dropdown actif lors de l'appuis sur entré
				userPicker.keyup(function(e){
					if(e.keyCode!=13 || input.is('[readonly]')) return;
					var active = $('.user-picker-li .dropdown-menu .active');
					if(active.length==0) return;
					active.trigger('click');
					input.val('');
				});

				var types = ['user'];
				if(input.data('types') && input.data('types')!='')
					types = input.data('types').split(',');
				//aucompletion sur le nom des users / rangs
				userPicker.autocomplete({
					action : 'user_autocomplete',
					data : {
						types : types
					},
					skin : function(item){
						var html = '';
						var re = new RegExp(userPicker.val(),"gi");

						name = item.name.replace(re, function (x) {
							return '<strong>'+x+'</strong>';
						});

						if(item.type=='user'){
							if(item.avatar) html += '<div class="user-logo"><img src="'+item.avatar+'" class="avatar-mini avatar-rounded"></div>'; 
							html += '<div class="user-infos"><span>'+name+'</span> <small class="text-muted">- Utilisateur</small>'; 
							html += item.function ? '<br/><small>'+item.function+'</small></div>' : '</div>';
							html += '<div class="clear"></div>';
						}else{
							html += '<div class="rank-logo"><i class="far fa-address-card"></i></div>'; 
							html += '<div class="rank-infos"><span>'+name+'</span> <small class="text-muted">- Rang</small>'; 
							html += item.description ? '<br/><small>'+item.description+'</small></div>' : '</div>';
							html += '<div class="clear"></div>';
						}
						
						return html;
					},
					highlight : function(item){
						return item;
					},
					onClick : function(selected,element){
						userPicker.val('');
						selected.fullname = selected.name;
						selected.uid = selected.id;
						
						pickerFunctions.addTag(userContainer,selected);
						input.trigger('click').trigger('change');
					},
					onBlur : function(selected){
						if(input.attr('data-force')!='false' && input.val() == '') userPicker.val('');
					}
				});
			break;

			/**
			 * data-labels  : tableau des libellés entre double quotes eg : ["Libellé 1","Libellé 2"] 
			 * data-values	: taleau des valeurs eg : [12,13]
			 * data-colors	: taleau des couleurs entre double quotes eg : ["#cecece","#222222"]
			 */
			case 'doughnut':
				var data = input.data();
				var myChart = new Chart(input.get(0).getContext('2d'), {
					type: 'doughnut',
					data: {
						labels: data.labels,
						datasets: [{
							data: data.values,
							backgroundColor: data.colors
						}]
					},
					options: {
						cutoutPercentage:80
					}
				});
			break;
			/**
			 * data-labels  : tableau des libellés entre double quotes eg : ["Libellé1","Libellé 2"] 
			 * data-values	: taleau des valeurs eg : [12,13]
			 * data-colors	: taleau des couleurs entre double quotes eg : ["#cecece","#222222"]
			 */
			case 'bar':
				var data = input.data();
				var myChart = new Chart(input.get(0).getContext('2d'), {
					type: 'bar',
					data: {
						labels: data.labels,
						datasets: [{
							label : input.html(),
							data: data.values,
							backgroundColor: data.colors
						}]
					},
					options: {
						scales: {
							yAxes: [{
								ticks: {
									beginAtZero:true
								}
							}]
						},
						legend: {
							display: false
						}
					}
				});
			break;
			/**
			 * data-labels  : tableau des libellés entre double quotes eg : ["Libellé1","Libellé 2"] 
			 * data-values	: taleau des valeurs eg : [12,13]
			 * data-color	: couleurs  eg : #cecece
			 */
			case 'line':
				var data = input.data();
				var myChart = new Chart(input.get(0).getContext('2d'), {
					type: 'line',
					
					data: {

						labels: data.labels,
						datasets: [{
							label : input.html(),
							data: data.values,
							borderColor: [data.color]
						}]
					},
					options: {
						 scales: {
							yAxes: [{
								ticks: {
									beginAtZero:true
								}
							}]
						}
					}
				});
			break;
			/**
			 * data-input-city 		: le champ d'id "#votre-id" à remplir avec la ville
			 * data-input-latitude	: le champ d'id "#votre-id" à remplir avec la latitude
			 * data-input-longitude	: le champ d'id "#votre-id" à remplir avec la longitude
			 * data-input-country	: le champ d'id "#votre-id" à remplir avec le pays
			 * data-input-code		: le champ d'id "#votre-id" à remplir avec le code postal
			 * data-input-street	: le champ d'id "#votre-id" à remplir avec la rue
			 * data-input-number	: le champ d'id "#votre-id" à remplir avec le n°
			 */
			case 'location':
				input.location({
					select :function(location){
						var attributes = {};
						for(var key in location){
							attributes['data-'+key] = location[key];
							if(input.attr('data-input-'+key)!='') $(input.attr('data-input-'+key)).val(location[key]).text(location[key]);
						}
						input.attr(attributes);
					}
				});
			break;
			/** 
			 * data-depth 			: nb de profondeur de liste (ex: 2, affichera 2 select au maximum), 1 par défaut
			 * data-slug 			: le slug de la liste mère à afficher, listes primaires par défaut
			 * data-value 			: la valeur de l'entité  à récup en base
			 * data-disable-label 	: cache le label de sous-liste si mentionné
			 * data-hierarchy		: si mentionné à false, ne récupère pas
			 * data-parent-id		: l'id de la liste parente associée
			 */
			case 'dictionnary':
				var slug = input.attr('data-slug') ? input.attr('data-slug') : "";
				var parentId = input.attr('data-parent-id') && input.attr('data-parent-id').length ? input.attr('data-parent-id') : "";
				if (!slug.match(/^[a-z\d\-_]+$/i) && parentId == '') return;

				$.action({
					action : 'load_dictionnary_component',
					slug: slug,
					parentId : parentId,
					hierarchy : input.attr('data-hierarchy') == 'false' ? 0 : 1,
					value: input.attr('data-value')
				},function(r){
					var children = r.content.childs ? r.content.childs : r.content;
					input.attr('onchange', 'get_sub_dictionnary(this, "'+input.attr('name')+'",'+1+');');
					input.append('<option value=""> - </option>');

					$.each(children, function (index, value){
						if (value.selected) {
							input.append('<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" selected>'+value.label+'</option>');
							get_selected_values(input, value);
						}
						else
							input.append('<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'">'+value.label+'</option>');
					});
				});
			 break;
			/** 
			 * data-label 	: le label affiché dans la zone
			 * data-delete 	: méthode de suppression de doc de l'entité 
			 * data-save 	: méthode de sauvegarde de doc de l'entité (si mentionné, save automatique) 
			 * data-readonly: Empeche l'ajout/suppression de documents
			 * data-allowed : les extensions de fichier acceptées
			 */
			case 'dropzone':
				if(input.find('form').length != 0) break;
				if(!input.attr('data-action')) input.attr('data-action','action.php?action=upload_temporary_file');
				var readonly = input.attr('data-readonly') == "true" ? true : false;
				if(!input.get(0).hasAttribute('id')) input.attr('id',generate_uuid(10));
				var customTpl = input.find('> *:not(:visible)');
				var customActions = '';
				if(customTpl && customTpl.length){
					$.each(customTpl, function(i, action){
						if(i>2) return;
						var valCalc = readonly ? i*28+3 : i*28+25;
						customActions += $(action).removeClass('hidden').css('right', valCalc).get(0).outerHTML;
					});
				}
				var preview = '<li data-path="{{path}}">';
			    preview += input.get(0).hasAttribute('data-preview') ? '<img style="margin: 0 5px;float: left;max-height:100px;max-width:80px;" src="{{url}}"/>' : '<i class="fa {{icon}}"></i>';
				preview += ' <a {{#url}}href="{{url}}"{{/url}} target="_blank" title="{{name}}">{{name}}{{lastModification}}</a> '+customActions+' <i class="fas fa-times pointer '+(input.attr('data-delete')?'':'hidden')+'" onclick="{{#temporary}}dropzone_delete_file(this);{{/temporary}}{{^temporary}}'+input.attr('data-delete')+'(this){{/temporary}}"></i><div class="clear"></div></li>';

				var valueFiles = input.html()!='' && is_json_string(input.text()) ? JSON.parse(input.text()) : [];
				input.html('');
				var allowed = input.attr('data-allowed');
				if(allowed) allowed = allowed.split(',');
				var save = input.attr('data-save');
				var size = input.attr('data-max-size');

				input.upload({
					allowed : allowed,
					size : size == '' ? 0 : size,
					readonly: readonly,
					start: function(){
						preload.show();
					},
					success: function(response){
						if(response.previews.length && response.previews[0].name) {
							var inputTemp = $('#'+input.attr('id')+'_temporary');
							var currVal = inputTemp.val().length ? JSON.parse(inputTemp.val()) : [];

							for(var i in response.previews){
								files.append(Mustache.render(preview,response.previews[i]));
								currVal.push(response.previews[i]);
							}
							inputTemp.val(JSON.stringify(currVal));
							if(save) 
								window[save](response.previews);
						}
						preload.fadeOut();
					},
					complete: function(){
						preload.fadeOut();
					}
				});
				var preload = $('<div class="preload progress-bar progress-bar-striped progress-bar-animated"></div>');
				input.append(preload);
				var files = $('<ul></ul>');
				input.append(files);

				var filesValues = $('<input type="hidden" name="'+input.attr('id')+'_temporary" id="'+input.attr('id')+'_temporary">');
				input.append(filesValues);

				for(var i in valueFiles) {
					files.append(Mustache.render(preview,valueFiles[i]));
					if(readonly) files.find('li > i.fa-times').remove();
				}
				if(!valueFiles.length && readonly)
					input.append('<div>Aucun document</div>');
			break;
			/** 
			 * data-simple : Si "true" alors interface avec moins de boutons
			 */
			case 'wysiwyg':
				var buttons = [
					['strong', 'em', 'underline','del'],
					['foreColor', 'backColor'],
					['undo', 'redo'], // Only supported in Blink browsers
					['formatting'],
					['superscript', 'subscript'],
					['link'],
					['insertImage'],
					['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
					['unorderedList', 'orderedList'],
					['horizontalRule'],
					['removeformat'],
					['fullscreen'],
					['viewHTML']
				]
				if(input.attr('data-simple') == 'true'){
					buttons = [
						['strong', 'em', 'underline','del'],
						['foreColor', 'backColor'],
						['undo', 'redo'], // Only supported in Blink browsers
						['formatting'],
						['link'],
						['unorderedList', 'orderedList'],
						['insertImage']
					]
				}
				var defaultOptions = {
					btns: buttons,
					lang: 'fr',
					autogrow: true,
					semantic: false
				};
				var data = input.data();
				var options = $.extend(defaultOptions,data);
				input.trumbowyg(options);
			break;
			/**
			 * data-join : Spécifie la liaison par défaut des filtres (and | or) si rien n'est spéficié ou que l'attrbute n'existe pas,
			 * 			   un select apparait pour que l'utilisateur puisse choisir,
			 * data-slug : Si spécifié, la recherche devient enregistrable pour une réutilisation ultérieure,
			 * data-only-advanced : Si l'attribut est présent, cache la recherche simple et ouvre par defaut la recherche avancée
			 */
			case 'filter':
				if(input.next('.filter-box:visible').length!=0) break;
				input.hide();
				var data = input.data();
				var box = $('.filter-box:not(:visible)').clone();
				input.after(box);
				box.show();

				if($('option',input).length == 0)
					box.find('.advanced-button-search').hide();

				box.attr('data-join',data.join);
				if(data.join!='' && data.join!=null)
					box.find('.filter-join').addClass('hidden');

				var options = '<option value=""> - Choix filtre - </option>';
				$('option',input).each(function(i,element){
					options += element.outerHTML;
				});
				$('.filter-column').append(options);
				box.on('keyup', '.filter-value, .filter-keyword', function(event){
					if(event.keyCode == 13) filter_search();
				});
				
				if(data.onlyAdvanced!=null){
					$('.simple-search').hide();
					box.find('.advanced-search').show();
				} 

				if(data.onlyAdvanced==null && $('option',input).length != 0)
					$('.simple-search div.btn.filter-button-search:visible').html('<i class="fas fa-search"></i>');

				if(data.slug && data.slug!=''){
					box.find('.advanced-search-save').removeClass('hidden');
					box.find('.advanced-search-action-separator').removeClass('hidden');
					$.action({
						action : 'filter_load',
						slug : data.slug,
					},function(response){
						if(response.filters.advanced && response.filters.advanced.length > 0) {
							box.find('.advanced-search').show();

							for(var i=response.filters.advanced.length-1 ; i != -1 ; i--){
								var filter = response.filters.advanced[i];
								filter_add(box.find('.filterRow:visible:eq(0)'),filter);
							}
						
						}
						box.find('.filterRow:visible:eq(0)').remove();

						if(data.function && (!data.hasOwnProperty('autosearch') || data.autosearch==true )) window[data.function]();

					});
				}
			break;
			/** 
			 * data-toggle-event : Pour le moment, que "hover", de base au click
			 * data-show-strength: Si indiqué, affiche la barre de force du mot de passe renseigné dans l'input
			 */
			case 'password':
				if(input.closest('.password-field').length) return;
				input.attr('type', 'password');
				input.wrap(function() {return '<div class="password-field"></div>';});
				var container = input.parent('.password-field');
				container.append('<i class="fas fa-eye-slash noPrint password-toggler"></i>');

				container.find('i.password-toggler').attr((input.attr('data-toggle-event') == 'hover')?{
					'onmouseover': 'toggle_password(this);',
					'onmouseleave': 'toggle_password(this);'
				}:{'onclick': 'toggle_password(this);'});

				if(input.attr('data-generator') !== undefined) {
					container.append('<i class="fas fa-shield-alt noPrint password-generator"></i>')
					container.find('i.password-generator').on('click', function(){
						if(input.val()!='' && !confirm('Attention, un mot de passe est déjà défini.\nVoulez-vous quand même en générer un nouveau ?')) return;

						var strong = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[=/\()%ยง!@#$%^&*])(?=.{10,})');
						do {
							password = generate_password();
						} while(!strong.test(password))
							
						input.val(password);
						if(input.attr('data-show-strength') !== undefined)
							check_password_strength(input);
					});

					function generate_password(){
						var password = "";
						var charset = get_characters_set();
						var length = Math.ceil(parseFloat(64) * Math.log(2) / Math.log(charset.length));

						for (var i=0; i<length; ++i)
							password += charset[get_random_int(charset.length)];
						return password;
					}
				}

				if(input.attr('data-show-strength') !== undefined) {
					input.parent('.password-field').append('<div class="strength-lines"><div class="line"></div><div class="line"></div><div class="line"></div></div>');
					// check_password_strength($('input[data-type="password"][data-show-strength]'));
					
					// Strength validation on keyup-event
					input.on("keyup mouseup", function(e) {
						check_password_strength($(this));
					});

					//Check password strength
					function check_password_strength(input) {
						var value = $(input).val();
						var container = $(input).closest('.password-field');
						$(".line", container).removeClass("strength-low strength-medium strength-hard").addClass("strength-transparent");
						if(!value.length) return;

						var strongRegex = new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[=/\()%ยง!@#$%^&*])(?=.{10,})'),
							mediumRegex = new RegExp('^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})');

						if(strongRegex.test(value)) {
							$(".line", container).removeClass("strength-transparent").addClass("strength-hard");
						} else if (mediumRegex.test(value)) {
							$(".line:not(:last-of-type)", container).removeClass("strength-transparent").addClass("strength-medium");
						} else {
							$(".line:nth-child(1)", container).removeClass("strength-transparent").addClass("strength-low");
						}
					}
				}
			break;
			case 'icon':
				input.hide();
				input.next('.component-icon').remove();
				
				var data = {
					value : input.val(),
					choices :  []
				};
			
				var icons = $.fontAwesome();
				var line = [];
				for(var key in icons){
					if(line.length==15){
						data.choices.push(line);
						line = [];
					}
					line.push(icons[key].icon);
				}

				var selector = $(Mustache.render($('.component-icon.hide').get(0).outerHTML,data));
				selector.removeClass('hide');
				input.after(selector);

				selector.on('show.bs.dropdown', function () {
					setTimeout(function(){selector.find('input.form-control').focus();},0);
				})

				selector.find('.dropdown-icon-item').click(function(){
					selector.find('.dropdown-icon-item').show();
					selector.find('input.form-control').val('');
					var icon = $(this).attr('data-icon');
					input.val(icon);
					selector.find('.dropdown-toggle i').attr('class',icon);
				});
				selector.find('input.form-control').keyup(function(){
					var value = $(this).val();
					$('.dropdown-icon-item i',selector).each(function(i,iconElement){
						iconElement = $(iconElement);
						parent = iconElement.parent();
						
						iconElement.attr('class').indexOf(value)!=-1 ? parent.show() : parent.hide();
					});
					/*var icon = $(this).attr('data-icon');
					input.val(icon);
					selector.find('.dropdown-toggle i').attr('class',icon);*/
				});
			break;
			/** 
			 * data-title (*) : Le titre du modal
			 * data-warning   : Message affiché dans le tooltip au survol
			 * data-loaded (*): fonction callback appelée auprès le chargement du modal (bien pour setter des actions custom sur les boutons dans le modal par exemple) 
			 * data-params 	: Les paramètres utilisés pour l'appel du callback
			 * data-url (*) : L'URL vers le contenu du modal qui sera ajouté au modal préexistant dans le footer
			 * data-precall : fonction appelée avant le chargement du modal (méthode de check sur l'UI par exemple)
			 * Pour customiser l'icône du quickform, il suffit de placer le contenu que l'on veut dans la div de data-type="quickform"
			 */
			case 'quickform':                
				if(input.find('span').length) return;
				if(input.attr('disabled')) return;

				var qfUrl = input.attr('data-url');
				var cbLoaded = input.attr('data-loaded');
				var preCb = input.attr('data-precall') ? input.attr('data-precall') : '';
				var warningMsg = input.attr('data-warning') ? input.attr('data-warning') : '';

				if(!input.find('* > i').length){
					var icon = input.children('i').detach();
					icon = icon.length ? icon : $('<i class="fas fa-plus-square"></i>');

					var checker = '<span title="'+warningMsg+'">'+icon.get(0).outerHTML+'</span>';
					input.append(checker);
				}
				var title = input.attr('data-title');
				var params = input.attr('data-params') ? input.attr('data-params').split(',') : [];

				$(document).ready(function(e){
					if(warningMsg.length)
						$('.quickform > span').tooltip({
							track: true,
							tooltipClass: 'quickform-tooltip',
						});
					input.on('click', function(e){
						if(preCb.length && !window[preCb]()) return;
						$.ajax({
							type: 'GET',
							url: qfUrl,
							async: true,
							success : function(modal){
								$('#quickform-modal-label').text(title);
								$('.quickform-modal .modal-footer > div:first-of-type').nextAll().remove();
								if(cbLoaded) window[cbLoaded].apply(null,params);
							}
						}).done(function(modalBody){
							var modal = $('.quickform-modal');
							var qfBody = $('.modal-body', modal)
							qfBody.html('').append(modalBody);
							reset_quickform_modal();
							modal.modal('show');
							init_components($('#quickform-modal'));
						});
					});
				});
			break;
			/** 
			 * data-class : Classe custom à ajouter au conteneur du l'input
			 */
			case 'checkbox':
				//3 cas possibles :
				//	- input sans rien, data-type="checkbox" --> on fait tout
				//	- input avec coquille sans data-uuid,	--> on génère simplement un data-uuid et maj valeur
				//	- input avec coquille et data-uuid 		--> on maj simplement sa valeur
					
				if(input.get(0).hasAttribute('data-uuid')) return;
				if(input.attr('type') != 'checkbox') input.attr('type', 'checkbox');

				if(!input.closest('label.check-component').length) {
					var labelBox = $('<label class="check-component"></label>');
					var checkbox = $('<div class="box"></div>');
					var id = input.attr('id');
					var title = input.attr('title');
					var customClass = input.attr('data-class');

					if(id) labelBox.attr('for', id);
					if(title) labelBox.attr('title', title);
					if(customClass) labelBox.addClass(customClass);
					input.removeAttr('title data-class').wrap(labelBox);
					input.after(checkbox);
				}
				var uuid = generate_uuid(15);
				input.attr('data-uuid', uuid);

				if(input.get(0).hasAttribute('id')) return;
				input.closest('label.check-component').find('div.box').click(function(e){
					$('input[data-uuid="'+uuid+'"]').prop('checked', $('input[data-uuid="'+uuid+'"]').prop('checked'));
				});
			break;
			/** 
			 * data-label : Libellé affiché à côté de l'input radio
			 * name (*)	  : Le nom du groupe dont fait partie l'input radio
			 */
			case 'radio':
				if(input.get(0).hasAttribute('data-uuid')) return;
				if(input.attr('type') != 'radio') input.attr('type', 'radio');

				var uuid = generate_uuid(15);
				var id = input.get(0).hasAttribute('id')? input.attr('id') : '';
				var title = input.get(0).hasAttribute('title') ? input.attr('title') : '';
				var label = input.attr('data-label');

				var labelBox = $('<label data-uid="'+uuid+'"></label>');
				labelBox.attr({
					'for': id,
					'title': title
				});

				input.addClass('radio-component').removeAttr('title data-label').attr('data-uuid', uuid);
				input.after(labelBox);
				if(label) labelBox.after('<label for="'+id+'">'+label+'</label>');

				if(input.attr('id') && input.attr('id').length) return;
				labelBox.click(function(e){ $('input[data-uuid="'+uuid+'"]').prop('checked', true); });
			break;
			/**
			 * data-action : l'action php pour récupérer l'UI de la card
			 * data-parameters : paramètres à passer avec l'action json encodés
			 */
			case 'card':
				if(!input.is(':visible')) return;
				var action = input.attr('data-action');
				if(!action) {
					console.log('CARD COMPONENT: Need "data-action" to get card content');
					return;
				}
				var showDelay = input.attr('data-show-delay') ? input.attr('data-show-delay') : 0;
				var hideDelay = input.attr('data-hide-delay') ? input.attr('data-hide-delay') : 600;
				var parameters = input.attr('data-parameters');
				var data = parameters ? JSON.parse(parameters) : {};
				data.action = action;
				input.addClass('card-component-container');

				$(document).ready(function(){
					input.mouseenter(function(event){
						var e = event.toElement || event.relatedTarget;
				        if (e.parentNode != this && e != this) return;
						event.stopImmediatePropagation();
						event.stopPropagation();
						$('*[data-type="card"]').find('.wrapper').addClass('card-component-hide').removeClass('card-component-hover').remove();

						timeout = setTimeout(function(){
							var curInput = input;
							if(!curInput.find('.card-component').length) {
								$.action(data, function(r){
									if(!r.content) return;
									//On utilise un wrapper pour gérer les overflows "out of the box"
									var wrapper = $('<div class="wrapper"></div>');
									wrapper.css({top: curInput.offset().top+'px'});
									var card = $(r.content);
									curInput.append(card);
									card.wrap(wrapper);
									card.addClass('card-component card-component-hover');
								});
							} else {
								var card = $(curInput.find('.card-component'));
					    		card.addClass('card-component-hover').removeClass('card-component-hide');
							}
						    clearTimeout(curInput.data('tOutbox'));
				        }, showDelay);
					});

					input.add(input.find('.card-component')).mouseleave(function(e){
						e.stopImmediatePropagation();
						e.stopPropagation();
					    var input = $(this),
					    	card = input.find('.card-component'),
					        tOutbox = setTimeout(function(){
					        	if(!$('.card-component:hover').length) {
					            	card.addClass('card-component-hide').removeClass('card-component-hover');
					            	setTimeout(function(){
					            		card.remove();
					            	}, 250);
					        	}
					        }, hideDelay);
					        //Clear du timeout d'apparition
			            	clearTimeout(timeout);
					    //Set du l'id de timeout, permet de clear ce trigger si la souris revient sur l'input
					    input.data('tOutbox', tOutbox);
					});
				});
			break;
			/** 
			 * data-dictionnary : Le slug du dictionnary à utiliser
			 */
			case 'dictionnary-table':
				if(input.hasClass('component-dictionnary-table')) return;
				if(!input.attr('data-dictionnary') || !input.attr('data-dictionnary').length) return;
				var tpl = $('.component-dictionnary-table').get(0).outerHTML;
				$.action({
					action: 'load_dictionnary_component',
					slug : input.attr('data-dictionnary')
				},function(r){
					var list = $(Mustache.render(tpl,{label:'{{label}}', slug:'{{slug}}', id:'{{id}}',parent:r.content}));
					input.append(list);
					list.show();

					dictionnary_table_refresh(list);
				
					//Save
					$(input).on('click','thead .btn-success',function(){
						var line = $(this).closest('tr');
						var data = {
							action: 'dictionnary_table_save',
							label: line.find('input.list-label').val(),
							id: list.attr('data-id'),
							list: list.attr('data-dictionnary')
						};
						if(list.find('input.list-slug')) data.slug = $('input.list-slug', list).val();

						$.action(data, function(r){
							list.attr('data-id', '');
							line.find('input').val('');
							$.message('success','Enregistré');
							dictionnary_table_refresh(list);
						});
					});

					//Suppression
					$(input).on('click','tbody tr .btn-danger',function(){
						if(!confirm('Êtes-vous sûr de vouloir supprimer cet élément de liste ?')) return;
						var line = $(this).closest('tr');
						$.action({
							action: 'delete_dictionnary',
							id: line.attr('data-id')
						},function(r){
							line.remove();
							line.closest('.edit-field').val('');
							$.message('info', 'Élément de liste supprimé');
						});
					});

					//Édition
					$(input).on('click','tbody tr .btn-edit',function(){
						var line = $(this).closest('tr');
						$.action({
							action: 'edit_dictionnary',
							id: line.attr('data-id')
						},function(r){
							list.find('input.list-label').val(r.label);
							if(list.find('input.list-slug')) $('input.list-slug', list).val(r.slug);
							list.attr('data-id',r.id);
						});
					});
				});
			break;
			//Permet aux plugins d'ajouter leurs composants 
			//via la fonction init_components_nomcomposant(input);
			default:
				var type = input.attr('data-type');
				if(window['init_components_'+type] !=null) window['init_components_'+type](input);
			break;
		}
	});
}

/* PRELOADER */ 
function toggle_preloader_to(elemToHide, parent){
	if(!$('#preloader-upload-container').length) {
		$(elemToHide).hide();
		$(parent).prepend('<div id="preloader"><div id="preloader-shadow"></div><div id="preloader-box"></div></div><div id="preloader-text">Connexion en cours...</div>').fadeIn(150);
		$('body').css('overflow', 'hidden');
	} else {
		$('body').css('overflow', '');
		$('#preloader').fadeOut(300).remove();
	}
}

/** BACK TO TOP **/
$('#toTheTop').click(function() {
	scroll_top(150);
});
// Affichage du bouton dès lors où l'on a scrollé
$(window).on('ready scroll', function(){
	scrollPos = $(document).scrollTop();
	if (scrollPos >= 100) {
		$('#toTheTop').css('display','flex').animate({opacity:1}, 100);
	} else {
		$('#toTheTop').stop().animate({opacity:0}, 100);
		$('#toTheTop').removeAttr('style');
	}
});
//Permet de scroller en haut de page
function scroll_top(time){
	$('html,body').animate({scrollTop:0},time);
}

/** CONTRÔLES DATE ET HEURE **/
function is_valid_date(string){
	var format = /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/;
	return format.test(string);
}
function is_valid_hour(string){
	var format = /^(?:\d|[01]\d|2[0-3]):[0-5]\d$/;
	return format.test(string);
}

//SHOW/HIDE PASSWORD
function toggle_password(element){
	if ($(element).hasClass('fa-eye-slash')) {
		$(element).removeClass('fa-eye-slash').addClass('fa-eye');
		$(element).prev('input').attr('type', 'text');
	} else {
		$(element).removeClass('fa-eye').addClass('fa-eye-slash');
		$(element).prev('input').attr('type', 'password');
	}
}

/** QUICKFORM **/
function reset_quickform_modal(){
	$('.modal form').attr('data-id','');
	$('input, textarea', '.modal').each(function(i, v){
		if($(v).attr('type') == 'checkbox')
			$(v).prop('checked', false);
		else
			$(v).val('');
	});
}

/** FILTER **/
$(document).ready(function(){
	// RESET KEYWORD
	$("input.filter-keyword").on('keyup',function(){
		var posx = (this.offsetWidth + this.offsetLeft - 20);
		var props = $(this).val()!='' ? {'left':posx,'opacity':'1'} : {'left':posx+30,'opacity':'0'}
		$('#search-clear').css(props);
	});
	
	$("#search-clear").click(function(){
		$(".filter-keyword").val('');
		$(this).attr('style', '');
		$(".filter-keyword").focus();
		var searchCallback = $('#filters').attr('data-function');
		if(searchCallback) window[searchCallback](); 
	});
});

//TOGGLE FILTERS SEARCH
function switch_advanced_filter(element){
	$(element).closest('.filter-box').find('.advanced-search').slideToggle(100);
}

// SEARCH
function filter_search(box){
	box = !box ? $('.filter-box:eq(0)'): box;
	var component = box.prev('[data-type="filter"]');
	var data = component.data();
	window[data.function]();
	if(data.callback) window[data.callback]();
}

function filter_clean(element){
	var box = $(element).closest('.filter-box');
	$('.filterRow:visible:not(:eq(0))',box).remove();
	$('.filterRow:visible .filter-column',box).prop('selectedIndex',0).trigger('change');
}
function filter_save(element){
	var input = $(element).closest('.filter-box').prev();
	var data = input.filters();

	$.action({
		action : 'filter_save',
		slug : input.attr('data-slug'),
		filters : data
	},function(response){
		$.message('info',response.message);
	});
}
// ADD
function filter_add(element,data){
	var box = $(element).closest('.filter-box');
	var line = $(element).closest('.filterRow');
	var newline = line.clone();

	newline.find('input').val('');
	newline.find('input:eq(3)').replaceWith('<div readonly="readonly" class="form-control">Sélectionnez la colonne de tri</div>');
	newline.find('.filter-values').show();
	newline.find('.filter-value-block').remove();
	line.after(newline);

	if(box.attr('data-join') == null || box.attr('data-join') == ''){
		box.find('.filter-join:not(:eq(0))').removeClass('invisible');
	} else {
		box.find('.filter-join:not(:eq(0))').val(box.attr('data-join'));		
	}
	init_components(newline);
	if(!data) return;	

	$('.filter-column',newline).val(data.column).trigger('change');
	$('.filter-operator',newline).val(data.operator).trigger('change');

		if(!Array.isArray(data.value)) data.value = [data.value];

		//Exception pour les composant dictionnary multi niveau
		$('.filter-value[data-type="dictionnary"]',newline).attr('data-value',data.value.slice(-1)[0] );

		for(var i in data.value){
			$('.filter-value:eq('+i+')',newline)
				.val(data.value[i])
				.trigger('change');
		}
	init_components(newline);
}

// DELETE
function filter_delete(element){
	var line = $(element).closest('.filterRow');
	if($('.filterRow:visible').length>1){
		line.remove();
	}else{
		line.find('input').val('');
		line.find('select').prop('selectedIndex',0);
		line.find('.filter-value-block').remove();
		line.find('.filter-join').addClass('invisible');
		line.find('div.filter-values').show();
	}
}

//SET COMPARATOR
function filter_set_comparator(element){
	var selected = $('option:selected',element);	
	var line = $(element).closest('.filterRow');
	filter_refresh_values(line);
	if(selected.attr('data-values')){
		if(selected.attr('data-values')==0){
			$('.filter-value:eq(0)',line).remove();
		}else if(selected.attr('data-values')>1){
			for(var i=0;i<selected.attr('data-values')-1;i++){
				var cloneValue = $('.filter-value:eq(0)',line).clone();
				cloneValue.addClass('ml-1').removeClass('hasDatepicker').removeAttr('id');
				$('.filter-value-block',line).append(cloneValue);
				init_components(line);
			}
		}
	}
	init_components(line);
}

// SET
function filter_set_column(element){
	var line = $(element).closest('.filterRow');
	$('.filter-operator,.filter-value',line).remove();
	filter_refresh_operator(line);
	filter_refresh_values(line);
	init_components(line);
}

function filter_refresh_operator(line){
	var valueZone = line.find('.filter-values');
	var filterColumn = line.find('.filter-column');
	var operatorColumn = line.find('.filter-operator');
	var option = $('option:selected',filterColumn);
	var data = option.data();

	// Si aucun filtre n'est selctionné, on remove les champs suivants
	if(!option.val().length) {
		line.find('input').val('');
		line.find('select').prop('selectedIndex',0);
		line.find('.filter-value-block').remove();
		line.find('.filter-join').addClass('invisible');
		valueZone.show();
		return;
	}

	data.value = filterColumn.val();
	//supression de lancien block operateur + valeur
	line.find('.filter-value-block').remove();
	//ajout du bloc operateur / valeur
	var templateOperator = '<div class="filter-value-block">'+$('.filter-value-block[data-value-type="'+data.filterType+'"]:hidden .filter-operator').get(0).outerHTML.replace('data-template','data-type')+"</div>";
	
	filterOperator = $(templateOperator);
	valueZone.hide().after(filterOperator);
	line.find('.filter-value-block').css('display','inline-block');
}

function filter_refresh_values(line){
	var filterColumn = line.find('.filter-column');
	var currOption = $('option:selected',filterColumn);
	var data = currOption.data();

	//data.value = filterColumn.val();
	//supression de lancien block operateur + valeur
	line.find('.filter-value-block .filter-value').remove();

	//ajout du bloc operateur / valeur
	var templateValue = $('.filter-value-block[data-value-type="'+data.filterType+'"]:hidden .filter-value').get(0).outerHTML.replace('data-template','data-type');
	filterValue = $(Mustache.render(templateValue,data));

	//Si le type de champ est une liste on la remplit avec le datasource
	if(data.filterSource){
		var source = JSON.parse(currOption.attr('data-filter-source'));
		var options = '<option value=""> - </option>';
		for (var k in source) 
			options += '<option value="'+k+'">'+source[k]+'</option>';
		filterValue.append(options);
	}
	filterValue.removeClass('hasDatepicker').removeAttr('id');
	$('.filter-operator',line).after(filterValue);
}

// INIT - INDEX
function init_index(){

}

function init_setting(parameter){

	switch(parameter.section){
		case 'plugin':
		search_plugin(function(){
			$('input.toggle').change(function(){
				var input = $(this);
				var button = input.closest('.activator');
				var label = $('> label', button).detach();
				var value = input.prop('checked');
				if(!value) {
					if(!confirm("Êtes-vous sûr de vouloir désactiver ce plugin ?\nCela entraînera la suppression de toutes les données associées.")) {
						input.prop('checked',!value);
						button.prepend(label);
						return;
					}
					button.removeClass('btn-danger').addClass('btn-info').text('Activer').prepend(label);
				} else {
					button.addClass('btn-danger').removeClass('btn-info').text('Désactiver').prepend(label);
				}
				$.action({
					action : 'change_plugin_state',
					plugin : input.closest('li').attr('data-id'),
					state: value ? 1 : 0
				}, function(r){
					
				}, function(r){
					input.prop('checked',!value);
				});				
			});
		});
		break;
		case 'user':
			search_user();
		break;
		case 'firm':
			search_firm();
		break;
		case 'firmPlugin':
			search_firm_plugin('update_checkboxes');
		break;
		case 'userfirmrank':
			search_userfirmrank();
		break;
		case 'log':
			search_log();
			$('#logs').sortable_table({
			    onSort : search_log
			});
		break;
	
		case 'rank':
			search_rank();
		break;

		case 'dictionnary':
			search_dictionnary();
		break;
		case 'right':
			search_right('update_checkboxes');
		break;
		default:
			if(parameter.section!= null){
				var section = parameter.section.replace(/[^a-z_0-9]/g,'_');
				var init = 'init_setting_'+section;
				if(window[init]!=null) window[init]($.urlParam());
			}
		break;
	}
}

/** RIGHT **/
function right_switch(element){
	$(element).closest('tr').find('input').trigger('click');
}

/** FORM **/
function send_form(element){
	var form = $(element).closest('[data-form]');
	var data = $.getForm(form);

	var data = {};
		
	for(var key in form.data()){
		if(key!="action" &&  key != "id") continue;
		data[key] = form.attr('data-'+key);
	}
			
	$('input,select,textarea',form).each(function(i,element){
		 element = $(element);
		 if(element.attr('data-id')!=null && element.attr('data-id')!=""){
			if(element.attr("type")=='checkbox' || element.attr("type")=='radio'){
				data[element.attr('data-id')] = (element.is(':checked')?1:0);
			}else{
				data[element.attr('data-id')] = element.val();
			}
		 }
	});
	data.action = 'send_form';
	$.action(data,function(r){
	});
}


/** LOG **/
// SEARCH
function search_log(callback){
	$('#logs').fill({
	    action:'search_log',
	    filters : $('#filters').filters(),
	    sort : $('#logs').sortable_table('get')
	},function(){
		if(callback!=null) callback();
	});
}

/** USER FIRM RANK**/
// SEARCH
function search_userfirmrank(callback){
	$('#userfirmranks').fill({firm : $('#firm').val(),action:'search_userfirmrank'},function(){
		if(callback!=null) callback();
	});
}

// SAVE
function save_userfirmrank(){
	var data = $.getForm('#userfirmrankForm');
	data.id = $('#userfirmrankForm').attr('data-id');
	$.action(data,function(r){
		if(typeof r.success !== 'undefined'){
			var messageSuccess = 'Utilisateur ajouté pour '+(r.success.length > 1 ? 'les ' : 'l\'')+'établissement'+(r.success.length > 1 ? 's : ' : ' : ')+r.success
			$.message('success',messageSuccess,0);
		}
	
		$('#userfirmrankForm').attr('data-id','');
		$('#userfirmrankForm input').val('');
		$('#firm').val($("#firm option:first").val());
		$('#rank').val($("#rank option:first").val());
		search_userfirmrank();
	});
}

// EDIT
function edit_userfirmrank(element){
	var line = $(element).closest('tr');
	$.action({
		action:'edit_userfirmrank',
		id:line.attr('data-id')
	},function(r){
		$.setForm('#userfirmrankForm',r);
		$('#firm').change();
		init_components($('#userfirmrankForm'));
		$('#userfirmrankForm').attr('data-id',r.id);
	});
}

// DELETE
function delete_userfirmrank(element){
	if(!confirm('Êtes vous sûr de vouloir supprimer ce lien Établissement / Utilisateur / Rang ?')) return;
	var line = $(element).closest('tr');
	$.action({
		action : 'delete_userfirmrank',
		id : line.attr('data-id')
	},function(r){
		$.message('info', 'Lien Établissement / Utilisateur / Rang supprimé.')
		line.remove();
	});
}



/** FIRM **/
// SEARCH
function search_firm(callback){
	$('#firms').fill({action:'search_firm'},function(){
		if(callback!=null) callback();
	});
}


// EDIT
function edit_firm(element){
	var line = $(element).closest('tr');
	window.location = 'firm.php?id='+line.attr('data-id');

}

// DELETE
function delete_firm(element){
	if(!confirm('Êtes vous sûr de vouloir supprimer cet établissement ?')) return;
	var line = $(element).closest('tr');
	$.action({
		action : 'delete_firm',
		id : line.attr('data-id')
	},function(r){
		$.message('info','Établissement supprimé');
		line.remove();
	});
}


/** FIRM PLUGINS **/
// SEARCH
function search_right(callback){
	$('#ranks').fill({
		action: 'search_right',
		rank: $('#rank').attr('data-rank'),
		firm: $('#firm').val()
	},function(r){
		if(callback!=null) update_checkboxes(r);
	});
}

// TOGGLE RIGHT
function toggle_right(element){
	var line = $(element).closest('tr');
	$.action({
		action:'toggle_right',
		rank:$('#rank').attr('data-rank'),
		firm:$('#firm').val(),
		section:line.attr('data-section'),
		right:$(element).attr('data-right'),
		state:$(element).prop('checked')?1:0
	});	
}

// SEARCH
function search_firm_plugin(callback){
	$('#firmplugins').fill({
		action:'search_firm_plugin',
		firm:$('#firm').val()
	},function(r){
		if(callback!=null) update_checkboxes(r);
	});
}

// ENABLE/DISABLE
function toggle_firm_plugin(element){
	var line = $(element).closest('tr');	
	$.action({
		action:'toggle_firm_plugin',
		firm :$('#firm').val(),
		state : $(element).prop('checked')?1:0,
		plugin: line.attr('data-id')
	});
}

function update_checkboxes(response){
	$('input[data-result="0"]').prop('checked',false);
	$('input[data-result="1"]').prop('checked',true);
	$('input[data-result="2"]').prop('indeterminate',true);
}

// SUPPRESSION LOGO ÉTABLISSEMENT
function firm_logo_delete(element){
    if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
    var imageComposer = $(element).parent().find("input[data-type='image']");
    
    $.action({
        action: 'firm_logo_delete',
        id: $('#firm').val()
    }, function(r){
        imageComposer.wrap('<form>').closest('form').get(0).reset();
        imageComposer.unwrap();
        $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
        $(element).remove();
    });
}

/** USER **/
// SEARCH
function search_user(callback){
	$('#users').fill({action:'search_user'},function(){
		if(callback!=null) callback();
	});
}

// SAVE
function save_user(){
	var data = $.getForm('#userFormAdmin');
	data.id = $('#userFormAdmin').attr('data-id');
	$.action(data,function(r){
		$.message('success','Utilisateur enregistré');
		$('#login').removeAttr('readonly');
		$('#userFormAdmin input').val('');
		$('#userFormAdmin').attr('data-id','');
		search_user();
	});
}

// EDIT
function edit_user(element){
    var line = $(element).closest('tr');
    $.action({
        action:'edit_user',
        login:line.attr('data-user')
    },function(r){
        $.setForm('#userFormAdmin',r);
        $('#userFormAdmin').attr('data-id',r.id);
        $('#login').attr('readonly', true);
        init_components('#userFormAdmin');
    });
}


// DELETE
function delete_user(element){
	if(!confirm('Êtes vous sûr de vouloir supprimer cet utilisateur ?')) return;
	var line = $(element).closest('tr');
	$.action({
		action : 'delete_user',
		login : line.attr('data-user')
	},function(r){
		$.message('info','Utilisateur supprimé');
		$('#userFormAdmin').attr('data-id','');
		reset_inputs($('#userFormAdmin'));
		$('#login').removeAttr('readonly');
		line.remove();
	});
}


/* ACCOUNT **/

function account_lost_password (){
	
	$.action({
		action: 'account_lost_password',
		mail : $('#mail').val()
	}, function(r){
    	$.message('success','Confirmation envoyée par e-mail');
    });
}

function account_save(element){
	var data = $('#user-form').toJson();
	data.login=  $('#login').val();
	data.avatar = $('#avatar')[0].files[0];
	data.action =  'account_save';

    $.action(data, function(r){
    	$.message('success','Enregistré');
    	if(r.warning) $.message('warning',r.warning);
    });
}

// SUPPRIME AVATAR USER
function account_avatar_delete(element){
    if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
    var imageComposer = $(element).parent().find("input[data-type='image']");
    
    $.action({
        action: 'account_avatar_delete',
        login: $('#login').val()
    }, function(r){
        imageComposer.wrap('<form>').closest('form').get(0).reset();
        imageComposer.unwrap();
        $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
        $(element).remove();
    });
}

/** RANKS **/
// SEARCH
function search_rank(callback){
	$('#ranks').fill({action:'search_rank'},function(){
		if(callback!=null) callback();
	});
}

// SAVE
function save_rank(){
	var data = $.getForm('#rankForm');
	data.id = $('#rankForm').attr('data-id');
	$.action(data,function(r){
		$.message('success','Rang enregistré');
		$('#rankForm input').val('');
		$('#rankForm').attr('data-id','');
		search_rank();
	});
}

// EDIT
function edit_rank(element){
	var line = $(element).closest('tr');
	$.action({action:'edit_rank',id:line.attr('data-id')},function(r){
		$.setForm('#rankForm',r);
		$('#rankForm').attr('data-id',r.id);
	});
}

// DELETE
function delete_rank(element){
	if(!confirm('Êtes vous sûr de vouloir supprimer ce rang ?')) return;
	var line = $(element).closest('tr');
	$.action({
		action : 'delete_rank',
		id : line.attr('data-id')
	},function(r){
		$.message('info','Rang supprimé');
		line.remove();
	});
}


/** DICTIONNARY **/
// SEARCH
function search_dictionnary(callback){
	var parentValue = $('#parent').val();
	parentValue != "" ? $('#prev-button').removeClass('hide') :  $('#prev-button').addClass('hide');
	$('#dictionnaries').fill({
		action:'search_dictionnary',
		parent : parentValue
	},function(r){
		reset_inputs($('#dictionnaryForm'), false, true);
		if(callback!=null) callback();
		var tpl = $('#parent').find('option[value="{{id}}"]');
		if(!tpl.parent('span').length) tpl.wrap('<span>').hide();
	});
}

// SAVE
function save_dictionnary(){
	var data = $.getForm('#dictionnaryForm');
	data.id = $('#dictionnaryForm').attr('data-id');
	data.parent = $('#parent').val();
	$.action(data,function(r){
		$.message('success','Liste enregistrée');
		$('#dictionnaryForm input').val('');
		$('#dictionnaryForm').attr('data-id','');
		search_dictionnary();
	});
}

// EDIT
function edit_dictionnary(element){
	var line = $(element).closest('tr');
	$.action({
		action: 'edit_dictionnary',
		id: line.attr('data-id')
	},function(r){
		$.setForm('#dictionnaryForm',r);
		$('#dictionnaryForm').attr('data-id',r.id);
	});
}

// DELETE
function delete_dictionnary(element){
	if(!confirm('Êtes-vous sûr de vouloir supprimer cette liste ?')) return;
	var line = $(element).closest('tr');
	$.action({
		action: 'delete_dictionnary',
		id: line.attr('data-id')
	},function(r){
		line.remove();
		$.message('info','Liste supprimée');
	});
}

// Remplissage de la liste (select) --> Dans les settings
function get_dictionnary_items(elem, elemToFill){
	var parent = $(elem).closest('tr');
	var id = $(parent).attr('data-id');
	var	parentId = $(parent).attr('data-parent');

	$(elemToFill).fill({
		action:'search_dictionnary',
		parent : parentId.toString()
	},function(){
		$(elemToFill).val(id).change();
	});
}

// Ajout de sous-liste --> Dans les settings
function add_sub_dictionnary(elem){
	reset_inputs($('#dictionnaryForm'), false, true);

	var parent = $(elem).closest('tr');
	var id = $(parent).attr('data-id');
	var value = parent.find(".itemLabel").text();

	if ($("#parent option[value='"+id+"']").length > 0)
		$('#parent').val(id).change();
	else {
		get_dictionnary_items(elem, "#parent");
		$('code').addClass('hide');
	}
	$('#prev-button').removeClass('hide');
}

// Récupération éléments de la liste précédente --> Dans les settings
function previous_list_dictionnary(elem){
	var selected = $('#parent > option:selected').val();
	reset_inputs($('#dictionnaryForm'), false, true);

	$.action({
		action: 'get_parent_dictionnary',
		selected: selected
	}, function(r){
		var data = r.rows[0];
		$('#parent option[value!="{{id}}"]').remove();

		if (data.parentId == "") $('#prev-button').addClass('hide');
		if (data.parents[0].parent == "0") {
			$('#parent').append("<option value='' selected>-</option>");
			$('code').removeClass('hide');
		}

		$.each(data.parents, function (index, value){
			if (value.id == data.parentId)
				$('#parent').append("<option selected value='"+value.id+"'>"+value.label+"</option>");
			else
				$('#parent').append("<option value='"+value.id+"'>"+value.label+"</option>");
		});
		search_dictionnary();
	});
}

// Récupération des sous-listes pour les champ de type "dictionnary" --> Où le module est appelé
function get_sub_dictionnary(elem, name, currentDepth){
	var input = $(elem);
	var selectValue = input.val();
	var optSubLabel = $('option:selected', elem).attr('data-sublabel');
	var depth = (input.attr('data-depth') && input.attr('data-depth') != "") ? input.attr('data-depth') : "1";
	var fieldName = name == '' ? input.attr('name') : name;

	currentDepth -= currentDepth != 1 ? input.nextAll('select').length : 0;
	if(input.closest('span.dictionnary-container').length != 0){
		var id = input.nextAll().last().attr('id');
		input.attr('id', id).nextAll().remove();
	}

	if (selectValue.length && currentDepth < depth) {
		input.removeAttr('name');
		currentDepth += 1;

		$.action({
			action: 'search_dictionnary',
			parent: selectValue
		}, function(r){
			var option = '';
			if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
			var newSelect = clone_input_dictionnary(input, selectValue, fieldName);
			var currentDepth = input.closest('span.dictionnary-container').children('select').length;

			if (input.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null") input.after('<label class="label-select">'+optSubLabel+'</label>');
			newSelect.attr('onchange', 'get_sub_dictionnary(this, "'+fieldName+'", '+currentDepth+');');
			newSelect.append('<option value=""> - </option>');
			
			$.each(r.rows, function(index, value){
				option += '<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'">'+value.label+'</option>';
			});
			newSelect.append(option);
		});
	} else if (!selectValue.length) {
		input.attr('name', fieldName);
	} else if (currentDepth == depth && input.attr('data-filter-type-value') && input.attr('data-filter-type-value').length) {
		data = input.data();

		input.closest('.filter-value-block').next('.filter-value-block[data-value-type="'+data.filterTypeValue+'"]').remove();
		var template = $('.filter-value-block[data-value-type="'+data.filterTypeValue+'"]:hidden').get(0).outerHTML;
		filterValue = $(Mustache.render(template,data));

		filterValue.css('display','inline-block');
		filterValue.find('input').removeClass('hasDatepicker').removeAttr('id');
		
		input.closest('.filter-value-block').after(filterValue);
	}
}

// Récupération des sous-listes depuis l'id du plus petit enfant --> Où le module est appelé
function get_selected_values(elem, select){
	var input = $(elem);
	if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
	var fieldName = input.attr('name');
	var currentDepth = 1+input.closest('span.dictionnary-container').children('select').length;
	var optSubLabel = select.sublistlabel;
	var option = '';

	if (typeof select.childs !== 'undefined' && select.childs.length > 0) {
		var newSelect = clone_input_dictionnary(input, select.id, fieldName);

		if (newSelect.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null" && optSubLabel != undefined) input.after('<label class="label-select">'+optSubLabel+'</label>');
		newSelect.append('<option value=""> - </option>');
	}
	$.each(select.childs, function(index, value){
		var selected = '';
		
		if (value.hasOwnProperty("selected")) {
			input.removeAttr('name');
			get_selected_values(newSelect, value);
			selected = "selected";
		}
		newSelect.attr('onchange', 'get_sub_dictionnary(this,"'+fieldName+'", '+currentDepth+');');
		option += '<option value="'+value.id+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" '+selected+'>'+value.label+'</option>';
	});
	if(newSelect) newSelect.append(option);
}

// Clone du select de type "dictionnary"
function clone_input_dictionnary(input, id, name){
	var newSelect = input.clone();
	input.removeAttr('id').after(newSelect).after(' ');
	newSelect.removeAttr("data-type").removeAttr('name').removeAttr('data-value');
	// newSelect.attr('id', 'children-select-'+id).attr('name', name);
	newSelect.find('option').remove();
	return newSelect;
}

//Rafraîchit la table de la liste donnée
//En lien avec le composant dictionnary_table
function dictionnary_table_refresh(elem){
	var id = $(elem).attr('data-dictionnary');
	var table = $(elem).find('table:eq(0)');
	$.action({
		action: 'dictionnary_table_search',
		id: id
	},function(r){
		table.find('tbody tr:visible').remove();
		var tpl = table.find('tbody tr:hidden').get(0).outerHTML;
		for(var key in r.rows){
			var row = r.rows[key];
			var line = $(Mustache.render(tpl,row));
			line.removeClass('hidden');
			table.find('tbody').append(line);
		}
	});
}

/** PLUGINS **/
// SEARCH
function search_plugin(callback){
	$('#plugins').fill({action:'search_plugin'},function(){
		if(callback!=null) callback();
	});
}

// RÉCUPÉRATION PARAMÈTRE URL
var get_url_parameter = function get_url_parameter(sParam, string) {
	var sPageURL = !string ? decodeURIComponent(window.location.search.substring(1)) : string;		
	var sURLVariables = sPageURL.split('&'),
		sParameterName,
		i;

	for (i = 0; i < sURLVariables.length; i++) {
		sParameterName = sURLVariables[i].split('=');

		if (sParameterName[0] === sParam) {
			return sParameterName[1] === undefined ? true : sParameterName[1];
		}
	}
};

// DROPZONE
function dropzone_delete_file(element){
	if(!confirm('Êtes-vous sûr de vouloir supprimer cet item ?')) return;
	var elem = $(element);
	var line = elem.closest('li');

	var container = elem.closest('div[data-type="dropzone"]');
	var inputTemp = container.find('#'+container.attr('id')+'_temporary');

	var values = inputTemp.val().length ? JSON.parse(inputTemp.val()) : [];

	for (var i in values) {
		if(values[i]['path'] == line.attr('data-path'))
			values.splice(i, 1);
	}
	line.remove();
	inputTemp.val(JSON.stringify(values));
}

/* GENERAL SETTINGS */
//Sauvegarde de la configuration générale
function general_settings_save(){
	var data = $('#general-settings').getForm();
	data.logo = $('#logo')[0].files[0];
	data.logo_dark = $('#logo_dark')[0].files[0];
	data.favicon = $('#favicon')[0].files[0];
	data.password_format = $('#password-format-form').attr('data-format');
	$.action(data, function(r){
		$.message('success', 'Configuration enregistrée');
	});
}

function general_reset_password_delay(){
	if(!confirm('Êtes-vous sûr de vouloir forcer tous les utilisateurs à réinitialiser leurs mot de passe ?')) return;
	$.action({
	    action: 'general_reset_password_delay'
	}, function(r){
	    $.message('info', 'Action confirmée');
	});
}

function password_settings_format(){
	var patterns = [];
	$('#password-format-form input[data-pattern]:checked').each(function(){
		patterns.push($(this).attr('data-pattern'));
	});

	$('#password-format-form').attr('data-format',JSON.stringify(patterns));
}

//Suppression image générale application
function general_logo_delete(element){
	if(!confirm('Êtes-vous sûr de vouloir supprimer l\'image ?')) return;
	var imageComposer = $(element).parent().find("input[data-type='image']");
	
	$.action({
	    action: 'general_logo_delete'
	}, function(r){
	    imageComposer.wrap('<form>').closest('form').get(0).reset();
	    imageComposer.unwrap();
	    $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
	    $(element).remove();
	    $.message('info', 'Image supprimée');
	});
}
//Suppression favicon générale application
function general_favicon_delete(element){
	if(!confirm('Êtes-vous sûr de vouloir supprimer l\'image ?')) return;
	var imageComposer = $(element).parent().find("input[data-type='image']");
	
	$.action({
	    action: 'general_favicon_delete'
	}, function(r){
	    imageComposer.wrap('<form>').closest('form').get(0).reset();
	    imageComposer.unwrap();
	    $(element).next('img').attr('src', $(imageComposer).attr('data-default-src'));
	    $(element).remove();
	    $.message('info', 'Favicon supprimée');
	});
}
//Active/Désactive la page de maintenance du site
function toggle_maintenance(){
	var checkbox = $('#maintenance');
	var state = checkbox.is(':checked') ? 'd\'activer' : 'de désactiver';
	if(!confirm("Vous êtes sur le point "+state+" la page de maintenance du site.\nVoulez-vous continuer ?")){
		checkbox.is(':checked') ? checkbox.removeAttr('checked').prop('checked', false) : checkbox.attr('checked', true).prop('checked', true);
		return;
	}
	general_settings_save();
}


/* FUNCTIONS */
//Récupère la plus petite valeur d'un tableau
function getMinValue(arr) {
	return arr.reduce(function (p, v) {
		return ( p < v ? p : v );
	});
};
//Récupère la plus grande valeur d'un tableau
function getMaxValue(arr) {
	return arr.reduce(function (p, v) {
		return ( p > v ? p : v );
	});
};

//Check si la valeur saisie dans l'input 
//est une adresse e-mail bien formatée
function is_email(email) {
    var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(String(email).toLowerCase());
}
//Check si la valeur saisie dans 
//l'input est une url bien formatée
function is_url(str) {
	regexp =  /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
    if (regexp.test(str))
    	return true;
    return false;
}
//Check format n° de téléphone
function is_phone_number(number, required, label){
	if (required && number == ''){
		$.message('error',label+' obligatoire');
		return false;
	}

	if (number != ''){
		number = number.replace(/\s/g, '');
		number = number.replace(/\./g, '');
		number = number.replace(/-/g, '');
		if(is_numeric(number)) {
			if(/^(?:(?:\+|00)\d{2}|0)\s*[1-9](?:[\s.-]*\d{2}){4}$/.test(number) == false){
				$.message('error',' Le format du n° de '+label.toLowerCase()+' est invalide');
				return false;
			}
		} else {
			$.message('error',' Le n° de '+label.toLowerCase()+' contient des caractères interdits');
			return false;
		}
	}
	return true;
}
//Check si la valeur de
//l'input est numérique
function is_numeric(n) {
	return !isNaN(parseFloat(n)) && isFinite(n);
}

function str_price_to_decimal(str){
	return str.replace(/,/g,'.').replace(/ /g,'');
}

//Comme la fonction ucfirst de PHP
function ucfirst(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

//Permet de revenir/rester sur l'onglet courant
//au reload de page, ou au clic sur un lien particulier
if (location.hash) {
  $('a[href="' + location.hash + '"]').tab('show');
}
var activeTab = localStorage.getItem('activeTab');
if (activeTab) {
  $('a[href="' + activeTab + '"]').tab('show');
}
$('body').on('click', 'a[data-toggle="tab"]', function(e){
	e.preventDefault();
	var tab_name = this.getAttribute('href');
	history.pushState ? history.pushState(null, null, tab_name) : location.hash = tab_name;
	localStorage.setItem('activeTab', tab_name);

	$(this).tab('show');
	return false;
});


$(window).on('popstate', function () {
	var anchor = location.hash || $('a[data-toggle="tab"]').first().attr('href');
	$('a[data-toggle="tab"][href="' + anchor + '"]').tab('show');
});

//Check si la chaîne de caractères
//fournies est une chaîne JSON
function is_json_string(str) {
	try {
		JSON.parse(str);
	} catch (e) {
		return false;
	}
	return true;
}

//Sélectionne le texte de l'élément passé en paramètre
function select_text(element, event){
	event.stopImmediatePropagation();
    var sel, range;
    var el = $(element).get(0); //get element id 
    if (window.getSelection && document.createRange) { //Browser compatibility
      sel = window.getSelection();
      if(sel.toString() == ''){ //no text selection
         window.setTimeout(function(){
            range = document.createRange(); //range object
            range.selectNodeContents(el); //sets Range
            sel.removeAllRanges(); //remove all ranges from selection
            sel.addRange(range);//add Range to a Selection.
        },1);
      }
    }else if (document.selection) { //older ie
        sel = document.selection.createRange();
        if(sel.text == ''){ //no text selection
            range = document.body.createTextRange();//Creates TextRange object
            range.moveToElementText(el);//sets Range
            range.select(); //make selection.
        }
    }
}

//Permet de copier le contenu de l'element dans le presse-papier
function copy_to_clipboard(element) {
	var element = $(element);
	var temp = $('<input>');

	$('body').append(temp);

	temp.val(element.text()).select();
	setTimeout(function(){document.execCommand('copy');},0);
	temp.remove();

	element.tooltip({
		items: 'code',
	    tooltipClass: 'quickform-tooltip',
	    content: 'Copié dans le presse papier',
	    open: {effect:'fade',duration:750},
	    close: {effect:'fade',duration:750}
	});
	element.tooltip('open');
	setTimeout(function(){element.tooltip('close');element.tooltip('destroy');}, 2000);
}

//Reset des inputs d'un conteneur
function reset_inputs(container, onlyVisible, domData){
	var container = container ? container : $('body');
	var visibility = onlyVisible ? onlyVisible : false;
	var dom = domData ? domData : false;
	if(dom) container.removeAttr('data-id');

	var classicInputs = visibility==true ? $('input:visible, textarea:visible', container) : $('input, textarea', container);
	classicInputs.each(function(i, v){
		if($(v).attr('type') == 'checkbox')
			$(v).prop('checked', false);
		else
			$(v).val('');
	});

	var customInputs = visibility==true ? $('*[contenteditable="true"]:visible', container) : $('*[contenteditable="true"]', container);
	customInputs.each(function(j,val){
		$(val).text('');
	});
}

//Check si le contenu d'un input est 
//selectionné (en surbrillance avec le curseur)
function is_text_selected(input) {
    if (typeof input.selectionStart == "number") {
        return input.selectionStart == 0 && input.selectionEnd == input.value.length;
    } else if (typeof document.selection != "undefined") {
        input.focus();
        return document.selection.createRange().text == input.value;
    }
}

//Renvoie un tableau en ayant supprimé
//toutes les valuers dupliquées
function only_uniq_values(a) {
    var seen = {};
    var out = [];
    var len = a.length;
    var j = 0;
    for(var i = 0; i < len; i++) {
         var item = a[i];
         if(seen[item] !== 1) {
               seen[item] = 1;
               out[j++] = item;
         }
    }
    return out;
}

//Contrôle éléments saisis dans input de type number.
//Autorise ou non les décimales et les nb négatifs
function input_number_control(e, decimal, relative){
	var authorizedKeys = [8,9,37,39,46,54,109,110,188,190];
	switch (e.keyCode) {
		case 110:
		case 188:
		case 190:
			return decimal?decimal:false;
		break;
		case 54:
		case 109:
			return relative?relative:false;
		break;
		default:
			return (
				(e.keyCode >= 48 && e.keyCode <= 57) || 
				(e.keyCode >= 96 && e.keyCode <= 105) ||
				((e.keyCode == 65 || e.keyCode == 86 || e.keyCode == 67) && (e.ctrlKey === true || e.metaKey === true)) ||
				(authorizedKeys.indexOf(e.keyCode) !== -1)
			);
		break;
	}
}

//Check si l'objet est vide ou non
//Retourne true si vide, false sinon
function is_empty_obj(obj) {
    for(var key in obj) {
        if(obj.hasOwnProperty(key))
            return false;
    }
    return true;
}

//Permet de retourner une propriété d'un
//objet de manière totalement aléatoire
function random_property(obj) {
    var keys = Object.keys(obj)
    return obj[keys[ keys.length * Math.random() << 0]];
}

function get_characters_set() {
	var CHARACTER_SETS = [
		["0123456789"],
		["abcdefghijklmnopqrstuvwxyz"],
		["ABCDEFGHIJKLMNOPQRSTUVWXYZ"],
		["!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"],
	];

	// Concatène les jeux de caractères
	var rawCharset = "";
	CHARACTER_SETS.forEach(function(entry, i) {
		rawCharset += entry[0];
	});
	
	// Parse en UTF-16, supprime les doublons, convertit en tableau de string
	var charset = [];
	for (var i = 0; i < rawCharset.length; ++i) {
		var c = rawCharset.charCodeAt(i);
		if (c<0xD800 || c>=0xE000) {//Check si character UTF-16 valide
			var s = rawCharset.charAt(i);
			if (charset.indexOf(s) == -1) charset.push(s);
			continue;
		}
		if (0xD800<=c && c<0xDC00 && i+1<rawCharset.length) {
			var d = rawCharset.charCodeAt(i + 1);
			if (0xDC00<=d && d<0xE000) {
				var s = rawCharset.substring(i, i+2);
				i++;
				if (charset.indexOf(s) == -1) charset.push(s);
				continue;
			}
		}
		throw "Invalid UTF-16";
	}
	return charset;
}

//Retourne un entier aléatoire dans la plage [0, n)
//(2 méthodes utilisées)
function get_random_int(maxRange) {
	//Récup d'un entier aléatoire via le module Math
	//(fallback si pas de module crypto)
	var x = random_int_math(maxRange);

	//Récupération d'un entier aléatoire via le moule crypto
	x = (x + random_int_crypto(maxRange)) % maxRange;
	return x;
}

//Retourne un entier aléatoire
//Peu sécurisé (car calculable) mais 
//présent sur tous les navigateurs
function random_int_math(maxRange) {
	var x = Math.floor(Math.random() * maxRange);
	if (x < 0 || x >= maxRange) throw "Arithmetic exception";
	return x;
}

//Retourne un entier aléatoire
//Extrêmement sécurisé, mais pas 
//disponible sur tous les navigateurs
//+ d'infos ici: https://developer.mozilla.org/fr/docs/Web/API/RandomSource/getRandomValues
function random_int_crypto(maxRange) {
	var cryptoObject = null
	if ("crypto" in window) {
		//Check si le module crypto est disponible (Chrome, Firefox, Safari)
		cryptoObject = crypto;
	} else if ("msCrypto" in window) {
		//Check si le module crypto est disponible (Edge, IE)
		cryptoObject = msCrypto;
	}
	
	//Check + récupération propriétés/fonctions nécessaires du module crypto
	if ("getRandomValues" in cryptoObject && "Uint32Array" in window && typeof Uint32Array == "function") {
		//Generate an unbiased sample
		var x = new Uint32Array(1);

		//Modification des élements du 
		//tableau par des nb aléatoires
		do cryptoObject.getRandomValues(x);
		while (x[0] - x[0] % maxRange > 4294967296 - maxRange);
		
		return x[0] % maxRange;
	} else {
		return 0;
	}
}

//Permet de générer un UUID de 
//longueur souhaitée (ou 10 si pas de paramètre)
function generate_uuid(length){
	var length = length !== undefined ? length : 10;
	var mem = "0x1"+("0".repeat(length));
	return Math.floor((1 + Math.random()) * mem).toString(16).substring(1);
}