Add modal for changing your nickname...
once you're already in a MUC.
This commit is contained in:
parent
ba52defdae
commit
f4fdc36d31
@ -5,8 +5,8 @@
|
|||||||
- Updated translations: lt
|
- Updated translations: lt
|
||||||
- Increased stanza timeout from 10 to 20 seconds
|
- Increased stanza timeout from 10 to 20 seconds
|
||||||
- Replace various font icons with SVG icons
|
- Replace various font icons with SVG icons
|
||||||
- Fix OMEMO race condition related to automatic reconnection
|
|
||||||
- #1761: Add a new dark theme based on the [Dracula](https://draculatheme.com/) theme
|
- #1761: Add a new dark theme based on the [Dracula](https://draculatheme.com/) theme
|
||||||
|
- #2733: Fix OMEMO race condition related to automatic reconnection
|
||||||
- #2751: Media not rendered when Converse runs in a browser extension
|
- #2751: Media not rendered when Converse runs in a browser extension
|
||||||
- #2786: Fix webpack configuration not working on Windows OS
|
- #2786: Fix webpack configuration not working on Windows OS
|
||||||
- #2788: `TypeError` when trying to use `@converse/headless`
|
- #2788: `TypeError` when trying to use `@converse/headless`
|
||||||
|
@ -124,6 +124,10 @@ const ChatRoomMixin = {
|
|||||||
this.initialized.resolve();
|
this.initialized.resolve();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isEntered () {
|
||||||
|
return this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether we're still joined and if so, restores the MUC state from cache.
|
* Checks whether we're still joined and if so, restores the MUC state from cache.
|
||||||
* @private
|
* @private
|
||||||
@ -131,7 +135,7 @@ const ChatRoomMixin = {
|
|||||||
* @returns { Boolean } Returns `true` if we're still joined, otherwise returns `false`.
|
* @returns { Boolean } Returns `true` if we're still joined, otherwise returns `false`.
|
||||||
*/
|
*/
|
||||||
async restoreFromCache () {
|
async restoreFromCache () {
|
||||||
if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED && (await this.isJoined())) {
|
if (this.isEntered() && (await this.isJoined())) {
|
||||||
// We've restored the room from cache and we're still joined.
|
// We've restored the room from cache and we're still joined.
|
||||||
await new Promise(resolve => this.features.fetch({ 'success': resolve, 'error': resolve }));
|
await new Promise(resolve => this.features.fetch({ 'success': resolve, 'error': resolve }));
|
||||||
await this.fetchOccupants().catch(e => log.error(e));
|
await this.fetchOccupants().catch(e => log.error(e));
|
||||||
@ -154,7 +158,7 @@ const ChatRoomMixin = {
|
|||||||
* model (if available).
|
* model (if available).
|
||||||
*/
|
*/
|
||||||
async join (nick, password) {
|
async join (nick, password) {
|
||||||
if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
|
if (this.isEntered()) {
|
||||||
// We have restored a groupchat from session storage,
|
// We have restored a groupchat from session storage,
|
||||||
// so we don't send out a presence stanza again.
|
// so we don't send out a presence stanza again.
|
||||||
return this;
|
return this;
|
||||||
@ -293,7 +297,7 @@ const ChatRoomMixin = {
|
|||||||
onOccupantRemoved (occupant) {
|
onOccupantRemoved (occupant) {
|
||||||
if (
|
if (
|
||||||
_converse.isInfoVisible(converse.MUC_TRAFFIC_STATES.EXITED) &&
|
_converse.isInfoVisible(converse.MUC_TRAFFIC_STATES.EXITED) &&
|
||||||
this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED &&
|
this.isEntered() &&
|
||||||
occupant.get('show') === 'online'
|
occupant.get('show') === 'online'
|
||||||
) {
|
) {
|
||||||
this.updateNotifications(occupant.get('nick'), converse.MUC_TRAFFIC_STATES.EXITED);
|
this.updateNotifications(occupant.get('nick'), converse.MUC_TRAFFIC_STATES.EXITED);
|
||||||
@ -339,7 +343,7 @@ const ChatRoomMixin = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async onConnectionStatusChanged () {
|
async onConnectionStatusChanged () {
|
||||||
if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
|
if (this.isEntered()) {
|
||||||
if (this.get('hidden') && api.settings.get('muc_subscribe_to_rai') && this.getOwnAffiliation() !== 'none') {
|
if (this.get('hidden') && api.settings.get('muc_subscribe_to_rai') && this.getOwnAffiliation() !== 'none') {
|
||||||
try {
|
try {
|
||||||
await this.leave();
|
await this.leave();
|
||||||
@ -491,8 +495,7 @@ const ChatRoomMixin = {
|
|||||||
* @param { XMLElement } stanza
|
* @param { XMLElement } stanza
|
||||||
*/
|
*/
|
||||||
handleMessageFromMUCHost (stanza) {
|
handleMessageFromMUCHost (stanza) {
|
||||||
const conn_status = this.session.get('connection_status');
|
if (this.isEntered()) {
|
||||||
if (conn_status === converse.ROOMSTATUS.ENTERED) {
|
|
||||||
// We're not interested in activity indicators when already joined to the room
|
// We're not interested in activity indicators when already joined to the room
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -513,7 +516,7 @@ const ChatRoomMixin = {
|
|||||||
* @param { XMLElement } stanza
|
* @param { XMLElement } stanza
|
||||||
*/
|
*/
|
||||||
handleForwardedMentions (stanza) {
|
handleForwardedMentions (stanza) {
|
||||||
if (this.session.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
|
if (this.isEntered()) {
|
||||||
// Avoid counting mentions twice
|
// Avoid counting mentions twice
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1023,7 +1026,7 @@ const ChatRoomMixin = {
|
|||||||
if (
|
if (
|
||||||
!api.settings.get('send_chat_state_notifications') ||
|
!api.settings.get('send_chat_state_notifications') ||
|
||||||
!this.get('chat_state') ||
|
!this.get('chat_state') ||
|
||||||
this.session.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
|
!this.isEntered() ||
|
||||||
(this.features.get('moderated') && this.getOwnRole() === 'visitor')
|
(this.features.get('moderated') && this.getOwnRole() === 'visitor')
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@ -1404,6 +1407,10 @@ const ChatRoomMixin = {
|
|||||||
return this.occupants.getOwnOccupant();
|
return this.occupants.getOwnOccupant();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a presence stanza to update the user's nickname in this MUC.
|
||||||
|
* @param { String } nick
|
||||||
|
*/
|
||||||
async setNickname (nick) {
|
async setNickname (nick) {
|
||||||
if (
|
if (
|
||||||
api.settings.get('auto_register_muc_nickname') &&
|
api.settings.get('auto_register_muc_nickname') &&
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ElementView } from '@converse/skeletor/src/element.js';
|
import { ElementView } from '@converse/skeletor/src/element.js';
|
||||||
import MUCInviteModal from 'modals/muc-invite.js';
|
import MUCInviteModal from 'modals/muc-invite.js';
|
||||||
|
import NicknameModal from './modals/nickname.js';
|
||||||
import RoomDetailsModal from 'modals/muc-details.js';
|
import RoomDetailsModal from 'modals/muc-details.js';
|
||||||
import debounce from 'lodash-es/debounce';
|
import debounce from 'lodash-es/debounce';
|
||||||
import tpl_muc_head from './templates/muc-head.js';
|
import tpl_muc_head from './templates/muc-head.js';
|
||||||
@ -107,6 +108,15 @@ export default class MUCHeading extends ElementView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buttons.push({
|
||||||
|
'i18n_text': __('Nickname'),
|
||||||
|
'i18n_title': __("Change the nickname you're using in this groupchat"),
|
||||||
|
'handler': ev => api.modal.show(NicknameModal, { 'model': this.model }, ev),
|
||||||
|
'a_class': 'open-nickname-modal',
|
||||||
|
'icon_class': 'fa-smile',
|
||||||
|
'name': 'nickname'
|
||||||
|
});
|
||||||
|
|
||||||
if (this.model.invitesAllowed()) {
|
if (this.model.invitesAllowed()) {
|
||||||
buttons.push({
|
buttons.push({
|
||||||
'i18n_text': __('Invite'),
|
'i18n_text': __('Invite'),
|
||||||
|
15
src/plugins/muc-views/modals/nickname.js
Normal file
15
src/plugins/muc-views/modals/nickname.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import tpl_nickname from "./templates/nickname.js";
|
||||||
|
import BaseModal from "plugins/modal/base.js";
|
||||||
|
|
||||||
|
export default BaseModal.extend({
|
||||||
|
id: 'change-nickname-modal',
|
||||||
|
|
||||||
|
initialize (attrs) {
|
||||||
|
this.model = attrs.model;
|
||||||
|
BaseModal.prototype.initialize.apply(this, arguments);
|
||||||
|
},
|
||||||
|
|
||||||
|
toHTML () {
|
||||||
|
return tpl_nickname(this);
|
||||||
|
},
|
||||||
|
});
|
21
src/plugins/muc-views/modals/templates/nickname.js
Normal file
21
src/plugins/muc-views/modals/templates/nickname.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { __ } from 'i18n';
|
||||||
|
import { html } from "lit";
|
||||||
|
import { modal_header_close_button } from "plugins/modal/templates/buttons.js"
|
||||||
|
|
||||||
|
export default (modal) => {
|
||||||
|
const jid = modal.model.get('jid');
|
||||||
|
const i18n_heading = __('Change your nickname');
|
||||||
|
return html`
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="converse-modtools-modal-label">
|
||||||
|
${i18n_heading}</h5>
|
||||||
|
${modal_header_close_button}
|
||||||
|
</div>
|
||||||
|
<div class="modal-body d-flex flex-column">
|
||||||
|
<converse-muc-nickname-form jid="${jid}"></converse-muc-nickname-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
@ -19,7 +19,27 @@ class MUCNicknameForm extends CustomElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return tpl_muc_nickname_form(this.model);
|
return tpl_muc_nickname_form(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitNickname (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
const nick = ev.target.nick.value.trim();
|
||||||
|
if (!nick) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.model.isEntered()) {
|
||||||
|
this.model.setNickname(nick);
|
||||||
|
this.closeModal();
|
||||||
|
} else {
|
||||||
|
this.model.join(nick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeModal () {
|
||||||
|
const evt = document.createEvent('Event');
|
||||||
|
evt.initEvent('hide.bs.modal', true, true);
|
||||||
|
this.dispatchEvent(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import '../message-form.js';
|
import '../message-form.js';
|
||||||
|
import '../nickname-form.js';
|
||||||
import 'shared/chat/toolbar.js';
|
import 'shared/chat/toolbar.js';
|
||||||
import tpl_muc_nickname_form from './muc-nickname-form.js';
|
|
||||||
import { __ } from 'i18n';
|
import { __ } from 'i18n';
|
||||||
import { api, converse } from "@converse/headless/core";
|
import { api, converse } from "@converse/headless/core";
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
@ -45,7 +45,9 @@ export default (o) => {
|
|||||||
${(o.can_edit) ? tpl_can_edit(o) : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`}`;
|
${(o.can_edit) ? tpl_can_edit(o) : html`<span class="muc-bottom-panel muc-bottom-panel--muted">${i18n_not_allowed}</span>`}`;
|
||||||
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
} else if (conn_status == converse.ROOMSTATUS.NICKNAME_REQUIRED) {
|
||||||
if (api.settings.get('muc_show_logs_before_join')) {
|
if (api.settings.get('muc_show_logs_before_join')) {
|
||||||
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">${tpl_muc_nickname_form(o.model)}</span>`;
|
return html`<span class="muc-bottom-panel muc-bottom-panel--nickname">
|
||||||
|
<converse-muc-nickname-form jid="${o.model.get('jid')}"></converse-muc-nickname-form>
|
||||||
|
</span>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
@ -2,24 +2,18 @@ import { __ } from 'i18n';
|
|||||||
import { api } from "@converse/headless/core";
|
import { api } from "@converse/headless/core";
|
||||||
import { html } from "lit";
|
import { html } from "lit";
|
||||||
|
|
||||||
function submitNickname (ev, model) {
|
export default (el) => {
|
||||||
ev.preventDefault();
|
|
||||||
const nick = ev.target.nick.value.trim();
|
|
||||||
nick && model.join(nick);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (model) => {
|
|
||||||
const i18n_nickname = __('Nickname');
|
const i18n_nickname = __('Nickname');
|
||||||
const i18n_join = __('Enter groupchat');
|
const i18n_join = el.model?.isEntered() ? __('Change nickname') : __('Enter groupchat');
|
||||||
const i18n_heading = api.settings.get('muc_show_logs_before_join') ?
|
const i18n_heading = api.settings.get('muc_show_logs_before_join') ?
|
||||||
__('Choose a nickname to enter') :
|
__('Choose a nickname to enter') :
|
||||||
__('Please choose your nickname');
|
__('Please choose your nickname');
|
||||||
|
|
||||||
const validation_message = model.get('nickname_validation_message');
|
const validation_message = el.model?.get('nickname_validation_message');
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="chatroom-form-container muc-nickname-form"
|
<div class="chatroom-form-container muc-nickname-form"
|
||||||
@submit=${ev => submitNickname(ev, model)}>
|
@submit=${ev => el.submitNickname(ev)}>
|
||||||
<form class="converse-form chatroom-form converse-centered-form">
|
<form class="converse-form chatroom-form converse-centered-form">
|
||||||
<fieldset class="form-group">
|
<fieldset class="form-group">
|
||||||
<label>${i18n_heading}</label>
|
<label>${i18n_heading}</label>
|
||||||
@ -27,7 +21,7 @@ export default (model) => {
|
|||||||
<input type="text"
|
<input type="text"
|
||||||
required="required"
|
required="required"
|
||||||
name="nick"
|
name="nick"
|
||||||
value="${model.get('nick') || ''}"
|
value="${el.model?.get('nick') || ''}"
|
||||||
class="form-control ${validation_message ? 'error': ''}"
|
class="form-control ${validation_message ? 'error': ''}"
|
||||||
placeholder="${i18n_nickname}"/>
|
placeholder="${i18n_nickname}"/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
@ -2,7 +2,36 @@
|
|||||||
|
|
||||||
const { $pres, $iq, Strophe, sizzle, u } = converse.env;
|
const { $pres, $iq, Strophe, sizzle, u } = converse.env;
|
||||||
|
|
||||||
fdescribe("A MUC", function () {
|
describe("A MUC", function () {
|
||||||
|
|
||||||
|
it("allows you to change your nickname via a modal",
|
||||||
|
mock.initConverse([], {'view_mode': 'fullscreen'}, async function (_converse) {
|
||||||
|
|
||||||
|
const muc_jid = 'lounge@montague.lit';
|
||||||
|
const nick = 'romeo';
|
||||||
|
await mock.openAndEnterChatRoom(_converse, muc_jid, nick);
|
||||||
|
|
||||||
|
const view = _converse.chatboxviews.get(muc_jid);
|
||||||
|
const dropdown_item = view.querySelector(".open-nickname-modal");
|
||||||
|
dropdown_item.click();
|
||||||
|
|
||||||
|
const modal = _converse.api.modal.get('change-nickname-modal');
|
||||||
|
await u.waitUntil(() => u.isVisible(modal.el));
|
||||||
|
|
||||||
|
const input = modal.el.querySelector('input[name="nick"]');
|
||||||
|
expect(input.value).toBe(nick);
|
||||||
|
|
||||||
|
const newnick = 'loverboy';
|
||||||
|
input.value = newnick;
|
||||||
|
modal.el.querySelector('input[type="submit"]')?.click();
|
||||||
|
|
||||||
|
await u.waitUntil(() => !u.isVisible(modal.el));
|
||||||
|
|
||||||
|
const { sent_stanzas } = _converse.connection;
|
||||||
|
const sent_stanza = sent_stanzas.pop()
|
||||||
|
expect(Strophe.serialize(sent_stanza).toLocaleString()).toBe(
|
||||||
|
`<presence from="${_converse.jid}" id="${sent_stanza.getAttribute('id')}" to="${muc_jid}/${newnick}" xmlns="jabber:client"/>`);
|
||||||
|
}));
|
||||||
|
|
||||||
it("informs users if their nicknames have been changed.",
|
it("informs users if their nicknames have been changed.",
|
||||||
mock.initConverse([], {}, async function (_converse) {
|
mock.initConverse([], {}, async function (_converse) {
|
||||||
@ -44,9 +73,8 @@ fdescribe("A MUC", function () {
|
|||||||
*/
|
*/
|
||||||
const __ = _converse.__;
|
const __ = _converse.__;
|
||||||
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'oldnick');
|
await mock.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'oldnick');
|
||||||
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
|
||||||
expect(view.model.session.get('connection_status')).toBe(converse.ROOMSTATUS.ENTERED);
|
|
||||||
|
|
||||||
|
const view = _converse.chatboxviews.get('lounge@montague.lit');
|
||||||
await u.waitUntil(() => view.querySelectorAll('li .occupant-nick').length, 500);
|
await u.waitUntil(() => view.querySelectorAll('li .occupant-nick').length, 500);
|
||||||
let occupants = view.querySelector('.occupant-list');
|
let occupants = view.querySelector('.occupant-list');
|
||||||
expect(occupants.childElementCount).toBe(1);
|
expect(occupants.childElementCount).toBe(1);
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
muc_domain: 'conference.chat.example.org',
|
muc_domain: 'conference.chat.example.org',
|
||||||
muc_respect_autojoin: true,
|
muc_respect_autojoin: true,
|
||||||
view_mode: 'fullscreen',
|
view_mode: 'fullscreen',
|
||||||
// websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
websocket_url: 'ws://chat.example.org:5380/xmpp-websocket',
|
||||||
websocket_url: 'wss://conversejs.org/xmpp-websocket',
|
// websocket_url: 'wss://conversejs.org/xmpp-websocket',
|
||||||
// bosh_service_url: 'http://chat.example.org:5280/http-bind',
|
// bosh_service_url: 'http://chat.example.org:5280/http-bind',
|
||||||
allow_user_defined_connection_url: true,
|
allow_user_defined_connection_url: true,
|
||||||
muc_show_logs_before_join: true,
|
muc_show_logs_before_join: true,
|
||||||
|
@ -9,7 +9,7 @@ module.exports = merge(common, {
|
|||||||
devtool: "inline-source-map",
|
devtool: "inline-source-map",
|
||||||
devServer: {
|
devServer: {
|
||||||
static: [ path.resolve(__dirname, '../') ],
|
static: [ path.resolve(__dirname, '../') ],
|
||||||
port: 3004
|
port: 3003
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new HTMLWebpackPlugin({
|
new HTMLWebpackPlugin({
|
||||||
|
Loading…
Reference in New Issue
Block a user