blob: 441fd0ef3de38717d18dab6d6ba352cc1db7eaf0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (callback) {
if (typeof define === 'function' && define.amd) {
define(['core/AbstractWidget', 'core/Parameter'], callback);
}
else {
callback();
}
}(function () {
/**
* Baseclass for all facet widgets.
*
* @class AbstractFacetWidget
* @augments AjaxSolr.AbstractWidget
*/
AjaxSolr.AbstractFacetWidget = AjaxSolr.AbstractWidget.extend(
/** @lends AjaxSolr.AbstractFacetWidget.prototype */
{
/**
* @param {Object} attributes
* @param {String} attributes.field The field to facet on.
* @param {Number} [attributes.start] This widget will by default set the
* offset parameter to 0 on each request.
* @param {Boolean} [attributes.multivalue] Set to <tt>false</tt> to force a
* single "fq" parameter for this widget. Defaults to <tt>true</tt>.
*/
constructor: function (attributes) {
AjaxSolr.AbstractFacetWidget.__super__.constructor.apply(this, arguments);
AjaxSolr.extend(this, {
start: 0,
field: null,
multivalue: true
}, attributes);
},
init: function () {
this.initStore();
},
/**
* Add facet parameters to the parameter store.
*/
initStore: function () {
/* http://wiki.apache.org/solr/SimpleFacetParameters */
var parameters = [
'facet.prefix',
'facet.sort',
'facet.limit',
'facet.offset',
'facet.mincount',
'facet.missing',
'facet.method',
'facet.enum.cache.minDf'
];
this.manager.store.addByValue('facet', true);
// Set facet.field, facet.date or facet.range to truthy values to add
// related per-field parameters to the parameter store.
if (this['facet.field'] !== undefined) {
this.manager.store.addByValue('facet.field', this.field);
}
else if (this['facet.date'] !== undefined) {
this.manager.store.addByValue('facet.date', this.field);
parameters = parameters.concat([
'facet.date.start',
'facet.date.end',
'facet.date.gap',
'facet.date.hardend',
'facet.date.other',
'facet.date.include'
]);
}
else if (this['facet.range'] !== undefined) {
this.manager.store.addByValue('facet.range', this.field);
parameters = parameters.concat([
'facet.range.start',
'facet.range.end',
'facet.range.gap',
'facet.range.hardend',
'facet.range.other',
'facet.range.include'
]);
}
for (var i = 0, l = parameters.length; i < l; i++) {
if (this[parameters[i]] !== undefined) {
this.manager.store.addByValue('f.' + this.field + '.' + parameters[i], this[parameters[i]]);
}
}
},
/**
* @returns {Boolean} Whether any filter queries have been set using this
* widget's facet field.
*/
isEmpty: function () {
return !this.manager.store.find('fq', new RegExp('^-?' + this.field + ':'));
},
/**
* Sets the filter query.
*
* @returns {Boolean} Whether the selection changed.
*/
set: function (value) {
return this.changeSelection(function () {
var a = this.manager.store.removeByValue('fq', new RegExp('^-?' + this.field + ':')),
b = this.manager.store.addByValue('fq', this.fq(value));
return a || b;
});
},
/**
* Adds a filter query.
*
* @returns {Boolean} Whether a filter query was added.
*/
add: function (value) {
return this.changeSelection(function () {
return this.manager.store.addByValue('fq', this.fq(value));
});
},
/**
* Removes a filter query.
*
* @returns {Boolean} Whether a filter query was removed.
*/
remove: function (value) {
return this.changeSelection(function () {
return this.manager.store.removeByValue('fq', this.fq(value));
});
},
/**
* Removes all filter queries using the widget's facet field.
*
* @returns {Boolean} Whether a filter query was removed.
*/
clear: function () {
return this.changeSelection(function () {
return this.manager.store.removeByValue('fq', new RegExp('^-?' + this.field + ':'));
});
},
/**
* Helper for selection functions.
*
* @param {Function} Selection function to call.
* @returns {Boolean} Whether the selection changed.
*/
changeSelection: function (func) {
changed = func.apply(this);
if (changed) {
this.afterChangeSelection();
}
return changed;
},
/**
* An abstract hook for child implementations.
*
* <p>This method is executed after the filter queries change.</p>
*/
afterChangeSelection: function () {},
/**
* One of "facet.field", "facet.date" or "facet.range" must be set on the
* widget in order to determine where the facet counts are stored.
*
* @returns {Array} An array of objects with the properties <tt>facet</tt> and
* <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>.
*/
getFacetCounts: function () {
var property;
if (this['facet.field'] !== undefined) {
property = 'facet_fields';
}
else if (this['facet.date'] !== undefined) {
property = 'facet_dates';
}
else if (this['facet.range'] !== undefined) {
property = 'facet_ranges';
}
if (property !== undefined) {
switch (this.manager.store.get('json.nl').val()) {
case 'map':
return this.getFacetCountsMap(property);
case 'arrarr':
return this.getFacetCountsArrarr(property);
default:
return this.getFacetCountsFlat(property);
}
}
throw 'Cannot get facet counts unless one of the following properties is set to "true" on widget "' + this.id + '": "facet.field", "facet.date", or "facet.range".';
},
/**
* Used if the facet counts are represented as a JSON object.
*
* @param {String} property "facet_fields", "facet_dates", or "facet_ranges".
* @returns {Array} An array of objects with the properties <tt>facet</tt> and
* <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>.
*/
getFacetCountsMap: function (property) {
var counts = [];
for (var facet in this.manager.response.facet_counts[property][this.field]) {
counts.push({
facet: facet,
count: parseInt(this.manager.response.facet_counts[property][this.field][facet])
});
}
return counts;
},
/**
* Used if the facet counts are represented as an array of two-element arrays.
*
* @param {String} property "facet_fields", "facet_dates", or "facet_ranges".
* @returns {Array} An array of objects with the properties <tt>facet</tt> and
* <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>.
*/
getFacetCountsArrarr: function (property) {
var counts = [];
for (var i = 0, l = this.manager.response.facet_counts[property][this.field].length; i < l; i++) {
counts.push({
facet: this.manager.response.facet_counts[property][this.field][i][0],
count: parseInt(this.manager.response.facet_counts[property][this.field][i][1])
});
}
return counts;
},
/**
* Used if the facet counts are represented as a flat array.
*
* @param {String} property "facet_fields", "facet_dates", or "facet_ranges".
* @returns {Array} An array of objects with the properties <tt>facet</tt> and
* <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>.
*/
getFacetCountsFlat: function (property) {
var counts = [];
for (var i = 0, l = this.manager.response.facet_counts[property][this.field].length; i < l; i += 2) {
counts.push({
facet: this.manager.response.facet_counts[property][this.field][i],
count: parseInt(this.manager.response.facet_counts[property][this.field][i+1])
});
}
return counts;
},
/**
* @param {String} value The value.
* @returns {Function} Sends a request to Solr if it successfully adds a
* filter query with the given value.
*/
clickHandler: function (value) {
var self = this, meth = this.multivalue ? 'add' : 'set';
return function () {
if (self[meth].call(self, value)) {
self.doRequest();
}
return false;
}
},
/**
* @param {String} value The value.
* @returns {Function} Sends a request to Solr if it successfully removes a
* filter query with the given value.
*/
unclickHandler: function (value) {
var self = this;
return function () {
if (self.remove(value)) {
self.doRequest();
}
return false;
}
},
/**
* @param {String} value The facet value.
* @param {Boolean} exclude Whether to exclude this fq parameter value.
* @returns {String} An fq parameter value.
*/
fq: function (value, exclude) {
return (exclude ? '-' : '') + this.field + ':' + AjaxSolr.Parameter.escapeValue(value);
}
});
}));