/ajax/libs/jquery.serializeJSON/2.2.0/jquery.serializejson.js
JavaScript | 193 lines | 124 code | 21 blank | 48 comment | 46 complexity | c5efeb768b9fa0e2e2497ef3ea242b89 MD5 | raw file
- /*!
- SerializeJSON jQuery plugin.
- https://github.com/marioizquierdo/jquery.serializeJSON
- version 2.2.0 (May, 2014)
- Copyright (c) 2014 Mario Izquierdo
- Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
- and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
- */
- (function ($) {
- "use strict";
- // jQuery('form').serializeJSON()
- $.fn.serializeJSON = function (options) {
- var serializedObject, formAsArray, keys, value, f, opts;
- f = $.serializeJSON;
- opts = f.optsWithDefaults(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls}
- formAsArray = this.serializeArray(); // array of objects {name, value}
- f.readCheckboxUncheckedValues(formAsArray, this, opts); // add {name, value} of unchecked checkboxes if needed
- serializedObject = {};
- $.each(formAsArray, function (i, input) {
- keys = f.splitInputNameIntoKeysArray(input.name); // "some[deep][key]" => ['some', 'deep', 'key']
- value = f.parseValue(input.value, opts); // string, number, boolean or null
- if (opts.parseWithFunction) value = opts.parseWithFunction(value); // allow for custom parsing
- f.deepSet(serializedObject, keys, value, opts);
- });
- return serializedObject;
- };
- // Use $.serializeJSON as namespace for the auxiliar functions
- // and to define defaults
- $.serializeJSON = {
- defaultOptions: {
- parseNumbers: false, // convert values like "1", "-2.33" to 1, -2.33
- parseBooleans: false, // convert "true", "false" to true, false
- parseNulls: false, // convert "null" to null
- parseAll: false, // all of the above
- parseWithFunction: null, // to use custom parser, a function like: function(val){ return parsed_val; }
- checkboxUncheckedValue: undefined, // to include that value for unchecked checkboxes (instead of ignoring them)
- useIntKeysAsArrayIndex: false // name="foo[2]" value="v" => {foo: [null, null, "v"]}, instead of {foo: ["2": "v"]}
- },
- // Merge options with defaults to get {parseNumbers, parseBoolens, parseNulls, useIntKeysAsArrayIndex}
- optsWithDefaults: function(options) {
- var f, parseAll;
- if (options == null) options = {}; // arg default value = {}
- f = $.serializeJSON;
- parseAll = f.optWithDefaults('parseAll', options);
- return {
- parseNumbers: parseAll || f.optWithDefaults('parseNumbers', options),
- parseBooleans: parseAll || f.optWithDefaults('parseBooleans', options),
- parseNulls: parseAll || f.optWithDefaults('parseNulls', options),
- parseWithFunction: f.optWithDefaults('parseWithFunction', options),
- checkboxUncheckedValue: f.optWithDefaults('checkboxUncheckedValue', options),
- useIntKeysAsArrayIndex: f.optWithDefaults('useIntKeysAsArrayIndex', options)
- }
- },
- optWithDefaults: function(key, options) {
- return (options[key] !== false) && (options[key] !== '') && (options[key] || $.serializeJSON.defaultOptions[key]);
- },
- // Convert the string to a number, boolean or null, depending on the enable option and the string format.
- parseValue: function(str, opts) {
- var value, f;
- f = $.serializeJSON;
- if (opts.parseNumbers && f.isNumeric(str)) return Number(str); // number
- if (opts.parseBooleans && (str === "true" || str === "false")) return str === "true"; // boolean
- if (opts.parseNulls && str == "null") return null; // null
- return str; // otherwise, keep same string
- },
- isObject: function(obj) { return obj === Object(obj); }, // is this variable an object?
- isUndefined: function(obj) { return obj === void 0; }, // safe check for undefined values
- isValidArrayIndex: function(val) { return /^[0-9]+$/.test(String(val)); }, // 1,2,3,4 ... are valid array indexes
- isNumeric: function(obj) { return obj - parseFloat(obj) >= 0; }, // taken from jQuery.isNumeric implementation. Not using jQuery.isNumeric to support old jQuery and Zepto versions
- // Split the input name in programatically readable keys
- // "foo" => ['foo']
- // "[foo]" => ['foo']
- // "foo[inn][bar]" => ['foo', 'inn', 'bar']
- // "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0']
- // "arr[][val]" => ['arr', '', 'val']
- splitInputNameIntoKeysArray: function (name) {
- var keys, last, f;
- f = $.serializeJSON;
- if (f.isUndefined(name)) { throw new Error("ArgumentError: param 'name' expected to be a string, found undefined"); }
- keys = $.map(name.split('['), function (key) {
- last = key[key.length - 1];
- return last === ']' ? key.substring(0, key.length - 1) : key;
- });
- if (keys[0] === '') { keys.shift(); } // "[foo][inn]" should be same as "foo[inn]"
- return keys;
- },
- // Set a value in an object or array, using multiple keys to set in a nested object or array:
- //
- // deepSet(obj, ['foo'], v) // obj['foo'] = v
- // deepSet(obj, ['foo', 'inn'], v) // obj['foo']['inn'] = v // Create the inner obj['foo'] object, if needed
- // deepSet(obj, ['foo', 'inn', '123'], v) // obj['foo']['arr']['123'] = v //
- //
- // deepSet(obj, ['0'], v) // obj['0'] = v
- // deepSet(arr, ['0'], v, {useIntKeysAsArrayIndex: true}) // arr[0] = v
- // deepSet(arr, [''], v) // arr.push(v)
- // deepSet(obj, ['arr', ''], v) // obj['arr'].push(v)
- //
- // arr = [];
- // deepSet(arr, ['', v] // arr => [v]
- // deepSet(arr, ['', 'foo'], v) // arr => [v, {foo: v}]
- // deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}]
- // deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}, {bar: v}]
- //
- deepSet: function (o, keys, value, opts) {
- var key, nextKey, tail, lastIdx, lastVal, f;
- if (opts == null) opts = {};
- f = $.serializeJSON;
- if (f.isUndefined(o)) { throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined"); }
- if (!keys || keys.length === 0) { throw new Error("ArgumentError: param 'keys' expected to be an array with least one element"); }
- key = keys[0];
- // Only one key, then it's not a deepSet, just assign the value.
- if (keys.length === 1) {
- if (key === '') {
- o.push(value); // '' is used to push values into the array (assume o is an array)
- } else {
- o[key] = value; // other keys can be used as object keys or array indexes
- }
- // With more keys is a deepSet. Apply recursively.
- } else {
- nextKey = keys[1];
- // '' is used to push values into the array,
- // with nextKey, set the value into the same object, in object[nextKey].
- // Covers the case of ['', 'foo'] and ['', 'var'] to push the object {foo, var}, and the case of nested arrays.
- if (key === '') {
- lastIdx = o.length - 1; // asume o is array
- lastVal = o[lastIdx];
- if (f.isObject(lastVal) && (f.isUndefined(lastVal[nextKey]) || keys.length > 2)) { // if nextKey is not present in the last object element, or there are more keys to deep set
- key = lastIdx; // then set the new value in the same object element
- } else {
- key = lastIdx + 1; // otherwise, point to set the next index in the array
- }
- }
- // o[key] defaults to object or array, depending if nextKey is an array index (int or '') or an object key (string)
- if (f.isUndefined(o[key])) {
- if (nextKey === '') { // '' is used to push values into the array.
- o[key] = [];
- } else if (opts.useIntKeysAsArrayIndex && f.isValidArrayIndex(nextKey)) { // if 1, 2, 3 ... then use an array, where nextKey is the index
- o[key] = [];
- } else { // for anything else, use an object, where nextKey is going to be the attribute name
- o[key] = {};
- }
- }
- // Recursively set the inner object
- tail = keys.slice(1);
- f.deepSet(o[key], tail, value, opts);
- }
- },
- // Fill the formAsArray object with values for the unchecked checkbox inputs,
- // using the same format as the jquery.serializeArray function.
- // The value of the uncheked values is determined from the opts.checkboxUncheckedValue
- // and/or the data-unchecked-value attribute of the inputs.
- readCheckboxUncheckedValues: function (formAsArray, $form, opts) {
- var selector, $uncheckedCheckboxes, $el, dataUncheckedValue, f;
- if (opts == null) opts = {};
- f = $.serializeJSON;
- selector = 'input[type=checkbox]:not(:checked)';
- $uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
- $uncheckedCheckboxes.each(function (i, el) {
- $el = $(el);
- dataUncheckedValue = $el.attr('data-unckecked-value');
- if(dataUncheckedValue) { // data-unchecked-value has precedence over option opts.checkboxUncheckedValue
- formAsArray.push({name: el.name, value: dataUncheckedValue});
- } else {
- if (!f.isUndefined(opts.checkboxUncheckedValue)) {
- formAsArray.push({name: el.name, value: opts.checkboxUncheckedValue});
- }
- }
- });
- }
- };
- }(window.jQuery || window.Zepto || window.$));