// SPDX-FileCopyrightText: 2024 John Livingston // SPDX-FileCopyrightText: 2025 Nicolas Chesnais // // SPDX-License-Identifier: AGPL-3.0-only // FIXME: @stylistic/indent is buggy with strings literrals. /* eslint-disable @stylistic/indent */ import { __ } from 'i18n' import { _converse, api } from '@converse/headless' import { html } from 'lit' import tplMucBottomPanel from '../../src/plugins/muc-views/templates/muc-bottom-panel.js' import { CustomElement } from 'shared/components/element.js' import 'shared/modals/livechat-external-login.js' async function setNicknameAndFocus (ev, model) { ev.preventDefault() const nick = ev.target.nick.value.trim() if (!nick) { return } await model.setNickname(nick) _converse.api.trigger('livechatViewerModeSetNickname', model, nick, { synchronous: true }) document.querySelector('.chat-textarea')?.focus() } class SlowMode extends CustomElement { static get properties () { return { jid: { type: String } } } hideInfoBox = false async connectedCallback () { super.connectedCallback() this.model = _converse.chatboxes.get(this.jid) await this.model.initialized let previousDuration = this.model.config.get('slow_mode_duration') this.listenTo(this.model.config, 'change:slow_mode_duration', () => { if (this.hideInfoBox) { const duration = this.model.config.get('slow_mode_duration') if (duration !== previousDuration) { previousDuration = duration // Duration changed, opening the infobox again. this.hideInfoBox = false } } this.requestUpdate() }) } render () { if (!(parseInt(this.model.config.get('slow_mode_duration')) > 0)) { // This includes NaN, for which ">0"===false return html`` } if (this.hideInfoBox) { return html`` } return html`
${__( // eslint-disable-next-line no-undef LOC_slow_mode_info, this.model.config.get('slow_mode_duration') )}
` } closeSlowModeInfoBox (ev) { ev?.preventDefault?.() ev?.stopPropagation?.() this.hideInfoBox = true this.requestUpdate() } } api.elements.define('livechat-slow-mode', SlowMode) const tplSlowMode = (o) => { if (!o.can_post) { return html`` } return html`` } const tplEmojiOnly = (o) => { if (!o.can_post) { return html`` } if (!o.model.features?.get?.('x_peertubelivechat_emoji_only_mode')) { return '' } return html`
${ // eslint-disable-next-line no-undef __(LOC_emoji_only_info) }
` } class BackToLastMsg extends CustomElement { static get properties () { return { jid: { type: String } } } show = false async connectedCallback () { super.connectedCallback() this.model = _converse.chatboxes.get(this.jid) await this.model.initialized let scrolled = this.model.ui.get('scrolled') let hasUnreadMsg = this.model.get('num_unread_general') > 0 this.listenTo(this.model.ui, 'change:scrolled', () => { scrolled = this.model.ui.get('scrolled') this.show = scrolled && !hasUnreadMsg this.requestUpdate() }) this.listenTo(this.model, 'change:num_unread_general', () => { hasUnreadMsg = this.model.get('num_unread_general') > 0 // Do not show the element if there is new messages since there is another element for that this.show = scrolled && !hasUnreadMsg this.requestUpdate() }) } onClick (ev) { ev?.preventDefault() const chatContainer = document.querySelector('converse-chat-content') chatContainer?.scrollTo({ top: chatContainer.scrollHeight }) } render () { return this.show ? html`
▼ ${ // eslint-disable-next-line no-undef __(LOC_back_to_last_msg) } ▼
` : '' } } api.elements.define('livechat-back-to-last-msg', BackToLastMsg) const tplViewerMode = (o) => { if (!api.settings.get('livechat_enable_viewer_mode')) { return html`` } const model = o.model const i18nNickname = __('Nickname') const i18nJoin = __('Enter groupchat') const i18nHeading = __('Choose a nickname to enter') // eslint-disable-next-line no-undef const i18nExternalLogin = __(LOC_login_using_external_account) return html`
setNicknameAndFocus(ev, model)}>
${ // If we open a room with forcetype, there is no current video... So just disabling external login // (in such case, we should be logged in as admin/moderator...) !api.settings.get('livechat_peertube_video_original_url') ? '' : html`
` }
` } export default (o) => { let mutedAnonymousMessage if ( !o.can_post && o.model.features?.get?.('x_peertubelivechat_mute_anonymous') && _converse.api.settings.get('livechat_specific_is_anonymous') === true ) { // If we are moderated because we are anonymous, we want to display a custom message. // FIXME: if x_peertubelivechat_mute_anonymous changes, user are first muted/voiced, and then only the // status 104 is sent. But we don't listen to 'change:x_peertubelivechat_mute_anonymous'. // So the custom message won't be correct. But this is not a big issue. // eslint-disable-next-line no-undef mutedAnonymousMessage = __(LOC_muted_anonymous_message) } return html` ${tplViewerMode(o)} ${tplSlowMode(o)} ${tplEmojiOnly(o)} ${ mutedAnonymousMessage ? html`${mutedAnonymousMessage}` : tplMucBottomPanel(o) }` }