epic-s6ts
[kivitendo-erp.git] / js / jquery.selectboxes.js
1 /*
2  *
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.
6  *
7  * Version 2.2.5
8  * Demo: http://www.texotela.co.uk/code/jquery/select/
9  *
10  *
11  */
12  
13 ;(function($) {
14  
15 /**
16  * Adds (single/multiple) options to a select box (or series of select boxes)
17  *
18  * @name     addOption
19  * @author   Sam Collett (http://www.texotela.co.uk)
20  * @type     jQuery
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
24  *
25  */
26 $.fn.addOption = function()
27 {
28         var add = function(el, v, t, sO, index)
29         {
30                 var option = document.createElement("option");
31                 option.value = v, option.text = t;
32                 // get options
33                 var o = el.options;
34                 // get number of options
35                 var oL = o.length;
36                 if(!el.cache)
37                 {
38                         el.cache = {};
39                         // loop through existing options, adding to cache
40                         for(var i = 0; i < oL; i++)
41                         {
42                                 el.cache[o[i].value] = i;
43                         }
44                 }
45                 if (index || index == 0)
46                 {
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
50                         var ti = option;
51                         for(var ii =index; ii <= oL; ii++)
52                         {
53                                 var tmp = el.options[ii];
54                                 el.options[ii] = ti;
55                                 o[ii] = ti;
56                                 el.cache[o[ii].value] = ii;
57                                 ti = tmp;
58                         }
59                 }
60     
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;
64                 if(sO)
65                 {
66                         option.selected = true;
67                 }
68         };
69         
70         var a = arguments;
71         if(a.length == 0) return this;
72         // select option when added? default is true
73         var sO = true;
74         // multiple items
75         var m = false;
76         // other variables
77         var items, v, t;
78         if(typeof(a[0]) == "object")
79         {
80                 m = true;
81                 items = a[0];
82         }
83         if(a.length >= 2)
84         {
85                 if(typeof(a[1]) == "boolean")
86                 {
87                         sO = a[1];
88                         startindex = a[2];
89                 }
90                 else if(typeof(a[2]) == "boolean")
91                 {
92                         sO = a[2];
93                         startindex = a[1];
94                 }
95                 else
96                 {
97                         startindex = a[1];
98                 }
99                 if(!m)
100                 {
101                         v = a[0];
102                         t = a[1];
103                 }
104         }
105         this.each(
106                 function()
107                 {
108                         if(this.nodeName.toLowerCase() != "select") return;
109                         if(m)
110                         {
111                                 for(var item in items)
112                                 {
113                                         add(this, item, items[item], sO, startindex);
114                                         startindex += 1;
115                                 }
116                         }
117                         else
118                         {
119                                 add(this, v, t, sO, startindex);
120                         }
121                 }
122         );
123         return this;
124 };
125
126 /**
127  * Add options via ajax
128  *
129  * @name     ajaxAddOption
130  * @author   Sam Collett (http://www.texotela.co.uk)
131  * @type     jQuery
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"}]);
140  *
141  */
142 $.fn.ajaxAddOption = function(url, params, select, fn, args)
143 {
144         if(typeof(url) != "string") return this;
145         if(typeof(params) != "object") params = {};
146         if(typeof(select) != "boolean") select = true;
147         this.each(
148                 function()
149                 {
150                         var el = this;
151                         $.getJSON(url,
152                                 params,
153                                 function(r)
154                                 {
155                                         $(el).addOption(r, select);
156                                         if(typeof fn == "function")
157                                         {
158                                                 if(typeof args == "object")
159                                                 {
160                                                         fn.apply(el, args);
161                                                 } 
162                                                 else
163                                                 {
164                                                         fn.call(el);
165                                                 }
166                                         }
167                                 }
168                         );
169                 }
170         );
171         return this;
172 };
173
174 /**
175  * Removes an option (by value or index) from a select box (or series of select boxes)
176  *
177  * @name     removeOption
178  * @author   Sam Collett (http://www.texotela.co.uk)
179  * @type     jQuery
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
188  *
189  */
190 $.fn.removeOption = function()
191 {
192         var a = arguments;
193         if(a.length == 0) return this;
194         var ta = typeof(a[0]);
195         var v, index;
196         // has to be a string or regular expression (object in IE, function in Firefox)
197         if(ta == "string" || ta == "object" || ta == "function" )
198         {
199                 v = a[0];
200                 // if an array, remove items
201                 if(v.constructor == Array)
202                 {
203                         var l = v.length;
204                         for(var i = 0; i<l; i++)
205                         {
206                                 this.removeOption(v[i], a[1]); 
207                         }
208                         return this;
209                 }
210         }
211         else if(ta == "number") index = a[0];
212         else return this;
213         this.each(
214                 function()
215                 {
216                         if(this.nodeName.toLowerCase() != "select") return;
217                         // clear cache
218                         if(this.cache) this.cache = null;
219                         // does the option need to be removed?
220                         var remove = false;
221                         // get options
222                         var o = this.options;
223                         if(!!v)
224                         {
225                                 // get number of options
226                                 var oL = o.length;
227                                 for(var i=oL-1; i>=0; i--)
228                                 {
229                                         if(v.constructor == RegExp)
230                                         {
231                                                 if(o[i].value.match(v))
232                                                 {
233                                                         remove = true;
234                                                 }
235                                         }
236                                         else if(o[i].value == v)
237                                         {
238                                                 remove = true;
239                                         }
240                                         // if the option is only to be removed if selected
241                                         if(remove && a[1] === true) remove = o[i].selected;
242                                         if(remove)
243                                         {
244                                                 o[i] = null;
245                                         }
246                                         remove = false;
247                                 }
248                         }
249                         else
250                         {
251                                 // only remove if selected?
252                                 if(a[1] === true)
253                                 {
254                                         remove = o[index].selected;
255                                 }
256                                 else
257                                 {
258                                         remove = true;
259                                 }
260                                 if(remove)
261                                 {
262                                         this.remove(index);
263                                 }
264                         }
265                 }
266         );
267         return this;
268 };
269
270 /**
271  * Sort options (ascending or descending) in a select box (or series of select boxes)
272  *
273  * @name     sortOptions
274  * @author   Sam Collett (http://www.texotela.co.uk)
275  * @type     jQuery
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);
281  *
282  */
283 $.fn.sortOptions = function(ascending)
284 {
285         // get selected values first
286         var sel = $(this).selectedValues();
287         var a = typeof(ascending) == "undefined" ? true : !!ascending;
288         this.each(
289                 function()
290                 {
291                         if(this.nodeName.toLowerCase() != "select") return;
292                         // get options
293                         var o = this.options;
294                         // get number of options
295                         var oL = o.length;
296                         // create an array for sorting
297                         var sA = [];
298                         // loop through options, adding to sort array
299                         for(var i = 0; i<oL; i++)
300                         {
301                                 sA[i] = {
302                                         v: o[i].value,
303                                         t: o[i].text
304                                 }
305                         }
306                         // sort items in array
307                         sA.sort(
308                                 function(o1, o2)
309                                 {
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;
314                                         if(a)
315                                         {
316                                                 return o1t < o2t ? -1 : 1;
317                                         }
318                                         else
319                                         {
320                                                 return o1t > o2t ? -1 : 1;
321                                         }
322                                 }
323                         );
324                         // change the options to match the sort array
325                         for(var i = 0; i<oL; i++)
326                         {
327                                 o[i].text = sA[i].t;
328                                 o[i].value = sA[i].v;
329                         }
330                 }
331         ).selectOptions(sel, true); // select values, clearing existing ones
332         return this;
333 };
334 /**
335  * Selects an option by value
336  *
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
340  * @type     jQuery
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
347  *
348  */
349 $.fn.selectOptions = function(value, clear)
350 {
351         var v = value;
352         var vT = typeof(value);
353         // handle arrays
354         if(vT == "object" && v.constructor == Array)
355         {
356                 var $this = this;
357                 $.each(v, function()
358                         {
359                                 $this.selectOptions(this, clear);
360                         }
361                 );
362         };
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;
366         this.each(
367                 function()
368                 {
369                         if(this.nodeName.toLowerCase() != "select") return this;
370                         // get options
371                         var o = this.options;
372                         // get number of options
373                         var oL = o.length;
374                         for(var i = 0; i<oL; i++)
375                         {
376                                 if(v.constructor == RegExp)
377                                 {
378                                         if(o[i].value.match(v))
379                                         {
380                                                 o[i].selected = true;
381                                         }
382                                         else if(c)
383                                         {
384                                                 o[i].selected = false;
385                                         }
386                                 }
387                                 else
388                                 {
389                                         if(o[i].value == v)
390                                         {
391                                                 o[i].selected = true;
392                                         }
393                                         else if(c)
394                                         {
395                                                 o[i].selected = false;
396                                         }
397                                 }
398                         }
399                 }
400         );
401         return this;
402 };
403
404 /**
405  * Copy options to another select
406  *
407  * @name     copyOptions
408  * @author   Sam Collett (http://www.texotela.co.uk)
409  * @type     jQuery
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'
415  *
416  */
417 $.fn.copyOptions = function(to, which)
418 {
419         var w = which || "selected";
420         if($(to).size() == 0) return this;
421         this.each(
422                 function()
423                 {
424                         if(this.nodeName.toLowerCase() != "select") return this;
425                         // get options
426                         var o = this.options;
427                         // get number of options
428                         var oL = o.length;
429                         for(var i = 0; i<oL; i++)
430                         {
431                                 if(w == "all" || (w == "selected" && o[i].selected))
432                                 {
433                                         $(to).addOption(o[i].value, o[i].text);
434                                 }
435                         }
436                 }
437         );
438         return this;
439 };
440
441 /**
442  * Checks if a select box has an option with the supplied value
443  *
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
453  *
454  */
455 $.fn.containsOption = function(value, fn)
456 {
457         var found = false;
458         var v = value;
459         var vT = typeof(v);
460         var fT = typeof(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;
463         this.each(
464                 function()
465                 {
466                         if(this.nodeName.toLowerCase() != "select") return this;
467                         // option already found
468                         if(found && fT != "function") return false;
469                         // get options
470                         var o = this.options;
471                         // get number of options
472                         var oL = o.length;
473                         for(var i = 0; i<oL; i++)
474                         {
475                                 if(v.constructor == RegExp)
476                                 {
477                                         if (o[i].value.match(v))
478                                         {
479                                                 found = true;
480                                                 if(fT == "function") fn.call(o[i], i);
481                                         }
482                                 }
483                                 else
484                                 {
485                                         if (o[i].value == v)
486                                         {
487                                                 found = true;
488                                                 if(fT == "function") fn.call(o[i], i);
489                                         }
490                                 }
491                         }
492                 }
493         );
494         return fT == "function" ? this : found;
495 };
496
497 /**
498  * Returns values which have been selected
499  *
500  * @name     selectedValues
501  * @author   Sam Collett (http://www.texotela.co.uk)
502  * @type     Array
503  * @example  $("#myselect").selectedValues();
504  *
505  */
506 $.fn.selectedValues = function()
507 {
508         var v = [];
509         this.selectedOptions().each(
510                 function()
511                 {
512                         v[v.length] = this.value;
513                 }
514         );
515         return v;
516 };
517
518 /**
519  * Returns text which has been selected
520  *
521  * @name     selectedTexts
522  * @author   Sam Collett (http://www.texotela.co.uk)
523  * @type     Array
524  * @example  $("#myselect").selectedTexts();
525  *
526  */
527 $.fn.selectedTexts = function()
528 {
529         var t = [];
530         this.selectedOptions().each(
531                 function()
532                 {
533                         t[t.length] = this.text;
534                 }
535         );
536         return t;
537 };
538
539 /**
540  * Returns options which have been selected
541  *
542  * @name     selectedOptions
543  * @author   Sam Collett (http://www.texotela.co.uk)
544  * @type     jQuery
545  * @example  $("#myselect").selectedOptions();
546  *
547  */
548 $.fn.selectedOptions = function()
549 {
550         return this.find("option:selected");
551 };
552
553 })(jQuery);