Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions src/components/layout/ThreadPagination.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<template>
<div v-if="pageCount > 1" class="pagination-component">
<ul class="pagination no-select">
<span v-for="pageKey in paginationKeys" :key="pageKey.val">
<li :class="pageKey.class">
<a href="#" @click.stop.prevent="gotoThreadPage(pageKey.page)" v-html="pageKey.val"></a>
</li>
</span>
</ul>
</div>
</template>

<script>
import { computed, reactive, toRefs, watch } from 'vue'
import { useRouter } from 'vue-router'

export default {
props: ['limit', 'count', 'slug'],
setup(props) {
/* View Methods */
const gotoThreadPage = page => {
// do nothing if no page is specified, or if page is out of range
if (!page || page > v.pageCount || page < 1) return

$router.push({
name: 'Posts',
params: { threadSlug: props.slug },
query: {
page: (page === 1 || page === 'all') ? undefined : page,
limit: page === 'all' ? 100 : undefined
}
})
}

const buildPages = () => {
// reset pagination keys
v.paginationKeys = []

// max pages before truncation
let pageMax = 5

// variable to hold ellipsis positions
let ellipsis

if (v.pageCount > pageMax)
ellipsis = [{ index: 3, nextIndex: v.pageCount - 1 }]

generatePageKeys(ellipsis)
}

const generatePageKeys = (ellipsis) => {
// Add Pagination Keys accounting for ellipsis
let ellipsisIndex = 0
let index = 1
// max posts before 'all' option is no longer displayed
let postMax = 100

while (index <= v.pageCount) {
let pageKey
// Insert ellipsis if index matches
if (ellipsis && ellipsis[ellipsisIndex] && ellipsis[ellipsisIndex].index === index) {
pageKey = {
val: '&hellip;',
page: null,
class: 'unavailable'
}
index = ellipsis[ellipsisIndex].nextIndex
ellipsisIndex++
}
// Otherwise generate page key
else {
pageKey = {
val: index,
page: index,
class: null
}
index++
}
v.paginationKeys.push(pageKey)
}

// Show all option if there are less than
// or equal to postMax posts in the thread
if (props.count <= postMax)
v.paginationKeys.push({
val: 'all',
page: 'all',
class: null
})
}

/* Internal Data */
const $router = useRouter()

/* View Data */
const v = reactive({
paginationKeys: [],
pageCount: computed(() => Math.ceil(props.count / props.limit) || 1)
})

buildPages()

/* Watch - this handles when pagination data changes */
watch(() => props.limit, () => buildPages())
watch(() => props.count, () => buildPages())

return { ...toRefs(v), gotoThreadPage }
}
}
</script>

<style lang="scss">
.thread-pagination {
margin-bottom: -0.65rem;
ul.pagination {
display: inline-block;
min-height: 1.3rem;
li {
line-height: 1.3rem;
font-size: 0.875rem;
margin-left: 0.125rem;
float: left;
display: block;
&.unavailable a:hover { background-color: transparent; }
&.current a, &.current a:hover { color: $button-text-color; }
&.arrow { font-family: 'Zapf Dingbats'; }
a {
@include transition(background-color 300ms ease-out);
display: block;
padding: 0.0325rem 0.325rem 0.0325rem;
color: $secondary-font-color;
background: none;
border-radius: 3px;
font-weight: normal;
font-size: 0.875rem;
line-height: inherit;
&:hover { color: $secondary-font-color-dark; background-color: $secondary-font-color-light; }
}
}
li.unavailable a { cursor: default; color: $secondary-font-color; }
li.current a {
background: $color-primary;
&:hover, &:focus { background: $color-primary-alt; }
}
}
}
</style>
2 changes: 1 addition & 1 deletion src/components/polls/PollViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
</span>
<input v-if="pollCopy.max_answers === 1 && canVote()" @click="pollAnswers.pop(); toggleAnswer(answer.id);" name="pollanswer" type="radio">
<input type="checkbox" @click="toggleAnswer(answer.id)" :disabled="pollAnswers.length >= pollCopy.max_answers && pollAnswers.indexOf(answer.id) === -1" :checked="pollAnswers.indexOf(answer.id) > -1" v-if="pollCopy.max_answers > 1 && canVote()"/>
<span>{{answer.answer}}</span>
<span v-html="answer.answer"></span>
</label>
<div v-if="showPollResults()" class="poll-results">
<div class="poll-results-data">
Expand Down
2 changes: 1 addition & 1 deletion src/components/threads/RecentThreads.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
</div>
<div class="user">
in
<router-link v-if="thread?.board" class="thread-board" :title="decode(thread.board.name)" :to="{ name: 'Threads', params: { boardSlug: thread.board.slug } }" onclick="event.stopPropagation()">{{decode(thread.board.name)}}</router-link>
<router-link v-if="thread?.board" class="thread-board" :title="decode(thread.board.name)" :to="{ name: 'Threads', params: { boardSlug: thread.board.slug } }" onclick="event.stopPropagation()"><span v-html="decode(thread.board.name)"></span></router-link>
by
<span v-if="thread.deleted">deleted</span>
<router-link onclick="event.stopPropagation()" v-if="!thread.deleted" :to="{ path: '/profile/' + thread?.user?.username.toLowerCase() }">{{thread?.user?.username}}</router-link>
Expand Down
4 changes: 2 additions & 2 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const routes = [
name: 'Profile',
component: Profile,
props: true,
meta: { requiresAuth: true, bodyClass: 'profile' },
meta: { requiresAuth: false, bodyClass: 'profile' },
children: [{
path: '',
name: 'Profile.UserPosts',
Expand All @@ -251,7 +251,7 @@ const routes = [
user: usersApi.find(route.params.username).then(u => u),
username: route.params.username
}),
meta: { requiresAuth: true, bodyClass: 'user-posts' }
meta: { requiresAuth: false, bodyClass: 'user-posts' }
},
{
path: '/profile/:username/trust',
Expand Down
2 changes: 1 addition & 1 deletion src/views/Posts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
</svg>
</span>
<router-link :to="{ path: '/profile/' + post.user.username.toLowerCase() }">
<img :src="'https://bitcointalk.org' + post.avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" />
<img :src="post.avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" />
</router-link>
</div>
<router-link :to="{ path: '/profile/' + post.user.username.toLowerCase() }">
Expand Down
12 changes: 9 additions & 3 deletions src/views/Threads.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@

<td class="last-post">
<span v-if="thread.last_deleted">deleted</span>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }"><img class="avatar-small" :class="defaultAvatarShape" :src="'https://bitcointalk.org/' + thread.last_post_avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" /></router-link>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }"><img class="avatar-small" :class="defaultAvatarShape" :src="thread.last_post_avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" /></router-link>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }">
<span v-html="thread.last_post_username"></span>
</router-link> posted on
Expand Down Expand Up @@ -193,6 +193,10 @@
</router-link>
<span> on {{ humanDate(thread.created_at)}}</span>
</div>

<div v-if="thread.post_count > posts_per_page" class="thread-pagination">
<thread-pagination :slug="thread.slug" :limit="posts_per_page" :count="thread.post_count" />
</div>
</td>

<td class="views-replies" v-if="thread.user.username">
Expand All @@ -202,7 +206,7 @@

<td class="last-post" v-if="thread.user.username">
<span v-if="thread.last_deleted">deleted</span>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }"><img class="avatar-small" :class="defaultAvatar" :src="'https://bitcointalk.org/' + thread.last_post_avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" /></router-link>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }"><img class="avatar-small" :class="defaultAvatar" :src="thread.last_post_avatar || defaultAvatar" @error="$event.target.src=defaultAvatar" /></router-link>
<router-link v-if="!thread.last_deleted" :to="{ path: '/profile/' + thread.last_post_username.toLowerCase() }"><span v-html="thread.last_post_username"></span></router-link> posted on <router-link :to="{ name: 'Posts', params: { threadSlug: thread.slug }, query: { start: thread.last_post_position }, hash: '#' + thread.last_post_id }"><span>{{humanDate(thread.last_post_created_at)}}</span>.</router-link>
<router-link v-if="thread.has_new_post" :to="{ name: 'Posts', params: { threadSlug: thread.slug }, query: { start: thread.latest_unread_position }, hash: '#' + thread.latest_unread_post_id }">(Last unread post)</router-link>
</td>
Expand Down Expand Up @@ -239,6 +243,7 @@

<script>
import { useRoute, useRouter } from 'vue-router'
import ThreadPagination from '@/components/layout/ThreadPagination.vue'
import Pagination from '@/components/layout/Pagination.vue'
import SetModeratorsModal from '@/components/modals/admin/management/SetModerators.vue'
import humanDate from '@/composables/filters/humanDate'
Expand All @@ -257,7 +262,7 @@ import slugify from 'slugify'
export default {
name: 'Threads',
props: ['boardSlug', 'boardId'],
components: { Pagination, SetModeratorsModal, Editor },
components: { ThreadPagination, Pagination, SetModeratorsModal, Editor },
beforeRouteEnter(to, from, next) {
const params = {
limit: to.query.limit || localStoragePrefs().data.threads_per_page,
Expand Down Expand Up @@ -424,6 +429,7 @@ export default {
showSetModerators: false,
defaultAvatar: window.default_avatar,
defaultAvatarShape: window.default_avatar_shape,
posts_per_page: localStoragePrefs().data.posts_per_page,
sortField: $route.query.field ? $route.query.field : 'updated_at',
sortItems: [
{
Expand Down