0
0
Fork 0

Custom emoji (#4988)

* Custom emoji

- In OStatus: `<link rel="emoji" name="coolcat" href="http://..." />`
- In ActivityPub: `{ type: "Emoji", name: ":coolcat:", href: "http://..." }`
- In REST API: Status object includes `emojis` array (`shortcode`, `url`)
- Domain blocks with reject media stop emojis
- Emoji file up to 50KB
- Web UI handles custom emojis
- Static pages render custom emojis as `<img />` tags

Side effects:

- Undo #4500 optimization, as I needed to modify it to restore
  shortcode handling in emojify()
- Formatter#plaintext should now make sure stripped out line-breaks
  and paragraphs are replaced with newlines

* Fix emoji at the start not being converted
This commit is contained in:
Eugen Rochko 2017-09-19 02:42:40 +02:00 committed by GitHub
parent c155d843f4
commit 81cec35dbf
20 changed files with 382 additions and 31 deletions

View file

@ -9,7 +9,7 @@ class Formatter
include ActionView::Helpers::TextHelper
def format(status)
def format(status, options = {})
if status.reblog?
prepend_reblog = status.reblog.account.acct
status = status.proper
@ -19,7 +19,11 @@ class Formatter
raw_content = status.text
return reformat(raw_content) unless status.local?
unless status.local?
html = reformat(raw_content)
html = encode_custom_emojis(html, status.emojis) if options[:custom_emojify]
return html
end
linkable_accounts = status.mentions.map(&:account)
linkable_accounts << status.account
@ -27,6 +31,7 @@ class Formatter
html = raw_content
html = "RT @#{prepend_reblog} #{html}" if prepend_reblog
html = encode_and_link_urls(html, linkable_accounts)
html = encode_custom_emojis(html, status.emojis) if options[:custom_emojify]
html = simple_format(html, {}, sanitize: false)
html = html.delete("\n")
@ -39,7 +44,9 @@ class Formatter
def plaintext(status)
return status.text if status.local?
strip_tags(status.text)
text = status.text.gsub(/(<br \/>|<br>|<\/p>)+/) { |match| "#{match}\n" }
strip_tags(text)
end
def simplified_format(account)
@ -76,6 +83,47 @@ class Formatter
end
end
def encode_custom_emojis(html, emojis)
return html if emojis.empty?
emoji_map = emojis.map { |e| [e.shortcode, full_asset_url(e.image.url)] }.to_h
i = -1
inside_tag = false
inside_shortname = false
shortname_start_index = -1
while i + 1 < html.size
i += 1
if inside_shortname && html[i] == ':'
shortcode = html[shortname_start_index + 1..i - 1]
emoji = emoji_map[shortcode]
if emoji
replacement = "<img draggable=\"false\" class=\"emojione\" alt=\":#{shortcode}:\" title=\":#{shortcode}:\" src=\"#{emoji}\" />"
before_html = shortname_start_index.positive? ? html[0..shortname_start_index - 1] : ''
html = before_html + replacement + html[i + 1..-1]
i += replacement.size - (shortcode.size + 2) - 1
else
i -= 1
end
inside_shortname = false
elsif inside_tag && html[i] == '>'
inside_tag = false
elsif html[i] == '<'
inside_tag = true
inside_shortname = false
elsif !inside_tag && html[i] == ':'
inside_shortname = true
shortname_start_index = i
end
end
html
end
def rewrite(text, entities)
chars = text.to_s.to_char_a