add reblogging/unreblogging
This commit is contained in:
parent
a82cc57f83
commit
00ccf35777
|
@ -5,7 +5,7 @@ import { toast } from '../_utils/toast'
|
|||
|
||||
export async function setFavorited (statusId, favorited) {
|
||||
if (!store.get('online')) {
|
||||
toast.say('You cannot favorite or unfavorite while offline.')
|
||||
toast.say(`You cannot ${favorited ? 'favorite' : 'unfavorite'} while offline.`)
|
||||
return
|
||||
}
|
||||
let instanceName = store.get('currentInstance')
|
||||
|
@ -22,6 +22,6 @@ export async function setFavorited (statusId, favorited) {
|
|||
store.set({statusModifications: statusModifications})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.say('Failed to favorite or unfavorite. ' + (e.message || ''))
|
||||
toast.say(`Failed to ${favorited ? 'favorite' : 'unfavorite'}. ` + (e.message || ''))
|
||||
}
|
||||
}
|
||||
|
|
27
routes/_actions/reblog.js
Normal file
27
routes/_actions/reblog.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { store } from '../_store/store'
|
||||
import { database } from '../_database/database'
|
||||
import { toast } from '../_utils/toast'
|
||||
import { reblogStatus, unreblogStatus } from '../_api/reblog'
|
||||
|
||||
export async function setReblogged (statusId, reblogged) {
|
||||
if (!store.get('online')) {
|
||||
toast.say(`You cannot ${reblogged ? 'boost' : 'unboost'} while offline.`)
|
||||
return
|
||||
}
|
||||
let instanceName = store.get('currentInstance')
|
||||
let accessToken = store.get('accessToken')
|
||||
try {
|
||||
await (reblogged
|
||||
? reblogStatus(instanceName, accessToken, statusId)
|
||||
: unreblogStatus(instanceName, accessToken, statusId))
|
||||
await database.setStatusReblogged(instanceName, statusId, reblogged)
|
||||
let statusModifications = store.get('statusModifications')
|
||||
let currentStatusModifications = statusModifications[instanceName] =
|
||||
(statusModifications[instanceName] || {favorites: {}, reblogs: {}})
|
||||
currentStatusModifications.reblogs[statusId] = reblogged
|
||||
store.set({statusModifications: statusModifications})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.say(`Failed to ${reblogged ? 'boost' : 'unboost'}. ` + (e.message || ''))
|
||||
}
|
||||
}
|
12
routes/_api/reblog.js
Normal file
12
routes/_api/reblog.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { post } from '../_utils/ajax'
|
||||
import { basename, auth } from './utils'
|
||||
|
||||
export async function reblogStatus (instanceName, accessToken, statusId) {
|
||||
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/reblog`
|
||||
return post(url, null, auth(accessToken))
|
||||
}
|
||||
|
||||
export async function unreblogStatus (instanceName, accessToken, statusId) {
|
||||
let url = `${basename(instanceName)}/api/v1/statuses/${statusId}/unreblog`
|
||||
return post(url, null, auth(accessToken))
|
||||
}
|
|
@ -4,11 +4,13 @@
|
|||
href="#fa-reply"
|
||||
/>
|
||||
<IconButton
|
||||
label="{{boostLabel}}"
|
||||
pressable="{{!boostDisabled}}"
|
||||
pressed="{{status.reblogged}}"
|
||||
disabled="{{boostDisabled}}"
|
||||
href="{{boostIcon}}"
|
||||
label="{{reblogLabel}}"
|
||||
pressable="{{!reblogDisabled}}"
|
||||
pressed="{{reblogged}}"
|
||||
disabled="{{reblogDisabled}}"
|
||||
href="{{reblogIcon}}"
|
||||
delegateKey="{{reblogKey}}"
|
||||
ref:reblogNode
|
||||
/>
|
||||
<IconButton
|
||||
label="Favorite"
|
||||
|
@ -38,17 +40,19 @@
|
|||
import { store } from '../../_store/store'
|
||||
import { registerClickDelegate, unregisterClickDelegate } from '../../_utils/delegate'
|
||||
import { setFavorited } from '../../_actions/favorite'
|
||||
import { setReblogged } from '../../_actions/reblog'
|
||||
|
||||
export default {
|
||||
oncreate() {
|
||||
this.onFavoriteClick = this.onFavoriteClick.bind(this)
|
||||
this.onReblogClick = this.onReblogClick.bind(this)
|
||||
|
||||
let favoriteKey = this.get('favoriteKey')
|
||||
registerClickDelegate(favoriteKey, this.onFavoriteClick)
|
||||
registerClickDelegate(this.get('favoriteKey'), this.onFavoriteClick)
|
||||
registerClickDelegate(this.get('reblogKey'), this.onReblogClick)
|
||||
},
|
||||
ondestroy() {
|
||||
let favoriteKey = this.get('favoriteKey')
|
||||
unregisterClickDelegate(favoriteKey)
|
||||
unregisterClickDelegate(this.get('favoriteKey'))
|
||||
unregisterClickDelegate(this.get('reblogKey'))
|
||||
},
|
||||
components: {
|
||||
IconButton
|
||||
|
@ -59,11 +63,16 @@
|
|||
let statusId = this.get('statusId')
|
||||
let favorited = this.get('favorited')
|
||||
/* no await */ setFavorited(statusId, !favorited)
|
||||
},
|
||||
onReblogClick() {
|
||||
let statusId = this.get('statusId')
|
||||
let reblogged = this.get('reblogged')
|
||||
/* no await */ setReblogged(statusId, !reblogged)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
visibility: (status) => status.visibility,
|
||||
boostLabel: (visibility) => {
|
||||
reblogLabel: (visibility) => {
|
||||
switch (visibility) {
|
||||
case 'private':
|
||||
return 'Cannot be boosted because this is followers-only'
|
||||
|
@ -73,7 +82,7 @@
|
|||
return 'Boost'
|
||||
}
|
||||
},
|
||||
boostIcon: (visibility) => {
|
||||
reblogIcon: (visibility) => {
|
||||
switch (visibility) {
|
||||
case 'private':
|
||||
return '#fa-lock'
|
||||
|
@ -83,9 +92,15 @@
|
|||
return '#fa-retweet'
|
||||
}
|
||||
},
|
||||
boostDisabled: (visibility) => {
|
||||
reblogDisabled: (visibility) => {
|
||||
return visibility === 'private' || visibility === 'direct'
|
||||
},
|
||||
reblogged: (status, $currentStatusModifications) => {
|
||||
if ($currentStatusModifications && status.id in $currentStatusModifications.reblogs) {
|
||||
return $currentStatusModifications.reblogs[status.id]
|
||||
}
|
||||
return status.reblogged
|
||||
},
|
||||
favorited: (status, $currentStatusModifications) => {
|
||||
if ($currentStatusModifications && status.id in $currentStatusModifications.favorites) {
|
||||
return $currentStatusModifications.favorites[status.id]
|
||||
|
@ -93,7 +108,8 @@
|
|||
return status.favourited
|
||||
},
|
||||
statusId: (status) => status.id,
|
||||
favoriteKey: (statusId, timelineType, timelineValue) => `fav-${timelineType}-${timelineValue}-${statusId}`
|
||||
favoriteKey: (statusId, timelineType, timelineValue) => `fav-${timelineType}-${timelineValue}-${statusId}`,
|
||||
reblogKey: (statusId, timelineType, timelineValue) => `reblog-${timelineType}-${timelineValue}-${statusId}`,
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -416,3 +416,11 @@ export async function setStatusFavorited (instanceName, statusId, favorited) {
|
|||
status.favourites_count = (status.favourites_count || 0) + delta
|
||||
})
|
||||
}
|
||||
|
||||
export async function setStatusReblogged (instanceName, statusId, reblogged) {
|
||||
return updateStatus(instanceName, statusId, status => {
|
||||
let delta = (reblogged ? 1 : 0) - (status.reblogged ? 1 : 0)
|
||||
status.reblogged = reblogged
|
||||
status.reblogs_count = (status.reblogs_count || 0) + delta
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ function fetchWithTimeout (url, options) {
|
|||
})
|
||||
}
|
||||
|
||||
async function throwErrorIfInvalidResponse(response) {
|
||||
async function throwErrorIfInvalidResponse (response) {
|
||||
let json = await response.json()
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return json
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
} from '../utils'
|
||||
import { foobarRole } from '../roles'
|
||||
|
||||
fixture`12-favorite-unfavorite.js`
|
||||
fixture`30-favorite-unfavorite.js`
|
||||
.page`http://localhost:4002`
|
||||
|
||||
test('favorites a status', async t => {
|
||||
|
@ -54,7 +54,7 @@ test('unfavorites a status', async t => {
|
|||
.expect(getNthFavorited(1)).eql('true')
|
||||
})
|
||||
|
||||
test('Keeps the correct count', async t => {
|
||||
test('Keeps the correct favorites count', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
.hover(getNthStatus(4))
|
||||
.click(getNthFavoriteButton(4))
|
78
tests/spec/31-reblog-unreblog.js
Normal file
78
tests/spec/31-reblog-unreblog.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
import {
|
||||
getNthReblogButton, getNthReblogged, getNthStatus, getReblogsCount, getUrl, homeNavButton,
|
||||
notificationsNavButton,
|
||||
scrollToBottomOfTimeline, scrollToTopOfTimeline
|
||||
} from '../utils'
|
||||
import { foobarRole } from '../roles'
|
||||
|
||||
fixture`31-reblog-unreblog.js`
|
||||
.page`http://localhost:4002`
|
||||
|
||||
test('reblogs a status', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
.hover(getNthStatus(0))
|
||||
.expect(getNthReblogged(0)).eql('false')
|
||||
.click(getNthReblogButton(0))
|
||||
.expect(getNthReblogged(0)).eql('true')
|
||||
|
||||
// scroll down and back up to force an unrender
|
||||
await scrollToBottomOfTimeline(t)
|
||||
await scrollToTopOfTimeline(t)
|
||||
await t
|
||||
.hover(getNthStatus(0))
|
||||
.expect(getNthReblogged(0)).eql('true')
|
||||
.click(notificationsNavButton)
|
||||
.click(homeNavButton)
|
||||
.expect(getNthReblogged(0)).eql('true')
|
||||
.click(notificationsNavButton)
|
||||
.expect(getUrl()).contains('/notifications')
|
||||
.click(homeNavButton)
|
||||
.expect(getUrl()).eql('http://localhost:4002/')
|
||||
.expect(getNthReblogged(0)).eql('true')
|
||||
.click(getNthReblogButton(0))
|
||||
.expect(getNthReblogged(0)).eql('false')
|
||||
})
|
||||
|
||||
test('unreblogs a status', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
.hover(getNthStatus(4))
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
.click(getNthReblogButton(4))
|
||||
.expect(getNthReblogged(4)).eql('true')
|
||||
.click(getNthReblogButton(4))
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
|
||||
// scroll down and back up to force an unrender
|
||||
await scrollToBottomOfTimeline(t)
|
||||
await scrollToTopOfTimeline(t)
|
||||
await t
|
||||
.hover(getNthStatus(4))
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
.click(notificationsNavButton)
|
||||
.click(homeNavButton)
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
.click(notificationsNavButton)
|
||||
.navigateTo('/')
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
.click(getNthReblogButton(4))
|
||||
.expect(getNthReblogged(4)).eql('true')
|
||||
})
|
||||
|
||||
test('Keeps the correct reblogs count', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
.hover(getNthStatus(4))
|
||||
.expect(getNthReblogged(4)).eql('true')
|
||||
.click(getNthStatus(4))
|
||||
.expect(getUrl()).contains('/status')
|
||||
.expect(getNthReblogged(0)).eql('true')
|
||||
.expect(getReblogsCount()).eql(2)
|
||||
.click(homeNavButton)
|
||||
.expect(getUrl()).eql('http://localhost:4002/')
|
||||
.hover(getNthStatus(4))
|
||||
.click(getNthReblogButton(4))
|
||||
.expect(getNthReblogged(4)).eql('false')
|
||||
.click(getNthStatus(4))
|
||||
.expect(getUrl()).contains('/status')
|
||||
.expect(getNthReblogged(0)).eql('false')
|
||||
.expect(getReblogsCount()).eql(1)
|
||||
})
|
|
@ -51,6 +51,14 @@ export function getFavoritesCount () {
|
|||
return favoritesCountElement.innerCount
|
||||
}
|
||||
|
||||
export function getNthReblogButton (n) {
|
||||
return getNthStatus(n).find('.status-toolbar button:nth-child(2)')
|
||||
}
|
||||
|
||||
export function getNthReblogged (n) {
|
||||
return getNthReblogButton(n).getAttribute('aria-pressed')
|
||||
}
|
||||
|
||||
export function getReblogsCount () {
|
||||
return reblogsCountElement.innerCount
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue