parent
4168b2ce41
commit
ffb8ac8ddc
@ -10,21 +10,49 @@ import '../styles/poll.scss'
|
|||||||
export default class MUCPollView extends CustomElement {
|
export default class MUCPollView extends CustomElement {
|
||||||
static get properties () {
|
static get properties () {
|
||||||
return {
|
return {
|
||||||
model: { type: Object, attribute: true }
|
model: { type: Object, attribute: true },
|
||||||
|
collapsed: { type: Boolean, attribute: false },
|
||||||
|
buttonDisabled: { type: Boolean, attribute: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize () {
|
async initialize () {
|
||||||
|
this.collapsed = false
|
||||||
|
this.buttonDisabled = false
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.listenTo(this.model, 'change:current_poll', () => this.requestUpdate())
|
this.listenTo(this.model, 'change:current_poll', () => {
|
||||||
|
this.buttonDisabled = false
|
||||||
|
this.requestUpdate()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const currentPoll = this.model?.get('current_poll')
|
const currentPoll = this.model?.get('current_poll')
|
||||||
return tplPoll(this, currentPoll)
|
return tplPoll(this, currentPoll)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggle () {
|
||||||
|
this.collapsed = !this.collapsed
|
||||||
|
}
|
||||||
|
|
||||||
|
voteFor (choice) {
|
||||||
|
if (this.buttonDisabled) { return }
|
||||||
|
|
||||||
|
const currentPoll = this.model?.get('current_poll')
|
||||||
|
if (!currentPoll) { return }
|
||||||
|
if (currentPoll.over) { return }
|
||||||
|
|
||||||
|
console.info('User has voted for choice: ', choice)
|
||||||
|
// We disable vote buttons until next refresh:
|
||||||
|
this.buttonDisabled = true
|
||||||
|
this.requestUpdate()
|
||||||
|
|
||||||
|
this.model.sendMessage({
|
||||||
|
body: '!' + choice.choice
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.elements.define('livechat-converse-muc-poll', MUCPollView)
|
api.elements.define('livechat-converse-muc-poll', MUCPollView)
|
||||||
|
@ -45,6 +45,7 @@ converse.plugins.add('livechat-converse-poll', {
|
|||||||
votes: parseInt(poll.getAttribute('votes') ?? 0),
|
votes: parseInt(poll.getAttribute('votes') ?? 0),
|
||||||
over: poll.hasAttribute('over'),
|
over: poll.hasAttribute('over'),
|
||||||
endDate: endDate,
|
endDate: endDate,
|
||||||
|
time: attrs.time, // this is to be sure that we update the custom element (needed to re-enable buttons)
|
||||||
choices: choices.map(c => {
|
choices: choices.map(c => {
|
||||||
return {
|
return {
|
||||||
label: c.textContent,
|
label: c.textContent,
|
||||||
@ -81,9 +82,10 @@ converse.plugins.add('livechat-converse-poll', {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.info('Got a poll message, setting it as the current_poll')
|
console.info('Got a poll message, setting it as the current_poll')
|
||||||
this.set('current_poll', attrs.current_poll)
|
|
||||||
// this will be displayed by the livechat-converse-muc-poll custom element,
|
// this will be displayed by the livechat-converse-muc-poll custom element,
|
||||||
// which is inserted in the DOM by the muc.js template overload.
|
// which is inserted in the DOM by the muc.js template overload.
|
||||||
|
this.set('current_poll', attrs.current_poll)
|
||||||
|
|
||||||
if (attrs.current_poll.over) {
|
if (attrs.current_poll.over) {
|
||||||
console.info('The poll is over, displaying the message in the chat')
|
console.info('The poll is over, displaying the message in the chat')
|
||||||
return this.__super__.onMessage(attrs)
|
return this.__super__.onMessage(attrs)
|
||||||
|
@ -13,12 +13,25 @@
|
|||||||
border: 1px solid var(--peertube-menu-background);
|
border: 1px solid var(--peertube-menu-background);
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
max-height: 150px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
.livechat-poll-toggle {
|
||||||
|
background: unset;
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0.25em;
|
||||||
|
padding-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
p.livechat-poll-question {
|
p.livechat-poll-question {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.livechat-poll-instructions {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
p.livechat-poll-end {
|
p.livechat-poll-end {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
@ -74,3 +87,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body[livechat-viewer-mode="on"] {
|
||||||
|
livechat-converse-muc-poll {
|
||||||
|
/* Dont display the poll before user choose a nickname */
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.livechat-readonly {
|
||||||
|
.conversejs {
|
||||||
|
livechat-converse-muc-poll {
|
||||||
|
/* stylelint-disable-next-line no-descending-specificity */
|
||||||
|
& > div {
|
||||||
|
// In readonly mode, dont impose max-height
|
||||||
|
max-height: initial !important;
|
||||||
|
overflow-y: visible !important;
|
||||||
|
|
||||||
|
&.livechat-poll-over {
|
||||||
|
// stop showing poll when over in readonly mode
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,18 @@ import { html } from 'lit'
|
|||||||
import { repeat } from 'lit/directives/repeat.js'
|
import { repeat } from 'lit/directives/repeat.js'
|
||||||
import { __ } from 'i18n'
|
import { __ } from 'i18n'
|
||||||
|
|
||||||
|
function _tplPollInstructions (el, currentPoll) {
|
||||||
|
if (currentPoll.over) {
|
||||||
|
return html``
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nPollInstructions = __(LOC_poll_vote_instructions)
|
||||||
|
return html`<p class="livechat-poll-instructions">
|
||||||
|
${i18nPollInstructions}
|
||||||
|
</p>`
|
||||||
|
}
|
||||||
|
|
||||||
function _tplPollEnd (el, currentPoll) {
|
function _tplPollEnd (el, currentPoll) {
|
||||||
if (!currentPoll.endDate) {
|
if (!currentPoll.endDate) {
|
||||||
return html``
|
return html``
|
||||||
@ -36,13 +48,9 @@ function _tplChoice (el, currentPoll, choice) {
|
|||||||
<button type="button" class="btn btn-primary btn-sm"
|
<button type="button" class="btn btn-primary btn-sm"
|
||||||
@click=${ev => {
|
@click=${ev => {
|
||||||
ev.preventDefault()
|
ev.preventDefault()
|
||||||
if (currentPoll.over) { return }
|
el.voteFor(choice)
|
||||||
|
|
||||||
console.info('User has voted for choice: ', choice)
|
|
||||||
el.model.sendMessage({
|
|
||||||
body: '!' + choice.choice
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
|
?disabled=${el.buttonDisabled}
|
||||||
>
|
>
|
||||||
${i18nChoiceN}
|
${i18nChoiceN}
|
||||||
</button>`
|
</button>`
|
||||||
@ -72,11 +80,36 @@ export function tplPoll (el, currentPoll) {
|
|||||||
return html``
|
return html``
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<div>
|
return html`<div class="${currentPoll.over ? 'livechat-poll-over' : ''}">
|
||||||
<p class="livechat-poll-question">${currentPoll.question}</p>
|
<p class="livechat-poll-question">
|
||||||
<table><tbody>
|
${el.collapsed
|
||||||
${repeat(currentPoll.choices ?? [], (c) => c.choice, (c) => _tplChoice(el, currentPoll, c))}
|
? html`
|
||||||
</tbody></table>
|
<button @click=${el.toggle} class="livechat-poll-toggle">
|
||||||
${_tplPollEnd(el, currentPoll)}
|
<converse-icon
|
||||||
|
color="var(--muc-toolbar-btn-color)"
|
||||||
|
class="fa fa-angle-right"
|
||||||
|
size="1em"></converse-icon>
|
||||||
|
</button>`
|
||||||
|
: html`
|
||||||
|
<button @click=${el.toggle} class="livechat-poll-toggle">
|
||||||
|
<converse-icon
|
||||||
|
color="var(--muc-toolbar-btn-color)"
|
||||||
|
class="fa fa-angle-down"
|
||||||
|
size="1em"></converse-icon>
|
||||||
|
</button>`
|
||||||
|
}
|
||||||
|
${currentPoll.question}
|
||||||
|
</p>
|
||||||
|
${
|
||||||
|
el.collapsed
|
||||||
|
? ''
|
||||||
|
: html`
|
||||||
|
<table><tbody>
|
||||||
|
${repeat(currentPoll.choices ?? [], (c) => c.choice, (c) => _tplChoice(el, currentPoll, c))}
|
||||||
|
</tbody></table>
|
||||||
|
${_tplPollInstructions(el, currentPoll)}
|
||||||
|
${_tplPollEnd(el, currentPoll)}
|
||||||
|
`
|
||||||
|
}
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@ const locKeys = [
|
|||||||
'poll_title',
|
'poll_title',
|
||||||
'poll_instructions',
|
'poll_instructions',
|
||||||
'poll_end',
|
'poll_end',
|
||||||
'poll'
|
'poll',
|
||||||
|
'poll_vote_instructions'
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = locKeys
|
module.exports = locKeys
|
||||||
|
@ -573,3 +573,5 @@ poll_duration: Poll duration (in minutes)
|
|||||||
poll_anonymous_results: Anonymous results
|
poll_anonymous_results: Anonymous results
|
||||||
poll_choice_n: 'Choice {{N}}:'
|
poll_choice_n: 'Choice {{N}}:'
|
||||||
poll_end: 'Poll ends at:'
|
poll_end: 'Poll ends at:'
|
||||||
|
poll_vote_instructions: |
|
||||||
|
To vote, click on your choice or send a message with an exclamation mark followed by your choice number (Example: !1)
|
||||||
|
@ -29,3 +29,5 @@ Here are the existing strings and default values:
|
|||||||
|
|
||||||
* poll_string_over: This poll is now over.
|
* poll_string_over: This poll is now over.
|
||||||
* poll_string_vote_instructions: Send a message with an exclamation mark followed by your choice number to vote. Example: !1
|
* poll_string_vote_instructions: Send a message with an exclamation mark followed by your choice number to vote. Example: !1
|
||||||
|
* poll_string_invalid_choice: This choice is not valid.
|
||||||
|
* poll_string_anonymous_vote_ok: You vote is taken into account. Votes are anonymous, it will not be shown to other participants.
|
||||||
|
@ -11,6 +11,9 @@ local poll_start_message = module:require("message").poll_start_message;
|
|||||||
local poll_end_message = module:require("message").poll_end_message;
|
local poll_end_message = module:require("message").poll_end_message;
|
||||||
local schedule_poll_update_message = module:require("message").schedule_poll_update_message;
|
local schedule_poll_update_message = module:require("message").schedule_poll_update_message;
|
||||||
|
|
||||||
|
local string_poll_invalid_choice = module:get_option_string("poll_string_invalid_choice") or "This choice is not valid.";
|
||||||
|
local string_poll_anonymous_vote_ok = module:get_option_string("poll_string_anonymous_vote_ok") or "You vote is taken into account. Votes are anonymous, it will not be shown to other participants.";
|
||||||
|
|
||||||
local scheduled_end = {};
|
local scheduled_end = {};
|
||||||
|
|
||||||
local function schedule_poll_purge(room_jid)
|
local function schedule_poll_purge(room_jid)
|
||||||
@ -171,7 +174,7 @@ local function handle_groupchat(event)
|
|||||||
"cancel",
|
"cancel",
|
||||||
-- error_condition = 'not-allowed' (see RFC 6120 Defined Error Conditions https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions)
|
-- error_condition = 'not-allowed' (see RFC 6120 Defined Error Conditions https://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions)
|
||||||
"bad-request",
|
"bad-request",
|
||||||
"This choice is not valid."
|
string_poll_invalid_choice
|
||||||
));
|
));
|
||||||
return true; -- stop!
|
return true; -- stop!
|
||||||
end
|
end
|
||||||
@ -205,7 +208,7 @@ local function handle_groupchat(event)
|
|||||||
"continue",
|
"continue",
|
||||||
-- error_condition
|
-- error_condition
|
||||||
"undefined-condition",
|
"undefined-condition",
|
||||||
"You vote is taken into account. Votes are anonymous, it will not be shown to other participants."
|
string_poll_anonymous_vote_ok
|
||||||
));
|
));
|
||||||
return true; -- stop!
|
return true; -- stop!
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user