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
-
Create the annotator specific package
<annotator
and add it as an dependency to your Fonto Editor inPackage> 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.
-
Add an
install.js
file to the package and importapi/register
and call the imported functionAnnotation Types.jsx.js register
. 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.Annotation Types() JavaScript
import registerAnnotationTypes from './api/registerAnnotationTypes.jsx'; export default function install() { registerAnnotationTypes(); }
-
Add an
api/register
to the package and export theAnnotation Types.jsx.js register
function.Annotation Types() 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 content
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 content
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 Content
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 render
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 Content
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')
})