from django import forms from django.utils.safestring import mark_safe from django.utils.html import format_html from django.urls import reverse from ..models.images import ImageLibrary class ImageLibraryWidget(forms.Select): """ Custom widget for selecting images from the library with thumbnails. """ def __init__(self, attrs=None, choices=(), show_thumbnails=True): self.show_thumbnails = show_thumbnails super().__init__(attrs, choices) def format_value(self, value): """ Format the selected value for display. """ if value is None: return "" return str(value) def render(self, name, value, attrs=None, renderer=None): """ Render the widget with thumbnails. """ if attrs is None: attrs = {} # Add CSS class for styling attrs["class"] = attrs.get("class", "") + " image-library-select" # Get all images for the select options images = ImageLibrary.objects.all().order_by("name") # Build choices with thumbnails choices = [("", "--- Select an image ---")] for image in images: thumbnail_html = "" if self.show_thumbnails and image.image: # Use img tag for all images in dropdowns to maintain functionality # SVG files will still display correctly with img tag thumbnail_html = format_html( ' ', image.image.url, ) choice_text = ( f"{image.name} ({image.get_category_display()}){thumbnail_html}" ) choices.append((image.pk, choice_text)) # Build the select element select_html = format_html( '', name, attrs.get("id", ""), self._build_attrs_string(attrs), self._build_options(choices, value), ) # Add preview area preview_html = "" if value: try: image = ImageLibrary.objects.get(pk=value) # Use img tag for all images in preview for consistency # Add SVG indicator in the text if it's an SVG file svg_indicator = " (SVG)" if image.is_svg() else "" preview_html = format_html( '
' '' '

{} - {}x{} - {}{}

' "
", image.image.url, image.name, image.width or "?", image.height or "?", image.get_file_size_display(), svg_indicator, ) except ImageLibrary.DoesNotExist: pass # Add JavaScript for preview updates js_html = format_html( "", attrs.get("id", ""), ) return mark_safe(select_html + preview_html + js_html) def _build_attrs_string(self, attrs): """ Build HTML attributes string. """ attr_parts = [] for key, value in attrs.items(): if key != "id": # id is handled separately attr_parts.append(f'{key}="{value}"') return " " + " ".join(attr_parts) if attr_parts else "" def _build_options(self, choices, selected_value): """ Build option elements for the select. """ options = [] for value, text in choices: selected = "selected" if str(value) == str(selected_value) else "" options.append(f'') return "".join(options) class ImageLibraryField(forms.ModelChoiceField): """ Custom form field for selecting images from the library. """ def __init__(self, queryset=None, widget=None, show_thumbnails=True, **kwargs): if queryset is None: queryset = ImageLibrary.objects.all() if widget is None: widget = ImageLibraryWidget(show_thumbnails=show_thumbnails) super().__init__(queryset=queryset, widget=widget, **kwargs) def label_from_instance(self, obj): """ Return the label for an image instance. """ return f"{obj.name} ({obj.get_category_display()})"