root/galaxy-central/static/scripts/jquery.form.js @ 2

リビジョン 2, 22.6 KB (コミッタ: hatakeyama, 14 年 前)

import galaxy-central

行番号 
1/*
2 * jQuery Form Plugin
3 * version: 2.21 (08-FEB-2009)
4 * @requires jQuery v1.2.2 or later
5 *
6 * Examples and documentation at: http://malsup.com/jquery/form/
7 * Dual licensed under the MIT and GPL licenses:
8 *   http://www.opensource.org/licenses/mit-license.php
9 *   http://www.gnu.org/licenses/gpl.html
10 */
11;(function($) {
12
13/*
14    Usage Note: 
15    -----------
16    Do not use both ajaxSubmit and ajaxForm on the same form.  These
17    functions are intended to be exclusive.  Use ajaxSubmit if you want
18    to bind your own submit handler to the form.  For example,
19
20    $(document).ready(function() {
21        $('#myForm').bind('submit', function() {
22            $(this).ajaxSubmit({
23                target: '#output'
24            });
25            return false; // <-- important!
26        });
27    });
28
29    Use ajaxForm when you want the plugin to manage all the event binding
30    for you.  For example,
31
32    $(document).ready(function() {
33        $('#myForm').ajaxForm({
34            target: '#output'
35        });
36    });
37       
38    When using ajaxForm, the ajaxSubmit function will be invoked for you
39    at the appropriate time. 
40*/
41
42/**
43 * ajaxSubmit() provides a mechanism for immediately submitting
44 * an HTML form using AJAX.
45 */
46$.fn.ajaxSubmit = function(options) {
47    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
48    if (!this.length) {
49        log('ajaxSubmit: skipping submit process - no element selected');
50        return this;
51    }
52
53    if (typeof options == 'function')
54        options = { success: options };
55
56    options = $.extend({
57        url:  this.attr('action') || window.location.toString(),
58        type: this.attr('method') || 'GET'
59    }, options || {});
60
61    // hook for manipulating the form data before it is extracted;
62    // convenient for use with rich editors like tinyMCE or FCKEditor
63    var veto = {};
64    this.trigger('form-pre-serialize', [this, options, veto]);
65    if (veto.veto) {
66        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
67        return this;
68    }
69
70    // provide opportunity to alter form data before it is serialized
71    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
72        log('ajaxSubmit: submit aborted via beforeSerialize callback');
73        return this;
74    }   
75   
76    var a = this.formToArray(options.semantic);
77    if (options.data) {
78        options.extraData = options.data;
79        for (var n in options.data) {
80          if(options.data[n] instanceof Array) {
81            for (var k in options.data[n])
82              a.push( { name: n, value: options.data[n][k] } )
83          } 
84          else
85             a.push( { name: n, value: options.data[n] } );
86        }
87    }
88
89    // give pre-submit callback an opportunity to abort the submit
90    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
91        log('ajaxSubmit: submit aborted via beforeSubmit callback');
92        return this;
93    }   
94
95    // fire vetoable 'validate' event
96    this.trigger('form-submit-validate', [a, this, options, veto]);
97    if (veto.veto) {
98        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
99        return this;
100    }   
101
102    var q = $.param(a);
103
104    if (options.type.toUpperCase() == 'GET') {
105        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
106        options.data = null;  // data is null for 'get'
107    }
108    else
109        options.data = q; // data is the query string for 'post'
110
111    var $form = this, callbacks = [];
112    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
113    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
114
115    // perform a load on the target only if dataType is not provided
116    if (!options.dataType && options.target) {
117        var oldSuccess = options.success || function(){};
118        callbacks.push(function(data) {
119            $(options.target).html(data).each(oldSuccess, arguments);
120        });
121    }
122    else if (options.success)
123        callbacks.push(options.success);
124
125    options.success = function(data, status) {
126        for (var i=0, max=callbacks.length; i < max; i++)
127            callbacks[i].apply(options, [data, status, $form]);
128    };
129
130    // are there files to upload?
131    var files = $('input:file', this).fieldValue();
132    var found = false;
133    for (var j=0; j < files.length; j++)
134        if (files[j])
135            found = true;
136
137    // options.iframe allows user to force iframe mode
138   if (options.iframe || found) {
139       // hack to fix Safari hang (thanks to Tim Molendijk for this)
140       // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
141       if (options.closeKeepAlive)
142           $.get(options.closeKeepAlive, fileUpload);
143       else
144           fileUpload();
145       }
146   else
147       $.ajax(options);
148
149    // fire 'notify' event
150    this.trigger('form-submit-notify', [this, options]);
151    return this;
152
153
154    // private function for handling file uploads (hat tip to YAHOO!)
155    function fileUpload() {
156        var form = $form[0];
157       
158        if ($(':input[name=submit]', form).length) {
159            alert('Error: Form elements must not be named "submit".');
160            return;
161        }
162       
163        var opts = $.extend({}, $.ajaxSettings, options);
164                var s = jQuery.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
165
166        var id = 'jqFormIO' + (new Date().getTime());
167        var $io = $('<iframe id="' + id + '" name="' + id + '" src="about:blank" />');
168        var io = $io[0];
169
170        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
171
172        var xhr = { // mock object
173            aborted: 0,
174            responseText: null,
175            responseXML: null,
176            status: 0,
177            statusText: 'n/a',
178            getAllResponseHeaders: function() {},
179            getResponseHeader: function() {},
180            setRequestHeader: function() {},
181            abort: function() {
182                this.aborted = 1;
183                $io.attr('src','about:blank'); // abort op in progress
184            }
185        };
186
187        var g = opts.global;
188        // trigger ajax global events so that activity/block indicators work like normal
189        if (g && ! $.active++) $.event.trigger("ajaxStart");
190        if (g) $.event.trigger("ajaxSend", [xhr, opts]);
191
192                if (s.beforeSend && s.beforeSend(xhr, s) === false) {
193                        s.global && jQuery.active--;
194                        return;
195        }
196        if (xhr.aborted)
197            return;
198       
199        var cbInvoked = 0;
200        var timedOut = 0;
201
202        // add submitting element to data if we know it
203        var sub = form.clk;
204        if (sub) {
205            var n = sub.name;
206            if (n && !sub.disabled) {
207                options.extraData = options.extraData || {};
208                options.extraData[n] = sub.value;
209                if (sub.type == "image") {
210                    options.extraData[name+'.x'] = form.clk_x;
211                    options.extraData[name+'.y'] = form.clk_y;
212                }
213            }
214        }
215
216        // take a breath so that pending repaints get some cpu time before the upload starts
217        setTimeout(function() {
218            // make sure form attrs are set
219            var t = $form.attr('target'), a = $form.attr('action');
220
221                        // update form attrs in IE friendly way
222                        form.setAttribute('target',id);
223                        if (form.getAttribute('method') != 'POST')
224                                form.setAttribute('method', 'POST');
225                        if (form.getAttribute('action') != opts.url)
226                                form.setAttribute('action', opts.url);
227                                                       
228            // ie borks in some cases when setting encoding
229            if (! options.skipEncodingOverride) {
230                $form.attr({
231                    encoding: 'multipart/form-data',
232                    enctype:  'multipart/form-data'
233                });
234            }
235
236            // support timout
237            if (opts.timeout)
238                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
239
240            // add "extra" data to form if provided in options
241            var extraInputs = [];
242            try {
243                if (options.extraData)
244                    for (var n in options.extraData)
245                        extraInputs.push(
246                            $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
247                                .appendTo(form)[0]);
248           
249                // add iframe to doc and submit the form
250                $io.appendTo('body');
251                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
252                form.submit();
253            }
254            finally {
255                // reset attrs and remove "extra" input elements
256                                form.setAttribute('action',a);
257                t ? form.setAttribute('target', t) : $form.removeAttr('target');
258                $(extraInputs).remove();
259            }
260        }, 10);
261
262        var nullCheckFlag = 0;
263               
264        function cb() {
265            if (cbInvoked++) return;
266           
267            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
268
269            var ok = true;
270            try {
271                if (timedOut) throw 'timeout';
272                // extract the server response from the iframe
273                var data, doc;
274
275                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
276               
277                if ((doc.body == null || doc.body.innerHTML == '') && !nullCheckFlag) {
278                    // in some browsers (cough, Opera 9.2.x) the iframe DOM is not always traversable when
279                    // the onload callback fires, so we give them a 2nd chance
280                    nullCheckFlag = 1;
281                    cbInvoked--;
282                    setTimeout(cb, 100);
283                    return;
284                }
285               
286                xhr.responseText = doc.body ? doc.body.innerHTML : null;
287                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
288                xhr.getResponseHeader = function(header){
289                    var headers = {'content-type': opts.dataType};
290                    return headers[header];
291                };
292
293                if (opts.dataType == 'json' || opts.dataType == 'script') {
294                    var ta = doc.getElementsByTagName('textarea')[0];
295                    xhr.responseText = ta ? ta.value : xhr.responseText;
296                }
297                else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
298                    xhr.responseXML = toXml(xhr.responseText);
299                }
300                data = $.httpData(xhr, opts.dataType);
301            }
302            catch(e){
303                ok = false;
304                $.handleError(opts, xhr, 'error', e);
305            }
306
307            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
308            if (ok) {
309                opts.success(data, 'success');
310                if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
311            }
312            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
313            if (g && ! --$.active) $.event.trigger("ajaxStop");
314            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
315
316            // clean up
317            setTimeout(function() {
318                $io.remove();
319                xhr.responseXML = null;
320            }, 100);
321        };
322
323        function toXml(s, doc) {
324            if (window.ActiveXObject) {
325                doc = new ActiveXObject('Microsoft.XMLDOM');
326                doc.async = 'false';
327                doc.loadXML(s);
328            }
329            else
330                doc = (new DOMParser()).parseFromString(s, 'text/xml');
331            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
332        };
333    };
334};
335
336/**
337 * ajaxForm() provides a mechanism for fully automating form submission.
338 *
339 * The advantages of using this method instead of ajaxSubmit() are:
340 *
341 * 1: This method will include coordinates for <input type="image" /> elements (if the element
342 *    is used to submit the form).
343 * 2. This method will include the submit element's name/value data (for the element that was
344 *    used to submit the form).
345 * 3. This method binds the submit() method to the form for you.
346 *
347 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
348 * passes the options argument along after properly binding events for submit elements and
349 * the form itself.
350 */
351$.fn.ajaxForm = function(options) {
352    return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
353        $(this).ajaxSubmit(options);
354        return false;
355    }).each(function() {
356        // store options in hash
357        $(":submit,input:image", this).bind('click.form-plugin',function(e) {
358            var form = this.form;
359            form.clk = this;
360            if (this.type == 'image') {
361                if (e.offsetX != undefined) {
362                    form.clk_x = e.offsetX;
363                    form.clk_y = e.offsetY;
364                } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
365                    var offset = $(this).offset();
366                    form.clk_x = e.pageX - offset.left;
367                    form.clk_y = e.pageY - offset.top;
368                } else {
369                    form.clk_x = e.pageX - this.offsetLeft;
370                    form.clk_y = e.pageY - this.offsetTop;
371                }
372            }
373            // clear form vars
374            setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
375        });
376    });
377};
378
379// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
380$.fn.ajaxFormUnbind = function() {
381    this.unbind('submit.form-plugin');
382    return this.each(function() {
383        $(":submit,input:image", this).unbind('click.form-plugin');
384    });
385
386};
387
388/**
389 * formToArray() gathers form element data into an array of objects that can
390 * be passed to any of the following ajax functions: $.get, $.post, or load.
391 * Each object in the array has both a 'name' and 'value' property.  An example of
392 * an array for a simple login form might be:
393 *
394 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
395 *
396 * It is this array that is passed to pre-submit callback functions provided to the
397 * ajaxSubmit() and ajaxForm() methods.
398 */
399$.fn.formToArray = function(semantic) {
400    var a = [];
401    if (this.length == 0) return a;
402
403    var form = this[0];
404    var els = semantic ? form.getElementsByTagName('*') : form.elements;
405    if (!els) return a;
406    for(var i=0, max=els.length; i < max; i++) {
407        var el = els[i];
408        var n = el.name;
409        if (!n) continue;
410
411        if (semantic && form.clk && el.type == "image") {
412            // handle image inputs on the fly when semantic == true
413            if(!el.disabled && form.clk == el)
414                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
415            continue;
416        }
417
418        var v = $.fieldValue(el, true);
419        if (v && v.constructor == Array) {
420            for(var j=0, jmax=v.length; j < jmax; j++)
421                a.push({name: n, value: v[j]});
422        }
423        else if (v !== null && typeof v != 'undefined')
424            a.push({name: n, value: v});
425    }
426
427    if (!semantic && form.clk) {
428        // input type=='image' are not found in elements array! handle them here
429        var inputs = form.getElementsByTagName("input");
430        for(var i=0, max=inputs.length; i < max; i++) {
431            var input = inputs[i];
432            var n = input.name;
433            if(n && !input.disabled && input.type == "image" && form.clk == input)
434                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
435        }
436    }
437    return a;
438};
439
440/**
441 * Serializes form data into a 'submittable' string. This method will return a string
442 * in the format: name1=value1&amp;name2=value2
443 */
444$.fn.formSerialize = function(semantic) {
445    //hand off to jQuery.param for proper encoding
446    return $.param(this.formToArray(semantic));
447};
448
449/**
450 * Serializes all field elements in the jQuery object into a query string.
451 * This method will return a string in the format: name1=value1&amp;name2=value2
452 */
453$.fn.fieldSerialize = function(successful) {
454    var a = [];
455    this.each(function() {
456        var n = this.name;
457        if (!n) return;
458        var v = $.fieldValue(this, successful);
459        if (v && v.constructor == Array) {
460            for (var i=0,max=v.length; i < max; i++)
461                a.push({name: n, value: v[i]});
462        }
463        else if (v !== null && typeof v != 'undefined')
464            a.push({name: this.name, value: v});
465    });
466    //hand off to jQuery.param for proper encoding
467    return $.param(a);
468};
469
470/**
471 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
472 *
473 *  <form><fieldset>
474 *      <input name="A" type="text" />
475 *      <input name="A" type="text" />
476 *      <input name="B" type="checkbox" value="B1" />
477 *      <input name="B" type="checkbox" value="B2"/>
478 *      <input name="C" type="radio" value="C1" />
479 *      <input name="C" type="radio" value="C2" />
480 *  </fieldset></form>
481 *
482 *  var v = $(':text').fieldValue();
483 *  // if no values are entered into the text inputs
484 *  v == ['','']
485 *  // if values entered into the text inputs are 'foo' and 'bar'
486 *  v == ['foo','bar']
487 *
488 *  var v = $(':checkbox').fieldValue();
489 *  // if neither checkbox is checked
490 *  v === undefined
491 *  // if both checkboxes are checked
492 *  v == ['B1', 'B2']
493 *
494 *  var v = $(':radio').fieldValue();
495 *  // if neither radio is checked
496 *  v === undefined
497 *  // if first radio is checked
498 *  v == ['C1']
499 *
500 * The successful argument controls whether or not the field element must be 'successful'
501 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
502 * The default value of the successful argument is true.  If this value is false the value(s)
503 * for each element is returned.
504 *
505 * Note: This method *always* returns an array.  If no valid value can be determined the
506 *       array will be empty, otherwise it will contain one or more values.
507 */
508$.fn.fieldValue = function(successful) {
509    for (var val=[], i=0, max=this.length; i < max; i++) {
510        var el = this[i];
511        var v = $.fieldValue(el, successful);
512        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
513            continue;
514        v.constructor == Array ? $.merge(val, v) : val.push(v);
515    }
516    return val;
517};
518
519/**
520 * Returns the value of the field element.
521 */
522$.fieldValue = function(el, successful) {
523    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
524    if (typeof successful == 'undefined') successful = true;
525
526    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
527        (t == 'checkbox' || t == 'radio') && !el.checked ||
528        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
529        tag == 'select' && el.selectedIndex == -1))
530            return null;
531
532    if (tag == 'select') {
533        var index = el.selectedIndex;
534        if (index < 0) return null;
535        var a = [], ops = el.options;
536        var one = (t == 'select-one');
537        var max = (one ? index+1 : ops.length);
538        for(var i=(one ? index : 0); i < max; i++) {
539            var op = ops[i];
540            if (op.selected) {
541                                var v = op.value;
542                                if (!v) // extra pain for IE...
543                        v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
544                if (one) return v;
545                a.push(v);
546            }
547        }
548        return a;
549    }
550    return el.value;
551};
552
553/**
554 * Clears the form data.  Takes the following actions on the form's input fields:
555 *  - input text fields will have their 'value' property set to the empty string
556 *  - select elements will have their 'selectedIndex' property set to -1
557 *  - checkbox and radio inputs will have their 'checked' property set to false
558 *  - inputs of type submit, button, reset, and hidden will *not* be effected
559 *  - button elements will *not* be effected
560 */
561$.fn.clearForm = function() {
562    return this.each(function() {
563        $('input,select,textarea', this).clearFields();
564    });
565};
566
567/**
568 * Clears the selected form elements.
569 */
570$.fn.clearFields = $.fn.clearInputs = function() {
571    return this.each(function() {
572        var t = this.type, tag = this.tagName.toLowerCase();
573        if (t == 'text' || t == 'password' || tag == 'textarea')
574            this.value = '';
575        else if (t == 'checkbox' || t == 'radio')
576            this.checked = false;
577        else if (tag == 'select')
578            this.selectedIndex = -1;
579    });
580};
581
582/**
583 * Resets the form data.  Causes all form elements to be reset to their original value.
584 */
585$.fn.resetForm = function() {
586    return this.each(function() {
587        // guard against an input with the name of 'reset'
588        // note that IE reports the reset function as an 'object'
589        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
590            this.reset();
591    });
592};
593
594/**
595 * Enables or disables any matching elements.
596 */
597$.fn.enable = function(b) {
598    if (b == undefined) b = true;
599    return this.each(function() {
600        this.disabled = !b
601    });
602};
603
604/**
605 * Checks/unchecks any matching checkboxes or radio buttons and
606 * selects/deselects and matching option elements.
607 */
608$.fn.selected = function(select) {
609    if (select == undefined) select = true;
610    return this.each(function() {
611        var t = this.type;
612        if (t == 'checkbox' || t == 'radio')
613            this.checked = select;
614        else if (this.tagName.toLowerCase() == 'option') {
615            var $sel = $(this).parent('select');
616            if (select && $sel[0] && $sel[0].type == 'select-one') {
617                // deselect all other options
618                $sel.find('option').selected(false);
619            }
620            this.selected = select;
621        }
622    });
623};
624
625// helper fn for console logging
626// set $.fn.ajaxSubmit.debug to true to enable debug logging
627function log() {
628    if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
629        window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
630};
631
632})(jQuery);
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。