init f0ckm
This commit is contained in:
147
public/s/js/upload-common.js
Normal file
147
public/s/js/upload-common.js
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* common upload logic for f0ck
|
||||
* shared between /upload page and global drag-and-drop modal
|
||||
*/
|
||||
window.F0ckUpload = class {
|
||||
constructor(options) {
|
||||
this.form = options.form;
|
||||
this.config = options.config || {};
|
||||
this.onProgress = options.onProgress || (() => {});
|
||||
this.onComplete = options.onComplete || (() => {});
|
||||
this.onError = options.onError || (() => {});
|
||||
this.onStatusChange = options.onStatusChange || (() => {});
|
||||
|
||||
this.selectedFile = null;
|
||||
this.tags = [];
|
||||
this.minTags = options.minTags || 3;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
if (!this.form) return;
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
// Tag input handling (if exists in this form instance)
|
||||
const tagInput = this.form.querySelector('.tag-input');
|
||||
if (tagInput) {
|
||||
tagInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
this.addTag(tagInput.value);
|
||||
tagInput.value = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
formatSize(bytes) {
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
let i = 0;
|
||||
while (bytes >= 1024 && i < units.length - 1) {
|
||||
bytes /= 1024;
|
||||
i++;
|
||||
}
|
||||
return bytes.toFixed(2) + ' ' + units[i];
|
||||
}
|
||||
|
||||
validateFile(file) {
|
||||
if (!file) return false;
|
||||
const allowedMimes = this.config.allowedMimes || [];
|
||||
if (allowedMimes.length > 0 && !allowedMimes.includes(file.type)) {
|
||||
return { error: `File type ${file.type} is not allowed.` };
|
||||
}
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
addTag(tagName) {
|
||||
tagName = tagName.trim();
|
||||
if (!tagName || this.tags.some(t => t.toLowerCase() === tagName.toLowerCase())) return;
|
||||
if (['sfw', 'nsfw', 'nsfl'].includes(tagName.toLowerCase())) return;
|
||||
|
||||
this.tags.push(tagName);
|
||||
this.onStatusChange({ type: 'tags_updated', tags: this.tags });
|
||||
}
|
||||
|
||||
removeTag(tagName) {
|
||||
this.tags = this.tags.filter(t => t !== tagName);
|
||||
this.onStatusChange({ type: 'tags_updated', tags: this.tags });
|
||||
}
|
||||
|
||||
clearTags() {
|
||||
this.tags = [];
|
||||
this.onStatusChange({ type: 'tags_updated', tags: this.tags });
|
||||
}
|
||||
|
||||
setFile(file) {
|
||||
const validation = this.validateFile(file);
|
||||
if (validation.error) {
|
||||
this.onError(validation.error);
|
||||
return false;
|
||||
}
|
||||
this.selectedFile = file;
|
||||
this.onStatusChange({ type: 'file_selected', file: file });
|
||||
return true;
|
||||
}
|
||||
|
||||
async upload() {
|
||||
if (!this.selectedFile) {
|
||||
this.onError('No file selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const rating = this.form.querySelector('input[name="rating"]:checked');
|
||||
if (!rating) {
|
||||
this.onError('Please select a rating');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.tags.length < this.minTags) {
|
||||
this.onError(`At least ${this.minTags} tags are required`);
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', this.selectedFile);
|
||||
formData.append('rating', rating.value);
|
||||
formData.append('tags', this.tags.join(','));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.upload.addEventListener('progress', (e) => {
|
||||
if (e.lengthComputable) {
|
||||
const percent = Math.round((e.loaded / e.total) * 100);
|
||||
this.onProgress(percent);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.onload = () => {
|
||||
try {
|
||||
const res = JSON.parse(xhr.responseText);
|
||||
if (res.success) {
|
||||
this.onComplete(res);
|
||||
resolve(res);
|
||||
} else {
|
||||
this.onError(res.msg, res);
|
||||
reject(res);
|
||||
}
|
||||
} catch (err) {
|
||||
this.onError('Upload failed. Server returned invalid response.');
|
||||
reject(err);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = (err) => {
|
||||
this.onError('Network error occurred during upload.');
|
||||
reject(err);
|
||||
};
|
||||
|
||||
xhr.open('POST', '/api/v2/upload');
|
||||
xhr.setRequestHeader('X-CSRF-Token', window.f0ckSession?.csrf_token || '');
|
||||
xhr.send(formData);
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user