The <input type="file"> exists but is hidden. The Upload button needs to trigger it:
const fileInput = document.getElementById('file-input');
uploadBtn.addEventListener('click', () => {
fileInput.click(); // Programmatically open file dialog
});
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (!file) return;
// Validate (from Session 19)
if (!validTypes.includes(file.type)) {
showToast('Invalid file type', 'error');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
console.log("File read complete!");
// e.target.result contains the image data
loadImageToCanvas(e.target.result);
};
reader.onerror = function() {
showToast('Failed to read file', 'error');
};
reader.readAsDataURL(file);
});
function loadImageToCanvas(dataURL) {
const img = new Image();
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
showToast('Image loaded!', 'success');
};
img.src = dataURL;
}
Another async operation: setting img.src starts loading, then onload fires when the image is decoded. Two layers of async chained together.
| File | Expected Result |
|---|---|
| .jpg photo | Loads and displays ✅ |
| .png with transparency | Loads and displays ✅ |
| .webp image | Loads and displays ✅ |
| .txt file | Toast: "Invalid file type" 🔴 |
| Very large file (50MB+) | Toast: "File too large" 🔴 |
Show the spinner from Session 17 while the file is being read. Hide it when the image loads.
git switch -c bugfix/PIXELCRAFT-012-file-upload
git add src/scripts/ src/index.html
git commit -m "Fix upload button and implement file reading pipeline (PIXELCRAFT-012)"
git push origin bugfix/PIXELCRAFT-012-file-upload
# PR → Review → Merge → Close ticket ✅
Asynchronous programming.
FileReader.readAsDataURL() starts reading but doesn't wait — it returns immediately. When the file is ready, the onload callback fires.