Change hashtags and mentions in bios to open in-app in web UI (#24643)
This commit is contained in:
		
							parent
							
								
									e9a79d46cd
								
							
						
					
					
						commit
						8099ba04be
					
				| @ -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(); | ||||||
|  |     } | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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} />} | ||||||
|  | |||||||
| @ -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} | ||||||
|         /> |         /> | ||||||
|  | |||||||
| @ -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)); | ||||||
|  | |||||||
| @ -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 = () => { | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user