replace vue-timeago with custom timeago
This commit is contained in:
parent
88c3103755
commit
e2dc0d85fc
|
@ -33,7 +33,6 @@
|
||||||
"vue-popperjs": "^2.0.3",
|
"vue-popperjs": "^2.0.3",
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
"vue-template-compiler": "^2.3.4",
|
"vue-template-compiler": "^2.3.4",
|
||||||
"vue-timeago": "^3.1.2",
|
|
||||||
"vuelidate": "^0.7.4",
|
"vuelidate": "^0.7.4",
|
||||||
"vuex": "^3.0.1",
|
"vuex": "^3.0.1",
|
||||||
"whatwg-fetch": "^2.0.3"
|
"whatwg-fetch": "^2.0.3"
|
||||||
|
|
38
src/App.scss
38
src/App.scss
|
@ -182,7 +182,43 @@ input, textarea, .select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type=radio],
|
&[type=radio] {
|
||||||
|
display: none;
|
||||||
|
&:checked + label::before {
|
||||||
|
box-shadow: 0px 0px 2px black inset, 0px 0px 0px 4px $fallback--fg inset;
|
||||||
|
box-shadow: var(--inputShadow), 0px 0px 0px 4px var(--fg, $fallback--fg) inset;
|
||||||
|
background-color: var(--link, $fallback--link);
|
||||||
|
}
|
||||||
|
&:disabled {
|
||||||
|
&,
|
||||||
|
& + label,
|
||||||
|
& + label::before {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ label::before {
|
||||||
|
display: inline-block;
|
||||||
|
content: '';
|
||||||
|
transition: box-shadow 200ms;
|
||||||
|
width: 1.1em;
|
||||||
|
height: 1.1em;
|
||||||
|
border-radius: 100%; // Radio buttons should always be circle
|
||||||
|
box-shadow: 0px 0px 2px black inset;
|
||||||
|
box-shadow: var(--inputShadow);
|
||||||
|
margin-right: .5em;
|
||||||
|
background-color: $fallback--fg;
|
||||||
|
background-color: var(--input, $fallback--fg);
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.1em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&[type=checkbox] {
|
&[type=checkbox] {
|
||||||
display: none;
|
display: none;
|
||||||
&:checked + label::before {
|
&:checked + label::before {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import Status from '../status/status.vue'
|
import Status from '../status/status.vue'
|
||||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import UserCard from '../user_card/user_card.vue'
|
import UserCard from '../user_card/user_card.vue'
|
||||||
|
import Timeago from '../timeago/timeago.vue'
|
||||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
|
||||||
|
@ -13,7 +14,10 @@ const Notification = {
|
||||||
},
|
},
|
||||||
props: [ 'notification' ],
|
props: [ 'notification' ],
|
||||||
components: {
|
components: {
|
||||||
Status, UserAvatar, UserCard
|
Status,
|
||||||
|
UserAvatar,
|
||||||
|
UserCard,
|
||||||
|
Timeago
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleUserExpanded () {
|
toggleUserExpanded () {
|
||||||
|
|
|
@ -30,12 +30,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="timeago" v-if="notification.type === 'follow'">
|
<div class="timeago" v-if="notification.type === 'follow'">
|
||||||
<span class="faint">
|
<span class="faint">
|
||||||
<timeago :since="notification.created_at" :auto-update="240"></timeago>
|
<Timeago :time="notification.created_at" :auto-update="240"></Timeago>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="timeago" v-else>
|
<div class="timeago" v-else>
|
||||||
<router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }" class="faint-link">
|
<router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }" class="faint-link">
|
||||||
<timeago :since="notification.created_at" :auto-update="240"></timeago>
|
<Timeago :time="notification.created_at" :auto-update="240"></Timeago>
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
v-if="currentUserHasVoted"
|
v-if="currentUserHasVoted"
|
||||||
:poll="poll"
|
:poll="poll"
|
||||||
:status-id="statusId"
|
:status-id="statusId"
|
||||||
v-on:poll-refreshed="handlePollUpdate"
|
|
||||||
/>
|
/>
|
||||||
<poll-vote
|
<poll-vote
|
||||||
v-else
|
v-else
|
||||||
:poll="poll"
|
:poll="poll"
|
||||||
:status-id="statusId"
|
:status-id="statusId"
|
||||||
v-on:user-has-voted="handlePollUpdate"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -26,17 +24,11 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentUserHasVoted () {
|
currentUserHasVoted () {
|
||||||
console.log('currentUserHasVoted poll', this.poll)
|
|
||||||
return this.poll.voted
|
return this.poll.voted
|
||||||
},
|
},
|
||||||
voted () {
|
voted () {
|
||||||
return this.poll.voted
|
return this.poll.voted
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
handlePollUpdate (poll) {
|
|
||||||
// this.poll = poll
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,19 +3,24 @@
|
||||||
<div class="votes">
|
<div class="votes">
|
||||||
<div
|
<div
|
||||||
class="poll-option"
|
class="poll-option"
|
||||||
v-for="(pollOption, index) in poll.options"
|
v-for="(option, index) in poll.options"
|
||||||
:key="index">
|
:key="index"
|
||||||
<div class="col">{{percentageForOption(pollOption.votes_count)}}%</div>
|
:title="`${option.votes_count}/${totalVotesCount} ${$t('polls.votes')}`"
|
||||||
<div class="col">{{pollOption.title}}</div>
|
>
|
||||||
<div class="col"><progress :max="totalVotesCount" :value="pollOption.votes_count"></progress></div>
|
<div class="vote-label">
|
||||||
|
<span>{{percentageForOption(option.votes_count)}}%</span>
|
||||||
|
<span>{{option.title}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="fill" :style="{ 'width': `${percentageForOption(option.votes_count)}%` }"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="refresh">
|
|
||||||
<a href="#" @click.stop.prevent="fetchPoll(poll.id)">Refresh</a> ·
|
|
||||||
</div>
|
|
||||||
<div class="total">
|
<div class="total">
|
||||||
{{totalVotesCount}} {{ $t("polls.votes") }}
|
{{totalVotesCount}} {{ $t("polls.votes") }} ·
|
||||||
|
</div>
|
||||||
|
<div class="refresh">
|
||||||
|
<a href="#" @click.stop.prevent="fetchPoll(poll.id)">Refresh</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,9 +30,6 @@
|
||||||
export default {
|
export default {
|
||||||
name: 'PollResults',
|
name: 'PollResults',
|
||||||
props: ['poll', 'statusId'],
|
props: ['poll', 'statusId'],
|
||||||
created () {
|
|
||||||
console.log(this.poll)
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
totalVotesCount () {
|
totalVotesCount () {
|
||||||
return this.poll.votes_count
|
return this.poll.votes_count
|
||||||
|
@ -35,7 +37,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
percentageForOption (count) {
|
percentageForOption (count) {
|
||||||
return (this.totalVotesCount === 0 ? 0 : (count / this.totalVotesCount * 100)).toFixed(1)
|
return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100)
|
||||||
},
|
},
|
||||||
fetchPoll () {
|
fetchPoll () {
|
||||||
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
|
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
|
||||||
|
@ -45,18 +47,39 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '../../../_variables.scss';
|
||||||
|
|
||||||
.poll-results {
|
.poll-results {
|
||||||
margin: 0.7em 0;
|
|
||||||
.votes {
|
.votes {
|
||||||
display: table;
|
display: flex;
|
||||||
width: 100%;
|
flex-direction: column;
|
||||||
margin: 0 0 0.5em;
|
margin: 0 0 0.5em;
|
||||||
}
|
}
|
||||||
.poll-option {
|
.poll-option {
|
||||||
display: table-row;
|
position: relative;
|
||||||
.col {
|
display: flex;
|
||||||
display: table-cell;
|
flex-direction: row;
|
||||||
padding: 0.7em 0.5em;
|
margin-top: 0.25em;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
|
}
|
||||||
|
.fill {
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background-color: $fallback--lightBg;
|
||||||
|
background-color: var(--faintLink, $fallback--lightBg);
|
||||||
|
border-radius: $fallback--panelRadius;
|
||||||
|
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transition: width 0.5s;
|
||||||
|
}
|
||||||
|
.vote-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.1em 0.25em;
|
||||||
|
z-index: 1;
|
||||||
|
span {
|
||||||
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
footer {
|
footer {
|
||||||
|
|
|
@ -2,50 +2,103 @@
|
||||||
<form class="poll-vote" v-bind:class="containerClass">
|
<form class="poll-vote" v-bind:class="containerClass">
|
||||||
<div
|
<div
|
||||||
class="poll-choice"
|
class="poll-choice"
|
||||||
v-for="(pollOption, index) in poll.options"
|
v-for="(option, index) in poll.options"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
|
v-if="poll.multiple"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="choice"
|
name="choice"
|
||||||
:id="index"
|
:id="index"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:value="pollOption.title"
|
:value="option.title"
|
||||||
v-model="checks[index]"
|
v-model="multipleChoices[index]"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
type="radio"
|
||||||
|
name="choice"
|
||||||
|
:id="index"
|
||||||
|
:disabled="loading"
|
||||||
|
:value="index"
|
||||||
|
v-model="singleChoiceIndex"
|
||||||
>
|
>
|
||||||
<label :for="index">
|
<label :for="index">
|
||||||
{{pollOption.title}}
|
{{option.title}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-default poll-vote-button" type="button" @click="vote">{{$t('polls.vote')}}</button>
|
<div class="footer">
|
||||||
|
<button
|
||||||
|
class="btn btn-default poll-vote-button"
|
||||||
|
type="button"
|
||||||
|
@click="vote"
|
||||||
|
:disabled="isDisabled"
|
||||||
|
>
|
||||||
|
{{$t('polls.vote')}}
|
||||||
|
</button>
|
||||||
|
<Timeago :time="this.poll.expires_at" :auto-update="1"></Timeago>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Timeago from '../../timeago/timeago.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PollVote',
|
name: 'PollVote',
|
||||||
props: ['poll', 'statusId'],
|
props: ['poll', 'statusId'],
|
||||||
|
components: { Timeago },
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
checks: []
|
multipleChoices: [],
|
||||||
|
singleChoiceIndex: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
containerClass: function () {
|
expired () {
|
||||||
|
return new Date() > this.poll.expires_at
|
||||||
|
},
|
||||||
|
timeleft () {
|
||||||
|
const expiresAt = new Date(this.poll.expires_at)
|
||||||
|
return expiresAt
|
||||||
|
},
|
||||||
|
expiresAt () {
|
||||||
|
return Date.parse(this.poll.expires_at).toLocaleString()
|
||||||
|
},
|
||||||
|
containerClass () {
|
||||||
return {
|
return {
|
||||||
loading: this.loading
|
loading: this.loading
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
choiceIndices () {
|
||||||
|
return this.multipleChoices.map((entry, index) => index).filter(value => typeof value === 'number')
|
||||||
|
},
|
||||||
|
isDisabled () {
|
||||||
|
const noChoice = this.poll.multiple ? this.choiceIndices.length === 0 : this.singleChoiceIndex === undefined
|
||||||
|
return this.loading || noChoice
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
vote () {
|
vote () {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
if (this.poll.multiple) {
|
||||||
const choices = this.checks.map((entry, index) => index).filter(value => typeof value === 'number')
|
if (this.choiceIndices.length === 0) return
|
||||||
this.$store.dispatch('votePoll', { id: this.statusId, pollId: this.poll.id, choices }).then(poll => {
|
this.$store.dispatch(
|
||||||
this.loading = false
|
'votePoll',
|
||||||
})
|
{ id: this.statusId, pollId: this.poll.id, choices: this.choiceIndices }
|
||||||
|
).then(poll => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (this.singleChoiceIndex === undefined) return
|
||||||
|
this.$store.dispatch(
|
||||||
|
'votePoll',
|
||||||
|
{ id: this.statusId, pollId: this.poll.id, choices: [this.singleChoiceIndex] }
|
||||||
|
).then(poll => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||||
import Gallery from '../gallery/gallery.vue'
|
import Gallery from '../gallery/gallery.vue'
|
||||||
import LinkPreview from '../link-preview/link-preview.vue'
|
import LinkPreview from '../link-preview/link-preview.vue'
|
||||||
import AvatarList from '../avatar_list/avatar_list.vue'
|
import AvatarList from '../avatar_list/avatar_list.vue'
|
||||||
|
import Timeago from '../timeago/timeago.vue'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
import fileType from 'src/services/file_type/file_type.service'
|
import fileType from 'src/services/file_type/file_type.service'
|
||||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||||
|
@ -291,7 +292,8 @@ const Status = {
|
||||||
UserAvatar,
|
UserAvatar,
|
||||||
Gallery,
|
Gallery,
|
||||||
LinkPreview,
|
LinkPreview,
|
||||||
AvatarList
|
AvatarList,
|
||||||
|
Timeago
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
visibilityIcon (visibility) {
|
visibilityIcon (visibility) {
|
||||||
|
@ -342,7 +344,6 @@ const Status = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleReplying () {
|
toggleReplying () {
|
||||||
console.log(this.status)
|
|
||||||
this.replying = !this.replying
|
this.replying = !this.replying
|
||||||
},
|
},
|
||||||
gotoOriginal (id) {
|
gotoOriginal (id) {
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
<span class="heading-right">
|
<span class="heading-right">
|
||||||
<router-link class="timeago faint-link" :to="{ name: 'conversation', params: { id: status.id } }">
|
<router-link class="timeago faint-link" :to="{ name: 'conversation', params: { id: status.id } }">
|
||||||
<timeago :since="status.created_at" :auto-update="60"></timeago>
|
<Timeago :time="status.created_at" :auto-update="60"></Timeago>
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class="button-icon visibility-icon" v-if="status.visibility">
|
<div class="button-icon visibility-icon" v-if="status.visibility">
|
||||||
<i :class="visibilityIcon(status.visibility)" :title="status.visibility | capitalize"></i>
|
<i :class="visibilityIcon(status.visibility)" :title="status.visibility | capitalize"></i>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<time :datetime="time" :title="localeDateString">
|
||||||
|
{{ $t(relativeTime.key, [relativeTime.num]) }}
|
||||||
|
</time>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as DateUtils from 'src/services/date_utils/date_utils.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Timeago',
|
||||||
|
props: ['time', 'autoUpdate', 'longFormat'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
relativeTime: { key: 'time.now', num: 0 },
|
||||||
|
interval: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.refreshRelativeTimeObject()
|
||||||
|
},
|
||||||
|
destroyed () {
|
||||||
|
clearTimeout(this.interval)
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
localeDateString () {
|
||||||
|
return typeof this.time === 'string'
|
||||||
|
? new Date(Date.parse(this.time)).toLocaleString()
|
||||||
|
: this.time.toLocaleString()
|
||||||
|
},
|
||||||
|
relativeTimeObject () {
|
||||||
|
return this.longFormat
|
||||||
|
? DateUtils.relativeTime(this.time)
|
||||||
|
: DateUtils.relativeTimeShort(this.time)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refreshRelativeTimeObject () {
|
||||||
|
this.relativeTime = this.longFormat
|
||||||
|
? DateUtils.relativeTime(this.time)
|
||||||
|
: DateUtils.relativeTimeShort(this.time)
|
||||||
|
|
||||||
|
if (this.autoUpdate) {
|
||||||
|
this.interval = setTimeout(
|
||||||
|
this.refreshRelativeTimeObject,
|
||||||
|
1000 * this.autoUpdate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -168,6 +168,40 @@
|
||||||
"true": "sí"
|
"true": "sí"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} dia",
|
||||||
|
"days": "{0} dies",
|
||||||
|
"day_short": "{0} dia",
|
||||||
|
"days_short": "{0} dies",
|
||||||
|
"hour": "{0} hour",
|
||||||
|
"hours": "{0} hours",
|
||||||
|
"hour_short": "{0}h",
|
||||||
|
"hours_short": "{0}h",
|
||||||
|
"in_future": "in {0}",
|
||||||
|
"in_past": "fa {0}",
|
||||||
|
"minute": "{0} minute",
|
||||||
|
"minutes": "{0} minutes",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} mes",
|
||||||
|
"months": "{0} mesos",
|
||||||
|
"month_short": "{0} mes",
|
||||||
|
"months_short": "{0} mesos",
|
||||||
|
"now": "ara mateix",
|
||||||
|
"now_short": "ara mateix",
|
||||||
|
"second": "{0} second",
|
||||||
|
"seconds": "{0} seconds",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} setm.",
|
||||||
|
"weeks": "{0} setm.",
|
||||||
|
"week_short": "{0} setm.",
|
||||||
|
"weeks_short": "{0} setm.",
|
||||||
|
"year": "{0} any",
|
||||||
|
"years": "{0} anys",
|
||||||
|
"year_short": "{0} any",
|
||||||
|
"years_short": "{0} anys"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Replega",
|
"collapse": "Replega",
|
||||||
"conversation": "Conversa",
|
"conversation": "Conversa",
|
||||||
|
|
|
@ -350,6 +350,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} day",
|
||||||
|
"days": "{0} days",
|
||||||
|
"day_short": "{0}d",
|
||||||
|
"days_short": "{0}d",
|
||||||
|
"hour": "{0} hour",
|
||||||
|
"hours": "{0} hours",
|
||||||
|
"hour_short": "{0}h",
|
||||||
|
"hours_short": "{0}h",
|
||||||
|
"in_future": "in {0}",
|
||||||
|
"in_past": "{0} ago",
|
||||||
|
"minute": "{0} minute",
|
||||||
|
"minutes": "{0} minutes",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} měs",
|
||||||
|
"months": "{0} měs",
|
||||||
|
"month_short": "{0} měs",
|
||||||
|
"months_short": "{0} měs",
|
||||||
|
"now": "teď",
|
||||||
|
"now_short": "teď",
|
||||||
|
"second": "{0} second",
|
||||||
|
"seconds": "{0} seconds",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} týd",
|
||||||
|
"weeks": "{0} týd",
|
||||||
|
"week_short": "{0} týd",
|
||||||
|
"weeks_short": "{0} týd",
|
||||||
|
"year": "{0} r",
|
||||||
|
"years": "{0} l",
|
||||||
|
"year_short": "{0}r",
|
||||||
|
"years_short": "{0}l"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Zabalit",
|
"collapse": "Zabalit",
|
||||||
"conversation": "Konverzace",
|
"conversation": "Konverzace",
|
||||||
|
|
|
@ -417,6 +417,40 @@
|
||||||
"frontend_version": "Frontend Version"
|
"frontend_version": "Frontend Version"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} day",
|
||||||
|
"days": "{0} days",
|
||||||
|
"day_short": "{0}d",
|
||||||
|
"days_short": "{0}d",
|
||||||
|
"hour": "{0} hour",
|
||||||
|
"hours": "{0} hours",
|
||||||
|
"hour_short": "{0}h",
|
||||||
|
"hours_short": "{0}h",
|
||||||
|
"in_future": "in {0}",
|
||||||
|
"in_past": "{0} ago",
|
||||||
|
"minute": "{0} minute",
|
||||||
|
"minutes": "{0} minutes",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} month",
|
||||||
|
"months": "{0} months",
|
||||||
|
"month_short": "{0}mo",
|
||||||
|
"months_short": "{0}mo",
|
||||||
|
"now": "just now",
|
||||||
|
"now_short": "now",
|
||||||
|
"second": "{0} second",
|
||||||
|
"seconds": "{0} seconds",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} week",
|
||||||
|
"weeks": "{0} weeks",
|
||||||
|
"week_short": "{0}w",
|
||||||
|
"weeks_short": "{0}w",
|
||||||
|
"year": "{0} year",
|
||||||
|
"years": "{0} years",
|
||||||
|
"year_short": "{0}y",
|
||||||
|
"years_short": "{0}y"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Collapse",
|
"collapse": "Collapse",
|
||||||
"conversation": "Conversation",
|
"conversation": "Conversation",
|
||||||
|
|
|
@ -210,6 +210,40 @@
|
||||||
"true": "päällä"
|
"true": "päällä"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} päivä",
|
||||||
|
"days": "{0} päivää",
|
||||||
|
"day_short": "{0}pv",
|
||||||
|
"days_short": "{0}pv",
|
||||||
|
"hour": "{0} tunti",
|
||||||
|
"hours": "{0} tuntia",
|
||||||
|
"hour_short": "{0}t",
|
||||||
|
"hours_short": "{0}t",
|
||||||
|
"in_future": "{0} tulevaisuudessa",
|
||||||
|
"in_past": "{0} sitten",
|
||||||
|
"minute": "{0} minuutti",
|
||||||
|
"minutes": "{0} minuuttia",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} kuukausi",
|
||||||
|
"months": "{0} kuukautta",
|
||||||
|
"month_short": "{0}kk",
|
||||||
|
"months_short": "{0}kk",
|
||||||
|
"now": "nyt",
|
||||||
|
"now_short": "juuri nyt",
|
||||||
|
"second": "{0} sekunti",
|
||||||
|
"seconds": "{0} sekuntia",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} viikko",
|
||||||
|
"weeks": "{0} viikkoa",
|
||||||
|
"week_short": "{0}vk",
|
||||||
|
"weeks_short": "{0}vk",
|
||||||
|
"year": "{0} vuosi",
|
||||||
|
"years": "{0} vuotta",
|
||||||
|
"year_short": "{0}v",
|
||||||
|
"years_short": "{0}v"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Sulje",
|
"collapse": "Sulje",
|
||||||
"conversation": "Keskustelu",
|
"conversation": "Keskustelu",
|
||||||
|
|
|
@ -170,6 +170,40 @@
|
||||||
"true": "tá"
|
"true": "tá"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} lá",
|
||||||
|
"days": "{0} lá",
|
||||||
|
"day_short": "{0}l",
|
||||||
|
"days_short": "{0}l",
|
||||||
|
"hour": "{0} uair",
|
||||||
|
"hours": "{0} uair",
|
||||||
|
"hour_short": "{0}u",
|
||||||
|
"hours_short": "{0}u",
|
||||||
|
"in_future": "in {0}",
|
||||||
|
"in_past": "{0} ago",
|
||||||
|
"minute": "{0} nóimeád",
|
||||||
|
"minutes": "{0} nóimeád",
|
||||||
|
"minute_short": "{0}n",
|
||||||
|
"minutes_short": "{0}n",
|
||||||
|
"month": "{0} mí",
|
||||||
|
"months": "{0} mí",
|
||||||
|
"month_short": "{0}m",
|
||||||
|
"months_short": "{0}m",
|
||||||
|
"now": "Anois",
|
||||||
|
"now_short": "Anois",
|
||||||
|
"second": "{0} s",
|
||||||
|
"seconds": "{0} s",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} seachtain",
|
||||||
|
"weeks": "{0} seachtaine",
|
||||||
|
"week_short": "{0}se",
|
||||||
|
"weeks_short": "{0}se",
|
||||||
|
"year": "{0} bliainta",
|
||||||
|
"years": "{0} bliainta",
|
||||||
|
"year_short": "{0}b",
|
||||||
|
"years_short": "{0}b"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Folaigh",
|
"collapse": "Folaigh",
|
||||||
"conversation": "Cómhra",
|
"conversation": "Cómhra",
|
||||||
|
|
|
@ -327,6 +327,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0}日",
|
||||||
|
"days": "{0}日",
|
||||||
|
"day_short": "{0}日",
|
||||||
|
"days_short": "{0}日",
|
||||||
|
"hour": "{0}時間",
|
||||||
|
"hours": "{0}時間",
|
||||||
|
"hour_short": "{0}時間",
|
||||||
|
"hours_short": "{0}時間",
|
||||||
|
"in_future": "{0}で",
|
||||||
|
"in_past": "{0}前",
|
||||||
|
"minute": "{0}分",
|
||||||
|
"minutes": "{0}分",
|
||||||
|
"minute_short": "{0}分",
|
||||||
|
"minutes_short": "{0}分",
|
||||||
|
"month": "{0}ヶ月前",
|
||||||
|
"months": "{0}ヶ月前",
|
||||||
|
"month_short": "{0}ヶ月前",
|
||||||
|
"months_short": "{0}ヶ月前",
|
||||||
|
"now": "たった今",
|
||||||
|
"now_short": "たった今",
|
||||||
|
"second": "{0}秒",
|
||||||
|
"seconds": "{0}秒",
|
||||||
|
"second_short": "{0}秒",
|
||||||
|
"seconds_short": "{0}秒",
|
||||||
|
"week": "{0}週間",
|
||||||
|
"weeks": "{0}週間",
|
||||||
|
"week_short": "{0}週間",
|
||||||
|
"weeks_short": "{0}週間",
|
||||||
|
"year": "{0}年",
|
||||||
|
"years": "{0}年",
|
||||||
|
"year_short": "{0}年",
|
||||||
|
"years_short": "{0}年"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "たたむ",
|
"collapse": "たたむ",
|
||||||
"conversation": "スレッド",
|
"conversation": "スレッド",
|
||||||
|
|
|
@ -327,6 +327,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0}日",
|
||||||
|
"days": "{0}日",
|
||||||
|
"day_short": "{0}日",
|
||||||
|
"days_short": "{0}日",
|
||||||
|
"hour": "{0}時間",
|
||||||
|
"hours": "{0}時間",
|
||||||
|
"hour_short": "{0}時間",
|
||||||
|
"hours_short": "{0}時間",
|
||||||
|
"in_future": "{0}で",
|
||||||
|
"in_past": "{0}前",
|
||||||
|
"minute": "{0}分",
|
||||||
|
"minutes": "{0}分",
|
||||||
|
"minute_short": "{0}分",
|
||||||
|
"minutes_short": "{0}分",
|
||||||
|
"month": "{0}ヶ月前",
|
||||||
|
"months": "{0}ヶ月前",
|
||||||
|
"month_short": "{0}ヶ月前",
|
||||||
|
"months_short": "{0}ヶ月前",
|
||||||
|
"now": "たった今",
|
||||||
|
"now_short": "たった今",
|
||||||
|
"second": "{0}秒",
|
||||||
|
"seconds": "{0}秒",
|
||||||
|
"second_short": "{0}秒",
|
||||||
|
"seconds_short": "{0}秒",
|
||||||
|
"week": "{0}週間",
|
||||||
|
"weeks": "{0}週間",
|
||||||
|
"week_short": "{0}週間",
|
||||||
|
"weeks_short": "{0}週間",
|
||||||
|
"year": "{0}年",
|
||||||
|
"years": "{0}年",
|
||||||
|
"year_short": "{0}年",
|
||||||
|
"years_short": "{0}年"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "たたむ",
|
"collapse": "たたむ",
|
||||||
"conversation": "スレッド",
|
"conversation": "スレッド",
|
||||||
|
|
|
@ -381,6 +381,40 @@
|
||||||
"frontend_version": "Version Frontend"
|
"frontend_version": "Version Frontend"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} jorn",
|
||||||
|
"days": "{0} jorns",
|
||||||
|
"day_short": "{0} jorn",
|
||||||
|
"days_short": "{0} jorns",
|
||||||
|
"hour": "{0} hour",
|
||||||
|
"hours": "{0} hours",
|
||||||
|
"hour_short": "{0}h",
|
||||||
|
"hours_short": "{0}h",
|
||||||
|
"in_future": "in {0}",
|
||||||
|
"in_past": "fa {0}",
|
||||||
|
"minute": "{0} minute",
|
||||||
|
"minutes": "{0} minutes",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} mes",
|
||||||
|
"months": "{0} meses",
|
||||||
|
"month_short": "{0} mes",
|
||||||
|
"months_short": "{0} meses",
|
||||||
|
"now": "ara meteis",
|
||||||
|
"now_short": "ara meteis",
|
||||||
|
"second": "{0} second",
|
||||||
|
"seconds": "{0} seconds",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} setm.",
|
||||||
|
"weeks": "{0} setm.",
|
||||||
|
"week_short": "{0} setm.",
|
||||||
|
"weeks_short": "{0} setm.",
|
||||||
|
"year": "{0} an",
|
||||||
|
"years": "{0} ans",
|
||||||
|
"year_short": "{0} an",
|
||||||
|
"years_short": "{0} ans"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Tampar",
|
"collapse": "Tampar",
|
||||||
"conversation": "Conversacion",
|
"conversation": "Conversacion",
|
||||||
|
|
|
@ -15,7 +15,6 @@ import oauthTokensModule from './modules/oauth_tokens.js'
|
||||||
import pollModule from './modules/poll.js'
|
import pollModule from './modules/poll.js'
|
||||||
import reportsModule from './modules/reports.js'
|
import reportsModule from './modules/reports.js'
|
||||||
|
|
||||||
import VueTimeago from 'vue-timeago'
|
|
||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from 'vue-i18n'
|
||||||
|
|
||||||
import createPersistedState from './lib/persisted_state.js'
|
import createPersistedState from './lib/persisted_state.js'
|
||||||
|
@ -32,14 +31,6 @@ const currentLocale = (window.navigator.language || 'en').split('-')[0]
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
Vue.use(VueTimeago, {
|
|
||||||
locale: currentLocale === 'cs' ? 'cs' : currentLocale === 'ja' ? 'ja' : 'en',
|
|
||||||
locales: {
|
|
||||||
'cs': require('../static/timeago-cs.json'),
|
|
||||||
'en': require('../static/timeago-en.json'),
|
|
||||||
'ja': require('../static/timeago-ja.json')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Vue.use(VueI18n)
|
Vue.use(VueI18n)
|
||||||
Vue.use(VueChatScroll)
|
Vue.use(VueChatScroll)
|
||||||
Vue.use(VueClickOutside)
|
Vue.use(VueClickOutside)
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
export const SECOND = 1000
|
||||||
|
export const MINUTE = 60 * SECOND
|
||||||
|
export const HOUR = 60 * MINUTE
|
||||||
|
export const DAY = 24 * HOUR
|
||||||
|
export const WEEK = 7 * DAY
|
||||||
|
export const MONTH = 30 * DAY
|
||||||
|
export const YEAR = 365.25 * DAY
|
||||||
|
|
||||||
|
export const relativeTime = date => {
|
||||||
|
if (typeof date === 'string') date = Date.parse(date)
|
||||||
|
const round = Date.now() > date ? Math.floor : Math.ceil
|
||||||
|
const d = Math.abs(Date.now() - date)
|
||||||
|
let r = { num: round(d / YEAR), key: 'time.years' }
|
||||||
|
if (d < 30 * SECOND) {
|
||||||
|
r.num = 0
|
||||||
|
r.key = 'time.now'
|
||||||
|
} else if (d < MINUTE) {
|
||||||
|
r.num = round(d / SECOND)
|
||||||
|
r.key = 'time.seconds'
|
||||||
|
} else if (d < HOUR) {
|
||||||
|
r.num = round(d / MINUTE)
|
||||||
|
r.key = 'time.minutes'
|
||||||
|
} else if (d < DAY) {
|
||||||
|
r.num = round(d / HOUR)
|
||||||
|
r.key = 'time.hours'
|
||||||
|
} else if (d < WEEK) {
|
||||||
|
r.num = round(d / DAY)
|
||||||
|
r.key = 'time.days'
|
||||||
|
} else if (d < MONTH) {
|
||||||
|
r.num = round(d / WEEK)
|
||||||
|
r.key = 'time.weeks'
|
||||||
|
} else if (d < YEAR) {
|
||||||
|
r.num = round(d / MONTH)
|
||||||
|
r.key = 'time.months'
|
||||||
|
}
|
||||||
|
// Remove plural form when singular
|
||||||
|
if (r.num === 1) r.key = r.key.slice(0, -1)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
export const relativeTimeShort = date => {
|
||||||
|
const r = relativeTime(date)
|
||||||
|
r.key += '_short'
|
||||||
|
return r
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"ara mateix",
|
|
||||||
["fa %s s", "fa %s s"],
|
|
||||||
["fa %s min", "fa %s min"],
|
|
||||||
["fa %s h", "fa %s h"],
|
|
||||||
["fa %s dia", "fa %s dies"],
|
|
||||||
["fa %s setm.", "fa %s setm."],
|
|
||||||
["fa %s mes", "fa %s mesos"],
|
|
||||||
["fa %s any", "fa %s anys"]
|
|
||||||
]
|
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"teď",
|
|
||||||
["%s s", "%s s"],
|
|
||||||
["%s min", "%s min"],
|
|
||||||
["%s h", "%s h"],
|
|
||||||
["%s d", "%s d"],
|
|
||||||
["%s týd", "%s týd"],
|
|
||||||
["%s měs", "%s měs"],
|
|
||||||
["%s r", "%s l"]
|
|
||||||
]
|
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"now",
|
|
||||||
["%ss", "%ss"],
|
|
||||||
["%smin", "%smin"],
|
|
||||||
["%sh", "%sh"],
|
|
||||||
["%sd", "%sd"],
|
|
||||||
["%sw", "%sw"],
|
|
||||||
["%smo", "%smo"],
|
|
||||||
["%sy", "%sy"]
|
|
||||||
]
|
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"Anois",
|
|
||||||
["%s s", "%s s"],
|
|
||||||
["%s n", "%s nóimeád"],
|
|
||||||
["%s u", "%s uair"],
|
|
||||||
["%s l", "%s lá"],
|
|
||||||
["%s se", "%s seachtaine"],
|
|
||||||
["%s m", "%s mí"],
|
|
||||||
["%s b", "%s bliainta"]
|
|
||||||
]
|
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"たった今",
|
|
||||||
"%s 秒前",
|
|
||||||
"%s 分前",
|
|
||||||
"%s 時間前",
|
|
||||||
"%s 日前",
|
|
||||||
"%s 週間前",
|
|
||||||
"%s ヶ月前",
|
|
||||||
"%s 年前"
|
|
||||||
]
|
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
"ara meteis",
|
|
||||||
["fa %s s", "fa %s s"],
|
|
||||||
["fa %s min", "fa %s min"],
|
|
||||||
["fa %s h", "fa %s h"],
|
|
||||||
["fa %s jorn", "fa %s jorns"],
|
|
||||||
["fa %s setm.", "fa %s setm."],
|
|
||||||
["fa %s mes", "fa %s meses"],
|
|
||||||
["fa %s an", "fa %s ans"]
|
|
||||||
]
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import * as DateUtils from 'src/services/date_utils/date_utils.js'
|
||||||
|
|
||||||
|
describe.only('DateUtils', () => {
|
||||||
|
describe('relativeTime', () => {
|
||||||
|
it('returns now with low amount of seconds', () => {
|
||||||
|
const futureTime = Date.now() + 20 * DateUtils.SECOND
|
||||||
|
const pastTime = Date.now() - 20 * DateUtils.SECOND
|
||||||
|
expect(DateUtils.relativeTime(futureTime)).to.eql({ num: 0, key: 'time.now' })
|
||||||
|
expect(DateUtils.relativeTime(pastTime)).to.eql({ num: 0, key: 'time.now' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rounds down for past', () => {
|
||||||
|
const time = Date.now() - 1.8 * DateUtils.HOUR
|
||||||
|
expect(DateUtils.relativeTime(time)).to.eql({ num: 1, key: 'time.hour' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rounds up for future', () => {
|
||||||
|
const time = Date.now() + 1.8 * DateUtils.HOUR
|
||||||
|
expect(DateUtils.relativeTime(time)).to.eql({ num: 2, key: 'time.hours' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('uses plural when necessary', () => {
|
||||||
|
const time = Date.now() - 3.8 * DateUtils.WEEK
|
||||||
|
expect(DateUtils.relativeTime(time)).to.eql({ num: 3, key: 'time.weeks' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('works with date string', () => {
|
||||||
|
const time = Date.now() - 4 * DateUtils.MONTH
|
||||||
|
const dateString = new Date(time).toISOString()
|
||||||
|
expect(DateUtils.relativeTime(dateString)).to.eql({ num: 4, key: 'time.months' })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('relativeTimeShort', () => {
|
||||||
|
it('returns the short version of the same relative time', () => {
|
||||||
|
const time = Date.now() + 2 * DateUtils.YEAR
|
||||||
|
expect(DateUtils.relativeTimeShort(time)).to.eql({ num: 2, key: 'time.years_short' })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue