tech(remaniement): extraction du passage d'une liste de champs a un simili arbre
This commit is contained in:
parent
ad77b9321b
commit
3b5d1bd55b
4 changed files with 186 additions and 13 deletions
|
@ -21,6 +21,17 @@
|
||||||
# type_de_champ_id :integer
|
# type_de_champ_id :integer
|
||||||
#
|
#
|
||||||
class Champs::HeaderSectionChamp < Champ
|
class Champs::HeaderSectionChamp < Champ
|
||||||
|
|
||||||
|
def level
|
||||||
|
if parent.present?
|
||||||
|
header_section_level_value.to_i + parent.current_section_level
|
||||||
|
elsif header_section_level_value
|
||||||
|
header_section_level_value.to_i
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def search_terms
|
def search_terms
|
||||||
# The user cannot enter any information here so it doesn’t make much sense to search
|
# The user cannot enter any information here so it doesn’t make much sense to search
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module Champs::Treeable
|
module TreeableConcern
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
MAX_DEPTH = 6 # deepest level for header_sections is 3.
|
MAX_DEPTH = 6 # deepest level for header_sections is 3.
|
||||||
|
@ -16,27 +16,22 @@ module Champs::Treeable
|
||||||
# are added to the most_recent_subtree
|
# are added to the most_recent_subtree
|
||||||
# given a root_depth at 0, we build a full tree
|
# given a root_depth at 0, we build a full tree
|
||||||
# given a root_depth > 0, we build a partial tree (aka, a repetition)
|
# given a root_depth > 0, we build a partial tree (aka, a repetition)
|
||||||
def to_tree(champs:, root_depth:, build_champs_subtree_component:)
|
def to_tree(champs:, root_depth:)
|
||||||
root = build_champs_subtree_component(header_section: nil)
|
root = []
|
||||||
depth_cache = Array.new(MAX_DEPTH)
|
depth_cache = Array.new(MAX_DEPTH)
|
||||||
depth_cache[root_depth] = root
|
depth_cache[root_depth] = root
|
||||||
most_recent_subtree = root
|
most_recent_subtree = root
|
||||||
|
|
||||||
champs.each do |champ|
|
champs.each do |champ|
|
||||||
if champ.header_section?
|
if champ.header_section?
|
||||||
champs_subtree = build_champs_subtree_component(header_section: champ)
|
champs_subtree = [champ]
|
||||||
depth_cache[champs_subtree.level - 1].add_node(champs_subtree)
|
depth_cache[champ.level - 1].push(champs_subtree)
|
||||||
most_recent_subtree = depth_cache[champs_subtree.level] = champs_subtree
|
most_recent_subtree = depth_cache[champ.level] = champs_subtree
|
||||||
else
|
else
|
||||||
most_recent_subtree.add_node(champ)
|
most_recent_subtree.push(champ)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
root
|
root
|
||||||
end
|
end
|
||||||
|
|
||||||
# must be implemented to render subtree
|
|
||||||
def build_champs_subtree_component(header_section:)
|
|
||||||
raise NotImplementedError
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -413,9 +413,14 @@ class TypeDeChamp < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def header_section_level_value
|
def header_section_level_value
|
||||||
header_section_level.presence || 1
|
if header_section_level.presence
|
||||||
|
header_section_level.to_i
|
||||||
|
else
|
||||||
|
1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def previous_section_level(upper_tdcs)
|
def previous_section_level(upper_tdcs)
|
||||||
previous_header_section = upper_tdcs.reverse.find(&:header_section?)
|
previous_header_section = upper_tdcs.reverse.find(&:header_section?)
|
||||||
|
|
||||||
|
|
162
spec/models/concern/treeable_concern_spec.rb
Normal file
162
spec/models/concern/treeable_concern_spec.rb
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
describe TreeableConcern do
|
||||||
|
class ChampsToTree
|
||||||
|
include TreeableConcern
|
||||||
|
attr_reader :root
|
||||||
|
def initialize(champs:, root_depth:)
|
||||||
|
@root = to_tree(champs:, root_depth:)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { ChampsToTree.new(champs: champs, root_depth: 0).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 'inlines champs at root level' do
|
||||||
|
expect(subject.size).to eq(champs.size)
|
||||||
|
expect(subject).to eq(champs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with header_section and champs' do
|
||||||
|
let(:champs) do
|
||||||
|
[
|
||||||
|
header_1,
|
||||||
|
champ_explication,
|
||||||
|
champ_text,
|
||||||
|
header_2,
|
||||||
|
champ_textarea
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
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 ]
|
||||||
|
])
|
||||||
|
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.size).to eq(4)
|
||||||
|
expect(subject).to eq([
|
||||||
|
champ_text,
|
||||||
|
champ_textarea,
|
||||||
|
[header_1, champ_explication, champ_communes],
|
||||||
|
[header_2, 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.size).to eq(2)
|
||||||
|
expect(subject).to eq([
|
||||||
|
[header_1, champ_explication, [header_1_2, champ_communes]],
|
||||||
|
[header_2, 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,
|
||||||
|
champ_text,
|
||||||
|
header_1_2_2,
|
||||||
|
champ_textarea,
|
||||||
|
header_1_2_3,
|
||||||
|
champ_communes
|
||||||
|
]
|
||||||
|
end
|
||||||
|
it 'chunk by uniq champs' do
|
||||||
|
expect(subject.size).to eq(1)
|
||||||
|
expect(subject).to eq([
|
||||||
|
[
|
||||||
|
header_1,
|
||||||
|
[header_1_2_1, champ_text],
|
||||||
|
[header_1_2_2, champ_textarea],
|
||||||
|
[header_1_2_3, champ_communes]
|
||||||
|
]
|
||||||
|
])
|
||||||
|
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.size).to eq(2)
|
||||||
|
expect(subject).to eq([
|
||||||
|
[
|
||||||
|
header_1,
|
||||||
|
champ_explication,
|
||||||
|
[
|
||||||
|
header_1_2,
|
||||||
|
champ_communes,
|
||||||
|
[
|
||||||
|
header_1_2_3, champ_text
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
header_2,
|
||||||
|
champ_textarea
|
||||||
|
]
|
||||||
|
])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue