Naviga Writer
6.3.3
6.3.3
  • Naviga Writer
  • Release notes
    • 6.3.3
    • 6.3.2
    • 6.3.1
    • 6.2.1
    • 6.2.0
    • 6.1.2
    • 6.1.1
    • 6.1.0
    • 6.0.0
    • 5.3.0
  • Introduction
    • Authoring
    • Developing
    • Publishing
    • User stories and reference cases
  • User Guide
    • Writer User Guide
      • The Content Area and Tabs
        • Help menu
        • Language menu
        • Article name
        • Writing teasers
        • Content area
        • Information
        • Search and replace words
        • History Button
        • Save and publish flow
        • Tabs
          • Meta Tab
            • Author
            • Channels
          • Integrations Tab
          • Image and Article search Tab
        • Locked article
      • Text management
      • Writer Keyboard Shortcuts
      • Personal Writer template
      • Channels to control access
      • Images User Guide
      • Common questions when starting using Writer
  • Admin Guide
    • Configuration files
    • Configurations Guide
    • Configuration of Writer templates
    • Publish Flow
      • Default configuration definitions
      • Starting part of the configuration
      • Publish flow config details
      • Configuration of calendarLocale
      • Preconditions for roles in the publish flow
    • Generic properties for Objects
      • Generic properties configuration
    • Image Services
      • Photo uploader
      • Binary Service Light
      • ImEngine
      • Imgix
    • Available Plugins
      • Naviga developed plugins
        • Plugins in earlier versions of Writer
      • Third-party plugins
  • Developer guide
    • Writer plugin development
      • Quickstart
      • Plugin overview
      • Creating an content object plugin
      • Validation and hooks
      • Interacting with external resources
    • Writer Plugin Building Blocks
      • Package
      • Component
      • Node
      • Converter
      • Events
    • Writer plugin style guide
      • CSS Guidelines
      • CSS variables, colors and fonts
      • UI Components
    • Tutorials
      • Popover & text analysis
      • Search & replace
      • Concept interaction
    • Infomaker NewsML
      • Overview
      • Document relations and types
      • Extensions XSD
      • NewsItem
      • ConceptItem
      • PlanningItem
      • Examples
        • NewsItem - Text
        • NewsItem - Picture
        • NewsItem - PDF
        • ConceptItem - Author
        • ConceptItem - Category
        • ConceptItem - Channel
        • ConceptItem - Content Profile
        • ConceptItem - Event
        • ConceptItem - Organisation
        • ConceptItem - Person
        • ConceptItem - Place (point)](point)](point)](point)](point)](point)](point)](point)](point)](point)]
        • ConceptItem - Place (polygon)](polygon)](polygon)](polygon)](polygon)](polygon)](polygon)](polygon)]
        • ConceptItem - Section
        • ConceptItem - Story
        • ConceptItem - Topic
        • PlanningItem
    • Media Enrichment
      • Images
  • API Reference
    • Writer Api
      • Api
      • Article
      • Browser
      • Concept
      • ConceptService
      • Document
      • Events
      • NewsItem
      • Router
      • Ui
      • Upload
      • User
      • settings
    • UI Components
      • UIAvatar
      • UIButton
      • UIByline
      • UICheckbox
      • UIChip
      • UIDatePicker
      • UIDatetimeFieldEditor
      • UIDropdown
      • UIFieldEditor
      • UIIconButton
      • UIInlineImage
      • UIPagination
      • UISelect
      • UITimePicker
      • UIToggle
      • UITooltip
      • UIInputText
      • UITextarea
Powered by GitBook
On this page
  • Plugin Structure
  • Example Plugin Structure
  • MyPluginPackage.js
  • The configurator object
  • Common Add-functions
  • Tools and Commands

Was this helpful?

  1. Developer guide
  2. Writer Plugin Building Blocks

Package

This text will explore the Package file used to define the parts included in, and used by a Writer plugin.

Plugin Structure

A plugin is a collection of many different resources, and the Package file is that collection's bootstrap. Label definitions, node- and converter-registration, adding validatiors, and registering tools and commands, are all placed in the Package file, using the Writer's NPWriterConfigurator-class.

The Package file also contains the plugin's name and id.

Example Plugin Structure

/ se.mydomain.myplugin
  / components
    MyPluginComponent.js
    ChildComponent.js
  MyPluginNode.js
  MyPluginConverter.js 
  MyPluginPackage.js
  index.js

In this example, index.js is the plugin's entrypoint. It's here where the Package file is imported and the plugin is registered in the Writer.

MyPluginPackage.js contains information about the plugin, and registers MyPluginNode.js as a substance node, MyPluginConverter.js as a NewsML-converter, and MyPluginComponent.js as the component used to present MyPluginNode.js.

Depending on the type of plugin, the Package will contain different definitions and registrations.

MyPluginPackage.js

import './scss/link.scss' // Provide an entrypoint for the plugin's style
import MyPluginNode from './MyPluginNode'
import MyPluginConverter from './MyPluginConverter'
import MyPluginComponent from './components/MyPluginComponent'

export default {
    name: 'my-plugin',
    id: 'se.mydomain.myplugin',
    configure: function (configurator, pluginConfig) {

        configurator.addNode(MyPluginNode)
        configurator.addComponent(MyPluginNode.type, MyPluginComponent)
        configurator.addConverter('newsml', MyPluginConverter)

        configurator.addLabel('Hello World', {
            sv: 'Tjena Världen'
        })
    }
}

This example Package file contains definitions for a Node, a Component linked to the Node's type-property, a Converter to import and export the Node-data using NewsML. It also adds a label which can be used within the plugin's components.

The configurator object

As seen in the Package example above, the supplied configurator-object is used to add different resources used in the plugin. Below are relevant configurator-functions which are useful when developing a plugin.

Common Add-functions

addNode(NodeClass) Registers a node in Substance configuration for use later.

addComponent(type, ComponentClass) Registers a class which extends Substance's Component-class for a Node type. A Component in this instance is a UI representation of a Node class. Only on Component can be registered to one specific type.

addConverter(converterObject) Registers a converter object for a specific output type. A converter is an object used for exporting and importing the data stored in a Node object.

addLabel(label, { translations }) Adds a localized label string which can be fetched in the plugin's components using this.getLabel(string), assuming that the component is extending Substance's Component-class. The first string property is used as fallback if none of the supplied translations are found.

Label Example:

configurator.addLabel('Hello World', {
    sv: 'Hejsan Världen'
})

this.getLabel('Hello World') 
// If the Writer's configured "labelLanguage" property is set 
// to "sv", "Hejsan Världen" is returned, any other language
// will return "Hello World"
configurator.addIcon('my-icon', {'fontawesome': 'fa-external-link'})

$$(Button, {
    icon: 'my-icon'
}).on('click', () => { console.info('Foobar') })

addKeyboardShortcut(combo, spec, globalCombo, description = '') Add keyboard shortcut and connect to a Command.

Keyboard Shortcut Example:

  // configure function in a Package file

  const combo = {
    standard: {
        'default': 'ctrl+d',
        'mac': 'cmd+d'
    }
  }

  configurator.addKeyboardShortcut(combo, {command: 'my-amazing-command'}, true, 'Runs my amazing command in the global context.')

addValidator(Validator) Adds a class which inherits from Validator to validate the Article's content and metadata before saving.

Validator Example:

import {Validator, api} from 'writer'

class MyHeadlineValidator extends Validator {

    constructor(...args) {
        super(...args)
    }

    /**
     * Main validation method
     */
    validate() {
        this.validateHeadline()
    }

    /**
     * Ensure that a valid headline exists
     */
    validateHeadline() {
        const headlines = this.newsItem.querySelectorAll('idf > group element[type="headline"]')
        const headline = headlines[0].childNodes.length === 0 ? '' : headlines[0].firstChild.textContent.trim()

        if (headlines.length === 0 || headline === '') {
            this.addError(
                api.getLabel('Headline is missing or empty!')
            )
        }
    }
}

export {MyHeadlineValidator}

addToSidebar(tabId, pluginConfig, ComponentClass) Registers a Component to be rendered in the Sidebar. tabId is a string, which is the id of the tab, but also the label which is used for the tab. If the tab does not exist, it will be created, and the Component added to this new tab.

addTopBarComponent(id, def, component) Registers a Component to be rendered in the Top bar. The parameter def is an object which contains alignment, whether the Component is placed on the left, or right, side of the top bar.

Topbar Example:

configurator.addTopBarComponent(
    'my-amazing-topbar-component',
    {
        align: 'left' // Or 'right'
    },
    MyAmazingTopBarComponent
)

addPopover(id, def, component) Similar to addTopBarComponent, this function adds an icon in the Top bar which, when clicked opens a popover overlay with its component rendered inside.

Popover Example:

configurator.addPopover(
    'my-amazing-popover',
    {
        icon: 'fa-smiley',
        align: 'right',
        sticky: true    // Set to `true` to keep the popover open when clicking somewhere else, default `false`
    },
    MyAmazingComponent
)

Tools and Commands

Tool class Example:

import {Tool} from 'substance'

class MyAmazingTool extends Tool {

    render($$) {
        return $$('div').attr('title', this.getLabel('Cheers you up'))
            .append(
                $$('button').addClass('se-tool').append(
                    $$('i').addClass('fa fa-smile')
                )
                    .on('click', this.executeCommand) // This will execute the command which name was used to register the Tool 
            )
      }
}

export {MyAmazingTool}

addCommand(name, CommandClass, options) Adds a Command which can be executed by a Tool, or manually using EditorSession. In its simplest form, a Command contains the logic for a Tool.

Command Example:

import {WriterCommand} from 'writer'

class MyAmazingCommand extends WriterCommand {

  /**
  * Executes command with supplied params.
  * When called from Tool class, props from Tools is contained in params.
  * 
  * @param params
  */
  execute(params) {
      console.info('Have a great day!')
      console.info('Also, here\'s the supplied data', params)
  }
}

export {MyAmazingCommand}

addContentMenuTool(commandName, ToolClass) Adds a Tool to the Content Menu, it should return a rendered ContextMenuItem instance.

addContentMenuTopTool(commandName, ToolClass) Adds a Tool to the top of the Content Menu.

addContextMenuTool(commandName, ToolClass) Adds a Tool to the context menu, e.g when right clicking on the editing surface.

addOverlayTool(commandName, ToolClass) Adds a Tool which is displayed when selecting text, such as annotation plugins.

PreviousWriter Plugin Building BlocksNextComponent

Last updated 5 years ago

Was this helpful?

To learn more about Nodes, Converters, and Components, have look at .

addIcon(iconName, options) Registers an icon from , or another registered icon provider for use in the plugin. Example:

Adding a Tool is a simple way to add a button, or some text, which can execute a Command when clicked. The only difference between the add***Tool()-functions is where in the Writer the Tool is added. When adding a Tool, it needs the name of the Command (which was previously registered) it should be bound to, and a class which is used to render the Tool. For a visual representation of all the Writer sections, see the .

their respective documents
FontAwesome
Plugin Overview