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