Changeset 23275


Ignore:
Timestamp:
06/16/13 22:53:20 (6 years ago)
Author:
mistic100
Message:

feature:2927 Update TokenInput to 1.6.1/mistic100

Location:
trunk
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/admin/themes/default/template/batch_manager_global.tpl

    r23055 r23275  
    5656{/literal}{/footer_script} 
    5757 
     58{combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 
    5859{combine_script id='jquery.tokeninput' load='footer' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 
    5960{combine_script id='jquery.progressBar' load='footer' path='themes/default/js/plugins/jquery.progressbar.min.js'} 
     
    7475      animateDropdown: false, 
    7576      preventDuplicates: true, 
    76       allowCreation: true 
     77      allowFreeTagging: true 
    7778    } 
    7879  ); 
     
    8687      animateDropdown: false, 
    8788      preventDuplicates: true, 
    88       allowCreation: false 
     89      allowFreeTagging: false 
    8990    } 
    9091  ); 
  • trunk/admin/themes/default/template/batch_manager_unit.tpl

    r18974 r23275  
    33{include file='include/colorbox.inc.tpl'} 
    44 
     5{combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 
    56{combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 
    67{footer_script require='jquery.tokeninput'} 
     
    1516      animateDropdown: false, 
    1617      preventDuplicates: true, 
    17       allowCreation: true 
     18      allowFreeTagging: true 
    1819    } 
    1920  ); 
  • trunk/admin/themes/default/template/picture_modify.tpl

    r20531 r23275  
    1212{/literal}{/footer_script} 
    1313 
     14{combine_css path='themes/default/js/plugins/jquery.tokeninput.css'} 
    1415{combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'} 
    1516{footer_script require='jquery.tokeninput'} 
     
    2425      animateDropdown: false, 
    2526      preventDuplicates: true, 
    26       allowCreation: true 
     27      allowFreeTagging: true 
    2728    } 
    2829  ); 
  • trunk/admin/themes/default/theme.css

    r23259 r23275  
    963963#batchManagerGlobal #filter_dimension .ui-slider-horizontal {width:650px;margin:5px 0 10px 0;} 
    964964 
    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  
    983965#mainConf a.addFilter {font-weight:normal;margin-left:20px;} 
    984966#mainConf a.removeFilter {font-weight:normal;} 
  • trunk/admin/themes/roma/theme.css

    r23121 r23275  
    275275 
    276276/* 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;} 
     277ul.token-input-list {border-color:#666 !important;background-color:#444 !important;} 
     278ul.token-input-list li input {background-color:#444 !important;} 
     279li.token-input-token span {color:#878787 !important;} 
     280div.token-input-dropdown {background-color:#eee !important;border-color:#666 !important;} 
     281div.token-input-dropdown ul li {background-color:#eee !important;} 
     282div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color:#FF7800 !important;} 
    283283 
    284284#progressbar {border:1px solid #666; background-color:#666;} 
  • trunk/themes/default/js/plugins/jquery.tokeninput.js

    r23231 r23275  
    1 /** 
    2   DON'T MAKE AUTOMATIC UPGRADE 
    3   This is a merged version of : 
    4   + https://github.com/gr2m/jquery-tokeninput/ 
    5   + https://github.com/mistic100/jquery-tokeninput/ 
    6 */ 
    7  
    81/* 
    92 * jQuery Plugin: Tokenizing Autocomplete Text Entry 
    10  * Version 1.4.2 
     3 * Version 1.6.1 
    114 * 
    125 * Copyright (c) 2009 James Smith (http://loopj.com) 
     
    147 * choose which one suits your project best! 
    158 * 
     9 * https://github.com/mistic100/jquery-tokeninput 
    1610 */ 
    1711 
     
    1913// Default settings 
    2014var 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 
    2129    hintText: "Type in a search term", 
    2230    noResultsText: "No results", 
    2331    searchingText: "Searching...", 
    24     newText: "(new)", 
    2532    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 
    2853    tokenLimit: null, 
    29     jsonContainer: null, 
    30     method: "GET", 
    31     contentType: "json", 
    32     queryParam: "q", 
    3354    tokenDelimiter: ",", 
    3455    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 
    3864    onResult: null, 
     65    onCachedResult: null, 
    3966    onAdd: null, 
     67    onFreeTaggingAdd: null, 
    4068    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 
    4376}; 
    4477 
     
    4780    tokenList: "token-input-list", 
    4881    token: "token-input-token", 
     82    tokenReadOnly: "token-input-token-readonly", 
    4983    tokenDelete: "token-input-delete-token", 
    5084    selectedToken: "token-input-selected-token", 
     
    5488    dropdownItem2: "token-input-dropdown-item2", 
    5589    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" 
    5793}; 
    5894 
     
    83119}; 
    84120 
     121var HTML_ESCAPES = { 
     122  '&': '&amp;', 
     123  '<': '&lt;', 
     124  '>': '&gt;', 
     125  '"': '&quot;', 
     126  "'": '&#x27;', 
     127  '/': '&#x2F;' 
     128}; 
     129 
     130var HTML_ESCAPE_CHARS = /[&<>"'\/]/g; 
     131 
     132function coerceToString(val) { 
     133  return String((val === null || val === undefined) ? '' : val); 
     134} 
     135 
     136function _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 
     143var 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}; 
    85187 
    86188// 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    } 
    93196}; 
    94  
    95197 
    96198// TokenList class for each input 
     
    101203 
    102204    // Configure the data source 
    103     if(typeof(url_or_data) === "string") { 
     205    if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") { 
    104206        // 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(); 
    106211 
    107212        // 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; 
    111216            } 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]); 
    113218            } 
    114219        } 
    115220    } else if(typeof(url_or_data) === "object") { 
    116221        // Set the local data to search through 
    117         settings.local_data = url_or_data; 
     222        $(input).data("settings").local_data = url_or_data; 
    118223    } 
    119224 
    120225    // Build class names 
    121     if(settings.classes) { 
     226    if($(input).data("settings").classes) { 
    122227        // 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) { 
    125230        // Use theme-suffixed default class names 
    126         settings.classes = {}; 
     231        $(input).data("settings").classes = {}; 
    127232        $.each(DEFAULT_CLASSES, function(key, value) { 
    128             settings.classes[key] = value + "-" + settings.theme; 
     233            $(input).data("settings").classes[key] = value + "-" + $(input).data("settings").theme; 
    129234        }); 
    130235    } else { 
    131         settings.classes = DEFAULT_CLASSES; 
     236        $(input).data("settings").classes = DEFAULT_CLASSES; 
    132237    } 
    133238 
     
    147252 
    148253    // 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\">") 
    150255        .css({ 
    151256            outline: "none" 
    152257        }) 
     258        .attr("id", $(input).data("settings").idPrefix + input.id) 
    153259        .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) { 
    155264                show_dropdown_hint(); 
    156265            } 
     266            token_list.addClass($(input).data("settings").classes.focused); 
    157267        }) 
    158268        .blur(function () { 
    159269            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); 
    160277        }) 
    161278        .bind("keyup keydown blur update", resize_input) 
     
    199316                            select_dropdown_item(dropdown_item); 
    200317                        } 
    201                         return false; 
    202318                    } 
     319                    return false; 
    203320                    break; 
    204321 
     
    209326                        if(selected_token) { 
    210327                            delete_token($(selected_token)); 
     328                            hidden_input.change(); 
    211329                        } else if(previous_token.length) { 
    212330                            select_token($(previous_token.get(0))); 
     
    227345                case KEY.COMMA: 
    228346                  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(); 
    231364                  } 
    232                   break; 
     365                  return false; 
    233366 
    234367                case KEY.ESCAPE: 
     
    245378        }); 
    246379 
     380    // Keep reference for placeholder 
     381    if (settings.placeholder) 
     382        input_box.attr("placeholder", settings.placeholder) 
     383 
    247384    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 
    259413    } 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                               }); 
    270426    } 
    271427 
     
    277433    // The list to store the token items in 
    278434    var token_list = $("<ul />") 
    279         .addClass(settings.classes.tokenList) 
     435        .addClass($(input).data("settings").classes.tokenList) 
    280436        .click(function (event) { 
    281437            var li = $(event.target).closest("li"); 
     
    289445 
    290446                // Focus input box 
    291                 input_box.focus(); 
     447                focus_with_timeout(input_box); 
    292448            } 
    293449        }) 
     
    295451            var li = $(event.target).closest("li"); 
    296452            if(li && selected_token !== this) { 
    297                 li.addClass(settings.classes.highlightedToken); 
     453                li.addClass($(input).data("settings").classes.highlightedToken); 
    298454            } 
    299455        }) 
     
    301457            var li = $(event.target).closest("li"); 
    302458            if(li && selected_token !== this) { 
    303                 li.removeClass(settings.classes.highlightedToken); 
     459                li.removeClass($(input).data("settings").classes.highlightedToken); 
    304460            } 
    305461        }) 
     
    308464    // The token holding the input box 
    309465    var input_token = $("<li />") 
    310         .addClass(settings.classes.inputToken) 
     466        .addClass($(input).data("settings").classes.inputToken) 
    311467        .appendTo(token_list) 
    312468        .append(input_box); 
     
    314470    // The list to store the dropdown items in 
    315471    var dropdown = $("<div>") 
    316         .addClass(settings.classes.dropdown) 
     472        .addClass($(input).data("settings").classes.dropdown) 
    317473        .appendTo("body") 
    318474        .hide(); 
     
    335491    // Pre-populate list if items exist 
    336492    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    } 
    341497    if(li_data && li_data.length) { 
    342498        $.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) 
    344502        }); 
    345503    } 
    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(); 
    355559 
    356560    // 
     
    358562    // 
    359563 
     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 
    360593    function resize_input() { 
    361594        if(input_val === (input_val = input_box.val())) {return;} 
    362595 
     596        // Get width left on the current line 
     597        var width_left = token_list.width() - input_box.offset().left - token_list.offset().left; 
    363598        // Enter new content into resizer and resize input accordingly 
    364         var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;'); 
    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))); 
    367603    } 
    368604 
     
    374610    } 
    375611 
     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 
    376629    // 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); 
    381637 
    382638        // 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        } 
    390651 
    391652        // 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); 
    394655 
    395656        // Save this token for duplicate checking 
     
    398659 
    399660        // 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); 
    404662 
    405663        token_count += 1; 
    406664 
    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; 
    408672    } 
    409673 
    410674    // Add a token to the token list based on user input 
    411675    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; 
    414677 
    415678        // 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) { 
    417680            var found_existing_token = null; 
    418681            token_list.children().each(function () { 
    419682                var existing_token = $(this); 
    420683                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]) { 
    422685                    found_existing_token = existing_token; 
    423686                    return false; 
     
    428691                select_token(found_existing_token); 
    429692                input_token.insertAfter(found_existing_token); 
    430                 input_box.focus(); 
     693                focus_with_timeout(input_box); 
    431694                return; 
    432695            } 
    433696        } 
    434697 
     698        // Squeeze input_box so we force no unnecessary line break 
     699        input_box.width(0); 
     700 
    435701        // 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(); 
    445707        } 
    446708 
     
    453715        // Execute the onAdd callback if defined 
    454716        if($.isFunction(callback)) { 
    455             callback.call(hidden_input,li_data); 
     717            callback.call(hidden_input,item); 
    456718        } 
    457719    } 
     
    459721    // Select a token in the token list 
    460722    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        } 
    469733    } 
    470734 
    471735    // Deselect a token in the token list 
    472736    function deselect_token (token, position) { 
    473         token.removeClass(settings.classes.selectedToken); 
     737        token.removeClass($(input).data("settings").classes.selectedToken); 
    474738        selected_token = null; 
    475739 
     
    486750 
    487751        // Show the input box and give it focus again 
    488         input_box.focus(); 
     752        focus_with_timeout(input_box); 
    489753    } 
    490754 
     
    508772        // Remove the id from the saved list 
    509773        var token_data = $.data(token.get(0), "tokeninput"); 
    510         var callback = settings.onDelete; 
     774        var callback = $(input).data("settings").onDelete; 
    511775 
    512776        var index = token.prevAll().length; 
     
    518782 
    519783        // Show the input box and give it focus again 
    520         input_box.focus(); 
     784        focus_with_timeout(input_box); 
    521785 
    522786        // Remove this token from the saved list 
    523787        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        } 
    524791        if(index < selected_token_index) selected_token_index--; 
    525792 
    526793        // 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); 
    531795 
    532796        token_count -= 1; 
    533797 
    534         if(settings.tokenLimit !== null) { 
     798        if($(input).data("settings").tokenLimit !== null) { 
    535799            input_box 
    536800                .show() 
    537                 .val("") 
    538                 .focus(); 
     801                .val(""); 
     802            focus_with_timeout(input_box); 
    539803        } 
    540804 
     
    543807            callback.call(hidden_input,token_data); 
    544808        } 
     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 
    545821    } 
    546822 
     
    555831            .css({ 
    556832                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 
    560837            }) 
    561838            .show(); 
     
    563840 
    564841    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>"); 
    567844            show_dropdown(); 
    568845        } 
     
    570847 
    571848    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>"); 
    574851            show_dropdown(); 
    575852        } 
     853    } 
     854 
     855    var regexp_special_chars = new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'); 
     856    function regexp_escape(term) { 
     857        return term.replace(regexp_special_chars, '\\$&'); 
    576858    } 
    577859 
    578860    // Highlight the query part of the search term 
    579861    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)); 
    588874    } 
    589875 
     
    598884                }) 
    599885                .mousedown(function (event) { 
    600                     add_token($(event.target).closest("li")); 
     886                    add_token($(event.target).closest("li").data("tokeninput")); 
     887                    hidden_input.change(); 
    601888                    return false; 
    602889                }) 
    603890                .hide(); 
    604891 
     892            if ($(input).data("settings").resultsLimit && results.length > $(input).data("settings").resultsLimit) { 
     893                results = results.slice(0, $(input).data("settings").resultsLimit); 
     894            } 
     895 
    605896            $.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); 
    608902 
    609903                if(index % 2) { 
    610                     this_li.addClass(settings.classes.dropdownItem); 
     904                    this_li.addClass($(input).data("settings").classes.dropdownItem); 
    611905                } else { 
    612                     this_li.addClass(settings.classes.dropdownItem2); 
     906                    this_li.addClass($(input).data("settings").classes.dropdownItem2); 
    613907                } 
    614908 
     
    617911                } 
    618912 
    619                 $.data(this_li.get(0), "tokeninput", {"id": value.id, "name": value.name}); 
     913                $.data(this_li.get(0), "tokeninput", value); 
    620914            }); 
    621915 
    622916            show_dropdown(); 
    623917 
    624             if(settings.animateDropdown) { 
     918            if($(input).data("settings").animateDropdown) { 
    625919                dropdown_ul.slideDown("fast"); 
    626920            } else { 
     
    628922            } 
    629923        } 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>"); 
    632926                show_dropdown(); 
    633927            } 
     
    642936            } 
    643937 
    644             item.addClass(settings.classes.selectedDropdownItem); 
     938            item.addClass($(input).data("settings").classes.selectedDropdownItem); 
    645939            selected_dropdown_item = item.get(0); 
    646940        } 
     
    649943    // Remove highlighting from an item in the results dropdown 
    650944    function deselect_dropdown_item (item) { 
    651         item.removeClass(settings.classes.selectedDropdownItem); 
     945        item.removeClass($(input).data("settings").classes.selectedDropdownItem); 
    652946        selected_dropdown_item = null; 
    653947    } 
    654948 
    655949    // Do a search and show the "searching" dropdown if the input is longer 
    656     // than settings.minChars 
     950    // than $(input).data("settings").minChars 
    657951    function do_search() { 
    658952        var query = input_box.val(); 
    659         if (!settings.caseSensitive) query = query.toLowerCase(); 
    660953 
    661954        if(query && query.length) { 
     
    664957            } 
    665958 
    666             if(query.length >= settings.minChars) { 
     959            if(query.length >= $(input).data("settings").minChars) { 
    667960                show_dropdown_searching(); 
    668961                clearTimeout(timeout); 
     
    670963                timeout = setTimeout(function(){ 
    671964                    run_search(query); 
    672                 }, settings.searchDelay); 
     965                }, $(input).data("settings").searchDelay); 
    673966            } else { 
    674967                hide_dropdown(); 
     
    679972    // Do the actual search 
    680973    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); 
    682976        if(cached_results) { 
     977            if ($.isFunction($(input).data("settings").onCachedResult)) { 
     978              cached_results = $(input).data("settings").onCachedResult.call(hidden_input, cached_results); 
     979            } 
    683980            populate_dropdown(query, cached_results); 
    684981        } else { 
    685982            // Are we doing an ajax search or local data search? 
    686             if(settings.url) { 
     983            if($(input).data("settings").url) { 
     984                var url = computeURL(); 
    687985                // Extract exisiting get params 
    688986                var ajax_params = {}; 
    689987                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("?"); 
    692990                    ajax_params.url = parts[0]; 
    693991 
     
    698996                    }); 
    699997                } else { 
    700                     ajax_params.url = settings.url; 
     998                    ajax_params.url = url; 
    701999                } 
    7021000 
    7031001                // 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) { 
    7081006                    ajax_params.dataType = "jsonp"; 
    7091007                } 
     
    7111009                // Attach the success callback 
    7121010                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); 
    7151014                  } 
    7161015                   
    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()}); 
    7191018                  } 
    720                   cache.add(query, settings.jsonContainer ? results[settings.jsonContainer] : results); 
    7211019 
    7221020                  // 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); 
    7271023                  } 
    7281024                }; 
     
    7301026                // Make the request 
    7311027                $.ajax(ajax_params); 
    732             } else if(settings.local_data) { 
     1028            } else if($(input).data("settings").local_data) { 
    7331029                // 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; 
    7411032                }); 
    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()}); 
    7451036                } 
    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); 
    7491041                } 
    750                  
    751                 cache.add(query, results);                 
    752                  
    7531042                populate_dropdown(query, results); 
    7541043            } 
    7551044        } 
    7561045    } 
    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 
    7611065}; 
    7621066 
     
    7921096}; 
    7931097}(jQuery)); 
     1098 
Note: See TracChangeset for help on using the changeset viewer.