| 1 |
// $Id: quicksearch.js,v 1.5 2007/04/16 22:35:35 stevemckenzie Exp $
|
| 2 |
|
| 3 |
// Create an object for quicksearch data.
|
| 4 |
Drupal.quicksearch = { }
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Auto attach quicksearch features.
|
| 8 |
*/
|
| 9 |
Drupal.quicksearch.autoAttach = function() {
|
| 10 |
$('input.autocomplete').each(function () {
|
| 11 |
Drupal.quicksearch.input = $('#' + this.id.substr(0, this.id.length - 13)).attr('autocomplete', 'OFF')[0];
|
| 12 |
|
| 13 |
// Only add quicksearch functionality to quicksearch configured forms.
|
| 14 |
if (Drupal.quicksearch.form(Drupal.quicksearch.input.id)) {
|
| 15 |
// Add a label to display inside the textfield only if the textfield has no value.
|
| 16 |
$(Drupal.quicksearch.input).val(Drupal.settings.quicksearch.fieldLabel).bind('click', function() { if($(this).val() == Drupal.settings.quicksearch.fieldLabel) { $(this).val(''); } });
|
| 17 |
$(Drupal.quicksearch.input).val(Drupal.settings.quicksearch.fieldLabel).bind('blur', function() { if($(this).val() == '') { $(this).val(Drupal.settings.quicksearch.fieldLabel); } });
|
| 18 |
|
| 19 |
// Hide the search form's submit button.
|
| 20 |
$('input[@type=submit]||[@type=image]', Drupal.quicksearch.input.form).hide();
|
| 21 |
// Setup craqbox.
|
| 22 |
if (!Drupal.settings.quicksearch.selector) {
|
| 23 |
Drupal.quicksearch.craqbox = $.craqbox(Drupal.quicksearch.input, {
|
| 24 |
type: 'dom',
|
| 25 |
title: Drupal.settings.quicksearch.title,
|
| 26 |
attachEvent: null,
|
| 27 |
width: Drupal.settings.quicksearch.uiWidth,
|
| 28 |
closeButtonTitle: Drupal.settings.quicksearch.closeButton,
|
| 29 |
verticalAlign: false
|
| 30 |
});
|
| 31 |
}
|
| 32 |
}
|
| 33 |
});
|
| 34 |
};
|
| 35 |
|
| 36 |
/**
|
| 37 |
* Setup the search pager queue to use AJAX vs its actual links.
|
| 38 |
*/
|
| 39 |
Drupal.quicksearch.pagerSetup = function(db) {
|
| 40 |
var parent;
|
| 41 |
|
| 42 |
// Setup pager caching.
|
| 43 |
Drupal.quicksearch.pagerCache = Drupal.quicksearch.pagerCache || [];
|
| 44 |
|
| 45 |
// Grab the right parent element based on what type of display quicksearch is setup for.
|
| 46 |
if (Drupal.settings.quicksearch.selector) {
|
| 47 |
parent = $(Drupal.settings.quicksearch.selector);
|
| 48 |
} else {
|
| 49 |
var craqbox = Drupal.quicksearch.craqbox;
|
| 50 |
parent = $('#'+ craqbox.o.craqboxId +' .'+ craqbox.o.contentClass).get(0);
|
| 51 |
}
|
| 52 |
|
| 53 |
// Loop through the links in the pager turning the links into AJAX.
|
| 54 |
$('.pager a', parent).each(function() {
|
| 55 |
$(this).click(function(event) {
|
| 56 |
// Cache id for this content.
|
| 57 |
var key = this.href.replace('http://', '').replace(/\//g, '_');
|
| 58 |
if (Drupal.quicksearch.pagerCache[key]) {
|
| 59 |
Drupal.quicksearch.display(db, Drupal.quicksearch.pagerCache[key]);
|
| 60 |
} else {
|
| 61 |
$.get(this.href, function(results) {
|
| 62 |
Drupal.quicksearch.pagerCache[key] = results;
|
| 63 |
Drupal.quicksearch.display(db, results);
|
| 64 |
});
|
| 65 |
}
|
| 66 |
|
| 67 |
return false;
|
| 68 |
})
|
| 69 |
});
|
| 70 |
};
|
| 71 |
|
| 72 |
/**
|
| 73 |
* Setup content / user tabs to load via AJAX.
|
| 74 |
*/
|
| 75 |
Drupal.quicksearch.tabSetup = function(db) {
|
| 76 |
var parent;
|
| 77 |
|
| 78 |
// Use the right parent.
|
| 79 |
if (Drupal.settings.quicksearch.selector) {
|
| 80 |
parent = $('#'+ Drupal.settings.quicksearch.selector);
|
| 81 |
} else {
|
| 82 |
parent = $('#'+ Drupal.quicksearch.craqbox.o.craqboxId);
|
| 83 |
}
|
| 84 |
|
| 85 |
// Add AJAX functionality.
|
| 86 |
$('.quicksearch-tabs a', parent).each(function() {
|
| 87 |
if ($(this).is('.active')) {
|
| 88 |
Drupal.quicksearch.searchType = $(this).parent().id().replace('quicksearch-', '').replace('-link', '');
|
| 89 |
}
|
| 90 |
$(this).
|
| 91 |
click(function(event) {
|
| 92 |
if (Drupal.quicksearch.searchTab != $(this).html()) {
|
| 93 |
$.get(this.href, function(results) {
|
| 94 |
Drupal.quicksearch.display(db, results);
|
| 95 |
});
|
| 96 |
// Save this tab name as the current tab to avoid unnecessary AJAX calls.
|
| 97 |
Drupal.quicksearch.searchTab = $(this).html();
|
| 98 |
}
|
| 99 |
return false;
|
| 100 |
});
|
| 101 |
});
|
| 102 |
};
|
| 103 |
|
| 104 |
/**
|
| 105 |
* Handle displaying the search results.
|
| 106 |
*/
|
| 107 |
Drupal.quicksearch.display = function(db, results) {
|
| 108 |
// Search results added to an element.
|
| 109 |
if (Drupal.settings.quicksearch.selector) {
|
| 110 |
var el = $(Drupal.settings.quicksearch.selector);
|
| 111 |
// A close button so the original page content can be restored.
|
| 112 |
var closeButton = $('<a>')
|
| 113 |
.attr({ title: Drupal.settings.quicksearch.closeButtonTitle, className: 'quicksearch_close_button', href: '#close' })
|
| 114 |
.click(function() { Drupal.quicksearch.remove(db.input); return false; })
|
| 115 |
.html(Drupal.settings.quicksearch.closeButtonLabel);
|
| 116 |
|
| 117 |
// Cache the original page content before quicksearch occurred.
|
| 118 |
if ($('#quicksearch_cache').length == 0) {
|
| 119 |
$('<div>').attr('id', 'quicksearch_cache').css('display', 'none').append($(el).children()).appendTo(document.body);
|
| 120 |
}
|
| 121 |
$(el).fadeOut('fast', function() {
|
| 122 |
$(el).html(results).prepend(closeButton).fadeIn('fast');
|
| 123 |
});
|
| 124 |
Drupal.quicksearch.pagerSetup(db);
|
| 125 |
Drupal.quicksearch.tabSetup(db);
|
| 126 |
}
|
| 127 |
// Search results displayed in craqbox.
|
| 128 |
else {
|
| 129 |
// Save the original parent so we can restore the element to its original state.
|
| 130 |
if (!db.input.originalParent) {
|
| 131 |
db.input.originalParent = db.input.parentNode;
|
| 132 |
}
|
| 133 |
|
| 134 |
// Remove craqbox on escape key.
|
| 135 |
$(db.input).bind('keyup', Drupal.quicksearch.removeEsc);
|
| 136 |
|
| 137 |
// Display in craqbox.
|
| 138 |
Drupal.quicksearch.craqbox.build({
|
| 139 |
content: $('<div>').append($(db.input)).append($('<div>').html(results)),
|
| 140 |
completeCallback: function() {
|
| 141 |
db.input.focus();
|
| 142 |
Drupal.quicksearch.pagerSetup(db);
|
| 143 |
Drupal.quicksearch.tabSetup(db);
|
| 144 |
},
|
| 145 |
removeCallback: function() {
|
| 146 |
Drupal.quicksearch.remove(db.input);
|
| 147 |
}
|
| 148 |
});
|
| 149 |
}
|
| 150 |
};
|
| 151 |
|
| 152 |
/**
|
| 153 |
* Check if a form is a quicksearch form.
|
| 154 |
*/
|
| 155 |
Drupal.quicksearch.form = function(id) {
|
| 156 |
for (var i in Drupal.settings.quicksearch.fields) {
|
| 157 |
field = 'edit-'+ Drupal.settings.quicksearch.fields[i].replace(/_/g, '-') +'-keys';
|
| 158 |
if (id == field) {
|
| 159 |
return true;
|
| 160 |
}
|
| 161 |
}
|
| 162 |
};
|
| 163 |
|
| 164 |
/**
|
| 165 |
* Remove the newly searched content.
|
| 166 |
*/
|
| 167 |
Drupal.quicksearch.remove = function(input) {
|
| 168 |
if (Drupal.settings.quicksearch.selector) {
|
| 169 |
// Remove the search results and bring back the original page content.
|
| 170 |
$(Drupal.settings.quicksearch.selector).html('').append($('#quicksearch_cache').children());
|
| 171 |
$('#quicksearch_cache').remove();
|
| 172 |
} else {
|
| 173 |
// Save the original display because one faded in, jQuery will set the display = block even if it was inline.
|
| 174 |
$(input)
|
| 175 |
.attr('originalDisplay', $(input).css('display'))
|
| 176 |
.css('display', 'none')
|
| 177 |
.unbind('keyup', Drupal.quicksearch.removeEsc)
|
| 178 |
.appendTo(input.originalParent)
|
| 179 |
.fadeIn('fast', function() {
|
| 180 |
input.focus();
|
| 181 |
$(input).css('display', $(input).attr('originalDisplay'));
|
| 182 |
});
|
| 183 |
}
|
| 184 |
}
|
| 185 |
|
| 186 |
/**
|
| 187 |
* Used by the textfield so the user can press escape to remove the UI version of the search results.
|
| 188 |
*/
|
| 189 |
Drupal.quicksearch.removeEsc = function(event) {
|
| 190 |
if (event.keyCode == 27) {
|
| 191 |
Drupal.quicksearch.craqbox.remove();
|
| 192 |
}
|
| 193 |
}
|
| 194 |
|
| 195 |
/**
|
| 196 |
* These functions below are taken from autocomplete.js and slightly modified to work for live searching.
|
| 197 |
* One noted improvement is that if it is a search autocomplete, use drupal's search module setting for min characters allowed in a search.
|
| 198 |
* Live search requests are also cached like normal autocomplete calls.
|
| 199 |
*/
|
| 200 |
|
| 201 |
/**
|
| 202 |
* Performs a cached and delayed search
|
| 203 |
*/
|
| 204 |
Drupal.ACDB.prototype.search = function (searchString, input) {
|
| 205 |
var db = input ? input : this;
|
| 206 |
db.searchString = searchString;
|
| 207 |
var quicksearch = Drupal.quicksearch.form(db.owner.input.id);
|
| 208 |
|
| 209 |
// Check the search module's min character count for a search so we don't get errors.
|
| 210 |
if (quicksearch && searchString.length < Drupal.settings.quicksearch.minCharacters) {
|
| 211 |
return false;
|
| 212 |
}
|
| 213 |
|
| 214 |
// See if db key has been searched for before
|
| 215 |
if (db.cache[searchString]) {
|
| 216 |
return db.owner.found(db.cache[searchString]);
|
| 217 |
}
|
| 218 |
|
| 219 |
// Initiate delayed search
|
| 220 |
if (db.timer) {
|
| 221 |
clearTimeout(db.timer);
|
| 222 |
}
|
| 223 |
db.timer = setTimeout(function() {
|
| 224 |
db.owner.setStatus('begin');
|
| 225 |
|
| 226 |
// Set a search type of node or user.
|
| 227 |
if (quicksearch && Drupal.quicksearch.searchType) {
|
| 228 |
db.uri = Drupal.settings.quicksearch.searchPath +'/'+ Drupal.quicksearch.searchType;
|
| 229 |
}
|
| 230 |
|
| 231 |
// Ajax GET request for autocompletion
|
| 232 |
$.ajax({
|
| 233 |
type: "GET",
|
| 234 |
url: db.uri +'/'+ Drupal.encodeURIComponent(searchString),
|
| 235 |
success: function (data) {
|
| 236 |
// Custom solution for live searching.
|
| 237 |
if (quicksearch && data) {
|
| 238 |
db.cache[searchString] = data;
|
| 239 |
// Verify if these are still the matches the user wants to see
|
| 240 |
if (db.searchString == searchString) {
|
| 241 |
db.owner.found(data);
|
| 242 |
}
|
| 243 |
db.owner.setStatus('found');
|
| 244 |
} else {
|
| 245 |
// Parse back result
|
| 246 |
var matches = Drupal.parseJson(data);
|
| 247 |
if (typeof matches['status'] == 'undefined' || matches['status'] != 0) {
|
| 248 |
db.cache[searchString] = matches;
|
| 249 |
// Verify if these are still the matches the user wants to see
|
| 250 |
if (db.searchString == searchString) {
|
| 251 |
db.owner.found(matches);
|
| 252 |
}
|
| 253 |
db.owner.setStatus('found');
|
| 254 |
}
|
| 255 |
}
|
| 256 |
},
|
| 257 |
error: function (xmlhttp) {
|
| 258 |
alert('An HTTP error '+ xmlhttp.status +' occured.\n'+ db.uri);
|
| 259 |
}
|
| 260 |
});
|
| 261 |
}, (quicksearch) ? Drupal.settings.quicksearch.uiDelay : db.delay);
|
| 262 |
}
|
| 263 |
|
| 264 |
/**
|
| 265 |
* Fills the suggestion popup with any matches received
|
| 266 |
*/
|
| 267 |
Drupal.jsAC.prototype.found = function (matches) {
|
| 268 |
// If no value in the textfield, do not show the popup.
|
| 269 |
if (!this.input.value.length) {
|
| 270 |
return false;
|
| 271 |
}
|
| 272 |
|
| 273 |
// Custom solution for live searching.
|
| 274 |
if (Drupal.quicksearch.form(this.input.id)) {
|
| 275 |
// We're not using the popup so just hide it.
|
| 276 |
if (this.popup) {
|
| 277 |
$(this.popup).css({visibility: 'hidden'});
|
| 278 |
}
|
| 279 |
// Do not redraw because we now have the search textfield in this element and this would break functionality.
|
| 280 |
if (this.lastMatches != matches) {
|
| 281 |
Drupal.quicksearch.display(this, matches);
|
| 282 |
this.lastMatches = matches;
|
| 283 |
}
|
| 284 |
} else {
|
| 285 |
// Prepare matches
|
| 286 |
var ul = document.createElement('ul');
|
| 287 |
var ac = this;
|
| 288 |
for (key in matches) {
|
| 289 |
var li = document.createElement('li');
|
| 290 |
$(li)
|
| 291 |
.html('<div>'+ matches[key] +'</div>')
|
| 292 |
.mousedown(function () { ac.select(this); })
|
| 293 |
.mouseover(function () { ac.highlight(this); })
|
| 294 |
.mouseout(function () { ac.unhighlight(this); });
|
| 295 |
li.autocompleteValue = key;
|
| 296 |
$(ul).append(li);
|
| 297 |
}
|
| 298 |
|
| 299 |
// Show popup with matches, if any
|
| 300 |
if (this.popup) {
|
| 301 |
if (ul.childNodes.length > 0) {
|
| 302 |
$(this.popup).empty().append(ul).show();
|
| 303 |
}
|
| 304 |
else {
|
| 305 |
$(this.popup).css({visibility: 'hidden'});
|
| 306 |
this.hidePopup();
|
| 307 |
}
|
| 308 |
}
|
| 309 |
}
|
| 310 |
}
|
| 311 |
|
| 312 |
// Global Killswitch.
|
| 313 |
if (Drupal.jsEnabled) {
|
| 314 |
$(document).ready(Drupal.quicksearch.autoAttach);
|
| 315 |
}
|