(function($) { var history; Drupal.search_api_ajax = {}; if (Drupal.settings.search_api_ajax) { var blocks = Drupal.settings.search_api_ajax.blocks; var content = Drupal.settings.search_api_ajax.content; var regions = Drupal.settings.search_api_ajax.regions; var spinner = Drupal.settings.search_api_ajax.spinner; var target = Drupal.settings.search_api_ajax.scrolltarget; var fade = Drupal.settings.search_api_ajax.fade; var opacity = Drupal.settings.search_api_ajax.opacity; var speed = Drupal.settings.search_api_ajax.scrollspeed; // notice the "search_api_ajax_path" instead of // "search_api_ajax.path" for magic reasons var ajaxPath = Drupal.settings.search_api_ajax_path; var qPath = Drupal.settings.search_api_ajax_qpath; var isView = Drupal.settings.search_api_ajax.view; // initialize listeners Drupal.search_api_ajax.initialize = function() { if (content) { Drupal.search_api_ajax.ajax(content); } if (blocks) { for (var block in blocks) { Drupal.search_api_ajax.ajax(blocks[block]); } } }; // extract url for ajax history Drupal.search_api_ajax.url_to_state = function(url) { var state = ''; if (isView) { var query = Drupal.search_api_ajax.get_url_state(url)["query"]; } state = url.replace(new RegExp('^.*' + Drupal.settings.basePath + ajaxPath + '/' + '?'), ''); if (query) { state = query + state.replace('?query=' + query, ''); } else { state = state.replace('?query=', ''); state = state.replace('?', '&'); } return state; }; Drupal.search_api_ajax.get_url_state = function(url) { var vars = [], hash; var hashes = url.slice(url.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { hash = hashes[i].split('='); vars.push(hash[0]); vars[hash[0]] = hash[1]; } return vars; } // prepare and perform ajax search request Drupal.search_api_ajax.request_callback = function(state) { if (content) { if (fade) { $(content + ':first').fadeTo('fast', opacity); } if (spinner) { $('#content').append('
') } } // Scroll back to top, when top is out of view. Inspired by views module. if (target) { var offset = $(target).offset(); var scrollTarget = target; while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) { scrollTarget = $(scrollTarget).parent() } if (offset.top - 10 < $(scrollTarget).scrollTop()) { $(scrollTarget).animate({ scrollTop: (offset.top - 10) }, speed); } } // post ajax, read json var keysPath = '/' + state; if (isView) { keysPath = '?query=' + state; } $.post(Drupal.settings.basePath + 'search_api_ajax/' + ajaxPath + keysPath, { js: 1 }, Drupal.search_api_ajax.response_callback, 'json'); }; // update search page with ajax, based on the json we read Drupal.search_api_ajax.response_callback = function(data) { if (content) { if (fade) { $(content + ':first').fadeTo('fast', 1); } if (spinner) { $('#search-api-ajax-spinner').remove(); } } for (var setting in data.settings) { Drupal.settings[setting] = data.settings[setting]; } var list = []; // we have to add the new blocks, that have come into existence // @see search_api_ajax.pages.inc where we add this blocks variable if (data.blocks) { for (var new_block in data.blocks) { blocks[new_block] = data.blocks[new_block]; } } // schedule items for removal to reduce page jumpiness. if (blocks) { for (var block in blocks) { list.push($(blocks[block])); } for (var i = 0, l = list.length; i < l; i++) { list[i].remove(); } } for (var region in data.regions) { if (region == 'search_api_ajax') { if (content) { $(content + ':first').html(data.regions[region]); } } else { for (var block in data.regions[region]) { if (regions[region] && blocks[block]) { $(regions[region]).append(data.regions[region][block]); } } } } // re-attach Drupal behaviors for whole document Drupal.attachBehaviors('body'); }; Drupal.search_api_ajax.navigate = function(url) { if (url !== undefined) { YUI().use('history', function(Y) { history.add({ q: Drupal.search_api_ajax.url_to_state(url) }); }); } return false; }; Drupal.search_api_ajax.ajax = function(selector) { // observe regular facet and sorts links ^ starts with * contains // check two paths: ^basePath/ajaxPath OR ^search_api_ajax/basePath/ajaxPath // @see http://api.jquery.com/category/selectors/attribute-selectors/ // Create an array of selectors for readability. var selectors = [selector + ' a[href^="' + Drupal.settings.basePath + ajaxPath + '"]', selector + ' a[href^="' + Drupal.settings.basePath + 'search_api_ajax/' + ajaxPath + '"]']; $(selectors.join(', ')).livequery('click', function() { return Drupal.search_api_ajax.navigate($(this).attr('href')); }); // Add support for facetapi checkboxes widget. // Unbind facetapi click event. $(selector + ' .facetapi-checkbox').unbind('click'); $(selector + ' .facetapi-checkbox').livequery('click', function() { return Drupal.search_api_ajax.navigate($(this).next('a').attr('href')); }) // observe search keys forms (or views input forms, must be custom set) $(selector + ' form[action^="' + Drupal.settings.basePath + ajaxPath + '"], ' + selector + ' form[action^="' + Drupal.settings.basePath + 'search_api_ajax/' + ajaxPath + '"]').livequery('submit', function() { return Drupal.search_api_ajax.navigate($(this).find('input[name*="keys"]').val()); }); // observe facet range sliders $(selector + ' .search-api-ranges-widget form[action^="' + Drupal.settings.basePath + ajaxPath + '"], ' + selector + ' .search-api-ranges-widget form[action^="' + Drupal.settings.basePath + 'search_api_ajax/' + ajaxPath + '"]').livequery('submit', function() { var separator = '?'; if ($(this).find('input[name="range-ajax-target"]').val().indexOf("?") !== -1) { separator = '&'; } // add a filter in the form of &f[n]=field_name:[A B] // instead of actually knowing what "n" is, we just f[] // @todo Facet API can have different 'f', how to know which? var addFilter = 'f[]=' + $(this).find('input[name="range-field"]').val() + ':' + '[' + $(this).find('input[name="range-from"]').val() + ' TO ' + $(this).find('input[name="range-to"]').val() + ']'; return Drupal.search_api_ajax.navigate($(this).find('input[name="range-ajax-target"]').val() + separator + addFilter); }); }; } // we initiate YUI3's History extension YUI().use('history', function(Y) { // initialize history = new Y.HistoryHash(); if (history.get('q')) { Drupal.search_api_ajax.request_callback(history.get('q')); } // listen to changes // @todo when going from /page#q= to /page it should also trigger Y.on('history:change', function(e) { var changed = e.changed; if (changed.q) { Drupal.search_api_ajax.request_callback(history.get('q')); } }); }); Drupal.behaviors.search_api_ajax = { attach: function(context, settings) { // initialize livequery() event only if there is an active search // only needed for search api pages, not for views paths if (Drupal.search_api_ajax.url_to_state(window.location.href) != '' || isView === 1) { Drupal.search_api_ajax.initialize(); } } }; })(jQuery);