PageSourceSearch

https://webdesigneracademy.com/wp-content/plugins/accessally/resource/frontend/js/jquery.csv.js?ver=4.9.4

js webdesigneracademy.com collected 2026-10-03 23:43:22 UTC 31,913 bytes, 975 lines download raw bytes

1/**
2 * jQuery-csv (jQuery Plugin)
3 *
4 * This document is licensed as free software under the terms of the
5 * MIT License: http://www.opensource.org/licenses/mit-license.php
6 *
7 * Acknowledgements:
8 * The original design and influence to implement this library as a jquery
9 * plugin is influenced by jquery-json (http://code.google.com/p/jquery-json/).
10 * If you're looking to use native JSON.Stringify but want additional backwards
11 * compatibility for browsers that don't support it, I highly recommend you
12 * check it out.
13 *
14 * A special thanks goes out to [email protected] for providing a lot of valuable
15 * feedback to the project including the core for the new FSM
16 * (Finite State Machine) parsers. If you're looking for a stable TSV parser
17 * be sure to take a look at jquery-tsv (http://code.google.com/p/jquery-tsv/).
18
19 * For legal purposes I'll include the "NO WARRANTY EXPRESSED OR IMPLIED.
20 * USE AT YOUR OWN RISK.". Which, in 'layman's terms' means, by using this
21 * library you are accepting responsibility if it breaks your code.
22 *
23 * Legal jargon aside, I will do my best to provide a useful and stable core
24 * that can effectively be built on.
25 *
26 * Copyrighted 2012 by Evan Plaice.
27 */
28
29RegExp.escape= function(s) {
30    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
31};
32
33(function (undefined) {
34  'use strict';
35
36  var $;
37
38  // to keep backwards compatibility
39  if (typeof jQuery !== 'undefined' && jQuery) {
40    $ = jQuery;
41  } else {
42    $ = {};
43  }
44
45
46  /**
47   * jQuery.csv.defaults
48   * Encapsulates the method paramater defaults for the CSV plugin module.
49   */
50
51  $.csv = {
52    defaults: {
53      separator:',',
54      delimiter:'"',
55      headers:true
56    },
57
58    hooks: {
59      castToScalar: function(value, state) {
60        var hasDot = /\./;
61        if (isNaN(value)) {
62          return value;
63        } else {
64          if (hasDot.test(value)) {
65            return parseFloat(value);
66          } else {
67            var integer = parseInt(value);
68            if(isNaN(integer)) {
69              return null;
70            } else {
71              return integer;
72            }
73          }
74        }
75      }
76    },
77
78    parsers: {
79      parse: function(csv, options) {
80        // cache settings
81        var separator = options.separator;
82        var delimiter = options.delimiter;
83
84        // set initial state if it's missing
85        if(!options.state.rowNum) {
86          options.state.rowNum = 1;
87        }
88        if(!options.state.colNum) {
89          options.state.colNum = 1;
90        }
91
92        // clear initial state
93        var data = [];
94        var entry = [];
95        var state = 0;
96        var value = '';
97        var exit = false;
98
99        function endOfEntry() {
100          // reset the state
101          state = 0;
102          value = '';
103
104          // if 'start' hasn't been met, don't output
105          if(options.start && options.state.rowNum < options.start) {
106            // update global state
107            entry = [];
108            options.state.rowNum++;
109            options.state.colNum = 1;
110            return;
111          }
112          
113          if(options.onParseEntry === undefined) {
114            // onParseEntry hook not set
115            data.push(entry);
116          } else {
117            var hookVal = options.onParseEntry(entry, options.state); // onParseEntry Hook
118            // false skips the row, configurable through a hook
119            if(hookVal !== false) {
120              data.push(hookVal);
121            }
122          }
123          //console.log('entry:' + entry);
124          
125          // cleanup
126          entry = [];
127
128          // if 'end' is met, stop parsing
129          if(options.end && options.state.rowNum >= options.end) {
130            exit = true;
131          }
132          
133          // update global state
134          options.state.rowNum++;
135          options.state.colNum = 1;
136        }
137
138        function endOfValue() {
139          if(options.onParseValue === undefined) {
140            // onParseValue hook not set
141            entry.push(value);
142          } else {
143            var hook = options.onParseValue(value, options.state); // onParseValue Hook
144            // false skips the row, configurable through a hook
145            if(hook !== false) {
146              entry.push(hook);
147            }
148          }
149          //console.log('value:' + value);
150          // reset the state
151          value = '';
152          state = 0;
153          // update global state
154          options.state.colNum++;
155        }
156
157        // escape regex-specific control chars
158        var escSeparator = RegExp.escape(separator);
159        var escDelimiter = RegExp.escape(delimiter);
160
161        // compile the regEx str using the custom delimiter/separator
162        var match = /(D|S|\r\n|\n|\r|[^DS\r\n]+)/;
163        var matchSrc = match.source;
164        matchSrc = matchSrc.replace(/S/g, escSeparator);
165        matchSrc = matchSrc.replace(/D/g, escDelimiter);
166        match = new RegExp(matchSrc, 'gm');
167
168        // put on your fancy pants...
169        // process control chars individually, use look-ahead on non-control chars
170        csv.replace(match, function (m0) {
171          if(exit) {
172            return;
173          }
174          switch (state) {
175            // the start of a value
176            case 0:
177              // null last value
178              if (m0 === separator) {
179                value += '';
180                endOfValue();
181                break;
182              }
183              // opening delimiter
184              if (m0 === delimiter) {
185                state = 1;
186                break;
187              }
188              // null last value
189              if (/^(\r\n|\n|\r)$/.test(m0)) {
190                endOfValue();
191                endOfEntry();
192                break;
193              }
194              // un-delimited value
195              value += m0;
196              state = 3;
197              break;
198
199            // delimited input
200            case 1:
201              // second delimiter? check further
202              if (m0 === delimiter) {
203                state = 2;
204                break;
205              }
206              // delimited data
207              value += m0;
208              state = 1;
209              break;
210
211            // delimiter found in delimited input
212            case 2:
213              // escaped delimiter?
214              if (m0 === delimiter) {
215                value += m0;
216                state = 1;
217                break;
218              }
219              // null value
220              if (m0 === separator) {
221                endOfValue();
222                break;
223              }
224              // end of entry
225              if (/^(\r\n|\n|\r)$/.test(m0)) {
226                endOfValue();
227                endOfEntry();
228                break;
229              }
230              // broken paser?
231              throw new Error('CSVDataError: Illegal State [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
232
233            // un-delimited input
234            case 3:
235              // null last value
236              if (m0 === separator) {
237                endOfValue();
238                break;
239              }
240              // end of entry
241              if (/^(\r\n|\n|\r)$/.test(m0)) {
242                endOfValue();
243                endOfEntry();
244                break;
245              }
246              if (m0 === delimiter) {
247              // non-compliant data
248                throw new Error('CSVDataError: Illegal Quote [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
249              }
250              // broken parser?
251              throw new Error('CSVDataError: Illegal Data [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
252            default:
253              // shenanigans
254              throw new Error('CSVDataError: Unknown State [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
255          }
256          //console.log('val:' + m0 + ' state:' + state);
257        });
258
259        // submit the last entry
260        // ignore null last line
261        if(entry.length !== 0) {
262          endOfValue();
263          endOfEntry();
264        }
265
266        return data;
267      },
268
269      // a csv-specific line splitter
270      splitLines: function(csv, options) {
271        // cache settings
272        var separator = options.separator;
273        var delimiter = options.delimiter;
274
275        // set initial state if it's missing
276        if(!options.state.rowNum) {
277          options.state.rowNum = 1;
278        }
279
280        // clear initial state
281        var entries = [];
282        var state = 0;
283        var entry = '';
284        var exit = false;
285
286        function endOfLine() {          
287          // reset the state
288          state = 0;
289          
290          // if 'start' hasn't been met, don't output
291          if(options.start && options.state.rowNum < options.start) {
292            // update global state
293            entry = '';
294            options.state.rowNum++;
295            return;
296          }
297          
298          if(options.onParseEntry === undefined) {
299            // onParseEntry hook not set
300            entries.push(entry);
301          } else {
302            var hookVal = options.onParseEntry(entry, options.state); // onParseEntry Hook
303            // false skips the row, configurable through a hook
304            if(hookVal !== false) {
305              entries.push(hookVal);
306            }
307          }
308
309          // cleanup
310          entry = '';
311
312          // if 'end' is met, stop parsing
313          if(options.end && options.state.rowNum >= options.end) {
314            exit = true;
315          }
316          
317          // update global state
318          options.state.rowNum++;
319        }
320
321        // escape regex-specific control chars
322        var escSeparator = RegExp.escape(separator);
323        var escDelimiter = RegExp.escape(delimiter);
324
325        // compile the regEx str using the custom delimiter/separator
326        var match = /(D|S|\n|\r|[^DS\r\n]+)/;
327        var matchSrc = match.source;
328        matchSrc = matchSrc.replace(/S/g, escSeparator);
329        matchSrc = matchSrc.replace(/D/g, escDelimiter);
330        match = new RegExp(matchSrc, 'gm');
331
332        // put on your fancy pants...
333        // process control chars individually, use look-ahead on non-control chars
334        csv.replace(match, function (m0) {
335          if(exit) {
336            return;
337          }
338          switch (state) {
339            // the start of a value/entry
340            case 0:
341              // null value
342              if (m0 === separator) {
343                entry += m0;
344                state = 0;
345                break;
346              }
347              // opening delimiter
348              if (m0 === delimiter) {
349                entry += m0;
350                state = 1;
351                break;
352              }
353              // end of line
354              if (m0 === '\n') {
355                endOfLine();
356                break;
357              }
358              // phantom carriage return
359              if (/^\r$/.test(m0)) {
360                break;
361              }
362              // un-delimit value
363              entry += m0;
364              state = 3;
365              break;
366
367            // delimited input
368            case 1:
369              // second delimiter? check further
370              if (m0 === delimiter) {
371                entry += m0;
372                state = 2;
373                break;
374              }
375              // delimited data
376              entry += m0;
377              state = 1;
378              break;
379
380            // delimiter found in delimited input
381            case 2:
382              // escaped delimiter?
383              var prevChar = entry.substr(entry.length - 1);
384              if (m0 === delimiter && prevChar === delimiter) {
385                entry += m0;
386                state = 1;
387                break;
388              }
389              // end of value
390              if (m0 === separator) {
391                entry += m0;
392                state = 0;
393                break;
394              }
395              // end of line
396              if (m0 === '\n') {
397                endOfLine();
398                break;
399              }
400              // phantom carriage return
401              if (m0 === '\r') {
402                break;
403              }
404              // broken paser?
405              throw new Error('CSVDataError: Illegal state [Row:' + options.state.rowNum + ']');
406
407            // un-delimited input
408            case 3:
409              // null value
410              if (m0 === separator) {
411                entry += m0;
412                state = 0;
413                break;
414              }
415              // end of line
416              if (m0 === '\n') {
417                endOfLine();
418                break;
419              }
420              // phantom carriage return
421              if (m0 === '\r') {
422                break;
423              }
424              // non-compliant data
425              if (m0 === delimiter) {
426                throw new Error('CSVDataError: Illegal quote [Row:' + options.state.rowNum + ']');
427              }
428              // broken parser?
429              throw new Error('CSVDataError: Illegal state [Row:' + options.state.rowNum + ']');
430            default:
431              // shenanigans
432              throw new Error('CSVDataError: Unknown state [Row:' + options.state.rowNum + ']');
433          }
434          //console.log('val:' + m0 + ' state:' + state);
435        });
436
437        // submit the last entry
438        // ignore null last line
439        if(entry !== '') {
440          endOfLine();
441        }
442
443        return entries;
444      },
445
446      // a csv entry parser
447      parseEntry: function(csv, options) {
448        // cache settings
449        var separator = options.separator;
450        var delimiter = options.delimiter;
451        
452        // set initial state if it's missing
453        if(!options.state.rowNum) {
454          options.state.rowNum = 1;
455        }
456        if(!options.state.colNum) {
457          options.state.colNum = 1;
458        }
459
460        // clear initial state
461        var entry = [];
462        var state = 0;
463        var value = '';
464
465        function endOfValue() {
466          if(options.onParseValue === undefined) {
467            // onParseValue hook not set
468            entry.push(value);
469          } else {
470            var hook = options.onParseValue(value, options.state); // onParseValue Hook
471            // false skips the value, configurable through a hook
472            if(hook !== false) {
473              entry.push(hook);
474            }
475          }
476          // reset the state
477          value = '';
478          state = 0;
479          // update global state
480          options.state.colNum++;
481        }
482
483        // checked for a cached regEx first
484        if(!options.match) {
485          // escape regex-specific control chars
486          var escSeparator = RegExp.escape(separator);
487          var escDelimiter = RegExp.escape(delimiter);
488          
489          // compile the regEx str using the custom delimiter/separator
490          var match = /(D|S|\n|\r|[^DS\r\n]+)/;
491          var matchSrc = match.source;
492          matchSrc = matchSrc.replace(/S/g, escSeparator);
493          matchSrc = matchSrc.replace(/D/g, escDelimiter);
494          options.match = new RegExp(matchSrc, 'gm');
495        }
496
497        // put on your fancy pants...
498        // process control chars individually, use look-ahead on non-control chars
499        csv.replace(options.match, function (m0) {
500          switch (state) {
501            // the start of a value
502            case 0:
503              // null last value
504              if (m0 === separator) {
505                value += '';
506                endOfValue();
507                break;
508              }
509              // opening delimiter
510              if (m0 === delimiter) {
511                state = 1;
512                break;
513              }
514              // skip un-delimited new-lines
515              if (m0 === '\n' || m0 === '\r') {
516                break;
517              }
518              // un-delimited value
519              value += m0;
520              state = 3;
521              break;
522
523            // delimited input
524            case 1:
525              // second delimiter? check further
526              if (m0 === delimiter) {
527                state = 2;
528                break;
529              }
530              // delimited data
531              value += m0;
532              state = 1;
533              break;
534
535            // delimiter found in delimited input
536            case 2:
537              // escaped delimiter?
538              if (m0 === delimiter) {
539                value += m0;
540                state = 1;
541                break;
542              }
543              // null value
544              if (m0 === separator) {
545                endOfValue();
546                break;
547              }
548              // skip un-delimited new-lines
549              if (m0 === '\n' || m0 === '\r') {
550                break;
551              }
552              // broken paser?
553              throw new Error('CSVDataError: Illegal State [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
554
555            // un-delimited input
556            case 3:
557              // null last value
558              if (m0 === separator) {
559                endOfValue();
560                break;
561              }
562              // skip un-delimited new-lines
563              if (m0 === '\n' || m0 === '\r') {
564                break;
565              }
566              // non-compliant data
567              if (m0 === delimiter) {
568                throw new Error('CSVDataError: Illegal Quote [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
569              }
570              // broken parser?
571              throw new Error('CSVDataError: Illegal Data [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
572            default:
573              // shenanigans
574              throw new Error('CSVDataError: Unknown State [Row:' + options.state.rowNum + '][Col:' + options.state.colNum + ']');
575          }
576          //console.log('val:' + m0 + ' state:' + state);
577        });
578
579        // submit the last value
580        endOfValue();
581
582        return entry;
583      }
584    },
585
586    helpers: {
587
588      /**
589       * $.csv.helpers.collectPropertyNames(objectsArray)
590       * Collects all unique property names from all passed objects.
591       *
592       * @param {Array} objects Objects to collect properties from.
593       *
594       * Returns an array of property names (array will be empty,
595       * if objects have no own properties).
596       */
597      collectPropertyNames: function (objects) {
598
599        var o, propName, props = [];
600        for (o in objects) {
601          for (propName in objects[o]) {
602            if ((objects[o].hasOwnProperty(propName)) &&
603                (props.indexOf(propName) < 0) && 
604                (typeof objects[o][propName] !== 'function')) {
605
606              props.push(propName);
607            }
608          }
609        }
610        return props;
611      }
612    },
613
614    /**
615     * $.csv.toArray(csv)
616     * Converts a CSV entry string to a javascript array.
617     *
618     * @param {Array} csv The string containing the CSV data.
619     * @param {Object}
619 [options] An object containing user-defined options.
620     * @param {Character} [separator] An override for the separator character. Defaults to a comma(,).
621     * @param {Character} [delimiter] An override for the delimiter character. Defaults to a double-quote(").
622     *
623     * This method deals with simple CSV strings only. It's useful if you only
624     * need to parse a single entry. If you need to parse more than one line,
625     * use $.csv2Array instead.
626     */
627    toArray: function(csv, options, callback) {
628      options = (options !== undefined ? options : {});
629      var config = {};
630      config.callback = ((callback !== undefined && typeof(callback) === 'function') ? callback : false);
631      config.separator = 'separator' in options ? options.separator : $.csv.defaults.separator;
632      config.delimiter = 'delimiter' in options ? options.delimiter : $.csv.defaults.delimiter;
633      var state = (options.state !== undefined ? options.state : {});
634
635      // setup
636      options = {
637        delimiter: config.delimiter,
638        separator: config.separator,
639        onParseEntry: options.onParseEntry,
640        onParseValue: options.onParseValue,
641        state: state
642      };
643
644      var entry = $.csv.parsers.parseEntry(csv, options);
645
646      // push the value to a callback if one is defined
647      if(!config.callback) {
648        return entry;
649      } else {
650        config.callback('', entry);
651      }
652    },
653
654    /**
655     * $.csv.toArrays(csv)
656     * Converts a CSV string to a javascript array.
657     *
658     * @param {String} csv The string containing the raw CSV data.
659     * @param {Object} [options] An object containing user-defined options.
660     * @param {Character} [separator] An override for the separator character. Defaults to a comma(,).
661     * @param {Character} [delimiter] An override for the delimiter character. Defaults to a double-quote(").
662     *
663     * This method deals with multi-line CSV. The breakdown is simple. The first
664     * dimension of the array represents the line (or entry/row) while the second
665     * dimension contains the values (or values/columns).
666     */
667    toArrays: function(csv, options, callback) {
668      options = (options !== undefined ? options : {});
669      var config = {};
670      config.callback = ((callback !== undefined && typeof(callback) === 'function') ? callback : false);
671      config.separator = 'separator' in options ? options.separator : $.csv.defaults.separator;
672      config.delimiter = 'delimiter' in options ? options.delimiter : $.csv.defaults.delimiter;
673
674      // setup
675      var data = [];
676      options = {
677        delimiter: config.delimiter,
678        separator: config.separator,
679        onPreParse: options.onPreParse,
680        onParseEntry: options.onParseEntry,
681        onParseValue: options.onParseValue,
682        onPostParse: options.onPostParse,
683        start: options.start,
684        end: options.end,
685        state: {
686          rowNum: 1,
687          colNum: 1
688        }
689      };
690
691      // onPreParse hook
692      if(options.onPreParse !== undefined) {
693        options.onPreParse(csv, options.state);
694      }
695
696      // parse the data
697      data = $.csv.parsers.parse(csv, options);
698
699      // onPostParse hook
700      if(options.onPostParse !== undefined) {
701        options.onPostParse(data, options.state);
702      }
703
704      // push the value to a callback if one is defined
705      if(!config.callback) {
706        return data;
707      } else {
708        config.callback('', data);
709      }
710    },
711
712    /**
713     * $.csv.toObjects(csv)
714     * Converts a CSV string to a javascript object.
715     * @param {String} csv The string containing the raw CSV data.
716     * @param {Object} [options] An object containing user-defined options.
717     * @param {Character} [separator] An override for the separator character. Defaults to a comma(,).
718     * @param {Character} [delimiter] An override for the delimiter character. Defaults to a double-quote(").
719     * @param {Boolean} [headers] Indicates whether the data contains a header line. Defaults to true.
720     *
721     * This method deals with multi-line CSV strings. Where the headers line is
722     * used as the key for each value per entry.
723     */
724    toObjects: function(csv, options, callback) {
725      options = (options !== undefined ? options : {});
726      var config = {};
727      config.callback = ((callback !== undefined && typeof(callback) === 'function') ? callback : false);
728      config.separator = 'separator' in options ? options.separator : $.csv.defaults.separator;
729      config.delimiter = 'delimiter' in options ? options.delimiter : $.csv.defaults.delimiter;
730      config.headers = 'headers' in options ? options.headers : $.csv.defaults.headers;
731      options.start = 'start' in options ? options.start : 1;
732      
733      // account for headers
734      if(config.headers) {
735        options.start++;
736      }
737      if(options.end && config.headers) {
738        options.end++;
739      }
740
741      // setup
742      var lines = [];
743      var data = [];
744
745      options = {
746        delimiter: config.delimiter,
747        separator: config.separator,
748        onPreParse: options.onPreParse,
749        onParseEntry: options.onParseEntry,
750        onParseValue: options.onParseValue,
751        onPostParse: options.onPostParse,
752        start: options.start,
753        end: options.end,
754        state: {
755          rowNum: 1,
756          colNum: 1
757        },
758        match: false,
759        transform: options.transform
760      };
761
762      // fetch the headers
763      var headerOptions = {
764        delimiter: config.delimiter,
765        separator: config.separator,
766        start: 1,
767        end: 1,
768        state: {
769          rowNum:1,
770          colNum:1
771        }
772      };
773
774      // onPreParse hook
775      if(options.onPreParse !== undefined) {
776        options.onPreParse(csv, options.state);
777      }
778
779      // parse the csv
780      var headerLine = $.csv.parsers.splitLines(csv, headerOptions);
781      var headers = $.csv.toArray(headerLine[0], options);
782
783      // fetch the data
784      lines = $.csv.parsers.splitLines(csv, options);
785
786      // reset the state for re-use
787      options.state.colNum = 1;
788      if(headers){
789        options.state.rowNum = 2;
790      } else {
791        options.state.rowNum = 1;
792      }
793      
794      // convert data to objects
795      for(var i=0, len=lines.length; i<len; i++) {
796        var entry = $.csv.toArray(lines[i], options);
797        var object = {};
798        for(var j=0; j <headers.length; j++) {
799          object[headers[j]] = entry[j];
800        }
801        if (options.transform !== undefined) {
802          data.push(options.transform.call(undefined, object));
803        } else {
804          data.push(object);
805        }
806        
807        // update row state
808        options.state.rowNum++;
809      }
810
811      // onPostParse hook
812      if(options.onPostParse !== undefined) {
813        options.onPostParse(data, options.state);
814      }
815
816      // push the value to a callback if one is defined
817      if(!config.callback) {
818        return data;
819      } else {
820        config.callback('', data);
821      }
822    },
823
824     /**
825     * $.csv.fromArrays(arrays)
826     * Converts a javascript array to a CSV String.
827     *
828     * @param {Array} arrays An array containing an array of CSV entries.
829     * @param {Object}
829 [options] An object containing user-defined options.
830     * @param {Character} [separator] An override for the separator character. Defaults to a comma(,).
831     * @param {Character} [delimiter] An override for the delimiter character. Defaults to a double-quote(").
832     *
833     * This method generates a CSV file from an array of arrays (representing entries).
834     */
835    fromArrays: function(arrays, options, callback) {
836      options = (options !== undefined ? options : {});
837      var config = {};
838      config.callback = ((callback !== undefined && typeof(callback) === 'function') ? callback : false);
839      config.separator = 'separator' in options ? options.separator : $.csv.defaults.separator;
840      config.delimiter = 'delimiter' in options ? options.delimiter : $.csv.defaults.delimiter;
841
842      var output = '',
843          line,
844          lineValues,
845          i, j;
846
847      for (i = 0; i < arrays.length; i++) {
848        line = arrays[i];
849        lineValues = [];
850        for (j = 0; j < line.length; j++) {
851          var strValue = (line[j] === undefined || line[j] === null) ? '' : line[j].toString();
852          if (strValue.indexOf(config.delimiter) > -1) {
853            strValue = strValue.replace(config.delimiter, config.delimiter + config.delimiter);
854          }
855
856          var escMatcher = '\n|\r|S|D';
857          escMatcher = escMatcher.replace('S', config.separator);
858          escMatcher = escMatcher.replace('D', config.delimiter);
859
860          if (strValue.search(escMatcher) > -1) {
861            strValue = config.delimiter + strValue + config.delimiter;
862          }
863          lineValues.push(strValue);
864        }
865        output += lineValues.join(config.separator) + '\r\n';
866      }
867
868      // push the value to a callback if one is defined
869      if(!config.callback) {
870        return output;
871      } else {
872        config.callback('', output);
873      }
874    },
875
876    /**
877     * $.csv.fromObjects(objects)
878     * Converts a javascript dictionary to a CSV string.
879     *
880     * @param {Object} objects An array of objects containing the data.
881     * @param {Object} [options] An object containing user-defined options.
882     * @param {Character} [separator] An override for the separator character. Defaults to a comma(,).
883     * @param {Character} [delimiter] An override for the delimiter character. Defaults to a double-quote(").
884     * @param {Character} [sortOrder] Sort order of columns (named after
885     *   object properties). Use 'alpha' for alphabetic. Default is 'declare',
886     *   which means, that properties will _probably_ appear in order they were
887     *   declared for the object. But without any guarantee.
888     * @param {Character or Array} [manualOrder] Manually order columns. May be
889     * a strin in a same csv format as an output or an array of header names
890     * (array items won't be parsed). All the properties, not present in
891     * `manualOrder` will be appended to the end in accordance with `sortOrder`
892     * option. So the `manualOrder` always takes preference, if present.
893     *
894     * This method generates a CSV file from an array of objects (name:value pairs).
895     * It starts by detecting the headers and adding them as the first line of
896     * the CSV file, followed by a structured dump of the data.
897     */
898    fromObjects: function(objects, options, callback) {
899      options = (options !== undefined ? options : {});
900      var config = {};
901      config.callback = ((callback !== undefined && typeof(callback) === 'function') ? callback : false);
902      config.separator = 'separator' in options ? options.separator : $.csv.defaults.separator;
903      config.delimiter = 'delimiter' in options ? options.delimiter : $.csv.defaults.delimiter;
904      config.headers = 'headers' in options ? options.headers : $.csv.defaults.headers;
905      config.sortOrder = 'sortOrder' in options ? options.sortOrder : 'declare';
906      config.manualOrder = 'manualOrder' in options ? options.manualOrder : [];
907      config.transform = options.transform;
908
909      if (typeof config.manualOrder === 'string') {
910        config.manualOrder = $.csv.toArray(config.manualOrder, config);
911      }
912
913      if (config.transform !== undefined) {
914        var origObjects = objects;
915        objects = [];
916
917        var i;
918        for (i = 0; i < origObjects.length; i++) {
919          objects.push(config.transform.call(undefined, origObjects[i]));
920        }
921      }
922
923      var props = $.csv.helpers.collectPropertyNames(objects);
924
925      if (config.sortOrder === 'alpha') {
926        props.sort();
927      } // else {} - nothing to do for 'declare' order
928
929      if (config.manualOrder.length > 0) {
930
931        var propsManual = [].concat(config.manualOrder);
932        var p;
933        for (p = 0; p < props.length; p++) {
934          if (propsManual.indexOf( props[p] ) < 0) {
935            propsManual.push( props[p] );
936          }
937        }
938        props = propsManual;
939      }
940
941      var o, p, line, output = [], propName;
942      if (config.headers) {
943        output.push(props);
944      }
945
946      for (o = 0; o < objects.length; o++) {
947        line = [];
948        for (p = 0; p < props.length; p++) {
949          propName = props[p];
950          if (propName in objects[o] && typeof objects[o][propName] !== 'function') {
951            line.push(objects[o][propName]);
952          } else {
953            line.push('');
954          }
955        }
956        output.push(line);
957      }
958
959      // push the value to a callback if one is defined
960      return $.csv.fromArrays(output, options, config.callback);
961    }
962  };
963
964  // Maintenance code to maintain backward-compatibility
965  // Will be removed in release 1.0
966  $.csvEntry2Array = $.csv.toArray;
967  $.csv2Array = $.csv.toArrays;
968  $.csv2Dictionary = $.csv.toObjects;
969
970  // CommonJS module is defined
971  if (typeof module !== 'undefined' && module.exports) {
972    module.exports = $.csv;
973  }
974
975}).call( this );

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.