Skip to content

Commit 3c1224f

Browse files
committed
Added Student ID converter
1 parent 4f2e7d5 commit 3c1224f

2 files changed

Lines changed: 140 additions & 6 deletions

File tree

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ This program simply adds a new page to the backs of multiple choice scanforms fo
99
**Example Input and Output files:**
1010
[https://github.com/CalebHendren/zipmerge/tree/master/Example](https://github.com/CalebHendren/zipmerge/tree/master/Example)
1111

12-
## Usage
12+
## Bubble Sheet + Written Sheet Merger Usage
1313

1414
> **Note:** Step 1 is optional if you don't want student names and other information pre-printed on the sheets, but at that point, you may as well just merge the two single-page PDF files manually in Adobe Acrobat. But you can still use this if you don't like dealing with Acrobat (my hatred of Acrobat is what prompted me to make this).
1515
@@ -31,10 +31,14 @@ Take your Answer Sheet Packets from ZipGrade and the Written Sheet PDF that you
3131
2. Select the Written Sheet as the **Written Answer Sheet**
3232
3. Click **Merge**
3333

34-
## Upcoming Features
34+
## Student ID Processor for ZipGrade Usage
3535

36-
### Accept Microsoft Word documents for the Written Answer Sheet to avoid the conversion to PDF.
37-
The issue is that after being uploaded, they will have to be converted into HTML then into a PDF because I cannot find a way to directly convert into a PDF in a way that can be done 100% in the browser.
36+
This tool converts student IDs from the format `#A00123456` to a ZipGrade-compatible numeric format `123456` by removing the unnecessary `#A00`.
3837

39-
### Process student IDs to make them ZipGrade compatable
40-
ZipGrade only accepts numbers in the student ID field. When exported from Brightspace, they are in the format #A00123456. ZipGrade can automatically assign random numbers as IDs, but if you would rather use their actual IDs, I plan to add a way to automatically cut off the unnecessary "#A00" and keep the "123456." In the mean time, this can be done quickly in Excel using the formula =RIGHT(A2, LEN(A2) - 4) and dragging the fill handle down.
38+
### Steps:
39+
1. **Prepare your CSV File:** Export your student roster from your LMS as a CSV file. Student IDs should be in the first column.
40+
2. **Go to the Website:** Navigate to [https://calebhendren.github.io/zipmerge/](https://calebhendren.github.io/zipmerge/).
41+
3. **Locate the ID Processor:** Scroll down to the "Student ID Processor for ZipGrade" section.
42+
4. **Upload CSV:** Click "Choose File" under "Student IDs CSV File (.csv only)" and select your CSV file.
43+
5. **Process IDs:** Click the "Process IDs" button.
44+
6. **Download:** The processed CSV file (e.g., `yourfile_processed_IDs.csv`) will be automatically downloaded by your browser. You can then import this file into ZipGrade as part of Step 1 in the above section.

index.html

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,23 @@ <h1>Bubble Sheet + Written Sheet Merger</h1>
222222
<div id="status" class="status"></div>
223223
</div>
224224

225+
<div class="container" style="margin-top: 40px;">
226+
<h1>Student ID Processor for ZipGrade</h1>
227+
<p class="subtitle" style="font-size: 0.9em; color: var(--comment);">
228+
Converts eLearn IDs (e.g., #A00123456) to ZipGrade compatible IDs (e.g., 123456).
229+
<br>Processes the first column of a CSV file.
230+
</p>
231+
232+
<div class="input-group">
233+
<label for="studentIdFile">Student IDs CSV File (.csv only):</label>
234+
<input type="file" id="studentIdFile" accept=".csv">
235+
<div id="studentIdFileInfo" class="file-info">No file selected</div>
236+
</div>
237+
238+
<button id="processIdsBtn" onclick="processStudentIds()">Process IDs</button>
239+
<div id="idStatus" class="status"></div>
240+
</div>
241+
225242
<script>
226243
document.getElementById('sheetPack').addEventListener('change', function(e) {
227244
updateFileInfo(e, 'sheetPackInfo');
@@ -330,6 +347,119 @@ <h1>Bubble Sheet + Written Sheet Merger</h1>
330347
processBtn.disabled = false;
331348
}
332349
}
350+
351+
// For Student ID Processor
352+
const studentIdFileInput = document.getElementById('studentIdFile');
353+
const processIdsButtonElement = document.getElementById('processIdsBtn');
354+
355+
if (studentIdFileInput) {
356+
studentIdFileInput.addEventListener('change', function(e) {
357+
updateFileInfo(e, 'studentIdFileInfo'); // Reuses existing updateFileInfo
358+
toggleProcessIdsButtonState();
359+
});
360+
}
361+
362+
function toggleProcessIdsButtonState() {
363+
if (processIdsButtonElement && studentIdFileInput) {
364+
processIdsButtonElement.disabled = studentIdFileInput.files.length === 0;
365+
}
366+
}
367+
368+
function formatStudentIdCore(idString) {
369+
let currentId = idString.trim();
370+
if (currentId.startsWith("#A00")) {
371+
currentId = currentId.substring(4);
372+
}
373+
return currentId.replace(/\D/g, ''); // Return only digits
374+
}
375+
376+
async function processStudentIds() {
377+
const statusElement = document.getElementById('idStatus');
378+
const processBtn = document.getElementById('processIdsBtn'); // processIdsButtonElement can be used here too
379+
// const studentIdFileElement = document.getElementById('studentIdFile'); // Already studentIdFileInput
380+
381+
statusElement.textContent = 'Processing IDs...';
382+
statusElement.className = 'status'; // Reset status style
383+
processBtn.disabled = true;
384+
385+
try {
386+
const csvFile = studentIdFileInput.files[0];
387+
if (!csvFile) {
388+
throw new Error("No CSV file selected.");
389+
}
390+
391+
const originalName = csvFile.name.replace(/\.csv$/i, '');
392+
const outputFilename = `${originalName}_processed_IDs.csv`;
393+
394+
const fileContent = await csvFile.text();
395+
const lines = fileContent.split(/\r\n|\r|\n/);
396+
const processedLines = [];
397+
398+
for (let i = 0; i < lines.length; i++) {
399+
const line = lines[i];
400+
401+
if (line.trim() === '') {
402+
if (i === lines.length - 1 && processedLines.length > 0 && processedLines[processedLines.length-1].trim() === '') {
403+
continue;
404+
} else if (i === lines.length -1 && lines.length > 1) {
405+
continue;
406+
} else if (lines.length === 1) {
407+
processedLines.push('');
408+
continue;
409+
} else if (i < lines.length -1 ) {
410+
processedLines.push('');
411+
continue;
412+
}
413+
}
414+
415+
416+
const columns = line.split(','); // Simple CSV split
417+
let firstColumnValue = columns[0];
418+
let processedFirstColumn;
419+
420+
if (i === 0) { // Header row: try to preserve text headers
421+
const formattedHeaderCell = formatStudentIdCore(firstColumnValue);
422+
if (/[a-zA-Z]/.test(firstColumnValue) &&
423+
(formattedHeaderCell === "" || (/^\d+$/.test(formattedHeaderCell) && firstColumnValue.trim() !== formattedHeaderCell))) {
424+
processedFirstColumn = firstColumnValue;
425+
} else {
426+
processedFirstColumn = formattedHeaderCell;
427+
}
428+
} else { // Data rows: always apply formatting
429+
processedFirstColumn = formatStudentIdCore(firstColumnValue);
430+
}
431+
432+
if (columns.length > 1) {
433+
columns[0] = processedFirstColumn;
434+
processedLines.push(columns.join(','));
435+
} else {
436+
processedLines.push(processedFirstColumn);
437+
}
438+
}
439+
440+
while (processedLines.length > 0 && processedLines[processedLines.length - 1].trim() === "") {
441+
processedLines.pop();
442+
}
443+
444+
const processedCsvContent = processedLines.join('\n');
445+
download(new Blob([processedCsvContent], { type: 'text/csv;charset=utf-8;' }), outputFilename, "text/csv");
446+
447+
statusElement.textContent = `Success! Processed IDs saved as ${outputFilename}`;
448+
statusElement.className = 'status success';
449+
450+
} catch (error) {
451+
console.error("Error processing student IDs:", error);
452+
statusElement.textContent = `Error: ${error.message}`;
453+
statusElement.className = 'status error';
454+
} finally {
455+
processBtn.disabled = false;
456+
}
457+
}
458+
459+
toggleProcessButton();
460+
if (document.getElementById('processIdsBtn')) {
461+
toggleProcessIdsButtonState();
462+
}
333463
</script>
334464
</body>
335465
</html>

0 commit comments

Comments
 (0)