diff --git a/src/entry.js b/src/entry.js index 4acd548ad6..814ea7e7fd 100644 --- a/src/entry.js +++ b/src/entry.js @@ -12,9 +12,6 @@ // // Once the rest converse.js has been loaded, window.converse will be replaced // with the full-fledged public API. -/** - * @typedef {module:shared.converse.ConversePrivateGlobal} ConversePrivateGlobal - */ const plugins = {}; @@ -68,9 +65,6 @@ const converse = { } } -/** - * @typedef {Window & {converse: ConversePrivateGlobal} } window - */ window['converse'] = converse; /** diff --git a/src/headless/plugins/chat/parsers.js b/src/headless/plugins/chat/parsers.js index b7b8cdc7a4..0656ba7023 100644 --- a/src/headless/plugins/chat/parsers.js +++ b/src/headless/plugins/chat/parsers.js @@ -109,7 +109,7 @@ export async function parseMessage (stanza) { } /** * The object which {@link parseMessage} returns - * @typedef {Object} module:plugin-chat-parsers.MessageAttributes + * @typedef {Object} MessageAttributes * @property { ('me'|'them') } sender - Whether the message was sent by the current user or someone else * @property { Array } references - A list of objects representing XEP-0372 references * @property { Boolean } editable - Is this message editable via XEP-0308? diff --git a/src/headless/plugins/smacks/tests/smacks.js b/src/headless/plugins/smacks/tests/smacks.js index cd4ac87dbc..0011de163d 100644 --- a/src/headless/plugins/smacks/tests/smacks.js +++ b/src/headless/plugins/smacks/tests/smacks.js @@ -213,6 +213,8 @@ describe("XEP-0198 Stream Management", function () { }, async function (_converse) { + const { api } = _converse; + const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit"; sessionStorage.setItem( key, @@ -251,15 +253,26 @@ describe("XEP-0198 Stream Management", function () { }) ); - _converse.no_connection_on_bind = true; // XXX Don't trigger CONNECTED in MockConnection - await _converse.api.user.login('romeo@montague.lit', 'secret'); + const proto = Object.getPrototypeOf(api.connection.get()) + const _changeConnectStatus = proto._changeConnectStatus; + let count = 0; + spyOn(proto, '_changeConnectStatus').and.callFake((status) => { + if (status === Strophe.Status.CONNECTED && count === 0) { + // Don't trigger CONNECTED + count++; + return; + } + _changeConnectStatus.call(api.connection.get(), status); + }); - const sent_stanzas = _converse.api.connection.get().sent_stanzas; + await api.user.login('romeo@montague.lit', 'secret'); + + const sent_stanzas = api.connection.get().sent_stanzas; const stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop()); expect(Strophe.serialize(stanza)).toEqual(''); const result = u.toStanza(``); - _converse.api.connection.get()._dataRecv(mock.createRequest(result)); + api.connection.get()._dataRecv(mock.createRequest(result)); expect(_converse.session.get('smacks_enabled')).toBe(true); const nick = 'romeo'; @@ -278,9 +291,9 @@ describe("XEP-0198 Stream Management", function () { type: 'groupchat' }).c('body').t('First message').tree(); - _converse.api.connection.get()._dataRecv(mock.createRequest(msg)); + api.connection.get()._dataRecv(mock.createRequest(msg)); - await _converse.api.waitUntil('chatBoxesFetched'); + await api.waitUntil('chatBoxesFetched'); const muc = _converse.chatboxes.get(muc_jid); await mock.getRoomFeatures(_converse, muc_jid); await mock.receiveOwnMUCPresence(_converse, muc_jid, nick); @@ -288,6 +301,5 @@ describe("XEP-0198 Stream Management", function () { await muc.messages.fetched; await u.waitUntil(() => muc.messages.length); expect(muc.messages.at(0).get('message')).toBe('First message') - delete _converse.no_connection_on_bind; })); }); diff --git a/src/headless/shared/_converse.js b/src/headless/shared/_converse.js index 3638741a37..28aa0858ce 100644 --- a/src/headless/shared/_converse.js +++ b/src/headless/shared/_converse.js @@ -79,6 +79,8 @@ class ConversePrivateGlobal extends EventEmitter(Object) { this.strict_plugin_dependencies = false; + this.pluggable = null; + this.templates = {}; this.promises = { diff --git a/src/headless/shared/api/public.js b/src/headless/shared/api/public.js index 037caedb44..54d2bdad17 100644 --- a/src/headless/shared/api/public.js +++ b/src/headless/shared/api/public.js @@ -1,3 +1,6 @@ +/** + * @typedef {module:shared-api-public.ConversePrivateGlobal} ConversePrivateGlobal + */ import ConnectionFeedback from './../connection/feedback.js'; import URI from 'urijs'; import _converse from '../_converse.js'; @@ -25,6 +28,8 @@ import { } from '../../utils/init.js'; /** + * @typedef {Window & {converse: ConversePrivateGlobal} } window + * * ### The Public API * * This namespace contains public API methods which are are @@ -37,7 +42,7 @@ import { * @global * @namespace converse */ -export const converse = Object.assign(window.converse || {}, { +export const converse = Object.assign(/** @type {ConversePrivateGlobal} */(window).converse || {}, { CHAT_STATES, diff --git a/src/headless/shared/api/send.js b/src/headless/shared/api/send.js index aefd51524e..e016eb27f4 100644 --- a/src/headless/shared/api/send.js +++ b/src/headless/shared/api/send.js @@ -1,3 +1,6 @@ +/** + * @typedef {import('strophe.js/src/builder.js').Builder} Strophe.Builder + */ import _converse from '../_converse.js'; import log from '../../log.js'; import { Strophe, toStanza } from 'strophe.js'; @@ -7,8 +10,8 @@ export default { /** * Allows you to send XML stanzas. * @method _converse.api.send - * @param { Element | Stanza } stanza - * @return { void } + * @param {Element|Strophe.Builder} stanza + * @return {void} * @example * const msg = converse.env.$msg({ * 'from': 'juliet@example.com/balcony', @@ -41,12 +44,12 @@ export default { /** * Send an IQ stanza * @method _converse.api.sendIQ - * @param { Element } stanza - * @param { number } [timeout] - The default timeout value is taken from + * @param {Element|Strophe.Builder} stanza + * @param {number} [timeout] - The default timeout value is taken from * the `stanza_timeout` configuration setting. - * @param { Boolean } [reject=true] - Whether an error IQ should cause the promise + * @param {boolean} [reject=true] - Whether an error IQ should cause the promise * to be rejected. If `false`, the promise will resolve instead of being rejected. - * @returns { Promise } A promise which resolves (or potentially rejected) once we + * @returns {Promise} A promise which resolves (or potentially rejected) once we * receive a `result` or `error` stanza or once a timeout is reached. * If the IQ stanza being sent is of type `result` or `error`, there's * nothing to wait for, so an already resolved promise is returned. diff --git a/src/headless/shared/chat/utils.js b/src/headless/shared/chat/utils.js index a79e8ca8d7..1d097ea43b 100644 --- a/src/headless/shared/chat/utils.js +++ b/src/headless/shared/chat/utils.js @@ -1,8 +1,19 @@ +/** + * @module:headless-shared-chat-utils + * @typedef {import('../../plugins/muc/muc.js').default} MUC + * @typedef {import('../../plugins/chat/model.js').default} ChatBox + * @typedef {import('../../plugins/chat/message.js').default} Message + * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLMetadata + * @typedef {module:headless-shared-chat-utils.MediaURLData} MediaURLData + */ import debounce from 'lodash-es/debounce.js'; import api, { converse } from '../../shared/api/index.js'; const { u } = converse.env; +/** + * @param {ChatBox|MUC} model + */ export function pruneHistory (model) { const max_history = api.settings.get('prune_messages_above'); if (max_history && typeof max_history === 'number') { @@ -17,7 +28,7 @@ export function pruneHistory (model) { * once older messages have been removed to keep the * number of messages below the value set in `prune_messages_above`. * @event _converse#historyPruned - * @type { _converse.ChatBox | _converse.ChatRoom } + * @type { ChatBox | MUC } * @example _converse.api.listen.on('historyPruned', this => { ... }); */ api.trigger('historyPruned', model); @@ -31,7 +42,7 @@ export function pruneHistory (model) { * array of {@link MediaURL} objects. * @param { Array } arr * @param { String } text - * @returns{ Array } + * @returns{ Array } */ export function getMediaURLs (arr, text, offset=0) { /** @@ -63,11 +74,11 @@ export function getMediaURLs (arr, text, offset=0) { * Determines whether the given attributes of an incoming message * represent a XEP-0308 correction and, if so, handles it appropriately. * @private - * @method _converse.ChatBox#handleCorrection - * @param { _converse.ChatBox | _converse.ChatRoom } - * @param { object } attrs - Attributes representing a received + * @method ChatBox#handleCorrection + * @param {ChatBox|MUC} model + * @param {object} attrs - Attributes representing a received * message, as returned by {@link parseMessage} - * @returns { _converse.Message|undefined } Returns the corrected + * @returns {Promise} Returns the corrected * message or `undefined` if not applicable. */ export async function handleCorrection (model, attrs) { diff --git a/src/headless/shared/connection/api.js b/src/headless/shared/connection/api.js index 04126adb44..0fb88ebda1 100644 --- a/src/headless/shared/connection/api.js +++ b/src/headless/shared/connection/api.js @@ -23,7 +23,7 @@ export default { * @method api.connection.init * @memberOf api.connection * @param {string} [jid] - * @return {Connection | MockConnection} + * @return {Connection|MockConnection} */ init (jid) { if (jid && connection?.jid && isSameDomain(connection.jid, jid)) return connection; diff --git a/src/headless/shared/connection/feedback.js b/src/headless/shared/connection/feedback.js index e60543c870..250dd599fd 100644 --- a/src/headless/shared/connection/feedback.js +++ b/src/headless/shared/connection/feedback.js @@ -15,7 +15,7 @@ class Feedback extends Model { initialize () { super.initialize(); const { api } = _converse; - this.on('change', () => api.trigger('connfeedback', _converse.connfeedback)); + this.on('change', () => api.trigger('connfeedback', _converse.state.connfeedback)); } } diff --git a/src/headless/shared/connection/index.js b/src/headless/shared/connection/index.js index a6590290d8..6945b7061d 100644 --- a/src/headless/shared/connection/index.js +++ b/src/headless/shared/connection/index.js @@ -158,7 +158,7 @@ export class Connection extends Strophe.Connection { this.reconnecting = true; await tearDown(); - const conn_status = _converse.connfeedback.get('connection_status'); + const conn_status = _converse.state.connfeedback.get('connection_status'); if (conn_status === Strophe.Status.CONNFAIL) { this.switchTransport(); } else if (conn_status === Strophe.Status.AUTHFAIL && api.settings.get("authentication") === ANONYMOUS) { @@ -246,7 +246,7 @@ export class Connection extends Strophe.Connection { setConnectionStatus (status, message) { this.status = status; - _converse.connfeedback.set({'connection_status': status, message }); + _converse.state.connfeedback.set({'connection_status': status, message }); } async finishDisconnection () { @@ -393,7 +393,7 @@ export class Connection extends Strophe.Connection { hasResumed () { if (api.settings.get("connection_options")?.worker || this.isType('bosh')) { - return _converse.connfeedback.get('connection_status') === Strophe.Status.ATTACHED; + return _converse.state.connfeedback.get('connection_status') === Strophe.Status.ATTACHED; } else { // Not binding means that the session was resumed. return !this.do_bind; @@ -468,8 +468,6 @@ export class MockConnection extends Connection { async bind () { await api.trigger('beforeResourceBinding', {'synchronous': true}); this.authenticated = true; - if (!_converse.no_connection_on_bind) { - this._changeConnectStatus(Strophe.Status.CONNECTED); - } + this._changeConnectStatus(Strophe.Status.CONNECTED); } } diff --git a/src/headless/shared/i18n.js b/src/headless/shared/i18n.js index dbe327ff2c..e944459aa3 100644 --- a/src/headless/shared/i18n.js +++ b/src/headless/shared/i18n.js @@ -4,6 +4,7 @@ import { sprintf } from 'sprintf-js'; * @namespace i18n */ export default { + // eslint-disable-next-line @typescript-eslint/no-empty-function initialize () {}, /** @@ -18,7 +19,6 @@ export default { * @method __ * @private * @memberOf i18n - * @param { String } str */ __ (...args) { return sprintf(...args); diff --git a/src/headless/shared/parsers.js b/src/headless/shared/parsers.js index 61f41650cf..caa352746f 100644 --- a/src/headless/shared/parsers.js +++ b/src/headless/shared/parsers.js @@ -1,3 +1,7 @@ +/** + * @module:headless-shared-parsers + * @typedef {module:headless-shared-parsers.MediaURLMetadata} MediaURLMetadata + */ import URI from 'urijs'; import _converse from './_converse.js'; import api from './api/index.js'; diff --git a/src/plugins/controlbox/controlbox.js b/src/plugins/controlbox/controlbox.js index c1e4bca05e..662c3aa2e2 100644 --- a/src/plugins/controlbox/controlbox.js +++ b/src/plugins/controlbox/controlbox.js @@ -34,8 +34,8 @@ class ControlBox extends CustomElement { } setModel () { - this.model = _converse.chatboxes.get('controlbox'); - this.listenTo(_converse.connfeedback, 'change:connection_status', () => this.requestUpdate()); + this.model = _converse.state.chatboxes.get('controlbox'); + this.listenTo(_converse.state.connfeedback, 'change:connection_status', () => this.requestUpdate()); this.listenTo(this.model, 'change:active-form', () => this.requestUpdate()); this.listenTo(this.model, 'change:connected', () => this.requestUpdate()); this.listenTo(this.model, 'change:closed', () => !this.model.get('closed') && this.afterShown()); diff --git a/src/plugins/controlbox/loginform.js b/src/plugins/controlbox/loginform.js index f405c3f783..2913d3e92f 100644 --- a/src/plugins/controlbox/loginform.js +++ b/src/plugins/controlbox/loginform.js @@ -5,13 +5,13 @@ import { CustomElement } from 'shared/components/element.js'; import { _converse, api, converse } from '@converse/headless'; import { updateSettingsWithFormData, validateJID } from './utils.js'; -const { Strophe, u } = converse.env; +const { Strophe } = converse.env; class LoginForm extends CustomElement { initialize () { - this.listenTo(_converse.connfeedback, 'change', () => this.requestUpdate()); + this.listenTo(_converse.state.connfeedback, 'change', () => this.requestUpdate()); this.handler = () => this.requestUpdate() } diff --git a/src/plugins/controlbox/templates/controlbox.js b/src/plugins/controlbox/templates/controlbox.js index e9ed52159e..18e925e3fa 100644 --- a/src/plugins/controlbox/templates/controlbox.js +++ b/src/plugins/controlbox/templates/controlbox.js @@ -6,7 +6,7 @@ const { Strophe } = converse.env; function whenNotConnected (o) { - const connection_status = _converse.connfeedback.get('connection_status'); + const connection_status = _converse.state.connfeedback.get('connection_status'); if ([Strophe.Status.RECONNECTING, Strophe.Status.CONNECTING].includes(connection_status)) { return tplSpinner(); } diff --git a/src/plugins/controlbox/templates/loginform.js b/src/plugins/controlbox/templates/loginform.js index b91f57a45e..bd1d5f2db2 100644 --- a/src/plugins/controlbox/templates/loginform.js +++ b/src/plugins/controlbox/templates/loginform.js @@ -143,13 +143,14 @@ const form_fields = (el) => { }; export default (el) => { - const connection_status = _converse.connfeedback.get('connection_status'); + const { connfeedback } = _converse.state; + const connection_status = connfeedback.get('connection_status'); let feedback_class, pretty_status; if (REPORTABLE_STATUSES.includes(connection_status)) { pretty_status = PRETTY_CONNECTION_STATUS[connection_status]; feedback_class = CONNECTION_STATUS_CSS_CLASS[connection_status]; } - const conn_feedback_message = _converse.connfeedback.get('message'); + const conn_feedback_message = connfeedback.get('message'); return html`