diff options
Diffstat (limited to 'app/assets/javascripts/components/features/status')
5 files changed, 0 insertions, 495 deletions
diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx deleted file mode 100644 index 1e0b3f74d..000000000 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import PropTypes from 'prop-types'; -import IconButton from '../../../components/icon_button'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import DropdownMenu from '../../../components/dropdown_menu'; -import { defineMessages, injectIntl } from 'react-intl'; - -const messages = defineMessages({ - delete: { id: 'status.delete', defaultMessage: 'Delete' }, - mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' }, - reply: { id: 'status.reply', defaultMessage: 'Reply' }, - reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, - cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, - favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, - report: { id: 'status.report', defaultMessage: 'Report @{name}' } -}); - -class ActionBar extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleReplyClick = this.handleReplyClick.bind(this); - this.handleReblogClick = this.handleReblogClick.bind(this); - this.handleFavouriteClick = this.handleFavouriteClick.bind(this); - this.handleDeleteClick = this.handleDeleteClick.bind(this); - this.handleMentionClick = this.handleMentionClick.bind(this); - this.handleReport = this.handleReport.bind(this); - } - - handleReplyClick () { - this.props.onReply(this.props.status); - } - - handleReblogClick (e) { - this.props.onReblog(this.props.status, e); - } - - handleFavouriteClick () { - this.props.onFavourite(this.props.status); - } - - handleDeleteClick () { - this.props.onDelete(this.props.status); - } - - handleMentionClick () { - this.props.onMention(this.props.status.get('account'), this.context.router); - } - - handleReport () { - this.props.onReport(this.props.status); - this.context.router.push('/report'); - } - - render () { - const { status, me, intl } = this.props; - - let menu = []; - - if (me === status.getIn(['account', 'id'])) { - menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); - } else { - menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick }); - menu.push(null); - menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport }); - } - - let reblogIcon = 'retweet'; - if (status.get('visibility') === 'direct') reblogIcon = 'envelope'; - else if (status.get('visibility') === 'private') reblogIcon = 'lock'; - - let reblog_disabled = (status.get('visibility') === 'direct' || status.get('visibility') === 'private'); - - return ( - <div className='detailed-status__action-bar'> - <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_id', null) === null ? 'reply' : 'reply-all'} onClick={this.handleReplyClick} /></div> - <div className='detailed-status__button'><IconButton disabled={reblog_disabled} active={status.get('reblogged')} title={reblog_disabled ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div> - <div className='detailed-status__button'><IconButton animate={true} active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} activeStyle={{ color: '#ca8f04' }} /></div> - <div className='detailed-status__button'><DropdownMenu size={18} icon='ellipsis-h' items={menu} direction="left" ariaLabel="More" /></div> - </div> - ); - } - -} - -ActionBar.contextTypes = { - router: PropTypes.object -}; - -ActionBar.propTypes = { - status: ImmutablePropTypes.map.isRequired, - onReply: PropTypes.func.isRequired, - onReblog: PropTypes.func.isRequired, - onFavourite: PropTypes.func.isRequired, - onDelete: PropTypes.func.isRequired, - onMention: PropTypes.func.isRequired, - onReport: PropTypes.func, - me: PropTypes.number.isRequired, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(ActionBar); diff --git a/app/assets/javascripts/components/features/status/components/card.jsx b/app/assets/javascripts/components/features/status/components/card.jsx deleted file mode 100644 index a5ce7f08a..000000000 --- a/app/assets/javascripts/components/features/status/components/card.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import ImmutablePropTypes from 'react-immutable-proptypes'; - -const hostStyle = { - display: 'block', - marginTop: '5px', - fontSize: '13px' -}; - -const getHostname = url => { - const parser = document.createElement('a'); - parser.href = url; - return parser.hostname; -}; - -class Card extends React.PureComponent { - - renderLink () { - const { card } = this.props; - - let image = ''; - let provider = card.get('provider_name'); - - if (card.get('image')) { - image = ( - <div className='status-card__image'> - <img src={card.get('image')} alt={card.get('title')} className='status-card__image-image' /> - </div> - ); - } - - if (provider.length < 1) { - provider = getHostname(card.get('url')) - } - - return ( - <a href={card.get('url')} className='status-card' target='_blank' rel='noopener'> - {image} - - <div className='status-card__content'> - <strong className='status-card__title' title={card.get('title')}>{card.get('title')}</strong> - <p className='status-card__description'>{(card.get('description') || '').substring(0, 50)}</p> - <span className='status-card__host' style={hostStyle}>{provider}</span> - </div> - </a> - ); - } - - renderPhoto () { - const { card } = this.props; - - return ( - <a href={card.get('url')} className='status-card-photo' target='_blank' rel='noopener'> - <img src={card.get('url')} alt={card.get('title')} width={card.get('width')} height={card.get('height')} /> - </a> - ); - } - - renderVideo () { - const { card } = this.props; - const content = { __html: card.get('html') }; - - return ( - <div - className='status-card-video' - dangerouslySetInnerHTML={content} - /> - ); - } - - render () { - const { card } = this.props; - - if (card === null) { - return null; - } - - switch(card.get('type')) { - case 'link': - return this.renderLink(); - case 'photo': - return this.renderPhoto(); - case 'video': - return this.renderVideo(); - case 'rich': - default: - return null; - } - } -} - -Card.propTypes = { - card: ImmutablePropTypes.map -}; - -export default Card; diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx deleted file mode 100644 index 0e2a7c17e..000000000 --- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx +++ /dev/null @@ -1,94 +0,0 @@ -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import Avatar from '../../../components/avatar'; -import DisplayName from '../../../components/display_name'; -import StatusContent from '../../../components/status_content'; -import MediaGallery from '../../../components/media_gallery'; -import VideoPlayer from '../../../components/video_player'; -import AttachmentList from '../../../components/attachment_list'; -import { Link } from 'react-router'; -import { FormattedDate, FormattedNumber } from 'react-intl'; -import CardContainer from '../containers/card_container'; - -class DetailedStatus extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleAccountClick = this.handleAccountClick.bind(this); - } - - handleAccountClick (e) { - if (e.button === 0) { - e.preventDefault(); - this.context.router.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`); - } - - e.stopPropagation(); - } - - render () { - const status = this.props.status.get('reblog') ? this.props.status.get('reblog') : this.props.status; - - let media = ''; - let applicationLink = ''; - - if (status.get('media_attachments').size > 0) { - if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) { - media = <AttachmentList media={status.get('media_attachments')} />; - } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') { - media = <VideoPlayer sensitive={status.get('sensitive')} media={status.getIn(['media_attachments', 0])} width={300} height={150} onOpenVideo={this.props.onOpenVideo} autoplay />; - } else { - media = <MediaGallery sensitive={status.get('sensitive')} media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} autoPlayGif={this.props.autoPlayGif} />; - } - } else if (status.get('spoiler_text').length === 0) { - media = <CardContainer statusId={status.get('id')} />; - } - - if (status.get('application')) { - applicationLink = <span> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener'>{status.getIn(['application', 'name'])}</a></span>; - } - - return ( - <div className='detailed-status'> - <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'> - <div className='detailed-status__display-avatar'><Avatar src={status.getIn(['account', 'avatar'])} staticSrc={status.getIn(['account', 'avatar_static'])} size={48} /></div> - <DisplayName account={status.get('account')} /> - </a> - - <StatusContent status={status} /> - - {media} - - <div className='detailed-status__meta'> - <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'> - <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /> - </a>{applicationLink} · <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'> - <i className='fa fa-retweet' /> - <span className='detailed-status__reblogs'> - <FormattedNumber value={status.get('reblogs_count')} /> - </span> - </Link> · <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'> - <i className='fa fa-star' /> - <span className='detailed-status__favorites'> - <FormattedNumber value={status.get('favourites_count')} /> - </span> - </Link> - </div> - </div> - ); - } - -} - -DetailedStatus.contextTypes = { - router: PropTypes.object -}; - -DetailedStatus.propTypes = { - status: ImmutablePropTypes.map.isRequired, - onOpenMedia: PropTypes.func.isRequired, - onOpenVideo: PropTypes.func.isRequired, - autoPlayGif: PropTypes.bool, -}; - -export default DetailedStatus; diff --git a/app/assets/javascripts/components/features/status/containers/card_container.jsx b/app/assets/javascripts/components/features/status/containers/card_container.jsx deleted file mode 100644 index 5c8bfeec2..000000000 --- a/app/assets/javascripts/components/features/status/containers/card_container.jsx +++ /dev/null @@ -1,8 +0,0 @@ -import { connect } from 'react-redux'; -import Card from '../components/card'; - -const mapStateToProps = (state, { statusId }) => ({ - card: state.getIn(['cards', statusId], null) -}); - -export default connect(mapStateToProps)(Card); diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx deleted file mode 100644 index 595df251c..000000000 --- a/app/assets/javascripts/components/features/status/index.jsx +++ /dev/null @@ -1,197 +0,0 @@ -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { fetchStatus } from '../../actions/statuses'; -import Immutable from 'immutable'; -import EmbeddedStatus from '../../components/status'; -import MissingIndicator from '../../components/missing_indicator'; -import DetailedStatus from './components/detailed_status'; -import ActionBar from './components/action_bar'; -import Column from '../ui/components/column'; -import { - favourite, - unfavourite, - reblog, - unreblog -} from '../../actions/interactions'; -import { - replyCompose, - mentionCompose -} from '../../actions/compose'; -import { deleteStatus } from '../../actions/statuses'; -import { initReport } from '../../actions/reports'; -import { - makeGetStatus, - getStatusAncestors, - getStatusDescendants -} from '../../selectors'; -import { ScrollContainer } from 'react-router-scroll'; -import ColumnBackButton from '../../components/column_back_button'; -import StatusContainer from '../../containers/status_container'; -import { openModal } from '../../actions/modal'; -import { isMobile } from '../../is_mobile' -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -const messages = defineMessages({ - deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, - deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' } -}); - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - const mapStateToProps = (state, props) => ({ - status: getStatus(state, Number(props.params.statusId)), - ancestorsIds: state.getIn(['timelines', 'ancestors', Number(props.params.statusId)]), - descendantsIds: state.getIn(['timelines', 'descendants', Number(props.params.statusId)]), - me: state.getIn(['meta', 'me']), - boostModal: state.getIn(['meta', 'boost_modal']), - autoPlayGif: state.getIn(['meta', 'auto_play_gif']) - }); - - return mapStateToProps; -}; - -class Status extends React.PureComponent { - - constructor (props, context) { - super(props, context); - this.handleFavouriteClick = this.handleFavouriteClick.bind(this); - this.handleReplyClick = this.handleReplyClick.bind(this); - this.handleModalReblog = this.handleModalReblog.bind(this); - this.handleReblogClick = this.handleReblogClick.bind(this); - this.handleDeleteClick = this.handleDeleteClick.bind(this); - this.handleMentionClick = this.handleMentionClick.bind(this); - this.handleOpenMedia = this.handleOpenMedia.bind(this); - this.handleOpenVideo = this.handleOpenVideo.bind(this); - this.handleReport = this.handleReport.bind(this); - } - - componentWillMount () { - this.props.dispatch(fetchStatus(Number(this.props.params.statusId))); - } - - componentWillReceiveProps (nextProps) { - if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) { - this.props.dispatch(fetchStatus(Number(nextProps.params.statusId))); - } - } - - handleFavouriteClick (status) { - if (status.get('favourited')) { - this.props.dispatch(unfavourite(status)); - } else { - this.props.dispatch(favourite(status)); - } - } - - handleReplyClick (status) { - this.props.dispatch(replyCompose(status, this.context.router)); - } - - handleModalReblog (status) { - this.props.dispatch(reblog(status)); - } - - handleReblogClick (status, e) { - if (status.get('reblogged')) { - this.props.dispatch(unreblog(status)); - } else { - if (e.shiftKey || !this.props.boostModal) { - this.handleModalReblog(status); - } else { - this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog })); - } - } - } - - handleDeleteClick (status) { - const { dispatch, intl } = this.props; - - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(deleteStatus(status.get('id'))) - })); - } - - handleMentionClick (account, router) { - this.props.dispatch(mentionCompose(account, router)); - } - - handleOpenMedia (media, index) { - this.props.dispatch(openModal('MEDIA', { media, index })); - } - - handleOpenVideo (media, time) { - this.props.dispatch(openModal('VIDEO', { media, time })); - } - - handleReport (status) { - this.props.dispatch(initReport(status.get('account'), status)); - } - - renderChildren (list) { - return list.map(id => <StatusContainer key={id} id={id} />); - } - - render () { - let ancestors, descendants; - const { status, ancestorsIds, descendantsIds, me, autoPlayGif } = this.props; - - if (status === null) { - return ( - <Column> - <ColumnBackButton /> - <MissingIndicator /> - </Column> - ); - } - - const account = status.get('account'); - - if (ancestorsIds && ancestorsIds.size > 0) { - ancestors = <div>{this.renderChildren(ancestorsIds)}</div>; - } - - if (descendantsIds && descendantsIds.size > 0) { - descendants = <div>{this.renderChildren(descendantsIds)}</div>; - } - - return ( - <Column> - <ColumnBackButton /> - - <ScrollContainer scrollKey='thread'> - <div className='scrollable detailed-status__wrapper'> - {ancestors} - - <DetailedStatus status={status} autoPlayGif={autoPlayGif} me={me} onOpenVideo={this.handleOpenVideo} onOpenMedia={this.handleOpenMedia} /> - <ActionBar status={status} me={me} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} onMention={this.handleMentionClick} onReport={this.handleReport} /> - - {descendants} - </div> - </ScrollContainer> - </Column> - ); - } - -} - -Status.contextTypes = { - router: PropTypes.object -}; - -Status.propTypes = { - params: PropTypes.object.isRequired, - dispatch: PropTypes.func.isRequired, - status: ImmutablePropTypes.map, - ancestorsIds: ImmutablePropTypes.list, - descendantsIds: ImmutablePropTypes.list, - me: PropTypes.number, - boostModal: PropTypes.bool, - autoPlayGif: PropTypes.bool, - intl: PropTypes.object.isRequired -}; - -export default injectIntl(connect(makeMapStateToProps)(Status)); |