diff --git a/config/initializers/markdown.rb b/config/initializers/markdown.rb
index 92b21b273..57e7c4384 100644
--- a/config/initializers/markdown.rb
+++ b/config/initializers/markdown.rb
@@ -1,4 +1,4 @@
ActiveSupport.on_load :action_text_markdown do
require "markdown_renderer"
- ActionText::Markdown.renderer = -> { MarkdownRenderer.build }
+ ActionText::Markdown.renderer = -> { MarkdownRenderer.new }
end
diff --git a/config/initializers/sanitization.rb b/config/initializers/sanitization.rb
index 961a62083..8b602bcb4 100644
--- a/config/initializers/sanitization.rb
+++ b/config/initializers/sanitization.rb
@@ -1,3 +1,3 @@
Rails.application.config.after_initialize do
- Rails::HTML5::SafeListSanitizer.allowed_tags.merge(%w[ table tr td th thead tbody details summary ])
+ Rails::HTML5::SafeListSanitizer.allowed_tags.merge(%w[ s table tr td th thead tbody details summary ])
end
diff --git a/lib/markdown_renderer.rb b/lib/markdown_renderer.rb
index 97c496856..1205e6d6d 100644
--- a/lib/markdown_renderer.rb
+++ b/lib/markdown_renderer.rb
@@ -1,33 +1,40 @@
-require "rouge/plugins/redcarpet"
+class MarkdownRenderer
+ require_relative "markdown_renderer/parsing"
+ require_relative "markdown_renderer/markup"
-class MarkdownRenderer < Redcarpet::Render::HTML
- include Rouge::Plugins::Redcarpet
+ include Parsing, Markup
- def self.build
- renderer = MarkdownRenderer.new(ActionText::Markdown::DEFAULT_RENDERER_OPTIONS)
- Redcarpet::Markdown.new(renderer, ActionText::Markdown::DEFAULT_MARKDOWN_EXTENSIONS)
- end
-
- def initialize(*args)
- super
+ def initialize
@id_counts = Hash.new(0)
end
- def header(text, header_level)
- unique_id(text).then do |id|
- ")
+ def render(content)
+ content
+ .then { |c| parse_paragraphs(c) }
+ .then { |c| parse_bold_italics(c) }
+ .then { |c| parse_bold(c) }
+ .then { |c| parse_italics(c) }
+ .then { |c| parse_strikethrough(c) }
+ .then { |c| parse_highlight(c) }
+ .then { |c| parse_headers(c) }
+ .then { |c| parse_tables(c) }
+ .then { |c| parse_ordered_lists(c) }
+ .then { |c| parse_unordered_lists(c) }
+ .then { |c| parse_block_quotes(c) }
+ .then { |c| parse_horizontal_rules(c) }
+ .then { |c| parse_images(c) }
+ .then { |c| parse_links(c) }
+ .then { |c| parse_code_blocks(c) }
+ .then { |c| parse_code_spans(c) }
end
private
+ attr_reader :id_counts
+
def unique_id(text)
text.parameterize.then do |base_id|
- @id_counts[base_id] += 1
- @id_counts[base_id] > 1 ? "#{base_id}-#{@id_counts[base_id]}" : base_id
+ id_counts[base_id] += 1
+ id_counts[base_id] > 1 ? "#{base_id}-#{id_counts[base_id]}" : base_id
end
end
end
diff --git a/lib/markdown_renderer/markup.rb b/lib/markdown_renderer/markup.rb
new file mode 100644
index 000000000..2e2753c5e
--- /dev/null
+++ b/lib/markdown_renderer/markup.rb
@@ -0,0 +1,117 @@
+require "rouge/plugins/redcarpet"
+
+module MarkdownRenderer::Markup
+ include Rouge::Plugins::Redcarpet
+
+ TABLE_ROW_INDENT = " " * 4
+ LIST_ITEM_INDENT = " " * 2
+ BLOCK_QUOTE_INDENT = " " * 2
+ TABLE_HEADER_INDENT = " " * 6
+
+ # FIXME: the attributes suggest this should be an app-level override instead
+ def header(text, header_level)
+ unique_id(text).then do |id|
+ <<~HTML.chomp
+
#{text}"
+ end
+
+ def highlight(text)
+ "#{text}"
+ end
+
+ def table(headers, rows)
+ <<~HTML
+
| #{header} | " }.join("\n" + TABLE_HEADER_INDENT)} +
|---|
| #{cell} | " }.join}
+ #{text.gsub(/^>\s?/, '').split("\n").join("\n" + BLOCK_QUOTE_INDENT)} ++ HTML + end + + def horizontal_rule + "
#{text}"
+ end
+
+ # FIXME: the attributes suggest this should be an app-level override instead
+ def image(url, alt_text)
+ <<~HTML.chomp
+
+ #{text}
" + end + + def soft_line_break + "\n#{line_break}\n" + end + + def line_break + "This is an introduction paragraph with some text.
+ +Hello, world! Hello, world! Hello, world! Hello, world! Hello, world!
Hello, world!
+
+ Hello, world!
+
+ Hello, world!
+
+ Hello, world!
+
+ Hello, world!
Here’s what you need to know:
+ +Our product offers:
+ +Here’s some
+
+ multiline text.
+
+ It has line breaks
+
+ in-between.
+ Please read this carefully + It contains vital information + That you shouldn’t miss ++ + + +
| Table 1 Header 1 | +Table 1 Header 2 | +
|---|---|
| Table 1 Data 1 | Table 1 Data 2 |
| Table 1 Data 3 | Table 1 Data 4 |
Some content between tables...
+ +| Table 2 Header 1 | +Table 2 Header 2 | +
|---|---|
| Table 2 Data 1 | Table 2 Data 2 |
| Table 2 Data 3 | Table 2 Data 4 |
class Post < ApplicationRecord
+ def title
+ "foo"
+ end
+ end
+ puts "Hello, world!"
Thanks for reading!
+ +