diff options
author | Akihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp> | 2017-04-24 11:49:08 +0900 |
---|---|---|
committer | Eugen <eugen@zeonfederated.com> | 2017-04-24 04:49:08 +0200 |
commit | cf845fed3824d3e3587ce9b2ad752c2b3f0a2a76 (patch) | |
tree | fca5dab5974340cb98eaecd22ac41733f5c8cdd6 /app/assets/javascripts/components/containers | |
parent | 72c984e1057306d1e4df49871b9fb658fd7cbcc6 (diff) |
Hide some components rather than unmounting (#2271)
Hide some components rather than unmounting them to allow to show again quickly and keep the view state such as the scrolled offset.
Diffstat (limited to 'app/assets/javascripts/components/containers')
-rw-r--r-- | app/assets/javascripts/components/containers/mastodon.jsx | 127 |
1 files changed, 120 insertions, 7 deletions
diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx index e2b91e5dd..c85a353ee 100644 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ b/app/assets/javascripts/components/containers/mastodon.jsx @@ -99,6 +99,125 @@ addLocaleData([ ...id, ]); +const getTopWhenReplacing = (previous, { location }) => location && location.action === 'REPLACE' && [0, 0]; + +const hiddenColumnContainerStyle = { + position: 'absolute', + left: '0', + top: '0', + visibility: 'hidden' +}; + +class Container extends React.PureComponent { + + constructor(props) { + super(props); + + this.state = { + renderedPersistents: [], + unrenderedPersistents: [], + }; + } + + componentWillMount () { + this.unlistenHistory = null; + + this.setState(() => { + return { + mountImpersistent: false, + renderedPersistents: [], + unrenderedPersistents: [ + {pathname: '/timelines/home', component: HomeTimeline}, + {pathname: '/timelines/public', component: PublicTimeline}, + {pathname: '/timelines/public/local', component: CommunityTimeline}, + + {pathname: '/notifications', component: Notifications}, + {pathname: '/favourites', component: FavouritedStatuses} + ], + }; + }, () => { + if (this.unlistenHistory) { + return; + } + + this.unlistenHistory = browserHistory.listen(location => { + const pathname = location.pathname.replace(/\/$/, '').toLowerCase(); + + this.setState(oldState => { + let persistentMatched = false; + + const newState = { + renderedPersistents: oldState.renderedPersistents.map(persistent => { + const givenMatched = persistent.pathname === pathname; + + if (givenMatched) { + persistentMatched = true; + } + + return { + hidden: !givenMatched, + pathname: persistent.pathname, + component: persistent.component + }; + }), + }; + + if (!persistentMatched) { + newState.unrenderedPersistents = []; + + oldState.unrenderedPersistents.forEach(persistent => { + if (persistent.pathname === pathname) { + persistentMatched = true; + + newState.renderedPersistents.push({ + hidden: false, + pathname: persistent.pathname, + component: persistent.component + }); + } else { + newState.unrenderedPersistents.push(persistent); + } + }); + } + + newState.mountImpersistent = !persistentMatched; + + return newState; + }); + }); + }); + } + + componentWillUnmount () { + if (this.unlistenHistory) { + this.unlistenHistory(); + } + + this.unlistenHistory = "done"; + } + + render () { + // Hide some components rather than unmounting them to allow to show again + // quickly and keep the view state such as the scrolled offset. + const persistentsView = this.state.renderedPersistents.map((persistent) => + <div aria-hidden={persistent.hidden} key={persistent.pathname} className='mastodon-column-container' style={persistent.hidden ? hiddenColumnContainerStyle : null}> + <persistent.component shouldUpdateScroll={persistent.hidden ? Function.prototype : getTopWhenReplacing} /> + </div> + ); + + return ( + <UI> + {this.state.mountImpersistent && this.props.children} + {persistentsView} + </UI> + ); + } +} + +Container.propTypes = { + children: PropTypes.node, +}; + class Mastodon extends React.Component { componentDidMount() { @@ -160,18 +279,12 @@ class Mastodon extends React.Component { <IntlProvider locale={locale} messages={getMessagesForLocale(locale)}> <Provider store={store}> <Router history={browserHistory} render={applyRouterMiddleware(useScroll())}> - <Route path='/' component={UI}> + <Route path='/' component={Container}> <IndexRedirect to="/getting-started" /> <Route path='getting-started' component={GettingStarted} /> - <Route path='timelines/home' component={HomeTimeline} /> - <Route path='timelines/public' component={PublicTimeline} /> - <Route path='timelines/public/local' component={CommunityTimeline} /> <Route path='timelines/tag/:id' component={HashtagTimeline} /> - <Route path='notifications' component={Notifications} /> - <Route path='favourites' component={FavouritedStatuses} /> - <Route path='statuses/new' component={Compose} /> <Route path='statuses/:statusId' component={Status} /> <Route path='statuses/:statusId/reblogs' component={Reblogs} /> |