Convert older docstrings to JSDoc syntax
This commit is contained in:
parent
7ed99092f5
commit
a45bd8d14b
2
Makefile
2
Makefile
@ -261,4 +261,4 @@ html: dev docsdev apidoc
|
||||
|
||||
PHONY: apidoc
|
||||
apidoc:
|
||||
$(JSDOC) --readme docs/source/jsdoc_intro.md -c docs/source/conf.json -d docs/html/api src/*.js src/utils/*.js src/headless/*.js src/headless/utils/*.js
|
||||
$(JSDOC) --private --readme docs/source/jsdoc_intro.md -c docs/source/conf.json -d docs/html/api src/*.js src/utils/*.js src/headless/*.js src/headless/utils/*.js
|
||||
|
1339
dist/converse.js
vendored
1339
dist/converse.js
vendored
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,5 @@ to fix a bug or to add new functionality.
|
||||
plugin_development
|
||||
api/index
|
||||
testing
|
||||
events
|
||||
other_frameworks
|
||||
builds
|
||||
|
@ -3,29 +3,31 @@
|
||||
Welcome to the new Converse API documentation, generated with
|
||||
[JSDoc](http://usejsdoc.org/).
|
||||
|
||||
The old (increasingly out of date and incomplete) API documentation is
|
||||
currently still [available here](/docs/html/developer_api.html).
|
||||
This documentation replaces the (increasingly out of date and incomplete) [old API documentation](/docs/html/developer_api.html)
|
||||
and [old "Events and Promises" documentation](/docs/html/events.html).
|
||||
|
||||
## The public and private API
|
||||
|
||||
Converse has a public API and a private API.
|
||||
r
|
||||
Converse has a public API and a private API only available to plugins.
|
||||
|
||||
The reason we make this distinction between public and private is so that API
|
||||
methods which might can be used to "impersonate" the user, for example by
|
||||
methods which could be used to "impersonate" the user, for example by
|
||||
sending messages on their behalf, are not available to random scripts running
|
||||
in the websites.
|
||||
in your website.
|
||||
|
||||
The public API is accessible via the `window.converse` global and is therefore
|
||||
available to all JavaScript running in the page.
|
||||
The public API is accessible via the [window.converse](/docs/html/api/converse.html)
|
||||
global and is therefore available to any JavaScript running in the page.
|
||||
|
||||
Tehe private API is only accessible to plugins, which have been whitelisted and
|
||||
registered before `converse.initialize` (which is a public API method) has been
|
||||
called. See the [plugin development](https://conversejs.org/docs/html/plugin_development.html)
|
||||
The private API is only accessible to plugins, which have been whitelisted and
|
||||
registered before [converse.initialize](/docs/html/api/converse.html#.initialize)
|
||||
(which is a public API method) has been called.
|
||||
|
||||
See the [plugin development](/docs/html/plugin_development.html)
|
||||
section for more info on writing plugins.
|
||||
|
||||
Inside a plugin, you can get access to the `_converse.api` object. Note the
|
||||
underscore in front of `_converse`, which indicates that this is a private,
|
||||
closured object.
|
||||
Inside a plugin, you can get access to the {@link _converse.api}
|
||||
object. Note the underscore in front of {@link _converse},
|
||||
which indicates that this is a private, closured object.
|
||||
|
||||
## API Namespaces
|
||||
|
||||
@ -35,9 +37,26 @@ group relevant methods.
|
||||
So, for example, all the XEP-0030 service discovery methods are under the
|
||||
{@link \_converse.api.disco} namespace, in the [private API]{@link \_converse.api}.
|
||||
|
||||
Which means that you access it via `_converse.api.disco`.
|
||||
Which means that you access it via {@link _converse.api.disco}.
|
||||
|
||||
Namespaces can be nested. So the {@link \_converse.api.disco} namespace
|
||||
namespace has {@link \_converse.api.disco.own} as a nested namespace.
|
||||
### Nested Namespaces
|
||||
|
||||
Namespaces can be nested.
|
||||
|
||||
{@link _converse.api} is the top-level namespace, of which {@link \_converse.api.disco}
|
||||
is a nested, child namespace and {@link \_converse.api.disco.own} is nested another
|
||||
level deeper.
|
||||
|
||||
Not all methods are however within a namespace. For example {@link converse.initialize}.
|
||||
|
||||
## Stable API versus unstable API
|
||||
|
||||
Converse uses [semantic versioning](https://semver.org/) for releases, which means that
|
||||
we try to maintain a stable API for minor and patch releases and when we do change the
|
||||
stable API we will make a major release.
|
||||
|
||||
In the JSDoc API documentation, all API methods that are **not** marked as *Private*
|
||||
are considered to be part of the stable API, and you can therefore expect them to
|
||||
not change between minor and patch releases. If a method is marked as *Private*,
|
||||
then you could still use it, but we don't provide any guarantee that it won't change
|
||||
between minor and patch releases.
|
||||
|
@ -586,18 +586,18 @@ converse.plugins.add('converse-chatview', {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts an indicator into the chat area, showing the
|
||||
* day as given by the passed in date.
|
||||
* The indicator is only inserted if necessary.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#insertDayIndicator
|
||||
* @param { HTMLElement } next_msg_el - The message element before
|
||||
* which the day indicator element must be inserted.
|
||||
* This element must have a "data-isodate" attribute
|
||||
* which specifies its creation date.
|
||||
*/
|
||||
insertDayIndicator (next_msg_el) {
|
||||
/* Inserts an indicator into the chat area, showing the
|
||||
* day as given by the passed in date.
|
||||
*
|
||||
* The indicator is only inserted if necessary.
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) next_msg_el - The message element before
|
||||
* which the day indicator element must be inserted.
|
||||
* This element must have a "data-isodate" attribute
|
||||
* which specifies its creation date.
|
||||
*/
|
||||
const prev_msg_el = u.getPreviousElement(next_msg_el, ".message:not(.chat-state-notification)"),
|
||||
prev_msg_date = _.isNull(prev_msg_el) ? null : prev_msg_el.getAttribute('data-isodate'),
|
||||
next_msg_date = next_msg_el.getAttribute('data-isodate');
|
||||
@ -616,13 +616,14 @@ converse.plugins.add('converse-chatview', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the ISO8601 format date of the latest message.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#getLastMessageDate
|
||||
* @param { object } cutoff - Moment Date cutoff date. The last
|
||||
* message received cutoff this date will be returned.
|
||||
*/
|
||||
getLastMessageDate (cutoff) {
|
||||
/* Return the ISO8601 format date of the latest message.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) cutoff: Moment Date cutoff date. The last
|
||||
* message received cutoff this date will be returned.
|
||||
*/
|
||||
const first_msg = u.getFirstChildElement(this.content, '.message:not(.chat-state-notification)'),
|
||||
oldest_date = first_msg ? first_msg.getAttribute('data-isodate') : null;
|
||||
if (!_.isNull(oldest_date) && moment(oldest_date).isAfter(cutoff)) {
|
||||
@ -713,13 +714,14 @@ converse.plugins.add('converse-chatview', {
|
||||
return !u.isVisible(this.el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a view representing a message, insert it into the
|
||||
* content area of the chat box.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#insertMessage
|
||||
* @param { Backbone.View } message - The message Backbone.View
|
||||
*/
|
||||
insertMessage (view) {
|
||||
/* Given a view representing a message, insert it into the
|
||||
* content area of the chat box.
|
||||
*
|
||||
* Parameters:
|
||||
* (Backbone.View) message: The message Backbone.View
|
||||
*/
|
||||
if (view.model.get('type') === 'error') {
|
||||
const previous_msg_el = this.content.querySelector(`[data-msgid="${view.model.get('msgid')}"]`);
|
||||
if (previous_msg_el) {
|
||||
@ -746,20 +748,22 @@ converse.plugins.add('converse-chatview', {
|
||||
return this.trigger('messageInserted', view.el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a message element, determine wether it should be
|
||||
* marked as a followup message to the previous element.
|
||||
*
|
||||
* Also determine whether the element following it is a
|
||||
* followup message or not.
|
||||
*
|
||||
* Followup messages are subsequent ones written by the same
|
||||
* author with no other conversation elements inbetween and
|
||||
* posted within 10 minutes of one another.
|
||||
*
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#markFollowups
|
||||
* @param { HTMLElement } el - The message element
|
||||
*/
|
||||
markFollowups (el) {
|
||||
/* Given a message element, determine wether it should be
|
||||
* marked as a followup message to the previous element.
|
||||
*
|
||||
* Also determine whether the element following it is a
|
||||
* followup message or not.
|
||||
*
|
||||
* Followup messages are subsequent ones written by the same
|
||||
* author with no other conversation elements inbetween and
|
||||
* posted within 10 minutes of one another.
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) el - The message element.
|
||||
*/
|
||||
const from = el.getAttribute('data-from'),
|
||||
previous_el = el.previousElementSibling,
|
||||
date = moment(el.getAttribute('data-isodate')),
|
||||
@ -783,15 +787,14 @@ converse.plugins.add('converse-chatview', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a chat message into the content area of the chat box.
|
||||
* Will also insert a new day indicator if the message is on a different day.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#showMessage
|
||||
* @param { _converse.Message } message - The message object
|
||||
*/
|
||||
async showMessage (message) {
|
||||
/* Inserts a chat message into the content area of the chat box.
|
||||
*
|
||||
* Will also insert a new day indicator if the message is on a
|
||||
* different day.
|
||||
*
|
||||
* Parameters:
|
||||
* (Backbone.Model) message: The message object
|
||||
*/
|
||||
if (!u.isNewMessage(message) && u.isEmptyMessage(message)) {
|
||||
// Handle archived or delayed messages without any message
|
||||
// text to show.
|
||||
@ -822,12 +825,13 @@ converse.plugins.add('converse-chatview', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler that gets called when a new message object is created.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#onMessageAdded
|
||||
* @param { object } message - The message Backbone object that was added.
|
||||
*/
|
||||
onMessageAdded (message) {
|
||||
/* Handler that gets called when a new message object is created.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) message - The message Backbone object that was added.
|
||||
*/
|
||||
this.showMessage(message);
|
||||
if (message.get('correcting')) {
|
||||
this.insertIntoTextArea(message.get('message'), true, true);
|
||||
@ -865,17 +869,18 @@ converse.plugins.add('converse-chatview', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Mutator for setting the chat state of this chat session.
|
||||
* Handles clearing of any chat state notification timeouts and
|
||||
* setting new ones if necessary.
|
||||
* Timeouts are set when the state being set is COMPOSING or PAUSED.
|
||||
* After the timeout, COMPOSING will become PAUSED and PAUSED will become INACTIVE.
|
||||
* See XEP-0085 Chat State Notifications.
|
||||
* @private
|
||||
* @method _converse.ChatBoxView#setChatState
|
||||
* @param { string } state - The chat state (consts ACTIVE, COMPOSING, PAUSED, INACTIVE, GONE)
|
||||
*/
|
||||
setChatState (state, options) {
|
||||
/* Mutator for setting the chat state of this chat session.
|
||||
* Handles clearing of any chat state notification timeouts and
|
||||
* setting new ones if necessary.
|
||||
* Timeouts are set when the state being set is COMPOSING or PAUSED.
|
||||
* After the timeout, COMPOSING will become PAUSED and PAUSED will become INACTIVE.
|
||||
* See XEP-0085 Chat State Notifications.
|
||||
*
|
||||
* Parameters:
|
||||
* (string) state - The chat state (consts ACTIVE, COMPOSING, PAUSED, INACTIVE, GONE)
|
||||
*/
|
||||
if (!_.isUndefined(this.chat_state_timeout)) {
|
||||
window.clearTimeout(this.chat_state_timeout);
|
||||
delete this.chat_state_timeout;
|
||||
|
@ -378,11 +378,6 @@ converse.plugins.add('converse-controlbox', {
|
||||
},
|
||||
|
||||
showHelpMessages () {
|
||||
/* Override showHelpMessages in ChatBoxView, for now do nothing.
|
||||
*
|
||||
* Parameters:
|
||||
* (Array) msgs: Array of messages
|
||||
*/
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
@ -203,15 +203,12 @@ converse.plugins.add('converse-muc-views', {
|
||||
};
|
||||
|
||||
|
||||
/* Insert groupchat info (based on returned #disco IQ stanza)
|
||||
* @function insertRoomInfo
|
||||
* @param { HTMLElement } el - The HTML DOM element that contains the info.
|
||||
* @param { XMLElement } stanza - The IQ stanza containing the groupchat info.
|
||||
*/
|
||||
function insertRoomInfo (el, stanza) {
|
||||
/* Insert groupchat info (based on returned #disco IQ stanza)
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) el: The HTML DOM element that should
|
||||
* contain the info.
|
||||
* (XMLElement) stanza: The IQ stanza containing the groupchat
|
||||
* info.
|
||||
*/
|
||||
// All MUC features found here: https://xmpp.org/registrar/disco-features.html
|
||||
el.querySelector('span.spinner').remove();
|
||||
el.querySelector('a.room-info').classList.add('selected');
|
||||
@ -1110,12 +1107,13 @@ converse.plugins.add('converse-muc-views', {
|
||||
this.model.addHandler('message', 'ChatRoomView.showStatusMessages', this.showStatusMessages.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles all MUC presence stanzas.
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#onPresence
|
||||
* @param { XMLElement } pres - The stanza
|
||||
*/
|
||||
onPresence (pres) {
|
||||
/* Handles all MUC presence stanzas.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) pres: The stanza
|
||||
*/
|
||||
// XXX: Current thinking is that excessive stanza
|
||||
// processing inside a view is a "code smell".
|
||||
// Instead stanza processing should happen inside the
|
||||
@ -1138,14 +1136,14 @@ converse.plugins.add('converse-muc-views', {
|
||||
this.fetchMessages();
|
||||
},
|
||||
|
||||
/**
|
||||
* Join the groupchat.
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#join
|
||||
* @param { String } nick - The user's nickname
|
||||
* @param { String } password - Optional password, if required by the groupchat
|
||||
*/
|
||||
join (nick, password) {
|
||||
/* Join the groupchat.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) nick: The user's nickname
|
||||
* (String) password: Optional password, if required by
|
||||
* the groupchat.
|
||||
*/
|
||||
if (!nick && !this.model.get('nick')) {
|
||||
this.checkForReservedNick();
|
||||
return this;
|
||||
@ -1154,17 +1152,16 @@ converse.plugins.add('converse-muc-views', {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders a form given an IQ stanza containing the current
|
||||
* groupchat configuration.
|
||||
* Returns a promise which resolves once the user has
|
||||
* either submitted the form, or canceled it.
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#renderConfigurationForm
|
||||
* @param { XMLElement } stanza: The IQ stanza containing the groupchat config.
|
||||
*/
|
||||
renderConfigurationForm (stanza) {
|
||||
/* Renders a form given an IQ stanza containing the current
|
||||
* groupchat configuration.
|
||||
*
|
||||
* Returns a promise which resolves once the user has
|
||||
* either submitted the form, or canceled it.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza: The IQ stanza containing the groupchat
|
||||
* config.
|
||||
*/
|
||||
const container_el = this.el.querySelector('.chatroom-body');
|
||||
_.each(container_el.querySelectorAll('.chatroom-form-container'), u.removeElement);
|
||||
_.each(container_el.children, u.hideElement);
|
||||
@ -1420,13 +1417,14 @@ converse.plugins.add('converse-muc-views', {
|
||||
u.showElement(container);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#getMessageFromStatus
|
||||
* @param { XMLElement } stat: A <status> element
|
||||
* @param { Boolean } is_self: Whether the element refers to the current user
|
||||
* @param { XMLElement } stanza: The original stanza received
|
||||
*/
|
||||
getMessageFromStatus (stat, stanza, is_self) {
|
||||
/* Parameters:
|
||||
* (XMLElement) stat: A <status> element.
|
||||
* (Boolean) is_self: Whether the element refers to the
|
||||
* current user.
|
||||
* (XMLElement) stanza: The original stanza received.
|
||||
*/
|
||||
const code = stat.getAttribute('code');
|
||||
if (code === '110' || (code === '100' && !is_self)) { return; }
|
||||
if (code in _converse.muc.info_messages) {
|
||||
@ -1697,14 +1695,14 @@ converse.plugins.add('converse-muc-views', {
|
||||
this.scrollDown();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check for status codes and communicate their purpose to the user.
|
||||
* See: https://xmpp.org/registrar/mucstatus.html
|
||||
* @private
|
||||
* @method _converse.ChatRoomView#showStatusMessages
|
||||
* @param { XMLElement } stanza - The message or presence stanza containing the status codes
|
||||
*/
|
||||
showStatusMessages (stanza) {
|
||||
/* Check for status codes and communicate their purpose to the user.
|
||||
* See: https://xmpp.org/registrar/mucstatus.html
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza: The message or presence stanza
|
||||
* containing the status codes.
|
||||
*/
|
||||
const elements = sizzle(`x[xmlns="${Strophe.NS.MUC_USER}"]`, stanza);
|
||||
const is_self = stanza.querySelectorAll("status[code='110']").length;
|
||||
const iteratee = _.partial(this.parseXUserElement.bind(this), _, stanza, is_self);
|
||||
|
@ -159,6 +159,11 @@ converse.plugins.add('converse-register', {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @namespace _converse.RegisterPanel
|
||||
* @memberOf _converse
|
||||
*/
|
||||
_converse.RegisterPanel = Backbone.NativeView.extend({
|
||||
tagName: 'div',
|
||||
id: "converse-register-panel",
|
||||
@ -200,20 +205,21 @@ converse.plugins.add('converse-register', {
|
||||
if (!this._registering) {
|
||||
connect_cb(req, callback, raw);
|
||||
} else {
|
||||
if (this.getRegistrationFields(req, callback, raw)) {
|
||||
if (this.getRegistrationFields(req, callback)) {
|
||||
this._registering = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
getRegistrationFields (req, _callback, raw) {
|
||||
/* Send an IQ stanza to the XMPP server asking for the
|
||||
* registration fields.
|
||||
* Parameters:
|
||||
* (Strophe.Request) req - The current request
|
||||
* (Function) callback
|
||||
*/
|
||||
/**
|
||||
* Send an IQ stanza to the XMPP server asking for the registration fields.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#getRegistrationFields
|
||||
* @param { Strophe.Request } req - The current request
|
||||
* @param { Function } callback - The callback function
|
||||
*/
|
||||
getRegistrationFields (req, _callback) {
|
||||
const conn = _converse.connection;
|
||||
conn.connected = true;
|
||||
|
||||
@ -248,12 +254,13 @@ converse.plugins.add('converse-register', {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for {@link _converse.RegisterPanel#getRegistrationFields}
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#onRegistrationFields
|
||||
* @param { XMLElement } stanza - The query stanza.
|
||||
*/
|
||||
onRegistrationFields (stanza) {
|
||||
/* Handler for Registration Fields Request.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) elem - The query stanza.
|
||||
*/
|
||||
if (stanza.getAttribute("type") === "error") {
|
||||
_converse.connection._changeConnectStatus(
|
||||
Strophe.Status.REGIFAIL,
|
||||
@ -309,13 +316,13 @@ converse.plugins.add('converse-register', {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback method that gets called when the user has chosen an XMPP provider
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#onProviderChosen
|
||||
* @param { HTMLElement } form - The form that was submitted
|
||||
*/
|
||||
onProviderChosen (form) {
|
||||
/* Callback method that gets called when the user has chosen an
|
||||
* XMPP provider.
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) form - The form that was submitted
|
||||
*/
|
||||
const domain_input = form.querySelector('input[name=domain]'),
|
||||
domain = _.get(domain_input, 'value');
|
||||
if (!domain) {
|
||||
@ -327,13 +334,13 @@ converse.plugins.add('converse-register', {
|
||||
this.fetchRegistrationForm(domain.trim());
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch a registration form from the requested domain
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#fetchRegistrationForm
|
||||
* @param { String } domain_name - XMPP server domain
|
||||
*/
|
||||
fetchRegistrationForm (domain_name) {
|
||||
/* This is called with a domain name based on which, it fetches a
|
||||
* registration form from the requested domain.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) domain_name - XMPP server domain
|
||||
*/
|
||||
if (!this.model.get('registration_form_rendered')) {
|
||||
this.renderRegistrationRequest();
|
||||
}
|
||||
@ -386,16 +393,14 @@ converse.plugins.add('converse-register', {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback function called by Strophe whenever the connection status changes.
|
||||
* Passed to Strophe specifically during a registration attempt.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#onConnectStatusChanged
|
||||
* @param { integer } status_code - The Strophe.Status status code
|
||||
*/
|
||||
onConnectStatusChanged(status_code) {
|
||||
/* Callback function called by Strophe whenever the
|
||||
* connection status changes.
|
||||
*
|
||||
* Passed to Strophe specifically during a registration
|
||||
* attempt.
|
||||
*
|
||||
* Parameters:
|
||||
* (Integer) status_code - The Stroph.Status status code
|
||||
*/
|
||||
_converse.log('converse-register: onConnectStatusChanged');
|
||||
if (_.includes([
|
||||
Strophe.Status.DISCONNECTED,
|
||||
@ -472,13 +477,14 @@ converse.plugins.add('converse-register', {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the registration form based on the XForm fields
|
||||
* received from the XMPP server.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#renderRegistrationForm
|
||||
* @param { XMLElement } stanza - The IQ stanza received from the XMPP server.
|
||||
*/
|
||||
renderRegistrationForm (stanza) {
|
||||
/* Renders the registration form based on the XForm fields
|
||||
* received from the XMPP server.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The IQ stanza received from the XMPP server.
|
||||
*/
|
||||
const form = this.el.querySelector('form');
|
||||
form.innerHTML = tpl_registration_form({
|
||||
'__': _converse.__,
|
||||
@ -528,14 +534,14 @@ converse.plugins.add('converse-register', {
|
||||
flash.classList.remove('hidden');
|
||||
},
|
||||
|
||||
/**
|
||||
* Report back to the user any error messages received from the
|
||||
* XMPP server after attempted registration.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#reportErrors
|
||||
* @param { XMLElement } stanza - The IQ stanza received from the XMPP server
|
||||
*/
|
||||
reportErrors (stanza) {
|
||||
/* Report back to the user any error messages received from the
|
||||
* XMPP server after attempted registration.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The IQ stanza received from the
|
||||
* XMPP server.
|
||||
*/
|
||||
const errors = stanza.querySelectorAll('error');
|
||||
_.each(errors, (error) => {
|
||||
this.showValidationError(error.textContent);
|
||||
@ -568,14 +574,14 @@ converse.plugins.add('converse-register', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler, when the user submits the registration form.
|
||||
* Provides form error feedback or starts the registration process.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#submitRegistrationForm
|
||||
* @param { HTMLElement } form - The HTML form that was submitted
|
||||
*/
|
||||
submitRegistrationForm (form) {
|
||||
/* Handler, when the user submits the registration form.
|
||||
* Provides form error feedback or starts the registration
|
||||
* process.
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) form - The HTML form that was submitted
|
||||
*/
|
||||
const has_empty_inputs = _.reduce(
|
||||
this.el.querySelectorAll('input.required'),
|
||||
function (result, input) {
|
||||
@ -606,13 +612,12 @@ converse.plugins.add('converse-register', {
|
||||
this.setFields(iq.tree());
|
||||
},
|
||||
|
||||
/* Stores the values that will be sent to the XMPP server during attempted registration.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#setFields
|
||||
* @param { XMLElement } stanza - the IQ stanza that will be sent to the XMPP server.
|
||||
*/
|
||||
setFields (stanza) {
|
||||
/* Stores the values that will be sent to the XMPP server
|
||||
* during attempted registration.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - the IQ stanza that will be sent to the XMPP server.
|
||||
*/
|
||||
const query = stanza.querySelector('query');
|
||||
const xform = sizzle(`x[xmlns="${Strophe.NS.XFORM}"]`, query);
|
||||
if (xform.length > 0) {
|
||||
@ -653,14 +658,15 @@ converse.plugins.add('converse-register', {
|
||||
this.form_type = 'xform';
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback method that gets called when a return IQ stanza
|
||||
* is received from the XMPP server, after attempting to
|
||||
* register a new user.
|
||||
* @private
|
||||
* @method _converse.RegisterPanel#reportErrors
|
||||
* @param { XMLElement } stanza - The IQ stanza.
|
||||
*/
|
||||
_onRegisterIQ (stanza) {
|
||||
/* Callback method that gets called when a return IQ stanza
|
||||
* is received from the XMPP server, after attempting to
|
||||
* register a new user.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The IQ stanza.
|
||||
*/
|
||||
if (stanza.getAttribute("type") === "error") {
|
||||
_converse.log("Registration failed.", Strophe.LogLevel.ERROR);
|
||||
this.reportErrors(stanza);
|
||||
|
@ -442,13 +442,13 @@ converse.plugins.add('converse-chatboxes', {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a {@link _converse.Message} return the XML stanza that represents it.
|
||||
* @private
|
||||
* @method _converse.ChatBox#createMessageStanza
|
||||
* @param { _converse.Message } message - The message object
|
||||
*/
|
||||
createMessageStanza (message) {
|
||||
/* Given a _converse.Message Backbone.Model, return the XML
|
||||
* stanza that represents it.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) message - The Backbone.Model representing the message
|
||||
*/
|
||||
const stanza = $msg({
|
||||
'from': _converse.connection.jid,
|
||||
'to': this.get('jid'),
|
||||
@ -630,13 +630,14 @@ converse.plugins.add('converse-chatboxes', {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Extract the XEP-0359 stanza IDs from the passed in stanza
|
||||
* and return a map containing them.
|
||||
* @private
|
||||
* @method _converse.ChatBox#getStanzaIDs
|
||||
* @param { XMLElement } stanza - The message stanza
|
||||
*/
|
||||
getStanzaIDs (stanza) {
|
||||
/* Extract the XEP-0359 stanza IDs from the passed in stanza
|
||||
* and return a map containing them.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The message stanza
|
||||
*/
|
||||
const attrs = {};
|
||||
const stanza_ids = sizzle(`stanza-id[xmlns="${Strophe.NS.SID}"]`, stanza);
|
||||
if (stanza_ids.length) {
|
||||
@ -659,18 +660,17 @@ converse.plugins.add('converse-chatboxes', {
|
||||
return !_.isNil(sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, original_stanza).pop());
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a passed in message stanza and returns an object
|
||||
* of attributes.
|
||||
* @private
|
||||
* @method _converse.ChatBox#getMessageAttributesFromStanza
|
||||
* @param { XMLElement } stanza - The message stanza
|
||||
* @param { XMLElement } delay - The <delay> node from the stanza, if there was one.
|
||||
* @param { XMLElement } original_stanza - The original stanza, that contains the
|
||||
* message stanza, if it was contained, otherwise it's the message stanza itself.
|
||||
*/
|
||||
getMessageAttributesFromStanza (stanza, original_stanza) {
|
||||
/* Parses a passed in message stanza and returns an object
|
||||
* of attributes.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The message stanza
|
||||
* (XMLElement) delay - The <delay> node from the
|
||||
* stanza, if there was one.
|
||||
* (XMLElement) original_stanza - The original stanza,
|
||||
* that contains the message stanza, if it was
|
||||
* contained, otherwise it's the message stanza itself.
|
||||
*/
|
||||
const spoiler = sizzle(`spoiler[xmlns="${Strophe.NS.SPOILER}"]`, original_stanza).pop(),
|
||||
delay = sizzle(`delay[xmlns="${Strophe.NS.DELAY}"]`, original_stanza).pop(),
|
||||
text = _converse.chatboxes.getMessageBody(stanza) || undefined,
|
||||
@ -864,13 +864,13 @@ converse.plugins.add('converse-chatboxes', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler method for all incoming single-user chat "message" stanzas.
|
||||
* @private
|
||||
* @method _converse.ChatBox#onMessage
|
||||
* @param { XMLElement } stanza - The incoming message stanza
|
||||
*/
|
||||
async onMessage (stanza) {
|
||||
/* Handler method for all incoming single-user chat "message"
|
||||
* stanzas.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza - The incoming message stanza
|
||||
*/
|
||||
let to_jid = stanza.getAttribute('to');
|
||||
const to_resource = Strophe.getResourceFromJid(to_jid);
|
||||
|
||||
@ -970,15 +970,16 @@ converse.plugins.add('converse-chatboxes', {
|
||||
_converse.api.trigger('message', {'stanza': original_stanza, 'chatbox': chatbox});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a chat box or optionally return a newly
|
||||
* created one if one doesn't exist.
|
||||
* @private
|
||||
* @method _converse.ChatBox#getChatBox
|
||||
* @param { string } jid - The JID of the user whose chat box we want
|
||||
* @param { boolean } create - Should a new chat box be created if none exists?
|
||||
* @param { object } attrs - Optional chat box atributes.
|
||||
*/
|
||||
getChatBox (jid, attrs={}, create) {
|
||||
/* Returns a chat box or optionally return a newly
|
||||
* created one if one doesn't exist.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) jid - The JID of the user whose chat box we want
|
||||
* (Boolean) create - Should a new chat box be created if none exists?
|
||||
* (Object) attrs - Optional chat box atributes.
|
||||
*/
|
||||
if (_.isObject(jid)) {
|
||||
create = attrs;
|
||||
attrs = jid;
|
||||
|
@ -225,20 +225,19 @@ _converse.default_settings = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs messages to the browser's developer console.
|
||||
* Available loglevels are 0 for 'debug', 1 for 'info', 2 for 'warn',
|
||||
* 3 for 'error' and 4 for 'fatal'.
|
||||
* When using the 'error' or 'warn' loglevels, a full stacktrace will be
|
||||
* logged as well.
|
||||
* @method log
|
||||
* @private
|
||||
* @memberOf _converse
|
||||
* @param { string } message - The message to be logged
|
||||
* @param { integer } level - The loglevel which allows for filtering of log messages
|
||||
*/
|
||||
_converse.log = function (message, level, style='') {
|
||||
/* Logs messages to the browser's developer console.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) message - The message to be logged.
|
||||
* (Integer) level - The loglevel which allows for filtering of log
|
||||
* messages.
|
||||
*
|
||||
* Available loglevels are 0 for 'debug', 1 for 'info', 2 for 'warn',
|
||||
* 3 for 'error' and 4 for 'fatal'.
|
||||
*
|
||||
* When using the 'error' or 'warn' loglevels, a full stacktrace will be
|
||||
* logged as well.
|
||||
*/
|
||||
if (level === Strophe.LogLevel.ERROR || level === Strophe.LogLevel.FATAL) {
|
||||
style = style || 'color: maroon';
|
||||
}
|
||||
@ -275,12 +274,15 @@ Strophe.log = function (level, msg) { _converse.log(level+' '+msg, level); };
|
||||
Strophe.error = function (msg) { _converse.log(msg, Strophe.LogLevel.ERROR); };
|
||||
|
||||
|
||||
/**
|
||||
* Translate the given string based on the current locale.
|
||||
* Handles all MUC presence stanzas.
|
||||
* @method __
|
||||
* @private
|
||||
* @memberOf _converse
|
||||
* @param { String } str - The string to translate
|
||||
*/
|
||||
_converse.__ = function (str) {
|
||||
/* Translate the given string based on the current locale.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) str - The string to translate.
|
||||
*/
|
||||
if (_.isUndefined(i18n)) {
|
||||
return str;
|
||||
}
|
||||
@ -565,12 +567,14 @@ _converse.initialize = async function (settings, callback) {
|
||||
|
||||
this.generateResource = () => `/converse.js-${Math.floor(Math.random()*139749528).toString()}`;
|
||||
|
||||
/**
|
||||
* Send out a Chat Status Notification (XEP-0352)
|
||||
* @private
|
||||
* @method sendCSI
|
||||
* @memberOf _converse
|
||||
* @param { String } stat - The user's chat status
|
||||
*/
|
||||
this.sendCSI = function (stat) {
|
||||
/* Send out a Chat Status Notification (XEP-0352)
|
||||
*
|
||||
* Parameters:
|
||||
* (String) stat: The user's chat status
|
||||
*/
|
||||
_converse.api.send($build(stat, {xmlns: Strophe.NS.CSI}));
|
||||
_converse.inactive = (stat === _converse.INACTIVE) ? true : false;
|
||||
};
|
||||
@ -661,14 +665,15 @@ _converse.initialize = async function (settings, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reject or cancel another user's subscription to our presence updates.
|
||||
* @method rejectPresenceSubscription
|
||||
* @private
|
||||
* @memberOf _converse
|
||||
* @param { String } jid - The Jabber ID of the user whose subscription is being canceled
|
||||
* @param { String } message - An optional message to the user
|
||||
*/
|
||||
this.rejectPresenceSubscription = function (jid, message) {
|
||||
/* Reject or cancel another user's subscription to our presence updates.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user whose subscription
|
||||
* is being canceled.
|
||||
* (String) message - An optional message to the user
|
||||
*/
|
||||
const pres = $pres({to: jid, type: "unsubscribed"});
|
||||
if (message && message !== "") { pres.c("status").t(message); }
|
||||
_converse.api.send(pres);
|
||||
|
@ -23,6 +23,11 @@ converse.plugins.add('converse-disco', {
|
||||
_converse.api.promises.add('discoInitialized');
|
||||
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @namespace _converse.DiscoEntity
|
||||
* @memberOf _converse
|
||||
*/
|
||||
_converse.DiscoEntity = Backbone.Model.extend({
|
||||
/* A Disco Entity is a JID addressable entity that can be queried
|
||||
* for features.
|
||||
@ -64,14 +69,15 @@ converse.plugins.add('converse-disco', {
|
||||
this.items.fetch();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a Promise which resolves with a map indicating
|
||||
* whether a given identity is provided by this entity.
|
||||
* @private
|
||||
* @method _converse.DiscoEntity#getIdentity
|
||||
* @param { String } category - The identity category
|
||||
* @param { String } type - The identity type
|
||||
*/
|
||||
async getIdentity (category, type) {
|
||||
/* Returns a Promise which resolves with a map indicating
|
||||
* whether a given identity is provided by this entity.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) category - The identity category
|
||||
* (String) type - The identity type
|
||||
*/
|
||||
await this.waitUntilFeaturesDiscovered;
|
||||
return this.identities.findWhere({
|
||||
'category': category,
|
||||
@ -79,13 +85,14 @@ converse.plugins.add('converse-disco', {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a Promise which resolves with a map indicating
|
||||
* whether a given feature is supported.
|
||||
* @private
|
||||
* @method _converse.DiscoEntity#hasFeature
|
||||
* @param { String } feature - The feature that might be supported.
|
||||
*/
|
||||
async hasFeature (feature) {
|
||||
/* Returns a Promise which resolves with a map indicating
|
||||
* whether a given feature is supported.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) feature - The feature that might be supported.
|
||||
*/
|
||||
await this.waitUntilFeaturesDiscovered
|
||||
if (this.features.findWhere({'var': feature})) {
|
||||
return this;
|
||||
|
@ -291,14 +291,14 @@ converse.plugins.add('converse-muc', {
|
||||
return this.get('name') || this.get('jid');
|
||||
},
|
||||
|
||||
/**
|
||||
* Join the groupchat.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#join
|
||||
* @param { String } nick - The user's nickname
|
||||
* @param { String } password - Optional password, if required by the groupchat.
|
||||
*/
|
||||
join (nick, password) {
|
||||
/* Join the groupchat.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) nick: The user's nickname
|
||||
* (String) password: Optional password, if required by
|
||||
* the groupchat.
|
||||
*/
|
||||
nick = nick ? nick : this.get('nick');
|
||||
if (!nick) {
|
||||
throw new TypeError('join: You need to provide a valid nickname');
|
||||
@ -322,13 +322,12 @@ converse.plugins.add('converse-muc', {
|
||||
return this;
|
||||
},
|
||||
|
||||
/* Leave the groupchat.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#leave
|
||||
* @param { string } exit_msg - Optional message to indicate your reason for leaving
|
||||
*/
|
||||
leave (exit_msg) {
|
||||
/* Leave the groupchat.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) exit_msg: Optional message to indicate your
|
||||
* reason for leaving.
|
||||
*/
|
||||
this.features.destroy();
|
||||
this.occupants.browserStorage._clear();
|
||||
this.occupants.reset();
|
||||
@ -479,12 +478,14 @@ converse.plugins.add('converse-muc', {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a direct invitation as per XEP-0249
|
||||
* @private
|
||||
* @method _converse.ChatRoom#directInvite
|
||||
* @param { String } recipient - JID of the person being invited
|
||||
* @param { String } reason - Optional reason for the invitation
|
||||
*/
|
||||
directInvite (recipient, reason) {
|
||||
/* Send a direct invitation as per XEP-0249
|
||||
* Parameters:
|
||||
* (String) recipient - JID of the person being invited
|
||||
* (String) reason - Optional reason for the invitation
|
||||
*/
|
||||
if (this.features.get('membersonly')) {
|
||||
// When inviting to a members-only groupchat, we first add
|
||||
// the person to the member list by giving them an
|
||||
@ -565,20 +566,17 @@ converse.plugins.add('converse-muc', {
|
||||
this.features.save(attrs);
|
||||
},
|
||||
|
||||
/* Send an IQ stanza to the server, asking it for the
|
||||
* member-list of this groupchat.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @private
|
||||
* @method _converse.ChatRoom#requestMemberList
|
||||
* @param { string } affiliation - The specific member list to
|
||||
* fetch. 'admin', 'owner' or 'member'.
|
||||
* @returns:
|
||||
* A promise which resolves once the list has been retrieved.
|
||||
*/
|
||||
requestMemberList (affiliation) {
|
||||
/* Send an IQ stanza to the server, asking it for the
|
||||
* member-list of this groupchat.
|
||||
*
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* Parameters:
|
||||
* (String) affiliation: The specific member list to
|
||||
* fetch. 'admin', 'owner' or 'member'.
|
||||
*
|
||||
* Returns:
|
||||
* A promise which resolves once the list has been
|
||||
* retrieved.
|
||||
*/
|
||||
affiliation = affiliation || 'member';
|
||||
const iq = $iq({to: this.get('jid'), type: "get"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_ADMIN})
|
||||
@ -586,28 +584,26 @@ converse.plugins.add('converse-muc', {
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to set an affiliation for
|
||||
* the provided JIDs.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* Prosody doesn't accept multiple JIDs' affiliations
|
||||
* being set in one IQ stanza, so as a workaround we send
|
||||
* a separate stanza for each JID.
|
||||
* Related ticket: https://issues.prosody.im/345
|
||||
*
|
||||
* @private
|
||||
* @method _converse.ChatRoom#setAffiliation
|
||||
* @param { string } affiliation - The affiliation
|
||||
* @param { object } members - A map of jids, affiliations and
|
||||
* optionally reasons. Only those entries with the
|
||||
* same affiliation as being currently set will be considered.
|
||||
* @returns
|
||||
* A promise which resolves and fails depending on the XMPP server response.
|
||||
*/
|
||||
setAffiliation (affiliation, members) {
|
||||
/* Send IQ stanzas to the server to set an affiliation for
|
||||
* the provided JIDs.
|
||||
*
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* XXX: Prosody doesn't accept multiple JIDs' affiliations
|
||||
* being set in one IQ stanza, so as a workaround we send
|
||||
* a separate stanza for each JID.
|
||||
* Related ticket: https://issues.prosody.im/345
|
||||
*
|
||||
* Parameters:
|
||||
* (String) affiliation: The affiliation
|
||||
* (Object) members: A map of jids, affiliations and
|
||||
* optionally reasons. Only those entries with the
|
||||
* same affiliation as being currently set will be
|
||||
* considered.
|
||||
*
|
||||
* Returns:
|
||||
* A promise which resolves and fails depending on the
|
||||
* XMPP server response.
|
||||
*/
|
||||
members = _.filter(members, (member) =>
|
||||
// We only want those members who have the right
|
||||
// affiliation (or none, which implies the provided one).
|
||||
@ -618,18 +614,19 @@ converse.plugins.add('converse-muc', {
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit the groupchat configuration form by sending an IQ
|
||||
* stanza to the server.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#saveConfiguration
|
||||
* @param { HTMLElement } form - The configuration form DOM element.
|
||||
* If no form is provided, the default configuration
|
||||
* values will be used.
|
||||
* @returns { promise }
|
||||
* Returns a promise which resolves once the XMPP server
|
||||
* has return a response IQ.
|
||||
*/
|
||||
saveConfiguration (form) {
|
||||
/* Submit the groupchat configuration form by sending an IQ
|
||||
* stanza to the server.
|
||||
*
|
||||
* Returns a promise which resolves once the XMPP server
|
||||
* has return a response IQ.
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) form: The configuration form DOM element.
|
||||
* If no form is provided, the default configuration
|
||||
* values will be used.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
const inputs = form ? sizzle(':input:not([type=button]):not([type=submit])', form) : [],
|
||||
configArray = _.map(inputs, u.webForm2xForm);
|
||||
@ -689,20 +686,21 @@ converse.plugins.add('converse-muc', {
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza with the groupchat configuration.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#sendConfiguration
|
||||
* @param { Array } config - The groupchat configuration
|
||||
* @param { Function } callback - Callback upon succesful IQ response
|
||||
* The first parameter passed in is IQ containing the
|
||||
* groupchat configuration.
|
||||
* The second is the response IQ from the server.
|
||||
* @param { Function } errback - Callback upon error IQ response
|
||||
* The first parameter passed in is IQ containing the
|
||||
* groupchat configuration.
|
||||
* The second is the response IQ from the server.
|
||||
*/
|
||||
sendConfiguration (config, callback, errback) {
|
||||
/* Send an IQ stanza with the groupchat configuration.
|
||||
*
|
||||
* Parameters:
|
||||
* (Array) config: The groupchat configuration
|
||||
* (Function) callback: Callback upon succesful IQ response
|
||||
* The first parameter passed in is IQ containing the
|
||||
* groupchat configuration.
|
||||
* The second is the response IQ from the server.
|
||||
* (Function) errback: Callback upon error IQ response
|
||||
* The first parameter passed in is IQ containing the
|
||||
* groupchat configuration.
|
||||
* The second is the response IQ from the server.
|
||||
*/
|
||||
const iq = $iq({to: this.get('jid'), type: "set"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_OWNER})
|
||||
.c("x", {xmlns: Strophe.NS.XFORM, type: "submit"});
|
||||
@ -712,13 +710,13 @@ converse.plugins.add('converse-muc', {
|
||||
return _converse.api.sendIQ(iq).then(callback).catch(errback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse the presence stanza for the current user's affiliation.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#saveAffiliationAndRole
|
||||
* @param { XMLElement } pres - A <presence> stanza.
|
||||
*/
|
||||
saveAffiliationAndRole (pres) {
|
||||
/* Parse the presence stanza for the current user's
|
||||
* affiliation.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) pres: A <presence> stanza.
|
||||
*/
|
||||
const item = sizzle(`x[xmlns="${Strophe.NS.MUC_USER}"] item`, pres).pop();
|
||||
const is_self = pres.querySelector("status[code='110']");
|
||||
if (is_self && !_.isNil(item)) {
|
||||
@ -733,15 +731,16 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza specifying an affiliation change.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#
|
||||
* @param { String } affiliation: affiliation
|
||||
* (could also be stored on the member object).
|
||||
* @param { Object } member: Map containing the member's jid and
|
||||
* optionally a reason and affiliation.
|
||||
*/
|
||||
sendAffiliationIQ (affiliation, member) {
|
||||
/* Send an IQ stanza specifying an affiliation change.
|
||||
*
|
||||
* Paremeters:
|
||||
* (String) affiliation: affiliation (could also be stored
|
||||
* on the member object).
|
||||
* (Object) member: Map containing the member's jid and
|
||||
* optionally a reason and affiliation.
|
||||
*/
|
||||
const iq = $iq({to: this.get('jid'), type: "set"})
|
||||
.c("query", {xmlns: Strophe.NS.MUC_ADMIN})
|
||||
.c("item", {
|
||||
@ -755,17 +754,17 @@ converse.plugins.add('converse-muc', {
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send IQ stanzas to the server to modify the
|
||||
* affiliations in this groupchat.
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
* @private
|
||||
* @method _converse.ChatRoom#setAffiliations
|
||||
* @param { object } members - A map of jids, affiliations and optionally reasons
|
||||
* @param { function } onSuccess - callback for a succesful response
|
||||
* @param { function } onError - callback for an error response
|
||||
*/
|
||||
setAffiliations (members) {
|
||||
/* Send IQ stanzas to the server to modify the
|
||||
* affiliations in this groupchat.
|
||||
*
|
||||
* See: https://xmpp.org/extensions/xep-0045.html#modifymember
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) members: A map of jids, affiliations and optionally reasons
|
||||
* (Function) onSuccess: callback for a succesful response
|
||||
* (Function) onError: callback for an error response
|
||||
*/
|
||||
const affiliations = _.uniq(_.map(members, 'affiliation'));
|
||||
return Promise.all(_.map(affiliations, _.partial(this.setAffiliation.bind(this), _, members)));
|
||||
},
|
||||
@ -787,39 +786,39 @@ converse.plugins.add('converse-muc', {
|
||||
return [].concat.apply([], result).filter(p => p);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the lists of users with the given affiliations.
|
||||
* Then compute the delta between those users and
|
||||
* the passed in members, and if it exists, send the delta
|
||||
* to the XMPP server to update the member list.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#updateMemberLists
|
||||
* @param { object } members - Map of member jids and affiliations.
|
||||
* @param { string|array } affiliation - An array of affiliations or
|
||||
* a string if only one affiliation.
|
||||
* @param { function } deltaFunc - The function to compute the delta
|
||||
* between old and new member lists.
|
||||
* @returns { promise }
|
||||
* A promise which is resolved once the list has been
|
||||
* updated or once it's been established there's no need
|
||||
* to update the list.
|
||||
*/
|
||||
updateMemberLists (members, affiliations, deltaFunc) {
|
||||
/* Fetch the lists of users with the given affiliations.
|
||||
* Then compute the delta between those users and
|
||||
* the passed in members, and if it exists, send the delta
|
||||
* to the XMPP server to update the member list.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) members: Map of member jids and affiliations.
|
||||
* (String|Array) affiliation: An array of affiliations or
|
||||
* a string if only one affiliation.
|
||||
* (Function) deltaFunc: The function to compute the delta
|
||||
* between old and new member lists.
|
||||
*
|
||||
* Returns:
|
||||
* A promise which is resolved once the list has been
|
||||
* updated or once it's been established there's no need
|
||||
* to update the list.
|
||||
*/
|
||||
this.getJidsWithAffiliations(affiliations)
|
||||
.then(old_members => this.setAffiliations(deltaFunc(members, old_members)))
|
||||
.then(() => this.occupants.fetchMembers())
|
||||
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
},
|
||||
|
||||
/**
|
||||
* Use service-discovery to ask the XMPP server whether
|
||||
* this user has a reserved nickname for this groupchat.
|
||||
* If so, we'll use that, otherwise we render the nickname form.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#checkForReservedNick
|
||||
* @returns { promise } A promise which resolves with the response IQ
|
||||
*/
|
||||
async checkForReservedNick () {
|
||||
/* Use service-discovery to ask the XMPP server whether
|
||||
* this user has a reserved nickname for this groupchat.
|
||||
* If so, we'll use that, otherwise we render the nickname form.
|
||||
*
|
||||
* Parameters:
|
||||
* (Function) callback: Callback upon succesful IQ response
|
||||
* (Function) errback: Callback upon error IQ response
|
||||
*/
|
||||
const iq = await _converse.api.sendIQ(
|
||||
$iq({
|
||||
'to': this.get('jid'),
|
||||
@ -887,13 +886,14 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a presence stanza, update the occupant model
|
||||
* based on its contents.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#updateOccupantsOnPresence
|
||||
* @param { XMLElement } pres - The presence stanza
|
||||
*/
|
||||
updateOccupantsOnPresence (pres) {
|
||||
/* Given a presence stanza, update the occupant model
|
||||
* based on its contents.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) pres: The presence stanza
|
||||
*/
|
||||
const data = this.parsePresence(pres);
|
||||
if (data.type === 'error' || (!data.jid && !data.nick)) {
|
||||
return true;
|
||||
@ -989,12 +989,13 @@ converse.plugins.add('converse-muc', {
|
||||
acknowledged[xmlns="${Strophe.NS.MARKERS}"]`, stanza).length > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a subject change and return `true` if so.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#subjectChangeHandled
|
||||
* @param { object } attrs - The message attributes
|
||||
*/
|
||||
subjectChangeHandled (attrs) {
|
||||
/* Handle a subject change and return `true` if so.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) attrs: The message attributes
|
||||
*/
|
||||
if (attrs.subject && !attrs.thread && !attrs.message) {
|
||||
// https://xmpp.org/extensions/xep-0045.html#subject-mod
|
||||
// -----------------------------------------------------
|
||||
@ -1007,13 +1008,14 @@ converse.plugins.add('converse-muc', {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Is this a chat state notification that can be ignored,
|
||||
* because it's old or because it's from us.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#ignorableCSN
|
||||
* @param { Object } attrs - The message attributes
|
||||
*/
|
||||
ignorableCSN (attrs) {
|
||||
/* Is this a chat state notification that can be ignored,
|
||||
* because it's old or because it's from us.
|
||||
*
|
||||
* Parameters:
|
||||
* (Object) attrs: The message attributes
|
||||
*/
|
||||
const is_csn = u.isOnlyChatStateNotification(attrs),
|
||||
own_message = Strophe.getResourceFromJid(attrs.from) == this.get('nick');
|
||||
return is_csn && (attrs.is_delayed || own_message);
|
||||
@ -1038,12 +1040,13 @@ converse.plugins.add('converse-muc', {
|
||||
return attrs;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for all MUC messages sent to this groupchat.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#onMessage
|
||||
* @param { XMLElement } stanza - The message stanza.
|
||||
*/
|
||||
async onMessage (stanza) {
|
||||
/* Handler for all MUC messages sent to this groupchat.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) stanza: The message stanza.
|
||||
*/
|
||||
this.fetchFeaturesIfConfigurationChanged(stanza);
|
||||
|
||||
const original_stanza = stanza,
|
||||
@ -1076,12 +1079,13 @@ converse.plugins.add('converse-muc', {
|
||||
_converse.api.trigger('message', {'stanza': original_stanza, 'chatbox': this});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles all MUC presence stanzas.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#onPresence
|
||||
* @param { XMLElement } pres - The stanza
|
||||
*/
|
||||
onPresence (pres) {
|
||||
/* Handles all MUC presence stanzas.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) pres: The stanza
|
||||
*/
|
||||
if (pres.getAttribute('type') === 'error') {
|
||||
this.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
|
||||
return;
|
||||
@ -1096,22 +1100,22 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles a received presence relating to the current user.
|
||||
*
|
||||
* For locked groupchats (which are by definition "new"), the
|
||||
* groupchat will either be auto-configured or created instantly
|
||||
* (with default config) or a configuration groupchat will be
|
||||
* rendered.
|
||||
*
|
||||
* If the groupchat is not locked, then the groupchat will be
|
||||
* auto-configured only if applicable and if the current
|
||||
* user is the groupchat's owner.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#onOwnPresence
|
||||
* @param { XMLElement } pres - The stanza
|
||||
*/
|
||||
onOwnPresence (pres) {
|
||||
/* Handles a received presence relating to the current
|
||||
* user.
|
||||
*
|
||||
* For locked groupchats (which are by definition "new"), the
|
||||
* groupchat will either be auto-configured or created instantly
|
||||
* (with default config) or a configuration groupchat will be
|
||||
* rendered.
|
||||
*
|
||||
* If the groupchat is not locked, then the groupchat will be
|
||||
* auto-configured only if applicable and if the current
|
||||
* user is the groupchat's owner.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) pres: The stanza
|
||||
*/
|
||||
this.saveAffiliationAndRole(pres);
|
||||
|
||||
const locked_room = pres.querySelector("status[code='201']");
|
||||
@ -1148,13 +1152,14 @@ converse.plugins.add('converse-muc', {
|
||||
this.save('connection_status', converse.ROOMSTATUS.ENTERED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a boolean to indicate whether the current user
|
||||
* was mentioned in a message.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#isUserMentioned
|
||||
* @param { String } - The text message
|
||||
*/
|
||||
isUserMentioned (message) {
|
||||
/* Returns a boolean to indicate whether the current user
|
||||
* was mentioned in a message.
|
||||
*
|
||||
* Parameters:
|
||||
* (String): The text message
|
||||
*/
|
||||
const nick = this.get('nick');
|
||||
if (message.get('references').length) {
|
||||
const mentions = message.get('references').filter(ref => (ref.type === 'mention')).map(ref => ref.value);
|
||||
@ -1164,13 +1169,12 @@ converse.plugins.add('converse-muc', {
|
||||
}
|
||||
},
|
||||
|
||||
/* Given a newly received message, update the unread counter if necessary.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#incrementUnreadMsgCounter
|
||||
* @param { XMLElement } - The <messsage> stanza
|
||||
*/
|
||||
incrementUnreadMsgCounter (message) {
|
||||
/* Given a newly received message, update the unread counter if
|
||||
* necessary.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement): The <messsage> stanza
|
||||
*/
|
||||
if (!message) { return; }
|
||||
const body = message.get('message');
|
||||
if (_.isNil(body)) { return; }
|
||||
@ -1311,14 +1315,14 @@ converse.plugins.add('converse-muc', {
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* A direct MUC invitation to join a groupchat has been received
|
||||
* See XEP-0249: Direct MUC invitations.
|
||||
* @private
|
||||
* @method _converse.ChatRoom#onDirectMUCInvitation
|
||||
* @param { XMLElement } message - The message stanza containing the invitation.
|
||||
*/
|
||||
_converse.onDirectMUCInvitation = function (message) {
|
||||
/* A direct MUC invitation to join a groupchat has been received
|
||||
* See XEP-0249: Direct MUC invitations.
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) message: The message stanza containing the
|
||||
* invitation.
|
||||
*/
|
||||
const x_el = sizzle('x[xmlns="jabber:x:conference"]', message).pop(),
|
||||
from = Strophe.getBareJidFromJid(message.getAttribute('from')),
|
||||
room_jid = x_el.getAttribute('jid'),
|
||||
|
@ -45,10 +45,13 @@ converse.plugins.add('converse-roster', {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the Bakcbone collections that represent the contats
|
||||
* roster and the roster groups.
|
||||
* @private
|
||||
* @method _converse.initRoster
|
||||
*/
|
||||
_converse.initRoster = function () {
|
||||
/* Initialize the Bakcbone collections that represent the contats
|
||||
* roster and the roster groups.
|
||||
*/
|
||||
const storage = _converse.config.get('storage');
|
||||
_converse.roster = new _converse.RosterContacts();
|
||||
_converse.roster.browserStorage = new Backbone.BrowserStorage[storage](
|
||||
@ -75,15 +78,16 @@ converse.plugins.add('converse-roster', {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fetch all the roster groups, and then the roster contacts.
|
||||
* Emit an event after fetching is done in each case.
|
||||
* @private
|
||||
* @method _converse.populateRoster
|
||||
* @param { Bool } ignore_cache - If set to to true, the local cache
|
||||
* will be ignored it's guaranteed that the XMPP server
|
||||
* will be queried for the roster.
|
||||
*/
|
||||
_converse.populateRoster = async function (ignore_cache=false) {
|
||||
/* Fetch all the roster groups, and then the roster contacts.
|
||||
* Emit an event after fetching is done in each case.
|
||||
*
|
||||
* Parameters:
|
||||
* (Bool) ignore_cache - If set to to true, the local cache
|
||||
* will be ignored it's guaranteed that the XMPP server
|
||||
* will be queried for the roster.
|
||||
*/
|
||||
if (ignore_cache) {
|
||||
_converse.send_initial_presence = true;
|
||||
try {
|
||||
@ -272,13 +276,14 @@ converse.plugins.add('converse-roster', {
|
||||
return this.vcard.get('fullname');
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a presence subscription request to this roster contact
|
||||
* @private
|
||||
* @method _converse.RosterContacts#subscribe
|
||||
* @param { String } message - An optional message to explain the
|
||||
* reason for the subscription request.
|
||||
*/
|
||||
subscribe (message) {
|
||||
/* Send a presence subscription request to this roster contact
|
||||
*
|
||||
* Parameters:
|
||||
* (String) message - An optional message to explain the
|
||||
* reason for the subscription request.
|
||||
*/
|
||||
const pres = $pres({to: this.get('jid'), type: "subscribe"});
|
||||
if (message && message !== "") {
|
||||
pres.c("status").t(message).up();
|
||||
@ -292,46 +297,55 @@ converse.plugins.add('converse-roster', {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Upon receiving the presence stanza of type "subscribed",
|
||||
* the user SHOULD acknowledge receipt of that subscription
|
||||
* state notification by sending a presence stanza of type
|
||||
* "subscribe" to the contact
|
||||
* @private
|
||||
* @method _converse.RosterContacts#ackSubscribe
|
||||
*/
|
||||
ackSubscribe () {
|
||||
/* Upon receiving the presence stanza of type "subscribed",
|
||||
* the user SHOULD acknowledge receipt of that subscription
|
||||
* state notification by sending a presence stanza of type
|
||||
* "subscribe" to the contact
|
||||
*/
|
||||
_converse.api.send($pres({
|
||||
'type': 'subscribe',
|
||||
'to': this.get('jid')
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* Upon receiving the presence stanza of type "unsubscribed",
|
||||
* the user SHOULD acknowledge receipt of that subscription state
|
||||
* notification by sending a presence stanza of type "unsubscribe"
|
||||
* this step lets the user's server know that it MUST no longer
|
||||
* send notification of the subscription state change to the user.
|
||||
* @private
|
||||
* @method _converse.RosterContacts#ackUnsubscribe
|
||||
* @param { String } jid - The Jabber ID of the user who is unsubscribing
|
||||
*/
|
||||
ackUnsubscribe () {
|
||||
/* Upon receiving the presence stanza of type "unsubscribed",
|
||||
* the user SHOULD acknowledge receipt of that subscription state
|
||||
* notification by sending a presence stanza of type "unsubscribe"
|
||||
* this step lets the user's server know that it MUST no longer
|
||||
* send notification of the subscription state change to the user.
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user who is unsubscribing
|
||||
*/
|
||||
_converse.api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
|
||||
this.removeFromRoster();
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
/**
|
||||
* Unauthorize this contact's presence subscription
|
||||
* @private
|
||||
* @method _converse.RosterContacts#unauthorize
|
||||
* @param { String } message - Optional message to send to the person being unauthorized
|
||||
*/
|
||||
unauthorize (message) {
|
||||
/* Unauthorize this contact's presence subscription
|
||||
* Parameters:
|
||||
* (String) message - Optional message to send to the person being unauthorized
|
||||
*/
|
||||
_converse.rejectPresenceSubscription(this.get('jid'), message);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Authorize presence subscription
|
||||
* @private
|
||||
* @method _converse.RosterContacts#authorize
|
||||
* @param { String } message - Optional message to send to the person being authorized
|
||||
*/
|
||||
authorize (message) {
|
||||
/* Authorize presence subscription
|
||||
* Parameters:
|
||||
* (String) message - Optional message to send to the person being authorized
|
||||
*/
|
||||
const pres = $pres({'to': this.get('jid'), 'type': "subscribed"});
|
||||
if (message && message !== "") {
|
||||
pres.c("status").t(message);
|
||||
@ -340,11 +354,13 @@ converse.plugins.add('converse-roster', {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Instruct the XMPP server to remove this contact from our roster
|
||||
* @private
|
||||
* @method _converse.RosterContacts#
|
||||
* @returns { Promise }
|
||||
*/
|
||||
removeFromRoster () {
|
||||
/* Instruct the XMPP server to remove this contact from our roster
|
||||
* Parameters:
|
||||
* (Function) callback
|
||||
*/
|
||||
const iq = $iq({type: 'set'})
|
||||
.c('query', {xmlns: Strophe.NS.ROSTER})
|
||||
.c('item', {jid: this.get('jid'), subscription: "remove"});
|
||||
@ -352,7 +368,11 @@ converse.plugins.add('converse-roster', {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @namespace _converse.RosterContacts
|
||||
* @memberOf _converse
|
||||
*/
|
||||
_converse.RosterContacts = Backbone.Collection.extend({
|
||||
model: _converse.RosterContact,
|
||||
|
||||
@ -460,17 +480,18 @@ converse.plugins.add('converse-roster', {
|
||||
return u.isSameBareJID(jid, _converse.connection.jid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a roster contact and then once we have confirmation from
|
||||
* the XMPP server we subscribe to that contact's presence updates.
|
||||
* @private
|
||||
* @method _converse.RosterContacts#addAndSubscribe
|
||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { String } message - An optional message to explain the reason for the subscription request.
|
||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
addAndSubscribe (jid, name, groups, message, attributes) {
|
||||
/* Add a roster contact and then once we have confirmation from
|
||||
* the XMPP server we subscribe to that contact's presence updates.
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user being added and subscribed to.
|
||||
* (String) name - The name of that user
|
||||
* (Array of Strings) groups - Any roster groups the user might belong to
|
||||
* (String) message - An optional message to explain the
|
||||
* reason for the subscription request.
|
||||
* (Object) attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
const handler = (contact) => {
|
||||
if (contact instanceof _converse.RosterContact) {
|
||||
contact.subscribe(message);
|
||||
@ -479,16 +500,17 @@ converse.plugins.add('converse-roster', {
|
||||
this.addContactToRoster(jid, name, groups, attributes).then(handler, handler);
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an IQ stanza to the XMPP server to add a new roster contact.
|
||||
* @private
|
||||
* @method _converse.RosterContacts#sendContactAddIQ
|
||||
* @param { String } jid - The Jabber ID of the user being added
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { Function } callback - A function to call once the IQ is returned
|
||||
* @param { Function } errback - A function to call if an error occurred
|
||||
*/
|
||||
sendContactAddIQ (jid, name, groups) {
|
||||
/* Send an IQ stanza to the XMPP server to add a new roster contact.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user being added
|
||||
* (String) name - The name of that user
|
||||
* (Array of Strings) groups - Any roster groups the user might belong to
|
||||
* (Function) callback - A function to call once the IQ is returned
|
||||
* (Function) errback - A function to call if an error occurred
|
||||
*/
|
||||
name = _.isEmpty(name) ? null : name;
|
||||
const iq = $iq({'type': 'set'})
|
||||
.c('query', {'xmlns': Strophe.NS.ROSTER})
|
||||
@ -497,18 +519,18 @@ converse.plugins.add('converse-roster', {
|
||||
return _converse.api.sendIQ(iq);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a RosterContact instance to _converse.roster and
|
||||
* registers the contact on the XMPP server.
|
||||
* Returns a promise which is resolved once the XMPP server has responded.
|
||||
* @private
|
||||
* @method _converse.RosterContacts#addContactToRoster
|
||||
* @param { String } jid - The Jabber ID of the user being added and subscribed to.
|
||||
* @param { String } name - The name of that user
|
||||
* @param { Array.String } groups - Any roster groups the user might belong to
|
||||
* @param { Object } attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
async addContactToRoster (jid, name, groups, attributes) {
|
||||
/* Adds a RosterContact instance to _converse.roster and
|
||||
* registers the contact on the XMPP server.
|
||||
* Returns a promise which is resolved once the XMPP server has
|
||||
* responded.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user being added and subscribed to.
|
||||
* (String) name - The name of that user
|
||||
* (Array of Strings) groups - Any roster groups the user might belong to
|
||||
* (Object) attributes - Any additional attributes to be stored on the user's model.
|
||||
*/
|
||||
groups = groups || [];
|
||||
try {
|
||||
await this.sendContactAddIQ(jid, name, groups);
|
||||
@ -551,13 +573,14 @@ converse.plugins.add('converse-roster', {
|
||||
return _.sum(this.models.filter((model) => !_.includes(ignored, model.presence.get('show'))));
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle roster updates from the XMPP server.
|
||||
* See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
||||
* @private
|
||||
* @method _converse.RosterContacts#onRosterPush
|
||||
* @param { XMLElement } IQ - The IQ stanza received from the XMPP server.
|
||||
*/
|
||||
onRosterPush (iq) {
|
||||
/* Handle roster updates from the XMPP server.
|
||||
* See: https://xmpp.org/rfcs/rfc6121.html#roster-syntax-actions-push
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) IQ - The IQ stanza received from the XMPP server.
|
||||
*/
|
||||
const id = iq.getAttribute('id');
|
||||
const from = iq.getAttribute('from');
|
||||
if (from && from !== _converse.bare_jid) {
|
||||
|
@ -100,12 +100,6 @@ converse.plugins.add('converse-vcard', {
|
||||
}
|
||||
|
||||
async function getVCard (_converse, jid) {
|
||||
/* Request the VCard of another user. Returns a promise.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) jid - The Jabber ID of the user whose VCard
|
||||
* is being requested.
|
||||
*/
|
||||
const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
|
||||
let iq;
|
||||
try {
|
||||
|
941
src/headless/dist/converse-headless.js
vendored
941
src/headless/dist/converse-headless.js
vendored
File diff suppressed because it is too large
Load Diff
@ -44,10 +44,8 @@ import moment from "moment";
|
||||
function detectLocale (library_check) {
|
||||
/* Determine which locale is supported by the user's system as well
|
||||
* as by the relevant library (e.g. converse.js or moment.js).
|
||||
*
|
||||
* Parameters:
|
||||
* (Function) library_check - Returns a boolean indicating whether
|
||||
* the locale is supported.
|
||||
* @param { Function } library_check - Returns a boolean indicating whether
|
||||
* the locale is supported.
|
||||
*/
|
||||
var locale, i;
|
||||
if (window.navigator.userLanguage) {
|
||||
@ -87,13 +85,11 @@ function getLocale (preferred_locale, isSupportedByLibrary) {
|
||||
return detectLocale(isSupportedByLibrary) || 'en';
|
||||
}
|
||||
|
||||
/* Check whether the locale or sub locale (e.g. en-US, en) is supported.
|
||||
* @param { String } locale - The locale to check for
|
||||
* @param { Function } available - Returns a boolean indicating whether the locale is supported
|
||||
*/
|
||||
function isLocaleAvailable (locale, available) {
|
||||
/* Check whether the locale or sub locale (e.g. en-US, en) is supported.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) locale - The locale to check for
|
||||
* (Function) available - returns a boolean indicating whether the locale is supported
|
||||
*/
|
||||
if (available(locale)) {
|
||||
return locale;
|
||||
} else {
|
||||
@ -106,6 +102,9 @@ function isLocaleAvailable (locale, available) {
|
||||
|
||||
let jed_instance;
|
||||
|
||||
/**
|
||||
* @namespace i18n
|
||||
*/
|
||||
export default {
|
||||
|
||||
setLocales (preferred_locale, _converse) {
|
||||
@ -120,23 +119,23 @@ export default {
|
||||
if (_.isNil(jed_instance)) {
|
||||
return Jed.sprintf.apply(Jed, arguments);
|
||||
}
|
||||
var t = jed_instance.translate(str);
|
||||
if (arguments.length>1) {
|
||||
const t = jed_instance.translate(str);
|
||||
if (arguments.length > 1) {
|
||||
return t.fetch.apply(t, [].slice.call(arguments, 1));
|
||||
} else {
|
||||
return t.fetch();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the translations for the given local at the given URL.
|
||||
* @private
|
||||
* @method i18n#fetchTranslations
|
||||
* @param { String } locale -The given i18n locale
|
||||
* @param { Array } supported_locales - List of locales supported
|
||||
* @param { String } locale_url - The URL from which the translations should be fetched
|
||||
*/
|
||||
fetchTranslations (locale, supported_locales, locale_url) {
|
||||
/* Fetch the translations for the given local at the given URL.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) locale: The given i18n locale
|
||||
* (Array) supported_locales: List of locales supported
|
||||
* (String) locale_url: The URL from which the translations
|
||||
* should be fetched.
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!isConverseLocale(locale, supported_locales) || locale === 'en') {
|
||||
return resolve();
|
||||
|
@ -14,6 +14,11 @@ import { Strophe } from "strophe.js";
|
||||
import _ from "../lodash.noconflict";
|
||||
import sizzle from "sizzle";
|
||||
|
||||
|
||||
/**
|
||||
* The utils object
|
||||
* @namespace u
|
||||
*/
|
||||
const u = {};
|
||||
|
||||
u.toStanza = function (string) {
|
||||
@ -147,14 +152,15 @@ u.applyUserSettings = function applyUserSettings (context, settings, user_settin
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an HTML string into a DOM Node.
|
||||
* Expects that the HTML string has only one top-level element,
|
||||
* i.e. not multiple ones.
|
||||
* @private
|
||||
* @method u#stringToNode
|
||||
* @param { String } s - The HTML string
|
||||
*/
|
||||
u.stringToNode = function (s) {
|
||||
/* Converts an HTML string into a DOM Node.
|
||||
* Expects that the HTML string has only one top-level element,
|
||||
* i.e. not multiple ones.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) s - The HTML string
|
||||
*/
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = s;
|
||||
return div.firstElementChild;
|
||||
@ -170,26 +176,28 @@ u.getOuterWidth = function (el, include_margin=false) {
|
||||
return width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts an HTML string into a DOM element.
|
||||
* Expects that the HTML string has only one top-level element,
|
||||
* i.e. not multiple ones.
|
||||
* @private
|
||||
* @method u#stringToElement
|
||||
* @param { String } s - The HTML string
|
||||
*/
|
||||
u.stringToElement = function (s) {
|
||||
/* Converts an HTML string into a DOM element.
|
||||
* Expects that the HTML string has only one top-level element,
|
||||
* i.e. not multiple ones.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) s - The HTML string
|
||||
*/
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = s;
|
||||
return div.firstElementChild;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the DOM element matches the given selector.
|
||||
* @private
|
||||
* @method u#matchesSelector
|
||||
* @param { DOMElement } el - The DOM element
|
||||
* @param { String } selector - The selector
|
||||
*/
|
||||
u.matchesSelector = function (el, selector) {
|
||||
/* Checks whether the DOM element matches the given selector.
|
||||
*
|
||||
* Parameters:
|
||||
* (DOMElement) el - The DOM element
|
||||
* (String) selector - The selector
|
||||
*/
|
||||
const match = (
|
||||
el.matches ||
|
||||
el.matchesSelector ||
|
||||
@ -201,15 +209,14 @@ u.matchesSelector = function (el, selector) {
|
||||
return match ? match.call(el, selector) : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a list of children of the DOM element that match the selector.
|
||||
* @private
|
||||
* @method u#queryChildren
|
||||
* @param { DOMElement } el - the DOM element
|
||||
* @param { String } selector - the selector they should be matched against
|
||||
*/
|
||||
u.queryChildren = function (el, selector) {
|
||||
/* Returns a list of children of the DOM element that match the
|
||||
* selector.
|
||||
*
|
||||
* Parameters:
|
||||
* (DOMElement) el - the DOM element
|
||||
* (String) selector - the selector they should be matched
|
||||
* against.
|
||||
*/
|
||||
return _.filter(el.childNodes, _.partial(u.matchesSelector, _, selector));
|
||||
};
|
||||
|
||||
@ -296,16 +303,17 @@ u.interpolate = function (string, o) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Call the callback once all the events have been triggered
|
||||
* @private
|
||||
* @method u#onMultipleEvents
|
||||
* @param { Array } events: An array of objects, with keys `object` and
|
||||
* `event`, representing the event name and the object it's
|
||||
* triggered upon.
|
||||
* @param { Function } callback: The function to call once all events have
|
||||
* been triggered.
|
||||
*/
|
||||
u.onMultipleEvents = function (events=[], callback) {
|
||||
/* Call the callback once all the events have been triggered
|
||||
*
|
||||
* Parameters:
|
||||
* (Array) events: An array of objects, with keys `object` and
|
||||
* `event`, representing the event name and the object it's
|
||||
* triggered upon.
|
||||
* (Function) callback: The function to call once all events have
|
||||
* been triggered.
|
||||
*/
|
||||
let triggered = [];
|
||||
|
||||
function handler (result) {
|
||||
|
@ -10,12 +10,13 @@ import _ from "../lodash.noconflict";
|
||||
import tpl_field from "../templates/field.html";
|
||||
import u from "./core";
|
||||
|
||||
/**
|
||||
* Takes an HTML DOM and turns it into an XForm field.
|
||||
* @private
|
||||
* @method u#webForm2xForm
|
||||
* @param { DOMElement } field - the field to convert
|
||||
*/
|
||||
u.webForm2xForm = function (field) {
|
||||
/* Takes an HTML DOM and turns it into an XForm field.
|
||||
*
|
||||
* Parameters:
|
||||
* (DOMElement) field - the field to convert
|
||||
*/
|
||||
let value;
|
||||
if (field.getAttribute('type') === 'checkbox') {
|
||||
value = field.checked && 1 || 0;
|
||||
|
@ -15,33 +15,34 @@ import u from "./core";
|
||||
const { Strophe, sizzle, _ } = converse.env;
|
||||
|
||||
|
||||
/**
|
||||
* Given two lists of objects with 'jid', 'affiliation' and
|
||||
* 'reason' properties, return a new list containing
|
||||
* those objects that are new, changed or removed
|
||||
* (depending on the 'remove_absentees' boolean).
|
||||
*
|
||||
* The affiliations for new and changed members stay the
|
||||
* same, for removed members, the affiliation is set to 'none'.
|
||||
*
|
||||
* The 'reason' property is not taken into account when
|
||||
* comparing whether affiliations have been changed.
|
||||
* @private
|
||||
* @method u#computeAffiliationsDelta
|
||||
* @param { boolean } exclude_existing - Indicates whether JIDs from
|
||||
* the new list which are also in the old list
|
||||
* (regardless of affiliation) should be excluded
|
||||
* from the delta. One reason to do this
|
||||
* would be when you want to add a JID only if it
|
||||
* doesn't have *any* existing affiliation at all.
|
||||
* @param { boolean } remove_absentees - Indicates whether JIDs
|
||||
* from the old list which are not in the new list
|
||||
* should be considered removed and therefore be
|
||||
* included in the delta with affiliation set
|
||||
* to 'none'.
|
||||
* @param { array } new_list - Array containing the new affiliations
|
||||
* @param { array } old_list - Array containing the old affiliations
|
||||
*/
|
||||
u.computeAffiliationsDelta = function computeAffiliationsDelta (exclude_existing, remove_absentees, new_list, old_list) {
|
||||
/* Given two lists of objects with 'jid', 'affiliation' and
|
||||
* 'reason' properties, return a new list containing
|
||||
* those objects that are new, changed or removed
|
||||
* (depending on the 'remove_absentees' boolean).
|
||||
*
|
||||
* The affiliations for new and changed members stay the
|
||||
* same, for removed members, the affiliation is set to 'none'.
|
||||
*
|
||||
* The 'reason' property is not taken into account when
|
||||
* comparing whether affiliations have been changed.
|
||||
*
|
||||
* Parameters:
|
||||
* (Boolean) exclude_existing: Indicates whether JIDs from
|
||||
* the new list which are also in the old list
|
||||
* (regardless of affiliation) should be excluded
|
||||
* from the delta. One reason to do this
|
||||
* would be when you want to add a JID only if it
|
||||
* doesn't have *any* existing affiliation at all.
|
||||
* (Boolean) remove_absentees: Indicates whether JIDs
|
||||
* from the old list which are not in the new list
|
||||
* should be considered removed and therefore be
|
||||
* included in the delta with affiliation set
|
||||
* to 'none'.
|
||||
* (Array) new_list: Array containing the new affiliations
|
||||
* (Array) old_list: Array containing the old affiliations
|
||||
*/
|
||||
const new_jids = _.map(new_list, 'jid');
|
||||
const old_jids = _.map(old_list, 'jid');
|
||||
|
||||
|
@ -304,13 +304,14 @@ u.nextUntil = function (el, selector, include_self=false) {
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that replace HTML-escaped symbols with equivalent characters
|
||||
* (e.g. transform occurrences of '&' to '&')
|
||||
* @private
|
||||
* @method u#unescapeHTML
|
||||
* @param { String } string - a String containing the HTML-escaped symbols.
|
||||
*/
|
||||
u.unescapeHTML = function (string) {
|
||||
/* Helper method that replace HTML-escaped symbols with equivalent characters
|
||||
* (e.g. transform occurrences of '&' to '&')
|
||||
*
|
||||
* Parameters:
|
||||
* (String) string: a String containing the HTML-escaped symbols.
|
||||
*/
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = string;
|
||||
return div.innerText;
|
||||
@ -381,13 +382,14 @@ u.slideToggleElement = function (el, duration) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shows/expands an element by sliding it out of itself
|
||||
* @private
|
||||
* @method u#slideOut
|
||||
* @param { HTMLElement } el - The HTML string
|
||||
* @param { Number } duration - The duration amount in milliseconds
|
||||
*/
|
||||
u.slideOut = function (el, duration=200) {
|
||||
/* Shows/expands an element by sliding it out of itself
|
||||
*
|
||||
* Parameters:
|
||||
* (HTMLElement) el - The HTML string
|
||||
* (Number) duration - The duration amount in milliseconds
|
||||
*/
|
||||
return new Promise((resolve, reject) => {
|
||||
if (_.isNil(el)) {
|
||||
const err = "Undefined or null element passed into slideOut"
|
||||
@ -528,16 +530,15 @@ u.fadeIn = function (el, callback) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Takes a field in XMPP XForm (XEP-004: Data Forms) format
|
||||
* and turns it into an HTML field.
|
||||
* Returns either text or a DOM element (which is not ideal, but fine for now).
|
||||
* @private
|
||||
* @method u#xForm2webForm
|
||||
* @param { XMLElement } field - the field to convert
|
||||
*/
|
||||
u.xForm2webForm = function (field, stanza, domain) {
|
||||
/* Takes a field in XMPP XForm (XEP-004: Data Forms) format
|
||||
* and turns it into an HTML field.
|
||||
*
|
||||
* Returns either text or a DOM element (which is not ideal, but fine
|
||||
* for now).
|
||||
*
|
||||
* Parameters:
|
||||
* (XMLElement) field - the field to convert
|
||||
*/
|
||||
if (field.getAttribute('type') === 'list-single' ||
|
||||
field.getAttribute('type') === 'list-multi') {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user