diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 8535199e7c..3ff2f97824 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -10,7 +10,7 @@ from django.db import models from django.db.models.signals import pre_delete from django.dispatch.dispatcher import receiver from django.utils.safestring import mark_safe -from django.utils.html import escape +from django.utils.html import escape, format_html_join from django.conf import settings from django.utils.translation import ugettext_lazy as _ @@ -68,8 +68,8 @@ class AbstractImage(models.Model, TagSearchable): except ObjectDoesNotExist: file_field = self.file - # If we have a backend attribute then pass it to process - # image - else pass 'default' + # If we have a backend attribute then pass it to process + # image - else pass 'default' backend_name = getattr(self, 'backend', 'default') generated_image_file = filter.process_image(file_field.file, backend_name=backend_name) @@ -242,8 +242,12 @@ class AbstractRendition(models.Model): 'src="%s" width="%d" height="%d" alt="%s"' % (escape(self.url), self.width, self.height, escape(self.image.title)) ) - def img_tag(self): - return mark_safe('' % self.attrs) + def img_tag(self, extra_attributes=None): + if extra_attributes: + extra_attributes_string = format_html_join(' ', '{0}="{1}"', extra_attributes.items()) + return mark_safe('' % (self.attrs, extra_attributes_string)) + else: + return mark_safe('' % self.attrs) class Meta: abstract = True diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index e59d9cd148..5c72734177 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -7,32 +7,36 @@ register = template.Library() # Local cache of filters, avoid hitting the DB filters = {} + @register.tag(name="image") def image(parser, token): - args = token.split_contents() + bits = token.split_contents()[1:] + image_var = bits[0] + filter_spec = bits[1] + bits = bits[2:] - if len(args) == 3: - # token is of the form {% image self.photo max-320x200 %} - tag_name, image_var, filter_spec = args - return ImageNode(image_var, filter_spec) - - elif len(args) == 5: + if len(bits) == 2 and bits[0] == 'as': # token is of the form {% image self.photo max-320x200 as img %} - tag_name, image_var, filter_spec, as_token, out_var = args - - if as_token != 'as': - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") - - return ImageNode(image_var, filter_spec, out_var) - + return ImageNode(image_var, filter_spec, output_var_name=bits[1]) else: - raise template.TemplateSyntaxError("'image' tag should be of the form {%% image self.photo max-320x200 %%} or {%% image self.photo max-320x200 as img %%}") + # token is of the form {% image self.photo max-320x200 %} - all additional tokens + # should be kwargs, which become attributes + attrs = {} + for bit in bits: + try: + name, value = bit.split('=') + except ValueError: + raise template.TemplateSyntaxError("'image' tag should be of the form {% image self.photo max-320x200 [ custom-attr=\"value\" ... ] %} or {% image self.photo max-320x200 as img %}") + attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value + + return ImageNode(image_var, filter_spec, attrs=attrs) class ImageNode(template.Node): - def __init__(self, image_var_name, filter_spec, output_var_name=None): + def __init__(self, image_var_name, filter_spec, output_var_name=None, attrs={}): self.image_var = template.Variable(image_var_name) self.output_var_name = output_var_name + self.attrs = attrs if filter_spec not in filters: filters[filter_spec], _ = Filter.objects.get_or_create(spec=filter_spec) @@ -66,4 +70,7 @@ class ImageNode(template.Node): return '' else: # render the rendition's image tag now - return rendition.img_tag() + resolved_attrs = {} + for key in self.attrs: + resolved_attrs[key] = self.attrs[key].resolve(context) + return rendition.img_tag(resolved_attrs) diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index d546c396dd..2fbac118c5 100644 --- a/wagtail/wagtailimages/tests.py +++ b/wagtail/wagtailimages/tests.py @@ -210,6 +210,20 @@ class TestImageTag(TestCase): self.assertTrue('height="300"' in result) self.assertTrue('alt="Test image"' in result) + def render_image_tag_with_extra_attributes(self, image, title): + temp = template.Template('{% load image_tags %}{% image image_obj width-400 class="photo" title=title|lower %}') + context = template.Context({'image_obj': image, 'title': title}) + return temp.render(context) + + def test_image_tag_with_extra_attributes(self): + result = self.render_image_tag_with_extra_attributes(self.image, 'My Wonderful Title') + + # Check that all the required HTML attributes are set + self.assertTrue('width="400"' in result) + self.assertTrue('height="300"' in result) + self.assertTrue('class="photo"' in result) + self.assertTrue('title="my wonderful title"' in result) + ## ===== ADMIN VIEWS =====