|
from django import template |
|
|
|
from wagtail.images.models import SourceImageIOError |
|
from wagtail.images.shortcuts import get_rendition_or_not_found |
|
from wagtail.images.templatetags.wagtailimages_tags import ImageNode |
|
|
|
register = template.Library() |
|
|
|
|
|
@register.tag(name="responsiveimage") |
|
def responsiveimage(parser, token): |
|
bits = token.split_contents()[1:] |
|
image_var = bits[0] |
|
filter_spec = bits[1] |
|
bits = bits[2:] |
|
|
|
if len(bits) == 2 and bits[0] == 'as': |
|
# token is of the form {% responsiveimage self.photo max-320x200 as img %} |
|
return ImageNode(image_var, filter_spec, output_var_name=bits[1]) |
|
else: |
|
# token is of the form {% responsiveimage 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( |
|
"""'responsiveimage' tag should be of the form |
|
{% responsiveimage self.photo max-320x200 [ custom-attr=\"value\" ... ] %} or |
|
{% responsiveimage self.photo max-320x200 as img %}""" |
|
) |
|
|
|
attrs[name] = parser.compile_filter(value) # setup to resolve context variables as value |
|
|
|
return ResponsiveImageNode(image_var, filter_spec, attrs=attrs) |
|
|
|
|
|
class ResponsiveImageNode(template.Node): |
|
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 |
|
self.filter_spec = filter_spec |
|
|
|
def render(self, context): |
|
try: |
|
image = self.image_var.resolve(context) |
|
except template.VariableDoesNotExist: |
|
return '' |
|
|
|
if not image: |
|
return '' |
|
|
|
Rendition = image.get_rendition_model() |
|
|
|
rendition = get_rendition_or_not_found(image, self.filter_spec) |
|
|
|
# Parse srcset format into array |
|
try: |
|
raw_sources = str(self.attrs['srcset']).replace('"', '').split(',') |
|
srcset_renditions = [] |
|
widths = [] |
|
newsrcseturls = [] |
|
|
|
for source in raw_sources: |
|
flt = source.strip().split(' ')[0] |
|
width = source.strip().split(' ')[1] |
|
|
|
# cache widths to be re-appended after filter has been converted to URL |
|
widths.append(width) |
|
|
|
try: |
|
srcset_renditions.append(image.get_rendition(flt)) |
|
except SourceImageIOError: |
|
tmprend = Rendition(image=image, width=0, height=0) |
|
tmprend.file.name = 'not-found' |
|
|
|
for index, rend in enumerate(srcset_renditions): |
|
newsrcseturls.append(' '.join([rend.url, widths[index]])) |
|
|
|
except KeyError: |
|
newsrcseturls = [] |
|
pass |
|
|
|
if self.output_var_name: |
|
# return the rendition object in the given variable |
|
context[self.output_var_name] = rendition |
|
return '' |
|
else: |
|
# render the rendition's image tag now |
|
resolved_attrs = {} |
|
for key in self.attrs: |
|
if key == 'srcset': |
|
resolved_attrs[key] = ','.join(newsrcseturls) |
|
continue |
|
|
|
resolved_attrs[key] = self.attrs[key].resolve(context) |
|
|
|
return rendition.img_tag(resolved_attrs) |