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 =====