reimplement monsterpit bbcode and markdown extensions on top of new glitch-soc formatting system + bbcode feature parity + new `i:am` footer + set content type from `format` bangtag
parent
09b7532805
commit
7a0dc34cad
2
Gemfile
2
Gemfile
|
@ -149,3 +149,5 @@ group :production do
|
|||
end
|
||||
|
||||
gem 'concurrent-ruby', require: false
|
||||
|
||||
gem "ruby-bbcode", "~> 2.0"
|
||||
|
|
|
@ -533,6 +533,8 @@ GEM
|
|||
rainbow (>= 2.2.2, < 4.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 1.7)
|
||||
ruby-bbcode (2.0.3)
|
||||
activesupport (>= 4.2.2)
|
||||
ruby-progressbar (1.10.0)
|
||||
ruby-saml (1.9.0)
|
||||
nokogiri (>= 1.5.10)
|
||||
|
@ -667,7 +669,6 @@ DEPENDENCIES
|
|||
brakeman (~> 4.5)
|
||||
browser
|
||||
bullet (~> 6.0)
|
||||
bundler (~> 1.17)
|
||||
bundler-audit (~> 0.6)
|
||||
capistrano (~> 3.11)
|
||||
capistrano-rails (~> 1.4)
|
||||
|
@ -751,6 +752,7 @@ DEPENDENCIES
|
|||
rspec-rails (~> 3.8)
|
||||
rspec-sidekiq (~> 3.0)
|
||||
rubocop (~> 0.69)
|
||||
ruby-bbcode (~> 2.0)
|
||||
sanitize (~> 5.0)
|
||||
scss_lint (~> 0.58)
|
||||
sidekiq (~> 5.2)
|
||||
|
|
|
@ -25,6 +25,14 @@ const messages = defineMessages({
|
|||
defaultMessage: 'Attach...',
|
||||
id: 'compose.attach',
|
||||
},
|
||||
bbcode: {
|
||||
defaultMessage: 'BBCode',
|
||||
id: 'compose.content-type.bbcode',
|
||||
},
|
||||
bbdown: {
|
||||
defaultMessage: 'BBdown',
|
||||
id: 'compose.content-type.bbdown',
|
||||
},
|
||||
change_privacy: {
|
||||
defaultMessage: 'Adjust status privacy',
|
||||
id: 'privacy.change',
|
||||
|
@ -232,7 +240,7 @@ class ComposerOptions extends ImmutablePureComponent {
|
|||
|
||||
const contentTypeItems = {
|
||||
plain: {
|
||||
icon: 'align-left',
|
||||
icon: 'file-text',
|
||||
name: 'text/plain',
|
||||
text: <FormattedMessage {...messages.plain} />,
|
||||
},
|
||||
|
@ -242,10 +250,20 @@ class ComposerOptions extends ImmutablePureComponent {
|
|||
text: <FormattedMessage {...messages.html} />,
|
||||
},
|
||||
markdown: {
|
||||
icon: 'arrow-circle-down',
|
||||
icon: 'hashtag',
|
||||
name: 'text/markdown',
|
||||
text: <FormattedMessage {...messages.markdown} />,
|
||||
},
|
||||
xbbcode: {
|
||||
icon: 'thumb-tack',
|
||||
name: 'text/x-bbcode',
|
||||
text: <FormattedMessage {...messages.bbcode} />,
|
||||
},
|
||||
xbbcodemarkdown: {
|
||||
icon: 'arrow-circle-down',
|
||||
name: 'text/x-bbcode+markdown',
|
||||
text: <FormattedMessage {...messages.bbdown} />,
|
||||
},
|
||||
};
|
||||
|
||||
// The result.
|
||||
|
@ -315,11 +333,13 @@ class ComposerOptions extends ImmutablePureComponent {
|
|||
{showContentTypeChoice && (
|
||||
<Dropdown
|
||||
disabled={disabled}
|
||||
icon={(contentTypeItems[contentType.split('/')[1]] || {}).icon}
|
||||
icon={(contentTypeItems[contentType.split('/')[1].replace(/[+-]/g, '')] || {}).icon}
|
||||
items={[
|
||||
contentTypeItems.plain,
|
||||
contentTypeItems.html,
|
||||
contentTypeItems.xbbcodemarkdown,
|
||||
contentTypeItems.markdown,
|
||||
contentTypeItems.xbbcode,
|
||||
contentTypeItems.html,
|
||||
contentTypeItems.plain,
|
||||
]}
|
||||
onChange={onChangeContentType}
|
||||
onModalClose={onModalClose}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
// Original:
|
||||
// https://github.com/computerfairies/mastodon/blob/master/app/javascript/styles/mastodon/bbcode.scss
|
||||
*/
|
||||
|
||||
.bbcode {
|
||||
&__flip-horizontal {
|
||||
display: inline-block;
|
||||
-webkit-transform: scale(-1, 1);
|
||||
-ms-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
&__flip-vertical {
|
||||
display: inline-block;
|
||||
-webkit-transform: scale(1, -1);
|
||||
-ms-transform: scale(1, -1);
|
||||
transform: scale(1, -1);
|
||||
}
|
||||
|
||||
@for $i from 1 through 6 {
|
||||
&__size-#{$i} {
|
||||
font-size: #{6 * $i}px;
|
||||
|
||||
& .emojione {
|
||||
width: #{6 * $i}px !important;
|
||||
height: #{6 * $i}px !important;
|
||||
}
|
||||
|
||||
& .hoverplay {
|
||||
padding-left: #{6 * $i}px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 2 {
|
||||
&__size-#{$i}:hover {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&__left { display: block; text-align: left; }
|
||||
&__center { display: block; text-align: center; }
|
||||
&__right { display: block; text-align: right; }
|
||||
&__lfloat { float: left; }
|
||||
&__rfloat { float: right; }
|
||||
&__spoiler-wrapper {
|
||||
background: black;
|
||||
color: black;
|
||||
padding: 1px 2em 1px 2em;
|
||||
}
|
||||
&__spoiler { color: black; visibility: hidden; }
|
||||
&__spoiler-wrapper:hover > &__spoiler,
|
||||
&__spoiler-wrapper:active > &__spoiler
|
||||
{ color: white; visibility: visible; }
|
||||
}
|
|
@ -24,3 +24,5 @@
|
|||
@import 'accessibility';
|
||||
@import 'rtl';
|
||||
@import 'dashboard';
|
||||
@import 'bbcode';
|
||||
@import 'monsterpit';
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
.status__content__text,
|
||||
.reply-indicator__content,
|
||||
.composer--reply > .content,
|
||||
.account__header__content,
|
||||
{
|
||||
s { text-decoration: line-through; }
|
||||
del { text-decoration: line-through; }
|
||||
h6 { font-size: 8px; font-weight: bold; }
|
||||
hr { border-color: lighten($dark-text-color, 10%); }
|
||||
sub {
|
||||
vertical-align: sub;
|
||||
font-size: smaller;
|
||||
}
|
||||
sup {
|
||||
vertical-align: super;
|
||||
font-size: smaller;
|
||||
}
|
||||
pre, code {
|
||||
color: lighten($dark-text-color, 33%);
|
||||
}
|
||||
mark {
|
||||
background-color: #ccff15;
|
||||
color: black;
|
||||
}
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
}
|
||||
.caption {
|
||||
display: block;
|
||||
margin: auto;
|
||||
font-size: 12px !important;
|
||||
padding-top: 0;
|
||||
text-align: center;
|
||||
max-width: 80%;
|
||||
}
|
||||
.caption-hidden {
|
||||
display: none;
|
||||
}
|
||||
p.signature {
|
||||
color: lighten($dark-text-color, 20%);
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
div.media-caption {
|
||||
p {
|
||||
font-size: 12px !important;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: $secondary-text-color;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
.fa {
|
||||
color: lighten($dark-text-color, 7%);
|
||||
}
|
||||
}
|
||||
|
||||
&.mention {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: $dark-text-color;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,3 +26,5 @@
|
|||
@import 'mastodon/dashboard';
|
||||
@import 'mastodon/rtl';
|
||||
@import 'mastodon/accessibility';
|
||||
@import 'mastodon/bbcode';
|
||||
@import 'mastodon/monsterpit';
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
// Original:
|
||||
// https://github.com/computerfairies/mastodon/blob/master/app/javascript/styles/mastodon/bbcode.scss
|
||||
*/
|
||||
|
||||
.bbcode {
|
||||
&__flip-horizontal {
|
||||
display: inline-block;
|
||||
-webkit-transform: scale(-1, 1);
|
||||
-ms-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
&__flip-vertical {
|
||||
display: inline-block;
|
||||
-webkit-transform: scale(1, -1);
|
||||
-ms-transform: scale(1, -1);
|
||||
transform: scale(1, -1);
|
||||
}
|
||||
|
||||
@for $i from 1 through 6 {
|
||||
&__size-#{$i} {
|
||||
font-size: #{6 * $i}px;
|
||||
|
||||
& .emojione {
|
||||
width: #{6 * $i}px !important;
|
||||
height: #{6 * $i}px !important;
|
||||
}
|
||||
|
||||
& .hoverplay {
|
||||
padding-left: #{6 * $i}px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 2 {
|
||||
&__size-#{$i}:hover {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&__left { display: block; text-align: left; }
|
||||
&__center { display: block; text-align: center; }
|
||||
&__right { display: block; text-align: right; }
|
||||
&__lfloat { float: left; }
|
||||
&__rfloat { float: right; }
|
||||
&__spoiler-wrapper {
|
||||
background: black;
|
||||
color: black;
|
||||
padding: 1px 2em 1px 2em;
|
||||
}
|
||||
&__spoiler { color: black; visibility: hidden; }
|
||||
&__spoiler-wrapper:hover > &__spoiler,
|
||||
&__spoiler-wrapper:active > &__spoiler
|
||||
{ color: white; visibility: visible; }
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
.status__content__text,
|
||||
.reply-indicator__content,
|
||||
.composer--reply > .content,
|
||||
.account__header__content,
|
||||
{
|
||||
s { text-decoration: line-through; }
|
||||
del { text-decoration: line-through; }
|
||||
h6 { font-size: 8px; font-weight: bold; }
|
||||
hr { border-color: lighten($dark-text-color, 10%); }
|
||||
sub {
|
||||
vertical-align: sub;
|
||||
font-size: smaller;
|
||||
}
|
||||
sup {
|
||||
vertical-align: super;
|
||||
font-size: smaller;
|
||||
}
|
||||
pre, code {
|
||||
color: lighten($dark-text-color, 33%);
|
||||
}
|
||||
mark {
|
||||
background-color: #ccff15;
|
||||
color: black;
|
||||
}
|
||||
blockquote {
|
||||
font-style: italic;
|
||||
}
|
||||
.caption {
|
||||
display: block;
|
||||
margin: auto;
|
||||
font-size: 12px !important;
|
||||
padding-top: 0;
|
||||
text-align: center;
|
||||
max-width: 80%;
|
||||
}
|
||||
.caption-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
div.media-caption {
|
||||
p {
|
||||
font-size: 12px !important;
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: $secondary-text-color;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
.fa {
|
||||
color: lighten($dark-text-color, 7%);
|
||||
}
|
||||
}
|
||||
|
||||
&.mention {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
color: $dark-text-color;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
# in_reply_to_account_id :bigint(8)
|
||||
# local_only :boolean
|
||||
# poll_id :bigint(8)
|
||||
# content_type :string
|
||||
# tsv :tsvector
|
||||
# curated :boolean default(FALSE), not null
|
||||
# sharekey :string
|
||||
# network :boolean default(FALSE), not null
|
||||
# content_type :string
|
||||
# footer :text
|
||||
#
|
||||
|
||||
class Status < ApplicationRecord
|
||||
|
@ -81,7 +82,7 @@ class Status < ApplicationRecord
|
|||
validates_with DisallowedHashtagsValidator
|
||||
validates :reblog, uniqueness: { scope: :account }, if: :reblog?
|
||||
validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?
|
||||
validates :content_type, inclusion: { in: %w(text/plain text/markdown text/html) }, allow_nil: true
|
||||
validates :content_type, inclusion: { in: %w(text/plain text/markdown text/x-bbcode text/x-bbcode+markdown text/html) }, allow_nil: true
|
||||
|
||||
accepts_nested_attributes_for :poll
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ defaults: &defaults
|
|||
show_known_fediverse_at_about_page: true
|
||||
show_reblogs_in_public_timelines: false
|
||||
show_replies_in_public_timelines: false
|
||||
default_content_type: 'text/plain'
|
||||
default_content_type: 'text/x-bbcode+markdown'
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
|
|
Loading…
Reference in New Issue