Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ make checks-before-pr
- Add `void` return type to all test methods
- Name tests descriptively without `test` prefix duplication
- Use `@testWith` and data providers when possible to avoid duplicated tests
- Don't add comments to describe tests; use the message argument of `assert*()` methods

### Test Fixtures
- Data fixtures in each functional app in `tests/Functional/Apps/`
Expand Down
21 changes: 21 additions & 0 deletions assets/css/easyadmin-theme/images.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/* Image preview in forms
/* ------------------------------------------------------------------------- */
.ea-imageupload-preview {
margin-block-end: 10px;
}
.ea-imageupload-preview .ea-lightbox-thumbnail {
display: inline-block;
max-inline-size: 200px;
margin-inline-end: 8px;
margin-block-end: 8px;
}
.ea-imageupload-preview img {
border: 1px solid var(--datalist-border-color);
border-radius: var(--border-radius);
max-block-size: 150px;
padding: 4px;
}
.ea-imageupload-preview img:hover {
border-color: var(--form-input-border-color);
}

/* Images and lightbox
/* ------------------------------------------------------------------------- */
.detail .field-image .form-control {
Expand Down
90 changes: 76 additions & 14 deletions assets/js/field-image.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,84 @@
import * as basicLightbox from 'basiclightbox';

document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.ea-lightbox-thumbnail').forEach((imageElement) => {
new Image(imageElement);
});
initLightboxes();
initImagePreviews();
});

class Image {
constructor(field) {
this.field = field;
this.field.addEventListener('click', this.#renderLightbox.bind(this));
}
document.addEventListener('ea.collection.item-added', () => {
initLightboxes();
initImagePreviews();
});

function initLightboxes() {
document.querySelectorAll('.ea-lightbox-thumbnail:not([data-ea-lightbox-initialized])').forEach((element) => {
element.setAttribute('data-ea-lightbox-initialized', '');
element.addEventListener('click', (e) => {
e.preventDefault();
const lightboxContent = document.querySelector(
element.getAttribute('data-ea-lightbox-content-selector')
).innerHTML;
const lightbox = basicLightbox.create(lightboxContent);
lightbox.show();
});
});
}

function initImagePreviews() {
document.querySelectorAll('.ea-imageupload:not([data-ea-imageupload-initialized])').forEach((container) => {
container.setAttribute('data-ea-imageupload-initialized', '');

const fileInput = container.querySelector('input[type="file"]');
const previewContainer = container.querySelector('[data-ea-imageupload-preview]');
if (!fileInput || !previewContainer) {
return;
}

fileInput.addEventListener('change', () => {
updateImagePreview(fileInput, previewContainer);
});

const deleteButton = container.querySelector('.ea-fileupload-delete-btn');
if (deleteButton) {
deleteButton.addEventListener('click', () => {
previewContainer.replaceChildren();
});
}
});
}

function updateImagePreview(fileInput, container) {
container.replaceChildren();

for (const file of fileInput.files) {
if (!file.type.startsWith('image/')) {
continue;
}

const objectUrl = URL.createObjectURL(file);
const lightboxId = `ea-lightbox-preview-${Math.random().toString(36).substring(2, 10)}`;

#renderLightbox() {
const lightboxContent = document.querySelector(
this.field.getAttribute('data-ea-lightbox-content-selector')
).innerHTML;
const lightbox = basicLightbox.create(lightboxContent);
lightbox.show();
const link = document.createElement('a');
link.href = '#';
link.className = 'ea-lightbox-thumbnail';
link.setAttribute('data-ea-lightbox-content-selector', `#${lightboxId}`);

const img = document.createElement('img');
img.src = objectUrl;
img.className = 'img-fluid';
link.appendChild(img);

const lightboxDiv = document.createElement('div');
lightboxDiv.id = lightboxId;
lightboxDiv.className = 'ea-lightbox';

const lightboxImg = document.createElement('img');
lightboxImg.src = objectUrl;
lightboxDiv.appendChild(lightboxImg);

container.appendChild(link);
container.appendChild(lightboxDiv);
}

initLightboxes();
}
6 changes: 6 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\EaMoneyType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\FileUploadType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\FiltersFormType;
use EasyCorp\Bundle\EasyAdminBundle\Form\Type\ImageUploadType;
use EasyCorp\Bundle\EasyAdminBundle\Intl\IntlFormatter;
use EasyCorp\Bundle\EasyAdminBundle\Maker\ClassMaker;
use EasyCorp\Bundle\EasyAdminBundle\Menu\MenuItemMatcher;
Expand Down Expand Up @@ -312,6 +313,11 @@
->arg(1, service('filesystem'))
->tag('form.type')

->set(ImageUploadType::class)
->arg(0, param('kernel.project_dir'))
->arg(1, service('filesystem'))
->tag('form.type')

->set(EaMoneyType::class)
->tag('form.type')

Expand Down
14 changes: 13 additions & 1 deletion doc/fields/ImageField.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Basic Information

* **PHP Class**: ``EasyCorp\Bundle\EasyAdminBundle\Field\ImageField``
* **Doctrine DBAL Type** used to store this value: ``string``
* **Symfony Form Type** used to render the field: ``FileUploadType``, a custom
* **Symfony Form Type** used to render the field: ``ImageUploadType``, a custom
form type created by EasyAdmin
* **Rendered as**:

Expand Down Expand Up @@ -54,6 +54,18 @@ option to define the constraints applied to the uploaded file::

yield ImageField::new('...')->setFileConstraints(new Image(maxSize: '100k'));

showPreview
~~~~~~~~~~~

By default, a thumbnail preview of the image is displayed in form pages (``edit``
and ``new``). When editing an existing entity, it shows the current image; when
selecting a new file, it shows a client-side preview of the selected image.
Clicking on the preview opens a lightbox to see the image at full size.

Use this option to disable the image preview::

yield ImageField::new('...')->showPreview(false);

setUploadedFileNamePattern
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion public/app.912702e5.css → public/app.42998e24.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions public/entrypoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"entrypoints": {
"app": {
"css": [
"/app.912702e5.css"
"/app.42998e24.css"
],
"js": [
"/app.e8e4fe24.js"
Expand Down Expand Up @@ -48,7 +48,7 @@
},
"field-image": {
"js": [
"/field-image.c338d2ad.js"
"/field-image.66366cf7.js"
]
},
"field-slug": {
Expand Down
1 change: 1 addition & 0 deletions public/field-image.66366cf7.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion public/field-image.c338d2ad.js

This file was deleted.

4 changes: 2 additions & 2 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"app.css": "app.912702e5.css",
"app.css": "app.42998e24.css",
"app.js": "app.e8e4fe24.js",
"form.js": "form.4f66b3e8.js",
"page-layout.js": "page-layout.6e9fe55d.js",
Expand All @@ -9,7 +9,7 @@
"field-code-editor.js": "field-code-editor.877c61fa.js",
"field-collection.js": "field-collection.b4d3688b.js",
"field-file-upload.js": "field-file-upload.5c32db38.js",
"field-image.js": "field-image.c338d2ad.js",
"field-image.js": "field-image.66366cf7.js",
"field-slug.js": "field-slug.ba7fb8e5.js",
"field-textarea.js": "field-textarea.98322d83.js",
"field-text-editor.css": "field-text-editor.d426785c.css",
Expand Down
2 changes: 2 additions & 0 deletions src/Field/Configurator/ImageConfigurator.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public function configure(FieldDto $field, EntityDto $entityDto, AdminContext $c
$field->setTemplateName('label/empty');
}

$field->setFormTypeOption('show_image_preview', $field->getCustomOption(ImageField::OPTION_SHOW_PREVIEW));

if (!\in_array($context->getCrud()->getCurrentPage(), [Crud::PAGE_EDIT, Crud::PAGE_NEW], true)) {
return;
}
Expand Down
Loading
Loading