Created
August 2, 2015 14:10
-
-
Save tino/655f515a56aff1931803 to your computer and use it in GitHub Desktop.
Using jQuery.guillotine in the Django Admin with Imagekit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.$ = django.jQuery; | |
window.jQuery = django.jQuery; // for guillotine | |
function showCropper(input, output_name, crop_width, crop_height) { | |
field = $(input); | |
if (input.files && input.files[0]) { | |
var reader = new FileReader(); | |
reader.onload = function (e) { | |
$('img.cropper').attr('src', e.target.result); | |
} | |
reader.readAsDataURL(input.files[0]); | |
} | |
$('img.cropper').on('load', function(){ | |
cropper = $(this); | |
cropper.guillotine({width: crop_width, height: crop_height, | |
onChange: function(data, action){ | |
$('input[name="' + output_name + '"]')[0].value = JSON.stringify(data); | |
} | |
}); | |
// Initial fit | |
cropper.guillotine('fit'); | |
// Bind button actions | |
$('#fit').click(function(){ cropper.guillotine('fit'); }); | |
$('#zoom_in').click(function(){ cropper.guillotine('zoomIn'); }); | |
$('#zoom_out').click(function(){ cropper.guillotine('zoomOut'); }); | |
cropper.show(); | |
field.parent().siblings('.cropper-frame').show() | |
field.parent().siblings('.cropper-buttons').show() | |
}); | |
} | |
window.showCropper = showCropper; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
from django import forms | |
from django.contrib import admin | |
from imagekit.admin import AdminThumbnail | |
from widgets import AdminClearableFileInputWithCrop | |
from .models import Item | |
class ItemAdmin(admin.ModelAdmin): | |
list_display = ('get_title', 'thumbnail', 'content_type', | |
'content_object', 'is_visible') | |
fields = ('content_type', 'object_id', 'title', 'subtitle', | |
'image', 'image_crop_dimensions', 'publication_date') | |
thumbnail = AdminThumbnail(image_field='admin_thumbnail') | |
def formfield_for_dbfield(self, db_field, **kwargs): | |
if db_field.name == 'image': | |
kwargs['widget'] = AdminClearableFileInputWithCrop | |
elif db_field.name == 'image_crop_dimensions': | |
kwargs['widget'] = forms.HiddenInput | |
return super(ItemAdmin, self).formfield_for_dbfield(db_field, **kwargs) | |
admin.site.register(Item, ItemAdmin) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import unicode_literals | |
from django.forms.widgets import ClearableFileInput, CheckboxInput | |
from django.utils.html import conditional_escape | |
from django.utils.safestring import mark_safe | |
class ClearableFileInputWithCrop(ClearableFileInput): | |
template_with_initial = ( | |
'%(initial_text)s: <a href="%(initial_url)s">%(initial)s</a> ' | |
'%(clear_template)s<br />%(input_text)s: %(input)s' | |
) | |
template_cropper = ( | |
'<script>django.jQuery(".croppable-file-input").on("change", ' | |
'function(){showCropper(this, "%(cropper_save_field_name)s", %(cropper_width)s, %(cropper_height)s)})</script>' | |
'<div style="width: 320px; height: 90px; margin-left:10em;" class="cropper-frame hidden">' | |
'<img src="" class="cropper"></div>' | |
'<div class="cropper-buttons hidden" style="margin-left:10em;">' | |
' <button id="zoom_out" type="button" title="Zoom out"> - </button>' | |
' <button id="fit" type="button" title="Fit image"> [ ] </button>' | |
' <button id="zoom_in" type="button" title="Zoom in"> + </button>' | |
'</div>' | |
) | |
template_with_initial = template_with_initial + template_cropper | |
def clear_checkbox_name(self, name): | |
""" | |
Given the name of the file input, return the name of the clear checkbox | |
input. | |
""" | |
return name + '-clear' | |
def clear_checkbox_id(self, name): | |
""" | |
Given the name of the clear checkbox input, return the HTML id for it. | |
""" | |
return name + '_id' | |
def is_initial(self, value): | |
""" | |
Return whether value is considered to be initial value. | |
""" | |
return bool(value and hasattr(value, 'url')) | |
def get_template_substitution_values(self, value): | |
""" | |
Return value-related substitutions. | |
""" | |
return { | |
'initial': conditional_escape(value), | |
'initial_url': conditional_escape(value.url), | |
} | |
def render(self, name, value, attrs=None): | |
self.attrs['class'] = 'croppable-file-input' | |
substitutions = { | |
'initial_text': self.initial_text, | |
'input_text': self.input_text, | |
'clear_template': '', | |
'clear_checkbox_label': self.clear_checkbox_label, | |
} | |
template = '<p>%(input)s<br>' + self.template_cropper + '</p>' | |
substitutions['input'] = super(ClearableFileInput, self).render(name, value, attrs) | |
substitutions['cropper_save_field_name'] = '%s_crop_dimensions' % name | |
substitutions['cropper_width'] = getattr(self, 'cropper_width', 320) | |
substitutions['cropper_height'] = getattr(self, 'cropper_height', 90) | |
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: | |
js = ('js/admin-cropper.js', | |
'js/vendor/guillotine/jquery.guillotine.js') | |
css = { | |
'all': ('js/vendor/guillotine/jquery.guillotine.css',) | |
} | |
class AdminClearableFileInputWithCrop(ClearableFileInputWithCrop): | |
template_with_initial = ('<p class="file-upload">%s</p>' | |
% ClearableFileInputWithCrop.template_with_initial) | |
template_with_clear = ('<span class="clearable-file-input">%s</span>' | |
% ClearableFileInputWithCrop.template_with_clear) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment