1/** 2 * @see http://wiki.apache.org/solr/SolJSON#JSON_specific_parameters 3 * @class Manager 4 * @augments AjaxSolr.AbstractManager 5 */ 6var RiotSolrManagers = []; 7 8(function($) { 9 AjaxSolr.Manager = AjaxSolr.AbstractManager.extend({ 10 11 init: function () { 12 13 var exposedParams = this.exposedParams.length ? this.exposedParams : [], 14 storeType = exposedParams.length ? 'ParameterHashStore' : 'ParameterStore'; 15 16 this.firstRequest = false; 17 18 this.initialized = true; 19 if (this.store === null) { 20 this.setStore(new AjaxSolr[storeType]({ 21 exposed: exposedParams 22 })); 23 } 24 if(this.store.storedString() != '') { 25 this.store.parseString(this.store.storedString()) 26 } 27 this.store.load(false); 28 for (var widgetId in this.widgets) { 29 this.widgets[widgetId].init(); 30 } 31 this.store.init() 32 this.docCacheMem = {} 33 if(typeof this.docCache != 'undefined' && this.docCache > 0) { 34 this.cache = new CacheInterface.Bucket({ 35 defaultLifetime: this.docCache, 36 bucket: 'RiotSolrManagerDocCache' 37 }) 38 } else { 39 this.cache = false 40 this.docCacheTS = Date.now() 41 this.docCacheDuration = 60 * 60 * 1000 42 } 43 44 if(typeof this.requestCache != 'undefined' && this.requestCache > 0) { 45 this.requestCache = new CacheInterface.Bucket({ 46 defaultLifetime: this.docCache, 47 bucket: 'RiotSolrManagerRequestCache' 48 }) 49 } else { 50 this.requestCache = false 51 } 52 53 RiotSolrManagers.push(this); 54 55 }, 56 57 regexEscape: function(str) { 58 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 59 }, 60 61 setObservable: function(o) { 62 this.observable = o; 63 }, 64 65 addWidget: function (widget) { 66 widget.manager = this; 67 this.widgets.push(widget); 68 }, 69 70 addBoost: function(name, field, values) { 71 if (typeof this.boosts == 'undefined') { 72 this.boosts = []; 73 } 74 75 this.boosts[name] = field + ":(" + values.join(" ") + ")"; 76 }, 77 78 hasBoost: function(name) { 79 if (typeof this.boosts == 'undefined' || typeof this.boosts[name] == 'undefined') { 80 return false; 81 } 82 return true; 83 }, 84 85 setBoost: function (name) { 86 var store = this.store; 87 if (!this.hasBoost(name)) { 88 return; 89 } 90 91 store.values('bq').map(function (value, index) { 92 store.removeByValue('bq', value); 93 }); 94 95 store.values('sort').map(function (value, index) { 96 store.removeByValue('sort', value); 97 }); 98 99 store.add('bq', new AjaxSolr.Parameter({ 100 name: 'bq', 101 value: this.boosts[name] 102 })); 103 104 if (store.exposed.indexOf('bq') == -1) { 105 store.exposed.push('bq'); 106 } 107 }, 108 109 clearBoost: function() { 110 var store = this.store; 111 store.values('bq').map(function(value, index) { 112 store.removeByValue('bq', value); 113 }); 114 }, 115 116 executeRequest: function (servlet, string, handler, errorHandler, skipCache, queue) { 117 var self = this, 118 options = {dataType: 'json'}, 119 cachedResponse, 120 requestCacheKey; 121 122 if(typeof skipCache === 'undefined') { 123 skipCache = false; 124 } 125 126 if(typeof queue === 'undefined') { 127 queue = 'RiotSolr'; 128 } 129 130 if(typeof this.docCacheMem != 'undefined') { 131 var ts = Date.now() 132 if(ts - this.docCacheTS > this.docCacheDuration) { 133 this.docCacheTS = ts 134 this.docCacheMem = {} 135 } 136 } 137
138 string = string || this.store.string() + '&fl=id'; 139 handler = handler || function (data) { 140 self.handleResponse(data); 141 }; 142 errorHandler = errorHandler || function (jqXHR, textStatus, errorThrown) { 143 self.handleError(textStatus + ', ' + errorThrown); 144 }; 145 if (this.proxyUrl) { 146 options.url = this.proxyUrl; 147 options.data = string + '&wt=json&json.wrf=?'; 148 options.type = 'POST'; 149 if(typeof this.indexId != 'undefined') { 150 options.data += '&fq=index_id:' + AjaxSolr.Parameter.escapeValue(this.indexId) 151 } 152 } 153 else { 154 options.url = this.solrUrl + servlet + '?' + string + '&wt=json&json.wrf=?'; 155 if(typeof this.indexId != 'undefined') { 156 options.url += '&fq=index_id:' + AjaxSolr.Parameter.escapeValue(this.indexId) 157 } 158 } 159 160 // Let handlers work alter search info before triggering it. 161 this.observable.trigger('RiotSolrRequestStart', options); 162 163 if(this.requestCache && !skipCache) { 164 requestCacheKey = self.observable.opts.id + '_' + btoa(JSON.stringify(options)); 165 cachedResponse = this.requestCache.getItem(requestCacheKey); 166 } 167 168 if(!this.requestCache || !cachedResponse) { 169 $ 170 .ajaxq(queue, options) 171 .done(function(data) { 172 if(self.requestCache && !skipCache) { 173 self.requestCache.setItem(requestCacheKey, data); 174 } 175 handler(data); 176 }) 177 .fail(function(err) { 178 errorHandler(err) 179 }) 180 .always(function() { 181 self.observable.trigger('RiotSolrRequestStop') 182 }); 183 } 184 else { 185 handler(cachedResponse); 186 self.observable.trigger('RiotSolrRequestStop') 187 } 188 189 }, 190 191 triggerEvents: function(response) { 192 for (var widgetId in this.widgets) {
193 this.widgets[widgetId].afterRequest(); 194 } 195 if(this.observable) { 196 this.observable.trigger('RiotSolrUpdate', { 197 response: response 198 }); 199 RiotTagsDispatch.trigger('RiotSolrUpdate', this.observable, { 200 response: response 201 }) 202 } 203 }, 204 205 handleResponse: function(response) { 206 var p, self = this, docids 207 this.response = response 208 docids = response.response.docs.map(function(e) { 209 return e.id 210 }) 211 response.getFullDocs = function() { 212 if(!p) { 213 p = self.getDocuments(docids) 214 } 215 return p 216 } 217 this.triggerEvents(response) 218 }, 219 220 getDocuments: function (documentIds) { 221 var promise = $.Deferred(), 222 resolvedDocuments = [], 223 unresolvedDocuments = [], 224 doc, 225 i, 226 self = this; 227 for(i in documentIds) { 228 if(this.cache) { 229 doc = this.cache.getItem(documentIds[i]) 230 } else { 231 doc = this.docCacheMem[documentIds[i]] 232 } 233 if(doc) { 234 resolvedDocuments.push(doc); 235 } 236 else { 237 unresolvedDocuments.push(documentIds[i]); 238 } 239 } 240 if(!unresolvedDocuments.length) { 241 promise.resolve(resolvedDocuments); 242 } 243 else { 244 var string = 'ids=' + unresolvedDocuments.join(','), 245 extraParams; 246 247 if(this.observable.opts.solr.params) { 248 extraParams = this.observable.opts.solr.params 249 for(var p in extraParams) { 250 string += '&'+ p +'=' + extraParams[p] 251 } 252 } 253 254 this.executeRequest( 255 'select', 256 string, 257 function (data) { 258 for(var d in data.response.docs) { 259 var rd = data.response.docs[d]; 260 if(self.cache) { 261 self.cache.setItem(rd.id, rd); 262 } else { 263 self.docCacheMem[rd.id] = rd; 264 } 265 resolvedDocuments.push(data.response.docs[d]); 266 } 267 268 // Resort resolved documents to match order of original document id request. 269 resolvedDocuments.sort(function(a, b) { 270 return documentIds.indexOf(a.id) - documentIds.indexOf(b.id); 271 }); 272 273 promise.resolve(resolvedDocuments) 274 }, 275 function (err) { 276 promise.reject(err); 277 }, 278 true, 279 'fullDocs' 280 ); 281 } 282 283 return promise; 284 }, 285 /** 286 * Get documents from the solr index by their base table primary key (eg. nid or eid) instead of by their 287 * solr id which is a composite of the index, site hash and primary key. 288 * 289 * @param pks array of integer 290 */ 291 getDocumentsByKeys: function(pks) { 292 var ids = [], ind, k 293 for(ind in pks) { 294 this.siteHash 295 ? k = [this.siteHash, this.indexId, pks[ind]] 296 : k = [this.indexId, pks[ind]] 297 ids.push(k.join('-')) 298 } 299 return this.getDocuments(ids) 300 } 301 }); 302 303 304 /** 305 * Override the default parameter.It's done this way because Parameter 306 * instances are initialized really high up in the inheritance chain 307 * for ParameterStore instances. This approach keeps us from needing to 308 * override (nearly) the entire store ourselves. 309 */ 310 AjaxSolr.Parameter = AjaxSolr.Parameter.extend({ 311 /** 312 * OVerridden to account for cases where tags have commas in them. 313 * @param str 314 * @returns {string} 315 */ 316 parseValueString: function(str) { 317 return decodeURIComponent(str); 318 }, 319 320 /** 321 * Overridden to apply regular expression escaping to facet values. 322 * @param value 323 * @returns {*} 324 */ 325 escapeValue: function (value) { 326 var v; 327 if (value.match(/[ :\/"]/) && !value.match(/[\[\{]\S+ TO \S+[\]\}]/) && !value.match(/^["\(].*["\)]$/)) { 328 v = '"' + value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'; 329 } 330 else { 331 v = value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") 332 } 333 334 return AjaxSolr.Manager.regexEscape(v); 335 } 336 }); 337 338 /** 339 * Override to allow stats.field to be multiple 340 */ 341 AjaxSolr.ParameterHashStore.prototype.isMultiple = function (name) { 342 return name.match(/^(?:bf|bq|stats\.field|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)$/); 343 } 344 345 /** 346 * Override to allow stats.field to be multiple 347 */ 348 AjaxSolr.ParameterStore.prototype.isMultiple = function (name) { 349 return name.match(/^(?:bf|bq|stats\.field|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)$/); 350 } 351 352 /** 353 * Override to parameters to explude 'private' parameters includsion in the URL 354 * 355 * @returns {String} A string representation of the exposed parameters. 356 */
357 AjaxSolr.ParameterHashStore.prototype.exposedString = function () { 358 var params = [], string; 359 for (var i = 0, l = this.exposed.length; i < l; i++) { 360 if (this.params[this.exposed[i]] !== undefined) { 361 if (this.isMultiple(this.exposed[i])) { 362 for (var j = 0, m = this.params[this.exposed[i]].length; j < m; j++) { 363 string = this.params[this.exposed[i]][j].string(); 364 if (string && this.params[this.exposed[i]][j]['private'] !== true) { 365 params.push(string); 366 } 367 } 368 } 369 else { 370 string = this.params[this.exposed[i]].string(); 371 if (string && this.params[this.exposed[i]]['private'] !== true) { 372 params.push(string); 373 } 374 } 375 } 376 } 377 return params.join('&'); 378 } 379 380})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.