perbaikan fominspeksi upload foto

This commit is contained in:
majid
2025-01-01 19:48:26 +07:00
parent 08de0eeb00
commit b2287838b7
6 changed files with 1002 additions and 493 deletions

View File

@@ -199,322 +199,4 @@
});
class DynamicFileUploader {
constructor(options) {
const defaultOptions = {
containerId: 'lantaiContainer',
addButtonId: null,
fileInputName: 'foto_lantai_unit',
maxFiles: 4,
allowMultiple: true,
name: null,
accept: 'image/*',
existingFiles: []
};
this.options = {
...defaultOptions,
...options
};
this.container = document.getElementById(this.options.containerId);
if (this.options.addButtonId) {
this.addButton = document.getElementById(this.options.addButtonId);
this.addButton.addEventListener('click', () => {
this.addNewItem();
});
}
// Inisialisasi global handlers
this.initGlobalHandlers();
this.init();
}
initGlobalHandlers() {
// Simpan instance ke window untuk akses global
// window.dynamicFileUploader = this;
// Global handler untuk drag and drop
window.handleDrop = (event) => {
event.preventDefault();
event.stopPropagation();
const dropzone = event.currentTarget;
const fileInput = dropzone.querySelector('.file-input');
this.handleDrop(event, fileInput);
};
window.allowDrop = (event) => {
event.preventDefault();
event.stopPropagation();
};
window.handleFileInput = (fileInput) => {
this.handleFileInput(fileInput);
};
}
init() {
// Proses file yang sudah ada
if (this.options.existingFiles && this.options.existingFiles.length > 0) {
this.processExistingFiles();
}
// Inisialisasi item pertama jika belum ada file
if (this.container.children.length === 0) {
this.addNewItem();
}
// Inisialisasi event listener untuk item yang sudah ada
this.container.querySelectorAll(".dynamic-item").forEach(item => {
this.attachEventListeners(item);
});
this.updateRemoveButtonVisibility();
}
addNewItem() {
const currentItemCount = this.container.children.length + 1;
const newItem = document.createElement("div");
newItem.classList.add("dynamic-item", "w-full", "mb-4");
newItem.innerHTML = this.generateItemHTML(currentItemCount);
this.container.appendChild(newItem);
if (currentItemCount > 1) {
this.attachEventListeners(newItem);
}
this.updateRemoveButtonVisibility();
return newItem;
}
generateItemHTML(itemCount) {
return `
<div class="flex w-full items-center justify-between">
${this.options.name ? `<label class="form-label">${this.options.name} ${itemCount}</label>` : ''}
<button type="button" class="btn btn-danger btn-sm btnRemoveLantai"
style="${itemCount === 1 ? 'display: none;' : ''}">
Hapus
</button>
</div>
<div class="dropzone w-full border-2 border-dashed border-gray-400 rounded-lg p-4 mt-2"
ondrop="handleDrop(event)" ondragover="allowDrop(event)">
<div class="preview-container grid grid-cols-2 md:grid-cols-4 gap-4"></div>
<input type="file"
name="${this.options.fileInputName}[${itemCount}][]"
class="file-input hidden"
multiple
accept="${this.options.accept}"
onchange="handleFileInput(this)"
data-lantai="${itemCount}">
<button type="button" class="btn btn-light btn-sm btnUploadFiles mt-2">
<i class="ki-outline ki-upload"></i> Unggah Gambar
</button>
</div>
`;
}
attachEventListeners(item) {
const uploadButton = item.querySelector('.btnUploadFiles');
const fileInput = item.querySelector('.file-input');
const previewContainer = item.querySelector('.preview-container');
if (!uploadButton.dataset.listenerAttached) {
uploadButton.addEventListener('click', () => {
fileInput.click();
});
uploadButton.dataset.listenerAttached = true;
}
const removeItemButton = item.querySelector('.btnRemoveLantai');
if (removeItemButton && !removeItemButton.dataset.listenerAttached) {
removeItemButton.addEventListener('click', () => {
this.removeItem(item);
});
removeItemButton.dataset.listenerAttached = true;
}
}
handleDrop(event, fileInput) {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
const previewContainer = fileInput.closest('.dropzone').querySelector('.preview-container');
this.processFiles(files, fileInput, previewContainer);
}
handleFileInput(fileInput) {
if (!fileInput || !fileInput.files) return;
const files = fileInput.files;
const dropzone = fileInput.closest('.dropzone');
const previewContainer = dropzone.querySelector('.preview-container');
// Proses file
this.processFiles(files, fileInput, previewContainer);
}
processFiles(files, fileInput, previewContainer) {
const existingPreviews = previewContainer.querySelectorAll('.preview-item img');
const existingFiles = Array.from(existingPreviews).map(img => img.src);
const maxFiles = this.options.maxFiles;
const remainingSlots = maxFiles - existingPreviews.length;
const filesToAdd = Array.from(files).filter(file => {
const reader = new FileReader();
reader.onload = (e) => {
return !existingFiles.includes(e.target.result);
};
reader.readAsDataURL(file);
return true;
}).slice(0, remainingSlots);
if (filesToAdd.length === 0) {
alert(`Maksimal ${maxFiles} foto per lantai`);
return;
}
filesToAdd.forEach(file => {
const isValidType = this.options.accept === '*' || file.type.match(this.options.accept
.replace('*', '.*'));
if (isValidType) {
this.createFilePreview(file, previewContainer, fileInput);
} else {
alert(`File ${file.name} tidak valid. Hanya file gambar yang diperbolehkan.`);
}
});
}
createFilePreview(file, previewContainer, fileInput) {
const reader = new FileReader();
reader.onload = (e) => {
const imgWrapper = document.createElement('div');
imgWrapper.classList.add('preview-item', 'relative');
const img = document.createElement('img');
img.src = e.target.result;
img.classList.add('w-full', 'h-40', 'object-cover', 'rounded-lg');
const removeBtn = document.createElement('button');
removeBtn.type = 'button';
removeBtn.classList.add(
'absolute', 'top-2', 'right-2',
'btn', 'btn-sm', 'btn-danger', 'btn-icon',
'btnRemoveFoto'
);
removeBtn.innerHTML = '<i class="ki-solid ki-cross"></i>';
removeBtn.addEventListener('click', () => {
imgWrapper.remove();
this.updatePreviewContainerVisibility(previewContainer);
this.resetFileInput(fileInput);
});
imgWrapper.appendChild(img);
imgWrapper.appendChild(removeBtn);
previewContainer.appendChild(imgWrapper);
this.updatePreviewContainerVisibility(previewContainer);
};
reader.readAsDataURL(file);
}
updatePreviewContainerVisibility(previewContainer) {
const previewItems = previewContainer.querySelectorAll('.preview-item');
previewContainer.style.display = previewItems.length > 0 ? 'grid' : 'none';
}
resetFileInput(fileInput) {
fileInput.value = '';
}
removeItem(item) {
this.container.removeChild(item);
this.updateRemoveButtonVisibility();
}
updateRemoveButtonVisibility() {
const removeButtons = this.container.querySelectorAll('.btnRemoveLantai');
removeButtons.forEach((btn, index) => {
btn.style.display = index === 0 ? 'none' : 'block';
});
}
processExistingFiles() {
this.container.innerHTML = '';
const groupedFiles = this.groupFilesByItem(this.options.existingFiles);
Object.keys(groupedFiles).forEach((itemKey, index) => {
const itemCount = index + 1;
const newItem = document.createElement("div");
newItem.classList.add("dynamic-item", "w-full", "mb-4");
newItem.innerHTML = this.generateItemHTML(itemCount);
this.container.appendChild(newItem);
const previewContainer = newItem.querySelector(".preview-container");
const fileInput = newItem.querySelector(".file-input");
groupedFiles[itemKey].forEach(file => {
this.addExistingFilePreview(previewContainer, fileInput, file, itemCount);
});
// this.attachEventListeners(newItem);
});
this.updateRemoveButtonVisibility();
}
groupFilesByItem(files) {
return files.reduce((acc, file) => {
const itemKey = file.item || '1';
if (!acc[itemKey]) {
acc[itemKey] = [];
}
acc[itemKey].push(file);
return acc;
}, {});
}
addExistingFilePreview(previewContainer, fileInput, file, itemCount) {
const imgWrapper = document.createElement("div");
imgWrapper.classList.add("relative", "preview-item");
const img = document.createElement("img");
img.src = file.url || file.path;
img.classList.add("w-full", "h-auto", "object-cover", "rounded-lg");
const removeBtn = document.createElement("button");
removeBtn.type = "button";
removeBtn.classList.add("absolute", "top-2", "right-2", "btn", "btn-danger", "btn-sm");
removeBtn.innerHTML = '<i class="ki-outline ki-cross"></i>';
removeBtn.addEventListener("click", () => {
imgWrapper.remove();
this.updatePreviewContainerVisibility(previewContainer);
});
imgWrapper.appendChild(img);
imgWrapper.appendChild(removeBtn);
previewContainer.appendChild(imgWrapper);
this.updatePreviewContainerVisibility(previewContainer);
}
getAllUploadedFiles() {
const files = [];
this.container.querySelectorAll('.file-input').forEach(input => {
if (input.files.length > 0) {
files.push(...input.files);
}
});
return files;
}
}
</script>