drupal/core/misc/autocomplete.js

202 lines
4.6 KiB
JavaScript

(function ($, Drupal) {
"use strict";
var autocomplete;
/**
* Helper splitting terms from the autocomplete value.
*
* @param {String} value
*
* @return {Array}
*/
function autocompleteSplitValues (value) {
// We will match the value against comma-seperated terms.
var result = [];
var quote = false;
var current = '';
var valueLength = value.length;
var i, character;
for (i = 0; i < valueLength; i++) {
character = value.charAt(i);
if (character === '"') {
current += character;
quote = !quote;
}
else if (character === ',' && !quote) {
result.push(current.trim());
current = '';
}
else {
current += character;
}
}
if (value.length > 0) {
result.push($.trim(current));
}
return result;
}
/**
* Returns the last value of an multi-value textfield.
*
* @param {String} terms
*
* @return {String}
*/
function extractLastTerm (terms) {
return autocomplete.splitValues(terms).pop();
}
/**
* The search handler is called before a search is performed.
*
* @param {Object} event
*
* @return {Boolean}
*/
function searchHandler (event) {
// Only search when the term is two characters or larger.
var term = autocomplete.extractLastTerm(event.target.value);
return term.length >= autocomplete.minLength;
}
/**
* jQuery UI autocomplete source callback.
*
* @param {Object} request
* @param {Function} response
*/
function sourceData (request, response) {
/*jshint validthis:true */
var elementId = this.element.attr('id');
if (!(elementId in autocomplete.cache)) {
autocomplete.cache[elementId] = {};
}
/**
* Filter through the suggestions removing all terms already tagged and
* display the available terms to the user.
*
* @param {Object} suggestions
*/
function showSuggestions (suggestions) {
var tagged = autocomplete.splitValues(request.term);
for (var i = 0, il = tagged.length; i < il; i++) {
var index = suggestions.indexOf(tagged[i]);
if (index >= 0) {
suggestions.splice(index, 1);
}
}
response(suggestions);
}
/**
* Transforms the data object into an array and update autocomplete results.
*
* @param {Object} data
*/
function sourceCallbackHandler (data) {
autocomplete.cache[elementId][term] = data;
// Send the new string array of terms to the jQuery UI list.
showSuggestions(data);
}
// Get the desired term and construct the autocomplete URL for it.
var term = autocomplete.extractLastTerm(request.term);
// Check if the term is already cached.
if (autocomplete.cache[elementId].hasOwnProperty(term)) {
showSuggestions(autocomplete.cache[elementId][term]);
}
else {
var options = $.extend({ success: sourceCallbackHandler, data: { q: term } }, autocomplete.ajax);
/*jshint validthis:true */
$.ajax(this.element.attr('data-autocomplete-path'), options);
}
}
/**
* Handles an autocompletefocus event.
*
* @return {Boolean}
*/
function focusHandler () {
return false;
}
/**
* Handles an autocompleteselect event.
*
* @param {Object} event
* @param {Object} ui
*
* @return {Boolean}
*/
function selectHandler (event, ui) {
var terms = autocomplete.splitValues(event.target.value);
// Remove the current input.
terms.pop();
// Add the selected item.
if (ui.item.value.search(",") > 0) {
terms.push('"' + ui.item.value + '"');
}
else {
terms.push(ui.item.value);
}
event.target.value = terms.join(', ');
// Return false to tell jQuery UI that we've filled in the value already.
return false;
}
/**
* Attaches the autocomplete behavior to all required fields.
*/
Drupal.behaviors.autocomplete = {
attach: function (context) {
// Act on textfields with the "form-autocomplete" class.
var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete');
if ($autocomplete.length) {
// Use jQuery UI Autocomplete on the textfield.
$autocomplete.autocomplete(autocomplete.options);
}
},
detach: function (context, settings, trigger) {
if (trigger === 'unload') {
$(context).find('input.form-autocomplete')
.removeOnce('autocomplete')
.autocomplete('destroy');
}
}
};
/**
* Autocomplete object implementation.
*/
autocomplete = {
cache: {},
// Exposes methods to allow overriding by contrib.
minLength: 1,
splitValues: autocompleteSplitValues,
extractLastTerm: extractLastTerm,
// jQuery UI autocomplete options.
options: {
source: sourceData,
focus: focusHandler,
search: searchHandler,
select: selectHandler
},
ajax: {
dataType: 'json'
}
};
Drupal.autocomplete = autocomplete;
})(jQuery, Drupal);