让外部链接在一个令人讨厌的新窗口中打开

时间:2015-10-23 11:11:46

标签: python html django hook wagtail

我最近实施了将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. 美丽的汤混淆了输出,添加了html, head & body标签 - Don't put html, head and body tags automatically, beautifulsoup

  2. 它也与嵌入标签混淆 - How to get BeautifulSoup 4 to respect a self-closing tag?

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

  4. 问题:

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

2 个答案:

答案 0 :(得分:7)

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

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

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

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

此代码将'target =“_ blank”'添加到包含'http://'的每个链接,因此所有内部链接都保留在现有标签中。它需要放在base.html(或类似的)的末尾,当然你需要在运行它之前加载它。 得到了here的答案。 不知道JQuery是否是正确的,最好的方法,但它对我来说就像是一个很少编码的魅力。

答案 1 :(得分:3)

从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"修复了known security issue


与以前解决此问题的方法相比,此新方法最可靠:完全在服务器端仅覆盖链接在网站前端上的呈现方式,而不是链接的存储方式,而仅依赖于已记录的API内部细节/实施细节。