various bangtag improvements squashed into one commit
parent
8d19acc618
commit
0e5935e475
|
@ -377,7 +377,7 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: $secondary-text-color;
|
color: $secondary-text-color;
|
||||||
background: linear-gradient(0deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent);
|
background: rgba($base-shadow-color, 0.90);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
@ -404,7 +404,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.composer--upload_form--actions {
|
.composer--upload_form--actions {
|
||||||
background: linear-gradient(180deg, rgba($base-shadow-color, 0.8) 0, rgba($base-shadow-color, 0.35) 80%, transparent);
|
background: rgba($base-shadow-color, 0.90);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
|
@ -577,28 +577,143 @@ class Status < ApplicationRecord
|
||||||
def process_bangtags
|
def process_bangtags
|
||||||
return if text&.nil?
|
return if text&.nil?
|
||||||
return unless '#!'.in?(text)
|
return unless '#!'.in?(text)
|
||||||
|
text.gsub!('#!!', "#\u200c!")
|
||||||
|
|
||||||
|
prefix_ns = {
|
||||||
|
'permalink' => ['link'],
|
||||||
|
'cloudroot' => ['link'],
|
||||||
|
'blogroot' => ['link'],
|
||||||
|
}
|
||||||
|
|
||||||
|
aliases = {
|
||||||
|
['media', 'end'] => ['var', 'end'],
|
||||||
|
['media', 'stop'] => ['var', 'end'],
|
||||||
|
['media', 'endall'] => ['var', 'endall'],
|
||||||
|
['media', 'stopall'] => ['var', 'endall'],
|
||||||
|
}
|
||||||
|
|
||||||
|
# sections of the final status text
|
||||||
chunks = []
|
chunks = []
|
||||||
tf_command = nil
|
# list of transformation commands
|
||||||
|
tf_cmds = []
|
||||||
|
# list of post-processing commands
|
||||||
|
post_cmds = []
|
||||||
|
# hash of bangtag variables
|
||||||
|
vars = {}
|
||||||
|
# keep track of what variables we're appending the value of between chunks
|
||||||
|
vore_stack = []
|
||||||
|
# keep track of what type of nested components are active so we can !end them in order
|
||||||
|
component_stack = []
|
||||||
|
|
||||||
text.split(/(#!(?:[\w:-]+|{.*?}))/).each do |chunk|
|
text.split(/(#!(?:.*:!#|{.*?}|[^\s#]+))/).each do |chunk|
|
||||||
if chunk.start_with?("#!")
|
if chunk.starts_with?("#!")
|
||||||
chunk.sub!(/{(.*)}$/, '\1')
|
chunk.sub!(/(\\:)?+:+?!#\Z/, '\1')
|
||||||
command = chunk[2..-1].split(':')
|
chunk.sub!(/{(.*)}\Z/, '\1')
|
||||||
next if command.blank?
|
|
||||||
|
|
||||||
case command[0]
|
if vore_stack.last != '_comment'
|
||||||
|
cmd = chunk[2..-1].strip
|
||||||
|
next if cmd.blank?
|
||||||
|
cmd = cmd.split(':::')
|
||||||
|
cmd = cmd[0].split('::') + cmd[1..-1]
|
||||||
|
cmd = cmd[0].split(':') + cmd[1..-1]
|
||||||
|
|
||||||
|
cmd.map! {|c| c.gsub(/\\:/, ':').gsub(/\\\\:/, '\:')}
|
||||||
|
|
||||||
|
prefix = prefix_ns[cmd[0]]
|
||||||
|
cmd = prefix + cmd unless prefix.nil?
|
||||||
|
|
||||||
|
aliases.each_key do |old_cmd|
|
||||||
|
cmd = aliases[old_cmd] + cmd.drop(old_cmd.length) if cmd.take(old_cmd.length) == old_cmd
|
||||||
|
end
|
||||||
|
elsif chunk.in?(['#!comment:end', '#!comment:stop', '#!comment:endall', '#!comment:stopall'])
|
||||||
|
vore_stack.pop
|
||||||
|
component_stack.pop
|
||||||
|
next
|
||||||
|
else
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
case cmd[0]
|
||||||
|
when 'var'
|
||||||
|
chunk = nil
|
||||||
|
case cmd[1]
|
||||||
|
when 'end', 'stop'
|
||||||
|
vore_stack.pop
|
||||||
|
component_stack.pop
|
||||||
|
when 'endall', 'stopall'
|
||||||
|
vore_stack = []
|
||||||
|
component_stack.reject! {|c| c == :var}
|
||||||
|
else
|
||||||
|
var = cmd[1]
|
||||||
|
next if var.nil? || var.starts_with?('_')
|
||||||
|
new_value = cmd[2..-1]
|
||||||
|
if new_value.blank?
|
||||||
|
chunk = vars[var]
|
||||||
|
elsif new_value.length == 1 && new_value[0] == '-'
|
||||||
|
vore_stack.push(var)
|
||||||
|
component_stack.push(:var)
|
||||||
|
else
|
||||||
|
vars[var] = new_value.join(':')
|
||||||
|
end
|
||||||
|
end
|
||||||
when 'tf'
|
when 'tf'
|
||||||
tf_command = command[1..-1]
|
chunk = nil
|
||||||
|
case cmd[1]
|
||||||
|
when 'end', 'stop'
|
||||||
|
tf_cmds.pop
|
||||||
|
component_stack.pop
|
||||||
|
when 'endall', 'stopall'
|
||||||
|
tf_cmds = []
|
||||||
|
component_stack.reject! {|c| c == :tf}
|
||||||
|
else
|
||||||
|
tf_cmds.push(cmd[1..-1])
|
||||||
|
component_stack.push(:tf)
|
||||||
|
end
|
||||||
when 'end', 'stop'
|
when 'end', 'stop'
|
||||||
tf_command = nil
|
chunk = nil
|
||||||
|
case component_stack.pop
|
||||||
|
when :tf
|
||||||
|
tf_cmds.pop
|
||||||
|
when :var, :hide
|
||||||
|
vore_stack.pop
|
||||||
|
end
|
||||||
|
when 'endall', 'stopall'
|
||||||
|
chunk = nil
|
||||||
|
tf_cmds = []
|
||||||
|
vore_stack = []
|
||||||
|
component_stack = []
|
||||||
|
when 'emoji'
|
||||||
|
next if cmd[1].nil?
|
||||||
|
shortcode = cmd[1]
|
||||||
|
domain = (cmd[2].blank? ? nil : cmd[2].downcase)
|
||||||
|
chunk = ":#{shortcode}:"
|
||||||
|
ours = CustomEmoji.find_or_initialize_by(shortcode: shortcode, domain: nil)
|
||||||
|
if ours.id.nil?
|
||||||
|
if domain.nil?
|
||||||
|
theirs = CustomEmoji.find_by(shortcode: shortcode)
|
||||||
|
else
|
||||||
|
theirs = CustomEmoji.find_by(shortcode: shortcode, domain: domain)
|
||||||
|
end
|
||||||
|
unless theirs.nil?
|
||||||
|
ours.image = theirs.image
|
||||||
|
ours.save
|
||||||
|
end
|
||||||
|
end
|
||||||
when 'char'
|
when 'char'
|
||||||
|
chunk = nil
|
||||||
charmap = {
|
charmap = {
|
||||||
'zws': "\u200c"
|
'zws' => "\u200b",
|
||||||
|
'zwnj' => "\u200c",
|
||||||
|
'zwj' => "\u200d",
|
||||||
|
'\n' => "\n",
|
||||||
|
'\r' => "\r",
|
||||||
|
'\t' => "\t",
|
||||||
|
'\T' => ' '
|
||||||
}
|
}
|
||||||
command[1..-1].each do |c|
|
cmd[1..-1].each do |c|
|
||||||
next if c.nil?
|
next if c.nil?
|
||||||
if c.in?(charmap)
|
if c.in?(charmap)
|
||||||
chunks << charmap[command[1]]
|
chunks << charmap[cmd[1]]
|
||||||
elsif (/^\h{1,5}$/ =~ c) && c.to_i(16) > 0
|
elsif (/^\h{1,5}$/ =~ c) && c.to_i(16) > 0
|
||||||
begin
|
begin
|
||||||
chunks << [c.to_i(16)].pack('U*')
|
chunks << [c.to_i(16)].pack('U*')
|
||||||
|
@ -607,67 +722,180 @@ class Status < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
when 'permalink'
|
when 'link'
|
||||||
chunks << TagManager.instance.url_for(self)
|
chunk = nil
|
||||||
when 'cloudroot'
|
case cmd[1]
|
||||||
chunks << "https://monsterpit.cloud/~/#{account.username}"
|
when 'permalink', 'self'
|
||||||
when 'blogroot'
|
chunk = TagManager.instance.url_for(self)
|
||||||
chunks << "https://monsterpit.blog/~/#{account.username}"
|
when 'cloudroot'
|
||||||
|
chunk = "https://monsterpit.cloud/~/#{account.username}"
|
||||||
|
when 'blogroot'
|
||||||
|
chunk = "https://monsterpit.blog/~/#{account.username}"
|
||||||
|
end
|
||||||
when 'ping'
|
when 'ping'
|
||||||
case command[1]
|
mentions = []
|
||||||
|
case cmd[1]
|
||||||
when 'admins'
|
when 'admins'
|
||||||
mentions = User.admins.map { |u| "@#{u.account.username}" }
|
mentions = User.admins.map { |u| "@#{u.account.username}" }
|
||||||
mentions.sort!
|
mentions.sort!
|
||||||
chunks << mentions.join(' ')
|
|
||||||
when 'mods'
|
when 'mods'
|
||||||
mentions = User.moderators.map { |u| "@#{u.account.username}" }
|
mentions = User.moderators.map { |u| "@#{u.account.username}" }
|
||||||
mentions.sort!
|
mentions.sort!
|
||||||
chunks << mentions.join(' ')
|
|
||||||
when 'staff'
|
when 'staff'
|
||||||
mentions = User.admins.map { |u| "@#{u.account.username}" }
|
mentions = User.admins.map { |u| "@#{u.account.username}" }
|
||||||
mentions += User.moderators.map { |u| "@#{u.account.username}" }
|
mentions += User.moderators.map { |u| "@#{u.account.username}" }
|
||||||
mentions.uniq!
|
mentions.uniq!
|
||||||
mentions.sort!
|
mentions.sort!
|
||||||
chunks << mentions.join(' ')
|
end
|
||||||
|
chunk = mentions.join(' ')
|
||||||
|
when 'tag'
|
||||||
|
chunk = nil
|
||||||
|
records = []
|
||||||
|
valid_name = /^[[:word:]_\-]*[[:alpha:]_·\-][[:word:]_\-]*$/
|
||||||
|
cmd[1..-1].select {|t| t.present? && valid_name.match?(t)}.uniq.each do |name|
|
||||||
|
next if self.tags.where(name: name).exists?
|
||||||
|
tag = Tag.where(name: name).first_or_create(name: name)
|
||||||
|
self.tags << tag
|
||||||
|
records << tag
|
||||||
|
TrendingTags.record_use!(tag, account, created_at) if distributable?
|
||||||
|
end
|
||||||
|
if public_visibility? || unlisted_visibility?
|
||||||
|
account.featured_tags.where(tag_id: records.map(&:id)).each do |featured_tag|
|
||||||
|
featured_tag.increment(created_at)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
when 'thread'
|
when 'thread'
|
||||||
case command[1]
|
chunk = nil
|
||||||
|
case cmd[1]
|
||||||
when 'reall'
|
when 'reall'
|
||||||
if conversation_id.present?
|
if conversation_id.present?
|
||||||
mention_ids = Status.where(conversation_id: conversation_id).flat_map { |s| s.mentions.pluck(:account_id) }
|
mention_ids = Status.where(conversation_id: conversation_id).flat_map { |s| s.mentions.pluck(:account_id) }
|
||||||
mention_ids.uniq!
|
mention_ids.uniq!
|
||||||
mentions = Account.where(id: mention_ids).map { |a| "@#{a.username}" }
|
mentions = Account.where(id: mention_ids).map { |a| "@#{a.username}" }
|
||||||
chunks << mentions.join(' ')
|
chunk = mentions.join(' ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
when 'parent'
|
||||||
|
chunk = nil
|
||||||
|
next unless reply?
|
||||||
|
parent_status = Status.where(id: in_reply_to_id).first
|
||||||
|
next if parent_status.nil?
|
||||||
|
case cmd[1]
|
||||||
|
when 'edit'
|
||||||
|
next unless reply? && in_reply_to_account_id == account_id
|
||||||
|
when 'permalink'
|
||||||
|
chunk = TagManager.instance.url_for(parent_status)
|
||||||
|
end
|
||||||
|
when 'media'
|
||||||
|
chunk = nil
|
||||||
|
|
||||||
|
media_idx = cmd[1]
|
||||||
|
media_cmd = cmd[2]
|
||||||
|
media_args = cmd[3..-1]
|
||||||
|
|
||||||
|
next unless media_cmd.present? && media_idx.present? && media_idx.scan(/\D/).empty?
|
||||||
|
media_idx = media_idx.to_i
|
||||||
|
next if media_attachments[media_idx-1].nil?
|
||||||
|
|
||||||
|
case media_cmd
|
||||||
|
when 'desc'
|
||||||
|
if media_args.present?
|
||||||
|
vars["media_#{media_idx}_desc"] = media_args.join(':')
|
||||||
|
else
|
||||||
|
vore_stack.push("media_#{media_idx}_desc")
|
||||||
|
component_stack.push(:var)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post_cmds.push(['media', media_idx, media_cmd])
|
||||||
|
when 'bangtag'
|
||||||
|
chunk = chunk.sub('bangtag:', '').gsub(':', ":\u200c")
|
||||||
|
when 'join'
|
||||||
|
chunk = nil
|
||||||
|
next if cmd[1].nil?
|
||||||
|
charmap = {
|
||||||
|
'zws' => "\u200b",
|
||||||
|
'zwnj' => "\u200c",
|
||||||
|
'zwj' => "\u200d",
|
||||||
|
'\n' => "\n",
|
||||||
|
'\r' => "\r",
|
||||||
|
'\t' => "\t",
|
||||||
|
'\T' => ' '
|
||||||
|
}
|
||||||
|
sep = charmap[cmd[1]]
|
||||||
|
chunk = cmd[2..-1].join(sep.nil? ? cmd[1] : sep)
|
||||||
|
when 'hide'
|
||||||
|
chunk = nil
|
||||||
|
case cmd[1]
|
||||||
|
when 'end', 'stop', 'endall', 'stopall'
|
||||||
|
vore_stack.reject! {|v| v == '_'}
|
||||||
|
compontent_stack.reject! {|c| c == :hide}
|
||||||
|
else
|
||||||
|
if cmd[1].nil? && !'_'.in?(vore_stack)
|
||||||
|
vore_stack.push('_')
|
||||||
|
component_stack.push(:hide)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
when 'comment'
|
||||||
|
chunk = nil
|
||||||
|
if cmd[1].nil?
|
||||||
|
vore_stack.push('_comment')
|
||||||
|
component_stack.push(:var)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if chunk.present? && tf_cmds.present?
|
||||||
|
tf_cmds.each do |tf_cmd|
|
||||||
|
next if chunk.nil?
|
||||||
|
case tf_cmd[0]
|
||||||
|
when 'replace', 'sub', 's'
|
||||||
|
tf_cmd[1..-1].in_groups_of(2) do |args|
|
||||||
|
chunk.sub!(*args) if args.all?
|
||||||
|
end
|
||||||
|
when 'replaceall', 'gsub', 'gs'
|
||||||
|
tf_cmd[1..-1].in_groups_of(2) do |args|
|
||||||
|
chunk.gsub!(*args) if args.all?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
unless chunk.blank? || vore_stack.empty?
|
||||||
|
var = vore_stack.last
|
||||||
|
next if var == '_'
|
||||||
|
if vars[var].nil?
|
||||||
|
vars[var] = chunk.lstrip
|
||||||
else
|
else
|
||||||
chunks << chunk
|
vars[var] += chunk.rstrip
|
||||||
end
|
end
|
||||||
elsif tf_command.present?
|
chunk = nil
|
||||||
case tf_command[0]
|
end
|
||||||
when 'replace', 'sub', 's'
|
|
||||||
tf_command[1..-1].in_groups_of(2) do |args|
|
chunks << chunk unless chunk.nil?
|
||||||
if args.all?
|
end
|
||||||
chunks << chunk.sub(*args)
|
|
||||||
else
|
vars.transform_values! {|v| v.rstrip}
|
||||||
chunks << chunk
|
|
||||||
end
|
if post_cmds.present?
|
||||||
end
|
post_cmds.each do |post_cmd|
|
||||||
when 'replaceall', 'gsub', 'gs'
|
case post_cmd[0]
|
||||||
tf_command[1..-1].in_groups_of(2) do |args|
|
when 'media'
|
||||||
if args.all?
|
media_idx = post_cmd[1]
|
||||||
chunks << chunk.gsub(*args)
|
media_cmd = post_cmd[2]
|
||||||
else
|
media_args = post_cmd[3..-1]
|
||||||
chunks << chunk
|
|
||||||
end
|
case media_cmd
|
||||||
|
when 'desc'
|
||||||
|
media_attachments[media_idx-1].description = vars["media_#{media_idx}_desc"]
|
||||||
|
media_attachments[media_idx-1].save
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
chunks << chunk
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.text = chunks.join('')
|
self.text = chunks.join('')
|
||||||
update_column(:text, text)
|
save
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_conversation
|
def set_conversation
|
||||||
|
|
Loading…
Reference in New Issue