1(function ($) { 2 3 /** 4 * Class containing functionality for Facet API. 5 */ 6 Drupal.ajax_facets = {}; 7 // Store current query value. 8 Drupal.ajax_facets.queryState = null; 9 // State of each facet. 10 Drupal.ajax_facets.facetQueryState = null; 11 // Determine if it is first page load. Will be reset in Drupal.ajax_facets.initHistoryState. 12 Drupal.ajax_facets.firstLoad = true; 13 // Settings of each ajax facet. 14 Drupal.ajax_facets.facetsSettings = {}; 15 // Buttons for ajax facets. 16 Drupal.ajax_facets.ajax_facets_buttons = false; 17 // Force update of the results 18 Drupal.ajax_facets.force_update_results = false; 19 // Tooltip timeout handler. 20 Drupal.ajax_facets.tooltipTimeout; 21 // Name of the facet which was clicked. 22 Drupal.ajax_facets.current_facet_name = undefined; 23 24 // You can use it for freeze facet form elements while ajax is processing. 25 Drupal.ajax_facets.beforeAjaxCallbacks = {}; 26 27 // You can use it to make actions after the ajax has updated the content. 28 Drupal.ajax_facets.afterContentUpdateCallbacks = {}; 29 30 Drupal.ajax_facets.beforeAjax = function () { 31 $.each(Drupal.ajax_facets.beforeAjaxCallbacks, function () { 32 if ($.isFunction(this)) { 33 this(); 34 } 35 }); 36 }; 37 38 Drupal.ajax_facets.afterContentUpdate = function (ajax, response) { 39 Drupal.ajax_facets.force_update_results = false; 40 $.each(Drupal.ajax_facets.afterContentUpdateCallbacks, function () { 41 if ($.isFunction(this)) { 42 this(ajax, response); 43 } 44 }); 45 $(".block-facetapi select").chosen(); 46 }; 47 48 Drupal.behaviors.ajax_facets = { 49 attach: function (context, settings) { 50 if (!Drupal.ajax_facets.queryState) { 51 // Add property for views and set data about facet values. 52 Drupal.ajax_facets.queryState = { 53 'views': new Array(), 54 'f': settings.facetapi.defaultQuery ? settings.facetapi.defaultQuery : [] 55 }; 56 57 // We will send original search path to server to get back proper reset links. 58 if (settings.facetapi.searchPath) { 59 Drupal.ajax_facets.queryState['searchPath'] = settings.facetapi.searchPath; 60 } 61 if (settings.facetapi.index_id) { 62 Drupal.ajax_facets.queryState['index_id'] = settings.facetapi.index_id; 63 } 64 // Check view name and display name for all views. 65 if (settings.facetapi.views) { 66 $.each(settings.facetapi.views, function(key, view) { 67 Drupal.ajax_facets.queryState['views'][key] = {}; 68 // Get view dom id. 69 var viewDomId = Drupal.ajax_facets.getViewDomId(settings, key); 70 if (viewDomId) { 71 // Take settings from view if it works by AJAX. 72 if (Drupal.views && Drupal.views.instances['views_dom_id:' + viewDomId]) { 73 $.extend(Drupal.ajax_facets.queryState['views'][key], Drupal.views.instances['views_dom_id:' + viewDomId].settings); 74 } 75 // If this view doesn't use ajax. 76 else { 77 Drupal.ajax_facets.queryState['views'][key] = { 78 'view_dom_id': viewDomId, 79 'view_name': view.view_name, 80 'view_display_id': view.view_display_id 81 }; 82 // Respect view arguments. 83 var nameDisplay = view.view_name + ':' + view.view_display_id; 84 if (settings.facetapi.view_args[nameDisplay]) { 85 Drupal.ajax_facets.queryState['views'][key]['view_args'] = settings.facetapi.view_args[nameDisplay]; 86 } 87 // Respect view path. 88 //alert(Drupal.ajax_facets.queryState['views'][key]['view_path']); 89 if (settings.facetapi.view_path[nameDisplay]) { 90 Drupal.ajax_facets.queryState['views'][key]['view_path'] = settings.facetapi.view_path[nameDisplay]; 91 } 92 } 93 } 94 95 // Respect arguments in exposed form. 96 if (view.view_name && view.view_display_id) { 97 var nameDisplay = view.view_name + ':' + view.view_display_id; 98 if (settings.facetapi.exposed_input[nameDisplay]) { 99 $.extend(Drupal.ajax_facets.queryState, settings.facetapi.exposed_input[nameDisplay]); 100 } 101 } 102 }); 103 } 104 105 if (settings.facetapi.facet_field) { 106 Drupal.ajax_facets.queryState['facet_field'] = settings.facetapi.facet_field; 107 } 108 } 109 110 // Iterates over facet settings, applies functionality like the "Show more" 111 // links for block realm facets. 112 // @todo We need some sort of JS API so we don't have to make decisions 113 // based on the realm. 114 if (settings.facetapi) { 115 for (var index in settings.facetapi.facets) { 116 Drupal.ajax_facets.bindResetLink(settings.facetapi.facets[index].id, index, settings); 117 118 // Checkboxes. 119 if (settings.facetapi.facets[index].widget == 'facetapi_ajax_checkboxes') { 120 $('#' + settings.facetapi.facets[index].id + '-wrapper input.facet-multiselect-checkbox:not(.processed)').change( 121 [settings.facetapi.facets[index]], 122 Drupal.ajax_facets.processCheckboxes 123 ).addClass('processed'); 124 } 125 126 // Selectboxes. 127 if (settings.facetapi.facets[index].widget == 'facetapi_ajax_select') { 128 $('#' + settings.facetapi.facets[index].id + '-wrapper select:not(.processed)').each(function () { 129 $(this).change( 130 [settings.facetapi.facets[index]], 131 Drupal.ajax_facets.processSelectbox 132 ).addClass('processed'); 133 }); 134 } 135 136 // Links. 137 if (settings.facetapi.facets[index].widget == 'facetapi_ajax_links') { 138 $('#' + settings.facetapi.facets[index].id + '-wrapper a:not(.processed)').each(function () { 139 $(this).click( 140 [settings.facetapi.facets[index]], 141 Drupal.ajax_facets.processLink 142 ).addClass('processed'); 143 }); 144 } 145 146 // Ranges. 147 if (settings.facetapi.facets[index].widget == 'facetapi_ajax_ranges') { 148 $('#' + settings.facetapi.facets[index].id + '-wrapper div.slider-wrapper:not(.processed)').each(function () { 149 var $sliderWrapper = $(this); 150 var $sliderWrapperParent = $sliderWrapper.parent(); 151 var $sliderMinInput = $sliderWrapperParent.find('.ajax-facets-slider-amount-min'); 152 var $sliderMaxInput = $sliderWrapperParent.find('.ajax-facets-slider-amount-max'); 153 $sliderWrapper.slider({ 154 range: true, 155 min: parseFloat($sliderWrapper.data('min')), 156 max: parseFloat($sliderWrapper.data('max')), 157 values: [ parseFloat($sliderWrapper.data('min-val')), parseFloat($sliderWrapper.data('max-val')) ], 158 stop: function( event, ui ) { 159 Drupal.ajax_facets.processSlider($sliderWrapper, ui.values[0], ui.values[1]); 160 }, 161 slide: function ( event, ui ) { 162 $sliderMinInput.val(ui.values[0]); 163 $sliderMaxInput.val(ui.values[1]); 164 }, 165 }).addClass('processed'); 166 167 // Bind input fields. 168 //var $sliderWrapperParent = $sliderWrapper.parent(); 169 // Auto update facets timeout (after input changed but not blurred) 170 var inputAutoUpdateTimeout; 171 var inputRangeHandler = function(e){ 172 clearTimeout(inputAutoUpdateTimeout); 173 // Validate numbers on keypress 174 // @thnx http://stackoverflow.com/questions/995183/how-to-allow-only-numeric-0-9-in-html-inputbox-using-jquery 175 // Allow: backspace, delete, tab, escape, enter and . 176 if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 || 177 // Allow: Ctrl+A, Command+A 178 (e.keyCode == 65 && ( e.ctrlKey === true || e.metaKey === true ) ) || 179 // Allow: home, end, left, right, down, up 180 (e.keyCode >= 35 && e.keyCode <= 40)) { 181 // let it happen, don't do anything 182 } 183 // Ensure that it is a number and stop the keypress 184 else if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { 185 e.preventDefault(); 186 return; 187 } 188 189 // Trigger 'change' event in 1 sec after keypress 190 var $input = $(this); 191 inputAutoUpdateTimeout = setTimeout(function(){$input.trigger('change');}, 1000); 192 }; 193 194 $sliderWrapperParent.find("input[type='text']").each(function() { 195 $(this) 196 .keydown(inputRangeHandler) 197 .keyup(inputRangeHandler) 198 .change(function() { 199 var min = parseFloat($sliderMinInput.val()); 200 var max = parseFloat($sliderMaxInput.val()); 201 // If values are numeric and min less than max. 202 if (isFinite(min) && isFinite(max) && min < max) { 203 $sliderWrapper.slider('values', 0, min); 204 $sliderWrapper.slider('values', 1, max); 205 Drupal.ajax_facets.processSlider($sliderWrapper, min, max); 206 } 207 }); 208 }); 209 210 }); 211 } 212 213 if (null != settings.facetapi.facets[index].limit) { 214 // Applies soft limit to the list. 215 if (Drupal.facetapi) { 216 Drupal.facetapi.applyLimit(settings.facetapi.facets[index]); 217 } 218 } 219 220 // Save settings for each facet by name. 221 Drupal.ajax_facets.facetsSettings[settings.facetapi.facets[index].facetName] = settings.facetapi.facets[index]; 222 } 223 } 224 225 // Hide blocks with ajax-facets-empty-behavior. 226 //$('.ajax-facets-empty-behavior').parents('.block--ajax_facets').hide(); 227 228 if ($('.ajax-facets-empty-behavio').find('select').length) { 229 $('.ajax-facets-empty-behavior').parents('.block--ajax_facets').hide(); 230 } 231 232 233 //alert('1'); 234 235 // Add facets tooltip. 236 $('body').once(function () { 237 $(this).append('<div id="ajax-facets-tooltip"><span></span></div>'); 238 }); 239 } 240 }; 241 242 Drupal.behaviors.ajax_facets_block = { 243 attach: function (context, settings) { 244 // Reset all link. 245 $('.ajax-facets-reset-all-link:not(.processed)').bind('click', function (e) { 246 e.preventDefault(); 247 248 // Clear all facets from queryState facets array. 249 Drupal.ajax_facets.queryState.f = []; 250 251 // Send ajax query with first found facet. 252 Drupal.ajax_facets.force_update_results = true; 253 Drupal.ajax_facets.sendAjaxQuery({ 254 pushStateNeeded: true, 255 searchResultsNeeded: true 256 }); 257 }).addClass('processed'); 258 259 var $submitLink = $('.ajax-facets-submit-all-link:not(.processed)'); 260 if ($submitLink.length) { 261 // Submit link found. 262 Drupal.ajax_facets.ajax_facets_buttons = true; 263 // Submit all link. 264 $submitLink.bind('click', function (e) { 265 e.preventDefault(); 266 // Send ajax query with first found facet. 267 Drupal.ajax_facets.force_update_results = true; 268 Drupal.ajax_facets.sendAjaxQuery({ 269 pushStateNeeded: true, 270 searchResultsNeeded: true 271 }); 272 }).addClass('processed'); 273 } 274 } 275 }; 276 277 278 Drupal.ajax_facets.bindResetLink = function (facetWrapperId, index, settings) { 279 var facet_values = Drupal.ajax_facets.getFacetValues(); 280 var $facetWrapper = $('#' + facetWrapperId + '-wrapper'); 281 if (facet_values[settings.facetapi.facets[index]['facetName']]) { 282 $facetWrapper.find('a.reset-link').show(); 283 } else { 284 $facetWrapper.find('a.reset-link').hide(); 285 } 286 287 $facetWrapper.find('a.reset-link:not(".processed")').addClass('processed').click(function (event) { 288 var $facet = $(this).parent().find('[data-facet-name]').first(); 289 var facetName = $facet.data('facet-name'); 290 Drupal.ajax_facets.excludeCurrentFacet(facetName); 291 Drupal.ajax_facets.sendAjaxQuery({ 292 pushStateNeeded: true, 293 searchResultsNeeded: true 294 }); 295 event.preventDefault(); 296 }); 297 }; 298 299 /** 300 * Callback for onClick event for widget selectbox. 301 */ 302 Drupal.ajax_facets.processSelectbox = function (event) { 303 var $this = $(this), 304 facetName = $this.data('facet-name'); 305 // Init history. 306 Drupal.ajax_facets.initHistoryState($this); 307 // If facets are already defined in queryState. 308 if (Drupal.ajax_facets.queryState['f']) { 309 // Exclude all values for this facet from query. 310 Drupal.ajax_facets.excludeCurrentFacet(facetName); 311 312 /* Default value. */ 313 if ($this.find(":selected").val() == '_none') { 314 delete Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length]; 315 } else { 316 Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length] = facetName + ':' + $this.find(":selected").val(); 317 } 318 } 319 320 Drupal.ajax_facets.sendAjaxQuery({ 321 pushStateNeeded: !Drupal.ajax_facets.ajax_facets_buttons, 322 searchResultsNeeded: !Drupal.ajax_facets.ajax_facets_buttons 323 }, $this); 324 }; 325 326 /** 327 * Callback for onClick event for widget checkboxes. 328 */ 329 Drupal.ajax_facets.processCheckboxes = function (event) { 330 var $this = $(this), 331 facetName = $this.data('facet-name'), 332 name_value = facetName + ':' + $this.attr('data-facet-value'),// $.data can round decimal values like 4.0 to 4, avoid it. 333 rawFacetName = $this.data('raw-facet-name'); 334 // Init history. 335 Drupal.ajax_facets.initHistoryState($this); 336 // If facets are already defined in queryState. 337 if (Drupal.ajax_facets.queryState['f']) { 338 var queryNew = []; 339 if ($this.is(':checked')) { 340 var addCurrentParam = true; 341 for (var index in Drupal.ajax_facets.queryState['f']) { 342 if (Drupal.ajax_facets.queryState['f'].hasOwnProperty(index)) { 343 // If we already have this value in queryState. 344 if (Drupal.ajax_facets.queryState['f'][index] == name_value) { 345 addCurrentParam = false;
346 } 347 } 348 } 349 // Add new value if need. 350 if (addCurrentParam) { 351 // Exclude all other values of this facet from query. 352 if (Drupal.ajax_facets.facetsSettings[rawFacetName].limit_active_items) { 353 Drupal.ajax_facets.excludeCurrentFacet(facetName); 354 } 355 Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length] = name_value; 356 } 357 } 358 // If we unset filter, remove it from query. 359 else { 360 for (var index in Drupal.ajax_facets.queryState['f']) { 361 if (Drupal.ajax_facets.queryState['f'].hasOwnProperty(index)) { 362 if (Drupal.ajax_facets.queryState['f'][index] != name_value) { 363 queryNew[queryNew.length] = Drupal.ajax_facets.queryState['f'][index]; 364 } 365 } 366 } 367 Drupal.ajax_facets.queryState['f'] = queryNew; 368 } 369 } 370 371 Drupal.ajax_facets.sendAjaxQuery({ 372 pushStateNeeded: !Drupal.ajax_facets.ajax_facets_buttons, 373 searchResultsNeeded: !Drupal.ajax_facets.ajax_facets_buttons 374 }, $this); 375 }; 376 377 /** 378 * Callback for onClick event for widget links. 379 */ 380 Drupal.ajax_facets.processLink = function (event) { 381 var $this = $(this), 382 facetName = $this.data('facet-name'), 383 name_value = facetName + ':' + $this.attr('data-facet-value'),// $.data can round decimal values like 4.0 to 4, avoid it. 384 rawFacetName = $this.data('raw-facet-name'); 385 // Init history. 386 Drupal.ajax_facets.initHistoryState($this); 387 // If facets are already defined in queryState. 388 if (Drupal.ajax_facets.queryState['f']) { 389 var queryNew = []; 390 /* Handle value - deactivate. */ 391 if ($this.hasClass('facetapi-active')) { 392 for (var index in Drupal.ajax_facets.queryState['f']) { 393 if (Drupal.ajax_facets.queryState['f'].hasOwnProperty(index)) { 394 if (Drupal.ajax_facets.queryState['f'][index] !== name_value) { 395 queryNew[queryNew.length] = Drupal.ajax_facets.queryState['f'][index]; 396 } 397 } 398 } 399 Drupal.ajax_facets.queryState['f'] = queryNew; 400 } 401 /* Handle value - activate. */ 402 else if ($this.hasClass('facetapi-inactive')) { 403 var addCurrentParam = true; 404 for (var index in Drupal.ajax_facets.queryState['f']) { 405 if (Drupal.ajax_facets.queryState['f'].hasOwnProperty(index)) { 406 if (Drupal.ajax_facets.queryState['f'][index] === name_value) { 407 addCurrentParam = false; 408 } 409 } 410 } 411 if (addCurrentParam) { 412 // Exclude all other values of this facet from query. 413 if (Drupal.ajax_facets.facetsSettings[rawFacetName].limit_active_items) { 414 Drupal.ajax_facets.excludeCurrentFacet(facetName); 415 } 416 Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length] = name_value; 417 } 418 } 419 } 420 421 Drupal.ajax_facets.sendAjaxQuery({ 422 pushStateNeeded: !Drupal.ajax_facets.ajax_facets_buttons, 423 searchResultsNeeded: !Drupal.ajax_facets.ajax_facets_buttons 424 }, $this); 425 event.preventDefault(); 426 }; 427 428 /** 429 * Callback for slide event for widget ranges. 430 */ 431 Drupal.ajax_facets.processSlider = function($sliderWrapper, min, max) { 432 var $this = $(this), 433 facetName = $sliderWrapper.data('facet-name'); 434 // Init history. 435 //var $facet = $sliderWrapper.parent(); 436 //$facet.find('.ajax-facets-slider-amount-min').val(min); 437 //$facet.find('.ajax-facets-slider-amount-max').val(max); 438 439 Drupal.ajax_facets.initHistoryState($sliderWrapper); 440 // If facets are already defined in queryState. 441 if (Drupal.ajax_facets.queryState['f']) { 442 // Exclude all values for this facet from query. 443 Drupal.ajax_facets.excludeCurrentFacet(facetName); 444 Drupal.ajax_facets.queryState['f'][Drupal.ajax_facets.queryState['f'].length] = facetName + ':[' + min + ' TO ' + max + ']'; 445 } 446 447 Drupal.ajax_facets.sendAjaxQuery({ 448 pushStateNeeded: !Drupal.ajax_facets.ajax_facets_buttons, 449 searchResultsNeeded: !Drupal.ajax_facets.ajax_facets_buttons 450 }, $this); 451 }; 452 453 /** 454 * Exclude all values for this facet from query. 455 */ 456 Drupal.ajax_facets.excludeCurrentFacet = function (facetName) { 457 facetName = facetName + ':'; 458 var queryNew = []; 459 for (var index in Drupal.ajax_facets.queryState['f']) { 460 if (Drupal.ajax_facets.queryState['f'].hasOwnProperty(index)) { 461 if (Drupal.ajax_facets.queryState['f'][index].substring(0, facetName.length) != facetName) { 462 queryNew[queryNew.length] = Drupal.ajax_facets.queryState['f'][index]; 463 } 464 } 465 } 466 Drupal.ajax_facets.queryState['f'] = queryNew; 467 }; 468 469 /** 470 * Send ajax. 471 */ 472 Drupal.ajax_facets.sendAjaxQuery = function (options, $facet) { 473 Drupal.ajax_facets.beforeAjax(); 474 var data = Drupal.ajax_facets.queryState; 475 // Render the exposed filter data to send along with the aja
475x request 476 $.each(Drupal.ajax_facets.queryState.views, function (key, view) { 477 var exposedFormId = '#views-exposed-form-' + view.view_name + '-' + view.view_display_id; 478 exposedFormId = exposedFormId.replace(/\_/g, '-'); 479 $.each($(exposedFormId).serializeArray(), function (index, value) { 480 data[value.name] = value.value; 481 }); 482 }); 483 484 // Set or reset current facet. 485 Drupal.ajax_facets.current_facet_name = $facet ? $facet.data('raw-facet-name') : undefined; 486 487 // Do not auto update facets and counts if auto update is turned off in block settings. 488 if (!Drupal.settings.ajax_facets.auto_update_facets && !options.searchResultsNeeded && !options.pushStateNeeded) { 489 return; 490 } 491 492 // Notify Drupal do we need search results or not. 493 data.searchResultsNeeded = options.searchResultsNeeded; 494 495 var settings = { 496 url: encodeURI(Drupal.settings.basePath + Drupal.settings.pathPrefix + 'ajax/ajax_facets/refresh'), 497 submit: {'ajax_facets': data} 498 }; 499 var ajax = new Drupal.ajax(false, false, settings); 500 ajax.success = function (response, status) { 501 // Push new state only on successful ajax response. 502 if (options.pushStateNeeded) { 503 Drupal.ajax_facets.writeState(false); 504 } 505 // Pass back to original method. 506 Drupal.ajax.prototype.success.call(this, response, status); 507 }; 508 ajax.eventResponse(ajax, {}); 509 }; 510 511 Drupal.ajax_facets.getFacetValues = function () { 512 var f = Drupal.ajax_facets.queryState.f; 513 var facets_values = {}; 514 var symbol = ':'; 515 jQuery.each(f, function (k, v) { 516 var parts = v.split(symbol); 517 var value = parts[parts.length - 1]; 518 var appendix = symbol + value; 519 var key = decodeURIComponent(v.substr(0, v.length - appendix.length)); 520 facets_values[key] = value; 521 }); 522 return facets_values; 523 }; 524 525 /* Get view dom id for both modes of views - ajax/not ajax. */ 526 Drupal.ajax_facets.getViewDomId = function(settings, key) { 527 // We use facetapi_view_display_id to find data in settings settings.facetapi.view_dom_id, 528 // because it can has there values like view_dom_id + numeric suffix 529 // if the same views display used several times on the page. 530 var nameDisplay = settings.facetapi.views[key].view_name + ':' + settings.facetapi.views[key].facetapi_view_display_id; 531 if (settings.facetapi.view_dom_id[nameDisplay]) { 532 var view = $('.view-dom-id-' + settings.facetapi.view_dom_id[nameDisplay]); 533 if (view.length > 0) { 534 return settings.facetapi.view_dom_id[nameDisplay] 535 } 536 } 537 return false; 538 }; 539 540 /** 541 * Returns query string with selected facets. 542 */ 543 Drupal.ajax_facets.getFacetsQueryUrl = function (baseUrl) { 544 var query = { 545 'f': [] 546 }; 547 548 // Clone variable. 549 $.extend(true, query.f, Drupal.ajax_facets.queryState.f); 550 551 // Facetapi module has a bug when facet name encodes twice. 552 // For example to get this facet work 'category:name:pineapple' it should be 'category%253Aname%3Apineapple'. 553 // It means that first ':' was encoded twice. Why we don't patch facetapi? Because a lot of sites have already 554 // used facetapi module and they links (with wrong encoded facets names) has been indexed by search engines 555 // like Bing or Google. So we just bring this behaviour to ajax_facets module. 556 // Encode each facet filter name (it have already encoded once in FacetapiAjaxWidgetCheckboxes::buildListItems()). 557 for (var filter in query.f) { 558 query.f[filter] = encodeURI(query.f[filter]); 559 } 560 561 562 if (Drupal.ajax_facets.queryState.query) { 563 query.query = Drupal.ajax_facets.queryState.query; 564 } 565 566 var skipAdditionalQueryParameters = true; 567 568 if (Drupal.ajax_facets.queryState.order) { 569 query.order = Drupal.ajax_facets.queryState.order; 570 query.sort = Drupal.ajax_facets.queryState.sort; 571 skipAdditionalQueryParameters = false; 572 } 573 574 if (Drupal.ajax_facets.queryState.pages) { 575 query.pages = Drupal.ajax_facets.queryState.pages; 576 } 577 578 // Respect existing query parameters in url. 579 // Merge respected parameters with facet parameters recursively without duplicates. 580 if (skipAdditionalQueryParameters) { 581 $.extend(true, query, Drupal.ajax_facets.simplifyObject(Drupal.ajax_facets.getAdditionalQueryParameters())); 582 } 583 584 // Add query string to base url. 585 if (!$.isEmptyObject(query)) { 586 // Clear empty items. 587 for (var item in query) { 588 if (typeof query[item] == 'undefined' || query[item].length == 0) { 589 delete query[item]; 590 } 591 } 592 var params = $.param(query); 593 // If we have params. 594 if (params.length) { 595 baseUrl += '?' + decodeURIComponent(params); 596 } 597 } 598 599 //console.log(baseUrl); 600 601 return baseUrl; 602 }; 603 604 /** 605 * Returns additional (not facet) query parameters from current url. 606 */ 607 Drupal.ajax_facets.getAdditionalQueryParameters = function () { 608 var result = {}; 609 610 // If we have GET params. 611 if (window.location.href.indexOf('?') !== -1) { 612 var respectedParameters = window.location.href.split('?')[1].split('&'); 613 614 // Get all query parameters in array.
615 for (var i = 0; i < respectedParameters.length; i++) { 616 var pair = respectedParameters[i].split('='); 617 618 // Remove brackets from multiple parameter. 619 pair[0] = pair[0].replace(/\[\d*\]/, ''); 620 621 // We interested only in additional parameters but not in facet parameters. 622 if (pair[0] !== 'f') { 623 if (!result[pair[0]]) { 624 result[pair[0]] = []; 625 result[pair[0]].push(pair[1]); 626 } else { 627 result[pair[0]].push(pair[1]); 628 } 629 } 630 } 631 } 632 633 return result; 634 }; 635 636 /** 637 * Returns simplified object. 638 * 639 * If object has array property with only one element then that array will be turn into simple value instead of array. 640 */ 641 Drupal.ajax_facets.simplifyObject = function (obj) { 642 for (var name in obj) { 643 if (obj[name].length === 1) { 644 obj[name] = obj[name][0]; 645 } 646 } 647 648 return obj; 649 }; 650 651 /** 652 * Initialize the history state. We only want to do this on the initial page 653 * load but we can't call it until after a facet has been clicked because we 654 * need to communicate which one is being "deactivated" for our ajax success 655 * handler. 656 */ 657 Drupal.ajax_facets.initHistoryState = function ($facet) { 658 // Set the initial state only initial page load. 659 if (Drupal.ajax_facets.firstLoad) { 660 Drupal.ajax_facets.firstLoad = false; 661 Drupal.ajax_facets.writeState(true); 662 } 663 }; 664 665 /** 666 * Writes new state to browser history, either as a push or replace call. 667 * 668 * History.js library fires "statechange" event even on API push/replace calls. 669 * So before pushing new state to history we should unbind from this event and after bind again. 670 * 671 * @param {boolean} replace Set to true to replace state, rather than push it. 672 */ 673 Drupal.ajax_facets.writeState = function (replace) { 674 var stateUrl = null, 675 state = { 676 facets: Drupal.ajax_facets.queryState['f'] 677 }, 678 title = document.title, 679 method = 'replaceState'; 680 681 682 if ($(body).hasClass('front')) { 683 return true; 684 } 685 686 687 if (replace !== true) { 688 stateUrl = Drupal.ajax_facets.getFacetsQueryUrl(Drupal.settings.facetapi.searchUrl); 689 method = 'pushState'; 690 } 691 692 //console.log(stateUrl); 693 694 // Try to use HTML5 history object. 695 if (history[method]) { 696 history[method](state, title, stateUrl); 697 } 698 else { 699 // If history.js available - use it. 700 if (Drupal.settings.facetapi.isHistoryJsExists) { 701 var $window = $(window); 702 703 $window.unbind('statechange', Drupal.ajax_facets.reactOnStateChange); 704 History[method](state, title, stateUrl); 705 $window.bind('statechange', Drupal.ajax_facets.reactOnStateChange); 706 } 707 } 708 }; 709 710 /** 711 * Callback for back/forward browser buttons. 712 */ 713 Drupal.ajax_facets.reactOnStateChange = function () { 714 var state = null, 715 facets = []; 716 717 // Try to use HTML5 history object. 718 if (history.pushState) { 719 if (state = history.state) { 720 facets = state.facets; 721 } 722 } 723 else { 724 // If history.js available - use it. 725 if (Drupal.settings.facetapi.isHistoryJsExists) { 726 if (state = History.getState()) { 727 facets = state.data.facets; 728 } 729 } 730 } 731 732 // Do something only if paths are match and facets is defined. 733 if (window.location.pathname === Drupal.settings.facetapi.searchUrl && facets) { 734 Drupal.ajax_facets.queryState['f'] = facets; 735 Drupal.ajax_facets.force_update_results = true; 736 Drupal.ajax_facets.sendAjaxQuery({ 737 pushStateNeeded: false, 738 searchResultsNeeded: true 739 }); 740 } 741 }; 742 743 // If user opened new page and then clicked browser's back button then would not be fired "statechange" event. 744 // So we need to bind on 'statechange' event and react only once. 745 // All farther work does Drupal.ajax_facets.pushState() function. 746 // Try to use HTML5 history object. 747 if (history) { 748 window.onpopstate = function () { 749 Drupal.ajax_facets.reactOnStateChange(); 750 }; 751 } else { 752 // If history.js Adapter available - use it to bind "statechange" event. 753 if (History.Adapter && Drupal.ajax_facets.firstLoad) { 754 History.Adapter.bind(window, 'statechange', Drupal.ajax_facets.reactOnStateChange); 755 } 756 } 757 758 /* Show tooltip if facet results are not updated by ajax (in settings). */ 759 Drupal.ajax_facets.showTooltip = function ($, response) { 760 // Reset the timeout handler to avoid troubles when user is clicking on items very fast. 761 window.clearTimeout(Drupal.ajax_facets.tooltipTimeout); 762 763 // If we have chosen facet. 764 if (Drupal.ajax_facets.current_facet_name) { 765 var pos = $('[data-raw-facet-name=' + Drupal.ajax_facets.current_facet_name + ']').offset(), 766 $tooltip = $('#ajax-facets-tooltip'); 767 $tooltip.css('top', pos.top - 15); 768 $tooltip.css('left', pos.left - $tooltip.width() - 40); 769 $tooltip.show(); 770 $tooltip.find('span').html(Drupal.t('Found:') + ' ' + response.total_results); 771 772 Drupal.ajax_facets.tooltipTimeout = setTimeout(function () { 773 $tooltip.hide(250); 774 }, 3000); 775 } 776 }; 777 778 if (Drupal.ajax) { 779 // Command for process search results and facets by ajax. 780 Drupal.ajax.prototype.commands.ajax_facets_update_content = function(ajax, response) { 781 if (response.data.activeItems) { 782 Drupal.ajax_facets.facetQueryState = response.data.activeItems; 783 } 784 // After Ajax success we should update reset, apply link to handle proper redirects. 785 if (response.data.resetUrls && Drupal.settings.facetapi.facets) { 786 for (var index in Drupal.settings.facetapi.facets) { 787 if (response.data.resetUrls[Drupal.settings.facetapi.facets[index].facetName]) { 788 // Update path from response. 789 Drupal.settings.facetapi.facets[index].resetPath = response.data.resetUrls[Drupal.settings.facetapi.facets[index].facetName]; 790 } 791 } 792 } 793 794 // Update content. 795 if (response.data.newContent) { 796 for (var id in response.data.newContent) { 797 var $blockToReplace = $('#' + id + '-wrapper'); 798 if ($blockToReplace.size()) { 799 $blockToReplace.replaceWith(response.data.newContent[id]); 800 } 801 var $block = $('#' + id + '-wrapper').parents('div.block--ajax_facets:not
801(:visible)'); 802 if ($block.size()) { 803 $block.show(); 804 } 805 } 806 } 807 808 /* Update results if we have they and ajax facets buttons are not enabled or force mode is enabled. */ 809 var show_tip = false; 810 var buttons_exist = Drupal.ajax_facets.ajax_facets_buttons, 811 force_update_results = Drupal.ajax_facets.force_update_results; 812 if (!buttons_exist || force_update_results) { 813 $.each(response.data.views, function (key, view) { 814 $('.view-dom-id-' + view.view_dom_id).replaceWith(view.content); 815 }); 816 817 // Update the exposed form separately if needed. 818 $.each(response.data.views, function(key, view) { 819 if (view.exposed_form) { 820 var viewId = view.view_name + '-' + view.view_display_id; 821 $('#views-exposed-form-' + viewId.replace(/_/g, '-')).replaceWith(view.exposed_form); 822 } 823 }); 824 } 825 else { 826 show_tip = true; 827 } 828 829 // As some blocks could be empty in results of filtering - hide them. 830 if (response.data.hideBlocks) { 831 for (var id in response.data.hideBlocks) { 832 if (response.data.hideBlocks.hasOwnProperty(id)) { 833 // Search for drupal blocks (id="block-facetapi-xcogxrrjodjldoogufmypf7sc4rpofuk"). 834 var $block = $('#' + response.data.hideBlocks[id]); 835 if ($block.size()) { 836 //$block.hide(); 837 // change select prop 838 if ($block.find('select').length) { 839 $block.find('select').prop('disabled',true).trigger('chosen:updated'); 840 } else { 841 $block.hide(); 842 } 843 } 844 // Search for panel panes (class="block-facetapi-xcogxrrjodjldoogufmypf7sc4rpofuk"). 845 else { 846 var $pane = $('.' + response.data.hideBlocks[id]); 847 if ($pane.size()) { 848 $pane.hide(); 849 } 850 } 851 } 852 } 853 } 854 855 if (response.data.settings.views) { 856 Drupal.settings.views = response.data.settings.views; 857 } 858 859 // We add this here so we can run custom code after content updates 860 Drupal.ajax_facets.afterContentUpdate(ajax, response); 861 862 Drupal.attachBehaviors(); 863 // Show the tooltip if need. 864 if (show_tip) { 865 Drupal.ajax_facets.showTooltip($, response.data); 866 } 867 }; 868 } 869})(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.