db981a3b27
* This moves our "development" versions from .dev.js to .js (same for css). * The compressed version then moves from .js to .min.js (same for css). By switching to the standard .min convention, it sets expectations for developers, and works nicely with existing tools such as ack. fixes #21633. git-svn-id: https://develop.svn.wordpress.org/trunk@21592 602fd350-edb4-49c9-b593-d223f7449a82
330 lines
7.1 KiB
JavaScript
330 lines
7.1 KiB
JavaScript
/*
|
|
* jquery.suggest 1.1b - 2007-08-06
|
|
* Patched by Mark Jaquith with Alexander Dick's "multiple items" patch to allow for auto-suggesting of more than one tag before submitting
|
|
* See: http://www.vulgarisoip.com/2007/06/29/jquerysuggest-an-alternative-jquery-based-autocomplete-library/#comment-7228
|
|
*
|
|
* Uses code and techniques from following libraries:
|
|
* 1. http://www.dyve.net/jquery/?autocomplete
|
|
* 2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js
|
|
*
|
|
* All the new stuff written by Peter Vulgaris (www.vulgarisoip.com)
|
|
* Feel free to do whatever you want with this file
|
|
*
|
|
*/
|
|
|
|
(function($) {
|
|
|
|
$.suggest = function(input, options) {
|
|
var $input, $results, timeout, prevLength, cache, cacheSize;
|
|
|
|
$input = $(input).attr("autocomplete", "off");
|
|
$results = $(document.createElement("ul"));
|
|
|
|
timeout = false; // hold timeout ID for suggestion results to appear
|
|
prevLength = 0; // last recorded length of $input.val()
|
|
cache = []; // cache MRU list
|
|
cacheSize = 0; // size of cache in chars (bytes?)
|
|
|
|
$results.addClass(options.resultsClass).appendTo('body');
|
|
|
|
|
|
resetPosition();
|
|
$(window)
|
|
.load(resetPosition) // just in case user is changing size of page while loading
|
|
.resize(resetPosition);
|
|
|
|
$input.blur(function() {
|
|
setTimeout(function() { $results.hide() }, 200);
|
|
});
|
|
|
|
|
|
// help IE users if possible
|
|
if ( $.browser.msie ) {
|
|
try {
|
|
$results.bgiframe();
|
|
} catch(e) { }
|
|
}
|
|
|
|
// I really hate browser detection, but I don't see any other way
|
|
if ($.browser.mozilla)
|
|
$input.keypress(processKey); // onkeypress repeats arrow keys in Mozilla/Opera
|
|
else
|
|
$input.keydown(processKey); // onkeydown repeats arrow keys in IE/Safari
|
|
|
|
|
|
|
|
|
|
function resetPosition() {
|
|
// requires jquery.dimension plugin
|
|
var offset = $input.offset();
|
|
$results.css({
|
|
top: (offset.top + input.offsetHeight) + 'px',
|
|
left: offset.left + 'px'
|
|
});
|
|
}
|
|
|
|
|
|
function processKey(e) {
|
|
|
|
// handling up/down/escape requires results to be visible
|
|
// handling enter/tab requires that AND a result to be selected
|
|
if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
|
|
(/^13$|^9$/.test(e.keyCode) && getCurrentResult())) {
|
|
|
|
if (e.preventDefault)
|
|
e.preventDefault();
|
|
if (e.stopPropagation)
|
|
e.stopPropagation();
|
|
|
|
e.cancelBubble = true;
|
|
e.returnValue = false;
|
|
|
|
switch(e.keyCode) {
|
|
|
|
case 38: // up
|
|
prevResult();
|
|
break;
|
|
|
|
case 40: // down
|
|
nextResult();
|
|
break;
|
|
|
|
case 9: // tab
|
|
case 13: // return
|
|
selectCurrentResult();
|
|
break;
|
|
|
|
case 27: // escape
|
|
$results.hide();
|
|
break;
|
|
|
|
}
|
|
|
|
} else if ($input.val().length != prevLength) {
|
|
|
|
if (timeout)
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(suggest, options.delay);
|
|
prevLength = $input.val().length;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
function suggest() {
|
|
|
|
var q = $.trim($input.val()), multipleSepPos, items;
|
|
|
|
if ( options.multiple ) {
|
|
multipleSepPos = q.lastIndexOf(options.multipleSep);
|
|
if ( multipleSepPos != -1 ) {
|
|
q = $.trim(q.substr(multipleSepPos + options.multipleSep.length));
|
|
}
|
|
}
|
|
if (q.length >= options.minchars) {
|
|
|
|
cached = checkCache(q);
|
|
|
|
if (cached) {
|
|
|
|
displayItems(cached['items']);
|
|
|
|
} else {
|
|
|
|
$.get(options.source, {q: q}, function(txt) {
|
|
|
|
$results.hide();
|
|
|
|
items = parseTxt(txt, q);
|
|
|
|
displayItems(items);
|
|
addToCache(q, items, txt.length);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$results.hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function checkCache(q) {
|
|
var i;
|
|
for (i = 0; i < cache.length; i++)
|
|
if (cache[i]['q'] == q) {
|
|
cache.unshift(cache.splice(i, 1)[0]);
|
|
return cache[0];
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
function addToCache(q, items, size) {
|
|
var cached;
|
|
while (cache.length && (cacheSize + size > options.maxCacheSize)) {
|
|
cached = cache.pop();
|
|
cacheSize -= cached['size'];
|
|
}
|
|
|
|
cache.push({
|
|
q: q,
|
|
size: size,
|
|
items: items
|
|
});
|
|
|
|
cacheSize += size;
|
|
|
|
}
|
|
|
|
function displayItems(items) {
|
|
var html = '', i;
|
|
if (!items)
|
|
return;
|
|
|
|
if (!items.length) {
|
|
$results.hide();
|
|
return;
|
|
}
|
|
|
|
resetPosition(); // when the form moves after the page has loaded
|
|
|
|
for (i = 0; i < items.length; i++)
|
|
html += '<li>' + items[i] + '</li>';
|
|
|
|
$results.html(html).show();
|
|
|
|
$results
|
|
.children('li')
|
|
.mouseover(function() {
|
|
$results.children('li').removeClass(options.selectClass);
|
|
$(this).addClass(options.selectClass);
|
|
})
|
|
.click(function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
selectCurrentResult();
|
|
});
|
|
|
|
}
|
|
|
|
function parseTxt(txt, q) {
|
|
|
|
var items = [], tokens = txt.split(options.delimiter), i, token;
|
|
|
|
// parse returned data for non-empty items
|
|
for (i = 0; i < tokens.length; i++) {
|
|
token = $.trim(tokens[i]);
|
|
if (token) {
|
|
token = token.replace(
|
|
new RegExp(q, 'ig'),
|
|
function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
|
|
);
|
|
items[items.length] = token;
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
function getCurrentResult() {
|
|
var $currentResult;
|
|
if (!$results.is(':visible'))
|
|
return false;
|
|
|
|
$currentResult = $results.children('li.' + options.selectClass);
|
|
|
|
if (!$currentResult.length)
|
|
$currentResult = false;
|
|
|
|
return $currentResult;
|
|
|
|
}
|
|
|
|
function selectCurrentResult() {
|
|
|
|
$currentResult = getCurrentResult();
|
|
|
|
if ($currentResult) {
|
|
if ( options.multiple ) {
|
|
if ( $input.val().indexOf(options.multipleSep) != -1 ) {
|
|
$currentVal = $input.val().substr( 0, ( $input.val().lastIndexOf(options.multipleSep) + options.multipleSep.length ) );
|
|
} else {
|
|
$currentVal = "";
|
|
}
|
|
$input.val( $currentVal + $currentResult.text() + options.multipleSep);
|
|
$input.focus();
|
|
} else {
|
|
$input.val($currentResult.text());
|
|
}
|
|
$results.hide();
|
|
|
|
if (options.onSelect)
|
|
options.onSelect.apply($input[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function nextResult() {
|
|
|
|
$currentResult = getCurrentResult();
|
|
|
|
if ($currentResult)
|
|
$currentResult
|
|
.removeClass(options.selectClass)
|
|
.next()
|
|
.addClass(options.selectClass);
|
|
else
|
|
$results.children('li:first-child').addClass(options.selectClass);
|
|
|
|
}
|
|
|
|
function prevResult() {
|
|
var $currentResult = getCurrentResult();
|
|
|
|
if ($currentResult)
|
|
$currentResult
|
|
.removeClass(options.selectClass)
|
|
.prev()
|
|
.addClass(options.selectClass);
|
|
else
|
|
$results.children('li:last-child').addClass(options.selectClass);
|
|
|
|
}
|
|
}
|
|
|
|
$.fn.suggest = function(source, options) {
|
|
|
|
if (!source)
|
|
return;
|
|
|
|
options = options || {};
|
|
options.multiple = options.multiple || false;
|
|
options.multipleSep = options.multipleSep || ", ";
|
|
options.source = source;
|
|
options.delay = options.delay || 100;
|
|
options.resultsClass = options.resultsClass || 'ac_results';
|
|
options.selectClass = options.selectClass || 'ac_over';
|
|
options.matchClass = options.matchClass || 'ac_match';
|
|
options.minchars = options.minchars || 2;
|
|
options.delimiter = options.delimiter || '\n';
|
|
options.onSelect = options.onSelect || false;
|
|
options.maxCacheSize = options.maxCacheSize || 65536;
|
|
|
|
this.each(function() {
|
|
new $.suggest(this, options);
|
|
});
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
})(jQuery); |