gearheads
/
mastodon
Archived
2
0
Fork 0

Change hashtags and mentions in bios to open in-app in web UI (#24643)

gh/dev
Eugen Rochko 2023-04-25 06:33:21 +02:00 committed by GitHub
parent e9a79d46cd
commit 8099ba04be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 9 deletions

View File

@ -135,8 +135,7 @@ export const showSearch = () => ({
type: SEARCH_SHOW, type: SEARCH_SHOW,
}); });
export const openURL = routerHistory => (dispatch, getState) => { export const openURL = (value, history, onFailure) => (dispatch, getState) => {
const value = getState().getIn(['search', 'value']);
const signedIn = !!getState().getIn(['meta', 'me']); const signedIn = !!getState().getIn(['meta', 'me']);
if (!signedIn) { 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 => { api(getState).get('/api/v2/search', { params: { q: value, resolve: true } }).then(response => {
if (response.data.accounts?.length > 0) { if (response.data.accounts?.length > 0) {
dispatch(importFetchedAccounts(response.data.accounts)); 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) { } else if (response.data.statuses?.length > 0) {
dispatch(importFetchedStatuses(response.data.statuses)); 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)); dispatch(fetchSearchSuccess(response.data, value));
}).catch(err => { }).catch(err => {
dispatch(fetchSearchFail(err)); dispatch(fetchSearchFail(err));
if (onFailure) {
onFailure();
}
}); });
}; };

View File

@ -80,6 +80,7 @@ class Header extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
identity: PropTypes.object, identity: PropTypes.object,
router: PropTypes.object,
}; };
static propTypes = { static propTypes = {
@ -101,11 +102,16 @@ class Header extends ImmutablePureComponent {
onChangeLanguages: PropTypes.func.isRequired, onChangeLanguages: PropTypes.func.isRequired,
onInteractionModal: PropTypes.func.isRequired, onInteractionModal: PropTypes.func.isRequired,
onOpenAvatar: PropTypes.func.isRequired, onOpenAvatar: PropTypes.func.isRequired,
onOpenURL: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
domain: PropTypes.string.isRequired, domain: PropTypes.string.isRequired,
hidden: PropTypes.bool, hidden: PropTypes.bool,
}; };
setRef = c => {
this.node = c;
};
openEditProfile = () => { openEditProfile = () => {
window.open('/settings/profile', '_blank'); 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 () { render () {
const { account, hidden, intl, domain } = this.props; const { account, hidden, intl, domain } = this.props;
const { signedIn, permissions } = this.context.identity; const { signedIn, permissions } = this.context.identity;
@ -360,7 +421,7 @@ class Header extends ImmutablePureComponent {
{!(suspended || hidden) && ( {!(suspended || hidden) && (
<div className='account__header__extra'> <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('id') !== me && signedIn) && <AccountNoteContainer account={account} />}
{account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />} {account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />}

View File

@ -26,6 +26,7 @@ export default class Header extends ImmutablePureComponent {
onChangeLanguages: PropTypes.func.isRequired, onChangeLanguages: PropTypes.func.isRequired,
onInteractionModal: PropTypes.func.isRequired, onInteractionModal: PropTypes.func.isRequired,
onOpenAvatar: PropTypes.func.isRequired, onOpenAvatar: PropTypes.func.isRequired,
onOpenURL: PropTypes.func.isRequired,
hideTabs: PropTypes.bool, hideTabs: PropTypes.bool,
domain: PropTypes.string.isRequired, domain: PropTypes.string.isRequired,
hidden: PropTypes.bool, hidden: PropTypes.bool,
@ -137,6 +138,7 @@ export default class Header extends ImmutablePureComponent {
onChangeLanguages={this.handleChangeLanguages} onChangeLanguages={this.handleChangeLanguages}
onInteractionModal={this.handleInteractionModal} onInteractionModal={this.handleInteractionModal}
onOpenAvatar={this.handleOpenAvatar} onOpenAvatar={this.handleOpenAvatar}
onOpenURL={this.props.onOpenURL}
domain={this.props.domain} domain={this.props.domain}
hidden={hidden} hidden={hidden}
/> />

View File

@ -10,6 +10,7 @@ import {
pinAccount, pinAccount,
unpinAccount, unpinAccount,
} from '../../../actions/accounts'; } from '../../../actions/accounts';
import { openURL } from 'mastodon/actions/search';
import { import {
mentionCompose, mentionCompose,
directCompose, 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)); export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Header));

View File

@ -161,9 +161,9 @@ class Search extends React.PureComponent {
handleURLClick = () => { handleURLClick = () => {
const { router } = this.context; const { router } = this.context;
const { onOpenURL } = this.props; const { value, onOpenURL } = this.props;
onOpenURL(router.history); onOpenURL(value, router.history);
}; };
handleStatusSearch = () => { handleStatusSearch = () => {

View File

@ -34,8 +34,8 @@ const mapDispatchToProps = dispatch => ({
dispatch(showSearch()); dispatch(showSearch());
}, },
onOpenURL (routerHistory) { onOpenURL (q, routerHistory) {
dispatch(openURL(routerHistory)); dispatch(openURL(q, routerHistory));
}, },
onClickSearchResult (q, type) { onClickSearchResult (q, type) {