Merge pull request #10584 from colinux/attestation-render-list
ETQ admin, améliore l'affichage de champ choix multiple et répétitions dans les attestations v2
This commit is contained in:
commit
8dfddba433
15 changed files with 389 additions and 18 deletions
|
@ -178,4 +178,20 @@
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tdc-repetition li {
|
||||||
|
margin-bottom: 5mm;
|
||||||
|
padding-left: 3mm;
|
||||||
|
|
||||||
|
dl {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
gap: 1mm 10mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
9
app/models/champ_presentations/base_presentation.rb
Normal file
9
app/models/champ_presentations/base_presentation.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module ChampPresentations
|
||||||
|
class BasePresentation
|
||||||
|
def block_level?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ChampPresentations::MultipleDropDownListPresentation < ChampPresentations::BasePresentation
|
||||||
|
attr_reader :selected_options
|
||||||
|
|
||||||
|
def initialize(selected_options)
|
||||||
|
@selected_options = selected_options
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
selected_options.join(', ')
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_tiptap_node
|
||||||
|
{
|
||||||
|
type: 'bulletList',
|
||||||
|
content: selected_options.map do |text|
|
||||||
|
{
|
||||||
|
type: 'listItem',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: text
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
59
app/models/champ_presentations/repetition_presentation.rb
Normal file
59
app/models/champ_presentations/repetition_presentation.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ChampPresentations::RepetitionPresentation < ChampPresentations::BasePresentation
|
||||||
|
attr_reader :libelle
|
||||||
|
attr_reader :rows
|
||||||
|
|
||||||
|
def initialize(libelle, rows)
|
||||||
|
@libelle = libelle
|
||||||
|
@rows = rows
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
([libelle] + rows.map do |champs|
|
||||||
|
champs.map do |champ|
|
||||||
|
"#{champ.libelle} : #{champ}"
|
||||||
|
end.join("\n")
|
||||||
|
end).join("\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_tiptap_node
|
||||||
|
{
|
||||||
|
type: 'orderedList',
|
||||||
|
attrs: { class: 'tdc-repetition' },
|
||||||
|
content: rows.map do |champs|
|
||||||
|
{
|
||||||
|
type: 'listItem',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'descriptionList',
|
||||||
|
content: champs.map do |champ|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
type: 'descriptionTerm',
|
||||||
|
attrs: champ.blank? ? { class: 'invisible' } : nil, # still render libelle so width & alignment are preserved
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: champ.libelle
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}.compact,
|
||||||
|
{
|
||||||
|
type: 'descriptionDetails',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: champ.to_s
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
end.flatten
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -44,14 +44,6 @@ class Champs::RepetitionChamp < Champ
|
||||||
# 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
|
||||||
|
|
||||||
def for_tag(path = :value)
|
|
||||||
([libelle] + rows.map do |champs|
|
|
||||||
champs.map do |champ|
|
|
||||||
"#{champ.libelle} : #{champ}"
|
|
||||||
end.join("\n")
|
|
||||||
end).join("\n\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def rows_for_export
|
def rows_for_export
|
||||||
row_ids.map.with_index(1) do |row_id, index|
|
row_ids.map.with_index(1) do |row_id, index|
|
||||||
Champs::RepetitionChamp::Row.new(index:, row_id:, dossier:)
|
Champs::RepetitionChamp::Row.new(index:, row_id:, dossier:)
|
||||||
|
|
|
@ -1015,10 +1015,12 @@ class Procedure < ApplicationRecord
|
||||||
|
|
||||||
def dossier_for_preview(user)
|
def dossier_for_preview(user)
|
||||||
# Try to use a preview or a dossier filled by current user
|
# Try to use a preview or a dossier filled by current user
|
||||||
dossiers.where(for_procedure_preview: true).or(dossiers.not_brouillon)
|
dossiers.where(for_procedure_preview: true).or(dossiers.visible_by_administration)
|
||||||
.order(Arel.sql("CASE WHEN user_id = #{user.id} THEN 1 ELSE 0 END DESC,
|
.order(Arel.sql("CASE WHEN user_id = #{user.id} THEN 1 ELSE 0 END DESC,
|
||||||
CASE WHEN state = 'accepte' THEN 1 ELSE 0 END DESC,
|
CASE WHEN state = 'accepte' THEN 1 ELSE 0 END DESC,
|
||||||
CASE WHEN for_procedure_preview = True THEN 1 ELSE 0 END DESC")) \
|
CASE WHEN state = 'brouillon' THEN 0 ELSE 1 END DESC,
|
||||||
|
CASE WHEN for_procedure_preview = True THEN 1 ELSE 0 END DESC,
|
||||||
|
id DESC")) \
|
||||||
.first
|
.first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ class TypesDeChamp::MultipleDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampB
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ_value_for_tag(champ, path = :value)
|
def champ_value_for_tag(champ, path = :value)
|
||||||
champ.selected_options.join(', ')
|
ChampPresentations::MultipleDropDownListPresentation.new(champ.selected_options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ_value_for_export(champ, path = :value)
|
def champ_value_for_export(champ, path = :value)
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
class TypesDeChamp::RepetitionTypeDeChamp < TypesDeChamp::TypeDeChampBase
|
||||||
|
def self.champ_value_for_tag(champ, path = :value)
|
||||||
|
return nil if path != :value
|
||||||
|
return champ_default_value if champ.rows.blank?
|
||||||
|
|
||||||
|
ChampPresentations::RepetitionPresentation.new(champ.libelle, champ.rows)
|
||||||
|
end
|
||||||
|
|
||||||
def estimated_fill_duration(revision)
|
def estimated_fill_duration(revision)
|
||||||
estimated_rows_in_repetition = 2.5
|
estimated_rows_in_repetition = 2.5
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TiptapService
|
||||||
def to_html(node, substitutions = {})
|
def to_html(node, substitutions = {})
|
||||||
return '' if node.nil?
|
return '' if node.nil?
|
||||||
|
|
||||||
children(node[:content], substitutions, 0)
|
children(node[:content], substitutions, 0).gsub('<p></p>', '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_texts_and_tags(node, substitutions = {})
|
def to_texts_and_tags(node, substitutions = {})
|
||||||
|
@ -79,10 +79,16 @@ class TiptapService
|
||||||
"<h#{hlevel}#{body_start_mark}#{text_align(attrs)}>#{children(content, substitutions, level + 1)}</h#{hlevel}>"
|
"<h#{hlevel}#{body_start_mark}#{text_align(attrs)}>#{children(content, substitutions, level + 1)}</h#{hlevel}>"
|
||||||
in type: 'bulletList', content:
|
in type: 'bulletList', content:
|
||||||
"<ul>#{children(content, substitutions, level + 1)}</ul>"
|
"<ul>#{children(content, substitutions, level + 1)}</ul>"
|
||||||
in type: 'orderedList', content:
|
in type: 'orderedList', content:, **rest
|
||||||
"<ol>#{children(content, substitutions, level + 1)}</ol>"
|
"<ol#{class_list(rest[:attrs])}>#{children(content, substitutions, level + 1)}</ol>"
|
||||||
in type: 'listItem', content:
|
in type: 'listItem', content:
|
||||||
"<li>#{children(content, substitutions, level + 1)}</li>"
|
"<li>#{children(content, substitutions, level + 1)}</li>"
|
||||||
|
in type: 'descriptionList', content:
|
||||||
|
"<dl>#{children(content, substitutions, level + 1)}</dl>"
|
||||||
|
in type: 'descriptionTerm', content:, **rest
|
||||||
|
"<dt#{class_list(rest[:attrs])}>#{children(content, substitutions, level + 1)}</dt>"
|
||||||
|
in type: 'descriptionDetails', content:
|
||||||
|
"<dd>#{children(content, substitutions, level + 1)}</dd>"
|
||||||
in type: 'text', text:, **rest
|
in type: 'text', text:, **rest
|
||||||
if rest[:marks].present?
|
if rest[:marks].present?
|
||||||
apply_marks(text, rest[:marks])
|
apply_marks(text, rest[:marks])
|
||||||
|
@ -90,7 +96,12 @@ class TiptapService
|
||||||
text
|
text
|
||||||
end
|
end
|
||||||
in type: 'mention', attrs: { id: }, **rest
|
in type: 'mention', attrs: { id: }, **rest
|
||||||
text = substitutions.fetch(id) { "--#{id}--" }
|
text_or_presentation = substitutions.fetch(id) { "--#{id}--" }
|
||||||
|
text = if text_or_presentation.respond_to?(:to_tiptap_node)
|
||||||
|
handle_presentation_node(text_or_presentation, substitutions, level + 1)
|
||||||
|
else
|
||||||
|
text_or_presentation
|
||||||
|
end
|
||||||
|
|
||||||
if rest[:marks].present?
|
if rest[:marks].present?
|
||||||
apply_marks(text, rest[:marks])
|
apply_marks(text, rest[:marks])
|
||||||
|
@ -102,6 +113,16 @@ class TiptapService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_presentation_node(presentation, substitutions, level)
|
||||||
|
node = presentation.to_tiptap_node
|
||||||
|
content = node_to_html(node, substitutions, level)
|
||||||
|
if presentation.block_level?
|
||||||
|
"</p>#{content}<p>"
|
||||||
|
else
|
||||||
|
content
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def text_align(attrs)
|
def text_align(attrs)
|
||||||
if attrs.present? && attrs[:textAlign].present?
|
if attrs.present? && attrs[:textAlign].present?
|
||||||
" style=\"text-align: #{attrs[:textAlign]}\""
|
" style=\"text-align: #{attrs[:textAlign]}\""
|
||||||
|
@ -110,6 +131,12 @@ class TiptapService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def class_list(attrs)
|
||||||
|
if attrs.present? && attrs[:class].present?
|
||||||
|
" class=\"#{attrs[:class]}\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def apply_marks(text, marks)
|
def apply_marks(text, marks)
|
||||||
marks.reduce(text) do |text, mark|
|
marks.reduce(text) do |text, mark|
|
||||||
case mark
|
case mark
|
||||||
|
|
|
@ -127,7 +127,9 @@
|
||||||
%iframe.attestation-preview{ title: "Aperçu", src: admin_procedure_attestation_template_v2_path(@procedure, format: :pdf), data: { attestation_target: 'preview' } }
|
%iframe.attestation-preview{ title: "Aperçu", src: admin_procedure_attestation_template_v2_path(@procedure, format: :pdf), data: { attestation_target: 'preview' } }
|
||||||
%p.fr-hint-text
|
%p.fr-hint-text
|
||||||
L’aperçu est mis à jour automatiquement après chaque modification.
|
L’aperçu est mis à jour automatiquement après chaque modification.
|
||||||
Pour générer un aperçu fidèle avec tous les champs et les dates, créez-vous un dossier et acceptez-le : l’aperçu l’utilisera.
|
Pour générer un aperçu fidèle avec champs et dates,
|
||||||
|
= link_to("créez-vous un dossier", new_dossier_path(procedure_id: @procedure, brouillon: true), **external_link_attributes)
|
||||||
|
et acceptez-le : l’aperçu l’utilisera.
|
||||||
|
|
||||||
- if @procedure.feature_enabled?(:attestation_v2) && @attestation_template.draft?
|
- if @procedure.feature_enabled?(:attestation_v2) && @attestation_template.draft?
|
||||||
- content_for(:sticky_header) do
|
- content_for(:sticky_header) do
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe ChampPresentations::MultipleDropDownListPresentation do
|
||||||
|
let(:options) { ["Option 1", "Option 2", "Option 3"] }
|
||||||
|
let(:representation) { described_class.new(options) }
|
||||||
|
|
||||||
|
describe '#to_s' do
|
||||||
|
it 'returns a comma-separated string of options' do
|
||||||
|
expect(representation.to_s).to eq("Option 1, Option 2, Option 3")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_tiptap_node' do
|
||||||
|
it 'returns the correct node structure' do
|
||||||
|
expected_node = {
|
||||||
|
type: "bulletList",
|
||||||
|
content: [
|
||||||
|
{ content: [{ content: [{ :text => "Option 1", type: "text" }], type: "paragraph" }], type: "listItem" },
|
||||||
|
{ content: [{ content: [{ :text => "Option 2", type: "text" }], type: "paragraph" }], type: "listItem" },
|
||||||
|
{ content: [{ content: [{ :text => "Option 3", type: "text" }], type: "paragraph" }], type: "listItem" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(representation.to_tiptap_node).to eq(expected_node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
107
spec/models/champ_presentations/repetition_presentation_spec.rb
Normal file
107
spec/models/champ_presentations/repetition_presentation_spec.rb
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe ChampPresentations::RepetitionPresentation do
|
||||||
|
let(:libelle) { "Langages de programmation" }
|
||||||
|
let(:procedure) {
|
||||||
|
create(:procedure, types_de_champ_public: [
|
||||||
|
{
|
||||||
|
type: :repetition,
|
||||||
|
children: [
|
||||||
|
{ type: :text, libelle: "nom" },
|
||||||
|
{ type: :integer_number, libelle: "stars" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:dossier) { create(:dossier, procedure:) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
nom, stars = dossier.champs[0].rows.first
|
||||||
|
nom.update(value: "ruby")
|
||||||
|
stars.update(value: 5)
|
||||||
|
|
||||||
|
nom, stars = dossier.champs[0].add_row(dossier.procedure.active_revision)
|
||||||
|
nom.update(value: "js")
|
||||||
|
|
||||||
|
nom, stars = dossier.champs[0].add_row(dossier.procedure.active_revision)
|
||||||
|
nom.update(value: "rust")
|
||||||
|
stars.update(value: 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:representation) { described_class.new(libelle, dossier.champs[0].reload.rows) }
|
||||||
|
|
||||||
|
describe '#to_s' do
|
||||||
|
it 'returns a key-value representation' do
|
||||||
|
expect(representation.to_s).to eq(
|
||||||
|
<<~TXT.strip
|
||||||
|
Langages de programmation
|
||||||
|
|
||||||
|
nom : ruby
|
||||||
|
stars : 5
|
||||||
|
|
||||||
|
nom : js
|
||||||
|
stars :#{' '}
|
||||||
|
|
||||||
|
nom : rust
|
||||||
|
stars : 4
|
||||||
|
TXT
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#to_tiptap_node' do
|
||||||
|
it 'returns the correct HTML structure, without libelle' do
|
||||||
|
expected_node = {
|
||||||
|
type: "orderedList",
|
||||||
|
attrs: { class: "tdc-repetition" },
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "listItem",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "descriptionList",
|
||||||
|
content: [
|
||||||
|
{ content: [{ text: "nom", type: "text" }], type: "descriptionTerm" },
|
||||||
|
{ content: [{ text: "ruby", type: "text" }], type: "descriptionDetails" },
|
||||||
|
{ content: [{ text: "stars", type: "text" }], type: "descriptionTerm" },
|
||||||
|
{ content: [{ text: "5", type: "text" }], type: "descriptionDetails" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "listItem",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "descriptionList",
|
||||||
|
content: [
|
||||||
|
{ content: [{ text: "nom", type: "text" }], type: "descriptionTerm" },
|
||||||
|
{ content: [{ text: "js", type: "text" }], type: "descriptionDetails" },
|
||||||
|
{ content: [{ text: "stars", type: "text" }], type: "descriptionTerm", attrs: { class: "invisible" } },
|
||||||
|
{ content: [{ text: "", type: "text" }], type: "descriptionDetails" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "listItem",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "descriptionList",
|
||||||
|
content: [
|
||||||
|
{ content: [{ text: "nom", type: "text" }], type: "descriptionTerm" },
|
||||||
|
{ content: [{ text: "rust", type: "text" }], type: "descriptionDetails" },
|
||||||
|
{ content: [{ text: "stars", type: "text" }], type: "descriptionTerm" },
|
||||||
|
{ content: [{ text: "4", type: "text" }], type: "descriptionDetails" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(representation.to_tiptap_node).to eq(expected_node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -84,4 +84,9 @@ describe Champs::MultipleDropDownListChamp do
|
||||||
it { expect(champ.next_checkbox_id("val1")).to eq(nil) }
|
it { expect(champ.next_checkbox_id("val1")).to eq(nil) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#for_tag" do
|
||||||
|
let(:value) { ["val1", "val2"] }
|
||||||
|
it { expect(champ.for_tag.to_s).to eq("val1, val2") }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
35
spec/models/champs/repetition_champ_spec.rb
Normal file
35
spec/models/champs/repetition_champ_spec.rb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe Champs::RepetitionChamp do
|
||||||
|
let(:procedure) {
|
||||||
|
create(:procedure,
|
||||||
|
types_de_champ_public: [
|
||||||
|
{
|
||||||
|
type: :repetition,
|
||||||
|
children: [{ type: :text, libelle: "Ext" }], libelle: "Languages"
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
let(:dossier) { create(:dossier, procedure:) }
|
||||||
|
let(:champ) { dossier.champs.first }
|
||||||
|
|
||||||
|
describe "#for_tag" do
|
||||||
|
before do
|
||||||
|
champ.rows[0][0].update(value: "rb")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can render as string" do
|
||||||
|
expect(champ.for_tag.to_s).to eq(
|
||||||
|
<<~TXT.strip
|
||||||
|
Languages
|
||||||
|
|
||||||
|
Ext : rb
|
||||||
|
TXT
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "as tiptap node" do
|
||||||
|
expect(champ.for_tag.to_tiptap_node).to include(type: 'orderedList')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -138,6 +138,19 @@ RSpec.describe TiptapService do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Langages de prédilection:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'mention',
|
||||||
|
attrs: { id: 'languages', label: 'Langages' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'footer',
|
type: 'footer',
|
||||||
content: [{ type: 'text', text: 'Footer' }]
|
content: [{ type: 'text', text: 'Footer' }]
|
||||||
|
@ -147,7 +160,7 @@ RSpec.describe TiptapService do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.to_html' do
|
describe '.to_html' do
|
||||||
let(:substitutions) { { 'name' => 'Paul' } }
|
let(:substitutions) { { 'name' => 'Paul', 'languages' => ChampPresentations::MultipleDropDownListPresentation.new(['ruby', 'rust']) } }
|
||||||
let(:html) do
|
let(:html) do
|
||||||
[
|
[
|
||||||
'<header><div>Left</div><div>Right</div></header>',
|
'<header><div>Left</div><div>Right</div></header>',
|
||||||
|
@ -158,6 +171,7 @@ RSpec.describe TiptapService do
|
||||||
'<p><s><em>Bonjour </em></s><u><strong>Paul</strong></u> <mark>!</mark></p>',
|
'<p><s><em>Bonjour </em></s><u><strong>Paul</strong></u> <mark>!</mark></p>',
|
||||||
'<ul><li><p>Item 1</p></li><li><p>Item 2</p></li></ul>',
|
'<ul><li><p>Item 1</p></li><li><p>Item 2</p></li></ul>',
|
||||||
'<ol><li><p>Item 1</p></li><li><p>Item 2</p></li></ol>',
|
'<ol><li><p>Item 1</p></li><li><p>Item 2</p></li></ol>',
|
||||||
|
'<p>Langages de prédilection:</p><ul><li><p>ruby</p></li><li><p>rust</p></li></ul>',
|
||||||
'<footer>Footer</footer>'
|
'<footer>Footer</footer>'
|
||||||
].join
|
].join
|
||||||
end
|
end
|
||||||
|
@ -187,11 +201,45 @@ RSpec.describe TiptapService do
|
||||||
expect(described_class.new.to_html(json, substitutions)).to eq("<h1>The Title</h1><p class=\"body-start\">First paragraph</p>")
|
expect(described_class.new.to_html(json, substitutions)).to eq("<h1>The Title</h1><p class=\"body-start\">First paragraph</p>")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'ordered list with custom classes' do
|
||||||
|
let(:json) do
|
||||||
|
{
|
||||||
|
type: 'doc',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'orderedList',
|
||||||
|
attrs: { class: "my-class" },
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'listItem',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Item 1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "set class attribute" do
|
||||||
|
expect(described_class.new.to_html(json, substitutions)).to eq('<ol class="my-class"><li><p>Item 1</p></li></ol>')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#used_tags' do
|
describe '#used_tags' do
|
||||||
it 'returns used tags' do
|
it 'returns used tags' do
|
||||||
expect(described_class.used_tags_and_libelle_for(json)).to eq(Set.new([['name', 'Nom']]))
|
expect(described_class.used_tags_and_libelle_for(json)).to eq(Set.new([['name', 'Nom'], ['languages', 'Langages']]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue