From 6e28a99c8e46295dd049f7af45565d4bea97c725 Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Sun, 16 Aug 2020 03:24:47 -0500 Subject: [Feature] Full article support --- app/lib/command_tag/command/status_tools.rb | 22 ++++++++++++++++++++-- app/lib/formatter.rb | 20 ++++++++++++++++++-- app/lib/sanitize_config.rb | 19 +++++++++++++++++-- 3 files changed, 55 insertions(+), 6 deletions(-) (limited to 'app/lib') diff --git a/app/lib/command_tag/command/status_tools.rb b/app/lib/command_tag/command/status_tools.rb index 1727a956e..1cdb90e4a 100644 --- a/app/lib/command_tag/command/status_tools.rb +++ b/app/lib/command_tag/command/status_tools.rb @@ -1,11 +1,29 @@ # frozen_string_literal: true module CommandTag::Command::StatusTools + def handle_article_before_save(args) + return unless author_of_status? && args.present? + + case args.shift.downcase + when 'title', 'name', 't' + status.title = args.join(' ') + when 'summary', 'abstract', 'cw', 'cn', 's', 'a' + @status.title = @status.spoiler_text if @status.title.blank? + @status.spoiler_text = args.join(' ') + end + end + def handle_title_before_save(args) - return unless author_of_status? + args.unshift('title') + handle_article_before_save(args) + end - @status.title = args[0] + def handle_summary_before_save(args) + args.unshift('summary') + handle_article_before_save(args) end + alias handle_abstract_before_save handle_summary_before_save + def handle_visibility_before_save(args) return unless author_of_status? && args[0].present? diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index d85bbf0e0..bf99701b7 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -39,8 +39,14 @@ class Formatter prepend_reblog = false end + summary = nil raw_content = status.text + if status.title.present? + summary = status.spoiler_text.presence || status.text + raw_content = options[:article_content] ? status.text : summary + end + if options[:inline_poll_options] && status.preloadable_poll raw_content = raw_content + "\n\n" + status.preloadable_poll.options.map { |title| "[ ] #{title}" }.join("\n") end @@ -50,6 +56,7 @@ class Formatter unless status.local? html = reformat(raw_content) html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify] + html = format_article_content(summary, html) if options[:article_content] && summary.present? return html.html_safe # rubocop:disable Rails/OutputSafety end @@ -68,6 +75,7 @@ class Formatter html = html.delete("\n") end + html = format_article_content(summary, html) if options[:article_content] && summary.present? html.html_safe # rubocop:disable Rails/OutputSafety end @@ -77,10 +85,14 @@ class Formatter end def format_article(text) - text = text.gsub(/>[\r\n]+<") + text = text.gsub(/>[\r\n]+<') text.html_safe # rubocop:disable Rails/OutputSafety end + def format_article_content(summary, html) + "
#{format_summary(summary, html)}
#{html}" + end + def reformat(html, outgoing = false) sanitize(html, Sanitize::Config::MASTODON_STRICT.merge(outgoing: outgoing)) rescue ArgumentError @@ -108,8 +120,12 @@ class Formatter Sanitize.fragment(html, config) end + def format_summary(summary, fallback) + summary&.strip.presence || fallback[/(?:

.*?<\/p>)/im].presence || '🗎❓' + end + def format_spoiler(status, **options) - html = encode(status.spoiler_text) + html = encode(status.title.presence || status.spoiler_text) html = encode_custom_emojis(html, status.emojis, options[:autoplay]) html.html_safe # rubocop:disable Rails/OutputSafety end diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb index 74a1d93fb..102dce2d2 100644 --- a/app/lib/sanitize_config.rb +++ b/app/lib/sanitize_config.rb @@ -30,12 +30,25 @@ class Sanitize next true if e =~ /^(h|p|u|dt|e)-/ # microformats classes next true if e =~ /^(mention|hashtag)$/ # semantic classes next true if e =~ /^(ellipsis|invisible)$/ # link formatting classes - next true if %w(center centered).include?(e) + next true if %w(center centered abstract).include?(e) end node['class'] = class_list.join(' ') end + DATA_NAME_ALLOWLIST_TRANSFORMER = lambda do |env| + node = env[:node] + name_list = node['data-name']&.split(/[\t\n\f\r ]/) + + return unless name_list + + name_list.keep_if do |name| + next true if %w(summary abstract).include?(name) + end + + node['data-name'] = name_list.join(' ') + end + LINK_REL_TRANSFORMER = lambda do |env| return unless env[:node_name] == 'a' and env[:node]['href'] @@ -71,10 +84,11 @@ class Sanitize 'a' => %w(href rel class title), 'span' => %w(class), 'abbr' => %w(title), - 'blockquote' => %w(cite), + 'blockquote' => %w(cite data-name), 'ol' => %w(start reversed), 'li' => %w(value), 'img' => %w(src alt title), + 'p' => %w(data-name), }, add_attributes: { @@ -90,6 +104,7 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, + DATA_NAME_ALLOWLIST_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, LINK_REL_TRANSFORMER, ] -- cgit