Открытие внешних ссылок в новом окне в трясогузке

Недавно я реализовал добавление 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 - ставить теги html, head и body автоматически, beautifulsoup

  2. Это также мешает тегам встраивания - заставить BeautifulSoup 4 уважать самозакрывающийся тег?

  3. Следовательно, мой дерьмовый "fix" вручную заменяет части вывода пустыми строками.

Вопрос:

Как правильно и лучше всего это сделать?


person Chris Barry    schedule 23.10.2015    source источник


Ответы (2)


Начиная с трясогузки версии 2.5, существует 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 вместо внутренних. те / детали реализации.

person Thibaud Colas    schedule 24.04.2019
comment
Учитывая, что это решение работает в новой версии трясогузки без взлома с помощью JS/JQuery, я прошу @Chris Berry отметить это как принятый ответ. - person Sanyam Khurana; 10.01.2020
comment
Однако относится ли это к ссылкам не внутри форматированного текста? - person Chris Barry; 30.03.2021
comment
@SanyamKhurana ^^^^ - person Chris Barry; 30.03.2021
comment
Это только для ссылок с форматированным текстом, так как эти ссылки единственные в Трясогузке, где разметка ссылки создается непосредственно с помощью Трясогузки. Для других ссылок добавление атрибута target должно быть просто вопросом редактирования шаблонов. Другие варианты, такие как использование JS, тоже будут работать, но это никоим образом не относится к трясогузке. - person Thibaud Colas; 31.03.2021

Боролся с той же проблемой и не мог решить ее, используя трясогузки. Моим первоначальным решением было манипулировать содержимым в 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 правильным и лучшим способом сделать это, но для меня это работает как шарм с минимальным кодированием.

person MartijnL    schedule 14.12.2015
comment
Я определенно не из тех, кто уклоняется от использования jquery таким образом, и похоже, что это не повредит SEO (не знаю, почему так, но стоит проверить). Тем не менее, это тоже не похоже на 100% лучшее решение. Не стесняйтесь не соглашаться со мной, и я дам вам ответ :) В противном случае я, вероятно, оставлю его открытым. - person Chris Barry; 15.12.2015
comment
Манипулирование ссылками с помощью Wagtailhooks, вероятно, возможно. Однако, на мой взгляд, есть несколько причин, по которым вы предпочитаете использовать JQuery: 1. Манипуляционный код в хуках поразит ядро ​​вашего веб-сайта, поэтому, если он содержит ошибки, потенциально весь ваш сайт может выйти из строя. Если ошибки JQuery не повлияют на ваш сайт, на той же вкладке будут открываться только внешние ссылки. 2. Использование Wagtailhooks для манипулирования таким контентом, вероятно, не входит в сферу его прямого назначения. В противном случае, вероятно, было бы доступно больше информации об этом, и на этот вопрос был бы дан ответ раньше. - person MartijnL; 18.12.2015
comment
3. Как код будет работать с будущими выпусками трясогузки? Будет ли он работать со всеми вашими будущими дополнениями? Зачем создавать потенциальную проблему, если в этом нет абсолютной необходимости? Моя идея заключается в том, что более простое решение в большинстве случаев является лучшим и его лучше поддерживать в будущем. И если вы уже используете JQuery на своем сайте, не составит труда использовать его и для внешних ссылок. - person MartijnL; 18.12.2015
comment
Просто чтобы подтвердить, вы абсолютно правы. Теперь это мой предпочтительный метод достижения этого. - person Chris Barry; 24.05.2016
comment
Вы также должны добавить $('a[href^="https://"]').attr('target', '_blank'); для покрытия URL-адресов https. - person kristian; 04.03.2017