histogram: Make histograms crash less
[ninja.git] / application / media / js / jquery.field.js
blob12d082c89e0e5d2cd3573741470fe1a9ae2a0d90
1 /*\r
2  * jQuery Field Plug-in\r
3  *\r
4  * Copyright (c) 2011 Dan G. Switzer, II\r
5  *\r
6  * Dual licensed under the MIT and GPL licenses:\r
7  *   http://www.opensource.org/licenses/mit-license.php\r
8  *   http://www.gnu.org/licenses/gpl.html\r
9  *\r
10  * Version: 0.9.6\r
11  *\r
12  * NOTES: The getValue() and setValue() methods are designed to be\r
13  * executed on single field (i.e. any field that would share the same\r
14  * "name" attribute--a single text box, a group of checkboxes or radio\r
15  * elements, etc.)\r
16  *\r
17  * Revision History\r
18  * v0.9.6\r
19  * - Added clear argument to fieldHash() and formHash() method for resetting\r
20  *   values not in the supplied hash map; default is still to ignore values\r
21  *   not in the hash map\r
22  * \r
23  * v0.9.5\r
24  * - Fixed issue with IE9 not getting option tag values with certain doctypes\r
25  * - Added fieldHash() for grabbing fields out by a CSS selector (the formHash()\r
26  *   requires a form object)\r
27  * \r
28  * v0.9.4\r
29  * - Fixed issues with jQuery v1.6.x\r
30  * - Fixed file fields not currently supported by getValue or getType\r
31  * - Fixed formHash breaks on fields with apostrophes\r
32  * - Fixed moveNext() did not work, it have invisible parent\r
33  * \r
34  * v0.9.3\r
35  * - Enhanced createCheckboxRange() to trigger change handler for each checkbox\r
36  *   being changed\r
37  * - Enhanced createCheckboxRange() to pass in event object when triggering click\r
38  *   callback\r
39  * \r
40  * v0.9.2\r
41  * - Fixed code for jQuery v1.3.x support\r
42  * - Fixed bug #6333 - setValue when value is typeof "number" and it is 0 (zero)\r
43  * - Fixed bug in autoAdvance where it wasn't correctly advancing to the next field\r
44  * - Fixed bug in createCheckboxRange where it where the high value wouldn't always\r
45  *   be unchecked/checked\r
46  * \r
47  * v0.9.1\r
48  * - Optimized the createCheckboxRange to reduced complexity and code size.\r
49  *   Functionality has not changed.\r
50  * \r
51  * v0.9\r
52  * - Removed createCheckboxRange custom event, this fixes problems with\r
53  *   older jQuery versions that have problems with the trigger\r
54  * - Changed the limitSelection() function to use an options argument, \r
55  *   instead of all the individual arguments\r
56  * \r
57  * v0.8.1\r
58  * - createCheckboxRange() no longer breaks the chain\r
59  * - Added callback to createCheckboxRange() (the trigger() method \r
60  *   does not execute correctly in jQuery v1.1.2, so this functionality \r
61  *   doesn't work in that version.)\r
62  * - Added configurable setting for the [SHIFT] key bind to the \r
63  *   createCheckboxRange().\r
64  * - Added the $.Field.setProperty() and getProperty() methods\r
65  * \r
66  * v0.8\r
67  * - Fixed "bug in checkbox range" (http://plugins.jquery.com/node/1642)\r
68  * - Fixed "Bug when setting value on a select element and the select is empty"\r
69  *   (http://plugins.jquery.com/node/1281)\r
70  *\r
71  * v0.7.1\r
72  * - Changed a comma in code to a semi-colon in a variable definition line\r
73  * - Fixed code to work in min mode\r
74  * - Fixed bug in hashForm() that would not see struct keys with empty values\r
75  *\r
76  * v0.7\r
77  * - Added tabIndex related function (getTabIndex, moveNext, movePrev, moveIndex)\r
78  *\r
79  * v0.6\r
80  * - Fixed bug in the $.formHash() where the arrayed form elements would\r
81  *   not correctly report their values.\r
82  * - Added the $.createCheckboxRange() which allow you to select multiple\r
83  *   checkbox elements by doing a [SHIFT] + click.\r
84  *\r
85  * v0.5\r
86  * - Added $.limitSelection() method for limiting the number of\r
87  *   selection in a select-multiple of checkbox array.\r
88  *\r
89  * v0.4.1\r
90  * - Moved $.type and $.isType into private functions\r
91  * - Rewrote $type() function to use instanceof operator\r
92  *\r
93  * v0.4\r
94  * - Added the formHash() method\r
95  *\r
96  * v0.3\r
97  * - First public release\r
98  *\r
99 */\r
100 (function($){\r
102         // set the defaults\r
103         var defaults = {\r
104                 // use a comma as the string delimiter\r
105                 delimiter: ",",\r
106                 // the default key binding to check for when using the createCheckboxRange()\r
107                 checkboxRangeKeyBinding: "shiftKey",\r
108                 // for methods that could return either a string or array, decide default behavior\r
109                 useArray: false\r
110         };\r
112         // set default options\r
113         $.Field = {\r
114                 version: "0.9.6",\r
115                 setDefaults: function(options){\r
116                         $.extend(defaults, options);\r
117                 },\r
118                 setProperty: function(prop, value){\r
119                         defaults[prop] = value;\r
120                 },\r
121                 getProperty: function(prop){\r
122                         return defaults[prop];\r
123                 }\r
124         };\r
127         /*\r
128          * jQuery.fn.fieldArray()\r
129          *\r
130          * returns either an array of values or a jQuery object\r
131          *\r
132          * NOTE: This *MAY* break the jQuery chain\r
133          *\r
134          * Examples:\r
135          * $("input[name='name']").fieldArray();\r
136          * > Gets the current value of the name text element\r
137          *\r
138          * $("input[name='name']").fieldArray(["Dan G. Switzer, II"]);\r
139          * > Sets the value of the name text element to "Dan G. Switzer, II"\r
140          *\r
141          * $("select[name='state']").fieldArray();\r
142          * > Gets the current value of the state text element\r
143          *\r
144          * $("select[name='state']").setValue(["OH","NY","CA"]);\r
145          * > Sets the selected value of the "state" select element to OH, NY and CA\r
146          *\r
147          */\r
148         // this will set/get the values for a field based upon and array\r
149         $.fn.fieldArray = function(v){\r
150                 var t = $type(v);\r
152                 // if no value supplied, return an array of values\r
153                 if( t == "undefined" ) return getValue(this);\r
155                 // convert the number/string into an array\r
156                 if( t == "string" ||  t == "number" ){\r
157                         v = v.toString().split(defaults.delimiter);\r
158                         t = "array";\r
159                 }\r
161                 // set the value -- doesn't break the chaing\r
162                 if( t == "array" ) return setValue(this, v);\r
164                 // if we don't know what do to, don't break the chain\r
165                 return this;\r
166         };\r
168         /*\r
169          * jQuery.fn.getValue()\r
170          *\r
171          * returns String - a comma delimited list of values for the field\r
172          *\r
173          * NOTE: Breaks the jQuery chain, since it returns a string.\r
174          *\r
175          * Examples:\r
176          * $("input[name='name']").getValue();\r
177          * > This would return the value of the name text element\r
178          *\r
179          * $("select[name='state']").getValue();\r
180          * > This would return the currently selected value of the "state" select element\r
181          *\r
182          */\r
183         // the getValue() method -- break the chain\r
184         $.fn.getValue = function(){\r
185                 // return the values as a comma-delimited string\r
186                 return getValue(this).join(defaults.delimiter);\r
187         };\r
189         /*\r
190          * getValue()\r
191          *\r
192          * returns Array - an array of values for the field\r
193          *\r
194          */\r
195         // the getValue() method -- break the chain\r
196         var getValue = function(jq){\r
197                 var v = [];\r
199                 jq.each(\r
200                         function (lc){\r
201                                 // get the current type\r
202                                 var t = getType(this);\r
204                                 switch( t ){\r
205                                         case "checkbox": case "radio":\r
206                                                 // if the checkbox or radio element is checked\r
207                                                 if( this.checked ) v.push(this.value);\r
208                                         break;\r
210                                         case "select":\r
211                                                 if( this.type == "select-one" ){\r
212                                                         v.push( (this.selectedIndex == -1) ? "" : getOptionVal(this[this.selectedIndex]) );\r
213                                                 } else {\r
214                                                         // loop through all element in the array for this field\r
215                                                         for( var i=0; i < this.length; i++ ){\r
216                                                                 // if the element is selected, get the selected values\r
217                                                                 if( this[i].selected ){\r
218                                                                         // append the selected value, if the value property doesn't exist, use the text\r
219                                                                         v.push(getOptionVal(this[i]));\r
220                                                                 }\r
221                                                         }\r
222                                                 }\r
223                                         break;\r
225                                         case "text":\r
226                                                 v.push(this.value);\r
227                                         break;\r
228                                 }\r
229                         }\r
230                 );\r
232                 // return the values as an array\r
233                 return v;\r
234         };\r
236         /*\r
237          * setValue()\r
238          *\r
239          * returns jQuery object\r
240          *\r
241          * NOTE: This does *NOT* break the jQuery chain\r
242          *\r
243          * Examples:\r
244          * $("input[name='name']").setValue("Dan G. Switzer, II");\r
245          * > Sets the value of the name text element to "Dan G. Switzer, II"\r
246          *\r
247          * $("select[name='state']").setValue("OH");\r
248          * > Sets the selected value of the "state" select element to "OH"\r
249          *\r
250          */\r
251         // the setValue() method -- does *not* break the chain\r
252         $.fn.setValue = function(v){\r
253                 // f no value, set to empty string\r
254                 return setValue(this, ((!v && (v !== 0)) ? [""] : v.toString().split(defaults.delimiter)));\r
255         };\r
257         /*\r
258          * setValue()\r
259          *\r
260          * returns jQuery object\r
261          *\r
262          */\r
263         // the setValue() method -- does *not* break the chain\r
264         var setValue = function(jq, v){\r
265                 jq.each(\r
266                         function (lc){\r
267                                 var t = getType(this), x;\r
269                                 switch( t ){\r
270                                         case "checkbox": case "radio":\r
271                                                 if( valueExists(v, this.value) ) this.checked = true;\r
272                                                 else this.checked = false;\r
273                                         break;\r
275                                         case "select":\r
276                                                 var bSelectOne = (this.type == "select-one");\r
277                                                 var bKeepLooking = true; // if select-one type, then only select the first value found\r
278                                                 // loop through all element in the array for this field\r
279                                                 for( var i=0; i < this.length; i++ ){\r
280                                                         x = getOptionVal(this[i]);\r
281                                                         bSelectItem = valueExists(v, x);\r
282                                                         if( bSelectItem ){\r
283                                                                 this[i].selected = true;\r
284                                                                 // if a select-one element\r
285                                                                 if( bSelectOne ){\r
286                                                                         // no need to look farther\r
287                                                                         bKeepLooking = false;\r
288                                                                         // stop the loop\r
289                                                                         break;\r
290                                                                 }\r
291                                                         } else if( !bSelectOne ) this[i].selected = false;\r
292                                                 }\r
293                                                 // if a select-one box and nothing selected, then try to select the default value\r
294                                                 if( bSelectOne && bKeepLooking && !!this[0] ){\r
295                                                         this[0].selected = true;\r
296                                                 }\r
297                                         break;\r
299                                         case "text":\r
300                                                 this.value = v.join(defaults.delimiter);\r
301                                         break;\r
302                                 }\r
304                         }\r
305                 );\r
307                 return jq;\r
308         };\r
310         /*\r
311          * jQuery.fn.formHash()\r
312          *\r
313          * returns either an hash table of form fields or a jQuery object\r
314          *\r
315          * NOTE: This *MAY* break the jQuery chain\r
316          *\r
317          * Examples:\r
318          * $("#formName").formHash();\r
319          * > Returns a hash map of all the form fields and their values\r
320          *\r
321          * $("#formName").formHash({"name": "Dan G. Switzer, II", "state": "OH"});\r
322          * > Returns the jQuery chain and sets the fields "name" and "state" with\r
323          * > the values "Dan G. Switzer, II" and "OH" respectively.\r
324          *\r
325          */\r
326         // the formHash() method -- break the chain (we could use fieldHash() now, but we stick w/DOM access for speed)\r
327         $.fn.formHash = function(map, clear){\r
328                 var isGet = (arguments.length == 0);\r
329                 // create a hash to return\r
330                 var hash = {};\r
332                 // run the code for each form\r
333                 this.filter("form").each(\r
334                         function (){\r
335                                 // get all the form elements\r
336                                 var els = this.elements, el, n, fields = {}, $el;\r
338                                 // loop through the elements and process\r
339                                 for( var i=0, elsMax = els.length; i < elsMax; i++ ){\r
340                                         el = els[i]; \r
341                                         n = el.name;\r
343                                         // if the element doesn't have a name, then skip it\r
344                                         if( !n || fields[n] ) continue;\r
346                                         // create a jquery object to the current named form elements (for fields containing apostrophe's, escape them)\r
347                                         var $el = $(el.form[n]);\r
349                                         // if we're getting the values, get them now\r
350                                         if( isGet ){\r
351                                                 hash[n] = $el[defaults.useArray ? "fieldArray" : "getValue"]();\r
352                                         // if we're setting values, set them now\r
353                                         } else if( n in map ){\r
354                                                 $el[defaults.useArray ? "fieldArray" : "setValue"](map[n]);\r
355                                         } else if( clear === true ){\r
356                                                 $el[defaults.useArray ? "fieldArray" : "setValue"]("");\r
357                                         }\r
359                                         fields[n] = true;\r
360                                 }\r
361                         }\r
362                 );\r
364                 // if getting a hash map return it, otherwise return the jQuery object\r
365                 return (isGet) ? hash : this;\r
366         };\r
368         /*\r
369          * jQuery.fn.fieldHash()\r
370          *\r
371          * Returns either an hash table of form fields matching the selector or a jQuery object\r
372          *\r
373          * NOTE: This *MAY* break the jQuery chain\r
374          *\r
375          * Examples:\r
376          * $("#formName").fieldHash();\r
377          * > Returns a hash map of all the form fields matched by the selector and their values.\r
378          *\r
379          * $("#formName").fieldHash({"name": "Dan G. Switzer, II", "state": "OH"});\r
380          * > Returns the jQuery chain and sets the fields "name" and "state" with \r
381          * > the values "Dan G. Switzer, II" and "OH" respectively--provided the fields exist in the jQuery selector.\r
382          *\r
383          */\r
384         // the fieldHash() method -- break the chain\r
385         $.fn.fieldHash = function(map, clear){\r
386                 var isGet = !(map && typeof map == "object");\r
387                 // create a hash to return\r
388                 var hash = {}, fields = {};\r
389                 \r
390                 // run the code for each form field\r
391                 this.filter(":input").each(\r
392                         function (){\r
393                                 var el = this, n = el.name;\r
395                                 // if the element doesn't have a name or it's already processed--stop\r
396                                 if( !n || fields[n] ) return;\r
398                                 // create a jquery object to the current named form elements (for fields containing apostrophe's, escape them)\r
399                                 var $el = $(el.form[n]);\r
400                                 \r
401                                 // if we're getting the values, get them now\r
402                                 if( isGet ){\r
403                                         hash[n] = $el[defaults.useArray ? "fieldArray" : "getValue"]();\r
404                                 // if we're setting values, set them now\r
405                                 } else if( n in map ){\r
406                                         $el[defaults.useArray ? "fieldArray" : "setValue"](map[n]);\r
407                                 } else if( clear === true ){\r
408                                         $el[defaults.useArray ? "fieldArray" : "setValue"]("");\r
409                                 }\r
411                                 fields[n] = true;\r
412                         }\r
413                 );\r
415                 // if getting a hash map return it, otherwise return the jQuery object\r
416                 return (isGet) ? hash : this;\r
417         };\r
419         /*\r
420          * jQuery.fn.autoAdvance()\r
421          *\r
422          * Finds all text-based input fields and makes them autoadvance to the next\r
423          * fields when they've met their maxlength property.\r
424          *\r
425          *\r
426          * Examples:\r
427          * $("#form").autoAdvance();\r
428          * > When a field reaches it's maxlength attribute value, it'll advance to the\r
429          * > next field in the form's tabindex.\r
430          *\r
431          * $("#form").autoAdvance(callback);\r
432          * > Automatic advances to next field and triggers the callback function on the\r
433          * > field the user left.\r
434          *\r
435          */\r
436         // the autoAdvance() method\r
437         $.fn.autoAdvance = function(callback){\r
438                 return this.find(":text,:password,textarea").bind(\r
439                         "keyup.autoAdvance",\r
440                         function (e){\r
441                                 var\r
442                                         // get the field\r
443                                         $field = $(this),\r
444                                         // get the maxlength for the field\r
445                                         iMaxLength = parseInt($field.attr("maxlength"), 10);\r
447                                 // if the user tabs to the field, exit event handler\r
448                                 // this will prevent movement if the field is already\r
449                                 // field in with the max number of characters\r
450                                 if( isNaN(iMaxLength) || ("|9|16|37|38|39|40|".indexOf("|" + e.keyCode + "|") > -1) ) return true;\r
452                                 // if the value of the field is greater than maxlength attribute,\r
453                                 // then move the focus to the next field\r
454                                 if( $field.getValue().length >= $field.attr("maxlength") ){\r
455                                         // move to the next field and select the existing value\r
456                                         var $next = $field.moveNext().select();\r
457                                         if( $.isFunction(callback) ) callback.apply($field, [$next]);\r
458                                 }\r
459                         }\r
460                 );\r
461         };\r
463         /*\r
464          * jQuery.fn.moveNext()\r
465          *\r
466          * places the focus in the next form field. if the field element is\r
467          * the last in the form array, it'll return to the top.\r
468          *\r
469          * returns a jQuery object pointing to the next field element\r
470          *\r
471          * NOTE: if the selector returns multiple items, the first item is used.\r
472          *\r
473          *\r
474          * Examples:\r
475          * $("#firstName").moveNext();\r
476          * > Moves the focus to the next form field found after firstName\r
477          *\r
478          */\r
479         // the moveNext() method\r
480         $.fn.moveNext = function(){\r
481                 return this.moveIndex("next");\r
482         };\r
484         /*\r
485          * jQuery.fn.movePrev()\r
486          *\r
487          * places the focus in the previous form field. if the field element is\r
488          * the first in the form array, it'll return to the last element.\r
489          *\r
490          * returns a jQuery object pointing to the previos field element\r
491          *\r
492          * NOTE: if the selector returns multiple items, the first item is used\r
493          *\r
494          * Examples:\r
495          * $("#firstName").movePrev();\r
496          * > Moves the focus to the next form field found after firstName\r
497          *\r
498          */\r
499         // the movePrev() method\r
500         $.fn.movePrev = function(){\r
501                 return this.moveIndex("prev");\r
502         };\r
504         /*\r
505          * jQuery.fn.moveIndex()\r
506          *\r
507          * Places the tab index into the specified index position\r
508          *\r
509          * returns a jQuery object pointing to the previos field element\r
510          *\r
511          * NOTE: if the selector returns multiple items, the first item is used\r
512          *\r
513          * Examples:\r
514          * $("#firstName").movePrev();\r
515          * > Moves the focus to the next form field found after firstName\r
516          *\r
517          */\r
518         // the moveIndex() method\r
519         $.fn.moveIndex = function(i){\r
520                 // get the current position and elements\r
521                 var pos = getFieldPosition(this);\r
522                 \r
523                 // if a string option has been specified, calculate the position\r
524                 if( i == "next" ) i = pos[0] + 1; // get the next item\r
525                 else if( i == "prev" ) i = pos[0] - 1; // get the previous item\r
527                 // make sure the index position is within the bounds of the elements array\r
528                 if( i < 0 ) i = pos[1].length - 1;\r
529                 else if( i >= pos[1].length ) i = 0;\r
531                 return $(pos[1][i]).trigger("focus");\r
532         };\r
534         /*\r
535          * jQuery.fn.getTabIndex()\r
536          *\r
537          * gets the current tab index of the first element found in the selector\r
538          *\r
539          * NOTE: if the selector returns multiple items, the first item is used\r
540          *\r
541          * Examples:\r
542          * $("#firstName").getTabIndex();\r
543          * > Gets the tabIndex for the firstName field\r
544          *\r
545          */\r
546         // the getTabIndex() method\r
547         $.fn.getTabIndex = function(){\r
548                 // return the position of the form field\r
549                 return getFieldPosition(this)[0];\r
550         };\r
552         var getFieldPosition = function (jq){\r
553                 var\r
554                         // get the first matching field\r
555                         $field = jq.filter("input, select, textarea").get(0),\r
556                         // store items with a tabindex\r
557                         tabIndex = [],\r
558                         // store items with no tabindex\r
559                         posIndex = [];\r
561                 // if there is no match, return 0\r
562                 if( !$field ) return [-1, []];\r
564                 // make a single pass thru all form elements\r
565                 $.each(\r
566                         $field.form.elements,\r
567                         function (i, o){\r
568                                 if( o.tagName != "FIELDSET" && !o.disabled && jQuery(o).is(":visible") ){\r
569                                         if( o.tabIndex > 0 ){\r
570                                                 tabIndex.push(o);\r
571                                         } else {\r
572                                                 posIndex.push(o);\r
573                                         }\r
574                                 }\r
575                         }\r
576                 );\r
578                 // sort the fields that had tab indexes\r
579                 tabIndex.sort(\r
580                         function (a, b){\r
581                                 return a.tabIndex - b.tabIndex;\r
582                         }\r
583                 );\r
585                 // merge the elements to create the correct tab position\r
586                 tabIndex = $.merge(tabIndex, posIndex);\r
588                 for( var i=0; i < tabIndex.length; i++ ){\r
589                         if( tabIndex[i] == $field ) return [i, tabIndex];\r
590                 }\r
592                 return [-1, tabIndex];\r
593         };\r
595         /*\r
596          * jQuery.fn.limitSelection()\r
597          *\r
598          * limits the number of items that can be selected\r
599          *\r
600          * Examples:\r
601          * $("input:checkbox").limitSelection(3);\r
602          * > No more than 3 items can be selected\r
603          *\r
604          * $("input:checkbox").limitSelection(2, {onsuccess: function (), onfailure: function ()});\r
605          * > Limits the selection to 2 items and runs the callback function when\r
606          * > more than 2 items have been selected.\r
607          *\r
608          * NOTE: Current when a "select-multiple" option undoes the selection,\r
609          * it selects the first 3 options in the array--which isn't necessarily\r
610          * the first 3 options the user selected. This is not the most desired\r
611          * behavior.\r
612          *\r
613          */\r
614         $.fn.limitSelection = function(limit, options){\r
615                 // get the options to use\r
616                 var opt = jQuery.extend(\r
617                         (limit && limit.constructor == Object ? limit : {\r
618                                         limit: limit\r
619                                 , onsuccess: function (limit){ return true; }\r
620                                 , onfailure: function (limit){ alert("You can only select a maximum a of " + limit + " items."); return false; }\r
621                         })\r
622                         , options);\r
623                 \r
624                 var self = this;\r
626                 var getCount = function (el){\r
627                         if( el.type == "select-multiple" ) return $("option:selected", self).length;\r
628                         else if( el.type == "checkbox" ) return self.filter(":checked").length;\r
629                         return 0;\r
630                 };\r
632                 var undoSelect = function (){\r
633                         // reduce selection to n items\r
634                         setValue(self, getValue(self).slice(0, opt.limit));\r
635                         // do callback\r
636                         return opt.onfailure.apply(self, [opt.limit]);\r
637                 };\r
639                 return this.bind(\r
640                         (!!self[0] && self[0].type == "select-multiple") ? "change.limitSelection" : "click.limitSelection",\r
641                         function (){\r
642                                 if( getCount(this) > opt.limit ){\r
643                                         // run callback, it must return false to prevent action\r
644                                         return (this.type == "select-multiple") ? undoSelect() : opt.onfailure.apply(self, [opt.limit]);\r
645                                 }\r
646                                 opt.onsuccess.apply(self, [opt.limit]);\r
647                                 return true;\r
648                         }\r
649                 );\r
650         };\r
652         /*\r
653          * jQuery.fn.createCheckboxRange()\r
654          *\r
655          * limits the number of items that can be selected\r
656          *\r
657          * Examples:\r
658          * $("input:checkbox").createCheckboxRange();\r
659          * > Allows a [SHIFT] + mouseclick to select all the items from the last\r
660          * > checked checkmark to the current checkbox.\r
661          *\r
662          * $("input:checkbox").createCheckboxRange(callback);\r
663          * > Runs the callback method for each item who's checked status changes.\r
664          * > This allows you to build hooks to highlight rows.\r
665          *\r
666          */\r
667         $.fn.createCheckboxRange = function(callback){\r
668                 // get the options to use\r
669                 var opt = jQuery.extend(\r
670                         (callback && callback.constructor == Object ? callback : {\r
671                                         bind: defaults.checkboxRangeKeyBinding\r
672                                 , click: callback\r
673                         })\r
674                         , callback);\r
676                 var iLastSelection = 0, self = this, bCallback = $.isFunction(opt.click);\r
678                 // if there's a call back, bind it now and run it\r
679                 if( bCallback ) \r
680                         this.each(function (){opt.click.apply(this, [$.event.fix({type: null}), $(this).is(":checked")])});\r
681                 \r
682                 // loop through each checkbox and return the jQuery object\r
683                 return this.each(\r
684                         function (){\r
685                                 // only perform this action on checkboxes\r
686                                 if( this.type != "checkbox" ) return false;\r
687                                 var el = this;\r
689                                 var updateLastCheckbox = function (e){\r
690                                         iLastSelection = self.index(e.target);\r
691                                 };\r
693                                 var checkboxClicked = function (e){\r
694                                         var bSetChecked = this.checked, current = self.index(e.target), low = Math.min(iLastSelection, current), high = Math.max(iLastSelection+1, current);\r
695                                         // run the callback for the clicked item\r
696                                         if( bCallback ) opt.click.apply(this, [e, bSetChecked]);\r
697                                         // if we don't detect the keypress, exit function\r
698                                         if( !e[opt.bind] ) return;\r
699                                         \r
700                                         // loop through the items in the selected range\r
701                                         for( var i=low; i < high; i++ ){\r
702                                                 // make sure to correctly set the checked status and run the change handler\r
703                                                 var item = self.eq(i).attr("checked", bSetChecked).trigger("change");\r
704                                                 // run the callback\r
705                                                 if( bCallback ) opt.click.apply(item[0], [e, bSetChecked]);\r
706                                         }\r
707                                         \r
708                                         return true;\r
709                                 };\r
710                                 \r
711                                 $(this)\r
712                                         // unbind the events so we can re-run the createCheckboxRange() plug-in for dynamically created elements\r
713                                         .unbind("click.createCheckboxRange")\r
715                                         // bind the functions, we bind on blur for keyboard selected items\r
716                                         .bind("click.createCheckboxRange", checkboxClicked)\r
717                                         .bind("click.createCheckboxRange", updateLastCheckbox)\r
718                                         ;\r
720                                 return true;\r
721                         }\r
722                 );\r
723         };\r
725         // determines how to process a field\r
726         var getType = function (el){\r
727                 var t = el.type;\r
729                 switch( t ){\r
730                         case "select": case "select-one": case "select-multiple":\r
731                                 t = "select";\r
732                                 break;\r
733                         case "text": case "hidden": case "textarea": case "password": case "button": case "submit": case "submit": case "file":\r
734                                 t = "text";\r
735                                 break;\r
736                         case "checkbox": case "radio":\r
737                                 t = t;\r
738                                 break;\r
739                 }\r
740                 return t;\r
741         };\r
743         // gets the value of a select element\r
744         var getOptionVal = function (el){\r
745                 // the attributes.specfied hack is for IE < 9 to deal with <option> tags with no value attribute\r
746                  return el.value || ((el.attributes && el.attributes['value'] && !(el.attributes['value'].specified)) ? el.text : null) || "";\r
747         };\r
749         // checks to see if a value exists in an array\r
750         var valueExists = function (a, v){\r
751                 return ($.inArray(v, a) > -1);\r
752         };\r
754         // correctly gets the type of an object (including array/dates)\r
755         var $type = function (o){\r
756                 var t = (typeof o).toLowerCase();\r
758                 if( t == "object" ){\r
759                         if( o instanceof Array ) t = "array";\r
760                         else if( o instanceof Date ) t = "date";\r
761                 }\r
762                 return t;\r
763         };\r
765         // checks to see if an object is the specified type\r
766         var $isType = function (o, v){\r
767                 return ($type(o) == String(v).toLowerCase());\r
768         };\r
770 })(jQuery);\r