[#62,faceting][s]: introduce Facet and FacetList models and use them.

* Conceptual breakthrough on how Faceting and Filtering interact (have updated issue #62 as a result).
This commit is contained in:
Rufus Pollock
2012-03-31 18:06:41 +01:00
parent 905659d86f
commit 3412962a35
4 changed files with 63 additions and 51 deletions

View File

@@ -95,9 +95,10 @@ function localDataset() {
backend.addDataset(inData); backend.addDataset(inData);
var dataset = new recline.Model.Dataset({id: datasetId}, backend); var dataset = new recline.Model.Dataset({id: datasetId}, backend);
// TODO: auto-compute in Memory backend ?? // TODO: auto-compute in Memory backend ??
dataset.facets = { dataset.facets = new recline.Model.FacetList([
'country': { {
terms: [ id: 'country',
result: [
{ {
term: 'UK', term: 'UK',
count: 3 count: 3
@@ -112,7 +113,7 @@ function localDataset() {
} }
] ]
} }
}; ]);
return dataset; return dataset;
} }

View File

@@ -23,7 +23,7 @@ my.Dataset = Backbone.Model.extend({
} }
this.fields = new my.FieldList(); this.fields = new my.FieldList();
this.currentDocuments = new my.DocumentList(); this.currentDocuments = new my.DocumentList();
this.facets = {}; this.facets = new my.FacetList();
this.docCount = null; this.docCount = null;
this.queryState = new my.Query(); this.queryState = new my.Query();
this.queryState.bind('change', this.query); this.queryState.bind('change', this.query);
@@ -119,24 +119,36 @@ my.Query = Backbone.Model.extend({
, from: 0 , from: 0
, facets: {} , facets: {}
}, },
initialize: function() { // Set (update or add) a terms filter
_.bindAll(this, 'addFacet'); // http://www.elasticsearch.org/guide/reference/query-dsl/terms-filter.html
}, setFilter: function(fieldId, values) {
}
});
my.Facet = Backbone.Model.extend({
defaults: {
query: null,
result: null
}
});
my.FacetList = Backbone.Collection.extend({
model: my.Facet,
addFacet: function(fieldId) { addFacet: function(fieldId) {
// TODO: utilize field info to determine facet type ?? // Assume id and fieldId should be the same (TODO: this need not be true if we want to add two different type of facets on same field)
var facets = this.get('facets'); if (fieldId in this) {
if (fieldId in facets) {
return; return;
} }
facets[fieldId] = { // TODO: utilize field info to determine facet type ??
var facet = new my.Facet({
id: fieldId,
query: {
terms: { terms: {
field: fieldId field: fieldId
} }
} }
this.set({facets: facets}); });
// trigger change event (does not seem to be triggered o/w) this.add(facet);
// this.change();
} }
}); });

View File

@@ -168,11 +168,9 @@ my.DataExplorer = Backbone.View.extend({
model: this.model.queryState model: this.model.queryState
}); });
this.el.find('.header').append(queryEditor.el); this.el.find('.header').append(queryEditor.el);
var queryFacetEditor = new my.QueryFacetEditor({ var queryFacetEditor = new my.FacetQueryEditor({
model: this.model.queryState model: this.model
}, });
this.model
);
this.el.find('.header').append(queryFacetEditor.el); this.el.find('.header').append(queryFacetEditor.el);
}, },
@@ -281,58 +279,52 @@ my.QueryEditor = Backbone.View.extend({
} }
}); });
my.QueryFacetEditor = Backbone.View.extend({ my.FacetQueryEditor = Backbone.View.extend({
className: 'recline-query-facet-editor', className: 'recline-query-facet-editor',
template: ' \ template: ' \
<a class="btn dropdown-toggle" data-toggle="drop-down">Add filter on</a> \ <div class="dropdown js-add-facet"> \
<ul class="dropdown-menu js-faceton"> \ <a class="btn dropdown-toggle" data-toggle="dropdown" href=".js-add-facet">Add Facet On <i class="caret"></i></a> \
<ul class="dropdown-menu"> \
{{#fields}} \ {{#fields}} \
<li name="{{id}}">{{label}}</li> \ <li><a href="#{{id}}">{{label}}</a></li> \
{{/fields}} \ {{/fields}} \
</ul> \ </ul> \
</div> \
<div class="facets"> \ <div class="facets"> \
{{#facets}} \ {{#facets}} \
<a class="btn js-facet-show-toggle" data-facet="{{label}}"><i class="icon-plus"></i> {{label}}</a> \ <a class="btn js-facet-show-toggle" data-facet="{{id}}"><i class="icon-plus"></i> {{id}} {{label}}</a> \
<ul class="facet-items" data-facet="{{label}}" style="display: none;"> \ <ul class="facet-items" data-facet="{{id}}" style="display: none;"> \
{{#terms}} \ {{#result}} \
<li>{{term}} ({{count}}) <input type="checkbox" class="facet-choice" data-facet="{{label}}" value="{{term}}" /></li> \ <li>{{term}} ({{count}}) <input type="checkbox" class="facet-choice" data-facet="{{label}}" value="{{term}}" /></li> \
{{/terms}} \ {{/result}} \
</ul> \ </ul> \
{{/facets}} \ {{/facets}} \
</div> \ </div> \
', ',
events: { events: {
'change .js-faceton': 'onAddFilter', 'click .js-add-facet .dropdown-menu a': 'onAddFacet',
'click .js-facet-show-toggle': 'onFacetShowToggle' 'click .js-facet-show-toggle': 'onFacetShowToggle'
}, },
initialize: function(model, dataset) { initialize: function(model) {
_.bindAll(this, 'render'); _.bindAll(this, 'render');
this.el = $(this.el); this.el = $(this.el);
this.model.bind('change', this.render); this.model.facets.bind('all', this.render);
this.dataset = dataset; this.model.fields.bind('all', this.render);
this.dataset.fields.bind('add', this.render);
this.dataset.fields.bind('reset', this.render);
this.dataset.fields.bind('remove', this.render);
this.render(); this.render();
}, },
render: function() { render: function() {
var tmplData = { var tmplData = {
query: this.model.toJSON(), facets: this.model.facets.toJSON(),
fields: this.dataset.fields.toJSON() fields: this.model.fields.toJSON()
}; };
tmplData.facets = _.map(this.dataset.facets, function(data, key) {
var out = _.extend({label: key}, data);
return out;
})
var templated = $.mustache(this.template, tmplData); var templated = $.mustache(this.template, tmplData);
this.el.html(templated); this.el.html(templated);
}, },
onAddFilter: function(e) { onAddFacet: function(e) {
var fieldId = $(e.target).find('option:selected').attr('name'); e.preventDefault();
this.model.addFacet(fieldId); var fieldId = $(e.target).attr('href').slice(1);
// calculate facets for that field (if not already there??) this.model.facets.addFacet(fieldId);
// re-render will happen automatically as dataset will have updated
}, },
onFacetShowToggle: function(e) { onFacetShowToggle: function(e) {
e.preventDefault(); e.preventDefault();

View File

@@ -43,4 +43,11 @@ test('Dataset', function () {
equal(out.fields.length, 2); equal(out.fields.length, 2);
}); });
test('Facet', function () {
var facets = new recline.Model.FacetList();
facets.addFacet('xyz');
equal(1, facets.length);
deepEqual({terms: {field: 'xyz'}}, facets.get('xyz').get('query'));
});
})(this.jQuery); })(this.jQuery);