93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
"""Inline "button" link for Draftail rich text fields.
|
|
|
|
Stored as `<a linktype="button" data-href="...">label</a>`. The linktype (not a
|
|
plain href) avoids colliding with the built-in link feature, and lets
|
|
expand_db_html rewrite it to `<a class="button" href="...">` for the front end.
|
|
Wired up in wagtail_hooks.py.
|
|
"""
|
|
|
|
from django.urls import reverse_lazy
|
|
from django.utils.html import escape
|
|
from draftjs_exporter.dom import DOM
|
|
from wagtail.admin.rich_text.converters.html_to_contentstate import (
|
|
InlineEntityElementHandler,
|
|
)
|
|
from wagtail.admin.rich_text.editors.draftail import features as draftail_features
|
|
from wagtail.rich_text import LinkHandler
|
|
|
|
FEATURE_NAME = "button-link"
|
|
ENTITY_TYPE = "BUTTON"
|
|
|
|
|
|
def button_link_entity_decorator(props):
|
|
"""ContentState to DB HTML (keeps just the chosen URL)."""
|
|
return DOM.create_element(
|
|
"a",
|
|
{"linktype": "button", "data-href": props.get("url", "")},
|
|
props["children"],
|
|
)
|
|
|
|
|
|
class ButtonLinkEntityElementHandler(InlineEntityElementHandler):
|
|
"""DB HTML to ContentState."""
|
|
|
|
mutability = "MUTABLE"
|
|
|
|
def get_attribute_data(self, attrs):
|
|
return {"url": attrs.get("data-href", "")}
|
|
|
|
|
|
class ButtonLinkRichTextHandler(LinkHandler):
|
|
"""DB HTML to front-end HTML (expand_db_html)."""
|
|
|
|
identifier = "button"
|
|
|
|
@classmethod
|
|
def expand_db_attributes(cls, attrs):
|
|
href = escape(attrs.get("data-href", ""))
|
|
return f'<a class="button" href="{href}">'
|
|
|
|
|
|
def register_button_link_feature(features):
|
|
features.register_editor_plugin(
|
|
"draftail",
|
|
FEATURE_NAME,
|
|
draftail_features.EntityFeature(
|
|
{
|
|
"type": ENTITY_TYPE,
|
|
"icon": "arrow-right-full",
|
|
"description": "Knapp",
|
|
# Reuse the link chooser modal + payload, so buttons work like links.
|
|
"attributes": ["url", "id", "parentId"],
|
|
"allowlist": {"href": "^(http:|https:|mailto:|tel:|#|/|undefined$)"},
|
|
"chooserUrls": {
|
|
"pageChooser": reverse_lazy("wagtailadmin_choose_page"),
|
|
"externalLinkChooser": reverse_lazy("wagtailadmin_choose_page_external_link"),
|
|
"emailLinkChooser": reverse_lazy("wagtailadmin_choose_page_email_link"),
|
|
"phoneLinkChooser": reverse_lazy("wagtailadmin_choose_page_phone_link"),
|
|
"anchorLinkChooser": reverse_lazy("wagtailadmin_choose_page_anchor_link"),
|
|
},
|
|
},
|
|
js=[
|
|
# Gives LinkModalWorkflowSource its PAGE_CHOOSER_MODAL_ONLOAD_HANDLERS.
|
|
"wagtailadmin/js/page-chooser-modal.js",
|
|
"js/draftail-button-link.js",
|
|
],
|
|
css={"all": ["css/draftail-button-link.css"]},
|
|
),
|
|
)
|
|
features.register_converter_rule(
|
|
"contentstate",
|
|
FEATURE_NAME,
|
|
{
|
|
"from_database_format": {
|
|
'a[linktype="button"]': ButtonLinkEntityElementHandler(ENTITY_TYPE),
|
|
},
|
|
"to_database_format": {
|
|
"entity_decorators": {ENTITY_TYPE: button_link_entity_decorator},
|
|
},
|
|
},
|
|
)
|
|
features.register_link_type(ButtonLinkRichTextHandler)
|
|
features.default_features.append(FEATURE_NAME)
|