add status context

This commit is contained in:
Nolan Lawson 2018-01-28 15:44:33 -08:00
parent 8b282de973
commit 6b2f16f3bf
11 changed files with 90 additions and 14 deletions

View file

@ -17,5 +17,6 @@ module.exports = [
{id:'fa-lock', src:'node_modules/font-awesome-svg-png/white/svg/lock.svg', title: 'Locked'}, {id:'fa-lock', src:'node_modules/font-awesome-svg-png/white/svg/lock.svg', title: 'Locked'},
{id:'fa-envelope', src:'node_modules/font-awesome-svg-png/white/svg/envelope.svg', title: 'Sealed Envelope'}, {id:'fa-envelope', src:'node_modules/font-awesome-svg-png/white/svg/envelope.svg', title: 'Sealed Envelope'},
{id:'fa-user-times', src:'node_modules/font-awesome-svg-png/white/svg/user-times.svg', title: 'Stop Following'}, {id:'fa-user-times', src:'node_modules/font-awesome-svg-png/white/svg/user-times.svg', title: 'Stop Following'},
{id:'fa-user-plus', src:'node_modules/font-awesome-svg-png/white/svg/user-plus.svg', title: 'Follow'} {id:'fa-user-plus', src:'node_modules/font-awesome-svg-png/white/svg/user-plus.svg', title: 'Follow'},
{id:'fa-comments', src:'node_modules/font-awesome-svg-png/white/svg/comments.svg', title: 'Statuses'},
] ]

View file

@ -31,6 +31,8 @@ async function fetchStatuses(instanceName, accessToken, timelineName, lastStatus
} }
async function addStatuses(instanceName, timelineName, newStatuses) { async function addStatuses(instanceName, timelineName, newStatuses) {
console.log('addStatuses, length:', newStatuses.length)
debugger
mark('addStatuses') mark('addStatuses')
let newStatusIds = newStatuses.map(status => status.id) let newStatusIds = newStatuses.map(status => status.id)
let oldStatusIds = store.getForTimeline(instanceName, timelineName, 'statusIds') || [] let oldStatusIds = store.getForTimeline(instanceName, timelineName, 'statusIds') || []

View file

@ -20,7 +20,7 @@
<span class="status-author-handle"> <span class="status-author-handle">
{{'@' + originalAccount.acct}} {{'@' + originalAccount.acct}}
</span> </span>
<a class="status-author-date" rel="noopener" target="_blank" href="{{originalStatus.uri}}"> <a class="status-author-date" href="/statuses/{{originalStatus.id}}">
<time datetime={{createdAtDate}} title="{{relativeDate}}">{{relativeDate}}</time> <time datetime={{createdAtDate}} title="{{relativeDate}}">{{relativeDate}}</time>
</a> </a>
</div> </div>

View file

@ -34,16 +34,25 @@
}), }),
computed: { computed: {
makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId), makeProps: ($currentInstance) => (statusId) => database.getStatus($currentInstance, statusId),
label: (timeline, $currentInstance) => { label: (timeline, $currentInstance, timelineType, timelineValue) => {
if (timelines[timeline]) { if (timelines[timeline]) {
`${timelines[timeline].label} timeline for ${$currentInstance}` return `${timelines[timeline].label} timeline for ${$currentInstance}`
} else if (timeline.startsWith('tag/')) {
let tag = timeline.split('/').slice(-1)[0]
return `#${tag} timeline for ${$currentInstance}`
} else if (timeline.startsWith('account/')) {
let account = timeline.split('/').slice(-1)[0]
return `Account #${account} on ${$currentInstance}`
} }
switch (timelineType) {
case 'tag':
return `#${timelineValue} timeline for ${$currentInstance}`
case 'status':
return 'Status context'
case 'account':
return `Account #${timelineValue} on ${$currentInstance}`
}
},
timelineType: (timeline) => {
return timeline.split('/')[0]
},
timelineValue: (timeline) => {
return timeline.split('/').slice(-1)[0]
} }
}, },
store: () => store, store: () => store,
@ -58,7 +67,9 @@
initializeTimeline() initializeTimeline()
}, },
onScrollToBottom() { onScrollToBottom() {
if (!this.store.get('initialized') || this.store.get('runningUpdate')) { if (!this.store.get('initialized') ||
this.store.get('runningUpdate') ||
this.get('timelineType') === 'status') { // for status contexts, we've already fetched the whole thread
return return
} }
fetchStatusesOnScrollToBottom() fetchStatusesOnScrollToBottom()

View file

@ -30,7 +30,7 @@ export function instanceComputations(store) {
store.compute( store.compute(
'accessToken', 'accessToken',
['currentInstanceData'], ['currentInstanceData'],
(currentInstanceData) => currentInstanceData.access_token (currentInstanceData) => currentInstanceData && currentInstanceData.access_token
) )
store.compute( store.compute(

View file

@ -2,6 +2,8 @@ import { updateVerifyCredentialsForInstance } from '../settings/instances/_actio
export function observers(store) { export function observers(store) {
store.observe('currentInstance', (currentInstance) => { store.observe('currentInstance', (currentInstance) => {
if (currentInstance) {
updateVerifyCredentialsForInstance(currentInstance) updateVerifyCredentialsForInstance(currentInstance)
}
}) })
} }

View file

@ -18,6 +18,7 @@ export function mergeArrays(leftArray, rightArray) {
let left = leftArray[leftIndex] let left = leftArray[leftIndex]
let right = rightArray[rightIndex] let right = rightArray[rightIndex]
if (right === left) { if (right === left) {
merged.push(left)
rightIndex++ rightIndex++
leftIndex++ leftIndex++
} else if (parseInt(right, 10) > parseInt(left, 10)) { } else if (parseInt(right, 10) > parseInt(left, 10)) {

View file

@ -11,6 +11,8 @@ function getTimelineUrlPath(timeline) {
} }
if (timeline.startsWith('tag/')) { if (timeline.startsWith('tag/')) {
return 'timelines/tag' return 'timelines/tag'
} else if (timeline.startsWith('status/')) {
return 'statuses'
} else if (timeline.startsWith('account/')) { } else if (timeline.startsWith('account/')) {
return 'accounts' return 'accounts'
} }
@ -22,6 +24,8 @@ export function getTimeline(instanceName, accessToken, timeline, maxId, since) {
if (timeline.startsWith('tag/')) { if (timeline.startsWith('tag/')) {
url += '/' + timeline.split('/').slice(-1)[0] url += '/' + timeline.split('/').slice(-1)[0]
} else if (timeline.startsWith('status/')) {
url += '/' + timeline.split('/').slice(-1)[0] + '/context'
} else if (timeline.startsWith('account/')) { } else if (timeline.startsWith('account/')) {
url += '/' + timeline.split('/').slice(-1)[0] +'/statuses' url += '/' + timeline.split('/').slice(-1)[0] +'/statuses'
} }
@ -41,6 +45,17 @@ export function getTimeline(instanceName, accessToken, timeline, maxId, since) {
url += '?' + paramsString(params) url += '?' + paramsString(params)
if (timeline.startsWith('status/')) {
// special case - this is a list of descendents and ancestors
let statusUrl = `${basename(instanceName)}/api/v1/statuses/${timeline.split('/').slice(-1)[0]}}`
return Promise.all([
get(url, {'Authorization': `Bearer ${accessToken}`}),
get(statusUrl, {'Authorization': `Bearer ${accessToken}`})
]).then(res => {
return [].concat(res[0].ancestors).concat([res[1]]).concat(res[0].descendants)
})
}
return get(url, { return get(url, {
'Authorization': `Bearer ${accessToken}` 'Authorization': `Bearer ${accessToken}`
}) })

View file

@ -0,0 +1,43 @@
<:Head>
<title>Pinafore</title>
</:Head>
<Layout page='statuses'
virtual="true"
virtualRealm='status/{{params.statusId}}'
dynamicPage="Status"
dynamicHref="/statuses/{{params.statusId}}"
dynamicLabel="Status"
dynamicIcon="#fa-comments" >
{{#if $isUserLoggedIn}}
<DynamicPageBanner title="Status"/>
<LazyTimeline timeline='status/{{params.statusId}}' />
{{else}}
<HiddenFromSSR>
<FreeTextLayout>
<h1>Status</h1>
<p>A status thread will appear here when logged in.</p>
</FreeTextLayout>
</HiddenFromSSR>
{{/if}}
</Layout>
<script>
import Layout from '../_components/Layout.html'
import LazyTimeline from '../_components/timeline/LazyTimeline.html'
import FreeTextLayout from '../_components/FreeTextLayout.html'
import { store } from '../_store/store.js'
import HiddenFromSSR from '../_components/HiddenFromSSR'
import DynamicPageBanner from '../_components/DynamicPageBanner.html'
export default {
store: () => store,
components: {
Layout,
LazyTimeline,
FreeTextLayout,
HiddenFromSSR,
DynamicPageBanner
}
}
</script>

View file

@ -83,6 +83,7 @@ body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-o
<symbol id="fa-envelope" viewBox="0 0 1792 1792"><title>Sealed Envelope</title><path d="M1792 710v794q0 66-47 113t-113 47H160q-66 0-113-47T0 1504V710q44 49 101 87 362 246 497 345 57 42 92.5 65.5t94.5 48 110 24.5h2q51 0 110-24.5t94.5-48 92.5-65.5q170-123 498-345 57-39 100-87zm0-294q0 79-49 151t-122 123q-376 261-468 325-10 7-42.5 30.5t-54 38-52 32.5-57.5 27-50 9h-2q-23 0-50-9t-57.5-27-52-32.5-54-38T639 1015q-91-64-262-182.5T172 690q-62-42-117-115.5T0 438q0-78 41.5-130T160 256h1472q65 0 112.5 47t47.5 113z"></path></symbol> <symbol id="fa-envelope" viewBox="0 0 1792 1792"><title>Sealed Envelope</title><path d="M1792 710v794q0 66-47 113t-113 47H160q-66 0-113-47T0 1504V710q44 49 101 87 362 246 497 345 57 42 92.5 65.5t94.5 48 110 24.5h2q51 0 110-24.5t94.5-48 92.5-65.5q170-123 498-345 57-39 100-87zm0-294q0 79-49 151t-122 123q-376 261-468 325-10 7-42.5 30.5t-54 38-52 32.5-57.5 27-50 9h-2q-23 0-50-9t-57.5-27-52-32.5-54-38T639 1015q-91-64-262-182.5T172 690q-62-42-117-115.5T0 438q0-78 41.5-130T160 256h1472q65 0 112.5 47t47.5 113z"></path></symbol>
<symbol id="fa-user-times" viewBox="0 0 2048 1792"><title>Stop Following</title><path d="M704 896q-159 0-271.5-112.5T320 512t112.5-271.5T704 128t271.5 112.5T1088 512 975.5 783.5 704 896zm1077 320l249 249q9 9 9 23 0 13-9 22l-136 136q-9 9-22 9-14 0-23-9l-249-249-249 249q-9 9-23 9-13 0-22-9l-136-136q-9-9-9-22 0-14 9-23l249-249-249-249q-9-9-9-23 0-13 9-22l136-136q9-9 22-9 14 0 23 9l249 249 249-249q9-9 23-9 13 0 22 9l136 136q9 9 9 22 0 14-9 23zm-498 0l-181 181q-37 37-37 91 0 53 37 90l83 83q-21 3-44 3H267q-121 0-194-69T0 1405q0-53 3.5-103.5t14-109T44 1084t43-97.5 62-81 85.5-53.5T346 832q19 0 39 17 154 122 319 122t319-122q20-17 39-17 28 0 57 6-28 27-41 50t-13 56q0 54 37 91z"></path></symbol> <symbol id="fa-user-times" viewBox="0 0 2048 1792"><title>Stop Following</title><path d="M704 896q-159 0-271.5-112.5T320 512t112.5-271.5T704 128t271.5 112.5T1088 512 975.5 783.5 704 896zm1077 320l249 249q9 9 9 23 0 13-9 22l-136 136q-9 9-22 9-14 0-23-9l-249-249-249 249q-9 9-23 9-13 0-22-9l-136-136q-9-9-9-22 0-14 9-23l249-249-249-249q-9-9-9-23 0-13 9-22l136-136q9-9 22-9 14 0 23 9l249 249 249-249q9-9 23-9 13 0 22 9l136 136q9 9 9 22 0 14-9 23zm-498 0l-181 181q-37 37-37 91 0 53 37 90l83 83q-21 3-44 3H267q-121 0-194-69T0 1405q0-53 3.5-103.5t14-109T44 1084t43-97.5 62-81 85.5-53.5T346 832q19 0 39 17 154 122 319 122t319-122q20-17 39-17 28 0 57 6-28 27-41 50t-13 56q0 54 37 91z"></path></symbol>
<symbol id="fa-user-plus" viewBox="0 0 2048 1792"><title>Follow</title><path d="M704 896q-159 0-271.5-112.5T320 512t112.5-271.5T704 128t271.5 112.5T1088 512 975.5 783.5 704 896zm960 128h352q13 0 22.5 9.5t9.5 22.5v192q0 13-9.5 22.5t-22.5 9.5h-352v352q0 13-9.5 22.5t-22.5 9.5h-192q-13 0-22.5-9.5t-9.5-22.5v-352h-352q-13 0-22.5-9.5t-9.5-22.5v-192q0-13 9.5-22.5t22.5-9.5h352V672q0-13 9.5-22.5t22.5-9.5h192q13 0 22.5 9.5t9.5 22.5v352zm-736 224q0 52 38 90t90 38h256v238q-68 50-171 50H267q-121 0-194-69T0 1405q0-53 3.5-103.5t14-109T44 1084t43-97.5 62-81 85.5-53.5T346 832q19 0 39 17 79 61 154.5 91.5T704 971t164.5-30.5T1023 849q20-17 39-17 132 0 217 96h-223q-52 0-90 38t-38 90v192z"></path></symbol> <symbol id="fa-user-plus" viewBox="0 0 2048 1792"><title>Follow</title><path d="M704 896q-159 0-271.5-112.5T320 512t112.5-271.5T704 128t271.5 112.5T1088 512 975.5 783.5 704 896zm960 128h352q13 0 22.5 9.5t9.5 22.5v192q0 13-9.5 22.5t-22.5 9.5h-352v352q0 13-9.5 22.5t-22.5 9.5h-192q-13 0-22.5-9.5t-9.5-22.5v-352h-352q-13 0-22.5-9.5t-9.5-22.5v-192q0-13 9.5-22.5t22.5-9.5h352V672q0-13 9.5-22.5t22.5-9.5h192q13 0 22.5 9.5t9.5 22.5v352zm-736 224q0 52 38 90t90 38h256v238q-68 50-171 50H267q-121 0-194-69T0 1405q0-53 3.5-103.5t14-109T44 1084t43-97.5 62-81 85.5-53.5T346 832q19 0 39 17 79 61 154.5 91.5T704 971t164.5-30.5T1023 849q20-17 39-17 132 0 217 96h-223q-52 0-90 38t-38 90v192z"></path></symbol>
<symbol id="fa-comments" viewBox="0 0 1792 1792"><title>Statuses</title><path d="M1408 768q0 139-94 257t-256.5 186.5T704 1280q-86 0-176-16-124 88-278 128-36 9-86 16h-3q-11 0-20.5-8t-11.5-21q-1-3-1-6.5t.5-6.5 2-6l2.5-5 3.5-5.5 4-5 4.5-5 4-4.5q5-6 23-25t26-29.5 22.5-29 25-38.5 20.5-44q-124-72-195-177T0 768q0-139 94-257t256.5-186.5T704 256t353.5 68.5T1314 511t94 257zm384 256q0 120-71 224.5T1526 1425q10 24 20.5 44t25 38.5 22.5 29 26 29.5 23 25q1 1 4 4.5t4.5 5 4 5 3.5 5.5l2.5 5 2 6 .5 6.5-1 6.5q-3 14-13 22t-22 7q-50-7-86-16-154-40-278-128-90 16-176 16-271 0-472-132 58 4 88 4 161 0 309-45t264-129q125-92 192-212t67-254q0-77-23-152 129 71 204 178t75 230z"></path></symbol>
</svg><!-- end insert svg here --> </svg><!-- end insert svg here -->
</svg> </svg>
<!-- The application will be rendered inside this element, <!-- The application will be rendered inside this element,