|
|
@ -1,11 +1,11 @@
|
|
|
|
import React from 'react';
|
|
|
|
import React from 'react';
|
|
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { FormattedMessage } from 'react-intl';
|
|
|
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
|
|
|
import Permalink from './permalink';
|
|
|
|
import Permalink from './permalink';
|
|
|
|
import classnames from 'classnames';
|
|
|
|
import classnames from 'classnames';
|
|
|
|
import Icon from 'flavours/glitch/components/icon';
|
|
|
|
import Icon from 'flavours/glitch/components/icon';
|
|
|
|
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
|
|
|
import { autoPlayGif, languages as preloadedLanguages, translationEnabled } from 'flavours/glitch/initial_state';
|
|
|
|
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
|
|
|
|
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
|
|
|
|
|
|
|
|
|
|
|
|
const textMatchesTarget = (text, origin, host) => {
|
|
|
|
const textMatchesTarget = (text, origin, host) => {
|
|
|
@ -62,13 +62,56 @@ const isLinkMisleading = (link) => {
|
|
|
|
return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host));
|
|
|
|
return !(textMatchesTarget(text, origin, host) || textMatchesTarget(text.toLowerCase(), origin, host));
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default class StatusContent extends React.PureComponent {
|
|
|
|
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 = {
|
|
|
|
|
|
|
|
identity: PropTypes.object,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
static propTypes = {
|
|
|
|
status: ImmutablePropTypes.map.isRequired,
|
|
|
|
status: ImmutablePropTypes.map.isRequired,
|
|
|
|
expanded: PropTypes.bool,
|
|
|
|
expanded: PropTypes.bool,
|
|
|
|
collapsed: PropTypes.bool,
|
|
|
|
collapsed: PropTypes.bool,
|
|
|
|
onExpandedToggle: PropTypes.func,
|
|
|
|
onExpandedToggle: PropTypes.func,
|
|
|
|
|
|
|
|
onTranslate: PropTypes.func,
|
|
|
|
media: PropTypes.node,
|
|
|
|
media: PropTypes.node,
|
|
|
|
extraMedia: PropTypes.node,
|
|
|
|
extraMedia: PropTypes.node,
|
|
|
|
mediaIcons: PropTypes.arrayOf(PropTypes.string),
|
|
|
|
mediaIcons: PropTypes.arrayOf(PropTypes.string),
|
|
|
@ -77,6 +120,7 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
onUpdate: PropTypes.func,
|
|
|
|
onUpdate: PropTypes.func,
|
|
|
|
tagLinks: PropTypes.bool,
|
|
|
|
tagLinks: PropTypes.bool,
|
|
|
|
rewriteMentions: PropTypes.string,
|
|
|
|
rewriteMentions: PropTypes.string,
|
|
|
|
|
|
|
|
intl: PropTypes.object,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static defaultProps = {
|
|
|
|
static defaultProps = {
|
|
|
@ -249,6 +293,10 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleTranslate = () => {
|
|
|
|
|
|
|
|
this.props.onTranslate();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setContentsRef = (c) => {
|
|
|
|
setContentsRef = (c) => {
|
|
|
|
this.contentsNode = c;
|
|
|
|
this.contentsNode = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -263,18 +311,24 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
disabled,
|
|
|
|
disabled,
|
|
|
|
tagLinks,
|
|
|
|
tagLinks,
|
|
|
|
rewriteMentions,
|
|
|
|
rewriteMentions,
|
|
|
|
|
|
|
|
intl,
|
|
|
|
} = this.props;
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
|
|
|
|
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
|
|
|
|
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
|
|
|
|
|
|
|
|
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('contentHtml') };
|
|
|
|
const content = { __html: status.get('translation') ? status.getIn(['translation', 'content']) : status.get('contentHtml') };
|
|
|
|
const spoilerContent = { __html: status.get('spoilerHtml') };
|
|
|
|
const spoilerContent = { __html: status.get('spoilerHtml') };
|
|
|
|
const lang = status.get('language');
|
|
|
|
const lang = status.get('translation') ? intl.locale : status.get('language');
|
|
|
|
const classNames = classnames('status__content', {
|
|
|
|
const classNames = classnames('status__content', {
|
|
|
|
'status__content--with-action': parseClick && !disabled,
|
|
|
|
'status__content--with-action': parseClick && !disabled,
|
|
|
|
'status__content--with-spoiler': status.get('spoiler_text').length > 0,
|
|
|
|
'status__content--with-spoiler': status.get('spoiler_text').length > 0,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const translateButton = renderTranslate && (
|
|
|
|
|
|
|
|
<TranslateButton onClick={this.handleTranslate} translation={status.get('translation')} />
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
if (status.get('spoiler_text').length > 0) {
|
|
|
|
if (status.get('spoiler_text').length > 0) {
|
|
|
|
let mentionsPlaceholder = '';
|
|
|
|
let mentionsPlaceholder = '';
|
|
|
|
|
|
|
|
|
|
|
@ -350,11 +404,11 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
lang={lang}
|
|
|
|
lang={lang}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
{!hidden && translateButton}
|
|
|
|
{media}
|
|
|
|
{media}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{extraMedia}
|
|
|
|
{extraMedia}
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
} else if (parseClick) {
|
|
|
|
} else if (parseClick) {
|
|
|
@ -375,6 +429,7 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
lang={lang}
|
|
|
|
lang={lang}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
{translateButton}
|
|
|
|
{media}
|
|
|
|
{media}
|
|
|
|
{extraMedia}
|
|
|
|
{extraMedia}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
@ -395,6 +450,7 @@ export default class StatusContent extends React.PureComponent {
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
onMouseLeave={this.handleMouseLeave}
|
|
|
|
lang={lang}
|
|
|
|
lang={lang}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
{translateButton}
|
|
|
|
{media}
|
|
|
|
{media}
|
|
|
|
{extraMedia}
|
|
|
|
{extraMedia}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|