2018-11-30 06:17:56 -05:00
import Immutable from 'immutable' ;
2017-05-02 20:04:16 -04:00
import React from 'react' ;
2017-02-17 20:37:59 -05:00
import { connect } from 'react-redux' ;
2017-04-21 14:05:35 -04:00
import PropTypes from 'prop-types' ;
2017-11-07 08:24:55 -05:00
import classNames from 'classnames' ;
2017-02-17 20:37:59 -05:00
import ImmutablePropTypes from 'react-immutable-proptypes' ;
2017-12-04 02:26:40 -05:00
import { fetchStatus } from 'flavours/glitch/actions/statuses' ;
import MissingIndicator from 'flavours/glitch/components/missing_indicator' ;
2017-02-17 20:37:59 -05:00
import DetailedStatus from './components/detailed_status' ;
import ActionBar from './components/action_bar' ;
2017-12-04 02:26:40 -05:00
import Column from 'flavours/glitch/features/ui/components/column' ;
2017-02-17 20:37:59 -05:00
import {
favourite ,
unfavourite ,
2018-04-11 13:42:25 -04:00
bookmark ,
unbookmark ,
2017-02-17 20:37:59 -05:00
reblog ,
2017-05-20 11:31:47 -04:00
unreblog ,
2017-08-24 19:41:18 -04:00
pin ,
unpin ,
2017-12-04 02:26:40 -05:00
} from 'flavours/glitch/actions/interactions' ;
2016-10-24 11:11:02 -04:00
import {
replyCompose ,
2017-05-20 11:31:47 -04:00
mentionCompose ,
2018-04-10 15:38:02 -04:00
directCompose ,
2017-12-04 02:26:40 -05:00
} from 'flavours/glitch/actions/compose' ;
2018-11-27 12:25:51 -05:00
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings' ;
2017-12-26 11:41:44 -05:00
import { blockAccount } from 'flavours/glitch/actions/accounts' ;
import { muteStatus , unmuteStatus , deleteStatus } from 'flavours/glitch/actions/statuses' ;
import { initMuteModal } from 'flavours/glitch/actions/mutes' ;
2017-12-04 02:26:40 -05:00
import { initReport } from 'flavours/glitch/actions/reports' ;
import { makeGetStatus } from 'flavours/glitch/selectors' ;
2017-10-31 17:58:38 -04:00
import { ScrollContainer } from 'react-router-scroll-4' ;
2017-12-04 02:26:40 -05:00
import ColumnBackButton from 'flavours/glitch/components/column_back_button' ;
2018-03-28 13:56:46 -04:00
import ColumnHeader from '../../components/column_header' ;
2017-12-04 02:26:40 -05:00
import StatusContainer from 'flavours/glitch/containers/status_container' ;
import { openModal } from 'flavours/glitch/actions/modal' ;
2017-12-26 11:13:38 -05:00
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
2017-05-02 20:04:16 -04:00
import ImmutablePureComponent from 'react-immutable-pure-component' ;
2017-10-05 19:07:59 -04:00
import { HotKeys } from 'react-hotkeys' ;
2017-12-09 11:26:22 -05:00
import { boostModal , favouriteModal , deleteModal } from 'flavours/glitch/util/initial_state' ;
2017-12-04 02:26:40 -05:00
import { attachFullscreenListener , detachFullscreenListener , isFullscreen } from 'flavours/glitch/util/fullscreen' ;
2018-08-28 11:16:30 -04:00
import { autoUnfoldCW } from 'flavours/glitch/util/content_warning' ;
2018-08-28 06:10:40 -04:00
import { textForScreenReader } from 'flavours/glitch/components/status' ;
2017-04-22 22:39:50 -04:00
const messages = defineMessages ( {
deleteConfirm : { id : 'confirmations.delete.confirm' , defaultMessage : 'Delete' } ,
2017-05-20 11:31:47 -04:00
deleteMessage : { id : 'confirmations.delete.message' , defaultMessage : 'Are you sure you want to delete this status?' } ,
2018-06-15 15:29:04 -04:00
redraftConfirm : { id : 'confirmations.redraft.confirm' , defaultMessage : 'Delete & redraft' } ,
redraftMessage : { id : 'confirmations.redraft.message' , defaultMessage : 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' } ,
2017-12-26 11:13:38 -05:00
blockConfirm : { id : 'confirmations.block.confirm' , defaultMessage : 'Block' } ,
2018-03-28 13:56:46 -04:00
revealAll : { id : 'status.show_more_all' , defaultMessage : 'Show more for all' } ,
hideAll : { id : 'status.show_less_all' , defaultMessage : 'Show less for all' } ,
2018-08-28 06:01:04 -04:00
detailedStatus : { id : 'status.detailed_status' , defaultMessage : 'Detailed conversation view' } ,
2018-10-05 11:46:35 -04:00
replyConfirm : { id : 'confirmations.reply.confirm' , defaultMessage : 'Reply' } ,
replyMessage : { id : 'confirmations.reply.message' , defaultMessage : 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' } ,
2017-04-22 22:39:50 -04:00
} ) ;
2016-09-15 18:21:51 -04:00
2016-10-24 11:11:02 -04:00
const makeMapStateToProps = ( ) => {
const getStatus = makeGetStatus ( ) ;
2018-11-30 06:17:56 -05:00
const mapStateToProps = ( state , props ) => {
const status = getStatus ( state , { id : props . params . statusId } ) ;
let ancestorsIds = Immutable . List ( ) ;
let descendantsIds = Immutable . List ( ) ;
if ( status ) {
ancestorsIds = ancestorsIds . withMutations ( mutable => {
2018-11-30 06:24:12 -05:00
let id = status . get ( 'in_reply_to_id' ) ;
2018-11-30 06:17:56 -05:00
2018-11-30 06:24:12 -05:00
while ( id ) {
mutable . unshift ( id ) ;
id = state . getIn ( [ 'contexts' , 'inReplyTos' , id ] ) ;
2018-11-30 06:17:56 -05:00
}
} ) ;
descendantsIds = descendantsIds . withMutations ( mutable => {
2018-11-30 06:24:12 -05:00
const ids = [ status . get ( 'id' ) ] ;
while ( ids . length > 0 ) {
let id = ids . shift ( ) ;
2018-11-30 06:17:56 -05:00
const replies = state . getIn ( [ 'contexts' , 'replies' , id ] ) ;
2018-11-30 06:24:58 -05:00
if ( status . get ( 'id' ) !== id ) {
mutable . push ( id ) ;
}
2018-11-30 06:17:56 -05:00
if ( replies ) {
2018-11-30 06:24:58 -05:00
replies . reverse ( ) . forEach ( reply => {
2018-11-30 06:24:12 -05:00
ids . unshift ( reply ) ;
2018-11-30 06:17:56 -05:00
} ) ;
}
}
} ) ;
}
return {
status ,
ancestorsIds ,
descendantsIds ,
settings : state . get ( 'local_settings' ) ,
2018-11-27 12:25:51 -05:00
askReplyConfirmation : state . getIn ( [ 'local_settings' , 'confirm_before_clearing_draft' ] ) && state . getIn ( [ 'compose' , 'text' ] ) . trim ( ) . length !== 0 ,
2018-11-30 06:17:56 -05:00
} ;
} ;
2016-10-24 11:11:02 -04:00
return mapStateToProps ;
} ;
2016-09-15 18:21:51 -04:00
2017-06-23 13:36:54 -04:00
@ injectIntl
@ connect ( makeMapStateToProps )
export default class Status extends ImmutablePureComponent {
2017-04-21 14:05:35 -04:00
2017-05-12 08:44:10 -04:00
static contextTypes = {
2017-05-20 11:31:47 -04:00
router : PropTypes . object ,
2017-05-12 08:44:10 -04:00
} ;
static propTypes = {
params : PropTypes . object . isRequired ,
dispatch : PropTypes . func . isRequired ,
status : ImmutablePropTypes . map ,
2017-06-30 05:15:18 -04:00
settings : ImmutablePropTypes . map . isRequired ,
2017-05-12 08:44:10 -04:00
ancestorsIds : ImmutablePropTypes . list ,
descendantsIds : ImmutablePropTypes . list ,
2017-05-20 11:31:47 -04:00
intl : PropTypes . object . isRequired ,
2018-10-05 11:46:35 -04:00
askReplyConfirmation : PropTypes . bool ,
2017-05-12 08:44:10 -04:00
} ;
2016-09-15 18:21:51 -04:00
2017-11-07 08:24:55 -05:00
state = {
fullscreen : false ,
2018-08-28 11:16:30 -04:00
isExpanded : undefined ,
2018-08-28 08:10:26 -04:00
threadExpanded : undefined ,
2018-11-28 14:20:03 -05:00
statusId : undefined ,
2017-11-07 08:24:55 -05:00
} ;
componentDidMount ( ) {
attachFullscreenListener ( this . onFullScreenChange ) ;
2018-11-28 14:20:03 -05:00
this . props . dispatch ( fetchStatus ( this . props . params . statusId ) ) ;
2018-11-30 11:14:01 -05:00
const { status , ancestorsIds } = this . props ;
if ( status && ancestorsIds && ancestorsIds . size > 0 ) {
const element = this . node . querySelectorAll ( '.focusable' ) [ ancestorsIds . size - 1 ] ;
window . requestAnimationFrame ( ( ) => {
element . scrollIntoView ( true ) ;
} ) ;
}
2017-11-07 08:24:55 -05:00
}
2018-11-28 14:20:03 -05:00
static getDerivedStateFromProps ( props , state ) {
if ( state . statusId === props . params . statusId || ! props . params . statusId ) {
return null ;
2016-09-15 18:21:51 -04:00
}
2018-11-28 14:20:03 -05:00
props . dispatch ( fetchStatus ( props . params . statusId ) ) ;
return {
threadExpanded : undefined ,
isExpanded : autoUnfoldCW ( props . settings , props . status ) ,
statusId : props . params . statusId ,
} ;
2017-04-21 14:05:35 -04:00
}
2016-09-15 18:21:51 -04:00
2017-11-27 17:05:03 -05:00
handleExpandedToggle = ( ) => {
if ( this . props . status . get ( 'spoiler_text' ) ) {
2018-03-28 09:40:34 -04:00
this . setExpansion ( ! this . state . isExpanded ) ;
2017-11-27 17:05:03 -05:00
}
} ;
2017-12-09 11:26:22 -05:00
handleModalFavourite = ( status ) => {
this . props . dispatch ( favourite ( status ) ) ;
}
handleFavouriteClick = ( status , e ) => {
2017-02-16 20:33:10 -05:00
if ( status . get ( 'favourited' ) ) {
this . props . dispatch ( unfavourite ( status ) ) ;
} else {
2018-10-18 12:42:02 -04:00
if ( ( e && e . shiftKey ) || ! favouriteModal ) {
2017-12-09 11:26:22 -05:00
this . handleModalFavourite ( status ) ;
} else {
this . props . dispatch ( openModal ( 'FAVOURITE' , { status , onFavourite : this . handleModalFavourite } ) ) ;
}
2017-02-16 20:33:10 -05:00
}
2017-04-21 14:05:35 -04:00
}
2016-09-17 11:47:26 -04:00
2017-08-24 19:41:18 -04:00
handlePin = ( status ) => {
if ( status . get ( 'pinned' ) ) {
this . props . dispatch ( unpin ( status ) ) ;
} else {
this . props . dispatch ( pin ( status ) ) ;
}
}
2017-05-12 08:44:10 -04:00
handleReplyClick = ( status ) => {
2018-10-05 11:46:35 -04:00
let { askReplyConfirmation , dispatch , intl } = this . props ;
if ( askReplyConfirmation ) {
dispatch ( openModal ( 'CONFIRM' , {
message : intl . formatMessage ( messages . replyMessage ) ,
confirm : intl . formatMessage ( messages . replyConfirm ) ,
2018-11-27 12:25:51 -05:00
onDoNotAsk : ( ) => dispatch ( changeLocalSetting ( [ 'confirm_before_clearing_draft' ] , false ) ) ,
2018-10-05 11:46:35 -04:00
onConfirm : ( ) => dispatch ( replyCompose ( status , this . context . router . history ) ) ,
} ) ) ;
} else {
dispatch ( replyCompose ( status , this . context . router . history ) ) ;
}
2017-04-21 14:05:35 -04:00
}
2016-09-17 11:47:26 -04:00
2017-05-12 08:44:10 -04:00
handleModalReblog = ( status ) => {
2017-04-10 22:28:52 -04:00
this . props . dispatch ( reblog ( status ) ) ;
2017-04-21 14:05:35 -04:00
}
2017-12-09 13:41:24 -05:00
2017-05-12 08:44:10 -04:00
handleReblogClick = ( status , e ) => {
2017-02-16 20:33:10 -05:00
if ( status . get ( 'reblogged' ) ) {
this . props . dispatch ( unreblog ( status ) ) ;
} else {
2018-10-18 12:42:02 -04:00
if ( ( e && e . shiftKey ) || ! boostModal ) {
2017-04-11 08:34:14 -04:00
this . handleModalReblog ( status ) ;
} else {
this . props . dispatch ( openModal ( 'BOOST' , { status , onReblog : this . handleModalReblog } ) ) ;
}
2017-02-16 20:33:10 -05:00
}
2017-04-21 14:05:35 -04:00
}
2016-09-17 11:47:26 -04:00
2018-04-11 13:42:25 -04:00
handleBookmarkClick = ( status ) => {
if ( status . get ( 'bookmarked' ) ) {
this . props . dispatch ( unbookmark ( status ) ) ;
} else {
this . props . dispatch ( bookmark ( status ) ) ;
}
}
2018-08-31 10:41:58 -04:00
handleDeleteClick = ( status , history , withRedraft = false ) => {
2017-04-22 22:39:50 -04:00
const { dispatch , intl } = this . props ;
2017-10-29 11:10:15 -04:00
if ( ! deleteModal ) {
2018-08-31 10:41:58 -04:00
dispatch ( deleteStatus ( status . get ( 'id' ) , history , withRedraft ) ) ;
2017-05-29 11:56:13 -04:00
} else {
dispatch ( openModal ( 'CONFIRM' , {
2018-06-15 15:29:04 -04:00
message : intl . formatMessage ( withRedraft ? messages . redraftMessage : messages . deleteMessage ) ,
confirm : intl . formatMessage ( withRedraft ? messages . redraftConfirm : messages . deleteConfirm ) ,
2018-08-31 10:41:58 -04:00
onConfirm : ( ) => dispatch ( deleteStatus ( status . get ( 'id' ) , history , withRedraft ) ) ,
2017-05-29 11:56:13 -04:00
} ) ) ;
}
2017-04-21 14:05:35 -04:00
}
2016-10-09 16:19:15 -04:00
2018-04-10 15:38:02 -04:00
handleDirectClick = ( account , router ) => {
this . props . dispatch ( directCompose ( account , router ) ) ;
}
2017-05-12 08:44:10 -04:00
handleMentionClick = ( account , router ) => {
2017-01-30 15:40:55 -05:00
this . props . dispatch ( mentionCompose ( account , router ) ) ;
2017-04-21 14:05:35 -04:00
}
2016-10-24 11:11:02 -04:00
2017-05-12 08:44:10 -04:00
handleOpenMedia = ( media , index ) => {
2017-04-01 16:11:28 -04:00
this . props . dispatch ( openModal ( 'MEDIA' , { media , index } ) ) ;
2017-04-21 14:05:35 -04:00
}
2016-10-24 12:07:40 -04:00
2017-05-12 08:44:10 -04:00
handleOpenVideo = ( media , time ) => {
2017-04-13 11:01:09 -04:00
this . props . dispatch ( openModal ( 'VIDEO' , { media , time } ) ) ;
2017-04-21 14:05:35 -04:00
}
2017-04-13 09:04:18 -04:00
2017-12-26 11:13:38 -05:00
handleMuteClick = ( account ) => {
this . props . dispatch ( initMuteModal ( account ) ) ;
}
handleConversationMuteClick = ( status ) => {
if ( status . get ( 'muted' ) ) {
this . props . dispatch ( unmuteStatus ( status . get ( 'id' ) ) ) ;
} else {
this . props . dispatch ( muteStatus ( status . get ( 'id' ) ) ) ;
}
}
2018-03-28 13:56:46 -04:00
handleToggleAll = ( ) => {
const { isExpanded } = this . state ;
this . setState ( { isExpanded : ! isExpanded , threadExpanded : ! isExpanded } ) ;
}
2017-12-26 11:13:38 -05:00
handleBlockClick = ( account ) => {
const { dispatch , intl } = this . props ;
dispatch ( openModal ( 'CONFIRM' , {
message : < FormattedMessage id = 'confirmations.block.message' defaultMessage = 'Are you sure you want to block {name}?' values = { { name : < strong > @ { account . get ( 'acct' ) } < /strong> }} / > ,
confirm : intl . formatMessage ( messages . blockConfirm ) ,
onConfirm : ( ) => dispatch ( blockAccount ( account . get ( 'id' ) ) ) ,
} ) ) ;
}
2017-05-12 08:44:10 -04:00
handleReport = ( status ) => {
2017-02-14 14:59:26 -05:00
this . props . dispatch ( initReport ( status . get ( 'account' ) , status ) ) ;
2017-04-21 14:05:35 -04:00
}
2017-02-14 14:59:26 -05:00
2017-08-30 21:38:35 -04:00
handleEmbed = ( status ) => {
this . props . dispatch ( openModal ( 'EMBED' , { url : status . get ( 'url' ) } ) ) ;
}
2017-10-05 19:07:59 -04:00
handleHotkeyMoveUp = ( ) => {
this . handleMoveUp ( this . props . status . get ( 'id' ) ) ;
}
handleHotkeyMoveDown = ( ) => {
this . handleMoveDown ( this . props . status . get ( 'id' ) ) ;
}
handleHotkeyReply = e => {
e . preventDefault ( ) ;
this . handleReplyClick ( this . props . status ) ;
}
handleHotkeyFavourite = ( ) => {
this . handleFavouriteClick ( this . props . status ) ;
}
handleHotkeyBoost = ( ) => {
this . handleReblogClick ( this . props . status ) ;
}
handleHotkeyMention = e => {
e . preventDefault ( ) ;
this . handleMentionClick ( this . props . status ) ;
}
handleHotkeyOpenProfile = ( ) => {
this . context . router . history . push ( ` /accounts/ ${ this . props . status . getIn ( [ 'account' , 'id' ] ) } ` ) ;
}
handleMoveUp = id => {
const { status , ancestorsIds , descendantsIds } = this . props ;
if ( id === status . get ( 'id' ) ) {
this . _selectChild ( ancestorsIds . size - 1 ) ;
} else {
let index = ancestorsIds . indexOf ( id ) ;
if ( index === - 1 ) {
index = descendantsIds . indexOf ( id ) ;
this . _selectChild ( ancestorsIds . size + index ) ;
} else {
this . _selectChild ( index - 1 ) ;
}
}
}
handleMoveDown = id => {
const { status , ancestorsIds , descendantsIds } = this . props ;
if ( id === status . get ( 'id' ) ) {
this . _selectChild ( ancestorsIds . size + 1 ) ;
} else {
let index = ancestorsIds . indexOf ( id ) ;
if ( index === - 1 ) {
index = descendantsIds . indexOf ( id ) ;
this . _selectChild ( ancestorsIds . size + index + 2 ) ;
} else {
this . _selectChild ( index + 1 ) ;
}
}
}
_selectChild ( index ) {
const element = this . node . querySelectorAll ( '.focusable' ) [ index ] ;
if ( element ) {
element . focus ( ) ;
}
}
2016-09-15 18:21:51 -04:00
renderChildren ( list ) {
2017-10-05 19:07:59 -04:00
return list . map ( id => (
< StatusContainer
key = { id }
id = { id }
2018-03-28 13:56:46 -04:00
expanded = { this . state . threadExpanded }
2017-10-05 19:07:59 -04:00
onMoveUp = { this . handleMoveUp }
onMoveDown = { this . handleMoveDown }
2018-07-08 14:04:53 -04:00
contextType = 'thread'
2017-10-05 19:07:59 -04:00
/ >
) ) ;
}
2017-11-27 17:05:03 -05:00
setExpansion = value => {
2018-03-28 09:40:34 -04:00
this . setState ( { isExpanded : value } ) ;
2017-11-27 17:05:03 -05:00
}
2017-10-05 19:07:59 -04:00
setRef = c => {
this . node = c ;
}
2018-11-28 14:20:03 -05:00
componentDidUpdate ( prevProps ) {
2018-11-30 06:27:19 -05:00
if ( this . props . params . statusId && ( this . props . params . statusId !== prevProps . params . statusId || prevProps . ancestorsIds . size < this . props . ancestorsIds . size ) ) {
2018-11-28 14:20:03 -05:00
const { status , ancestorsIds } = this . props ;
2017-10-11 13:21:44 -04:00
2018-11-28 14:20:03 -05:00
if ( status && ancestorsIds && ancestorsIds . size > 0 ) {
const element = this . node . querySelectorAll ( '.focusable' ) [ ancestorsIds . size - 1 ] ;
2017-10-05 19:07:59 -04:00
2018-11-28 14:20:03 -05:00
window . requestAnimationFrame ( ( ) => {
element . scrollIntoView ( true ) ;
} ) ;
}
2017-10-05 19:07:59 -04:00
}
2017-04-21 14:05:35 -04:00
}
2016-09-15 18:21:51 -04:00
2017-11-07 08:24:55 -05:00
componentWillUnmount ( ) {
detachFullscreenListener ( this . onFullScreenChange ) ;
}
onFullScreenChange = ( ) => {
this . setState ( { fullscreen : isFullscreen ( ) } ) ;
}
2018-07-27 11:59:52 -04:00
shouldUpdateScroll = ( prevRouterProps , { location } ) => {
2018-10-06 12:53:49 -04:00
if ( ( ( ( prevRouterProps || { } ) . location || { } ) . state || { } ) . mastodonModalOpen ) return false ;
return ! ( location . state && location . state . mastodonModalOpen ) ;
2018-07-27 11:59:52 -04:00
}
2016-09-15 18:21:51 -04:00
render ( ) {
2016-10-24 11:11:02 -04:00
let ancestors , descendants ;
2017-11-27 17:05:03 -05:00
const { setExpansion } = this ;
2018-03-28 13:56:46 -04:00
const { status , settings , ancestorsIds , descendantsIds , intl } = this . props ;
2017-11-27 17:05:03 -05:00
const { fullscreen , isExpanded } = this . state ;
2016-09-15 18:21:51 -04:00
if ( status === null ) {
2016-10-07 10:00:11 -04:00
return (
< Column >
2017-02-19 02:32:35 -05:00
< ColumnBackButton / >
2017-02-26 17:06:27 -05:00
< MissingIndicator / >
2016-10-07 10:00:11 -04:00
< / C o l u m n >
) ;
2016-09-15 18:21:51 -04:00
}
2016-10-30 10:06:43 -04:00
if ( ancestorsIds && ancestorsIds . size > 0 ) {
2016-10-24 11:11:02 -04:00
ancestors = < div > { this . renderChildren ( ancestorsIds ) } < / d i v > ;
}
2016-10-30 10:06:43 -04:00
if ( descendantsIds && descendantsIds . size > 0 ) {
2016-10-24 11:11:02 -04:00
descendants = < div > { this . renderChildren ( descendantsIds ) } < / d i v > ;
}
2017-10-05 19:07:59 -04:00
const handlers = {
moveUp : this . handleHotkeyMoveUp ,
moveDown : this . handleHotkeyMoveDown ,
reply : this . handleHotkeyReply ,
favourite : this . handleHotkeyFavourite ,
boost : this . handleHotkeyBoost ,
mention : this . handleHotkeyMention ,
openProfile : this . handleHotkeyOpenProfile ,
2017-11-27 17:05:03 -05:00
toggleSpoiler : this . handleExpandedToggle ,
2017-10-05 19:07:59 -04:00
} ;
2016-09-15 18:21:51 -04:00
return (
2018-08-28 06:01:04 -04:00
< Column label = { intl . formatMessage ( messages . detailedStatus ) } >
2018-03-28 13:56:46 -04:00
< ColumnHeader
showBackButton
extraButton = { (
< button className = 'column-header__button' title = { intl . formatMessage ( ! isExpanded ? messages . revealAll : messages . hideAll ) } aria - label = { intl . formatMessage ( ! isExpanded ? messages . revealAll : messages . hideAll ) } onClick = { this . handleToggleAll } aria - pressed = { ! isExpanded ? 'false' : 'true' } > < i className = { ` fa fa- ${ ! isExpanded ? 'eye-slash' : 'eye' } ` } / > < / b u t t o n >
) }
/ >
2016-09-18 07:03:37 -04:00
2018-07-27 11:59:52 -04:00
< ScrollContainer scrollKey = 'thread' shouldUpdateScroll = { this . shouldUpdateScroll } >
2017-11-07 08:24:55 -05:00
< div className = { classNames ( 'scrollable' , 'detailed-status__wrapper' , { fullscreen } ) } ref = { this . setRef } >
2016-10-24 11:11:02 -04:00
{ ancestors }
2016-09-18 07:03:37 -04:00
2017-10-05 19:07:59 -04:00
< HotKeys handlers = { handlers } >
2018-08-28 06:10:40 -04:00
< div className = 'focusable' tabIndex = '0' aria - label = { textForScreenReader ( intl , status , false , ! status . get ( 'hidden' ) ) } >
2017-10-05 19:07:59 -04:00
< DetailedStatus
status = { status }
2017-10-11 13:43:10 -04:00
settings = { settings }
2017-10-05 19:07:59 -04:00
onOpenVideo = { this . handleOpenVideo }
onOpenMedia = { this . handleOpenMedia }
2017-11-27 17:05:03 -05:00
expanded = { isExpanded }
2018-03-28 13:56:46 -04:00
onToggleHidden = { this . handleExpandedToggle }
2017-10-05 19:07:59 -04:00
/ >
< ActionBar
status = { status }
onReply = { this . handleReplyClick }
onFavourite = { this . handleFavouriteClick }
onReblog = { this . handleReblogClick }
2018-04-11 13:42:25 -04:00
onBookmark = { this . handleBookmarkClick }
2017-10-05 19:07:59 -04:00
onDelete = { this . handleDeleteClick }
2018-04-10 15:38:02 -04:00
onDirect = { this . handleDirectClick }
2017-10-05 19:07:59 -04:00
onMention = { this . handleMentionClick }
2017-12-26 11:13:38 -05:00
onMute = { this . handleMuteClick }
onMuteConversation = { this . handleConversationMuteClick }
onBlock = { this . handleBlockClick }
2017-10-05 19:07:59 -04:00
onReport = { this . handleReport }
onPin = { this . handlePin }
onEmbed = { this . handleEmbed }
/ >
< / d i v >
< / H o t K e y s >
2016-10-19 12:20:19 -04:00
2016-10-24 11:11:02 -04:00
{ descendants }
2016-10-19 12:20:19 -04:00
< / d i v >
< / S c r o l l C o n t a i n e r >
2016-10-07 10:00:11 -04:00
< / C o l u m n >
2016-09-15 18:21:51 -04:00
) ;
}
2017-04-21 14:05:35 -04:00
}