mephux/komanda — pull request #157 by xqwzts (2014-06-30 19:42:09+00:00)
Title: Modular plugins

### Overview:
This pull request creates a basic plugin system.

The main components of the PR are:
- The plugin loader.
- The channel API.
- The github plugins.

### Plugin Loader:

Plugins must be valid node modules located in a plugins folder under the application's [datapath](https://github.com/rogerwang/node-webkit/wiki/App#datapath). To be included the plugin has to be registered in the plugins.json file.

plugins.json example:
```json
[
{
"name": "github-feed",
"location": "github-feed",
"main": "main.js",
"channel": true,
"topic": true,
"stylesheet": "/styles/github-feed.css"
}
]
```

`name`: the plugin name, should be unique to this plugin.
`location`: plugin folder's location.
`main`: script the plugin is located in.
`channel`: [boolean] flag determining if this is a channel plugin and should be loaded/initialized when a new channel is open.
`stylesheet`: [optional] location of stylesheet that should be injected when the plugin is loaded [relative to the plugin's location]
`disabled`: [optional][boolean] If set to true the plugin will not be loaded by komanda.

The `loadPlugins()` function in helpers.js is responsible for checking the plugins.json file and reading each plugin's settings before loading it. It checks to make sure that the plugin file specified under `main` exists in the specified `location`, and does the same for the `stylesheet` if one is specified.

A JSON definition for each plugin is then pushed to the Komanda.settings.plugins array.

When a new ChannelView is created it instantiates each plugin that has defined `channel: true` in its settings.

### Channel API:
The ChannelView module defines a ChannelAPI with the following methods:

`getTimestamp`: Returns a Komanda formatted timestamp, using the timestamp helper.
`addChannelMessage`: Appends the provided HTML to the channel's message attach point and scrolls the view to display the full message.
`setToolbar`: Prepends the provided HTML to the channel's toolbar attach point and sets the toolbar-attached class. This will replace any other toolbar currently attached.
`removeToolbar`: Removes the toolbar attached at the channel's toolbar attach point.
`onChannelTopicChange`: Registers a callback to be triggered when the channel's topic changes.

When a new plugin is loaded, the ChannelView creates a new instance of the ChannelAPI and provides it to the plugin. The plugin is required to provided an initialize() method which gets called by the ChannelView and to which the ChannelAPI will be passed.

### Github Plugins:
The github functionality that was previously part of the ChannelView has been extracted into two github plugins.

##### github-feed:
A plugin that handles feed changes and adds them as channel messages.

##### github-toolbar:
A plugin that displays a toolbar at the top of the channel with the github repo's metadata.

Each plugin is a node module with its own package.json definition as well as a stylesheet [extracted from komanda.css] and template.

There is an issue here when using hbs/handlerbars that people should be aware of: The handlebars context used when rendering a plugin template will not be the same context that the plugin itself has, so while this can be used to compile the template, any helpers [and partials?] will _not_ be available at runtime. To work around this helper functions can be defined in the module and passed in manually to the template when resolving it.

### Installing Plugins:
The github plugins are included in the `/plugins` directory in the source. These should be copied to the app's data path and installed there individually [with `npm install`] in order to pull their node dependencies. The `plugins.json` file should be in the root plugins directory.

### Plugin Contract:
Plugins are required to proved the following functionality, and accessible methods:

`initialize`: An initialize method will be called when the plugin is loaded, and a copy of the channel API will be provided to it.
`close`: The close method will be called when the channel is closed, the plugin should gracefully terminate when called.

### Improvements:
Some places this can be improved:

- Custom plugin directory: At the moment the plugins folder is expected to be found under the app's [DataPath](https://github.com/rogerwang/node-webkit/wiki/App#datapath). We could have a folder selector to change that directory.
- Move ChannelAPI: The channel API is currently part of the ChannelView, we might want to move this to live in its own module, `Komanda.API` perhaps?