plugin_development.rst 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. .. raw:: html
  2. <div id="banner"><a href="https://github.com/jcbrand/converse.js/blob/master/docs/source/theming.rst">Edit me on GitHub</a></div>
  3. .. _`writing-a-plugin`:
  4. Writing a converse.js plugin
  5. ============================
  6. .. contents:: Table of Contents
  7. :depth: 2
  8. :local:
  9. Introduction
  10. ------------
  11. Developers are able to extend and override the objects, functions and the
  12. Backbone models and views that make up converse.js by means of writing plugins.
  13. Converse.js uses `pluggable.js <https://github.com/jcbrand/pluggable.js/>`_ as
  14. its plugin architecture.
  15. To understand how this plugin architecture works, please read the
  16. `pluggable.js documentation <https://jcbrand.github.io/pluggable.js/>`_
  17. and to understand its inner workins, please refer to the `annotated source code
  18. <https://jcbrand.github.io/pluggable.js/docs/pluggable.html>`_.
  19. You register a converse.js plugin as follows:
  20. .. code-block:: javascript
  21. converse.plugins.add('myplugin', {
  22. initialize: function () {
  23. // This method gets called once converse.initialize has been called
  24. // and the plugin itself has been loaded.
  25. // Inside this method, you have access to the closured
  26. // _converse object as an attribute on "this".
  27. // E.g. this._converse
  28. },
  29. });
  30. Security and access to the inner workings
  31. -----------------------------------------
  32. The globally available ``converse`` object, which exposes the API methods, such
  33. as ``initialize`` and ``plugins.add``, is a wrapper that encloses and protects
  34. a sensitive inner object, named ``_converse`` (not the underscore prefix).
  35. This inner ``_converse`` object contains all the Backbone models and views,
  36. as well as various other attributes and functions.
  37. Within a plugin, you will have access to this internal
  38. `"closured" <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures>`_
  39. ``_converse`` object, which is normally not exposed in the global variable scope.
  40. The inner ``_converse`` object is made private in order to safely hide and
  41. encapsulate sensitive information and methods which should not be exposed
  42. to any 3rd-party scripts that might be running in the same page.
  43. An example plugin
  44. -----------------
  45. In the example below, you can see how to access 3rd party libraries (such
  46. moment, underscore and jQuery) via the ``converse.env`` map.
  47. There is an ``initialize`` method as you've seen in the example above, and then
  48. also an ``overrides`` map, which can be used to override functions, objects or
  49. Backbone views and models of Converse.js.
  50. Use the ``overrides`` functionality with caution. It basically resorts to
  51. monkey patching which pollutes the call stack and can make your code fragile
  52. and prone to bugs when Converse.js gets updated. Too much use of ``overrides``
  53. is therefore a "code smell" which should ideally be avoided.
  54. A better approach is to listen to the events emitted by Converse.js, and to add
  55. your code in event handlers. This is however not always possible, in which case
  56. the overrides are a powerful tool.
  57. .. code-block:: javascript
  58. (function (root, factory) {
  59. if (typeof define === 'function' && define.amd) {
  60. // AMD. Register as a module called "myplugin"
  61. define("myplugin", ["converse"], factory);
  62. } else {
  63. // Browser globals. If you're not using a module loader such as require.js,
  64. // then this line below executes. Make sure that your plugin's <script> tag
  65. // appears after the one from converse.js.
  66. factory(converse);
  67. }
  68. }(this, function (converse) {
  69. // Commonly used utilities and variables can be found under the "env"
  70. // namespace of the "converse" global.
  71. var Strophe = converse.env.Strophe,
  72. $iq = converse.env.$iq,
  73. $msg = converse.env.$msg,
  74. $pres = converse.env.$pres,
  75. $build = converse.env.$build,
  76. b64_sha1 = converse.env.b64_sha1;
  77. $ = converse.env.jQuery,
  78. _ = converse.env._,
  79. moment = converse.env.moment;
  80. // The following line registers your plugin.
  81. converse.plugins.add('myplugin', {
  82. initialize: function () {
  83. // Converse.js's plugin mechanism will call the initialize
  84. // method on any plugin (if it exists) as soon as the plugin has
  85. // been loaded.
  86. // Inside this method, you have access to the closured
  87. // _converse object, from which you can get any configuration
  88. // options that the user might have passed in via
  89. // converse.initialize. These values are stored in the
  90. // "user_settings" attribute.
  91. // Let's assume the user might pass in a custom setting, like so:
  92. //
  93. // converse.initialize({
  94. // "initialize_message": "My plugin has been initialized"
  95. // });
  96. //
  97. // Then we can alert that message, like so:
  98. alert(this._converse.user_settings.initialize_message);
  99. },
  100. overrides: {
  101. // If you want to override some function or a Backbone model or
  102. // view defined elsewhere in converse.js, then you do that under
  103. // this "overrides" namespace.
  104. // For example, the inner protected *_converse* object has a
  105. // method "onConnected". You can override that method as follows:
  106. onConnected: function () {
  107. // Overrides the onConnected method in converse.js
  108. // Top-level functions in "overrides" are bound to the
  109. // inner "_converse" object.
  110. var _converse = this;
  111. // Your custom code comes here.
  112. // ...
  113. // You can access the original function being overridden
  114. // via the __super__ attribute.
  115. // Make sure to pass on the arguments supplied to this
  116. // function and also to apply the proper "this" object.
  117. _converse.__super__.onConnected.apply(this, arguments);
  118. },
  119. XMPPStatus: {
  120. // Override converse.js's XMPPStatus Backbone model so that we can override the
  121. // function that sends out the presence stanza.
  122. sendPresence: function (type, status_message, jid) {
  123. // The "_converse" object is available via the __super__
  124. // attribute.
  125. var _converse = this.__super__._converse;
  126. // Custom code can come here
  127. // ...
  128. // You can call the original overridden method, by
  129. // accessing it via the __super__ attribute.
  130. // When calling it, you need to apply the proper
  131. // context as reference by the "this" variable.
  132. this.__super__.sendPresence.apply(this, arguments);
  133. }
  134. }
  135. }
  136. });
  137. }));