浏览代码

[search] Prepare for multi select of range facets

Romain Rigaux 11 年之前
父节点
当前提交
8609451957

+ 4 - 2
apps/search/src/search/api.py

@@ -210,7 +210,9 @@ class SolrApi(object):
              ('f.%s.facet.range.gap' % facet['field'], facet['properties']['gap']),]
           )          
         elif facet['type'] == 'field':
-          params += (('facet.field', '{!ex=%s}%s' % (facet['field'], facet['field'])),)
+          params += (
+              ('facet.field', '{!ex=%s}%s' % (facet['field'], facet['field'])),
+              ('f.%s.facet.limit' % facet['field'], facet['properties']['limit']))
 
     for fq in query['fqs']:
       #model_facet = [facet for facet in collection['facets'] if facet['id'] == fq['id']][0]
@@ -221,7 +223,7 @@ class SolrApi(object):
 #        if fq['filter'].get('to'):
 #          model_facet = [facet for facet in collection['facets'] if facet['id'] == fq['id']][0]           
 #          fq['filter']['to'] = model_facet['properties']['end'] if model_facet else '*'
-        params += (('fq', urllib.unquote(utf_quoter('{!tag=%s}%s:[%s TO %s}' % (fq['field'],fq['field'], fq['filter']['from'], fq['filter']['to'])))),)
+        params += (('fq', urllib.unquote(utf_quoter('{!tag=%s}%s:[%s TO %s}' % (fq['field'], fq['field'], fq['properties']['from'], fq['properties']['to'])))),)
 
     if collection['template']['fieldsSelected'] and collection['template']['isGridLayout']:
       fields = collection['template']['fieldsSelected'] + [collection['idField']] if collection['idField'] else []

+ 3 - 7
apps/search/src/search/models.py

@@ -470,7 +470,7 @@ def augment_solr_response2(response, collection, query):
       pairs.append({'cat': cat, 'value': element, 'count': next(a), 'selected': element in selected_values})
     return pairs
 
-  def range_pair(cat, selected_values, iterable, end, facet):
+  def range_pair(cat, selected_values, iterable, end):
     # e.g. counts":["0",17430,"1000",1949,"2000",671,"3000",404,"4000",243,"5000",165],"gap":1000,"start":0,"end":6000}
     pairs = []
     a, to = itertools.tee(iterable)
@@ -478,11 +478,7 @@ def augment_solr_response2(response, collection, query):
     for element in a:
       next(to, None)
       to_value = next(to, end)
-      if facet['widgetType'] == 'pie-widget':        
-        label = '%s - %s ' % (element, to_value)
-      else:
-        label = element
-      pairs.append({'field': cat, 'from': label, 'value': next(a), 'to': to_value, 'selected': element == selected_values})
+      pairs.append({'field': cat, 'from': element, 'value': next(a), 'to': to_value, 'selected': element == selected_values})
     return pairs
 
   selected_values = dict([((fq['id'], fq['field'], fq['type']), fq['filter']) for fq in query['fqs']])
@@ -512,7 +508,7 @@ def augment_solr_response2(response, collection, query):
         collection_facet = get_facet_field(category, name, collection['facets'])
         counts = response['facet_counts']['facet_ranges'][name]['counts']
         end = response['facet_counts']['facet_ranges'][name]['end']
-        counts = range_pair(name, selected_values.get((facet['id'], name, 'range'), {}).get('from', None), counts, end, facet)
+        counts = range_pair(name, selected_values.get((facet['id'], name, 'range'), [''])[0], counts, end) # Single val selected
         if collection_facet['properties']['sort'] == 'asc':
           counts.reverse()
         facet = {

+ 28 - 23
apps/search/src/search/templates/search2.mako

@@ -221,6 +221,27 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <!-- /ko -->
 </script>
 
+<script type="text/html" id="facet-toggle">
+      ${ _('Label') }: <input type="text" data-bind="value: label" />
+      <!-- ko if: type() == 'range' -->
+        <br/>
+        ${ _('Start') }: <input type="text" data-bind="value: properties.start" />
+        ${ _('End') }: <input type="text" data-bind="value: properties.end" />
+        ${ _('Gap') }: <input type="text" data-bind="value: properties.gap" />
+      <!-- /ko -->
+      <!-- ko if: type() == 'field' -->
+        ${ _('Limit') }: <input type="text" data-bind="value: properties.limit" />      
+      <!-- /ko -->
+    <span data-bind="text: label" style="font-weight: bold"></span>
+
+    <a href="javascript: void(0)" class="btn btn-loading" data-bind="visible: properties.canRange, click: $root.collection.toggleRangeFacet" data-loading-text="...">
+      <i class="fa" data-bind="css: { 'fa-arrows-h': type() == 'range', 'fa-circle': type() == 'field' }"></i>
+    </a>
+    <a href="javascript: void(0)" class="btn btn-loading" data-bind="click: $root.collection.toggleSortFacet" data-loading-text="...">          
+      <i class="fa" data-bind="css: { 'fa-caret-down': properties.sort() == 'desc', 'fa-caret-up': properties.sort() == 'asc' }"></i>
+    </a>
+</script>
+
 <script type="text/html" id="facet-widget">
   <!-- ko ifnot: $root.getFacetFromQuery(id()) -->
     <a data-bind="click: showAddFacetDemiModal" class="btn" href="javascript:void(0)"><i class="fa fa-plus"></i></a>
@@ -234,22 +255,7 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <!-- ko if: $root.getFacetFromQuery(id()) -->
   <div class="row-fluid" data-bind="with: $root.getFacetFromQuery(id())">
     <div data-bind="visible: $root.isEditing, with: $root.collection.getFacetById($parent.id())" style="margin-bottom: 20px">      
-      ${ _('Label') }: <input type="text" data-bind="value: label" />
-      <!-- ko if: type() == 'range' -->
-        <br/>
-        ${ _('Start') }: <input type="text" data-bind="value: properties.start" />
-        ${ _('End') }: <input type="text" data-bind="value: properties.end" />
-        ${ _('Gap') }: <input type="text" data-bind="value: properties.gap" />
-      <!-- /ko -->
-      <span>
-        <span data-bind="text: label" style="font-weight: bold"></span>
-        
-        <a href="javascript: void(0)" class="btn btn-loading" data-bind="visible: properties.canRange, click: $root.collection.toggleRangeFacet" data-loading-text="...">
-          <i class="fa" data-bind="css: { 'fa-arrows-h': type() == 'range', 'fa-bars': type() == 'field' }"></i>
-        </a>
-        <a href="javascript: void(0)" class="btn btn-loading" data-bind="click: $root.collection.toggleSortFacet" data-loading-text="...">          
-          <i class="fa" data-bind="css: { 'fa-caret-down': properties.sort() == 'desc', 'fa-caret-up': properties.sort() == 'asc' }"></i>
-        </a>
+      <span data-bind="template: { name: 'facet-toggle' }">
       </span>
     </div>
     <div data-bind="with: $root.collection.getFacetById($parent.id())">
@@ -448,7 +454,8 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
     </div> 
 
     <div data-bind="barChart: {datum: {counts: counts, widget_id: $parent.id(), label: label}, stacked: false, field: field, label: label,
-      transformer: barChartDataTransformer, onStateChange: function(state){ console.log(state); },
+      transformer: barChartDataTransformer,
+      onStateChange: function(state){ console.log(state); },
       onClick: function(d){ viewModel.query.selectRangeFacet({count: d.obj.value, widget_id: d.obj.widget_id, from: d.obj.from, to: d.obj.to, cat: d.obj.field}) }, 
       onComplete: function(){ viewModel.getWidgetById(id).isLoading(false) } }"
     />
@@ -494,12 +501,10 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <!-- ko if: $root.getFacetFromQuery(id()) -->
   <div class="row-fluid" data-bind="with: $root.getFacetFromQuery(id())">
     <div data-bind="visible: $root.isEditing, with: $root.collection.getFacetById($parent.id())" style="margin-bottom: 20px">
-      ${ _('Label') }: <input type="text" data-bind="value: label" />
-      <br/>      
-      ${ _('Start') }: <input type="text" data-bind="value: properties.start" />
-      ${ _('End') }: <input type="text" data-bind="value: properties.end" />
-      ${ _('Gap') }: <input type="text" data-bind="value: properties.gap" />      
+      <span data-bind="template: { name: 'facet-toggle' }">
+      </span>
     </div>
+
     <div data-bind="with: $root.collection.getFacetById($parent.id())">
       <!-- ko if: type() == 'range' -->
       <div data-bind="pieChart: {data: {counts: $parent.counts, widget_id: $parent.id}, field: field, fqs: $root.query.fqs,
@@ -854,7 +859,7 @@ function rangePieChartDataTransformer(data) {
   $(data.counts).each(function (cnt, item) {
     item.widget_id = data.widget_id;
     _data.push({
-      label: item.from,
+      label: item.from + ' - ' + item.to,
       value: item.value,
       to: item.to,
       obj: item

+ 2 - 1
apps/search/src/search/views.py

@@ -535,7 +535,8 @@ def new_facet(request):
       'canRange': False,
       'stacked': False,
       'limit': 10,
-      'mincount': 0
+      'mincount': 0, # Not used yet
+      'andUp': False,
     }
     
     solr_api = SolrApi(SOLR_URL.get(), request.user)

+ 64 - 55
apps/search/static/js/search.ko.js

@@ -263,7 +263,7 @@ var Query = function (vm, query) {
             fq.filter.remove(data.facet.value);
             if (fq.filter().length == 0) {
               self.fqs.remove(fq);
-             }
+            }
           } else {
             fq.filter.push(data.facet.value);
           }
@@ -278,13 +278,22 @@ var Query = function (vm, query) {
     var fq = self.getFacetFilter(data.widget_id);
     var unselect = fq != null && fq.id() == data.widget_id && data.force == undefined;
   
-    self.removeFilter(ko.mapping.fromJS({'id': data.widget_id})); // TODO: could combine ranges
+    // if range already in --> unselect
+    // if not: add
+    //var filter = self.getFacetFilter(data.widget_id);
+    //if (filter != null && filter.filter().indexOf(data.from) > -1) {
+    	//
+    //}
+    
+    // if empty now or force
+    self.removeFilter(ko.mapping.fromJS({'id': data.widget_id}));
   
     if (! unselect) {
       self.fqs.push(ko.mapping.fromJS({
         'id': data.widget_id,
         'field': data.cat,
-        'filter': {'from': data.from, 'to': data.to},
+        'filter': [data.from],
+        'properties': {'from': data.from, 'to': data.to},
         'type': 'range'
       }));
     }
@@ -434,15 +443,15 @@ var Collection = function (vm, collection) {
   }
 
   self.toggleSortColumnGridLayout = function (template_field) {
-   if (! template_field.sort.direction()) {
-     template_field.sort.direction('desc');
-   } else if (template_field.sort.direction() == 'desc') {
-     template_field.sort.direction('asc');
-   } else {
-     template_field.sort.direction(null); 
-   }
-
-   vm.search();
+    if (! template_field.sort.direction()) {
+      template_field.sort.direction('desc');
+    } else if (template_field.sort.direction() == 'desc') {
+      template_field.sort.direction('asc');
+    } else {
+      template_field.sort.direction(null); 
+    }
+
+    vm.search();
   };
   
   self.toggleSortFacet = function (facet_field, event) {
@@ -470,69 +479,69 @@ var Collection = function (vm, collection) {
   };  
 
   self.selectTimelineFacet = function (data) { // alert(ko.mapping.toJSON(facet)); 
-  var facet = self.getFacetById(data.widget_id);
+    var facet = self.getFacetById(data.widget_id);
   
-  facet.properties.start(data.from);
-  facet.properties.end(data.to);
+    facet.properties.start(data.from);
+    facet.properties.end(data.to);
   
-  vm.query.selectRangeFacet({widget_id: data.widget_id, from: data.from, to: data.to, cat: data.cat, no_refresh: true, force: true});
+    vm.query.selectRangeFacet({widget_id: data.widget_id, from: data.from, to: data.to, cat: data.cat, no_refresh: true, force: true});
   
-  $.ajax({
-    type: "POST",
-    url: "/search/get_range_facet",    
-    data: {
-      collection: ko.mapping.toJSON(self),
-      facet: ko.mapping.toJSON(facet),
-      action: 'select'
-    },
-    success: function (data) {
-      if (data.status == 0) {
-        facet.properties.gap(data.properties.gap);
-      }
-    },
-    async: false
-  });  
+    $.ajax({
+      type: "POST",
+      url: "/search/get_range_facet",    
+      data: {
+        collection: ko.mapping.toJSON(self),
+        facet: ko.mapping.toJSON(facet),
+        action: 'select'
+      },
+      success: function (data) {
+        if (data.status == 0) {
+          facet.properties.gap(data.properties.gap);
+        }
+      },
+      async: false
+    });  
   
     vm.search();
   }
 
   self.timeLineZoom = function (facet_json) { 
-  var facet = self.getFacetById(facet_json.id);
-  
-  facet.properties.start(facet.from);
-  facet.properties.end(facet.to);
+    var facet = self.getFacetById(facet_json.id);
+
+    facet.properties.start(facet.from);
+    facet.properties.end(facet.to);
   
-  $.ajax({
-    type: "POST",
-    url: "/search/get_range_facet",    
-    data: {
-      collection: ko.mapping.toJSON(self),
-      facet: ko.mapping.toJSON(facet),
-      action: "zoom_out"
-    },
-    success: function (data) {
-      if (data.status == 0) {
-        facet.properties.start(data.properties.start);
-        facet.properties.end(data.properties.end);
-        facet.properties.gap(data.properties.gap);
-      }
-    },
-    async: false
-  });  
+    $.ajax({
+      type: "POST",
+      url: "/search/get_range_facet",    
+      data: {
+        collection: ko.mapping.toJSON(self),
+        facet: ko.mapping.toJSON(facet),
+        action: "zoom_out"
+      },
+      success: function (data) {
+        if (data.status == 0) {
+          facet.properties.start(data.properties.start);
+          facet.properties.end(data.properties.end);
+          facet.properties.gap(data.properties.gap);
+        }
+      },
+      async: false
+    });  
   
     vm.search();
   }
   
   self.translateSelectedField = function (index, direction) {
-  var array = self.template.fieldsSelected();
+    var array = self.template.fieldsSelected();
 
     if (direction == 'left') {
-    self.template.fieldsSelected.splice(index - 1, 2, array[index], array[index - 1]);
+      self.template.fieldsSelected.splice(index - 1, 2, array[index], array[index - 1]);
     } else {
       self.template.fieldsSelected.splice(index, 2, array[index + 1], array[index]);
     }
   
-  vm.search();
+    vm.search();
   };
 };