Skip to content

Instantly share code, notes, and snippets.

@gonvaled
Last active June 26, 2021 14:48

Revisions

  1. gonvaled renamed this gist Nov 1, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. gonvaled created this gist Nov 1, 2015.
    13 changes: 13 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    from django.forms import ModelForm, FileField

    from .models import Campaign
    from .widgets import ImagePreviewWidget


    class DesignCampaignForm(ModelForm):

    brand_logo = FileField(widget=ImagePreviewWidget)

    class Meta:
    model = Campaign
    fields = ['brand_logo', 'brand_description']
    5 changes: 5 additions & 0 deletions image-preview-widget.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    /* Hide the input element for the image-preview widgets.
    The "open file" dialog will be triggered by a click on the image preview */
    input[type="file"].image-preview {
    display: none;
    }
    35 changes: 35 additions & 0 deletions image-preview-widget.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    function ImageRefresher() {
    };

    function init(inputId) {
    var that = this;
    this.inputId = '#' + inputId;
    this.imgId = '#' + inputId + '_img';
    this.origData = $(this.imgId).attr('src');
    $(this.inputId).change(function(){
    that.readURL(this);
    });
    }

    function readURL(input) {
    var that = this;
    if (input.files && input.files[0]) {
    var reader = new FileReader();
    reader.onload = function (e) {
    $(that.imgId).attr('src', e.target.result);
    }
    reader.readAsDataURL(input.files[0]);
    } else {
    $(this.imgId).attr('src', this.origData);
    }
    }

    ImageRefresher.prototype.init = init;
    ImageRefresher.prototype.readURL = readURL;

    window.onload = function() {
    $('.image-preview').each(function(index) {
    var refresher = new ImageRefresher();
    refresher.init(this.id);
    });
    };
    60 changes: 60 additions & 0 deletions widgets.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    from django.forms.widgets import ClearableFileInput, Input, CheckboxInput
    from django.utils.safestring import mark_safe
    from django.utils.html import conditional_escape, format_html, html_safe


    class ImagePreviewWidget(ClearableFileInput):

    '''Basically a ClearableFileInput widget, but:
    - remove from the template most clutter: we leave only the image, the clear and the <input>
    - we define a class for the input, so that we can hide it with CSS
    '''

    # The "for" in the <label> allows to open the "open file" dialog by clicking on the image, no js involved
    template_with_initial = (
    '<label for=%(id_for_label)s><img id="%(img_id)s" src="/media/%(initial)s" width="100px"></label>'
    '%(clear_template)s<br />%(input)s'
    )

    INPUT_CLASS = 'image-preview' # This is the class of the <input> element, which we want to hide

    def __init__(self, attrs=None):
    super(ImagePreviewWidget, self).__init__(attrs)
    self.attrs['class'] = self.INPUT_CLASS

    # Override ClearableFileInput:render
    def render(self, name, value, attrs=None):
    id_for_label = self.id_for_label(attrs.get('id'))
    substitutions = {
    'initial_text': self.initial_text,
    'input_text': self.input_text,
    'clear_template': '',
    'clear_checkbox_label': self.clear_checkbox_label,
    # We need the id, so that clicking in the image triggers the "Open file" native window
    'id_for_label': id_for_label,
    #
    'img_id': id_for_label + '_img',
    }
    template = '%(input)s'
    substitutions['input'] = Input.render(self, name, value, attrs) # call Input.render directly

    if self.is_initial(value):
    template = self.template_with_initial
    substitutions.update(self.get_template_substitution_values(value))
    if not self.is_required:
    checkbox_name = self.clear_checkbox_name(name)
    checkbox_id = self.clear_checkbox_id(checkbox_name)
    substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
    substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
    substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
    substitutions['clear_template'] = self.template_with_clear % substitutions

    return mark_safe(template % substitutions)


    class Media:

    css = {
    'all': ('css/image-preview-widget.css',)
    }
    js = ('js/image-preview-widget.js', )