1 // $Id$ 2 3 /** 4 * The ParameterStore, as its name suggests, stores Solr parameters. Widgets 5 * expose some of these parameters to the user. Whenever the user changes the 6 * values of these parameters, the state of the application changes. In order to 7 * allow the user to move back and forth between these states with the browser's 8 * Back and Forward buttons, and to bookmark these states, each state needs to 9 * be stored. The easiest method is to store the exposed parameters in the URL 10 * hash (see the <tt>ParameterHashStore</tt> class). However, you may implement 11 * your own storage method by extending this class. 12 * 13 * <p>For a list of possible parameters, please consult the links below.</p> 14 * 15 * @see http://wiki.apache.org/solr/CoreQueryParameters 16 * @see http://wiki.apache.org/solr/CommonQueryParameters 17 * @see http://wiki.apache.org/solr/SimpleFacetParameters 18 * @see http://wiki.apache.org/solr/HighlightingParameters 19 * @see http://wiki.apache.org/solr/MoreLikeThis 20 * @see http://wiki.apache.org/solr/SpellCheckComponent 21 * @see http://wiki.apache.org/solr/StatsComponent 22 * @see http://wiki.apache.org/solr/TermsComponent 23 * @see http://wiki.apache.org/solr/TermVectorComponent 24 * @see http://wiki.apache.org/solr/LocalParams 25 * 26 * @param properties A map of fields to set. Refer to the list of public fields. 27 * @class ParameterStore 28 */ 29 AjaxSolr.ParameterStore = AjaxSolr.Class.extend( 30 /** @lends AjaxSolr.ParameterStore.prototype */ 31 { 32 /** 33 * The names of the exposed parameters. Any parameters that your widgets 34 * expose to the user, directly or indirectly, should be listed here. 35 * 36 * @field 37 * @public 38 * @type String[] 39 * @default [] 40 */ 41 exposed: [], 42 43 /** 44 * The Solr parameters. 45 * 46 * @field 47 * @private 48 * @type Object 49 * @default {} 50 */ 51 params: {}, 52 53 /** 54 * A reference to the parameter store's manager. For internal use only. 55 * 56 * @field 57 * @private 58 * @type AjaxSolr.AbstractManager 59 */ 60 manager: null, 61 62 /** 63 * An abstract hook for child implementations. 64 * 65 * <p>This method should do any necessary one-time initializations.</p> 66 */ 67 init: function () {}, 68 69 /** 70 * Some Solr parameters may be specified multiple times. It is easiest to 71 * hard-code a list of such parameters. You may change the list by passing 72 * <code>{ multiple: /pattern/ }</code> as an argument to the constructor of 73 * this class or one of its children, e.g.: 74 * 75 * <p><code>new ParameterStore({ multiple: /pattern/ })</code> 76 * 77 * @param {String} name The name of the parameter. 78 * @returns {Boolean} Whether the parameter may be specified multiple times. 79 * @see http://lucene.apache.org/solr/api/org/apache/solr/handler/DisMaxRequestHandler.html 80 */ 81 isMultiple: function (name) { 82 return name.match(/^(?:bf|bq|facet\.date|facet\.date\.other|facet\.date\.include|facet\.field|facet\.pivot|facet\.range|facet\.range\.other|facet\.range\.include|facet\.query|fq|group\.field|group\.func|group\.query|pf|qf)$/); 83 }, 84 85 /** 86 * Returns a parameter. If the parameter doesn't exist, creates it. 87 * 88 * @param {String} name The name of the parameter. 89 * @returns {AjaxSolr.Parameter|AjaxSolr.Parameter[]} The parameter. 90 */ 91 get: function (name) { 92 if (this.params[name] === undefined) { 93 var param = new AjaxSolr.Parameter({ name: name }); 94 if (this.isMultiple(name)) { 95 this.params[name] = [ param ]; 96 } 97 else { 98 this.params[name] = param; 99 } 100 } 101 return this.params[name]; 102 }, 103 104 /** 105 * If the parameter may be specified multiple times, returns the values of 106 * all identically-named parameters. If the parameter may be specified only 107 * once, returns the value of that parameter. 108 * 109 * @param {String} name The name of the parameter. 110 * @returns {String[]|Number[]} The value(s) of the parameter. 111 */ 112 values: function (name) { 113 if (this.params[name] !== undefined) { 114 if (this.isMultiple(name)) { 115 var values = []; 116 for (var i = 0, l = this.params[name].length; i < l; i++) { 117 values.push(this.params[name][i].val()); 118 } 119 return values; 120 } 121 else { 122 return [ this.params[name].val() ]; 123 } 124 } 125 return []; 126 }, 127 128 /** 129 * If the parameter may be specified multiple times, adds the given parameter 130 * to the list of identically-named parameters, unless one already exists with 131 * the same value. If it may be specified only once, replaces the parameter. 132 * 133 * @param {String} name The name of the parameter. 134 * @param {AjaxSolr.Parameter} [param] The parameter. 135 * @returns {AjaxSolr.Parameter|Boolean} The parameter, or false. 136 */ 137 add: function (name, param) { 138 if (param === undefined) { 139 param = new AjaxSolr.Parameter({ name: name }); 140 } 141 if (this.isMultiple(name)) { 142 if (this.params[name] === undefined) { 143 this.params[name] = [ param ]; 144 } 145 else { 146 if (AjaxSolr.inArray(param.val(), this.values(name)) == -1) { 147 this.params[name].push(param); 148 } 149 else { 150 return false; 151 } 152 } 153 } 154 else { 155 this.params[name] = param; 156 } 157 return param; 158 }, 159 160 /** 161 * Deletes a parameter. 162 * 163 * @param {String} name The name of the parameter. 164 * @param {Number} [index] The index of the parameter. 165 */ 166 remove: function (name, index) { 167 if (index === undefined) { 168 delete this.params[name]; 169 } 170 else { 171 this.params[name].splice(index, 1); 172 if (this.params[name].length == 0) { 173 delete this.params[name]; 174 } 175 } 176 }, 177 178 /** 179 * Finds all parameters with matching values. 180 * 181 * @param {String} name The name of the parameter. 182 * @param {String|Number|String[]|Number[]|RegExp} value The value. 183 * @returns {String|Number[]} The indices of the parameters found. 184 */ 185 find: function (name, value) { 186 if (this.params[name] !== undefined) { 187 if (this.isMultiple(name)) { 188 var indices = []; 189 for (var i = 0, l = this.params[name].length; i < l; i++) { 190 if (AjaxSolr.equals(this.params[name][i].val(), value)) { 191 indices.push(i); 192 } 193 } 194 return indices.length ? indices : false; 195 } 196 else { 197 if (AjaxSolr.equals(this.params[name].val(), value)) { 198 return name; 199 } 200 } 201 } 202 return false; 203 }, 204 205 /** 206 * If the parameter may be specified multiple times, creates a parameter using 207 * the given name and value, and adds it to the list of identically-named 208 * parameters, unless one already exists with the same value. If it may be 209 * specified only once, replaces the parameter. 210 * 211 * @param {String} name The name of the parameter. 212 * @param {String|Number|String[]|Number[]} value The value. 213 * @returns {AjaxSolr.Parameter|Boolean} The parameter, or false. 214 */ 215 addByValue: function (name, value) { 216 if (this.isMultiple(name) && AjaxSolr.isArray(value)) { 217 var ret = []; 218 for (var i = 0, l = value.length; i < l; i++) { 219 ret.push(this.add(name, new AjaxSolr.Parameter({ name: name, value: value[i] }))); 220 } 221 return ret; 222 } 223 else { 224 return this.add(name, new AjaxSolr.Parameter({ name: name, value: value })) 225 } 226 }, 227 228 /** 229 * Deletes any parameter with a matching value. 230 * 231 * @param {String} name The name of the parameter. 232 * @param {String|Number|String[]|Number[]|RegExp} value The value. 233 * @returns {String|Number[]} The indices deleted. 234 */ 235 removeByValue: function (name, value) { 236 var indices = this.find(name, value); 237 if (indices) { 238 if (AjaxSolr.isArray(indices)) { 239 for (var i = indices.length - 1; i >= 0; i--) { 240 this.remove(name, indices[i]); 241 } 242 } 243 else { 244 this.remove(indices); 245 } 246 } 247 return indices; 248 }, 249 250 /** 251 * Returns the Solr parameters as a query string. 252 * 253 * <p>IE6 calls the default toString() if you write <tt>store.toString() 254 * </tt>. So, we need to choose another name for toString().</p> 255 */ 256 string: function () { 257 var params = []; 258 for (var name in this.params) { 259 if (this.isMultiple(name)) { 260 for (var i = 0, l = this.params[name].length; i < l; i++) { 261 params.push(this.params[name][i].string()); 262 } 263 } 264 else { 265 params.push(this.params[name].string()); 266 } 267 } 268 return AjaxSolr.compact(params).join('&'); 269 }, 270 271 /** 272 * Parses a query string into Solr parameters. 273 * 274 * @param {String} str The string to parse. 275 */ 276 parseString: function (str) { 277 var pairs = str.split('&'); 278 for (var i = 0, l = pairs.length; i < l; i++) { 279 if (pairs[i]) { // ignore leading, trailing, and consecutive &'s 280 var param = new AjaxSolr.Parameter(); 281 param.parseString(pairs[i]); 282 this.add(param.name, param); 283 } 284 } 285 }, 286 287 /** 288 * Returns the exposed parameters as a query string. 289 * 290 * @returns {String} A string representation of the exposed parameters. 291 */ 292 exposedString: function () { 293 var params = []; 294 for (var i = 0, l = this.exposed.length; i < l; i++) { 295 if (this.params[this.exposed[i]] !== undefined) { 296 if (this.isMultiple(this.exposed[i])) { 297 for (var j = 0, m = this.params[this.exposed[i]].length; j < m; j++) { 298 params.push(this.params[this.exposed[i]][j].string()); 299 } 300 } 301 else { 302 params.push(this.params[this.exposed[i]].string()); 303 } 304 } 305 } 306 return AjaxSolr.compact(params).join('&'); 307 }, 308 309 /** 310 * Resets the values of the exposed parameters. 311 */ 312 exposedReset: function () { 313 for (var i = 0, l = this.exposed.length; i < l; i++) { 314 this.remove(this.exposed[i]); 315 } 316 }, 317 318 /** 319 * Loads the values of exposed parameters from persistent storage. It is 320 * necessary, in most cases, to reset the values of exposed parameters before 321 * setting the parameters to the values in storage. This is to ensure that a 322 * parameter whose name is not present in storage is properly reset. 323 * 324 * @param {Boolean} [reset=true] Whether to reset the exposed parameters. 325 * before loading new values from persistent storage. Default: true. 326 */ 327 load: function (reset) { 328 if (reset === undefined) { 329 reset = true; 330 } 331 if (reset) { 332 this.exposedReset(); 333 } 334 this.parseString(this.storedString()); 335 }, 336 337 /** 338 * An abstract hook for child implementations. 339 * 340 * <p>Stores the values of the exposed parameters in persistent storage. This 341 * method should usually be called before each Solr request.</p> 342 */ 343 save: function () {}, 344 345 /** 346 * An abstract hook for child implementations. 347 * 348 * <p>Returns the string to parse from persistent storage.</p> 349 * 350 * @returns {String} The string from persistent storage. 351 */ 352 storedString: function () { 353 return ''; 354 } 355 }); 356