forked from cybrespace/mastodon
Enable custom emojis in profiles (notes, field values, display names) (#7374)
Follow-up to #6124
This commit is contained in:
parent
bd10a7e480
commit
61a9018607
|
@ -4,8 +4,8 @@ module StreamEntriesHelper
|
||||||
EMBEDDED_CONTROLLER = 'statuses'
|
EMBEDDED_CONTROLLER = 'statuses'
|
||||||
EMBEDDED_ACTION = 'embed'
|
EMBEDDED_ACTION = 'embed'
|
||||||
|
|
||||||
def display_name(account)
|
def display_name(account, **options)
|
||||||
account.display_name.presence || account.username
|
Formatter.instance.format_display_name(account, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_description(account)
|
def account_description(account)
|
||||||
|
|
|
@ -3,18 +3,25 @@ import emojify from '../../features/emoji/emoji';
|
||||||
|
|
||||||
const domParser = new DOMParser();
|
const domParser = new DOMParser();
|
||||||
|
|
||||||
|
const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => {
|
||||||
|
obj[`:${emoji.shortcode}:`] = emoji;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
export function normalizeAccount(account) {
|
export function normalizeAccount(account) {
|
||||||
account = { ...account };
|
account = { ...account };
|
||||||
|
|
||||||
|
const emojiMap = makeEmojiMap(account);
|
||||||
const displayName = account.display_name.length === 0 ? account.username : account.display_name;
|
const displayName = account.display_name.length === 0 ? account.username : account.display_name;
|
||||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName));
|
|
||||||
account.note_emojified = emojify(account.note);
|
account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap);
|
||||||
|
account.note_emojified = emojify(account.note, emojiMap);
|
||||||
|
|
||||||
if (account.fields) {
|
if (account.fields) {
|
||||||
account.fields = account.fields.map(pair => ({
|
account.fields = account.fields.map(pair => ({
|
||||||
...pair,
|
...pair,
|
||||||
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
name_emojified: emojify(escapeTextContentForBrowser(pair.name)),
|
||||||
value_emojified: emojify(pair.value),
|
value_emojified: emojify(pair.value, emojiMap),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +49,7 @@ export function normalizeStatus(status, normalOldStatus) {
|
||||||
normalStatus.hidden = normalOldStatus.get('hidden');
|
normalStatus.hidden = normalOldStatus.get('hidden');
|
||||||
} else {
|
} else {
|
||||||
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n');
|
||||||
|
const emojiMap = makeEmojiMap(normalStatus);
|
||||||
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => {
|
|
||||||
obj[`:${emoji.shortcode}:`] = emoji;
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
|
||||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||||
|
|
|
@ -67,9 +67,17 @@ class Formatter
|
||||||
html.html_safe # rubocop:disable Rails/OutputSafety
|
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||||
end
|
end
|
||||||
|
|
||||||
def format_field(account, str)
|
def format_display_name(account, **options)
|
||||||
|
html = encode(account.display_name.presence || account.username)
|
||||||
|
html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify]
|
||||||
|
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||||
|
end
|
||||||
|
|
||||||
|
def format_field(account, str, **options)
|
||||||
return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety
|
return reformat(str).html_safe unless account.local? # rubocop:disable Rails/OutputSafety
|
||||||
encode_and_link_urls(str, me: true).html_safe # rubocop:disable Rails/OutputSafety
|
html = encode_and_link_urls(str, me: true)
|
||||||
|
html = encode_custom_emojis(html, account.emojis) if options[:custom_emojify]
|
||||||
|
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||||
end
|
end
|
||||||
|
|
||||||
def linkify(text)
|
def linkify(text)
|
||||||
|
|
|
@ -398,7 +398,7 @@ class Account < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def emojis
|
def emojis
|
||||||
@emojis ||= CustomEmoji.from_text(note, domain)
|
@emojis ||= CustomEmoji.from_text(emojifiable_text, domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
before_create :generate_keys
|
before_create :generate_keys
|
||||||
|
@ -425,4 +425,8 @@ class Account < ApplicationRecord
|
||||||
|
|
||||||
self.domain = TagManager.instance.normalize_domain(domain)
|
self.domain = TagManager.instance.normalize_domain(domain)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def emojifiable_text
|
||||||
|
[note, display_name, fields.map(&:value)].join(' ')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
||||||
:followers_count, :following_count, :statuses_count
|
:followers_count, :following_count, :statuses_count
|
||||||
|
|
||||||
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
||||||
|
has_many :emojis, serializer: REST::CustomEmojiSerializer
|
||||||
|
|
||||||
class FieldSerializer < ActiveModel::Serializer
|
class FieldSerializer < ActiveModel::Serializer
|
||||||
attributes :name, :value
|
attributes :name, :value
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
.account__avatar{ style: "background-image: url(#{@instance_presenter.contact_account.avatar.url})" }
|
.account__avatar{ style: "background-image: url(#{@instance_presenter.contact_account.avatar.url})" }
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%bdi
|
%bdi
|
||||||
%strong.display-name__html.emojify= display_name(@instance_presenter.contact_account)
|
%strong.display-name__html.emojify= display_name(@instance_presenter.contact_account, custom_emojify: true)
|
||||||
%span.display-name__account @#{@instance_presenter.contact_account.acct}
|
%span.display-name__account @#{@instance_presenter.contact_account.acct}
|
||||||
- else
|
- else
|
||||||
.account__display-name
|
.account__display-name
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
.avatar= image_tag contact.contact_account.avatar.url
|
.avatar= image_tag contact.contact_account.avatar.url
|
||||||
.name
|
.name
|
||||||
= link_to TagManager.instance.url_for(contact.contact_account) do
|
= link_to TagManager.instance.url_for(contact.contact_account) do
|
||||||
%span.display_name.emojify= display_name(contact.contact_account)
|
%span.display_name.emojify= display_name(contact.contact_account, custom_emojify: true)
|
||||||
%span.username @#{contact.contact_account.acct}
|
%span.username @#{contact.contact_account.acct}
|
||||||
- else
|
- else
|
||||||
.owner
|
.owner
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
.avatar= image_tag account.avatar.url(:original)
|
.avatar= image_tag account.avatar.url(:original)
|
||||||
.name
|
.name
|
||||||
= link_to TagManager.instance.url_for(account) do
|
= link_to TagManager.instance.url_for(account) do
|
||||||
%span.display_name.emojify= display_name(account)
|
%span.display_name.emojify= display_name(account, custom_emojify: true)
|
||||||
%span.username
|
%span.username
|
||||||
@#{account.local? ? account.local_username_and_domain : account.acct}
|
@#{account.local? ? account.local_username_and_domain : account.acct}
|
||||||
= fa_icon('lock') if account.locked?
|
= fa_icon('lock') if account.locked?
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
.card__bio
|
.card__bio
|
||||||
%h1.name
|
%h1.name
|
||||||
%span.p-name.emojify= display_name(account)
|
%span.p-name.emojify= display_name(account, custom_emojify: true)
|
||||||
%small<
|
%small<
|
||||||
%span>< @#{account.local_username_and_domain}
|
%span>< @#{account.local_username_and_domain}
|
||||||
= fa_icon('lock') if account.locked?
|
= fa_icon('lock') if account.locked?
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
- account.fields.each do |field|
|
- account.fields.each do |field|
|
||||||
%dl
|
%dl
|
||||||
%dt.emojify{ title: field.name }= field.name
|
%dt.emojify{ title: field.name }= field.name
|
||||||
%dd.emojify{ title: field.value }= Formatter.instance.format_field(account, field.value)
|
%dd.emojify{ title: field.value }= Formatter.instance.format_field(account, field.value, custom_emojify: true)
|
||||||
|
|
||||||
.details-counters
|
.details-counters
|
||||||
.counter{ class: active_nav_class(short_account_url(account)) }
|
.counter{ class: active_nav_class(short_account_url(account)) }
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
.moved-strip
|
.moved-strip
|
||||||
.moved-strip__message
|
.moved-strip__message
|
||||||
= fa_icon 'suitcase'
|
= fa_icon 'suitcase'
|
||||||
= t('accounts.moved_html', name: content_tag(:strong, display_name(account), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
|
= t('accounts.moved_html', name: content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
|
||||||
|
|
||||||
.moved-strip__card
|
.moved-strip__card
|
||||||
= link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
= link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
||||||
|
@ -13,5 +13,5 @@
|
||||||
.account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" }
|
.account__avatar-overlay-overlay{ style: "background-image: url('#{account.avatar.url(:original)}')" }
|
||||||
|
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%strong.emojify= display_name(moved_to_account)
|
%strong.emojify= display_name(moved_to_account, custom_emojify: true)
|
||||||
%span @#{moved_to_account.acct}
|
%span @#{moved_to_account.acct}
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
.account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" }
|
.account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" }
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%bdi
|
%bdi
|
||||||
%strong.display-name__html.emojify= display_name(account)
|
%strong.display-name__html.emojify= display_name(account, custom_emojify: true)
|
||||||
%span.display-name__account @#{account.acct}
|
%span.display-name__account @#{account.acct}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
%span.display-name
|
%span.display-name
|
||||||
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
|
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
|
||||||
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
||||||
%strong.emojify= display_name(account)
|
%strong.emojify= display_name(account, custom_emojify: true)
|
||||||
%span @#{account.acct}
|
%span @#{account.acct}
|
||||||
|
|
||||||
- if account.note?
|
- if account.note?
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
%span.display-name
|
%span.display-name
|
||||||
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
|
- account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account)
|
||||||
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
= link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
|
||||||
%strong.emojify= display_name(account)
|
%strong.emojify= display_name(account, custom_emojify: true)
|
||||||
%span @#{account.acct}
|
%span @#{account.acct}
|
||||||
|
|
||||||
- if account.note?
|
- if account.note?
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
= image_tag asset_pack_path('logo.svg'), class: 'logo'
|
= image_tag asset_pack_path('logo.svg'), class: 'logo'
|
||||||
|
|
||||||
%div
|
%div
|
||||||
= t('landing_strip_html', name: content_tag(:span, display_name(account), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path))
|
= t('landing_strip_html', name: content_tag(:span, display_name(account, custom_emojify: true), class: :emojify), link_to_root_path: link_to(content_tag(:strong, site_hostname), root_path))
|
||||||
|
|
||||||
- if open_registrations?
|
- if open_registrations?
|
||||||
= t('landing_strip_signup_html', sign_up_path: new_user_registration_path)
|
= t('landing_strip_signup_html', sign_up_path: new_user_registration_path)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
.avatar
|
.avatar
|
||||||
= image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo'
|
= image_tag status.account.avatar.url(:original), width: 48, height: 48, alt: '', class: 'u-photo'
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%strong.p-name.emojify= display_name(status.account)
|
%strong.p-name.emojify= display_name(status.account, custom_emojify: true)
|
||||||
%span= acct(status.account)
|
%span= acct(status.account)
|
||||||
|
|
||||||
- if embedded_view?
|
- if embedded_view?
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
%div
|
%div
|
||||||
= image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo'
|
= image_tag status.account.avatar(:original), width: 48, height: 48, alt: '', class: 'u-photo'
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%strong.p-name.emojify= display_name(status.account)
|
%strong.p-name.emojify= display_name(status.account, custom_emojify: true)
|
||||||
%span= acct(status.account)
|
%span= acct(status.account)
|
||||||
|
|
||||||
.status__content.p-name.emojify<
|
.status__content.p-name.emojify<
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
= fa_icon('retweet fw')
|
= fa_icon('retweet fw')
|
||||||
%span
|
%span
|
||||||
= link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
|
= link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do
|
||||||
%strong.emojify= display_name(status.account)
|
%strong.emojify= display_name(status.account, custom_emojify: true)
|
||||||
= t('stream_entries.reblogged')
|
= t('stream_entries.reblogged')
|
||||||
- elsif pinned
|
- elsif pinned
|
||||||
.pre-header
|
.pre-header
|
||||||
|
|
Loading…
Reference in New Issue