Change to treat the url to a account already owned as an internal link
This commit is contained in:
parent
dde6c4f845
commit
28b9828f06
5 changed files with 66 additions and 5 deletions
|
@ -9,6 +9,7 @@ import Icon from 'mastodon/components/icon';
|
|||
import { autoPlayGif, show_reply_tree_button } from 'mastodon/initial_state';
|
||||
|
||||
const messages = defineMessages({
|
||||
linkToAcct: { id: 'status.link_to_acct', defaultMessage: 'Link to @{acct}' },
|
||||
postByAcct: { id: 'status.post_by_acct', defaultMessage: 'Post by @{acct}' },
|
||||
});
|
||||
|
||||
|
@ -64,6 +65,9 @@ export default class StatusContent extends React.PureComponent {
|
|||
link.setAttribute('title', mention.get('acct'));
|
||||
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
||||
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
|
||||
} else if (link.classList.contains('account-url-link')) {
|
||||
link.setAttribute('title', this.props.intl.formatMessage(messages.linkToAcct, { acct: link.dataset.accountAcct }));
|
||||
link.addEventListener('click', this.onAccountUrlClick.bind(this, link.dataset.accountId, link.dataset.accountActorType), false);
|
||||
} else if (link.classList.contains('status-url-link')) {
|
||||
link.setAttribute('title', this.props.intl.formatMessage(messages.postByAcct, { acct: link.dataset.statusAccountAcct }));
|
||||
link.addEventListener('click', this.onStatusUrlClick.bind(this, link.dataset.statusId), false);
|
||||
|
@ -146,6 +150,13 @@ export default class StatusContent extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
onAccountUrlClick = (accountId, accountActorType, e) => {
|
||||
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
this.context.router.history.push(`${accountActorType == 'Group' ? '/timelines/groups/' : '/accounts/'}${accountId}`);
|
||||
}
|
||||
}
|
||||
|
||||
onStatusUrlClick = (statusId, e) => {
|
||||
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -500,6 +500,7 @@
|
|||
"status.emoji_reaction": "Emoji reaction",
|
||||
"status.favourite": "Favourite",
|
||||
"status.filtered": "Filtered",
|
||||
"status.link_to_acct": "Link to @{acct}",
|
||||
"status.load_more": "Load more",
|
||||
"status.media_hidden": "Media hidden",
|
||||
"status.mention": "Mention @{name}",
|
||||
|
|
|
@ -501,6 +501,7 @@
|
|||
"status.emoji_reaction": "絵文字リアクション",
|
||||
"status.favourite": "お気に入り",
|
||||
"status.filtered": "フィルターされました",
|
||||
"status.link_to_acct": "@{acct}へのリンク",
|
||||
"status.load_more": "もっと見る",
|
||||
"status.media_hidden": "非表示のメディア",
|
||||
"status.mention": "@{name}さんに投稿",
|
||||
|
|
|
@ -35,6 +35,30 @@ class EntityCache
|
|||
shortcodes.filter_map { |shortcode| cached[to_key(:emoji, shortcode, domain)] || uncached[shortcode] }
|
||||
end
|
||||
|
||||
def holding_account(url)
|
||||
return Rails.cache.read(to_key(:holding_account, url)) if Rails.cache.exist?(to_key(:holding_account, url))
|
||||
|
||||
account = begin
|
||||
if ActivityPub::TagManager.instance.local_uri?(url)
|
||||
recognized_params = Rails.application.routes.recognize_path(url)
|
||||
|
||||
return nil unless recognized_params[:action] == 'show'
|
||||
|
||||
if recognized_params[:controller] == 'accounts'
|
||||
Account.find_local(recognized_params[:username])
|
||||
end
|
||||
else
|
||||
Account.where(uri: url).or(Account.where(url: url)).first
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
nil
|
||||
end
|
||||
|
||||
Rails.cache.write(to_key(:holding_account, url), account, expires_in: account.nil? ? MIN_EXPIRATION : MAX_EXPIRATION)
|
||||
|
||||
account
|
||||
end
|
||||
|
||||
def holding_status_and_account(url)
|
||||
return Rails.cache.read(to_key(:holding_status, url)) if Rails.cache.exist?(to_key(:holding_status, url))
|
||||
|
||||
|
|
|
@ -243,6 +243,10 @@ class Formatter
|
|||
Extractor.remove_overlapping_entities(special + standard + extra)
|
||||
end
|
||||
|
||||
def class_append(c, items)
|
||||
(c || '').split.concat(items).uniq.join(' ')
|
||||
end
|
||||
|
||||
def link_to_url(entity, options = {})
|
||||
url = Addressable::URI.parse(entity[:url])
|
||||
html_attrs = { target: '_blank', rel: 'nofollow noopener noreferrer' }
|
||||
|
@ -250,11 +254,17 @@ class Formatter
|
|||
html_attrs[:rel] = "me #{html_attrs[:rel]}" if options[:me]
|
||||
|
||||
status, account = url_to_holding_status_and_account(url.normalize.to_s)
|
||||
account = url_to_holding_account(url.normalize.to_s) if status.nil?
|
||||
|
||||
if account.present?
|
||||
html_attrs[:class] = 'status-url-link'
|
||||
html_attrs[:'data-status-id'] = status.id
|
||||
if status.present? && account.present?
|
||||
html_attrs[:class] = class_append(html_attrs[:class], ['status-url-link'])
|
||||
html_attrs[:'data-status-id'] = status.id
|
||||
html_attrs[:'data-status-account-acct'] = account.acct
|
||||
elsif account.present?
|
||||
html_attrs[:class] = class_append(html_attrs[:class], ['account-url-link'])
|
||||
html_attrs[:'data-account-id'] = account.id
|
||||
html_attrs[:'data-account-actor-type'] = account.actor_type
|
||||
html_attrs[:'data-account-acct'] = account.acct
|
||||
end
|
||||
|
||||
Twitter::TwitterText::Autolink.send(:link_to_text, entity, link_html(entity[:url]), url, html_attrs)
|
||||
|
@ -266,17 +276,31 @@ class Formatter
|
|||
doc = Nokogiri::HTML.parse(html, nil, 'utf-8')
|
||||
doc.css('a').map do |x|
|
||||
status, account = url_to_holding_status_and_account(x['href'])
|
||||
account = url_to_holding_account(x['href']) if status.nil?
|
||||
|
||||
if account.present?
|
||||
if status.present? && account.present?
|
||||
x.add_class('status-url-link')
|
||||
x['data-status-id'] = status.id
|
||||
x['data-status-id'] = status.id
|
||||
x['data-status-account-acct'] = account.acct
|
||||
elsif account.present?
|
||||
x.add_class('account-url-link')
|
||||
x['data-account-id'] = account.id
|
||||
x['data-account-actor-type'] = account.actor_type
|
||||
x['data-account-acct'] = account.acct
|
||||
end
|
||||
end
|
||||
html = doc.css('body')[0]&.inner_html || ''
|
||||
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
|
||||
def url_to_holding_account(url)
|
||||
url = url.split('#').first
|
||||
|
||||
return if url.nil?
|
||||
|
||||
EntityCache.instance.holding_account(url)
|
||||
end
|
||||
|
||||
def url_to_holding_status_and_account(url)
|
||||
url = url.split('#').first
|
||||
|
||||
|
|
Loading…
Reference in a new issue