perbaikan foto dan penambahan basic data foto objek jaminan, print-out
This commit is contained in:
@@ -1,71 +1,76 @@
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const ruteLainnyaDiv = document.getElementById("ruteLainnya");
|
||||
// const lantaiLainnyaDiv = document.getElementById("lantaiLainnya");
|
||||
const lantaiLainnyaDiv = document.getElementById("lantaiLainnya");
|
||||
|
||||
// Function to add delete event listeners to existing buttons
|
||||
function addDeleteListeners(container) {
|
||||
container.querySelectorAll(".delete-btn").forEach(button => {
|
||||
button.addEventListener("click", function() {
|
||||
this.closest(
|
||||
".flex.items-baseline.flex-wrap.lg\\:flex-nowrap.gap-2\\.5.mb-5"
|
||||
).remove();
|
||||
".flex.items-baseline.flex-wrap.lg\\:flex-nowrap.gap-2\\.5.mb-5")
|
||||
.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add delete listeners to existing buttons
|
||||
addDeleteListeners(ruteLainnyaDiv);
|
||||
// addDeleteListeners(lantaiLainnyaDiv);
|
||||
|
||||
// Create new div for additional items
|
||||
function createNewDiv(container, inputName) {
|
||||
const newDiv = document.createElement("div");
|
||||
newDiv.className = "flex items-baseline flex-wrap lg:flex-nowrap gap-2.5 mb-5";
|
||||
|
||||
const index = container.querySelectorAll(".flex.items-baseline")
|
||||
.length; // Get index for dynamic IDs
|
||||
|
||||
newDiv.innerHTML = `
|
||||
<div class="flex items-baseline w-full flex-wrap lg:flex-nowrap gap-2.5 mb-5" id="photoContainer">
|
||||
<label class="flex flex-col form-label max-w-56">
|
||||
Masukkan nama ${inputName}
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<div class="flex flex-wrap items-baseline w-full gap-4">
|
||||
<img id="foto_${inputName}-preview-${index}"
|
||||
src="{{ isset($formFoto['gerbang']) ? asset('storage/' . $formFoto['gerbang']) : '' }}"
|
||||
alt="Foto Gerbong" class="mt-2 max-w-full h-auto"
|
||||
style="{{ isset($formFoto['gerbang']) ? '' : 'display: none;' }} width: 30rem;">
|
||||
|
||||
<div class="flex flex-col lg:flex-row gap-2 w-full">
|
||||
<div class="flex flex-wrap items-baseline px-2">
|
||||
<input class="input" type="text" name="name_${inputName}[]">
|
||||
</div>
|
||||
<div class=" w-full flex flex-col gap-2">
|
||||
<img id="foto_${inputName}-preview"
|
||||
src="{{ isset($formFoto['gerbang']) ? asset('storage/' . $formFoto['gerbang']) : '' }}"
|
||||
alt="Foto Gerbong" class="mt-2 max-w-full h-auto"
|
||||
style="{{ isset($formFoto['gerbang']) ? '' : 'display: none;' }} width: 30rem;">
|
||||
|
||||
|
||||
<div class="input-group w-full flex gap-2">
|
||||
<input id="inputLainnya" type="file" name="foto_${inputName}[]"
|
||||
class="file-input file-input-bordered w-full" accept="image/*" capture="camera"
|
||||
onchange="previewImage(this, 'foto_${inputName}-preview')"
|
||||
>
|
||||
<button type="button" id="btnCamera" class="btn btn-light"
|
||||
data-modal-toggle="#cameraModal">
|
||||
<i class="ki-outline ki-abstract-33"></i> Camera
|
||||
<div class="input-group w-full flex flex-col gap-2">
|
||||
<div class="input-group w-full flex gap-2">
|
||||
<input id="inputLainnya-${index}" type="file" name="foto_${inputName}[]"
|
||||
class="file-input file-input-bordered w-full" accept="image/*"
|
||||
capture="camera" onchange="previewImage(this, 'foto_${inputName}-preview-${index}')">
|
||||
<button type="button" id="btnCamera-${index}" class="btn btn-light"
|
||||
data-modal-toggle="#cameraModal">
|
||||
<i class="ki-outline ki-abstract-33"></i> Camera
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-danger btn-sm delete-btn">
|
||||
<i class="ki-filled ki-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;x
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(newDiv);
|
||||
addDeleteListeners(container);
|
||||
addDeleteListeners(container); // Re-add listeners for delete buttons in the new div
|
||||
}
|
||||
|
||||
// Event listener for adding more items
|
||||
document.getElementById("btnAddMore").addEventListener("click", function() {
|
||||
createNewDiv(ruteLainnyaDiv, "rute_lainnya");
|
||||
});
|
||||
|
||||
// document.getElementById("btnAddMoreObject").addEventListener("click", function() {
|
||||
// createNewDiv(lantaiLainnyaDiv, "lantai_lainnya");
|
||||
// });
|
||||
document.getElementById("btnAddMoreObject").addEventListener("click", function() {
|
||||
createNewDiv(lantaiLainnyaDiv, "lantai_lainnya");
|
||||
});
|
||||
|
||||
function setupInputHandlers(containerId, buttonId, labelText, inputDataClass, buttonDeleteClass) {
|
||||
const addButton = document.getElementById(buttonId);
|
||||
@@ -185,13 +190,331 @@
|
||||
}
|
||||
|
||||
|
||||
setupInputHandlers('inputContainerRute', 'btnRute', 'Foto Rute Menuju Lokasi', 'file-input',
|
||||
'delete-btn');
|
||||
// setupInputHandlers('inputContainerRute', 'btnRute', 'Foto Rute Menuju Lokasi', 'file-input',
|
||||
// 'delete-btn');
|
||||
// setupInputHandlers('inputContainerLantai', 'btnLantai', 'Foto Lantai', 'file-input',
|
||||
// 'delete-btn');
|
||||
setupInputHandlers('inputContainerLingkungan', 'btnLingkungan', 'Lingkungan', 'file-input',
|
||||
'delete-btn');
|
||||
// setupInputHandlers('inputContainerLingkungan', 'btnLingkungan', 'Lingkungan', 'file-input',
|
||||
// 'delete-btn');
|
||||
|
||||
|
||||
});
|
||||
|
||||
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