Operations

What are operations?

Interaction with the state of the FontoXML instance usually occurs through executing operations. Packages can define their own operations by combining operations, transforms and actions defined by the platform or the instance‚Äôs own packages. 

Please refer to the Editor API reference for a complete overview of the operations and transforms provided by the FontoXML platform.

Operations are defined in an operations.json, which is an object mapping operation names to their definitions. Any operations.json or operations-*.json file in the src directory of your package will be automatically included.

Each operation is defined as an object with the following properties:

Property Type Description
label string (Optional) label used when the operation is used in a UI element such as a button or menu item.
description string (Optional) used as tooltip text by UI elements using the operation.
icon string (Optional) icon displayed by UI elements using the operation. This should be a Fontawesome (v4.7.0) icon.
errorsAreFatal boolean (Optional) whether failure of the operation should redirect to the error route. If this is false (the default value), a modal will be shown.
steps object | object[ ] Steps executed when the operation is invoked. Steps form a pipeline, passing step data from each step to the next.
getStateSteps

object | object[ ]

(Optional) for operations with side-effects, it may be necessary to provide separate steps used to compute the state of the operation. Defaults to the steps of the operation, but using the getState callbacks for transforms and actions as appropriate.
initialData object (Optional) data with which to start the steps and getStateSteps pipelines.
keyBinding string

(Optional) sets a keyboard listener that executes this operation when a particular combination is pressed. For information on syntax and examples for keybindings, see the KeyBinding documentation. While it is possible to use a ctrl+b/cmd+b keybinding here, it would cause the shortcut win+b on Windows or super+b on Linux to also bind to the operation. Use osxKeyBinding if this should not happen.

Please note that browser keybindings and OS keybindings are reserved and will take precedence over any keybinding you will configure for FontoXML.


keyBindingDisabled boolean (Optional) Prevents FontoXML from actually listening for the keyboard combination.
osxKeyBinding string (Optional) Keybindings for OSx keyboards. this can be used to redefine shortcuts using the cmd key instead of the ctrl key.

Labels, footnotes and icons can be overriden for an operation by using the "label", "description" or "icon" props on buttons or menu items.

"Alternatives" operations

An alternative form of the operation definition uses the alternatives property instead of steps, providing an array of operation names. Such an operation will adopt the behavior of the first of these operations which is enabled.

Operation steps

Steps or getStateSteps can either consist out of one step or out of an array of steps. Each step has a type and optional data. Each step can modify step data internally, and the data template for each step can define new properties, possibly reusing existing data using the "expression.to.property" syntax.

There are different types of steps, which are prefixed in the type property of the step. The steps can already exist in the platform or else can be created:

Step type Description See also
transform Is used to manipulate the step data. This should ideally not have any side-effects. List of existing transforms, addTransform
action Is used to change the state of the application other than the document content. This includes, for example, controlling UI components or communicating with the CMS. An action can also abort the running operation by returning the addAction.CANCEL_OPERATION value from its run callback. List of existing actions, addAction
operation

Not all operations should be directly used in a button, these operations can be used as sub-operation. Sub-operations are passed the current step data from the operation that invokes them, which can be used to control their behavior.

It is also possible to omit the operation name part of a step with the type operation. In this case, the name of the operation will be read from the operationName property of the stepData. This allows for composing fully dynamic operations. Because the state of these operations may not be automatically invalidated, it is recommended to consider alternatives instead.

List of existing operations, Creating an operation
custom-mutation Is used to manipulate the xml. Only use this if none of the existing operations can be used. addCustomMutation
modal Is used to open a modal. Modals can be submitted to provide step data for the next step in the operation, or canceled to abort the operation.

Create a modal

Operation state

Each operation has an associated state, consisting of two booleans: enabled and active. The enabled flag indicates whether the operation is allowed to run given the current context. The active flag symbolizes whether the effect of the operation already applies, and is usually visualized by showing the UI component as active/pressed/selected (using the isSelected prop).

The state of an operation is derived from the loaded documents and other application state, including the current cursor position or selection, but also the state of UI elements. Normally, the steps used to determine the state of an application are derived from the steps used to run it, although an operation can also specify the getStateSteps explicitly. Be careful that the behavior of these steps still corresponds to the actual behavior of the operation, so an operation is not enabled when it cannot be executed correctly.

When determining the state of the operation, each of the step types functions as follows:

Step type Behavior when getting operation state
transform It is assumed that a transform glues other operation steps together by modifying step data without side-effects, so in most cases the transform is executed as normal. If a separate get state callback was passed to addTransform, that is executed instead. This can be used if the transform is not entirely without side-effects, or can be simplified when getting operation state.
action If a get state callback was passed to addAction, that function may return the state of the operation at this point, or return null to continue processing. Otherwise, processing continues with the next operation step (the action is ignored).
operation The state of the operation being referenced is computed and used. Built-in operations that modify the DOM use a process similar to custom mutations to determine their state.
custom-mutation The CustomMutation is executed on a Blueprint without affecting the actual DOM. If the custom mutation returns CustomMutationResult.ok() and the resulting DOM is valid, the operation is enabled. If the custom mutation returns CustomMutationResult.notAllowed() or the result is not valid according to the schema or other validation concerns (e.g., tables or configureAsInvalid rules), the operation is disabled. Custom mutations can set the active flag using the setActive() method on the CustomMutationResult created by either method.
modal Modals are obviously only opened when the operation is executed. However, the data returned by a modal could be required to correctly compute the state of subsequent operation steps. Therefore, if the modal's React component specifies a default value for the data prop (using the standard React defaultProps property), the properties in this object are assigned to the step data for the operation. This way, modals can define stub data as a stand-in during state computation for data that would otherwise be provided by the user. For more complex scenarios, we recommend adding a transform step after the modal that may perform additional processing on the step data as required.

If any step determines the operation state to be disabled, processing stops.

Localization

Some strings in an operation should be localized, namely everything that is shown in the interface to the user at some point. These alwasy include the label and description, but could also include any step data property you've added on your own. They can be marked for localization by using the t__ prefix. See the documentation on Localize the interface for more information.

Inline XPath

In the step data of an operation step, the x__ prefix can be used to signal the rest of the string should be interpreted and be executed as an XPath query. This query is supplied the following context:

Propery

Description

$data

A map() containing the step data. All keys ending with 'nodeId' or 'NodeId' are resolved and placed on the $data object under the same key, without the 'Id' part of their key. The keys are of type xs:string.

A step data containing a contextNodeId creates $data variable with two keys: the plain contextNodeId property of type xs:string and a contextNode property of type node().

context item The context item is absent.

The result of this XPath will be inserted in the step data, under the given key. Values of type xs:string will be kept strings, xs:numeric will be a JavaScript Number, etc, etc. However, Values of type node() will be transformed to their NodeId. This way, it is valid to return a node into a property like contextNodeId.

PleaseWaitMessage

The step data may contain a property called pleaseWaitMessage. This should be a string that should be displayed during the run of the operation. Use this for long running operations (like saving all documents). The modal opens when the step setting this property is ran and will close when the operation ends.

Examples

The following operations are valid operation definitions using standard FontoXML functionality.

Inserting an important note

{
	"note-important-insert": {
		"label": "t__Important note",
		"steps": {
			"type": "operation/vertical-insert",
			"data": {
				"childNodeStructure": [
					"note",
					{ "type": "important" },
					[{ "bindTo": "selection", "empty": true }]
				]
			}
		}
	}
}

Marking a word or selection as a trademark

{
	"tm-insert": {
		"label": "t__Trademark",
		"description": "t__Identifies a term or phrase that is trademarked.",
		"icon": "trademark",
		"steps": [
			{
				"type": "operation/toggle-inline-frame-element",
				"data": {
					"nodeName": "tm",
					"attributes": { "tmtype": "tm" }
				}
			}
		]
	}
}

Using data from the previous operation step

{
	"equation-block-insert": {
		"label": "Add equation",
		"description": "Add an equation to this figure.",
		"icon": "calculator",
		"steps": [
			{
				"type": "operation/open-mathml-editor",
				"data": {
					"mathMlPart": ["mathml"]
				}
			},
			{
				"type": "command/horizontal-insert",
				"data": {
					"childNodeStructure": [
						"equation-block",
						"{{mathMlPart}}"
					]
				}
			}
		]
	}
}

Evaluating XPath inline

{
	"clone-attribute-to-parent": {
		"steps": [
			{
				"type": "transform/setContextNodeIdToSelectedElement"
			},
			{
				"type": "operation/set-attributes",
				"data": {
					"contextNodeId": "x__$data('contextNode')/..",
					"attributes": {
						"clonableAttribute": "x__$data('contextNode')/@clonableAttribute"
					}
				}
			}
		]
	}
}