Skip to content
Snippets Groups Projects
README.md 4.9 KiB
Newer Older
Xiao Gui's avatar
Xiao Gui committed
# Plugin README

Xiao Gui's avatar
Xiao Gui committed
A plugin needs to contain three files. 
- Manifest JSON
- template HTML
Xiao Gui's avatar
Xiao Gui committed

Xiao Gui's avatar
Xiao Gui committed
These files need to be served by GET requests over HTTP with appropriate CORS header. 
Xiao Gui's avatar
Xiao Gui committed

## Manifest JSON

Xiao Gui's avatar
Xiao Gui committed
The manifest JSON file describes the metadata associated with the plugin. 

```json
{
  "name":"fzj.xg.helloWorld",
  "displayName": "Hello World - my first plugin",
Xiao Gui's avatar
Xiao Gui committed
  "templateURL":"http://LINK-TO-YOUR-PLUGIN-TEMPLATE/template.html",
  "scriptURL":"http://LINK-TO-YOUR-PLUGIN-SCRIPT/script.js",
  "initState":{
    "key1": "value1",
    "key2" : {
      "nestedKey1" : "nestedValue1"
    }
  },
Xiao Gui's avatar
Xiao Gui committed
  "initStateUrl": "http://LINK-TO-PLUGIN-STATE",
Xiao Gui's avatar
Xiao Gui committed
  "persistency": false,

  "description": "Human readable description of the plugin.",
  "desc": "Same as description. If both present, description takes more priority.",
  "homepage": "https://HOMEPAGE-URL-TO-YOUR-PLUGIN/doc.html",
  "authors": "Author <author@example.com>, Author2 <author2@example.org>"
Xiao Gui's avatar
Xiao Gui committed
}
```
*NB* 
Xiao Gui's avatar
Xiao Gui committed
- Plugin name must be unique globally. To prevent plugin name clashing, please adhere to the convention of naming your package **AFFILIATION.AUTHORNAME.PACKAGENAME\[.VERSION\]**. 
- the `initState` object and `initStateUrl` will be available prior to the evaluation of `script.js`, and will populate the objects `interactiveViewer.pluginControl[MANIFEST.name].initState` and `interactiveViewer.pluginControl[MANIFEST.name].initStateUrl` respectively. 
Xiao Gui's avatar
Xiao Gui committed

## Template HTML

Xiao Gui's avatar
Xiao Gui committed
The template HTML file describes the HTML view that will be rendered in the widget.


```html
<form>
  <div class = "input-group">
    <span class = "input-group-addon">Area 1</span>
    <input type = "text" id = "fzj.xg.helloWorld.area1" name = "fzj.xg.helloWorld.area1" class = "form-control" placeholder="Select a region" value = "">
  </div>

  <div class = "input-group">
    <span class = "input-group-addon">Area 2</span>
    <input type = "text" id = "fzj.xg.helloWorld.area2" name = "fzj.xg.helloWorld.area2" class = "form-control" placeholder="Select a region" value = "">
  </div>

  <hr class = "col-md-10">

  <div class = "col-md-12">
    Select genes of interest:
  </div>
  <div class = "input-group">
    <input type = "text" id = "fzj.xg.helloWorld.genes" name = "fzj.xg.helloWorld.genes" class = "form-control" placeholder = "Genes of interest ...">
    <span class = "input-group-btn">
      <button id = "fzj.xg.helloWorld.addgenes" name = "fzj.xg.helloWorld.addgenes" class = "btn btn-default" type = "button">Add</button>
    </span>
  </div>

  <hr class = "col-md-10">

  <button id = "fzj.xg.helloWorld.submit" name = "fzj.xg.helloWorld.submit" type = "button" class = "btn btn-default btn-block">Submit</button>

  <hr class = "col-md-10">

  <div class = "col-md-12" id = "fzj.xg.helloWorld.result">

  </div>
</form>
```
Xiao Gui's avatar
Xiao Gui committed

Xiao Gui's avatar
Xiao Gui committed
*NB*
Xiao Gui's avatar
Xiao Gui committed
- *bootstrap 3.3.6* css is already included for templating.
Xiao Gui's avatar
Xiao Gui committed
- keep in mind of the widget width restriction (400px) when crafting the template
- whilst there are no vertical limits on the widget, contents can be rendered outside the viewport. Consider setting the *max-height* attribute.
- your template and script will interact with each other likely via *element id*. As a result, it is highly recommended that unique id's are used. Please adhere to the convention: **AFFILIATION.AUTHOR.PACKAGENAME.ELEMENTID** 
Xiao Gui's avatar
Xiao Gui committed

Xiao Gui's avatar
Xiao Gui committed
---
Xiao Gui's avatar
Xiao Gui committed

## Script JS

Xiao Gui's avatar
Xiao Gui committed
The script will always be appended **after** the rendering of the template. 

```javascript
(()=>{
  /* your code here */

  if(interactiveViewer.pluginControl['fzj.xg.helloWorld'].initState){
    /* init plugin with initState */
  }
  
Xiao Gui's avatar
Xiao Gui committed
  const submitButton = document.getElemenById('fzj.xg.helloWorld.submit')
  submitButton.addEventListener('click',(ev)=>{
    console.log('submit button was clicked')
  })
})()
```
*NB*
Xiao Gui's avatar
Xiao Gui committed
- JS is loaded and executed **before** the attachment of DOM (template). This is to allow webcomponents have a chance to be loaded. If your script needs the DOM to be attached, use a `setTimeout` callback to delay script execution.
Xiao Gui's avatar
Xiao Gui committed
- ensure the script is scoped locally, instead of poisoning the global scope
- for every observable subscription, call *unsubscribe()* in the *onShutdown* callback
- some frameworks such as *jquery2*, *jquery3*, *react/reactdom* and *webcomponents* can be loaded via *interactiveViewer.pluinControl.loadExternalLibraries([LIBRARY_NAME_1, LIBRARY_NAME_2])*. if the libraries are loaded, remember to hook *interactiveViewer.pluginControl.unloadExternalLibraries([LIBRARY_NAME_1,LIBRARY_NAME_2])* in the *onShutdown* callback
- when/if using webcomponents, please be aware that the `connectedCallback()` and `disconnectedCallback()` will be called everytime user toggle between *floating* and *docked* modes. 
Xiao Gui's avatar
Xiao Gui committed
- when user navigate to a new template all existing widgets will be destroyed, unless the `persistency` is set to `true` in `manifest.json`.
Xiao Gui's avatar
Xiao Gui committed
- for a list of APIs, see [plugin_api.md](plugin_api.md)