active_admin_csv_import 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
@@ -2,53 +2,79 @@ this.recline = this.recline || {};
|
|
2
2
|
this.recline.Backend = this.recline.Backend || {};
|
3
3
|
this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
4
4
|
|
5
|
+
// Note that provision of jQuery is optional (it is **only** needed if you use fetch on a remote file)
|
5
6
|
(function(my) {
|
7
|
+
"use strict";
|
8
|
+
my.__type__ = 'csv';
|
9
|
+
|
10
|
+
// use either jQuery or Underscore Deferred depending on what is available
|
11
|
+
var Deferred = (typeof jQuery !== "undefined" && jQuery.Deferred) || _.Deferred;
|
12
|
+
|
6
13
|
// ## fetch
|
7
14
|
//
|
8
|
-
// 3 options
|
15
|
+
// fetch supports 3 options depending on the attribute provided on the dataset argument
|
9
16
|
//
|
10
|
-
// 1.
|
11
|
-
// 2.
|
12
|
-
//
|
17
|
+
// 1. `dataset.file`: `file` is an HTML5 file object. This is opened and parsed with the CSV parser.
|
18
|
+
// 2. `dataset.data`: `data` is a string in CSV format. This is passed directly to the CSV parser
|
19
|
+
// 3. `dataset.url`: a url to an online CSV file that is ajax accessible (note this usually requires either local or on a server that is CORS enabled). The file is then loaded using jQuery.ajax and parsed using the CSV parser (NB: this requires jQuery)
|
13
20
|
//
|
14
|
-
// All options generates similar data and
|
21
|
+
// All options generates similar data and use the memory store outcome, that is they return something like:
|
22
|
+
//
|
23
|
+
// <pre>
|
24
|
+
// {
|
25
|
+
// records: [ [...], [...], ... ],
|
26
|
+
// metadata: { may be some metadata e.g. file name }
|
27
|
+
// useMemoryStore: true
|
28
|
+
// }
|
29
|
+
// </pre>
|
15
30
|
my.fetch = function(dataset) {
|
16
|
-
var dfd =
|
31
|
+
var dfd = new Deferred();
|
17
32
|
if (dataset.file) {
|
18
33
|
var reader = new FileReader();
|
19
34
|
var encoding = dataset.encoding || 'UTF-8';
|
20
35
|
reader.onload = function(e) {
|
21
|
-
var
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
useMemoryStore: true
|
28
|
-
});
|
36
|
+
var out = my.extractFields(my.parseCSV(e.target.result, dataset), dataset);
|
37
|
+
out.useMemoryStore = true;
|
38
|
+
out.metadata = {
|
39
|
+
filename: dataset.file.name
|
40
|
+
}
|
41
|
+
dfd.resolve(out);
|
29
42
|
};
|
30
43
|
reader.onerror = function(e) {
|
31
44
|
alert('Failed to load file. Code: ' + e.target.error.code);
|
32
45
|
};
|
33
46
|
reader.readAsText(dataset.file, encoding);
|
34
47
|
} else if (dataset.data) {
|
35
|
-
var
|
36
|
-
|
37
|
-
|
38
|
-
useMemoryStore: true
|
39
|
-
});
|
48
|
+
var out = my.extractFields(my.parseCSV(dataset.data, dataset), dataset);
|
49
|
+
out.useMemoryStore = true;
|
50
|
+
dfd.resolve(out);
|
40
51
|
} else if (dataset.url) {
|
41
|
-
|
42
|
-
var
|
43
|
-
|
44
|
-
|
45
|
-
useMemoryStore: true
|
46
|
-
});
|
52
|
+
jQuery.get(dataset.url).done(function(data) {
|
53
|
+
var out = my.extractFields(my.parseCSV(data, dataset), dataset);
|
54
|
+
out.useMemoryStore = true;
|
55
|
+
dfd.resolve(out);
|
47
56
|
});
|
48
57
|
}
|
49
58
|
return dfd.promise();
|
50
59
|
};
|
51
60
|
|
61
|
+
// Convert array of rows in { records: [ ...] , fields: [ ... ] }
|
62
|
+
// @param {Boolean} noHeaderRow If true assume that first row is not a header (i.e. list of fields but is data.
|
63
|
+
my.extractFields = function(rows, noFields) {
|
64
|
+
if (noFields.noHeaderRow !== true && rows.length > 0) {
|
65
|
+
return {
|
66
|
+
fields: rows[0],
|
67
|
+
records: rows.slice(1)
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
return {
|
71
|
+
records: rows
|
72
|
+
}
|
73
|
+
}
|
74
|
+
};
|
75
|
+
|
76
|
+
// ## parseCSV
|
77
|
+
//
|
52
78
|
// Converts a Comma Separated Values string into an array of arrays.
|
53
79
|
// Each line in the CSV becomes an array.
|
54
80
|
//
|
@@ -56,11 +82,19 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
56
82
|
//
|
57
83
|
// @return The CSV parsed as an array
|
58
84
|
// @type Array
|
59
|
-
//
|
85
|
+
//
|
60
86
|
// @param {String} s The string to convert
|
61
87
|
// @param {Object} options Options for loading CSV including
|
62
|
-
//
|
63
|
-
//
|
88
|
+
// @param {Boolean} [trim=false] If set to True leading and trailing
|
89
|
+
// whitespace is stripped off of each non-quoted field as it is imported
|
90
|
+
// @param {String} [delimiter=','] A one-character string used to separate
|
91
|
+
// fields. It defaults to ','
|
92
|
+
// @param {String} [quotechar='"'] A one-character string used to quote
|
93
|
+
// fields containing special characters, such as the delimiter or
|
94
|
+
// quotechar, or which contain new-line characters. It defaults to '"'
|
95
|
+
//
|
96
|
+
// @param {Integer} skipInitialRows A integer number of rows to skip (default 0)
|
97
|
+
//
|
64
98
|
// Heavily based on uselesscode's JS CSV parser (MIT Licensed):
|
65
99
|
// http://www.uselesscode.org/javascript/csv/
|
66
100
|
my.parseCSV = function(s, options) {
|
@@ -69,8 +103,9 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
69
103
|
|
70
104
|
var options = options || {};
|
71
105
|
var trm = (options.trim === false) ? false : true;
|
72
|
-
var
|
73
|
-
var
|
106
|
+
var delimiter = options.delimiter || ',';
|
107
|
+
var quotechar = options.quotechar || '"';
|
108
|
+
|
74
109
|
var cur = '', // The character we are currently processing.
|
75
110
|
inQuote = false,
|
76
111
|
fieldQuoted = false,
|
@@ -104,7 +139,7 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
104
139
|
cur = s.charAt(i);
|
105
140
|
|
106
141
|
// If we are at a EOF or EOR
|
107
|
-
if (inQuote === false && (cur ===
|
142
|
+
if (inQuote === false && (cur === delimiter || cur === "\n")) {
|
108
143
|
field = processField(field);
|
109
144
|
// Add the current field to the current row
|
110
145
|
row.push(field);
|
@@ -117,8 +152,8 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
117
152
|
field = '';
|
118
153
|
fieldQuoted = false;
|
119
154
|
} else {
|
120
|
-
// If it's not a
|
121
|
-
if (cur !==
|
155
|
+
// If it's not a quotechar, add it to the field buffer
|
156
|
+
if (cur !== quotechar) {
|
122
157
|
field += cur;
|
123
158
|
} else {
|
124
159
|
if (!inQuote) {
|
@@ -126,9 +161,9 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
126
161
|
inQuote = true;
|
127
162
|
fieldQuoted = true;
|
128
163
|
} else {
|
129
|
-
// Next char is
|
130
|
-
if (s.charAt(i + 1) ===
|
131
|
-
field +=
|
164
|
+
// Next char is quotechar, this is an escaped quotechar
|
165
|
+
if (s.charAt(i + 1) === quotechar) {
|
166
|
+
field += quotechar;
|
132
167
|
// Skip the next char
|
133
168
|
i += 1;
|
134
169
|
} else {
|
@@ -145,6 +180,97 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
145
180
|
row.push(field);
|
146
181
|
out.push(row);
|
147
182
|
|
183
|
+
// Expose the ability to discard initial rows
|
184
|
+
if (options.skipInitialRows) out = out.slice(options.skipInitialRows);
|
185
|
+
|
186
|
+
return out;
|
187
|
+
};
|
188
|
+
|
189
|
+
// ## serializeCSV
|
190
|
+
//
|
191
|
+
// Convert an Object or a simple array of arrays into a Comma
|
192
|
+
// Separated Values string.
|
193
|
+
//
|
194
|
+
// Nulls are converted to empty fields and integers or floats are converted to non-quoted numbers.
|
195
|
+
//
|
196
|
+
// @return The array serialized as a CSV
|
197
|
+
// @type String
|
198
|
+
//
|
199
|
+
// @param {Object or Array} dataToSerialize The Object or array of arrays to convert. Object structure must be as follows:
|
200
|
+
//
|
201
|
+
// {
|
202
|
+
// fields: [ {id: .., ...}, {id: ...,
|
203
|
+
// records: [ { record }, { record }, ... ]
|
204
|
+
// ... // more attributes we do not care about
|
205
|
+
// }
|
206
|
+
//
|
207
|
+
// @param {object} options Options for serializing the CSV file including
|
208
|
+
// delimiter and quotechar (see parseCSV options parameter above for
|
209
|
+
// details on these).
|
210
|
+
//
|
211
|
+
// Heavily based on uselesscode's JS CSV serializer (MIT Licensed):
|
212
|
+
// http://www.uselesscode.org/javascript/csv/
|
213
|
+
my.serializeCSV = function(dataToSerialize, options) {
|
214
|
+
var a = null;
|
215
|
+
if (dataToSerialize instanceof Array) {
|
216
|
+
a = dataToSerialize;
|
217
|
+
} else {
|
218
|
+
a = [];
|
219
|
+
var fieldNames = _.pluck(dataToSerialize.fields, 'id');
|
220
|
+
a.push(fieldNames);
|
221
|
+
_.each(dataToSerialize.records, function(record, index) {
|
222
|
+
var tmp = _.map(fieldNames, function(fn) {
|
223
|
+
return record[fn];
|
224
|
+
});
|
225
|
+
a.push(tmp);
|
226
|
+
});
|
227
|
+
}
|
228
|
+
var options = options || {};
|
229
|
+
var delimiter = options.delimiter || ',';
|
230
|
+
var quotechar = options.quotechar || '"';
|
231
|
+
|
232
|
+
var cur = '', // The character we are currently processing.
|
233
|
+
field = '', // Buffer for building up the current field
|
234
|
+
row = '',
|
235
|
+
out = '',
|
236
|
+
i,
|
237
|
+
j,
|
238
|
+
processField;
|
239
|
+
|
240
|
+
processField = function(field) {
|
241
|
+
if (field === null) {
|
242
|
+
// If field is null set to empty string
|
243
|
+
field = '';
|
244
|
+
} else if (typeof field === "string" && rxNeedsQuoting.test(field)) {
|
245
|
+
// Convert string to delimited string
|
246
|
+
field = quotechar + field + quotechar;
|
247
|
+
} else if (typeof field === "number") {
|
248
|
+
// Convert number to string
|
249
|
+
field = field.toString(10);
|
250
|
+
}
|
251
|
+
|
252
|
+
return field;
|
253
|
+
};
|
254
|
+
|
255
|
+
for (i = 0; i < a.length; i += 1) {
|
256
|
+
cur = a[i];
|
257
|
+
|
258
|
+
for (j = 0; j < cur.length; j += 1) {
|
259
|
+
field = processField(cur[j]);
|
260
|
+
// If this is EOR append row to output and flush row
|
261
|
+
if (j === (cur.length - 1)) {
|
262
|
+
row += field;
|
263
|
+
out += row + "\n";
|
264
|
+
row = '';
|
265
|
+
} else {
|
266
|
+
// Add the current field to the current row
|
267
|
+
row += field + delimiter;
|
268
|
+
}
|
269
|
+
// Flush the field buffer
|
270
|
+
field = '';
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
148
274
|
return out;
|
149
275
|
};
|
150
276
|
|
@@ -178,4 +304,4 @@ this.recline.Backend.CSV = this.recline.Backend.CSV || {};
|
|
178
304
|
}
|
179
305
|
|
180
306
|
|
181
|
-
}(this.recline.Backend.CSV));
|
307
|
+
}(this.recline.Backend.CSV));
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_admin_csv_import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &70178438708240 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70178438708240
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: railties
|
27
|
-
requirement: &
|
27
|
+
requirement: &70178438707680 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '3.1'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70178438707680
|
36
36
|
description: CSV import for Active Admin capable of handling CSV files too large to
|
37
37
|
import via direct file upload to Heroku
|
38
38
|
email:
|