9 changed files with 188 additions and 1181 deletions
@ -0,0 +1 @@ |
|||
div.token-input-dropdown,ul.token-input-list{overflow:hidden;font-size:12px;font-family:Verdana,sans-serif}ul.token-input-list,ul.token-input-list li{list-style-type:none}ul.token-input-list{height:auto!important;height:1%;width:400px;border:1px solid #999;cursor:text;z-index:999;margin:0;padding:0;background-color:#fff;clear:left}ul.token-input-list li input{border:0;width:350px;padding:3px 8px;background-color:#fff;-webkit-appearance:caret}ul.token-input-disabled,ul.token-input-disabled li input{background-color:#E8E8E8}ul.token-input-disabled li.token-input-token{background-color:#D9E3CA;color:#7D7D7D}ul.token-input-disabled li.token-input-token span{color:#CFCFCF;cursor:default}li.token-input-token{overflow:hidden;height:auto!important;height:1%;margin:3px;padding:3px 5px;background-color:#d0efa0;color:#000;font-weight:700;cursor:default;display:block}li.token-input-token p{float:left;padding:0;margin:0}li.token-input-token span{float:right;color:#777;cursor:pointer}li.token-input-selected-token{background-color:#08844e;color:#fff}li.token-input-selected-token span{color:#bbb}div.token-input-dropdown{position:absolute;width:400px;background-color:#fff;border-left:1px solid #ccc;border-right:1px solid #ccc;border-bottom:1px solid #ccc;cursor:default;z-index:1}div.token-input-dropdown p{margin:0;padding:5px;font-weight:700;color:#777}div.token-input-dropdown ul{margin:0;padding:0}div.token-input-dropdown ul li{background-color:#fff;padding:3px;list-style-type:none}div.token-input-dropdown ul li.token-input-dropdown-item{background-color:#fafafa}div.token-input-dropdown ul li.token-input-dropdown-item2{background-color:#fff}div.token-input-dropdown ul li em{font-weight:700;font-style:normal}div.token-input-dropdown ul li.token-input-selected-dropdown-item{background-color:#d0efa0} |
@ -1,861 +0,0 @@ |
|||
/* |
|||
* jQuery Plugin: Tokenizing Autocomplete Text Entry |
|||
* Version 1.6.0 |
|||
* |
|||
* Copyright (c) 2009 James Smith (http://loopj.com)
|
|||
* Licensed jointly under the GPL and MIT licenses, |
|||
* choose which one suits your project best! |
|||
* |
|||
*/ |
|||
|
|||
(function ($) { |
|||
// Default settings
|
|||
var DEFAULT_SETTINGS = { |
|||
// Search settings
|
|||
method: "GET", |
|||
contentType: "json", |
|||
queryParam: "q", |
|||
searchDelay: 300, |
|||
minChars: 1, |
|||
propertyToSearch: "name", |
|||
jsonContainer: null, |
|||
|
|||
// Display settings
|
|||
hintText: "Type in a search term", |
|||
noResultsText: "No results", |
|||
searchingText: "Searching...", |
|||
deleteText: "×", |
|||
animateDropdown: true, |
|||
|
|||
// Tokenization settings
|
|||
tokenLimit: null, |
|||
tokenDelimiter: ",", |
|||
preventDuplicates: false, |
|||
|
|||
// Output settings
|
|||
tokenValue: "id", |
|||
|
|||
// Prepopulation settings
|
|||
prePopulate: null, |
|||
processPrePopulate: true, |
|||
|
|||
// Manipulation settings
|
|||
idPrefix: "token-input-", |
|||
|
|||
// Formatters
|
|||
resultsFormatter: function(item){ return "<li><img src='"+sbRoot+"/images/flags/"+item["id"]+".png' /> " + item[this.propertyToSearch]+ "</li>" }, |
|||
tokenFormatter: function(item) { return "<li><img src='"+sbRoot+"/images/flags/"+item["id"]+".png' /> <p>" + item[this.propertyToSearch] + "</p></li>" }, |
|||
flag: "flag", |
|||
|
|||
// Callbacks
|
|||
onResult: null, |
|||
onAdd: null, |
|||
onDelete: null, |
|||
onReady: null |
|||
}; |
|||
|
|||
// Default classes to use when theming
|
|||
var DEFAULT_CLASSES = { |
|||
tokenList: "token-input-list", |
|||
token: "token-input-token", |
|||
tokenDelete: "token-input-delete-token", |
|||
selectedToken: "token-input-selected-token", |
|||
highlightedToken: "token-input-highlighted-token", |
|||
dropdown: "token-input-dropdown", |
|||
dropdownItem: "token-input-dropdown-item", |
|||
dropdownItem2: "token-input-dropdown-item2", |
|||
selectedDropdownItem: "token-input-selected-dropdown-item", |
|||
inputToken: "token-input-input-token" |
|||
}; |
|||
|
|||
// Input box position "enum"
|
|||
var POSITION = { |
|||
BEFORE: 0, |
|||
AFTER: 1, |
|||
END: 2 |
|||
}; |
|||
|
|||
// Keys "enum"
|
|||
var KEY = { |
|||
BACKSPACE: 8, |
|||
TAB: 9, |
|||
ENTER: 13, |
|||
ESCAPE: 27, |
|||
SPACE: 32, |
|||
PAGE_UP: 33, |
|||
PAGE_DOWN: 34, |
|||
END: 35, |
|||
HOME: 36, |
|||
LEFT: 37, |
|||
UP: 38, |
|||
RIGHT: 39, |
|||
DOWN: 40, |
|||
NUMPAD_ENTER: 108, |
|||
COMMA: 188 |
|||
}; |
|||
|
|||
// Additional public (exposed) methods
|
|||
var methods = { |
|||
init: function(url_or_data_or_function, options) { |
|||
var settings = $.extend({}, DEFAULT_SETTINGS, options || {}); |
|||
|
|||
return this.each(function () { |
|||
$(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings)); |
|||
}); |
|||
}, |
|||
clear: function() { |
|||
this.data("tokenInputObject").clear(); |
|||
return this; |
|||
}, |
|||
add: function(item) { |
|||
this.data("tokenInputObject").add(item); |
|||
return this; |
|||
}, |
|||
remove: function(item) { |
|||
this.data("tokenInputObject").remove(item); |
|||
return this; |
|||
}, |
|||
get: function() { |
|||
return this.data("tokenInputObject").getTokens(); |
|||
} |
|||
} |
|||
|
|||
// Expose the .tokenInput function to jQuery as a plugin
|
|||
$.fn.tokenInput = function (method) { |
|||
// Method calling and initialization logic
|
|||
if(methods[method]) { |
|||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); |
|||
} else { |
|||
return methods.init.apply(this, arguments); |
|||
} |
|||
}; |
|||
|
|||
// TokenList class for each input
|
|||
$.TokenList = function (input, url_or_data, settings) { |
|||
//
|
|||
// Initialization
|
|||
//
|
|||
|
|||
// Configure the data source
|
|||
if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") { |
|||
// Set the url to query against
|
|||
settings.url = url_or_data; |
|||
|
|||
// If the URL is a function, evaluate it here to do our initalization work
|
|||
var url = computeURL(); |
|||
|
|||
// Make a smart guess about cross-domain if it wasn't explicitly specified
|
|||
if(settings.crossDomain === undefined) { |
|||
if(url.indexOf("://") === -1) { |
|||
settings.crossDomain = false; |
|||
} else { |
|||
settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]); |
|||
} |
|||
} |
|||
} else if(typeof(url_or_data) === "object") { |
|||
// Set the local data to search through
|
|||
settings.local_data = url_or_data; |
|||
} |
|||
|
|||
// Build class names
|
|||
if(settings.classes) { |
|||
// Use custom class names
|
|||
settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes); |
|||
} else if(settings.theme) { |
|||
// Use theme-suffixed default class names
|
|||
settings.classes = {}; |
|||
$.each(DEFAULT_CLASSES, function(key, value) { |
|||
settings.classes[key] = value + "-" + settings.theme; |
|||
}); |
|||
} else { |
|||
settings.classes = DEFAULT_CLASSES; |
|||
} |
|||
|
|||
|
|||
// Save the tokens
|
|||
var saved_tokens = []; |
|||
|
|||
// Keep track of the number of tokens in the list
|
|||
var token_count = 0; |
|||
|
|||
// Basic cache to save on db hits
|
|||
var cache = new $.TokenList.Cache(); |
|||
|
|||
// Keep track of the timeout, old vals
|
|||
var timeout; |
|||
var input_val; |
|||
|
|||
// Create a new text input an attach keyup events
|
|||
var input_box = $("<input type=\"text\" autocomplete=\"off\" >") |
|||
.css({ |
|||
outline: "none" |
|||
}) |
|||
.attr("id", settings.idPrefix + input.id) |
|||
.focus(function () { |
|||
if (settings.tokenLimit === null || settings.tokenLimit !== token_count) { |
|||
show_dropdown_hint(); |
|||
} |
|||
}) |
|||
.blur(function () { |
|||
hide_dropdown(); |
|||
$(this).val(""); |
|||
}) |
|||
.bind("keyup keydown blur update", resize_input) |
|||
.keydown(function (event) { |
|||
var previous_token; |
|||
var next_token; |
|||
|
|||
switch(event.keyCode) { |
|||
case KEY.LEFT: |
|||
case KEY.RIGHT: |
|||
case KEY.UP: |
|||
case KEY.DOWN: |
|||
if(!$(this).val()) { |
|||
previous_token = input_token.prev(); |
|||
next_token = input_token.next(); |
|||
|
|||
if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) { |
|||
// Check if there is a previous/next token and it is selected
|
|||
if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) { |
|||
deselect_token($(selected_token), POSITION.BEFORE); |
|||
} else { |
|||
deselect_token($(selected_token), POSITION.AFTER); |
|||
} |
|||
} else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) { |
|||
// We are moving left, select the previous token if it exists
|
|||
select_token($(previous_token.get(0))); |
|||
} else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) { |
|||
// We are moving right, select the next token if it exists
|
|||
select_token($(next_token.get(0))); |
|||
} |
|||
} else { |
|||
var dropdown_item = null; |
|||
|
|||
if(event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) { |
|||
dropdown_item = $(selected_dropdown_item).next(); |
|||
} else { |
|||
dropdown_item = $(selected_dropdown_item).prev(); |
|||
} |
|||
|
|||
if(dropdown_item.length) { |
|||
select_dropdown_item(dropdown_item); |
|||
} |
|||
return false; |
|||
} |
|||
break; |
|||
|
|||
case KEY.BACKSPACE: |
|||
previous_token = input_token.prev(); |
|||
|
|||
if(!$(this).val().length) { |
|||
if(selected_token) { |
|||
delete_token($(selected_token)); |
|||
hidden_input.change(); |
|||
} else if(previous_token.length) { |
|||
select_token($(previous_token.get(0))); |
|||
} |
|||
|
|||
return false; |
|||
} else if($(this).val().length === 1) { |
|||
hide_dropdown(); |
|||
} else { |
|||
// set a timeout just long enough to let this function finish.
|
|||
setTimeout(function(){do_search();}, 5); |
|||
} |
|||
break; |
|||
|
|||
case KEY.TAB: |
|||
case KEY.ENTER: |
|||
case KEY.NUMPAD_ENTER: |
|||
case KEY.COMMA: |
|||
if(selected_dropdown_item) { |
|||
add_token($(selected_dropdown_item).data("tokeninput")); |
|||
hidden_input.change(); |
|||
return false; |
|||
} |
|||
break; |
|||
|
|||
case KEY.ESCAPE: |
|||
hide_dropdown(); |
|||
return true; |
|||
|
|||
default: |
|||
if(String.fromCharCode(event.which)) { |
|||
// set a timeout just long enough to let this function finish.
|
|||
setTimeout(function(){do_search();}, 5); |
|||
} |
|||
break; |
|||
} |
|||
}); |
|||
|
|||
// Keep a reference to the original input box
|
|||
var hidden_input = $(input) |
|||
.hide() |
|||
.val("") |
|||
.focus(function () { |
|||
input_box.focus(); |
|||
}) |
|||
.blur(function () { |
|||
input_box.blur(); |
|||
}); |
|||
|
|||
// Keep a reference to the selected token and dropdown item
|
|||
var selected_token = null; |
|||
var selected_token_index = 0; |
|||
var selected_dropdown_item = null; |
|||
|
|||
// The list to store the token items in
|
|||
var token_list = $("<ul />") |
|||
.addClass(settings.classes.tokenList) |
|||
.click(function (event) { |
|||
var li = $(event.target).closest("li"); |
|||
if(li && li.get(0) && $.data(li.get(0), "tokeninput")) { |
|||
toggle_select_token(li); |
|||
} else { |
|||
// Deselect selected token
|
|||
if(selected_token) { |
|||
deselect_token($(selected_token), POSITION.END); |
|||
} |
|||
|
|||
// Focus input box
|
|||
input_box.focus(); |
|||
} |
|||
}) |
|||
.mouseover(function (event) { |
|||
var li = $(event.target).closest("li"); |
|||
if(li && selected_token !== this) { |
|||
li.addClass(settings.classes.highlightedToken); |
|||
} |
|||
}) |
|||
.mouseout(function (event) { |
|||
var li = $(event.target).closest("li"); |
|||
if(li && selected_token !== this) { |
|||
li.removeClass(settings.classes.highlightedToken); |
|||
} |
|||
}) |
|||
.insertBefore(hidden_input); |
|||
|
|||
// The token holding the input box
|
|||
var input_token = $("<li />") |
|||
.addClass(settings.classes.inputToken) |
|||
.appendTo(token_list) |
|||
.append(input_box); |
|||
|
|||
// The list to store the dropdown items in
|
|||
var dropdown = $("<div>") |
|||
.addClass(settings.classes.dropdown) |
|||
.appendTo("body") |
|||
.hide(); |
|||
|
|||
// Magic element to help us resize the text input
|
|||
var input_resizer = $("<tester/>") |
|||
.insertAfter(input_box) |
|||
.css({ |
|||
position: "absolute", |
|||
top: -9999, |
|||
left: -9999, |
|||
width: "auto", |
|||
fontSize: input_box.css("fontSize"), |
|||
fontFamily: input_box.css("fontFamily"), |
|||
fontWeight: input_box.css("fontWeight"), |
|||
letterSpacing: input_box.css("letterSpacing"), |
|||
whiteSpace: "nowrap" |
|||
}); |
|||
|
|||
// Pre-populate list if items exist
|
|||
hidden_input.val(""); |
|||
var li_data = settings.prePopulate || hidden_input.data("pre"); |
|||
if(settings.processPrePopulate && $.isFunction(settings.onResult)) { |
|||
li_data = settings.onResult.call(hidden_input, li_data); |
|||
} |
|||
if(li_data && li_data.length) { |
|||
$.each(li_data, function (index, value) { |
|||
insert_token(value); |
|||
checkTokenLimit(); |
|||
}); |
|||
} |
|||
|
|||
// Initialization is done
|
|||
if($.isFunction(settings.onReady)) { |
|||
settings.onReady.call(); |
|||
} |
|||
|
|||
//
|
|||
// Public functions
|
|||
//
|
|||
|
|||
this.clear = function() { |
|||
token_list.children("li").each(function() { |
|||
if ($(this).children("input").length === 0) { |
|||
delete_token($(this)); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
this.add = function(item) { |
|||
add_token(item); |
|||
} |
|||
|
|||
this.remove = function(item) { |
|||
token_list.children("li").each(function() { |
|||
if ($(this).children("input").length === 0) { |
|||
var currToken = $(this).data("tokeninput"); |
|||
var match = true; |
|||
for (var prop in item) { |
|||
if (item[prop] !== currToken[prop]) { |
|||
match = false; |
|||
break; |
|||
} |
|||
} |
|||
if (match) { |
|||
delete_token($(this)); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
this.getTokens = function() { |
|||
return saved_tokens; |
|||
} |
|||
|
|||
//
|
|||
// Private functions
|
|||
//
|
|||
|
|||
function checkTokenLimit() { |
|||
if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) { |
|||
input_box.hide(); |
|||
hide_dropdown(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
function resize_input() { |
|||
if(input_val === (input_val = input_box.val())) {return;} |
|||
|
|||
// Enter new content into resizer and resize input accordingly
|
|||
var escaped = input_val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>'); |
|||
input_resizer.html(escaped); |
|||
input_box.width(input_resizer.width() + 30); |
|||
} |
|||
|
|||
function is_printable_character(keycode) { |
|||
return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
|
|||
(keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
|
|||
(keycode >= 186 && keycode <= 192) || // ; = , - . / ^
|
|||
(keycode >= 219 && keycode <= 222)); // ( \ ) '
|
|||
} |
|||
|
|||
// Inner function to a token to the list
|
|||
function insert_token(item) { |
|||
var this_token = settings.tokenFormatter(item); |
|||
this_token = $(this_token) |
|||
.addClass(settings.classes.token) |
|||
.insertBefore(input_token); |
|||
|
|||
// The 'delete token' button
|
|||
$("<span>" + settings.deleteText + "</span>") |
|||
.addClass(settings.classes.tokenDelete) |
|||
.appendTo(this_token) |
|||
.click(function () { |
|||
delete_token($(this).parent()); |
|||
hidden_input.change(); |
|||
return false; |
|||
}); |
|||
|
|||
// Store data on the token
|
|||
var token_data = {"id": item.id}; |
|||
token_data[settings.propertyToSearch] = item[settings.propertyToSearch]; |
|||
$.data(this_token.get(0), "tokeninput", item); |
|||
|
|||
// Save this token for duplicate checking
|
|||
saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index)); |
|||
selected_token_index++; |
|||
|
|||
// Update the hidden input
|
|||
update_hidden_input(saved_tokens, hidden_input); |
|||
|
|||
token_count += 1; |
|||
|
|||
// Check the token limit
|
|||
if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) { |
|||
input_box.hide(); |
|||
hide_dropdown(); |
|||
} |
|||
|
|||
return this_token; |
|||
} |
|||
|
|||
// Add a token to the token list based on user input
|
|||
function add_token (item) { |
|||
var callback = settings.onAdd; |
|||
|
|||
// See if the token already exists and select it if we don't want duplicates
|
|||
if(token_count > 0 && settings.preventDuplicates) { |
|||
var found_existing_token = null; |
|||
token_list.children().each(function () { |
|||
var existing_token = $(this); |
|||
var existing_data = $.data(existing_token.get(0), "tokeninput"); |
|||
if(existing_data && existing_data.id === item.id) { |
|||
found_existing_token = existing_token; |
|||
return false; |
|||
} |
|||
}); |
|||
|
|||
if(found_existing_token) { |
|||
select_token(found_existing_token); |
|||
input_token.insertAfter(found_existing_token); |
|||
input_box.focus(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
// Insert the new tokens
|
|||
if(settings.tokenLimit == null || token_count < settings.tokenLimit) { |
|||
insert_token(item); |
|||
checkTokenLimit(); |
|||
} |
|||
|
|||
// Clear input box
|
|||
input_box.val(""); |
|||
|
|||
// Don't show the help dropdown, they've got the idea
|
|||
hide_dropdown(); |
|||
|
|||
// Execute the onAdd callback if defined
|
|||
if($.isFunction(callback)) { |
|||
callback.call(hidden_input,item); |
|||
} |
|||
} |
|||
|
|||
// Select a token in the token list
|
|||
function select_token (token) { |
|||
token.addClass(settings.classes.selectedToken); |
|||
selected_token = token.get(0); |
|||
|
|||
// Hide input box
|
|||
input_box.val(""); |
|||
|
|||
// Hide dropdown if it is visible (eg if we clicked to select token)
|
|||
hide_dropdown(); |
|||
} |
|||
|
|||
// Deselect a token in the token list
|
|||
function deselect_token (token, position) { |
|||
token.removeClass(settings.classes.selectedToken); |
|||
selected_token = null; |
|||
|
|||
if(position === POSITION.BEFORE) { |
|||
input_token.insertBefore(token); |
|||
selected_token_index--; |
|||
} else if(position === POSITION.AFTER) { |
|||
input_token.insertAfter(token); |
|||
selected_token_index++; |
|||
} else { |
|||
input_token.appendTo(token_list); |
|||
selected_token_index = token_count; |
|||
} |
|||
|
|||
// Show the input box and give it focus again
|
|||
input_box.focus(); |
|||
} |
|||
|
|||
// Toggle selection of a token in the token list
|
|||
function toggle_select_token(token) { |
|||
var previous_selected_token = selected_token; |
|||
|
|||
if(selected_token) { |
|||
deselect_token($(selected_token), POSITION.END); |
|||
} |
|||
|
|||
if(previous_selected_token === token.get(0)) { |
|||
deselect_token(token, POSITION.END); |
|||
} else { |
|||
select_token(token); |
|||
} |
|||
} |
|||
|
|||
// Delete a token from the token list
|
|||
function delete_token (token) { |
|||
// Remove the id from the saved list
|
|||
var token_data = $.data(token.get(0), "tokeninput"); |
|||
var callback = settings.onDelete; |
|||
|
|||
var index = token.prevAll().length; |
|||
if(index > selected_token_index) index--; |
|||
|
|||
// Delete the token
|
|||
token.remove(); |
|||
selected_token = null; |
|||
|
|||
// Show the input box and give it focus again
|
|||
input_box.focus(); |
|||
|
|||
// Remove this token from the saved list
|
|||
saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1)); |
|||
if(index < selected_token_index) selected_token_index--; |
|||
|
|||
// Update the hidden input
|
|||
update_hidden_input(saved_tokens, hidden_input); |
|||
|
|||
token_count -= 1; |
|||
|
|||
if(settings.tokenLimit !== null) { |
|||
input_box |
|||
.show() |
|||
.val("") |
|||
.focus(); |
|||
} |
|||
|
|||
// Execute the onDelete callback if defined
|
|||
if($.isFunction(callback)) { |
|||
callback.call(hidden_input,token_data); |
|||
} |
|||
} |
|||
|
|||
// Update the hidden input box value
|
|||
function update_hidden_input(saved_tokens, hidden_input) { |
|||
var token_values = $.map(saved_tokens, function (el) { |
|||
return el[settings.tokenValue]; |
|||
}); |
|||
hidden_input.val(token_values.join(settings.tokenDelimiter)); |
|||
|
|||
} |
|||
|
|||
// Hide and clear the results dropdown
|
|||
function hide_dropdown () { |
|||
dropdown.hide().empty(); |
|||
selected_dropdown_item = null; |
|||
} |
|||
|
|||
function show_dropdown() { |
|||
dropdown |
|||
.css({ |
|||
position: "absolute", |
|||
top: $(token_list).offset().top + $(token_list).outerHeight(), |
|||
left: $(token_list).offset().left, |
|||
zindex: 999 |
|||
}) |
|||
.show(); |
|||
} |
|||
|
|||
function show_dropdown_searching () { |
|||
if(settings.searchingText) { |
|||
dropdown.html("<p>"+settings.searchingText+"</p>"); |
|||
show_dropdown(); |
|||
} |
|||
} |
|||
|
|||
function show_dropdown_hint () { |
|||
if(settings.hintText) { |
|||
dropdown.html("<p>"+settings.hintText+"</p>"); |
|||
show_dropdown(); |
|||
} |
|||
} |
|||
|
|||
// Highlight the query part of the search term
|
|||
function highlight_term(value, term) { |
|||
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>"); |
|||
} |
|||
|
|||
function find_value_and_highlight_term(template, value, term) { |
|||
return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term)); |
|||
} |
|||
|
|||
// Populate the results dropdown with some results
|
|||
function populate_dropdown (query, results) { |
|||
if(results && results.length) { |
|||
dropdown.empty(); |
|||
var dropdown_ul = $("<ul>") |
|||
.appendTo(dropdown) |
|||
.mouseover(function (event) { |
|||
select_dropdown_item($(event.target).closest("li")); |
|||
}) |
|||
.mousedown(function (event) { |
|||
add_token($(event.target).closest("li").data("tokeninput")); |
|||
hidden_input.change(); |
|||
return false; |
|||
}) |
|||
.hide(); |
|||
|
|||
$.each(results, function(index, value) { |
|||
var this_li = settings.resultsFormatter(value); |
|||
|
|||
this_li = find_value_and_highlight_term(this_li ,value[settings.propertyToSearch], query); |
|||
|
|||
this_li = $(this_li).appendTo(dropdown_ul); |
|||
|
|||
if(index % 2) { |
|||
this_li.addClass(settings.classes.dropdownItem); |
|||
} else { |
|||
this_li.addClass(settings.classes.dropdownItem2); |
|||
} |
|||
|
|||
if(index === 0) { |
|||
select_dropdown_item(this_li); |
|||
} |
|||
|
|||
$.data(this_li.get(0), "tokeninput", value); |
|||
}); |
|||
|
|||
show_dropdown(); |
|||
|
|||
if(settings.animateDropdown) { |
|||
dropdown_ul.slideDown("fast"); |
|||
} else { |
|||
dropdown_ul.show(); |
|||
} |
|||
} else { |
|||
if(settings.noResultsText) { |
|||
dropdown.html("<p>"+settings.noResultsText+"</p>"); |
|||
show_dropdown(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Highlight an item in the results dropdown
|
|||
function select_dropdown_item (item) { |
|||
if(item) { |
|||
if(selected_dropdown_item) { |
|||
deselect_dropdown_item($(selected_dropdown_item)); |
|||
} |
|||
|
|||
item.addClass(settings.classes.selectedDropdownItem); |
|||
selected_dropdown_item = item.get(0); |
|||
} |
|||
} |
|||
|
|||
// Remove highlighting from an item in the results dropdown
|
|||
function deselect_dropdown_item (item) { |
|||
item.removeClass(settings.classes.selectedDropdownItem); |
|||
selected_dropdown_item = null; |
|||
} |
|||
|
|||
// Do a search and show the "searching" dropdown if the input is longer
|
|||
// than settings.minChars
|
|||
function do_search() { |
|||
var query = input_box.val().toLowerCase(); |
|||
|
|||
if(query && query.length) { |
|||
if(selected_token) { |
|||
deselect_token($(selected_token), POSITION.AFTER); |
|||
} |
|||
|
|||
if(query.length >= settings.minChars) { |
|||
show_dropdown_searching(); |
|||
clearTimeout(timeout); |
|||
|
|||
timeout = setTimeout(function(){ |
|||
run_search(query); |
|||
}, settings.searchDelay); |
|||
} else { |
|||
hide_dropdown(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Do the actual search
|
|||
function run_search(query) { |
|||
var cache_key = query + computeURL(); |
|||
var cached_results = cache.get(cache_key); |
|||
if(cached_results) { |
|||
populate_dropdown(query, cached_results); |
|||
} else { |
|||
// Are we doing an ajax search or local data search?
|
|||
if(settings.url) { |
|||
var url = computeURL(); |
|||
// Extract exisiting get params
|
|||
var ajax_params = {}; |
|||
ajax_params.data = {}; |
|||
if(url.indexOf("?") > -1) { |
|||
var parts = url.split("?"); |
|||
ajax_params.url = parts[0]; |
|||
|
|||
var param_array = parts[1].split("&"); |
|||
$.each(param_array, function (index, value) { |
|||
var kv = value.split("="); |
|||
ajax_params.data[kv[0]] = kv[1]; |
|||
}); |
|||
} else { |
|||
ajax_params.url = url; |
|||
} |
|||
|
|||
// Prepare the request
|
|||
ajax_params.data[settings.queryParam] = query; |
|||
ajax_params.type = settings.method; |
|||
ajax_params.dataType = settings.contentType; |
|||
if(settings.crossDomain) { |
|||
ajax_params.dataType = "jsonp"; |
|||
} |
|||
|
|||
// Attach the success callback
|
|||
ajax_params.success = function(results) { |
|||
if($.isFunction(settings.onResult)) { |
|||
results = settings.onResult.call(hidden_input, results); |
|||
} |
|||
cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results); |
|||
|
|||
// only populate the dropdown if the results are associated with the active search query
|
|||
if(input_box.val().toLowerCase() === query) { |
|||
populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results); |
|||
} |
|||
}; |
|||
|
|||
// Make the request
|
|||
$.ajax(ajax_params); |
|||
} else if(settings.local_data) { |
|||
// Do the search through local data
|
|||
var results = $.grep(settings.local_data, function (row) { |
|||
return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1; |
|||
}); |
|||
|
|||
if($.isFunction(settings.onResult)) { |
|||
results = settings.onResult.call(hidden_input, results); |
|||
} |
|||
cache.add(cache_key, results); |
|||
populate_dropdown(query, results); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// compute the dynamic URL
|
|||
function computeURL() { |
|||
var url = settings.url; |
|||
if(typeof settings.url == 'function') { |
|||
url = settings.url.call(); |
|||
} |
|||
return url; |
|||
} |
|||
}; |
|||
|
|||
// Really basic cache for the results
|
|||
$.TokenList.Cache = function (options) { |
|||
var settings = $.extend({ |
|||
max_size: 500 |
|||
}, options); |
|||
|
|||
var data = {}; |
|||
var size = 0; |
|||
|
|||
var flush = function () { |
|||
data = {}; |
|||
size = 0; |
|||
}; |
|||
|
|||
this.add = function (query, results) { |
|||
if(size > settings.max_size) { |
|||
flush(); |
|||
} |
|||
|
|||
if(!data[query]) { |
|||
size += 1; |
|||
} |
|||
|
|||
data[query] = results; |
|||
}; |
|||
|
|||
this.get = function (query) { |
|||
return data[query]; |
|||
}; |
|||
}; |
|||
}(jQuery)); |
@ -0,0 +1,39 @@ |
|||
/* |
|||
* jQuery Plugin: Tokenizing Autocomplete Text Entry |
|||
* Version 1.6.2 |
|||
* |
|||
* Copyright (c) 2009 James Smith (http://loopj.com)
|
|||
* Licensed jointly under the GPL and MIT licenses, |
|||
* choose which one suits your project best |
|||
* |
|||
*/ |
|||
var $jscomp={scope:{},findInternal:function(a,h,g){a instanceof String&&(a=String(a));for(var q=a.length,l=0;l<q;l++){var A=a[l];if(h.call(g,A,l,a))return{i:l,v:A}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(a,h,g){if(g.get||g.set)throw new TypeError("ES3 does not support getters and setters.");a!=Array.prototype&&a!=Object.prototype&&(a[h]=g.value)}; |
|||
$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(a,h,g,q){if(h){g=$jscomp.global;a=a.split(".");for(q=0;q<a.length-1;q++){var l=a[q];l in g||(g[l]={});g=g[l]}a=a[a.length-1];q=g[a];h=h(q);h!=q&&null!=h&&$jscomp.defineProperty(g,a,{configurable:!0,writable:!0,value:h})}}; |
|||
$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,g){return $jscomp.findInternal(this,a,g).v}},"es6-impl","es3"); |
|||
(function(a){function h(a){return String(null===a||void 0===a?"":a).replace(A,function(a){return l[a]})}var g={method:"GET",queryParam:"q",searchDelay:300,minChars:1,propertyToSearch:"name",jsonContainer:null,contentType:"json",excludeCurrent:!1,excludeCurrentParameter:"x",prePopulate:null,processPrePopulate:!1,hintText:"Type in a search term",noResultsText:"No results",searchingText:"Searching...",deleteText:"×",animateDropdown:!0,placeholder:null,theme:null,zindex:999,resultsLimit:null,enableHTML:!1, |
|||
resultsFormatter:function(a){a=a[this.propertyToSearch];return"<li>"+(this.enableHTML?a:h(a))+"</li>"},tokenFormatter:function(a){a=a[this.propertyToSearch];return"<li><p>"+(this.enableHTML?a:h(a))+"</p></li>"},tokenLimit:null,tokenDelimiter:",",preventDuplicates:!1,tokenValue:"id",allowFreeTagging:!1,allowTabOut:!1,autoSelectFirstResult:!1,onResult:null,onCachedResult:null,onAdd:null,onFreeTaggingAdd:null,onDelete:null,onReady:null,idPrefix:"token-input-",disabled:!1},q={tokenList:"token-input-list", |
|||
token:"token-input-token",tokenReadOnly:"token-input-token-readonly",tokenDelete:"token-input-delete-token",selectedToken:"token-input-selected-token",highlightedToken:"token-input-highlighted-token",dropdown:"token-input-dropdown",dropdownItem:"token-input-dropdown-item",dropdownItem2:"token-input-dropdown-item2",selectedDropdownItem:"token-input-selected-dropdown-item",inputToken:"token-input-input-token",focused:"token-input-focused",disabled:"token-input-disabled"},l={"&":"&","<":"<",">":">", |
|||
'"':""","'":"'","/":"/"},A=/[&<>"'\/]/g,C={init:function(b,p){var h=a.extend({},g,p||{});return this.each(function(){a(this).data("settings",h);a(this).data("tokenInputObject",new a.TokenList(this,b,h))})},clear:function(){this.data("tokenInputObject").clear();return this},add:function(a){this.data("tokenInputObject").add(a);return this},remove:function(a){this.data("tokenInputObject").remove(a);return this},get:function(){return this.data("tokenInputObject").getTokens()},toggleDisabled:function(a){this.data("tokenInputObject").toggleDisabled(a); |
|||
return this},setOptions:function(b){a(this).data("settings",a.extend({},a(this).data("settings"),b||{}));return this},destroy:function(){if(this.data("tokenInputObject")){this.data("tokenInputObject").clear();var a=this.parent();a.empty();this.show();a.append(this);return this}}};a.fn.tokenInput=function(a){return C[a]?C[a].apply(this,Array.prototype.slice.call(arguments,1)):C.init.apply(this,arguments)};a.TokenList=function(b,p,g){function l(c){return a(b).data("settings").enableHTML?c:h(c)}function O(c){"boolean"=== |
|||
typeof c?a(b).data("settings").disabled=c:a(b).data("settings").disabled=!a(b).data("settings").disabled;f.attr("disabled",a(b).data("settings").disabled);r.toggleClass(a(b).data("settings").classes.disabled,a(b).data("settings").disabled);m&&B(a(m),2);n.attr("disabled",a(b).data("settings").disabled)}function P(){null!==a(b).data("settings").tokenLimit&&x>=a(b).data("settings").tokenLimit&&(f.hide(),y())}function A(){if(I!==(I=f.val())){var a=r.width()-f.offset().left-r.offset().left;Q.html(h(I)|| |
|||
h(g.placeholder));f.width(Math.min(r.width(),Math.max(a,Q.width()+30)))}}function N(){var c=a.trim(f.val()).split(a(b).data("settings").tokenDelimiter);a.each(c,function(c,d){if(d){a.isFunction(a(b).data("settings").onFreeTaggingAdd)&&(d=a(b).data("settings").onFreeTaggingAdd.call(n,d));var e={};e[a(b).data("settings").tokenValue]=e[a(b).data("settings").propertyToSearch]=d;F(e)}})}function C(c){var e=a(a(b).data("settings").tokenFormatter(c)),d=!0===c.readonly;d&&e.addClass(a(b).data("settings").classes.tokenReadOnly); |
|||
e.addClass(a(b).data("settings").classes.token).insertBefore(z);d||a("<span>"+a(b).data("settings").deleteText+"</span>").addClass(a(b).data("settings").classes.tokenDelete).appendTo(e).click(function(){if(!a(b).data("settings").disabled)return G(a(this).parent()),n.change(),!1});a.data(e.get(0),"tokeninput",c);u=u.slice(0,v).concat([c]).concat(u.slice(v));v++;R(u,n);x+=1;null!==a(b).data("settings").tokenLimit&&x>=a(b).data("settings").tokenLimit&&(f.hide(),y());return e}function F(c){var e=a(b).data("settings").onAdd; |
|||
if(0<x&&a(b).data("settings").preventDuplicates){var d=null;r.children().each(function(){var b=a(this),e=a.data(b.get(0),"tokeninput");if(e&&e[g.tokenValue]===c[g.tokenValue])return d=b,!1});if(d){E(d);z.insertAfter(d);D(f);return}}f.width(1);if(null==a(b).data("settings").tokenLimit||x<a(b).data("settings").tokenLimit)C(c),f.attr("placeholder",null),P();f.val("");y();a.isFunction(e)&&e.call(n,c)}function E(c){a(b).data("settings").disabled||(c.addClass(a(b).data("settings").classes.selectedToken), |
|||
m=c.get(0),f.val(""),y())}function B(c,e){c.removeClass(a(b).data("settings").classes.selectedToken);m=null;0===e?(z.insertBefore(c),v--):1===e?(z.insertAfter(c),v++):(z.appendTo(r),v=x);D(f)}function G(c){var e=a.data(c.get(0),"tokeninput"),d=a(b).data("settings").onDelete,k=c.prevAll().length;k>v&&k--;c.remove();m=null;D(f);u=u.slice(0,k).concat(u.slice(k+1));0==u.length&&f.attr("placeholder",g.placeholder);k<v&&v--;R(u,n);--x;null!==a(b).data("settings").tokenLimit&&(f.show().val(""),D(f));a.isFunction(d)&& |
|||
d.call(n,e)}function R(c,e){var d=a.map(c,function(c){return"function"==typeof a(b).data("settings").tokenValue?a(b).data("settings").tokenValue.call(this,c):c[a(b).data("settings").tokenValue]});e.val(d.join(a(b).data("settings").tokenDelimiter))}function y(){w.hide().empty();t=null}function H(){w.css({position:"absolute",top:r.offset().top+r.outerHeight(!0),left:r.offset().left,width:r.width(),"z-index":a(b).data("settings").zindex}).show()}function V(a,b){return a.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+ |
|||
b.replace(S,"\\$&")+")(?![^<>]*>)(?![^&;]+;)","gi"),function(a,b){return"<b>"+l(b)+"</b>"})}function W(c){if(a(b).data("settings").excludeCurrent){var e=a(b).data("tokenInputObject").getTokens(),d=[];e.length&&(a.each(c,function(c,f){var k=!0;a.each(e,function(c,e){if(f[a(b).data("settings").propertyToSearch]==e[a(b).data("settings").propertyToSearch])return k=!1});k&&d.push(f)}),c=d)}return c}function J(c,e){if((e=W(e))&&e.length){w.empty();var d=a("<ul/>").appendTo(w).mouseover(function(b){K(a(b.target).closest("li"))}).mousedown(function(b){F(a(b.target).closest("li").data("tokeninput")); |
|||
n.change();return!1}).hide();a(b).data("settings").resultsLimit&&e.length>a(b).data("settings").resultsLimit&&(e=e.slice(0,a(b).data("settings").resultsLimit));a.each(e,function(e,f){var g=a(b).data("settings").resultsFormatter(f),k=f[a(b).data("settings").propertyToSearch],g=g.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+k.replace(S,"\\$&")+")(?![^<>]*>)(?![^&;]+;)","g"),V(k,c)),g=a(g).appendTo(d);e%2?g.addClass(a(b).data("settings").classes.dropdownItem):g.addClass(a(b).data("settings").classes.dropdownItem2); |
|||
0===e&&a(b).data("settings").autoSelectFirstResult&&K(g);a.data(g.get(0),"tokeninput",f)});H();a(b).data("settings").animateDropdown?d.slideDown("fast"):d.show()}else a(b).data("settings").noResultsText&&(w.html("<p>"+l(a(b).data("settings").noResultsText)+"</p>"),H())}function K(c){c&&(t&&(a(t).removeClass(a(b).data("settings").classes.selectedDropdownItem),t=null),c.addClass(a(b).data("settings").classes.selectedDropdownItem),t=c.get(0))}function T(){var c=f.val();c&&c.length&&(m&&B(a(m),1),c.length>= |
|||
a(b).data("settings").minChars?(a(b).data("settings").searchingText&&(w.html("<p>"+l(a(b).data("settings").searchingText)+"</p>"),H()),clearTimeout(U),U=setTimeout(function(){X(c)},a(b).data("settings").searchDelay)):y())}function X(c){var e=c+L(),d=M.get(e);if(d)a.isFunction(a(b).data("settings").onCachedResult)&&(d=a(b).data("settings").onCachedResult.call(n,d)),J(c,d);else if(a(b).data("settings").url){var d=L(),k={data:{}};-1<d.indexOf("?")?(d=d.split("?"),k.url=d[0],d=d[1].split("&"),a.each(d, |
|||
function(a,b){var c=b.split("=");k.data[c[0]]=c[1]})):k.url=d;k.data[a(b).data("settings").queryParam]=c;k.type=a(b).data("settings").method;k.dataType=a(b).data("settings").contentType;a(b).data("settings").crossDomain&&(k.dataType="jsonp");a(b).data("settings").excludeCurrent&&(d=a(b).data("tokenInputObject").getTokens(),d=a.map(d,function(c){return"function"==typeof a(b).data("settings").tokenValue?a(b).data("settings").tokenValue.call(this,c):c[a(b).data("settings").tokenValue]}),k.data[a(b).data("settings").excludeCurrentParameter]= |
|||
d.join(a(b).data("settings").tokenDelimiter));k.success=function(d){M.add(e,a(b).data("settings").jsonContainer?d[a(b).data("settings").jsonContainer]:d);a.isFunction(a(b).data("settings").onResult)&&(d=a(b).data("settings").onResult.call(n,d));f.val()===c&&J(c,a(b).data("settings").jsonContainer?d[a(b).data("settings").jsonContainer]:d)};if(g.onSend)g.onSend(k);a.ajax(k)}else a(b).data("settings").local_data&&(d=a.grep(a(b).data("settings").local_data,function(e){return-1<e[a(b).data("settings").propertyToSearch].toLowerCase().indexOf(c.toLowerCase())}), |
|||
M.add(e,d),a.isFunction(a(b).data("settings").onResult)&&(d=a(b).data("settings").onResult.call(n,d)),J(c,d))}function L(){var c=a(b).data("settings");return"function"==typeof c.url?c.url.call(c):c.url}function D(a){setTimeout(function(){a.focus()},50)}"string"===typeof p||"function"===typeof p?(a(b).data("settings").url=p,p=L(),void 0===a(b).data("settings").crossDomain&&"string"===typeof p&&(-1===p.indexOf("://")?a(b).data("settings").crossDomain=!1:a(b).data("settings").crossDomain=location.href.split(/\/+/g)[1]!== |
|||
p.split(/\/+/g)[1])):"object"===typeof p&&(a(b).data("settings").local_data=p);a(b).data("settings").classes?a(b).data("settings").classes=a.extend({},q,a(b).data("settings").classes):a(b).data("settings").theme?(a(b).data("settings").classes={},a.each(q,function(c,e){a(b).data("settings").classes[c]=e+"-"+a(b).data("settings").theme})):a(b).data("settings").classes=q;var u=[],x=0,M=new a.TokenList.Cache,U,I,f=a('<input type="text" autocomplete="off" autocapitalize="off"/>').css({outline:"none"}).attr("id", |
|||
a(b).data("settings").idPrefix+b.id).focus(function(){if(a(b).data("settings").disabled)return!1;null!==a(b).data("settings").tokenLimit&&a(b).data("settings").tokenLimit===x||!a(b).data("settings").hintText||(w.html("<p>"+l(a(b).data("settings").hintText)+"</p>"),H());r.addClass(a(b).data("settings").classes.focused)}).blur(function(){y();a(b).data("settings").allowFreeTagging&&N();a(this).val("");r.removeClass(a(b).data("settings").classes.focused)}).bind("keyup keydown blur update",A).keydown(function(c){var e, |
|||
d;switch(c.keyCode){case 37:case 39:case 38:case 40:0===this.value.length?(e=z.prev(),d=z.next(),e.length&&e.get(0)===m||d.length&&d.get(0)===m?37===c.keyCode||38===c.keyCode?B(a(m),0):B(a(m),1):37!==c.keyCode&&38!==c.keyCode||!e.length?39!==c.keyCode&&40!==c.keyCode||!d.length||E(a(d.get(0))):E(a(e.get(0)))):(e=null,40===c.keyCode||39===c.keyCode?(e=a(w).find("li").first(),t&&(e=a(t).next())):(e=a(w).find("li").last(),t&&(e=a(t).prev())),K(e));break;case 8:e=z.prev();if(0===this.value.length)return m? |
|||
(G(a(m)),n.change()):e.length&&E(a(e.get(0))),!1;1===a(this).val().length?y():setTimeout(function(){T()},5);break;case 9:case 13:case 108:case 188:if(t)F(a(t).data("tokeninput")),n.change();else{if(a(b).data("settings").allowFreeTagging){if(a(b).data("settings").allowTabOut&&""===a(this).val())return!0;N()}else if(a(this).val(""),a(b).data("settings").allowTabOut)return!0;c.stopPropagation();c.preventDefault()}return!1;case 27:return y(),!0;default:String.fromCharCode(c.which)&&setTimeout(function(){T()}, |
|||
5)}});g.placeholder&&f.attr("placeholder",g.placeholder);var n=a(b).hide().val("").focus(function(){D(f)}).blur(function(){f.blur();return n}),m=null,v=0,t=null,r=a("<ul />").addClass(a(b).data("settings").classes.tokenList).click(function(b){if((b=a(b.target).closest("li"))&&b.get(0)&&a.data(b.get(0),"tokeninput")){var c=m;m&&B(a(m),2);c===b.get(0)?B(b,2):E(b)}else m&&B(a(m),2),D(f)}).mouseover(function(c){(c=a(c.target).closest("li"))&&m!==this&&c.addClass(a(b).data("settings").classes.highlightedToken)}).mouseout(function(c){(c= |
|||
a(c.target).closest("li"))&&m!==this&&c.removeClass(a(b).data("settings").classes.highlightedToken)}).insertBefore(n),z=a("<li />").addClass(a(b).data("settings").classes.inputToken).appendTo(r).append(f),w=a("<div/>").addClass(a(b).data("settings").classes.dropdown).appendTo("body").hide(),Q=a("<tester/>").insertAfter(f).css({position:"absolute",top:-9999,left:-9999,width:"auto",fontSize:f.css("fontSize"),fontFamily:f.css("fontFamily"),fontWeight:f.css("fontWeight"),letterSpacing:f.css("letterSpacing"), |
|||
whiteSpace:"nowrap"});n.val("");p=a(b).data("settings").prePopulate||n.data("pre");a(b).data("settings").processPrePopulate&&a.isFunction(a(b).data("settings").onResult)&&(p=a(b).data("settings").onResult.call(n,p));p&&p.length&&a.each(p,function(a,b){C(b);P();f.attr("placeholder",null)});a(b).data("settings").disabled&&O(!0);"function"===typeof a(b).data("settings").onReady&&a(b).data("settings").onReady.call();this.clear=function(){r.children("li").each(function(){0===a(this).children("input").length&& |
|||
G(a(this))})};this.add=function(a){F(a)};this.remove=function(b){r.children("li").each(function(){if(0===a(this).children("input").length){var c=a(this).data("tokeninput"),d=!0,f;for(f in b)if(b[f]!==c[f]){d=!1;break}d&&G(a(this))}})};this.getTokens=function(){return u};this.toggleDisabled=function(a){O(a)};A();var S=RegExp("[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]","g")};a.TokenList.Cache=function(b){var g,h={},l=0,q;g=a.extend({max_size:500},b);q=function(){h={};l=0};this.add=function(a,b){l>g.max_size&& |
|||
q();h[a]||(l+=1);h[a]=b};this.get=function(a){return h[a]}}})(jQuery); |
Loading…
Reference in new issue