about summary refs log tree commit diff
path: root/app/lib
diff options
context:
space:
mode:
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/bangtags.rb51
-rw-r--r--app/lib/formatter.rb178
-rw-r--r--app/lib/sanitize_config.rb5
3 files changed, 213 insertions, 21 deletions
diff --git a/app/lib/bangtags.rb b/app/lib/bangtags.rb
index 404d20a0f..4ba6b5e92 100644
--- a/app/lib/bangtags.rb
+++ b/app/lib/bangtags.rb
@@ -26,7 +26,7 @@ class Bangtags
     # list of transformation commands
     @tf_cmds = []
     # list of post-processing commands
-    @post_cmds = [['signature']]
+    @post_cmds = []
     # hash of bangtag variables
     @vars = account.vars
     # keep track of what variables we're appending the value of between chunks
@@ -36,7 +36,7 @@ class Bangtags
   end
 
   def process
-    return unless status.text&.present?
+    return unless status.text&.present? && status.text.include?('#!')
 
     status.text.gsub!('#!!', "#\u200c!")
 
@@ -367,16 +367,19 @@ class Bangtags
             who = cmd[2]
             if who.blank?
               @vars.delete('_they:are')
+              status.footer = nil
               next
             elsif who == 'not'
               who = cmd[3]
               next if who.blank?
               name = who.downcase.gsub(/\s+/, '')
               @vars.delete("_they:are:#{name}")
-              @vars.delete('_they:are') if @vars['_they:are'] == name
+              next unless @vars['_they:are'] == name
+              @vars.delete('_they:are')
+              status.footer = nil
               next
             end
-            name = who.downcase.gsub(/\s+/, '')
+            name = who.downcase.gsub(/\s+/, '').strip
             description = cmd[3..-1].join(':').strip
             if description.blank?
               if @vars["_they:are:#{name}"].nil?
@@ -385,7 +388,8 @@ class Bangtags
             else
               @vars["_they:are:#{name}"] = description
             end
-            @vars['_they:are'] = name.strip
+            @vars['_they:are'] = name
+            status.footer = @vars["_they:are:#{name}"]
           end
         when 'sharekey'
           next if cmd[1].nil?
@@ -401,6 +405,30 @@ class Bangtags
           @vore_stack.push('_draft')
           @component_stack.push(:var)
           add_tags(status, 'self:draft')
+        when 'format', 'type'
+          chunk = nil
+          next if cmd[1].nil?
+          content_types = {
+            't'           => 'text/plain',
+            'txt'         => 'text/plain',
+            'text'        => 'text/plain',
+            'plain'       => 'text/plain',
+            'plaintext'   => 'text/plain',
+
+            'm'           => 'text/markdown',
+            'md'          => 'text/markdown',
+            'markdown'    => 'text/markdown',
+
+            'b'           => 'text/x-bbcode',
+            'bbc'         => 'text/x-bbcode',
+            'bbcode'      => 'text/x-bbcode',
+
+            'bm'          => 'text/x-bbcode+markdown',
+            'bbm'         => 'text/x-bbcode+markdown',
+            'bbdown'      => 'text/x-bbcode+markdown',
+          }
+          v = cmd[1].downcase
+          status.content_type = content_types[c] unless content_types[c].nil?
         when 'visibility'
           chunk = nil
           next if cmd[1].nil?
@@ -421,7 +449,7 @@ class Bangtags
             'world'       => :public,
           }
           v = cmd[1].downcase
-          status.visibility = visibilities[v] if visibilities[v].nil?
+          status.visibility = visibilities[v] unless visibilities[v].nil?
         end
       end
 
@@ -472,17 +500,6 @@ class Bangtags
   def postprocess_before_save
     @post_cmds.each do |post_cmd|
       case post_cmd[0]
-      when 'signature'
-        name = @vars['_they:are']
-        next if name.blank?
-        description = @vars["_they:are:#{name}"]
-        next if description.blank? || @chunks.last(5).join.include?('—')
-        status.local_only = true if Status::LOCAL_ONLY_TOKENS.match?(@chunks.last)
-        if @chunks.first(5).any? { |c| c.strip.match?(/[\r\n]/) || c.lstrip.match?(/^(?:[>#]|```|---|\* |\d+\)|\[\wi+)/) }
-          @chunks << "\n\n[right]— #{description}\u200c[/right]"
-        else
-          @chunks << " [rfloat]— #{description}\u200c[/rfloat]"
-        end
       when 'media'
         media_idx = post_cmd[1]
         media_cmd = post_cmd[2]
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index cb9ca8336..42911b52a 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -30,6 +30,141 @@ class Formatter
 
   include ActionView::Helpers::TextHelper
 
+	BBCODE_TAGS = {
+    :url => {
+			:html_open => '<a href="%url%" rel="noopener nofollow" target="_blank">', :html_close => '</a>',
+			:description => '', :example => '',
+			:allow_quick_param => true, :allow_between_as_param => false,
+			:quick_param_format => /(\S+)/,
+			:quick_param_format_description => 'The size parameter \'%param%\' is incorrect, a number is expected',
+			:param_tokens => [{:token => :url}]
+    },
+		:ul => {
+			:html_open => '<ul>', :html_close => '</ul>',
+			:description => '', :example => '',
+		},
+		:ol => {
+			:html_open => '<ol>', :html_close => '</ol>',
+			:description => '', :example => '',
+		},
+		:li => {
+			:html_open => '<li>', :html_close => '</li>',
+			:description => '', :example => '',
+		},
+		:sub => {
+			:html_open => '<sub>', :html_close => '</sub>',
+			:description => '', :example => '',
+		},
+		:sup => {
+			:html_open => '<sup>', :html_close => '</sup>',
+			:description => '', :example => '',
+		},
+		:h1 => {
+			:html_open => '<h1>', :html_close => '</h1>',
+			:description => '', :example => '',
+		},
+		:h2 => {
+			:html_open => '<h2>', :html_close => '</h2>',
+			:description => '', :example => '',
+		},
+		:h3 => {
+			:html_open => '<h3>', :html_close => '</h3>',
+			:description => '', :example => '',
+		},
+		:h4 => {
+			:html_open => '<h4>', :html_close => '</h4>',
+			:description => '', :example => '',
+		},
+		:h5 => {
+			:html_open => '<h5>', :html_close => '</h5>',
+			:description => '', :example => '',
+		},
+		:h6 => {
+			:html_open => '<h6>', :html_close => '</h6>',
+			:description => '', :example => '',
+		},
+		:abbr => {
+			:html_open => '<abbr>', :html_close => '</abbr>',
+			:description => '', :example => '',
+		},
+		:hr => {
+			:html_open => '<hr>', :html_close => '</hr>',
+			:description => '', :example => '',
+		},
+		:b => {
+			:html_open => '<strong>', :html_close => '</strong>',
+			:description => '', :example => '',
+		},
+		:i => {
+			:html_open => '<em>', :html_close => '</em>',
+			:description => '', :example => '',
+		},
+		:flip => {
+			:html_open => '<span class="bbcode__flip-%direction%">', :html_close => '</span>',
+			:description => '', :example => '',
+			:allow_quick_param => true, :allow_between_as_param => false,
+			:quick_param_format => /(h|v)/,
+			:quick_param_format_description => 'The size parameter \'%param%\' is incorrect, a number is expected',
+			:param_tokens => [{:token => :direction}]
+    },
+		:size => {
+			:html_open => '<span class="bbcode__size-%size%">', :html_close => '</span>',
+			:description => '', :example => '',
+			:allow_quick_param => true, :allow_between_as_param => false,
+			:quick_param_format => /([1-6])/,
+			:quick_param_format_description => 'The size parameter \'%param%\' is incorrect, a number is expected',
+			:param_tokens => [{:token => :size}]
+    },
+		:quote => {
+			:html_open => '<blockquote>', :html_close => '</blockquote>',
+			:description => '', :example => '',
+    },
+		:kbd => {
+			:html_open => '<pre><code>', :html_close => '</code></pre>',
+			:description => '', :example => '',
+    },
+		:code => {
+			:html_open => '<pre>', :html_close => '</pre>',
+			:description => '', :example => '',
+    },
+		:u => {
+			:html_open => '<u>', :html_close => '</u>',
+			:description => '', :example => '',
+    },
+		:s => {
+			:html_open => '<s>', :html_close => '</s>',
+			:description => '', :example => '',
+    },
+		:del => {
+			:html_open => '<del>', :html_close => '</del>',
+			:description => '', :example => '',
+    },
+		:left => {
+			:html_open => '<span class="bbcode__left">', :html_close => '</span>',
+			:description => '', :example => '',
+    },
+		:center => {
+			:html_open => '<span class="bbcode__center">', :html_close => '</span>',
+			:description => '', :example => '',
+    },
+		:right => {
+			:html_open => '<span class="bbcode__right">', :html_close => '</span>',
+			:description => '', :example => '',
+    },
+		:lfloat => {
+			:html_open => '<span class="bbcode__lfloat">', :html_close => '</span>',
+			:description => '', :example => '',
+    },
+		:rfloat => {
+			:html_open => '<span class="bbcode__rfloat">', :html_close => '</span>',
+			:description => '', :example => '',
+    },
+		:spoiler => {
+			:html_open => '<span class="bbcode__spoiler-wrapper"><span class="bbcode__spoiler">', :html_close => '</span></span>',
+			:description => '', :example => '',
+    },
+	}
+
   def format(status, **options)
     if status.reblog?
       prepend_reblog = status.reblog.account.acct
@@ -57,15 +192,26 @@ class Formatter
 
     html = raw_content
     html = "RT @#{prepend_reblog} #{html}" if prepend_reblog
-    html = format_markdown(html) if status.content_type == 'text/markdown'
-    html = encode_and_link_urls(html, linkable_accounts, keep_html: %w(text/markdown text/html).include?(status.content_type))
+
+    case status.content_type
+    when 'text/markdown'
+      html = format_markdown(html)
+    when 'text/x-bbcode'
+      html = format_bbcode(html)
+    when 'text/x-bbcode+markdown'
+      html = format_bbdown(html)
+    end
+
+    html = encode_and_link_urls(html, linkable_accounts, keep_html: %w(text/markdown text/x-bbcode text/x-bbcode+markdown text/html).include?(status.content_type))
     html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]
 
-    unless %w(text/markdown text/html).include?(status.content_type)
+    unless %w(text/markdown text/x-bbcode text/x-bbcode+markdown text/html).include?(status.content_type)
       html = simple_format(html, {}, sanitize: false)
       html = html.delete("\n")
     end
 
+    html = append_footer(html, status.footer)
+
     html.html_safe # rubocop:disable Rails/OutputSafety
   end
 
@@ -74,6 +220,19 @@ class Formatter
     html.delete("\r").delete("\n")
   end
 
+  def format_bbcode(html, sanitize = true)
+    html = bbcode_formatter(html)
+    html = html.gsub(/<hr>.*<\/hr>/im, '<hr />')
+    return html unless sanitize
+    html = reformat(html)
+    html.delete("\n")
+  end
+
+  def format_bbdown(html)
+    html = format_bbcode(html, false)
+    format_markdown(html)
+  end
+
   def reformat(html)
     sanitize(html, Sanitize::Config::MASTODON_STRICT)
   end
@@ -134,6 +293,19 @@ class Formatter
 
   private
 
+  def append_footer(html, footer)
+    return html if footer.blank?
+    "#{html.strip}<p class=\"signature\">— #{encode(footer)}</p>"
+  end
+
+  def bbcode_formatter(html)
+    begin
+      html = html.bbcode_to_html(false, BBCODE_TAGS, :enable, *BBCODE_TAGS.keys)
+    rescue Exception => e
+    end
+    html
+  end
+
   def markdown_formatter
     return @markdown_formatter if defined?(@markdown_formatter)
 
diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb
index db6f50ed1..9756f2ef6 100644
--- a/app/lib/sanitize_config.rb
+++ b/app/lib/sanitize_config.rb
@@ -14,6 +14,8 @@ 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 e =~ /^bbcode__([a-z1-6\-]+)$/ # bbcode
+        next true if e == 'signature'
       end
 
       node['class'] = class_list.join(' ')
@@ -23,10 +25,11 @@ class Sanitize
       elements: %w(p br span a abbr del pre sub sup blockquote code b strong u i em h1 h2 h3 h4 h5 h6 ul ol li hr),
 
       attributes: {
-        'a'          => %w(href rel class title),
+        'a'          => %w(href rel class title alt),
         'span'       => %w(class),
         'abbr'       => %w(title),
         'blockquote' => %w(cite),
+        'p'          => %w(class),
       },
 
       add_attributes: {