/** * Copyright (c) 2010 Maxim Vasiliev * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * @author Maxim Vasiliev * Date: 19.09.11 * Time: 23:40 */ (function (root, factory) { if (typeof exports !== 'undefined' && typeof module !== 'undefined' && module.exports) { // NodeJS module.exports = factory(); } else if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); } else { // Browser globals root.js2form = factory(); } }(this, function () { "use strict"; var _subArrayRegexp = /^\[\d+?\]/, _subObjectRegexp = /^[a-zA-Z_][a-zA-Z_0-9]*/, _arrayItemRegexp = /\[[0-9]+?\]$/, _lastIndexedArrayRegexp = /(.*)(\[)([0-9]*)(\])$/, _arrayOfArraysRegexp = /\[([0-9]+)\]\[([0-9]+)\]/g, _inputOrTextareaRegexp = /INPUT|TEXTAREA/i; /** * * @param rootNode * @param data * @param delimiter * @param nodeCallback * @param useIdIfEmptyName */ function js2form(rootNode, data, delimiter, nodeCallback, useIdIfEmptyName) { if (arguments.length < 3) delimiter = '.'; if (arguments.length < 4) nodeCallback = null; if (arguments.length < 5) useIdIfEmptyName = false; rootNode = (typeof rootNode == 'string') ? document.getElementById(rootNode) : rootNode; var fieldValues, formFieldsByName; fieldValues = object2array(data); formFieldsByName = getFields(rootNode, useIdIfEmptyName, delimiter, {}, true); for (var i = 0; i < fieldValues.length; i++) { var fieldName = fieldValues[i].name, fieldValue = fieldValues[i].value; if (typeof formFieldsByName[fieldName] != 'undefined') { setValue(formFieldsByName[fieldName], fieldValue); } else if (typeof formFieldsByName[fieldName.replace(_arrayItemRegexp, '[]')] != 'undefined') { setValue(formFieldsByName[fieldName.replace(_arrayItemRegexp, '[]')], fieldValue); } else if (typeof formFieldsByName[fieldName.replace(_arrayItemRegexp, "")] != 'undefined') { setValue(formFieldsByName[fieldName.replace(_arrayItemRegexp, "")], fieldValue); } } } function setValue(field, value) { var children, i, l; if (field instanceof Array) { for(i = 0; i < field.length; i++) { if (field[i].value == value || value === true) field[i].checked = true; } } else if (_inputOrTextareaRegexp.test(field.nodeName)) { field.value = value; } else if (/SELECT/i.test(field.nodeName)) { children = field.getElementsByTagName('option'); for (i = 0,l = children.length; i < l; i++) { if (children[i].value == value) { children[i].selected = true; if (field.multiple) break; } else if (!field.multiple) { children[i].selected = false; } } } } function getFields(rootNode, useIdIfEmptyName, delimiter, arrayIndexes, shouldClean) { if (arguments.length < 4) arrayIndexes = {}; var result = {}, currNode = rootNode.firstChild, name, nameNormalized, subFieldName, i, j, l, options; while (currNode) { name = ''; if (currNode.name && currNode.name != '') { name = currNode.name; } else if (useIdIfEmptyName && currNode.id && currNode.id != '') { name = currNode.id; } if (name == '') { var subFields = getFields(currNode, useIdIfEmptyName, delimiter, arrayIndexes, shouldClean); for (subFieldName in subFields) { if (typeof result[subFieldName] == 'undefined') { result[subFieldName] = subFields[subFieldName]; } else { for (i = 0; i < subFields[subFieldName].length; i++) { result[subFieldName].push(subFields[subFieldName][i]); } } } } else { if (/SELECT/i.test(currNode.nodeName)) { for(j = 0, options = currNode.getElementsByTagName('option'), l = options.length; j < l; j++) { if (shouldClean) { options[j].selected = false; } nameNormalized = normalizeName(name, delimiter, arrayIndexes); result[nameNormalized] = currNode; } } else if (/INPUT/i.test(currNode.nodeName) && /CHECKBOX|RADIO/i.test(currNode.type)) { if(shouldClean) { currNode.checked = false; } nameNormalized = normalizeName(name, delimiter, arrayIndexes); nameNormalized = nameNormalized.replace(_arrayItemRegexp, '[]'); if (!result[nameNormalized]) result[nameNormalized] = []; result[nameNormalized].push(currNode); } else { if (shouldClean) { currNode.value = ''; } nameNormalized = normalizeName(name, delimiter, arrayIndexes); result[nameNormalized] = currNode; } } currNode = currNode.nextSibling; } return result; } /** * Normalizes names of arrays, puts correct indexes (consecutive and ordered by element appearance in HTML) * @param name * @param delimiter * @param arrayIndexes */ function normalizeName(name, delimiter, arrayIndexes) { var nameChunksNormalized = [], nameChunks = name.split(delimiter), currChunk, nameMatches, nameNormalized, currIndex, newIndex, i; name = name.replace(_arrayOfArraysRegexp, '[$1].[$2]'); for (i = 0; i < nameChunks.length; i++) { currChunk = nameChunks[i]; nameChunksNormalized.push(currChunk); nameMatches = currChunk.match(_lastIndexedArrayRegexp); if (nameMatches != null) { nameNormalized = nameChunksNormalized.join(delimiter); currIndex = nameNormalized.replace(_lastIndexedArrayRegexp, '$3'); nameNormalized = nameNormalized.replace(_lastIndexedArrayRegexp, '$1'); if (typeof (arrayIndexes[nameNormalized]) == 'undefined') { arrayIndexes[nameNormalized] = { lastIndex: -1, indexes: {} }; } if (currIndex == '' || typeof arrayIndexes[nameNormalized].indexes[currIndex] == 'undefined') { arrayIndexes[nameNormalized].lastIndex++; arrayIndexes[nameNormalized].indexes[currIndex] = arrayIndexes[nameNormalized].lastIndex; } newIndex = arrayIndexes[nameNormalized].indexes[currIndex]; nameChunksNormalized[nameChunksNormalized.length - 1] = currChunk.replace(_lastIndexedArrayRegexp, '$1$2' + newIndex + '$4'); } } nameNormalized = nameChunksNormalized.join(delimiter); nameNormalized = nameNormalized.replace('].[', ']['); return nameNormalized; } function object2array(obj, lvl) { var result = [], i, name; if (arguments.length == 1) lvl = 0; if (obj == null) { result = [{ name: "", value: null }]; } else if (typeof obj == 'string' || typeof obj == 'number' || typeof obj == 'date' || typeof obj == 'boolean') { result = [ { name: "", value : obj } ]; } else if (obj instanceof Array) { for (i = 0; i < obj.length; i++) { name = "[" + i + "]"; result = result.concat(getSubValues(obj[i], name, lvl + 1)); } } else { for (i in obj) { name = i; result = result.concat(getSubValues(obj[i], name, lvl + 1)); } } return result; } function getSubValues(subObj, name, lvl) { var itemName; var result = [], tempResult = object2array(subObj, lvl + 1), i, tempItem; for (i = 0; i < tempResult.length; i++) { itemName = name; if (_subArrayRegexp.test(tempResult[i].name)) { itemName += tempResult[i].name; } else if (_subObjectRegexp.test(tempResult[i].name)) { itemName += '.' + tempResult[i].name; } tempItem = { name: itemName, value: tempResult[i].value }; result.push(tempItem); } return result; } return js2form; }));