about summary refs log tree commit diff
path: root/app/assets/javascripts/components/containers/mastodon.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/components/containers/mastodon.jsx')
-rw-r--r--app/assets/javascripts/components/containers/mastodon.jsx127
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} />