tech(remaniement): isole la logique de rendu au champs_subtree_component
This commit is contained in:
parent
3b5d1bd55b
commit
88abefb370
10 changed files with 137 additions and 191 deletions
|
@ -1,41 +1,47 @@
|
|||
class EditableChamp::ChampsSubtreeComponent < ApplicationComponent
|
||||
include ApplicationHelper
|
||||
include TreeableConcern
|
||||
|
||||
attr_reader :header_section, :nodes
|
||||
|
||||
def initialize(header_section:)
|
||||
@header_section = header_section
|
||||
@nodes = []
|
||||
end
|
||||
|
||||
# a nodes can be either a champs, or a subtree
|
||||
def add_node(node)
|
||||
nodes.push(node)
|
||||
def initialize(nodes:)
|
||||
@nodes = to_fieldset(nodes:)
|
||||
end
|
||||
|
||||
def render_within_fieldset?
|
||||
header_section && !empty_section?
|
||||
first_champ_is_an_header_section? && any_champ_fillable?
|
||||
end
|
||||
|
||||
def render_header_section_only?
|
||||
header_section && empty_section?
|
||||
def header_section
|
||||
first_champ = @nodes.first
|
||||
return first_champ if first_champ.is_a?(Champs::HeaderSectionChamp)
|
||||
nil
|
||||
end
|
||||
|
||||
def empty_section?
|
||||
nodes.none? { |node| node.is_a?(Champ) }
|
||||
end
|
||||
def champs
|
||||
return @nodes if !first_champ_is_an_header_section?
|
||||
_, *rest_of_champ = @nodes
|
||||
|
||||
def level
|
||||
if header_section.parent.present?
|
||||
header_section.header_section_level_value.to_i + header_section.parent.current_section_level
|
||||
elsif header_section
|
||||
header_section.header_section_level_value.to_i
|
||||
else
|
||||
0
|
||||
end
|
||||
rest_of_champ
|
||||
end
|
||||
|
||||
def tag_for_depth
|
||||
"h#{level + 1}"
|
||||
"h#{header_section.level + 1}"
|
||||
end
|
||||
|
||||
def fillable?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def to_fieldset(nodes:)
|
||||
nodes.map { _1.is_a?(Array) ? EditableChamp::ChampsSubtreeComponent.new(nodes: _1) : _1 }
|
||||
end
|
||||
|
||||
def first_champ_is_an_header_section?
|
||||
header_section.present?
|
||||
end
|
||||
|
||||
def any_champ_fillable?
|
||||
champs.any? { _1&.fillable? }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
- if render_within_fieldset?
|
||||
= tag.fieldset(class: "reset-#{tag_for_depth}") do
|
||||
= tag.legend do
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section, form: nil, level: level)
|
||||
- @nodes.each do |champ_or_section|
|
||||
- if champ_or_section.is_a?(Champ)
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section, form: nil)
|
||||
- champs.each do |champ_or_section|
|
||||
- if !champ_or_section.is_a?(EditableChamp::ChampsSubtreeComponent)
|
||||
= render EditableChamp::FieldsForChampComponent.new(champ: champ_or_section, seen_at: nil)
|
||||
- else
|
||||
= render champ_or_section
|
||||
- elsif render_header_section_only?
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section, form: nil, level: level)
|
||||
- else
|
||||
- @nodes.each do |champ_or_section|
|
||||
- if champ_or_section.is_a?(Champ)
|
||||
- if header_section
|
||||
= render EditableChamp::HeaderSectionComponent.new(champ: header_section, form: nil)
|
||||
- champs.each do |champ_or_section|
|
||||
- if !champ_or_section.is_a?(EditableChamp::ChampsSubtreeComponent)
|
||||
= render EditableChamp::FieldsForChampComponent.new(champ: champ_or_section, seen_at: nil)
|
||||
- else
|
||||
= render champ_or_section
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
class EditableChamp::ChampsTreeComponent < ApplicationComponent
|
||||
include Champs::Treeable
|
||||
|
||||
attr_reader :root
|
||||
include TreeableConcern
|
||||
|
||||
def initialize(champs:, root_depth:)
|
||||
@root = to_tree(champs:, root_depth:, build_champs_subtree_component: method(:build_champs_subtree_component))
|
||||
end
|
||||
|
||||
def build_champs_subtree_component(header_section:)
|
||||
EditableChamp::ChampsSubtreeComponent.new(header_section:)
|
||||
@tree = to_tree(champs:, root_depth:)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1 +1 @@
|
|||
= render @root
|
||||
= render EditableChamp::ChampsSubtreeComponent.new(nodes: @tree)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
class EditableChamp::HeaderSectionComponent < ApplicationComponent
|
||||
def initialize(form:, champ:, seen_at: nil, level: 1)
|
||||
def initialize(form:, champ:, seen_at: nil)
|
||||
@champ = champ
|
||||
@form = form
|
||||
@level = level
|
||||
end
|
||||
|
||||
def level
|
||||
@champ.level
|
||||
end
|
||||
|
||||
def libelle
|
||||
|
@ -10,13 +13,13 @@ class EditableChamp::HeaderSectionComponent < ApplicationComponent
|
|||
end
|
||||
|
||||
def header_section_classnames
|
||||
class_names = ["fr-h#{@level}", 'header-section']
|
||||
class_names = ["fr-h#{level}", 'header-section']
|
||||
|
||||
class_names << 'header-section-counter' if @champ.dossier.auto_numbering_section_headers_for?(@champ)
|
||||
class_names
|
||||
end
|
||||
|
||||
def tag_for_depth
|
||||
"h#{@level + 1}"
|
||||
"h#{level + 1}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
# type_de_champ_id :integer
|
||||
#
|
||||
class Champs::HeaderSectionChamp < Champ
|
||||
|
||||
def level
|
||||
if parent.present?
|
||||
header_section_level_value.to_i + parent.current_section_level
|
||||
|
|
|
@ -420,7 +420,6 @@ class TypeDeChamp < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def previous_section_level(upper_tdcs)
|
||||
previous_header_section = upper_tdcs.reverse.find(&:header_section?)
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
describe EditableChamp::ChampsSubtreeComponent, type: :component do
|
||||
include TreeableConcern
|
||||
let(:component) { described_class.new(nodes: nodes) }
|
||||
let(:nodes) { to_tree(champs:, root_depth:) }
|
||||
let(:root_depth) { 0 }
|
||||
before { render_inline(component).to_html }
|
||||
|
||||
context 'list of champs without an header_section' do
|
||||
let(:champs) { [build(:champ_text), build(:champ_textarea)] }
|
||||
|
||||
it 'does not render fieldset' do
|
||||
expect(page).not_to have_selector("fieldset")
|
||||
end
|
||||
|
||||
it 'renders champs' do
|
||||
expect(page).to have_selector("input[type=text]", count: 1)
|
||||
expect(page).to have_selector("textarea", count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'list of champs with an header_section' do
|
||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_text), build(:champ_textarea)] }
|
||||
|
||||
it 'renders fieldset' do
|
||||
expect(page).to have_selector("fieldset")
|
||||
expect(page).to have_selector("legend h2")
|
||||
end
|
||||
|
||||
it 'renders champs within fieldset' do
|
||||
expect(page).to have_selector("fieldset input[type=text]")
|
||||
expect(page).to have_selector("fieldset textarea")
|
||||
end
|
||||
end
|
||||
|
||||
context 'list of champs without section and an header_section having champs' do
|
||||
let(:champs) { [build(:champ_text), build(:champ_header_section_level_1), build(:champ_text)] }
|
||||
|
||||
it 'renders fieldset' do
|
||||
expect(page).to have_selector("fieldset")
|
||||
expect(page).to have_selector("legend h2")
|
||||
end
|
||||
|
||||
it 'renders all champs, one outside fieldset, one within fieldset' do
|
||||
expect(page).to have_selector("input[type=text]", count: 2)
|
||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
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)] }
|
||||
|
||||
it 'does not render header within fieldset' do
|
||||
expect(page).not_to have_selector("fieldset")
|
||||
expect(page).to have_selector("h2")
|
||||
expect(page).to have_selector("h3")
|
||||
expect(page).to have_selector("h4")
|
||||
end
|
||||
end
|
||||
|
||||
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)] }
|
||||
|
||||
it 'render fieldset, header_section (one within fieldset, one outside), also render explication' do
|
||||
expect(page).to have_selector("h2", count: 2)
|
||||
expect(page).to have_selector("h3") # explication
|
||||
expect(page).to have_selector("fieldset h2", count: 1)
|
||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'nested fieldsset' do
|
||||
let(:champs) { [build(:champ_header_section_level_1), build(:champ_text), build(:champ_header_section_level_2), build(:champ_textarea)] }
|
||||
|
||||
it 'render nested fieldsets' do
|
||||
expect(page).to have_selector("fieldset")
|
||||
expect(page).to have_selector("legend h2")
|
||||
expect(page).to have_selector("fieldset fieldset")
|
||||
expect(page).to have_selector("fieldset fieldset legend h3")
|
||||
end
|
||||
|
||||
it 'contains all champs' do
|
||||
expect(page).to have_selector("fieldset input[type=text]", count: 1)
|
||||
expect(page).to have_selector("fieldset fieldset textarea", count: 1)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,142 +0,0 @@
|
|||
describe EditableChamp::ChampsTreeComponent, type: :component do
|
||||
let(:component) { described_class.new(champs: champs, root_depth: 0) }
|
||||
subject { component.root }
|
||||
describe "to_tree" do
|
||||
let(:header_1) { build(:champ_header_section_level_1) }
|
||||
let(:header_1_2) { build(:champ_header_section_level_2) }
|
||||
let(:header_2) { build(:champ_header_section_level_1) }
|
||||
let(:champ_text) { build(:champ_text) }
|
||||
let(:champ_textarea) { build(:champ_textarea) }
|
||||
let(:champ_explication) { build(:champ_explication) }
|
||||
let(:champ_communes) { build(:champ_communes) }
|
||||
|
||||
context 'without section' do
|
||||
let(:champs) do
|
||||
[
|
||||
champ_text, champ_textarea
|
||||
]
|
||||
end
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.header_section).to eq(nil)
|
||||
expect(subject.nodes.size).to eq(champs.size)
|
||||
expect(subject.nodes).to eq(champs)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with sections only' do
|
||||
let(:champs) do
|
||||
[
|
||||
header_1,
|
||||
champ_explication,
|
||||
champ_text,
|
||||
header_2,
|
||||
champ_textarea
|
||||
]
|
||||
end
|
||||
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].header_section).to eq(header_1)
|
||||
expect(subject.nodes[0].nodes).to eq([champ_explication, champ_text])
|
||||
expect(subject.nodes[1].header_section).to eq(header_2)
|
||||
expect(subject.nodes[1].nodes).to eq([champ_textarea])
|
||||
end
|
||||
end
|
||||
|
||||
context 'leading champs, and in between sections only' do
|
||||
let(:champs) do
|
||||
[
|
||||
champ_text,
|
||||
champ_textarea,
|
||||
header_1,
|
||||
champ_explication,
|
||||
champ_communes,
|
||||
header_2,
|
||||
champ_textarea
|
||||
]
|
||||
end
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.nodes.size).to eq(4)
|
||||
expect(subject.nodes[0]).to eq(champ_text)
|
||||
expect(subject.nodes[1]).to eq(champ_textarea)
|
||||
expect(subject.nodes[2].header_section).to eq(header_1)
|
||||
expect(subject.nodes[2].nodes).to eq([champ_explication, champ_communes])
|
||||
expect(subject.nodes[3].header_section).to eq(header_2)
|
||||
expect(subject.nodes[3].nodes).to eq([champ_textarea])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with one sub sections' do
|
||||
let(:champs) do
|
||||
[
|
||||
header_1,
|
||||
champ_explication,
|
||||
header_1_2,
|
||||
champ_communes,
|
||||
header_2,
|
||||
champ_textarea
|
||||
]
|
||||
end
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].header_section).to eq(header_1)
|
||||
expect(subject.nodes[0].nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].nodes[1].header_section).to eq(header_1_2)
|
||||
expect(subject.nodes[0].nodes[1].nodes).to eq([champ_communes])
|
||||
expect(subject.nodes[1].header_section).to eq(header_2)
|
||||
expect(subject.nodes[1].nodes).to eq([champ_textarea])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with consecutive subsection' do
|
||||
let(:header_1) { build(:champ_header_section_level_1) }
|
||||
let(:header_1_2_1) { build(:champ_header_section_level_2) }
|
||||
let(:header_1_2_2) { build(:champ_header_section_level_2) }
|
||||
let(:header_1_2_3) { build(:champ_header_section_level_2) }
|
||||
let(:champs) do
|
||||
[
|
||||
header_1,
|
||||
header_1_2_1,
|
||||
build(:champ_text),
|
||||
header_1_2_2,
|
||||
build(:champ_text),
|
||||
header_1_2_3,
|
||||
build(:champ_text)
|
||||
]
|
||||
end
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.nodes.size).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with one sub sections and one subsub section' do
|
||||
let(:header_1_2_3) { build(:champ_header_section_level_3) }
|
||||
|
||||
let(:champs) do
|
||||
[
|
||||
header_1,
|
||||
champ_explication,
|
||||
header_1_2,
|
||||
champ_communes,
|
||||
header_1_2_3,
|
||||
champ_text,
|
||||
header_2,
|
||||
champ_textarea
|
||||
]
|
||||
end
|
||||
|
||||
it 'chunk by uniq champs' do
|
||||
expect(subject.nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].header_section).to eq(header_1)
|
||||
expect(subject.nodes[0].nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].nodes[1].header_section).to eq(header_1_2)
|
||||
expect(subject.nodes[0].nodes[1].nodes.size).to eq(2)
|
||||
expect(subject.nodes[0].nodes[1].nodes.first).to eq(champ_communes)
|
||||
expect(subject.nodes[0].nodes[1].nodes[1].header_section).to eq(header_1_2_3)
|
||||
expect(subject.nodes[0].nodes[1].nodes[1].nodes).to eq([champ_text])
|
||||
expect(subject.nodes[1].header_section).to eq(header_2)
|
||||
expect(subject.nodes[1].nodes).to eq([champ_textarea])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
describe TreeableConcern do
|
||||
class ChampsToTree
|
||||
include TreeableConcern
|
||||
|
||||
attr_reader :root
|
||||
def initialize(champs:, root_depth:)
|
||||
@root = to_tree(champs:, root_depth:)
|
||||
|
@ -43,8 +44,8 @@ describe TreeableConcern do
|
|||
it 'wraps champs within preview header section' do
|
||||
expect(subject.size).to eq(2)
|
||||
expect(subject).to eq([
|
||||
[ header_1, champ_explication, champ_text ],
|
||||
[ header_2, champ_textarea ]
|
||||
[header_1, champ_explication, champ_text],
|
||||
[header_2, champ_textarea]
|
||||
])
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue