From 2f029fc336510ab40fc9cb29c3eaf74e3f252134 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Wed, 4 Jun 2014 11:28:14 -0700 Subject: [PATCH 1/4] adding custom img attrs to image_tags, but no custom TestCasecreated for it --- wagtail/wagtailimages/models.py | 5 ++- .../templates/wagtailimages/imagetag.html | 1 + .../wagtailimages/templatetags/image_tags.py | 41 +++++++++++++------ 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 wagtail/wagtailimages/templates/wagtailimages/imagetag.html diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 24fd1f0bf..bd2fc8751 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -12,6 +12,7 @@ from django.utils.safestring import mark_safe from django.utils.html import escape from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from django.template.loader import render_to_string from unidecode import unidecode @@ -225,9 +226,9 @@ class AbstractRendition(models.Model): def url(self): return self.file.url - def img_tag(self): + def img_tag(self, attrs={}): return mark_safe( - '%s' % (escape(self.url), self.width, self.height, escape(self.image.title)) + render_to_string('wagtailimages/imagetag.html',{'self' : self, 'attrs' : attrs, }) ) class Meta: diff --git a/wagtail/wagtailimages/templates/wagtailimages/imagetag.html b/wagtail/wagtailimages/templates/wagtailimages/imagetag.html new file mode 100644 index 000000000..d10496739 --- /dev/null +++ b/wagtail/wagtailimages/templates/wagtailimages/imagetag.html @@ -0,0 +1 @@ +{{ self.image.title }} \ No newline at end of file diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index e59d9cd14..48800d920 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -7,32 +7,46 @@ 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: + if len(bits) == 0: # 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: + elif len(bits) == 2: # 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 %%}") + if bits[0] == 'as': + return ImageNode(image_var, filter_spec, output_var_name=bits[1]) - return ImageNode(image_var, filter_spec, out_var) + if len(bits) > 0: + # customized attrs + attrs = {} + for bit in bits: + try: + name,value = bit.split('=') + except: + 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 %%}") + if name + attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value - else: - 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, attrs=attrs) + + # something is wrong if we made it this far + 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 %%}") 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 +80,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) From f70768cc4e65dd07bf51629a07387f9dd6c959e0 Mon Sep 17 00:00:00 2001 From: Ben Margolis Date: Wed, 4 Jun 2014 12:52:17 -0700 Subject: [PATCH 2/4] typo --- wagtail/wagtailimages/templatetags/image_tags.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index 48800d920..e8a4c2191 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -33,7 +33,6 @@ def image(parser, token): name,value = bit.split('=') except: 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 %%}") - if name attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value return ImageNode(image_var, filter_spec, attrs=attrs) From 5e055972cde55f373a41e1012e1ada3a5b07e9b4 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Thu, 19 Jun 2014 21:55:45 +0100 Subject: [PATCH 3/4] Refactor image tag parser so that it only has two cases to handle --- wagtail/wagtailimages/models.py | 4 +-- .../wagtailimages/templatetags/image_tags.py | 25 ++++++------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py index 550be2034..3ff2f9782 100644 --- a/wagtail/wagtailimages/models.py +++ b/wagtail/wagtailimages/models.py @@ -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) diff --git a/wagtail/wagtailimages/templatetags/image_tags.py b/wagtail/wagtailimages/templatetags/image_tags.py index e8a4c2191..5c7273417 100644 --- a/wagtail/wagtailimages/templatetags/image_tags.py +++ b/wagtail/wagtailimages/templatetags/image_tags.py @@ -15,31 +15,22 @@ def image(parser, token): filter_spec = bits[1] bits = bits[2:] - if len(bits) == 0: - # token is of the form {% image self.photo max-320x200 %} - return ImageNode(image_var, filter_spec) - - elif len(bits) == 2: + if len(bits) == 2 and bits[0] == 'as': # token is of the form {% image self.photo max-320x200 as img %} - - if bits[0] == 'as': - return ImageNode(image_var, filter_spec, output_var_name=bits[1]) - - if len(bits) > 0: - # customized attrs + return ImageNode(image_var, filter_spec, output_var_name=bits[1]) + else: + # 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: - 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 %%}") + 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) - # something is wrong if we made it this far - 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 %%}") - class ImageNode(template.Node): def __init__(self, image_var_name, filter_spec, output_var_name=None, attrs={}): From 0c4b5ba5566f1a32bc6fe1769741407a18820298 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Thu, 19 Jun 2014 22:02:45 +0100 Subject: [PATCH 4/4] Add unit test for image tag with extra attributes --- wagtail/wagtailimages/tests.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/wagtail/wagtailimages/tests.py b/wagtail/wagtailimages/tests.py index d546c396d..2fbac118c 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 =====