Bladeren bron

Move `updateSettings` to the private API.

Also add an API method for exposing new promises.

Update the plugin and API documentation, specifically concerning the above
changes.
JC Brand 8 jaren geleden
bovenliggende
commit
f81a94baf1

+ 21 - 7
CHANGES.md

@@ -2,23 +2,30 @@
 
 ## 3.1.0 (Unreleased)
 
-- Support for [XMPP-0313 Message Archive Management](https://xmpp.org/extensions/xep-0313.html)
-  has been upgraded to version 2. [jcbrand]
+### API changes
+- Deprecate the `updateSettings` method in favour of
+  `_converse.settings.update`. [jcbrand]
+- Add a new API method `_converse.promises.add` for exposing promises to be
+  used with `_converse.waitUntil`. [jcbrand]
+- The `message` event now returns a data object with `stanza` and
+  `chatbox` attributes, instead of just the stanza. [jcbrand]
+
+### New Plugins
 - New non-core plugin `converse-singleton` which ensures that no more than
   one chat is visible at any given time. Used in the mobile build:
   `converse-mobile.js` and makes the unread messages counter possible there.
   [jcbrand]
 - New non-core plugin `converse-roomslist`, which shows a list of open rooms
   in the `Rooms` tab of the control box. [jcbrand]
-- Show unread messages for minimized chats. [jcbrand]
-- New configuration setting for `converse-bookmarks`:
+
+### New configuration settings
+- New setting for `converse-bookmarks`:
   [hide_open_bookmarks](https://conversejs.org/docs/html/configurations.html#hide-open-bookmarks)
   It is meant to be set to `true` when using `converse-roomslist` so that open
   rooms aren't listed twice (in the rooms list and the bookmarks list).
   [jcbrand]
-- API change: the `message` event now returns a data object with `stanza` and
-  `chatbox` attributes, instead of just the stanza. [jcbrand]
-- Render nickname form when entering a room via invitation. [jcbrand]
+
+### Github tickets resolved
 - #567 Unreaded message count reset on page load [novokrest]
 - #575 Logging out from converse.js doesn't clear the connection status from the
   sessionStorage [jcbrand]
@@ -30,6 +37,13 @@
 - #890 Message carbons not sent out after reconnection [jcbrand]
 - #894 Room affiliation lost when connection jid and room presence jid are of different case [Rayzen]
 
+### Miscellaneous
+
+- Support for [XMPP-0313 Message Archive Management](https://xmpp.org/extensions/xep-0313.html)
+  has been upgraded to version 2. [jcbrand]
+- Show unread messages for minimized chats. [jcbrand]
+- Render nickname form when entering a room via invitation. [jcbrand]
+
 ## 3.0.2 (2017-04-23)
 
 *Dependency updates*:

+ 3 - 3
docs/source/configuration.rst

@@ -26,10 +26,10 @@ After you have configured *Converse.js*, you'll have to regenerate the minified
 JS file so that it will include the new settings. Please refer to the
 :ref:`minification` section for more info on how to do this.
 
-.. _`configuration-variables`:
+.. _`configuration-settings`:
 
-Configuration variables
-=======================
+Configuration settings
+======================
 
 authentication
 --------------

+ 112 - 4
docs/source/developer_api.rst

@@ -55,6 +55,8 @@ 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.
 
+.. _`initialize`:
+
 initialize
 ----------
 
@@ -63,7 +65,7 @@ initialize
 Publich API method which initializes converse.js.
 This method must always be called when using converse.js.
 
-The `initialize` method takes a map of :ref:`configuration-variables`.
+The `initialize` method takes a map of :ref:`configuration-settings`.
 
 Example:
 
@@ -133,6 +135,22 @@ that might be running in the page.
     time-constriaints these limitations are ignored in the examples below. For
     a fuller picture, refer to the section :ref:`events-API` as well.
 
+emit
+----
+
+This method allows you to emit events, which can be listened to via
+``_converse.api.listen.on`` or ``_converse.api.listen.once``.
+
+For example:
+
+.. code-block:: javascript
+
+    _converse.emit('foo-completed');
+
+Additionally, if a promise has been registered under the same name
+(via ``_converse.api.promises.add``), then that promise will also be resolved
+when calling ``emit``.
+
 send
 ----
 
@@ -155,7 +173,6 @@ For example, to send a message stanza:
         }
     });
 
-
 .. _`waituntil-grouping`:
 
 waitUntil
@@ -202,7 +219,7 @@ Converse.js supports the *Message Archive Management*
 (`XEP-0313 <https://xmpp.org/extensions/xep-0313.html>`_) protocol,
 through which it is able to query an XMPP server for archived messages.
 
-See also the **message_archiving** option in the :ref:`configuration-variables` section, which you'll usually
+See also the **message_archiving** option in the :ref:`configuration-settings` section, which you'll usually
 want to  in conjunction with this API.
 
 query
@@ -880,10 +897,101 @@ Lets you close open chat rooms. You can call this method without any arguments
 to close all open chat rooms, or you can specify a single JID or an array of
 JIDs.
 
+.. _`promises-grouping`:
+
+The **promises** grouping
+-------------------------
+
+Converse.js and its plugins emit various events which you can listen to via the 
+:refs:`listen-grouping`.
+
+These events can also be turned into promises, and by default some already
+are.
+
+The core events, which are also promises are:
+
+* cachedRoster
+* chatBoxesFetched
+* connected
+* pluginsInitialized
+* roster
+* rosterContactsFetched
+* rosterGroupsFetched
+* rosterInitialized
+* statusInitialized
+
+The various plugins might also provide promises, and they do this by using the
+``promises.add`` api method.
+
+add(promises)
+~~~~~~~~~~~~~
+
+By calling ``promises.add``, a new promise is made available for other code or
+plugins to depend on via the ``_converse.api.waitUntil`` method.
+
+This method accepts either a string or list of strings which specify the
+promise(s) to be added.
+
+For example:
+
+.. code-block:: javascript
+
+    converse.plugins.add('myplugin', {
+        initialize: function () {
+            this._converse.api.promises.add('foo-completed');
+        }
+    });
+
+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 resolve the
+promise, but also emit an event with the same name (which can be listened to
+via ``_converse.api.listen``).
+
+For example:
+
+.. code-block:: javascript
+
+    _converse.api.emit('foo-completed');
+
+
 The **settings** grouping
 -------------------------
 
-This grouping allows you to get or set the configuration settings of converse.js.
+This grouping allows access to the configuration settings of converse.js.
+
+.. _`settings-update`:
+
+update(settings)
+~~~~~~~~~~~~~~~~
+
+Allows new configuration settings to be specified, or new default values for
+existing configuration settings to be specified.
+
+For example:
+
+.. code-block:: javascript
+
+    converse.plugins.add('myplugin', {
+        initialize: function () {
+            this._converse.api.settings.update({
+                'enable_foo': true
+            });
+        }
+    });
+
+The user can then override the default value of the configuration setting when
+calling `converse.initialize`.
+
+For example:
+
+.. code-block:: javascript
+
+    converse.initialize({
+        'enable_foo': false
+    });
+
 
 get(key)
 ~~~~~~~~

+ 67 - 5
docs/source/plugin_development.rst

@@ -126,7 +126,6 @@ Here's an example of the plugin shown above wrapped inside a UMD module:
     });
 
 
-
 Accessing 3rd party libraries
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -198,11 +197,36 @@ If the setting :ref:`strict_plugin_dependencies` is set to true,
 an error will be raised if the plugin is not found, thereby making them
 non-optional.
 
+Extending converse.js's configuration settings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Converse.js comes with various :ref:`configuration-settings`_ that can be used to
+modify its functionality and behavior.
+
+All configuration settings have default values which can be overridden when
+`converse.initialize` (see :ref:`initialize`_) gets called.
+
+Plugins often need their own additional configuration settings and you can add
+these settings with the `_converse.api.settings.update` method (see
+:ref:`settings-update`_).
+
+Exposing promises
+~~~~~~~~~~~~~~~~~
+
+Converse.js has a ``waitUntil`` API method (see :ref:`waituntil-grouping`_)
+which allows you to wait for various promises to resolve before executing a
+piece of code.
+
+You can add new promises for your plugin by calling
+``_converse.api.promises.add`` (see :ref:`promises-grouping`_).
+
+Generally, your plugin will then also be responsible for making sure these
+promises are resolved. You do this by calling ``_converse.api.emit``, which not
+only resolves the plugin but will also emit an event with the same name.
 
 A full example plugin
 ---------------------
 
-
 .. code-block:: javascript
 
     (function (root, factory) {
@@ -237,20 +261,58 @@ A full example plugin
                 // method on any plugin (if it exists) as soon as the plugin has
                 // been loaded.
 
+                var _converse = this._converse;
+
                 // Inside this method, you have access to the closured
                 // _converse object, from which you can get any configuration
                 // options that the user might have passed in via
                 // converse.initialize. These values are stored in the
                 // "user_settings" attribute.
 
-                // Let's assume the user might pass in a custom setting, like so:
+                // We can also specify new configuration settings for this
+                // plugin, or override the default values of existing
+                // configuration settings. This is done like so:
+
+                _converse.api.settings.update({
+                    'initialize_message': 'Initialized', // New configuration setting
+                    'auto_subscribe': true, // New default value for an
+                                            // existing "core" configuration setting
+                });
+
+                // The user can then pass in values for the configuration
+                // settings when `converse.initialize` gets called.
+                // For example:
                 //
                 // converse.initialize({
                 //      "initialize_message": "My plugin has been initialized"
                 // });
                 //
-                // Then we can alert that message, like so:
-                alert(this._converse.user_settings.initialize_message);
+                // And the configuration setting is then available via the
+                // `user_settings` attribute:
+
+                // alert(this._converse.user_settings.initialize_message);
+
+                // Besides `_converse.api.settings.update`, there is also a
+                // `_converse.api.promises.add` method, which allows you to
+                // add new promises that your plugin is obligated to fulfill.
+
+                // This method takes a string or a list of strings which
+                // represent the promise names.
+
+                _converse.api.promises.add('operationCompleted');
+
+                // Your plugin should then, when appropriate, resolve the
+                // promise by calling `_converse.api.emit`, which will also
+                // emit an event with the same name as the promise.
+                // For example:
+                // _converse.api.emit('operationCompleted');
+                //
+                // Other plugins can then either listen for the event
+                // `operationCompleted` like so:
+                // `_converse.api.listen.on('operationCompleted', function { ... });`
+                //
+                // or they can wait for the promise to be fulfilled like so:
+                // `_converse.api.waitUntil('operationCompleted', function { ... });`
             },
 
             // Optional dependencies are other plugins which might be

+ 1 - 1
docs/source/quickstart.rst

@@ -42,7 +42,7 @@ Initializing Converse.js
 ------------------------
 
 You'll then need to initialize Converse.js with configuration settings relevant to your requirements.
-Refer to the :ref:`configuration-variables` section for info on all the available configuration settings.
+Refer to the :ref:`configuration-settings` section for info on all the available configuration settings.
 
 To quickly get started, you can put the following Javascript code at the
 bottom of your page (after the closing *</body>* element)::

+ 1 - 1
docs/source/setup.rst

@@ -212,7 +212,7 @@ your authentication backend, since you could then configure your XMPP server to
 use that as well.
 
 To prebind you will require a BOSH-enabled XMPP server for converse.js to connect to
-(see the :ref:`bosh-service-url` under :ref:`configuration-variables`)
+(see the :ref:`bosh-service-url` under :ref:`configuration-settings`)
 as well as a BOSH client in your web application (written for example in
 Python, Ruby or PHP) that will set up an authenticated BOSH session, which
 converse.js can then attach to.

+ 1 - 1
spec/converse.js

@@ -326,7 +326,7 @@
                     {'play_sounds': true}, 
                     function (_converse) {
 
-                expect(_.keys(_converse.api.settings)).toEqual(["get", "set"]);
+                expect(_.keys(_converse.api.settings)).toEqual(["update", "get", "set"]);
                 expect(_converse.api.settings.get("play_sounds")).toBe(true);
                 _converse.api.settings.set("play_sounds", false);
                 expect(_converse.api.settings.get("play_sounds")).toBe(false);

+ 3 - 1
src/converse-bookmarks.js

@@ -194,10 +194,12 @@
             // ====================================
             // Refer to docs/source/configuration.rst for explanations of these
             // configuration settings.
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_bookmarks: true,
                 hide_open_bookmarks: false
             });
+            // Promises exposed by this plugin
+            _converse.api.promises.add('bookmarksInitialized');
 
             _converse.Bookmark = Backbone.Model;
 

+ 1 - 1
src/converse-chatview.js

@@ -76,7 +76,7 @@
             var _converse = this._converse,
                 __ = _converse.__;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 chatview_avatar_height: 32,
                 chatview_avatar_width: 32,
                 show_toolbar: true,

+ 1 - 1
src/converse-controlbox.js

@@ -191,7 +191,7 @@
             var _converse = this._converse,
                 __ = _converse.__;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_logout: true,
                 default_domain: undefined,
                 show_controlbox_by_default: false,

+ 17 - 10
src/converse-core.js

@@ -2154,15 +2154,6 @@
             this.chatboxviews = new this.ChatBoxViews({model: this.chatboxes});
         };
 
-        var updateSettings = function (settings) {
-            /* Helper method which gets put on the plugin and allows it to
-             * add more user-facing config settings to converse.js.
-             */
-            utils.merge(_converse.default_settings, settings);
-            utils.merge(_converse, settings);
-            utils.applyUserSettings(_converse, settings, _converse.user_settings);
-        };
-
         this.initPlugins = function () {
             // If initialize gets called a second time (e.g. during tests), then we
             // need to re-apply all plugins (for a new converse instance), and we
@@ -2175,7 +2166,7 @@
                 _converse.whitelisted_plugins);
 
             _converse.pluggable.initializePlugins({
-                'updateSettings': updateSettings,
+                'updateSettings': _converse.api.settings.update,
                 '_converse': _converse
             }, whitelist, _converse.blacklisted_plugins);
             _converse.emit('pluginsInitialized');
@@ -2212,6 +2203,9 @@
                 _converse.connection.disconnect();
             },
         },
+        'emit': function () {
+            _converse.emit.apply(_converse, arguments);
+        },
         'user': {
             'jid': function () {
                 return _converse.connection.jid;
@@ -2249,6 +2243,11 @@
             },
         },
         'settings': {
+            'update': function (settings) {
+                utils.merge(_converse.default_settings, settings);
+                utils.merge(_converse, settings);
+                utils.applyUserSettings(_converse, settings, _converse.user_settings);
+            },
             'get': function (key) {
                 if (_.includes(_.keys(_converse.default_settings), key)) {
                     return _converse[key];
@@ -2264,6 +2263,14 @@
                 }
             }
         },
+        'promises': {
+            'add': function (promises) {
+                promises = _.isArray(promises) ? promises : [promises]
+                _.each(promises, function (promise) {
+                    _converse.promises[promise] = new $.Deferred();
+                });
+            }
+        },
         'contacts': {
             'get': function (jids) {
                 var _transform = function (jid) {

+ 1 - 1
src/converse-dragresize.js

@@ -335,7 +335,7 @@
              */
             var _converse = this._converse;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_dragresize: true,
             });
 

+ 1 - 1
src/converse-inverse.js

@@ -97,7 +97,7 @@
         },
 
         initialize: function () {
-            this.updateSettings({
+            this._converse.api.settings.update({
                 chatview_avatar_height: 44,
                 chatview_avatar_width: 44,
                 hide_open_bookmarks: true,

+ 1 - 1
src/converse-mam.js

@@ -205,7 +205,7 @@
              */
             var _converse = this._converse;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 archived_messages_page_size: '50',
                 message_archiving: undefined, // Supported values are 'always', 'never', 'roster' (https://xmpp.org/extensions/xep-0313.html#prefs)
                 message_archiving_timeout: 8000, // Time (in milliseconds) to wait before aborting MAM request

+ 1 - 1
src/converse-minimize.js

@@ -312,7 +312,7 @@
             _converse.templates.trimmed_chat = tpl_trimmed_chat;
             _converse.templates.chats_panel = tpl_chats_panel;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 no_trimming: false, // Set to true for phantomjs tests (where browser apparently has no width)
             });
 

+ 2 - 5
src/converse-muc.js

@@ -330,7 +330,7 @@
             // ====================================
             // Refer to docs/source/configuration.rst for explanations of these
             // configuration settings.
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_muc: true,
                 allow_muc_invitations: true,
                 auto_join_on_invite: false,
@@ -347,10 +347,7 @@
                     'toggle_occupants': true
                 },
             });
-
-            _.extend(_converse.promises, {
-                'roomsPanelRendered': new $.Deferred()
-            });
+            _converse.api.promises.add('roomsPanelRendered');
 
             _converse.openChatRoom = function (settings) {
                 /* Opens a chat room, making sure that certain attributes

+ 1 - 1
src/converse-notification.js

@@ -28,7 +28,7 @@
 
             _converse.supports_html5_notification = "Notification" in window;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 notify_all_room_messages: false,
                 show_desktop_notifications: true,
                 show_chatstate_notifications: false,

+ 1 - 1
src/converse-otr.js

@@ -459,7 +459,7 @@
             var _converse = this._converse,
                 __ = _converse.__;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_otr: true,
                 cache_otr_key: false,
                 use_otr_by_default: false

+ 1 - 1
src/converse-ping.js

@@ -25,7 +25,7 @@
              */
             var _converse = this._converse;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 ping_interval: 180 //in seconds
             });
 

+ 1 - 1
src/converse-register.js

@@ -112,7 +112,7 @@
             _converse.templates.registration_form = tpl_registration_form;
             _converse.templates.registration_request = tpl_registration_request;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_registration: true,
                 domain_placeholder: __(" e.g. conversejs.org"),  // Placeholder text shown in the domain input on the registration form
                 providers_link: 'https://xmpp.net/directory.php', // Link to XMPP providers shown on registration page

+ 1 - 1
src/converse-rosterview.js

@@ -75,7 +75,7 @@
                 __ = _converse.__,
                 ___ = _converse.___;
 
-            this.updateSettings({
+            _converse.api.settings.update({
                 allow_chat_pending_contacts: true,
                 allow_contact_removal: true,
                 show_toolbar: true,

+ 1 - 1
src/converse-vcard.js

@@ -56,7 +56,7 @@
              * loaded by converse.js's plugin machinery.
              */
             var _converse = this._converse;
-            this.updateSettings({
+            _converse.api.settings.update({
                 use_vcards: true,
             });