-
Notifications
You must be signed in to change notification settings - Fork 12
/
params.json
6 lines (6 loc) · 11.1 KB
/
params.json
1
2
3
4
5
6
{
"name": "pluggable.js",
"tagline": "Lets you make your JS code pluggable while still keeping sensitive objects and data private through closures.",
"body": " ____ __ __ __ _\r\n / __ \\/ /_ __ ___ ___ ____ _/ /_ / /__ (_)____\r\n / /_/ / / / / / __ \\/ __ \\/ __/ / __ \\/ / _ \\ / / ___/\r\n / ____/ / /_/ / /_/ / /_/ / /_/ / /_/ / / __/ / (__ )\r\n /_/ /_/\\__,_/\\__, /\\__, /\\__/_/_.___/_/\\___(_)_/ /____/\r\n /____//____/ /___/ \r\n\r\n# Introduction\r\n\r\npluggable.js lets you make your JS project extendable via plugins, while still\r\nkeeping sensitive objects and data private through closures.\r\n\r\nIt was originally written for [converse.js](https://conversejs.org), to provide\r\na plugin architecture that allows 3rd party developers to extend and override\r\nprivate objects and [backbone.js](http://backbonejs.org) classes, but it does not\r\nrequire nor depend on either library.\r\n\r\n# Size and dependencies\r\n\r\nCurrently pluggable.js depends on [underscore.js](http://underscorejs.org) or\r\n[lodash.js](http://lodash.com), however if there is enough demand for this\r\ndependency to be dropped I might do so later on.\r\n\r\nPluggable.js itself (without underscore/lodash) is only 2.5KB when minified\r\n(without gzip compression).\r\n\r\n# Documentation\r\n\r\nTo understand how it works under the hood, read the [annotated source code](\r\nhttps://jcbrand.github.io/pluggable.js/docs/pluggable.html).\r\n\r\n## Live demo of the example code\r\n\r\nYou can try out the [live demo](https://jcbrand.github.io/pluggable.js/example)\r\nof the example code given below.\r\n\r\nThe files themselves are in the [example folder of the\r\nrepo](https://github.com/jcbrand/pluggable.js/tree/master/example).\r\n\r\n## Usage\r\n\r\n*Please note: The code in pluggable.js and all the examples to follow use the\r\nES5 version of Javascript.*\r\n\r\nSuppose you have a module with a private scope and two private methods,\r\n`_showNotification` and `_fadeOut`. Let's just assume for the sake of\r\nillustration that there's a good reason why these methods are private.\r\n\r\nWhat we want to do, is to make this module pluggable. In other words, we want\r\npeople to be able to write plugins for this module, in which they can:\r\n\r\n- Access the closured scope of this module.\r\n- Add new methods to the module.\r\n- Override or extend existng methods (private or public) on this module.\r\n\r\nTo make the module pluggable, we simply call `pluggable.enable(module);`.\r\nOnce we've made this call, the `module` object will have a new property\r\n`pluginSocket`, which you can think of as the thing into which the plugins are\r\nplugged into. It is an instance of `PluginSocket`, which represents the plugin\r\narchitecture and manages all the plugins.\r\n\r\nAdditionally, we need to expose some way for plugins to register themselves.\r\nSince the module itself is private, we'll need to expose the `registerPlugin`\r\nmethod on the `pluginSocket` via a public method.\r\n\r\nAnd then finally, once all plugins have been registered, they need to be\r\ninitialized by calling `initializePlugins` on the `PluginSocket` instance.\r\n\r\nFor example:\r\n\r\n``` Javascript\r\n module.pluginSocket.initializePlugins();\r\n```\r\n\r\n### Example code of a module to be made pluggable\r\n\r\nLet's now look at the code for our module (which will go into a file called `app.js`):\r\n\r\n``` Javascript\r\n// An example application, used to demonstrate how pluggable.js can\r\n// allow a module to be made pluggable.\r\n(function () {\r\n var module = this;\r\n\r\n // A private method, not available outside the scope of this module.\r\n module._showNotification = function (text) {\r\n /* Displays a notification message */\r\n var el = document.createElement('p');\r\n el.setAttribute('class', 'notification');\r\n el.appendChild(document.createTextNode(text));\r\n el = document.getElementById('notifications').appendChild(el);\r\n setTimeout(_.partial(module._fadeOut, el), 3000);\r\n return el;\r\n };\r\n\r\n // Another private method, not available outside the scope of this module.\r\n module._fadeOut = function (el) {\r\n /* Fades out the passed in DOM element. */\r\n el.style.opacity = 1;\r\n (function fade() {\r\n if ((el.style.opacity -= 0.1) < 0) {\r\n el.remove();\r\n } else {\r\n setTimeout(fade, 25);\r\n }\r\n })();\r\n };\r\n\r\n // Initialize this module.\r\n // -----------------------\r\n // There are two buttons for which we register event handlers.\r\n //\r\n // This will be a public method.\r\n module.initialize = function () {\r\n var notify_el = document.getElementById('notify');\r\n notify_el.addEventListener('click', function () {\r\n module._showNotification('This is a notification.');\r\n });\r\n\r\n var enable_el = document.getElementById('enable');\r\n enable_el.addEventListener('click', function () {\r\n this.setAttribute('disabled', 'disabled');\r\n module.pluginSocket.initializePlugins();\r\n });\r\n };\r\n\r\n // Register a plugin for this module.\r\n // ----------------------------------\r\n // This is a wrapper method which defers to the `registerPlugin` method\r\n // of pluggable.js, which is on the `pluginSocket` property of the\r\n // private `module` object that was made pluggable, via\r\n // `pluggable.enable(module).\r\n //\r\n // This will be a public method.\r\n module.registerPlugin = function (name, plugin) {\r\n module.pluginSocket.registerPlugin(name, plugin);\r\n };\r\n\r\n // Calling `pluggable.enable` on the closured `module` object, will make it\r\n // pluggable. Additionally, it will get the `pluginSocket` attribute, which\r\n // refers to the object that the plugins get plugged into.\r\n pluggable.enable(module);\r\n\r\n // Declare the two public methods\r\n var _public = {\r\n 'initialize': module.initialize,\r\n 'registerPlugin': module.registerPlugin\r\n };\r\n window.myApp = _public;\r\n return _public;\r\n})();\r\n```\r\n\r\n### Creating the plugin\r\n\r\nSo, as you can see in the example above, the module has a private method\r\n`_showNotification`, which will show a notification message in the page.\r\n\r\nLet's now create a plugin which overrides this method, so that we can modify the\r\nway the notification message will be displayed.\r\n\r\nBy the way, multiple plugins can override the same method. As long as\r\neach overriding method calls the original method, via the `__super__` property,\r\nthe method call will travel up through all the overrides (in the reverse order\r\nin which the plugins were registered) back to the original method.\r\n\r\nThe way to call the method being overridden, is like this:\r\n\r\n``` Javascript\r\n this.__super__.methodName.apply(this, arguments);\r\n```\r\n\r\nwhere `methodName` is the name of the method. In our example, this will be\r\n`showNotification`.\r\n\r\n### Example plugin code\r\n\r\nSo, with that said, here's what the plugin code (which goes into the file `plugin.js`)\r\nwill look like:\r\n\r\n``` Javascript\r\n(function () {\r\n // We call the public `registerPlugin` method from our module in app.js\r\n window.myApp.registerPlugin('my-plugin', {\r\n\r\n overrides: {\r\n // Here you specify your overrides of methods or objects on the\r\n // module that has been made pluggable.\r\n\r\n // Override _showNotification to change the color of notification\r\n // messages.\r\n _showNotification: function (text) {\r\n // When overriding a method, you can still call the original method\r\n // via `this.__super__`. To properly call with the proper `this`\r\n // context and parameters, use `.apply(this, arguments)`.\r\n var el = this.__super__._showNotification.apply(this, arguments);\r\n\r\n // Now we simply set another class on the element containing\r\n // the notifications, so that they'll appear in a different\r\n // color.\r\n el.setAttribute('class', el.getAttribute('class')+' extra');\r\n }\r\n\r\n // BTW, new methods which don't exist yet can also be added here.\r\n },\r\n\r\n initialize: function (socket) {\r\n // The initialize function gets called as soon as the plugin is\r\n // loaded by pluggable.js's plugin machinery.\r\n\r\n // We are passed in an instance of the `PluginSocket`, which\r\n // represents the plugin architecture and gets created when\r\n // `pluggable.enable` is called on an object.\r\n\r\n // The `PluginSocket` instance is also accessible via the `pluginSocket`\r\n // attribute, on the module that was passed to `pluggable.enable`.\r\n\r\n // You can get hold of the module which was made pluggable\r\n // via the `plugged` property of the `PluginSocket` instance.\r\n\r\n // Once you have the module, you can access its private properties\r\n // and call its private methods.\r\n\r\n // Here, once this plugin is initialized, we show a notification.\r\n socket.plugged._showNotification(\r\n \"The plugin has been enabled. Notifications are now a different color.\"\r\n );\r\n }\r\n });\r\n})();\r\n```\r\n### Custom plugin code\r\n\r\nThe plugin has three important parts to it. Firstly, a call to register the\r\nplugin must be made, and then passed in with this call is an object which\r\nrepresents the plugin itself.\r\n\r\nThis plugin object has an `overrides` key, which is another object containing methods\r\nand objects that will override similarly named methods and object properties on the\r\nmodule itself.\r\n\r\nAdditionally, the `initializePlugins` method has been called on the\r\n`pluginSocket` instance.\r\n\r\nThis happens inside our module in app.js and this methods should generally be\r\ncalled once, after all plugins have been registered and after the module being\r\nmade pluggable has itself been initialized.\r\n\r\nIn the `initialize` method, you have access the module's scope, which would\r\notherwise not be available to you.\r\n\r\nSo, as you can see, the plugin lets us achieve our three goals stated earlier:\r\n\r\n### Access the closured scope of this module.\r\n\r\nWe have access to the module and all its properties and methods inside the\r\n`initialize` method of our plugin.\r\n\r\n### Add new methods to the module.\r\n\r\nWe can add new methods to our module, either inside the `initialize` method of\r\nour plugin, or by stating them declaratively in `overrides` object.\r\n\r\n### Override or extend existng methods (private or public) on this module.\r\n\r\nWe can override existing methods and object properties via the `overrides`\r\nobject.\r\n",
"note": "Don't delete this file! It's used internally to help with page regeneration."
}