Merge pull request #4358 from consul/sdg_related_list_fieldest

Improve goals/targets selector accessibility
This commit is contained in:
Javi Martín
2021-02-15 16:12:15 +01:00
committed by GitHub
11 changed files with 95 additions and 52 deletions

View File

@@ -30,11 +30,11 @@
var keep_goal = $(amsify_suggestags.selector).val().split(",").some(function(selected_value) { var keep_goal = $(amsify_suggestags.selector).val().split(",").some(function(selected_value) {
return App.SDGRelatedListSelector.goal_code(value) === App.SDGRelatedListSelector.goal_code(selected_value); return App.SDGRelatedListSelector.goal_code(value) === App.SDGRelatedListSelector.goal_code(selected_value);
}); });
App.SDGRelatedListSelector.goal_element(value).attr("aria-checked", keep_goal); App.SDGRelatedListSelector.goal_element(value).prop("checked", keep_goal);
App.SDGRelatedListSelector.manage_remove_help(amsify_suggestags, value); App.SDGRelatedListSelector.manage_remove_help(amsify_suggestags, value);
}, },
afterAdd: function(value) { afterAdd: function(value) {
App.SDGRelatedListSelector.goal_element(value).attr("aria-checked", true); App.SDGRelatedListSelector.goal_element(value).prop("checked", true);
App.SDGRelatedListSelector.manage_add_help(amsify_suggestags, value); App.SDGRelatedListSelector.manage_add_help(amsify_suggestags, value);
}, },
keepLastOnHoverTag: false, keepLastOnHoverTag: false,
@@ -48,23 +48,24 @@
} }
}, },
manage_icons: function(amsify_suggestags) { manage_icons: function(amsify_suggestags) {
$("[role='checkbox']").on("click keydown", function(event) { $(".sdg-related-list-selector .goals input").on("change", function() {
var goal_id = this.dataset.code; var goal_id = this.dataset.code;
if (event.type === "click" || (event.type === "keydown" && [13, 32].indexOf(event.keyCode) >= 0)) {
if (amsify_suggestags.isPresent(goal_id)) { if (amsify_suggestags.isPresent(goal_id)) {
amsify_suggestags.removeTag(goal_id, false); amsify_suggestags.removeTag(goal_id, false);
} else { } else {
amsify_suggestags.addTag(goal_id, false); amsify_suggestags.addTag(goal_id, false);
} }
}).on("keydown", function(event) {
if (event.keyCode === 13) {
$(this).trigger("click");
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} }
}); });
}, },
goal_element: function(value) { goal_element: function(value) {
return $("li[data-code=" + App.SDGRelatedListSelector.goal_code(value) + "]"); return $(".sdg-related-list-selector .goals [data-code=" + App.SDGRelatedListSelector.goal_code(value) + "]");
}, },
goal_code: function(value) { goal_code: function(value) {
return value.toString().split(".")[0]; return value.toString().split(".")[0];

View File

@@ -244,7 +244,7 @@
width: calc(100% + #{$spacing}); width: calc(100% + #{$spacing});
width: calc(100% + #{$max-spacing}); width: calc(100% + #{$max-spacing});
li { > * {
margin-bottom: 0; margin-bottom: 0;
margin-left: $spacing; margin-left: $spacing;
margin-left: $max-spacing; margin-left: $max-spacing;

View File

@@ -2,6 +2,10 @@
@include grid-column-gutter; @include grid-column-gutter;
clear: both; clear: both;
> legend {
margin-bottom: 0;
}
.amsify-suggestags-area .amsify-select-tag { .amsify-suggestags-area .amsify-select-tag {
color: $white; color: $white;
@@ -12,22 +16,19 @@
} }
} }
label + ul { .goals {
$spacing: 0.5%; $spacing: 0.5%;
@include sdg-goal-list($spacing); @include sdg-goal-list($spacing);
li { legend {
font-weight: normal;
font-style: italic;
}
label {
min-width: $sdg-icon-min-width; min-width: $sdg-icon-min-width;
width: calc(100% / 17 - #{$spacing}); width: calc(100% / 17 - #{$spacing});
&[aria-checked=true] img {
opacity: 0.15;
}
&:focus {
outline: $outline-focus;
}
&:hover { &:hover {
cursor: pointer; cursor: pointer;
} }
@@ -36,6 +37,23 @@
width: 100%; width: 100%;
} }
} }
input {
@include element-invisible;
&:focus + label {
outline: $outline-focus;
}
&:checked + label img {
opacity: 0.15;
}
}
}
label {
font-weight: normal;
font-style: italic;
} }
.input-section { .input-section {

View File

@@ -1,26 +1,24 @@
<div class="sdg-related-list-selector"> <fieldset class="sdg-related-list-selector">
<div class="input-section"> <legend><%= t("sdg.related_list_selector.title") %></legend>
<%= f.label :related_sdg_list %>
<ul aria-label="<%= t("sdg.related_list_selector.goal_list") %>"> <div class="input-section">
<% goals.each do |goal| %> <fieldset class="goals">
<li data-code="<%= goal.code %>" role="checkbox" aria-checked="<%= checked?(goal.code) %>" tabindex="0"> <legend><%= t("sdg.related_list_selector.goal_list", record: relatable_name) %></legend>
<%= render SDG::Goals::IconComponent.new(goal) %> <%= f.collection_check_boxes(:sdg_goal_ids, goals, :id, :code) do |checkbox_form| %>
</li> <%= goal_field(checkbox_form) %>
<% end %> <% end %>
</ul> </fieldset>
<%= f.text_field :related_sdg_list, <%= f.text_field :related_sdg_list,
class: "input", class: "input",
label: false,
placeholder: t("sdg.related_list_selector.placeholder"), placeholder: t("sdg.related_list_selector.placeholder"),
hint: t("sdg.related_list_selector.hint"), label: t("sdg.related_list_selector.hint"),
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") } %>
</div> </div>
<div class="help-section callout primary hide"> <div class="help-section callout primary hide">
<h3><%= t("sdg.related_list_selector.help.title", record: f.object.model_name.human) %></h3> <h3><%= t("sdg.related_list_selector.help.title", record: relatable_name) %></h3>
<ul class="selected-info"></ul> <ul class="selected-info"></ul>
</div> </div>
</div> </fieldset>

View File

@@ -5,10 +5,6 @@ class SDG::RelatedListSelectorComponent < ApplicationComponent
@f = form @f = form
end end
def checked?(code)
f.object.sdg_goals.find_by(code: code).present?
end
def sdg_related_suggestions def sdg_related_suggestions
goals_and_targets.map { |goal_or_target| suggestion_tag_for(goal_or_target) } goals_and_targets.map { |goal_or_target| suggestion_tag_for(goal_or_target) }
end end
@@ -39,6 +35,13 @@ class SDG::RelatedListSelectorComponent < ApplicationComponent
SDG::Goal.order(:code) SDG::Goal.order(:code)
end end
def goal_field(checkbox_form)
goal = checkbox_form.object
checkbox_form.check_box(data: { code: goal.code }) +
checkbox_form.label { render(SDG::Goals::IconComponent.new(goal)) }
end
def text_for(goal_or_target) def text_for(goal_or_target)
if goal_or_target.class.name == "SDG::Goal" if goal_or_target.class.name == "SDG::Goal"
t("sdg.related_list_selector.goal_identifier", code: goal_or_target.code) t("sdg.related_list_selector.goal_identifier", code: goal_or_target.code)
@@ -46,4 +49,8 @@ class SDG::RelatedListSelectorComponent < ApplicationComponent
goal_or_target.code goal_or_target.code
end end
end end
def relatable_name
f.object.model_name.human.downcase
end
end end

View File

@@ -2,7 +2,6 @@ en:
attributes: attributes:
geozone_id: "Scope of operation" geozone_id: "Scope of operation"
results_enabled: "Show results" results_enabled: "Show results"
related_sdg_list: "Sustainable Development Goals and Targets"
stats_enabled: "Show stats" stats_enabled: "Show stats"
advanced_stats_enabled: "Show advanced stats" advanced_stats_enabled: "Show advanced stats"
name: Name name: Name

View File

@@ -455,12 +455,13 @@ en:
other: "%{count} more goals" other: "%{count} more goals"
related_list_selector: related_list_selector:
goal_identifier: "SDG%{code}" goal_identifier: "SDG%{code}"
goal_list: "Goal list" goal_list: "You can choose one or several SDGs aligned with your %{record}"
help: help:
title: "Which SDGs and targets are aligned with my %{record}?" title: "Which SDGs and targets are aligned with my %{record}?"
hint: "You can introduce the code of a specific goal/target or a text to find one" hint: "You can introduce the code of a specific goal/target or a text to find one"
placeholder: "Write a goal or target code or description" placeholder: "Write a goal or target code or description"
remove_tag: "Remove" remove_tag: "Remove"
title: "Sustainable Development Goals and Targets"
targets: targets:
filter: filter:
link: "See all %{resources} related to target %{code}" link: "See all %{resources} related to target %{code}"

View File

@@ -2,7 +2,6 @@ es:
attributes: attributes:
geozone_id: "Ámbito de actuación" geozone_id: "Ámbito de actuación"
results_enabled: "Mostrar resultados" results_enabled: "Mostrar resultados"
related_sdg_list: "Objetivos de Desarrollo Sostenible y Metas"
stats_enabled: "Mostrar estadísticas" stats_enabled: "Mostrar estadísticas"
advanced_stats_enabled: "Mostrar estadísticas avanzadas" advanced_stats_enabled: "Mostrar estadísticas avanzadas"
name: Nombre name: Nombre

View File

@@ -455,12 +455,13 @@ es:
other: "%{count} objetivos más" other: "%{count} objetivos más"
related_list_selector: related_list_selector:
goal_identifier: "ODS%{code}" goal_identifier: "ODS%{code}"
goal_list: "Listado de objetivos" goal_list: "Puedes seleccionar uno o varios ODS con los que se alinea tu %{record}"
help: help:
title: "¿Qué ODS y metas se alinean con mi %{record}?" title: "¿Qué ODS y metas se alinean con mi %{record}?"
hint: "Puedes introducir el código de un objetivo/meta específico o un texto para encontrar uno" hint: "Puedes introducir el código de un objetivo/meta específico o un texto para encontrar uno"
placeholder: "Escribe las etiquetas que desees" placeholder: "Escribe las etiquetas que desees"
remove_tag: "Eliminar" remove_tag: "Eliminar"
title: "Objetivos de Desarrollo Sostenible y Metas"
targets: targets:
filter: filter:
link: "Ver %{resources} de la meta %{code}" link: "Ver %{resources} de la meta %{code}"

View File

@@ -45,7 +45,9 @@ module CommonActions
end end
def click_sdg_goal(code) def click_sdg_goal(code)
find("li[data-code='#{code}']").click within(".sdg-related-list-selector .goals") do
find("[data-code='#{code}'] + label").click
end
end end
def remove_sdg_goal_or_target_tag(code) def remove_sdg_goal_or_target_tag(code)

View File

@@ -299,17 +299,17 @@ describe "SDG Relations", :js do
create(:sdg_local_target, code: "1.1.1") create(:sdg_local_target, code: "1.1.1")
visit sdg_management_edit_legislation_process_path(process) visit sdg_management_edit_legislation_process_path(process)
fill_in "Sustainable Development Goals and Targets", with: "3" fill_in "You can introduce the code of a specific goal/target or a text to find one", with: "3"
within(".amsify-list") { find(:css, "[data-val='3']").click } within(".amsify-list") { find(:css, "[data-val='3']").click }
within(".amsify-suggestags-input-area") { expect(page).to have_content "SDG3" } within(".amsify-suggestags-input-area") { expect(page).to have_content "SDG3" }
fill_in "Sustainable Development Goals and Targets", with: "1.1" fill_in "You can introduce the code of a specific goal/target or a text to find one", with: "1.1"
within(".amsify-list") { find(:css, "[data-val='1.1']").click } within(".amsify-list") { find(:css, "[data-val='1.1']").click }
within(".amsify-suggestags-input-area") { expect(page).to have_content "1.1" } within(".amsify-suggestags-input-area") { expect(page).to have_content "1.1" }
fill_in "Sustainable Development Goals and Targets", with: "1.1.1" fill_in "You can introduce the code of a specific goal/target or a text to find one", with: "1.1.1"
within(".amsify-list") { find(:css, "[data-val='1.1.1']").click } within(".amsify-list") { find(:css, "[data-val='1.1.1']").click }
within(".amsify-suggestags-input-area") { expect(page).to have_content "1.1.1" } within(".amsify-suggestags-input-area") { expect(page).to have_content "1.1.1" }
@@ -327,8 +327,8 @@ describe "SDG Relations", :js do
process = create(:legislation_process, title: "SDG process") process = create(:legislation_process, title: "SDG process")
visit sdg_management_edit_legislation_process_path(process) visit sdg_management_edit_legislation_process_path(process)
fill_in "You can introduce the code of a specific goal/target or a text to find one", with: "tag nonexistent,"
fill_in "Sustainable Development Goals and Targets", with: "tag nonexistent,"
within(".amsify-suggestags-input-area") { expect(page).not_to have_content "tag nonexistent" } within(".amsify-suggestags-input-area") { expect(page).not_to have_content "tag nonexistent" }
end end
@@ -368,7 +368,7 @@ describe "SDG Relations", :js do
visit sdg_management_edit_legislation_process_path(process) visit sdg_management_edit_legislation_process_path(process)
click_sdg_goal(1) click_sdg_goal(1)
expect(find("li[data-code='1']")["aria-checked"]).to eq "true" expect(find("input[data-code='1']")).to be_checked
end end
scenario "when remove a last tag related to a Goal, the icon will not be checked" do scenario "when remove a last tag related to a Goal, the icon will not be checked" do
@@ -380,15 +380,32 @@ describe "SDG Relations", :js do
visit sdg_management_edit_legislation_process_path(process) visit sdg_management_edit_legislation_process_path(process)
remove_sdg_goal_or_target_tag(1) remove_sdg_goal_or_target_tag(1)
expect(find("li[data-code='1']")["aria-checked"]).to eq "true" expect(find("input[data-code='1']")).to be_checked
remove_sdg_goal_or_target_tag(1.1) remove_sdg_goal_or_target_tag(1.1)
expect(find("li[data-code='1']")["aria-checked"]).to eq "true" expect(find("input[data-code='1']")).to be_checked
remove_sdg_goal_or_target_tag("1.1.1") remove_sdg_goal_or_target_tag("1.1.1")
expect(find("li[data-code='1']")["aria-checked"]).to eq "false" expect(find("input[data-code='1']")).not_to be_checked
end
context "when we have a Goal and a related Target selected" do
scenario "we can remove and add same Goal always keeping the icon as checked" do
process = create(:legislation_process, title: "SDG process")
process.sdg_goals = [SDG::Goal[1]]
process.sdg_targets = [SDG::Target[1.1]]
visit sdg_management_edit_legislation_process_path(process)
click_sdg_goal(1)
expect(find("input[data-code='1']")).to be_checked
click_sdg_goal(1)
expect(find("input[data-code='1']")).to be_checked
end
end end
end end