web/data/cubicweb.facets.js
branchstable
changeset 5994 97c55baefa0c
parent 5937 82cac9383dd8
child 6551 50ec97e4f9cc
equal deleted inserted replaced
5976:00b1b6b906cf 5994:97c55baefa0c
     1 /*
     1 /** filter form, aka facets, javascript functions
       
     2  *
     2  *  :organization: Logilab
     3  *  :organization: Logilab
     3  *  :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     4  *  :copyright: 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     4  *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     5  *  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
     5  */
     6  */
     6 
     7 
     7 CubicWeb.require('htmlhelpers.js');
     8 var SELECTED_IMG = baseuri() + "data/black-check.png";
     8 CubicWeb.require('ajax.js');
     9 var UNSELECTED_IMG = baseuri() + "data/no-check-no-border.png";
     9 
    10 var UNSELECTED_BORDER_IMG = baseuri() + "data/black-uncheck.png";
    10 //============= filter form functions ========================================//
    11 
       
    12 
    11 function copyParam(origparams, newparams, param) {
    13 function copyParam(origparams, newparams, param) {
    12     var index = findValue(origparams[0], param);
    14     var index = jQuery.inArray(param, origparams[0]);
    13     if (index > -1) {
    15     if (index > - 1) {
    14 	newparams[param] = origparams[1][index];
    16         newparams[param] = origparams[1][index];
    15     }
    17     }
    16 }
    18 }
    17 
    19 
    18 function facetFormContent(form) {
    20 
       
    21 function facetFormContent($form) {
    19     var names = [];
    22     var names = [];
    20     var values = [];
    23     var values = [];
    21     jQuery(form).find('.facet').each(function () {
    24     $form.find('.facet').each(function() {
    22         var facetName = jQuery(this).find('.facetTitle').attr('cubicweb:facetName');
    25         var facetName = jQuery(this).find('.facetTitle').attr('cubicweb:facetName');
    23         var facetValues = jQuery(this).find('.facetValueSelected').each(function(x) {
    26         var facetValues = jQuery(this).find('.facetValueSelected').each(function(x) {
    24   	    names.push(facetName);
    27             names.push(facetName);
    25   	    values.push(this.getAttribute('cubicweb:value'));
    28             values.push(this.getAttribute('cubicweb:value'));
    26         });
    29         });
    27     });
    30     });
    28     jQuery(form).find('input').each(function () {
    31     $form.find('input').each(function() {
    29         names.push(this.name);
    32         names.push(this.name);
    30         values.push(this.value);
    33         values.push(this.value);
    31     });
    34     });
    32     jQuery(form).find('select option[selected]').each(function () {
    35     $form.find('select option[selected]').each(function() {
    33 	names.push(this.parentNode.name);
    36         names.push(this.parentNode.name);
    34 	values.push(this.value);
    37         values.push(this.value);
    35     });
    38     });
    36     return [names, values];
    39     return [names, values];
    37 }
    40 }
       
    41 
    38 
    42 
    39 function buildRQL(divid, vid, paginate, vidargs) {
    43 function buildRQL(divid, vid, paginate, vidargs) {
    40     jQuery(CubicWeb).trigger('facets-content-loading', [divid, vid, paginate, vidargs]);
    44     jQuery(CubicWeb).trigger('facets-content-loading', [divid, vid, paginate, vidargs]);
    41     var form = getNode(divid+'Form');
    45     var $form = $('#' + divid + 'Form');
    42     var zipped = facetFormContent(form);
    46     var zipped = facetFormContent($form);
    43     zipped[0].push('facetargs');
    47     zipped[0].push('facetargs');
    44     zipped[1].push(vidargs);
    48     zipped[1].push(vidargs);
    45     var d = asyncRemoteExec('filter_build_rql', zipped[0], zipped[1]);
    49     var d = loadRemote('json', ajaxFuncArgs('filter_build_rql', null, zipped[0], zipped[1]));
    46     d.addCallback(function(result) {
    50     d.addCallback(function(result) {
    47 	var rql = result[0];
    51         var rql = result[0];
    48 	var $bkLink = jQuery('#facetBkLink');
    52         var $bkLink = jQuery('#facetBkLink');
    49 	if ($bkLink.length) {
    53         if ($bkLink.length) {
    50 	    var bkPath = 'view?rql=' + escape(rql);
    54             var bkPath = 'view?rql=' + escape(rql);
    51 	    if (vid) {
    55             if (vid) {
    52 		bkPath += '&vid=' + escape(vid);
    56                 bkPath += '&vid=' + escape(vid);
    53 	    }
    57             }
    54 	    var bkUrl = $bkLink.attr('cubicweb:target') + '&path=' + escape(bkPath);
    58             var bkUrl = $bkLink.attr('cubicweb:target') + '&path=' + escape(bkPath);
    55 	    $bkLink.attr('href', bkUrl);
    59             $bkLink.attr('href', bkUrl);
    56 	}
    60         }
    57 	var toupdate = result[1];
    61         var toupdate = result[1];
    58 	var extraparams = vidargs;
    62         var extraparams = vidargs;
    59 	if (paginate) { extraparams['paginate'] = '1'; } // XXX in vidargs
    63         if (paginate) { extraparams['paginate'] = '1'; } // XXX in vidargs
    60 	// copy some parameters
    64         // copy some parameters
    61 	// XXX cleanup vid/divid mess
    65         // XXX cleanup vid/divid mess
    62 	// if vid argument is specified , the one specified in form params will
    66         // if vid argument is specified , the one specified in form params will
    63 	// be overriden by replacePageChunk
    67         // be overriden by replacePageChunk
    64 	copyParam(zipped, extraparams, 'vid');
    68         copyParam(zipped, extraparams, 'vid');
    65 	extraparams['divid'] = divid;
    69         extraparams['divid'] = divid;
    66 	copyParam(zipped, extraparams, 'divid');
    70         copyParam(zipped, extraparams, 'divid');
    67 	copyParam(zipped, extraparams, 'subvid');
    71         copyParam(zipped, extraparams, 'subvid');
    68 	copyParam(zipped, extraparams, 'fromformfilter');
    72         copyParam(zipped, extraparams, 'fromformfilter');
    69 	// paginate used to know if the filter box is acting, in which case we
    73         // paginate used to know if the filter box is acting, in which case we
    70 	// want to reload action box to match current selection (we don't want
    74         // want to reload action box to match current selection (we don't want
    71 	// this from a table filter)
    75         // this from a table filter)
    72 	replacePageChunk(divid, rql, vid, extraparams, true, function() {
    76         extraparams['rql'] = rql;
    73 	  jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
    77         if (vid) { // XXX see copyParam above. Need cleanup
    74 	});
    78             extraparams['vid'] = vid;
    75 	if (paginate) {
    79         }
    76 	    // FIXME the edit box might not be displayed in which case we don't
    80         d = $('#' + divid).loadxhtml('json', ajaxFuncArgs('view', extraparams),
    77 	    // know where to put the potential new one, just skip this case
    81                                      null, 'swap');
    78 	    // for now
    82         d.addCallback(function() {
    79 	    if (jQuery('#edit_box').length) {
    83             // XXX rql/vid in extraparams
    80 		reloadComponent('edit_box', rql, 'boxes', 'edit_box');
    84             jQuery(CubicWeb).trigger('facets-content-loaded', [divid, rql, vid, extraparams]);
    81 	    }
    85         });
    82 	    if (jQuery('#breadcrumbs').length) {
    86         if (paginate) {
    83 		reloadComponent('breadcrumbs', rql, 'components', 'breadcrumbs');
    87             // FIXME the edit box might not be displayed in which case we don't
    84 	    }
    88             // know where to put the potential new one, just skip this case for
    85 	}
    89             // now
    86 	var d = asyncRemoteExec('filter_select_content', toupdate, rql);
    90             var $node = jQuery('#edit_box');
    87 	d.addCallback(function(updateMap) {
    91             if ($node.length) {
    88 	    for (facetId in updateMap) {
    92                 $node.loadxhtml('json', ajaxFuncArgs('render', {
    89 		var values = updateMap[facetId];
    93                     'rql': rql
    90 		jqNode(facetId).find('.facetCheckBox').each(function () {
    94                 },
    91 		    var value = this.getAttribute('cubicweb:value');
    95                 'boxes', 'edit_box'));
    92 		    if (!values.contains(value)) {
    96             }
    93 			if (!jQuery(this).hasClass('facetValueDisabled')) {
    97             $node = jQuery('#breadcrumbs')
    94 			    jQuery(this).addClass('facetValueDisabled');
    98             if ($node.length) {
    95 			}
    99                 $node.loadxhtml('json', ajaxFuncArgs('render', {
    96 		    } else {
   100                     'rql': rql
    97 			if (jQuery(this).hasClass('facetValueDisabled')) {
   101                 },
    98 			    jQuery(this).removeClass('facetValueDisabled');
   102                 'components', 'breadcrumbs'));
    99 			}
   103             }
   100 		    }
   104         }
   101 		});
   105         var d = loadRemote('json', ajaxFuncArgs('filter_select_content', null, toupdate, rql));
   102 	    }
   106         d.addCallback(function(updateMap) {
   103 	});
   107             for (facetId in updateMap) {
   104     });
   108                 var values = updateMap[facetId];
   105 }
   109                 cw.jqNode(facetId).find('.facetCheckBox').each(function() {
   106 
   110                     var value = this.getAttribute('cubicweb:value');
   107 
   111                     if (jQuery.inArray(value, values) == -1) {
   108 var SELECTED_IMG = baseuri()+"data/black-check.png";
   112                         if (!jQuery(this).hasClass('facetValueDisabled')) {
   109 var UNSELECTED_IMG = baseuri()+"data/no-check-no-border.png";
   113                             jQuery(this).addClass('facetValueDisabled');
   110 var UNSELECTED_BORDER_IMG = baseuri()+"data/black-uncheck.png";
   114                         }
       
   115                     } else {
       
   116                         if (jQuery(this).hasClass('facetValueDisabled')) {
       
   117                             jQuery(this).removeClass('facetValueDisabled');
       
   118                         }
       
   119                     }
       
   120                 });
       
   121             }
       
   122         });
       
   123     });
       
   124 }
       
   125 
   111 
   126 
   112 function initFacetBoxEvents(root) {
   127 function initFacetBoxEvents(root) {
   113     // facetargs : (divid, vid, paginate, extraargs)
   128     // facetargs : (divid, vid, paginate, extraargs)
   114     root = root || document;
   129     root = root || document;
   115     jQuery(root).find('form').each(function () {
   130     jQuery(root).find('form').each(function() {
   116 	var form = jQuery(this);
   131         var form = jQuery(this);
   117 	// NOTE: don't evaluate facetargs here but in callbacks since its value
   132         // NOTE: don't evaluate facetargs here but in callbacks since its value
   118 	//       may changes and we must send its value when the callback is
   133         //       may changes and we must send its value when the callback is
   119 	//       called, not when the page is initialized
   134         //       called, not when the page is initialized
   120 	var facetargs = form.attr('cubicweb:facetargs');
   135         var facetargs = form.attr('cubicweb:facetargs');
   121 	if (facetargs !== undefined) {
   136         if (facetargs !== undefined) {
   122 	    form.submit(function() {
   137             form.submit(function() {
   123 	        buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
   138                 buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
   124 	        return false;
   139                 return false;
   125 	    });
   140             });
   126 	    form.find('div.facet').each(function() {
   141             form.find('div.facet').each(function() {
   127 		var facet = jQuery(this);
   142                 var facet = jQuery(this);
   128 		facet.find('div.facetCheckBox').each(function (i) {
   143                 facet.find('div.facetCheckBox').each(function(i) {
   129 		    this.setAttribute('cubicweb:idx', i);
   144                     this.setAttribute('cubicweb:idx', i);
   130 		});
   145                 });
   131 		facet.find('div.facetCheckBox').click(function () {
   146                 facet.find('div.facetCheckBox').click(function() {
   132 		    var $this = jQuery(this);
   147                     var $this = jQuery(this);
   133 		    // NOTE : add test on the facet operator (i.e. OR, AND)
   148                     // NOTE : add test on the facet operator (i.e. OR, AND)
   134 		    // if ($this.hasClass('facetValueDisabled')){
   149                     // if ($this.hasClass('facetValueDisabled')){
   135 		    //  	    return
   150                     //          return
   136 		    // }
   151                     // }
   137 		    if ($this.hasClass('facetValueSelected')) {
   152                     if ($this.hasClass('facetValueSelected')) {
   138 			$this.removeClass('facetValueSelected');
   153                         $this.removeClass('facetValueSelected');
   139 			$this.find('img').each(function (i){
   154                         $this.find('img').each(function(i) {
   140 			if (this.getAttribute('cubicweb:unselimg')){
   155                             if (this.getAttribute('cubicweb:unselimg')) {
   141 			       this.setAttribute('src', UNSELECTED_BORDER_IMG);
   156                                 this.setAttribute('src', UNSELECTED_BORDER_IMG);
   142 			       this.setAttribute('alt', (_('not selected')));
   157                                 this.setAttribute('alt', (_('not selected')));
   143 			    }
   158                             }
   144 			    else{
   159                             else {
   145 			       this.setAttribute('src', UNSELECTED_IMG);
   160                                 this.setAttribute('src', UNSELECTED_IMG);
   146 			       this.setAttribute('alt', (_('not selected')));
   161                                 this.setAttribute('alt', (_('not selected')));
   147 			    }
   162                             }
   148 			});
   163                         });
   149 			var index = parseInt($this.attr('cubicweb:idx'));
   164                         var index = parseInt($this.attr('cubicweb:idx'));
   150 			// we dont need to move the element when cubicweb:idx == 0
   165                         // we dont need to move the element when cubicweb:idx == 0
   151 			if (index > 0){
   166                         if (index > 0) {
   152 			    var shift = jQuery.grep(facet.find('.facetValueSelected'), function (n) {
   167                             var shift = jQuery.grep(facet.find('.facetValueSelected'), function(n) {
   153 				    var nindex = parseInt(n.getAttribute('cubicweb:idx'));
   168                                 var nindex = parseInt(n.getAttribute('cubicweb:idx'));
   154 				    return nindex > index;
   169                                 return nindex > index;
   155 				}).length;
   170                             }).length;
   156 			    index += shift;
   171                             index += shift;
   157 			    var parent = this.parentNode;
   172                             var parent = this.parentNode;
   158 			    var $insertAfter = jQuery(parent).find('.facetCheckBox:nth('+index+')');
   173                             var $insertAfter = jQuery(parent).find('.facetCheckBox:nth(' + index + ')');
   159 			    if ( ! ($insertAfter.length == 1 && shift == 0) ) {
   174                             if (! ($insertAfter.length == 1 && shift == 0)) {
   160 				// only rearrange element if necessary
   175                                 // only rearrange element if necessary
   161 				$insertAfter.after(this);
   176                                 $insertAfter.after(this);
   162 			    }
   177                             }
   163 			}
   178                         }
   164 		    } else {
   179                     } else {
   165 			var lastSelected = facet.find('.facetValueSelected:last');
   180                         var lastSelected = facet.find('.facetValueSelected:last');
   166 			if (lastSelected.length) {
   181                         if (lastSelected.length) {
   167 			    lastSelected.after(this);
   182                             lastSelected.after(this);
   168 			} else {
   183                         } else {
   169 			    var parent = this.parentNode;
   184                             var parent = this.parentNode;
   170 			    jQuery(parent).prepend(this);
   185                             jQuery(parent).prepend(this);
   171 			}
   186                         }
   172 			jQuery(this).addClass('facetValueSelected');
   187                         jQuery(this).addClass('facetValueSelected');
   173 			var $img = jQuery(this).find('img');
   188                         var $img = jQuery(this).find('img');
   174 			$img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
   189                         $img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
   175 		    }
   190                     }
   176 		    buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
   191                     buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
   177 		    facet.find('.facetBody').animate({scrollTop: 0}, '');
   192                     facet.find('.facetBody').animate({
   178 		});
   193                         scrollTop: 0
   179 		facet.find('select.facetOperator').change(function() {
   194                     },
   180 		    var nbselected = facet.find('div.facetValueSelected').length;
   195                     '');
   181 		    if (nbselected >= 2) {
   196                 });
   182 			buildRQL.apply(null, evalJSON(form.attr('cubicweb:facetargs')));
   197                 facet.find('select.facetOperator').change(function() {
   183 		    }
   198                     var nbselected = facet.find('div.facetValueSelected').length;
   184 		});
   199                     if (nbselected >= 2) {
   185 		facet.find('div.facetTitle').click(function() {
   200                         buildRQL.apply(null, cw.evalJSON(form.attr('cubicweb:facetargs')));
   186 		  facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
   201                     }
   187 		  jQuery(this).toggleClass('opened');
   202                 });
   188 		   });
   203                 facet.find('div.facetTitle').click(function() {
   189 
   204                     facet.find('div.facetBody').toggleClass('hidden').toggleClass('opened');
   190 	    });
   205                     jQuery(this).toggleClass('opened');
   191 	}
   206                 });
   192     });
   207 
   193 }
   208             });
       
   209         }
       
   210     });
       
   211 }
       
   212 
   194 
   213 
   195 // trigger this function on document ready event if you provide some kind of
   214 // trigger this function on document ready event if you provide some kind of
   196 // persistent search (eg crih)
   215 // persistent search (eg crih)
   197 function reorderFacetsItems(root){
   216 function reorderFacetsItems(root) {
   198     root = root || document;
   217     root = root || document;
   199     jQuery(root).find('form').each(function () {
   218     jQuery(root).find('form').each(function() {
   200 	var form = jQuery(this);
   219         var form = jQuery(this);
   201 	if (form.attr('cubicweb:facetargs')) {
   220         if (form.attr('cubicweb:facetargs')) {
   202 	    form.find('div.facet').each(function() {
   221             form.find('div.facet').each(function() {
   203 		var facet = jQuery(this);
   222                 var facet = jQuery(this);
   204 		var lastSelected = null;
   223                 var lastSelected = null;
   205 		facet.find('div.facetCheckBox').each(function (i) {
   224                 facet.find('div.facetCheckBox').each(function(i) {
   206 		    var $this = jQuery(this);
   225                     var $this = jQuery(this);
   207 		    if ($this.hasClass('facetValueSelected')) {
   226                     if ($this.hasClass('facetValueSelected')) {
   208 			if (lastSelected) {
   227                         if (lastSelected) {
   209 			    lastSelected.after(this);
   228                             lastSelected.after(this);
   210 			} else {
   229                         } else {
   211 			    var parent = this.parentNode;
   230                             var parent = this.parentNode;
   212 			    jQuery(parent).prepend(this);
   231                             jQuery(parent).prepend(this);
   213 			}
   232                         }
   214 			lastSelected = $this;
   233                         lastSelected = $this;
   215 		    }
   234                     }
   216 		});
   235                 });
   217 	    });
   236             });
   218 	}
   237         }
   219     });
   238     });
   220 }
   239 }
   221 
   240 
   222 // we need to differenciate cases where initFacetBoxEvents is called
   241 
   223 // with one argument or without any argument. If we use `initFacetBoxEvents`
   242 // we need to differenciate cases where initFacetBoxEvents is called with one
   224 // as the direct callback on the jQuery.ready event, jQuery will pass some argument
   243 // argument or without any argument. If we use `initFacetBoxEvents` as the
   225 // of his, so we use this small anonymous function instead.
   244 // direct callback on the jQuery.ready event, jQuery will pass some argument of
   226 jQuery(document).ready(function() {initFacetBoxEvents();});
   245 // his, so we use this small anonymous function instead.
   227 
   246 jQuery(document).ready(function() {
   228 CubicWeb.provide('facets.js');
   247     initFacetBoxEvents();
       
   248 });