Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/src/components/poll/poll.js b/src/components/poll/poll.js
index ace31e8b8c..cbf5d1421a 100644
--- a/src/components/poll/poll.js
+++ b/src/components/poll/poll.js
@@ -1,130 +1,134 @@
+import { useId } from 'vue'
+
import Checkbox from 'components/checkbox/checkbox.vue'
import Timeago from 'components/timeago/timeago.vue'
-import genRandomSeed from '../../services/random_seed/random_seed.service.js'
-
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { usePollsStore } from 'src/stores/polls.js'
import { useUsersStore } from 'src/stores/users.js'
export default {
name: 'Poll',
props: ['basePoll', 'emoji'],
components: {
Timeago,
Checkbox,
},
+ setup() {
+ const uniqueId = useId()
+
+ return { uniqueId }
+ },
data() {
return {
loading: false,
choices: [],
- randomSeed: genRandomSeed(),
}
},
created() {
if (!usePollsStore().pollsObject[this.pollId]) {
usePollsStore().mergeOrAddPoll(this.basePoll)
}
usePollsStore().trackPoll(this.pollId)
},
unmounted() {
usePollsStore().untrackPoll(this.pollId)
},
computed: {
pollId() {
return this.basePoll.id
},
poll() {
const storePoll = usePollsStore().pollsObject[this.pollId]
return storePoll || {}
},
options() {
return this.poll?.options || []
},
expiresAt() {
return this.poll?.expires_at || null
},
expired() {
return this.poll?.expired || false
},
expirationLabel() {
if (useMergedConfigStore().mergedConfig.useAbsoluteTimeFormat) {
return this.expired ? 'polls.expired_at' : 'polls.expires_at'
} else {
return this.expired ? 'polls.expired' : 'polls.expires_in'
}
},
allowNonSquareEmoji() {
return useMergedConfigStore().mergedConfig.nonSquareEmoji
},
pauseMfm() {
return useMergedConfigStore().mergedConfig.pauseMfm
},
scaleMfm() {
return useMergedConfigStore().mergedConfig.scaleMfm
},
loggedIn() {
return useUsersStore().currentUser
},
showResults() {
return this.poll.voted || this.expired || !this.loggedIn
},
totalVotesCount() {
return this.poll.votes_count
},
containerClass() {
return {
loading: this.loading,
}
},
choiceIndices() {
// Convert array of booleans into an array of indices of the
// items that were 'true', so [true, false, false, true] becomes
// [0, 3].
return this.choices
.map((entry, index) => entry && index)
.filter((value) => typeof value === 'number')
},
isDisabled() {
const noChoice = this.choiceIndices.length === 0
return this.loading || noChoice
},
},
methods: {
percentageForOption(count) {
return this.totalVotesCount === 0
? 0
: Math.round((count / this.totalVotesCount) * 100)
},
resultTitle(option) {
return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}`
},
activateOption(index, value) {
let result
if (this.poll.multiple) {
result = this.choices || this.options.map(() => false)
} else {
result = this.options.map(() => false)
}
result[index] = value
this.choices = result
},
optionId(index) {
return `poll${this.poll.id}-${index}`
},
vote() {
if (this.choiceIndices.length === 0) return
this.loading = true
usePollsStore()
.votePoll({
id: this.statusId,
pollId: this.poll.id,
choices: this.choiceIndices,
})
.then(() => {
this.loading = false
})
},
},
}
diff --git a/src/components/poll/poll.vue b/src/components/poll/poll.vue
index 89f103d159..dfb46cb8f7 100644
--- a/src/components/poll/poll.vue
+++ b/src/components/poll/poll.vue
@@ -1,105 +1,105 @@
<template>
<div
class="poll"
:class="containerClass"
>
<div
:role="showResults ? 'section' : (poll.multiple ? 'group' : 'radiogroup')"
>
<div
v-for="(option, index) in options"
:key="index"
class="poll-option"
>
<div
v-if="showResults"
:title="resultTitle(option)"
class="option-result"
>
<div class="option-result-label">
<span class="result-percentage">
{{ percentageForOption(option.votes_count) }}%
</span>
<RichContent
:html="option.title_html"
:handle-links="false"
:emoji="emoji"
:allow-non-square-emoji="allowNonSquareEmoji"
:pause-mfm="pauseMfm"
:scale-mfm="scaleMfm"
/>
</div>
<div
class="result-fill"
:style="{ 'width': `${percentageForOption(option.votes_count)}%` }"
/>
</div>
<div
v-else
- :aria-labelledby="`option-vote-${uniqueId}-${index}`"
>
<Checkbox
:radio="!poll.multiple"
:disabled="loading"
:model-value="choices[index]"
+ :aria-labelledby="`option-vote-${uniqueId}-${index}`"
@update:model-value="value => activateOption(index, value)"
>
<RichContent
:id="`option-vote-${uniqueId}-${index}`"
:html="option.title_html"
:handle-links="false"
:emoji="emoji"
/>
</Checkbox>
</div>
</div>
</div>
<div class="footer faint">
<p>
<span
v-if="poll.pleroma?.non_anonymous"
:title="$t('polls.non_anonymous_title')"
>
{{ $t('polls.non_anonymous') }}
&nbsp;·&nbsp;
</span>
<span class="total">
<template v-if="typeof poll.voters_count === 'number'">
{{ $t("polls.people_voted_count", { count: poll.voters_count }, poll.voters_count) }}
</template>
<template v-else>
{{ $t("polls.votes_count", { count: poll.votes_count }, poll.votes_count) }}
</template>
<span v-if="expiresAt !== null">
&nbsp;·&nbsp;
</span>
</span>
<span v-if="expiresAt !== null">
<i18n-t
scope="global"
:keypath="expirationLabel"
>
<Timeago
:time="expiresAt"
:auto-update="60"
:now-threshold="0"
/>
</i18n-t>
</span>
</p>
<button
v-if="!showResults"
class="btn button-default poll-vote-button"
type="button"
:disabled="isDisabled"
@click="vote"
>
{{ $t('polls.vote') }}
</button>
</div>
</div>
</template>
<script src="./poll.js"></script>
<style src="./poll.scss" lang="scss" />

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 1, 3:11 PM (12 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1803126
Default Alt Text
(7 KB)

Event Timeline