Annotation types

In order to implement an annotation type in an instance of the FontoXML 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 FontoXML Content Quality App documentation.

Registering a custom annotation type

Create a package

  1. Create the annotator specific package <annotatorPackage> and add it as an dependency to your FontoXML 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.

    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.

    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 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.

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 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.

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 the Fonto Editor for 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.

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.

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.

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.

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>
);

Read our guide on how to create a good user experience when configuring the Fonto Editor for 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.

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')
})
Was this page helpful?