chore(form): respect dsfr fr-fieldset and elements expected markup
This commit is contained in:
parent
2cec44109d
commit
60882e0844
4 changed files with 88 additions and 36 deletions
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
.section-2 {
|
.section-2 {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
padding-top: 1rem;
|
padding-top: 2rem;
|
||||||
border-top: 2px solid var(--border-default-grey);
|
border-top: 2px solid var(--border-default-grey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,11 @@
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep only bottom margin in nested (consecutive) header sections, ie. first legend for a same level
|
||||||
|
.fr-fieldset > .fr-fieldset__legend + .fr-fieldset__element > .fr-fieldset:first-of-type .header-section {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
legend {
|
legend {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_within_fieldset?
|
def render_within_fieldset?
|
||||||
first_champ_is_an_header_section? && any_champ_fillable?
|
first_champ_is_an_header_section?
|
||||||
end
|
end
|
||||||
|
|
||||||
def header_section
|
def header_section
|
||||||
return @nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
@nodes.first if @nodes.first.is_a?(Champs::HeaderSectionChamp)
|
||||||
end
|
end
|
||||||
|
|
||||||
def splitted_tail
|
def splitted_tail
|
||||||
|
@ -30,13 +30,6 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
"h#{header_section.level + 1}"
|
"h#{header_section.level + 1}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# if two headers follows each others [h1, [h2, c]]
|
|
||||||
# the first one must not be contained in fieldset
|
|
||||||
# so we make the tree not fillable
|
|
||||||
def fillable?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def split_section_champ(node)
|
def split_section_champ(node)
|
||||||
case node
|
case node
|
||||||
when EditableChamp::SectionComponent
|
when EditableChamp::SectionComponent
|
||||||
|
@ -55,8 +48,4 @@ class EditableChamp::SectionComponent < ApplicationComponent
|
||||||
def first_champ_is_an_header_section?
|
def first_champ_is_an_header_section?
|
||||||
header_section.present?
|
header_section.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def any_champ_fillable?
|
|
||||||
tail.any? { _1&.fillable? }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
- if render_within_fieldset?
|
- if render_within_fieldset?
|
||||||
= tag.fieldset(class: "reset-#{tag_for_depth} fr-m-0 fr-p-0") do
|
.fr-fieldset__element{ class: class_names("fr-my-0" => render_within_fieldset?) }
|
||||||
= tag.legend do
|
%fieldset.fr-fieldset.fr-my-0{ class: "reset-#{tag_for_depth}" }
|
||||||
|
%legend.fr-fieldset__legend
|
||||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
||||||
- splitted_tail.each do |section, champ|
|
- splitted_tail.each do |section, champ|
|
||||||
- if section.present?
|
- if section.present?
|
||||||
= render section
|
= render section
|
||||||
- else
|
- else
|
||||||
= fields_for champ.input_name, champ do |form|
|
= fields_for champ.input_name, champ do |form|
|
||||||
= render EditableChamp::EditableChampComponent.new form: ,champ:
|
.fr-fieldset__element
|
||||||
|
= render EditableChamp::EditableChampComponent.new form:, champ:
|
||||||
- else
|
- else
|
||||||
|
%fieldset.fr-fieldset.fr-my-0
|
||||||
- if header_section
|
- if header_section
|
||||||
%div{ class: "reset-#{tag_for_depth}" }= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
%legend.fr-fieldset__legend.fr-my-0{ class: "reset-#{tag_for_depth}" }
|
||||||
|
= render EditableChamp::HeaderSectionComponent.new(champ: header_section)
|
||||||
- splitted_tail.each do |section, champ|
|
- splitted_tail.each do |section, champ|
|
||||||
- if section.present?
|
- if section.present?
|
||||||
= render section
|
= render section
|
||||||
- else
|
- else
|
||||||
= fields_for champ.input_name, champ do |form|
|
= fields_for champ.input_name, champ do |form|
|
||||||
= render EditableChamp::EditableChampComponent.new form: ,champ:
|
.fr-fieldset__element
|
||||||
|
= render EditableChamp::EditableChampComponent.new form:, champ:
|
||||||
|
|
|
@ -6,8 +6,8 @@ describe EditableChamp::SectionComponent, type: :component do
|
||||||
context 'list of champs without an header_section' do
|
context 'list of champs without an header_section' do
|
||||||
let(:champs) { [build(:champ_text), build(:champ_textarea)] }
|
let(:champs) { [build(:champ_text), build(:champ_textarea)] }
|
||||||
|
|
||||||
it 'does not render fieldset' do
|
it 'render in a fieldset' do
|
||||||
expect(page).not_to have_selector("fieldset")
|
expect(page).to have_selector("fieldset", count: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders champs' do
|
it 'renders champs' do
|
||||||
|
@ -34,21 +34,21 @@ describe EditableChamp::SectionComponent, type: :component do
|
||||||
let(:champs) { [build(:champ_text), build(:champ_header_section_level_1), build(:champ_text)] }
|
let(:champs) { [build(:champ_text), build(:champ_header_section_level_1), build(:champ_text)] }
|
||||||
|
|
||||||
it 'renders fieldset' do
|
it 'renders fieldset' do
|
||||||
expect(page).to have_selector("fieldset")
|
expect(page).to have_selector("fieldset", count: 2)
|
||||||
expect(page).to have_selector("legend h2")
|
expect(page).to have_selector("legend h2")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders all champs, one outside fieldset, one within fieldset' do
|
it 'renders all champs, each in its fieldset' do
|
||||||
expect(page).to have_selector("input[type=text]", count: 2)
|
expect(page).to have_selector("input[type=text]", count: 2)
|
||||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
expect(page).to have_selector("fieldset > .fr-fieldset__element input[type=text]", count: 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'list of header_section without champs' do
|
context 'list of header_section without champs' do
|
||||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_header_section_level_2), build(:champ_header_section_level_3)] }
|
let(:champs) { [build(:champ_header_section_level_1), build(:champ_header_section_level_2), build(:champ_header_section_level_3)] }
|
||||||
|
|
||||||
it 'does not render header within fieldset' do
|
it 'render header within fieldset' do
|
||||||
expect(page).not_to have_selector("fieldset")
|
expect(page).to have_selector("fieldset > legend", count: 3)
|
||||||
expect(page).to have_selector("h2")
|
expect(page).to have_selector("h2")
|
||||||
expect(page).to have_selector("h3")
|
expect(page).to have_selector("h3")
|
||||||
expect(page).to have_selector("h4")
|
expect(page).to have_selector("h4")
|
||||||
|
@ -58,10 +58,10 @@ describe EditableChamp::SectionComponent, type: :component do
|
||||||
context 'header_section followed by explication and another fieldset' do
|
context 'header_section followed by explication and another fieldset' do
|
||||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_explication), build(:champ_header_section_level_1), build(:champ_text)] }
|
let(:champs) { [build(:champ_header_section_level_1), build(:champ_explication), build(:champ_header_section_level_1), build(:champ_text)] }
|
||||||
|
|
||||||
it 'render fieldset, header_section (one within fieldset, one outside), also render explication' do
|
it 'render fieldset, header_section, also render explication' do
|
||||||
expect(page).to have_selector("h2", count: 2)
|
expect(page).to have_selector("h2", count: 2)
|
||||||
expect(page).to have_selector("h3") # explication
|
expect(page).to have_selector("h3") # explication
|
||||||
expect(page).to have_selector("fieldset h2", count: 1)
|
expect(page).to have_selector("fieldset > legend > h2", count: 2)
|
||||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -110,4 +110,57 @@ describe EditableChamp::SectionComponent, type: :component do
|
||||||
expect(page).to have_selector("fieldset fieldset input[type=text]", count: dossier.champs_public.find(&:repetition?).rows.size)
|
expect(page).to have_selector("fieldset fieldset input[type=text]", count: dossier.champs_public.find(&:repetition?).rows.size)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with complex markup structure' do
|
||||||
|
def check_fieldset_structure(fieldset)
|
||||||
|
expect(fieldset[:class]).to include('fr-fieldset')
|
||||||
|
|
||||||
|
# Vérifie que chaque fr-fieldset a un enfant fr-fieldset__element ou une légende
|
||||||
|
fieldset.all('> *').each do |child|
|
||||||
|
expect(child.tag_name).to be_in(['div', 'legend', 'input'])
|
||||||
|
|
||||||
|
case child.tag_name
|
||||||
|
when 'legend'
|
||||||
|
expect(child[:class]).to include('fr-fieldset__legend')
|
||||||
|
when 'input'
|
||||||
|
expect(child[:type]).to eq("hidden")
|
||||||
|
else
|
||||||
|
expect(child[:class]).to include('fr-fieldset__element')
|
||||||
|
# Vérifie récursivement les fieldsets imbriqués
|
||||||
|
child.all('> fieldset').each do |nested_fieldset|
|
||||||
|
check_fieldset_structure(nested_fieldset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:champs) {
|
||||||
|
[
|
||||||
|
build(:champ_header_section_level_1),
|
||||||
|
build(:champ_header_section_level_2),
|
||||||
|
build(:champ_header_section_level_3),
|
||||||
|
build(:champ_integer_number),
|
||||||
|
|
||||||
|
build(:champ_header_section_level_3),
|
||||||
|
build(:champ_yes_no),
|
||||||
|
|
||||||
|
build(:champ_header_section_level_2),
|
||||||
|
build(:champ_header_section_level_3),
|
||||||
|
build(:champ_integer_number),
|
||||||
|
|
||||||
|
build(:champ_header_section_level_1),
|
||||||
|
build(:champ_text),
|
||||||
|
build(:champ_header_section_level_2),
|
||||||
|
build(:champ_text)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'respect dsfr fieldset hierarchy' do
|
||||||
|
within('.dossier-edit .form') do
|
||||||
|
all('fieldset').each do |fieldset|
|
||||||
|
check_fieldset_structure(fieldset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue