-
Notifications
You must be signed in to change notification settings - Fork 114
/
Copy pathcommon.js
439 lines (393 loc) · 13 KB
/
common.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/* ==========================================================================
Common application-wide scripts for rural-or-underserved-tool.
========================================================================== */
import { ExpandableGroup } from '@cfpb/cfpb-expandables';
import * as addressUtils from './address-utils.js';
import callCensus from './call-census.js';
import contentControl from './content-control.js';
import { updateCount, updateAddressCount } from './count.js';
import {
bindEvents,
addEl,
getElData,
createEl,
addClass,
hasClass,
removeClass,
getEl,
getEls,
getParentEls,
} from './dom-tools.js';
import { resetError, setError, getUploadName, isCSV } from './file-input.js';
import Papaparse from 'papaparse';
import getRuralCounties from './get-rural-counties.js';
import * as textInputs from './text-inputs.js';
import callTiger from './call-tiger.js';
import('./show-map.js');
ExpandableGroup.init();
const MAX_CSV_ROWS = 250;
/**
* @param {object} data - Census API results object.
* @param {object} ruralCounties - Object from the census API.
*/
function censusAPI(data, ruralCounties) {
const result = {};
if (addressUtils.isFound(data.result)) {
result.x = data.result.addressMatches[0].coordinates.x;
result.y = data.result.addressMatches[0].coordinates.y;
/*
In the 2019 tigerweb API the layer IDs/name mappings are as follows:
84 = Counties
64 = 2010 Census Urban Clusters
62 = 2010 Census Urbanized Areas
*/
Promise.all([
callTiger(result.x, result.y, '84'),
callTiger(result.x, result.y, '64'),
callTiger(result.x, result.y, '62'),
])
.then(function ([censusCounty, censusUC, censusUA]) {
result.input = data.result.input.address.address;
result.address = data.result.addressMatches[0].matchedAddress;
result.countyName = censusCounty.features[0].attributes.BASENAME;
const fips =
censusCounty.features[0].attributes.STATE +
censusCounty.features[0].attributes.COUNTY;
if (addressUtils.isRural(fips, ruralCounties)) {
result.type = 'rural';
} else if (
addressUtils.isRuralCensus(censusUC.features, censusUA.features)
) {
result.type = 'rural';
} else {
result.type = 'notRural';
}
result.id = Date.now();
addressUtils.render(result);
updateCount(result.type);
})
.catch(function (err) {
console.log(err);
const addressElement = createEl('<li>' + result.address + '</li>');
addEl(getEl('#process-error-desc'), addressElement);
removeClass('#process-error', 'u-hidden');
});
} else {
result.input = data.result.input.address.address;
result.address = 'Address not identfied';
result.countyName = '-';
result.block = '-';
result.type = 'notFound';
updateCount(result.type);
addressUtils.render(result);
}
}
/**
* @param {Array} addresses - A list of addresses.
*/
function processAddresses(addresses) {
const processed = [];
getRuralCounties(getEl('#year').value).then(function (ruralCounties) {
addresses.forEach(function (address) {
if (addressUtils.isDup(address, processed)) {
// setup the result to render
const result = {};
result.input = address;
result.address = 'Duplicate';
result.countyName = '-';
result.block = '-';
result.type = 'duplicate';
addressUtils.render(result);
updateCount(result.type);
} else {
// if its not dup
callCensus(address, ruralCounties, censusAPI);
processed.push(address);
}
});
});
}
// On submit of address entered manually.
const addressFormDom = document.querySelector('#geocode');
addressFormDom.addEventListener('submit', function (evt) {
evt.preventDefault();
window.location.hash = 'rural-or-underserved';
const addresses = [];
contentControl.setup();
[].slice.call(getEls('.input-address')).forEach(function (element) {
if (element.value !== '') {
addresses.push(element.value);
}
});
if (addresses.length > 1) {
removeClass('#results-total', 'u-hidden');
}
updateAddressCount(addresses.length);
processAddresses(addresses);
});
// when file upload is used
const fileChangeDom = document.querySelector('#file');
fileChangeDom.addEventListener('change', function () {
let rowCount = 0;
const fileElement = getEl('#file');
const fileValue = fileElement.value;
textInputs.reset();
getEl('#file-name').value = getUploadName(fileValue);
resetError();
if (isCSV(fileValue)) {
// parse the csv to get the count
Papaparse.parse(fileElement.files[0], {
header: true,
step: function (results, parser) {
if (!addressUtils.isValid(results)) {
parser.abort();
setError(
'The header row of your CSV file does not match' +
' our <a href="https://files.consumerfinance.gov/rural-or-underserved-tool/csv-template.csv"' +
' title="Download CSV template">CSV template</a>.' +
' Please adjust your CSV file and try again.',
);
return;
}
if (results.data['Street Address'] !== '') {
rowCount++;
}
},
error: function () {
console.log(arguments);
},
complete: function (/*results, file*/) {
if (rowCount === 0) {
setError(
'There are no rows in this csv. Please update and try again.',
);
}
if (rowCount >= MAX_CSV_ROWS) {
const leftOver = rowCount - MAX_CSV_ROWS;
setError(
'You entered ' +
rowCount +
' addresses for ' +
getEl('#year').value +
' safe harbor designation. We have a limit of ' +
MAX_CSV_ROWS +
' addresses. You can run the first ' +
MAX_CSV_ROWS +
' now, but please recheck the remaining ' +
leftOver +
'.',
);
}
},
});
} else {
setError(
'The file uploaded is not a CSV file. ' +
'Please try again with a CSV file that uses ' +
'our <a href="https://files.consumerfinance.gov/rural-or-underserved-tool/csv-template.csv"' +
'title="Download CSV template">CSV template</a>.' +
' For more information about CSV files, view our' +
' Frequently Asked Questions below.',
);
}
});
// on file submission
const geocodeCSVDom = document.querySelector('#geocode-csv');
geocodeCSVDom.addEventListener('submit', function (evt) {
evt.preventDefault();
window.location.hash = 'rural-or-underserved';
let fileElement = getEl('#file-name');
const fileValue = fileElement.value;
if (
fileValue === '' ||
fileValue === 'No file chosen' ||
fileValue === null
) {
setError(
'You have not selected a file. ' +
'Use the "Select file" button to select the file with your addresses.',
);
} else if (isCSV(fileValue)) {
let pass = true;
let rowCount = 0;
let addresses = [];
fileElement = getEl('#file');
textInputs.reset();
// Parse the csv to get the
Papaparse.parse(fileElement.files[0], {
header: true,
step: function (results, parser) {
if (addressUtils.isValid(results)) {
if (
rowCount < MAX_CSV_ROWS &&
results.data['Street Address'] !== ''
) {
addresses = addressUtils.pushAddress(results, addresses);
}
rowCount++;
} else {
parser.abort();
pass = false;
setError(
'The header row of your CSV file does not match' +
' our <a href="https://files.consumerfinance.gov/rural-or-underserved-tool/csv-template.csv"' +
' title="Download CSV template">CSV template</a>.' +
' Please adjust your CSV file and try again.',
);
}
},
complete: function (/* results, file */) {
if (rowCount === 0) {
pass = false;
setError(
'There are no rows in this csv. Please update and try again.',
);
}
if (rowCount >= MAX_CSV_ROWS) {
const leftOver = rowCount - MAX_CSV_ROWS;
setError(
'You entered ' +
rowCount +
' addresses for ' +
getEl('#year').value +
' safe harbor designation. We have a limit of ' +
MAX_CSV_ROWS +
' addresses. You can run the first ' +
MAX_CSV_ROWS +
' now, but please recheck the remaining ' +
leftOver +
'.',
);
}
if (addresses.length > 1) {
removeClass('#results-total', 'u-hidden');
}
if (pass === true) {
contentControl.setup();
updateAddressCount(addresses.length);
processAddresses(addresses);
}
},
});
} else {
setError(
'The file uploaded is not a CSV file.' +
' Please try again with a CSV file that uses our' +
' <a href="https://files.consumerfinance.gov/rural-or-underserved-tool/csv-template.csv"' +
' title="Download CSV template">CSV template</a>.' +
' For more information about CSV files,' +
' view our Frequently Asked Questions below.',
);
}
return false;
});
// add inputs
const addAnotherLinkDom = document.querySelector('#add-another');
addAnotherLinkDom.addEventListener('click', function (evt) {
evt.preventDefault();
textInputs.add();
});
// input blur
const inputAddressDom = document.querySelector('.input-address');
inputAddressDom.addEventListener('blur', function (evt) {
textInputs.toggleError(evt);
});
// show more rows
bindEvents('.button-more', 'click', function (evt) {
const moreButton = evt.target;
evt.preventDefault();
const tableID = getElData(moreButton, 'table');
const tableRows = getEls('#' + tableID + ' tbody tr.data');
const tableRowsLength = tableRows.length;
const lengthShown = Array.prototype.filter.call(tableRows, function (item) {
return !item.classList.contains('u-hidden');
}).length;
for (let i = lengthShown; i < lengthShown + 10; i++) {
removeClass(tableRows[i], 'u-hidden');
}
if (lengthShown + 10 >= tableRowsLength) {
addClass('#' + tableID + 'More', 'u-hidden');
addClass('#' + tableID + 'All', 'u-hidden');
}
});
bindEvents('.view-all', 'click', function (evt) {
evt.preventDefault();
const tableID = getElData(evt.target, 'table');
removeClass('#' + tableID + ' tbody tr.data', 'u-hidden');
addClass('#' + tableID + 'More', 'u-hidden');
addClass('#' + tableID + 'All', 'u-hidden');
});
// print
bindEvents('#print', 'click', window.print.bind(window));
// csv download
/**
*
*/
function detectIE() {
const ua = window.navigator.userAgent;
const msie = ua.indexOf('MSIE ');
if (msie > 0) {
// IE 10 or older => return version number
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
const trident = ua.indexOf('Trident/');
if (trident > 0) {
// IE 11 => return version number
const rv = ua.indexOf('rv:');
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
}
const edge = ua.indexOf('Edge/');
if (edge > 0) {
// IE 12 => return version number
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
}
// other browser
return false;
}
bindEvents('#download', 'click', function (evt) {
evt.preventDefault();
const theCSV = generateCSV();
if (detectIE() === false) {
window.open(' data:text/csv;charset=utf-8,' + encodeURIComponent(theCSV));
} else {
const blob = new Blob([theCSV], { type: 'text/csv;charset=utf-8,' });
navigator.msSaveOrOpenBlob(blob, 'rural-or-underserved.csv');
}
});
/**
* @returns {string} A comma-separate values string of address info.
*/
function generateCSV() {
let theCSV = '';
const date = new Date();
const day = date.getDate();
const monthIndex = date.getMonth();
const year = date.getFullYear();
theCSV =
'Address entered, Address identified, County, Rural' +
' or underserved?, Date processed\n';
/**
* Process each cell in a table row.
* @param {HTMLElement} element - A table data element to process.
*/
function _loopHandler(element) {
const isHidden = hasClass(getParentEls('.js-table'), 'u-hidden');
/* Add a data row, if table isn't hidden (!)
and map cols have colspan and we don't want those. */
if (isHidden === false && element.getAttribute('colspan') === null) {
const CSVLabel = element.textContent.replace('Show map', '');
// Put the content in first.
theCSV += '"' + CSVLabel + '"';
if (element.matches(':last-child')) {
theCSV = theCSV + ',' + monthIndex + '/' + day + '/' + year + '\n';
} else {
theCSV += ',';
}
}
}
// loop through each row
[].slice
.call(getEls('.rout-results-table tbody tr td'))
.forEach(_loopHandler);
return theCSV;
}