Changeset 23275
- Timestamp:
- 06/16/13 22:53:20 (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/admin/themes/default/template/batch_manager_global.tpl
r23055 r23275 56 56 {/literal}{/footer_script} 57 57 58 {combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 58 59 {combine_script id='jquery.tokeninput' load='footer' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 59 60 {combine_script id='jquery.progressBar' load='footer' path='themes/default/js/plugins/jquery.progressbar.min.js'} … … 74 75 animateDropdown: false, 75 76 preventDuplicates: true, 76 allow Creation: true77 allowFreeTagging: true 77 78 } 78 79 ); … … 86 87 animateDropdown: false, 87 88 preventDuplicates: true, 88 allow Creation: false89 allowFreeTagging: false 89 90 } 90 91 ); -
trunk/admin/themes/default/template/batch_manager_unit.tpl
r18974 r23275 3 3 {include file='include/colorbox.inc.tpl'} 4 4 5 {combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 5 6 {combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 6 7 {footer_script require='jquery.tokeninput'} … … 15 16 animateDropdown: false, 16 17 preventDuplicates: true, 17 allow Creation: true18 allowFreeTagging: true 18 19 } 19 20 ); -
trunk/admin/themes/default/template/picture_modify.tpl
r20531 r23275 12 12 {/literal}{/footer_script} 13 13 14 {combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 14 15 {combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 15 16 {footer_script require='jquery.tokeninput'} … … 24 25 animateDropdown: false, 25 26 preventDuplicates: true, 26 allow Creation: true27 allowFreeTagging: true 27 28 } 28 29 ); -
trunk/admin/themes/default/theme.css
r23259 r23275 963 963 #batchManagerGlobal #filter_dimension .ui-slider-horizontal {width:650px;margin:5px 0 10px 0;} 964 964 965 966 /* TokenInput (with Facebook style) */967 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;}968 ul.token-input-list li input {border: 0;width: 100px;padding: 3px 8px;background-color: white;margin: 2px 0;-webkit-appearance: caret;}969 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;}970 li.token-input-token p {display: inline;padding: 0;margin: 0;}971 li.token-input-token span {color: #a6b3cf;margin-left: 5px;font-weight: bold;cursor: pointer;}972 li.token-input-selected-token {background-color: #5670a6;border: 1px solid #3b5998;color: #fff;}973 li.token-input-input-token {float: left;margin: 0;padding: 0;list-style-type: none;width:10px;}974 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;}975 div.token-input-dropdown p {margin: 0;padding: 5px;font-weight: bold;color: #777;}976 div.token-input-dropdown ul {margin: 0;padding: 0;}977 div.token-input-dropdown ul li {background-color: #fff;padding: 3px;margin: 0;list-style-type: none;}978 div.token-input-dropdown ul li.token-input-dropdown-item {background-color: #fff;}979 div.token-input-dropdown ul li.token-input-dropdown-item2 {background-color: #fff;}980 div.token-input-dropdown ul li em {font-weight: bold;font-style: normal;}981 div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color: #3b5998;color: #fff;}982 983 965 #mainConf a.addFilter {font-weight:normal;margin-left:20px;} 984 966 #mainConf a.removeFilter {font-weight:normal;} -
trunk/admin/themes/roma/theme.css
r23121 r23275 275 275 276 276 /* TokenInput (with Facebook style for ROMA) */ 277 ul.token-input-list {border-color:#666 ;background-color:#444;}278 ul.token-input-list li input {background-color:#444 ;}279 li.token-input-token span {color:#878787 ;}280 div.token-input-dropdown {background-color:#eee ;border-color:#666;}281 div.token-input-dropdown ul li {background-color:#eee ;}282 div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color:#FF7800 ;}277 ul.token-input-list {border-color:#666 !important;background-color:#444 !important;} 278 ul.token-input-list li input {background-color:#444 !important;} 279 li.token-input-token span {color:#878787 !important;} 280 div.token-input-dropdown {background-color:#eee !important;border-color:#666 !important;} 281 div.token-input-dropdown ul li {background-color:#eee !important;} 282 div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color:#FF7800 !important;} 283 283 284 284 #progressbar {border:1px solid #666; background-color:#666;} -
trunk/themes/default/js/plugins/jquery.tokeninput.js
r23231 r23275 1 /**2 DON'T MAKE AUTOMATIC UPGRADE3 This is a merged version of :4 + https://github.com/gr2m/jquery-tokeninput/5 + https://github.com/mistic100/jquery-tokeninput/6 */7 8 1 /* 9 2 * jQuery Plugin: Tokenizing Autocomplete Text Entry 10 * Version 1. 4.23 * Version 1.6.1 11 4 * 12 5 * Copyright (c) 2009 James Smith (http://loopj.com) … … 14 7 * choose which one suits your project best! 15 8 * 9 * https://github.com/mistic100/jquery-tokeninput 16 10 */ 17 11 … … 19 13 // Default settings 20 14 var DEFAULT_SETTINGS = { 15 // Search settings 16 method: "GET", 17 queryParam: "q", 18 searchDelay: 300, 19 minChars: 1, 20 propertyToSearch: "name", 21 jsonContainer: null, 22 contentType: "json", 23 24 // Prepopulation settings 25 prePopulate: null, 26 processPrePopulate: false, 27 28 // Display settings 21 29 hintText: "Type in a search term", 22 30 noResultsText: "No results", 23 31 searchingText: "Searching...", 24 newText: "(new)",25 32 deleteText: "×", 26 searchDelay: 300, 27 minChars: 1, 33 newText: " (new)", 34 animateDropdown: true, 35 placeholder: null, 36 theme: null, 37 zindex: 999, 38 resultsLimit: null, 39 40 enableHTML: false, 41 42 resultsFormatter: function(item) { 43 var string = item[this.propertyToSearch]; 44 return "<li>" + (this.enableHTML ? string : _escapeHTML(string)) + "</li>"; 45 }, 46 47 tokenFormatter: function(item) { 48 var string = item[this.propertyToSearch]; 49 return "<li><p>" + (this.enableHTML ? string : _escapeHTML(string)) + "</p></li>"; 50 }, 51 52 // Tokenization settings 28 53 tokenLimit: null, 29 jsonContainer: null,30 method: "GET",31 contentType: "json",32 queryParam: "q",33 54 tokenDelimiter: ",", 34 55 preventDuplicates: false, 35 prePopulate: null, 36 processPrePopulate: false, 37 animateDropdown: true, 56 tokenValue: "id", 57 58 // Behavioral settings 59 allowFreeTagging: false, 60 freeTaggingHint: true, 61 allowTabOut: false, 62 63 // Callbacks 38 64 onResult: null, 65 onCachedResult: null, 39 66 onAdd: null, 67 onFreeTaggingAdd: null, 40 68 onDelete: null, 41 allowCreation: false, 42 caseSensitive: false 69 onReady: null, 70 71 // Other settings 72 idPrefix: "token-input-", 73 74 // Keep track if the input is currently in disabled mode 75 disabled: false 43 76 }; 44 77 … … 47 80 tokenList: "token-input-list", 48 81 token: "token-input-token", 82 tokenReadOnly: "token-input-token-readonly", 49 83 tokenDelete: "token-input-delete-token", 50 84 selectedToken: "token-input-selected-token", … … 54 88 dropdownItem2: "token-input-dropdown-item2", 55 89 selectedDropdownItem: "token-input-selected-dropdown-item", 56 inputToken: "token-input-input-token" 90 inputToken: "token-input-input-token", 91 focused: "token-input-focused", 92 disabled: "token-input-disabled" 57 93 }; 58 94 … … 83 119 }; 84 120 121 var HTML_ESCAPES = { 122 '&': '&', 123 '<': '<', 124 '>': '>', 125 '"': '"', 126 "'": ''', 127 '/': '/' 128 }; 129 130 var HTML_ESCAPE_CHARS = /[&<>"'\/]/g; 131 132 function coerceToString(val) { 133 return String((val === null || val === undefined) ? '' : val); 134 } 135 136 function _escapeHTML(text) { 137 return coerceToString(text).replace(HTML_ESCAPE_CHARS, function(match) { 138 return HTML_ESCAPES[match]; 139 }); 140 } 141 142 // Additional public (exposed) methods 143 var methods = { 144 init: function(url_or_data_or_function, options) { 145 var settings = $.extend({}, DEFAULT_SETTINGS, options || {}); 146 147 return this.each(function () { 148 $(this).data("settings", settings); 149 $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings)); 150 }); 151 }, 152 clear: function() { 153 this.data("tokenInputObject").clear(); 154 return this; 155 }, 156 add: function(item) { 157 this.data("tokenInputObject").add(item); 158 return this; 159 }, 160 remove: function(item) { 161 this.data("tokenInputObject").remove(item); 162 return this; 163 }, 164 get: function() { 165 return this.data("tokenInputObject").getTokens(); 166 }, 167 toggleDisabled: function(disable) { 168 this.data("tokenInputObject").toggleDisabled(disable); 169 return this; 170 }, 171 setOptions: function(options){ 172 $(this).data("settings", $.extend({}, $(this).data("settings"), options || {})); 173 return this; 174 }, 175 destroy: function () { 176 if(this.data("tokenInputObject")){ 177 this.data("tokenInputObject").clear(); 178 var tmpInput = this; 179 var closest = this.parent(); 180 closest.empty(); 181 tmpInput.show(); 182 closest.append(tmpInput); 183 return tmpInput; 184 } 185 } 186 }; 85 187 86 188 // Expose the .tokenInput function to jQuery as a plugin 87 $.fn.tokenInput = function (url_or_data, options) { 88 var settings = $.extend({}, DEFAULT_SETTINGS, options || {}); 89 90 return this.each(function () { 91 new $.TokenList(this, url_or_data, settings); 92 }); 189 $.fn.tokenInput = function (method) { 190 // Method calling and initialization logic 191 if(methods[method]) { 192 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 193 } else { 194 return methods.init.apply(this, arguments); 195 } 93 196 }; 94 95 197 96 198 // TokenList class for each input … … 101 203 102 204 // Configure the data source 103 if( typeof(url_or_data) === "string") {205 if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") { 104 206 // Set the url to query against 105 settings.url = url_or_data; 207 $(input).data("settings").url = url_or_data; 208 209 // If the URL is a function, evaluate it here to do our initalization work 210 var url = computeURL(); 106 211 107 212 // Make a smart guess about cross-domain if it wasn't explicitly specified 108 if( settings.crossDomain === undefined) {109 if( settings.url.indexOf("://") === -1) {110 settings.crossDomain = false;213 if($(input).data("settings").crossDomain === undefined && typeof url === "string") { 214 if(url.indexOf("://") === -1) { 215 $(input).data("settings").crossDomain = false; 111 216 } else { 112 settings.crossDomain = (location.href.split(/\/+/g)[1] !== settings.url.split(/\/+/g)[1]);217 $(input).data("settings").crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]); 113 218 } 114 219 } 115 220 } else if(typeof(url_or_data) === "object") { 116 221 // Set the local data to search through 117 settings.local_data = url_or_data;222 $(input).data("settings").local_data = url_or_data; 118 223 } 119 224 120 225 // Build class names 121 if( settings.classes) {226 if($(input).data("settings").classes) { 122 227 // Use custom class names 123 settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);124 } else if( settings.theme) {228 $(input).data("settings").classes = $.extend({}, DEFAULT_CLASSES, $(input).data("settings").classes); 229 } else if($(input).data("settings").theme) { 125 230 // Use theme-suffixed default class names 126 settings.classes = {};231 $(input).data("settings").classes = {}; 127 232 $.each(DEFAULT_CLASSES, function(key, value) { 128 settings.classes[key] = value + "-" + settings.theme;233 $(input).data("settings").classes[key] = value + "-" + $(input).data("settings").theme; 129 234 }); 130 235 } else { 131 settings.classes = DEFAULT_CLASSES;236 $(input).data("settings").classes = DEFAULT_CLASSES; 132 237 } 133 238 … … 147 252 148 253 // Create a new text input an attach keyup events 149 var input_box = $("<input type=\"text\" autocomplete=\"off\" >")254 var input_box = $("<input type=\"text\" autocomplete=\"off\" autocapitalize=\"off\">") 150 255 .css({ 151 256 outline: "none" 152 257 }) 258 .attr("id", $(input).data("settings").idPrefix + input.id) 153 259 .focus(function () { 154 if (settings.tokenLimit === null || settings.tokenLimit !== token_count) { 260 if ($(input).data("settings").disabled) { 261 return false; 262 } else 263 if ($(input).data("settings").tokenLimit === null || $(input).data("settings").tokenLimit !== token_count) { 155 264 show_dropdown_hint(); 156 265 } 266 token_list.addClass($(input).data("settings").classes.focused); 157 267 }) 158 268 .blur(function () { 159 269 hide_dropdown(); 270 271 if ($(input).data("settings").allowFreeTagging) { 272 add_freetagging_tokens(); 273 } 274 275 $(this).val(""); 276 token_list.removeClass($(input).data("settings").classes.focused); 160 277 }) 161 278 .bind("keyup keydown blur update", resize_input) … … 199 316 select_dropdown_item(dropdown_item); 200 317 } 201 return false;202 318 } 319 return false; 203 320 break; 204 321 … … 209 326 if(selected_token) { 210 327 delete_token($(selected_token)); 328 hidden_input.change(); 211 329 } else if(previous_token.length) { 212 330 select_token($(previous_token.get(0))); … … 227 345 case KEY.COMMA: 228 346 if(selected_dropdown_item) { 229 add_token($(selected_dropdown_item)); 230 return false; 347 add_token($(selected_dropdown_item).data("tokeninput")); 348 hidden_input.change(); 349 } else { 350 if ($(input).data("settings").allowFreeTagging) { 351 if($(input).data("settings").allowTabOut && $(this).val() === "") { 352 return true; 353 } else { 354 add_freetagging_tokens(); 355 } 356 } else { 357 $(this).val(""); 358 if($(input).data("settings").allowTabOut) { 359 return true; 360 } 361 } 362 event.stopPropagation(); 363 event.preventDefault(); 231 364 } 232 break;365 return false; 233 366 234 367 case KEY.ESCAPE: … … 245 378 }); 246 379 380 // Keep reference for placeholder 381 if (settings.placeholder) 382 input_box.attr("placeholder", settings.placeholder) 383 247 384 if ($(input).get(0).tagName == 'SELECT') { 248 // Create a new input to store selected tokens, original will be delete later 249 var hidden_input = $("<input type=\"text\" name=\"" + $(input).attr('name') + "\" autocomplete=\"off\">") 250 .hide() 251 .val("") 252 .focus(function () { 253 input_box.focus(); 254 }) 255 .blur(function () { 256 input_box.blur(); 257 }) 258 .insertBefore(input); 385 // Create a new input to store selected tokens, original will be removed later 386 var hidden_input = $("<input type=\"text\" name=\"" + $(input).attr('name') + "\" autocomplete=\"off\">") 387 .hide() 388 .val("") 389 .focus(function () { 390 focus_with_timeout(input_box); 391 }) 392 .blur(function () { 393 input_box.blur(); 394 return hidden_input; 395 }) 396 .insertBefore(input); 397 398 // get prepopulate options and store them in hidden_input 399 var select_data = []; 400 $(input).children('option').each(function () { 401 var item = {}; 402 item[$(input).data("settings").tokenValue] = $(this).attr('value'); 403 item[$(input).data("settings").propertyToSearch] = $(this).text(); 404 select_data[ select_data.length ] = item; 405 }); 406 hidden_input.data("pre", select_data); 407 408 // remove the SELECT object 409 hidden_input.data("settings", $(input).data("settings")); 410 $(input).remove(); 411 input = hidden_input[0]; 412 259 413 } else { 260 // Keep a reference to the original input box 261 var hidden_input = $(input) 262 .hide() 263 .val("") 264 .focus(function () { 265 input_box.focus(); 266 }) 267 .blur(function () { 268 input_box.blur(); 269 }); 414 // Keep a reference to the original input box 415 var hidden_input = $(input) 416 .hide() 417 .val("") 418 .focus(function () { 419 focus_with_timeout(input_box); 420 }) 421 .blur(function () { 422 input_box.blur(); 423 //return the object to this can be referenced in the callback functions. 424 return hidden_input; 425 }); 270 426 } 271 427 … … 277 433 // The list to store the token items in 278 434 var token_list = $("<ul />") 279 .addClass( settings.classes.tokenList)435 .addClass($(input).data("settings").classes.tokenList) 280 436 .click(function (event) { 281 437 var li = $(event.target).closest("li"); … … 289 445 290 446 // Focus input box 291 input_box.focus();447 focus_with_timeout(input_box); 292 448 } 293 449 }) … … 295 451 var li = $(event.target).closest("li"); 296 452 if(li && selected_token !== this) { 297 li.addClass( settings.classes.highlightedToken);453 li.addClass($(input).data("settings").classes.highlightedToken); 298 454 } 299 455 }) … … 301 457 var li = $(event.target).closest("li"); 302 458 if(li && selected_token !== this) { 303 li.removeClass( settings.classes.highlightedToken);459 li.removeClass($(input).data("settings").classes.highlightedToken); 304 460 } 305 461 }) … … 308 464 // The token holding the input box 309 465 var input_token = $("<li />") 310 .addClass( settings.classes.inputToken)466 .addClass($(input).data("settings").classes.inputToken) 311 467 .appendTo(token_list) 312 468 .append(input_box); … … 314 470 // The list to store the dropdown items in 315 471 var dropdown = $("<div>") 316 .addClass( settings.classes.dropdown)472 .addClass($(input).data("settings").classes.dropdown) 317 473 .appendTo("body") 318 474 .hide(); … … 335 491 // Pre-populate list if items exist 336 492 hidden_input.val(""); 337 var li_data = settings.prePopulate || hidden_input.data("pre");338 if( settings.processPrePopulate && $.isFunction(settings.onResult)) {339 li_data = settings.onResult.call(hidden_input, li_data);340 } 493 var li_data = $(input).data("settings").prePopulate || hidden_input.data("pre"); 494 if($(input).data("settings").processPrePopulate && $.isFunction($(input).data("settings").onResult)) { 495 li_data = $(input).data("settings").onResult.call(hidden_input, li_data); 496 } 341 497 if(li_data && li_data.length) { 342 498 $.each(li_data, function (index, value) { 343 insert_token(value.id, value.name); 499 insert_token(value); 500 checkTokenLimit(); 501 input_box.attr("placeholder", null) 344 502 }); 345 503 } 346 347 // Pre-populate from SELECT options 348 if ($(input).get(0).tagName == 'SELECT') { 349 $(input).children('option').each(function () { 350 insert_token($(this).attr('value'), $(this).text()); 351 }); 352 } 353 354 504 505 // Check if widget should initialize as disabled 506 if ($(input).data("settings").disabled) { 507 toggleDisabled(true); 508 } 509 510 // Initialization is done 511 if($.isFunction($(input).data("settings").onReady)) { 512 $(input).data("settings").onReady.call(); 513 } 514 515 // 516 // Public functions 517 // 518 519 this.clear = function() { 520 token_list.children("li").each(function() { 521 if ($(this).children("input").length === 0) { 522 delete_token($(this)); 523 } 524 }); 525 }; 526 527 this.add = function(item) { 528 add_token(item); 529 }; 530 531 this.remove = function(item) { 532 token_list.children("li").each(function() { 533 if ($(this).children("input").length === 0) { 534 var currToken = $(this).data("tokeninput"); 535 var match = true; 536 for (var prop in item) { 537 if (item[prop] !== currToken[prop]) { 538 match = false; 539 break; 540 } 541 } 542 if (match) { 543 delete_token($(this)); 544 } 545 } 546 }); 547 }; 548 549 this.getTokens = function() { 550 return saved_tokens; 551 }; 552 553 this.toggleDisabled = function(disable) { 554 toggleDisabled(disable); 555 }; 556 557 // Resize input to maximum width so the placeholder can be seen 558 resize_input(); 355 559 356 560 // … … 358 562 // 359 563 564 function escapeHTML(text) { 565 return $(input).data("settings").enableHTML ? text : _escapeHTML(text); 566 } 567 568 // Toggles the widget between enabled and disabled state, or according 569 // to the [disable] parameter. 570 function toggleDisabled(disable) { 571 if (typeof disable === 'boolean') { 572 $(input).data("settings").disabled = disable 573 } else { 574 $(input).data("settings").disabled = !$(input).data("settings").disabled; 575 } 576 input_box.attr('disabled', $(input).data("settings").disabled); 577 token_list.toggleClass($(input).data("settings").classes.disabled, $(input).data("settings").disabled); 578 // if there is any token selected we deselect it 579 if(selected_token) { 580 deselect_token($(selected_token), POSITION.END); 581 } 582 hidden_input.attr('disabled', $(input).data("settings").disabled); 583 } 584 585 function checkTokenLimit() { 586 if($(input).data("settings").tokenLimit !== null && token_count >= $(input).data("settings").tokenLimit) { 587 input_box.hide(); 588 hide_dropdown(); 589 return; 590 } 591 } 592 360 593 function resize_input() { 361 594 if(input_val === (input_val = input_box.val())) {return;} 362 595 596 // Get width left on the current line 597 var width_left = token_list.width() - input_box.offset().left - token_list.offset().left; 363 598 // Enter new content into resizer and resize input accordingly 364 var escaped = input_val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>'); 365 input_resizer.html(escaped); 366 input_box.width(input_resizer.width() + 30); 599 input_resizer.html(_escapeHTML(input_val)); 600 // Get maximum width, minimum the size of input and maximum the widget's width 601 input_box.width(Math.min(token_list.width(), 602 Math.max(width_left, input_resizer.width() + 30))); 367 603 } 368 604 … … 374 610 } 375 611 612 function add_freetagging_tokens() { 613 var value = $.trim(input_box.val()); 614 var tokens = value.split($(input).data("settings").tokenDelimiter); 615 $.each(tokens, function(i, token) { 616 if (!token) { 617 return; 618 } 619 620 if ($.isFunction($(input).data("settings").onFreeTaggingAdd)) { 621 token = $(input).data("settings").onFreeTaggingAdd.call(hidden_input, token); 622 } 623 var object = {}; 624 object[$(input).data("settings").tokenValue] = object[$(input).data("settings").propertyToSearch] = token; 625 add_token(object); 626 }); 627 } 628 376 629 // Inner function to a token to the list 377 function insert_token(id, value) { 378 var this_token = $("<li><p>"+ value +"</p></li>") 379 .addClass(settings.classes.token) 380 .insertBefore(input_token); 630 function insert_token(item) { 631 var $this_token = $($(input).data("settings").tokenFormatter(item)); 632 var readonly = item.readonly === true ? true : false; 633 634 if(readonly) $this_token.addClass($(input).data("settings").classes.tokenReadOnly); 635 636 $this_token.addClass($(input).data("settings").classes.token).insertBefore(input_token); 381 637 382 638 // The 'delete token' button 383 $("<span>" + settings.deleteText + "</span>") 384 .addClass(settings.classes.tokenDelete) 385 .appendTo(this_token) 386 .click(function () { 387 delete_token($(this).parent()); 388 return false; 389 }); 639 if(!readonly) { 640 $("<span>" + $(input).data("settings").deleteText + "</span>") 641 .addClass($(input).data("settings").classes.tokenDelete) 642 .appendTo($this_token) 643 .click(function () { 644 if (!$(input).data("settings").disabled) { 645 delete_token($(this).parent()); 646 hidden_input.change(); 647 return false; 648 } 649 }); 650 } 390 651 391 652 // Store data on the token 392 var token_data = {"id": id, "name": value};393 $.data( this_token.get(0), "tokeninput", token_data);653 var token_data = item; 654 $.data($this_token.get(0), "tokeninput", item); 394 655 395 656 // Save this token for duplicate checking … … 398 659 399 660 // Update the hidden input 400 var token_ids = $.map(saved_tokens, function (el) { 401 return el.id; 402 }); 403 hidden_input.val(token_ids.join(settings.tokenDelimiter)); 661 update_hidden_input(saved_tokens, hidden_input); 404 662 405 663 token_count += 1; 406 664 407 return this_token; 665 // Check the token limit 666 if($(input).data("settings").tokenLimit !== null && token_count >= $(input).data("settings").tokenLimit) { 667 input_box.hide(); 668 hide_dropdown(); 669 } 670 671 return $this_token; 408 672 } 409 673 410 674 // Add a token to the token list based on user input 411 675 function add_token (item) { 412 var li_data = $.data(item.get(0), "tokeninput"); 413 var callback = settings.onAdd; 676 var callback = $(input).data("settings").onAdd; 414 677 415 678 // See if the token already exists and select it if we don't want duplicates 416 if(token_count > 0 && settings.preventDuplicates) {679 if(token_count > 0 && $(input).data("settings").preventDuplicates) { 417 680 var found_existing_token = null; 418 681 token_list.children().each(function () { 419 682 var existing_token = $(this); 420 683 var existing_data = $.data(existing_token.get(0), "tokeninput"); 421 if(existing_data && existing_data .id === li_data.id) {684 if(existing_data && existing_data[settings.tokenValue] === item[settings.tokenValue]) { 422 685 found_existing_token = existing_token; 423 686 return false; … … 428 691 select_token(found_existing_token); 429 692 input_token.insertAfter(found_existing_token); 430 input_box.focus();693 focus_with_timeout(input_box); 431 694 return; 432 695 } 433 696 } 434 697 698 // Squeeze input_box so we force no unnecessary line break 699 input_box.width(0); 700 435 701 // Insert the new tokens 436 insert_token(li_data.id, li_data.name); 437 438 // Check the token limit 439 if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) { 440 input_box.hide(); 441 hide_dropdown(); 442 return; 443 } else { 444 input_box.focus(); 702 if($(input).data("settings").tokenLimit == null || token_count < $(input).data("settings").tokenLimit) { 703 insert_token(item); 704 // Remove the placeholder so it's not seen after you've added a token 705 input_box.attr("placeholder", null) 706 checkTokenLimit(); 445 707 } 446 708 … … 453 715 // Execute the onAdd callback if defined 454 716 if($.isFunction(callback)) { 455 callback.call(hidden_input, li_data);717 callback.call(hidden_input,item); 456 718 } 457 719 } … … 459 721 // Select a token in the token list 460 722 function select_token (token) { 461 token.addClass(settings.classes.selectedToken); 462 selected_token = token.get(0); 463 464 // Hide input box 465 input_box.val(""); 466 467 // Hide dropdown if it is visible (eg if we clicked to select token) 468 hide_dropdown(); 723 if (!$(input).data("settings").disabled) { 724 token.addClass($(input).data("settings").classes.selectedToken); 725 selected_token = token.get(0); 726 727 // Hide input box 728 input_box.val(""); 729 730 // Hide dropdown if it is visible (eg if we clicked to select token) 731 hide_dropdown(); 732 } 469 733 } 470 734 471 735 // Deselect a token in the token list 472 736 function deselect_token (token, position) { 473 token.removeClass( settings.classes.selectedToken);737 token.removeClass($(input).data("settings").classes.selectedToken); 474 738 selected_token = null; 475 739 … … 486 750 487 751 // Show the input box and give it focus again 488 input_box.focus();752 focus_with_timeout(input_box); 489 753 } 490 754 … … 508 772 // Remove the id from the saved list 509 773 var token_data = $.data(token.get(0), "tokeninput"); 510 var callback = settings.onDelete;774 var callback = $(input).data("settings").onDelete; 511 775 512 776 var index = token.prevAll().length; … … 518 782 519 783 // Show the input box and give it focus again 520 input_box.focus();784 focus_with_timeout(input_box); 521 785 522 786 // Remove this token from the saved list 523 787 saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1)); 788 if (saved_tokens.length == 0) { 789 input_box.attr("placeholder", settings.placeholder) 790 } 524 791 if(index < selected_token_index) selected_token_index--; 525 792 526 793 // Update the hidden input 527 var token_ids = $.map(saved_tokens, function (el) { 528 return el.id; 529 }); 530 hidden_input.val(token_ids.join(settings.tokenDelimiter)); 794 update_hidden_input(saved_tokens, hidden_input); 531 795 532 796 token_count -= 1; 533 797 534 if( settings.tokenLimit !== null) {798 if($(input).data("settings").tokenLimit !== null) { 535 799 input_box 536 800 .show() 537 .val("") 538 .focus();801 .val(""); 802 focus_with_timeout(input_box); 539 803 } 540 804 … … 543 807 callback.call(hidden_input,token_data); 544 808 } 809 } 810 811 // Update the hidden input box value 812 function update_hidden_input(saved_tokens, hidden_input) { 813 var token_values = $.map(saved_tokens, function (el) { 814 if(typeof $(input).data("settings").tokenValue == 'function') 815 return $(input).data("settings").tokenValue.call(this, el); 816 817 return el[$(input).data("settings").tokenValue]; 818 }); 819 hidden_input.val(token_values.join($(input).data("settings").tokenDelimiter)); 820 545 821 } 546 822 … … 555 831 .css({ 556 832 position: "absolute", 557 top: $(token_list).offset().top + $(token_list).outerHeight(), 558 left: $(token_list).offset().left, 559 zindex: 999 833 top: token_list.offset().top + token_list.outerHeight(), 834 left: token_list.offset().left, 835 width: token_list.width(), 836 'z-index': $(input).data("settings").zindex 560 837 }) 561 838 .show(); … … 563 840 564 841 function show_dropdown_searching () { 565 if( settings.searchingText) {566 dropdown.html("<p>" +settings.searchingText+"</p>");842 if($(input).data("settings").searchingText) { 843 dropdown.html("<p>" + escapeHTML($(input).data("settings").searchingText) + "</p>"); 567 844 show_dropdown(); 568 845 } … … 570 847 571 848 function show_dropdown_hint () { 572 if( settings.hintText) {573 dropdown.html("<p>" +settings.hintText+"</p>");849 if($(input).data("settings").hintText) { 850 dropdown.html("<p>" + escapeHTML($(input).data("settings").hintText) + "</p>"); 574 851 show_dropdown(); 575 852 } 853 } 854 855 var regexp_special_chars = new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'); 856 function regexp_escape(term) { 857 return term.replace(regexp_special_chars, '\\$&'); 576 858 } 577 859 578 860 // Highlight the query part of the search term 579 861 function highlight_term(value, term) { 580 var param = "g"; 581 if (!settings.caseSensitive) param+= "i"; 582 return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + escape_regexp_chars(term) + ")(?![^<>]*>)(?![^&;]+;)", param), "<b>$1</b>"); 583 } 584 585 function escape_regexp_chars(string) { 586 var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\ 587 return string.replace(specials, "\\$&"); 862 return value.replace( 863 new RegExp( 864 "(?![^&;]+;)(?!<[^<>]*)(" + regexp_escape(term) + ")(?![^<>]*>)(?![^&;]+;)", 865 "gi" 866 ), function(match, p1) { 867 return "<b>" + escapeHTML(p1) + "</b>"; 868 } 869 ); 870 } 871 872 function find_value_and_highlight_term(template, value, term) { 873 return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + regexp_escape(value) + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term)); 588 874 } 589 875 … … 598 884 }) 599 885 .mousedown(function (event) { 600 add_token($(event.target).closest("li")); 886 add_token($(event.target).closest("li").data("tokeninput")); 887 hidden_input.change(); 601 888 return false; 602 889 }) 603 890 .hide(); 604 891 892 if ($(input).data("settings").resultsLimit && results.length > $(input).data("settings").resultsLimit) { 893 results = results.slice(0, $(input).data("settings").resultsLimit); 894 } 895 605 896 $.each(results, function(index, value) { 606 var this_li = $("<li>" + highlight_term(value.name, query) + "</li>") 607 .appendTo(dropdown_ul); 897 var this_li = $(input).data("settings").resultsFormatter(value); 898 899 this_li = find_value_and_highlight_term(this_li ,value[$(input).data("settings").propertyToSearch], query); 900 901 this_li = $(this_li).appendTo(dropdown_ul); 608 902 609 903 if(index % 2) { 610 this_li.addClass( settings.classes.dropdownItem);904 this_li.addClass($(input).data("settings").classes.dropdownItem); 611 905 } else { 612 this_li.addClass( settings.classes.dropdownItem2);906 this_li.addClass($(input).data("settings").classes.dropdownItem2); 613 907 } 614 908 … … 617 911 } 618 912 619 $.data(this_li.get(0), "tokeninput", {"id": value.id, "name": value.name});913 $.data(this_li.get(0), "tokeninput", value); 620 914 }); 621 915 622 916 show_dropdown(); 623 917 624 if( settings.animateDropdown) {918 if($(input).data("settings").animateDropdown) { 625 919 dropdown_ul.slideDown("fast"); 626 920 } else { … … 628 922 } 629 923 } else { 630 if( settings.noResultsText) {631 dropdown.html("<p>" +settings.noResultsText+"</p>");924 if($(input).data("settings").noResultsText) { 925 dropdown.html("<p>" + escapeHTML($(input).data("settings").noResultsText) + "</p>"); 632 926 show_dropdown(); 633 927 } … … 642 936 } 643 937 644 item.addClass( settings.classes.selectedDropdownItem);938 item.addClass($(input).data("settings").classes.selectedDropdownItem); 645 939 selected_dropdown_item = item.get(0); 646 940 } … … 649 943 // Remove highlighting from an item in the results dropdown 650 944 function deselect_dropdown_item (item) { 651 item.removeClass( settings.classes.selectedDropdownItem);945 item.removeClass($(input).data("settings").classes.selectedDropdownItem); 652 946 selected_dropdown_item = null; 653 947 } 654 948 655 949 // Do a search and show the "searching" dropdown if the input is longer 656 // than settings.minChars950 // than $(input).data("settings").minChars 657 951 function do_search() { 658 952 var query = input_box.val(); 659 if (!settings.caseSensitive) query = query.toLowerCase();660 953 661 954 if(query && query.length) { … … 664 957 } 665 958 666 if(query.length >= settings.minChars) {959 if(query.length >= $(input).data("settings").minChars) { 667 960 show_dropdown_searching(); 668 961 clearTimeout(timeout); … … 670 963 timeout = setTimeout(function(){ 671 964 run_search(query); 672 }, settings.searchDelay);965 }, $(input).data("settings").searchDelay); 673 966 } else { 674 967 hide_dropdown(); … … 679 972 // Do the actual search 680 973 function run_search(query) { 681 var cached_results = cache.get(query); 974 var cache_key = query + computeURL(); 975 var cached_results = cache.get(cache_key); 682 976 if(cached_results) { 977 if ($.isFunction($(input).data("settings").onCachedResult)) { 978 cached_results = $(input).data("settings").onCachedResult.call(hidden_input, cached_results); 979 } 683 980 populate_dropdown(query, cached_results); 684 981 } else { 685 982 // Are we doing an ajax search or local data search? 686 if(settings.url) { 983 if($(input).data("settings").url) { 984 var url = computeURL(); 687 985 // Extract exisiting get params 688 986 var ajax_params = {}; 689 987 ajax_params.data = {}; 690 if( settings.url.indexOf("?") > -1) {691 var parts = settings.url.split("?");988 if(url.indexOf("?") > -1) { 989 var parts = url.split("?"); 692 990 ajax_params.url = parts[0]; 693 991 … … 698 996 }); 699 997 } else { 700 ajax_params.url = settings.url;998 ajax_params.url = url; 701 999 } 702 1000 703 1001 // Prepare the request 704 ajax_params.data[ settings.queryParam] = query;705 ajax_params.type = settings.method;706 ajax_params.dataType = settings.contentType;707 if( settings.crossDomain) {1002 ajax_params.data[$(input).data("settings").queryParam] = query; 1003 ajax_params.type = $(input).data("settings").method; 1004 ajax_params.dataType = $(input).data("settings").contentType; 1005 if($(input).data("settings").crossDomain) { 708 1006 ajax_params.dataType = "jsonp"; 709 1007 } … … 711 1009 // Attach the success callback 712 1010 ajax_params.success = function(results) { 713 if($.isFunction(settings.onResult)) { 714 results = settings.onResult.call(hidden_input, results); 1011 cache.add(cache_key, $(input).data("settings").jsonContainer ? results[$(input).data("settings").jsonContainer] : results); 1012 if($.isFunction($(input).data("settings").onResult)) { 1013 results = $(input).data("settings").onResult.call(hidden_input, results); 715 1014 } 716 1015 717 if( settings.allowCreation) {718 results.push({name: input_box.val() + settings.newText, id: input_box.val()});1016 if($(input).data("settings").allowFreeTagging && $(input).data("settings").freeTaggingHint) { 1017 results.push({name: input_box.val() + $(input).data("settings").newText, id: input_box.val()}); 719 1018 } 720 cache.add(query, settings.jsonContainer ? results[settings.jsonContainer] : results);721 1019 722 1020 // only populate the dropdown if the results are associated with the active search query 723 var value = input_box.val(); 724 if (!settings.caseSensitive) value = value.toLowerCase(); 725 if(value === query) { 726 populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results); 1021 if(input_box.val() === query) { 1022 populate_dropdown(query, $(input).data("settings").jsonContainer ? results[$(input).data("settings").jsonContainer] : results); 727 1023 } 728 1024 }; … … 730 1026 // Make the request 731 1027 $.ajax(ajax_params); 732 } else if( settings.local_data) {1028 } else if($(input).data("settings").local_data) { 733 1029 // Do the search through local data 734 var results = $.grep(settings.local_data, function (row) { 735 if (settings.caseSensitive) { 736 return row.name.indexOf(query) > -1; 737 } 738 else { 739 return row.name.toLowerCase().indexOf(query.toLowerCase()) > -1; 740 } 1030 var results = $.grep($(input).data("settings").local_data, function (row) { 1031 return row[$(input).data("settings").propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1; 741 1032 }); 742 743 if($ .isFunction(settings.onResult)) {744 results = settings.onResult.call(hidden_input, results);1033 1034 if($(input).data("settings").allowFreeTagging && $(input).data("settings").freeTaggingHint) { 1035 results.push({name: input_box.val() + $(input).data("settings").newText, id: input_box.val()}); 745 1036 } 746 747 if(settings.allowCreation) { 748 results.push({name: input_box.val() + settings.newText, id: input_box.val()}); 1037 1038 cache.add(cache_key, results); 1039 if($.isFunction($(input).data("settings").onResult)) { 1040 results = $(input).data("settings").onResult.call(hidden_input, results); 749 1041 } 750 751 cache.add(query, results);752 753 1042 populate_dropdown(query, results); 754 1043 } 755 1044 } 756 1045 } 757 758 if ($(input).get(0).tagName == 'SELECT') { 759 $(input).remove(); 760 } 1046 1047 // compute the dynamic URL 1048 function computeURL() { 1049 var url = $(input).data("settings").url; 1050 if(typeof $(input).data("settings").url == 'function') { 1051 url = $(input).data("settings").url.call($(input).data("settings")); 1052 } 1053 return url; 1054 } 1055 1056 // Bring browser focus to the specified object. 1057 // Use of setTimeout is to get around an IE bug. 1058 // (See, e.g., http://stackoverflow.com/questions/2600186/focus-doesnt-work-in-ie) 1059 // 1060 // obj: a jQuery object to focus() 1061 function focus_with_timeout(obj) { 1062 setTimeout(function() { obj.focus(); }, 50); 1063 } 1064 761 1065 }; 762 1066 … … 792 1096 }; 793 1097 }(jQuery)); 1098
Note: See TracChangeset
for help on using the changeset viewer.