- Document `optional_plugin_dependencies`
- Also make `converse-headlines` an optional dependency of `converse-dragresize`
This commit is contained in:
JC Brand 2017-03-08 11:15:19 +00:00
parent 5fc6ab1e4e
commit f1bf5a9654
5 changed files with 140 additions and 9 deletions

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
## 3.0.1 (Unreleased)
- #807 Error: Plugin "converse-dragresize" tried to override HeadlinesBoxView but it's not found. [jcbrand]
## 3.0.0 (2017-03-05) ## 3.0.0 (2017-03-05)
- **Breaking changes**: - **Breaking changes**:

View File

@ -1035,6 +1035,7 @@ devices when the intent is to use converse.js as a web app. In this case
it doesn't make sense to close the control box, as there's often then nothing it doesn't make sense to close the control box, as there's often then nothing
"behind" it that's relevant to the user. "behind" it that's relevant to the user.
.. _`strict_plugin_dependencies`:
strict_plugin_dependencies strict_plugin_dependencies
-------------------------- --------------------------

View File

@ -4,8 +4,8 @@
.. _`writing-a-plugin`: .. _`writing-a-plugin`:
Writing a converse.js plugin Writing a plugin
============================ ================
.. contents:: Table of Contents .. contents:: Table of Contents
:depth: 2 :depth: 2
@ -59,15 +59,75 @@ The inner ``_converse`` object is made private in order to safely hide and
encapsulate sensitive information and methods which should not be exposed encapsulate sensitive information and methods which should not be exposed
to any 3rd-party scripts that might be running in the same page. to any 3rd-party scripts that might be running in the same page.
An example plugin Loading a plugin
----------------- -----------------
In the example below, you can see how to access 3rd party libraries (such Converse.js uses the UMD (Universal Modules Definition) as its module syntax.
This makes modules loadable via `require.js`, `webpack` or other module
loaders, but also includable as old-school `<script>` tags in your HTML.
Here's an example of the plugin shown above wrapped inside a UMD module:
.. code-block:: javascript
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as a module called "myplugin"
define("myplugin", ["converse"], factory);
} else {
// Browser globals. If you're not using a module loader such as require.js,
// then this line below executes. Make sure that your plugin's <script> tag
// appears after the one from converse.js.
factory(converse);
}
}(this, function (converse) {
converse.plugins.add('myplugin', {
initialize: function () {
// This method gets called once converse.initialize has been called
// and the plugin itself has been loaded.
// Inside this method, you have access to the closured
// _converse object as an attribute on "this".
// E.g. this._converse
},
});
});
Accessing 3rd party libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Immediately inside the module shown above you can access 3rd party libraries (such
moment, underscore and jQuery) via the ``converse.env`` map. moment, underscore and jQuery) via the ``converse.env`` map.
There is an ``initialize`` method as you've seen in the example above, and then The code for it would look something like this:
also an ``overrides`` map, which can be used to override functions, objects or
Backbone views and models of Converse.js.
.. code-block:: javascript
// Commonly used utilities and variables can be found under the "env"
// namespace of the "converse" global.
var Strophe = converse.env.Strophe,
$iq = converse.env.$iq,
$msg = converse.env.$msg,
$pres = converse.env.$pres,
$build = converse.env.$build,
b64_sha1 = converse.env.b64_sha1;
$ = converse.env.jQuery,
_ = converse.env._,
moment = converse.env.moment;
These dependencies are closured so that they don't pollute the global
namespace, that's why you need to access them in such a way inside the module.
Overrides
---------
Plugins can override core code or code from other plugins. Refer to the full
example at the bottom for code details.
Use the ``overrides`` functionality with caution. It basically resorts to Use the ``overrides`` functionality with caution. It basically resorts to
monkey patching which pollutes the call stack and can make your code fragile monkey patching which pollutes the call stack and can make your code fragile
@ -78,6 +138,41 @@ A better approach is to listen to the events emitted by Converse.js, and to add
your code in event handlers. This is however not always possible, in which case your code in event handlers. This is however not always possible, in which case
the overrides are a powerful tool. the overrides are a powerful tool.
Optional plugin dependencies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using ``overrides``, the code that you want to override (which is either
in ``converse-core`` or in other plugins), needs to be loaded already by the
type the ``overrides`` object is being parsed.
So it's important to include overridden plugins in the AMD ``define`` statement
at the top of the plugin module.
However, sometimes you want to override parts of another plugin if it exists, but you
don't want anything to break if it doesn't exist (for example when using a
custom build which excludes that plugin). An example is the
`converse-dragresize <https://github.com/jcbrand/converse.js/blob/master/src/converse-dragresize.js>`_
plugin, which will add drag-resize handles to the headlines box (which shows
messages of type ``headline``) but doesn't care if that particular plugin isn't
actually loaded.
In this case, you can't specify the plugin as a dependency in the ``define``
statement at the top of the plugin, since it might not always be available,
which would cause ``require.js`` to throw an error.
To resolve this problem we thave the ``optional_dependencies`` Array attribute.
With this you can specify those dependencies which need to be loaded before
your plugin, if they exist. If they don't exist, they won't be ignored.
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.
A full example plugin
---------------------
.. code-block:: javascript .. code-block:: javascript
(function (root, factory) { (function (root, factory) {
@ -128,6 +223,20 @@ the overrides are a powerful tool.
alert(this._converse.user_settings.initialize_message); alert(this._converse.user_settings.initialize_message);
}, },
// Optional dependencies are other plugins which might be
// overridden or relied upon, and therefore need to be loaded before
// this plugin. They are called "optional" because they might not be
// available, in which case any overrides applicable to them will be
// ignored.
// It's possible however to make optional dependencies non-optional.
// If the setting "strict_plugin_dependencies" is set to true,
// an error will be raised if the plugin is not found.
//
// NB: These plugins need to have already been loaded via require.js.
optional_dependencies: [],
overrides: { overrides: {
// If you want to override some function or a Backbone model or // If you want to override some function or a Backbone model or
// view defined elsewhere in converse.js, then you do that under // view defined elsewhere in converse.js, then you do that under

View File

@ -20,6 +20,19 @@
_ = converse.env._; _ = converse.env._;
converse.plugins.add('converse-dragresize', { converse.plugins.add('converse-dragresize', {
/* Optional dependencies are other plugins which might be
* overridden or relied upon, and therefore need to be loaded before
* this plugin. They are called "optional" because they might not be
* available, in which case any overrides applicable to them will be
* ignored.
*
* It's possible however to make optional dependencies non-optional.
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found.
*
* NB: These plugins need to have already been loaded via require.js.
*/
optional_dependencies: ["converse-headline"],
overrides: { overrides: {
// Overrides mentioned here will be picked up by converse.js's // Overrides mentioned here will be picked up by converse.js's

View File

@ -91,9 +91,13 @@
converse.plugins.add('converse-muc', { converse.plugins.add('converse-muc', {
/* Optional dependencies are other plugins which might be /* Optional dependencies are other plugins which might be
* overridden or relied upon, if they exist, otherwise they're ignored. * overridden or relied upon, and therefore need to be loaded before
* this plugin. They are called "optional" because they might not be
* available, in which case any overrides applicable to them will be
* ignored.
* *
* However, if the setting "strict_plugin_dependencies" is set to true, * It's possible however to make optional dependencies non-optional.
* If the setting "strict_plugin_dependencies" is set to true,
* an error will be raised if the plugin is not found. * an error will be raised if the plugin is not found.
* *
* NB: These plugins need to have already been loaded via require.js. * NB: These plugins need to have already been loaded via require.js.