UNPKG

jquery-deserialize

Version:

Decodes serialized form data and populates the form with that data.

277 lines (241 loc) 7.83 kB
/** * Copyright (C) 2017 Kyle Florence * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * @website https://github.com/kflorence/jquery-deserialize/ * @version 2.0.0-rc1 * * Dual licensed under the MIT and GPLv2 licenses. */ (function( factory ) { if ( typeof module === "object" && module.exports ) { // Node/CommonJS module.exports = factory( require( "jquery" ) ); } else { // Browser globals factory( window.jQuery ); } }(function( $ ) { /** * Updates a key/valueArray with the given property and value. Values will always be stored as arrays. * * @param prop The property to add the value to. * @param value The value to add. * @param obj The object to update. * @returns {object} Updated object. */ function updateKeyValueArray( prop, value, obj ) { var current = obj[ prop ]; if ( current === undefined ) { obj[ prop ] = [ value ]; } else { current.push( value ); } return obj; } /** * Get all of the fields contained within the given elements by name. * * @param $elements jQuery object of elements. * @param filter Custom filter to apply to the list of fields. * @returns {object} All of the fields contained within the given elements, keyed by name. */ function getFieldsByName( $elements, filter ) { var elementsByName = {}; // Extract fields from elements var fields = $elements .map(function convertFormToElements() { return this.elements ? $.makeArray( this.elements ) : this; }) .filter( filter || ":input:not(:disabled)" ) .get(); $.each( fields, function( index, field ) { updateKeyValueArray( field.name, field, elementsByName ); }); return elementsByName; } /** * Figure out the type of an element. Input type will be used first, falling back to nodeName. * * @param element DOM element to check type of. * @returns {string} The element's type. */ function getElementType( element ) { return ( element.type || element.nodeName ).toLowerCase(); } /** * Normalize the provided data into a key/valueArray store. * * @param data The data provided by the user to the plugin. * @returns {object} The data normalized into a key/valueArray store. */ function normalizeData( data ) { var normalized = {}; var rPlus = /\+/g; // Convert data from .serializeObject() notation if ( $.isPlainObject( data ) ) { $.extend( normalized, data ); // Convert non-array values into an array $.each( normalized, function( name, value ) { if ( !$.isArray( value ) ) { normalized[ name ] = [ value ]; } }); // Convert data from .serializeArray() notation } else if ( $.isArray( data ) ) { $.each( data, function( index, field ) { updateKeyValueArray( field.name, field.value, normalized ); }); // Convert data from .serialize() notation } else if ( typeof data === "string" ) { $.each( data.split( "&" ), function( index, field ) { var current = field.split( "=" ); var name = decodeURIComponent( current[ 0 ].replace( rPlus, "%20" ) ); var value = decodeURIComponent( current[ 1 ].replace( rPlus, "%20" ) ); updateKeyValueArray( name, value, normalized ); }); } return normalized; } /** * Map of property name -> element types. * * @type {object} */ var updateTypes = { checked: [ "radio", "checkbox" ], selected: [ "option", "select-one", "select-multiple" ], value: [ "button", "color", "date", "datetime", "datetime-local", "email", "hidden", "month", "number", "password", "range", "reset", "search", "submit", "tel", "text", "textarea", "time", "url", "week" ] }; /** * Get the property to update on an element being updated. * * @param element The DOM element to get the property for. * @returns The name of the property to update if element is supported, otherwise `undefined`. */ function getPropertyToUpdate( element ) { var type = getElementType( element ); var elementProperty = undefined; $.each( updateTypes, function( property, types ) { if ( $.inArray( type, types ) > -1 ) { elementProperty = property; return false; } }); return elementProperty; } /** * Update the element based on the provided data. * * @param element The DOM element to update. * @param elementIndex The index of this element in the list of elements with the same name. * @param value The serialized element value. * @param valueIndex The index of the value in the list of values for elements with the same name. * @param callback A function to call if the value of an element was updated. */ function update( element, elementIndex, value, valueIndex, callback ) { var property = getPropertyToUpdate( element ); // Handle value inputs // If there are multiple value inputs with the same name, they will be populated by matching indexes. if ( property == "value" && elementIndex == valueIndex ) { element.value = value; callback.call( element, value ); // Handle select menus, checkboxes and radio buttons } else if ( property == "checked" || property == "selected" ) { var fields = []; // Extract option fields from select menus if ( element.options ) { $.each( element.options, function( index, option ) { fields.push( option ); }); } else { fields.push( element ); } // #37: Remove selection from multiple select menus before deserialization if ( element.multiple && valueIndex == 0 ) { element.selectedIndex = -1; } $.each( fields, function( index, field ) { if ( field.value == value ) { field[ property ] = true; callback.call( field, value ); } }); } } /** * Default plugin options. * * @type {object} */ var defaultOptions = { change: $.noop, complete: $.noop }; /** * The $.deserialize function. * * @param data The data to deserialize. * @param options Additional options. * @returns {jQuery} The jQuery object that was provided to the plugin. */ $.fn.deserialize = function( data, options ) { // Backwards compatible with old arguments: data, callback if ( $.isFunction( options ) ) { options = { complete: options }; } options = $.extend( defaultOptions, options || {} ); data = normalizeData( data ); var elementsByName = getFieldsByName( this, options.filter ); $.each( data, function( name, values ) { $.each( elementsByName[ name ], function( elementIndex, element ) { $.each( values, function( valueIndex, value ) { update( element, elementIndex, value, valueIndex, options.change ); }); }); }); options.complete.call( this ); return this; }; }));