Improve modal flow and back button handling (#16499)

* Refactor shouldUpdateScroll passing

So far, shouldUpdateScroll has been manually passed down from the very top of
the React component hierarchy even though it is a static function common to
all ScrollContainer instances, so replaced that with a custom class extending
ScrollContainer.

* Generalize “press back to close modal” to any modal and to public pages

* Fix boost confirmation modal closing media modal
shrike
Claire 2021-07-13 15:45:17 +02:00 committed by GitHub
parent a2ce7508c9
commit d3791cca0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 120 additions and 197 deletions

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import 'wicg-inert'; import 'wicg-inert';
import { createBrowserHistory } from 'history';
import { multiply } from 'color-blend'; import { multiply } from 'color-blend';
export default class ModalRoot extends React.PureComponent { export default class ModalRoot extends React.PureComponent {
@ -48,6 +49,7 @@ export default class ModalRoot extends React.PureComponent {
componentDidMount () { componentDidMount () {
window.addEventListener('keyup', this.handleKeyUp, false); window.addEventListener('keyup', this.handleKeyUp, false);
window.addEventListener('keydown', this.handleKeyDown, false); window.addEventListener('keydown', this.handleKeyDown, false);
this.history = this.context.router ? this.context.router.history : createBrowserHistory();
} }
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
@ -69,6 +71,14 @@ export default class ModalRoot extends React.PureComponent {
this.activeElement.focus({ preventScroll: true }); this.activeElement.focus({ preventScroll: true });
this.activeElement = null; this.activeElement = null;
}).catch(console.error); }).catch(console.error);
this._handleModalClose();
}
if (this.props.children && !prevProps.children) {
this._handleModalOpen();
}
if (this.props.children) {
this._ensureHistoryBuffer();
} }
} }
@ -77,6 +87,32 @@ export default class ModalRoot extends React.PureComponent {
window.removeEventListener('keydown', this.handleKeyDown); window.removeEventListener('keydown', this.handleKeyDown);
} }
_handleModalOpen () {
this._modalHistoryKey = Date.now();
this.unlistenHistory = this.history.listen((_, action) => {
if (action === 'POP') {
this.props.onClose();
}
});
}
_handleModalClose () {
if (this.unlistenHistory) {
this.unlistenHistory();
}
const { state } = this.history.location;
if (state && state.mastodonModalKey === this._modalHistoryKey) {
this.history.goBack();
}
}
_ensureHistoryBuffer () {
const { pathname, state } = this.history.location;
if (!state || state.mastodonModalKey !== this._modalHistoryKey) {
this.history.push(pathname, { ...state, mastodonModalKey: this._modalHistoryKey });
}
}
getSiblings = () => { getSiblings = () => {
return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node); return Array(...this.node.parentElement.childNodes).filter(node => node !== this.node);
} }

View File

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { ScrollContainer } from 'react-router-scroll-4'; import ScrollContainer from 'mastodon/containers/scroll_container';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container'; import IntersectionObserverArticleContainer from '../containers/intersection_observer_article_container';
import LoadMore from './load_more'; import LoadMore from './load_more';
@ -34,7 +34,6 @@ class ScrollableList extends PureComponent {
onScrollToTop: PropTypes.func, onScrollToTop: PropTypes.func,
onScroll: PropTypes.func, onScroll: PropTypes.func,
trackScroll: PropTypes.bool, trackScroll: PropTypes.bool,
shouldUpdateScroll: PropTypes.func,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
showLoading: PropTypes.bool, showLoading: PropTypes.bool,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
@ -290,7 +289,7 @@ class ScrollableList extends PureComponent {
} }
render () { render () {
const { children, scrollKey, trackScroll, shouldUpdateScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props; const { children, scrollKey, trackScroll, showLoading, isLoading, hasMore, numPending, prepend, alwaysPrepend, append, emptyMessage, onLoadMore } = this.props;
const { fullscreen } = this.state; const { fullscreen } = this.state;
const childrenCount = React.Children.count(children); const childrenCount = React.Children.count(children);
@ -356,7 +355,7 @@ class ScrollableList extends PureComponent {
if (trackScroll) { if (trackScroll) {
return ( return (
<ScrollContainer scrollKey={scrollKey} shouldUpdateScroll={shouldUpdateScroll}> <ScrollContainer scrollKey={scrollKey}>
{scrollableArea} {scrollableArea}
</ScrollContainer> </ScrollContainer>
); );

View File

@ -18,7 +18,6 @@ export default class StatusList extends ImmutablePureComponent {
onScrollToTop: PropTypes.func, onScrollToTop: PropTypes.func,
onScroll: PropTypes.func, onScroll: PropTypes.func,
trackScroll: PropTypes.bool, trackScroll: PropTypes.bool,
shouldUpdateScroll: PropTypes.func,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
isPartial: PropTypes.bool, isPartial: PropTypes.bool,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
@ -77,7 +76,7 @@ export default class StatusList extends ImmutablePureComponent {
} }
render () { render () {
const { statusIds, featuredStatusIds, shouldUpdateScroll, onLoadMore, timelineId, ...other } = this.props; const { statusIds, featuredStatusIds, onLoadMore, timelineId, ...other } = this.props;
const { isLoading, isPartial } = other; const { isLoading, isPartial } = other;
if (isPartial) { if (isPartial) {
@ -120,7 +119,7 @@ export default class StatusList extends ImmutablePureComponent {
} }
return ( return (
<ScrollableList {...other} showLoading={isLoading && statusIds.size === 0} onLoadMore={onLoadMore && this.handleLoadOlder} shouldUpdateScroll={shouldUpdateScroll} ref={this.setRef}> <ScrollableList {...other} showLoading={isLoading && statusIds.size === 0} onLoadMore={onLoadMore && this.handleLoadOlder} ref={this.setRef}>
{scrollableContent} {scrollableContent}
</ScrollableList> </ScrollableList>
); );

View File

@ -10,8 +10,6 @@ import { hydrateStore } from '../actions/store';
import { connectUserStream } from '../actions/streaming'; import { connectUserStream } from '../actions/streaming';
import { IntlProvider, addLocaleData } from 'react-intl'; import { IntlProvider, addLocaleData } from 'react-intl';
import { getLocale } from '../locales'; import { getLocale } from '../locales';
import { previewState as previewMediaState } from 'mastodon/features/ui/components/media_modal';
import { previewState as previewVideoState } from 'mastodon/features/ui/components/video_modal';
import initialState from '../initial_state'; import initialState from '../initial_state';
import ErrorBoundary from '../components/error_boundary'; import ErrorBoundary from '../components/error_boundary';
@ -41,8 +39,8 @@ export default class Mastodon extends React.PureComponent {
} }
} }
shouldUpdateScroll (_, { location }) { shouldUpdateScroll (prevRouterProps, { location }) {
return location.state !== previewMediaState && location.state !== previewVideoState; return !(location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey);
} }
render () { render () {

View File

@ -0,0 +1,18 @@
import { ScrollContainer as OriginalScrollContainer } from 'react-router-scroll-4';
// ScrollContainer is used to automatically scroll to the top when pushing a
// new history state and remembering the scroll position when going back.
// There are a few things we need to do differently, though.
const defaultShouldUpdateScroll = (prevRouterProps, { location }) => {
// If the change is caused by opening a modal, do not scroll to top
return !(location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey);
};
export default
class ScrollContainer extends OriginalScrollContainer {
static defaultProps = {
shouldUpdateScroll: defaultShouldUpdateScroll,
};
}

View File

@ -11,7 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { getAccountGallery } from 'mastodon/selectors'; import { getAccountGallery } from 'mastodon/selectors';
import MediaItem from './components/media_item'; import MediaItem from './components/media_item';
import HeaderContainer from '../account_timeline/containers/header_container'; import HeaderContainer from '../account_timeline/containers/header_container';
import { ScrollContainer } from 'react-router-scroll-4'; import ScrollContainer from 'mastodon/containers/scroll_container';
import LoadMore from 'mastodon/components/load_more'; import LoadMore from 'mastodon/components/load_more';
import MissingIndicator from 'mastodon/components/missing_indicator'; import MissingIndicator from 'mastodon/components/missing_indicator';
import { openModal } from 'mastodon/actions/modal'; import { openModal } from 'mastodon/actions/modal';
@ -29,7 +29,6 @@ const mapStateToProps = (state, props) => ({
class LoadMoreMedia extends ImmutablePureComponent { class LoadMoreMedia extends ImmutablePureComponent {
static propTypes = { static propTypes = {
shouldUpdateScroll: PropTypes.func,
maxId: PropTypes.string, maxId: PropTypes.string,
onLoadMore: PropTypes.func.isRequired, onLoadMore: PropTypes.func.isRequired,
}; };
@ -127,7 +126,7 @@ class AccountGallery extends ImmutablePureComponent {
} }
render () { render () {
const { attachments, shouldUpdateScroll, isLoading, hasMore, isAccount, multiColumn, blockedBy, suspended } = this.props; const { attachments, isLoading, hasMore, isAccount, multiColumn, blockedBy, suspended } = this.props;
const { width } = this.state; const { width } = this.state;
if (!isAccount) { if (!isAccount) {
@ -164,7 +163,7 @@ class AccountGallery extends ImmutablePureComponent {
<Column> <Column>
<ColumnBackButton multiColumn={multiColumn} /> <ColumnBackButton multiColumn={multiColumn} />
<ScrollContainer scrollKey='account_gallery' shouldUpdateScroll={shouldUpdateScroll}> <ScrollContainer scrollKey='account_gallery'>
<div className='scrollable scrollable--flex' onScroll={this.handleScroll}> <div className='scrollable scrollable--flex' onScroll={this.handleScroll}>
<HeaderContainer accountId={this.props.params.accountId} /> <HeaderContainer accountId={this.props.params.accountId} />

View File

@ -50,7 +50,6 @@ class AccountTimeline extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
statusIds: ImmutablePropTypes.list, statusIds: ImmutablePropTypes.list,
featuredStatusIds: ImmutablePropTypes.list, featuredStatusIds: ImmutablePropTypes.list,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
@ -115,7 +114,7 @@ class AccountTimeline extends ImmutablePureComponent {
} }
render () { render () {
const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, suspended, isAccount, multiColumn, remote, remoteUrl } = this.props; const { statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, suspended, isAccount, multiColumn, remote, remoteUrl } = this.props;
if (!isAccount) { if (!isAccount) {
return ( return (
@ -162,7 +161,6 @@ class AccountTimeline extends ImmutablePureComponent {
isLoading={isLoading} isLoading={isLoading}
hasMore={hasMore} hasMore={hasMore}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
timelineId='account' timelineId='account'

View File

@ -29,7 +29,6 @@ class Blocks extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
@ -46,7 +45,7 @@ class Blocks extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, accountIds, shouldUpdateScroll, hasMore, multiColumn, isLoading } = this.props; const { intl, accountIds, hasMore, multiColumn, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -66,7 +65,6 @@ class Blocks extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >

View File

@ -27,7 +27,6 @@ class Bookmarks extends ImmutablePureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
statusIds: ImmutablePropTypes.list.isRequired, statusIds: ImmutablePropTypes.list.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
columnId: PropTypes.string, columnId: PropTypes.string,
@ -68,7 +67,7 @@ class Bookmarks extends ImmutablePureComponent {
}, 300, { leading: true }) }, 300, { leading: true })
render () { render () {
const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
const emptyMessage = <FormattedMessage id='empty_column.bookmarked_statuses' defaultMessage="You don't have any bookmarked toots yet. When you bookmark one, it will show up here." />; const emptyMessage = <FormattedMessage id='empty_column.bookmarked_statuses' defaultMessage="You don't have any bookmarked toots yet. When you bookmark one, it will show up here." />;
@ -93,7 +92,6 @@ class Bookmarks extends ImmutablePureComponent {
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />

View File

@ -41,7 +41,6 @@ class CommunityTimeline extends React.PureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
columnId: PropTypes.string, columnId: PropTypes.string,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
@ -103,7 +102,7 @@ class CommunityTimeline extends React.PureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, hasUnread, columnId, multiColumn, onlyMedia } = this.props; const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
return ( return (
@ -127,7 +126,6 @@ class CommunityTimeline extends React.PureComponent {
timelineId={`community${onlyMedia ? ':media' : ''}`} timelineId={`community${onlyMedia ? ':media' : ''}`}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />} emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -14,7 +14,6 @@ export default class ConversationsList extends ImmutablePureComponent {
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
onLoadMore: PropTypes.func, onLoadMore: PropTypes.func,
shouldUpdateScroll: PropTypes.func,
}; };
getCurrentIndex = id => this.props.conversations.findIndex(x => x.get('id') === id) getCurrentIndex = id => this.props.conversations.findIndex(x => x.get('id') === id)

View File

@ -19,7 +19,6 @@ class DirectTimeline extends React.PureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
columnId: PropTypes.string, columnId: PropTypes.string,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
@ -71,7 +70,7 @@ class DirectTimeline extends React.PureComponent {
} }
render () { render () {
const { intl, hasUnread, columnId, multiColumn, shouldUpdateScroll } = this.props; const { intl, hasUnread, columnId, multiColumn } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
return ( return (
@ -93,7 +92,6 @@ class DirectTimeline extends React.PureComponent {
timelineId='direct' timelineId='direct'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />} emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />}
shouldUpdateScroll={shouldUpdateScroll}
/> />
</Column> </Column>
); );

View File

@ -12,7 +12,7 @@ import AccountCard from './components/account_card';
import RadioButton from 'mastodon/components/radio_button'; import RadioButton from 'mastodon/components/radio_button';
import classNames from 'classnames'; import classNames from 'classnames';
import LoadMore from 'mastodon/components/load_more'; import LoadMore from 'mastodon/components/load_more';
import { ScrollContainer } from 'react-router-scroll-4'; import ScrollContainer from 'mastodon/containers/scroll_container';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'column.directory', defaultMessage: 'Browse profiles' }, title: { id: 'column.directory', defaultMessage: 'Browse profiles' },
@ -40,7 +40,6 @@ class Directory extends React.PureComponent {
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
accountIds: ImmutablePropTypes.list.isRequired, accountIds: ImmutablePropTypes.list.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
columnId: PropTypes.string, columnId: PropTypes.string,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -125,7 +124,7 @@ class Directory extends React.PureComponent {
} }
render () { render () {
const { isLoading, accountIds, intl, columnId, multiColumn, domain, shouldUpdateScroll } = this.props; const { isLoading, accountIds, intl, columnId, multiColumn, domain } = this.props;
const { order, local } = this.getParams(this.props, this.state); const { order, local } = this.getParams(this.props, this.state);
const pinned = !!columnId; const pinned = !!columnId;
@ -163,7 +162,7 @@ class Directory extends React.PureComponent {
multiColumn={multiColumn} multiColumn={multiColumn}
/> />
{multiColumn && !pinned ? <ScrollContainer scrollKey='directory' shouldUpdateScroll={shouldUpdateScroll}>{scrollableArea}</ScrollContainer> : scrollableArea} {multiColumn && !pinned ? <ScrollContainer scrollKey='directory'>{scrollableArea}</ScrollContainer> : scrollableArea}
</Column> </Column>
); );
} }

View File

@ -29,7 +29,6 @@ class Blocks extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
domains: ImmutablePropTypes.orderedSet, domains: ImmutablePropTypes.orderedSet,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
@ -45,7 +44,7 @@ class Blocks extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, domains, shouldUpdateScroll, hasMore, multiColumn } = this.props; const { intl, domains, hasMore, multiColumn } = this.props;
if (!domains) { if (!domains) {
return ( return (
@ -64,7 +63,6 @@ class Blocks extends ImmutablePureComponent {
scrollKey='domain_blocks' scrollKey='domain_blocks'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >

View File

@ -27,7 +27,6 @@ class Favourites extends ImmutablePureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
statusIds: ImmutablePropTypes.list.isRequired, statusIds: ImmutablePropTypes.list.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
columnId: PropTypes.string, columnId: PropTypes.string,
@ -68,7 +67,7 @@ class Favourites extends ImmutablePureComponent {
}, 300, { leading: true }) }, 300, { leading: true })
render () { render () {
const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const { intl, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite toots yet. When you favourite one, it will show up here." />; const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite toots yet. When you favourite one, it will show up here." />;
@ -93,7 +92,6 @@ class Favourites extends ImmutablePureComponent {
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />

View File

@ -27,7 +27,6 @@ class Favourites extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
@ -50,7 +49,7 @@ class Favourites extends ImmutablePureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, accountIds, multiColumn } = this.props; const { intl, accountIds, multiColumn } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -74,7 +73,6 @@ class Favourites extends ImmutablePureComponent {
<ScrollableList <ScrollableList
scrollKey='favourites' scrollKey='favourites'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >

View File

@ -32,7 +32,6 @@ class FollowRequests extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
@ -51,7 +50,7 @@ class FollowRequests extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, shouldUpdateScroll, accountIds, hasMore, multiColumn, locked, domain, isLoading } = this.props; const { intl, accountIds, hasMore, multiColumn, locked, domain, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -80,7 +79,6 @@ class FollowRequests extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
prepend={unlockedPrependMessage} prepend={unlockedPrependMessage}

View File

@ -43,7 +43,6 @@ class Followers extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
@ -73,7 +72,7 @@ class Followers extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props; const { accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props;
if (!isAccount) { if (!isAccount) {
return ( return (
@ -112,7 +111,6 @@ class Followers extends ImmutablePureComponent {
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}
alwaysPrepend alwaysPrepend
append={remoteMessage} append={remoteMessage}

View File

@ -43,7 +43,6 @@ class Following extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
@ -73,7 +72,7 @@ class Following extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props; const { accountIds, hasMore, blockedBy, isAccount, multiColumn, isLoading, remote, remoteUrl } = this.props;
if (!isAccount) { if (!isAccount) {
return ( return (
@ -112,7 +111,6 @@ class Following extends ImmutablePureComponent {
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
shouldUpdateScroll={shouldUpdateScroll}
prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />} prepend={<HeaderContainer accountId={this.props.params.accountId} hideTabs />}
alwaysPrepend alwaysPrepend
append={remoteMessage} append={remoteMessage}

View File

@ -24,7 +24,6 @@ class HashtagTimeline extends React.PureComponent {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
columnId: PropTypes.string, columnId: PropTypes.string,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
}; };
@ -130,7 +129,7 @@ class HashtagTimeline extends React.PureComponent {
} }
render () { render () {
const { shouldUpdateScroll, hasUnread, columnId, multiColumn } = this.props; const { hasUnread, columnId, multiColumn } = this.props;
const { id, local } = this.props.params; const { id, local } = this.props.params;
const pinned = !!columnId; const pinned = !!columnId;
@ -156,7 +155,6 @@ class HashtagTimeline extends React.PureComponent {
timelineId={`hashtag:${id}${local ? ':local' : ''}`} timelineId={`hashtag:${id}${local ? ':local' : ''}`}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />} emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -34,7 +34,6 @@ class HomeTimeline extends React.PureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
isPartial: PropTypes.bool, isPartial: PropTypes.bool,
@ -112,7 +111,7 @@ class HomeTimeline extends React.PureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props; const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
let announcementsButton = null; let announcementsButton = null;
@ -154,7 +153,6 @@ class HomeTimeline extends React.PureComponent {
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
timelineId='home' timelineId='home'
emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Follow more people to fill it up. {suggestions}' values={{ suggestions: <Link to='/start'><FormattedMessage id='empty_column.home.suggestions' defaultMessage='See some suggestions' /></Link> }} />} emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Follow more people to fill it up. {suggestions}' values={{ suggestions: <Link to='/start'><FormattedMessage id='empty_column.home.suggestions' defaultMessage='See some suggestions' /></Link> }} />}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -41,7 +41,6 @@ class ListTimeline extends React.PureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
columnId: PropTypes.string, columnId: PropTypes.string,
hasUnread: PropTypes.bool, hasUnread: PropTypes.bool,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -142,7 +141,7 @@ class ListTimeline extends React.PureComponent {
} }
render () { render () {
const { shouldUpdateScroll, hasUnread, columnId, multiColumn, list, intl } = this.props; const { hasUnread, columnId, multiColumn, list, intl } = this.props;
const { id } = this.props.params; const { id } = this.props.params;
const pinned = !!columnId; const pinned = !!columnId;
const title = list ? list.get('title') : id; const title = list ? list.get('title') : id;
@ -207,7 +206,6 @@ class ListTimeline extends React.PureComponent {
timelineId={`list:${id}`} timelineId={`list:${id}`}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />} emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -48,7 +48,7 @@ class Lists extends ImmutablePureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, lists, multiColumn } = this.props; const { intl, lists, multiColumn } = this.props;
if (!lists) { if (!lists) {
return ( return (
@ -68,7 +68,6 @@ class Lists extends ImmutablePureComponent {
<ScrollableList <ScrollableList
scrollKey='lists' scrollKey='lists'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />} prepend={<ColumnSubheading text={intl.formatMessage(messages.subheading)} />}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View File

@ -29,7 +29,6 @@ class Mutes extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
@ -46,7 +45,7 @@ class Mutes extends ImmutablePureComponent {
}, 300, { leading: true }); }, 300, { leading: true });
render () { render () {
const { intl, shouldUpdateScroll, hasMore, accountIds, multiColumn, isLoading } = this.props; const { intl, hasMore, accountIds, multiColumn, isLoading } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -66,7 +65,6 @@ class Mutes extends ImmutablePureComponent {
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
hasMore={hasMore} hasMore={hasMore}
isLoading={isLoading} isLoading={isLoading}
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >

View File

@ -74,7 +74,6 @@ class Notifications extends React.PureComponent {
notifications: ImmutablePropTypes.list.isRequired, notifications: ImmutablePropTypes.list.isRequired,
showFilterBar: PropTypes.bool.isRequired, showFilterBar: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
isUnread: PropTypes.bool, isUnread: PropTypes.bool,
@ -176,7 +175,7 @@ class Notifications extends React.PureComponent {
}; };
render () { render () {
const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props; const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, showFilterBar, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. When other people interact with you, you will see it here." />; const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. When other people interact with you, you will see it here." />;
@ -227,7 +226,6 @@ class Notifications extends React.PureComponent {
onLoadPending={this.handleLoadPending} onLoadPending={this.handleLoadPending}
onScrollToTop={this.handleScrollToTop} onScrollToTop={this.handleScrollToTop}
onScroll={this.handleScroll} onScroll={this.handleScroll}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >
{scrollableContent} {scrollableContent}

View File

@ -24,7 +24,6 @@ class PinnedStatuses extends ImmutablePureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
statusIds: ImmutablePropTypes.list.isRequired, statusIds: ImmutablePropTypes.list.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
hasMore: PropTypes.bool.isRequired, hasMore: PropTypes.bool.isRequired,
@ -44,7 +43,7 @@ class PinnedStatuses extends ImmutablePureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, statusIds, hasMore, multiColumn } = this.props; const { intl, statusIds, hasMore, multiColumn } = this.props;
return ( return (
<Column bindToDocument={!multiColumn} icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}> <Column bindToDocument={!multiColumn} icon='thumb-tack' heading={intl.formatMessage(messages.heading)} ref={this.setRef}>
@ -53,7 +52,6 @@ class PinnedStatuses extends ImmutablePureComponent {
statusIds={statusIds} statusIds={statusIds}
scrollKey='pinned_statuses' scrollKey='pinned_statuses'
hasMore={hasMore} hasMore={hasMore}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -43,7 +43,6 @@ class PublicTimeline extends React.PureComponent {
static propTypes = { static propTypes = {
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
columnId: PropTypes.string, columnId: PropTypes.string,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
@ -106,7 +105,7 @@ class PublicTimeline extends React.PureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, columnId, hasUnread, multiColumn, onlyMedia, onlyRemote } = this.props; const { intl, columnId, hasUnread, multiColumn, onlyMedia, onlyRemote } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
return ( return (
@ -130,7 +129,6 @@ class PublicTimeline extends React.PureComponent {
trackScroll={!pinned} trackScroll={!pinned}
scrollKey={`public_timeline-${columnId}`} scrollKey={`public_timeline-${columnId}`}
emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />} emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />}
shouldUpdateScroll={shouldUpdateScroll}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
/> />
</Column> </Column>

View File

@ -27,7 +27,6 @@ class Reblogs extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
shouldUpdateScroll: PropTypes.func,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
multiColumn: PropTypes.bool, multiColumn: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
@ -50,7 +49,7 @@ class Reblogs extends ImmutablePureComponent {
} }
render () { render () {
const { intl, shouldUpdateScroll, accountIds, multiColumn } = this.props; const { intl, accountIds, multiColumn } = this.props;
if (!accountIds) { if (!accountIds) {
return ( return (
@ -74,7 +73,6 @@ class Reblogs extends ImmutablePureComponent {
<ScrollableList <ScrollableList
scrollKey='reblogs' scrollKey='reblogs'
shouldUpdateScroll={shouldUpdateScroll}
emptyMessage={emptyMessage} emptyMessage={emptyMessage}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}
> >

View File

@ -45,7 +45,7 @@ import { initBlockModal } from '../../actions/blocks';
import { initBoostModal } from '../../actions/boosts'; import { initBoostModal } from '../../actions/boosts';
import { initReport } from '../../actions/reports'; import { initReport } from '../../actions/reports';
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors'; import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
import { ScrollContainer } from 'react-router-scroll-4'; import ScrollContainer from 'mastodon/containers/scroll_container';
import ColumnBackButton from '../../components/column_back_button'; import ColumnBackButton from '../../components/column_back_button';
import ColumnHeader from '../../components/column_header'; import ColumnHeader from '../../components/column_header';
import StatusContainer from '../../containers/status_container'; import StatusContainer from '../../containers/status_container';
@ -498,7 +498,7 @@ class Status extends ImmutablePureComponent {
render () { render () {
let ancestors, descendants; let ancestors, descendants;
const { shouldUpdateScroll, status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props; const { status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props;
const { fullscreen } = this.state; const { fullscreen } = this.state;
if (status === null) { if (status === null) {
@ -541,7 +541,7 @@ class Status extends ImmutablePureComponent {
)} )}
/> />
<ScrollContainer scrollKey='thread' shouldUpdateScroll={shouldUpdateScroll}> <ScrollContainer scrollKey='thread'>
<div className={classNames('scrollable', { fullscreen })} ref={this.setRef}> <div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
{ancestors} {ancestors}

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import Audio from 'mastodon/features/audio'; import Audio from 'mastodon/features/audio';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { previewState } from './video_modal';
import Footer from 'mastodon/features/picture_in_picture/components/footer'; import Footer from 'mastodon/features/picture_in_picture/components/footer';
const mapStateToProps = (state, { statusId }) => ({ const mapStateToProps = (state, { statusId }) => ({
@ -25,32 +24,6 @@ class AudioModal extends ImmutablePureComponent {
onChangeBackgroundColor: PropTypes.func.isRequired, onChangeBackgroundColor: PropTypes.func.isRequired,
}; };
static contextTypes = {
router: PropTypes.object,
};
componentDidMount () {
if (this.context.router) {
const history = this.context.router.history;
history.push(history.location.pathname, previewState);
this.unlistenHistory = history.listen(() => {
this.props.onClose();
});
}
}
componentWillUnmount () {
if (this.context.router) {
this.unlistenHistory();
if (this.context.router.history.location.state === previewState) {
this.context.router.history.goBack();
}
}
}
render () { render () {
const { media, accountStaticAvatar, statusId, onClose } = this.props; const { media, accountStaticAvatar, statusId, onClose } = this.props;
const options = this.props.options || {}; const options = this.props.options || {};

View File

@ -20,8 +20,6 @@ const messages = defineMessages({
next: { id: 'lightbox.next', defaultMessage: 'Next' }, next: { id: 'lightbox.next', defaultMessage: 'Next' },
}); });
export const previewState = 'previewMediaModal';
export default @injectIntl export default @injectIntl
class MediaModal extends ImmutablePureComponent { class MediaModal extends ImmutablePureComponent {
@ -37,10 +35,6 @@ class MediaModal extends ImmutablePureComponent {
volume: PropTypes.number, volume: PropTypes.number,
}; };
static contextTypes = {
router: PropTypes.object,
};
state = { state = {
index: null, index: null,
navigationHidden: false, navigationHidden: false,
@ -98,16 +92,6 @@ class MediaModal extends ImmutablePureComponent {
componentDidMount () { componentDidMount () {
window.addEventListener('keydown', this.handleKeyDown, false); window.addEventListener('keydown', this.handleKeyDown, false);
if (this.context.router) {
const history = this.context.router.history;
history.push(history.location.pathname, previewState);
this.unlistenHistory = history.listen(() => {
this.props.onClose();
});
}
this._sendBackgroundColor(); this._sendBackgroundColor();
} }
@ -131,14 +115,6 @@ class MediaModal extends ImmutablePureComponent {
componentWillUnmount () { componentWillUnmount () {
window.removeEventListener('keydown', this.handleKeyDown); window.removeEventListener('keydown', this.handleKeyDown);
if (this.context.router) {
this.unlistenHistory();
if (this.context.router.history.location.state === previewState) {
this.context.router.history.goBack();
}
}
this.props.onChangeBackgroundColor(null); this.props.onChangeBackgroundColor(null);
} }

View File

@ -6,8 +6,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import Footer from 'mastodon/features/picture_in_picture/components/footer'; import Footer from 'mastodon/features/picture_in_picture/components/footer';
import { getAverageFromBlurhash } from 'mastodon/blurhash'; import { getAverageFromBlurhash } from 'mastodon/blurhash';
export const previewState = 'previewVideoModal';
export default class VideoModal extends ImmutablePureComponent { export default class VideoModal extends ImmutablePureComponent {
static propTypes = { static propTypes = {
@ -22,19 +20,9 @@ export default class VideoModal extends ImmutablePureComponent {
onChangeBackgroundColor: PropTypes.func.isRequired, onChangeBackgroundColor: PropTypes.func.isRequired,
}; };
static contextTypes = {
router: PropTypes.object,
};
componentDidMount () { componentDidMount () {
const { router } = this.context;
const { media, onChangeBackgroundColor, onClose } = this.props; const { media, onChangeBackgroundColor, onClose } = this.props;
if (router) {
router.history.push(router.history.location.pathname, previewState);
this.unlistenHistory = router.history.listen(() => onClose());
}
const backgroundColor = getAverageFromBlurhash(media.get('blurhash')); const backgroundColor = getAverageFromBlurhash(media.get('blurhash'));
if (backgroundColor) { if (backgroundColor) {
@ -42,18 +30,6 @@ export default class VideoModal extends ImmutablePureComponent {
} }
} }
componentWillUnmount () {
const { router } = this.context;
if (router) {
this.unlistenHistory();
if (router.history.location.state === previewState) {
router.history.goBack();
}
}
}
render () { render () {
const { media, statusId, onClose } = this.props; const { media, statusId, onClose } = this.props;
const options = this.props.options || {}; const options = this.props.options || {};

View File

@ -3,8 +3,8 @@ import { closeModal } from '../../../actions/modal';
import ModalRoot from '../components/modal_root'; import ModalRoot from '../components/modal_root';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
type: state.get('modal').modalType, type: state.getIn(['modal', 0, 'modalType'], null),
props: state.get('modal').modalProps, props: state.getIn(['modal', 0, 'modalProps'], {}),
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -54,8 +54,6 @@ import {
FollowRecommendations, FollowRecommendations,
} from './util/async-components'; } from './util/async-components';
import { me } from '../../initial_state'; import { me } from '../../initial_state';
import { previewState as previewMediaState } from './components/media_modal';
import { previewState as previewVideoState } from './components/video_modal';
import { closeOnboarding, INTRODUCTION_VERSION } from 'mastodon/actions/onboarding'; import { closeOnboarding, INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
// Dummy import, to make sure that <Status /> ends up in the application bundle. // Dummy import, to make sure that <Status /> ends up in the application bundle.
@ -138,10 +136,6 @@ class SwitchingColumnsArea extends React.PureComponent {
} }
} }
shouldUpdateScroll (_, { location }) {
return location.state !== previewMediaState && location.state !== previewVideoState;
}
setRef = c => { setRef = c => {
if (c) { if (c) {
this.node = c.getWrappedInstance(); this.node = c.getWrappedInstance();
@ -158,38 +152,38 @@ class SwitchingColumnsArea extends React.PureComponent {
{redirect} {redirect}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} /> <WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} /> <WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} />
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
<WrappedRoute path='/notifications' component={Notifications} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/notifications' component={Notifications} content={children} />
<WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/favourites' component={FavouritedStatuses} content={children} />
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} /> <WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
<WrappedRoute path='/start' component={FollowRecommendations} content={children} /> <WrappedRoute path='/start' component={FollowRecommendations} content={children} />
<WrappedRoute path='/search' component={Search} content={children} /> <WrappedRoute path='/search' component={Search} content={children} />
<WrappedRoute path='/directory' component={Directory} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/directory' component={Directory} content={children} />
<WrappedRoute path='/statuses/new' component={Compose} content={children} /> <WrappedRoute path='/statuses/new' component={Compose} content={children} />
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
<WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/statuses/:statusId/reblogs' component={Reblogs} content={children} />
<WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/statuses/:statusId/favourites' component={Favourites} content={children} />
<WrappedRoute path='/accounts/:accountId' exact component={AccountTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/accounts/:accountId' exact component={AccountTimeline} content={children} />
<WrappedRoute path='/accounts/:accountId/with_replies' component={AccountTimeline} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll, withReplies: true }} /> <WrappedRoute path='/accounts/:accountId/with_replies' component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />
<WrappedRoute path='/accounts/:accountId/followers' component={Followers} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/accounts/:accountId/followers' component={Followers} content={children} />
<WrappedRoute path='/accounts/:accountId/following' component={Following} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/accounts/:accountId/following' component={Following} content={children} />
<WrappedRoute path='/accounts/:accountId/media' component={AccountGallery} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/accounts/:accountId/media' component={AccountGallery} content={children} />
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
<WrappedRoute path='/blocks' component={Blocks} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/blocks' component={Blocks} content={children} />
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
<WrappedRoute path='/mutes' component={Mutes} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/mutes' component={Mutes} content={children} />
<WrappedRoute path='/lists' component={Lists} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} /> <WrappedRoute path='/lists' component={Lists} content={children} />
<WrappedRoute component={GenericNotFound} content={children} /> <WrappedRoute component={GenericNotFound} content={children} />
</WrappedSwitch> </WrappedSwitch>

View File

@ -1,19 +1,15 @@
import { MODAL_OPEN, MODAL_CLOSE } from '../actions/modal'; import { MODAL_OPEN, MODAL_CLOSE } from '../actions/modal';
import { TIMELINE_DELETE } from '../actions/timelines'; import { TIMELINE_DELETE } from '../actions/timelines';
import { Stack as ImmutableStack, Map as ImmutableMap } from 'immutable';
const initialState = { export default function modal(state = ImmutableStack(), action) {
modalType: null,
modalProps: {},
};
export default function modal(state = initialState, action) {
switch(action.type) { switch(action.type) {
case MODAL_OPEN: case MODAL_OPEN:
return { modalType: action.modalType, modalProps: action.modalProps }; return state.unshift(ImmutableMap({ modalType: action.modalType, modalProps: action.modalProps }));
case MODAL_CLOSE: case MODAL_CLOSE:
return (action.modalType === undefined || action.modalType === state.modalType) ? initialState : state; return (action.modalType === undefined || action.modalType === state.getIn([0, 'modalType'])) ? state.shift() : state;
case TIMELINE_DELETE: case TIMELINE_DELETE:
return (state.modalProps.statusId === action.id) ? initialState : state; return state.filterNot((modal) => modal.get('modalProps').statusId === action.id);
default: default:
return state; return state;
} }