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 @@
" + item[this.propertyToSearch] + "
"+settings.searchingText+"
"); + show_dropdown(); + } + } + + function show_dropdown_hint () { + if(settings.hintText) { + dropdown.html(""+settings.hintText+"
"); + show_dropdown(); + } + } + + function regexSanitize(str) { + return str.replace(/([.+*?:\[\](){}|\\])/g, "\\$1"); + } + + // Highlight the query part of the search term + function highlight_term(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + regexSanitize(term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + } + + function find_value_and_highlight_term(template, value, term) { + try { + b = regexSanitize(value); + a = template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + regexSanitize(value) + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term)); + } + catch (e) + { + alert(e); + + return false; + } + + return a; + } + + // Populate the results dropdown with some results + function populate_dropdown (query, results) { + if(results && results.length) { + dropdown.empty(); + var dropdown_ul = $(""+settings.noResultsText+"
"); + 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)); diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 592ae1fc04a..b65830158b2 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -16887,8 +16887,31 @@ storageTags: { label: 'label.storage.tags', docID: 'helpPrimaryStorageTags', + isTokenInput: true, validation: { required: false + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listStorageTags"), + dataType: "json", + success: function (json) { + var item = json.liststoragetagsresponse.storagetag; + var tags = $.map(item, function (tag) { + return { + id: tag.name, + name: tag.name + }; + }); + args.response.success({ + data: tags + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); } } //always appear (end) diff --git a/ui/scripts/ui/dialog.js b/ui/scripts/ui/dialog.js index ff1353e3b9d..14ea4dd1556 100644 --- a/ui/scripts/ui/dialog.js +++ b/ui/scripts/ui/dialog.js @@ -464,6 +464,60 @@ if (field.defaultValue) { $input.val(strOrFunc(field.defaultValue)); } + } else if (field.isTokenInput) { // jquery.tokeninput.js + isAsync = true; + selectArgs = { + context: args.context, + response: { + success: function(args) { + function equals(tag1, tag2) { + return (tag1.name == tag2.name) && (tag1.id == tag2.id); + } + + function contains(tag, tags) + { + for (var i = 0; i < tags.length; i++) + { + if (equals(tags[i], tag)) return true; + } + + return false; + } + + function unique_tags(tags) + { + var unique = []; + + if (tags != null) + { + for (var i = 0; i < tags.length; i++) + { + if (!contains(tags[i], unique)) + { + unique.push(tags[i]); + } + } + } + + return unique; + } + + $input.tokenInput(unique_tags(args.data), { theme: "facebook", preventDuplicates: true }); + } + } + }; + + $input = $('').attr({ + name: key, + type: 'text' + }).appendTo($value); + + $.extend(selectArgs, { + $form: $form, + type: 'createForm' + }); + + field.dataProvider(selectArgs); } else if (field.isDatepicker) { //jQuery datepicker $input = $('').attr({ name: key,