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'
|
||||||
gem 'rails-i18n' # Locales par défaut
|
gem 'rails-i18n' # Locales par défaut
|
||||||
gem 'rake-progressbar', require: false
|
gem 'rake-progressbar', require: false
|
||||||
|
gem 'redcarpet'
|
||||||
gem 'rexml' # add missing gem due to ruby3 (https://github.com/Shopify/bootsnap/issues/325)
|
gem 'rexml' # add missing gem due to ruby3 (https://github.com/Shopify/bootsnap/issues/325)
|
||||||
gem 'rgeo-geojson'
|
gem 'rgeo-geojson'
|
||||||
gem 'rqrcode'
|
gem 'rqrcode'
|
||||||
|
|
|
@ -573,6 +573,7 @@ GEM
|
||||||
rb-fsevent (0.10.4)
|
rb-fsevent (0.10.4)
|
||||||
rb-inotify (0.10.1)
|
rb-inotify (0.10.1)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
|
redcarpet (3.6.0)
|
||||||
regexp_parser (2.6.0)
|
regexp_parser (2.6.0)
|
||||||
request_store (1.5.0)
|
request_store (1.5.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
|
@ -909,6 +910,7 @@ DEPENDENCIES
|
||||||
rails-erd
|
rails-erd
|
||||||
rails-i18n
|
rails-i18n
|
||||||
rake-progressbar
|
rake-progressbar
|
||||||
|
redcarpet
|
||||||
rexml
|
rexml
|
||||||
rgeo-geojson
|
rgeo-geojson
|
||||||
rqrcode
|
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