1/** 2 * Copyright (c) 2010 Maxim Vasiliev 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 * THE SOFTWARE. 21 * 22 * @author Maxim Vasiliev 23 * Date: 09.09.2010 24 * Time: 19:02:33 25 */ 26 27 28(function (root, factory) 29{ 30 if (typeof define === 'function' && define.amd) 31 { 32 // AMD. Register as an anonymous module. 33 define(factory); 34 } 35 else 36 { 37 // Browser globals 38 root.form2js = factory(); 39 } 40}(this, function () 41{ 42 "use strict"; 43 44 /** 45 * Returns form values represented as Javascript object 46 * "name" attribute defines structure of resulting object 47 * 48 * @param rootNode {Element|String} root form element (or it's id) or array of root elements 49 * @param delimiter {String} structure parts delimiter defaults to '.' 50 * @param skipEmpty {Boolean} should skip empty text values, defaults to true 51 * @param nodeCallback {Function} custom function to get node value 52 * @param useIdIfEmptyName {Boolean} if true value of id attribute of field will be used if name of field is empty 53 */ 54 function form2js(rootNode, delimiter, skipEmpty, nodeCallback, useIdIfEmptyName) 55 { 56 if (typeof skipEmpty == 'undefined' || skipEmpty == null) skipEmpty = true; 57 if (typeof delimiter == 'undefined' || delimiter == null) delimiter = '.'; 58 if (arguments.length < 5) useIdIfEmptyName = false; 59 60 rootNode = typeof rootNode == 'string' ? document.getElementById(rootNode) : rootNode; 61 62 var formValues = [], 63 currNode, 64 i = 0; 65 66 /* If rootNode is array - combine values */ 67 if (rootNode.constructor == Array || (typeof NodeList != "undefined" && rootNode.constructor == NodeList)) 68 { 69 while(currNode = rootNode[i++]) 70 { 71 formValues = formValues.concat(getFormValues(currNode, nodeCallback, useIdIfEmptyName)); 72 } 73 } 74 else 75 { 76 formValues = getFormValues(rootNode, nodeCallback, useIdIfEmptyName); 77 } 78 79 return processNameValues(formValues, skipEmpty, delimiter); 80 } 81 82 /** 83 * Processes collection of { name: 'name', value: 'value' } objects. 84 * @param nameValues 85 * @param skipEmpty if true skips elements with value == '' or value == null 86 * @param delimiter 87 */ 88 function processNameValues(nameValues, skipEmpty, delimiter) 89 { 90 var result = {}, 91 arrays = {}, 92 i, j, k, l, 93 value, 94 nameParts, 95 currResult, 96 arrNameFull, 97 arrName, 98 arrIdx, 99 namePart, 100 name, 101 _nameParts; 102 103 for (i = 0; i < nameValues.length; i++) 104 { 105 value = nameValues[i].value; 106 107 if (skipEmpty && (value === '' || value === null)) continue; 108 109 name = nameValues[i].name; 110 _nameParts = name.split(delimiter); 111 nameParts = []; 112 currResult = result; 113 arrNameFull = ''; 114 115 for(j = 0; j < _nameParts.length; j++) 116 { 117 namePart = _nameParts[j].split(']['); 118 if (namePart.length > 1) 119 { 120 for(k = 0; k < namePart.length; k++) 121 { 122 if (k == 0) 123 { 124 namePart[k] = namePart[k] + ']'; 125 } 126 else if (k == namePart.length - 1) 127 { 128 namePart[k] = '[' + namePart[k]; 129 } 130 else 131 { 132 namePart[k] = '[' + namePart[k] + ']'; 133 } 134 135 arrIdx = namePart[k].match(/([a-z_]+)?\[([a-z_][a-z0-9_]+?)\]/i); 136 if (arrIdx) 137 { 138 for(l = 1; l < arrIdx.length; l++) 139 { 140 if (arrIdx[l]) nameParts.push(arrIdx[l]); 141 } 142 } 143 else{ 144 nameParts.push(namePart[k]); 145 } 146 } 147 } 148 else
149 nameParts = nameParts.concat(namePart); 150 } 151 152 for (j = 0; j < nameParts.length; j++) 153 { 154 namePart = nameParts[j]; 155 156 if (namePart.indexOf('[]') > -1 && j == nameParts.length - 1) 157 { 158 arrName = namePart.substr(0, namePart.indexOf('[')); 159 arrNameFull += arrName; 160 161 if (!currResult[arrName]) currResult[arrName] = []; 162 currResult[arrName].push(value); 163 } 164 else if (namePart.indexOf('[') > -1) 165 { 166 arrName = namePart.substr(0, namePart.indexOf('[')); 167 arrIdx = namePart.replace(/(^([a-z_]+)?\[)|(\]$)/gi, ''); 168 169 /* Unique array name */ 170 arrNameFull += '_' + arrName + '_' + arrIdx; 171 172 /* 173 * Because arrIdx in field name can be not zero-based and step can be 174 * other than 1, we can't use them in target array directly. 175 * Instead we're making a hash where key is arrIdx and value is a reference to 176 * added array element 177 */ 178 179 if (!arrays[arrNameFull]) arrays[arrNameFull] = {}; 180 if (arrName != '' && !currResult[arrName]) currResult[arrName] = []; 181 182 if (j == nameParts.length - 1) 183 { 184 if (arrName == '') 185 { 186 currResult.push(value); 187 arrays[arrNameFull][arrIdx] = currResult[currResult.length - 1]; 188 } 189 else 190 { 191 currResult[arrName].push(value); 192 arrays[arrNameFull][arrIdx] = currResult[arrName][currResult[arrName].length - 1]; 193 } 194 } 195 else 196 { 197 if (!arrays[arrNameFull][arrIdx]) 198 { 199 if ((/^[a-z_]+\[?/i).test(nameParts[j+1])) currResult[arrName].push({}); 200 else currResult[arrName].push([]); 201 202 arrays[arrNameFull][arrIdx] = currResult[arrName][currResult[arrName].length - 1]; 203 } 204 } 205 206 currResult = arrays[arrNameFull][arrIdx]; 207 } 208 else 209 { 210 arrNameFull += namePart; 211 212 if (j < nameParts.length - 1) /* Not the last part of name - means object */ 213 { 214 if (!currResult[namePart]) currResult[namePart] = {}; 215 currResult = currResult[namePart]; 216 } 217 else 218 { 219 currResult[namePart] = value; 220 } 221 } 222 } 223 } 224 225 return result; 226 } 227 228 function getFormValues(rootNode, nodeCallback, useIdIfEmptyName) 229 { 230 var result = extractNodeValues(rootNode, nodeCallback, useIdIfEmptyName); 231 return result.length > 0 ? result : getSubFormValues(rootNode, nodeCallback, useIdIfEmptyName); 232 } 233 234 function getSubFormValues(rootNode, nodeCallback, useIdIfEmptyName) 235 { 236 var result = [], 237 currentNode = rootNode.firstChild; 238 239 while (currentNode) 240 { 241 result = result.concat(extractNodeValues(currentNode, nodeCallback, useIdIfEmptyName)); 242 currentNode = currentNode.nextSibling; 243 } 244 245 return result; 246 } 247 248 function extractNodeValues(node, nodeCallback, useIdIfEmptyName) { 249 var callbackResult, fieldValue, result, fieldName = getFieldName(node, useIdIfEmptyName); 250 251 callbackResult = nodeCallback && nodeCallback(node); 252 253 if (callbackResult && callbackResult.name) { 254 result = [callbackResult]; 255 } 256 else if (fieldName != '' && node.nodeName.match(/INPUT|TEXTAREA/i)) { 257 fieldValue = getFieldValue(node); 258 result = [ { name: fieldName, value: fieldValue} ]; 259 } 260 else if (fieldName != '' && node.nodeName.match(/SELECT/i)) { 261 fieldValue = getFieldValue(node); 262 result = [ { name: fieldName.replace(/\[\]$/, ''), value: fieldValue } ]; 263 } 264 else { 265 result = getSubFormValues(node, nodeCallback, useIdIfEmptyName); 266 } 267 268 return result; 269 } 270 271 function getFieldName(node, useIdIfEmptyName) 272 { 273 if (node.name && node.name != '') return node.name; 274 else if (useIdIfEmptyName && node.id && node.id != '') return node.id; 275 else return ''; 276 } 277 278 279 function getFieldValue(fieldNode) 280 { 281 if (fieldNode.disabled) return null; 282 283 switch (fieldNode.nodeName) { 284 case 'INPUT': 285 case 'TEXTAREA': 286 switch (fieldNode.type.toLowerCase()) { 287 case 'radio': 288 if (fieldNode.checked && fieldNode.value === "false") return false; 289 case 'checkbox': 290 if (fieldNode.checked && fieldNode.value === "true") return true; 291 if (!fieldNode.checked && fieldNode.value === "true") return false;
292 if (fieldNode.checked) return fieldNode.value; 293 break; 294 295 case 'button': 296 case 'reset': 297 case 'submit': 298 case 'image': 299 return ''; 300 break; 301 302 default: 303 return fieldNode.value; 304 break; 305 } 306 break; 307 308 case 'SELECT': 309 return getSelectedOptionValue(fieldNode); 310 break; 311 312 default: 313 break; 314 } 315 316 return null; 317 } 318 319 function getSelectedOptionValue(selectNode) 320 { 321 var multiple = selectNode.multiple, 322 result = [], 323 options, 324 i, l; 325 326 if (!multiple) return selectNode.value; 327 328 for (options = selectNode.getElementsByTagName("option"), i = 0, l = options.length; i < l; i++) 329 { 330 if (options[i].selected) result.push(options[i].value); 331 } 332 333 return result; 334 } 335 336 return form2js; 337 338}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.