Commit 3ccee3ee3366469a9b2f7321b1fa36234019c44a

Authored by Lucas D'Avila
1 parent 3fbe291a
Exists in master

Adicionado plugin jquery, para suportar submissão de formulários via ajax

Showing 1 changed file with 919 additions and 0 deletions   Show diff stats
ieducar/intranet/scripts/jquery/jquery.form.js 0 → 100644
... ... @@ -0,0 +1,919 @@
  1 +/*!
  2 + * jQuery Form Plugin
  3 + * version: 2.87 (20-OCT-2011)
  4 + * @requires jQuery v1.3.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(e) {
  22 + e.preventDefault(); // <-- important
  23 + $(this).ajaxSubmit({
  24 + target: '#output'
  25 + });
  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 + var method, action, url, $form = this;
  54 +
  55 + if (typeof options == 'function') {
  56 + options = { success: options };
  57 + }
  58 +
  59 + method = this.attr('method');
  60 + action = this.attr('action');
  61 + url = (typeof action === 'string') ? $.trim(action) : '';
  62 + url = url || window.location.href || '';
  63 + if (url) {
  64 + // clean url (don't include hash vaue)
  65 + url = (url.match(/^([^#]+)/)||[])[1];
  66 + }
  67 +
  68 + options = $.extend(true, {
  69 + url: url,
  70 + success: $.ajaxSettings.success,
  71 + type: method || 'GET',
  72 + iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
  73 + }, options);
  74 +
  75 + // hook for manipulating the form data before it is extracted;
  76 + // convenient for use with rich editors like tinyMCE or FCKEditor
  77 + var veto = {};
  78 + this.trigger('form-pre-serialize', [this, options, veto]);
  79 + if (veto.veto) {
  80 + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
  81 + return this;
  82 + }
  83 +
  84 + // provide opportunity to alter form data before it is serialized
  85 + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
  86 + log('ajaxSubmit: submit aborted via beforeSerialize callback');
  87 + return this;
  88 + }
  89 +
  90 + var traditional = options.traditional;
  91 + if ( traditional === undefined ) {
  92 + traditional = $.ajaxSettings.traditional;
  93 + }
  94 +
  95 + var qx,n,v,a = this.formToArray(options.semantic);
  96 + if (options.data) {
  97 + options.extraData = options.data;
  98 + qx = $.param(options.data, traditional);
  99 + }
  100 +
  101 + // give pre-submit callback an opportunity to abort the submit
  102 + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
  103 + log('ajaxSubmit: submit aborted via beforeSubmit callback');
  104 + return this;
  105 + }
  106 +
  107 + // fire vetoable 'validate' event
  108 + this.trigger('form-submit-validate', [a, this, options, veto]);
  109 + if (veto.veto) {
  110 + log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
  111 + return this;
  112 + }
  113 +
  114 + var q = $.param(a, traditional);
  115 + if (qx)
  116 + q = ( q ? (q + '&' + qx) : qx );
  117 +
  118 + if (options.type.toUpperCase() == 'GET') {
  119 + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
  120 + options.data = null; // data is null for 'get'
  121 + }
  122 + else {
  123 + options.data = q; // data is the query string for 'post'
  124 + }
  125 +
  126 + var callbacks = [];
  127 + if (options.resetForm) {
  128 + callbacks.push(function() { $form.resetForm(); });
  129 + }
  130 + if (options.clearForm) {
  131 + callbacks.push(function() { $form.clearForm(options.includeHidden); });
  132 + }
  133 +
  134 + // perform a load on the target only if dataType is not provided
  135 + if (!options.dataType && options.target) {
  136 + var oldSuccess = options.success || function(){};
  137 + callbacks.push(function(data) {
  138 + var fn = options.replaceTarget ? 'replaceWith' : 'html';
  139 + $(options.target)[fn](data).each(oldSuccess, arguments);
  140 + });
  141 + }
  142 + else if (options.success) {
  143 + callbacks.push(options.success);
  144 + }
  145 +
  146 + options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
  147 + var context = options.context || options; // jQuery 1.4+ supports scope context
  148 + for (var i=0, max=callbacks.length; i < max; i++) {
  149 + callbacks[i].apply(context, [data, status, xhr || $form, $form]);
  150 + }
  151 + };
  152 +
  153 + // are there files to upload?
  154 + var fileInputs = $('input:file', this).length > 0;
  155 + var mp = 'multipart/form-data';
  156 + var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
  157 +
  158 + // options.iframe allows user to force iframe mode
  159 + // 06-NOV-09: now defaulting to iframe mode if file input is detected
  160 + if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
  161 + // hack to fix Safari hang (thanks to Tim Molendijk for this)
  162 + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
  163 + if (options.closeKeepAlive) {
  164 + $.get(options.closeKeepAlive, function() { fileUpload(a); });
  165 + }
  166 + else {
  167 + fileUpload(a);
  168 + }
  169 + }
  170 + else {
  171 + // IE7 massage (see issue 57)
  172 + if ($.browser.msie && method == 'get' && typeof options.type === "undefined") {
  173 + var ieMeth = $form[0].getAttribute('method');
  174 + if (typeof ieMeth === 'string')
  175 + options.type = ieMeth;
  176 + }
  177 + $.ajax(options);
  178 + }
  179 +
  180 + // fire 'notify' event
  181 + this.trigger('form-submit-notify', [this, options]);
  182 + return this;
  183 +
  184 +
  185 + // private function for handling file uploads (hat tip to YAHOO!)
  186 + function fileUpload(a) {
  187 + var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
  188 + var useProp = !!$.fn.prop;
  189 +
  190 + if (a) {
  191 + if ( useProp ) {
  192 + // ensure that every serialized input is still enabled
  193 + for (i=0; i < a.length; i++) {
  194 + el = $(form[a[i].name]);
  195 + el.prop('disabled', false);
  196 + }
  197 + } else {
  198 + for (i=0; i < a.length; i++) {
  199 + el = $(form[a[i].name]);
  200 + el.removeAttr('disabled');
  201 + }
  202 + };
  203 + }
  204 +
  205 + if ($(':input[name=submit],:input[id=submit]', form).length) {
  206 + // if there is an input with a name or id of 'submit' then we won't be
  207 + // able to invoke the submit fn on the form (at least not x-browser)
  208 + alert('Error: Form elements must not have name or id of "submit".');
  209 + return;
  210 + }
  211 +
  212 + s = $.extend(true, {}, $.ajaxSettings, options);
  213 + s.context = s.context || s;
  214 + id = 'jqFormIO' + (new Date().getTime());
  215 + if (s.iframeTarget) {
  216 + $io = $(s.iframeTarget);
  217 + n = $io.attr('name');
  218 + if (n == null)
  219 + $io.attr('name', id);
  220 + else
  221 + id = n;
  222 + }
  223 + else {
  224 + $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
  225 + $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
  226 + }
  227 + io = $io[0];
  228 +
  229 +
  230 + xhr = { // mock object
  231 + aborted: 0,
  232 + responseText: null,
  233 + responseXML: null,
  234 + status: 0,
  235 + statusText: 'n/a',
  236 + getAllResponseHeaders: function() {},
  237 + getResponseHeader: function() {},
  238 + setRequestHeader: function() {},
  239 + abort: function(status) {
  240 + var e = (status === 'timeout' ? 'timeout' : 'aborted');
  241 + log('aborting upload... ' + e);
  242 + this.aborted = 1;
  243 + $io.attr('src', s.iframeSrc); // abort op in progress
  244 + xhr.error = e;
  245 + s.error && s.error.call(s.context, xhr, e, status);
  246 + g && $.event.trigger("ajaxError", [xhr, s, e]);
  247 + s.complete && s.complete.call(s.context, xhr, e);
  248 + }
  249 + };
  250 +
  251 + g = s.global;
  252 + // trigger ajax global events so that activity/block indicators work like normal
  253 + if (g && ! $.active++) {
  254 + $.event.trigger("ajaxStart");
  255 + }
  256 + if (g) {
  257 + $.event.trigger("ajaxSend", [xhr, s]);
  258 + }
  259 +
  260 + if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
  261 + if (s.global) {
  262 + $.active--;
  263 + }
  264 + return;
  265 + }
  266 + if (xhr.aborted) {
  267 + return;
  268 + }
  269 +
  270 + // add submitting element to data if we know it
  271 + sub = form.clk;
  272 + if (sub) {
  273 + n = sub.name;
  274 + if (n && !sub.disabled) {
  275 + s.extraData = s.extraData || {};
  276 + s.extraData[n] = sub.value;
  277 + if (sub.type == "image") {
  278 + s.extraData[n+'.x'] = form.clk_x;
  279 + s.extraData[n+'.y'] = form.clk_y;
  280 + }
  281 + }
  282 + }
  283 +
  284 + var CLIENT_TIMEOUT_ABORT = 1;
  285 + var SERVER_ABORT = 2;
  286 +
  287 + function getDoc(frame) {
  288 + var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
  289 + return doc;
  290 + }
  291 +
  292 + // take a breath so that pending repaints get some cpu time before the upload starts
  293 + function doSubmit() {
  294 + // make sure form attrs are set
  295 + var t = $form.attr('target'), a = $form.attr('action');
  296 +
  297 + // update form attrs in IE friendly way
  298 + form.setAttribute('target',id);
  299 + if (!method) {
  300 + form.setAttribute('method', 'POST');
  301 + }
  302 + if (a != s.url) {
  303 + form.setAttribute('action', s.url);
  304 + }
  305 +
  306 + // ie borks in some cases when setting encoding
  307 + if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
  308 + $form.attr({
  309 + encoding: 'multipart/form-data',
  310 + enctype: 'multipart/form-data'
  311 + });
  312 + }
  313 +
  314 + // support timout
  315 + if (s.timeout) {
  316 + timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
  317 + }
  318 +
  319 + // look for server aborts
  320 + function checkState() {
  321 + try {
  322 + var state = getDoc(io).readyState;
  323 + log('state = ' + state);
  324 + if (state.toLowerCase() == 'uninitialized')
  325 + setTimeout(checkState,50);
  326 + }
  327 + catch(e) {
  328 + log('Server abort: ' , e, ' (', e.name, ')');
  329 + cb(SERVER_ABORT);
  330 + timeoutHandle && clearTimeout(timeoutHandle);
  331 + timeoutHandle = undefined;
  332 + }
  333 + }
  334 +
  335 + // add "extra" data to form if provided in options
  336 + var extraInputs = [];
  337 + try {
  338 + if (s.extraData) {
  339 + for (var n in s.extraData) {
  340 + extraInputs.push(
  341 + $('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n])
  342 + .appendTo(form)[0]);
  343 + }
  344 + }
  345 +
  346 + if (!s.iframeTarget) {
  347 + // add iframe to doc and submit the form
  348 + $io.appendTo('body');
  349 + io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
  350 + }
  351 + setTimeout(checkState,15);
  352 + form.submit();
  353 + }
  354 + finally {
  355 + // reset attrs and remove "extra" input elements
  356 + form.setAttribute('action',a);
  357 + if(t) {
  358 + form.setAttribute('target', t);
  359 + } else {
  360 + $form.removeAttr('target');
  361 + }
  362 + $(extraInputs).remove();
  363 + }
  364 + }
  365 +
  366 + if (s.forceSync) {
  367 + doSubmit();
  368 + }
  369 + else {
  370 + setTimeout(doSubmit, 10); // this lets dom updates render
  371 + }
  372 +
  373 + var data, doc, domCheckCount = 50, callbackProcessed;
  374 +
  375 + function cb(e) {
  376 + if (xhr.aborted || callbackProcessed) {
  377 + return;
  378 + }
  379 + try {
  380 + doc = getDoc(io);
  381 + }
  382 + catch(ex) {
  383 + log('cannot access response document: ', ex);
  384 + e = SERVER_ABORT;
  385 + }
  386 + if (e === CLIENT_TIMEOUT_ABORT && xhr) {
  387 + xhr.abort('timeout');
  388 + return;
  389 + }
  390 + else if (e == SERVER_ABORT && xhr) {
  391 + xhr.abort('server abort');
  392 + return;
  393 + }
  394 +
  395 + if (!doc || doc.location.href == s.iframeSrc) {
  396 + // response not received yet
  397 + if (!timedOut)
  398 + return;
  399 + }
  400 + io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
  401 +
  402 + var status = 'success', errMsg;
  403 + try {
  404 + if (timedOut) {
  405 + throw 'timeout';
  406 + }
  407 +
  408 + var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
  409 + log('isXml='+isXml);
  410 + if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
  411 + if (--domCheckCount) {
  412 + // in some browsers (Opera) the iframe DOM is not always traversable when
  413 + // the onload callback fires, so we loop a bit to accommodate
  414 + log('requeing onLoad callback, DOM not available');
  415 + setTimeout(cb, 250);
  416 + return;
  417 + }
  418 + // let this fall through because server response could be an empty document
  419 + //log('Could not access iframe DOM after mutiple tries.');
  420 + //throw 'DOMException: not available';
  421 + }
  422 +
  423 + //log('response detected');
  424 + var docRoot = doc.body ? doc.body : doc.documentElement;
  425 + xhr.responseText = docRoot ? docRoot.innerHTML : null;
  426 + xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
  427 + if (isXml)
  428 + s.dataType = 'xml';
  429 + xhr.getResponseHeader = function(header){
  430 + var headers = {'content-type': s.dataType};
  431 + return headers[header];
  432 + };
  433 + // support for XHR 'status' & 'statusText' emulation :
  434 + if (docRoot) {
  435 + xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
  436 + xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
  437 + }
  438 +
  439 + var dt = (s.dataType || '').toLowerCase();
  440 + var scr = /(json|script|text)/.test(dt);
  441 + if (scr || s.textarea) {
  442 + // see if user embedded response in textarea
  443 + var ta = doc.getElementsByTagName('textarea')[0];
  444 + if (ta) {
  445 + xhr.responseText = ta.value;
  446 + // support for XHR 'status' & 'statusText' emulation :
  447 + xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
  448 + xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
  449 + }
  450 + else if (scr) {
  451 + // account for browsers injecting pre around json response
  452 + var pre = doc.getElementsByTagName('pre')[0];
  453 + var b = doc.getElementsByTagName('body')[0];
  454 + if (pre) {
  455 + xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
  456 + }
  457 + else if (b) {
  458 + xhr.responseText = b.textContent ? b.textContent : b.innerText;
  459 + }
  460 + }
  461 + }
  462 + else if (dt == 'xml' && !xhr.responseXML && xhr.responseText != null) {
  463 + xhr.responseXML = toXml(xhr.responseText);
  464 + }
  465 +
  466 + try {
  467 + data = httpData(xhr, dt, s);
  468 + }
  469 + catch (e) {
  470 + status = 'parsererror';
  471 + xhr.error = errMsg = (e || status);
  472 + }
  473 + }
  474 + catch (e) {
  475 + log('error caught: ',e);
  476 + status = 'error';
  477 + xhr.error = errMsg = (e || status);
  478 + }
  479 +
  480 + if (xhr.aborted) {
  481 + log('upload aborted');
  482 + status = null;
  483 + }
  484 +
  485 + if (xhr.status) { // we've set xhr.status
  486 + status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
  487 + }
  488 +
  489 + // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
  490 + if (status === 'success') {
  491 + s.success && s.success.call(s.context, data, 'success', xhr);
  492 + g && $.event.trigger("ajaxSuccess", [xhr, s]);
  493 + }
  494 + else if (status) {
  495 + if (errMsg == undefined)
  496 + errMsg = xhr.statusText;
  497 + s.error && s.error.call(s.context, xhr, status, errMsg);
  498 + g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
  499 + }
  500 +
  501 + g && $.event.trigger("ajaxComplete", [xhr, s]);
  502 +
  503 + if (g && ! --$.active) {
  504 + $.event.trigger("ajaxStop");
  505 + }
  506 +
  507 + s.complete && s.complete.call(s.context, xhr, status);
  508 +
  509 + callbackProcessed = true;
  510 + if (s.timeout)
  511 + clearTimeout(timeoutHandle);
  512 +
  513 + // clean up
  514 + setTimeout(function() {
  515 + if (!s.iframeTarget)
  516 + $io.remove();
  517 + xhr.responseXML = null;
  518 + }, 100);
  519 + }
  520 +
  521 + var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
  522 + if (window.ActiveXObject) {
  523 + doc = new ActiveXObject('Microsoft.XMLDOM');
  524 + doc.async = 'false';
  525 + doc.loadXML(s);
  526 + }
  527 + else {
  528 + doc = (new DOMParser()).parseFromString(s, 'text/xml');
  529 + }
  530 + return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
  531 + };
  532 + var parseJSON = $.parseJSON || function(s) {
  533 + return window['eval']('(' + s + ')');
  534 + };
  535 +
  536 + var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
  537 +
  538 + var ct = xhr.getResponseHeader('content-type') || '',
  539 + xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
  540 + data = xml ? xhr.responseXML : xhr.responseText;
  541 +
  542 + if (xml && data.documentElement.nodeName === 'parsererror') {
  543 + $.error && $.error('parsererror');
  544 + }
  545 + if (s && s.dataFilter) {
  546 + data = s.dataFilter(data, type);
  547 + }
  548 + if (typeof data === 'string') {
  549 + if (type === 'json' || !type && ct.indexOf('json') >= 0) {
  550 + data = parseJSON(data);
  551 + } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
  552 + $.globalEval(data);
  553 + }
  554 + }
  555 + return data;
  556 + };
  557 + }
  558 +};
  559 +
  560 +/**
  561 + * ajaxForm() provides a mechanism for fully automating form submission.
  562 + *
  563 + * The advantages of using this method instead of ajaxSubmit() are:
  564 + *
  565 + * 1: This method will include coordinates for <input type="image" /> elements (if the element
  566 + * is used to submit the form).
  567 + * 2. This method will include the submit element's name/value data (for the element that was
  568 + * used to submit the form).
  569 + * 3. This method binds the submit() method to the form for you.
  570 + *
  571 + * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
  572 + * passes the options argument along after properly binding events for submit elements and
  573 + * the form itself.
  574 + */
  575 +$.fn.ajaxForm = function(options) {
  576 + // in jQuery 1.3+ we can fix mistakes with the ready state
  577 + if (this.length === 0) {
  578 + var o = { s: this.selector, c: this.context };
  579 + if (!$.isReady && o.s) {
  580 + log('DOM not ready, queuing ajaxForm');
  581 + $(function() {
  582 + $(o.s,o.c).ajaxForm(options);
  583 + });
  584 + return this;
  585 + }
  586 + // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
  587 + log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
  588 + return this;
  589 + }
  590 +
  591 + return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
  592 + if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
  593 + e.preventDefault();
  594 + $(this).ajaxSubmit(options);
  595 + }
  596 + }).bind('click.form-plugin', function(e) {
  597 + var target = e.target;
  598 + var $el = $(target);
  599 + if (!($el.is(":submit,input:image"))) {
  600 + // is this a child element of the submit el? (ex: a span within a button)
  601 + var t = $el.closest(':submit');
  602 + if (t.length == 0) {
  603 + return;
  604 + }
  605 + target = t[0];
  606 + }
  607 + var form = this;
  608 + form.clk = target;
  609 + if (target.type == 'image') {
  610 + if (e.offsetX != undefined) {
  611 + form.clk_x = e.offsetX;
  612 + form.clk_y = e.offsetY;
  613 + } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
  614 + var offset = $el.offset();
  615 + form.clk_x = e.pageX - offset.left;
  616 + form.clk_y = e.pageY - offset.top;
  617 + } else {
  618 + form.clk_x = e.pageX - target.offsetLeft;
  619 + form.clk_y = e.pageY - target.offsetTop;
  620 + }
  621 + }
  622 + // clear form vars
  623 + setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
  624 + });
  625 +};
  626 +
  627 +// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
  628 +$.fn.ajaxFormUnbind = function() {
  629 + return this.unbind('submit.form-plugin click.form-plugin');
  630 +};
  631 +
  632 +/**
  633 + * formToArray() gathers form element data into an array of objects that can
  634 + * be passed to any of the following ajax functions: $.get, $.post, or load.
  635 + * Each object in the array has both a 'name' and 'value' property. An example of
  636 + * an array for a simple login form might be:
  637 + *
  638 + * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  639 + *
  640 + * It is this array that is passed to pre-submit callback functions provided to the
  641 + * ajaxSubmit() and ajaxForm() methods.
  642 + */
  643 +$.fn.formToArray = function(semantic) {
  644 + var a = [];
  645 + if (this.length === 0) {
  646 + return a;
  647 + }
  648 +
  649 + var form = this[0];
  650 + var els = semantic ? form.getElementsByTagName('*') : form.elements;
  651 + if (!els) {
  652 + return a;
  653 + }
  654 +
  655 + var i,j,n,v,el,max,jmax;
  656 + for(i=0, max=els.length; i < max; i++) {
  657 + el = els[i];
  658 + n = el.name;
  659 + if (!n) {
  660 + continue;
  661 + }
  662 +
  663 + if (semantic && form.clk && el.type == "image") {
  664 + // handle image inputs on the fly when semantic == true
  665 + if(!el.disabled && form.clk == el) {
  666 + a.push({name: n, value: $(el).val()});
  667 + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  668 + }
  669 + continue;
  670 + }
  671 +
  672 + v = $.fieldValue(el, true);
  673 + if (v && v.constructor == Array) {
  674 + for(j=0, jmax=v.length; j < jmax; j++) {
  675 + a.push({name: n, value: v[j]});
  676 + }
  677 + }
  678 + else if (v !== null && typeof v != 'undefined') {
  679 + a.push({name: n, value: v});
  680 + }
  681 + }
  682 +
  683 + if (!semantic && form.clk) {
  684 + // input type=='image' are not found in elements array! handle it here
  685 + var $input = $(form.clk), input = $input[0];
  686 + n = input.name;
  687 + if (n && !input.disabled && input.type == 'image') {
  688 + a.push({name: n, value: $input.val()});
  689 + a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  690 + }
  691 + }
  692 + return a;
  693 +};
  694 +
  695 +/**
  696 + * Serializes form data into a 'submittable' string. This method will return a string
  697 + * in the format: name1=value1&amp;name2=value2
  698 + */
  699 +$.fn.formSerialize = function(semantic) {
  700 + //hand off to jQuery.param for proper encoding
  701 + return $.param(this.formToArray(semantic));
  702 +};
  703 +
  704 +/**
  705 + * Serializes all field elements in the jQuery object into a query string.
  706 + * This method will return a string in the format: name1=value1&amp;name2=value2
  707 + */
  708 +$.fn.fieldSerialize = function(successful) {
  709 + var a = [];
  710 + this.each(function() {
  711 + var n = this.name;
  712 + if (!n) {
  713 + return;
  714 + }
  715 + var v = $.fieldValue(this, successful);
  716 + if (v && v.constructor == Array) {
  717 + for (var i=0,max=v.length; i < max; i++) {
  718 + a.push({name: n, value: v[i]});
  719 + }
  720 + }
  721 + else if (v !== null && typeof v != 'undefined') {
  722 + a.push({name: this.name, value: v});
  723 + }
  724 + });
  725 + //hand off to jQuery.param for proper encoding
  726 + return $.param(a);
  727 +};
  728 +
  729 +/**
  730 + * Returns the value(s) of the element in the matched set. For example, consider the following form:
  731 + *
  732 + * <form><fieldset>
  733 + * <input name="A" type="text" />
  734 + * <input name="A" type="text" />
  735 + * <input name="B" type="checkbox" value="B1" />
  736 + * <input name="B" type="checkbox" value="B2"/>
  737 + * <input name="C" type="radio" value="C1" />
  738 + * <input name="C" type="radio" value="C2" />
  739 + * </fieldset></form>
  740 + *
  741 + * var v = $(':text').fieldValue();
  742 + * // if no values are entered into the text inputs
  743 + * v == ['','']
  744 + * // if values entered into the text inputs are 'foo' and 'bar'
  745 + * v == ['foo','bar']
  746 + *
  747 + * var v = $(':checkbox').fieldValue();
  748 + * // if neither checkbox is checked
  749 + * v === undefined
  750 + * // if both checkboxes are checked
  751 + * v == ['B1', 'B2']
  752 + *
  753 + * var v = $(':radio').fieldValue();
  754 + * // if neither radio is checked
  755 + * v === undefined
  756 + * // if first radio is checked
  757 + * v == ['C1']
  758 + *
  759 + * The successful argument controls whether or not the field element must be 'successful'
  760 + * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  761 + * The default value of the successful argument is true. If this value is false the value(s)
  762 + * for each element is returned.
  763 + *
  764 + * Note: This method *always* returns an array. If no valid value can be determined the
  765 + * array will be empty, otherwise it will contain one or more values.
  766 + */
  767 +$.fn.fieldValue = function(successful) {
  768 + for (var val=[], i=0, max=this.length; i < max; i++) {
  769 + var el = this[i];
  770 + var v = $.fieldValue(el, successful);
  771 + if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
  772 + continue;
  773 + }
  774 + v.constructor == Array ? $.merge(val, v) : val.push(v);
  775 + }
  776 + return val;
  777 +};
  778 +
  779 +/**
  780 + * Returns the value of the field element.
  781 + */
  782 +$.fieldValue = function(el, successful) {
  783 + var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
  784 + if (successful === undefined) {
  785 + successful = true;
  786 + }
  787 +
  788 + if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
  789 + (t == 'checkbox' || t == 'radio') && !el.checked ||
  790 + (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
  791 + tag == 'select' && el.selectedIndex == -1)) {
  792 + return null;
  793 + }
  794 +
  795 + if (tag == 'select') {
  796 + var index = el.selectedIndex;
  797 + if (index < 0) {
  798 + return null;
  799 + }
  800 + var a = [], ops = el.options;
  801 + var one = (t == 'select-one');
  802 + var max = (one ? index+1 : ops.length);
  803 + for(var i=(one ? index : 0); i < max; i++) {
  804 + var op = ops[i];
  805 + if (op.selected) {
  806 + var v = op.value;
  807 + if (!v) { // extra pain for IE...
  808 + v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
  809 + }
  810 + if (one) {
  811 + return v;
  812 + }
  813 + a.push(v);
  814 + }
  815 + }
  816 + return a;
  817 + }
  818 + return $(el).val();
  819 +};
  820 +
  821 +/**
  822 + * Clears the form data. Takes the following actions on the form's input fields:
  823 + * - input text fields will have their 'value' property set to the empty string
  824 + * - select elements will have their 'selectedIndex' property set to -1
  825 + * - checkbox and radio inputs will have their 'checked' property set to false
  826 + * - inputs of type submit, button, reset, and hidden will *not* be effected
  827 + * - button elements will *not* be effected
  828 + */
  829 +$.fn.clearForm = function(includeHidden) {
  830 + return this.each(function() {
  831 + $('input,select,textarea', this).clearFields(includeHidden);
  832 + });
  833 +};
  834 +
  835 +/**
  836 + * Clears the selected form elements.
  837 + */
  838 +$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
  839 + var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
  840 + return this.each(function() {
  841 + var t = this.type, tag = this.tagName.toLowerCase();
  842 + if (re.test(t) || tag == 'textarea' || (includeHidden && /hidden/.test(t)) ) {
  843 + this.value = '';
  844 + }
  845 + else if (t == 'checkbox' || t == 'radio') {
  846 + this.checked = false;
  847 + }
  848 + else if (tag == 'select') {
  849 + this.selectedIndex = -1;
  850 + }
  851 + });
  852 +};
  853 +
  854 +/**
  855 + * Resets the form data. Causes all form elements to be reset to their original value.
  856 + */
  857 +$.fn.resetForm = function() {
  858 + return this.each(function() {
  859 + // guard against an input with the name of 'reset'
  860 + // note that IE reports the reset function as an 'object'
  861 + if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
  862 + this.reset();
  863 + }
  864 + });
  865 +};
  866 +
  867 +/**
  868 + * Enables or disables any matching elements.
  869 + */
  870 +$.fn.enable = function(b) {
  871 + if (b === undefined) {
  872 + b = true;
  873 + }
  874 + return this.each(function() {
  875 + this.disabled = !b;
  876 + });
  877 +};
  878 +
  879 +/**
  880 + * Checks/unchecks any matching checkboxes or radio buttons and
  881 + * selects/deselects and matching option elements.
  882 + */
  883 +$.fn.selected = function(select) {
  884 + if (select === undefined) {
  885 + select = true;
  886 + }
  887 + return this.each(function() {
  888 + var t = this.type;
  889 + if (t == 'checkbox' || t == 'radio') {
  890 + this.checked = select;
  891 + }
  892 + else if (this.tagName.toLowerCase() == 'option') {
  893 + var $sel = $(this).parent('select');
  894 + if (select && $sel[0] && $sel[0].type == 'select-one') {
  895 + // deselect all other options
  896 + $sel.find('option').selected(false);
  897 + }
  898 + this.selected = select;
  899 + }
  900 + });
  901 +};
  902 +
  903 +// expose debug var
  904 +$.fn.ajaxSubmit.debug = false;
  905 +
  906 +// helper fn for console logging
  907 +function log() {
  908 + if (!$.fn.ajaxSubmit.debug)
  909 + return;
  910 + var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
  911 + if (window.console && window.console.log) {
  912 + window.console.log(msg);
  913 + }
  914 + else if (window.opera && window.opera.postError) {
  915 + window.opera.postError(msg);
  916 + }
  917 +};
  918 +
  919 +})(jQuery);
... ...