9

我最近实现了添加target="_blank"到这样的外部链接:

@hooks.register('after_edit_page')
def do_after_page_edit(request, page):
    if hasattr(page, "body"):
        soup = BeautifulSoup(page.body)
        for a in soup.findAll('a'):
            if hasattr(a, "href"):
            a["target"] = "_blank"
        page.body = str(soup)
        page.body = page.body.replace("<html><head></head><body>", "")
        page.body = page.body.replace("</body></html>", "")
        page.body = page.body.replace("></embed>", "/>")
        page.save()

@hooks.register('construct_whitelister_element_rules')
def whitelister_element_rules():
    return {
        'a': attribute_rule({'href': check_url, 'target': True}),
    }

问题:

  1. Beautifulsoup 与输出混淆,添加html, head & body标签 -不要自动放置 html、head 和 body 标签,beautifulsoup

  2. 它还与嵌入标签混淆 -如何让 BeautifulSoup 4 尊重自闭合标签?

  3. 因此,我的蹩脚“ fix”用空白字符串手动替换部分输出。

问题:

这样做的正确和最佳方法是什么?

4

2 回答 2

22

从 Wagtail v2.5 开始,作为 Wagtail 富文本处理的一部分,有一个 API 可以进行这样的自定义:Rewrite handlers,带有register_rich_text_features钩子。

下面是一个使用这个新 API 来创建一个重写处理程序的示例,该处理程序target="_blank"为所有外部链接设置一个属性:

from django.utils.html import escape
from wagtail.core import hooks
from wagtail.core.rich_text import LinkHandler


class NewWindowExternalLinkHandler(LinkHandler):
    # This specifies to do this override for external links only.
    # Other identifiers are available for other types of links.
    identifier = 'external'

    @classmethod
    def expand_db_attributes(cls, attrs):
        href = attrs["href"]
        # Let's add the target attr, and also rel="noopener" + noreferrer fallback.
        # See https://github.com/whatwg/html/issues/4078.
        return '<a href="%s" target="_blank" rel="noopener noreferrer">' % escape(href)


@hooks.register('register_rich_text_features')
def register_external_link(features):
    features.register_link_type(NewWindowExternalLinkHandler)

在此示例中,我还将添加rel="noopener"修复.target="_blank"


与以前的解决方案相比,这种新方法是最可靠的:它完全是服务器端的,仅覆盖链接在站点前端的呈现方式而不是它们的存储方式,并且仅依赖于文档化的 API 而不是内部那些/实施细节。

于 2019-04-24T20:02:54.083 回答
9

一直在努力解决同样的问题,并且无法使用 wagtailhooks 实现它。我最初的解决方案是使用过滤器来操作 base.html 中的内容。当放置在内容块中时,用于剪切代码片段的过滤器可以完美地工作,例如:

{{ self.body|cut: ‘ href="http:’}}

上面的过滤器删除了部分内容,但不幸的是,“替换”不能用作过滤器(我使用的是 Python 3.x)。因此,我的下一个方法是构建一个 custom_filter 来创建“替换”作为过滤器选项。长话短说:它部分有效,但前提是内容从原始的“StreamValue”数据类型转换为“字符串”。此转换导致显示所有 html 标记的内容,因此替换不会导致工作 html。我无法再次将内容返回到 StreamValue,并且没有其他 Python 数据类型解决了这个问题。最终,JQuery 为我完成了这项工作:

$(document).ready(function(){
$('a[href^="http://"]').attr('target', '_blank');
});        

此代码将 'target="_blank"' 添加到包含 'http://' 的每个链接,因此所有内部链接都保留在现有选项卡中。它需要放在 base.html(或类似文件)的末尾,当然您需要在运行之前加载 JQuery。从这里得到了我的答案。不知道 JQuery 是否是正确和最好的方法,但它对我来说就像一个魅力,只需最少的编码。

于 2015-12-14T15:34:40.887 回答