/[drupal]/contributions/modules/autosave/jquery.field.js
ViewVC logotype

Contents of /contributions/modules/autosave/jquery.field.js

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Tue Oct 27 07:39:05 2009 UTC (4 weeks, 1 day ago) by ptalindstrom
Branch: MAIN
CVS Tags: DRUPAL-6--2-5, DRUPAL-6--2-4, DRUPAL-6--2-3, DRUPAL-6--2-2, DRUPAL-6--2-1, DRUPAL-6--2-0, HEAD
Changes since 1.2: +2 -3 lines
File MIME type: text/javascript
- 6.x-2.0 version is a complete re-write to remove dependencies on TinyMCE.
- this version is now tied to the WYSIWYG module and currently is known to work with FCK, CK and TinyMCE 3.0 editors but requires
the 6.x-2.x-dev version of WYSIWYG with this patch: http://drupal.org/node/614146#comment-2193764; this patch should be commited soon and will
eventually be expanded to include other editors.
1 // $Id: jquery.field.js,v 1.2.2.6 2008/07/20 23:42:11 ptalindstrom Exp $
2
3 /*
4 * jQuery Field Plug-in
5 *
6 * Copyright (c) 2007 Dan G. Switzer, II
7 *
8 * Dual licensed under the MIT and GPL licenses:
9 * http://www.opensource.org/licenses/mit-license.php
10 * http://www.gnu.org/licenses/gpl.html
11 *
12 * Revision: 8
13 * Version: 0.7-mod
14 *
15 * NOTES: The getValue() and setValue() methods are designed to be
16 * executed on single field (i.e. any field that would share the same
17 * "name" attribute--a single text box, a group of checkboxes or radio
18 * elements, etc.)
19 *
20 * Revision History
21 * v0.7-mod
22 * - Modified slightly by Edmund Kwok to work with Drupal's autosave.module. Refer to $.formHash().
23 *
24 * v0.7
25 * - Added tabIndex related function (getTabIndex, moveNext, movePrev, moveIndex)
26 *
27 * v0.6
28 * - Fixed bug in the $.formHash() where the arrayed form elements would
29 * not correctly report their values.
30 * - Added the $.createCheckboxRange() which allow you to select multiple
31 * checkbox elements by doing a [SHIFT] + click.
32 *
33 * v0.5
34 * - Added $.limitSelection() method for limiting the number of
35 * selection in a select-multiple of checkbox array.
36 *
37 * v0.4.1
38 * - Moved $.type and $.isType into private functions
39 * - Rewrote $type() function to use instanceof operator
40 *
41 * v0.4
42 * - Added the formHash() method
43 *
44 * v0.3
45 * - First public release
46 *
47 */
48 (function($){
49
50 // set the defaults
51 var defaults = {
52 // use a comma as the string delimiter
53 delimiter: ",",
54 // for methods that could return either a string or array, decide default behavior
55 useArray: false
56 }
57
58 // set default options
59 $.Field = {
60 version: "0.7",
61 setDefaults: function(options){
62 $.extend(defaults, options);
63 }
64 }
65
66
67 /*
68 * jQuery.fn.fieldArray()
69 *
70 * returns either an array of values or a jQuery object
71 *
72 * NOTE: This *MAY* break the jQuery chain
73 *
74 * Examples:
75 * $("input[@name='name']").fieldArray();
76 * > Gets the current value of the name text element
77 *
78 * $("input[@name='name']").fieldArray(["Dan G. Switzer, II"]);
79 * > Sets the value of the name text element to "Dan G. Switzer, II"
80 *
81 * $("select[@name='state']").fieldArray();
82 * > Gets the current value of the state text element
83 *
84 * $("select[@name='state']").setValue(["OH","NY","CA"]);
85 * > Sets the selected value of the "state" select element to OH, NY and CA
86 *
87 */
88 // this will set/get the values for a field based upon and array
89 $.fn.fieldArray = function(v){
90 var t = $type(v);
91
92 // if no value supplied, return an array of values
93 if( t == "undefined" ) return getValue(this);
94
95 // convert the number/string into an array
96 if( t == "string" || t == "number" ){
97 v = v.toString().split(defaults.delimiter);
98 t = "array";
99 }
100
101 // set the value -- doesn't break the chaing
102 if( t == "array" ) return setValue(this, v);
103
104 // if we don't know what do to, don't break the chain
105 return this;
106 }
107
108 /*
109 * jQuery.fn.getValue()
110 *
111 * returns String - a comma delimited list of values for the field
112 *
113 * NOTE: Breaks the jQuery chain, since it returns a string.
114 *
115 * Examples:
116 * $("input[@name='name']").getValue();
117 * > This would return the value of the name text element
118 *
119 * $("select[@name='state']").getValue();
120 * > This would return the currently selected value of the "state" select element
121 *
122 */
123 // the getValue() method -- break the chain
124 $.fn.getValue = function(){
125 // return the values as a comma-delimited string
126 return getValue(this).join(defaults.delimiter);
127 }
128
129 /*
130 * getValue()
131 *
132 * returns Array - an array of values for the field
133 *
134 */
135 // the getValue() method -- break the chain
136 var getValue = function(jq){
137 var v = [];
138
139 jq.each(
140 function (lc){
141 // get the current type
142 var t = getType(this);
143
144 switch( t ){
145 case "checkbox": case "radio":
146 // if the checkbox or radio element is checked
147 if( this.checked ) v.push(this.value);
148 break;
149
150 case "select":
151 if( this.type == "select-one" ){
152 v.push( (this.selectedIndex == -1) ? "" : getOptionVal(this[this.selectedIndex]) );
153 } else {
154 // loop through all element in the array for this field
155 for( var i=0; i < this.length; i++ ){
156 // if the element is selected, get the selected values
157 if( this[i].selected ){
158 // append the selected value, if the value property doesn't exist, use the text
159 v.push(getOptionVal(this[i]));
160 }
161 }
162 }
163 break;
164
165 case "text":
166 v.push(this.value);
167 break;
168 }
169 }
170 );
171
172 // return the values as an array
173 return v;
174 }
175
176 /*
177 * setValue()
178 *
179 * returns jQuery object
180 *
181 * NOTE: This does *NOT* break the jQuery chain
182 *
183 * Examples:
184 * $("input[@name='name']").setValue("Dan G. Switzer, II");
185 * > Sets the value of the name text element to "Dan G. Switzer, II"
186 *
187 * $("select[@name='state']").setValue("OH");
188 * > Sets the selected value of the "state" select element to "OH"
189 *
190 */
191 // the setValue() method -- does *not* break the chain
192 $.fn.setValue = function(v){
193 // f no value, set to empty string
194 return setValue(this, (!v ? [""] : v.toString().split(defaults.delimiter)));
195 }
196
197 /*
198 * setValue()
199 *
200 * returns jQuery object
201 *
202 */
203 // the setValue() method -- does *not* break the chain
204 var setValue = function(jq, v){
205
206 jq.each(
207 function (lc){
208 var t = getType(this), x;
209
210 switch( t ){
211 case "checkbox": case "radio":
212 if( valueExists(v, this.value) ) this.checked = true;
213 else this.checked = false;
214 break;
215
216 case "select":
217 var bSelectOne = (this.type == "select-one");
218 var bKeepLooking = true; // if select-one type, then only select the first value found
219 // loop through all element in the array for this field
220 for( var i=0; i < this.length; i++ ){
221 x = getOptionVal(this[i]);
222 bSelectItem = valueExists(v, x);
223 if( bSelectItem ){
224 this[i].selected = true;
225 // if a select-one element
226 if( bSelectOne ){
227 // no need to look farther
228 bKeepLooking = false;
229 // stop the loop
230 break;
231 }
232 } else if( !bSelectOne ) this[i].selected = false;
233 }
234 // if a select-one box and nothing selected, then try to select the default value
235 if( bSelectOne && bKeepLooking ){
236 this[0].selected = true;
237 }
238 break;
239
240 case "text":
241 this.value = v.join(defaults.delimiter);
242 break;
243 }
244
245 }
246 );
247
248 return jq;
249 }
250
251 /*
252 * jQuery.fn.formHash()
253 *
254 * returns either an hash table of form fields or a jQuery object
255 *
256 * NOTE: This *MAY* break the jQuery chain
257 *
258 * Examples:
259 * $("#formName").formHash();
260 * > Returns a hash map of all the form fields and their values
261 *
262 * $("#formName").formHash({"name": "Dan G. Switzer, II", "state": "OH"});
263 * > Returns the jQuery chain and sets the fields "name" and "state" with
264 * > the values "Dan G. Switzer, II" and "OH" respectively.
265 *
266 */
267 // the formHash() method -- break the chain
268 $.fn.formHash = function(inHash){
269 var bGetHash = (arguments.length == 0);
270 // create a hash to return
271 var stHash = {};
272
273 // run the code for each form
274 this.filter("form").each(
275 function (){
276 // get all the form elements
277 var els = this.elements, el, n, stProcessed = {}, jel;
278 // loop through the elements and process
279 for( var i=0, elsMax = els.length; i < elsMax; i++ ){
280 el = els[i], n = el.name;
281
282 // Avoid submit buttons; Drupal forms with two submit buttons (eg Submit and Cancel) usually has the same name - op.
283 // These buttons will then have same names when value is set.
284 if (el.type == 'submit') {
285 continue;
286 }
287
288 // if the element doesn't have a name, then skip it
289 if( !n || stProcessed[n] ) continue;
290
291 // create a jquery object to the current named form elements
292 var jel = $(el.tagName.toLowerCase() + "[@name='"+n+"']", this);
293
294 // if we're getting the values, get them now
295 if( bGetHash ){
296 stHash[n] = jel[defaults.useArray ? "fieldArray" : "getValue"]();
297 // if we're setting values, set them now
298 } else {
299 if(!!inHash[n] ){
300 jel[defaults.useArray ? "fieldArray" : "setValue"](inHash[n]);
301 }
302 else {
303 // Deal with Drupal form elements with square brackets in their name (eg field_name[key]).
304 var value=null;
305 n = n.replace(/\[/g,','); n = n.replace(/\]/g,',');
306 keys = n.split(",");
307 if (keys.length > 1) {
308 for (var key in keys) {
309 if (keys[key]) {
310 if (!value) value = inHash[keys[key]];
311 else value = value[keys[key]];
312 }
313 }
314 }
315 jel[defaults.useArray ? "fieldArray" : "setValue"](value);
316 }
317 }
318 stProcessed[n] = true;
319 }
320 }
321 );
322
323 // if getting a hash map return it, otherwise return the jQuery object
324 return (bGetHash) ? stHash : this;
325 }
326
327 /*
328 * jQuery.fn.autoAdvance()
329 *
330 * Finds all text-based input fields and makes them autoadvance to the next
331 * fields when they've met their maxlength property.
332 *
333 *
334 * Examples:
335 * $("#form").autoAdvance();
336 * > When a field reaches it's maxlength attribute value, it'll advance to the
337 * > next field in the form's tabindex.
338 *
339 */
340 // the autoAdvance() method
341 $.fn.autoAdvance = function(){
342 return this.find(":text,:password,textarea").bind(
343 "keyup",
344 function (e){
345 var
346 // get the field
347 $field = $(this),
348 // get the maxlength for the field
349 iMaxLength = parseInt($field.attr("maxlength"), 10);
350
351 // if the user tabs to the field, exit event handler
352 // this will prevent movement if the field is already
353 // field in with the max number of characters
354 if( isNaN(iMaxLength) || ("|9|16|37|38|39|40|".indexOf("|" + e.keyCode + "|") > -1) ) return true;
355
356 // if the value of the field is greater than maxlength attribute,
357 // then move the focus to the next field
358 if( $field.getValue().length >= $field.attr("maxlength") ){
359 // move to the next field and select the existing value
360 $field.moveNext().select();
361 }
362 }
363 );
364 }
365
366 /*
367 * jQuery.fn.moveNext()
368 *
369 * places the focus in the next form field. if the field element is
370 * the last in the form array, it'll return to the top.
371 *
372 * returns a jQuery object pointing to the next field element
373 *
374 * NOTE: if the selector returns multiple items, the first item is used.
375 *
376 *
377 * Examples:
378 * $("#firstName").moveNext();
379 * > Moves the focus to the next form field found after firstName
380 *
381 */
382 // the moveNext() method
383 $.fn.moveNext = function(){
384 return this.moveIndex("next");
385 }
386
387 /*
388 * jQuery.fn.movePrev()
389 *
390 * places the focus in the previous form field. if the field element is
391 * the first in the form array, it'll return to the last element.
392 *
393 * returns a jQuery object pointing to the previos field element
394 *
395 * NOTE: if the selector returns multiple items, the first item is used
396 *
397 * Examples:
398 * $("#firstName").movePrev();
399 * > Moves the focus to the next form field found after firstName
400 *
401 */
402 // the movePrev() method
403 $.fn.movePrev = function(){
404 return this.moveIndex("prev");
405 }
406
407 /*
408 * jQuery.fn.moveIndex()
409 *
410 * Places the tab index into the specified index position
411 *
412 * returns a jQuery object pointing to the previos field element
413 *
414 * NOTE: if the selector returns multiple items, the first item is used
415 *
416 * Examples:
417 * $("#firstName").movePrev();
418 * > Moves the focus to the next form field found after firstName
419 *
420 */
421 // the moveIndex() method
422 $.fn.moveIndex = function(i){
423 // get the current position and elements
424 var aPos = getFieldPosition(this);
425
426 // if a string option has been specified, calculate the position
427 if( i == "next" ) i = aPos[0] + 1; // get the next item
428 else if( i == "prev" ) i = aPos[0] - 1; // get the previous item
429
430 // make sure the index position is within the bounds of the elements array
431 if( i < 0 ) i = aPos[1].length-1;
432 else if( i >= aPos[1].length ) i = 0;
433
434 return $(aPos[1][i]).trigger("focus");
435 }
436
437 /*
438 * jQuery.fn.getTabIndex()
439 *
440 * gets the current tab index of the first element found in the selector
441 *
442 * NOTE: if the selector returns multiple items, the first item is used
443 *
444 * Examples:
445 * $("#firstName").getTabIndex();
446 * > Gets the tabIndex for the firstName field
447 *
448 */
449 // the getTabIndex() method
450 $.fn.getTabIndex = function(){
451 // return the position of the form field
452 return getFieldPosition(this)[0];
453 }
454
455 var getFieldPosition = function (jq){
456 var
457 // get the first matching field
458 $field = jq.filter("input select textarea").get(0),
459 // store items with a tabindex
460 aTabIndex = [],
461 // store items with no tabindex
462 aPosIndex = []
463 ;
464
465 // if there is no match, return 0
466 if( !$field ) return [-1, []];
467
468 // make a single pass thru all form elements
469 $.each(
470 $field.form.elements,
471 function (i, o){
472 if( o.tagName != "FIELDSET" && !o.disabled ){
473 if( o.tabIndex > 0 ){
474 aTabIndex.push(o);
475 } else {
476 aPosIndex.push(o);
477 }
478 }
479 }
480 );
481
482 // sort the fields that had tab indexes
483 aTabIndex.sort(
484 function (a, b){
485 return a.tabIndex - b.tabIndex;
486 }
487 );
488
489 // merge the elements to create the correct tab position
490 aTabIndex = $.merge(aTabIndex, aPosIndex);
491
492 for( var i=0; i < aTabIndex.length; i++ ){
493 if( aTabIndex[i] == $field ) return [i, aTabIndex];
494 }
495
496 return [-1, aTabIndex];
497 }
498
499 /*
500 * jQuery.fn.limitSelection()
501 *
502 * limits the number of items that can be selected
503 *
504 * Examples:
505 * $("input:checkbox").limitSelection(3);
506 * > No more than 3 items can be selected
507 *
508 * $("input:checkbox").limitSelection(2, errorCallback, successCallback);
509 * > Limits the selection to 2 items and runs the callback function when
510 * > more than 2 items have been selected.
511 *
512 * NOTE: Current when a "select-multiple" option undoes the selection,
513 * it selects the first 3 options in the array--which isn't necessarily
514 * the first 3 options the user selected. This is not the most desired
515 * behavior.
516 *
517 */
518 $.fn.limitSelection = function(n, _e, _s){
519 var self = this;
520 // define the callback actions
521 var cb_onError = (!!_e) ? _e : function (n){ alert("You can only select a maximum a of " + n + " items."); return false; };
522 var cb_onSuccess = (!!_s) ? _s : function (n){ return true; };
523
524 var getCount = function (el){
525 if( el.type == "select-multiple" ) return $("option:selected", self).length;
526 else if( el.type == "checkbox" ) return self.filter(":checked").length;
527 return 0;
528 }
529
530 var undoSelect = function (){
531 // reduce selection to n items
532 setValue(self, getValue(self).slice(0, n));
533 // do callback
534 return cb_onError(n, self);
535 }
536
537 self.bind(
538 (!!self[0] && self[0].type == "select-multiple") ? "change" : "click",
539 function (){
540 if( getCount(this) > n ){
541 // run callback, it must return false to prevent action
542 return (this.type == "select-multiple") ? undoSelect() : cb_onError(n, self);
543 }
544 cb_onSuccess(n, self);
545 return true;
546 }
547 );
548 return this;
549 }
550
551 /*
552 * jQuery.fn.createCheckboxRange()
553 *
554 * limits the number of items that can be selected
555 *
556 * Examples:
557 * $("input:checkbox").createCheckboxRange();
558 * > Allows a [SHIFT] + mouseclick to select all the items from the last
559 * > checked checkmark to the current checkbox.
560 *
561 */
562 $.fn.createCheckboxRange = function(){
563 var iLastSelection = 0, me = this;
564
565 // this finds the position of the current element in the array
566 var findArrayPos = function (el){
567 var pos = -1;
568 $("input[@name='"+me[0].name+"']").each(
569 function (i){
570 if( this == el ){
571 pos = i;
572 return false;
573 }
574 }
575 );
576
577 return pos;
578 }
579
580 this.each(
581 function (lc){
582 // only perform this action on checkboxes
583 if( this.type != "checkbox" ) return false;
584 var self = this;
585
586 var updateLastCheckbox = function (e){
587 iLastSelection = findArrayPos(e.target);
588 }
589
590 var checkboxClicked = function (e){
591 var bSetChecked = this.checked, current = findArrayPos(e.target), iHigh, iLow;
592 // if we don't detect the keypress, exit function
593 if( !e.shiftKey ) return;
594
595 // figure out which is the highest and which is the lowest value
596 if( iLastSelection > current ){
597 iHigh = iLastSelection;
598 iLow = current-1;
599 } else {
600 iHigh = current;
601 iLow = iLastSelection-1;
602 }
603
604 $("input[@name='"+self.name+"']:gt("+iLow+"):lt("+iHigh+")").attr("checked", bSetChecked ? "checked" : "");
605 }
606
607 $(this)
608 // unbind the events so we can re-run the createCheckboxRange() plug-in for dynamicall created elements
609 .unbind("blur", updateLastCheckbox)
610 .unbind("click", checkboxClicked)
611
612 // bind the functions
613 .bind("blur", updateLastCheckbox)
614 .bind("click", checkboxClicked)
615 ;
616
617 return true;
618 }
619 );
620 }
621
622 // determines how to process a field
623 var getType = function (el){
624 var t = el.type;
625
626 switch( t ){
627 case "select": case "select-one": case "select-multiple":
628 t = "select";
629 break;
630 case "text": case "hidden": case "textarea": case "password": case "button": case "submit": case "submit":
631 t = "text";
632 break;
633 case "checkbox": case "radio":
634 t = t;
635 break;
636 }
637 return t;
638 }
639
640 // gets the value of a select element
641 var getOptionVal = function (el){
642 return jQuery.browser.msie && !(el.attributes['value'].specified) ? el.text : el.value;
643 }
644
645 // checks to see if a value exists in an array
646 var valueExists = function (a, v){
647 return ($.inArray(v, a) > -1);
648 }
649
650 // correctly gets the type of an object (including array/dates)
651 var $type = function (o){
652 var t = (typeof o).toLowerCase();
653
654 if( t == "object" ){
655 if( o instanceof Array ) t = "array";
656 else if( o instanceof Date ) t = "date";
657 }
658 return t;
659 }
660
661 // checks to see if an object is the specified type
662 var $isType = function (o, v){
663 return ($type(o) == String(v).toLowerCase());
664 }
665
666 })(jQuery);
667

  ViewVC Help
Powered by ViewVC 1.1.2