Merge pull request #4358 from consul/sdg_related_list_fieldest
Improve goals/targets selector accessibility
This commit is contained in:
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user