diff --git a/Gemfile b/Gemfile
index 263be0ac3..cbf00459c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -96,6 +96,8 @@ gem 'json-ld', git: 'https://github.com/ruby-rdf/json-ld.git', ref: '345b7a57333
gem 'json-ld-preloaded', '~> 3.0'
gem 'rdf-normalize', '~> 0.3'
+gem 'redcarpet', "~> 3.4.0"
+
group :development, :test do
gem 'fabrication', '~> 2.20'
gem 'fuubar', '~> 2.4'
diff --git a/Gemfile.lock b/Gemfile.lock
index f185f3fa5..eb5e5445a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -496,6 +496,7 @@ GEM
link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.3.3)
rdf (>= 2.2, < 4.0)
+ redcarpet (3.4.0)
redis (4.1.2)
redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6)
@@ -755,6 +756,7 @@ DEPENDENCIES
rails-i18n (~> 5.1)
rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.3)
+ redcarpet (~> 3.4.0)
redis (~> 4.1)
redis-namespace (~> 1.5)
redis-rails (~> 5.0)
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index b5f42305f..c1ad9c701 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'singleton'
+require_relative './formatter_markdown'
require_relative './sanitize_config'
class Formatter
@@ -35,12 +36,21 @@ class Formatter
linkable_accounts << status.account
html = raw_content
+
+ mdFormatter = Formatter_Markdown.new(html)
+ html = mdFormatter.formatted
+
html = "RT @#{prepend_reblog} #{html}" if prepend_reblog
html = encode_and_link_urls(html, linkable_accounts)
html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]
html = simple_format(html, {}, sanitize: false)
html = html.delete("\n")
+ mdLinkDecoder = MDLinkDecoder.new(html)
+ html = mdLinkDecoder.decode
+
+ html.gsub!(/(&)/){"&"}
+
html.html_safe # rubocop:disable Rails/OutputSafety
end
@@ -111,13 +121,18 @@ class Formatter
def encode_and_link_urls(html, accounts = nil, options = {})
entities = utf8_friendly_extractor(html, extract_url_without_protocol: false)
+ mdExtractor = MDExtractor.new(html)
+ entities.concat(mdExtractor.extractEntities)
+
if accounts.is_a?(Hash)
options = accounts
accounts = nil
end
rewrite(html.dup, entities) do |entity|
- if entity[:url]
+ if entity[:markdown]
+ html[entity[:indices][0]...entity[:indices][1]]
+ elsif entity[:url]
link_to_url(entity, options)
elsif entity[:hashtag]
link_to_hashtag(entity)
diff --git a/app/lib/formatter_markdown.rb b/app/lib/formatter_markdown.rb
new file mode 100644
index 000000000..30a08d558
--- /dev/null
+++ b/app/lib/formatter_markdown.rb
@@ -0,0 +1,340 @@
+require 'uri'
+require 'redcarpet'
+require 'redcarpet/render_strip'
+
+class Formatter_Markdown
+ def initialize(html)
+ @html = html.dup
+ end
+
+ def formatted
+ mdRenderer = CustomMDRenderer.new(
+ strikethrough: true,
+ hard_wrap: true,
+ autolink: false,
+ superscript:false,
+ fenced_link: true,
+ fenced_image: true,
+ no_intra_emphasis: true,
+ no_links: true,
+ no_styles: true,
+ no_images: true,
+ filter_html: true,
+ escape_html: true,
+ safe_links_only: true,
+ with_toc_data: true,
+ xhtml: false,
+ prettify: true,
+ link_attributes: true
+ )
+
+ md = Redcarpet::Markdown.new(
+ mdRenderer,
+ strikethrough: true,
+ hard_wrap: true,
+ superscript:false,
+ autolink: false,
+ space_after_headers: true,
+ no_intra_emphasis: true,
+ no_links: true,
+ no_styles: true,
+ no_images: true,
+ filter_html: true,
+ escape_html: true,
+ safe_links_only: true,
+ with_toc_data: true,
+ xhtml: false,
+ prettify: true,
+ link_attributes: true
+ )
+ s = @html
+ s.gsub!(/\n[\n]+/) {"\n \n"}# 改行周りの問題を修正
+ s.gsub!(/`[ ]+`/) {"` `"}# code内が半角スペースのみだとHTMLが壊れるのでそれの回避
+
+ renderedMD = md.render(s)
+
+ result = renderedMD
+ result.gsub!(/(<\w+)([^>]*>)/) { "#{$1} data-md='true' #{$2}" }# ToDo data-md="true" を認識して他鯖の人にmarkdownの使用を伝える機能の実装
+ result.gsub!(/(https?:\/\/[^<>"\[\] ]+)/){"#{$1} "}#URLの後ろにスペースをねじ込む奴 mastodonのURL認識がゆるいのをmarkdownで対処
+
+ result
+
+ end
+
+ class CustomMDRenderer < Redcarpet::Render::HTML
+
+ #基本的な実装の流れ
+ #URLの削除(mastodonの機能上URLとして認識されると十中八九HTMLが壊れるので)
+ #markdownコンテンツ内でのmarkdownコンテンツの禁止(意図しないHTMLタグの生成によってHTMLの不正出力を防ぐ目的)
+ #最後にHTMLに出力される際にHTML的にヤバイ子たちのエスケープ
+
+ def paragraph(text)
+ %(#{text.strip})
+ end
+
+ def linebreak()
+ %(
)
+ end
+
+ def block_quote(quote)
+ urlRemoved = "#{remove_url(quote)}"
+ escapedContents = "#{blockquote_markdown_escape(urlRemoved)}"
+ %(
#{escapedContents.strip}) + end + + def header(text, header_level) + urlRemoved = "#{remove_url(text)}" + mdContentsRemoved = "#{markdown_escape(urlRemoved)}" + %(
#{encode(escapedCode)}
)
+ end
+
+ def list(contents, list_type)
+ if list_type == :unordered
+ %(