diff --git a/CHANGES.md b/CHANGES.md
index 44063fdf4..c312cc145 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,7 +7,9 @@
- Fix `autojoin` checkbox state in MUC bookmark form
- Remove call to `api.confirm` in `@converse/headless`
- Generate TypeScript declaration files into `dist/types`
+- Removed documentation about the no longer implemented `fullname` option.
- #3156: Add function to prevent drag stutter effect over iframes when resize is called in overlay mode
+- #3165: Use configured nickname in profile view in the control box
- New config option [stanza_timeout](https://conversejs.org/docs/html/configuration.html#stanza-timeout)
diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst
index 29f20988b..1f4b6047d 100644
--- a/docs/source/configuration.rst
+++ b/docs/source/configuration.rst
@@ -925,12 +925,6 @@ filter_url_query_params
Accepts a string or array of strings. Any query strings from URLs that match this setting will be removed.
-fullname
---------
-
-If you are using prebinding, can specify the fullname of the currently
-logged in user, otherwise the user's vCard will be fetched.
-
geouri_regex
------------
diff --git a/karma.conf.js b/karma.conf.js
index 90fa14b6c..2a6268a3c 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -104,6 +104,8 @@ module.exports = function(config) {
{ pattern: "src/plugins/omemo/tests/muc.js", type: 'module' },
{ pattern: "src/plugins/omemo/tests/omemo.js", type: 'module' },
{ pattern: "src/plugins/profile/tests/password-reset.js", type: 'module' },
+ { pattern: "src/plugins/profile/tests/profile.js", type: 'module' },
+ { pattern: "src/plugins/profile/tests/status.js", type: 'module' },
{ pattern: "src/plugins/push/tests/push.js", type: 'module' },
{ pattern: "src/plugins/register/tests/register.js", type: 'module' },
{ pattern: "src/plugins/roomslist/tests/roomslist.js", type: 'module' },
diff --git a/src/headless/plugins/status/status.js b/src/headless/plugins/status/status.js
index d01927862..2428d5cb2 100644
--- a/src/headless/plugins/status/status.js
+++ b/src/headless/plugins/status/status.js
@@ -5,11 +5,11 @@ import { _converse, api, converse } from '@converse/headless/core';
const { Strophe, $pres } = converse.env;
-const XMPPStatus = Model.extend({
+export default class XMPPStatus extends Model {
- defaults () {
+ defaults () { // eslint-disable-line class-methods-use-this
return { "status": api.settings.get("default_state") }
- },
+ }
initialize () {
this.on('change', item => {
@@ -20,16 +20,19 @@ const XMPPStatus = Model.extend({
api.user.presence.send(this.get('status'), null, this.get('status_message'));
}
});
- },
+ }
- getNickname () {
+ getDisplayName () {
+ return this.getFullname() || this.getNickname() || _converse.bare_jid;
+ }
+
+ getNickname () { // eslint-disable-line class-methods-use-this
return api.settings.get('nickname');
- },
+ }
- getFullname () {
- // Gets overridden in converse-vcard
- return '';
- },
+ getFullname () { // eslint-disable-line class-methods-use-this
+ return ''; // Gets overridden in converse-vcard
+ }
/** Constructs a presence stanza
* @param { string } [type]
@@ -85,6 +88,4 @@ const XMPPStatus = Model.extend({
presence = await api.hook('constructedPresence', null, presence);
return presence;
}
-});
-
-export default XMPPStatus;
+}
diff --git a/src/plugins/controlbox/tests/controlbox.js b/src/plugins/controlbox/tests/controlbox.js
index ebe70cb31..01100c0de 100644
--- a/src/plugins/controlbox/tests/controlbox.js
+++ b/src/plugins/controlbox/tests/controlbox.js
@@ -2,7 +2,6 @@
const $msg = converse.env.$msg;
const u = converse.env.utils;
-const Strophe = converse.env.Strophe;
describe("The Controlbox", function () {
@@ -105,67 +104,4 @@ describe("The Controlbox", function () {
await u.waitUntil(() => rosterview.querySelector('.msgs-indicator') === null);
}));
});
-
- describe("The Status Widget", function () {
-
- it("shows the user's chat status, which is online by default",
- mock.initConverse([], {}, async function (_converse) {
- mock.openControlBox(_converse);
- const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
- expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
- expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
- }));
-
- it("can be used to set the current user's chat status",
- mock.initConverse([], {}, async function (_converse) {
-
- await mock.openControlBox(_converse);
- const cbview = _converse.chatboxviews.get('controlbox');
- cbview.querySelector('.change-status').click()
- const modal = _converse.api.modal.get('converse-chat-status-modal');
- await u.waitUntil(() => u.isVisible(modal), 1000);
- modal.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
- modal.querySelector('[type="submit"]').click();
- const sent_stanzas = _converse.connection.sent_stanzas;
- const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
- expect(Strophe.serialize(sent_presence)).toBe(
- ``+
- `dnd`+
- `0`+
- ``+
- ``);
- const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
- const first_child = view.querySelector('.xmpp-status span:first-child');
- expect(u.hasClass('online', first_child)).toBe(false);
- expect(u.hasClass('dnd', first_child)).toBe(true);
- expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
- }));
-
- it("can be used to set a custom status message",
- mock.initConverse([], {}, async function (_converse) {
-
- await mock.openControlBox(_converse);
- const cbview = _converse.chatboxviews.get('controlbox');
- cbview.querySelector('.change-status').click()
- const modal = _converse.api.modal.get('converse-chat-status-modal');
-
- await u.waitUntil(() => u.isVisible(modal), 1000);
- const msg = 'I am happy';
- modal.querySelector('input[name="status_message"]').value = msg;
- modal.querySelector('[type="submit"]').click();
- const sent_stanzas = _converse.connection.sent_stanzas;
- const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
- expect(Strophe.serialize(sent_presence)).toBe(
- ``+
- `I am happy`+
- `0`+
- ``+
- ``);
-
- const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
- const first_child = view.querySelector('.xmpp-status span:first-child');
- expect(u.hasClass('online', first_child)).toBe(true);
- expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
- }));
- });
});
diff --git a/src/plugins/profile/templates/profile.js b/src/plugins/profile/templates/profile.js
index 18a5e2d4b..a0ab723d3 100644
--- a/src/plugins/profile/templates/profile.js
+++ b/src/plugins/profile/templates/profile.js
@@ -1,6 +1,6 @@
import 'shared/avatar/avatar.js';
import { __ } from 'i18n';
-import { _converse, api } from "@converse/headless/core";
+import { api } from "@converse/headless/core";
import { getPrettyStatus, logOut } from '../utils.js';
import { html } from "lit";
@@ -21,7 +21,6 @@ function tplUserSettingsButton (o) {
export default (el) => {
const chat_status = el.model.get('status') || 'offline';
- const fullname = el.model.vcard?.get('fullname') || el.model.vcard?.get('nickname') || _converse.bare_jid;
const status_message = el.model.get('status_message') || __("I am %1$s", getPrettyStatus(chat_status));
const i18n_change_status = __('Click to change your chat status');
const show_settings_button = api.settings.get('show_client_info') || api.settings.get('allow_adhoc_commands');
@@ -44,7 +43,7 @@ export default (el) => {
nonce=${el.model.vcard?.get('vcard_updated')}
height="40" width="40">
- ${fullname}
+ ${el.model.getDisplayName()}
${show_settings_button ? tplUserSettingsButton(el) : ''}
${api.settings.get('allow_logout') ? tplSignout() : ''}
diff --git a/src/plugins/profile/tests/profile.js b/src/plugins/profile/tests/profile.js
new file mode 100644
index 000000000..38e2a789d
--- /dev/null
+++ b/src/plugins/profile/tests/profile.js
@@ -0,0 +1,17 @@
+/*global mock, converse */
+
+const u = converse.env.utils;
+
+describe("The Controlbox", function () {
+ describe("The user profile", function () {
+
+ it("shows the user's configured nickname",
+ mock.initConverse([], { blacklisted_plugins: ['converse-vcard'], nickname: 'nicky'},
+ async function (_converse) {
+
+ mock.openControlBox(_converse);
+ const el = await u.waitUntil(() => document.querySelector('converse-user-profile .username'));
+ expect(el.textContent).toBe('nicky');
+ }));
+ });
+});
diff --git a/src/plugins/profile/tests/status.js b/src/plugins/profile/tests/status.js
new file mode 100644
index 000000000..18a206962
--- /dev/null
+++ b/src/plugins/profile/tests/status.js
@@ -0,0 +1,69 @@
+/*global mock, converse */
+
+const u = converse.env.utils;
+const Strophe = converse.env.Strophe;
+
+describe("The Controlbox", function () {
+ describe("The Status Widget", function () {
+
+ it("shows the user's chat status, which is online by default",
+ mock.initConverse([], {}, async function (_converse) {
+ mock.openControlBox(_converse);
+ const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
+ expect(u.hasClass('online', view.querySelector('.xmpp-status span:first-child'))).toBe(true);
+ expect(view.querySelector('.xmpp-status span.online').textContent.trim()).toBe('I am online');
+ }));
+
+ it("can be used to set the current user's chat status",
+ mock.initConverse([], {}, async function (_converse) {
+
+ await mock.openControlBox(_converse);
+ const cbview = _converse.chatboxviews.get('controlbox');
+ cbview.querySelector('.change-status').click()
+ const modal = _converse.api.modal.get('converse-chat-status-modal');
+ await u.waitUntil(() => u.isVisible(modal), 1000);
+ modal.querySelector('label[for="radio-busy"]').click(); // Change status to "dnd"
+ modal.querySelector('[type="submit"]').click();
+ const sent_stanzas = _converse.connection.sent_stanzas;
+ const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
+ expect(Strophe.serialize(sent_presence)).toBe(
+ ``+
+ `dnd`+
+ `0`+
+ ``+
+ ``);
+ const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
+ const first_child = view.querySelector('.xmpp-status span:first-child');
+ expect(u.hasClass('online', first_child)).toBe(false);
+ expect(u.hasClass('dnd', first_child)).toBe(true);
+ expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe('I am busy');
+ }));
+
+ it("can be used to set a custom status message",
+ mock.initConverse([], {}, async function (_converse) {
+
+ await mock.openControlBox(_converse);
+ const cbview = _converse.chatboxviews.get('controlbox');
+ cbview.querySelector('.change-status').click()
+ const modal = _converse.api.modal.get('converse-chat-status-modal');
+
+ await u.waitUntil(() => u.isVisible(modal), 1000);
+ const msg = 'I am happy';
+ modal.querySelector('input[name="status_message"]').value = msg;
+ modal.querySelector('[type="submit"]').click();
+ const sent_stanzas = _converse.connection.sent_stanzas;
+ const sent_presence = await u.waitUntil(() => sent_stanzas.filter(s => Strophe.serialize(s).match('presence')).pop());
+ expect(Strophe.serialize(sent_presence)).toBe(
+ ``+
+ `I am happy`+
+ `0`+
+ ``+
+ ``);
+
+ const view = await u.waitUntil(() => document.querySelector('converse-user-profile'));
+ const first_child = view.querySelector('.xmpp-status span:first-child');
+ expect(u.hasClass('online', first_child)).toBe(true);
+ expect(view.querySelector('.xmpp-status span:first-child').textContent.trim()).toBe(msg);
+ }));
+ });
+});
diff --git a/src/shared/tests/mock.js b/src/shared/tests/mock.js
index 2fa74c4ae..af781369f 100644
--- a/src/shared/tests/mock.js
+++ b/src/shared/tests/mock.js
@@ -643,31 +643,8 @@ function clearStores () {
window.sessionStorage.removeItem(cache_key+'fetched');
}
-const theme = ['dracula', 'classic', 'concord'][Math.floor(Math.random()*3)];
-
-async function _initConverse (settings) {
- clearStores();
- await clearIndexedDB();
-
- _converse = await converse.initialize(Object.assign({
- 'animate': false,
- 'auto_subscribe': false,
- 'bosh_service_url': 'montague.lit/http-bind',
- 'discover_connection_methods': false,
- 'enable_smacks': false,
- 'i18n': 'en',
- 'loglevel': 'debug',
- 'no_trimming': true,
- 'persistent_store': 'localStorage',
- 'play_sounds': false,
- 'theme': theme,
- 'use_emojione': false,
- 'view_mode': view_mode
- }, settings || {}));
-
- window._converse = _converse;
-
- _converse.api.vcard.get = function (model, force) {
+function getMockVcardFetcher (settings) {
+ return (model, force) => {
let jid;
if (typeof model === 'string' || model instanceof String) {
jid = model;
@@ -702,7 +679,37 @@ async function _initConverse (settings) {
'vcard_updated': dayjs().format(),
'vcard_error': undefined
};
- };
+ }
+}
+
+const theme = ['dracula', 'classic', 'concord'][Math.floor(Math.random()*3)];
+
+async function _initConverse (settings) {
+ clearStores();
+ await clearIndexedDB();
+
+ _converse = await converse.initialize(Object.assign({
+ 'animate': false,
+ 'auto_subscribe': false,
+ 'bosh_service_url': 'montague.lit/http-bind',
+ 'discover_connection_methods': false,
+ 'enable_smacks': false,
+ 'i18n': 'en',
+ 'loglevel': 'debug',
+ 'no_trimming': true,
+ 'persistent_store': 'localStorage',
+ 'play_sounds': false,
+ 'theme': theme,
+ 'use_emojione': false,
+ 'view_mode': view_mode
+ }, settings || {}));
+
+ window._converse = _converse;
+
+ if (_converse.api.vcard) {
+ _converse.api.vcard.get = getMockVcardFetcher(settings);
+ }
+
if (settings?.auto_login !== false) {
_converse.api.user.login('romeo@montague.lit/orchard', 'secret');
await _converse.api.waitUntil('afterResourceBinding');