Merge pull request #5283 from consuldemocracy/label_links

Allow links in forms to open in new tabs
This commit is contained in:
Javi Martín
2023-10-24 16:30:59 +02:00
committed by GitHub
28 changed files with 95 additions and 58 deletions

View File

@@ -34,7 +34,7 @@
<%= actions.action(:show, <%= actions.action(:show,
text: t("admin.site_customization.pages.index.see_page"), text: t("admin.site_customization.pages.index.see_page"),
path: page.url, path: page.url,
options: { target: "_blank" }) %> target: "_blank") %>
<% end %> <% end %>
<% end %> <% end %>
</td> </td>

View File

@@ -89,11 +89,7 @@
<div class="actions"> <div class="actions">
<% unless current_user.manager? || investment.persisted? %> <% unless current_user.manager? || investment.persisted? %>
<div> <div>
<%= f.check_box :terms_of_service, <%= render Shared::AgreeWithTermsOfServiceFieldComponent.new(f) %>
title: t("form.accept_terms_title"),
label: t("form.accept_terms",
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")) %>
</div> </div>
<% end %> <% end %>

View File

@@ -41,11 +41,7 @@
<div class="actions"> <div class="actions">
<% if debate.new_record? %> <% if debate.new_record? %>
<div> <div>
<%= f.check_box :terms_of_service, <%= render Shared::AgreeWithTermsOfServiceFieldComponent.new(f) %>
title: t("form.accept_terms_title"),
label: t("form.accept_terms",
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")) %>
</div> </div>
<% end %> <% end %>

View File

@@ -2,9 +2,7 @@
<%= back_link_to debates_path, t("debates.index.section_header.title") %> <%= back_link_to debates_path, t("debates.index.section_header.title") %>
<%= header do %> <%= header do %>
<%= link_to help_path(anchor: "debates"), title: t("shared.target_blank"), target: "_blank" do %> <%= link_to t("debates.new.more_info"), help_path(anchor: "debates") %>
<%= t("debates.new.more_info") %>
<% end %>
<% end %> <% end %>
<aside> <aside>

View File

@@ -1,6 +1,7 @@
class Debates::NewComponent < ApplicationComponent class Debates::NewComponent < ApplicationComponent
include Header include Header
attr_reader :debate attr_reader :debate
delegate :new_window_link_to, to: :helpers
def initialize(debate) def initialize(debate)
@debate = debate @debate = debate

View File

@@ -7,8 +7,8 @@
<p class="info"> <p class="info">
<%= sanitize(t("layouts.footer.description", <%= sanitize(t("layouts.footer.description",
open_source: link_to(t("layouts.footer.open_source"), t("layouts.footer.open_source_url"), target: "blank", rel: "nofollow"), open_source: link_to(t("layouts.footer.open_source"), t("layouts.footer.open_source_url"), target: "_blank", rel: "nofollow"),
consul: link_to(t("layouts.footer.consul"), t("layouts.footer.consul_url"), target: "blank", rel: "nofollow"))) %> consul: link_to(t("layouts.footer.consul"), t("layouts.footer.consul_url"), target: "_blank", rel: "nofollow"))) %>
</p> </p>
</div> </div>

View File

@@ -96,11 +96,7 @@
<div class="actions"> <div class="actions">
<% if proposal.new_record? %> <% if proposal.new_record? %>
<div> <div>
<%= f.check_box :terms_of_service, <%= render Shared::AgreeWithTermsOfServiceFieldComponent.new(f) %>
title: t("form.accept_terms_title"),
label: t("form.accept_terms",
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")) %>
</div> </div>
<% end %> <% end %>

View File

@@ -2,9 +2,7 @@
<%= back_link_to proposals_path, t("proposals.index.section_header.title") %> <%= back_link_to proposals_path, t("proposals.index.section_header.title") %>
<%= header do %> <%= header do %>
<%= link_to help_path(anchor: "proposals"), title: t("shared.target_blank"), target: "_blank" do %> <%= new_window_link_to t("proposals.new.more_info"), help_path(anchor: "proposals") %>
<%= t("proposals.new.more_info") %>
<% end %>
<% end %> <% end %>
<aside> <aside>

View File

@@ -1,6 +1,7 @@
class Proposals::NewComponent < ApplicationComponent class Proposals::NewComponent < ApplicationComponent
include Header include Header
attr_reader :proposal attr_reader :proposal
delegate :new_window_link_to, to: :helpers
def initialize(proposal) def initialize(proposal)
@proposal = proposal @proposal = proposal

View File

@@ -14,10 +14,8 @@
<%= f.text_field :related_sdg_list, <%= f.text_field :related_sdg_list,
class: "input", class: "input",
hint: sanitize(t("sdg.related_list_selector.hint", hint: sanitize(t("sdg.related_list_selector.hint",
link: link_to(t("sdg.related_list_selector.help.text"), link: new_window_link_to(t("sdg.related_list_selector.help.text"),
sdg_help_path, sdg_help_path)),
title: t("shared.target_blank"),
target: "_blank")),
attributes: %w[href title target]), attributes: %w[href title target]),
data: { "suggestions-list": sdg_related_suggestions, data: { "suggestions-list": sdg_related_suggestions,
"remove-tag-text": t("sdg.related_list_selector.remove_tag") } %> "remove-tag-text": t("sdg.related_list_selector.remove_tag") } %>

View File

@@ -1,5 +1,6 @@
class SDG::RelatedListSelectorComponent < ApplicationComponent class SDG::RelatedListSelectorComponent < ApplicationComponent
attr_reader :f attr_reader :f
delegate :new_window_link_to, to: :helpers
def initialize(form) def initialize(form)
@f = form @f = form

View File

@@ -0,0 +1 @@
<%= form.check_box :terms_of_service, label: label %>

View File

@@ -0,0 +1,16 @@
class Shared::AgreeWithTermsOfServiceFieldComponent < ApplicationComponent
attr_reader :form
delegate :new_window_link_to, to: :helpers
def initialize(form)
@form = form
end
private
def label
t("form.accept_terms",
policy: new_window_link_to(t("form.policy"), "/privacy"),
conditions: new_window_link_to(t("form.conditions"), "/conditions"))
end
end

View File

@@ -30,6 +30,10 @@ module ApplicationHelper
end end
end end
def new_window_link_to(text, path, **options)
link_to text, path, { target: "_blank", title: t("shared.target_blank") }.merge(options)
end
def image_path_for(filename) def image_path_for(filename)
image = SiteCustomization::Image.image_for(filename) image = SiteCustomization::Image.image_for(filename)

View File

@@ -62,11 +62,7 @@
<div class="small-12 column"> <div class="small-12 column">
<% if @proposal.new_record? %> <% if @proposal.new_record? %>
<%= f.check_box :terms_of_service, <%= render Shared::AgreeWithTermsOfServiceFieldComponent.new(f) %>
title: t("form.accept_terms_title"),
label: t("form.accept_terms",
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")) %>
<% end %> <% end %>
</div> </div>

View File

@@ -25,12 +25,9 @@
label: t("devise_views.organizations.registrations.new.password_confirmation_label") %> label: t("devise_views.organizations.registrations.new.password_confirmation_label") %>
<%= f.check_box :terms_of_service, <%= f.check_box :terms_of_service,
title: t("devise_views.users.registrations.new.terms_title"),
label: t("devise_views.users.registrations.new.terms", label: t("devise_views.users.registrations.new.terms",
terms: link_to(t("devise_views.users.registrations.new.terms_link"), terms: new_window_link_to(t("devise_views.users.registrations.new.terms_link"),
"/conditions", "/conditions")) %>
title: t("shared.target_blank"),
target: "_blank")) %>
<div class="small-12 medium-6 small-centered"> <div class="small-12 medium-6 small-centered">
<%= f.submit t("devise_views.organizations.registrations.new.submit"), class: "button expanded" %> <%= f.submit t("devise_views.organizations.registrations.new.submit"), class: "button expanded" %>

View File

@@ -35,12 +35,9 @@
<% end %> <% end %>
<%= f.check_box :terms_of_service, <%= f.check_box :terms_of_service,
title: t("devise_views.users.registrations.new.terms_title"),
label: t("devise_views.users.registrations.new.terms", label: t("devise_views.users.registrations.new.terms",
terms: link_to(t("devise_views.users.registrations.new.terms_link"), terms: new_window_link_to(t("devise_views.users.registrations.new.terms_link"),
"/conditions", "/conditions")) %>
title: t("shared.target_blank"),
target: "_blank")) %>
<div class="small-12 medium-6 small-centered"> <div class="small-12 medium-6 small-centered">
<%= f.submit t("devise_views.users.registrations.new.submit"), class: "button expanded" %> <%= f.submit t("devise_views.users.registrations.new.submit"), class: "button expanded" %>

View File

@@ -69,12 +69,9 @@
<div class="small-12"> <div class="small-12">
<%= f.check_box :terms_of_service, <%= f.check_box :terms_of_service,
title: t("verification.residence.new.accept_terms_text_title"),
label: t("verification.residence.new.accept_terms_text", label: t("verification.residence.new.accept_terms_text",
terms_url: link_to(t("verification.residence.new.terms"), terms_url: new_window_link_to(t("verification.residence.new.terms"),
page_path("census_terms"), page_path("census_terms"))) %>
title: t("shared.target_blank"),
target: "_blank")) %>
</div> </div>
<div class="small-12 medium-3 clear"> <div class="small-12 medium-3 clear">

View File

@@ -103,7 +103,6 @@ en:
submit: Register submit: Register
terms: By registering you accept the %{terms} terms: By registering you accept the %{terms}
terms_link: terms and conditions of use terms_link: terms and conditions of use
terms_title: By registering you accept the terms and conditions of use
title: Register title: Register
username_is_available: Username available username_is_available: Username available
username_is_not_available: Username already in use username_is_not_available: Username already in use

View File

@@ -143,7 +143,6 @@ en:
poll_ended: "Cannot be changed if voting has already ended" poll_ended: "Cannot be changed if voting has already ended"
form: form:
accept_terms: I agree to the %{policy} and the %{conditions} accept_terms: I agree to the %{policy} and the %{conditions}
accept_terms_title: I agree to the Privacy Policy and the Terms and conditions of use
conditions: Terms and conditions of use conditions: Terms and conditions of use
debate: Debate debate: Debate
direct_message: private message direct_message: private message

View File

@@ -46,7 +46,6 @@ en:
success: Residence verified success: Residence verified
new: new:
accept_terms_text: I accept %{terms_url} of the Census accept_terms_text: I accept %{terms_url} of the Census
accept_terms_text_title: I accept the terms and conditions of access of the Census
document_number: Document number document_number: Document number
document_number_help_title: Help document_number_help_title: Help
document_number_help_text: "<strong>DNI</strong>: 12345678A<br> <strong>Passport</strong>: AAA000001<br> <strong>Residence card</strong>: X1234567P" document_number_help_text: "<strong>DNI</strong>: 12345678A<br> <strong>Passport</strong>: AAA000001<br> <strong>Residence card</strong>: X1234567P"

View File

@@ -103,7 +103,6 @@ es:
submit: Registrarse submit: Registrarse
terms: Al registrarte aceptas las %{terms} terms: Al registrarte aceptas las %{terms}
terms_link: condiciones de uso terms_link: condiciones de uso
terms_title: Al registrarte aceptas las condiciones de uso
title: Registrarse title: Registrarse
username_is_available: Nombre de usuario disponible username_is_available: Nombre de usuario disponible
username_is_not_available: Nombre de usuario ya existente username_is_not_available: Nombre de usuario ya existente

View File

@@ -143,7 +143,6 @@ es:
poll_ended: "No puede ser cambiada si la votación ha acabado" poll_ended: "No puede ser cambiada si la votación ha acabado"
form: form:
accept_terms: Acepto la %{policy} y las %{conditions} accept_terms: Acepto la %{policy} y las %{conditions}
accept_terms_title: Acepto la Política de privacidad y las Condiciones de uso
conditions: Condiciones de uso conditions: Condiciones de uso
debate: el debate debate: el debate
direct_message: el mensaje privado direct_message: el mensaje privado

View File

@@ -46,7 +46,6 @@ es:
success: Residencia verificada success: Residencia verificada
new: new:
accept_terms_text: Acepto %{terms_url} al Padrón accept_terms_text: Acepto %{terms_url} al Padrón
accept_terms_text_title: Acepto los términos de acceso al Padrón
document_number: Número de documento document_number: Número de documento
document_number_help_title: Ayuda document_number_help_title: Ayuda
document_number_help_text: "<strong>DNI</strong>: 12345678A<br> <strong>Pasaporte</strong>: AAA000001<br> <strong>Tarjeta de residencia</strong>: X1234567P" document_number_help_text: "<strong>DNI</strong>: 12345678A<br> <strong>Pasaporte</strong>: AAA000001<br> <strong>Tarjeta de residencia</strong>: X1234567P"

View File

@@ -23,7 +23,7 @@ class ConsulFormBuilder < FoundationRailsHelper::FormBuilder
if options[:label] == false if options[:label] == false
super super
else else
label = tag.span sanitize(label_text(attribute, options[:label])), class: "checkbox" label = tag.span sanitized_label_text(attribute, options[:label]), class: "checkbox"
super(attribute, options.merge( super(attribute, options.merge(
label: label, label: label,
@@ -51,7 +51,7 @@ class ConsulFormBuilder < FoundationRailsHelper::FormBuilder
if text == false if text == false
super super
else else
super(attribute, sanitize(label_text(attribute, text)), options) super(attribute, sanitized_label_text(attribute, text), options)
end end
end end
@@ -68,6 +68,14 @@ class ConsulFormBuilder < FoundationRailsHelper::FormBuilder
end end
end end
def sanitized_label_text(attribute, text)
sanitize(label_text(attribute, text), attributes: allowed_attributes)
end
def allowed_attributes
self.class.sanitized_allowed_attributes + ["target"]
end
def label_options_for(options) def label_options_for(options)
label_options = options[:label_options] || {} label_options = options[:label_options] || {}

View File

@@ -0,0 +1,30 @@
require "rails_helper"
describe Shared::AgreeWithTermsOfServiceFieldComponent do
before do
dummy_model = Class.new do
include ActiveModel::Model
attr_accessor :terms_of_service
end
stub_const("DummyModel", dummy_model)
end
let(:form) { ConsulFormBuilder.new(:dummy, DummyModel.new, ApplicationController.new.view_context, {}) }
let(:component) { Shared::AgreeWithTermsOfServiceFieldComponent.new(form) }
it "contains links that open in a new window" do
render_inline component
expect(page).to have_css "a[target=_blank]", count: 2
end
it "contains links indicating they open in a new window" do
render_inline component
expect(page).to have_link count: 2
expect(page).to have_link "Privacy Policy"
expect(page).to have_link "Terms and conditions of use"
expect(page).to have_link " (link opens in new window)", count: 2
end
end

View File

@@ -13,6 +13,17 @@ describe ConsulFormBuilder do
let(:builder) { ConsulFormBuilder.new(:dummy, DummyModel.new, ApplicationController.new.view_context, {}) } let(:builder) { ConsulFormBuilder.new(:dummy, DummyModel.new, ApplicationController.new.view_context, {}) }
describe "label" do
it "accepts links that open in a new window in its content" do
render builder.text_field(:title, label: 'My <a href="/" target="_blank" title="New tab">title</a>')
expect(page).to have_link count: 1
expect(page).to have_link "title"
expect(page).to have_link "New tab"
expect(page).to have_css "a[target=_blank]"
end
end
describe "hints" do describe "hints" do
it "does not generate hints by default" do it "does not generate hints by default" do
render builder.text_field(:title) render builder.text_field(:title)

View File

@@ -164,8 +164,9 @@ describe "Residence" do
login_as(create(:user)) login_as(create(:user))
visit new_residence_path visit new_residence_path
click_link "the terms and conditions of access"
within_window(window_opened_by { click_link "the terms and conditions of access" }) do
expect(page).to have_content "Terms and conditions of access of the Census" expect(page).to have_content "Terms and conditions of access of the Census"
end end
end end
end