corrade-nucleus-nucleons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 (function (window, document, undefined) {
2 'use strict';
3  
4 var formToObject = function () {
5  
6 if (!(this instanceof formToObject)) {
7 var test = new formToObject(); // jscs:ignore requireCapitalizedConstructors
8 return test.init.call(test, Array.prototype.slice.call(arguments));
9 }
10  
11 /**
12 * Defaults
13 */
14  
15 var formRef = null;
16  
17 // Experimental. Don't rely on them yet.
18 var settings = {
19 includeEmptyValuedElements: false,
20 w3cSuccessfulControlsOnly: false
21 };
22  
23 // Currently matching only '[]'.
24 var keyRegex = /[^\[\]]+|\[\]/g;
25 var $form = null;
26 var $formElements = [];
27  
28 /**
29 * Private methods
30 */
31  
32 /**
33 * Check to see if the object is a HTML node.
34 *
35 * @param {object} node
36 * @returns {boolean}
37 */
38 function isDomElementNode(node) {
39 return !!(node &&
40 typeof node === 'object' &&
41 'nodeType' in node &&
42 node.nodeType === 1);
43 }
44  
45 /**
46 * Check for last numeric key.
47 *
48 * @param o object
49 * @return mixed (string|undefined)
50 */
51 function checkForLastNumericKey(o) {
52 if (!o || typeof o !== 'object') {
53 return undefined;
54 }
55  
56 return Object.keys(o).filter(function (elem) {
57 return !isNaN(parseInt(elem, 10));
58 }).splice(-1)[0];
59 }
60  
61 /**
62 * Get last numeric key from an object.
63 * @param o object
64 * @return int
65 */
66 function getLastIntegerKey(o) {
67 var lastKeyIndex = checkForLastNumericKey(o);
68 if (typeof lastKeyIndex === 'string') {
69 return parseInt(lastKeyIndex, 10);
70 } else {
71 return 0;
72 }
73 }
74  
75 /**
76 * Get the next numeric key (like the index from a PHP array)
77 * @param o object
78 * @return int
79 */
80 function getNextIntegerKey(o) {
81 var lastKeyIndex = checkForLastNumericKey(o);
82 if (typeof lastKeyIndex === 'string') {
83 return parseInt(lastKeyIndex, 10) + 1;
84 } else {
85 return 0;
86 }
87 }
88  
89 /**
90 * Get the real number of properties from an object.
91 *
92 * @param {object} o
93 * @returns {number}
94 */
95 function getObjLength(o) {
96 if (typeof o !== 'object' || o === null) {
97 return 0;
98 }
99  
100 var l = 0;
101 var k;
102  
103 if (typeof Object.keys === 'function') {
104 l = Object.keys(o).length;
105 } else {
106 for (k in o) {
107 if (o.hasOwnProperty(k)) {
108 l++;
109 }
110 }
111 }
112  
113 return l;
114 }
115  
116 /**
117 * Simple extend of own properties.
118 * Needed for our settings.
119 *
120 * @param {object} destination The object we want to extend.
121 * @param {object} sources The object with new properties that we want to add the the destination.
122 * @return {object}
123 */
124 function extend(destination, sources) {
125 var i;
126 for (i in sources) {
127 if (sources.hasOwnProperty(i)) {
128 destination[i] = sources[i];
129 }
130 }
131  
132 return destination;
133 }
134  
135 // Iteration through arrays and objects. Compatible with IE.
136 function forEach(arr, callback) {
137 if ([].forEach) {
138 return [].forEach.call(arr, callback);
139 }
140  
141 var i;
142 for (i in arr) {
143 // Using Object.prototype.hasOwnProperty instead of
144 // arr.hasOwnProperty for IE8 compatibility.
145 if (Object.prototype.hasOwnProperty.call(arr, i)) {
146 callback.call(arr, arr[i]);
147 }
148 }
149  
150 return;
151 }
152  
153 // Constructor
154 function init(options) {
155 // Assign the current form reference.
156 if (!options || typeof options !== 'object' || !options[0]) {
157 return false;
158 }
159  
160 // The form reference is always the first parameter of the method.
161 // Eg: formToObject('myForm')
162 formRef = options[0];
163  
164 // Override current settings.
165 // Eg. formToObject('myForm', {mySetting: true})
166 if (typeof options[1] !== 'undefined' && getObjLength(options[1]) > 0) {
167 extend(settings, options[1]);
168 }
169  
170 if (!setForm()) {
171 return false;
172 }
173  
174 if (!setFormElements()) {
175 return false;
176 }
177  
178 return convertToObj();
179 }
180  
181 // Set the main form object we are working on.
182 function setForm() {
183 switch (typeof formRef) {
184 case 'string':
185 $form = document.getElementById(formRef);
186 break;
187  
188 case 'object':
189 if (isDomElementNode(formRef)) {
190 $form = formRef;
191 }
192  
193 break;
194 }
195  
196 return $form;
197 }
198  
199 function isUploadForm() {
200 return ($form.enctype && $form.enctype === 'multipart/form-data' ? true : false);
201 }
202  
203 // Set the elements we need to parse.
204 function setFormElements() {
205 $formElements = $form.querySelectorAll('input, textarea, select');
206 return $formElements.length;
207 }
208  
209 function isRadio($domNode) {
210 return $domNode.nodeName === 'INPUT' && $domNode.type === 'radio';
211 }
212  
213 function isCheckbox($domNode) {
214 return $domNode.nodeName === 'INPUT' && $domNode.type === 'checkbox';
215 }
216  
217 function isFileField($domNode) {
218 return $domNode.nodeName === 'INPUT' && $domNode.type === 'file';
219 }
220  
221 function isTextarea($domNode) {
222 return $domNode.nodeName === 'TEXTAREA';
223 }
224  
225 function isSelectSimple($domNode) {
226 return $domNode.nodeName === 'SELECT' && $domNode.type === 'select-one';
227 }
228  
229 function isSelectMultiple($domNode) {
230 return $domNode.nodeName === 'SELECT' && $domNode.type === 'select-multiple';
231 }
232  
233 function isSubmitButton($domNode) {
234 return $domNode.nodeName === 'BUTTON' && $domNode.type === 'submit';
235 }
236  
237 function isChecked($domNode) {
238 return $domNode.checked;
239 }
240  
241 //function isMultiple($domNode){
242 // return ($domNode.multiple ? true : false);
243 //}
244  
245 function isFileList($domNode) {
246 return (window.FileList && $domNode.files instanceof window.FileList);
247 }
248  
249 function getNodeValues($domNode) {
250 // We're only interested in the radio that is checked.
251 if (isRadio($domNode)) {
252 return isChecked($domNode) ? $domNode.value : false;
253 }
254  
255 // We're only interested in the checkbox that is checked.
256 if (isCheckbox($domNode)) {
257 return isChecked($domNode) ? $domNode.value : false;
258 }
259  
260 // File inputs are a special case.
261 // We have to grab the .files property of the input, which is a FileList.
262 if (isFileField($domNode)) {
263 // Ignore input file fields if the form is not encoded properly.
264 if (isUploadForm()) {
265 // HTML5 compatible browser.
266 if (isFileList($domNode) && $domNode.files.length > 0) {
267 return $domNode.files;
268 } else {
269 return ($domNode.value && $domNode.value !== '' ? $domNode.value : false);
270 }
271 } else {
272 return false;
273 }
274 }
275  
276 // We're only interested in textarea fields that have values.
277 if (isTextarea($domNode)) {
278 return ($domNode.value && $domNode.value !== '' ? $domNode.value : false);
279 }
280  
281 if (isSelectSimple($domNode)) {
282 if ($domNode.value && $domNode.value !== '') {
283 return $domNode.value;
284 } else if ($domNode.options && $domNode.options.length && $domNode.options[0].value !== '') {
285 return $domNode.options[0].value;
286 } else {
287 return false;
288 }
289 }
290  
291 // We're only interested in multiple selects that have at least one option selected.
292 if (isSelectMultiple($domNode)) {
293 if ($domNode.options && $domNode.options.length > 0) {
294 var values = [];
295 forEach($domNode.options, function ($option) {
296 if ($option.selected) {
297 values.push($option.value);
298 }
299 });
300  
301 if (settings.includeEmptyValuedElements) {
302 return values;
303 } else {
304 return (values.length ? values : false);
305 }
306  
307 } else {
308 return false;
309 }
310 }
311  
312 // We're only interested if the button is type="submit"
313 if (isSubmitButton($domNode)) {
314 if ($domNode.value && $domNode.value !== '') {
315 return $domNode.value;
316 }
317  
318 if ($domNode.innerText && $domNode.innerText !== '') {
319 return $domNode.innerText;
320 }
321  
322 return false;
323 }
324  
325 // Fallback or other non special fields.
326 if (typeof $domNode.value !== 'undefined') {
327 if (settings.includeEmptyValuedElements) {
328 return $domNode.value;
329 } else {
330 return ($domNode.value !== '' ? $domNode.value : false);
331 }
332 } else {
333 return false;
334 }
335 }
336  
337 function processSingleLevelNode($domNode, arr, domNodeValue, result) {
338 // Get the last remaining key.
339 var key = arr[0];
340  
341 // We're only interested in the radio that is checked.
342 if (isRadio($domNode)) {
343 if (domNodeValue !== false) {
344 result[key] = domNodeValue;
345 return domNodeValue;
346 } else {
347 return;
348 }
349 }
350  
351 // Checkboxes are a special case.
352 // We have to grab each checked values
353 // and put them into an array.
354 if (isCheckbox($domNode)) {
355 if (domNodeValue !== false) {
356 if (!result[key]) {
357 result[key] = [];
358 }
359  
360 return result[key].push(domNodeValue);
361 } else {
362 return;
363 }
364 }
365  
366 // Multiple select is a special case.
367 // We have to grab each selected option and put them into an array.
368 if (isSelectMultiple($domNode)) {
369 if (domNodeValue !== false) {
370 result[key] = domNodeValue;
371 } else {
372 return;
373 }
374 }
375  
376 // Fallback or other cases that don't
377 // need special treatment of the value.
378 result[key] = domNodeValue;
379  
380 return domNodeValue;
381 }
382  
383 function processMultiLevelNode($domNode, arr, value, result) {
384 var keyName = arr[0];
385  
386 if (arr.length > 1) {
387 if (keyName === '[]') {
388 //result.push({});
389 result[getNextIntegerKey(result)] = {};
390 return processMultiLevelNode(
391 $domNode,
392 arr.splice(1, arr.length),
393 value,
394 result[getLastIntegerKey(result)]
395 );
396 } else {
397 if (result[keyName] && getObjLength(result[keyName]) > 0) {
398 //result[keyName].push(null);
399 return processMultiLevelNode(
400 $domNode,
401 arr.splice(1, arr.length),
402 value,
403 result[keyName]
404 );
405 } else {
406 result[keyName] = {};
407 }
408  
409 return processMultiLevelNode($domNode, arr.splice(1, arr.length), value, result[keyName]);
410 }
411 }
412  
413 // Last key, attach the original value.
414 if (arr.length === 1) {
415 if (keyName === '[]') {
416 //result.push(value);
417 result[getNextIntegerKey(result)] = value;
418 return result;
419 } else {
420 processSingleLevelNode($domNode, arr, value, result);
421  
422 // result[keyName] = value;
423 return result;
424 }
425 }
426 }
427  
428 function convertToObj() {
429 var i = 0;
430 var objKeyNames;
431 var $domNode;
432 var domNodeValue;
433 var result = {};
434 var resultLength;
435  
436 for (i = 0; i < $formElements.length; i++) {
437  
438 $domNode = $formElements[i];
439  
440 // Skip the element if the 'name' attribute is empty.
441 // Skip the 'disabled' elements.
442 // Skip the non selected radio elements.
443 if (!$domNode.name ||
444 $domNode.name === '' ||
445 $domNode.disabled ||
446 (isRadio($domNode) && !isChecked($domNode))
447 ) {
448 continue;
449 }
450  
451 // Get the final processed domNode value.
452 domNodeValue = getNodeValues($domNode);
453  
454 // Exclude empty valued nodes if the settings allow it.
455 if (domNodeValue === false && !settings.includeEmptyValuedElements) {
456 continue;
457 }
458  
459 // Extract all possible keys
460 // Eg. name="firstName", name="settings[a][b]", name="settings[0][a]"
461 objKeyNames = $domNode.name.match(keyRegex);
462  
463 if (objKeyNames.length === 1) {
464 processSingleLevelNode(
465 $domNode,
466 objKeyNames,
467 (domNodeValue ? domNodeValue : ''),
468 result
469 );
470 }
471  
472 if (objKeyNames.length > 1) {
473 processMultiLevelNode(
474 $domNode,
475 objKeyNames,
476 (domNodeValue ? domNodeValue : ''),
477 result
478 );
479 }
480  
481 }
482  
483 // Check the length of the result.
484 resultLength = getObjLength(result);
485  
486 return resultLength > 0 ? result : false;
487 }
488  
489 /**
490 * Expose public methods.
491 */
492 return {
493 init: init
494 };
495  
496 };
497  
498 /**
499 * Expose the final class.
500 * @type Function
501 */
502  
503 if (typeof define === 'function' && define.amd) {
504 // AMD/requirejs: Define the module
505 define(function () {
506 return formToObject;
507 });
508 } else if (typeof module === 'object' && module.exports) {
509 module.exports = formToObject;
510 } else {
511 // Browser: Expose to window
512 window.formToObject = formToObject;
513 }
514  
515 })(window, document);