-
-
Save Qubadi/5793d9bd3fbc996fb35cee7e50031f33 to your computer and use it in GitHub Desktop.
UPDATED: 04.11.2024 | |
Copy the following HTML code and create a HTML snippet using your snippet plugins. | |
Paste the code into the plugin and save it. | |
Don't forget to add MIME types (image formats), for example, PNG and JPEG, in the media field where it shows 'Allow MIME types. | |
______________________________________________________ | |
<style> | |
/* Custom styles for the file upload field */ | |
.jet-form-builder__field-wrap.jet-form-builder-file-upload { | |
background: #ecf6ff !important; | |
border: 3px dashed #c7d4e1 !important; | |
padding: 20px !important; | |
text-align: center; | |
position: relative; | |
margin-bottom: 20px; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
border-radius: 6px !important; | |
transition: border-color 0.3s ease, background-color 0.3s ease; | |
} | |
/* Styles for the image upload */ | |
.jet-form-builder-file-upload__file img { | |
display: block; | |
width: 100%; | |
height: 100% !important; | |
padding: 0; | |
margin: 0; | |
-o-object-fit: cover; | |
object-fit: cover; | |
-o-object-position: center center; | |
object-position: center center; | |
border-radius: 6px !important; | |
box-shadow: 0 0 30px -8px rgba(0, 0, 0, 0.24) !important; | |
} | |
/* Styles for image content */ | |
.jet-form-builder-file-upload__content { | |
min-height: auto !important; | |
} | |
/* Styles for the custom "Choose File" and "File Uploaded" buttons */ | |
.addfile { | |
padding: 10px 20px; | |
background-color: #0037fd !important; | |
color: #ffffff !important; | |
border: none !important; | |
font-size: 16px; | |
font-weight: 600; | |
cursor: pointer; | |
border-radius: 6px; | |
margin-top: 10px; /* Space between button and label */ | |
} | |
.addfile:hover { | |
background-color: #000000 !important; | |
color: #ffffff !important; | |
} | |
/* Styles for the label that shows file upload status */ | |
.labeladdfile { | |
padding: 6px 12px; | |
background-color: transparent; | |
color: #000000 !important; | |
font-size: 12px; | |
font-weight: 400; | |
display: block; | |
margin-top: 10px; | |
border-radius: 6px; | |
} | |
/* Class added when files are uploaded */ | |
.files-uploaded { | |
background-color: #09b872 !important; | |
padding: 6px 12px; | |
color: #ffffff !important; | |
border-radius: 6px; | |
} | |
/* Hide the default file input visually */ | |
.jet-form-builder-file-upload__input { | |
display: none; | |
} | |
/* Drag and drop hover effect */ | |
.jet-form-builder__field-wrap.jet-form-builder-file-upload.dragover { | |
border-color: #0037fd !important; | |
background: rgba(0, 55, 253, 0.1) !important; | |
} | |
/* New styles for drag and drop text and icon */ | |
.drag-drop-text { | |
font-size: 30px; | |
font-weight: 700; | |
color: #333; | |
margin-bottom: 10px; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
transition: opacity 0.3s ease, height 0.3s ease; | |
height: auto; | |
} | |
.drag-drop-text.hidden { | |
opacity: 0; | |
height: 0; | |
overflow: hidden; | |
} | |
.drag-drop-text .icon { | |
font-size: 24px; | |
margin-bottom: 10px; | |
} | |
.allowed-mime-types { | |
font-size: 14px; | |
color: #666; | |
margin-bottom: 10px; | |
transition: opacity 0.3s ease, height 0.3s ease; | |
height: auto; | |
} | |
.allowed-mime-types.hidden { | |
opacity: 0; | |
height: 0; | |
overflow: hidden; | |
} | |
.allowed-mime-types .formats { | |
font-weight: bold; | |
} | |
.or-text { | |
font-size: 14px; | |
color: #666; | |
margin-bottom: 10px; | |
transition: opacity 0.3s ease, height 0.3s ease; | |
height: auto; | |
} | |
.or-text.hidden { | |
opacity: 0; | |
height: 0; | |
overflow: hidden; | |
} | |
/* Responsive adjustments */ | |
@media (max-width: 767px) { | |
.addfile, .labeladdfile { | |
padding: 8px 16px; | |
font-size: 12px; | |
} | |
} | |
@media (max-width: 1024px) { | |
.addfile, .labeladdfile { | |
padding: 8px 16px; | |
font-size: 12px; | |
} | |
} | |
</style> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
const { addAction } = window.JetPlugins.hooks; | |
addAction('jet.fb.input.makeReactive', 'set-upload-labels', function(input) { | |
if (!input?.nodes?.length || !input.nodes[0].classList.contains('jet-form-builder-file-upload__input')) { | |
return; | |
} | |
const $ = jQuery; | |
const upload = $(input.nodes[0]); | |
const fields = $(input.nodes[0].closest('.jet-form-builder-file-upload__fields')); | |
// Extract allowed MIME types from the input element and format them | |
let mimeTypes = upload.attr('accept')?.split(',').map(type => type.split('/')[1].trim()) || []; | |
if (!fields.find('.addfile').length) { | |
fields.prepend(` | |
<div class="drag-drop-text"> | |
<i class="fas fa-file-upload icon"></i> | |
Drag and drop your files here | |
</div> | |
<div class="allowed-mime-types"> | |
Files supported: <span class="formats">${mimeTypes.join(', ')}</span> | |
</div> | |
<div class="or-text">OR</div> | |
`); | |
fields.append(`<input type="button" class="addfile" value="Choose File"/>`); | |
fields.append(`<div class="labeladdfile"></div>`); | |
} | |
const labelAdd = fields.find('.labeladdfile'); | |
const buttonAdd = fields.find('.addfile'); | |
const dragDropText = fields.find('.drag-drop-text'); | |
const allowedMimeText = fields.find('.allowed-mime-types'); | |
const orText = fields.find('.or-text'); | |
upload.css('display', 'none'); | |
buttonAdd.click(function() { | |
upload.trigger('click'); | |
}); | |
function updateFileLabel() { | |
const fileCount = upload[0].files.length; | |
if (fileCount > 0) { | |
buttonAdd.val('File Uploaded'); | |
labelAdd.html(`Uploaded files (${fileCount})`); | |
labelAdd.addClass('files-uploaded'); | |
buttonAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
labelAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
} else { | |
resetFileLabel(); | |
} | |
} | |
function resetFileLabel() { | |
// Smoothly hide the button and label | |
buttonAdd.css({ opacity: 0, transform: 'scale(0.9)' }); | |
labelAdd.css({ opacity: 0, transform: 'scale(0.9)' }); | |
// After the transition, reset them | |
setTimeout(() => { | |
buttonAdd.val('Choose File'); | |
labelAdd.html('Choose File'); | |
labelAdd.removeClass('files-uploaded'); | |
buttonAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
labelAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
$('.jet-form-builder-file-upload__file').remove(); // Remove any previews | |
}, 300); | |
} | |
const fieldWrap = fields.closest('.jet-form-builder__field-wrap.jet-form-builder-file-upload'); | |
fieldWrap.on('dragover', function(event) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
fieldWrap.addClass('dragover'); | |
dragDropText.addClass('hidden'); | |
allowedMimeText.addClass('hidden'); | |
orText.addClass('hidden'); | |
}); | |
fieldWrap.on('dragleave', function(event) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
fieldWrap.removeClass('dragover'); | |
if (input.value.get().length === 0) { | |
dragDropText.removeClass('hidden'); | |
allowedMimeText.removeClass('hidden'); | |
orText.removeClass('hidden'); | |
} | |
}); | |
fieldWrap.on('drop', function(event) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
fieldWrap.removeClass('dragover'); | |
let files = event.originalEvent.dataTransfer.files; | |
{ | |
const dt = new DataTransfer(); | |
// Keep previously selected | |
for (let i = 0; i < upload[0].files.length; i++) { | |
dt.items.add(upload[0].files[i]); | |
} | |
// Add newly dropped | |
for (let i = 0; i < files.length; i++) { | |
dt.items.add(files[i]); | |
} | |
// Remove duplicates | |
for (let i = 0; i < dt.files.length; i++) { | |
for (let j = i + 1; j < dt.files.length; j++) { | |
if ( | |
dt.files[i].name === dt.files[j].name && | |
dt.files[i].lastModified === dt.files[j].lastModified && | |
dt.files[i].size === dt.files[j].size && | |
dt.files[i].type === dt.files[j].type | |
) { | |
dt.items.remove(j); | |
j--; | |
} | |
} | |
} | |
files = dt.files; | |
} | |
// Assign files, trigger change, rely on JetFormBuilder’s validation | |
upload[0].files = files; | |
const eventChange = new Event('change', { bubbles: true }); | |
upload[0].dispatchEvent(eventChange); | |
// Give JetFormBuilder time to detect error (if any) | |
setTimeout(() => { | |
const errorMessage = $('.jet-form-builder-row.field-has-error .error-message') | |
.text().trim(); | |
if (errorMessage) { | |
alert(errorMessage); | |
window.location.reload(); | |
resetFileInput(); | |
} | |
}, 300); // Increased to 300ms to ensure validation is done | |
}); | |
// We rely on JetFormBuilder’s own validation | |
function validateFiles(files) { | |
return true; | |
} | |
function showErrorMessage() { | |
const errorMessage = $('.jet-form-builder-row.field-has-error .error-message') | |
.text().trim(); | |
if (errorMessage) { | |
alert(errorMessage); | |
resetFileInput(); | |
setTimeout(() => { | |
window.location.reload(); | |
}, 700); | |
} | |
} | |
/* | |
* Merge chosen files, remove duplicates, | |
* then let JetFormBuilder do its validation | |
*/ | |
upload.on('change', function() { | |
let chosenFiles = upload[0].files; | |
{ | |
const dt = new DataTransfer(); | |
for (let i = 0; i < upload[0].files.length; i++) { | |
dt.items.add(upload[0].files[i]); | |
} | |
// Remove duplicates (same logic as drag-and-drop) | |
for (let i = 0; i < dt.files.length; i++) { | |
for (let j = i + 1; j < dt.files.length; j++) { | |
if ( | |
dt.files[i].name === dt.files[j].name && | |
dt.files[i].lastModified === dt.files[j].lastModified && | |
dt.files[i].size === dt.files[j].size && | |
dt.files[i].type === dt.files[j].type | |
) { | |
dt.items.remove(j); | |
j--; | |
} | |
} | |
} | |
chosenFiles = dt.files; | |
upload[0].files = chosenFiles; | |
} | |
// Wait for JetFormBuilder to validate before checking for errors | |
setTimeout(() => { | |
const errorMessage = $('.jet-form-builder-row.field-has-error .error-message') | |
.text().trim(); | |
if (errorMessage) { | |
alert(errorMessage); | |
window.location.reload(); | |
resetFileInput(); | |
} else { | |
// If no error, update the file label | |
updateFileLabel(); | |
} | |
}, 300); | |
}); | |
// Keep the real-time UI changes | |
input.value.watch(function() { | |
const fileCount = this.current.length; | |
const fileText = fileCount > 0 ? `Uploaded files (${fileCount})` : ''; | |
buttonAdd.val(fileCount > 0 ? 'File Uploaded' : 'Choose File'); | |
labelAdd.html(fileText); | |
labelAdd.toggleClass('files-uploaded', fileCount > 0); | |
if (fileCount > 0) { | |
dragDropText.addClass('hidden'); | |
allowedMimeText.addClass('hidden'); | |
orText.addClass('hidden'); | |
} else { | |
dragDropText.removeClass('hidden'); | |
allowedMimeText.removeClass('hidden'); | |
orText.removeClass('hidden'); | |
} | |
}); | |
$(document).on('click', '.jet-form-builder-file-upload__file-remove', function() { | |
setTimeout(() => { | |
if ($('.jet-form-builder-file-upload__file').length === 0) { | |
resetFileLabel(); | |
} else { | |
buttonAdd.val('File Uploaded'); | |
labelAdd.html(`Uploaded files (${$('.jet-form-builder-file-upload__file').length})`); | |
labelAdd.addClass('files-uploaded'); | |
buttonAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
labelAdd.css({ opacity: 1, transform: 'scale(1)' }); | |
} | |
}, 100); | |
}); | |
const successMessageObserver = new MutationObserver((mutationsList) => { | |
for (let mutation of mutationsList) { | |
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { | |
const successMessage = $(mutation.addedNodes).find('.jet-form-builder-message--success'); | |
if (successMessage.length > 0) { | |
resetFileLabel(); | |
} | |
} | |
} | |
}); | |
const formContainer = $('.jet-form-builder')[0]; | |
if (formContainer) { | |
successMessageObserver.observe(formContainer, { childList: true, subtree: true }); | |
} | |
function resetFileInput() { | |
upload.val(''); | |
resetFileLabel(); | |
input.value.set([]); | |
} | |
}); | |
}); | |
</script> |
Hello friendly people
I write from Lisbon (Portugal) and just stopped by to say that you are fantastic, your "codes" are a valuable help. I share what someone already said here, you should get help (€€€) from Crocoblock. True public knowledge sharing service. Big Hug Mário Freiria
Happy to hear that my codes are helpful. I create my codes completely for free, and I work independently. Follow us here—I’ll be sharing new codes and updating existing ones as I’m home and have time.
@Qubadi thanks so much for this. I'm having a few little issues and I was hoping you could help me make it work. Please take a look at the screen recording: https://www.loom.com/share/b9e939fc4bf74ce0993f1a656dc63379?sid=7fc7b541-6ef0-4b9f-bbda-f9d3d9d9fc6e
I've updated the image limit in your code to 5.
The first issue is with the duplicate images being dropped in. When you upload an image, it goes in, when you then drop-in the same image, it won't appear since it's a duplicate which is correct, but the image still counts towards the limits. So in green bar you can see the duplicate image has been added in.
Now when I reach the limit of 5 images, I don't get any popup message informing about the limits.
Instead, all of the previously uploaded images will now disappear and I'm not able to re-upload or re-drop any more images even if there are currently no images showing in the drop zone.
So I wonder if this has anything to do with the first issue, basically the images still being all counted in and for that reason not being able to upload any more.
I hope this makes any sense, but the video recording should be quite self-explanatory.
@Qubadi thanks so much for this. I'm having a few little issues and I was hoping you could help me make it work. Please take a look at the screen recording: https://www.loom.com/share/b9e939fc4bf74ce0993f1a656dc63379?sid=7fc7b541-6ef0-4b9f-bbda-f9d3d9d9fc6e
I've updated the image limit in your code to 5. The first issue is with the duplicate images being dropped in. When you upload an image, it goes in, when you then drop-in the same image, it won't appear since it's a duplicate which is correct, but the image still counts towards the limits. So in green bar you can see the duplicate image has been added in.
Now when I reach the limit of 5 images, I don't get any popup message informing about the limits.
Instead, all of the previously uploaded images will now disappear and I'm not able to re-upload or re-drop any more images even if there are currently no images showing in the drop zone.
So I wonder if this has anything to do with the first issue, basically the images still being all counted in and for that reason not being able to upload any more.
I hope this makes any sense, but the video recording should be quite self-explanatory.
Hello
Please add the lasted updated code, and i have try the code again from my side, and it works with any issue,
See the image too please. If u still have issue, please contact me on Facebook group for Crocoblock community.
@Qubadi Thank you for sharing the code! Please add or implement a new functionality that enables image rearrangement via drag-and-drop, including on mobile devices. Currently, rearranging images is not possible on mobile, so this enhancement would be highly beneficial
Hello friendly people
I write from Lisbon (Portugal) and just stopped by to say that you are fantastic, your "codes" are a valuable help. I share what someone already said here, you should get help (€€€) from Crocoblock. True public knowledge sharing service. Big Hug Mário Freiria