Skip to content

Commit bf3bcb7

Browse files
committed
🔧 Fix three critical UX issues
1. Remove Clear All button - was confusing users 2. Fix file dialog opening - use label wrapper for better browser compatibility 3. Fix file download naming - preserve original filename with _cleaned.txt extension - Properly extract filename without extension - Add charset=utf-8 to blob - Show toast notification with download name - Better error handling Update cache-busting to v=5
1 parent da2933b commit bf3bcb7

File tree

3 files changed

+71
-59
lines changed

3 files changed

+71
-59
lines changed

docs/assets/app.js

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ class App {
174174
this.fileList = document.getElementById('fileList');
175175
this.resultsSection = document.getElementById('resultsSection');
176176
this.resultsContainer = document.getElementById('resultsContainer');
177-
this.clearBtn = document.getElementById('clearBtn');
178177

179178
// Check if elements exist
180179
if (!this.uploadArea || !this.fileInput) {
@@ -184,30 +183,34 @@ class App {
184183
}
185184

186185
setupEventListeners() {
187-
// Click to upload - ensure it works even if upload-content is clicked
186+
// Click to upload - use label approach for better browser compatibility
187+
// The label wraps the file input, so clicking anywhere on upload area triggers it
188+
const fileInputLabel = this.uploadArea.querySelector('.file-input-label');
189+
if (fileInputLabel) {
190+
// Make label cover entire upload area
191+
fileInputLabel.style.position = 'absolute';
192+
fileInputLabel.style.top = '0';
193+
fileInputLabel.style.left = '0';
194+
fileInputLabel.style.width = '100%';
195+
fileInputLabel.style.height = '100%';
196+
fileInputLabel.style.cursor = 'pointer';
197+
fileInputLabel.style.zIndex = '1';
198+
}
199+
200+
// Also handle clicks on upload area as fallback
188201
this.uploadArea.addEventListener('click', (e) => {
189202
// Don't trigger if clicking on remove button or other interactive elements
190203
if (e.target.closest('.remove-file') || e.target.closest('.btn')) {
191204
return;
192205
}
193-
// Trigger file input click
194-
if (this.fileInput) {
195-
e.preventDefault();
196-
e.stopPropagation();
197-
this.fileInput.click();
206+
// Trigger file input click if label didn't work
207+
if (this.fileInput && e.target !== this.fileInput && !e.target.closest('label')) {
208+
// Use setTimeout for better compatibility
209+
setTimeout(() => {
210+
this.fileInput.click();
211+
}, 0);
198212
}
199213
});
200-
201-
// Also make upload-content clickable (bypass pointer-events: none)
202-
const uploadContent = this.uploadArea.querySelector('.upload-content');
203-
if (uploadContent) {
204-
uploadContent.addEventListener('click', (e) => {
205-
e.stopPropagation();
206-
if (this.fileInput) {
207-
this.fileInput.click();
208-
}
209-
});
210-
}
211214

212215
// Drag and drop
213216
this.uploadArea.addEventListener('dragover', (e) => {
@@ -229,11 +232,6 @@ class App {
229232
this.fileInput.addEventListener('change', (e) => {
230233
this.handleFiles(e.target.files);
231234
});
232-
233-
// Clear button
234-
this.clearBtn.addEventListener('click', () => {
235-
this.clearAll();
236-
});
237235
}
238236

239237
handleFiles(files) {
@@ -259,11 +257,9 @@ class App {
259257
updateFileList() {
260258
if (this.files.length === 0) {
261259
this.fileList.innerHTML = '';
262-
this.clearBtn.style.display = 'none';
263260
return;
264261
}
265262

266-
this.clearBtn.style.display = 'inline-block';
267263
this.fileList.innerHTML = '<h3>Uploaded Files:</h3>';
268264

269265
this.files.forEach((file, index) => {
@@ -279,7 +275,13 @@ class App {
279275
this.files.splice(index, 1);
280276
this.updateFileList();
281277
if (this.files.length === 0) {
282-
this.clearAll();
278+
this.files = [];
279+
this.results = [];
280+
if (this.fileInput) {
281+
this.fileInput.value = '';
282+
}
283+
this.updateFileList();
284+
this.resultsSection.style.display = 'none';
283285
} else {
284286
this.processFiles();
285287
}
@@ -425,15 +427,35 @@ class App {
425427
}
426428

427429
downloadFile(result) {
428-
const blob = new Blob([result.cleanedText], { type: 'text/plain' });
429-
const url = URL.createObjectURL(blob);
430-
const a = document.createElement('a');
431-
a.href = url;
432-
a.download = result.fileName.replace(/\.(txt|docx)$/, '_cleaned.txt');
433-
document.body.appendChild(a);
434-
a.click();
435-
document.body.removeChild(a);
436-
URL.revokeObjectURL(url);
430+
try {
431+
const blob = new Blob([result.cleanedText], { type: 'text/plain;charset=utf-8' });
432+
const url = URL.createObjectURL(blob);
433+
434+
// Get original filename and extension
435+
const originalName = result.fileName;
436+
const nameWithoutExt = originalName.replace(/\.(txt|docx)$/i, '');
437+
const downloadName = `${nameWithoutExt}_cleaned.txt`;
438+
439+
const a = document.createElement('a');
440+
a.href = url;
441+
a.download = downloadName;
442+
a.style.display = 'none';
443+
document.body.appendChild(a);
444+
445+
// Trigger download
446+
a.click();
447+
448+
// Cleanup
449+
setTimeout(() => {
450+
document.body.removeChild(a);
451+
URL.revokeObjectURL(url);
452+
}, 100);
453+
454+
this.showToast(`Downloaded: ${downloadName}`);
455+
} catch (error) {
456+
console.error('Download error:', error);
457+
this.showToast('Failed to download file', 'error');
458+
}
437459
}
438460

439461
copyToClipboard(text) {
@@ -458,21 +480,6 @@ class App {
458480
}, 3000);
459481
}
460482

461-
clearAll() {
462-
if (this.files.length === 0) {
463-
return;
464-
}
465-
466-
this.files = [];
467-
this.results = [];
468-
if (this.fileInput) {
469-
this.fileInput.value = '';
470-
}
471-
this.updateFileList();
472-
this.resultsSection.style.display = 'none';
473-
this.showToast('All files cleared');
474-
}
475-
476483
formatFileSize(bytes) {
477484
if (bytes === 0) return '0 Bytes';
478485
const k = 1024;

docs/assets/style.css

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,16 @@ body {
170170
}
171171

172172
.upload-content {
173-
pointer-events: auto;
173+
pointer-events: none;
174174
user-select: none;
175-
cursor: pointer;
175+
position: relative;
176+
z-index: 2;
177+
}
178+
179+
.file-input-label {
180+
display: block;
181+
width: 100%;
182+
height: 100%;
176183
}
177184

178185
.upload-icon {

docs/index.html

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>DocStripper - Batch Document Cleaner</title>
77
<meta name="description" content="DocStripper - Remove noise from text documents automatically. Clean page numbers, headers, footers, duplicates, and empty lines.">
8-
<link rel="stylesheet" href="assets/style.css?v=4">
8+
<link rel="stylesheet" href="assets/style.css?v=5">
99
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🧹</text></svg>">
1010
</head>
1111
<body>
@@ -43,11 +43,9 @@ <h2>Upload Your Documents</h2>
4343
</p>
4444
<p class="upload-hint">Supports: .txt, .docx files</p>
4545
</div>
46-
<input type="file" id="fileInput" multiple accept=".txt,.docx" style="display: none;">
47-
</div>
48-
49-
<div class="upload-options">
50-
<button class="btn btn-secondary" id="clearBtn" style="display: none;">Clear All</button>
46+
<label for="fileInput" class="file-input-label">
47+
<input type="file" id="fileInput" multiple accept=".txt,.docx" style="position: absolute; width: 0; height: 0; opacity: 0; overflow: hidden;">
48+
</label>
5149
</div>
5250

5351
<div id="fileList" class="file-list"></div>
@@ -180,6 +178,6 @@ <h2>Prefer Command Line?</h2>
180178
</div>
181179
</footer>
182180

183-
<script src="assets/app.js?v=4"></script>
181+
<script src="assets/app.js?v=5"></script>
184182
</body>
185183
</html>

0 commit comments

Comments
 (0)