Create your first plugin

In this guide you will learn how to create your first plugin. You'll see, it's actually very easy!

Installation

With CTO UI, you can quickly bootstrap a new CTO plugin in seconds, instead of hours. Open up Terminal and enter:

  • First let's install the CLI
npm install -g @cryptool/cto-ui
  • Then let's create an new project.
ctoui create

Once that's done, you're ready-to-rock! A new project has been created with everything you need to start working on your first plugin.

Useful commands

Below is a list of commands you will probably find useful:

ctoui serve

Runs the project in development/watch mode. Your project will be rebuilt upon changes. CTO UI will create a development server where you'll be able to preview and debug your work.

Besides the hosting of the assets, we also start a Hot Module Reload server which is a websocket that listens to build events and reloads a script, style or your entire page depending on what changed. This is super useful as you no longer have to wait for the build to complete and manually refresh the page. Unfortunately, it might not be 100% stable so sometimes you might have to refresh the page yourself.

It also ensures all used libraries and frameworks are built in development mode, meaning you will get additional debug information if they provide any.

ctoui build

The production build command ctoui build does exactly what it says it does, which is building your plugin.

It creates production-ready bundles that contain very little to no unused and development code, ensuring your end-user gets fast load times. We achieve this by telling frameworks and libraries we're building for production by setting the process.env.NODE_ENV variable to production.

We also run a minifier over most assets to ensure code is as minimal as it can and do scope hoisting on all the JavaScript bundles to ensure as little unused code as possible ends up in the JavaScript bundles.

These bundles are also named in such a way that any non-html assets can be cached safely by a CDN for a very long time without any user ever having an incorrect or outdated bundle as the name includes a hash of the final bundle content.

Plugin creation

Now, let's create our first plugin! The first we'll want to do is open the index.js in the code editor of our choice. This is where we'll create our plugin. If you plan to create a basic plugin, you can keep all of your code in this file, but if you plan making something bigger, consider splitting your code into smaller pieces and use import/export to link everything together.

The algorithm

Let's start with the main piece of your plugin: the algorithm. This is the very reason of your plugin. So we've tried to make your life as easy as possible by proposing a very simple model to implement your code: nothing. That's right! You make your own algorithm, so why impose a particular structure?

Once you have your algorithm, you'll have to explain to CTO UI how it works. To do this, you need to create a class that we'll call "Algorithm" (although you can name it whatever you want).

class Algorithm {
/**
* You need to implement a constructor that will store the bindings. This way, you will be able to access them later.
*/
constructor(bindings) {
this.bindings = bindings;
}
/**
* Create an encode method that must set the output by itself. You do this by accessing `output.value` in your bindings.
*
* This way, we can ensure that only the ouput is re-rendered.
*/
encode() {
this.bindings.output = yourEncodeMethod(this.bindings.input) // Access the input value from the bindings
}
/**
* (Optional, only if you want to encode and decode)
*
* Same thing as the encode method but this time you need to set the input.
*/
decode() {
this.bindings.input = yourDecodeMethod(this.bindings.input)
}
}

Configuration

CTO UI needs a configuration object to understand how you want your plugin to work. This is where you will be able to customize almost everything.

The configuration object is organized in a simple way: each key is associated with a view. And these views are organized in the order you specified (i.e. the first element in the configuration object will appear first in the page). You will also need to define a parent entry that represents where the plugin should be rendered.

CTO UI already has pre-designed components that you can use.

import {
IO,
Direction
} from "@cryptool/cto-ui"; // Make sure to import the components from the package
const configuration = {
input: IO.Text,
direction: Direction.Both,
output: IO.Text,
parent: window.document.querySelector(".plugin") // Where the plugin will be rendered. Not an actual view.
}

If you're using CTO UI's template, the parent entry will be window.document.querySelector(".plugin"). This is because each plugin must provide an entry HTML file in CTO. The template includes this HTML file for you. Otherwise, if you want to use a custom HTML file, make sure to select the correct element.

Also, make sure that the element is empty otherwise its content will be cleared at render time.

Rendering

CTO UI exports a main object responsible for rendering and updating your plugin: PluginUI. This object has a `render' method that will be used to generate the interface.

PluginUI is compatible with server rendering (with jsDOM), so it is necessary to tell it the context it is in, taking care to add window as an argument to .render().

So in the end you should write:

import { PluginUI } from "@cryptool/cto-ui"; // Make sure to import from the package
const plugin = new PluginUI(Algorithm, configuration)
// Loads translations. Make sure to leave that here, even when you don't need to translate anything!
plugin.loadTranslations({}, window)
// Renders the final UI!
plugin.render(window)