public
Description: Prototype JavaScript framework
Homepage: http://prototypejs.org/
Clone URL: git://github.com/sstephenson/prototype.git
Prototype: merges from form branch.  Closes #5031, #5902, #7595, #8401, #8483, 
#8767.  [Mislav Marohnić, Tomas, Christophe Porteneuve, Jonathan Viney]
madrobby (author)
Wed Jun 27 03:38:54 -0700 2007
commit  9e7efd53610d6268c53de1f26029c7e2f2f977ea
tree    47094edf70d4a47eacf9d2dcb181845dff3f165b
parent  f2d304b3eebdb46665eb3935632ec138eddc2a30
...
1
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
4
5
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0
@@ -1,5 +1,20 @@
0
 *SVN*
0
 
0
+* The action for Form#request defaults to the current URL if the "action" attribute is empty. (This is what most of the major browsers do.) Fixes #8483. [Tomas, Mislav Marohnić]
0
+
0
+* In form serialization, change the way submit buttons are handled. Previously all submit buttons were serialized; now Prototype serializes only the first one. Change Form#serialize and Form.serializeElements to accept a params hash. With the "hash: false" option, a serialized string is returned instead of the hash data object. With the "submit: 'foo'" option, only the submit button with the name "foo" is serialized.  References #5031.  [Mislav Marohnić]
0
+  Examples:
0
+    $('form').serialize({ submit: 'delete' })
0
+    $('form').serialize({ hash: false }) //-> equivalent to $('form').serialize()
0
+
0
+* Form#findFirstElement respects HTML tabindexes.  Closes #7595.  [Christophe Porteneuve]
0
+
0
+* Added Form.Element#setValue method for setting values on various form controls. Checkboxes and radio buttons respond to a boolean and multiple select boxes expect an array of values.  Closes #5902.  [Jonathan Viney, Mislav Marohnić]
0
+  Examples:
0
+    $('text_input').setValue('hello world!')
0
+    $('remember_me').setValue(true)
0
+    $('attend_classes').setValue(['cheese rolling', 'evil chemistry'])
0
+
0
 * Make document.getElementsByClassName match a subset of the WHATWG Web Applications 1.0 specification which was adopted in Firefox 3 (http://www.whatwg.org/specs/web-apps/current-work/#getelementsbyclassname). It now supports multiple class names given as a whitespace-separated list in a string. Array argument is not supported. The method will only return the nodes that match all the class names. In browsers that implement the method natively it will not be overwritten.  Closes #8401.  [Mislav Marohnić]
0
   Example:
0
     document.getElementsByClassName('foo bar')
...
4
5
6
7
 
 
 
 
 
8
9
10
11
12
 
 
 
 
 
13
14
15
...
19
20
21
22
 
23
24
25
26
27
28
 
 
29
30
31
...
67
68
69
70
71
72
 
 
 
 
 
 
 
 
 
73
74
75
...
82
83
84
85
 
 
86
87
88
...
93
94
95
96
 
97
98
99
...
131
132
133
 
 
 
 
 
 
 
134
135
136
...
145
146
147
148
 
149
150
151
...
173
174
175
176
 
177
178
179
180
 
181
182
 
183
184
185
186
187
 
 
 
188
189
190
191
 
 
 
192
193
194
195
196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
198
199
...
4
5
6
 
7
8
9
10
11
12
13
 
 
 
14
15
16
17
18
19
20
21
...
25
26
27
 
28
29
30
31
32
 
 
33
34
35
36
37
...
73
74
75
 
 
 
76
77
78
79
80
81
82
83
84
85
86
87
...
94
95
96
 
97
98
99
100
101
...
106
107
108
 
109
110
111
112
...
144
145
146
147
148
149
150
151
152
153
154
155
156
...
165
166
167
 
168
169
170
171
...
193
194
195
 
196
197
198
199
 
200
201
 
202
203
204
205
 
 
206
207
208
209
210
 
 
211
212
213
214
215
 
 
 
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
0
@@ -4,12 +4,18 @@ var Form = {
0
     return form;
0
   },
0
   
0
-  serializeElements: function(elements, getHash) {
0
+  serializeElements: function(elements, options) {
0
+    if (typeof options != 'object') options = { hash: !!options };
0
+    else if (options.hash === undefined) options.hash = true;
0
+    var key, value, submitted = false, submit = options.submit;
0
+    
0
     var data = elements.inject({}, function(result, element) {
0
       if (!element.disabled && element.name) {
0
-        var key = element.name, value = $(element).getValue();
0
-        if (value != null) { 
0
-           if (key in result) {
0
+        key = element.name; value = $(element).getValue();
0
+        if (value != null && (element.type != 'submit' || (!submitted &&
0
+            submit !== false && (!submit || key == submit) && (submitted = true)))) { 
0
+          if (key in result) {
0
+            // a key is already present; construct an array of values
0
             if (result[key].constructor != Array) result[key] = [result[key]];
0
             result[key].push(value);
0
           }
0
@@ -19,13 +25,13 @@ var Form = {
0
       return result;
0
     });
0
     
0
-    return getHash ? data : Hash.toQueryString(data);
0
+    return options.hash ? data : Hash.toQueryString(data);
0
   }
0
 };
0
 
0
 Form.Methods = {
0
-  serialize: function(form, getHash) {
0
-    return Form.serializeElements(Form.getElements(form), getHash);
0
+  serialize: function(form, options) {
0
+    return Form.serializeElements(Form.getElements(form), options);
0
   },
0
   
0
   getElements: function(form) {
0
@@ -67,9 +73,15 @@ Form.Methods = {
0
   },
0
 
0
   findFirstElement: function(form) {
0
-    return $(form).getElements().find(function(element) {
0
-      return element.type != 'hidden' && !element.disabled &&
0
-        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
0
+    var elements = $(form).getElements().findAll(function(element) {
0
+      return 'hidden' != element.type && !element.disabled;
0
+    });
0
+    var firstByIndex = elements.findAll(function(element) {
0
+      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
0
+    }).sortBy(function(element) { return element.tabIndex }).first();
0
+    
0
+    return firstByIndex ? firstByIndex : elements.find(function(element) {
0
+      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
0
     });
0
   },
0
 
0
@@ -82,7 +94,8 @@ Form.Methods = {
0
   request: function(form, options) {
0
     form = $(form), options = Object.clone(options || {});
0
 
0
-    var params = options.parameters;
0
+    var params = options.parameters, action = form.readAttribute('action') || '';
0
+    if (action.blank()) action = window.location.href;
0
     options.parameters = form.serialize(true);
0
     
0
     if (params) {
0
@@ -93,7 +106,7 @@ Form.Methods = {
0
     if (form.hasAttribute('method') && !options.method)
0
       options.method = form.method;
0
     
0
-    return new Ajax.Request(form.readAttribute('action'), options);
0
+    return new Ajax.Request(action, options);
0
   }
0
 }
0
 
0
@@ -131,6 +144,13 @@ Form.Element.Methods = {
0
     return Form.Element.Serializers[method](element);
0
   },
0
 
0
+  setValue: function(element, value) {
0
+    element = $(element);
0
+    var method = element.tagName.toLowerCase();
0
+    Form.Element.Serializers[method](element, value);
0
+    return element;
0
+  },
0
+
0
   clear: function(element) {
0
     $(element).value = '';
0
     return element;
0
@@ -145,7 +165,7 @@ Form.Element.Methods = {
0
     try {
0
       element.focus();
0
       if (element.select && (element.tagName.toLowerCase() != 'input' ||
0
-        !['button', 'reset', 'submit'].include(element.type)))
0
+          !['button', 'reset', 'submit'].include(element.type)))
0
         element.select();
0
     } catch (e) {}
0
     return element;
0
@@ -173,27 +193,44 @@ var $F = Form.Element.Methods.getValue;
0
 /*--------------------------------------------------------------------------*/
0
 
0
 Form.Element.Serializers = {
0
-  input: function(element) {
0
+  input: function(element, value) {
0
     switch (element.type.toLowerCase()) {
0
       case 'checkbox':  
0
       case 'radio':
0
-        return Form.Element.Serializers.inputSelector(element);
0
+        return Form.Element.Serializers.inputSelector(element, value);
0
       default:
0
-        return Form.Element.Serializers.textarea(element);
0
+        return Form.Element.Serializers.textarea(element, value);
0
     }
0
   },
0
 
0
-  inputSelector: function(element) {
0
-    return element.checked ? element.value : null;
0
+  inputSelector: function(element, value) {
0
+    if (value === undefined) return element.checked ? element.value : null;
0
+    else element.checked = !!value;
0
   },
0
 
0
-  textarea: function(element) {
0
-    return element.value;
0
+  textarea: function(element, value) {
0
+    if (value === undefined) return element.value;
0
+    else element.value = value;
0
   },
0
   
0
-  select: function(element) {
0
-    return this[element.type == 'select-one' ? 
0
-      'selectOne' : 'selectMany'](element);
0
+  select: function(element, index) {
0
+    if (index === undefined)
0
+      return this[element.type == 'select-one' ? 
0
+        'selectOne' : 'selectMany'](element);
0
+    else {
0
+      var opt, value, single = index.constructor != Array;
0
+      for (var i = 0, length = element.length; i < length; i++) {
0
+        opt = element.options[i];
0
+        value = this.optionValue(opt);
0
+        if (single) {
0
+          if (value == index) {
0
+            opt.selected = true;
0
+            return;
0
+          }
0
+        }
0
+        else opt.selected = index.include(value);
0
+      }
0
+    }
0
   },
0
   
0
   selectOne: function(element) {
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
59
60
61
62
63
64
 
 
 
 
 
 
 
 
 
65
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
 
 
 
123
124
125
...
190
191
192
193
194
195
196
197
198
 
 
 
199
200
201
202
 
 
203
204
205
206
207
208
209
 
 
 
 
 
 
210
211
212
213
214
 
 
 
215
216
217
 
218
219
220
 
221
222
223
224
225
226
227
228
 
 
 
 
 
229
230
231
232
233
234
 
 
 
 
 
 
235
236
 
237
238
239
...
250
251
252
253
254
 
 
255
256
257
 
258
259
260
...
272
273
274
275
276
277
278
279
280
281
282
283
284
 
 
 
285
286
287
288
289
290
291
292
293
294
295
296
 
 
 
 
 
 
 
 
 
 
 
 
297
298
299
300
301
 
 
 
 
302
303
304
305
306
307
308
309
310
311
312
313
314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
316
317
318
 
 
319
320
321
322
323
324
325
326
327
 
328
329
330
331
332
333
334
335
336
337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
339
340
341
 
 
342
343
 
344
345
346
347
348
349
 
 
 
350
351
352
353
 
 
 
354
355
356
357
 
 
 
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
 
375
376
377
 
378
379
 
 
380
 
 
 
 
 
 
381
382
383
384
385
 
386
387
388
389
390
391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
393
394
 
395
396
397
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 
 
 
 
59
60
61
62
63
64
65
66
67
68
 
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
 
 
 
 
 
 
 
 
 
 
154
155
156
157
158
159
...
224
225
226
 
 
 
 
 
 
227
228
229
230
 
 
 
231
232
233
 
 
 
 
 
 
234
235
236
237
238
239
240
241
 
 
 
242
243
244
245
246
 
247
248
249
 
250
251
252
253
 
 
 
 
 
254
255
256
257
258
259
 
 
 
 
 
260
261
262
263
264
265
266
 
267
268
269
270
...
281
282
283
 
 
284
285
286
287
 
288
289
290
291
...
303
304
305
 
 
 
 
 
 
 
 
 
 
306
307
308
309
310
311
 
 
 
 
 
 
 
 
 
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
 
 
327
328
329
330
331
 
 
 
 
 
 
 
 
 
 
 
 
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
 
352
353
354
 
 
 
 
 
355
356
 
357
358
359
360
361
 
 
 
 
 
 
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
 
381
382
383
 
384
385
386
387
388
 
 
389
390
391
392
 
 
 
393
394
395
396
 
 
 
397
398
399
400
401
402
 
 
 
 
 
 
 
 
 
 
 
403
404
 
405
406
407
 
408
409
 
410
411
412
413
414
415
416
417
418
419
420
421
422
 
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
 
461
462
463
464
0
@@ -1,125 +1,159 @@
0
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
0
-        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
0
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
0
-<head>
0
-  <title>Prototype Unit test file</title>
0
-  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
0
-  <script src="../../dist/prototype.js" type="text/javascript"></script>
0
-  <script src="../lib/unittest.js" type="text/javascript"></script>
0
-  <link rel="stylesheet" href="../test.css" type="text/css" />
0
-  <style type="text/css" media="screen">
0
-  /* <![CDATA[ */
0
-    #testcss1 { font-size:11px; color: #f00; }
0
-    #testcss2 { font-size:12px; color: #0f0; display: none; }
0
-  /* ]]> */
0
-  </style>
0
-</head>
0
-<body>
0
-<h1>Prototype Unit test file</h1>
0
-<p>
0
-  Test of utility functions in form.js
0
-</p>
0
-
0
-<!-- Log output -->
0
-<div id="testlog"> </div>
0
-
0
-<form id="form" method="get" action="fixtures/empty.js">
0
-  <input type="text" name="val1" id="input_enabled" value="4" />
0
-  <div>This is not a form element</div>
0
-  <input type="text" name="val2" id="input_disabled" disabled="disabled" value="5" />
0
-  <input type="submit" />
0
-  <input type="text" name="action" value="blah" />
0
-</form>
0
-<div id="form_wrapper">
0
-  <form id="form_selects" action="fixtures/empty.js">
0
-    <select name="vu">
0
-       <option value="1" selected="selected">One</option>
0
-       <option value="2">Two</option>
0
-       <option value="3">Three</option>
0
-    </select>
0
-    <select id="multiSel1" name="vm[]" multiple="multiple">
0
-       <option id="multiSel1_opt1" value="1" selected="selected">One</option>
0
-       <option id="multiSel1_opt2" value="2">Two</option>
0
-       <option id="multiSel1_opt3" value="3" selected="selected">Three</option>
0
-    </select>
0
-    <select name="nvu">
0
-       <option selected="selected">One</option>
0
-       <option value="2">Two</option>
0
-       <option value="3">Three</option>
0
-    </select>
0
-    <fieldset id="form_fieldset">
0
-      <select name="nvm[]" multiple="multiple">
0
-         <option selected="selected">One</option>
0
-         <option>Two</option>
0
-         <option selected="selected">Three</option>
0
-      </select>
0
-      <select name="evu">
0
-         <option value="" selected="selected">One</option>
0
+  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
0
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
0
+  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
0
+  <head>
0
+    <title>Prototype Unit test file</title>
0
+    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
0
+    <script src="../../dist/prototype.js" type="text/javascript"></script>
0
+    <script src="../lib/unittest.js" type="text/javascript"></script>
0
+    <link rel="stylesheet" href="../test.css" type="text/css" />
0
+    <style type="text/css" media="screen">
0
+    /* <![CDATA[ */
0
+      #testlog { margin-bottom:2em }
0
+    /* ]]> */
0
+    </style>
0
+  </head>
0
+  <body>
0
+  <h1>Prototype Unit test file</h1>
0
+  <p>
0
+    Test of utility functions in form.js
0
+  </p>
0
+
0
+  <!-- Log output -->
0
+  <div id="testlog"> </div>
0
+
0
+  <form id="form" method="get" action="fixtures/empty.js">
0
+    <input type="text" name="val1" id="input_enabled" value="4" />
0
+    <div>This is not a form element</div>
0
+    <input type="text" name="val2" id="input_disabled" disabled="disabled" value="5" />
0
+    <input type="submit" name="first_submit" value="Commit it!" />
0
+    <input type="submit" name="second_submit" value="Delete it!" />
0
+    <input type="text" name="action" value="blah" />
0
+  </form>
0
+
0
+  <form id="bigform" method="get" action="fixtures/empty.js">
0
+    <div id="inputs">
0
+      <input type="text"   name="dummy"  id="dummy_disabled" disabled="disabled"/>
0
+      <input type="submit" name="commit" id="submit" />
0
+      <input type="button" name="clicky" value="click me" />
0
+      <input type="reset"  name="revert" />
0
+      <input type="text"   name="greeting" id="focus_text" value="Hello" />
0
+    </div>
0
+
0
+    <!-- some edge cases in serialization -->
0
+    <div id="value_checks">
0
+      <input name="twin" type="text" value="" /> 
0
+      <input name="twin" type="text" value="siamese" />
0
+      <!-- Rails checkbox hack with hidden input: -->
0
+      <input name="checky" type="checkbox" id="checkbox_hack" value="1" /> 
0
+      <input name="checky" type="hidden" value="0" />
0
+    </div>
0
+
0
+    <!-- all variations of SELECT controls -->
0
+    <div id="selects_wrapper">
0
+      <select name="vu">
0
+         <option value="1" selected="selected">One</option>
0
          <option value="2">Two</option>
0
          <option value="3">Three</option>
0
       </select>
0
-      <select name="evm[]" multiple="multiple">
0
-         <option value="" selected="selected">One</option>
0
-         <option>Two</option>
0
-         <option selected="selected">Three</option>
0
+      <select id="multiSel1" name="vm[]" multiple="multiple">
0
+         <option id="multiSel1_opt1" value="1" selected="selected">One</option>
0
+         <option id="multiSel1_opt2" value="2">Two</option>
0
+         <option id="multiSel1_opt3" value="3" selected="selected">Three</option>
0
+      </select>
0
+      <select name="nvu">
0
+         <option selected="selected">One</option>
0
+         <option value="2">Two</option>
0
+         <option value="3">Three</option>
0
       </select>
0
-    </fieldset>
0
+
0
+      <fieldset id="selects_fieldset">
0
+        <select name="nvm[]" multiple="multiple">
0
+           <option selected="selected">One</option>
0
+           <option>Two</option>
0
+           <option selected="selected">Three</option>
0
+        </select>
0
+        <select name="evu">
0
+           <option value="" selected="selected">One</option>
0
+           <option value="2">Two</option>
0
+           <option value="3">Three</option>
0
+        </select>
0
+        <select name="evm[]" multiple="multiple">
0
+           <option value="" selected="selected">One</option>
0
+           <option>Two</option>
0
+           <option selected="selected">Three</option>
0
+        </select>
0
+      </fieldset>
0
+    </div>
0
+
0
+    <div id="various">
0
+      <select name="tf_selectOne"><option selected="selected"></option><option>1</option></select>
0
+      <textarea name="tf_textarea"></textarea>
0
+      <input type="checkbox" name="tf_checkbox" value="on" />
0
+      <select name="tf_selectMany" multiple="multiple"></select>
0
+      <input type="text" name="tf_text" />
0
+      <div>This is not a form element</div>
0
+      <input type="radio" name="tf_radio" value="on" />
0
+      <input type="hidden" name="tf_hidden" />
0
+      <input type="password" name="tf_password" />
0
+    </div>
0
+  </form>
0
+
0
+  <form id="form_focus_hidden" style="display: none">
0
+    <input type="text" />
0
   </form>
0
-</div>
0
-
0
-<form id="form_array"> 
0
-  <input type="text" name="twin" value="" /> 
0
-  <input type="text" name="twin" value="siamese" />
0
-  <!-- Rails checkbox hack with hidden input: -->
0
-  <input type="checkbox" id="checkbox_hack" name="checky" value="1" /> 
0
-  <input name="checky" type="hidden" value="0" />
0
-</form>
0
-
0
-<form id="form_getelements">
0
-  <select id="tf_selectOne" name="tf_selectOne"><option></option><option>1</option></select>
0
-  <textarea id="tf_textarea" name="tf_textarea"></textarea>
0
-  <input type="checkbox" id="tf_checkbox" name="tf_checkbox" value="on" />
0
-  <select id="tf_selectMany" name="tf_selectMany" multiple="multiple"></select>
0
-  <input type="text" id="tf_text" name="tf_text" />
0
-  <div>This is not a form element</div>
0
-  <input type="radio" id="tf_radio" name="tf_radio" value="on" />
0
-  <input type="hidden" id="tf_hidden" name="tf_hidden" />
0
-  <input type="password" id="tf_password" name="tf_password" />
0
-</form>
0
-
0
-<form id="form_focus">
0
-  <input type="text" name="focus_disabled" id="focus_disabled" disabled="disabled"/>
0
-  <input type="submit" name="focus_submit" id="focus_submit" />
0
-  <input type="button" name="focus_button" id="focus_button" value="button" />
0
-  <input type="reset" name="focus_reset" id="focus_reset" />
0
-  <input type="text" name="focus_text" id="focus_text" value="Hello" />
0
-</form>
0
-
0
-<form id="form_focus_hidden" style="display: none">
0
-  <input type="text" />
0
-</form>
0
-
0
-<!-- Tests follow -->
0
-<script type="text/javascript" language="javascript" charset="utf-8">
0
-// <![CDATA[
0
-  var callbackCounter = 0;
0
-  var timedCounter = 0;
0
+
0
+  <!-- tabindexed forms -->
0
+  <div id="tabindex">
0
+    <form id="ffe">
0
+      <p><input type="text" disabled="disabled" id="ffe_disabled" /></p>
0
+      <input type="hidden" id="ffe_hidden" />
0
+      <input type="checkbox" id="ffe_checkbox" />
0
+    </form>
0
+
0
+    <form id="ffe_ti">
0
+      <p><input type="text" disabled="disabled" id="ffe_ti_disabled" /></p>
0
+      <input type="hidden" id="ffe_ti_hidden" />
0
+      <input type="checkbox" id="ffe_ti_checkbox" />
0
+      <input type="submit" id="ffe_ti_submit" tabindex="1" />
0
+    </form>
0
+
0
+    <form id="ffe_ti2">
0
+      <p><input type="text" disabled="disabled" id="ffe_ti2_disabled" /></p>
0
+      <input type="hidden" id="ffe_ti2_hidden" />
0
+      <input type="checkbox" id="ffe_ti2_checkbox" tabindex="0" />
0
+      <input type="submit" id="ffe_ti2_submit" tabindex="1" />
0
+    </form>
0
+  </div>
0
+
0
+  <!-- Tests follow -->
0
+  <script type="text/javascript" charset="utf-8">
0
+  // <![CDATA[
0
+    var callbackCounter = 0;
0
+    var timedCounter = 0;
0
+
0
+    // sweet sweet additional assertions
0
+    Object.extend(Test.Unit.Testcase.prototype, {
0
+      assertEnabled: function() {
0
+        for (var i = 0, element; element = arguments[i]; i++) {
0
+          this.assert(!$(element).disabled, Test.Unit.inspect(element) + ' was disabled');
0
+        }
0
+      },
0
+      assertDisabled: function() {
0
+        for (var i = 0, element; element = arguments[i]; i++) {
0
+          this.assert($(element).disabled, Test.Unit.inspect(element) + ' was enabled');
0
+        }
0
+      }
0
+    });
0
 
0
   new Test.Unit.Runner({
0
     
0
     // Make sure to set defaults in the test forms, as some browsers override this
0
     // with previously entered values on page reload
0
     setup: function(){ with(this) {
0
-      $('input_enabled').value = '4';
0
-      $('input_disabled').value = '5';
0
-      
0
-      $('tf_selectOne').selectedIndex = 0;
0
-      $('tf_textarea').value = '';
0
-      $('tf_text').value = '';
0
-      $('tf_hidden').value = '';
0
-      $('tf_password').value = '';
0
-      $('tf_checkbox').checked = false;
0
-      $('tf_radio').checked = false;
0
+      $$('form').each(function(f){ f.reset() });
0
+      // hidden value does not reset (for some reason)
0
+      $('bigform')['tf_hidden'].value = '';
0
     }},
0
     
0
     testDollarF: function(){ with(this) {
0
@@ -190,50 +224,47 @@
0
     }},
0
     
0
     testFormEnabling: function(){ with(this) {
0
-      var form = $('form_focus')
0
-      var input1 = form.focus_disabled
0
-      var input2 = form.focus_text
0
-      
0
-      assert(input1.disabled)
0
-      assert(!input2.disabled)
0
+      var form = $('bigform')
0
+      var input1 = $('dummy_disabled');
0
+      var input2 = $('focus_text');
0
       
0
-      form.disable()
0
-      assert(input1.disabled)
0
-      assert(input2.disabled)
0
+      assertDisabled(input1);
0
+      assertEnabled(input2);
0
       
0
-      form.enable()
0
-      assert(!input1.disabled)
0
-      assert(!input2.disabled)
0
-      
0
-      input1.disable()
0
-      assert(input1.disabled)
0
+      form.disable();
0
+      assertDisabled(input1, input2);
0
+      form.enable();
0
+      assertEnabled(input1, input2);
0
+      input1.disable();
0
+      assertDisabled(input1);
0
       
0
       // non-form elements:
0
-      var fieldset = $('form_fieldset')
0
-      var fields = fieldset.immediateDescendants()
0
-      assert(fields.all(function(select){ return !select.disabled }))
0
+      var fieldset = $('selects_fieldset');
0
+      var fields = fieldset.immediateDescendants();
0
+      fields.each(function(select) { assertEnabled(select) });
0
       
0
       Form.disable(fieldset)
0
-      assert(fields.all(function(select){ return select.disabled }))
0
+      fields.each(function(select) { assertDisabled(select) });
0
       
0
       Form.enable(fieldset)
0
-      assert(fields.all(function(select){ return !select.disabled }))
0
+      fields.each(function(select) { assertEnabled(select) });
0
     }},
0
     
0
     testFormElementEnabling: function(){ with(this) {
0
-      assert($('input_disabled').disabled);
0
-      $('input_disabled').enable();
0
-      assert(!$('input_disabled').disabled);
0
-      $('input_disabled').disable();
0
-      assert($('input_disabled').disabled);
0
+      var field = $('input_disabled');
0
+      field.enable();
0
+      assertEnabled(field);
0
+      field.disable();
0
+      assertDisabled(field);
0
       
0
-      assert(!$('input_enabled').disabled);
0
-      $('input_enabled').disable();
0
-      assert($('input_enabled').disabled);
0
-      $('input_enabled').enable();
0
-      assert(!$('input_enabled').disabled);
0
+      var field = $('input_enabled');
0
+      assertEnabled(field);
0
+      field.disable();
0
+      assertDisabled(field);
0
+      field.enable();
0
+      assertEnabled(field);
0
     }},
0
-    
0
+
0
     // due to the lack of a DOM hasFocus() API method,
0
     // we're simulating things here a little bit
0
     testFormActivating: function(){ with(this) {
0
@@ -250,11 +281,11 @@
0
       }
0
       
0
       // Form.focusFirstElement shouldn't focus disabled elements
0
-      var element = Form.findFirstElement('form_focus');
0
-      assertEqual('focus_submit',element.id);
0
+      var element = Form.findFirstElement('bigform');
0
+      assertEqual('submit', element.id);
0
       
0
       // Test IE doesn't select text on buttons
0
-      Form.focusFirstElement('form_focus');
0
+      Form.focusFirstElement('bigform');
0
       if(document.selection) assertEqual('', getSelection(element));
0
       
0
       // Form.Element.activate shouldn't select text on buttons
0
@@ -272,126 +303,162 @@
0
     }},
0
     
0
     testFormGetElements: function() {with(this) {
0
-      var formElements = $('form_getelements').getElements();
0
-      assertEqual(8, formElements.length);
0
-      assertEqual('tf_selectOne', formElements[0].id);
0
-      assertEqual('tf_textarea', formElements[1].id);
0
-      assertEqual('tf_checkbox', formElements[2].id);
0
-      assertEqual('tf_selectMany', formElements[3].id);
0
-      assertEqual('tf_text', formElements[4].id);
0
-      assertEqual('tf_radio', formElements[5].id);
0
-      assertEqual('tf_hidden', formElements[6].id);
0
-      assertEqual('tf_password', formElements[7].id);
0
+      var elements = Form.getElements('various'),
0
+        names = $w('tf_selectOne tf_textarea tf_checkbox tf_selectMany tf_text tf_radio tf_hidden tf_password');
0
+      assertEnumEqual(names, elements.pluck('name'))
0
     }},
0
     
0
     testFormGetInputs: function() {with(this){
0
-      var form = $('form_getelements'), formInputs = Form.getInputs(form);
0
-      assertEqual(formInputs.length, 5);
0
-      assert(formInputs instanceof Array);
0
-      assert(formInputs.all(function(input) { return (input.tagName == "INPUT"); }));
0
-      
0
-      var formInputs2 = form.getInputs();
0
-      assertEqual(formInputs2.length, 5);
0
-      assert(formInputs2 instanceof Array);
0
-      assert(formInputs2.all(function(input) { return (input.tagName == "INPUT"); }));
0
+      var form = $('form');
0
+      [form.getInputs(), Form.getInputs(form)].each(function(inputs){
0
+        assertEqual(inputs.length, 5);
0
+        assert(inputs instanceof Array);
0
+        assert(inputs.all(function(input) { return (input.tagName == "INPUT"); }));
0
+      });
0
+    }},
0
+
0
+    testFormFindFirstElement: function() {with(this) {
0
+      assertEqual($('ffe_checkbox'), $('ffe').findFirstElement());
0
+      assertEqual($('ffe_ti_submit'), $('ffe_ti').findFirstElement());
0
+      assertEqual($('ffe_ti2_checkbox'), $('ffe_ti2').findFirstElement());
0
     }},
0
     
0
     testFormSerialize: function() {with(this){
0
-      assertEqual('tf_selectOne=&tf_textarea=&tf_text=&tf_hidden=&tf_password=', 
0
-        Form.serialize('form_getelements'));
0
+      // form is initially empty
0
+      var form = $('bigform');
0
+      var expected = { tf_selectOne:'', tf_textarea:'', tf_text:'', tf_hidden:'', tf_password:'' };
0
+      assertHashEqual(expected, Form.serialize('various', true));
0
         
0
-      $('tf_selectOne').selectedIndex = 1;
0
-      $('tf_textarea').value = "boo hoo!";
0
-      $('tf_text').value = "123öäü";
0
-      $('tf_hidden').value = "moo%hoo&test";
0
-      $('tf_password').value = 'sekrit code';
0
-      $('tf_checkbox').checked = true;
0
-      $('tf_radio').checked = true;
0
-      
0
-      assertEqual(
0
-        'tf_selectOne=1&tf_textarea=boo%20hoo!&tf_checkbox=on&tf_text=123%C3%B6%C3%A4%C3%BC&'+
0
-        'tf_radio=on&tf_hidden=moo%25hoo%26test&tf_password=sekrit%20code',
0
-        Form.serialize('form_getelements'));
0
+      // set up some stuff
0
+      form['tf_selectOne'].selectedIndex = 1;
0
+      form['tf_textarea'].value = "boo hoo!";
0
+      form['tf_text'].value = "123öäü";
0
+      form['tf_hidden'].value = "moo%hoo&test";
0
+      form['tf_password'].value = 'sekrit code';
0
+      form['tf_checkbox'].checked = true;
0
+      form['tf_radio'].checked = true;
0
+      var expected = { tf_selectOne:1, tf_textarea:"boo hoo!", tf_text:"123öäü",
0
+        tf_hidden:"moo%hoo&test", tf_password:'sekrit code', tf_checkbox:'on', tf_radio:'on' }
0
+
0
+      // return params
0
+      assertHashEqual(expected, Form.serialize('various', true));
0
+      // return string
0
+      assertEnumEqual(Hash.toQueryString(expected).split('&').sort(),
0
+                      Form.serialize('various').split('&').sort());
0
+      assertEqual('string', typeof $('form').serialize({ hash:false }));
0
 
0
       // Checks that disabled element is not included in serialized form.
0
       $('input_enabled').enable();
0
-      assertEqual('val1=4&action=blah', Form.serialize('form'));
0
+      assertHashEqual({ val1:4, action:'blah', first_submit:'Commit it!' },
0
+                      $('form').serialize(true));
0
 
0
-      // Checks that select-related serializations work just fine
0
-      assertEqual('vu=1&vm%5B%5D=1&vm%5B%5D=3&nvu=One&nvm%5B%5D=One'+
0
-        '&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three', 
0
-        Form.serialize('form_selects'));
0
-      
0
       // should not eat empty values for duplicate names 
0
       $('checkbox_hack').checked = false;
0
-      var data = Form.serialize('form_array', true); 
0
+      var data = Form.serialize('value_checks', true); 
0
       assertEnumEqual(['', 'siamese'], data['twin']); 
0
       assertEqual('0', data['checky']);
0
       
0
       $('checkbox_hack').checked = true; 
0
-      assertEnumEqual($w('1 0'), Form.serialize('form_array', true)['checky']);
0
-    }},
0
-    
0
-    testFormSerializeWorksWithNonFormElements: function() {with(this) {
0
-      assertEqual('nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three', Form.serialize('form_fieldset'));
0
-      assertEqual('vu=1&vm%5B%5D=1&vm%5B%5D=3&nvu=One&nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three', Form.serialize('form_wrapper'));
0
+      assertEnumEqual($w('1 0'), Form.serialize('value_checks', true)['checky']);
0
+
0
+      // all kinds of SELECT controls
0
+      var params = Form.serialize('selects_fieldset', true);
0
+      var expected = { 'nvm[]':['One', 'Three'], evu:'', 'evm[]':['', 'Three'] };
0
+      assertHashEqual(expected, params);
0
+      params = Form.serialize('selects_wrapper', true);
0
+      assertHashEqual(Object.extend(expected, { vu:1, 'vm[]':[1, 3], nvu:'One' }), params);
0
+
0
+      // explicit submit button
0
+      assertHashEqual({ val1:4, action:'blah', second_submit:'Delete it!' },
0
+                      $('form').serialize({ submit: 'second_submit' }));
0
+      assertHashEqual({ val1:4, action:'blah' },
0
+                      $('form').serialize({ submit: false }));
0
+      assertHashEqual({ val1:4, action:'blah' },
0
+                      $('form').serialize({ submit: 'inexistent' }));
0
     }},
0
     
0
     testFormMethodsOnExtendedElements: function() {with(this) {
0
-      assertEqual(Form.serialize('form'), $('form').serialize());
0
+      var form = $('form');
0
+      assertEqual(Form.serialize('form'), form.serialize());
0
       assertEqual(Form.Element.serialize('input_enabled'), $('input_enabled').serialize());
0
-      assertNotEqual($('form').serialize, $('input_enabled').serialize);
0
+      assertNotEqual(form.serialize, $('input_enabled').serialize);
0
       
0
       Element.addMethods('INPUT',  { anInputMethod: function(input)  { return 'input'  } });
0
       Element.addMethods('SELECT', { aSelectMethod: function(select) { return 'select' } });
0
 
0
-      document.getElementById('tf_text')._extendedByPrototype = false;
0
-      document.getElementById('tf_selectOne')._extendedByPrototype = false;
0
+      form = $('bigform');
0
+      var input = form['tf_text'], select = form['tf_selectOne'];
0
+      input._extendedByPrototype = select._extendedByPrototype = false;
0
 
0
-      assert($('tf_text').anInputMethod);
0
-      assert(!$('tf_text').aSelectMethod);
0
-      assertEqual('input', $('tf_text').anInputMethod());
0
+      assert($(input).anInputMethod);
0
+      assert(!input.aSelectMethod);
0
+      assertEqual('input', input.anInputMethod());
0
 
0
-      assert($('tf_selectOne').aSelectMethod);
0
-      assert(!$('tf_selectOne').anInputMethod);      
0
-      assertEqual('select', $('tf_selectOne').aSelectMethod());
0
+      assert($(select).aSelectMethod);
0
+      assert(!select.anInputMethod);      
0
+      assertEqual('select', select.aSelectMethod());
0
     }},
0
     
0
     testFormRequest: function() {with(this) {
0
-      var request = $("form_selects").request();
0
-      assert(!$("form_selects").hasAttribute("method"));
0
-      assert(request.url.endsWith("fixtures/empty.js"));
0
-      assertEqual("post", request.method);
0
-      assertEqual("vu=1&vm%5B%5D=1&vm%5B%5D=3&nvu=One&nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three", Hash.toQueryString(request.options.parameters));
0
-
0
-      request = $("form_selects").request({method: "put", parameters: {val2: "hello", val3: "world"}});
0
-      assertEqual("post", request.method);
0
-      assertEqual("put", request.parameters['_method']);
0
-      assertEqual("vu=1&vm%5B%5D=1&vm%5B%5D=3&nvu=One&nvm%5B%5D=One&nvm%5B%5D=Three&evu=&evm%5B%5D=&evm%5B%5D=Three&val2=hello&val3=world", Hash.toQueryString(request.options.parameters));
0
-      
0
       request = $("form").request();
0
       assert($("form").hasAttribute("method"));
0
-      assert(request.url.endsWith("fixtures/empty.js?val1=4&action=blah"));
0
+      assert(request.url.include("fixtures/empty.js?val1=4"));
0
       assertEqual("get", request.method);
0
       
0
-      request = $("form").request({method: "post"});
0
+      request = $("form").request({ method: "put", parameters: {val2: "hello"} });
0
       assert(request.url.endsWith("fixtures/empty.js"));
0
-      assertEqual("val1=4&action=blah", Hash.toQueryString(request.options.parameters));
0
+      assertEqual(4, request.options.parameters['val1']);
0
+      assertEqual('hello', request.options.parameters['val2']);
0
       assertEqual("post", request.method);
0
+      assertEqual("put", request.parameters['_method']);
0
+
0
+      // with empty action attribute
0
+      request = $("ffe").request({ method: 'post' });
0
+      assert(request.url.include("unit/form.html"),
0
+        'wrong default action for form element with empty action attribute');
0
     }},
0
     
0
     testFormElementMethodsChaining: function(){ with(this) {
0
       var methods = $w('clear activate disable enable'),
0
-        formElements = $('form_getelements').getElements();
0
+        formElements = $('form').getElements();
0
       methods.each(function(method){
0
         formElements.each(function(element){
0
           var returned = element[method]();
0
           assertIdentical(element, returned);
0
         });
0
       });
0
+    }},
0
+
0
+    testSetValue: function(){ with(this) {
0
+      // text input
0
+      var input = $('input_enabled'), oldValue = input.getValue();
0
+      assertEqual(input, input.setValue('foo'), 'setValue chaining is broken');
0
+      assertEqual('foo', input.getValue(), 'value improperly set');
0
+      input.setValue(oldValue);
0
+      assertEqual(oldValue, input.getValue(), 'value improperly restored to original');
0
+
0
+      // checkbox
0
+      input = $('checkbox_hack');
0
+      input.setValue(false);
0
+      assertEqual(null, input.getValue(), 'checkbox should be unchecked');
0
+      input.setValue(true);
0
+      assertEqual("1", input.getValue(), 'checkbox should be checked');
0
+      // selectbox
0
+      input = $('bigform')['vu'];
0
+      input.setValue('3');
0
+      assertEqual('3', input.getValue(), 'single select option improperly set');
0
+      input.setValue('1');
0
+      assertEqual('1', input.getValue());
0
+      // multiple select
0
+      input = $('bigform')['vm[]'];
0
+      input.setValue(['2', '3']);
0
+      assertEnumEqual(['2', '3'], input.getValue(),
0
+        'multiple select options improperly set');
0
+      input.setValue(['1', '3']);
0
+      assertEnumEqual(['1', '3'], input.getValue());
0
     }}
0
     
0
-  }, 'testlog');
0
+  });
0
 // ]]>
0
 </script>
0
 </body>

Comments