Change to treat the url to a post already owned as an internal link
This commit is contained in:
parent
ff063001d5
commit
bd183630a4
5 changed files with 73 additions and 2 deletions
|
@ -1,15 +1,20 @@
|
|||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import Permalink from './permalink';
|
||||
import classnames from 'classnames';
|
||||
import PollContainer from 'mastodon/containers/poll_container';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
import { autoPlayGif, show_reply_tree_button } from 'mastodon/initial_state';
|
||||
|
||||
const messages = defineMessages({
|
||||
postByAcct: { id: 'status.post_by_acct', defaultMessage: 'Post by @{acct}' },
|
||||
});
|
||||
|
||||
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
|
||||
|
||||
@injectIntl
|
||||
export default class StatusContent extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
|
@ -25,6 +30,7 @@ export default class StatusContent extends React.PureComponent {
|
|||
collapsable: PropTypes.bool,
|
||||
onCollapsedToggle: PropTypes.func,
|
||||
quote: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -58,6 +64,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('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);
|
||||
} else {
|
||||
link.setAttribute('title', link.href);
|
||||
link.classList.add('unhandled-link');
|
||||
|
@ -137,6 +146,13 @@ export default class StatusContent extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
onStatusUrlClick = (statusId, e) => {
|
||||
if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
this.context.router.history.push(`/statuses/${statusId}`);
|
||||
}
|
||||
}
|
||||
|
||||
onQuoteClick = (statusId, e) => {
|
||||
let statusUrl = `/statuses/${statusId}`;
|
||||
|
||||
|
|
|
@ -510,6 +510,7 @@
|
|||
"status.open": "Expand this post",
|
||||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned post",
|
||||
"status.post_by_acct": "Post by @{acct}",
|
||||
"status.quote": "Quote",
|
||||
"status.read_more": "Read more",
|
||||
"status.reblog": "Boost",
|
||||
|
|
|
@ -511,6 +511,7 @@
|
|||
"status.open": "詳細を表示",
|
||||
"status.pin": "プロフィールに固定表示",
|
||||
"status.pinned": "固定された投稿",
|
||||
"status.post_by_acct": "@{acct}による投稿",
|
||||
"status.quote": "引用",
|
||||
"status.read_more": "もっと見る",
|
||||
"status.reblog": "ブースト",
|
||||
|
|
|
@ -6,6 +6,7 @@ class EntityCache
|
|||
include Singleton
|
||||
|
||||
MAX_EXPIRATION = 7.days.freeze
|
||||
MIN_EXPIRATION = 60.seconds.freeze
|
||||
|
||||
def status(url)
|
||||
Rails.cache.fetch(to_key(:status, url), expires_in: MAX_EXPIRATION) { FetchRemoteStatusService.new.call(url) }
|
||||
|
@ -34,6 +35,26 @@ class EntityCache
|
|||
shortcodes.filter_map { |shortcode| cached[to_key(:emoji, shortcode, domain)] || uncached[shortcode] }
|
||||
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))
|
||||
|
||||
status = begin
|
||||
if ActivityPub::TagManager.instance.local_uri?(url)
|
||||
StatusFinder.new(url).status
|
||||
else
|
||||
Status.where(uri: url).or(Status.where(url: url)).first
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
nil
|
||||
end
|
||||
|
||||
account = status&.account
|
||||
|
||||
Rails.cache.write(to_key(:holding_status, url), [status, account], expires_in: account.nil? ? MIN_EXPIRATION : MAX_EXPIRATION)
|
||||
|
||||
[status, account]
|
||||
end
|
||||
|
||||
def to_key(type, *ids)
|
||||
"#{type}:#{ids.compact.map(&:downcase).join(':')}"
|
||||
end
|
||||
|
|
|
@ -26,6 +26,7 @@ class Formatter
|
|||
|
||||
unless status.local?
|
||||
html = reformat(raw_content)
|
||||
html = apply_inner_link(html)
|
||||
html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify]
|
||||
return html.html_safe # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
|
@ -52,7 +53,7 @@ class Formatter
|
|||
html.sub!(/^<p>(.+)<\/p>$/, '\1')
|
||||
html = Sanitize.clean(html).delete("\n").truncate(150)
|
||||
html = encode_custom_emojis(html, status.emojis) if options[:custom_emojify]
|
||||
html.html_safe
|
||||
html.html_safe # rubocop:disable Rails/OutputSafety
|
||||
end
|
||||
|
||||
def reformat(html)
|
||||
|
@ -248,11 +249,42 @@ class Formatter
|
|||
|
||||
html_attrs[:rel] = "me #{html_attrs[:rel]}" if options[:me]
|
||||
|
||||
status, account = url_to_holding_status_and_account(url.normalize.to_s)
|
||||
|
||||
if account.present?
|
||||
html_attrs[:class] = 'status-url-link'
|
||||
html_attrs[:'data-status-id'] = status.id
|
||||
html_attrs[:'data-status-account-acct'] = account.acct
|
||||
end
|
||||
|
||||
Twitter::TwitterText::Autolink.send(:link_to_text, entity, link_html(entity[:url]), url, html_attrs)
|
||||
rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError
|
||||
encode(entity[:url])
|
||||
end
|
||||
|
||||
def apply_inner_link(html)
|
||||
doc = Nokogiri::HTML.parse(html, nil, 'utf-8')
|
||||
doc.css('a').map do |x|
|
||||
status, account = url_to_holding_status_and_account(x['href'])
|
||||
|
||||
if account.present?
|
||||
x.add_class('status-url-link')
|
||||
x['data-status-id'] = status.id
|
||||
x['data-status-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_status_and_account(url)
|
||||
url = url.split('#').first
|
||||
|
||||
return if url.nil?
|
||||
|
||||
EntityCache.instance.holding_status_and_account(url)
|
||||
end
|
||||
|
||||
def link_to_mention(entity, linkable_accounts, options = {})
|
||||
acct = entity[:screen_name]
|
||||
|
||||
|
|
Loading…
Reference in a new issue