3  * Copyright (c) 2006-2010 Sam Collett (http://www.texotela.co.uk)
 
   4  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 
   5  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 
   8  * Demo: http://www.texotela.co.uk/code/jquery/select/
 
  16  * Adds (single/multiple) options to a select box (or series of select boxes)
 
  19  * @author   Sam Collett (http://www.texotela.co.uk)
 
  21  * @example  $("#myselect").addOption("Value", "Text"); // add single value (will be selected)
 
  22  * @example  $("#myselect").addOption("Value 2", "Text 2", false); // add single value (won't be selected)
 
  23  * @example  $("#myselect").addOption({"foo":"bar","bar":"baz"}, false); // add multiple values, but don't select
 
  26 $.fn.addOption = function()
 
  28         var add = function(el, v, t, sO, index)
 
  30                 var option = document.createElement("option");
 
  31                 option.value = v, option.text = t;
 
  34                 // get number of options
 
  39                         // loop through existing options, adding to cache
 
  40                         for(var i = 0; i < oL; i++)
 
  42                                 el.cache[o[i].value] = i;
 
  45                 if (index || index == 0)
 
  47                         // we're going to insert these starting  at a specific index...
 
  48                         // this has the side effect of el.cache[v] being the 
 
  49                         // correct value for the typeof check below
 
  51                         for(var ii =index; ii <= oL; ii++)
 
  53                                 var tmp = el.options[ii];
 
  56                                 el.cache[o[ii].value] = ii;
 
  61                 // add to cache if it isn't already
 
  62                 if(typeof el.cache[v] == "undefined") el.cache[v] = oL;
 
  63                 el.options[el.cache[v]] = option;
 
  66                         option.selected = true;
 
  71         if(a.length == 0) return this;
 
  72         // select option when added? default is true
 
  78         if(typeof(a[0]) == "object")
 
  85                 if(typeof(a[1]) == "boolean")
 
  90                 else if(typeof(a[2]) == "boolean")
 
 108                         if(this.nodeName.toLowerCase() != "select") return;
 
 111                                 for(var item in items)
 
 113                                         add(this, item, items[item], sO, startindex);
 
 119                                 add(this, v, t, sO, startindex);
 
 127  * Add options via ajax
 
 129  * @name     ajaxAddOption
 
 130  * @author   Sam Collett (http://www.texotela.co.uk)
 
 132  * @param    String url      Page to get options from (must be valid JSON)
 
 133  * @param    Object params   (optional) Any parameters to send with the request
 
 134  * @param    Boolean select  (optional) Select the added options, default true
 
 135  * @param    Function fn     (optional) Call this function with the select object as param after completion
 
 136  * @param    Array args      (optional) Array with params to pass to the function afterwards
 
 137  * @example  $("#myselect").ajaxAddOption("myoptions.php");
 
 138  * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"});
 
 139  * @example  $("#myselect").ajaxAddOption("myoptions.php", {"code" : "007"}, false, sortoptions, [{"dir": "desc"}]);
 
 142 $.fn.ajaxAddOption = function(url, params, select, fn, args)
 
 144         if(typeof(url) != "string") return this;
 
 145         if(typeof(params) != "object") params = {};
 
 146         if(typeof(select) != "boolean") select = true;
 
 155                                         $(el).addOption(r, select);
 
 156                                         if(typeof fn == "function")
 
 158                                                 if(typeof args == "object")
 
 175  * Removes an option (by value or index) from a select box (or series of select boxes)
 
 178  * @author   Sam Collett (http://www.texotela.co.uk)
 
 180  * @param    String|RegExp|Number what  Option to remove
 
 181  * @param    Boolean selectedOnly       (optional) Remove only if it has been selected (default false)   
 
 182  * @example  $("#myselect").removeOption("Value"); // remove by value
 
 183  * @example  $("#myselect").removeOption(/^val/i); // remove options with a value starting with 'val'
 
 184  * @example  $("#myselect").removeOption(/./); // remove all options
 
 185  * @example  $("#myselect").removeOption(/./, true); // remove all options that have been selected
 
 186  * @example  $("#myselect").removeOption(0); // remove by index
 
 187  * @example  $("#myselect").removeOption(["myselect_1","myselect_2"]); // values contained in passed array
 
 190 $.fn.removeOption = function()
 
 193         if(a.length == 0) return this;
 
 194         var ta = typeof(a[0]);
 
 196         // has to be a string or regular expression (object in IE, function in Firefox)
 
 197         if(ta == "string" || ta == "object" || ta == "function" )
 
 200                 // if an array, remove items
 
 201                 if(v.constructor == Array)
 
 204                         for(var i = 0; i<l; i++)
 
 206                                 this.removeOption(v[i], a[1]); 
 
 211         else if(ta == "number") index = a[0];
 
 216                         if(this.nodeName.toLowerCase() != "select") return;
 
 218                         if(this.cache) this.cache = null;
 
 219                         // does the option need to be removed?
 
 222                         var o = this.options;
 
 225                                 // get number of options
 
 227                                 for(var i=oL-1; i>=0; i--)
 
 229                                         if(v.constructor == RegExp)
 
 231                                                 if(o[i].value.match(v))
 
 236                                         else if(o[i].value == v)
 
 240                                         // if the option is only to be removed if selected
 
 241                                         if(remove && a[1] === true) remove = o[i].selected;
 
 251                                 // only remove if selected?
 
 254                                         remove = o[index].selected;
 
 271  * Sort options (ascending or descending) in a select box (or series of select boxes)
 
 274  * @author   Sam Collett (http://www.texotela.co.uk)
 
 276  * @param    Boolean ascending   (optional) Sort ascending (true/undefined), or descending (false)
 
 277  * @example  // ascending
 
 278  * $("#myselect").sortOptions(); // or $("#myselect").sortOptions(true);
 
 279  * @example  // descending
 
 280  * $("#myselect").sortOptions(false);
 
 283 $.fn.sortOptions = function(ascending)
 
 285         // get selected values first
 
 286         var sel = $(this).selectedValues();
 
 287         var a = typeof(ascending) == "undefined" ? true : !!ascending;
 
 291                         if(this.nodeName.toLowerCase() != "select") return;
 
 293                         var o = this.options;
 
 294                         // get number of options
 
 296                         // create an array for sorting
 
 298                         // loop through options, adding to sort array
 
 299                         for(var i = 0; i<oL; i++)
 
 306                         // sort items in array
 
 310                                         // option text is made lowercase for case insensitive sorting
 
 311                                         o1t = o1.t.toLowerCase(), o2t = o2.t.toLowerCase();
 
 312                                         // if options are the same, no sorting is needed
 
 313                                         if(o1t == o2t) return 0;
 
 316                                                 return o1t < o2t ? -1 : 1;
 
 320                                                 return o1t > o2t ? -1 : 1;
 
 324                         // change the options to match the sort array
 
 325                         for(var i = 0; i<oL; i++)
 
 328                                 o[i].value = sA[i].v;
 
 331         ).selectOptions(sel, true); // select values, clearing existing ones
 
 335  * Selects an option by value
 
 337  * @name     selectOptions
 
 338  * @author   Mathias Bank (http://www.mathias-bank.de), original function
 
 339  * @author   Sam Collett (http://www.texotela.co.uk), addition of regular expression matching
 
 341  * @param    String|RegExp|Array value  Which options should be selected
 
 342  * can be a string or regular expression, or an array of strings / regular expressions
 
 343  * @param    Boolean clear  Clear existing selected options, default false
 
 344  * @example  $("#myselect").selectOptions("val1"); // with the value 'val1'
 
 345  * @example  $("#myselect").selectOptions(["val1","val2","val3"]); // with the values 'val1' 'val2' 'val3'
 
 346  * @example  $("#myselect").selectOptions(/^val/i); // with the value starting with 'val', case insensitive
 
 349 $.fn.selectOptions = function(value, clear)
 
 352         var vT = typeof(value);
 
 354         if(vT == "object" && v.constructor == Array)
 
 359                                 $this.selectOptions(this, clear);
 
 363         var c = clear || false;
 
 364         // has to be a string or regular expression (object in IE, function in Firefox)
 
 365         if(vT != "string" && vT != "function" && vT != "object") return this;
 
 369                         if(this.nodeName.toLowerCase() != "select") return this;
 
 371                         var o = this.options;
 
 372                         // get number of options
 
 374                         for(var i = 0; i<oL; i++)
 
 376                                 if(v.constructor == RegExp)
 
 378                                         if(o[i].value.match(v))
 
 380                                                 o[i].selected = true;
 
 384                                                 o[i].selected = false;
 
 391                                                 o[i].selected = true;
 
 395                                                 o[i].selected = false;
 
 405  * Copy options to another select
 
 408  * @author   Sam Collett (http://www.texotela.co.uk)
 
 410  * @param    String to  Element to copy to
 
 411  * @param    String which  (optional) Specifies which options should be copied - 'all' or 'selected'. Default is 'selected'
 
 412  * @example  $("#myselect").copyOptions("#myselect2"); // copy selected options from 'myselect' to 'myselect2'
 
 413  * @example  $("#myselect").copyOptions("#myselect2","selected"); // same as above
 
 414  * @example  $("#myselect").copyOptions("#myselect2","all"); // copy all options from 'myselect' to 'myselect2'
 
 417 $.fn.copyOptions = function(to, which)
 
 419         var w = which || "selected";
 
 420         if($(to).size() == 0) return this;
 
 424                         if(this.nodeName.toLowerCase() != "select") return this;
 
 426                         var o = this.options;
 
 427                         // get number of options
 
 429                         for(var i = 0; i<oL; i++)
 
 431                                 if(w == "all" || (w == "selected" && o[i].selected))
 
 433                                         $(to).addOption(o[i].value, o[i].text);
 
 442  * Checks if a select box has an option with the supplied value
 
 444  * @name     containsOption
 
 445  * @author   Sam Collett (http://www.texotela.co.uk)
 
 446  * @type     Boolean|jQuery
 
 447  * @param    String|RegExp value  Which value to check for. Can be a string or regular expression
 
 448  * @param    Function fn          (optional) Function to apply if an option with the given value is found.
 
 449  * Use this if you don't want to break the chaining
 
 450  * @example  if($("#myselect").containsOption("val1")) alert("Has an option with the value 'val1'");
 
 451  * @example  if($("#myselect").containsOption(/^val/i)) alert("Has an option with the value starting with 'val'");
 
 452  * @example  $("#myselect").containsOption("val1", copyoption).doSomethingElseWithSelect(); // calls copyoption (user defined function) for any options found, chain is continued
 
 455 $.fn.containsOption = function(value, fn)
 
 461         // has to be a string or regular expression (object in IE, function in Firefox)
 
 462         if(vT != "string" && vT != "function" && vT != "object") return fT == "function" ? this: found;
 
 466                         if(this.nodeName.toLowerCase() != "select") return this;
 
 467                         // option already found
 
 468                         if(found && fT != "function") return false;
 
 470                         var o = this.options;
 
 471                         // get number of options
 
 473                         for(var i = 0; i<oL; i++)
 
 475                                 if(v.constructor == RegExp)
 
 477                                         if (o[i].value.match(v))
 
 480                                                 if(fT == "function") fn.call(o[i], i);
 
 488                                                 if(fT == "function") fn.call(o[i], i);
 
 494         return fT == "function" ? this : found;
 
 498  * Returns values which have been selected
 
 500  * @name     selectedValues
 
 501  * @author   Sam Collett (http://www.texotela.co.uk)
 
 503  * @example  $("#myselect").selectedValues();
 
 506 $.fn.selectedValues = function()
 
 509         this.selectedOptions().each(
 
 512                         v[v.length] = this.value;
 
 519  * Returns text which has been selected
 
 521  * @name     selectedTexts
 
 522  * @author   Sam Collett (http://www.texotela.co.uk)
 
 524  * @example  $("#myselect").selectedTexts();
 
 527 $.fn.selectedTexts = function()
 
 530         this.selectedOptions().each(
 
 533                         t[t.length] = this.text;
 
 540  * Returns options which have been selected
 
 542  * @name     selectedOptions
 
 543  * @author   Sam Collett (http://www.texotela.co.uk)
 
 545  * @example  $("#myselect").selectedOptions();
 
 548 $.fn.selectedOptions = function()
 
 550         return this.find("option:selected");