More changes to uploads:

- Have got upload images appearing in the post list
- Allowed for deleting uploads
- Allowed for seeing the upload progress
- Fixed the setting of upload properties like the MIME type
- Removed the stripe exif logic with just re-encoding PNGs and JPEGs by loading them and saving them
This commit is contained in:
Leon Mika 2026-03-04 22:33:39 +11:00
parent d0cebe6564
commit 199ff9feb9
21 changed files with 471 additions and 65 deletions

View file

@ -4,6 +4,8 @@ import {showToast} from "../services/toast";
export default class ShowUploadController extends Controller {
static values = {
copySnippet: String,
siteId: Number,
uploadId: Number,
};
async copy(ev) {
@ -16,4 +18,24 @@ export default class ShowUploadController extends Controller {
body: "Copied to clipboard.",
});
}
async delete(ev) {
ev.preventDefault();
if (!confirm("Are you sure you want to delete this upload?")) {
return;
}
await this._doDelete();
window.location = `/sites/${this.siteIdValue}/uploads/`;
}
async _doDelete() {
const url = `/sites/${this.siteIdValue}/uploads/${this.uploadIdValue}`
await fetch(url, {
method: 'DELETE',
headers: {
'Accept': 'application/json'
}
})
}
}

View file

@ -1,6 +1,12 @@
import { Controller } from "@hotwired/stimulus"
export default class UploadController extends Controller {
static targets = [
'uploadBtn',
'progressbar',
'progressbarProgress',
];
static values = {
siteId: Number,
};
@ -30,13 +36,17 @@ export default class UploadController extends Controller {
}
async _doUploads(files) {
for (let file of files) {
await this._doUpload(file);
this.uploadBtnTarget.disabled = true;
this._showUploadProgressBar();
for (let i = 0; i < files.length; i++) {
await this._doUpload(files[i], i, files.length);
}
window.location.reload();
}
async _doUpload(file) {
async _doUpload(file, thisFileIndex, nFiles) {
console.log(`Uploading ${file.name}: new pending`);
// Prepare upload of file supplying size and mime-type
@ -60,12 +70,11 @@ export default class UploadController extends Controller {
let chunk = file.slice(offset, offset + chunkSize);
console.log(`Uploading ${file.name}: uploading part`);
await fetch(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}`, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream'
},
body: chunk
await this._uploadChunk(`/sites/${this.siteIdValue}/uploads/pending/${newPending.guid}`, chunk, {
chunkOffset: offset,
totalSize: file.size,
thisFileIndex,
nFiles,
});
offset += chunkSize;
@ -88,6 +97,44 @@ export default class UploadController extends Controller {
});
}
_uploadChunk(url, chunk, progressInfo) {
let { chunkOffset, totalSize, thisFileIndex, nFiles } = progressInfo;
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
const bytesUploaded = chunkOffset + e.loaded;
const fractionalCompleteOfThisFile = +bytesUploaded / +totalSize;
const percentComplete = (thisFileIndex + fractionalCompleteOfThisFile) * 100 / nFiles;
console.log(`Uploading ${chunk.name}: ${percentComplete.toFixed(2)}%`);
this.progressbarProgressTarget.style.width = `${percentComplete}%`;
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve();
} else {
reject(new Error(`Upload failed with status ${xhr.status}`));
}
});
xhr.addEventListener('error', () => reject(new Error('Upload failed')));
xhr.addEventListener('abort', () => reject(new Error('Upload aborted')));
xhr.open('POST', url);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.send(chunk);
});
}
_showUploadProgressBar() {
this.progressbarTarget.classList.remove('d-none');
this.progressbarProgressTarget.style.width = '0%';
}
async _calculateSHA256(file) {
const arrayBuffer = await file.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);