Change hashtags and mentions in bios to open in-app in web UI (#24643)
parent
24d5626e02
commit
49493f8b50
|
@ -135,8 +135,7 @@ export const showSearch = () => ({
|
|||
type: SEARCH_SHOW,
|
||||
});
|
||||
|
||||
export const openURL = routerHistory => (dispatch, getState) => {
|
||||
const value = getState().getIn(['search', 'value']);
|
||||
export const openURL = (value, history, onFailure) => (dispatch, getState) => {
|
||||
const signedIn = !!getState().getIn(['meta', 'me']);
|
||||
|
||||
if (!signedIn) {
|
||||
|
@ -148,15 +147,21 @@ export const openURL = routerHistory => (dispatch, getState) => {
|
|||
api(getState).get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => {
|
||||
if (response.data.accounts?.length > 0) {
|
||||
dispatch(importFetchedAccounts(response.data.accounts));
|
||||
routerHistory.push(`/@${response.data.accounts[0].acct}`);
|
||||
history.push(`/@${response.data.accounts[0].acct}`);
|
||||
} else if (response.data.statuses?.length > 0) {
|
||||
dispatch(importFetchedStatuses(response.data.statuses));
|
||||
routerHistory.push(`/@${response.data.statuses[0].account.acct}/${response.data.statuses[0].id}`);
|
||||
history.push(`/@${response.data.statuses[0].account.acct}/${response.data.statuses[0].id}`);
|
||||
} else if (onFailure) {
|
||||
onFailure();
|
||||
}
|
||||
|
||||
dispatch(fetchSearchSuccess(response.data, value));
|
||||
}).catch(err => {
|
||||
dispatch(fetchSearchFail(err));
|
||||
|
||||
if (onFailure) {
|
||||
onFailure();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
|
@ -101,11 +102,16 @@ class Header extends ImmutablePureComponent {
|
|||
onChangeLanguages: PropTypes.func.isRequired,
|
||||
onInteractionModal: PropTypes.func.isRequired,
|
||||
onOpenAvatar: PropTypes.func.isRequired,
|
||||
onOpenURL: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
domain: PropTypes.string.isRequired,
|
||||
hidden: PropTypes.bool,
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
};
|
||||
|
||||
openEditProfile = () => {
|
||||
window.open('/settings/profile', '_blank');
|
||||
};
|
||||
|
@ -162,6 +168,61 @@ class Header extends ImmutablePureComponent {
|
|||
});
|
||||
};
|
||||
|
||||
handleHashtagClick = e => {
|
||||
const { router } = this.context;
|
||||
const value = e.currentTarget.textContent.replace(/^#/, '');
|
||||
|
||||
if (router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
router.history.push(`/tags/${value}`);
|
||||
}
|
||||
};
|
||||
|
||||
handleMentionClick = e => {
|
||||
const { router } = this.context;
|
||||
const { onOpenURL } = this.props;
|
||||
|
||||
if (router && e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
|
||||
const link = e.currentTarget;
|
||||
|
||||
onOpenURL(link.href, router.history, () => {
|
||||
window.location = link.href;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
_attachLinkEvents () {
|
||||
const node = this.node;
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
const links = node.querySelectorAll('a');
|
||||
|
||||
let link;
|
||||
|
||||
for (var i = 0; i < links.length; ++i) {
|
||||
link = links[i];
|
||||
|
||||
if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
||||
link.addEventListener('click', this.handleHashtagClick, false);
|
||||
} else if (link.classList.contains('mention')) {
|
||||
link.addEventListener('click', this.handleMentionClick, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this._attachLinkEvents();
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._attachLinkEvents();
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, hidden, intl, domain } = this.props;
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
|
@ -360,7 +421,7 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
{!(suspended || hidden) && (
|
||||
<div className='account__header__extra'>
|
||||
<div className='account__header__bio'>
|
||||
<div className='account__header__bio' ref={this.setRef}>
|
||||
{(account.get('id') !== me && signedIn) && <AccountNoteContainer account={account} />}
|
||||
|
||||
{account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />}
|
||||
|
|
|
@ -26,6 +26,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
onChangeLanguages: PropTypes.func.isRequired,
|
||||
onInteractionModal: PropTypes.func.isRequired,
|
||||
onOpenAvatar: PropTypes.func.isRequired,
|
||||
onOpenURL: PropTypes.func.isRequired,
|
||||
hideTabs: PropTypes.bool,
|
||||
domain: PropTypes.string.isRequired,
|
||||
hidden: PropTypes.bool,
|
||||
|
@ -137,6 +138,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
onChangeLanguages={this.handleChangeLanguages}
|
||||
onInteractionModal={this.handleInteractionModal}
|
||||
onOpenAvatar={this.handleOpenAvatar}
|
||||
onOpenURL={this.props.onOpenURL}
|
||||
domain={this.props.domain}
|
||||
hidden={hidden}
|
||||
/>
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
pinAccount,
|
||||
unpinAccount,
|
||||
} from '../../../actions/accounts';
|
||||
import { openURL } from 'mastodon/actions/search';
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
|
@ -159,6 +160,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}));
|
||||
},
|
||||
|
||||
onOpenURL (url, routerHistory, onFailure) {
|
||||
dispatch(openURL(url, routerHistory, onFailure));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));
|
||||
|
|
|
@ -161,9 +161,9 @@ class Search extends React.PureComponent {
|
|||
|
||||
handleURLClick = () => {
|
||||
const { router } = this.context;
|
||||
const { onOpenURL } = this.props;
|
||||
const { value, onOpenURL } = this.props;
|
||||
|
||||
onOpenURL(router.history);
|
||||
onOpenURL(value, router.history);
|
||||
};
|
||||
|
||||
handleStatusSearch = () => {
|
||||
|
|
|
@ -34,8 +34,8 @@ const mapDispatchToProps = dispatch => ({
|
|||
dispatch(showSearch());
|
||||
},
|
||||
|
||||
onOpenURL (routerHistory) {
|
||||
dispatch(openURL(routerHistory));
|
||||
onOpenURL (q, routerHistory) {
|
||||
dispatch(openURL(q, routerHistory));
|
||||
},
|
||||
|
||||
onClickSearchResult (q, type) {
|
||||
|
|
Loading…
Reference in New Issue