Compare commits

..

No commits in common. "b043e1e9c4a3fa6aca950e26ee598396404925c0" and "274a95ab7430500185f0d72aac6735bad113bde7" have entirely different histories.

43 changed files with 110 additions and 291 deletions

View File

@ -1,18 +1,5 @@
# Changelog
## 11.0.0 (Not Released Yet)
### New features
* Updating ConverseJS, to use upstream (v11 WIP). This comes with many improvments and new features.
## 10.3.1
### Minor changes and fixes
* Moderation delay: fix accessibility on the timer shown to moderators.
* Fix «create new poll» icon.
## 10.3.0
### New features

View File

@ -15,21 +15,32 @@ set -x
# Set CONVERSE_VERSION and CONVERSE_REPO to select which repo and tag/commit/branch use.
# Defaults values:
CONVERSE_VERSION="v11.0.0"
CONVERSE_VERSION="v10.1.6"
CONVERSE_REPO="https://github.com/conversejs/converse.js.git"
# You can eventually set CONVERSE_COMMIT to a specific commit ID, if you want to apply some patches.
# 2024-07-15: using Converse upstream (v11 WIP).
CONVERSE_COMMIT="46313ad92c1a861bcb50b9653859cfa9a960ae4a"
# 2024-07-15, FIXME: the following commit includes a quick fix for Converse/#3443, waiting for upstream to be fixed.
CONVERSE_COMMIT="7d65ef8d30a1f3949dbc590b6d27a9d786bf819f"
CONVERSE_COMMIT=""
# It is possible to use another repository, if we want some customization that are not upstream (yet):
# CONVERSE_VERSION="livechat"
# # CONVERSE_COMMIT="4402fcc3fc60f6c9334f86528c33a0b463371d12"
# 2014-01-16: we are using a custom version, to wait for some PR to be apply upstream.
# This version includes following changes:
# - #converse.js/3300: Adding the maxWait option for `debouncedPruneHistory`
# - #converse.js/3302: debounce MUC sidebar rendering
# - Fix: refresh the MUC sidebar when participants collection is sorted
# - Fix: MUC occupant list does not sort itself on nicknames or roles changes
# - Fix inconsistency between browsers on textarea outlines
# - Fix: room information not correctly refreshed when modifications are made by other users
# This version already includes following changes that will not be merged in ConverseJS upstream:
# - Don't load vCards for all room occupants when the right menu is closed
# - Changing the default avatar, for something very light (to mitigate blinking effect when vCards are loaded)
# - Custom settings livechat_load_all_vcards for the readonly mode
# - Adding "users" icon in the menu toggle button
# - Removing unecessary plugins: headless/pubsub, minimize, notifications, profile, omemo, push, roomlist, dragresize.
# - Destroy room: remove the challenge, and the new JID
# - New config option [colorize_username](https://conversejs.org/docs/html/configuration.html#colorize_username)
# - New loadEmojis hook, to customize emojis at runtime.
# - Fix custom emojis path when assets_path is not the default path.
CONVERSE_VERSION="livechat-10.1.0"
# CONVERSE_COMMIT="4402fcc3fc60f6c9334f86528c33a0b463371d12"
CONVERSE_REPO="https://github.com/JohnXLivingston/converse.js"
# 2024-07-15, fix MUC save.
CONVERSE_COMMIT="58c682b9ba09038beb961e9d8f804c270408ea69"
CONVERSE_COMMIT="bbee0e4e8d2dc43636385cf4cca34f3604f59520"
rootdir="$(pwd)"
src_dir="$rootdir/conversejs"

View File

@ -8,11 +8,12 @@
* @description This files will override the original ConverseJS index.js file.
*/
import '@converse/headless'
import './i18n/index.js'
import 'shared/registry.js'
import { CustomElement } from 'shared/components/element'
import { VIEW_PLUGINS } from './shared/constants.js'
import { _converse, converse } from '@converse/headless'
import { _converse, converse } from '@converse/headless/core'
import 'shared/styles/index.scss'
@ -49,9 +50,6 @@ import '../custom/plugins/terms/index.js'
import '../custom/plugins/poll/index.js'
/* END: Removable components */
// Running some specific livechat patches:
import '../custom/livechat-patch-vcard.js'
import { CORE_PLUGINS } from './headless/shared/constants.js'
import { ROOM_FEATURES } from './headless/plugins/muc/constants.js'
// We must add our custom plugins to CORE_PLUGINS (so it is white listed):
@ -63,7 +61,7 @@ CORE_PLUGINS.push('livechat-converse-poll')
// (see headless/plugins/muc, getDiscoInfoFeatures, which loops on this const)
ROOM_FEATURES.push('x_peertubelivechat_mute_anonymous')
_converse.exports.CustomElement = CustomElement
_converse.CustomElement = CustomElement
const initialize = converse.initialize

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless/index.js'
import { api } from '@converse/headless/core.js'
import { CustomElement } from 'shared/components/element.js'
import { tplExternalLoginModal } from 'templates/livechat-external-login-modal.js'
import { __ } from 'i18n'

View File

@ -1,61 +0,0 @@
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
//
// SPDX-License-Identifier: AGPL-3.0-only
// Here we are patching the vCard plugin, to add some specific optimizations.
import { _converse, api } from '@converse/headless/index.js'
import {
onOccupantAvatarChanged,
setVCardOnModel,
setVCardOnOccupant
} from '@converse/headless/plugins/vcard/utils.js'
const pluginDefinition = _converse.pluggable.plugins['converse-vcard']
const originalInitialize = pluginDefinition.initialize
pluginDefinition.initialize = function initialize () {
const previousListeners = _converse._events.chatRoomInitialized ?? []
originalInitialize.apply(this)
_converse.api.settings.extend({
livechat_load_all_vcards: false
})
// Now we must detect the new chatRoomInitialized listener, and remove it:
const listenersToRemove = []
for (const def of _converse._events.chatRoomInitialized ?? []) {
if (def.callback && !previousListeners.includes(def.callback)) {
listenersToRemove.push(def.callback)
}
}
for (const callback of listenersToRemove) {
console.debug('Livechat patching vcard: we must remove this listener', callback)
api.listen.not('chatRoomInitialized', callback)
}
// Adding the new listener:
api.listen.on('chatRoomInitialized', (m) => {
console.debug('Patched version of the vcard chatRoomInitialized event.')
setVCardOnModel(m)
// loadAll: when in readonly mode (ie: OBS integration), always load all avatars.
const loadAll = api.settings.get('livechat_load_all_vcards') === true
let hiddenOccupants = m.get('hidden_occupants')
if (hiddenOccupants !== true || loadAll) {
m.occupants.forEach(setVCardOnOccupant)
}
m.listenTo(m.occupants, 'add', (occupant) => {
if (hiddenOccupants !== true || loadAll) {
setVCardOnOccupant(occupant)
}
})
m.on('change:hidden_occupants', () => {
hiddenOccupants = m.get('hidden_occupants')
if (hiddenOccupants !== true || loadAll) {
m.occupants.forEach(setVCardOnOccupant)
}
})
m.listenTo(m.occupants, 'change:image_hash', o => onOccupantAvatarChanged(o))
})
}

View File

@ -4,7 +4,7 @@
import { XMLNS_POLL } from '../constants.js'
import { tplPollForm } from '../templates/poll-form.js'
import { CustomElement } from 'shared/components/element.js'
import { converse, api, parsers } from '@converse/headless'
import { converse, api } from '@converse/headless/core'
import { webForm2xForm } from '@converse/headless/utils/form'
import { __ } from 'i18n'
import '../styles/poll-form.scss'
@ -18,6 +18,7 @@ export default class MUCPollFormView extends CustomElement {
return {
model: { type: Object, attribute: true },
modal: { type: Object, attribute: true },
form_fields: { type: Object, attribute: false },
alert_message: { type: Object, attribute: false },
title: { type: String, attribute: false },
instructions: { type: String, attribute: false }
@ -26,8 +27,6 @@ export default class MUCPollFormView extends CustomElement {
_fieldTranslationMap = new Map()
xform = undefined
async initialize () {
this.alert_message = undefined
if (!this.model) {
@ -37,18 +36,20 @@ export default class MUCPollFormView extends CustomElement {
try {
this._initFieldTranslations()
const stanza = await this._fetchPollForm()
const xform = parsers.parseXForm(stanza)
const query = stanza.querySelector('query')
const xform = sizzle(`x[xmlns="${Strophe.NS.XFORM}"]`, query)[0]
if (!xform) {
throw Error('Missing xform in stanza')
}
xform.fields?.map(f => this._translateField(f))
this.xform = xform
// eslint-disable-next-line no-undef
this.title = __(LOC_poll_title) // xform.querySelector('title')?.textContent ?? ''
// eslint-disable-next-line no-undef
this.instructions = __(LOC_poll_instructions) // xform.querySelector('instructions')?.textContent ?? ''
this.form_fields = Array.from(xform.querySelectorAll('field')).map(field => {
this._translateField(field)
return u.xForm2TemplateResult(field, stanza)
})
} catch (err) {
console.error(err)
this.alert_message = __('Error')
@ -85,10 +86,10 @@ export default class MUCPollFormView extends CustomElement {
}
_translateField (field) {
const v = field.var
const v = field.getAttribute('var')
const label = this._fieldTranslationMap.get(v)
if (label) {
field.label = label
field.setAttribute('label', label)
}
}

View File

@ -4,7 +4,7 @@
import { tplPoll } from '../templates/poll.js'
import { CustomElement } from 'shared/components/element.js'
import { converse, _converse, api } from '@converse/headless'
import { converse, _converse, api } from '@converse/headless/core'
import '../styles/poll.scss'
export default class MUCPollView extends CustomElement {

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse } from '../../../src/headless/index.js'
import { _converse, converse } from '../../../src/headless/core.js'
import { getHeadingButtons } from './utils.js'
import { POLL_MESSAGE_TAG, POLL_QUESTION_TAG, POLL_CHOICE_TAG } from './constants.js'
import { __ } from 'i18n'

View File

@ -4,7 +4,7 @@
import { __ } from 'i18n'
import BaseModal from 'plugins/modal/modal.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { modal_close_button as ModalCloseButton } from 'plugins/modal/templates/buttons.js'
import { html } from 'lit'

View File

@ -5,10 +5,6 @@
import { converseLocalizedHelpUrl } from '../../../shared/lib/help'
import { html } from 'lit'
import { __ } from 'i18n'
import { converse } from '@converse/headless'
const u = converse.env.utils
export function tplPollForm (el) {
const i18nOk = __('Ok')
// eslint-disable-next-line no-undef
@ -17,18 +13,10 @@ export function tplPollForm (el) {
page: 'documentation/user/streamers/polls'
})
let formFieldTemplates
if (el.xform) {
const fields = el.xform.fields
formFieldTemplates = fields.map(field => {
return u.xFormField2TemplateResult(field)
})
}
return html`
${el.alert_message ? html`<div class="error">${el.alert_message}</div>` : ''}
${
formFieldTemplates
el.form_fields
? html`
<form class="converse-form" @submit=${ev => el.formSubmit(ev)}>
<p class="title">
@ -42,7 +30,7 @@ export function tplPollForm (el) {
<p class="form-help instructions">${el.instructions}</p>
<div class="form-errors hidden"></div>
${formFieldTemplates}
${el.form_fields}
<fieldset class="buttons form-group">
<input type="submit" class="btn btn-primary" value="${i18nOk}" />

View File

@ -63,7 +63,7 @@ function _tplChoice (el, currentPoll, choice, canVote) {
<div class="livechat-progress-bar">
<div
role="progressbar"
style=${'width: ' + percent + '%;'}
style="width: ${percent}%;"
aria-valuenow="${percent}" aria-valuemin="0" aria-valuemax="100"
></div>
<p>

View File

@ -3,12 +3,12 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { XMLNS_POLL } from './constants.js'
import { _converse, api } from '../../../src/headless/index.js'
import { _converse, api } from '../../../src/headless/core.js'
import { __ } from 'i18n'
export function getHeadingButtons (view, buttons) {
const muc = view.model
if (muc.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (muc.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}
@ -32,7 +32,7 @@ export function getHeadingButtons (view, buttons) {
api.modal.show('livechat-converse-poll-form-modal', { model: muc })
},
a_class: '',
icon_class: 'fa-square-poll-horizontal',
icon_class: 'fa-list-check', // FIXME
name: 'muc-create-poll'
})

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse, api } from '../../../src/headless/index.js'
import { _converse, converse, api } from '../../../src/headless/core.js'
/**
* This plugin computes the available width of converse-root, and adds classes

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { CustomElement } from 'shared/components/element.js'
import { tplMUCTaskApp } from '../templates/muc-task-app.js'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMucTaskList from '../templates/muc-task-list'
import { __ } from 'i18n'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMucTaskLists from '../templates/muc-task-lists'
import { __ } from 'i18n'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { tplMucTask } from '../templates/muc-task'
import { __ } from 'i18n'

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, converse } from '../../../src/headless/index.js'
import { _converse, converse } from '../../../src/headless/core.js'
import { ChatRoomTaskLists } from './task-lists.js'
import { ChatRoomTaskList } from './task-list.js'
import { ChatRoomTasks } from './tasks.js'
@ -18,14 +18,9 @@ converse.plugins.add('livechat-converse-tasks', {
dependencies: ['converse-muc', 'converse-disco', 'converse-pubsub'],
initialize () {
Object.assign(
_converse.exports,
{
ChatRoomTaskLists,
ChatRoomTaskList,
ChatRoomTasks
}
)
_converse.ChatRoomTaskLists = ChatRoomTaskLists
_converse.ChatRoomTaskList = ChatRoomTaskList
_converse.ChatRoomTasks = ChatRoomTasks
_converse.api.settings.extend({
livechat_task_app_enabled: false,

View File

@ -4,7 +4,7 @@
import BaseModal from 'plugins/modal/modal.js'
import tplPickTaskList from './templates/pick-task-list.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { __ } from 'i18n'
export default class PickTaskListModal extends BaseModal {

View File

@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js'
/**
* A chat room task list.
* @class
* @namespace _converse.exports.ChatRoomTaskList
* @namespace _converse.ChatRoomTaskList
* @memberof _converse
*/
class ChatRoomTaskList extends Model {

View File

@ -7,9 +7,9 @@ import { ChatRoomTaskList } from './task-list'
import { initStorage } from '@converse/headless/utils/storage.js'
/**
* A list of {@link _converse.exports.ChatRoomTaskList} instances, representing task lists associated to a MUC.
* A list of {@link _converse.ChatRoomTaskList} instances, representing task lists associated to a MUC.
* @class
* @namespace _converse.exports.ChatRoomTaskLists
* @namespace _converse.ChatRoomTaskLists
* @memberOf _converse
*/
class ChatRoomTaskLists extends Collection {

View File

@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js'
/**
* A chat room task.
* @class
* @namespace _converse.exports.ChatRoomTask
* @namespace _converse.ChatRoomTask
* @memberof _converse
*/
class ChatRoomTask extends Model {

View File

@ -7,9 +7,9 @@ import { ChatRoomTask } from './task'
import { initStorage } from '@converse/headless/utils/storage.js'
/**
* A list of {@link _converse.exports.ChatRoomTask} instances, representing all tasks associated to a MUC.
* A list of {@link _converse.ChatRoomTask} instances, representing all tasks associated to a MUC.
* @class
* @namespace _converse.exports.ChatRoomTasks
* @namespace _converse.ChatRoomTasks
* @memberOf _converse
*/
class ChatRoomTasks extends Collection {

View File

@ -4,12 +4,12 @@
import { XMLNS_TASKLIST, XMLNS_TASK } from './constants.js'
import { PubSubManager } from '../../shared/lib/pubsub-manager.js'
import { converse, _converse, api } from '../../../src/headless/index.js'
import { converse, _converse, api } from '../../../src/headless/core.js'
import { __ } from 'i18n'
export function getHeadingButtons (view, buttons) {
const muc = view.model
if (muc.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (muc.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}
@ -74,8 +74,8 @@ function _initChatRoomTaskLists (mucModel) {
return
}
mucModel.tasklists = new _converse.exports.ChatRoomTaskLists(undefined, { chatroom: mucModel })
mucModel.tasks = new _converse.exports.ChatRoomTasks(undefined, { chatroom: mucModel })
mucModel.tasklists = new _converse.ChatRoomTaskLists(undefined, { chatroom: mucModel })
mucModel.tasks = new _converse.ChatRoomTasks(undefined, { chatroom: mucModel })
mucModel.taskManager = new PubSubManager(
mucModel.get('jid'),
@ -127,7 +127,7 @@ function _destroyChatRoomTaskLists (mucModel) {
}
export function initOrDestroyChatRoomTaskLists (mucModel) {
if (mucModel.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (mucModel.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return _destroyChatRoomTaskLists(mucModel)
}

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { CustomElement } from 'shared/components/element.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { html } from 'lit'
import { __ } from 'i18n'

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { converse, api } from '../../../src/headless/index.js'
import { converse, api } from '../../../src/headless/core.js'
import './components/muc-terms.js'
const { sizzle } = converse.env

View File

@ -4,7 +4,7 @@
/* eslint-disable max-len */
import { html } from 'lit'
import tplIcons from '../../../src/shared/components/templates/icons.js'
import tplIcons from '../../../src/shared/templates/icons.js'
export default () => {
// Here we are adding some additonal icons to ConverseJS defaults
@ -23,11 +23,6 @@ export default () => {
<symbol id="icon-circle-question" viewBox="0 0 448 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM169.8 165.3c7.9-22.3 29.1-37.3 52.8-37.3h58.3c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24V250.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1H222.6c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/>
</symbol>
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
<symbol id="icon-square-poll-horizontal" viewBox="0 0 448 512">
<path d="M448 96c0-35.3-28.7-64-64-64L64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-320zM256 160c0 17.7-14.3 32-32 32l-96 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l96 0c17.7 0 32 14.3 32 32zm64 64c17.7 0 32 14.3 32 32s-14.3 32-32 32l-192 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l192 0zM192 352c0 17.7-14.3 32-32 32l-32 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l32 0c17.7 0 32 14.3 32 32z"/>
</symbol>
</svg>
`
}

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { converse, _converse, api } from '../../../src/headless/index.js'
import { converse, _converse, api } from '../../../src/headless/core.js'
const { $build, Strophe, $iq, sizzle } = converse.env
/**
@ -50,7 +50,7 @@ export class PubSubManager {
async start () {
// FIXME: handle errors. Find a way to display to user that this failed.
this.stanzaHandler = api.connection.get().addHandler(
this.stanzaHandler = _converse.connection.addHandler(
(message) => {
try {
this._handleMessage(message)
@ -79,7 +79,7 @@ export class PubSubManager {
// Note: no need to unsubscribe from the pubsub node, the backend will do when users leave the room.
if (this.stanzaHandler) {
api.connection.get().deleteHandler(this.stanzaHandler)
_converse.connection.deleteHandler(this.stanzaHandler)
this.stanzaHandler = undefined
}
}

View File

@ -4,7 +4,7 @@
import { __ } from 'i18n'
import BaseModal from 'plugins/modal/modal.js'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { html } from 'lit'
import 'livechat-external-login-content.js'

View File

@ -5,7 +5,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { api } from '@converse/headless/index.js'
import { api } from '@converse/headless/core.js'
export default () => html`
<div class="inner-content converse-brand row">

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { _converse, api } from '@converse/headless'
import { _converse, api } from '@converse/headless/core'
import { __ } from 'i18n'
import { html } from 'lit'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { __ } from 'i18n'
import { _converse, api } from '@converse/headless'
import { _converse, api } from '@converse/headless/core'
import { html } from 'lit'
import tplMucBottomPanel from '../../src/plugins/muc-views/templates/muc-bottom-panel.js'
import { CustomElement } from 'shared/components/element.js'
@ -79,7 +79,7 @@ class SlowMode extends CustomElement {
api.elements.define('livechat-slow-mode', SlowMode)
const tplSlowMode = (o) => {
if (!o.can_post) { return html`` }
if (!o.can_edit) { return html`` }
return html`<livechat-slow-mode jid=${o.model.get('jid')}>`
}
@ -128,9 +128,17 @@ const tplViewerMode = (o) => {
}
export default (o) => {
// ConverseJS 10.x does not handle properly the visitor role in unmoderated rooms.
// See https://github.com/conversejs/converse.js/issues/3428 for more info.
// So we will do a dirty hack here to fix this case.
// Note: ConverseJS 11.x has changed the code, and could be fixed more cleanly (or will be fixed if #3428 is fixed).
if (o.can_edit && o.model.getOwnRole() === 'visitor') {
o.can_edit = false
}
let mutedAnonymousMessage
if (
!o.can_post &&
!o.can_edit &&
o.model.features?.get?.('x_peertubelivechat_mute_anonymous') &&
_converse.api.settings.get('livechat_specific_is_anonymous') === true
) {

View File

@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: AGPL-3.0-only
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import tplMUCChatarea from '../../src/plugins/muc-views/templates/muc-chatarea.js'
import { html } from 'lit'

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { html } from 'lit'
import { api } from '@converse/headless'
import { api } from '@converse/headless/core'
import { until } from 'lit/directives/until.js'
import { repeat } from 'lit/directives/repeat.js'
import { unsafeHTML } from 'lit/directives/unsafe-html.js'

View File

@ -44,7 +44,7 @@ module.exports = merge(prod, {
'../../templates/background_logo.js$': path.resolve(__dirname, 'custom/templates/background_logo.js'),
'./templates/muc-chatarea.js': path.resolve('custom/templates/muc-chatarea.js'),
'./templates/icons.js': path.resolve(__dirname, 'custom/shared/components/font-awesome.js'),
'../templates/icons.js': path.resolve(__dirname, 'custom/shared/components/font-awesome.js'),
'shared/styles/index.scss$': path.resolve(__dirname, 'custom/shared/styles/livechat.scss'),

View File

@ -97,7 +97,6 @@ function defaultConverseParams (
pruning_behavior: 'unscrolled',
colorize_username: true,
send_chat_markers: [],
reuse_scram_keys: false, // for now we don't use this.
// This is a specific settings, that is used in ConverseJS customization, to force avatars loading in readonly mode.
livechat_load_all_vcards: !!forceReadonly,

View File

@ -16,7 +16,7 @@ export const livechatMiniMucHeadPlugin = {
})
_converse.api.listen.on('getHeadingButtons', (view: any, buttons: any[]) => {
if (view.model.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (view.model.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}

View File

@ -15,7 +15,7 @@ export const livechatSpecificsPlugin = {
})
_converse.api.listen.on('getHeadingButtons', (view: any, buttons: any[]) => {
if (view.model.get('type') !== _converse.constants.CHATROOMS_TYPE) {
if (view.model.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return buttons
}
@ -53,71 +53,6 @@ export const livechatSpecificsPlugin = {
return buttons
})
_converse.api.listen.on('getToolbarButtons', (toolbarEl: any, buttons: any[]) => {
// We will replace the toggle occupant button, to change its appearance.
// First, we must find it. We search from the end, because usually it is the last one.
let toggleOccupantButton: any
for (const button of buttons.reverse()) {
if (button.strings?.find((s: string) => s.includes('toggle_occupants'))) { // searching the classname
console.debug('[livechatSpecificsPlugin] found the toggle occupants button', button)
toggleOccupantButton = button
break
}
}
if (!toggleOccupantButton) {
console.debug('[livechatSpecificsPlugin] Did not found the toggle occupants button')
return buttons
}
buttons = buttons.filter(b => b !== toggleOccupantButton)
// Replacing by the new button...
// Note: we don't need to test conditions, we know the button was here.
const i18nHideOccupants = _converse.__('Hide participants')
const i18nShowOccupants = _converse.__('Show participants')
const html = window.converse.env.html
const icon = toolbarEl.hidden_occupants
? html`<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa fa-angle-double-left"
size="1em">
</converse-icon>
<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa users"
size="1em">
</converse-icon>`
: html`<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa users"
size="1em">
</converse-icon>
<converse-icon
color="var(--muc-toolbar-btn-color)"
class="fa fa-angle-double-right"
size="1em">
</converse-icon>`
buttons.push(html`
<button class="toggle_occupants right"
title="${toolbarEl.hidden_occupants ? i18nShowOccupants : i18nHideOccupants}"
@click=${toolbarEl.toggleOccupants}>
${icon}
</button>`
)
return buttons
})
// Overriding the MUCHeading custom element, to customize the destroyMUC function:
const MUCHeading = _converse.api.elements.registry['converse-muc-heading']
if (MUCHeading) {
class MUCHeadingOverloaded extends MUCHeading {
async destroy (ev: Event): Promise<void> {
ev.preventDefault()
await destroyMUC(_converse, this.model) // here we call a custom version of destroyMUC
}
}
_converse.api.elements.define('converse-muc-heading', MUCHeadingOverloaded)
}
_converse.api.listen.on('chatRoomViewInitialized', function (this: any, _model: any): void {
// Remove the spinner if present...
document.getElementById('livechat-loading-spinner')?.remove()
@ -182,7 +117,7 @@ export const livechatSpecificsPlugin = {
},
overrides: {
ChatRoom: {
getActionInfoMessage: function getActionInfoMessage (this: any, code: string, nick: string, actor: any): any {
getActionInfoMessage: function (this: any, code: string, nick: string, actor: any): any {
if (code === '303') {
// When there is numerous anonymous users joining at the same time,
// they can all change their nicknames at the same time, generating a log of action messages.
@ -195,12 +130,6 @@ export const livechatSpecificsPlugin = {
}
}
return this.__super__.getActionInfoMessage(code, nick, actor)
},
canPostMessages: function canPostMessages (this: any) {
// ConverseJS does not handle properly the visitor role in unmoderated rooms.
// See https://github.com/conversejs/converse.js/issues/3428 for more info.
// FIXME: if #3428 is fixed, remove this override.
return this.isEntered() && this.getOwnRole() !== 'visitor'
}
},
ChatRoomMessage: {
@ -254,26 +183,3 @@ function getOpenPromise (): any {
)
return promise
}
async function destroyMUC (_converse: any, model: any): Promise<void> {
const __ = _converse.__
const messages = [__('Are you sure you want to destroy this groupchat?')]
// Note: challenge and newjid make no sens for peertube-plugin-livechat,
// we remove them comparing to the original function.
let fields = [
{
name: 'reason',
label: __('Optional reason for destroying this groupchat'),
placeholder: __('Reason'),
value: undefined
}
]
try {
fields = await _converse.api.confirm(__('Confirm'), messages, fields)
const reason = fields.filter(f => f.name === 'reason').pop()?.value
const newjid = undefined
return model.sendDestroyIQ(reason, newjid).then(() => model.close())
} catch (e) {
console.error(e)
}
}

View File

@ -17,11 +17,11 @@ export const livechatViewerModePlugin = {
livechat_external_auth_reconnect_mode: undefined
})
const originalGetDefaultMUCNickname = _converse.exports.getDefaultMUCNickname
const originalGetDefaultMUCNickname = _converse.getDefaultMUCNickname
if (!originalGetDefaultMUCNickname) {
console.error('[livechatViewerModePlugin] getDefaultMUCNickname is not initialized.')
} else {
Object.assign(_converse.exports, {
Object.assign(_converse, {
getDefaultMUCNickname: function (this: any): any {
if (!_converse.api.settings.get('livechat_enable_viewer_mode')) {
return originalGetDefaultMUCNickname.apply(this, arguments)

View File

@ -42,7 +42,7 @@ export const moderationDelayPlugin = {
// Ok... We will add some info about how many remains...
r.pretty_time = window.converse.env.html`
${r.pretty_time}<span aria-hidden="true">&nbsp;-&nbsp;${Math.round(remains)}</span>
${r.pretty_time}&nbsp;-&nbsp;${Math.round(remains)}
`
// and we must update in 1 second...
setTimeout(() => this.requestUpdate(), 1000)

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "peertube-plugin-livechat",
"version": "10.3.1",
"version": "10.3.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "peertube-plugin-livechat",
"version": "10.3.1",
"version": "10.3.0",
"license": "AGPL-3.0",
"dependencies": {
"@xmpp/jid": "^0.13.1",

View File

@ -1,7 +1,7 @@
{
"name": "peertube-plugin-livechat",
"description": "NCTV fork of the peertube-plugin-livechat plugin, containing styling and other shit. This will be maintained with upstream.",
"version": "10.3.1",
"version": "10.3.0",
"license": "AGPL-3.0",
"author": {
"name": "Matty Boombalatty",

View File

@ -8,11 +8,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2024-07-10 16:54+0200\n"
"PO-Revision-Date: 2024-07-12 09:10+0000\n"
"Last-Translator: Victor Hampel <v.hampel@users.noreply.weblate.framasoft.org>"
"\n"
"Language-Team: German <https://weblate.framasoft.org/projects/"
"peertube-livechat/peertube-plugin-livechat-documentation/de/>\n"
"PO-Revision-Date: 2024-07-05 19:12+0000\n"
"Last-Translator: Victor Hampel <v.hampel@users.noreply.weblate.framasoft.org>\n"
"Language-Team: German <https://weblate.framasoft.org/projects/peertube-livechat/peertube-plugin-livechat-documentation/de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -3274,30 +3272,25 @@ msgstr "Um den Wert für einen bereits bestehenden Raum zu ändern, öffnen Sie
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
msgid "Currently, this feature has one known bug: users that join the chat will get all messages, even messages that are still pending for other participants. However, messages sent after they joined will be delayed correctly."
msgstr ""
"Derzeit gibt es bei dieser Funktion einen bekannten Fehler: Benutzer, die "
"dem Chat beitreten, erhalten alle Nachrichten, auch solche, die noch für "
"andere Teilnehmer ausstehen. Allerdings werden Nachrichten, die nach dem "
"Beitritt gesendet werden, korrekt verzögert."
#. type: Title ##
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
#, no-wrap
#, fuzzy, no-wrap
#| msgid "Share the chat"
msgid "In the chat"
msgstr "Im Chat"
msgstr "Teilen Sie den Chat"
#. type: Plain text
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
msgid "As a moderator, you will see the remaining time (in seconds) before the message is broadcasted, just besides the message datetime."
msgstr ""
"Als Moderator sehen Sie neben dem Datum der Nachricht auch die verbleibende "
"Zeit (in Sekunden), bevor die Nachricht veröffentlicht wird."
#. type: Plain text
#: support/documentation/content/en/documentation/user/streamers/moderation_delay.md
#, fuzzy
#| msgid "![Channel configuration / Moderation delay](/peertube-plugin-livechat/images/moderation_delay_channel_option.png?classes=shadow,border&height=400px)"
msgid "![Moderation delay timer](/peertube-plugin-livechat/images/moderation_delay_timer.png?classes=shadow,border)"
msgstr ""
"![Moderationsverzögerungstimer](/peertube-plugin-livechat/images/"
"moderation_delay_timer.png?classes=shadow,border)"
msgstr "![Kanalkonfiguration / Moderationsverzögerung](/peertube-plugin-livechat/images/moderation_delay_channel_option.png?classes=shadow,border&height=400px)"
#. type: Yaml Front Matter Hash Value: description
#: build/documentation/pot_in/documentation/user/streamers/moderation.md
@ -3344,11 +3337,10 @@ msgstr "Über das [Chat Dropdown Menü](/peertube-plugin-livechat/de/documentati
#. type: Plain text
#: build/documentation/pot_in/documentation/user/streamers/moderation.md
#, fuzzy
#| msgid "The video owner will be owner of the chat room. This means he can configure the room, delete it, promote other users as admins, ..."
msgid "The video owner will be owner of the chat room. This means they can configure the room, delete it, promote other users as admins, ..."
msgstr ""
"Der Videobesitzer ist der Besitzer des Chatraums. Das bedeutet, er kann den "
"Raum konfigurieren, löschen, andere Benutzer als Administratoren befördern, "
"..."
msgstr "Der Videobesitzer ist der Besitzer des Chatraums. Das bedeutet, er kann den Raum konfigurieren, löschen, andere Benutzer als Administratoren befördern, ..."
#. type: Plain text
#: build/documentation/pot_in/documentation/user/streamers/moderation.md