diff options
Diffstat (limited to 'app/javascript/mastodon/components/status_content.js')
-rw-r--r-- | app/javascript/mastodon/components/status_content.js | 304 |
1 files changed, 0 insertions, 304 deletions
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js deleted file mode 100644 index 6f3093d63..000000000 --- a/app/javascript/mastodon/components/status_content.js +++ /dev/null @@ -1,304 +0,0 @@ -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import PropTypes from 'prop-types'; -import { FormattedMessage, injectIntl } from 'react-intl'; -import { Link } from 'react-router-dom'; -import classnames from 'classnames'; -import PollContainer from 'mastodon/containers/poll_container'; -import Icon from 'mastodon/components/icon'; -import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'mastodon/initial_state'; - -const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top) - -class TranslateButton extends React.PureComponent { - - static propTypes = { - translation: ImmutablePropTypes.map, - onClick: PropTypes.func, - }; - - render () { - const { translation, onClick } = this.props; - - if (translation) { - const language = preloadedLanguages.find(lang => lang[0] === translation.get('detected_source_language')); - const languageName = language ? language[2] : translation.get('detected_source_language'); - const provider = translation.get('provider'); - - return ( - <div className='translate-button'> - <div className='translate-button__meta'> - <FormattedMessage id='status.translated_from_with' defaultMessage='Translated from {lang} using {provider}' values={{ lang: languageName, provider }} /> - </div> - - <button className='link-button' onClick={onClick}> - <FormattedMessage id='status.show_original' defaultMessage='Show original' /> - </button> - </div> - ); - } - - return ( - <button className='status__content__read-more-button' onClick={onClick}> - <FormattedMessage id='status.translate' defaultMessage='Translate' /> - </button> - ); - } - -} - -export default @injectIntl -class StatusContent extends React.PureComponent { - - static contextTypes = { - router: PropTypes.object, - identity: PropTypes.object, - }; - - static propTypes = { - status: ImmutablePropTypes.map.isRequired, - expanded: PropTypes.bool, - onExpandedToggle: PropTypes.func, - onTranslate: PropTypes.func, - onClick: PropTypes.func, - collapsable: PropTypes.bool, - onCollapsedToggle: PropTypes.func, - intl: PropTypes.object, - }; - - state = { - hidden: true, - }; - - _updateStatusLinks () { - const node = this.node; - - if (!node) { - return; - } - - const { status, onCollapsedToggle } = this.props; - const links = node.querySelectorAll('a'); - - let link, mention; - - for (var i = 0; i < links.length; ++i) { - link = links[i]; - - if (link.classList.contains('status-link')) { - continue; - } - - link.classList.add('status-link'); - - mention = this.props.status.get('mentions').find(item => link.href === item.get('url')); - - if (mention) { - link.addEventListener('click', this.onMentionClick.bind(this, mention), false); - link.setAttribute('title', mention.get('acct')); - link.setAttribute('href', `/@${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); - link.setAttribute('href', `/tags/${link.text.slice(1)}`); - } else { - link.setAttribute('title', link.href); - link.classList.add('unhandled-link'); - } - } - - if (status.get('collapsed', null) === null && onCollapsedToggle) { - const { collapsable, onClick } = this.props; - - const collapsed = - collapsable - && onClick - && node.clientHeight > MAX_HEIGHT - && status.get('spoiler_text').length === 0; - - onCollapsedToggle(collapsed); - } - } - - handleMouseEnter = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-original'); - } - } - - handleMouseLeave = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-static'); - } - } - - componentDidMount () { - this._updateStatusLinks(); - } - - componentDidUpdate () { - this._updateStatusLinks(); - } - - onMentionClick = (mention, e) => { - if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { - e.preventDefault(); - this.context.router.history.push(`/@${mention.get('acct')}`); - } - } - - onHashtagClick = (hashtag, e) => { - hashtag = hashtag.replace(/^#/, ''); - - if (this.context.router && e.button === 0 && !(e.ctrlKey || e.metaKey)) { - e.preventDefault(); - this.context.router.history.push(`/tags/${hashtag}`); - } - } - - handleMouseDown = (e) => { - this.startXY = [e.clientX, e.clientY]; - } - - handleMouseUp = (e) => { - if (!this.startXY) { - return; - } - - const [ startX, startY ] = this.startXY; - const [ deltaX, deltaY ] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)]; - - let element = e.target; - while (element) { - if (element.localName === 'button' || element.localName === 'a' || element.localName === 'label') { - return; - } - element = element.parentNode; - } - - if (deltaX + deltaY < 5 && e.button === 0 && this.props.onClick) { - this.props.onClick(); - } - - this.startXY = null; - } - - handleSpoilerClick = (e) => { - e.preventDefault(); - - if (this.props.onExpandedToggle) { - // The parent manages the state - this.props.onExpandedToggle(); - } else { - this.setState({ hidden: !this.state.hidden }); - } - } - - handleTranslate = () => { - this.props.onTranslate(); - } - - setRef = (c) => { - this.node = c; - } - - render () { - const { status, intl } = this.props; - - const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden; - const renderReadMore = this.props.onClick && status.get('collapsed'); - const renderTranslate = translationEnabled && this.context.identity.signedIn && this.props.onTranslate && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('contentHtml').length > 0 && status.get('language') !== null && intl.locale !== status.get('language'); - - const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') }; - const spoilerContent = { __html: status.get('spoilerHtml') }; - const lang = status.get('translation') ? intl.locale : status.get('language'); - const classNames = classnames('status__content', { - 'status__content--with-action': this.props.onClick && this.context.router, - 'status__content--with-spoiler': status.get('spoiler_text').length > 0, - 'status__content--collapsed': renderReadMore, - }); - - const readMoreButton = renderReadMore && ( - <button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'> - <FormattedMessage id='status.read_more' defaultMessage='Read more' /><Icon id='angle-right' fixedWidth /> - </button> - ); - - const translateButton = renderTranslate && ( - <TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} /> - ); - - const poll = !!status.get('poll') && ( - <PollContainer pollId={status.get('poll')} /> - ); - - if (status.get('spoiler_text').length > 0) { - let mentionsPlaceholder = ''; - - const mentionLinks = status.get('mentions').map(item => ( - <Link to={`/@${item.get('acct')}`} key={item.get('id')} className='status-link mention'> - @<span>{item.get('username')}</span> - </Link> - )).reduce((aggregate, item) => [...aggregate, item, ' '], []); - - const toggleText = hidden ? <FormattedMessage id='status.show_more' defaultMessage='Show more' /> : <FormattedMessage id='status.show_less' defaultMessage='Show less' />; - - if (hidden) { - mentionsPlaceholder = <div>{mentionLinks}</div>; - } - - return ( - <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> - <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}> - <span dangerouslySetInnerHTML={spoilerContent} className='translate' lang={lang} /> - {' '} - <button type='button' className={`status__content__spoiler-link ${hidden ? 'status__content__spoiler-link--show-more' : 'status__content__spoiler-link--show-less'}`} onClick={this.handleSpoilerClick} aria-expanded={!hidden}>{toggleText}</button> - </p> - - {mentionsPlaceholder} - - <div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''} translate`} lang={lang} dangerouslySetInnerHTML={content} /> - - {!hidden && poll} - {!hidden && translateButton} - </div> - ); - } else if (this.props.onClick) { - return ( - <> - <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> - <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} /> - - {poll} - {translateButton} - </div> - - {readMoreButton} - </> - ); - } else { - return ( - <div className={classNames} ref={this.setRef} tabIndex='0' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> - <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} /> - - {poll} - {translateButton} - </div> - ); - } - } - -} |