jquery.form.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. /*
  2. * jQuery Form Plugin
  3. * @requires jQuery v1.1 or later
  4. *
  5. * Examples at: http://malsup.com/jquery/form/
  6. * Dual licensed under the MIT and GPL licenses:
  7. * http://www.opensource.org/licenses/mit-license.php
  8. * http://www.gnu.org/licenses/gpl.html
  9. *
  10. * Revision: $Id: jquery.form.js 3028 2007-08-31 13:37:36Z joern.zaefferer $
  11. */
  12. (function($) {
  13. /**
  14. * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.
  15. *
  16. * ajaxSubmit accepts a single argument which can be either a success callback function
  17. * or an options Object. If a function is provided it will be invoked upon successful
  18. * completion of the submit and will be passed the response from the server.
  19. * If an options Object is provided, the following attributes are supported:
  20. *
  21. * target: Identifies the element(s) in the page to be updated with the server response.
  22. * This value may be specified as a jQuery selection string, a jQuery object,
  23. * or a DOM element.
  24. * default value: null
  25. *
  26. * url: URL to which the form data will be submitted.
  27. * default value: value of form's 'action' attribute
  28. *
  29. * type: The method in which the form data should be submitted, 'GET' or 'POST'.
  30. * default value: value of form's 'method' attribute (or 'GET' if none found)
  31. *
  32. * data: Additional data to add to the request, specified as key/value pairs (see $.ajax).
  33. *
  34. * beforeSubmit: Callback method to be invoked before the form is submitted.
  35. * default value: null
  36. *
  37. * success: Callback method to be invoked after the form has been successfully submitted
  38. * and the response has been returned from the server
  39. * default value: null
  40. *
  41. * dataType: Expected dataType of the response. One of: null, 'xml', 'script', or 'json'
  42. * default value: null
  43. *
  44. * semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).
  45. * default value: false
  46. *
  47. * resetForm: Boolean flag indicating whether the form should be reset if the submit is successful
  48. *
  49. * clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful
  50. *
  51. *
  52. * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for
  53. * validating the form data. If the 'beforeSubmit' callback returns false then the form will
  54. * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data
  55. * in array format, the jQuery object, and the options object passed into ajaxSubmit.
  56. * The form data array takes the following form:
  57. *
  58. * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  59. *
  60. * If a 'success' callback method is provided it is invoked after the response has been returned
  61. * from the server. It is passed the responseText or responseXML value (depending on dataType).
  62. * See jQuery.ajax for further details.
  63. *
  64. *
  65. * The dataType option provides a means for specifying how the server response should be handled.
  66. * This maps directly to the jQuery.httpData method. The following values are supported:
  67. *
  68. * 'xml': if dataType == 'xml' the server response is treated as XML and the 'success'
  69. * callback method, if specified, will be passed the responseXML value
  70. * 'json': if dataType == 'json' the server response will be evaluted and passed to
  71. * the 'success' callback, if specified
  72. * 'script': if dataType == 'script' the server response is evaluated in the global context
  73. *
  74. *
  75. * Note that it does not make sense to use both the 'target' and 'dataType' options. If both
  76. * are provided the target will be ignored.
  77. *
  78. * The semantic argument can be used to force form serialization in semantic order.
  79. * This is normally true anyway, unless the form contains input elements of type='image'.
  80. * If your form must be submitted with name/value pairs in semantic order and your form
  81. * contains an input of type='image" then pass true for this arg, otherwise pass false
  82. * (or nothing) to avoid the overhead for this logic.
  83. *
  84. *
  85. * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:
  86. *
  87. * $("#form-id").submit(function() {
  88. * $(this).ajaxSubmit(options);
  89. * return false; // cancel conventional submit
  90. * });
  91. *
  92. * When using ajaxForm(), however, this is done for you.
  93. *
  94. * @example
  95. * $('#myForm').ajaxSubmit(function(data) {
  96. * alert('Form submit succeeded! Server returned: ' + data);
  97. * });
  98. * @desc Submit form and alert server response
  99. *
  100. *
  101. * @example
  102. * var options = {
  103. * target: '#myTargetDiv'
  104. * };
  105. * $('#myForm').ajaxSubmit(options);
  106. * @desc Submit form and update page element with server response
  107. *
  108. *
  109. * @example
  110. * var options = {
  111. * success: function(responseText) {
  112. * alert(responseText);
  113. * }
  114. * };
  115. * $('#myForm').ajaxSubmit(options);
  116. * @desc Submit form and alert the server response
  117. *
  118. *
  119. * @example
  120. * var options = {
  121. * beforeSubmit: function(formArray, jqForm) {
  122. * if (formArray.length == 0) {
  123. * alert('Please enter data.');
  124. * return false;
  125. * }
  126. * }
  127. * };
  128. * $('#myForm').ajaxSubmit(options);
  129. * @desc Pre-submit validation which aborts the submit operation if form data is empty
  130. *
  131. *
  132. * @example
  133. * var options = {
  134. * url: myJsonUrl.php,
  135. * dataType: 'json',
  136. * success: function(data) {
  137. * // 'data' is an object representing the the evaluated json data
  138. * }
  139. * };
  140. * $('#myForm').ajaxSubmit(options);
  141. * @desc json data returned and evaluated
  142. *
  143. *
  144. * @example
  145. * var options = {
  146. * url: myXmlUrl.php,
  147. * dataType: 'xml',
  148. * success: function(responseXML) {
  149. * // responseXML is XML document object
  150. * var data = $('myElement', responseXML).text();
  151. * }
  152. * };
  153. * $('#myForm').ajaxSubmit(options);
  154. * @desc XML data returned from server
  155. *
  156. *
  157. * @example
  158. * var options = {
  159. * resetForm: true
  160. * };
  161. * $('#myForm').ajaxSubmit(options);
  162. * @desc submit form and reset it if successful
  163. *
  164. * @example
  165. * $('#myForm).submit(function() {
  166. * $(this).ajaxSubmit();
  167. * return false;
  168. * });
  169. * @desc Bind form's submit event to use ajaxSubmit
  170. *
  171. *
  172. * @name ajaxSubmit
  173. * @type jQuery
  174. * @param options object literal containing options which control the form submission process
  175. * @cat Plugins/Form
  176. * @return jQuery
  177. */
  178. $.fn.ajaxSubmit = function(options) {
  179. if (typeof options == 'function')
  180. options = { success: options };
  181. options = $.extend({
  182. url: this.attr('action') || window.location,
  183. type: this.attr('method') || 'GET'
  184. }, options || {});
  185. // hook for manipulating the form data before it is extracted;
  186. // convenient for use with rich editors like tinyMCE or FCKEditor
  187. var veto = {};
  188. $.event.trigger('form.pre.serialize', [this, options, veto]);
  189. if (veto.veto) return this;
  190. var a = this.formToArray(options.semantic);
  191. if (options.data) {
  192. for (var n in options.data)
  193. a.push( { name: n, value: options.data[n] } );
  194. }
  195. // give pre-submit callback an opportunity to abort the submit
  196. if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;
  197. // fire vetoable 'validate' event
  198. $.event.trigger('form.submit.validate', [a, this, options, veto]);
  199. if (veto.veto) return this;
  200. var q = $.param(a);//.replace(/%20/g,'+');
  201. if (options.type.toUpperCase() == 'GET') {
  202. options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
  203. options.data = null; // data is null for 'get'
  204. }
  205. else
  206. options.data = q; // data is the query string for 'post'
  207. var $form = this, callbacks = [];
  208. if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
  209. if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
  210. // perform a load on the target only if dataType is not provided
  211. if (!options.dataType && options.target) {
  212. var oldSuccess = options.success || function(){};
  213. callbacks.push(function(data) {
  214. if (this.evalScripts)
  215. $(options.target).attr("innerHTML", data).evalScripts().each(oldSuccess, arguments);
  216. else // jQuery v1.1.4
  217. $(options.target).html(data).each(oldSuccess, arguments);
  218. });
  219. }
  220. else if (options.success)
  221. callbacks.push(options.success);
  222. options.success = function(data, status) {
  223. for (var i=0, max=callbacks.length; i < max; i++)
  224. callbacks[i](data, status, $form);
  225. };
  226. // are there files to upload?
  227. var files = $('input:file', this).fieldValue();
  228. var found = false;
  229. for (var j=0; j < files.length; j++)
  230. if (files[j])
  231. found = true;
  232. if (options.iframe || found) // options.iframe allows user to force iframe mode
  233. fileUpload();
  234. else
  235. $.ajax(options);
  236. // fire 'notify' event
  237. $.event.trigger('form.submit.notify', [this, options]);
  238. return this;
  239. // private function for handling file uploads (hat tip to YAHOO!)
  240. function fileUpload() {
  241. var form = $form[0];
  242. var opts = $.extend({}, $.ajaxSettings, options);
  243. var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;
  244. var $io = $('<iframe id="' + id + '" name="' + id + '" />');
  245. var io = $io[0];
  246. var op8 = $.browser.opera && window.opera.version() < 9;
  247. if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
  248. $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
  249. var xhr = { // mock object
  250. responseText: null,
  251. responseXML: null,
  252. status: 0,
  253. statusText: 'n/a',
  254. getAllResponseHeaders: function() {},
  255. getResponseHeader: function() {},
  256. setRequestHeader: function() {}
  257. };
  258. var g = opts.global;
  259. // trigger ajax global events so that activity/block indicators work like normal
  260. if (g && ! $.active++) $.event.trigger("ajaxStart");
  261. if (g) $.event.trigger("ajaxSend", [xhr, opts]);
  262. var cbInvoked = 0;
  263. var timedOut = 0;
  264. // take a breath so that pending repaints get some cpu time before the upload starts
  265. setTimeout(function() {
  266. $io.appendTo('body');
  267. // jQuery's event binding doesn't work for iframe events in IE
  268. io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
  269. // make sure form attrs are set
  270. var encAttr = form.encoding ? 'encoding' : 'enctype';
  271. var t = $form.attr('target');
  272. $form.attr({
  273. target: id,
  274. method: 'POST',
  275. action: opts.url
  276. });
  277. form[encAttr] = 'multipart/form-data';
  278. // support timout
  279. if (opts.timeout)
  280. setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
  281. form.submit();
  282. $form.attr('target', t); // reset target
  283. }, 10);
  284. function cb() {
  285. if (cbInvoked++) return;
  286. io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
  287. var ok = true;
  288. try {
  289. if (timedOut) throw 'timeout';
  290. // extract the server response from the iframe
  291. var data, doc;
  292. doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
  293. xhr.responseText = doc.body ? doc.body.innerHTML : null;
  294. xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
  295. if (opts.dataType == 'json' || opts.dataType == 'script') {
  296. var ta = doc.getElementsByTagName('textarea')[0];
  297. data = ta ? ta.value : xhr.responseText;
  298. if (opts.dataType == 'json')
  299. eval("data = " + data);
  300. else
  301. $.globalEval(data);
  302. }
  303. else if (opts.dataType == 'xml') {
  304. data = xhr.responseXML;
  305. if (!data && xhr.responseText != null)
  306. data = toXml(xhr.responseText);
  307. }
  308. else {
  309. data = xhr.responseText;
  310. }
  311. }
  312. catch(e){
  313. ok = false;
  314. $.handleError(opts, xhr, 'error', e);
  315. }
  316. // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
  317. if (ok) {
  318. opts.success(data, 'success');
  319. if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
  320. }
  321. if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
  322. if (g && ! --$.active) $.event.trigger("ajaxStop");
  323. if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
  324. // clean up
  325. setTimeout(function() {
  326. $io.remove();
  327. xhr.responseXML = null;
  328. }, 100);
  329. };
  330. function toXml(s, doc) {
  331. if (window.ActiveXObject) {
  332. doc = new ActiveXObject('Microsoft.XMLDOM');
  333. doc.async = 'false';
  334. doc.loadXML(s);
  335. }
  336. else
  337. doc = (new DOMParser()).parseFromString(s, 'text/xml');
  338. return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
  339. };
  340. };
  341. };
  342. $.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids
  343. /**
  344. * ajaxForm() provides a mechanism for fully automating form submission.
  345. *
  346. * The advantages of using this method instead of ajaxSubmit() are:
  347. *
  348. * 1: This method will include coordinates for <input type="image" /> elements (if the element
  349. * is used to submit the form).
  350. * 2. This method will include the submit element's name/value data (for the element that was
  351. * used to submit the form).
  352. * 3. This method binds the submit() method to the form for you.
  353. *
  354. * Note that for accurate x/y coordinates of image submit elements in all browsers
  355. * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
  356. *
  357. * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
  358. * passes the options argument along after properly binding events for submit elements and
  359. * the form itself. See ajaxSubmit for a full description of the options argument.
  360. *
  361. *
  362. * @example
  363. * var options = {
  364. * target: '#myTargetDiv'
  365. * };
  366. * $('#myForm').ajaxSForm(options);
  367. * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
  368. * when the form is submitted.
  369. *
  370. *
  371. * @example
  372. * var options = {
  373. * success: function(responseText) {
  374. * alert(responseText);
  375. * }
  376. * };
  377. * $('#myForm').ajaxSubmit(options);
  378. * @desc Bind form's submit event so that server response is alerted after the form is submitted.
  379. *
  380. *
  381. * @example
  382. * var options = {
  383. * beforeSubmit: function(formArray, jqForm) {
  384. * if (formArray.length == 0) {
  385. * alert('Please enter data.');
  386. * return false;
  387. * }
  388. * }
  389. * };
  390. * $('#myForm').ajaxSubmit(options);
  391. * @desc Bind form's submit event so that pre-submit callback is invoked before the form
  392. * is submitted.
  393. *
  394. *
  395. * @name ajaxForm
  396. * @param options object literal containing options which control the form submission process
  397. * @return jQuery
  398. * @cat Plugins/Form
  399. * @type jQuery
  400. */
  401. $.fn.ajaxForm = function(options) {
  402. return this.ajaxFormUnbind().submit(submitHandler).each(function() {
  403. // store options in hash
  404. this.formPluginId = $.fn.ajaxForm.counter++;
  405. $.fn.ajaxForm.optionHash[this.formPluginId] = options;
  406. $(":submit,input:image", this).click(clickHandler);
  407. });
  408. };
  409. $.fn.ajaxForm.counter = 1;
  410. $.fn.ajaxForm.optionHash = {};
  411. function clickHandler(e) {
  412. var $form = this.form;
  413. $form.clk = this;
  414. if (this.type == 'image') {
  415. if (e.offsetX != undefined) {
  416. $form.clk_x = e.offsetX;
  417. $form.clk_y = e.offsetY;
  418. } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
  419. var offset = $(this).offset();
  420. $form.clk_x = e.pageX - offset.left;
  421. $form.clk_y = e.pageY - offset.top;
  422. } else {
  423. $form.clk_x = e.pageX - this.offsetLeft;
  424. $form.clk_y = e.pageY - this.offsetTop;
  425. }
  426. }
  427. // clear form vars
  428. setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
  429. };
  430. function submitHandler() {
  431. // retrieve options from hash
  432. var id = this.formPluginId;
  433. var options = $.fn.ajaxForm.optionHash[id];
  434. $(this).ajaxSubmit(options);
  435. return false;
  436. };
  437. /**
  438. * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
  439. *
  440. * @name ajaxFormUnbind
  441. * @return jQuery
  442. * @cat Plugins/Form
  443. * @type jQuery
  444. */
  445. $.fn.ajaxFormUnbind = function() {
  446. this.unbind('submit', submitHandler);
  447. return this.each(function() {
  448. $(":submit,input:image", this).unbind('click', clickHandler);
  449. });
  450. };
  451. /**
  452. * formToArray() gathers form element data into an array of objects that can
  453. * be passed to any of the following ajax functions: $.get, $.post, or load.
  454. * Each object in the array has both a 'name' and 'value' property. An example of
  455. * an array for a simple login form might be:
  456. *
  457. * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  458. *
  459. * It is this array that is passed to pre-submit callback functions provided to the
  460. * ajaxSubmit() and ajaxForm() methods.
  461. *
  462. * The semantic argument can be used to force form serialization in semantic order.
  463. * This is normally true anyway, unless the form contains input elements of type='image'.
  464. * If your form must be submitted with name/value pairs in semantic order and your form
  465. * contains an input of type='image" then pass true for this arg, otherwise pass false
  466. * (or nothing) to avoid the overhead for this logic.
  467. *
  468. * @example var data = $("#myForm").formToArray();
  469. * $.post( "myscript.cgi", data );
  470. * @desc Collect all the data from a form and submit it to the server.
  471. *
  472. * @name formToArray
  473. * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
  474. * @type Array<Object>
  475. * @cat Plugins/Form
  476. */
  477. $.fn.formToArray = function(semantic) {
  478. var a = [];
  479. if (this.length == 0) return a;
  480. var form = this[0];
  481. var els = semantic ? form.getElementsByTagName('*') : form.elements;
  482. if (!els) return a;
  483. for(var i=0, max=els.length; i < max; i++) {
  484. var el = els[i];
  485. var n = el.name;
  486. if (!n) continue;
  487. if (semantic && form.clk && el.type == "image") {
  488. // handle image inputs on the fly when semantic == true
  489. if(!el.disabled && form.clk == el)
  490. a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  491. continue;
  492. }
  493. var v = $.fieldValue(el, true);
  494. if (v && v.constructor == Array) {
  495. for(var j=0, jmax=v.length; j < jmax; j++)
  496. a.push({name: n, value: v[j]});
  497. }
  498. else if (v !== null && typeof v != 'undefined')
  499. a.push({name: n, value: v});
  500. }
  501. if (!semantic && form.clk) {
  502. // input type=='image' are not found in elements array! handle them here
  503. var inputs = form.getElementsByTagName("input");
  504. for(var i=0, max=inputs.length; i < max; i++) {
  505. var input = inputs[i];
  506. var n = input.name;
  507. if(n && !input.disabled && input.type == "image" && form.clk == input)
  508. a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  509. }
  510. }
  511. return a;
  512. };
  513. /**
  514. * Serializes form data into a 'submittable' string. This method will return a string
  515. * in the format: name1=value1&amp;name2=value2
  516. *
  517. * The semantic argument can be used to force form serialization in semantic order.
  518. * If your form must be submitted with name/value pairs in semantic order then pass
  519. * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
  520. * this logic (which can be significant for very large forms).
  521. *
  522. * @example var data = $("#myForm").formSerialize();
  523. * $.ajax('POST', "myscript.cgi", data);
  524. * @desc Collect all the data from a form into a single string
  525. *
  526. * @name formSerialize
  527. * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
  528. * @type String
  529. * @cat Plugins/Form
  530. */
  531. $.fn.formSerialize = function(semantic) {
  532. //hand off to jQuery.param for proper encoding
  533. return $.param(this.formToArray(semantic));
  534. };
  535. /**
  536. * Serializes all field elements in the jQuery object into a query string.
  537. * This method will return a string in the format: name1=value1&amp;name2=value2
  538. *
  539. * The successful argument controls whether or not serialization is limited to
  540. * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  541. * The default value of the successful argument is true.
  542. *
  543. * @example var data = $("input").formSerialize();
  544. * @desc Collect the data from all successful input elements into a query string
  545. *
  546. * @example var data = $(":radio").formSerialize();
  547. * @desc Collect the data from all successful radio input elements into a query string
  548. *
  549. * @example var data = $("#myForm :checkbox").formSerialize();
  550. * @desc Collect the data from all successful checkbox input elements in myForm into a query string
  551. *
  552. * @example var data = $("#myForm :checkbox").formSerialize(false);
  553. * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
  554. *
  555. * @example var data = $(":input").formSerialize();
  556. * @desc Collect the data from all successful input, select, textarea and button elements into a query string
  557. *
  558. * @name fieldSerialize
  559. * @param successful true if only successful controls should be serialized (default is true)
  560. * @type String
  561. * @cat Plugins/Form
  562. */
  563. $.fn.fieldSerialize = function(successful) {
  564. var a = [];
  565. this.each(function() {
  566. var n = this.name;
  567. if (!n) return;
  568. var v = $.fieldValue(this, successful);
  569. if (v && v.constructor == Array) {
  570. for (var i=0,max=v.length; i < max; i++)
  571. a.push({name: n, value: v[i]});
  572. }
  573. else if (v !== null && typeof v != 'undefined')
  574. a.push({name: this.name, value: v});
  575. });
  576. //hand off to jQuery.param for proper encoding
  577. return $.param(a);
  578. };
  579. /**
  580. * Returns the value(s) of the element in the matched set. For example, consider the following form:
  581. *
  582. * <form><fieldset>
  583. * <input name="A" type="text" />
  584. * <input name="A" type="text" />
  585. * <input name="B" type="checkbox" value="B1" />
  586. * <input name="B" type="checkbox" value="B2"/>
  587. * <input name="C" type="radio" value="C1" />
  588. * <input name="C" type="radio" value="C2" />
  589. * </fieldset></form>
  590. *
  591. * var v = $(':text').fieldValue();
  592. * // if no values are entered into the text inputs
  593. * v == ['','']
  594. * // if values entered into the text inputs are 'foo' and 'bar'
  595. * v == ['foo','bar']
  596. *
  597. * var v = $(':checkbox').fieldValue();
  598. * // if neither checkbox is checked
  599. * v === undefined
  600. * // if both checkboxes are checked
  601. * v == ['B1', 'B2']
  602. *
  603. * var v = $(':radio').fieldValue();
  604. * // if neither radio is checked
  605. * v === undefined
  606. * // if first radio is checked
  607. * v == ['C1']
  608. *
  609. * The successful argument controls whether or not the field element must be 'successful'
  610. * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  611. * The default value of the successful argument is true. If this value is false the value(s)
  612. * for each element is returned.
  613. *
  614. * Note: This method *always* returns an array. If no valid value can be determined the
  615. * array will be empty, otherwise it will contain one or more values.
  616. *
  617. * @example var data = $("#myPasswordElement").fieldValue();
  618. * alert(data[0]);
  619. * @desc Alerts the current value of the myPasswordElement element
  620. *
  621. * @example var data = $("#myForm :input").fieldValue();
  622. * @desc Get the value(s) of the form elements in myForm
  623. *
  624. * @example var data = $("#myForm :checkbox").fieldValue();
  625. * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
  626. *
  627. * @example var data = $("#mySingleSelect").fieldValue();
  628. * @desc Get the value(s) of the select control
  629. *
  630. * @example var data = $(':text').fieldValue();
  631. * @desc Get the value(s) of the text input or textarea elements
  632. *
  633. * @example var data = $("#myMultiSelect").fieldValue();
  634. * @desc Get the values for the select-multiple control
  635. *
  636. * @name fieldValue
  637. * @param Boolean successful true if only the values for successful controls should be returned (default is true)
  638. * @type Array<String>
  639. * @cat Plugins/Form
  640. */
  641. $.fn.fieldValue = function(successful) {
  642. for (var val=[], i=0, max=this.length; i < max; i++) {
  643. var el = this[i];
  644. var v = $.fieldValue(el, successful);
  645. if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
  646. continue;
  647. v.constructor == Array ? $.merge(val, v) : val.push(v);
  648. }
  649. return val;
  650. };
  651. /**
  652. * Returns the value of the field element.
  653. *
  654. * The successful argument controls whether or not the field element must be 'successful'
  655. * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  656. * The default value of the successful argument is true. If the given element is not
  657. * successful and the successful arg is not false then the returned value will be null.
  658. *
  659. * Note: If the successful flag is true (default) but the element is not successful, the return will be null
  660. * Note: The value returned for a successful select-multiple element will always be an array.
  661. * Note: If the element has no value the return value will be undefined.
  662. *
  663. * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
  664. * @desc Gets the current value of the myPasswordElement element
  665. *
  666. * @name fieldValue
  667. * @param Element el The DOM element for which the value will be returned
  668. * @param Boolean successful true if value returned must be for a successful controls (default is true)
  669. * @type String or Array<String> or null or undefined
  670. * @cat Plugins/Form
  671. */
  672. $.fieldValue = function(el, successful) {
  673. var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
  674. if (typeof successful == 'undefined') successful = true;
  675. if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
  676. (t == 'checkbox' || t == 'radio') && !el.checked ||
  677. (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
  678. tag == 'select' && el.selectedIndex == -1))
  679. return null;
  680. if (tag == 'select') {
  681. var index = el.selectedIndex;
  682. if (index < 0) return null;
  683. var a = [], ops = el.options;
  684. var one = (t == 'select-one');
  685. var max = (one ? index+1 : ops.length);
  686. for(var i=(one ? index : 0); i < max; i++) {
  687. var op = ops[i];
  688. if (op.selected) {
  689. // extra pain for IE...
  690. var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
  691. if (one) return v;
  692. a.push(v);
  693. }
  694. }
  695. return a;
  696. }
  697. return el.value;
  698. };
  699. /**
  700. * Clears the form data. Takes the following actions on the form's input fields:
  701. * - input text fields will have their 'value' property set to the empty string
  702. * - select elements will have their 'selectedIndex' property set to -1
  703. * - checkbox and radio inputs will have their 'checked' property set to false
  704. * - inputs of type submit, button, reset, and hidden will *not* be effected
  705. * - button elements will *not* be effected
  706. *
  707. * @example $('form').clearForm();
  708. * @desc Clears all forms on the page.
  709. *
  710. * @name clearForm
  711. * @type jQuery
  712. * @cat Plugins/Form
  713. */
  714. $.fn.clearForm = function() {
  715. return this.each(function() {
  716. $('input,select,textarea', this).clearFields();
  717. });
  718. };
  719. /**
  720. * Clears the selected form elements. Takes the following actions on the matched elements:
  721. * - input text fields will have their 'value' property set to the empty string
  722. * - select elements will have their 'selectedIndex' property set to -1
  723. * - checkbox and radio inputs will have their 'checked' property set to false
  724. * - inputs of type submit, button, reset, and hidden will *not* be effected
  725. * - button elements will *not* be effected
  726. *
  727. * @example $('.myInputs').clearFields();
  728. * @desc Clears all inputs with class myInputs
  729. *
  730. * @name clearFields
  731. * @type jQuery
  732. * @cat Plugins/Form
  733. */
  734. $.fn.clearFields = $.fn.clearInputs = function() {
  735. return this.each(function() {
  736. var t = this.type, tag = this.tagName.toLowerCase();
  737. if (t == 'text' || t == 'password' || tag == 'textarea')
  738. this.value = '';
  739. else if (t == 'checkbox' || t == 'radio')
  740. this.checked = false;
  741. else if (tag == 'select')
  742. this.selectedIndex = -1;
  743. });
  744. };
  745. /**
  746. * Resets the form data. Causes all form elements to be reset to their original value.
  747. *
  748. * @example $('form').resetForm();
  749. * @desc Resets all forms on the page.
  750. *
  751. * @name resetForm
  752. * @type jQuery
  753. * @cat Plugins/Form
  754. */
  755. $.fn.resetForm = function() {
  756. return this.each(function() {
  757. // guard against an input with the name of 'reset'
  758. // note that IE reports the reset function as an 'object'
  759. if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
  760. this.reset();
  761. });
  762. };
  763. })(jQuery);