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.
This commit is contained in:
JC Brand 2017-07-05 11:03:13 +02:00
parent 857c5ccdb3
commit f81a94baf1
22 changed files with 240 additions and 50 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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