浏览代码

More JSDoc docstrings for API methods

JC Brand 6 年之前
父节点
当前提交
866f2737da

文件差异内容过多而无法显示
+ 583 - 115
dist/converse.js


+ 12 - 18
docs/source/developer_api.rst

@@ -303,7 +303,6 @@ room under the  ``with`` key.
 
 .. code-block:: javascript
 
-
     converse.plugins.add('myplugin', {
         initialize: function () {
 
@@ -541,24 +540,19 @@ Returns a `Promise` which, when resolved, returns a map/object with keys
     converse.plugins.add('myplugin', {
         initialize: function () {
 
-            _converse.api.disco.supports(Strophe.NS.MAM, _converse.bare_jid).then(
-                function (value) {
-                    // `value` is a map with two keys, `supported` and `feature`.
-
-                    if (value.supported) {
-                        // The feature is supported
-                    } else {
-                        // The feature is not supported
-                    }
-                },
-                function () { // Error
-                    _converse.log(
-                        "Error or timeout while checking for feature support",
-                        Strophe.LogLevel.ERROR
-                    );
+            _converse.api.disco.supports(Strophe.NS.MAM, _converse.bare_jid)
+            .then(value => {
+                // `value` is a map with two keys, `supported` and `feature`.
+                if (value.supported) {
+                    // The feature is supported
+                } else {
+                    // The feature is not supported
                 }
-            ).catch((msg) => {
-                _converse.log(msg, Strophe.LogLevel.FATAL);
+            }).catch(() => {
+                _converse.log(
+                    "Error or timeout while checking for feature support",
+                    Strophe.LogLevel.ERROR
+                );
             });
         }
     });

+ 8 - 22
docs/source/jsdoc_intro.md

@@ -23,29 +23,15 @@ closured object.
 
 ## API Namespaces
 
-The Converse API is often broken up into different logical "namespaces" (for
-example `converse.plugins` or `converse.contacts`).
+The Converse API (private and public) makes use of namespaces to logically
+group relevant methods.
 
-There are some exceptions to this, like `converse.initialize`, which aren't
-namespaces but single 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}.
 
-The namespaces logically group methods, such as standardised accessors and
-mutators:
+Which means that you access it via `_converse.api.disco`.
 
-* .get
-* .set
-* .add
-* .remove
-
-So for example, to get a contact, you would do the following:
-
-    _converse.api.contacts.get('jid@example.com');
-
-To get multiple contacts, just pass in an array of jids:
-
-    _converse.api.contacts.get(['jid1@example.com', 'jid2@example.com']);
-
-To get all contacts, simply call ``get`` without any jids:
-
-    _converse.api.contacts.get();
+Namespaces can be nested. So the {@link \_converse.api.disco} namespace
+namespace has {@link \_converse.api.disco.own} as a nested namespace.
 
+Not all methods are however within a namespace. For example {@link converse.initialize}.

+ 3 - 2
spec/disco.js

@@ -164,8 +164,9 @@
                                     'name': 'Music from the time of Shakespeare'
                                 });
                             _converse.connection._dataRecv(test_utils.createRequest(stanza));
-
-                            entities = _converse.disco_entities;
+                            return test_utils.waitUntil(() => _converse.disco_entities);
+                        }).then(() => {
+                            const entities = _converse.disco_entities;
                             expect(entities.length).toBe(2); // We have an extra entity, which is the user's JID
                             expect(entities.get(_converse.domain).items.length).toBe(3);
                             expect(_.includes(entities.get(_converse.domain).items.pluck('jid'), 'people.shakespeare.lit')).toBeTruthy();

+ 5 - 5
spec/presence.js

@@ -47,7 +47,7 @@
                 "<presence xmlns='jabber:client'>"+
                     "<status>Hello world</status>"+
                     "<priority>0</priority>"+
-                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='ggltNSI5YG/7dFKB57Bk2dRYRU0='/>"+
+                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='K7kn/M6VtmdMyo61pgn/jkZlax8='/>"+
                 "</presence>"
             );
             _converse.priority = 2;
@@ -57,7 +57,7 @@
                     "<show>away</show>"+
                     "<status>Going jogging</status>"+
                     "<priority>2</priority>"+
-                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='ggltNSI5YG/7dFKB57Bk2dRYRU0='/>"+
+                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='K7kn/M6VtmdMyo61pgn/jkZlax8='/>"+
                 "</presence>"
             );
 
@@ -68,7 +68,7 @@
                     "<show>dnd</show>"+
                     "<status>Doing taxes</status>"+
                     "<priority>0</priority>"+
-                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='ggltNSI5YG/7dFKB57Bk2dRYRU0='/>"+
+                    "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='K7kn/M6VtmdMyo61pgn/jkZlax8='/>"+
                 "</presence>"
             );
         }));
@@ -97,7 +97,7 @@
                     .toBe("<presence xmlns='jabber:client'>"+
                           "<status>My custom status</status>"+
                           "<priority>0</priority>"+
-                          "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='ggltNSI5YG/7dFKB57Bk2dRYRU0='/>"+
+                          "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='K7kn/M6VtmdMyo61pgn/jkZlax8='/>"+
                           "</presence>")
 
                 return test_utils.waitUntil(function () {
@@ -113,7 +113,7 @@
                 modal.el.querySelector('[type="submit"]').click();
                 expect(_converse.connection.send.calls.mostRecent().args[0].toLocaleString())
                     .toBe("<presence xmlns='jabber:client'><show>dnd</show><status>My custom status</status><priority>0</priority>"+
-                          "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='ggltNSI5YG/7dFKB57Bk2dRYRU0='/>"+
+                          "<c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='https://conversejs.org' ver='K7kn/M6VtmdMyo61pgn/jkZlax8='/>"+
                           "</presence>")
                 done();
             });

+ 10 - 6
src/converse-chatboxes.js

@@ -906,11 +906,17 @@
             /************************ BEGIN API ************************/
             _.extend(_converse.api, {
                 /**
-                 * The "chats" grouping (used for one-on-one chats)
+                 * The "chats" namespace (used for one-on-one chats)
                  *
-                 * @namespace
+                 * @namespace _converse.api.chats
+                 * @memberOf _converse.api
                  */
                 'chats': {
+                    /**
+                     * @method _converse.api.chats.create
+                     * @param {string|string[]} jid|jids An jid or array of jids
+                     * @param {object} attrs An object containing configuration attributes.
+                     */
                     'create' (jids, attrs) {
                         if (_.isUndefined(jids)) {
                             _converse.log(
@@ -939,8 +945,7 @@
                     /**
                      * Opens a new one-on-one chat.
                      *
-                     * @function
-                     *
+                     * @method _converse.api.chats.open
                      * @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
                      * @returns {Promise} Promise which resolves with the Backbone.Model representing the chat.
                      *
@@ -991,8 +996,7 @@
                     /**
                      * Returns a chat model. The chat should already be open.
                      *
-                     * @function
-                     *
+                     * @method _converse.api.chats.get
                      * @param {String|string[]} name - e.g. 'buddy@example.com' or ['buddy1@example.com', 'buddy2@example.com']
                      * @returns {Backbone.Model}
                      *

+ 22 - 0
src/converse-chatview.js

@@ -1275,7 +1275,29 @@
 
             /************************ BEGIN API ************************/
             _.extend(_converse.api, {
+                /**
+                 * The "chatview" namespace groups methods pertaining to views
+                 * for one-on-one chats.
+                 *
+                 * @namespace _converse.api.chatviews
+                 * @memberOf _converse.api
+                 */
                 'chatviews': {
+                     /**
+                      * Get the view of an already open chat.
+                      *
+                      * @method _converse.api.chatviews.get
+                      * @returns {ChatBoxView} A [Backbone.View](http://backbonejs.org/#View) instance.
+                      *     The chat should already be open, otherwise `undefined` will be returned.
+                      * 
+                      * @example
+                      * // To return a single view, provide the JID of the contact:
+                      * _converse.api.chatviews.get('buddy@example.com')
+                      * 
+                      * @example
+                      * // To return an array of views, provide an array of JIDs:
+                      * _converse.api.chatviews.get(['buddy1@example.com', 'buddy2@example.com'])
+                      */
                     'get' (jids) {
                         if (_.isUndefined(jids)) {
                             _converse.log(

+ 43 - 38
src/converse-core.js

@@ -59,9 +59,8 @@
     };
 
     /** 
-     * A private, closured object containing the private api (via
-     * `_converse.api`) as well as private methods and internal
-     * data-structures.
+     * A private, closured object containing the private api (via `_converse.api`)
+     * as well as private methods and internal data-structures.
      *
      * @namespace _converse
      */
@@ -1234,7 +1233,7 @@
     /** 
      * ### The private API
      *
-     * The private API methods are only accessible via the closured `_converse`
+     * The private API methods are only accessible via the closured {@link _converse}
      * object, which is only available to plugins.
      * 
      * These methods are kept private (i.e. not global) because they may return
@@ -1273,10 +1272,10 @@
 
         /**
          * Lets you emit (i.e. trigger) events, which can be listened to via
-         * `_converse.api.listen.on` or `_converse.api.listen.once`
+         * {@link _converse.api.listen.on} or {@link _converse.api.listen.once}
          * (see [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)).
          *
-         * @method _converse.api.connection.emit
+         * @method _converse.api.emit
          */
         'emit' () {
             _converse.emit.apply(_converse, arguments);
@@ -1395,7 +1394,9 @@
         },
 
         /**
-         * This grouping allows access to the configuration settings of Converse.
+         * This grouping allows access to the
+         * [configuration settings](/docs/html/configuration.html#configuration-settings)
+         * of Converse.
          *
          * @namespace _converse.api.settings
          * @memberOf _converse.api
@@ -1436,7 +1437,7 @@
             /**
              * Set one or many configuration settings.
              *
-             * Note, this is not an alternative to calling `converse.initialize`, which still needs
+             * Note, this is not an alternative to calling {@link converse.initialize}, which still needs
              * to be called. Generally, you'd use this method after Converse is already
              * running and you want to change the configuration on-the-fly.
              *
@@ -1464,8 +1465,7 @@
 
         /**
          * Converse and its plugins emit various events which you can listen to via the
-         * [_converse.api.listen](http://localhost:8000/docs/html/api/-_converse.api.listen.html)
-         * namespace.
+         * {@link _converse.api.listen} namespace.
          * 
          * Some of these events are also available as [ES2015 Promises](http://es6-features.org/#PromiseUsage)
          * although not all of them could logically act as promises, since some events
@@ -1494,14 +1494,14 @@
             /**
              * By calling `promises.add`, a new [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
              * is made available for other code or plugins to depend on via the
-             * `_converse.api.waitUntil` method.
+             * {@link _converse.api.waitUntil} method.
              * 
              * Generally, it's the responsibility of the plugin which adds the promise to
              * also resolve it.
              * 
-             * This is done by calling `_converse.api.emit`, which not only resolves the
+             * This is done by calling {@link _converse.api.emit}, which not only resolves the
              * promise, but also emits an event with the same name (which can be listened to
-             * via `_converse.api.listen`).
+             * via {@link _converse.api.listen}).
              * 
              * @method _converse.api.promises.add
              * @param {string|array} [name|names] The name or an array of names for the promise(s) to be added
@@ -1550,7 +1550,7 @@
         'listen': {
             /**
              * Lets you listen to an event exactly once.
-
+             *
              * @method _converse.api.listen.once
              * @param {string} name The event's name
              * @param {function} callback The callback method to be called when the event is emitted.
@@ -1563,7 +1563,7 @@
              * Lets you subscribe to an event.
              *
              * Every time the event fires, the callback method specified by `callback` will be called.
-
+             *
              * @method _converse.api.listen.on
              * @param {string} name The event's name
              * @param {function} callback The callback method to be called when the event is emitted.
@@ -1573,10 +1573,10 @@
             'on': _converse.on.bind(_converse),
 
             /**
-             * To stop listening to an event, you can use the ``not`` method.
+             * To stop listening to an event, you can use the `not` method.
              *
              * Every time the event fires, the callback method specified by `callback` will be called.
-
+             *
              * @method _converse.api.listen.not
              * @param {string} name The event's name
              * @param {function} callback The callback method that is to no longer be called when the event fires
@@ -1588,7 +1588,7 @@
              * Subscribe to an incoming stanza
              *
              * Every a matched stanza is received, the callback method specified by `callback` will be called.
-
+             *
              * @method _converse.api.listen.stanza
              * @param {string} name The stanza's name
              * @param {object} options Matching options
@@ -1619,6 +1619,7 @@
          *
          * @method _converse.api.waitUntil
          * @param {string} name The name of the promise
+         * @returns {Promise}
          */
         'waitUntil' (name) {
             const promise = _converse.promises[name];
@@ -1627,14 +1628,23 @@
             }
             return promise;
         },
+
         /**
-         * Send a stanza
-         *
+         * Allows you to send XML stanzas.
+         * 
          * @method _converse.api.send
+         * @example
+         * const msg = converse.env.$msg({
+         *     'from': 'juliet@example.com/balcony',
+         *     'to': 'romeo@example.net',
+         *     'type':'chat'
+         * });
+         * _converse.api.send(msg);
          */
         'send' (stanza) {
             _converse.connection.send(stanza);
         },
+
         /**
          * Send an IQ stanza and receive a promise
          *
@@ -1649,33 +1659,28 @@
         }
     };
 
-    /** 
-     * The Public API
-     * @namespace window
-     */
-
     /**
+     * ### The Public API
+     *
      * This namespace contains public API methods which are are
-     * accessible on the global window.converse object.
+     * accessible on the global `converse` object.
      * They are public, because any JavaScript in the
      * page can call them. Public methods therefore don’t expose any sensitive
      * or closured data. To do that, you’ll need to create a plugin, which has
      * access to the private API method.
      *
-     * @namespace window.converse
-     * @memberOf window
+     * @namespace converse
      */
-    window.converse = {
+    const converse = {
         /**
          * Public API method which initializes Converse.
          * This method must always be called when using Converse. 
          *
-         * @memberOf window.converse
+         * @memberOf converse
          * @method initialize
          * @param {object} config A map of [configuration-settings](https://conversejs.org/docs/html/configuration.html#configuration-settings).
          *
          * @example
-         *
          * converse.initialize({
          *     allow_otr: true,
          *     auto_list_rooms: false,
@@ -1698,16 +1703,15 @@
          * Exposes methods for adding and removing plugins. You'll need to write a plugin
          * if you want to have access to the private API methods defined further down below.
          * 
-         * For more information on plugins, read the section :ref:`writing-a-plugin`.
+         * For more information on plugins, read the documentation on [writing a plugin](/docs/html/plugin_development.html).
          *
-         * @property {object} window.converse
-         * @memberOf window.converse
+         * @namespace plugins
+         * @memberOf converse
          */
         'plugins': {
             /** Registers a new plugin.
              * 
-             * @memberOf window.converse.plugins
-             * @method add
+             * @method converse.plugins.add
              * @param {string} name The name of the plugin
              * @param {object} plugin The plugin object
              *
@@ -1740,7 +1744,7 @@
         },
         /**
          * Utility methods and globals from bundled 3rd party libraries.
-         * @memberOf window.converse
+         * @memberOf converse
          *
          * @property {function} converse.env.$build    - Creates a Strophe.Builder, for creating stanza objects.
          * @property {function} converse.env.$iq       - Creates a Strophe.Builder with an <iq/> element as the root.
@@ -1772,6 +1776,7 @@
             'utils': u
         }
     };
+    window.converse = converse;
     window.dispatchEvent(new CustomEvent('converse-loaded'));
-    return window.converse;
+    return converse;
 }));

+ 156 - 87
src/converse-disco.js

@@ -1,10 +1,10 @@
 // Converse.js
 // http://conversejs.org
 //
-// Copyright (c) 2013-2018, the Converse.js developers
+// Copyright (c) 2013-2018, the Converse developers
 // Licensed under the Mozilla Public License (MPLv2)
 
-/* This is a Converse.js plugin which add support for XEP-0030: Service Discovery */
+/* This is a Converse plugin which add support for XEP-0030: Service Discovery */
 
 (function (root, factory) {
     define(["converse-core", "sizzle"], factory);
@@ -116,7 +116,7 @@
                         this.features.fetch({
                             add: true,
                             success: () => {
-                                this.waitUntilFeaturesDiscovered.resolve();
+                                this.waitUntilFeaturesDiscovered.resolve(this);
                                 this.trigger('featuresDiscovered');
                             }
                         });
@@ -127,8 +127,8 @@
                 queryInfo () {
                     _converse.api.disco.info(this.get('jid'), null)
                         .then((stanza) => this.onInfo(stanza))
-                        .catch((iq) => {
-                            this.waitUntilFeaturesDiscovered.resolve();
+                        .catch(iq => {
+                            this.waitUntilFeaturesDiscovered.resolve(this);
                             _converse.log(iq, Strophe.LogLevel.ERROR);
                         });
                 },
@@ -158,7 +158,7 @@
                         // server or a conference component.
                         return;
                     }
-                    _converse.api.disco.items(this.get('jid'), null, this.onDiscoItems.bind(this));
+                    _converse.api.disco.items(this.get('jid')).then(stanza => this.onDiscoItems(stanza));
                 },
 
                 onInfo (stanza) {
@@ -190,7 +190,7 @@
                             'from': stanza.getAttribute('from')
                         });
                     });
-                    this.waitUntilFeaturesDiscovered.resolve();
+                    this.waitUntilFeaturesDiscovered.resolve(this);
                     this.trigger('featuresDiscovered');
                 }
             });
@@ -213,7 +213,7 @@
 
             function addClientFeatures () {
                 // See http://xmpp.org/registrar/disco-categories.html
-                _converse.api.disco.own.identities.add('client', 'web', 'Converse.js');
+                _converse.api.disco.own.identities.add('client', 'web', 'Converse');
 
                 _converse.api.disco.own.features.add(Strophe.NS.BOSH);
                 _converse.api.disco.own.features.add(Strophe.NS.CHATSTATES);
@@ -317,14 +317,29 @@
                 return true;
             }
 
-            /* We extend the default converse.js API to add methods specific to service discovery */
+
             _.extend(_converse.api, {
                 /**
-                 * The service discovery API
-                 * @namespace
+                 * The XEP-0030 service discovery API
+                 *
+                 * This API lets you discover information about entities on the
+                 * XMPP network.
+                 *
+                 * @namespace _converse.api.disco
+                 * @memberOf _converse.api
                  */
                 'disco': {
+                    /**
+                     * @namespace _converse.api.disco.stream
+                     * @memberOf _converse.api.disco
+                     */
                     'stream': {
+                        /**
+                         * @method _converse.api.disco.stream.getFeature
+                         * @param {String} name The feature name
+                         * @param {String} xmlns The XML namespace
+                         * @example _converse.api.disco.stream.getFeature('ver', 'urn:xmpp:features:rosterver')
+                         */
                         'getFeature': function (name, xmlns) {
                             if (_.isNil(name) || _.isNil(xmlns)) {
                                 throw new Error("name and xmlns need to be provided when calling disco.stream.getFeature");
@@ -334,26 +349,25 @@
                     },
 
                     /**
-                     * The "own" grouping
-                     * @namespace
+                     * @namespace _converse.api.disco.own
+                     * @memberOf _converse.api.disco
                      */
                     'own': {
                         /**
-                         * The "identities" grouping
-                         * @namespace
+                         * @namespace _converse.api.disco.own.identities
+                         * @memberOf _converse.api.disco.own
                          */
                         'identities': {
                             /**
-                             * Lets you add new identities for this client (i.e. instance of Converse.js)
-                             * @function
+                             * Lets you add new identities for this client (i.e. instance of Converse)
+                             * @method _converse.api.disco.own.identities.add
                              *
                              * @param {String} category - server, client, gateway, directory, etc.
                              * @param {String} type - phone, pc, web, etc.
-                             * @param {String} name - "Converse.js"
+                             * @param {String} name - "Converse"
                              * @param {String} lang - en, el, de, etc.
                              *
-                             * @example
-                             * _converse.api.disco.own.identities.clear();
+                             * @example _converse.api.disco.own.identities.clear();
                              */
                             add (category, type, name, lang) {
                                 for (var i=0; i<plugin._identities.length; i++) {
@@ -368,39 +382,33 @@
                             },
                             /**
                              * Clears all previously registered identities.
-                             * @function
-                             *
-                             * @example
-                             * _converse.api.disco.own.identities.clear();
+                             * @method _converse.api.disco.own.identities.clear
+                             * @example _converse.api.disco.own.identities.clear();
                              */
                             clear () {
                                 plugin._identities = []
                             },
                             /**
                              * Returns all of the identities registered for this client
-                             * (i.e. instance of Converse.js).
-                             * @function
-                             *
-                             * @example
-                             * const identities = _converse.api.disco.own.identities.get();
+                             * (i.e. instance of Converse).
+                             * @method _converse.api.disco.identities.get
+                             * @example const identities = _converse.api.disco.own.identities.get();
                              */
                             get () {
                                 return plugin._identities;
                             }
                         },
+
                         /**
-                         * The "features" grouping
-                         * @namespace
+                         * @namespace _converse.api.disco.own.features
+                         * @memberOf _converse.api.disco.own
                          */
                         'features': {
                             /**
-                             * Lets you register new disco features for this client (i.e. instance of Converse.js)
-                             * @function
-                             *
+                             * Lets you register new disco features for this client (i.e. instance of Converse)
+                             * @method _converse.api.disco.own.features.add
                              * @param {String} name - e.g. http://jabber.org/protocol/caps
-                             *
-                             * @example
-                             * _converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
+                             * @example _converse.api.disco.own.features.add("http://jabber.org/protocol/caps");
                              */
                             add (name) {
                                 for (var i=0; i<plugin._features.length; i++) {
@@ -410,21 +418,16 @@
                             },
                             /**
                              * Clears all previously registered features.
-                             * @function
-                             *
-                             * @example
-                             * _converse.api.disco.own.features.clear();
+                             * @method _converse.api.disco.own.features.clear
+                             * @example _converse.api.disco.own.features.clear();
                              */
                             clear () {
                                 plugin._features = []
                             },
                             /**
-                             * Returns all of the features registered for this client
-                             * (i.e. instance of Converse.js).
-                             * @function
-                             *
-                             * @example
-                             * const features = _converse.api.disco.own.features.get();
+                             * Returns all of the features registered for this client (i.e. instance of Converse).
+                             * @method _converse.api.disco.own.features.get
+                             * @example const features = _converse.api.disco.own.features.get();
                              */
                             get () {
                                 return plugin._features;
@@ -432,6 +435,14 @@
                         }
                     },
 
+                    /**
+                     * Query for information about an XMPP entity
+                     *
+                     * @method _converse.api.disco.info
+                     * @param {string} jid The Jabber ID of the entity to query
+                     * @param {string} [node] A specific node identifier associated with the JID
+                     * @returns {promise} Promise which resolves once we have a result from the server.
+                     */
                     'info' (jid, node) {
                         const attrs = {xmlns: Strophe.NS.DISCO_INFO};
                         if (node) {
@@ -445,48 +456,90 @@
                         return _converse.api.sendIQ(info);
                     },
 
-                    'items' (jid, node, callback, errback, timeout) {
+                    /**
+                     * Query for items associated with an XMPP entity
+                     *
+                     * @method _converse.api.disco.items
+                     * @param {string} jid The Jabber ID of the entity to query for items
+                     * @param {string} [node] A specific node identifier associated with the JID
+                     * @returns {promise} Promise which resolves once we have a result from the server.
+                     */
+                    'items' (jid, node) {
                         const attrs = {'xmlns': Strophe.NS.DISCO_ITEMS};
                         if (node) {
                             attrs.node = node;
                         }
-                        const items = $iq({
-                            'from': _converse.connection.jid,
-                            'to':jid,
-                            'type':'get'
-                        }).c('query', attrs);
-                        _converse.connection.sendIQ(items, callback, errback, timeout);
+                        return _converse.api.sendIQ(
+                            $iq({
+                                'from': _converse.connection.jid,
+                                'to':jid,
+                                'type':'get'
+                            }).c('query', attrs)
+                        );
                     },
 
+                    /**
+                     * Namespace for methods associated with disco entities
+                     *
+                     * @namespace _converse.api.disco.entities
+                     * @memberOf _converse.api.disco
+                     */
                     'entities': {
-                        'get' (entity_jid, create=false) {
-                            return _converse.api.waitUntil('discoInitialized').then(() => {
-                                if (_.isNil(entity_jid)) {
+                        /**
+                         * Get the the corresponding `DiscoEntity` instance.
+                         * 
+                         * @method _converse.api.disco.entities.get
+                         * @param {string} jid The Jabber ID of the entity
+                         * @param {boolean} [create] Whether the entity should be created if it doesn't exist.
+                         * @example _converse.api.disco.entities.get(jid);
+                         */
+                        'get' (jid, create=false) {
+                            return _converse.api.waitUntil('discoInitialized')
+                            .then(() => {
+                                if (_.isNil(jid)) {
                                     return _converse.disco_entities;
                                 }
-                                const entity = _converse.disco_entities.get(entity_jid);
+                                const entity = _converse.disco_entities.get(jid);
                                 if (entity || !create) {
                                     return entity;
                                 }
-                                return _converse.disco_entities.create({'jid': entity_jid});
+                                return _converse.disco_entities.create({'jid': jid});
                             });
                         }
                     },
 
+                     /**
+                      * Used to determine whether an entity supports a given feature.
+                      *
+                      * @method _converse.api.disco.supports
+                      * @param {string} feature The feature that might be
+                      *     supported. In the XML stanza, this is the `var`
+                      *     attribute of the `<feature>` element. For
+                      *     example: `http://jabber.org/protocol/muc`
+                      * @param {string} jid The JID of the entity
+                      *     (and its associated items) which should be queried
+                      * @returns {promise} A promise which resolves with a list containing
+                      *     _converse.Entity instances representing the entity
+                      *     itself or those items associated with the entity if
+                      *     they support the given feature.
+                      *
+                      * @example
+                      * _converse.api.disco.supports(Strophe.NS.MAM, _converse.bare_jid)
+                      * .then(value => {
+                      *     // `value` is a map with two keys, `supported` and `feature`.
+                      *     if (value.supported) {
+                      *         // The feature is supported
+                      *     } else {
+                      *         // The feature is not supported
+                      *     }
+                      * }).catch(() => {
+                      *     _converse.log(
+                      *         "Error or timeout while checking for feature support",
+                      *         Strophe.LogLevel.ERROR
+                      *     );
+                      * });
+                      */
                     'supports' (feature, jid) {
-                        /* Returns a Promise which resolves with a list containing
-                         * _converse.Entity instances representing the entity
-                         * itself or those items associated with the entity if
-                         * they support the given feature.
-                         *
-                         * Parameters:
-                         *    (String) feature - The feature that might be
-                         *         supported. In the XML stanza, this is the `var`
-                         *         attribute of the `<feature>` element. For
-                         *         example: 'http://jabber.org/protocol/muc'
-                         *    (String) jid - The JID of the entity
-                         *         (and its associated items) which should be queried
-                         */
                         if (_.isNil(jid)) {
                             throw new TypeError('disco.supports: You need to provide an entity JID');
                         }
@@ -502,22 +555,38 @@
                         }).then(result => f.filter(f.isObject, result));
                     },
 
+                    /**
+                     * Get the identity (with the given category and type) for a given disco entity.
+                     *
+                     * For example, when determining support for PEP (personal eventing protocol), you
+                     * want to know whether the user's own JID has an identity with
+                     * `category='pubsub'` and `type='pep'` as explained in this section of
+                     * XEP-0163: https://xmpp.org/extensions/xep-0163.html#support
+                     * 
+                     * @method _converse.api.disco.getIdentity
+                     * @param {string} The identity category.
+                     *     In the XML stanza, this is the `category`
+                     *     attribute of the `<identity>` element.
+                     *     For example: 'pubsub'
+                     * @param {string} type The identity type.
+                     *     In the XML stanza, this is the `type`
+                     *     attribute of the `<identity>` element.
+                     *     For example: 'pep'
+                     * @param {string} jid The JID of the entity which might have the identity
+                     * @returns {promise} A promise which resolves with a map indicating
+                     *     whether an identity with a given type is provided by the entity.
+                     * @example
+                     * _converse.api.disco.getIdentity('pubsub', 'pep', _converse.bare_jid).then(
+                     *     function (identity) {
+                     *         if (_.isNil(identity)) {
+                     *             // The entity DOES NOT have this identity
+                     *         } else {
+                     *             // The entity DOES have this identity
+                     *         }
+                     *     }
+                     * ).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
+                     */
                     'getIdentity' (category, type, jid) {
-                        /* Returns a Promise which resolves with a map indicating
-                         * whether an identity with a given type is provided by
-                         * the entity.
-                         *
-                         * Parameters:
-                         *    (String) category - The identity category.
-                         *          In the XML stanza, this is the `category`
-                         *          attribute of the `<identity>` element.
-                         *          For example: 'pubsub'
-                         *    (String) type - The identity type.
-                         *          In the XML stanza, this is the `type`
-                         *          attribute of the `<identity>` element.
-                         *          For example: 'pep'
-                         *    (String) jid - The JID of the entity which might have the identity
-                         */
                         return _converse.api.disco.entities.get(jid, true).then(e => e.getIdentity(category, type));
                     }
                 }

+ 167 - 19
src/converse-mam.js

@@ -407,28 +407,176 @@
             });
 
             _.extend(_converse.api, {
-                /* Extend default converse.js API to add methods specific to MAM
+                /**
+                 * The [XEP-0313](https://xmpp.org/extensions/xep-0313.html) Message Archive Management API
+                 *
+                 * Enables you to query an XMPP server for archived messages.
+                 *
+                 * See also the [message-archiving](/docs/html/configuration.html#message-archiving)
+                 * option in the configuration settings section, which you'll
+                 * usually want to use in conjunction with this API.
+                 *
+                 * @namespace _converse.api.archive
+                 * @memberOf _converse.api
                  */
                 'archive': {
+                     /**
+                      * Query for archived messages.
+                      *
+                      * The options parameter can also be an instance of
+                      * Strophe.RSM to enable easy querying between results pages.
+                      *
+                      * @method _converse.api.archive.query
+                      * @param {(Object|Strophe.RSM)} options Query parameters, either
+                      *      MAM-specific or also for Result Set Management.
+                      *      Can be either an object or an instance of Strophe.RSM.
+                      *      Valid query parameters are:
+                      * * `with`
+                      * * `start`
+                      * * `end`
+                      * * `first`
+                      * * `last`
+                      * * `after`
+                      * * `before`
+                      * * `index`
+                      * * `count`
+                      * @param {Function} callback A function to call whenever
+                      *      we receive query-relevant stanza.
+                      *      When the callback is called, a Strophe.RSM object is
+                      *      returned on which "next" or "previous" can be called
+                      *      before passing it in again to this method, to
+                      *      get the next or previous page in the result set.
+                      * @param {Function} errback A function to call when an
+                      *      error stanza is received, for example when it
+                      *      doesn't support message archiving.
+                      *
+                      * @example
+                      * // Requesting all archived messages
+                      * // ================================
+                      * //
+                      * // The simplest query that can be made is to simply not pass in any parameters.
+                      * // Such a query will return all archived messages for the current user.
+                      * //
+                      * // Generally, you'll however always want to pass in a callback method, to receive
+                      * // the returned messages.
+                      *
+                      * this._converse.api.archive.query(
+                      *     (messages) => {
+                      *         // Do something with the messages, like showing them in your webpage.
+                      *     },
+                      *     (iq) => {
+                      *         // The query was not successful, perhaps inform the user?
+                      *         // The IQ stanza returned by the XMPP server is passed in, so that you
+                      *         // may inspect it and determine what the problem was.
+                      *     }
+                      * )
+                      * @example
+                      * // Waiting until server support has been determined
+                      * // ================================================
+                      * //
+                      * // The query method will only work if Converse has been able to determine that
+                      * // the server supports MAM queries, otherwise the following error will be raised:
+                      * //
+                      * // "This server does not support XEP-0313, Message Archive Management"
+                      * //
+                      * // The very first time Converse loads in a browser tab, if you call the query
+                      * // API too quickly, the above error might appear because service discovery has not
+                      * // yet been completed.
+                      * //
+                      * // To work solve this problem, you can first listen for the `serviceDiscovered` event,
+                      * // through which you can be informed once support for MAM has been determined.
+                      *
+                      *  _converse.api.listen.on('serviceDiscovered', function (feature) {
+                      *      if (feature.get('var') === converse.env.Strophe.NS.MAM) {
+                      *          _converse.api.archive.query()
+                      *      }
+                      *  });
+                      *
+                      * @example
+                      * // Requesting all archived messages for a particular contact or room
+                      * // =================================================================
+                      * //
+                      * // To query for messages sent between the current user and another user or room,
+                      * // the query options need to contain the the JID (Jabber ID) of the user or
+                      * // room under the  `with` key.
+                      *
+                      * // For a particular user
+                      * this._converse.api.archive.query({'with': 'john@doe.net'}, callback, errback);)
+                      *
+                      * // For a particular room
+                      * this._converse.api.archive.query({'with': 'discuss@conference.doglovers.net'}, callback, errback);)
+                      *
+                      * @example
+                      * // Requesting all archived messages before or after a certain date
+                      * // ===============================================================
+                      * //
+                      * // The `start` and `end` parameters are used to query for messages
+                      * // within a certain timeframe. The passed in date values may either be ISO8601
+                      * // formatted date strings, or JavaScript Date objects.
+                      *
+                      *  const options = {
+                      *      'with': 'john@doe.net',
+                      *      'start': '2010-06-07T00:00:00Z',
+                      *      'end': '2010-07-07T13:23:54Z'
+                      *  };
+                      *  this._converse.api.archive.query(options, callback, errback);
+                      *
+                      * @example
+                      * // Limiting the amount of messages returned
+                      * // ========================================
+                      * //
+                      * // The amount of returned messages may be limited with the `max` parameter.
+                      * // By default, the messages are returned from oldest to newest.
+                      *
+                      * // Return maximum 10 archived messages
+                      * this._converse.api.archive.query({'with': 'john@doe.net', 'max':10}, callback, errback);
+                      *
+                      * @example
+                      * // Paging forwards through a set of archived messages
+                      * // ==================================================
+                      * //
+                      * // When limiting the amount of messages returned per query, you might want to
+                      * // repeatedly make a further query to fetch the next batch of messages.
+                      * //
+                      * // To simplify this usecase for you, the callback method receives not only an array
+                      * // with the returned archived messages, but also a special RSM (*Result Set
+                      * // Management*) object which contains the query parameters you passed in, as well
+                      * // as two utility methods `next`, and `previous`.
+                      * //
+                      * // When you call one of these utility methods on the returned RSM object, and then
+                      * // pass the result into a new query, you'll receive the next or previous batch of
+                      * // archived messages. Please note, when calling these methods, pass in an integer
+                      * // to limit your results.
+                      *
+                      * const callback = function (messages, rsm) {
+                      *     // Do something with the messages, like showing them in your webpage.
+                      *     // ...
+                      *     // You can now use the returned "rsm" object, to fetch the next batch of messages:
+                      *     _converse.api.archive.query(rsm.next(10), callback, errback))
+                      *
+                      * }
+                      * _converse.api.archive.query({'with': 'john@doe.net', 'max':10}, callback, errback);
+                      *
+                      * @example
+                      * // Paging backwards through a set of archived messages
+                      * // ===================================================
+                      * //
+                      * // To page backwards through the archive, you need to know the UID of the message
+                      * // which you'd like to page backwards from and then pass that as value for the
+                      * // `before` parameter. If you simply want to page backwards from the most recent
+                      * // message, pass in the `before` parameter with an empty string value `''`.
+                      *
+                      * _converse.api.archive.query({'before': '', 'max':5}, function (message, rsm) {
+                      *     // Do something with the messages, like showing them in your webpage.
+                      *     // ...
+                      *     // You can now use the returned "rsm" object, to fetch the previous batch of messages:
+                      *     rsm.previous(5); // Call previous method, to update the object's parameters,
+                      *                      // passing in a limit value of 5.
+                      *     // Now we query again, to get the previous batch.
+                      *     _converse.api.archive.query(rsm, callback, errback);
+                      * }
+                      */
                     'query': function (options, callback, errback) {
-                        /* Do a MAM (XEP-0313) query for archived messages.
-                         *
-                         * Parameters:
-                         *    (Object) options - Query parameters, either
-                         *      MAM-specific or also for Result Set Management.
-                         *    (Function) callback - A function to call whenever
-                         *      we receive query-relevant stanza.
-                         *    (Function) errback - A function to call when an
-                         *      error stanza is received.
-                         *
-                         * The options parameter can also be an instance of
-                         * Strophe.RSM to enable easy querying between results pages.
-                         *
-                         * When the the callback is called, a Strophe.RSM object is
-                         * returned on which "next" or "previous" can be called
-                         * before passing it in again to this method, to
-                         * get the next or previous page in the result set.
-                         */
                         if (!_converse.api.connection.connected()) {
                             throw new Error('Can\'t call `api.archive.query` before having established an XMPP session');
                         }

+ 41 - 1
src/converse-muc-views.js

@@ -1951,7 +1951,6 @@
             }
 
             /************************ BEGIN Event Handlers ************************/
-
             _converse.on('chatBoxesInitialized', () => {
                 const that = _converse.chatboxviews;
                 _converse.chatboxes.on('add', item => {
@@ -1983,6 +1982,47 @@
             }
             _converse.on('reconnected', reconnectToChatRooms);
             /************************ END Event Handlers ************************/
+
+
+            /************************ BEGIN API ************************/
+            _.extend(_converse.api, {
+                /**
+                 * The "roomviews" namespace groups methods relevant to chatroom
+                 * (aka groupchats) views.
+                 *
+                 * @namespace _converse.api.roomviews
+                 * @memberOf _converse.api
+                 */
+                'roomviews': {
+                    /**
+                     * Lets you close open chatrooms.
+                     *
+                     * You can call this method without any arguments to close
+                     * all open chatrooms, or you can specify a single JID or
+                     * an array of JIDs.
+                     *
+                     * @method _converse.api.roomviews.close
+                     * @param {(String[]|String)} jids The JID or array of JIDs of the chatroom(s)
+                     */
+                    'close' (jids) {
+                        if (_.isUndefined(jids)) {
+                            _converse.chatboxviews.each(function (view) {
+                                if (view.is_chatroom && view.model) {
+                                    view.close();
+                                }
+                            });
+                        } else if (_.isString(jids)) {
+                            const view = _converse.chatboxviews.get(jids);
+                            if (view) { view.close(); }
+                        } else {
+                            _.each(jids, function (jid) {
+                                const view = _converse.chatboxviews.get(jid);
+                                if (view) { view.close(); }
+                            });
+                        }
+                    }
+                }
+            });
         }
     });
 }));

+ 98 - 20
src/converse-muc.js

@@ -423,7 +423,7 @@
                     const jid = Strophe.getBareJidFromJid(groupchat);
                     return jid + (nick !== null ? `/${nick}` : "");
                 },
-                
+
                 sendChatState () {
                     /* Sends a message with the status of the user in this chat session
                      * as taken from the 'chat_state' attribute of the chat box.
@@ -956,7 +956,7 @@
                         this.save('connection_status', converse.ROOMSTATUS.CONNECTED);
                     }
                 },
- 
+
                 onOwnPresence (pres) {
                     /* Handles a received presence relating to the current
                      * user.
@@ -1288,25 +1288,26 @@
             /************************ BEGIN API ************************/
             // We extend the default converse.js API to add methods specific to MUC groupchats.
             _.extend(_converse.api, {
+                /**
+                 * The "rooms" namespace groups methods relevant to chatrooms
+                 * (aka groupchats).
+                 *
+                 * @namespace _converse.api.rooms
+                 * @memberOf _converse.api
+                 */
                 'rooms': {
-                    'close' (jids) {
-                        if (_.isUndefined(jids)) {
-                            // FIXME: can't access views here
-                            _converse.chatboxviews.each(function (view) {
-                                if (view.is_chatroom && view.model) {
-                                    view.close();
-                                }
-                            });
-                        } else if (_.isString(jids)) {
-                            const view = _converse.chatboxviews.get(jids);
-                            if (view) { view.close(); }
-                        } else {
-                            _.each(jids, function (jid) {
-                                const view = _converse.chatboxviews.get(jid);
-                                if (view) { view.close(); }
-                            });
-                        }
-                    },
+                    /**
+                     * Creates a new MUC chatroom (aka groupchat)
+                     *
+                     * Similar to {@link _converse.api.rooms.open}, but creates
+                     * the chatroom in the background (i.e. doesn't cause a
+                     * view to open).
+                     *
+                     * @method _converse.api.rooms.create
+                     * @param {(string[]|string)} jid|jids The JID or array of
+                     *     JIDs of the chatroom(s) to create
+                     * @param {object} [attrs] attrs The room attributes
+                     */
                     'create' (jids, attrs) {
                         if (_.isString(attrs)) {
                             attrs = {'nick': attrs};
@@ -1327,6 +1328,60 @@
                         return _.map(jids, _.partial(createChatRoom, _, attrs));
                     },
 
+                    /**
+                     * Opens a MUC chatroom (aka groupchat)
+                     *
+                     * Similar to {@link _converse.api.chats.open}, but for groupchats.
+                     *
+                     * @method _converse.api.rooms.open
+                     * @param {string} jid The room JID or JIDs (if not specified, all
+                     *     currently open rooms will be returned).
+                     * @param {string} attrs A map  containing any extra room attributes.
+                     * @param {string} [attrs.nick] The current user's nickname for the MUC
+                     * @param {boolean} [attrs.auto_configure] A boolean, indicating
+                     *     whether the room should be configured automatically or not.
+                     *     If set to `true`, then it makes sense to pass in configuration settings.
+                     * @param {object} [attrs.roomconfig] A map of configuration settings to be used when the room gets
+                     *     configured automatically. Currently it doesn't make sense to specify
+                     *     `roomconfig` values if `auto_configure` is set to `false`.
+                     *     For a list of configuration values that can be passed in, refer to these values
+                     *     in the [XEP-0045 MUC specification](http://xmpp.org/extensions/xep-0045.html#registrar-formtype-owner).
+                     *     The values should be named without the `muc#roomconfig_` prefix.
+                     * @param {boolean} [attrs.maximize] A boolean, indicating whether minimized rooms should also be
+                     *     maximized, when opened. Set to `false` by default.
+                     * @param {boolean} [attrs.bring_to_foreground] A boolean indicating whether the room should be
+                     *     brought to the foreground and therefore replace the currently shown chat.
+                     *     If there is no chat currently open, then this option is ineffective.
+                     *
+                     * @example
+                     * this._converse.api.rooms.open('group@muc.example.com')
+                     *
+                     * @example
+                     * // To return an array of rooms, provide an array of room JIDs:
+                     * _converse.api.rooms.open(['group1@muc.example.com', 'group2@muc.example.com'])
+                     *
+                     * @example
+                     * // To setup a custom nickname when joining the room, provide the optional nick argument:
+                     * _converse.api.rooms.open('group@muc.example.com', {'nick': 'mycustomnick'})
+                     *
+                     * @example
+                     * // For example, opening a room with a specific default configuration:
+                     * _converse.api.rooms.open(
+                     *     'myroom@conference.example.org',
+                     *     { 'nick': 'coolguy69',
+                     *       'auto_configure': true,
+                     *       'roomconfig': {
+                     *           'changesubject': false,
+                     *           'membersonly': true,
+                     *           'persistentroom': true,
+                     *           'publicroom': true,
+                     *           'roomdesc': 'Comfy room for hanging out',
+                     *           'whois': 'anyone'
+                     *       }
+                     *     },
+                     *     true
+                     * );
+                     */
                     'open' (jids, attrs) {
                         return new Promise((resolve, reject) => {
                             _converse.api.waitUntil('chatBoxesFetched').then(() => {
@@ -1343,6 +1398,29 @@
                         });
                     },
 
+                    /**
+                     * Returns an object representing a MUC chatroom (aka groupchat)
+                     *
+                     * @method _converse.api.rooms.get
+                     * @param {string} [jid] The room JID (if not specified, all rooms will be returned).
+                     * @param {object} attrs A map containing any extra room attributes For example, if you want
+                     *     to specify the nickname, use `{'nick': 'bloodninja'}`. Previously (before
+                     *     version 1.0.7, the second parameter only accepted the nickname (as a string
+                     *     value). This is currently still accepted, but then you can't pass in any
+                     *     other room attributes. If the nickname is not specified then the node part of
+                     *     the user's JID will be used.
+                     * @param {boolean} create A boolean indicating whether the room should be created
+                     *     if not found (default: `false`)
+                     * @example
+                     * _converse.api.waitUntil('roomsAutoJoined').then(() => {
+                     *     const create_if_not_found = true;
+                     *     _converse.api.rooms.get(
+                     *         'group@muc.example.com',
+                     *         {'nick': 'dread-pirate-roberts'},
+                     *         create_if_not_found
+                     *     )
+                     * });
+                     */
                     'get' (jids, attrs, create) {
                         if (_.isString(attrs)) {
                             attrs = {'nick': attrs};

+ 1 - 1
src/converse-push.js

@@ -36,7 +36,7 @@
                 }
                 Promise.all([
                     _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)
-                ]).then((result) => {
+                ]).then(result => {
                     if (!result[0].length && !result[1].length) {
                         return _converse.log(
                             `Not disabling push app server "${push_app_server.jid}", no disco support from your server.`,

+ 48 - 0
src/converse-roster.js

@@ -864,7 +864,43 @@
             // API methods only available to plugins
 
             _.extend(_converse.api, {
+                /**
+                 * @namespace _converse.api.contacts
+                 * @memberOf _converse.api
+                 */
                 'contacts': {
+                    /**
+                     * This method is used to retrieve roster contacts.
+                     * 
+                     * @method _converse.api.contacts.get
+                     * @params {(string[]|string)} jid|jids The JID or JIDs of
+                     *      the contacts to be returned.
+                     * @returns {(RosterContact[]|RosterContact)} [Backbone.Model](http://backbonejs.org/#Model)
+                     *      (or an array of them) representing the contact.
+                     *
+                     * @example
+                     * // Fetch a single contact
+                     * _converse.api.listen.on('rosterContactsFetched', function () {
+                     *     const contact = _converse.api.contacts.get('buddy@example.com')
+                     *     // ...
+                     * });
+                     * 
+                     * @example
+                     * // To get multiple contacts, pass in an array of JIDs:
+                     * _converse.api.listen.on('rosterContactsFetched', function () {
+                     *     const contacts = _converse.api.contacts.get(
+                     *         ['buddy1@example.com', 'buddy2@example.com']
+                     *     )
+                     *     // ...
+                     * });
+                     * 
+                     * @example
+                     * // To return all contacts, simply call ``get`` without any parameters:
+                     * _converse.api.listen.on('rosterContactsFetched', function () {
+                     *     const contacts = _converse.api.contacts.get();
+                     *     // ...
+                     * });
+                     */
                     'get' (jids) {
                         const _getter = function (jid) {
                             return _converse.roster.get(Strophe.getBareJidFromJid(jid)) || null;
@@ -876,6 +912,18 @@
                         }
                         return _.map(jids, _getter);
                     },
+                    /**
+                     * Add a contact.
+                     * 
+                     * @method _converse.api.contacts.add
+                     * @param {string} jid The JID of the contact to be added
+                     * @param {string} [name] A custom name to show the user by
+                     *     in the roster.
+                     * @example
+                     *     _converse.api.contacts.add('buddy@example.com')
+                     * @example
+                     *     _converse.api.contacts.add('buddy@example.com', 'Buddy')
+                     */
                     'add' (jid, name) {
                         if (!_.isString(jid) || !_.includes(jid, '@')) {
                             throw new TypeError('contacts.add: invalid jid');

+ 64 - 5
src/converse-vcard.js

@@ -146,12 +146,57 @@
             });
 
             _.extend(_converse.api, {
+                /**
+                 * The XEP-0054 VCard API
+                 *
+                 * This API lets you access and update user VCards
+                 *
+                 * @namespace _converse.api.vcard
+                 * @memberOf _converse.api
+                 */
                 'vcard': {
+                    /**
+                     * Enables setting new values for a VCard.
+                     *
+                     * @method _converse.api.vcard.set
+                     * @param {string} jid The JID for which the VCard should be set
+                     * @param {object} data A map of VCard keys and values
+                     * @example
+                     * _converse.api.vcard.set({
+                     *     'jid': _converse.bare_jid,
+                     *     'fn': 'John Doe',
+                     *     'nickname': 'jdoe'
+                     * }).then(() => {
+                     *     // Succes
+                     * }).catch(() => {
+                     *     // Failure
+                     * }).
+                     */
                     'set' (jid, data) {
                         return setVCard(jid, data);
                     },
 
-                    'get' (model, force) {
+                    /**
+                     * @method _converse.api.vcard.get
+                     * @param {Backbone.Model|string} model Either a `Backbone.Model` instance, or a string JID.
+                     *     If a `Backbone.Model` instance is passed in, then it must have either a `jid`
+                     *     attribute or a `muc_jid` attribute.
+                     * @param {boolean} [force] A boolean indicating whether the vcard should be
+                     *     fetched even if it's been fetched before.
+                     * @returns {promise} A Promise which resolves with the VCard data for a particular JID or for
+                     *     a `Backbone.Model` instance which represents an entity with a JID (such as a roster contact,
+                     *     chat or chatroom occupant).
+                     *
+                     * @example
+                     * _converse.api.waitUntil('rosterContactsFetched').then(() => {
+                     *     _converse.api.vcard.get('someone@example.org').then(
+                     *         (vcard) => {
+                     *             // Do something with the vcard...
+                     *         }
+                     *     );
+                     * });
+                     */
+                     'get' (model, force) {
                         if (_.isString(model)) {
                             return getVCard(_converse, model);
                         } else if (force ||
@@ -168,14 +213,28 @@
                         }
                     },
 
+                    /**
+                     * Fetches the VCard associated with a particular `Backbone.Model` instance
+                     * (by using its `jid` or `muc_jid` attribute) and then updates the model with the
+                     * returned VCard data.
+                     *
+                     * @method _converse.api.vcard.update
+                     * @param {Backbone.Model} model A `Backbone.Model` instance
+                     * @param {boolean} [force] A boolean indicating whether the vcard should be
+                     *     fetched again even if it's been fetched before.
+                     * @returns {promise} A promise which resolves once the update has completed.
+                     * @example
+                     * _converse.api.waitUntil('rosterContactsFetched').then(() => {
+                     *     const chatbox = _converse.chatboxes.getChatBox('someone@example.org');
+                     *     _converse.api.vcard.update(chatbox);
+                     * });
+                     */
                     'update' (model, force) {
-                        return new Promise((resolve, reject) => {
-                            this.get(model, force).then((vcard) => {
+                        return this.get(model, force)
+                            .then(vcard => {
                                 delete vcard['stanza']
                                 model.save(vcard);
-                                resolve();
                             });
-                        });
                     }
                 }
             });

部分文件因为文件数量过多而无法显示