扩展Wagtail富文本链接选择器的自定义属性存储问题
扩展Wagtail富文本默认链接选择器的问题与实现尝试
我想扩展Wagtail富文本的默认链接选择器,目前已成功为链接选择器添加表单字段(内部页面选择器视图暂未处理,暂时可接受),且能看到数据已提交到视图并传入get_result_data方法,但后续流程完全失效,不清楚原因。尝试注册自定义链接处理器或register_converter_rule处理转换,但custom_link_entity似乎从未被调用。
有没有人成功为默认链接选择器弹窗添加自定义内容并保存到数据库?能否分享实现思路?
我找到两篇参考文章,但存在不足:
- 方法偏取巧且仅适用于外部URL
- 缺少便捷的页面选择器功能
已实现的代码
class ExtendedLinkMixin: """Mixin to add hover_link and new_tab to all link forms""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Add the extra fields after the existing fields self.fields['hover_link'] = forms.BooleanField( required=False, label='Hover link', initial=False, help_text='Add hover-link class to this link' ) self.fields['new_tab'] = forms.BooleanField( required=False, label='Open in new tab', initial=False, help_text='Open link in a new browser tab' ) class CustomExternalLinkChooserForm(ExtendedLinkMixin, ExternalLinkChooserForm): pass class ExtendedLinkViewMixin: """Mixin to handle the extra fields in result data and initial data""" def get_initial_data(self): """Include hover_link and new_tab in initial data""" initial = super().get_initial_data() # Parse boolean values from GET parameters initial['hover_link'] = self.request.POST.get('hover_link', '').lower() == 'true' initial['new_tab'] = self.request.POST.get('new_tab', '').lower() == 'true' return initial def get_result_data(self): """Add hover_link and new_tab to the result data""" result = super().get_result_data() # Add our custom fields to the result result['hover_link'] = self.form.cleaned_data.get('hover_link', False) result['new_tab'] = self.form.cleaned_data.get('new_tab', False) return result class CustomExternalLinkView(ExtendedLinkViewMixin, BaseExternalLinkView): form_class = CustomExternalLinkChooserForm
patched_urls.py中的配置:
... path('admin/choose-external-link/', CustomExternalLinkView.as_view(), name='wagtailadmin_choose_page_external_link'), ...
到目前为止上述代码均可正常工作,但后续关联配置无法生效。我尝试了以下两种方案:
方案一:重写整个editor_plugin
from draftjs_exporter.dom import DOM from wagtail.whitelist import check_url def custom_link_entity(props): """ Custom link entity that handles our extra attributes. This is called when converting from contentstate to database format. Props come from the link chooser's get_result_data() method. """ id_ = props.get("id") link_props = {} if id_ is not None: # Internal page link link_props["linktype"] = "page" link_props["id"] = id_ else: # External link link_props["href"] = check_url(props.get("url")) # Add our custom attributes if props.get("hover_link"): link_props["hover_link"] = str(props.get("hover_link")).lower() if props.get("new_tab"): link_props["new_tab"] = str(props.get("new_tab")).lower() return DOM.create_element("a", link_props, props["children"]) def register_custom_link_handlers(features): features.register_editor_plugin( "draftail", "link", draftail_features.EntityFeature( { "type": "LINK", "icon": "link", "description": "Link", # We want to enforce constraints on which links can be pasted into rich text. # Keep only the attributes Wagtail needs. "attributes": ["url", "id", "parentId"], "allowlist": { # Keep pasted links with http/https protocol, and not-pasted links (href = undefined). "href": "^(http:|https:|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=[ "wagtailadmin/js/page-chooser-modal.js", ], ), ) features.register_converter_rule( "contentstate", "link", { "from_database_format": { "a[href]": ExternalLinkElementHandler("LINK"), 'a[linktype="page"]': PageLinkElementHandler("LINK"), }, "to_database_format": {"entity_decorators": {"LINK": custom_link_entity}}, }, )
方案二:仅添加转换规则
@hooks.register('register_rich_text_features') def register_custom_link_handlers(features): """ Override the default link feature to support our custom attributes """ # Register our custom link handlers (for rendering) features.register_link_type(CustomPageLinkHandler) features.register_link_type(CustomExternalLinkHandler) features.register_link_type(CustomEmailLinkHandler) # Override the converter rule for the 'link' feature features.register_converter_rule( "contentstate", "link", { "from_database_format": { "a[href]": ExternalLinkElementHandler("LINK"), 'a[linktype="page"]': PageLinkElementHandler("LINK"), }, "to_database_format": { "entity_decorators": {"LINK": custom_link_entity} }, }, )
内容的提问来源于stack exchange,提问作者bruecksen
相关产品推荐
相关产品推荐

