From 9d776f4f2ce5a5c0d8364eed0959683830428cd0 Mon Sep 17 00:00:00 2001 From: seif Date: Fri, 8 Aug 2014 15:15:22 -0600 Subject: [PATCH] GUI changes to leverage a new control for storage tags --- ui/css/token-input-facebook.css | 123 +++++ ui/index.jsp | 3 + ui/lib/jquery.tokeninput.js | 927 ++++++++++++++++++++++++++++++++ ui/scripts/system.js | 23 + ui/scripts/ui/dialog.js | 54 ++ 5 files changed, 1130 insertions(+) create mode 100644 ui/css/token-input-facebook.css create mode 100644 ui/lib/jquery.tokeninput.js diff --git a/ui/css/token-input-facebook.css b/ui/css/token-input-facebook.css new file mode 100644 index 00000000000..304a3bc40d2 --- /dev/null +++ b/ui/css/token-input-facebook.css @@ -0,0 +1,123 @@ +/* Example tokeninput style #2: Facebook style */ +ul.token-input-list-facebook { + overflow: hidden; + height: auto !important; + height: 1%; + width: 233px; + border: 1px solid #AFAFAF; + cursor: text; + font-size: 12px; + font-family: Verdana; + min-height: 1px; + z-index: 1010; + margin: 0; + padding: 0; + background-color: #F6F6F6; + list-style-type: none; + clear: left; +} + +ul.token-input-list-facebook li input { + border: 0; + width: 100px; + padding: 3px 8px; + background-color: white; + margin: 2px 0; + -webkit-appearance: caret; +} + +li.token-input-token-facebook { + 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-facebook p { + display: inline; + padding: 0; + margin: 0; +} + +li.token-input-token-facebook span { + color: #a6b3cf; + margin-left: 5px; + font-weight: bold; + cursor: pointer; +} + +li.token-input-selected-token-facebook { + background-color: #5670a6; + border: 1px solid #3b5998; + color: #fff; +} + +li.token-input-input-token-facebook { + float: left; + margin: 0; + padding: 0; + list-style-type: none; +} + +div.token-input-dropdown-facebook { + position: absolute; + width: 233px; + 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: 1010; +} + +div.token-input-dropdown-facebook p { + margin: 0; + width : 233px; + padding: 5px; + font-weight: bold; + color: #777; +} + +div.token-input-dropdown-facebook ul { + margin: 0; + padding: 0; +} + +div.token-input-dropdown-facebook ul li { + background-color: #fff; + padding: 3px; + margin: 0; + list-style-type: none; +} + +div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook { + background-color: #fff; +} + +div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook { + background-color: #fff; +} + +div.token-input-dropdown-facebook ul li em { + font-weight: bold; + font-style: normal; +} + +div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook { + background-color: #3b5998; + color: #fff; +} diff --git a/ui/index.jsp b/ui/index.jsp index 5840e7171d9..48afa6a6759 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -32,6 +32,7 @@ + @@ -1688,6 +1689,8 @@ + + diff --git a/ui/lib/jquery.tokeninput.js b/ui/lib/jquery.tokeninput.js new file mode 100644 index 00000000000..1a684d2e69a --- /dev/null +++ b/ui/lib/jquery.tokeninput.js @@ -0,0 +1,927 @@ +/* + * 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 part of a storage tag", + noResultsText: "No storage tags found", + searchingText: "Searching...", + deleteText: "×", + animateDropdown: true, + + // Tokenization settings + tokenLimit: null, + tokenDelimiter: ",", + preventDuplicates: false, + + // Output settings + tokenValue: "id", + + // Prepopulation settings + prePopulate: null, + processPrePopulate: false, + + // Manipulation settings + idPrefix: "token-input-", + + // Formatters + resultsFormatter: function(item){ return "
  • " + item[this.propertyToSearch]+ "
  • " }, + tokenFormatter: function(item) { return "
  • " + item[this.propertyToSearch] + "

  • " }, + + // 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(); + } +} + +//jquery function that sets the position of the cursor inside a text input +$.fn.selectRange = function(start, end) { + return this.each(function() { + if (this.setSelectionRange) { + this.focus(); + this.setSelectionRange(start, end); + } else if (this.createTextRange) { + var range = this.createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', start); + range.select(); + } + }); +}; + +// 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 = $("") + .css({ + outline: "none" + }) + .attr("id", settings.idPrefix + input.id) + .focus(function () { + if (settings.tokenLimit === null || settings.tokenLimit !== token_count) { + show_dropdown_hint(); + } + }) + .keyup(function() { + var contenu = $(this).val(); + var longueur = contenu.length; + var lastChar = contenu.substr(contenu.length - 1); + + if ((lastChar === ',' || lastChar === ' ') && ($.trim($(this).val()).length >= 1)) + { + var custom_token = { id : $.trim($(this).val().substring(0, longueur - 1)), name : $(this).val().substring(0, longueur - 1) }; + + add_token(custom_token); + $(this).val(""); + } + }) + .blur(function() { + hide_dropdown(); + + if ($.trim($(this).val()) != '') + { + var custom_token = { id : $.trim($(this).val()), name : $.trim($(this).val()) }; + + add_token(custom_token); + $(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: if(selected_dropdown_item) { + add_token($(selected_dropdown_item).data("tokeninput")); + hidden_input.change(); + return false; + } + break; + case KEY.NUMPAD_ENTER: if(selected_dropdown_item) { + add_token($(selected_dropdown_item).data("tokeninput")); + hidden_input.change(); + return false; + } + break; + case KEY.COMMA: + + 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; + } + }) + .keyup(function(event) { + var previous_token; + var next_token; + + switch(event.keyCode) { + case KEY.ENTER: + 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 = $("