diff --git a/app/components/alchemy/ingredients/link_view.rb b/app/components/alchemy/ingredients/link_view.rb
index 8e7467f742..be828aa8e1 100644
--- a/app/components/alchemy/ingredients/link_view.rb
+++ b/app/components/alchemy/ingredients/link_view.rb
@@ -1,6 +1,8 @@
module Alchemy
module Ingredients
class LinkView < BaseView
+ include LinkTarget
+
attr_reader :link_text
# @param ingredient [Alchemy::Ingredient]
@@ -12,7 +14,11 @@ def initialize(ingredient, text: nil, html_options: {})
end
def call
- link_to(link_text, value, {target: ingredient.link_target.presence}.merge(html_options)).html_safe
+ target = ingredient.link_target.presence
+ link_to(link_text, value, {
+ target: link_target_value(target),
+ rel: link_rel_value(target)
+ }.merge(html_options)).html_safe
end
end
end
diff --git a/app/components/alchemy/ingredients/picture_view.rb b/app/components/alchemy/ingredients/picture_view.rb
index d32ab0ab99..33e2cfc438 100644
--- a/app/components/alchemy/ingredients/picture_view.rb
+++ b/app/components/alchemy/ingredients/picture_view.rb
@@ -4,6 +4,8 @@ module Alchemy
module Ingredients
# Renders a picture ingredient view
class PictureView < BaseView
+ include LinkTarget
+
attr_reader :ingredient,
:show_caption,
:disable_link,
@@ -46,10 +48,11 @@ def call
output = caption ? img_tag + caption : img_tag
if is_linked?
+ target = ingredient.link_target.presence
output = link_to(output, url_for(ingredient.link), {
title: ingredient.link_title.presence,
- target: (ingredient.link_target == "blank") ? "_blank" : nil,
- data: {link_target: ingredient.link_target.presence}
+ rel: link_rel_value(target),
+ target: link_target_value(target)
})
end
diff --git a/app/components/alchemy/ingredients/text_view.rb b/app/components/alchemy/ingredients/text_view.rb
index 62a7e665f5..5954a1b850 100644
--- a/app/components/alchemy/ingredients/text_view.rb
+++ b/app/components/alchemy/ingredients/text_view.rb
@@ -1,6 +1,8 @@
module Alchemy
module Ingredients
class TextView < BaseView
+ include LinkTarget
+
attr_reader :disable_link
delegate :dom_id, :link, :link_title, :link_target,
@@ -21,7 +23,8 @@ def call
link_to(value, url_for(link), {
id: dom_id.presence,
title: link_title,
- target: link_target
+ target: link_target_value(link_target),
+ rel: link_rel_value(link_target)
}.merge(html_options))
end.html_safe
end
diff --git a/app/components/concerns/alchemy/ingredients/link_target.rb b/app/components/concerns/alchemy/ingredients/link_target.rb
new file mode 100644
index 0000000000..3e3a168b9b
--- /dev/null
+++ b/app/components/concerns/alchemy/ingredients/link_target.rb
@@ -0,0 +1,18 @@
+module Alchemy
+ module Ingredients
+ module LinkTarget
+ BLANK_VALUE = "_blank"
+ REL_VALUE = "noopener noreferrer"
+
+ def link_rel_value(target)
+ if link_target_value(target) == BLANK_VALUE
+ REL_VALUE
+ end
+ end
+
+ def link_target_value(target)
+ (target == "blank") ? BLANK_VALUE : target
+ end
+ end
+ end
+end
diff --git a/spec/components/alchemy/ingredients/picture_view_spec.rb b/spec/components/alchemy/ingredients/picture_view_spec.rb
index 22d3c901a8..c3e848ee52 100644
--- a/spec/components/alchemy/ingredients/picture_view_spec.rb
+++ b/spec/components/alchemy/ingredients/picture_view_spec.rb
@@ -169,6 +169,32 @@
expect(page).to have_selector('a[href="/home"] img')
end
+ context "with link target set to '_blank'" do
+ before do
+ ingredient.link_target = "_blank"
+ end
+
+ it "adds rel noopener noreferrer" do
+ render_view
+ expect(page).to have_selector(
+ 'a[href="/home"][target="_blank"][rel="noopener noreferrer"] img'
+ )
+ end
+ end
+
+ context "with link target set to 'blank'" do
+ before do
+ ingredient.link_target = "blank"
+ end
+
+ it "sets target '_blank' and adds rel noopener noreferrer" do
+ render_view
+ expect(page).to have_selector(
+ 'a[href="/home"][target="_blank"][rel="noopener noreferrer"] img'
+ )
+ end
+ end
+
context "but disabled link option" do
before do
options[:disable_link] = true
diff --git a/spec/views/alchemy/ingredients/link_view_spec.rb b/spec/views/alchemy/ingredients/link_view_spec.rb
index 14301faee3..fd1d1830b4 100644
--- a/spec/views/alchemy/ingredients/link_view_spec.rb
+++ b/spec/views/alchemy/ingredients/link_view_spec.rb
@@ -45,4 +45,30 @@
expect(rendered).to eq('http://google.com')
end
end
+
+ context "with link target set to '_blank'" do
+ let(:ingredient) do
+ Alchemy::Ingredients::Link.new(value: "http://google.com", link_target: "_blank")
+ end
+
+ it "adds rel noopener noreferrer" do
+ render ingredient
+ expect(rendered).to eq(
+ 'http://google.com'
+ )
+ end
+ end
+
+ context "with link target set to 'blank'" do
+ let(:ingredient) do
+ Alchemy::Ingredients::Link.new(value: "http://google.com", link_target: "blank")
+ end
+
+ it "sets target '_blank' and adds rel noopener noreferrer" do
+ render ingredient
+ expect(rendered).to eq(
+ 'http://google.com'
+ )
+ end
+ end
end
diff --git a/spec/views/alchemy/ingredients/text_view_spec.rb b/spec/views/alchemy/ingredients/text_view_spec.rb
index 1ac9a0ac2f..cb277bf98e 100644
--- a/spec/views/alchemy/ingredients/text_view_spec.rb
+++ b/spec/views/alchemy/ingredients/text_view_spec.rb
@@ -50,6 +50,24 @@
expect(rendered).to have_selector('a[title="Foo"][target="_blank"][href="http://google.com"]')
end
+ context "with link target set to '_blank'" do
+ it "adds rel noopener noreferrer" do
+ render ingredient
+ expect(rendered).to have_selector(
+ 'a[title="Foo"][target="_blank"][href="http://google.com"][rel="noopener noreferrer"]'
+ )
+ end
+ end
+
+ context "with link target set to 'blank'" do
+ it "sets target '_blank' and adds rel noopener noreferrer" do
+ render ingredient
+ expect(rendered).to have_selector(
+ 'a[title="Foo"][target="_blank"][href="http://google.com"][rel="noopener noreferrer"]'
+ )
+ end
+ end
+
context "with html_options given" do
it "renders the linked with these options" do
render ingredient, html_options: {title: "Bar", class: "blue"}