From 68ffc79d86eebbe981b65913c67dc0ae7fa4531d Mon Sep 17 00:00:00 2001 From: mistic100 Date: Sun, 16 Jun 2013 20:53:20 +0000 Subject: feature:2927 Update TokenInput to 1.6.1/mistic100 git-svn-id: http://piwigo.org/svn/trunk@23275 68402e56-0260-453c-a942-63ccdbb3a9ee --- themes/default/js/plugins/jquery.tokeninput.css | 16 + themes/default/js/plugins/jquery.tokeninput.js | 713 +++++++++++++++++------- 2 files changed, 525 insertions(+), 204 deletions(-) create mode 100644 themes/default/js/plugins/jquery.tokeninput.css (limited to 'themes') diff --git a/themes/default/js/plugins/jquery.tokeninput.css b/themes/default/js/plugins/jquery.tokeninput.css new file mode 100644 index 000000000..8db9cff44 --- /dev/null +++ b/themes/default/js/plugins/jquery.tokeninput.css @@ -0,0 +1,16 @@ +/* TokenInput (with Facebook style) */ +ul.token-input-list {overflow: hidden; height: auto !important; height: 1%;width: 400px;border: 1px solid #8496ba;cursor: text;font-size: 12px;font-family: Verdana;min-height: 1px;z-index: 999;margin: 0;padding: 0;background-color: #fff;list-style-type: none;clear: left;} +ul.token-input-list li input {border: 0;width: 100px;padding: 3px 8px;background-color: white;margin: 2px 0;-webkit-appearance: caret;} +li.token-input-token {overflow: hidden; height: auto !important; height: 15px;margin: 3px;padding: 1px 3px;background-color: #eff2f7;color: #000;cursor: default;border: 1px solid #ccd5e4;font-size: 11px;border-radius: 5px;-moz-border-radius: 5px;-webkit-border-radius: 5px;float: left;white-space: nowrap;} +li.token-input-token p {display: inline;padding: 0;margin: 0;} +li.token-input-token span {color: #a6b3cf;margin-left: 5px;font-weight: bold;cursor: pointer;} +li.token-input-selected-token {background-color: #5670a6;border: 1px solid #3b5998;color: #fff;} +li.token-input-input-token {float: left;margin: 0;padding: 0;list-style-type: none;width:10px;} +div.token-input-dropdown {position: absolute;width: 400px;background-color: #fff;overflow: hidden;border-left: 1px solid #ccc;border-right: 1px solid #ccc;border-bottom: 1px solid #ccc;cursor: default;font-size: 11px;font-family: Verdana;z-index: 1;} +div.token-input-dropdown p {margin: 0;padding: 5px;font-weight: bold;color: #777;} +div.token-input-dropdown ul {margin: 0;padding: 0;} +div.token-input-dropdown ul li {background-color: #fff;padding: 3px;margin: 0;list-style-type: none;} +div.token-input-dropdown ul li.token-input-dropdown-item {background-color: #fff;} +div.token-input-dropdown ul li.token-input-dropdown-item2 {background-color: #fff;} +div.token-input-dropdown ul li em {font-weight: bold;font-style: normal;} +div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color: #3b5998;color: #fff;} \ No newline at end of file diff --git a/themes/default/js/plugins/jquery.tokeninput.js b/themes/default/js/plugins/jquery.tokeninput.js index 0bbf8336b..7348639ae 100644 --- a/themes/default/js/plugins/jquery.tokeninput.js +++ b/themes/default/js/plugins/jquery.tokeninput.js @@ -1,51 +1,85 @@ -/** - DON'T MAKE AUTOMATIC UPGRADE - This is a merged version of : - + https://github.com/gr2m/jquery-tokeninput/ - + https://github.com/mistic100/jquery-tokeninput/ -*/ - /* * jQuery Plugin: Tokenizing Autocomplete Text Entry - * Version 1.4.2 + * Version 1.6.1 * * Copyright (c) 2009 James Smith (http://loopj.com) * Licensed jointly under the GPL and MIT licenses, * choose which one suits your project best! * + * https://github.com/mistic100/jquery-tokeninput */ (function ($) { // Default settings var DEFAULT_SETTINGS = { - hintText: "Type in a search term", - noResultsText: "No results", - searchingText: "Searching...", - newText: "(new)", - deleteText: "×", + // Search settings + method: "GET", + queryParam: "q", searchDelay: 300, minChars: 1, - tokenLimit: null, + propertyToSearch: "name", jsonContainer: null, - method: "GET", contentType: "json", - queryParam: "q", - tokenDelimiter: ",", - preventDuplicates: false, + + // Prepopulation settings prePopulate: null, processPrePopulate: false, + + // Display settings + hintText: "Type in a search term", + noResultsText: "No results", + searchingText: "Searching...", + deleteText: "×", + newText: " (new)", animateDropdown: true, + placeholder: null, + theme: null, + zindex: 999, + resultsLimit: null, + + enableHTML: false, + + resultsFormatter: function(item) { + var string = item[this.propertyToSearch]; + return "
  • " + (this.enableHTML ? string : _escapeHTML(string)) + "
  • "; + }, + + tokenFormatter: function(item) { + var string = item[this.propertyToSearch]; + return "
  • " + (this.enableHTML ? string : _escapeHTML(string)) + "

  • "; + }, + + // Tokenization settings + tokenLimit: null, + tokenDelimiter: ",", + preventDuplicates: false, + tokenValue: "id", + + // Behavioral settings + allowFreeTagging: false, + freeTaggingHint: true, + allowTabOut: false, + + // Callbacks onResult: null, + onCachedResult: null, onAdd: null, + onFreeTaggingAdd: null, onDelete: null, - allowCreation: false, - caseSensitive: false + onReady: null, + + // Other settings + idPrefix: "token-input-", + + // Keep track if the input is currently in disabled mode + disabled: false }; // Default classes to use when theming var DEFAULT_CLASSES = { 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", @@ -53,7 +87,9 @@ var DEFAULT_CLASSES = { dropdownItem: "token-input-dropdown-item", dropdownItem2: "token-input-dropdown-item2", selectedDropdownItem: "token-input-selected-dropdown-item", - inputToken: "token-input-input-token" + inputToken: "token-input-input-token", + focused: "token-input-focused", + disabled: "token-input-disabled" }; // Input box position "enum" @@ -82,16 +118,82 @@ var KEY = { COMMA: 188 }; +var HTML_ESCAPES = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/' +}; -// Expose the .tokenInput function to jQuery as a plugin -$.fn.tokenInput = function (url_or_data, options) { - var settings = $.extend({}, DEFAULT_SETTINGS, options || {}); +var HTML_ESCAPE_CHARS = /[&<>"'\/]/g; + +function coerceToString(val) { + return String((val === null || val === undefined) ? '' : val); +} + +function _escapeHTML(text) { + return coerceToString(text).replace(HTML_ESCAPE_CHARS, function(match) { + return HTML_ESCAPES[match]; + }); +} + +// Additional public (exposed) methods +var methods = { + init: function(url_or_data_or_function, options) { + var settings = $.extend({}, DEFAULT_SETTINGS, options || {}); - return this.each(function () { - new $.TokenList(this, url_or_data, settings); - }); + return this.each(function () { + $(this).data("settings", settings); + $(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(); + }, + toggleDisabled: function(disable) { + this.data("tokenInputObject").toggleDisabled(disable); + return this; + }, + setOptions: function(options){ + $(this).data("settings", $.extend({}, $(this).data("settings"), options || {})); + return this; + }, + destroy: function () { + if(this.data("tokenInputObject")){ + this.data("tokenInputObject").clear(); + var tmpInput = this; + var closest = this.parent(); + closest.empty(); + tmpInput.show(); + closest.append(tmpInput); + return tmpInput; + } + } }; +// 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) { @@ -100,35 +202,38 @@ $.TokenList = function (input, url_or_data, settings) { // // Configure the data source - if(typeof(url_or_data) === "string") { + if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") { // Set the url to query against - settings.url = url_or_data; + $(input).data("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(settings.url.indexOf("://") === -1) { - settings.crossDomain = false; + if($(input).data("settings").crossDomain === undefined && typeof url === "string") { + if(url.indexOf("://") === -1) { + $(input).data("settings").crossDomain = false; } else { - settings.crossDomain = (location.href.split(/\/+/g)[1] !== settings.url.split(/\/+/g)[1]); + $(input).data("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; + $(input).data("settings").local_data = url_or_data; } // Build class names - if(settings.classes) { + if($(input).data("settings").classes) { // Use custom class names - settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes); - } else if(settings.theme) { + $(input).data("settings").classes = $.extend({}, DEFAULT_CLASSES, $(input).data("settings").classes); + } else if($(input).data("settings").theme) { // Use theme-suffixed default class names - settings.classes = {}; + $(input).data("settings").classes = {}; $.each(DEFAULT_CLASSES, function(key, value) { - settings.classes[key] = value + "-" + settings.theme; + $(input).data("settings").classes[key] = value + "-" + $(input).data("settings").theme; }); } else { - settings.classes = DEFAULT_CLASSES; + $(input).data("settings").classes = DEFAULT_CLASSES; } @@ -146,17 +251,29 @@ $.TokenList = function (input, url_or_data, settings) { var input_val; // Create a new text input an attach keyup events - var input_box = $("") + var input_box = $("") .css({ outline: "none" }) + .attr("id", $(input).data("settings").idPrefix + input.id) .focus(function () { - if (settings.tokenLimit === null || settings.tokenLimit !== token_count) { + if ($(input).data("settings").disabled) { + return false; + } else + if ($(input).data("settings").tokenLimit === null || $(input).data("settings").tokenLimit !== token_count) { show_dropdown_hint(); } + token_list.addClass($(input).data("settings").classes.focused); }) .blur(function () { hide_dropdown(); + + if ($(input).data("settings").allowFreeTagging) { + add_freetagging_tokens(); + } + + $(this).val(""); + token_list.removeClass($(input).data("settings").classes.focused); }) .bind("keyup keydown blur update", resize_input) .keydown(function (event) { @@ -198,8 +315,8 @@ $.TokenList = function (input, url_or_data, settings) { if(dropdown_item.length) { select_dropdown_item(dropdown_item); } - return false; } + return false; break; case KEY.BACKSPACE: @@ -208,6 +325,7 @@ $.TokenList = function (input, url_or_data, settings) { 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))); } @@ -226,10 +344,25 @@ $.TokenList = function (input, url_or_data, settings) { case KEY.NUMPAD_ENTER: case KEY.COMMA: if(selected_dropdown_item) { - add_token($(selected_dropdown_item)); - return false; + add_token($(selected_dropdown_item).data("tokeninput")); + hidden_input.change(); + } else { + if ($(input).data("settings").allowFreeTagging) { + if($(input).data("settings").allowTabOut && $(this).val() === "") { + return true; + } else { + add_freetagging_tokens(); + } + } else { + $(this).val(""); + if($(input).data("settings").allowTabOut) { + return true; + } + } + event.stopPropagation(); + event.preventDefault(); } - break; + return false; case KEY.ESCAPE: hide_dropdown(); @@ -244,29 +377,52 @@ $.TokenList = function (input, url_or_data, settings) { } }); + // Keep reference for placeholder + if (settings.placeholder) + input_box.attr("placeholder", settings.placeholder) + if ($(input).get(0).tagName == 'SELECT') { - // Create a new input to store selected tokens, original will be delete later - var hidden_input = $("") - .hide() - .val("") - .focus(function () { - input_box.focus(); - }) - .blur(function () { - input_box.blur(); - }) - .insertBefore(input); + // Create a new input to store selected tokens, original will be removed later + var hidden_input = $("") + .hide() + .val("") + .focus(function () { + focus_with_timeout(input_box); + }) + .blur(function () { + input_box.blur(); + return hidden_input; + }) + .insertBefore(input); + + // get prepopulate options and store them in hidden_input + var select_data = []; + $(input).children('option').each(function () { + var item = {}; + item[$(input).data("settings").tokenValue] = $(this).attr('value'); + item[$(input).data("settings").propertyToSearch] = $(this).text(); + select_data[ select_data.length ] = item; + }); + hidden_input.data("pre", select_data); + + // remove the SELECT object + hidden_input.data("settings", $(input).data("settings")); + $(input).remove(); + input = hidden_input[0]; + } else { - // 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 original input box + var hidden_input = $(input) + .hide() + .val("") + .focus(function () { + focus_with_timeout(input_box); + }) + .blur(function () { + input_box.blur(); + //return the object to this can be referenced in the callback functions. + return hidden_input; + }); } // Keep a reference to the selected token and dropdown item @@ -276,7 +432,7 @@ $.TokenList = function (input, url_or_data, settings) { // The list to store the token items in var token_list = $("