diff --git a/app/assets/stylesheets/legislation_process.scss b/app/assets/stylesheets/legislation_process.scss
index c605af7e7..a18266d97 100644
--- a/app/assets/stylesheets/legislation_process.scss
+++ b/app/assets/stylesheets/legislation_process.scss
@@ -459,6 +459,10 @@
padding: rem-calc(32) rem-calc(32) rem-calc(32) rem-calc(48);
}
+ table {
+ @include table-scroll;
+ }
+
h2 {
font-weight: 400;
margin-bottom: rem-calc(32);
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a0ff6f621..1377b27d2 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -10,26 +10,8 @@ module ApplicationHelper
%i[ar fa he].include?(locale)
end
- def markdown(text)
- return text if text.blank?
-
- # See https://github.com/vmg/redcarpet for options
- render_options = {
- filter_html: false,
- hard_wrap: true,
- link_attributes: { target: "_blank" }
- }
- renderer = Redcarpet::Render::HTML.new(render_options)
- extensions = {
- autolink: true,
- fenced_code_blocks: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- strikethrough: true,
- superscript: true
- }
-
- AdminLegislationSanitizer.new.sanitize(Redcarpet::Markdown.new(renderer, extensions).render(text))
+ def markdown(text, **render_options)
+ MarkdownConverter.new(text, **render_options).render
end
def wysiwyg(text)
diff --git a/app/models/legislation/draft_version.rb b/app/models/legislation/draft_version.rb
index c7576c421..b36cb688a 100644
--- a/app/models/legislation/draft_version.rb
+++ b/app/models/legislation/draft_version.rb
@@ -22,15 +22,11 @@ class Legislation::DraftVersion < ApplicationRecord
scope :published, -> { where(status: "published").order("id DESC") }
def body_html
- renderer = Redcarpet::Render::HTML.new(with_toc_data: true)
-
- Redcarpet::Markdown.new(renderer).render(body)
+ MarkdownConverter.new(body, with_toc_data: true).render
end
def toc_html
- renderer = Redcarpet::Render::HTML_TOC.new(with_toc_data: true)
-
- Redcarpet::Markdown.new(renderer).render(body)
+ MarkdownConverter.new(body).render_toc
end
def display_title
diff --git a/lib/admin_legislation_sanitizer.rb b/lib/admin_legislation_sanitizer.rb
index 103b305b6..358de0199 100644
--- a/lib/admin_legislation_sanitizer.rb
+++ b/lib/admin_legislation_sanitizer.rb
@@ -1,6 +1,6 @@
class AdminLegislationSanitizer < WYSIWYGSanitizer
def allowed_tags
- super + %w[img h1 h4 h5 h6]
+ super + %w[img h1 h4 h5 h6 table thead tbody tr th td]
end
def allowed_attributes
diff --git a/lib/markdown_converter.rb b/lib/markdown_converter.rb
new file mode 100644
index 000000000..d5d9845f0
--- /dev/null
+++ b/lib/markdown_converter.rb
@@ -0,0 +1,48 @@
+class MarkdownConverter
+ attr_reader :text, :render_options
+
+ def initialize(text, **render_options)
+ @text = text
+ @render_options = render_options
+ end
+
+ def render
+ return text if text.blank?
+
+ AdminLegislationSanitizer.new.sanitize(Redcarpet::Markdown.new(renderer, extensions).render(text))
+ end
+
+ def render_toc
+ Redcarpet::Markdown.new(toc_renderer).render(text)
+ end
+
+ private
+
+ def renderer
+ Redcarpet::Render::HTML.new(default_render_options.merge(render_options))
+ end
+
+ def toc_renderer
+ Redcarpet::Render::HTML_TOC.new(with_toc_data: true)
+ end
+
+ def default_render_options
+ {
+ filter_html: false,
+ hard_wrap: true,
+ link_attributes: { target: "_blank" }
+ }
+ end
+
+ def extensions
+ {
+ autolink: true,
+ fenced_code_blocks: true,
+ lax_spacing: true,
+ no_intra_emphasis: true,
+ strikethrough: true,
+ superscript: true,
+ tables: true
+ }
+ end
+end
diff --git a/spec/factories/legislations.rb b/spec/factories/legislations.rb
index 069899884..3c1dbe41b 100644
--- a/spec/factories/legislations.rb
+++ b/spec/factories/legislations.rb
@@ -127,6 +127,15 @@ FactoryBot.define do
trait :final_version do
final_version { true }
end
+
+ trait :with_table do
+ body { <<~BODY_MARKDOWN }
+ | id | name | age | gender |
+ |----|---------|-----|--------|
+ | 1 | Roberta | 39 | M |
+ | 2 | Oliver | 25 | F |
+ BODY_MARKDOWN
+ end
end
factory :legislation_annotation, class: "Legislation::Annotation" do
diff --git a/spec/lib/admin_legislation_sanitizer_spec.rb b/spec/lib/admin_legislation_sanitizer_spec.rb
new file mode 100644
index 000000000..bc467ba84
--- /dev/null
+++ b/spec/lib/admin_legislation_sanitizer_spec.rb
@@ -0,0 +1,65 @@
+require "rails_helper"
+
+describe AdminLegislationSanitizer do
+ let(:sanitizer) { AdminLegislationSanitizer.new }
+
+ describe "#sanitize" do
+ it "allows images" do
+ html = 'Dangerous
image'
+ expect(sanitizer.sanitize(html)).to eq(html)
+ end
+
+ it "allows h1 to h6" do
+ html = '
| id | +name | +age | +gender | +
|---|---|---|---|
| 1 | +Roberta | +39 | +M | +
| 2 | +Oliver | +25 | +F | +
image'
+ expect(sanitizer.sanitize(html)).to eq(html)
+ end
+
+ it "doesn't allow style" do
+ html = 'Dangerous
image'
+ expect(sanitizer.sanitize(html)).not_to eq(html)
+ end
+
+ it "doesn't allow class" do
+ html = 'Dangerous
image'
+ expect(sanitizer.sanitize(html)).not_to eq(html)
+ end
+ end
+end
diff --git a/spec/models/legislation/draft_version_spec.rb b/spec/models/legislation/draft_version_spec.rb
index 910a15f65..58123c837 100644
--- a/spec/models/legislation/draft_version_spec.rb
+++ b/spec/models/legislation/draft_version_spec.rb
@@ -29,6 +29,15 @@ describe Legislation::DraftVersion do
expect(legislation_draft_version.toc_html).to eq(toc_html)
end
+ it "renders the tables from the markdown body field" do
+ legislation_draft_version.body = body_with_table_markdown
+
+ legislation_draft_version.save!
+
+ expect(legislation_draft_version.body_html).to eq(body_with_table_html)
+ expect(legislation_draft_version.toc_html).to eq(toc_html)
+ end
+
def body_markdown
<<~BODY_MARKDOWN
# Title 1
@@ -50,6 +59,32 @@ describe Legislation::DraftVersion do
BODY_MARKDOWN
end
+ def body_with_table_markdown
+ <<~BODY_MARKDOWN
+ # Title 1
+
+ Some paragraph.
+
+ A list:
+
+ - item 1
+ - item 2
+
+ ## Subtitle
+
+ Another paragraph.
+
+ # Title 2
+
+ Something about this.
+
+ | id | name | age | gender |
+ |----|---------|-----|--------|
+ | 1 | Roberta | 39 | M |
+ | 2 | Oliver | 25 | F |
+ BODY_MARKDOWN
+ end
+
def body_html
<<~BODY_HTML
Some paragraph.
+ +A list:
+ +Another paragraph.
+ +Something about this.
+ +| id | +name | +age | +gender | +
|---|---|---|---|
| 1 | +Roberta | +39 | +M | +
| 2 | +Oliver | +25 | +F | +