Annotation types

In order to implement an annotation type in an instance of Fonto Editor, you need to register the annotation type and the corresponding visualisations.

Annotations of a specific type must be created by the corresponding Annotator in the backend. See the documentation for setting up these Annotators in the Fonto Content Quality documentation.

Registering a custom annotation type

Create a package

  1. Create the annotator specific package <annotatorPackage> and add it as an dependency to your Fonto Editor in config/fonto-manifest.json.

    A single annotator in the backend can return multiple annotation types, which can be registered in a single package. If you have multiple annotators (groups), for example hyperlink detection and entity recognition, you might want to split those into multiple packages.

  2. Add an install.js file to the package and import api/registerAnnotationTypes.jsx.js and call the imported function registerAnnotationTypes(). We include put the annotation type configuration inside a JSX file for convenience. since the configuration consists in large part render functions which use React components.

    JavaScript

    import registerAnnotationTypes from './api/registerAnnotationTypes.jsx';
    
    export default function install() {
        registerAnnotationTypes();
    }
  3. Add an api/registerAnnotationTypes.jsx.js to the package and export the registerAnnotationTypes() function.

    JavaScript

    import contentQualityManager from 'fontoxml-content-quality/src/contentQualityManager.js';
    import ContentQualityDefaultSidebarListCardContent from 'fontoxml-content-quality/src/ContentQualityDefaultSidebarListCardContent.jsx';
    import t from 'fontoxml-localization/src/t.js';
    
    export default function registerAnnotationTypes() {
        // TODO: Register the annotation type(s).
    }

Register the annotation type with the Fonto Content Quality manager

Any and all annotation types which can be returned by the annotators in the backend must be registered in the editor. To do so, you must call the contentQualityManager.registerAnnotationType() method for each of the annotation types and pass the namespace, name of the annotation type and supply its configuration. See the documentation for registerAnnotationType() in the contentQualityManager for more informations and available options.

JavaScript

contentQualityManager.registerAnnotationType(
	'urn:mycompany:fontoxml:fcq:annotations:myannotator',
	'type1',
	{
		getContextMenuGroup,
		renderSidebarDetails,
		renderSidebarListCardContent,
		icon: 'code'
	}
);

Every annotator can supply metadata with an annotation. This is an implementation specific object which can differ between annotation types. You can access the metadata on the annotation (annotation.metadata). The examples below show how you might use this metadata.

Please design your metadata carefully. Be sure to not send unneeded or redundant data, or fixed texts in order to minimize network and memory overhead.

Create the sidebar list card content renderer

You should return a ReactNode which shows the sidebar's list card content. You can use the a Component provided by the Fonto Content Quality add-on to adhere to the default style, see ContentQualityDefaultSidebarListCardContent, which supports setting a title, and optionally a renderBody callback function if you need to show something other then the annotation's text.

Card contents should only contain the minimally needed information to determine what it is about, and should not have actions available. All actions should be done in either the details card or the context menu.

JavaScript

const renderSidebarListCardContent = ({ annotation }) => {
	let title = t('Textual issue');
	// This example assumes this annotation type has an optional short message in the metadata.
	if (annotation && annotation.metadata && annotation.metadata.shortMessage) {
		title = annotation.metadata.shortMessage;
	}

	return (
		<ContentQualityDefaultSidebarListCardContent
			annotation={annotation}
			title={title}
		/>
	);
}

Read our guide on how to create a good user experience when configuring Fonto Editor for Fonto Content Quality.

Create the sidebar details renderer

You should return a ReactNode which shows the sidebar's details. This usually consists of some information about the annotation, optionally a choice from a list, and a few operations which can be performed.

JavaScript

import { applyCss } from 'fds/system';
import { Flex, Icon, Inlay, Label, Text } from 'fds/components';
import FxOperationButton from 'fontoxml-fx/src/FxOperationButton.jsx';
import ContentQualityTextWithAnnotationStyle from 'fontoxml-content-quality/src/ContentQualityTextWithAnnotationStyle.jsx';

// This example assumes this annotation type has an optional short message and a replacement text in the metadata.
const iconContainerStyle = {
    color: this.props.annotation.type.color
};

const CSS_FOR_REPLACEMENT = applyCss({
    lineHeight: 2
});

const renderSidebarDetails = ({ annotation, next }) => (
    <Flex flexDirection="column" justifyContent="flex-start" spaceSize="m">
        <Inlay isScrollContainer>
            <Flex spaceSize="m">
                <Flex flexDirection="column" applyCss={iconContainerStyle}>
                    <Icon
                        colorName="inherit"
                        icon={this.props.annotation.type.icon}
                        size="s"
                    />
                </Flex>
                <Label isBold>{annotation.metadata.shortMessage || SHORT_MESSAGE_FALLBACK}</Label>
            </Flex>
            <ContentQualityTextWithAnnotationStyle
                text={t('%style_start%{ANNOTATION_TEXT}%style_end%', {
                    ANNOTATION_TEXT: annotation.text
                })}
                annotationType={annotation.type}
            />
            <Icon colorName="text-muted-color" icon="arrow-right" size="s" />
            <Text>
                <span {...CSS_FOR_REPLACEMENT}>{annotation.metadata.replacement}</span>
            </Text>
        </Inlay>
        <Flex flex="0 0 auto" justifyContent="flex-end">
            <FxOperationButton
                operationName="my-operation"
                operationData={{ annotationId: annotation.id }}
                onClick={next}
            />
        </Flex>
    </Flex>
);

Alternatively, if a Functional Component is too limited and your details require state, you can create your own React Component for the details component, and just return it in the renderSidebarDetails render function.

JavaScript

import MySidebarDetailsComponent from '../ui/MySidebarDetailsComponent.jsx';

const renderSidebarDetails = properties => {
	// properties contains the annotation and an next callback function.
	return <MySidebarDetailsComponent {...properties} />;
}

To help with development of the details, you can use the ContentQualityAnnotationDebugInformation component. This shows all information of the annotation, which can help with wiring your own details component.

Other

import { Flex, HorizontalSeparationLine, Inlay, Label } from 'fds/components';
import FxOperationButton from 'fontoxml-fx/src/FxOperationButton.jsx';
import ContentQualityAnnotationDebugInformation from 'fontoxml-content-quality/src/ContentQualityAnnotationDebugInformation.jsx';

const renderSidebarDetails = ({ annotation, next }) => (
    <Flex flexDirection="column" justifyContent="flex-start" spaceSize="m">
        <Inlay isScrollContainer>
            <Label isBold>{'TODO: Implement the annotation details and operations'}</Label>
        </Inlay>
        <Flex flex="0 0 auto" justifyContent="flex-end">
            <FxOperationButton
                operationName="my-operation"
                operationData={{ annotationId: annotation.id }}
                onClick={next}
            />
        </Flex>

        <HorizontalSeparationLine marginSizeTop="m" marginSizeBottom="m" />

        <ContentQualityAnnotationDebugInformation annotation={annotation} />
    </Flex>
);

Do not use this component in production. The component's UX is not geared toward end-users, and it's layout and contents can change without notice.

Read our guide on how to create a good user experience when configuring Fonto Editor for Fonto Content Quality.

(Recommended) Configure the context menu group

Additionally you can add context menu operations, these can be generated based on the actual annotation at the time the context menu is opened. You can specify the operations and optionally the heading, and the label for the show more details menu entry.

JavaScript

const getContextMenuOperations = annotation => {
	// This example assumes this annotation type has optional replacements supplied in the metadata.
	if (!annotation || !annotation.metadata || !annotation.metadata.replacements) {
		return null;
	}
	return annotation.metadata.replacements.map(replacement => {
		return {
			label: replacement,
			icon: 'check',
			operationName: 'content-quality-replace-text',
			operationData: {
				annotationId: annotation.id,
				text: replacement
			}
		};
	});
};

annotation => ({
	heading: t('MenuGroup heading or MenuItemWithDrop label here'),
	operations: getContextMenuOperations(annotation),
	showDetailsInSidebarLabel: t('MenuItem label here')
})