Created
July 22, 2020 14:56
-
-
Save cnk/a0eab7c981c7f34127955b384cebcad7 to your computer and use it in GitHub Desktop.
Wagtail link block requiring exactly one of 3 options
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AirspaceRequiredLinkBlock(blocks.StructBlock): | |
""" | |
Allows a user to create a link to a Page, a Document, or a relative or absolute URL. | |
This version requires that you provide one and only one of the destinations above. | |
NOTE: Due to limitations in CSS, callers of LinkBlock() must not specify a label in the construction arguments. | |
See the comment in the Meta class for why. | |
NOTE: Within a template, checking for the existence of `self.link` will always return True because the LinkBlock | |
object is not falsy, even if it has no contents. To retrieve the value of a LinkBlock, use the {% link_url %} | |
template tag from airspace_tags. ex: | |
{% load airspace_tags %} | |
{% link_url self.link as url %} | |
{% if url %} | |
<a href={{ url }}></a> | |
{% endif %} | |
""" | |
page = blocks.PageChooserBlock( | |
required=False, | |
help_text="Link to the chosen page. If you are going to a page on this site, use this option if possible. " | |
"NOTE: you must choose one and only one of 'page', 'document' or 'url'." | |
) | |
document = DocumentChooserBlock( | |
required=False, | |
help_text="Link to the chosen document." | |
) | |
url = blocks.CharBlock( | |
required=False, | |
help_text="Link to the given URL. This can be a relative URL to a location your own site (e.g. /example#FAQ1) " | |
"or an absolute URL to a page on another site (e.g. http://www.caltech.edu). Note: absolute URLs " | |
"must include the http:// otherwise they will not work." | |
) | |
class Meta: | |
label = 'Link' | |
form_classname = 'link-block' | |
def clean(self, value): | |
result = [] # build up a list of (name, value) tuples to be passed to the StructValue constructor | |
errors = {} | |
found_items = [] | |
for name, val in value.items(): | |
try: | |
result.append((name, self.child_blocks[name].clean(val))) | |
# Blank values are None for 'page' and 'document' but blank urls are '', so check length of str(val) | |
# We need to str() the value because if there is a document or page, the classes don't have len() method | |
if val and len(str(val)) > 0: | |
found_items.append(val) | |
except ValidationError as e: | |
errors[name] = ErrorList([e]) | |
if not found_items: | |
errors['page'] = ErrorList(["You must provide one of 'page', 'document' or 'url'"]) | |
if len(found_items) > 1: | |
first_item = result[0][0] | |
errors[first_item] = ErrorList(["You may provide only one of 'page', 'document' or 'url'"]) | |
if errors: | |
# The message here is arbitrary - StructBlock.render_form will suppress it | |
# and delegate the errors contained in the 'params' dict to the child blocks instead | |
raise ValidationError('Validation error in StructBlock', params=errors) | |
return self._to_struct_value(result) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment