/*
@author valentin.carruesco
* data-hide-filters: Si renseigné, masque la recherche,
* data-default: permet de renseigner des filtres par défaut à la recherche (au format attendu -> voir fonction php filer_set()),
* data-label: Libellé affiché dans la partie gauche de la recherche simple,
* 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
* data-autosearch (default: true) : si définit a false, ne lancera pas la fonction data-function automatiquement en fin de chargement du composant
nb : La touche shift enfoncée lors de l'indentation d'un filtre forcera la création d'un nouveau groupe au lieu de chercher une fusion de groupe.
nb 2: ce composant fonctionne avec les templates de type de filtres situés dans la page footer, exemple de type de filtre
data-value-type="" : permet de définir le data-type si la donnée est un composant
data-value-selector : selecteur permetant de choisir le(s) iputs représeant la valeur réele du filtre (le selecteur est scopé sur la ligne du filtre)
data-values="0" : sur l'operateur, cela permet de multiplier ou anihiler le champs de valeurs (0: supression, 1(default) un champs de valeur , n : n champs d valeur )
*/
var FilterBox = function(input,options){
var input = $(input);
var object = input.data('component-object');
this.input = input;
//Premiere création du composant
if(object == null){
object = this;
object.shift = false;
//permet le forcing de création d'un nouveau groupe lors de l'appuis sur maj
$(document).keydown(function(e) {
if((e.which | e.keyCode) != 16) return;
object.shift = true;
}).keyup(function(e) {
if((e.which | e.keyCode) != 16) return;
object.shift = false;
});
object.data = options;
object.slug = input.attr('data-slug');
if(object.slug != null) {
$('.btn-search-save',object.box).removeClass('hidden');
$('.dropdown-divider',object.box).removeClass('hidden');
$('.btn-search-reset',object.box).removeClass('hidden');
}
input.addClass('hidden');
object.box = $('.advanced-search-box.hidden').clone().removeClass('hidden');
input.after(object.box);
object.columns = [];
object.tpl = $('.criterias .condition.hidden',object.box).get(0).outerHTML;
input.data('component-object',object);
object.columns.push({label : ' - Choix filtre - ',value:''});
$('option',input).each(function(i,element){
object.columns.push({
label : $(element).text(),
type : $(element).attr('data-filter-type'),
value : $(element).val()
});
});
if(object.columns.length<=1){
$('.options', object.box).addClass('hidden');
$('.simple-search .input-group-append').removeClass('hidden');
}
object.box.on('change','.filter-column',function(){
var condition = $(this).closest('.condition');
object.filter_refresh(condition,true);
}).on('change','.filter-operator',function(){
var condition = $(this).closest('.condition');
object.filter_refresh(condition);
}).on('click','.filter-option .btn-add',function(){
var button = $(this);
var condition = button.closest('.condition');
object.filter_add(condition);
}).on('keyup click','.filter-keyword',function(){
// RESET KEYWORD
var posx = (this.offsetWidth + this.offsetLeft - 20);
var props = $(this).val()!='' ? {'left':posx,'opacity':'1'} : {'left':posx+30,'opacity':'0'}
$('#search-clear').css(props)
}).on('mouseover','li.condition',function(event){
event.stopPropagation();
event.preventDefault();
$(this).addClass('hover');
}).on('mouseout','li.condition',function(event){
event.stopPropagation();
event.preventDefault();
$(this).removeClass('hover');
//Indentation d'un groupe
}).on('click',' li.condition .btn-indent',function(){
var line = $(this).closest('li');
//si un groupe existe AVANT la condition, on déplace celle ci en FIN de ce groupe
if(!object.shift && line.prev('.condition').find('>ul.group').length!=0){
group = line.prev('.condition').find('>ul.group')
group.append(line.detach());
//si un groupe existe APRES la condition, on déplace celle ci en DEBUT de ce groupe
}else if(!object.shift && line.next('.condition').find('>ul.group').length!=0){
group = line.next('.condition').find('>ul.group');
group.prepend(line.detach());
//si aucun groupe a proximité, on créé un nouveau groupe
}else{
//tweak js car jquery ne capte pas bien les selected sur les clones
line.find(':selected').attr('selected','selected');
var newline = line.clone();
var newGroup = $('
');
newline.prepend(newGroup);
newline.find('.filter-column,.filter-operator,.filter-value').remove();
line.after(newline);
newGroup.append(line.detach());
group = newGroup;
}
$(group).sortable({
axis : 'y',
handle: ".btn-move",
});
}).on('click',' li.condition .btn-unindent',function(){
var line = $(this).closest('li.condition');
var parent = line.closest('ul.group');
if(parent.hasClass('criterias')) return;
//en fonction de la position de l'item dans son group on définit si on le déplace apres ou avant le groupe d'ou on le sort.
var middleGroup = Math.trunc($("li.condition",parent).length / 2);
var index = $("li.condition",parent).index(line) +1 ;
var parentLine = parent.parent();
var current = line.detach();
if(index <= middleGroup){
parentLine.before(current);
}else{
parentLine.after(current);
}
//Supression auto du groupe si plus aucun condition à l'interieur
if(parent.find('.condition').length==0) parent.parent().remove();
}).on('click',' li .btn-delete',function(){
var line = $(this).closest('li.condition');
object.filter_remove(line);
}).on('click','.btn-search',function(){
object.search();
}).on('keypress','.filter-keyword, .filter-value input',function(e){
if((e.wich | e.keyCode) != 13) return;
object.search();
}).on('click','.btn-search-save',function(){
object.filter_save();
}).on('click','.btn-search-reset',function(){
if(!confirm('Êtes-vous sûr de supprimer tous vos filtres définitivement ?')) return;
$.urlParam('filters','');
$('.condition:visible',object.box).each(function(i,element){
object.filter_remove($(element));
});
object.filter_save();
$('.condition',object.box).removeClass('error');
}).on('click','.btn-search-clean',function(){
$.urlParam('filters','');
$('.condition:visible',object.box).each(function(i,element){
object.filter_remove($(element));
});
$('.condition',object.box).removeClass('error');
});
//ajout de la premiere condition
object.filter_add();
$('.advanced-button-search',object.box).click(function(){
object.box.toggleClass('advanced');
});
//Preset des filtres depuis l'url si défini
var filters = $.urlParam('filters');
if(filters && filters!=''){
filters = JSON.parse(atob(filters));
} else if (input.attr('data-default') && input.attr('data-default').length){
//Preset des filtres depuis l'attribut data-default
filters = JSON.parse(input.attr('data-default'));
//Récupération du type de filtre pour la colonne ciblée
$.each(filters.a, function(i, filter){
if(filter.c==null || !filter.c.length || (filter.t!=null && filter.t.length)) return;
var option = $('option[value="'+filter.c+'"]', object.input);
if(!option.length){
delete filters.a[i];
return;
}
filters.a[i]['t'] = option.attr('data-filter-type');
filters.a[i]['o'] = filter.o.toLowerCase();
});
}
if(filters && filters!='') {
filters.keyword = filters.k;
filters.advanced = filters.a;
delete filters.a;
delete filters.k;
filters.advanced = object.filter_rename_keys(filters.advanced,{j:'join',o:'operator',v:'value',t:'type',c:'column',g:'group'});
if(filters.keyword && filters.keyword!='') $('.filter-keyword',object.box).val(filters.keyword);
if(filters.advanced.length>0){
$(object.box).addClass('advanced');
object.filters(filters.advanced);
object.box.find('.condition:visible:eq(0)').remove();
}
object.load_callback();
}else{
if(object.slug!=null && object.slug!=''){
$.action({
action : 'filter_load',
slug : object.slug,
},function(response){
if(!response.filters.advanced || response.filters.advanced.length == 0){
object.load_callback();
return;
}
var filters = response.filters.advanced;
object.box.addClass('advanced');
object.filter_recursive_set(null,filters);
object.box.find('.condition:visible:eq(0)').remove();
object.search();
});
}else{
object.load_callback();
}
}
$('#search-clear',object.box).click(function(){
$(".filter-keyword",object.box).val('').focus();
$(this).attr('style', '');
object.load_callback();
});
}else{
//Rafraichissement et/ou récuperation du composant
//on reload les données de l'input aux cas ou elles aient changées
object.data = input.data();
}
if(object.data && object.data.onlyAdvanced!=null){
$('.simple-search,.advanced-button-search',object.box).addClass('hidden');
object.box.addClass('advanced');
}
if(object.data && object.data.label != null && object.data.label.length) $('.simple-search .data-search-label',object.box).html(object.data.label);
if(object.data && object.data.hideFilters != null) setTimeout(function(){object.box.addClass('hidden');}, 0);
}
FilterBox.prototype.load_callback = function(){
if(this.data && this.data.function && (!this.data.hasOwnProperty('autosearch') || this.data.autosearch==true))
window[this.data.function]();
};
//Enregistrement des filtres
FilterBox.prototype.filter_save = function(){
var object = this;
var data = object.filters();
$.action({
action : 'filter_save',
slug : object.slug,
filters : data
},function(response){
if(response.message != null)
$.message('info',response.message);
});
};
//Rafraichissement des données et de la structure d'un filtre
FilterBox.prototype.filter_refresh = function(condition,refreshOperator,data){
var object = this;
var column = $('.filter-column select',condition);
var optionColumn = $('option:selected',column);
if(data && data.column)
column.val(data.column);
var type = optionColumn.attr('data-filter-type');
var dataAttributes = object.input.find('option[value="'+column.val()+'"]').data();
var operator = $('>.filter-operator',condition);
var operatorSelect = $('select',operator);
if(column.val()==""){
$('.filter-operator,.filter-value',condition).html('');
return;
}
if(!type) return;
if(operator.length==0 || refreshOperator){
var operatorSelect = $($('.filter-value-block[data-value-type="'+type+'"] > .filter-operator').get(0).outerHTML);
//On normalise en lowercase les opérateurs
$('option', operatorSelect).val(function(){
return this.value.toLowerCase();
});
condition.find('> .filter-operator').html(operatorSelect);
}
if(data && data.operator) operatorSelect.val(data.operator);
if(data && data.join) $('>.filter-join',condition).val(data.join);
condition.find('.filter-value').html('');
var value = $('.filter-value-block[data-value-type="'+type+'"] .filter-value').get(0).outerHTML;
value = value.replace('data-template','data-type');
var repeat = $('option:selected',operator).attr('data-values');
repeat = repeat==null || repeat == '' ? 1 : repeat;
for(i=0;i'+source[k]+'';
valueInput.append(options);
}
if(data && data.value!=null){
valueInput
.val(data.value[i])
.attr('data-value',data.value[i])
.trigger('change');
}
}
init_components(condition);
}
//lance la recherche (via le bouton)
FilterBox.prototype.search = function(){
var object = this;
var filters = object.filters();
if(filters.advanced.length>0 || filters.keyword!=''){
filters.k = filters.keyword;
filters.a = filters.advanced;
delete filters.advanced;
delete filters.keyword;
filters.a = object.filter_rename_keys(filters.a,{join:'j',operator:'o',value:'v',type:'t',column:'c',group:'g'});
filters = JSON.stringify(filters);
if(!this.data.hasOwnProperty('urlsearch') || this.data.urlsearch==true)
$.urlParam('filters',btoa(filters));
}else{
$.urlParam('filters','');
}
window[object.data.function]();
if(object.data.callback) window[object.data.callback]();
}
//Renommage des clés des filtres (permet de compresser la chaine base64 encodée en url)
FilterBox.prototype.filter_rename_keys = function(filters,mapping){
object = this;
var newFilters = [];
for(var k in filters){
newFilters[k] = {};
var keys = Object.keys(filters[k]);
for(var i in keys){
var key = keys[i];
if(mapping[key] === null) continue;
newFilters[k][mapping[key]] = filters[k][key];
}
if(newFilters[k].g) newFilters[k].g = object.filter_rename_keys(newFilters[k].g,mapping);
if(newFilters[k].group) newFilters[k].group = object.filter_rename_keys(newFilters[k].group,mapping);
}
return newFilters;
}
//définition ou récuperation d'un tableau de filtres
FilterBox.prototype.filters = function(values,showErrors){
var object = this;
if(values){
object.filter_recursive_set($('.criterias',object.box),values);
return;
}
filters = object.filter_recursive_get($('.criterias',object.box));
return {
keyword : $('.filter-keyword',object.box).val(),
advanced : filters
};
}
//Définition des filtres dpeuis un objet values de manière récursive
FilterBox.prototype.filter_recursive_set = function(parent,values){
var object = this;
var filters = [];
for(var key in values){
condition = object.filter_add(null,values[key],parent);
if(values[key].group){
var newGroup = $('
');
condition.find('.filter-column').after(newGroup);
condition.find('.filter-column').remove();
condition.find('.filter-operator').remove();
condition.find('.filter-value').remove();
if(values[key].join && values[key].join!='') condition.find('>.filter-join').val(values[key].join);
condition.prepend(newGroup);
object.filter_recursive_set(newGroup,values[key].group);
}
}
return filters;
}
//Récuperation des diltres définis sur l'ui dans un object et d emanière récursive
FilterBox.prototype.filter_recursive_get = function(parent){
var object = this;
var filters = [];
$(parent).find('> .condition:visible').each(function(i,element){
var filter = {};
var element = $(element);
if(element.find('> .group').length>0){
filter.join = element.find('> .filter-join:visible').val();
filter.group = object.filter_recursive_get(element.find('> .group'));
}else{
filter.type = element.find('> .filter-column select option:selected').attr('data-filter-type');
var typeData = $('.filter-value-block[data-value-type="'+filter.type+'"]').data();
filter.column = element.find('> .filter-column select').val();
if(filter.column == null || filter.column == ''){
object.filter_remove(element);
return;
} else {
filter.operator = element.find('> .filter-operator select').val();
filter.value = [];
if(typeData.valueSelector){
var valueElements = element.find('> .filter-value '+typeData.valueSelector);
}else{
var valueElements = element.find('> .filter-value > .filter-value');
}
valueElements.each(function(u,input){
filter.value.push($(input).val());
});
filter.join = element.find('> .filter-join:visible').val();
}
}
if(!filter.group || filter.group.length) filters.push(filter);
});
return filters;
}
//Ajout d'un filtre visuel (vide ou replis avec l'obj data) dans un parent (optionnel) ou après un element (optionnel)
//si pas de parent ou d'élements définis, le filtre s'ajoute au premier niveau.
FilterBox.prototype.filter_add = function(element,data,parent){
var object = this;
if(!data) data = {};
data.columns = object.columns;
var condition = $(Mustache.render(object.tpl,data));
condition.removeClass('hidden');
if(element){
element.after(condition);
}else if(parent){
parent.append(condition);
}else{
$('.criterias',object.box).append(condition);
}
if(data) object.filter_refresh(condition,true,data);
$(condition.parent()).sortable({
axis : 'y',
handle: ".btn-move",
});
return condition;
}
//Supression d'un filtre et de ses parents vides.
FilterBox.prototype.filter_remove = function(line){
var object = this;
var group = line.closest('ul.group');
//Si le filter est le dernier de la recherche, on reset ses champs sans le supprimer
if($('.criterias .condition:visible:has(>.filter-column)',object.box).length==1){
line.find('.filter-column select').prop('selectedIndex',0);
line.find('.filter-operator,.filter-value').html('');
line.find('.btn-unindent').trigger('click');
return;
}
//sinon on le supprime complétement
if($('.criterias > .condition:visible',object.box).length>1 || line.siblings('.condition:visible').length>0) line.remove();
//suppression ascendante récursive des groupes vides après suppression de la ligne
while(1){
if(!group || group.length == 0 || group.find('.condition').length!=0) break;
oldgroup = group.parent().parent();
group.parent().remove();
group = oldgroup;
}
}