diff --git a/app/assets/javascripts/components/actions/accounts.jsx b/app/assets/javascripts/components/actions/accounts.jsx
index 4847c37e290..c1c99d6bd8b 100644
--- a/app/assets/javascripts/components/actions/accounts.jsx
+++ b/app/assets/javascripts/components/actions/accounts.jsx
@@ -57,7 +57,16 @@ export function fetchAccountTimeline(id) {
return (dispatch, getState) => {
dispatch(fetchAccountTimelineRequest(id));
- api(getState).get(`/api/v1/accounts/${id}/statuses`).then(response => {
+ const ids = getState().getIn(['timelines', 'accounts_timelines', id], Immutable.List());
+ const newestId = ids.size > 0 ? ids.first() : null;
+
+ let params = '';
+
+ if (newestId !== null) {
+ params = `?since_id=${newestId}`;
+ }
+
+ api(getState).get(`/api/v1/accounts/${id}/statuses${params}`).then(response => {
dispatch(fetchAccountTimelineSuccess(id, response.data));
}).catch(error => {
dispatch(fetchAccountTimelineFail(id, error));
diff --git a/app/assets/javascripts/components/actions/timelines.jsx b/app/assets/javascripts/components/actions/timelines.jsx
index f92f758f5a8..5258d7103e6 100644
--- a/app/assets/javascripts/components/actions/timelines.jsx
+++ b/app/assets/javascripts/components/actions/timelines.jsx
@@ -45,7 +45,16 @@ export function refreshTimeline(timeline) {
return function (dispatch, getState) {
dispatch(refreshTimelineRequest(timeline));
- api(getState).get(`/api/v1/statuses/${timeline}`).then(function (response) {
+ const ids = getState().getIn(['timelines', timeline]);
+ const newestId = ids.size > 0 ? ids.first() : null;
+
+ let params = '';
+
+ if (newestId !== null) {
+ params = `?since_id=${newestId}`;
+ }
+
+ api(getState).get(`/api/v1/statuses/${timeline}${params}`).then(function (response) {
dispatch(refreshTimelineSuccess(timeline, response.data));
}).catch(function (error) {
dispatch(refreshTimelineFail(timeline, error));
diff --git a/app/assets/javascripts/components/components/status_list.jsx b/app/assets/javascripts/components/components/status_list.jsx
index f70d5326359..4977d84ce28 100644
--- a/app/assets/javascripts/components/components/status_list.jsx
+++ b/app/assets/javascripts/components/components/status_list.jsx
@@ -1,6 +1,7 @@
-import Status from './status';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import PureRenderMixin from 'react-addons-pure-render-mixin';
+import Status from './status';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+import { ScrollContainer } from 'react-router-scroll';
const StatusList = React.createClass({
@@ -11,9 +12,16 @@ const StatusList = React.createClass({
onFavourite: React.PropTypes.func,
onDelete: React.PropTypes.func,
onScrollToBottom: React.PropTypes.func,
+ trackScroll: React.PropTypes.bool,
me: React.PropTypes.number
},
+ getDefaultProps () {
+ return {
+ trackScroll: true
+ };
+ },
+
mixins: [PureRenderMixin],
handleScroll (e) {
@@ -25,9 +33,9 @@ const StatusList = React.createClass({
},
render () {
- const { statuses, onScrollToBottom, ...other } = this.props;
+ const { statuses, onScrollToBottom, trackScroll, ...other } = this.props;
- return (
+ const scrollableArea = (
{statuses.map((status) => {
@@ -36,6 +44,16 @@ const StatusList = React.createClass({
);
+
+ if (trackScroll) {
+ return (
+
+ {scrollableArea}
+
+ );
+ } else {
+ return scrollableArea;
+ }
}
});
diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx
index e5c0887a95c..4eb9f83c8de 100644
--- a/app/assets/javascripts/components/containers/mastodon.jsx
+++ b/app/assets/javascripts/components/containers/mastodon.jsx
@@ -10,11 +10,13 @@ import { setAccessToken } from '../actions/meta';
import { setAccountSelf } from '../actions/accounts';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import {
+ applyRouterMiddleware,
Router,
Route,
hashHistory,
IndexRoute
} from 'react-router';
+import { useScroll } from 'react-router-scroll';
import UI from '../features/ui';
import Account from '../features/account';
import Status from '../features/status';
@@ -71,7 +73,7 @@ const Mastodon = React.createClass({
render () {
return (
-
+
diff --git a/app/assets/javascripts/components/features/home_timeline/index.jsx b/app/assets/javascripts/components/features/home_timeline/index.jsx
index 9be3f3964be..e4cd8bdca96 100644
--- a/app/assets/javascripts/components/features/home_timeline/index.jsx
+++ b/app/assets/javascripts/components/features/home_timeline/index.jsx
@@ -19,7 +19,7 @@ const HomeTimeline = React.createClass({
render () {
return (
-
+
);
},
diff --git a/app/assets/javascripts/components/features/mentions_timeline/index.jsx b/app/assets/javascripts/components/features/mentions_timeline/index.jsx
index a1b511d3e80..919a75d1891 100644
--- a/app/assets/javascripts/components/features/mentions_timeline/index.jsx
+++ b/app/assets/javascripts/components/features/mentions_timeline/index.jsx
@@ -19,7 +19,7 @@ const MentionsTimeline = React.createClass({
render () {
return (
-
+
);
},
diff --git a/app/assets/javascripts/components/features/ui/index.jsx b/app/assets/javascripts/components/features/ui/index.jsx
index fab32a31e20..06a9d2f509d 100644
--- a/app/assets/javascripts/components/features/ui/index.jsx
+++ b/app/assets/javascripts/components/features/ui/index.jsx
@@ -28,8 +28,8 @@ const UI = React.createClass({
-
-
+
+
{this.props.children}
diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx
index 65bccb44d88..06534971d2e 100644
--- a/app/assets/javascripts/components/reducers/timelines.jsx
+++ b/app/assets/javascripts/components/reducers/timelines.jsx
@@ -85,7 +85,7 @@ function normalizeTimeline(state, timeline, statuses) {
ids = ids.set(i, status.get('id'));
});
- return state.set(timeline, ids);
+ return state.update(timeline, list => list.unshift(...ids));
};
function appendNormalizedTimeline(state, timeline, statuses) {
@@ -100,16 +100,14 @@ function appendNormalizedTimeline(state, timeline, statuses) {
};
function normalizeAccountTimeline(state, accountId, statuses) {
- state = state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => {
- return (list.size > 0) ? list.clear() : list;
- });
+ let ids = Immutable.List([]);
statuses.forEach((status, i) => {
state = normalizeStatus(state, status);
- state = state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => list.set(i, status.get('id')));
+ ids = ids.set(i, status.get('id'));
});
- return state;
+ return state.updateIn(['accounts_timelines', accountId], Immutable.List([]), list => list.unshift(...ids));
};
function appendNormalizedAccountTimeline(state, accountId, statuses) {
@@ -137,7 +135,7 @@ function updateTimeline(state, timeline, status) {
return list.unshift(status.get('id'));
});
- state = state.updateIn(['accounts_timelines', status.getIn(['account', 'id'])], Immutable.List([]), list => (list.includes(status.get('id')) ? list : list.unshift(status.get('id'))));
+ //state = state.updateIn(['accounts_timelines', status.getIn(['account', 'id'])], Immutable.List([]), list => (list.includes(status.get('id')) ? list : list.unshift(status.get('id'))));
return state;
};
diff --git a/package.json b/package.json
index 3d1878e15aa..78560f71721 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"sinon": "^1.17.6"
},
"dependencies": {
- "react-responsive": "^1.1.5"
+ "react-responsive": "^1.1.5",
+ "react-router-scroll": "^0.3.2"
}
}
diff --git a/yarn.lock b/yarn.lock
index 353106819a8..6ee2398186f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1743,6 +1743,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
+dom-helpers@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-2.4.0.tgz#9bb4b245f637367b1fa670274272aa28fe06c367"
+
dom-serializer@~0.1.0, dom-serializer@0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -3892,6 +3896,14 @@ react-responsive:
matchmedia "^0.1.2"
object-assign "^4.0.1"
+react-router-scroll:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/react-router-scroll/-/react-router-scroll-0.3.2.tgz#ba8b1d01b3681dc5a68d72865d35c10e84065e52"
+ dependencies:
+ history "^2.1.2"
+ scroll-behavior "^0.8.0"
+ warning "^3.0.0"
+
react-router@^2.8.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-2.8.1.tgz#73e9491f6ceb316d0f779829081863e378ee4ed7"
@@ -4147,6 +4159,13 @@ sax@^1.1.4, sax@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
+scroll-behavior@^0.8.0:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.8.2.tgz#ace13e40b001d8d4d007aec0e7fb668cf9043546"
+ dependencies:
+ dom-helpers "^2.4.0"
+ invariant "^2.2.1"
+
semver@~5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"