UNPKG

convertionanalytics-tracking

Version:

Track events - custom user actions, clicks, pageviews, purchases.

262 lines (221 loc) 7.88 kB
/* 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 export function serializeForm(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; }