2024-06-27 17:56:12 +00:00
|
|
|
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
import { _converse, converse } from '../../../src/headless/core.js'
|
|
|
|
import { getHeadingButtons } from './utils.js'
|
2024-07-01 15:45:11 +00:00
|
|
|
import { POLL_MESSAGE_TAG, POLL_QUESTION_TAG, POLL_CHOICE_TAG } from './constants.js'
|
2024-07-04 15:39:40 +00:00
|
|
|
import { __ } from 'i18n'
|
2024-06-28 16:38:59 +00:00
|
|
|
import './modals/poll-form.js'
|
2024-07-01 15:45:11 +00:00
|
|
|
import './components/poll-view.js'
|
2024-06-28 16:38:59 +00:00
|
|
|
import './components/poll-form-view.js'
|
2024-06-27 17:56:12 +00:00
|
|
|
|
2024-07-01 15:45:11 +00:00
|
|
|
const { sizzle } = converse.env
|
|
|
|
|
2024-07-18 08:24:54 +00:00
|
|
|
const delayedTimeout = 2 // for delayed poll message, how long must the be considered as valid.
|
|
|
|
|
2024-06-27 17:56:12 +00:00
|
|
|
converse.plugins.add('livechat-converse-poll', {
|
|
|
|
dependencies: ['converse-muc', 'converse-disco'],
|
|
|
|
|
|
|
|
initialize () {
|
|
|
|
// adding the poll actions in the MUC heading buttons:
|
|
|
|
_converse.api.listen.on('getHeadingButtons', getHeadingButtons)
|
2024-07-01 15:45:11 +00:00
|
|
|
|
|
|
|
_converse.api.listen.on('parseMUCMessage', (stanza, attrs) => {
|
2024-07-04 15:39:40 +00:00
|
|
|
// Localizing specific error messages
|
|
|
|
if (attrs.is_error) {
|
|
|
|
// eslint-disable-next-line no-undef, camelcase
|
|
|
|
if (attrs.error_text === LOC_poll_is_over) {
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
attrs.error_text = __(LOC_poll_is_over)
|
|
|
|
// eslint-disable-next-line no-undef, camelcase
|
|
|
|
} else if (attrs.error_text === LOC_poll_choice_invalid) {
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
attrs.error_text = __(LOC_poll_choice_invalid)
|
|
|
|
// eslint-disable-next-line no-undef, camelcase
|
|
|
|
} else if (attrs.error_text === LOC_poll_anonymous_vote_ok) {
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
attrs.error_text = __(LOC_poll_anonymous_vote_ok)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-01 15:45:11 +00:00
|
|
|
// Checking if there is any poll data in the message.
|
|
|
|
const poll = sizzle(POLL_MESSAGE_TAG, stanza)?.[0]
|
|
|
|
if (!poll) {
|
|
|
|
return attrs
|
|
|
|
}
|
|
|
|
const question = sizzle(POLL_QUESTION_TAG, poll)?.[0]
|
|
|
|
const choices = sizzle(POLL_CHOICE_TAG, poll)
|
|
|
|
if (!question || !choices.length) {
|
|
|
|
return attrs
|
|
|
|
}
|
|
|
|
|
|
|
|
const endDate = poll.hasAttribute('end')
|
|
|
|
? new Date(1000 * parseInt(poll.getAttribute('end')))
|
|
|
|
: null
|
|
|
|
|
|
|
|
const currentPoll = {
|
|
|
|
question: question.textContent,
|
|
|
|
id: poll.getAttribute('id'),
|
|
|
|
votes: parseInt(poll.getAttribute('votes') ?? 0),
|
|
|
|
over: poll.hasAttribute('over'),
|
|
|
|
endDate: endDate,
|
2024-07-04 13:15:28 +00:00
|
|
|
time: attrs.time, // this is to be sure that we update the custom element (needed to re-enable buttons)
|
2024-07-01 15:45:11 +00:00
|
|
|
choices: choices.map(c => {
|
|
|
|
return {
|
|
|
|
label: c.textContent,
|
|
|
|
choice: c.getAttribute('choice'),
|
|
|
|
votes: parseInt(c.getAttribute('votes') ?? 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-04 15:39:40 +00:00
|
|
|
// We will also translate some strings here.
|
2024-07-05 08:39:38 +00:00
|
|
|
const body = (attrs.body ?? '')
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
.replace(LOC_poll_is_over, __(LOC_poll_is_over))
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
.replace(LOC_poll_vote_instructions_xmpp, __(LOC_poll_vote_instructions)) // changing instructions on the fly
|
2024-07-04 15:39:40 +00:00
|
|
|
|
2024-07-01 15:45:11 +00:00
|
|
|
return Object.assign(
|
|
|
|
attrs,
|
|
|
|
{
|
2024-07-04 15:39:40 +00:00
|
|
|
current_poll: currentPoll,
|
|
|
|
body
|
2024-07-01 15:45:11 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
overrides: {
|
|
|
|
ChatRoom: {
|
|
|
|
onMessage: function onMessage (attrs) {
|
|
|
|
if (!attrs.current_poll) {
|
|
|
|
return this.__super__.onMessage(attrs)
|
|
|
|
}
|
2024-07-05 08:39:38 +00:00
|
|
|
|
2024-07-04 12:04:33 +00:00
|
|
|
// We intercept poll messages, to show the banner.
|
2024-07-05 08:39:38 +00:00
|
|
|
// We just drop archived messages, to not show the banner for finished polls.
|
|
|
|
if (attrs.is_archived) {
|
|
|
|
return this.__super__.onMessage(attrs)
|
2024-07-01 15:45:11 +00:00
|
|
|
}
|
2024-07-18 08:24:54 +00:00
|
|
|
if (attrs.is_delayed) {
|
|
|
|
// When archiving is disabled, the "history" mechanism is still available:
|
|
|
|
// Last X (20 by default) messages will be kept, and sent to users.
|
|
|
|
// The only thing that differentiates such messages is that they are delayed.
|
|
|
|
// We can't just ignore all delayed messages, because if one day we enable SMACKS
|
|
|
|
// (to handle deconnections on poor network), there could be some legitimate delayed messages.
|
|
|
|
// So we will only ignore the poll if it was sent more than X minutes ago.
|
|
|
|
console.debug('Got a delayed poll message, checking if old or not')
|
|
|
|
const d = new Date()
|
|
|
|
d.setMinutes(d.getMinutes() - delayedTimeout)
|
|
|
|
if (attrs.time < d.toISOString()) {
|
|
|
|
console.debug(
|
|
|
|
`Poll message was delayed fore more than ${delayedTimeout} minutes (${attrs.time} < ${d.toISOString()}).`
|
|
|
|
)
|
|
|
|
return this.__super__.onMessage(attrs)
|
|
|
|
}
|
|
|
|
}
|
2024-07-01 15:45:11 +00:00
|
|
|
|
|
|
|
console.info('Got a poll message, setting it as the current_poll')
|
|
|
|
// this will be displayed by the livechat-converse-muc-poll custom element,
|
|
|
|
// which is inserted in the DOM by the muc.js template overload.
|
2024-07-04 13:15:28 +00:00
|
|
|
this.set('current_poll', attrs.current_poll)
|
|
|
|
|
2024-07-05 08:39:38 +00:00
|
|
|
return this.__super__.onMessage(attrs)
|
2024-07-01 15:45:11 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-27 17:56:12 +00:00
|
|
|
}
|
|
|
|
})
|