The code powering m.abunchtell.com https://m.abunchtell.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

107 lines
3.4 KiB

  1. import {
  2. ACCOUNT_BLOCK_SUCCESS,
  3. ACCOUNT_MUTE_SUCCESS,
  4. } from '../actions/accounts';
  5. import { CONTEXT_FETCH_SUCCESS } from '../actions/statuses';
  6. import { TIMELINE_DELETE, TIMELINE_UPDATE } from '../actions/timelines';
  7. import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
  8. import compareId from '../compare_id';
  9. const initialState = ImmutableMap({
  10. inReplyTos: ImmutableMap(),
  11. replies: ImmutableMap(),
  12. });
  13. const normalizeContext = (immutableState, id, ancestors, descendants) => immutableState.withMutations(state => {
  14. state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => {
  15. state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => {
  16. function addReply({ id, in_reply_to_id }) {
  17. if (in_reply_to_id && !inReplyTos.has(id)) {
  18. replies.update(in_reply_to_id, ImmutableList(), siblings => {
  19. const index = siblings.findLastIndex(sibling => compareId(sibling, id) < 0);
  20. return siblings.insert(index + 1, id);
  21. });
  22. inReplyTos.set(id, in_reply_to_id);
  23. }
  24. }
  25. // We know in_reply_to_id of statuses but `id` itself.
  26. // So we assume that the status of the id replies to last ancestors.
  27. ancestors.forEach(addReply);
  28. if (ancestors[0]) {
  29. addReply({ id, in_reply_to_id: ancestors[ancestors.length - 1].id });
  30. }
  31. descendants.forEach(addReply);
  32. }));
  33. }));
  34. });
  35. const deleteFromContexts = (immutableState, ids) => immutableState.withMutations(state => {
  36. state.update('inReplyTos', immutableAncestors => immutableAncestors.withMutations(inReplyTos => {
  37. state.update('replies', immutableDescendants => immutableDescendants.withMutations(replies => {
  38. ids.forEach(id => {
  39. const inReplyToIdOfId = inReplyTos.get(id);
  40. const repliesOfId = replies.get(id);
  41. const siblings = replies.get(inReplyToIdOfId);
  42. if (siblings) {
  43. replies.set(inReplyToIdOfId, siblings.filterNot(sibling => sibling === id));
  44. }
  45. if (repliesOfId) {
  46. repliesOfId.forEach(reply => inReplyTos.delete(reply));
  47. }
  48. inReplyTos.delete(id);
  49. replies.delete(id);
  50. });
  51. }));
  52. }));
  53. });
  54. const filterContexts = (state, relationship, statuses) => {
  55. const ownedStatusIds = statuses
  56. .filter(status => status.get('account') === relationship.id)
  57. .map(status => status.get('id'));
  58. return deleteFromContexts(state, ownedStatusIds);
  59. };
  60. const updateContext = (state, status) => {
  61. if (status.in_reply_to_id) {
  62. return state.withMutations(mutable => {
  63. const replies = mutable.getIn(['replies', status.in_reply_to_id], ImmutableList());
  64. mutable.setIn(['inReplyTos', status.id], status.in_reply_to_id);
  65. if (!replies.includes(status.id)) {
  66. mutable.setIn(['replies', status.in_reply_to_id], replies.push(status.id));
  67. }
  68. });
  69. }
  70. return state;
  71. };
  72. export default function replies(state = initialState, action) {
  73. switch(action.type) {
  74. case ACCOUNT_BLOCK_SUCCESS:
  75. case ACCOUNT_MUTE_SUCCESS:
  76. return filterContexts(state, action.relationship, action.statuses);
  77. case CONTEXT_FETCH_SUCCESS:
  78. return normalizeContext(state, action.id, action.ancestors, action.descendants);
  79. case TIMELINE_DELETE:
  80. return deleteFromContexts(state, [action.id]);
  81. case TIMELINE_UPDATE:
  82. return updateContext(state, action.status);
  83. default:
  84. return state;
  85. }
  86. };