1 (function (callback) { 2 if (typeof define === 'function' && define.amd) { 3 define(['core/AbstractWidget', 'core/Parameter'], callback); 4 } 5 else { 6 callback(); 7 } 8 }(function () { 9 10 /** 11 * Baseclass for all facet widgets. 12 * 13 * @class AbstractFacetWidget 14 * @augments AjaxSolr.AbstractWidget 15 */ 16 AjaxSolr.AbstractFacetWidget = AjaxSolr.AbstractWidget.extend( 17 /** @lends AjaxSolr.AbstractFacetWidget.prototype */ 18 { 19 /** 20 * @param {Object} attributes 21 * @param {String} attributes.field The field to facet on. 22 * @param {Number} [attributes.start] This widget will by default set the 23 * offset parameter to 0 on each request. 24 * @param {Boolean} [attributes.multivalue] Set to <tt>false</tt> to force a 25 * single "fq" parameter for this widget. Defaults to <tt>true</tt>. 26 */ 27 constructor: function (attributes) { 28 AjaxSolr.extend(this, { 29 start: 0, 30 field: null, 31 multivalue: true 32 }, attributes); 33 }, 34 35 init: function () { 36 this.initStore(); 37 }, 38 39 /** 40 * Add facet parameters to the parameter store. 41 */ 42 initStore: function () { 43 /* http://wiki.apache.org/solr/SimpleFacetParameters */ 44 var parameters = [ 45 'facet.prefix', 46 'facet.sort', 47 'facet.limit', 48 'facet.offset', 49 'facet.mincount', 50 'facet.missing', 51 'facet.method', 52 'facet.enum.cache.minDf' 53 ]; 54 55 this.manager.store.addByValue('facet', true); 56 57 // Set facet.field, facet.date or facet.range to truthy values to add 58 // related per-field parameters to the parameter store. 59 if (this['facet.field'] !== undefined) { 60 this.manager.store.addByValue('facet.field', this.field); 61 } 62 else if (this['facet.date'] !== undefined) { 63 this.manager.store.addByValue('facet.date', this.field); 64 parameters = parameters.concat([ 65 'facet.date.start', 66 'facet.date.end', 67 'facet.date.gap', 68 'facet.date.hardend', 69 'facet.date.other', 70 'facet.date.include' 71 ]); 72 } 73 else if (this['facet.range'] !== undefined) { 74 this.manager.store.addByValue('facet.range', this.field); 75 parameters = parameters.concat([ 76 'facet.range.start', 77 'facet.range.end', 78 'facet.range.gap', 79 'facet.range.hardend', 80 'facet.range.other', 81 'facet.range.include' 82 ]); 83 } 84 85 for (var i = 0, l = parameters.length; i < l; i++) { 86 if (this[parameters[i]] !== undefined) { 87 this.manager.store.addByValue('f.' + this.field + '.' + parameters[i], this[parameters[i]]); 88 } 89 } 90 }, 91 92 /** 93 * @returns {Boolean} Whether any filter queries have been set using this 94 * widget's facet field. 95 */ 96 isEmpty: function () { 97 return !this.manager.store.find('fq', new RegExp('^-?' + this.field + ':')); 98 }, 99 100 /** 101 * Sets the filter query. 102 * 103 * @returns {Boolean} Whether the selection changed. 104 */ 105 set: function (value) { 106 return this.changeSelection(function () { 107 var a = this.manager.store.removeByValue('fq', new RegExp('^-?' + this.field + ':')), 108 b = this.manager.store.addByValue('fq', this.fq(value)); 109 return a || b; 110 }); 111 }, 112 113 /** 114 * Adds a filter query. 115 * 116 * @returns {Boolean} Whether a filter query was added. 117 */ 118 add: function (value) { 119 return this.changeSelection(function () { 120 return this.manager.store.addByValue('fq', this.fq(value)); 121 }); 122 }, 123 124 /** 125 * Removes a filter query. 126 * 127 * @returns {Boolean} Whether a filter query was removed. 128 */ 129 remove: function (value) { 130 return this.changeSelection(function () { 131 return this.manager.store.removeByValue('fq', this.fq(value)); 132 }); 133 }, 134 135 /** 136 * Removes all filter queries using the widget's facet field. 137 * 138 * @returns {Boolean} Whether a filter query was removed. 139 */ 140 clear: function () { 141 return this.changeSelection(function () { 142 return this.manager.store.removeByValue('fq', new RegExp('^-?' + this.field + ':')); 143 }); 144 }, 145 146 /** 147 * Helper for selection functions. 148 * 149 * @param {Function} Selection function to call. 150 * @returns {Boolean} Whether the selection changed. 151 */ 152 changeSelection: function (func) { 153 changed = func.apply(this); 154 if (changed) { 155 this.afterChangeSelection(); 156 } 157 return changed; 158 }, 159 160 /** 161 * An abstract hook for child implementations. 162 * 163 * <p>This method is executed after the filter queries change.</p> 164 */ 165 afterChangeSelection: function () {}, 166 167 /** 168 * One of "facet.field", "facet.date" or "facet.range" must be set on the 169 * widget in order to determine where the facet counts are stored. 170 * 171 * @returns {Array} An array of objects with the properties <tt>facet</tt> and 172 * <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>. 173 */ 174 getFacetCounts: function () { 175 var property; 176 if (this['facet.field'] !== undefined) { 177 property = 'facet_fields'; 178 } 179 else if (this['facet.date'] !== undefined) { 180 property = 'facet_dates'; 181 } 182 else if (this['facet.range'] !== undefined) { 183 property = 'facet_ranges'; 184 } 185 if (property !== undefined) { 186 switch (this.manager.store.get('json.nl').val()) { 187 case 'map': 188 return this.getFacetCountsMap(property); 189 case 'arrarr': 190 return this.getFacetCountsArrarr(property); 191 default: 192 return this.getFacetCountsFlat(property); 193 } 194 } 195 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".'; 196 }, 197 198 /** 199 * Used if the facet counts are represented as a JSON object. 200 * 201 * @param {String} property "facet_fields", "facet_dates", or "facet_ranges". 202 * @returns {Array} An array of objects with the properties <tt>facet</tt> and 203 * <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>. 204 */ 205 getFacetCountsMap: function (property) { 206 var counts = []; 207 for (var facet in this.manager.response.facet_counts[property][this.field]) { 208 counts.push({ 209 facet: facet, 210 count: parseInt(this.manager.response.facet_counts[property][this.field][facet]) 211 }); 212 } 213 return counts; 214 }, 215 216 /** 217 * Used if the facet counts are represented as an array of two-element arrays. 218 * 219 * @param {String} property "facet_fields", "facet_dates", or "facet_ranges". 220 * @returns {Array} An array of objects with the properties <tt>facet</tt> and 221 * <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>. 222 */ 223 getFacetCountsArrarr: function (property) { 224 var counts = []; 225 for (var i = 0, l = this.manager.response.facet_counts[property][this.field].length; i < l; i++) { 226 counts.push({ 227 facet: this.manager.response.facet_counts[property][this.field][i][0], 228 count: parseInt(this.manager.response.facet_counts[property][this.field][i][1]) 229 }); 230 } 231 return counts; 232 }, 233 234 /** 235 * Used if the facet counts are represented as a flat array. 236 * 237 * @param {String} property "facet_fields", "facet_dates", or "facet_ranges". 238 * @returns {Array} An array of objects with the properties <tt>facet</tt> and 239 * <tt>count</tt>, e.g <tt>{ facet: 'facet', count: 1 }</tt>. 240 */ 241 getFacetCountsFlat: function (property) { 242 var counts = []; 243 for (var i = 0, l = this.manager.response.facet_counts[property][this.field].length; i < l; i += 2) { 244 counts.push({ 245 facet: this.manager.response.facet_counts[property][this.field][i], 246 count: parseInt(this.manager.response.facet_counts[property][this.field][i+1]) 247 }); 248 } 249 return counts; 250 }, 251 252 /** 253 * @param {String} value The value. 254 * @returns {Function} Sends a request to Solr if it successfully adds a 255 * filter query with the given value. 256 */ 257 clickHandler: function (value) { 258 var self = this, meth = this.multivalue ? 'add' : 'set'; 259 return function () { 260 if (self[meth].call(self, value)) { 261 self.doRequest(); 262 } 263 return false; 264 } 265 }, 266 267 /** 268 * @param {String} value The value. 269 * @returns {Function} Sends a request to Solr if it successfully removes a 270 * filter query with the given value. 271 */ 272 unclickHandler: function (value) { 273 var self = this; 274 return function () { 275 if (self.remove(value)) { 276 self.doRequest(); 277 } 278 return false; 279 } 280 }, 281 282 /** 283 * @param {String} value The facet value. 284 * @param {Boolean} exclude Whether to exclude this fq parameter value. 285 * @returns {String} An fq parameter value. 286 */ 287 fq: function (value, exclude) { 288 return (exclude ? '-' : '') + this.field + ':' + AjaxSolr.Parameter.escapeValue(value); 289 } 290 }); 291 292 })); 293