Creating an content object plugin
Last updated
Last updated
This article will teach you how to go about creating a simple but complete content block object plugin. (There are also inline content objects in the Writer. Even so, we normally talk about content objects and inline objects.) A content object lives in the editable area.
Examples of content objects might be images, videos, maps or embedded social media posts.
There are number of css classes and building blocks you need to use in order to create a Writer compliant content object. These building blocks will ensure that your content object follows the UX guidelines of the Writer as well as give it support for generic properties
Generic properties are configurable key/values that can be attached to any content object through configuration independent of individual plugin configurations.
The Writer, and its plugins, are all built on a component model. There is a complete separation between the data a plugin handles and the UI used to visualize, or render, the data. As the UI is data driven this means that changes to data results in the UI being rerendered.
Even though the Writer is not based on React a good knowledge of React and how components, props and state works is very useful.
A simple content object require building a few different building blocks, of which some are tightly coupled through naming only. The parts required are:
Tool A small component rendering a menu option in the content menu.
Command Executed by clicking the tool in the content menu.
Node A schema that defines a data node. A data node is created by the command. (Data nodes can be inserted in other ways, e.g. drag’n drop, which is not part of this tutorial.)
Component Renders the data node into a visible UI object in the editors content area. Many plugins will have many sub components to maintain a good coding structure.
Converter Exports the data node to an articles xml and imports the xml from an article into a data node.
What binds all the parts together is the package file. This is a simple object with a configure function which you provide to the Writer. The configure function is called whenever the Writer is ready to initialise the plugin.
The configure function has two parameters. First a configurator object which contains all the functions necessary to register the plugins different building blocks. The second parameter is the plugin configuration as a plain object.
First you need a menu item in the content menu. A tool is a simple button component that can be rendered in the content menu (or other menus). Tools are normally very simple and there only to execute a command. The responsibility of the command is to perform the desired action. For example create and insert a data node.
To work as intended a tool must have a command registered with the same name. A command on the other hand can be be used independently.
The tool is a class that inherits from Tool found in Substance whereas the command inherits from WriterCommand found in Writer.
Both the tool and the command is registered in the package configure function.
A block node is in this context is a simple schema. Its purpose is to describe the data structure of a content objects data node. The data node will later be handed to a component as props to be rendered in the Writers editor area or be used by the converter to convert the data to and from XML.
The node schema, which extends the BlockNode imported from the Writer, must have a property called type. The type is what ties the data node to a specific (named) converter and a specific (named) component.
The component is what render the user interface your plugin displays to the user in the editor content area. Only one component is needed, but most plugins are split into many sub components to keep the project well structured.
A component without any bells an whistles could look like below.
And again both the node and the component must be added to the writer in the package configure function.
Note that we use the node type as the first parameter when we add the component to make sure the Writer know that these are connected.
Now that a node and component to render the node is defined you can go back to the command and actually create the node.
Note the type property of the node object which tells the Writer which node schema to use.
Now that the plugin can create and render a data node it is time to look into how to make sure the data is included when the article is saved. And of course that the plugin also picks it up when the article is opened in the Writer again.
For this a converter needs to be defined. A converter includes an export() function for converting the data node to XML and an import function to parse the XML into the data node again.
In addition two properties, type and tagName, as well as a matchElement() function is needed. The type property is what ties the converter to the node for exporting. The tagName defines the xml element name for the exported data. The matchElement() function on the other hand allows your code to investigate which xml elements you understand and wants to import.
Note the type which ties this converter to the specific node type.
Adding the converter should then make the package file complete.
Finally it is time to wrap it up by registering the plugin package when the Writer loads the plugin. This is done through a self executing function that call the registerPlugin() function in the Writer. Usually this is done in a separate index.js file.
These are the most basic building blocks needed to create a simple content object plugin in the Writer and it should get you started. Other things you might want to look into are drop handlers, events, macros and ways to add components to the top bar or the meta data column.