1from django.core.exceptions import ValidationError 2from django.utils.functional import cached_property 3from django.utils.translation import gettext_lazy as _ 4 5from wagtail.core import blocks 6from wagtail.embeds.format import embed_to_frontend_html 7 8 9class EmbedValue: 10 """ 11 Native value of an EmbedBlock. Should, at minimum, have a 'url' property 12 and render as the embed HTML when rendered in a template. 13 NB We don't use a wagtailembeds.model.Embed object for this, because 14 we want to be able to do {% embed value.url 500 %} without 15 doing a redundant fetch of the embed at the default width. 16 """ 17 def __init__(self, url, max_width=None, max_height=None): 18 self.url = url 19 self.max_width = max_width 20 self.max_height = max_height 21 22 @cached_property 23 def html(self): 24 return embed_to_frontend_html(self.url, self.max_width, self.max_height) 25 26 def __str__(self): 27 return self.html 28 29 30class EmbedBlock(blocks.URLBlock): 31 def get_default(self): 32 # Allow specifying the default for an EmbedBlock as either an EmbedValue or a string (or None). 33 if not self.meta.default: 34 return None 35 elif isinstance(self.meta.default, EmbedValue): 36 return self.meta.default 37 else: 38 # assume default has been passed as a string 39 return EmbedValue(self.meta.default, getattr(self.meta, 'max_width', None), getattr(self.meta, 'max_height', None)) 40 41 def to_python(self, value): 42 # The JSON representation of an EmbedBlock's value is a URL string; 43 # this should be converted to an EmbedValue (or None). 44 if not value: 45 return None 46 else: 47 return EmbedValue(value, getattr(self.meta, 'max_width', None), getattr(self.meta, 'max_height', None)) 48 49 def get_prep_value(self, value): 50 # serialisable value should be a URL string 51 if value is None: 52 return '' 53 else: 54 return value.url 55 56 def value_for_form(self, value): 57 # the value to be handled by the URLField is a plain URL string (or the empty string) 58 if value is None: 59 return '' 60 else: 61 return value.url 62 63 def value_from_form(self, value): 64 # convert the value returned from the form (a URL string) to an EmbedValue (or None) 65 if not value: 66 return None 67 else: 68 return EmbedValue(value, getattr(self.meta, 'max_width', None), getattr(self.meta, 'max_height', None)) 69 70 def clean(self, value): 71 if isinstance(value, EmbedValue) and not value.html: 72 raise ValidationError(_("Cannot find an embed for this URL.")) 73 return super().clean(value) 74 75 class Meta: 76 icon = "media" 77