How could Action Text be customized to render hyperlinks pointing to a different domain with target="blank"
and be preceded by a special icon ? Preferably without needing to build some custom attachment system, just processing all the hyperlinks present in the text at the moment of rendering.
I’ve found ActionText (like Trix before it) to be fairly resistant to these sorts of refinements, but what you are describing would be fairly trivial to do in your page with JavaScript.
Walter
1 Like
Actually I’ve managed to do it server-side as follows, don’t know if there’s a simpler way:
# config/initializers/action_text.rb
module ActionText
Rails.application.reloader.to_prepare do
ContentHelper.allowed_attributes += ["target", "rel"]
unless ContentHelper.included_modules.include?(ContentHelperMonkeyPatch)
ContentHelper.include(ContentHelperMonkeyPatch)
end
unless Content.included_modules.include?(ContentMonkeyPatch)
Content.include(ContentMonkeyPatch)
end
end
end
# lib/action_text/content_helper_monkey_patch.rb
module ActionText
module ContentHelperMonkeyPatch
def custom_render_action_text(content)
local_base_url = request.base_url
self.prefix_partial_path_with_controller_namespace = false
rendered = render_action_text_attachments(content).render_links(local_base_url)
sanitize_action_text_content(rendered)
end
end
end
# lib/action_text/content_monkey_patch.rb
module ActionText
module ContentMonkeyPatch
def render_links(local_base_url)
content = fragment.replace("a") do |node|
unless node.attribute("href")&.value&.start_with?(local_base_url)
node.set_attribute("target", "_blank")
node.set_attribute("rel", "noreferrer noopener")
node.set_attribute("class", "external")
end
node
end
self.class.new(content, canonicalize: false)
end
end
end
# app/views/action_text/content/_layout.html.erb
<div class="trix-content">
<%= custom_render_action_text(content) %>
</div>
2 Likes
Thanks! That is really helpful.
Walter
NB: the view needs to be changed when migrating from Rails 6 to Rails 7 (pull request).
Before:
# app/views/action_text/content/_layout.html.erb
<div class="trix-content">
<%= custom_render_action_text(content) %>
</div>
After:
# app/views/action_text/contents/_content.html.erb
<%= custom_render_action_text(content) %>