-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
120 lines (97 loc) · 3.48 KB
/
script.js
File metadata and controls
120 lines (97 loc) · 3.48 KB
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
const excelFile = document.getElementById('excelFile');
const errorDiv = document.getElementById('error');
const successDiv = document.getElementById('success');
const downloadBtn = document.getElementById('downloadBtn');
let generatedCSV = "";
excelFile.addEventListener('change', function (e) {
clearMessages();
generatedCSV = "";
downloadBtn.disabled = true;
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (evt) {
try {
const data = new Uint8Array(evt.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(firstSheet, { header: 1 });
if (rows.length < 2) throw new Error("Excel must have headers and at least one row.");
function normalized(str) {
return str.toString().replace(/\s+/g, "").toLowerCase();
}
const headers = rows[0].map(h => normalized(h));
const emailIdx = headers.findIndex(h => h.includes("email"));
const nameIdx = headers.findIndex(h => h.includes("name"));
if (emailIdx === -1 || nameIdx === -1)
throw new Error('Headers "email" and "name" are required.');
const attrHeaders = headers
.map((h, i) => ({ h, i }))
.filter(x => x.i !== emailIdx && x.i !== nameIdx)
.map(x => x.h);
let csvLines = [];
csvLines.push('email,name,attributes');
for (let i = 1; i < rows.length; i++) {
const row = rows[i];
while (row.length < headers.length) row.push("");
const email = (row[emailIdx] || "").toString().replace(/"/g, '""');
const name = (row[nameIdx] || "").toString().replace(/"/g, '""');
const attrsObj = {};
attrHeaders.forEach(hdr => {
const idx = headers.indexOf(hdr);
let val = "";
if (row[idx] !== undefined && row[idx] !== null) {
val = row[idx].toString();
}
attrsObj[hdr] = val;
});
const attrPairs = Object.entries(attrsObj).map(([k, v]) =>
`"${k}": "${v.replace(/"/g, '\\"')}"`
);
const attrJSONString = `{${attrPairs.join(", ")}}`.replace(/"/g, '""');
csvLines.push(`"${email}","${name}","${attrJSONString}"`);
}
generatedCSV = csvLines.join("\r\n");
downloadBtn.disabled = false;
showSuccess("");
} catch (err) {
showError("Processing error: " + err.message);
}
};
reader.onerror = function () {
showError("Failed to read file.");
};
reader.readAsArrayBuffer(file);
});
downloadBtn.addEventListener('click', function () {
if (!generatedCSV) return;
try {
const blob = new Blob([generatedCSV], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = "processed.csv";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
showSuccess("");
} catch (err) {
showError("Download error: " + err.message);
}
});
function showError(msg) {
errorDiv.textContent = msg;
errorDiv.classList.remove('hidden');
successDiv.classList.add('hidden');
}
function showSuccess(msg) {
successDiv.textContent = msg;
successDiv.classList.remove('hidden');
errorDiv.classList.add('hidden');
}
function clearMessages() {
errorDiv.textContent = "";
successDiv.textContent = "";
errorDiv.classList.add('hidden');
successDiv.classList.add('hidden');
}