Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/dom/forms.js
2868 views
1
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Utilities for manipulating a form and elements.
17
*
18
* @author [email protected] (Erik Arvidsson)
19
*/
20
21
goog.provide('goog.dom.forms');
22
23
goog.require('goog.dom.InputType');
24
goog.require('goog.dom.TagName');
25
goog.require('goog.structs.Map');
26
goog.require('goog.window');
27
28
29
30
/**
31
* Submits form data via a new window. This hides references to the parent
32
* window and should be used when submitting forms to untrusted 3rd party urls.
33
* By default, this uses the action and method of the specified form
34
* element. It is possible to override the default action and method if an
35
* optional submit element with formaction and/or formmethod attributes is
36
* provided.
37
* @param {!HTMLFormElement} form The form.
38
* @param {!HTMLElement=} opt_submitElement The `<button>` or `<input>` element
39
* used to submit the form. The element should have a submit type.
40
* @return {boolean} true If the form was submitted succesfully.
41
* @throws {!Error} If opt_submitElement is not a valid form submit element.
42
*/
43
goog.dom.forms.submitFormInNewWindow = function(form, opt_submitElement) {
44
var formData = goog.dom.forms.getFormDataMap(form);
45
var action = form.action;
46
var method = form.method;
47
48
if (opt_submitElement) {
49
if (goog.dom.InputType.SUBMIT != opt_submitElement.type.toLowerCase()) {
50
throw Error('opt_submitElement does not have a valid type.');
51
}
52
53
54
var submitValue =
55
/** @type {?string} */ (goog.dom.forms.getValue(opt_submitElement));
56
if (submitValue != null) {
57
goog.dom.forms.addFormDataToMap_(
58
formData, opt_submitElement.name, submitValue);
59
}
60
61
if (opt_submitElement.getAttribute('formaction')) {
62
action = opt_submitElement.getAttribute('formaction');
63
}
64
65
if (opt_submitElement.getAttribute('formmethod')) {
66
method = opt_submitElement.getAttribute('formmethod');
67
}
68
}
69
70
return goog.dom.forms.submitFormDataInNewWindow(action, method, formData);
71
};
72
73
/**
74
* Submits form data via a new window. This hides references to the parent
75
* window and should be used when submitting forms to untrusted 3rd party urls.
76
* @param {string} actionUri uri to submit form content to.
77
* @param {string} method HTTP method used to submit the form.
78
* @param {!goog.structs.Map<string, !Array<string>>} formData A map of the form
79
* data as field name to arrays of values.
80
* @return {boolean} true If the form was submitted succesfully.
81
*/
82
goog.dom.forms.submitFormDataInNewWindow = function(
83
actionUri, method, formData) {
84
var newWin = goog.window.openBlank('', {noreferrer: true});
85
86
// This could be null if a new window could not be opened. e.g. if it was
87
// stopped by a popup blocker.
88
if (!newWin) {
89
return false;
90
}
91
92
var newDocument = newWin.document;
93
94
var newForm =
95
/** @type {!HTMLFormElement} */ (newDocument.createElement('form'));
96
newForm.method = method;
97
newForm.action = actionUri;
98
99
// After this point, do not directly reference the form object's functions as
100
// field names can shadow the form's properties.
101
102
formData.forEach(function(fieldValues, fieldName) {
103
for (var i = 0; i < fieldValues.length; i++) {
104
var fieldValue = fieldValues[i];
105
var newInput = newDocument.createElement('input');
106
newInput.name = fieldName;
107
newInput.value = fieldValue;
108
newInput.type = 'hidden';
109
HTMLFormElement.prototype.appendChild.call(newForm, newInput);
110
}
111
});
112
113
HTMLFormElement.prototype.submit.call(newForm);
114
return true;
115
};
116
117
118
/**
119
* Returns form data as a map of name to value arrays. This doesn't
120
* support file inputs.
121
* @param {HTMLFormElement} form The form.
122
* @return {!goog.structs.Map<string, !Array<string>>} A map of the form data
123
* as field name to arrays of values.
124
*/
125
goog.dom.forms.getFormDataMap = function(form) {
126
var map = new goog.structs.Map();
127
goog.dom.forms.getFormDataHelper_(
128
form, map, goog.dom.forms.addFormDataToMap_);
129
return map;
130
};
131
132
133
/**
134
* Returns the form data as an application/x-www-url-encoded string. This
135
* doesn't support file inputs.
136
* @param {HTMLFormElement} form The form.
137
* @return {string} An application/x-www-url-encoded string.
138
*/
139
goog.dom.forms.getFormDataString = function(form) {
140
var sb = [];
141
goog.dom.forms.getFormDataHelper_(
142
form, sb, goog.dom.forms.addFormDataToStringBuffer_);
143
return sb.join('&');
144
};
145
146
147
/**
148
* Returns the form data as a map or an application/x-www-url-encoded
149
* string. This doesn't support file inputs.
150
* @param {HTMLFormElement} form The form.
151
* @param {Object} result The object form data is being put in.
152
* @param {Function} fnAppend Function that takes {@code result}, an element
153
* name, and an element value, and adds the name/value pair to the result
154
* object.
155
* @private
156
*/
157
goog.dom.forms.getFormDataHelper_ = function(form, result, fnAppend) {
158
var els = form.elements;
159
for (var el, i = 0; el = els[i]; i++) {
160
if ( // Make sure we don't include elements that are not part of the form.
161
// Some browsers include non-form elements. Check for 'form' property.
162
// See http://code.google.com/p/closure-library/issues/detail?id=227
163
// and
164
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element
165
(el.form != form) || el.disabled ||
166
// HTMLFieldSetElement has a form property but no value.
167
el.tagName == goog.dom.TagName.FIELDSET) {
168
continue;
169
}
170
171
var name = el.name;
172
switch (el.type.toLowerCase()) {
173
case goog.dom.InputType.FILE:
174
// file inputs are not supported
175
case goog.dom.InputType.SUBMIT:
176
case goog.dom.InputType.RESET:
177
case goog.dom.InputType.BUTTON:
178
// don't submit these
179
break;
180
case goog.dom.InputType.SELECT_MULTIPLE:
181
var values = goog.dom.forms.getValue(el);
182
if (values != null) {
183
for (var value, j = 0; value = values[j]; j++) {
184
fnAppend(result, name, value);
185
}
186
}
187
break;
188
default:
189
var value = goog.dom.forms.getValue(el);
190
if (value != null) {
191
fnAppend(result, name, value);
192
}
193
}
194
}
195
196
// input[type=image] are not included in the elements collection
197
var inputs = form.getElementsByTagName(String(goog.dom.TagName.INPUT));
198
for (var input, i = 0; input = inputs[i]; i++) {
199
if (input.form == form &&
200
input.type.toLowerCase() == goog.dom.InputType.IMAGE) {
201
name = input.name;
202
fnAppend(result, name, input.value);
203
fnAppend(result, name + '.x', '0');
204
fnAppend(result, name + '.y', '0');
205
}
206
}
207
};
208
209
210
/**
211
* Adds the name/value pair to the map.
212
* @param {!goog.structs.Map<string, !Array<string>>} map The map to add to.
213
* @param {string} name The name.
214
* @param {string} value The value.
215
* @private
216
*/
217
goog.dom.forms.addFormDataToMap_ = function(map, name, value) {
218
var array = map.get(name);
219
if (!array) {
220
array = [];
221
map.set(name, array);
222
}
223
array.push(value);
224
};
225
226
227
/**
228
* Adds a name/value pair to an string buffer array in the form 'name=value'.
229
* @param {Array<string>} sb The string buffer array for storing data.
230
* @param {string} name The name.
231
* @param {string} value The value.
232
* @private
233
*/
234
goog.dom.forms.addFormDataToStringBuffer_ = function(sb, name, value) {
235
sb.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
236
};
237
238
239
/**
240
* Whether the form has a file input.
241
* @param {HTMLFormElement} form The form.
242
* @return {boolean} Whether the form has a file input.
243
*/
244
goog.dom.forms.hasFileInput = function(form) {
245
var els = form.elements;
246
for (var el, i = 0; el = els[i]; i++) {
247
if (!el.disabled && el.type &&
248
el.type.toLowerCase() == goog.dom.InputType.FILE) {
249
return true;
250
}
251
}
252
return false;
253
};
254
255
256
/**
257
* Enables or disables either all elements in a form or a single form element.
258
* @param {Element} el The element, either a form or an element within a form.
259
* @param {boolean} disabled Whether the element should be disabled.
260
*/
261
goog.dom.forms.setDisabled = function(el, disabled) {
262
// disable all elements in a form
263
if (el.tagName == goog.dom.TagName.FORM) {
264
var els = /** @type {!HTMLFormElement} */ (el).elements;
265
for (var i = 0; el = els[i]; i++) {
266
goog.dom.forms.setDisabled(el, disabled);
267
}
268
} else {
269
// makes sure to blur buttons, multi-selects, and any elements which
270
// maintain keyboard/accessibility focus when disabled
271
if (disabled == true) {
272
el.blur();
273
}
274
el.disabled = disabled;
275
}
276
};
277
278
279
/**
280
* Focuses, and optionally selects the content of, a form element.
281
* @param {Element} el The form element.
282
*/
283
goog.dom.forms.focusAndSelect = function(el) {
284
el.focus();
285
if (el.select) {
286
el.select();
287
}
288
};
289
290
291
/**
292
* Whether a form element has a value.
293
* @param {Element} el The element.
294
* @return {boolean} Whether the form has a value.
295
*/
296
goog.dom.forms.hasValue = function(el) {
297
var value = goog.dom.forms.getValue(el);
298
return !!value;
299
};
300
301
302
/**
303
* Whether a named form field has a value.
304
* @param {HTMLFormElement} form The form element.
305
* @param {string} name Name of an input to the form.
306
* @return {boolean} Whether the form has a value.
307
*/
308
goog.dom.forms.hasValueByName = function(form, name) {
309
var value = goog.dom.forms.getValueByName(form, name);
310
return !!value;
311
};
312
313
314
/**
315
* Gets the current value of any element with a type.
316
* @param {Element} el The element.
317
* @return {string|Array<string>|null} The current value of the element
318
* (or null).
319
*/
320
goog.dom.forms.getValue = function(el) {
321
var type = /** @type {!HTMLInputElement} */ (el).type;
322
if (!goog.isDef(type)) {
323
return null;
324
}
325
switch (type.toLowerCase()) {
326
case goog.dom.InputType.CHECKBOX:
327
case goog.dom.InputType.RADIO:
328
return goog.dom.forms.getInputChecked_(el);
329
case goog.dom.InputType.SELECT_ONE:
330
return goog.dom.forms.getSelectSingle_(el);
331
case goog.dom.InputType.SELECT_MULTIPLE:
332
return goog.dom.forms.getSelectMultiple_(el);
333
default:
334
return goog.isDef(el.value) ? el.value : null;
335
}
336
};
337
338
339
/**
340
* Returns the value of the named form field. In the case of radio buttons,
341
* returns the value of the checked button with the given name.
342
*
343
* @param {HTMLFormElement} form The form element.
344
* @param {string} name Name of an input to the form.
345
*
346
* @return {Array<string>|string|null} The value of the form element, or
347
* null if the form element does not exist or has no value.
348
*/
349
goog.dom.forms.getValueByName = function(form, name) {
350
var els = form.elements[name];
351
352
if (els) {
353
if (els.type) {
354
return goog.dom.forms.getValue(els);
355
} else {
356
for (var i = 0; i < els.length; i++) {
357
var val = goog.dom.forms.getValue(els[i]);
358
if (val) {
359
return val;
360
}
361
}
362
}
363
}
364
return null;
365
};
366
367
368
/**
369
* Gets the current value of a checkable input element.
370
* @param {Element} el The element.
371
* @return {?string} The value of the form element (or null).
372
* @private
373
*/
374
goog.dom.forms.getInputChecked_ = function(el) {
375
return el.checked ? /** @type {?} */ (el).value : null;
376
};
377
378
379
/**
380
* Gets the current value of a select-one element.
381
* @param {Element} el The element.
382
* @return {?string} The value of the form element (or null).
383
* @private
384
*/
385
goog.dom.forms.getSelectSingle_ = function(el) {
386
var selectedIndex = /** @type {!HTMLSelectElement} */ (el).selectedIndex;
387
return selectedIndex >= 0 ?
388
/** @type {!HTMLSelectElement} */ (el).options[selectedIndex].value :
389
null;
390
};
391
392
393
/**
394
* Gets the current value of a select-multiple element.
395
* @param {Element} el The element.
396
* @return {Array<string>?} The value of the form element (or null).
397
* @private
398
*/
399
goog.dom.forms.getSelectMultiple_ = function(el) {
400
var values = [];
401
for (var option, i = 0;
402
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
403
if (option.selected) {
404
values.push(option.value);
405
}
406
}
407
return values.length ? values : null;
408
};
409
410
411
/**
412
* Sets the current value of any element with a type.
413
* @param {Element} el The element.
414
* @param {*=} opt_value The value to give to the element, which will be coerced
415
* by the browser in the default case using toString. This value should be
416
* an array for setting the value of select multiple elements.
417
*/
418
goog.dom.forms.setValue = function(el, opt_value) {
419
var type = /** @type {!HTMLInputElement} */ (el).type;
420
if (goog.isDef(type)) {
421
switch (type.toLowerCase()) {
422
case goog.dom.InputType.CHECKBOX:
423
case goog.dom.InputType.RADIO:
424
goog.dom.forms.setInputChecked_(
425
el,
426
/** @type {string} */ (opt_value));
427
break;
428
case goog.dom.InputType.SELECT_ONE:
429
goog.dom.forms.setSelectSingle_(
430
el,
431
/** @type {string} */ (opt_value));
432
break;
433
case goog.dom.InputType.SELECT_MULTIPLE:
434
goog.dom.forms.setSelectMultiple_(
435
el,
436
/** @type {Array<string>} */ (opt_value));
437
break;
438
default:
439
el.value = goog.isDefAndNotNull(opt_value) ? opt_value : '';
440
}
441
}
442
};
443
444
445
/**
446
* Sets a checkable input element's checked property.
447
* #TODO(user): This seems potentially unintuitive since it doesn't set
448
* the value property but my hunch is that the primary use case is to check a
449
* checkbox, not to reset its value property.
450
* @param {Element} el The element.
451
* @param {string|boolean=} opt_value The value, sets the element checked if
452
* val is set.
453
* @private
454
*/
455
goog.dom.forms.setInputChecked_ = function(el, opt_value) {
456
el.checked = opt_value;
457
};
458
459
460
/**
461
* Sets the value of a select-one element.
462
* @param {Element} el The element.
463
* @param {string=} opt_value The value of the selected option element.
464
* @private
465
*/
466
goog.dom.forms.setSelectSingle_ = function(el, opt_value) {
467
// unset any prior selections
468
el.selectedIndex = -1;
469
if (goog.isString(opt_value)) {
470
for (var option, i = 0;
471
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
472
if (option.value == opt_value) {
473
option.selected = true;
474
break;
475
}
476
}
477
}
478
};
479
480
481
/**
482
* Sets the value of a select-multiple element.
483
* @param {Element} el The element.
484
* @param {Array<string>|string=} opt_value The value of the selected option
485
* element(s).
486
* @private
487
*/
488
goog.dom.forms.setSelectMultiple_ = function(el, opt_value) {
489
// reset string opt_values as an array
490
if (goog.isString(opt_value)) {
491
opt_value = [opt_value];
492
}
493
for (var option, i = 0;
494
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
495
// we have to reset the other options to false for select-multiple
496
option.selected = false;
497
if (opt_value) {
498
for (var value, j = 0; value = opt_value[j]; j++) {
499
if (option.value == value) {
500
option.selected = true;
501
}
502
}
503
}
504
}
505
};
506
507