From 4147bf68891a685b8c401b4918693e06e092eff0 Mon Sep 17 00:00:00 2001 From: Juan Munoz Date: Tue, 6 Feb 2024 10:02:32 +0000 Subject: [PATCH] docs: added @pascalwilbrink's guide for plugin development --- .../How-to-write-a-plugin-for-OpenSCD.md | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 collections/_guides/How-to-write-a-plugin-for-OpenSCD.md diff --git a/collections/_guides/How-to-write-a-plugin-for-OpenSCD.md b/collections/_guides/How-to-write-a-plugin-for-OpenSCD.md new file mode 100644 index 0000000..ca9933a --- /dev/null +++ b/collections/_guides/How-to-write-a-plugin-for-OpenSCD.md @@ -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 { + ... 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`
My plugin works!
`; + } +``` + +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``; + } + + render(): TemplateResult { + return html`
${this.renderSubstationNames()}
`; + } +``` + +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.