1/** 2 * Init some global vars. 3 * @var RiotSolrCookieStore - this is the default browser storage mechanism for 4 * the RiotSolrFlag system. See it as an example of how you can implement your own. 5 * Storage mechanism will be instantiated via "new window['MyStorageVar']". So it's 6 * important to declare them in the global namespace. To add your own storage instance, 7 * you'll also need to implement hook_riot_solr_flag_stores_alter(). 8 * 9 * @var RiotSolrCreateInstance - Super compact helper for calling constructors from a string. 10 * 11 * @var RiotSolrItemSortHandlers - Callback functions for sorting items. 12 * 13 * @var RiotSolrIntObs - Singular instance intersection observer 14 * 15 */ 16var RiotSolrCookieStore, RiotSolrCreateInstance, RiotSolrItemSortHandlers, 17 RiotSolrIntObs = (typeof IntersectionObserver == 'undefined' || RiotTagsUtils.detectIE()) ? undefined : new IntersectionObserver(function(entries) { 18 for(ind in entries) { 19 if (entries[ind].target._tag) { 20 entries[ind].target._tag.trigger('RiotSolrIntersect', entries[ind]) 21 } 22 } 23 }, {rootMargin: "80px 0px 80px 0px"}); 24 25(function($) { 26 /** 27 * 28 * @type {{init: init, RiotSolrGetFacets: RiotSolrGetFacets, RiotSolrInitManager: RiotSolrInitManager}} 29 */ 30 var RiotSolrConnection = { 31 init: function() { 32 var self = this; 33 if (!self.opts.solr) { 34 return; 35 } 36 self.RiotSolrInitManager(); 37 if (typeof self.RiotSolrManager != 'undefined') { 38 self.RiotSolrManager.observable.on('RiotSolrRequestStart', function() { 39 $(self.root).addClass('pending'); 40 }); 41 42 self.RiotSolrManager.observable.on('RiotSolrRequestStop', function() { 43 $(self.root).removeClass('pending'); 44 }); 45 46 self.getChildExtraOptions = function(c) { 47 return { 48 manager: self.RiotSolrManager, 49 facets: self.RiotSolrFacets, 50 }; 51 }; 52 } 53 54 self.on('RiotSolrUpdate', function() { 55 self.RiotSolrManager.firstRequest = true; 56 }); 57 }, 58 59 RiotSolrGetFacets: function(options) { 60 var facets = [], 61 w, 62 f; 63 for (f in options.facets) { 64 if (options.facets.hasOwnProperty(f)) { 65 w = options.facets[f]['settings']['settings']['widget']; 66 if (this.RiotSolrManager.facetWidgetMap && typeof this.RiotSolrManager.facetWidgetMap[w] !== 'undefined') { 67 facets.push({ 68 definition: options.facets[f], 69 field: options.fields[f]['solr_field'], 70 label: options.fields[f]['name'], 71 htmlTagName: this.RiotSolrManager.facetWidgetMap[w]['tag'], 72 }); 73 } 74 } 75 } 76 return facets; 77 }, 78 79 RiotSolrInitManager: function() { 80 var self = this, 81 name, 82 params = { 83 facet: true, 84 rows: self.opts.solr.max_rows, 85 'facet.range': [], 86 'facet.mincount': 1, 87 'json.nl': 'map', 88 }, 89 constructorArgs = { 90 observable: self, 91 proxyUrl: self.opts.solr.url, 92 indexId: self.opts.solr.index, 93 bundles: self.opts.solr.bundles, 94 entityType: self.opts.solr.entity_type, 95 docCache: self.opts.solr.doc_cache, 96 requestCache: self.opts.solr.doc_cache, 97 exposedParams: self.opts.solr.exposed_params, 98 siteHash: self.opts.solr.hash, 99 facetWidgetMap: self.opts.facet_widget_map, 100 widgets: [], 101 }; 102 103 if (self.opts.solr.index === 'inherit' || typeof self.opts.solr.index == 'undefined') { 104 if (typeof self.parent !== 'undefined') { 105 self.RiotSolrManager = self.parent.RiotSolrManager; 106 } else if (typeof self.opts.manager !== 'undefined') { 107 self.RiotSolrManager = self.opts.manager; 108 } 109 } 110 111 if (self.RiotSolrManager) { 112 if (!self.RiotSolrFacets && self.opts.facets) { 113 self.RiotSolrFacets = self.opts.facets; 114 } else { 115 self.RiotSolrFacets = []; 116 } 117 } else if (self.opts.solr.index != 'inherit' && typeof self.opts.solr.index != 'undefined') { 118 self.RiotSolrManager = new AjaxSolr.Manager(constructorArgs); 119 self.RiotSolrFacets = self.RiotSolrGetFacets(self.opts.solr); 120 self.RiotSolrManager.observable.on('RiotSolrBoot', function() { 121 self.RiotSolrManager.observable.trigger('RiotSolrAddWidgets', self.RiotSolrManager); 122 self.RiotSolrManager.init(); 123 self.RiotSolrManager.observable.trigger('RiotSolrInit', self.RiotSolrManager, params); 124 if (self.RiotSolrManager.store.storedString() == '' && self.opts.solr.default_q) { 125 params['q'] = self.opts.solr.default_q; 126 } 127 if (!self.RiotSolrManager.store.get('boost').value && self.opts.solr.default_boost) { 128 if(!self.RiotSolrManager.store.get('bq') || !self.RiotSolrManager.store.get('bq').value) { 129 params['boost'] = self.opts.solr.default_boost; 130 } 131 params['defType'] = 'edismax'; 132 } 133 134 if (self.opts.solr.params) { 135 params = $.extend(params, self.opts.solr.params); 136 } 137 for (name in params) { 138 self.RiotSolrManager.store.addByValue(name, params[name]); 139 } 140 if (self.opts.solr.max_rows > 0) { 141 self.RiotSolrManager.doRequest(); 142 } 143 self.RiotSolrManager.observable.trigger('RiotSolrReady', self.RiotSolrManager);
144 RiotTagsDispatch.trigger('RiotSolrReady', self.RiotSolrManager.observable, self.RiotSolrManager); 145 }); 146 self.one('updated', function() { 147 self.RiotSolrManager.observable.trigger('RiotSolrBoot'); 148 }); 149 } 150 }, 151 }; 152 153 riot.mixin('RiotSolrConnection', RiotSolrConnection); 154 155 /** 156 * Abstracts initializing a facet, maintaining a map of Drupal UI facet types to 157 * RiotSolr facet types. 158 * @type {{clickHandler: RiotSolrFacetProvider.clickHandler}} 159 */ 160 var RiotSolrFacetProvider = { 161 init: function() { 162 var self = this; 163 self.mixin('RiotSolrConnection'); 164 165 self.on(self.opts.widget + 'Update', function(results) { 166 self.items = this.FacetProcessItems(results); 167 self.update(); 168 }); 169 170 self.RiotSolrManager.observable.on('RiotSolrAddWidgets', function(manager) { 171 self.FacetBuildWidget(manager); 172 }); 173 }, 174 175 FacetGetDefinition: function() { 176 for (var f in this.RiotSolrFacets) { 177 if (this.RiotSolrFacets[f].definition.data.field === this.opts.facet_field) { 178 return this.RiotSolrFacets[f]; 179 } 180 } 181 return false; 182 }, 183 184 FacetClickHandler: function(value) { 185 if (value.item.active) { 186 this.FacetRemove(value); 187 } else { 188 this.FacetAdd(value); 189 } 190 }, 191 192 FacetProcessParams: function(params) { 193 return params; 194 }, 195 196 FacetFilterChars: function(str) { 197 return str.replace(/[\[\]\{\}\(\)\*\+\?\.\\]/g,""); 198 }, 199 200 FacetBuildWidget: function(manager) { 201 var facetOpts = this.FacetGetDefinition(), 202 facetArgs, 203 realmSettings, 204 def = facetOpts.definition, 205 label = ''; 206 207 for (var o in facetOpts) { 208 this.opts[o] = facetOpts[o]; 209 } 210 211 if (typeof def == 'undefined') { 212 return; 213 } 214 215 if (typeof def.settings.settings['riot_solr'] !== 'undefined') { 216 realmSettings = def.settings.settings['riot_solr']; 217 } 218 219 if ( 220 typeof realmSettings !== 'undefined' && 221 typeof realmSettings.facet_label !== 'undefined' && 222 realmSettings.facet_label !== '' 223 ) { 224 label = realmSettings.facet_label; 225 } else { 226 label = def.settings_global.settings['riotjs_label']; 227 } 228 229 this.opts.label = label; 230 231 facetArgs = { 232 id: this.opts.widget + '-' + this.opts.field, 233 target: '[data-facetId="' + this.opts.widget + '-' + this.opts.field + '"]', 234 field: this.opts.field, 235 label: label, 236 observable: this, 237 operator: def.settings_global.settings['operator'], 238 'facet.limit': def.settings_global.settings['hard_limit'], 239 'facet.field': this.opts.field, 240 'facet.missing': def.settings_global.settings['facet_missing'] > 0 ? 'true' : 'false', 241 multivalue: def.settings_global.settings['limit_active_items'] <= 0, 242 }; 243 244 if (def.settings_global.settings['facet_mincount']) { 245 facetArgs['facet.mincount'] = def.settings_global.settings['facet_mincount']; 246 } 247 this.instance = new AjaxSolr[this.opts.widget](this.FacetProcessParams(facetArgs)); 248 249 manager.addWidget(this.instance); 250 }, 251 252 FacetProcessItems: function(results) { 253 var items = [], 254 self = this, 255 pattern, 256 k; 257 if (results.field === this.opts.field && results.widget === this.opts.widget) { 258 if (this.opts.definition.settings.settings.exclude) { 259 pattern = new RegExp(self.FacetFilterChars(this.opts.definition.settings.settings.exclude)); 260 items = results.items.filter(function(item) { 261 return !pattern.test(self.FacetFilterChars(item.facet)); 262 }); 263 } else { 264 items = results.items; 265 } 266 267 // Process sorting options. 268 this.trigger('RiotSolrFacetProviderSort', { 269 'items': items, 270 'field': results.field, 271 'sortOptions': this.opts.definition.settings.settings.active_sorts, 272 'results': results, 273 }); 274 RiotTagsDispatch.trigger('RiotSolrFacetProviderSort', { 275 'items': items, 276 'field': results.field, 277 'sortOptions': this.opts.definition.settings.settings.active_sorts, 278 'results': results, 279 }); 280 281 for (k in items) { 282 (function(self) { 283 if (!items.hasOwnProperty(k)) { 284 return; 285 } 286 items[k]['active'] = self.IsActive(items[k].facet); 287 })(this); 288 } 289 } 290 return items; 291 }, 292 293 /** 294 * @param value 295 * @constructor 296 */ 297 FacetAdd: function(value) { 298 var meth = this.instance.multivalue ? 'add' : 'set'; 299 if (this.instance[meth].call(this.instance, value.item.facet)) { 300 this.instance.doRequest(); 301 } 302 }, 303 304 /** 305 * @param value 306 * @constructor 307 */ 308 FacetRemove: function(value) { 309 this.instance.remove(value.item.facet); 310 this.instance.doRequest(); 311 }, 312 313 /** 314 * @param value 315 * @constructor 316 */ 317 FacetReset: function() { 318 this.instance.removeAll(); 319 this.instance.doRequest(); 320 }, 321 322 /** 323 * @param facetValue 324 * @returns {boolean} 325 * @constructor 326 */ 327 IsActive: function(facetValue) { 328 return this.instance.isActive(facetValue); 329 }, 330 }; 331 332 riot.mixin('RiotSolrFacetProvider', RiotSolrFacetProvider); 333 334 var RiotSolrItemsContainer = { 335 init: function() { 336 var self = this; 337 338 this.riotSolrItems = []; 339 this.items = []; 340 341 self.getChildExtraOptions = function() { 342 return { 343 manager: self.RiotSolrManager, 344 }; 345 }; 346 347 // Override process children 348 var procc = self.processChildren; 349 self.processChildren = function() { 350 procc.apply(self); 351 for (var c in self.children) { 352 if (self.children[c].tag === 'riot-solr-no-results' || self.children[c].tag === 'riot-solr-alternates') { 353 self.noResultsTag = self.children[c]; 354 self.children.splice(c, 1); 355 } 356 } 357 if (typeof self.children != 'undefined' && self.children.length > 0) { 358 self.children[0].mounted = true; 359 } 360 }; 361 362 (self.numvisible = parseInt(self.opts.numvisible)), (self.pagecount = parseInt(self.opts.numvisible)); 363 364 self.RiotSolrManager.observable.on('RiotSolrUpdate', function(data) { 365 if (self.opts.solr.return_full_docs && data.response.getFullDocs) { 366 data.response.getFullDocs().done(function(docs) { 367 data.response.docs = docs; 368 self.RiotSolrManager.triggerEvents(data); 369 self.setRiotSolrItems(data.response.docs); 370 }); 371 } 372 }); 373 self.RiotSolrManager.observable.on('RiotSolrItemsSorted', function(data) { 374 self.setRiotSolrItems(data.items); 375 }); 376
377 self.displayitems = []; 378 379 self.on('RiotSolrItemsUpdated', function() { 380 $.Deferred(function() { 381 self.items = self.getRiotSolrItems(); 382 self.numvisible = parseInt(self.opts.numvisible); 383 if (self.numvisible > 0) { 384 self.displayitems = self.items.slice(0, self.numvisible); 385 } else { 386 self.displayitems = self.items; 387 } 388 self.update(); 389 RiotTagsDispatch.trigger('RiotSolrItemsUpdated', self, self.items); 390 self.RiotSolrManager.observable.trigger('RiotSolrItemsUpdated', self, self.items); 391 }); 392 }); 393 394 self.on('RiotSolrItemsSorted', function(sorted) { 395 $.Deferred(function() { 396 self.items = sorted.items; 397 numvisible = self.opts.numvisible; 398 if (numvisible > 0) { 399 self.displayitems = self.items.slice(0, self.numvisible); 400 } else { 401 self.displayitems = self.items; 402 } 403 self.update(); 404 }); 405 }); 406 407 if (self.numvisible > 0) { 408 (function($, tag) { 409 var scrollCallback = function(e) { 410 var resultsWrap = tag.root.querySelector('.result-list'); 411 if ( 412 resultsWrap && 413 resultsWrap.lastElementChild !== null && 414 resultsWrap.lastElementChild.isVisible() && 415 tag.numvisible < tag.items.length 416 ) { 417 tag.numvisible += parseInt(tag.pagecount); 418 Array.prototype.push.apply(tag.displayitems, tag.items.slice(tag.displayitems.length, tag.numvisible)); 419 tag.update(); 420 } 421 }; 422 // $(tag.root).scroll(scrollCallback); 423 document.addEventListener('scroll', scrollCallback); 424 })(jQuery, self); 425 } 426 }, 427 setRiotSolrItems: function(items) { 428 this.riotSolrItems = items; 429 this.trigger('RiotSolrItemsUpdated', items); 430 }, 431 getRiotSolrItems: function() { 432 return this.riotSolrItems; 433 }, 434 }; 435 riot.mixin('RiotSolrItemsContainer', RiotSolrItemsContainer); 436 437 var RiotSolrLinkedItem = { 438 RiotSolrLinkedItem: riot.observable(), 439 }; 440 riot.mixin('RiotSolrLinkedItem', RiotSolrLinkedItem); 441 442 var RiotSolrIntersectionObserver = { 443 init: function() { 444 this.observeAfterFirstVisible = true; 445 this.on('mount', function() { 446 this.hasBeenVisible = false; 447 this.observeInt(); 448 }); 449 this.on('RiotSolrIntersect', function(data) { 450 // When visible first time, loadImages 451 if (data.isIntersecting) { 452 if (!this.hasBeenVisible) { 453 this.hasBeenVisible = true; 454 this.trigger('RiotSolrIntersectFirstVisible', data); 455 456 if (!this.observeAfterFirstVisible) { 457 this.unobserveInt(); 458 } 459 } 460 } 461 }); 462 }, 463 unobserveInt: function() { 464 if (typeof RiotSolrIntObs != 'undefined') { 465 RiotSolrIntObs.unobserve(this.root); 466 } 467 }, 468 observeInt: function() { 469 if (typeof RiotSolrIntObs != 'undefined') { 470 RiotSolrIntObs.observe(this.root); 471 } 472 }, 473 canObserveInt: function() { 474 return typeof IntersectionObserver != 'undefined' && !RiotTagsUtils.detectIE(); 475 }, 476 }; 477 riot.mixin('RiotSolrIntersectionObserver', RiotSolrIntersectionObserver); 478 479 var RiotSolrLazyImage = { 480 init: function() { 481 this.mixin('RiotSolrIntersectionObserver'); 482 this.observeAfterFirstVisible = false; 483 this.on('RiotSolrIntersectFirstVisible', function(data) { 484 // When visible first time, loadImages 485 this.loadImages(); 486 }); 487 }, 488 loadImages: function() { 489 $('img[data-src]:not(.RiotSolrLazyLoaded)', this.root).each(function() { 490 $(this).attr('src', $(this).attr('data-src')).addClass('RiotSolrLazyLoaded'); 491 }); 492 }, 493 }; 494 riot.mixin('RiotSolrLazyImage', RiotSolrLazyImage); 495 496 var RiotSolrIf = { 497 _if: function(expr) { 498 return expr ? [expr] : []; 499 }, 500 }; 501 502 riot.mixin(RiotSolrIf); 503 504 var RiotSolrItem = { 505 init: function() { 506 var self = this, 507 ext = self.getChildExtraOptions; 508 self.getChildExtraOptions = function(c) { 509 var opts = ext.apply(c); 510 opts['item'] = self.RiotSolrGetItem(); 511 opts['manager'] = self.RiotSolrManager; 512 return opts; 513 }; 514 self.valueOrFirst = function(value) { 515 return Array.isArray(value) ? value[0] : value; 516 }; 517 518 this.one('updated', function() {
519 RiotTagsDispatch.trigger('RiotSolrResultItemMounted', self, self.opts); 520 }); 521 }, 522 523 RiotSolrGetItem: function() { 524 return this.item; 525 }, 526 }; 527 528 riot.mixin('RiotSolrItem', RiotSolrItem); 529 530 var RiotSolrFlag = { 531 init: function() { 532 var self = this, 533 item = self.opts.item; 534 535 if (self.opts.flag_options) { 536 self.RiotSolrFlagOpts = self.opts.flag_options; 537 } 538 539 if (self.RiotSolrFlagOpts.skip_solr && self.RiotSolrFlagOpts.skip_solr_prefix) { 540 self.flagItemID = self.RiotSolrFlagOpts.skip_solr_prefix + self.opts.eid; 541 self.RiotSolrFlagSetFlag(); 542 } 543 else { 544 if (!item) { 545 self.RiotSolrManager.observable.on('RiotSolrReady', function() { 546 self.RiotSolrManager.getDocumentsByKeys([self.opts.eid]).done(function(docs) { 547 self.RiotSolrFlagSetItem(docs[0]); 548 }); 549 }); 550 } else { 551 self.one('update', function () { 552 self.RiotSolrFlagSetItem(item); 553 }); 554 } 555 } 556 557 /** 558 * When updates come from an outside source 559 */ 560 RiotTagsDispatch.on('RiotSolrFlagUpdate', function(tag, namespace) { 561 if ( 562 tag._riot_id !== self._riot_id && 563 self.RiotSolrFlagOpts.namespace === namespace && 564 self.flagItemID === tag.flagItemID 565 ) { 566 self.RiotSolrFlagClass = tag.RiotSolrFlagClass; 567 self.RiotSolrFlagText = tag.RiotSolrFlagText; 568 self.update(); 569 } 570 }); 571 }, 572 573 RiotSolrFlagSetItem: function(item) { 574 if(item) { 575 this.flagItemID = item[this.RiotSolrFlagOpts.key] + ''; //always force to a string 576 this.RiotSolrFlagSetFlag(); 577 } 578 }, 579 580 RiotSolrFlagSetFlag: function() { 581 this.RiotSolrFlagInitStore(); 582 if (this.RiotSolrFlagStore.has(this.flagItemID)) { 583 this.RiotSolrFlagText = this.RiotSolrFlagOpts.text.unflag; 584 this.RiotSolrFlagClass = this.RiotSolrFlagOpts.classes.unflag; 585 } else { 586 this.RiotSolrFlagText = this.RiotSolrFlagOpts.text.flag; 587 this.RiotSolrFlagClass = this.RiotSolrFlagOpts.classes.flag; 588 } 589 this.update(); 590 }, 591 592 RiotSolrFlagInitStore: function() { 593 this.RiotSolrFlagStore = RiotSolrCreateInstance(this.RiotSolrFlagOpts.store, this.RiotSolrFlagOpts.namespace); 594 }, 595 596 RiotSolrFlagOpts: { 597 text: { 598 flag: 'Flag', 599 unflag: 'Unflag', 600 }, 601 classes: { 602 flag: 'rs-flag', 603 unflag: 'rs-unflag', 604 }, 605 namespace: 'riot_solr_flag_items', 606 store: 'RiotSolrCookieStore', 607 key: 'id', 608 }, 609 610 RiotSolrHandleFlag: function(e) { 611 var self = this, 612 store = self.RiotSolrFlagStore; 613 614 if (store.has(self.flagItemID)) { 615 store.remove(self.flagItemID); 616 self.RiotSolrFlagText = self.RiotSolrFlagOpts.text.flag; 617 self.RiotSolrFlagClass = self.RiotSolrFlagOpts.classes.flag; 618 } else { 619 store.add(self.flagItemID); 620 self.RiotSolrFlagText = self.RiotSolrFlagOpts.text.unflag; 621 self.RiotSolrFlagClass = self.RiotSolrFlagOpts.classes.unflag; 622 } 623 RiotTagsDispatch.trigger('RiotSolrFlagUpdate', this, this.RiotSolrFlagOpts.namespace); 624 self.update(); 625 }, 626 }; 627 628 riot.mixin('RiotSolrFlag', RiotSolrFlag); 629 630 var RiotSolrFlagCounter = { 631 init: function() { 632 var self = this, 633 fcu; 634 635 self.RiotSolrManager.observable.on('RiotSolrInit', function(manager) { 636 self.RiotSolrManager.setStore(new AjaxSolr.ParameterStore()); 637 self.RiotSolrManager.store.load(false); 638 self.RiotSolrManager.store.init(); 639 }); 640 641 if (self.opts.flag_options) { 642 self.RiotSolrFlagOpts = self.opts.flag_options; 643 } 644 645 self.showItems = false; 646 647 self.RiotSolrFlagStore = RiotSolrCreateInstance(self.opts.flag_options.store, self.opts.flag_options.namespace); 648 649 fcu = function() { 650 self.RiotSolrFlagCounterUpdate(); 651 }; 652 653 RiotTagsDispatch.on('RiotSolrFlagUpdate', fcu); 654 655 self.one('update', function() { 656 self.RiotSolrFlagCount = self.RiotSolrFlagStore.get().length; 657 }); 658 659 self.one('updated', function() { 660 self.root.addEventListener('mouseenter', function() { 661 self.showItems = true; 662 fcu(); 663 }); 664 665 self.root.addEventListener('mouseleave', function() { 666 self.showItems = false;
667 self.update(); 668 }); 669 }); 670 671 self.on('unmount', function() { 672 RiotTagsDispatch.off('RiotSolrFlagUpdate', fcu); 673 }); 674 }, 675 676 RiotSolrFlagOpts: { 677 text: { 678 flag: 'Flag', 679 unflag: 'Unflag', 680 }, 681 classes: { 682 flag: 'rs-flag', 683 unflag: 'rs-unflag', 684 }, 685 namespace: 'riot_solr_flag_items', 686 store: 'RiotSolrCookieStore', 687 key: 'id', 688 }, 689 690 /** 691 * Override the default handler for RiotSolrFlag. Do everything the default handler does except triggering 692 * RiotSolrUpdate. Doing so would replace the search results data with data for favorites. 693 * 694 * @param response 695 * @constructor 696 */ 697 RiotSolrFlagHandler: function(response) { 698 var manager = this.RiotSolrManager, 699 p, 700 docids; 701 702 manager.response = response; 703 docids = response.response.docs.map(function(e) { 704 return e.id; 705 }); 706 707 response.getFullDocs = function() { 708 if (!p) { 709 p = manager.getDocuments(docids); 710 } 711 return p; 712 } 713 714 manager.widgets.map(function(widget) {
715 widget.afterRequest(); 716 }); 717 718 this.setRiotSolrItems(response.response.docs); 719 this.update(); 720 }, 721 722 RiotSolrFlagCounterUpdate: function() { 723 var ids = this.RiotSolrFlagStore.get(), 724 self = this, 725 string = 'rows=' + ids.length + '&fq=' + self.RiotSolrFlagOpts.key + ':(' + ids.join(' OR ') + ')'; 726 self.RiotSolrFlagCount = ids.length; 727 if (ids.length > 0) { 728 self.RiotSolrManager.executeRequest('select', string, this.RiotSolrFlagHandler); 729 } else { 730 self.setRiotSolrItems([]); 731 } 732 }, 733 734 RiotSolrFlagCounterViewPage: function() { 735 var path, ids, q; 736 737 if (!this.opts.flag_options.path) { 738 return; 739 } 740 741 ids = this.RiotSolrFlagStore.get(); 742 if (ids.length > 0) { 743 path = this.opts.flag_options.path; 744 q = this.RiotSolrFlagOpts.key + ':(' + ids.join(' OR ') + ')'; 745 window.location.href = path + '#q=' + q; 746 } 747 }, 748 }; 749 750 riot.mixin('RiotSolrFlagCounter', RiotSolrFlagCounter); 751 752 /** 753 * GLobal Objects 754 */ 755 756 RiotSolrCreateInstance = function(strClass) { 757 var args = Array.prototype.slice.call(arguments, 1); 758 return new window[strClass](args); 759 }; 760 761 RiotSolrCookieStore = function(namespace) { 762 // Private vars. 763 var _namespace = namespace, 764 _items = [], 765 cookie; 766 767 // Private update method. This is used to refresh the objects with cookie 768 // data so that collections on multiple open tabs will work properly. 769 var refresh = function() { 770 // Load cookie values. 771 cookie = $.cookie(_namespace); 772 // Populate items from cookie. 773 _items[_namespace] = cookie ? $.parseJSON(cookie) : []; 774 }; // Don't auto-execute so we lazy-load fetching cookie data. 775 776 // Private save method. 777 var save = function() { 778 $.cookie(_namespace, JSON.stringify(_items[_namespace]), { path: '/' }); 779 }; 780 781 // Public get methd. 782 this.get = function() { 783 refresh(); 784 return _items[_namespace]; 785 }; 786 787 // Public add method. 788 this.add = function(val) { 789 refresh(); 790 // Don't add duplicate items. 791 if (_items[_namespace].indexOf(val) === -1) { 792 _items[_namespace].push(val); 793 save(); 794 } 795 796 if (typeof ga4 !== 'undefined') { 797 ga4.event({ 798 event: 'add_' + _namespace, 799 value: val, 800 eventCategory: 'RiotSolr Flag', 801 eventAction: 'Add ' + _namespace, 802 eventLabel: val, 803 }); 804 } 805 806 if (typeof ga !== 'undefined') { 807 ga('send', { 808 hitType: 'event', 809 eventCategory: 'RiotSolr Flag', 810 eventAction: 'Add ' + _namespace, 811 eventLabel: val, 812 nonInteraction: 1, 813 }); 814 } else if (typeof _gaq !== 'undefined') { 815 _gaq.push(['_trackEvent', 'RiotSolr Flag', 'Add ' + _namespace, val, 0, true]); 816 } 817 }; 818 819 // Public remove method. 820 this.remove = function(val) { 821 refresh(); 822 // We can't use this.has() here because we need the index. 823 var index = _items[_namespace].indexOf(val); 824 825 if (index !== -1) { 826 _items[_namespace].splice(index, 1); 827 save(); 828 } 829 830 if (typeof ga4 !== 'undefined') { 831 ga4.event({ 832 event: 'remove_' + _namespace, 833 value: val, 834 eventCategory: 'RiotSolr Flag', 835 eventAction: 'Remove ' + _namespace, 836 eventLabel: val, 837 }); 838 } 839 840 if (typeof ga !== 'undefined') { 841 ga('send', { 842 hitType: 'event', 843 eventCategory: 'RiotSolr Flag', 844 eventAction: 'Remove ' + _namespace, 845 eventLabel: val, 846 nonInteraction: 1, 847 }); 848 } else if (typeof _gaq !== 'undefined') { 849 _gaq.push(['_trackEvent', 'RiotSolr Flag', 'Remove ' + _namespace, val, 0, true]); 850 } 851 }; 852 853 // Public reset method. 854 this.reset = function() { 855 _items[_namespace] = []; 856 save(); 857 }; 858 859 // Public lookup method. 860 this.has = function(val) { 861 refresh(); 862 // IE 8 and below do not have the Array.prototype.indexOf method. 863 return this.indexOf.call(_items[_namespace], val) !== -1; 864 }; 865 866 // Shim for IE8 and below not supporting indexOf natively. 867 // Public so others can use it. 868 this.indexOf = function(needle) { 869 var indexOf; 870 871 if (typeof Array.prototype.indexOf === 'function') { 872 indexOf = Array.prototype.indexOf; 873 } else { 874 indexOf = function(needle) { 875 var i = -1, 876 index = -1; 877 878 for (i = 0; i < this.length; i++) { 879 if (this[i] === needle) { 880 index = i; 881 break; 882 } 883 } 884 885 return index; 886 }; 887 } 888 889 return indexOf.call(this, needle); 890 }; 891 }; 892 893 RiotSolrItemSortHandlers = { 894 sortNumeric: { 895 primer: function(x) { 896 return parseFloat(x); 897 }, 898 callback: function(items, field, reverse) { 899 var self = this, 900 r = !reverse ? 1 : -1; 901 items.sort(function(a, b) { 902 return (a = self.primer(a[field])), (b = self.primer(b[field])), r * ((a > b) - (b > a)); 903 }); 904 return items; 905 }, 906 }, 907 908 sortLexicographic: { 909 primer: function(x) { 910 if (typeof x === 'string') { 911 return x.trim(); 912 } else if (Array.isArray(x)) { 913 return x[0].trim(); 914 } 915 }, 916 callback: function(items, field, reverse) { 917 var self = this; 918 items.sort(function(a, b) { 919 return (a = self.primer(a[field])), (b = self.primer(b[field])), a.toLowerCase().localeCompare(b); 920 }); 921 922 if (reverse) { 923 items.reverse(); 924 } 925 926 return items; 927 }, 928 }, 929 930 sortRandom: { 931 primer: function() { 932 var max = 9999, 933 min = 1; 934 return Math.floor(Math.random() * (max - min)) + min; 935 }, 936 callback: function(items, field, reverse) { 937 var self = this, 938 r = !reverse ? 1 : -1; 939 items.sort(function() { 940 return (a = self.primer()), (b = self.primer()), r * ((a > b) - (b > a)); 941 }); 942 return items; 943 }, 944 }, 945 }; 946 947 /** 948 * Author: Jason Farrell 949 * Author URI: http://useallfive.com/ 950 * 951 * Description: Checks if a DOM element is truly visible. 952 * Package URL: https://github.com/UseAllFive/true-visibility 953 */ 954 Element.prototype.isVisible = function() { 955 'use strict'; 956 /** 957 * Checks if a DOM element is visible. Takes into 958 * consideration its parents and overflow. 959 * 960 * @param (el) the DOM element to check if is visible 961 * 962 * These params are optional that are sent in recursively, 963 * you typically won't use these: 964 * 965 * @param (t) Top corner position number 966 * @param (r) Right corner position number 967 * @param (b) Bottom corner position number 968 * @param (l) Left corner position number 969 * @param (w) Element width number 970 * @param (h) Element height number 971 */ 972 function _isVisible(el, t, r, b, l, w, h) { 973 var p = el.parentNode, 974 VISIBLE_PADDING = 2; 975 976 if (!_elementInViewport(el)) { 977 return false;
978 } 979 980 if (!_elementInDocument(el)) { 981 return false; 982 } 983 984 //-- Return true for document node 985 if (9 === p.nodeType) { 986 return true; 987 } 988 989 //-- Return false if our element is invisible 990 if ( 991 '0' === _getStyle(el, 'opacity') || 992 'none' === _getStyle(el, 'display') || 993 'hidden' === _getStyle(el, 'visibility') 994 ) { 995 return false; 996 } 997 998 if ( 999 'undefined' === typeof t || 1000 'undefined' === typeof r || 1001 'undefined' === typeof b || 1002 'undefined' === typeof l || 1003 'undefined' === typeof w || 1004 'undefined' === typeof h 1005 ) { 1006 t = el.offsetTop; 1007 l = el.offsetLeft; 1008 b = t + el.offsetHeight; 1009 r = l + el.offsetWidth; 1010 w = el.offsetWidth; 1011 h = el.offsetHeight; 1012 } 1013 //-- If we have a parent, let's continue: 1014 if (p) { 1015 //-- Check if the parent can hide its children. 1016 if ( 1017 'hidden' === _getStyle(p, 'overflow') || 1018 'scroll' === _getStyle(p, 'overflow') || 1019 'hidden' === _getStyle(p, 'overflow-y') || 1020 'scroll' === _getStyle(p, 'overflow-y') 1021 ) { 1022 //-- Only check if the offset is different for the parent 1023 if ( 1024 //-- If the target element is to the right of the parent elm 1025 l + VISIBLE_PADDING > p.offsetWidth + p.scrollLeft || 1026 //-- If the target element is to the left of the parent elm 1027 l + w - VISIBLE_PADDING < p.scrollLeft || 1028 //-- If the target element is under the parent elm 1029 t + VISIBLE_PADDING > p.offsetHeight + p.scrollTop || 1030 //-- If the target element is above the parent elm 1031 t + h - VISIBLE_PADDING < p.scrollTop 1032 ) { 1033 //-- Our target element is out of bounds: 1034 return false; 1035 } 1036 } 1037 //-- Add the offset parent's left/top coords to our element's offset: 1038 if (el.offsetParent === p) { 1039 l += p.offsetLeft; 1040 t += p.offsetTop; 1041 } 1042 //-- Let's recursively check upwards: 1043 return _isVisible(p, t, r, b, l, w, h); 1044 } 1045 return true; 1046 } 1047 1048 //-- Cross browser method to get style properties: 1049 function _getStyle(el, property) { 1050 if (window.getComputedStyle) { 1051 return document.defaultView.getComputedStyle(el, null)[property]; 1052 } 1053 if (el.currentStyle) { 1054 return el.currentStyle[property]; 1055 } 1056 } 1057 1058 function _elementInDocument(element) { 1059 while ((element = element.parentNode)) { 1060 if (element == document) { 1061 return true; 1062 } 1063 } 1064 return false; 1065 } 1066 1067 function _elementInViewport(element) { 1068 var VISIBLE_PADDING = 2; 1069 1070 var br = element.getBoundingClientRect(); 1071 var ret = 1072 br.top - VISIBLE_PADDING <= (window.innerHeight || document.documentElement.clientHeight) && 1073 br.bottom >= 0 - VISIBLE_PADDING && 1074 br.left - VISIBLE_PADDING <= (window.innerWidth || document.documentElement.clientWidth) && 1075 br.right >= 0 - VISIBLE_PADDING; 1076 return ret; 1077 } 1078 1079 return _isVisible(this); 1080 }; 1081 1082 /** 1083 * A utilities helper object. 1084 * 1085 * Purposefully namespaced to prevent collisions. 1086 */ 1087 var RiotSolrUtils = { 1088 RiotSolrUtils: { 1089 debounce: function (func, wait, immediate) { 1090 var timeout; 1091 return function() { 1092 var context = this, args = arguments; 1093 clearTimeout(timeout); 1094 timeout = setTimeout(function() { 1095 timeout = null; 1096 if (!immediate) func.apply(context, args); 1097 }, wait); 1098 if (immediate && !timeout) func.apply(context, args); 1099 }; 1100 } 1101 } 1102 } 1103 1104 riot.mixin('RiotSolrUtils', RiotSolrUtils); 1105 1106})(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.