diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index fd5ea60407ea6d..c50fd866424522 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -19,6 +19,7 @@ import Button from './button'; import { FollowersCounter } from './counters'; import { DisplayName } from './display_name'; import { IconButton } from './icon_button'; +import Permalink from './permalink'; import { RelativeTimestamp } from './relative_timestamp'; const messages = defineMessages({ @@ -151,7 +152,7 @@ class Account extends ImmutablePureComponent { return (
- +
@@ -164,7 +165,7 @@ class Account extends ImmutablePureComponent {
)}
- + {!minimal && (
diff --git a/app/javascript/mastodon/components/hashtag.jsx b/app/javascript/mastodon/components/hashtag.jsx index 14bb4ddc64c8f1..4c2b622c91c3a8 100644 --- a/app/javascript/mastodon/components/hashtag.jsx +++ b/app/javascript/mastodon/components/hashtag.jsx @@ -5,7 +5,7 @@ import { Component } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -14,6 +14,8 @@ import { Sparklines, SparklinesCurve } from 'react-sparklines'; import { ShortNumber } from 'mastodon/components/short_number'; import { Skeleton } from 'mastodon/components/skeleton'; +import Permalink from './permalink'; + class SilentErrorBoundary extends Component { static propTypes = { @@ -58,6 +60,7 @@ export const accountsCountRenderer = (displayNumber, pluralReady) => ( export const ImmutableHashtag = ({ hashtag }) => ( ( +const Hashtag = ({ name, href, to, people, uses, history, className, description, withGraph }) => (
- + {name ? <>#{name} : } - + {description ? ( {description} @@ -104,6 +107,7 @@ const Hashtag = ({ name, to, people, uses, history, className, description, with Hashtag.propTypes = { name: PropTypes.string, + href: PropTypes.string, to: PropTypes.string, people: PropTypes.number, description: PropTypes.node, diff --git a/app/javascript/mastodon/components/permalink.jsx b/app/javascript/mastodon/components/permalink.jsx new file mode 100644 index 00000000000000..7bd0f61e4cca6a --- /dev/null +++ b/app/javascript/mastodon/components/permalink.jsx @@ -0,0 +1,40 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +export default class Permalink extends React.PureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + className: PropTypes.string, + href: PropTypes.string.isRequired, + to: PropTypes.string.isRequired, + children: PropTypes.node, + onInterceptClick: PropTypes.func, + }; + + handleClick = e => { + if (this.props.onInterceptClick && this.props.onInterceptClick()) { + e.preventDefault(); + return; + } + + if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { + e.preventDefault(); + this.context.router.history.push(this.props.to); + } + } + + render () { + const { href, children, className, onInterceptClick, ...other } = this.props; + + return ( + + {children} + + ); + } + +} diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 4a5ad54a1c99bc..dd4f37ee4b879f 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -417,7 +417,7 @@ class Status extends ImmutablePureComponent { prepend = (
- }} /> + }} />
); @@ -438,7 +438,7 @@ class Status extends ImmutablePureComponent { prepend = (
- }} /> + }} />
); } @@ -558,12 +558,12 @@ class Status extends ImmutablePureComponent { {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
- + {status.get('edited_at') && *} - +
{statusAvatar}
diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index d3bbc1ba023e3f..659e086ff141f7 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -4,7 +4,7 @@ import { PureComponent } from 'react'; import { FormattedMessage, injectIntl } from 'react-intl'; import classnames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; import { connect } from 'react-redux'; @@ -13,6 +13,8 @@ import { Icon } from 'mastodon/components/icon'; import PollContainer from 'mastodon/containers/poll_container'; import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state'; +import Permalink from './permalink'; + const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top) /** @@ -270,9 +272,9 @@ class StatusContent extends PureComponent { let mentionsPlaceholder = ''; const mentionLinks = status.get('mentions').map(item => ( - + @{item.get('username')} - + )).reduce((aggregate, item) => [...aggregate, item, ' '], []); const toggleText = hidden ? : ; diff --git a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx index 2c996ff769d4d0..44e4485e347206 100644 --- a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx +++ b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx @@ -1,12 +1,12 @@ import { FormattedMessage } from 'react-intl'; -import { Link } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { AvatarOverlay } from '../../../components/avatar_overlay'; import { DisplayName } from '../../../components/display_name'; +import Permalink from '../../../components/permalink'; export default class MovedNote extends ImmutablePureComponent { @@ -25,12 +25,12 @@ export default class MovedNote extends ImmutablePureComponent {
- +
- +
- +
); diff --git a/app/javascript/mastodon/features/compose/components/navigation_bar.jsx b/app/javascript/mastodon/features/compose/components/navigation_bar.jsx index 5af38da43cf4f0..6241f96ca36cd4 100644 --- a/app/javascript/mastodon/features/compose/components/navigation_bar.jsx +++ b/app/javascript/mastodon/features/compose/components/navigation_bar.jsx @@ -2,12 +2,12 @@ import PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; -import { Link } from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { Avatar } from '../../../components/avatar'; +import Permalink from '../../../components/permalink'; import ActionBar from './action_bar'; @@ -23,16 +23,16 @@ export default class NavigationBar extends ImmutablePureComponent { const username = this.props.account.get('acct') return (
- + {username} - +
- + @{username} - + diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx index bf0a9da95aad91..4233cc8daa83f8 100644 --- a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx +++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -13,6 +13,7 @@ import { HotKeys } from 'react-hotkeys'; import AttachmentList from 'mastodon/components/attachment_list'; import AvatarComposite from 'mastodon/components/avatar_composite'; import { IconButton } from 'mastodon/components/icon_button'; +import Permalink from 'mastodon/components/permalink'; import { RelativeTimestamp } from 'mastodon/components/relative_timestamp'; import StatusContent from 'mastodon/components/status_content'; import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container'; @@ -136,7 +137,7 @@ class Conversation extends ImmutablePureComponent { menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDelete }); - const names = accounts.map(a => ).reduce((prev, cur) => [prev, ', ', cur]); + const names = accounts.map(a => ).reduce((prev, cur) => [prev, ', ', cur]); const handlers = { reply: this.handleReply, diff --git a/app/javascript/mastodon/features/directory/components/account_card.jsx b/app/javascript/mastodon/features/directory/components/account_card.jsx index 0306b63d322077..b0520ca3369e5e 100644 --- a/app/javascript/mastodon/features/directory/components/account_card.jsx +++ b/app/javascript/mastodon/features/directory/components/account_card.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -19,6 +19,7 @@ import { openModal } from 'mastodon/actions/modal'; import { Avatar } from 'mastodon/components/avatar'; import Button from 'mastodon/components/button'; import { DisplayName } from 'mastodon/components/display_name'; +import Permalink from 'mastodon/components/permalink'; import { ShortNumber } from 'mastodon/components/short_number'; import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state'; import { makeGetAccount } from 'mastodon/selectors'; @@ -174,7 +175,7 @@ class AccountCard extends ImmutablePureComponent { return (
- +
- + {account.get('note').length > 0 && (
- +
- +
diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx index 43c5e85cef8618..509e48b80cdcd7 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.jsx +++ b/app/javascript/mastodon/features/notifications/components/notification.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'; import classNames from 'classnames'; -import { Link } from 'react-router-dom'; + import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -11,6 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import { HotKeys } from 'react-hotkeys'; import { Icon } from 'mastodon/components/icon'; +import Permalink from 'mastodon/components/permalink'; import AccountContainer from 'mastodon/containers/account_container'; import StatusContainer from 'mastodon/containers/status_container'; import { me } from 'mastodon/initial_state'; @@ -398,7 +399,7 @@ class Notification extends ImmutablePureComponent { const targetAccount = report.get('target_account'); const targetDisplayNameHtml = { __html: targetAccount.get('display_name_html') }; - const targetLink = ; + const targetLink = ; return ( @@ -423,7 +424,7 @@ class Notification extends ImmutablePureComponent { const { notification } = this.props; const account = notification.get('account'); const displayNameHtml = { __html: account.get('display_name_html') }; - const link = ; + const link = ; switch(notification.get('type')) { case 'follow': diff --git a/app/javascript/mastodon/features/ui/components/header.jsx b/app/javascript/mastodon/features/ui/components/header.jsx index 68484b59ab0f5e..3a6b7e30c76b0a 100644 --- a/app/javascript/mastodon/features/ui/components/header.jsx +++ b/app/javascript/mastodon/features/ui/components/header.jsx @@ -5,6 +5,7 @@ import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { Link, withRouter } from 'react-router-dom'; + import { connect } from 'react-redux'; import { openModal } from 'mastodon/actions/modal'; @@ -12,14 +13,15 @@ import { fetchServer } from 'mastodon/actions/server'; import { Avatar } from 'mastodon/components/avatar'; import { Icon } from 'mastodon/components/icon'; import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo'; +import Permalink from 'mastodon/components/permalink'; import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state'; const Account = connect(state => ({ account: state.getIn(['accounts', me]), }))(({ account }) => ( - + - + )); const messages = defineMessages({