perbaikan fominspeksi upload foto
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user