{"_id":"54e65455d8873117005c773f","__v":60,"parentDoc":null,"version":{"_id":"54d5635532d98b0d00384afb","project":"54d53c7b23010a0d001aca0c","__v":10,"forked_from":"54d53c7c23010a0d001aca0f","createdAt":"2015-02-07T00:59:01.934Z","releaseDate":"2015-02-07T00:59:01.934Z","categories":["54d5635632d98b0d00384afc","54d5635632d98b0d00384afd","54d5635632d98b0d00384afe","54d5635632d98b0d00384aff","54d5635632d98b0d00384b00","54d5635632d98b0d00384b01","54d5635632d98b0d00384b02","54d652097e05890d006f153e","54dd1315ca1e5219007e9daa","54e21e2b22de1c230094b147","54e68e62a43fe13500db3879","54fa1d3fe7a0ba2f00306309","551c453a23a1ee190034d19a","551df586e52a0b23000c62b6","551f39be6886f8230055f02a","55a6720751457325000e4d97"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"0.1.0","version":"0.1"},"user":"54cfa8e1a8a4fd0d00b7fd1d","category":{"_id":"54d5635632d98b0d00384afd","project":"54d53c7b23010a0d001aca0c","version":"54d5635532d98b0d00384afb","__v":7,"pages":["54d5635632d98b0d00384b03","54d5635632d98b0d00384b04","54d5635632d98b0d00384b05","54d5635632d98b0d00384b06","54d5635632d98b0d00384b07","54d5635632d98b0d00384b08","54d5635632d98b0d00384b09","54d5635632d98b0d00384b0a","54d5635632d98b0d00384b0b","54d5635632d98b0d00384b0c","54d5635632d98b0d00384b0d","54d5635632d98b0d00384b0e","54d5635632d98b0d00384b0f","54e2254d22de1c230094b156","54e2255622de1c230094b158","54e23b349d045721004cbc26","54e65455d8873117005c773f","54e6b5c0ba1a980d00e3ecb0","551c12c781b8563500fd998e"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-06T23:43:39.709Z","from_sync":false,"order":7,"slug":"plugin-base-classes","title":"Plugin Base Classes"},"project":"54d53c7b23010a0d001aca0c","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-02-19T21:23:33.713Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"The `Plugin` base class is the primary base class that all plugins are based on. Any other base class is eventually an instance of `Plugin`. This base class provides an event system, load and unload flows and keeps state such as events, ui elements and css for clean up when a plugin is unloaded. In addition it provides an API to fetch and store private data.\n\n# Approach\n\nJavascript gives a lot of freedom to system builders in terms of what object creation and inheritance looks like. As a result there are many different ways this is done in different frameworks. Cloud9 settled on a way that values some aspects of Javascript more than others. For our purpose, we deem prototypical inheritance as unnecessarily complex and we value closures as a great way to simplify code - specifically removing the need for the `this` keyword which can be very confusing when writing asynchronous code. \n\nAs a consequence we created an API that allows you to decorate a plugin, rather than inherit from it. In addition all functions are local to the `main()` function and deal with variables in that scope as well. \n\n```\ndefine(function(require, exports, module) {\n    main.consumes = [\"dependency\"];\n    main.provides = [\"myplugin\"];\n    return main;\n\n    function main(options, imports, register) {\n        var dependency = imports.dependency;\n        \n        var plugin = new Plugin(\"Your Name\", main.consumes);\n\n        function doSomething(){}\n    \n        plugin.freezePublicAPI({\n            doSomething : doSomething\n        });\n        \n        register(\"\", {\n            \"myplugin\": plugin\n        });\n    }\n});\n```\n\nA constructor for a new object that is based on `Plugin()` is in fact a simple factory that returns a new plugin object, offering the exact same simple way of writing code for your plugin as the singleton plugin above.\n\n```\nfunction Foo(){        \n    var plugin = new Plugin(\"Your Name\", main.consumes);\n    var emit = plugin.getEmitter();\n\n    plugin.freezePublicAPI({});\n    plugin.load(null, \"foo\");\n    \n    return plugin;\n}\n\nvar bar = new Foo();\n```\n\nFor more information on creating base classes check out [this guide](doc:base-classes).\n\n# Immutable API\n\nIt is common practice in javascript to extend objects with new properties and methods at will. This often is a great way to add state to an object or quickly hack around something that was not originally designed in an API. The down side of this practice is that code can quickly *rot* and that there is potential for conflicts when multiple plugins from different vendors would do something like that. This is the main reason that Cloud9 plugins have an immutable API - which means that outside plugins are not able to add, remove or overwrite properties on a plugin. \n\nThere is a security aspect here as well: if a third party plugin could overwrite something like `http.request` it would have access to any private data that another plugin sends. This is prevented by the immutable APIs of Cloud9 plugins, which is achieved by the `freezePublicAPI()` method. This function *freezes* your plugin object.\n\nBecause all properties on the API are immutable, you'll work with property getters and setters to set any dynamic properties and keep the state in a local variable. Also make sure to list the events that your plugin emits for documentation purpose and for future use.\n\n```\nvar propertyName;\n\nfunction doSomething(){}\n\n/**\n * Describe your plugin here\n */\nplugin.freezePublicAPI({\n    /**\n     * :::at:::property type description\n     */\n    type: \"type\",\n    \n    /**\n     * @property propertyName description\n     */\n    get propertyName(){ return propertyName; },\n    set propertyName(value){ propertyName = value; },\n    \n    _events: [\n        /**\n         * @event eventName description\n         */\n        \"eventName\"\n    ],\n    \n    /**\n     * Description\n     * @param {String} name description\n     */\n    doSomething: doSomething\n});\n```\n\nThe Cloud9 documentation parser - which is forthcoming - will generate documentation for your plugin and make that available to whoever wants to build a plugin that consumes the APIs that you provide.\n\n# Event System\n\nEvents are an integral part of Cloud9's plugin system. Events provide hooks that other plugins can use to add or alter functionality. \n\n## Emitting events\n\nEmit plugins using the `emit()` function. You get a reference to this function by calling `getEmitter()` on the plugin.\n\n```\nvar plugin = new Plugin(\"Your Name\", main.consumes);\nvar emit = plugin.getEmitter();\n```\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Only emit events from within your plugin\",\n  \"body\": \"Events *must* only be emitted by your plugin itself (or any of it's super classes). This helps keep code flows clean and prevents *hacky* solutions that will eventually cause spaghetti code and code paths with unexpected consequences.\"\n}\n[/block]\nThe `getEmitter()` method is available *until* you call `freezePublicAPI()`, after which that function will no longer be provided. This secures your plugin from external plugins that might otherwise try to fire an event on your plugin.\n\nThe `emit()` function takes two arguments; the event name and an optional event object.\n\n```\nemit(\"beforeExample\", { data: [1, 2, 3] });\n```\n\nMake an event *sticky* by calling `emit.sticky()`.\n\n```\nemit.sticky(\"initialized\", { worker: worker });\n```\n\nFor more information on emitting events see [this guide](doc:events).\n\n## Listening to events\n\nSimilar to Node.js use the `on()` and `off()` methods to set and remove events.\n\n```\nplugin.on(\"beforeExample\", function(e){\n    console.log(\"Event fired\", e.data);\n}, otherPlugin);\n```\nThe third argument is a reference to the plugin that is setting the event listener. When the `otherPlugin` is unloaded this event handler is automatically cleared.\n\n```\nplugin.off(\"beforeExample\", someFunction);\n```\n\nFor more in-depth information on events see [this guide](doc:events).\n\n# Load, Unload and CleanUp\n\nThe `load()` method on `Plugin` will register the plugin and give it a name. Every plugin *must* have a name and the name is immutable once it's set. Fetch the name of a plugin using the `name` property. The `load()` method will fire the `load` event which you can use to execute code that initializes your plugin.\n\n```\nplugin.on(\"load\", function(){\n    // i.e. add a menu item\n});\n```\n\nThe `unload()` method will unregister the plugin and clean up any resources that were used by your plugin. Note that a plugin won't unload if other plugins depend on it and will return `false` in that case.\n\n```\nplugin.unload();\n```\n\n## Clean up\n\nThroughout the Cloud9 APIs you'll find functions that take a plugin reference as their last argument. Some examples include adding a command, create a menu, adding an event listener, setting css and inserting html. By referencing your plugin as the plugin responsible for those resources, they will be cleaned up when your plugin unloads.\n\nYou can also add some clean up code to a plugin by calling the `addOther()` method.\n\n```\nvar resource = createSomething();\nplugin.addOther(function(){\n    resource.destroy();\n});\n```","excerpt":"","slug":"plugin","type":"basic","title":"Plugin"}
The `Plugin` base class is the primary base class that all plugins are based on. Any other base class is eventually an instance of `Plugin`. This base class provides an event system, load and unload flows and keeps state such as events, ui elements and css for clean up when a plugin is unloaded. In addition it provides an API to fetch and store private data. # Approach Javascript gives a lot of freedom to system builders in terms of what object creation and inheritance looks like. As a result there are many different ways this is done in different frameworks. Cloud9 settled on a way that values some aspects of Javascript more than others. For our purpose, we deem prototypical inheritance as unnecessarily complex and we value closures as a great way to simplify code - specifically removing the need for the `this` keyword which can be very confusing when writing asynchronous code. As a consequence we created an API that allows you to decorate a plugin, rather than inherit from it. In addition all functions are local to the `main()` function and deal with variables in that scope as well. ``` define(function(require, exports, module) { main.consumes = ["dependency"]; main.provides = ["myplugin"]; return main; function main(options, imports, register) { var dependency = imports.dependency; var plugin = new Plugin("Your Name", main.consumes); function doSomething(){} plugin.freezePublicAPI({ doSomething : doSomething }); register("", { "myplugin": plugin }); } }); ``` A constructor for a new object that is based on `Plugin()` is in fact a simple factory that returns a new plugin object, offering the exact same simple way of writing code for your plugin as the singleton plugin above. ``` function Foo(){ var plugin = new Plugin("Your Name", main.consumes); var emit = plugin.getEmitter(); plugin.freezePublicAPI({}); plugin.load(null, "foo"); return plugin; } var bar = new Foo(); ``` For more information on creating base classes check out [this guide](doc:base-classes). # Immutable API It is common practice in javascript to extend objects with new properties and methods at will. This often is a great way to add state to an object or quickly hack around something that was not originally designed in an API. The down side of this practice is that code can quickly *rot* and that there is potential for conflicts when multiple plugins from different vendors would do something like that. This is the main reason that Cloud9 plugins have an immutable API - which means that outside plugins are not able to add, remove or overwrite properties on a plugin. There is a security aspect here as well: if a third party plugin could overwrite something like `http.request` it would have access to any private data that another plugin sends. This is prevented by the immutable APIs of Cloud9 plugins, which is achieved by the `freezePublicAPI()` method. This function *freezes* your plugin object. Because all properties on the API are immutable, you'll work with property getters and setters to set any dynamic properties and keep the state in a local variable. Also make sure to list the events that your plugin emits for documentation purpose and for future use. ``` var propertyName; function doSomething(){} /** * Describe your plugin here */ plugin.freezePublicAPI({ /** * @property type description */ type: "type", /** * @property propertyName description */ get propertyName(){ return propertyName; }, set propertyName(value){ propertyName = value; }, _events: [ /** * @event eventName description */ "eventName" ], /** * Description * @param {String} name description */ doSomething: doSomething }); ``` The Cloud9 documentation parser - which is forthcoming - will generate documentation for your plugin and make that available to whoever wants to build a plugin that consumes the APIs that you provide. # Event System Events are an integral part of Cloud9's plugin system. Events provide hooks that other plugins can use to add or alter functionality. ## Emitting events Emit plugins using the `emit()` function. You get a reference to this function by calling `getEmitter()` on the plugin. ``` var plugin = new Plugin("Your Name", main.consumes); var emit = plugin.getEmitter(); ``` [block:callout] { "type": "danger", "title": "Only emit events from within your plugin", "body": "Events *must* only be emitted by your plugin itself (or any of it's super classes). This helps keep code flows clean and prevents *hacky* solutions that will eventually cause spaghetti code and code paths with unexpected consequences." } [/block] The `getEmitter()` method is available *until* you call `freezePublicAPI()`, after which that function will no longer be provided. This secures your plugin from external plugins that might otherwise try to fire an event on your plugin. The `emit()` function takes two arguments; the event name and an optional event object. ``` emit("beforeExample", { data: [1, 2, 3] }); ``` Make an event *sticky* by calling `emit.sticky()`. ``` emit.sticky("initialized", { worker: worker }); ``` For more information on emitting events see [this guide](doc:events). ## Listening to events Similar to Node.js use the `on()` and `off()` methods to set and remove events. ``` plugin.on("beforeExample", function(e){ console.log("Event fired", e.data); }, otherPlugin); ``` The third argument is a reference to the plugin that is setting the event listener. When the `otherPlugin` is unloaded this event handler is automatically cleared. ``` plugin.off("beforeExample", someFunction); ``` For more in-depth information on events see [this guide](doc:events). # Load, Unload and CleanUp The `load()` method on `Plugin` will register the plugin and give it a name. Every plugin *must* have a name and the name is immutable once it's set. Fetch the name of a plugin using the `name` property. The `load()` method will fire the `load` event which you can use to execute code that initializes your plugin. ``` plugin.on("load", function(){ // i.e. add a menu item }); ``` The `unload()` method will unregister the plugin and clean up any resources that were used by your plugin. Note that a plugin won't unload if other plugins depend on it and will return `false` in that case. ``` plugin.unload(); ``` ## Clean up Throughout the Cloud9 APIs you'll find functions that take a plugin reference as their last argument. Some examples include adding a command, create a menu, adding an event listener, setting css and inserting html. By referencing your plugin as the plugin responsible for those resources, they will be cleaned up when your plugin unloads. You can also add some clean up code to a plugin by calling the `addOther()` method. ``` var resource = createSomething(); plugin.addOther(function(){ resource.destroy(); }); ```