Adding bits and pieces

This page will give you a few examples of how you add common bits and pieces to your plugin in your plugin package file.

The examples here will focus on the plugin package configure() method of your plugin You can read more about the anatomy of a plugin here.

const MyPackage = {
    id: 'se.infomaker.myplugin',
    name: 'myplugin',
    configure(configurator) {
        // Registration of all the bits and pieces
    }
}

export {MyPackage}

Adding tools and commands

Tools are essentially button components rendered in either the content or overlay menu. Tools normally execute commands, and commands perform actions.

Tools and commands are tightly interconnected, a tool must have a command registered with the same name, a command on the other hand can be used independently. Tools must extend from the Tool class and Command must extend from the Command class

This example adds a content tool to the content menu.

MyCommand.js

import {Command} from 'substance'

class MyCommandClass extends Command {

    getCommandState() {
        return {
            disabled: false
        }
    }

    execute() {
        console.log("Execute command")
    }
}
export {MyCommand}

MyTool.js

import {Tool} from 'substance'

class MyToolClass extends Tool {

    render($$) {
        const el = $$('span').append('click')
        el.on('click', () => {
            this.executeCommand('mycommand')
        })
        return el
    }
}

export {MyTool}

MyPackage.js

import {MyTool} from './MyTool'
import {MyCommand} from './MyCommand'

//...
    configure(configurator) {
        configurator.addContentMenuTopTool('mytool', MyTool)
        configurator.addCommand('mycommand', MyCommand)        
    }
///...

Adding tabs to sidebar

You can add your UI element components to tabs in the sidebar using configurator.addToSidebar() method. In this example a UI element component is added to the main sidebar tab. This code also forwards the plugin configuration to the component.

MyComponent.js

import {Component} from 'substance'

class MyComponent extends Component {

    render($$) {
        el.append($$('h2').append('Hello world'))
        return el
    }
}

export {MyComponent}

MyPackage.js

import {MyComponent} from './MyComponent'
// ...
    configure(configurator, pluginConfig) {
        configurator.addToSidebar(
            'main', // The main tab id, can be set to other
             pluginConfig,
             MyComponent)
    }
// ...

Adding Components

The configurator.addComponent() adds components to be rendered in the actual editor area. Components however can be used to render UI elements in the sidedar, dialogs, buttons etc.

MyComponent.js

import {Component} from 'substance'

class MyComponent extends Component {

    render($$) {
        el.append($$('h2').append('Hello world'))
        return el
    }
}

export {MyComponent}

MyPackage.js

import {MyComponent} from './MyComponent'

// ...
    configure(configurator) {
        configurator.addComponent('mycomponent', MyComponent)
    }
// ...

Adding nodes

What a component is rendering in the editor areas is mostly based on some data. This data is represented by a Node. A node is an internal data representation that can be converted to and from XML.

The NodeClass must have a property called type. This type is matched with the converters (see below) which is responsible for converting back and forth between XML and the node.

MyNode.js

import {BlockNode} from 'substance'

class MyNode extends BlockNode {}

    MyNode.type = 'mytype'
    MyNode.define({
        "propertyNumber": { type: "number", default: 1 },
        "propertyString": { type: "string", optional: true },
    })

export {MyNode}

MyPackage.js

import {MyNode} from './MyNode'

// ...
    configure(configurator) {
        configurator.addNode(MyNode)
    }
// ...

Adding converters

Converters are, as mentioned above, responsible for transforming XML into a Node and back to XML.

When you add a converter the first parameter specifies the format of the document, we are using newsml. As mentioned above the type property is what ties a converter and a node together. So the type must be the same as for the node.

The converter must have three methods:

  • matchElement() receives an xml element and returns either true or false to indicate whether it wants to transform the xml element into a node.
  • import() receives an xml element and an empty node of the correct type. The node should be initalized from the xml element. This method is called when a NewsML document is opened.
  • export() receives the node (with data), an xml element and a text converter that is used to handle annotated text (ie text with bold, italic and other annotations). This method is called when the NewsML is saved (serialized).

MyConverter.js

const MyConverter = {
    type: 'mytype',
    tagName: 'object',

    matchElement: function (el) {
        return el.is('object[type="mytype"]');
    },

    import: function (el, node) {
        node.id = el.attr('id')
        node.propertyNumber = el.attr('mynumber')
        node.propertyString = el.attr('mystring')
    },

    export: function (node, el, converter) {
        var $$ = converter.$$;
        el.attr({
            id: node.id,
            mynumber: node.propertyNumber,
            mystring: converter.annotatedText([node.id, 'propertyString'])
        });
    }
}

export {MyConverter}

MyPackage.js

import {MyConverter} from './MyConverter'

// ...
    configure(configurator) {
        configurator.addConverter(Converter)
    }
// ...

results matching ""

    No results matching ""