Small utility library for working with browser web forms.
/**
* Various form utils from Google Closure Library.
* https://github.com/google/closure-library/
*/
var forms = forms || {};
/**
* Enum of all input types (for INPUT, BUTTON, SELECT and TEXTAREA elements)
* specified by the W3C HTML4.01 and HTML5 specifications.
*
* @enum {string}
*/
forms.InputType = {
BUTTON: 'button',
CHECKBOX: 'checkbox',
COLOR: 'color',
DATE: 'date',
DATETIME: 'datetime',
DATETIME_LOCAL: 'datetime-local',
EMAIL: 'email',
FILE: 'file',
HIDDEN: 'hidden',
IMAGE: 'image',
MENU: 'menu',
MONTH: 'month',
NUMBER: 'number',
PASSWORD: 'password',
RADIO: 'radio',
RANGE: 'range',
RESET: 'reset',
SEARCH: 'search',
SELECT_MULTIPLE: 'select-multiple',
SELECT_ONE: 'select-one',
SUBMIT: 'submit',
TEL: 'tel',
TEXT: 'text',
TEXTAREA: 'textarea',
TIME: 'time',
URL: 'url',
WEEK: 'week'
};
/**
* Whether the form has a file input.
*
* @param {HTMLFormElement} form The form.
* @return {boolean} Whether the form has a file input.
*/
forms.hasFileInput = function(form) {
var els = form.elements;
for (var el, i = 0; el = els[i]; i++) {
if (!el.disabled && el.type &&
el.type.toLowerCase() == forms.InputType.FILE) {
return true;
}
}
return false;
};
/**
* Enables or disables either all elements in a form or a single form element.
*
* @param {Element} el The element, either a form or an element within a form.
* @param {boolean} disabled Whether the element should be disabled.
*/
forms.setDisabled = function(el, disabled) {
// disable all elements in a form
if (el.tagName == "FORM") {
var els = /** @type {!HTMLFormElement} */ (el).elements;
for (var i = 0; (el = els.item(i)); i++) {
forms.setDisabled(el, disabled);
}
} else {
// makes sure to blur buttons, multi-selects, and any elements which
// maintain keyboard/accessibility focus when disabled
if (disabled == true) {
el.blur();
}
el.disabled = disabled;
}
};
/**
* Focuses, and optionally selects the content of, a form element.
*
* @param {Element} el The form element.
*/
forms.focusAndSelect = function(el) {
el.focus();
if (el.select) {
el.select();
}
};
/**
* Whether a form element has a value.
*
* @param {Element} el The element.
* @return {boolean} Whether the form has a value.
*/
forms.hasValue = function(el) {
var value = forms.getValue(el);
return !!value;
};
/**
* Whether a named form field has a value.
*
* @param {HTMLFormElement} form The form element.
* @param {string} name Name of an input to the form.
* @return {boolean} Whether the form has a value.
*/
forms.hasValueByName = function(form, name) {
var value = forms.getValueByName(form, name);
return !!value;
};
/**
* Gets the current value of any element with a type.
*
* @param {null|!Element|!RadioNodeList<?>} input The element.
* @return {string|Array<string>|null} The current value of the element (or null).
*/
forms.getValue = function(input) {
// Elements with a type may need more specialized logic.
var type = /** {{type: (string|undefined)}} */ input.type;
if (typeof type === "string") {
var el = /** @type {!Element} */ (input);
switch (type.toLowerCase()) {
case forms.InputType.CHECKBOX:
case forms.InputType.RADIO:
return forms.getInputChecked_(el);
case forms.InputType.SELECT_ONE:
return forms.getSelectSingle_(el);
case forms.InputType.SELECT_MULTIPLE:
return forms.getSelectMultiple_(el);
default:
// Not every element with a value has a type (e.g. meter and progress).
}
}
// Coerce `undefined` to `null`.
return input.value != null ? input.value : null;
};
/**
* Returns the value of the named form field. In the case of radio buttons,
* returns the value of the checked button with the given name.
*
* @param {HTMLFormElement} form The form element.
* @param {string} name Name of an input to the form.
* @return {Array<string>|string|null} The value of the form element, or null if the form element does not exist or has no value.
*/
forms.getValueByName = function(form, name) {
var els = form.elements[name];
if (!els) {
return null;
} else if (els.type) {
return forms.getValue(/** @type {!Element} */ (els));
} else {
for (var i = 0; i < els.length; i++) {
var val = forms.getValue(els[i]);
if (val) {
return val;
}
}
return null;
}
};
/**
* Gets the current value of a checkable input element.
*
* @param {Element} el The element.
* @return {?string} The value of the form element (or null).
* @private
*/
forms.getInputChecked_ = function(el) {
return el.checked ? /** @type {?} */ (el).value : null;
};
/**
* Gets the current value of a select-one element.
*
* @param {Element} el The element.
* @return {?string} The value of the form element (or null).
* @private
*/
forms.getSelectSingle_ = function(el) {
var selectedIndex = /** @type {!HTMLSelectElement} */ (el).selectedIndex;
return selectedIndex >= 0
? /** @type {!HTMLSelectElement} */ (el).options[selectedIndex].value
: null;
};
/**
* Gets the current value of a select-multiple element.
*
* @param {Element} el The element.
* @return {Array<string>?} The value of the form element (or null).
* @private
*/
forms.getSelectMultiple_ = function(el) {
var values = [];
for (var option, i = 0;
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
if (option.selected) {
values.push(option.value);
}
}
return values.length ? values : null;
};
/**
* Sets a checkable input element's checked property.
*
* #TODO(user): This seems potentially unintuitive since it doesn't set
* the value property but my hunch is that the primary use case is to check a
* checkbox, not to reset its value property.
*
* @param {Element} el The element.
* @param {string|boolean=} opt_value The value, sets the element checked if val is set.
* @private
*/
forms.setInputChecked_ = function(el, opt_value) {
el.checked = opt_value;
};
/**
* Sets the value of a select-one element.
*
* @param {Element} el The element.
* @param {string=} opt_value The value of the selected option element.
* @private
*/
forms.setSelectSingle_ = function(el, opt_value) {
// unset any prior selections
el.selectedIndex = -1;
if (typeof opt_value === "string") {
for (var option, i = 0;
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
if (option.value == opt_value) {
option.selected = true;
break;
}
}
}
};
/**
* Sets the value of a select-multiple element.
*
* @param {Element} el The element.
* @param {Array<string>|string=} opt_value The value of the selected option element(s).
* @private
*/
forms.setSelectMultiple_ = function(el, opt_value) {
// reset string opt_values as an array
if (typeof opt_value === "string") {
opt_value = [opt_value];
}
for (var option, i = 0;
option = /** @type {!HTMLSelectElement} */ (el).options[i]; i++) {
// we have to reset the other options to false for select-multiple
option.selected = false;
if (opt_value) {
for (var value, j = 0; value = opt_value[j]; j++) {
if (option.value == value) {
option.selected = true;
}
}
}
}
};