-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: added @pascalwilbrink's guide for plugin development
- Loading branch information
1 parent
1a25078
commit 4147bf6
Showing
1 changed file
with
229 additions
and
0 deletions.
There are no files selected for viewing
229 changes: 229 additions & 0 deletions
229
collections/_guides/How-to-write-a-plugin-for-OpenSCD.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
|
||
|
||
# How to write a plugin for OpenSCD | ||
|
||
This tutorial will explain on how to write a plugin for OpenSCD. | ||
|
||
## Prerequisites | ||
* Node ( LTS) | ||
* Git | ||
* An IDE | ||
|
||
In this example, we will use the Lit framework ([https://lit.dev](https://lit.dev)) to create a plugin for OpenSCD. On top of the Lit framework, we make use of the standards provided by Open Web Components ([open-wc.org](https://open-wc.org/)). | ||
|
||
# TOC | ||
* Scaffolding a new plugin | ||
* Setting up property injection | ||
* Choosing the plugin type | ||
* Adding functionality to the plugin | ||
|
||
|
||
## Scaffolding a new plugin | ||
We can scaffold a new empty project by using the `@open-wc` init command. | ||
|
||
```bash | ||
npm init @open-wc | ||
``` | ||
--- | ||
|
||
When prompted, choose the following: | ||
|
||
`What would you like to do today?` › Scaffold a new project | ||
|
||
`What would you like to scaffold?` › Web Component | ||
|
||
`What would you like to add?` › Linting (eslint & prettier), Testing (web-test-runner), Demoing (storybook) | ||
|
||
`Would you like to use typescript?` › Yes | ||
|
||
`What is the tag name of your web component?` › oscd-my-new-plugin | ||
|
||
--- | ||
|
||
After scaffolding is complete, the first thing that we need to do is to change the plugin class. | ||
|
||
Open the `OscdMyNewPlugin.ts` file in the `src` folder and change the following line: | ||
|
||
```diff | ||
- export class OscdMyNewPlugin extends LitElement { | ||
+ export default class OscdMyNewPlugin extends LitElement { | ||
``` | ||
|
||
> Note the `default` keyword. | ||
--- | ||
|
||
Now, the `src/oscd-my-new-plugin.ts` file needs to be changed: | ||
|
||
```diff | ||
- import { OscdMyNewPlugin } from './OscdMyNewPlugin.js'; | ||
+ import OscdMyNewPlugin from './OscdMyNewPlugin.js'; | ||
``` | ||
|
||
> Note the removed brackets | ||
--- | ||
|
||
The last thing we have to change, is the `src/index.ts` file. | ||
|
||
```diff | ||
- export { OscdMyNewPlugin } from './OscdMyNewPlugin.js'; | ||
+ export * from './OscdMyNewPlugin.js'; | ||
``` | ||
|
||
> Note the asterisk on export | ||
--- | ||
|
||
This change is making sure that the plugin is default exported, so that OpenSCD can dynamically import it correctly. | ||
|
||
## Setting up property injection | ||
In order to start displaying or editing the SCL file, we first need to add properties that will be injected into the plugin. | ||
|
||
Inside the `OscdMyNewPlugin.ts` file, add the following code: | ||
|
||
```TypeScript | ||
import { html, css, LitElement } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
|
||
export default class OscdMyNewPlugin extends LitElement { | ||
|
||
@property({ type: Object }) | ||
doc!: XMLDocument; | ||
|
||
@property({ type: Number }) | ||
editCount = -1; | ||
|
||
@property({ type: String }) | ||
locale!: string; | ||
|
||
... | ||
``` | ||
These properties will be injected into the Plugin from the OpenSCD host. | ||
## Choosing the Plugin type | ||
OpenSCD currently supports 2 different plugin types. | ||
* Menu type plugins | ||
* Editor type plugins | ||
### Menu type plugins | ||
--- | ||
Menu type plugins usually run on the background. They are displayed in the sidebar menu and are rendered at all times. | ||
Example of menu type plugins are: | ||
* Validators | ||
* Generators | ||
### Editor type plugins | ||
--- | ||
Editor type plugins are displayed in the main Editor. An editor type plugin will be rendered when it's being activated by the Tab bar on top of OpenSCD. | ||
Examples of editor type plugins are: | ||
* Communication editor | ||
* Substation editor | ||
* Single Line Diagram | ||
If you choose to make your plugin a Menu type plugin, you need to implement the `run` method in your plugin. | ||
```TypeScript | ||
import { html, css, LitElement } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
|
||
export default class OscdMyNewPlugin extends LitElement { | ||
|
||
@property({ type: Object }) | ||
doc!: XMLDocument; | ||
|
||
@property({ type: Number }) | ||
editCount = -1; | ||
|
||
@property({ type: String }) | ||
locale!: string; | ||
|
||
async run(): Promise<void> { | ||
... Plugin implementation goes here | ||
} | ||
``` | ||
If you choose to make your plugin an Editor type plugin, you need to implement the `render` function from Lit. | ||
```TypeScript | ||
import { html, css, LitElement, TemplateResult } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
|
||
export default class OscdMyNewPlugin extends LitElement { | ||
|
||
@property({ type: Object }) | ||
doc!: XMLDocument; | ||
|
||
@property({ type: Number }) | ||
editCount = -1; | ||
|
||
@property({ type: String }) | ||
locale!: string; | ||
|
||
render(): TemplateResult { | ||
return html`<div>My plugin works!</div>`; | ||
} | ||
``` | ||
In this example, we'll choose for an editor type plugin. | ||
## Adding functionality to the plugin | ||
The SCL document can be traversed like any other HTMLElement. | ||
Let's say you want to list all the SubStations inside the plugin. | ||
You can do so by using | ||
```TypeScript | ||
Array.from(doc.querySelectorAll('Substation')).map((substation) => substation.getAttribute('name')); | ||
``` | ||
```TypeScript | ||
import { html, css, LitElement, TemplateResult } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
|
||
export default class OscdMyNewPlugin extends LitElement { | ||
|
||
@property({ type: Object }) | ||
doc!: XMLDocument; | ||
|
||
@property({ type: Number }) | ||
editCount = -1; | ||
|
||
@property({ type: String }) | ||
locale!: string; | ||
|
||
renderSubstationNames(): TemplateResult { | ||
return html`<ul> | ||
${Array | ||
.from(this.doc.querySelectorAll('Substation')) | ||
.map((substation) => substation.getAttribute('name')) | ||
.map((name) => html`<li>${name}</li>`) | ||
}</ul>`; | ||
} | ||
|
||
render(): TemplateResult { | ||
return html`<div>${this.renderSubstationNames()}</div>`; | ||
} | ||
``` | ||
You can make the plugin as simple or difficult as you want. | ||
## Building the plugin | ||
After implementing your logic in the plugin, it's time to build the plugin. | ||
Thankfully, the Open-WC standard provides us with npm scripts to easily build the plugin. | ||
```bash | ||
npm run build | ||
``` | ||
The script above creates the build output which can be hosted on GitHub for example. Just copy over the build directory and you're good to go. | ||
--- | ||
And that's it! You just successfully created and built a plugin that can be used with OpenSCD. | ||
In a different guide, we will cover more advanced things, like editing the SCL file. | ||
> If you're looking for the full code of this guide, [you can find it here](https://github.com/openscd/oscd-plugin-template). This repository also has templates for other frameworks. |