dustinlarimer
7 years ago
6 changed files with 518 additions and 26 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,263 @@ |
|||
/* |
|||
This is a modified copy of https://github.com/defunctzombie/form-serialize/ v0.7.1
|
|||
Includes a new configuration option: |
|||
* ignoreTypes - Array, Default: [], Example: [ 'password' ] |
|||
*/ |
|||
|
|||
// types which indicate a submit action and are not successful controls
|
|||
// these will be ignored
|
|||
var k_r_submitter = /^(?:submit|button|image|reset|file)$/i; |
|||
|
|||
// node names which could be successful controls
|
|||
var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i; |
|||
|
|||
// Matches bracket notation.
|
|||
var brackets = /(\[[^\[\]]*\])/g; |
|||
|
|||
// serializes form fields
|
|||
// @param form MUST be an HTMLForm element
|
|||
// @param options is an optional argument to configure the serialization. Default output
|
|||
// with no options specified is a url encoded string
|
|||
// - hash: [true | false] Configure the output type. If true, the output will
|
|||
// be a js object.
|
|||
// - serializer: [function] Optional serializer function to override the default one.
|
|||
// The function takes 3 arguments (result, key, value) and should return new result
|
|||
// hash and url encoded str serializers are provided with this module
|
|||
// - disabled: [true | false]. If true serialize disabled fields.
|
|||
// - empty: [true | false]. If true serialize empty fields
|
|||
function serialize(form, options) { |
|||
if (typeof options != 'object') { |
|||
options = { hash: !!options }; |
|||
} |
|||
else if (options.hash === undefined) { |
|||
options.hash = true; |
|||
} |
|||
|
|||
var result = (options.hash) ? {} : ''; |
|||
var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize); |
|||
|
|||
var elements = form && form.elements ? form.elements : []; |
|||
|
|||
// Object store each radio and set if it's empty or not
|
|||
var radio_store = Object.create(null); |
|||
|
|||
for (var i=0 ; i<elements.length ; ++i) { |
|||
var element = elements[i]; |
|||
|
|||
// NEW: Skip ignored field types
|
|||
if (options.ignoreTypes && options.ignoreTypes.indexOf(element.type) > -1) { |
|||
continue; |
|||
} |
|||
// ingore disabled fields
|
|||
if ((!options.disabled && element.disabled) || !element.name) { |
|||
continue; |
|||
} |
|||
// ignore anyhting that is not considered a success field
|
|||
if (!k_r_success_contrls.test(element.nodeName) || |
|||
k_r_submitter.test(element.type)) { |
|||
continue; |
|||
} |
|||
|
|||
var key = element.name; |
|||
var val = element.value; |
|||
|
|||
// we can't just use element.value for checkboxes cause some browsers lie to us
|
|||
// they say "on" for value when the box isn't checked
|
|||
if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) { |
|||
val = undefined; |
|||
} |
|||
|
|||
// If we want empty elements
|
|||
if (options.empty) { |
|||
if (element.type === 'checkbox' && !element.checked) { |
|||
val = ''; |
|||
} |
|||
|
|||
// for radio
|
|||
if (element.type === 'radio') { |
|||
if (!radio_store[element.name] && !element.checked) { |
|||
radio_store[element.name] = false; |
|||
} |
|||
else if (element.checked) { |
|||
radio_store[element.name] = true; |
|||
} |
|||
} |
|||
|
|||
// if options empty is true, continue only if its radio
|
|||
if (val == undefined && element.type == 'radio') { |
|||
continue; |
|||
} |
|||
} |
|||
else { |
|||
// value-less fields are ignored unless options.empty is true
|
|||
if (!val) { |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
// multi select boxes
|
|||
if (element.type === 'select-multiple') { |
|||
val = []; |
|||
|
|||
var selectOptions = element.options; |
|||
var isSelectedOptions = false; |
|||
for (var j=0 ; j<selectOptions.length ; ++j) { |
|||
var option = selectOptions[j]; |
|||
var allowedEmpty = options.empty && !option.value; |
|||
var hasValue = (option.value || allowedEmpty); |
|||
if (option.selected && hasValue) { |
|||
isSelectedOptions = true; |
|||
|
|||
// If using a hash serializer be sure to add the
|
|||
// correct notation for an array in the multi-select
|
|||
// context. Here the name attribute on the select element
|
|||
// might be missing the trailing bracket pair. Both names
|
|||
// "foo" and "foo[]" should be arrays.
|
|||
if (options.hash && key.slice(key.length - 2) !== '[]') { |
|||
result = serializer(result, key + '[]', option.value); |
|||
} |
|||
else { |
|||
result = serializer(result, key, option.value); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (!isSelectedOptions && options.empty) { |
|||
result = serializer(result, key, ''); |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
result = serializer(result, key, val); |
|||
} |
|||
|
|||
if (options.empty) { |
|||
for (var key in radio_store) { |
|||
if (!radio_store[key]) { |
|||
result = serializer(result, key, ''); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
function parse_keys(string) { |
|||
var keys = []; |
|||
var prefix = /^([^\[\]]*)/; |
|||
var children = new RegExp(brackets); |
|||
var match = prefix.exec(string); |
|||
|
|||
if (match[1]) { |
|||
keys.push(match[1]); |
|||
} |
|||
|
|||
while ((match = children.exec(string)) !== null) { |
|||
keys.push(match[1]); |
|||
} |
|||
|
|||
return keys; |
|||
} |
|||
|
|||
function hash_assign(result, keys, value) { |
|||
if (keys.length === 0) { |
|||
result = value; |
|||
return result; |
|||
} |
|||
|
|||
var key = keys.shift(); |
|||
var between = key.match(/^\[(.+?)\]$/); |
|||
|
|||
if (key === '[]') { |
|||
result = result || []; |
|||
|
|||
if (Array.isArray(result)) { |
|||
result.push(hash_assign(null, keys, value)); |
|||
} |
|||
else { |
|||
// This might be the result of bad name attributes like "[][foo]",
|
|||
// in this case the original `result` object will already be
|
|||
// assigned to an object literal. Rather than coerce the object to
|
|||
// an array, or cause an exception the attribute "_values" is
|
|||
// assigned as an array.
|
|||
result._values = result._values || []; |
|||
result._values.push(hash_assign(null, keys, value)); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// Key is an attribute name and can be assigned directly.
|
|||
if (!between) { |
|||
result[key] = hash_assign(result[key], keys, value); |
|||
} |
|||
else { |
|||
var string = between[1]; |
|||
// +var converts the variable into a number
|
|||
// better than parseInt because it doesn't truncate away trailing
|
|||
// letters and actually fails if whole thing is not a number
|
|||
var index = +string; |
|||
|
|||
// If the characters between the brackets is not a number it is an
|
|||
// attribute name and can be assigned directly.
|
|||
if (isNaN(index)) { |
|||
result = result || {}; |
|||
result[string] = hash_assign(result[string], keys, value); |
|||
} |
|||
else { |
|||
result = result || []; |
|||
result[index] = hash_assign(result[index], keys, value); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// Object/hash encoding serializer.
|
|||
function hash_serializer(result, key, value) { |
|||
var matches = key.match(brackets); |
|||
|
|||
// Has brackets? Use the recursive assignment function to walk the keys,
|
|||
// construct any missing objects in the result tree and make the assignment
|
|||
// at the end of the chain.
|
|||
if (matches) { |
|||
var keys = parse_keys(key); |
|||
hash_assign(result, keys, value); |
|||
} |
|||
else { |
|||
// Non bracket notation can make assignments directly.
|
|||
var existing = result[key]; |
|||
|
|||
// If the value has been assigned already (for instance when a radio and
|
|||
// a checkbox have the same name attribute) convert the previous value
|
|||
// into an array before pushing into it.
|
|||
//
|
|||
// NOTE: If this requirement were removed all hash creation and
|
|||
// assignment could go through `hash_assign`.
|
|||
if (existing) { |
|||
if (!Array.isArray(existing)) { |
|||
result[key] = [ existing ]; |
|||
} |
|||
|
|||
result[key].push(value); |
|||
} |
|||
else { |
|||
result[key] = value; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
// urlform encoding serializer
|
|||
function str_serialize(result, key, value) { |
|||
// encode newlines as \r\n cause the html spec says so
|
|||
value = value.replace(/(\r)?\n/g, '\r\n'); |
|||
value = encodeURIComponent(value); |
|||
|
|||
// spaces should be '+' rather than '%20'.
|
|||
value = value.replace(/%20/g, '+'); |
|||
return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value; |
|||
} |
|||
|
|||
module.exports = serialize; |
@ -0,0 +1,59 @@ |
|||
var assert = require('proclaim'); |
|||
|
|||
var serializeForm = require('../../../../lib/utils/serializeForm'); |
|||
|
|||
var ELEMENT_ID = 'test-serialize-form'; |
|||
var INPUT_NAME = 'email'; |
|||
var INPUT_VALUE = 'team@keen.io'; |
|||
var PASSWORD_NAME = 'password'; |
|||
var PASSWORD_VALUE = 'password'; |
|||
|
|||
describe('Keen.utils.serializeForm', function() { |
|||
|
|||
beforeEach(function(){ |
|||
var el = document.createElement('FORM'); |
|||
el.id = ELEMENT_ID; |
|||
el.action = './'; |
|||
el.method = 'POST'; |
|||
document.body.appendChild(el); |
|||
this.form = document.getElementById(ELEMENT_ID); |
|||
|
|||
var input = document.createElement('INPUT'); |
|||
input.name = INPUT_NAME; |
|||
input.type = 'text'; |
|||
input.value = INPUT_VALUE; |
|||
this.form.appendChild(input); |
|||
|
|||
var password = document.createElement('INPUT'); |
|||
password.name = PASSWORD_NAME; |
|||
password.type = 'password'; |
|||
password.value = PASSWORD_VALUE; |
|||
this.form.appendChild(password); |
|||
}); |
|||
|
|||
afterEach(function(){ |
|||
this.form.outerHTML = ''; |
|||
}); |
|||
|
|||
it('should be a function', function() { |
|||
assert.isFunction(serializeForm); |
|||
}); |
|||
|
|||
it('should accept a FORM element and return an object', function() { |
|||
var serialized = serializeForm(this.form, { hash: true }); |
|||
assert.isObject(serialized); |
|||
assert.ok(serialized.email); |
|||
assert.ok(serialized.password); |
|||
}); |
|||
|
|||
it('should omit fields by type (password example)', function() { |
|||
var serialized = serializeForm(this.form, { |
|||
hash: true, |
|||
ignoreTypes: ['password'] |
|||
}); |
|||
assert.isObject(serialized); |
|||
assert.ok(serialized.email); |
|||
assert.notOk(serialized.password); |
|||
}); |
|||
|
|||
}); |
Loading…
Reference in new issue