amelioration(a11y): extrait un nouveau composant pour rendre du texte saisi par un humain accessible
This commit is contained in:
parent
1e37e5ca60
commit
4d8b4e078b
6 changed files with 149 additions and 0 deletions
1
Gemfile
1
Gemfile
|
@ -70,6 +70,7 @@ gem 'rack-attack'
|
|||
gem 'rails'
|
||||
gem 'rails-i18n' # Locales par défaut
|
||||
gem 'rake-progressbar', require: false
|
||||
gem 'redcarpet'
|
||||
gem 'rexml' # add missing gem due to ruby3 (https://github.com/Shopify/bootsnap/issues/325)
|
||||
gem 'rgeo-geojson'
|
||||
gem 'rqrcode'
|
||||
|
|
|
@ -573,6 +573,7 @@ GEM
|
|||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redcarpet (3.6.0)
|
||||
regexp_parser (2.6.0)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
|
@ -909,6 +910,7 @@ DEPENDENCIES
|
|||
rails-erd
|
||||
rails-i18n
|
||||
rake-progressbar
|
||||
redcarpet
|
||||
rexml
|
||||
rgeo-geojson
|
||||
rqrcode
|
||||
|
|
51
app/components/simple_format_component.rb
Normal file
51
app/components/simple_format_component.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
class SimpleFormatComponent < ApplicationComponent
|
||||
# see: https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
|
||||
REDCARPET_EXTENSIONS = {
|
||||
no_intra_emphasis: false,
|
||||
tables: false,
|
||||
fenced_code_blocks: false,
|
||||
autolink: false,
|
||||
disable_indented_code_blocks: false,
|
||||
strikethrough: false,
|
||||
lax_spacing: false,
|
||||
space_after_headers: false,
|
||||
superscript: false,
|
||||
underline: false,
|
||||
highlight: false,
|
||||
quote: false,
|
||||
footnotes: false
|
||||
}
|
||||
|
||||
# see: https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch
|
||||
REDCARPET_RENDERER_OPTS = {
|
||||
no_images: true
|
||||
}
|
||||
|
||||
def initialize(text, allow_a: true, class_names_map: {})
|
||||
@text = (text || "").gsub(/\R/, "\n\n") # force double \n otherwise a single one won't split paragraph
|
||||
.split("\n\n") #
|
||||
.map(&:lstrip) # this block prevent redcarpet to consider " text" as block code by lstriping
|
||||
.join("\n\n") #
|
||||
@allow_a = allow_a
|
||||
@renderer = Redcarpet::Markdown.new(
|
||||
Redcarpet::BareRenderer.new(link_attributes: external_link_attributes, class_names_map: class_names_map),
|
||||
REDCARPET_EXTENSIONS.merge(autolink: @allow_a)
|
||||
)
|
||||
end
|
||||
|
||||
def external_link_attributes
|
||||
{ target: '_blank', rel: 'noopener noreferrer' }
|
||||
end
|
||||
|
||||
def tags
|
||||
if @allow_a
|
||||
Rails.configuration.action_view.sanitized_allowed_tags + ['a']
|
||||
else
|
||||
Rails.configuration.action_view.sanitized_allowed_tags
|
||||
end
|
||||
end
|
||||
|
||||
def attributes
|
||||
['target', 'rel', 'href', 'class']
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
= sanitize(@renderer.render(@text), tags:, attributes:)
|
21
app/lib/redcarpet/bare_renderer.rb
Normal file
21
app/lib/redcarpet/bare_renderer.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module Redcarpet
|
||||
class BareRenderer < Redcarpet::Render::HTML
|
||||
include ActionView::Helpers::TagHelper
|
||||
|
||||
# won't use rubocop tag method because it is missing output buffer
|
||||
# rubocop:disable Rails/ContentTag
|
||||
def list(content, list_type)
|
||||
tag = list_type == :ordered ? :ol : :ul
|
||||
content_tag(tag, content, { class: @options[:class_names_map].fetch(:list) {} }, false)
|
||||
end
|
||||
|
||||
def list_item(content, list_type)
|
||||
content_tag(:li, content.strip.gsub(/<\/?p>/, ''), {}, false)
|
||||
end
|
||||
|
||||
def paragraph(text)
|
||||
content_tag(:p, text, { class: @options[:class_names_map].fetch(:paragraph) {} }, false)
|
||||
end
|
||||
# rubocop:enable Rails/ContentTag
|
||||
end
|
||||
end
|
73
spec/components/simple_format_component_spec.rb
Normal file
73
spec/components/simple_format_component_spec.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
describe SimpleFormatComponent, type: :component do
|
||||
let(:allow_a) { false }
|
||||
before { render_inline(described_class.new(text, allow_a: allow_a)) }
|
||||
|
||||
context 'one line' do
|
||||
let(:text) do
|
||||
"1er paragraphe"
|
||||
end
|
||||
it { expect(page).to have_selector("p", count: 1, text: text) }
|
||||
end
|
||||
|
||||
context 'one with leading spaces' do
|
||||
let(:text) do
|
||||
<<-TEXT
|
||||
1er paragraphe
|
||||
TEXT
|
||||
end
|
||||
it { expect(page).to have_selector("p", count: 1, text: text.strip) }
|
||||
end
|
||||
|
||||
context 'two lines' do
|
||||
let(:text) do
|
||||
<<~TEXT
|
||||
1er paragraphe
|
||||
2eme paragraphe
|
||||
TEXT
|
||||
end
|
||||
|
||||
it { expect(page).to have_selector("p", count: 2) }
|
||||
it { text.split("\n").map(&:strip).map { expect(page).to have_text(_1) } }
|
||||
end
|
||||
|
||||
context 'unordered list items' do
|
||||
let(:text) do
|
||||
<<~TEXT
|
||||
- 1er paragraphe
|
||||
- paragraphe
|
||||
TEXT
|
||||
end
|
||||
|
||||
it { expect(page).to have_selector("ul", count: 1) }
|
||||
it { expect(page).to have_selector("li", count: 2) }
|
||||
end
|
||||
|
||||
context 'ordered list items' do
|
||||
let(:text) do
|
||||
<<~TEXT
|
||||
1. 1er paragraphe
|
||||
2. paragraphe
|
||||
TEXT
|
||||
end
|
||||
|
||||
it { expect(page).to have_selector("ol", count: 1) }
|
||||
it { expect(page).to have_selector("li", count: 2) }
|
||||
end
|
||||
|
||||
context 'auto-link' do
|
||||
let(:text) do
|
||||
<<~TEXT
|
||||
bonjour https://www.demarches-simplifiees.fr
|
||||
TEXT
|
||||
end
|
||||
|
||||
context 'enabled' do
|
||||
let(:allow_a) { true }
|
||||
it { expect(page).to have_selector("a") }
|
||||
end
|
||||
|
||||
context 'disabled' do
|
||||
it { expect(page).not_to have_selector("a") }
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue