Convert older docstrings to JSDoc syntax

This commit is contained in:
JC Brand 2019-03-29 23:47:56 +01:00
parent 7ed99092f5
commit a45bd8d14b
20 changed files with 1918 additions and 1734 deletions

View File

@ -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

1115
dist/converse.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,5 @@ to fix a bug or to add new functionality.
plugin_development
api/index
testing
events
other_frameworks
builds

View File

@ -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.

View File

@ -586,18 +586,18 @@ converse.plugins.add('converse-chatview', {
);
},
insertDayIndicator (next_msg_el) {
/* Inserts an indicator into the chat area, showing the
/**
* 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
* @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) {
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', {
}
},
getLastMessageDate (cutoff) {
/* Return the ISO8601 format date of the latest message.
*
* Parameters:
* (Object) cutoff: Moment Date cutoff date. The last
/**
* 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) {
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);
},
insertMessage (view) {
/* Given a view representing a message, insert it into the
/**
* Given a view representing a message, insert it into the
* content area of the chat box.
*
* Parameters:
* (Backbone.View) message: The message Backbone.View
* @private
* @method _converse.ChatBoxView#insertMessage
* @param { Backbone.View } message - The message Backbone.View
*/
insertMessage (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,8 +748,8 @@ converse.plugins.add('converse-chatview', {
return this.trigger('messageInserted', view.el);
},
markFollowups (el) {
/* Given a message element, determine wether it should be
/**
* 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
@ -757,9 +759,11 @@ converse.plugins.add('converse-chatview', {
* author with no other conversation elements inbetween and
* posted within 10 minutes of one another.
*
* Parameters:
* (HTMLElement) el - The message element.
* @private
* @method _converse.ChatBoxView#markFollowups
* @param { HTMLElement } el - The message element
*/
markFollowups (el) {
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', {
}
},
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
/**
* 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) {
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', {
}
},
onMessageAdded (message) {
/* Handler that gets called when a new message object is created.
*
* Parameters:
* (Object) message - The message Backbone object that was added.
/**
* 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) {
this.showMessage(message);
if (message.get('correcting')) {
this.insertIntoTextArea(message.get('message'), true, true);
@ -865,17 +869,18 @@ converse.plugins.add('converse-chatview', {
}
},
setChatState (state, options) {
/* Mutator for setting the chat state of this chat session.
/**
* 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)
* @private
* @method _converse.ChatBoxView#setChatState
* @param { string } state - The chat state (consts ACTIVE, COMPOSING, PAUSED, INACTIVE, GONE)
*/
setChatState (state, options) {
if (!_.isUndefined(this.chat_state_timeout)) {
window.clearTimeout(this.chat_state_timeout);
delete this.chat_state_timeout;

View File

@ -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;
}
});

View File

@ -203,15 +203,12 @@ converse.plugins.add('converse-muc-views', {
};
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.
* @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) {
// 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));
},
onPresence (pres) {
/* Handles all MUC presence stanzas.
*
* Parameters:
* (XMLElement) pres: The stanza
/**
* Handles all MUC presence stanzas.
* @private
* @method _converse.ChatRoomView#onPresence
* @param { XMLElement } pres - The stanza
*/
onPresence (pres) {
// 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 (nick, password) {
/* Join the groupchat.
*
* Parameters:
* (String) nick: The user's nickname
* (String) password: Optional password, if required by
* the groupchat.
/**
* 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) {
if (!nick && !this.model.get('nick')) {
this.checkForReservedNick();
return this;
@ -1154,17 +1152,16 @@ converse.plugins.add('converse-muc-views', {
return this;
},
renderConfigurationForm (stanza) {
/* Renders a form given an IQ stanza containing the current
/**
* 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.
* @private
* @method _converse.ChatRoomView#renderConfigurationForm
* @param { XMLElement } stanza: The IQ stanza containing the groupchat config.
*/
renderConfigurationForm (stanza) {
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);
},
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.
/**
* @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) {
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();
},
showStatusMessages (stanza) {
/* Check for status codes and communicate their purpose to the user.
/**
* 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.
* @private
* @method _converse.ChatRoomView#showStatusMessages
* @param { XMLElement } stanza - The message or presence stanza containing the status codes
*/
showStatusMessages (stanza) {
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);

View File

@ -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;
},
onRegistrationFields (stanza) {
/* Handler for Registration Fields Request.
*
* Parameters:
* (XMLElement) elem - The query stanza.
/**
* Handler for {@link _converse.RegisterPanel#getRegistrationFields}
* @private
* @method _converse.RegisterPanel#onRegistrationFields
* @param { XMLElement } stanza - The query stanza.
*/
onRegistrationFields (stanza) {
if (stanza.getAttribute("type") === "error") {
_converse.connection._changeConnectStatus(
Strophe.Status.REGIFAIL,
@ -309,13 +316,13 @@ converse.plugins.add('converse-register', {
},
onProviderChosen (form) {
/* Callback method that gets called when the user has chosen an
* XMPP provider.
*
* Parameters:
* (HTMLElement) form - The form that was submitted
/**
* 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) {
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());
},
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
/**
* Fetch a registration form from the requested domain
* @private
* @method _converse.RegisterPanel#fetchRegistrationForm
* @param { String } domain_name - XMPP server domain
*/
fetchRegistrationForm (domain_name) {
if (!this.model.get('registration_form_rendered')) {
this.renderRegistrationRequest();
}
@ -386,16 +393,14 @@ converse.plugins.add('converse-register', {
return this;
},
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
/**
* 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) {
_converse.log('converse-register: onConnectStatusChanged');
if (_.includes([
Strophe.Status.DISCONNECTED,
@ -472,13 +477,14 @@ converse.plugins.add('converse-register', {
});
},
renderRegistrationForm (stanza) {
/* Renders the registration form based on the XForm fields
/**
* 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.
* @private
* @method _converse.RegisterPanel#renderRegistrationForm
* @param { XMLElement } stanza - The IQ stanza received from the XMPP server.
*/
renderRegistrationForm (stanza) {
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');
},
reportErrors (stanza) {
/* Report back to the user any error messages received from the
/**
* 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.
* @private
* @method _converse.RegisterPanel#reportErrors
* @param { XMLElement } stanza - The IQ stanza received from the XMPP server
*/
reportErrors (stanza) {
const errors = stanza.querySelectorAll('error');
_.each(errors, (error) => {
this.showValidationError(error.textContent);
@ -568,14 +574,14 @@ converse.plugins.add('converse-register', {
}
},
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
/**
* 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) {
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());
},
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.
/* 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) {
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';
},
_onRegisterIQ (stanza) {
/* Callback method that gets called when a return IQ 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.
* @private
* @method _converse.RegisterPanel#reportErrors
* @param { XMLElement } stanza - The IQ stanza.
*/
_onRegisterIQ (stanza) {
if (stanza.getAttribute("type") === "error") {
_converse.log("Registration failed.", Strophe.LogLevel.ERROR);
this.reportErrors(stanza);

View File

@ -442,13 +442,13 @@ converse.plugins.add('converse-chatboxes', {
return false;
},
createMessageStanza (message) {
/* Given a _converse.Message Backbone.Model, return the XML
* stanza that represents it.
*
* Parameters:
* (Object) message - The Backbone.Model representing the message
/**
* 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) {
const stanza = $msg({
'from': _converse.connection.jid,
'to': this.get('jid'),
@ -630,13 +630,14 @@ converse.plugins.add('converse-chatboxes', {
});
},
getStanzaIDs (stanza) {
/* Extract the XEP-0359 stanza IDs from the passed in stanza
/**
* Extract the XEP-0359 stanza IDs from the passed in stanza
* and return a map containing them.
*
* Parameters:
* (XMLElement) stanza - The message stanza
* @private
* @method _converse.ChatBox#getStanzaIDs
* @param { XMLElement } stanza - The message stanza
*/
getStanzaIDs (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());
},
getMessageAttributesFromStanza (stanza, original_stanza) {
/* Parses a passed in message stanza and returns an object
/**
* 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.
* @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) {
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', {
}
},
async onMessage (stanza) {
/* Handler method for all incoming single-user chat "message"
* stanzas.
*
* Parameters:
* (XMLElement) stanza - The incoming message stanza
/**
* 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) {
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});
},
getChatBox (jid, attrs={}, create) {
/* Returns a chat box or optionally return a newly
/**
* 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.
* @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) {
if (_.isObject(jid)) {
create = attrs;
attrs = jid;

View File

@ -225,20 +225,19 @@ _converse.default_settings = {
};
_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.
*
/**
* 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='') {
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); };
_converse.__ = function (str) {
/* Translate the given string based on the current locale.
*
* Parameters:
* (String) str - The string to translate.
/**
* 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) {
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()}`;
this.sendCSI = function (stat) {
/* Send out a Chat Status Notification (XEP-0352)
*
* Parameters:
* (String) stat: The user's chat status
/**
* 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) {
_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) {
});
};
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
/**
* 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) {
const pres = $pres({to: jid, type: "unsubscribed"});
if (message && message !== "") { pres.c("status").t(message); }
_converse.api.send(pres);

View File

@ -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();
},
async getIdentity (category, type) {
/* Returns a Promise which resolves with a map indicating
/**
* 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
* @private
* @method _converse.DiscoEntity#getIdentity
* @param { String } category - The identity category
* @param { String } type - The identity type
*/
async getIdentity (category, type) {
await this.waitUntilFeaturesDiscovered;
return this.identities.findWhere({
'category': category,
@ -79,13 +85,14 @@ converse.plugins.add('converse-disco', {
});
},
async hasFeature (feature) {
/* Returns a Promise which resolves with a map indicating
/**
* Returns a Promise which resolves with a map indicating
* whether a given feature is supported.
*
* Parameters:
* (String) feature - The feature that might be supported.
* @private
* @method _converse.DiscoEntity#hasFeature
* @param { String } feature - The feature that might be supported.
*/
async hasFeature (feature) {
await this.waitUntilFeaturesDiscovered
if (this.features.findWhere({'var': feature})) {
return this;

View File

@ -291,14 +291,14 @@ converse.plugins.add('converse-muc', {
return this.get('name') || this.get('jid');
},
join (nick, password) {
/* Join the groupchat.
*
* Parameters:
* (String) nick: The user's nickname
* (String) password: Optional password, if required by
* the groupchat.
/**
* 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) {
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 (exit_msg) {
/* Leave the groupchat.
*
* Parameters:
* (String) exit_msg: Optional message to indicate your
* reason for leaving.
* @private
* @method _converse.ChatRoom#leave
* @param { string } exit_msg - Optional message to indicate your reason for leaving
*/
leave (exit_msg) {
this.features.destroy();
this.occupants.browserStorage._clear();
this.occupants.reset();
@ -479,12 +478,14 @@ converse.plugins.add('converse-muc', {
);
},
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
/**
* 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) {
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);
},
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
* @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.
* @returns:
* A promise which resolves once the list has been retrieved.
*/
requestMemberList (affiliation) {
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);
},
setAffiliation (affiliation, members) {
/* Send IQ stanzas to the server to set an affiliation for
/**
* 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
* 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
* @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.
* 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) {
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);
},
saveConfiguration (form) {
/* Submit the groupchat configuration form by sending an IQ
/**
* 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.
* @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) {
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', {
);
},
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
/**
* 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.
* (Function) errback: Callback upon error IQ response
* @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) {
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);
},
saveAffiliationAndRole (pres) {
/* Parse the presence stanza for the current user's
* affiliation.
*
* Parameters:
* (XMLElement) pres: A <presence> stanza.
/**
* Parse the presence stanza for the current user's affiliation.
* @private
* @method _converse.ChatRoom#saveAffiliationAndRole
* @param { XMLElement } pres - A <presence> stanza.
*/
saveAffiliationAndRole (pres) {
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', {
}
},
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
/**
* 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) {
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);
},
setAffiliations (members) {
/* Send IQ stanzas to the server to modify the
/**
* 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
* @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) {
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);
},
updateMemberLists (members, affiliations, deltaFunc) {
/* Fetch the lists of users with the given affiliations.
/**
* 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
* @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.
* (Function) deltaFunc: The function to compute the delta
* @param { function } deltaFunc - The function to compute the delta
* between old and new member lists.
*
* Returns:
* @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) {
this.getJidsWithAffiliations(affiliations)
.then(old_members => this.setAffiliations(deltaFunc(members, old_members)))
.then(() => this.occupants.fetchMembers())
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
},
async checkForReservedNick () {
/* Use service-discovery to ask the XMPP server whether
/**
* 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
* @private
* @method _converse.ChatRoom#checkForReservedNick
* @returns { promise } A promise which resolves with the response IQ
*/
async checkForReservedNick () {
const iq = await _converse.api.sendIQ(
$iq({
'to': this.get('jid'),
@ -887,13 +886,14 @@ converse.plugins.add('converse-muc', {
}
},
updateOccupantsOnPresence (pres) {
/* Given a presence stanza, update the occupant model
/**
* Given a presence stanza, update the occupant model
* based on its contents.
*
* Parameters:
* (XMLElement) pres: The presence stanza
* @private
* @method _converse.ChatRoom#updateOccupantsOnPresence
* @param { XMLElement } pres - The presence stanza
*/
updateOccupantsOnPresence (pres) {
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;
},
subjectChangeHandled (attrs) {
/* Handle a subject change and return `true` if so.
*
* Parameters:
* (Object) attrs: The message attributes
/**
* Handle a subject change and return `true` if so.
* @private
* @method _converse.ChatRoom#subjectChangeHandled
* @param { object } attrs - The message attributes
*/
subjectChangeHandled (attrs) {
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;
},
ignorableCSN (attrs) {
/* Is this a chat state notification that can be ignored,
/**
* 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
* @private
* @method _converse.ChatRoom#ignorableCSN
* @param { Object } attrs - The message attributes
*/
ignorableCSN (attrs) {
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;
},
async onMessage (stanza) {
/* Handler for all MUC messages sent to this groupchat.
*
* Parameters:
* (XMLElement) stanza: The message stanza.
/**
* Handler for all MUC messages sent to this groupchat.
* @private
* @method _converse.ChatRoom#onMessage
* @param { XMLElement } stanza - The message stanza.
*/
async onMessage (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});
},
onPresence (pres) {
/* Handles all MUC presence stanzas.
*
* Parameters:
* (XMLElement) pres: The stanza
/**
* Handles all MUC presence stanzas.
* @private
* @method _converse.ChatRoom#onPresence
* @param { XMLElement } pres - The stanza
*/
onPresence (pres) {
if (pres.getAttribute('type') === 'error') {
this.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
return;
@ -1096,9 +1100,8 @@ converse.plugins.add('converse-muc', {
}
},
onOwnPresence (pres) {
/* Handles a received presence relating to the current
* user.
/**
* 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
@ -1108,10 +1111,11 @@ converse.plugins.add('converse-muc', {
* 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
* @private
* @method _converse.ChatRoom#onOwnPresence
* @param { XMLElement } pres - The stanza
*/
onOwnPresence (pres) {
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);
},
isUserMentioned (message) {
/* Returns a boolean to indicate whether the current user
/**
* Returns a boolean to indicate whether the current user
* was mentioned in a message.
*
* Parameters:
* (String): The text message
* @private
* @method _converse.ChatRoom#isUserMentioned
* @param { String } - The text message
*/
isUserMentioned (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', {
}
},
incrementUnreadMsgCounter (message) {
/* Given a newly received message, update the unread counter if
* necessary.
*
* Parameters:
* (XMLElement): The <messsage> stanza
/* Given a newly received message, update the unread counter if necessary.
* @private
* @method _converse.ChatRoom#incrementUnreadMsgCounter
* @param { XMLElement } - The <messsage> stanza
*/
incrementUnreadMsgCounter (message) {
if (!message) { return; }
const body = message.get('message');
if (_.isNil(body)) { return; }
@ -1311,14 +1315,14 @@ converse.plugins.add('converse-muc', {
});
_converse.onDirectMUCInvitation = function (message) {
/* A direct MUC invitation to join a groupchat has been received
/**
* 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.
* @private
* @method _converse.ChatRoom#onDirectMUCInvitation
* @param { XMLElement } message - The message stanza containing the invitation.
*/
_converse.onDirectMUCInvitation = function (message) {
const x_el = sizzle('x[xmlns="jabber:x:conference"]', message).pop(),
from = Strophe.getBareJidFromJid(message.getAttribute('from')),
room_jid = x_el.getAttribute('jid'),

View File

@ -45,10 +45,13 @@ converse.plugins.add('converse-roster', {
};
_converse.initRoster = function () {
/* Initialize the Bakcbone collections that represent the contats
/**
* Initialize the Bakcbone collections that represent the contats
* roster and the roster groups.
* @private
* @method _converse.initRoster
*/
_converse.initRoster = function () {
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', {
};
_converse.populateRoster = async function (ignore_cache=false) {
/* Fetch all the roster groups, and then the roster contacts.
/**
* 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
* @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) {
if (ignore_cache) {
_converse.send_initial_presence = true;
try {
@ -272,13 +276,14 @@ converse.plugins.add('converse-roster', {
return this.vcard.get('fullname');
},
subscribe (message) {
/* Send a presence subscription request to this roster contact
*
* Parameters:
* (String) message - An optional message to explain the
/**
* 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) {
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;
},
ackSubscribe () {
/* Upon receiving the presence stanza of type "subscribed",
/**
* 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 () {
_converse.api.send($pres({
'type': 'subscribe',
'to': this.get('jid')
}));
},
ackUnsubscribe () {
/* Upon receiving the presence stanza of type "unsubscribed",
/**
* 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
* @private
* @method _converse.RosterContacts#ackUnsubscribe
* @param { String } jid - The Jabber ID of the user who is unsubscribing
*/
ackUnsubscribe () {
_converse.api.send($pres({'type': 'unsubscribe', 'to': this.get('jid')}));
this.removeFromRoster();
this.destroy();
},
unauthorize (message) {
/* Unauthorize this contact's presence subscription
* Parameters:
* (String) message - Optional message to send to the person being unauthorized
/**
* 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) {
_converse.rejectPresenceSubscription(this.get('jid'), message);
return this;
},
authorize (message) {
/* Authorize presence subscription
* Parameters:
* (String) message - Optional message to send to the person being authorized
/**
* Authorize presence subscription
* @private
* @method _converse.RosterContacts#authorize
* @param { String } message - Optional message to send to the person being authorized
*/
authorize (message) {
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;
},
removeFromRoster () {
/* Instruct the XMPP server to remove this contact from our roster
* Parameters:
* (Function) callback
/**
* Instruct the XMPP server to remove this contact from our roster
* @private
* @method _converse.RosterContacts#
* @returns { Promise }
*/
removeFromRoster () {
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);
},
addAndSubscribe (jid, name, groups, message, attributes) {
/* Add a roster contact and then once we have confirmation from
/**
* 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.
* @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) {
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);
},
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
/**
* 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) {
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);
},
async addContactToRoster (jid, name, groups, attributes) {
/* Adds a RosterContact instance to _converse.roster and
/**
* 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.
* 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) {
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'))));
},
onRosterPush (iq) {
/* Handle roster updates from the XMPP server.
/**
* 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.
* @private
* @method _converse.RosterContacts#onRosterPush
* @param { XMLElement } IQ - The IQ stanza received from the XMPP server.
*/
onRosterPush (iq) {
const id = iq.getAttribute('id');
const from = iq.getAttribute('from');
if (from && from !== _converse.bare_jid) {

View File

@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -44,9 +44,7 @@ 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
* @param { Function } library_check - Returns a boolean indicating whether
* the locale is supported.
*/
var locale, i;
@ -87,13 +85,11 @@ function getLocale (preferred_locale, isSupportedByLibrary) {
return detectLocale(isSupportedByLibrary) || 'en';
}
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
* @param { String } locale - The locale to check for
* @param { Function } available - Returns a boolean indicating whether the locale is supported
*/
function isLocaleAvailable (locale, available) {
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,7 +119,7 @@ export default {
if (_.isNil(jed_instance)) {
return Jed.sprintf.apply(Jed, arguments);
}
var t = jed_instance.translate(str);
const t = jed_instance.translate(str);
if (arguments.length > 1) {
return t.fetch.apply(t, [].slice.call(arguments, 1));
} else {
@ -128,15 +127,15 @@ export default {
}
},
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.
/**
* 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) {
return new Promise((resolve, reject) => {
if (!isConverseLocale(locale, supported_locales) || locale === 'en') {
return resolve();

View File

@ -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
}
};
u.stringToNode = function (s) {
/* Converts an HTML string into a DOM Node.
/**
* 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
* @private
* @method u#stringToNode
* @param { String } s - The HTML string
*/
u.stringToNode = function (s) {
var div = document.createElement('div');
div.innerHTML = s;
return div.firstElementChild;
@ -170,26 +176,28 @@ u.getOuterWidth = function (el, include_margin=false) {
return width;
};
u.stringToElement = function (s) {
/* Converts an HTML string into a DOM element.
/**
* 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
* @private
* @method u#stringToElement
* @param { String } s - The HTML string
*/
u.stringToElement = function (s) {
var div = document.createElement('div');
div.innerHTML = s;
return div.firstElementChild;
};
u.matchesSelector = function (el, selector) {
/* Checks whether the DOM element matches the given selector.
*
* Parameters:
* (DOMElement) el - The DOM element
* (String) selector - The selector
/**
* 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) {
const match = (
el.matches ||
el.matchesSelector ||
@ -201,15 +209,14 @@ u.matchesSelector = function (el, selector) {
return match ? match.call(el, selector) : false;
};
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.
/**
* 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) {
return _.filter(el.childNodes, _.partial(u.matchesSelector, _, selector));
};
@ -296,16 +303,17 @@ u.interpolate = function (string, o) {
});
};
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
/**
* 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.
* (Function) callback: The function to call once all events have
* @param { Function } callback: The function to call once all events have
* been triggered.
*/
u.onMultipleEvents = function (events=[], callback) {
let triggered = [];
function handler (result) {

View File

@ -10,12 +10,13 @@ import _ from "../lodash.noconflict";
import tpl_field from "../templates/field.html";
import u from "./core";
u.webForm2xForm = function (field) {
/* Takes an HTML DOM and turns it into an XForm field.
*
* Parameters:
* (DOMElement) field - the field to convert
/**
* 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) {
let value;
if (field.getAttribute('type') === 'checkbox') {
value = field.checked && 1 || 0;

View File

@ -15,8 +15,8 @@ import u from "./core";
const { Strophe, sizzle, _ } = converse.env;
u.computeAffiliationsDelta = function computeAffiliationsDelta (exclude_existing, remove_absentees, new_list, old_list) {
/* Given two lists of objects with 'jid', 'affiliation' and
/**
* 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).
@ -26,22 +26,23 @@ u.computeAffiliationsDelta = function computeAffiliationsDelta (exclude_existing
*
* The 'reason' property is not taken into account when
* comparing whether affiliations have been changed.
*
* Parameters:
* (Boolean) exclude_existing: Indicates whether JIDs from
* @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.
* (Boolean) remove_absentees: Indicates whether JIDs
* @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'.
* (Array) new_list: Array containing the new affiliations
* (Array) old_list: Array containing the old affiliations
* @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) {
const new_jids = _.map(new_list, 'jid');
const old_jids = _.map(old_list, 'jid');

View File

@ -304,13 +304,14 @@ u.nextUntil = function (el, selector, include_self=false) {
return matches;
}
u.unescapeHTML = function (string) {
/* Helper method that replace HTML-escaped symbols with equivalent characters
/**
* Helper method that replace HTML-escaped symbols with equivalent characters
* (e.g. transform occurrences of '&amp;' to '&')
*
* Parameters:
* (String) string: a String containing the HTML-escaped symbols.
* @private
* @method u#unescapeHTML
* @param { String } string - a String containing the HTML-escaped symbols.
*/
u.unescapeHTML = function (string) {
var div = document.createElement('div');
div.innerHTML = string;
return div.innerText;
@ -381,13 +382,14 @@ u.slideToggleElement = function (el, duration) {
};
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
/**
* 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) {
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) {
};
u.xForm2webForm = function (field, stanza, domain) {
/* Takes a field in XMPP XForm (XEP-004: Data Forms) format
/**
* 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
* 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) {
if (field.getAttribute('type') === 'list-single' ||
field.getAttribute('type') === 'list-multi') {