Add new types of annotations

This page describes options to configure new types of annotations together with the configuration you should do in the cards of the annotations.

You can add new types of annotations through the different registration methods.

The fontoxml-feedback add-on provides the following functions:

You can call these functions inside an install.js of your editor application package. You can call these functions as many times as you like; once for each annotation type you want to register.

For more information on the annotation target types, please click here.

Create your own CardContentComponent

Because you can customize everything about the contents of a card for an annotation, you can decide for yourself how each of the states of an annotation and each of the states of a reply should be visualized.

The review sharing sidebar CANNOT be turned off or customized.

Make sure to also implement something for this context similar to the included implementation to support batch sharing of annotations. Use reviewAnnotation.context and reviewAnnotation.isSelectedToShare as appropriate.

Inside the source code of the reference configuration package, you can read about the UX choices we made and how we implemented them. The API descriptions below were written based on the UX choices we made, but with other options in mind.

A custom CardContentComponent is injected with the following props. The callbacks have already been bound to the specific annotation.

CardContentComponent props

Name

Type

Description

context

ContextType

Where is the card rendered. Use this to change which information is shown in the card based on where it is used.

isSelectedToShare

boolean

Whether or not the annotation is included in the batch of annotations to share.

In the reference configuration, this is used as the value of the checkbox displayed in the card when the context is ContextType.EDITOR_SHARING_SIDEBAR OR the context is ContextType.REVIEW_SHARING_SIDEBAR.

reviewAnnotation

ReviewAnnotation

A collection of data and states for one annotation and its replies.

onReviewAnnotationEdit

function

When pressing the "Edit" button, call this callback.

This sets reviewAnnotation.busyState to BusyState EDITING which should trigger your card to display the edit form.

onReviewAnnotationErrorAcknowledge

function

When pressing the "Ok" button in an error state of an error with error.recovery set to RecoveryOption ACKNOWLEDGEABLE, call this callback.

This removes the annotation from the list of cards in the front-end, in the CMS the annotation is usually already "removed" (actually, "archived") whenever this type or error occurs.

onReviewAnnotationFormCancel

function

When pressing the "Cancel" button in an annotation (add, edit or resolve) form, call this callback.

This sets the busyState to BusyState IDLE which should trigger your card to display the annotation content instead of the annotation (add, edit or resolve) form.

onReviewAnnotationFormSubmit

function(valueByName)

When pressing the "Save" button in an annotation (add, edit or resolve) form, call this callback with the valueByName mapping directly from your (FDS) Form. The given valueByName mapping will be stored as-is in the metadata or the resolvedMetadata in case of the resolve form.

This submits the data of the form to the CMS.

While the data is submitted, isLoading is set to true and after the request completes, isLoading is set to false again and the busyState is updated to BusyState IDLE.

onReviewAnnotationRefresh

function

When pressing the "Refresh" button in an error state of an error with recovery set to RecoveryOption REFRESHABLE, call this callback.

This gets new data from the CMS with could potentially solve the current error state.

onReviewAnnotationRemove

function

When pressing the "Remove" menu item, call this callback.

This sends an edit request to the CMS to set the status to AnnotationStatus ARCHIVED.

onReviewAnnotationResolve

function

When pressing the "Resolve" button, call this callback.

This sets the busyState to BusyState RESOLVING which should trigger your card to display the resolve form.

onReviewAnnotationShare

function

When pressing the "Share" button, call this callback.

This sets the status to AnnotationStatus SHARED and sends it to the CMS.

While the data is submitted, isLoading is set to true and after the request completes, isLoading is set to false again and the busyState is updated to BusyState IDLE.

onReviewAnnotationShareAddRemoveToggle

function

When toggling the share checkbox for batch sharing, call this callback.

This toggles the isSelectedToShare property on an annotation and does not update the CMS yet (the CMS is updated when the user presses the "Share comments" button in the sharing sidebar).

onReviewAnnotationShowInCreatedContext

function

When pressing the "created context" text link, call this callback.

This opens a modal with the revision of the document when the annotation was created and a card for the annotation in its current state with its current data.

onReviewAnnotationShowInResolvedContext

function

When pressing the "resolved context" text link, call this callback.

This opens a modal with the revision of the document when the current card was resolved and a card for the annotation in its current state with its current data.

onProposalMerge

function

When pressing the "merge proposal" button, call this callback.

This merges the proposed change into the content. The button associated to this callback is only useful in the editor route. This property can be passed to the ReviewAnnotationAcceptProposalButton. It uses the proposedChange property of the metadata object to do this. Model your data like this to enable the feature. For more information, see Configure change proposals.

onReplyAdd

function

When pressing the "Reply" button, call this callback; this creates a new stub reply at the end (bottom) of the replies array with its busyState set to BusyState ADDING, which should trigger the card to display the (add) reply form.

onReplyEdit

function(replyId)

When pressing the "Edit" menu item, call this callback; this sets busyState on the reply to BusyState EDITING, which should trigger the card to display the (edit) reply form.

onReplyFormCancel

function(replyId)

When pressing the "Cancel" button of the reply (add or edit) form, call this callback

This resets busyState on the reply back to BusyState IDLE, which should trigger your card to display the reply content instead of the reply (add or edit) form for the current reply.

onReplyFormSubmit

function(replyId, valueByName)

When pressing the "Save" button in an reply (add or edit) form, call this callback with the valueByName mapping directly from your (FDS) Form. The given valueByName mapping will be stored as-is in the reply's metadata property.

This submits the data of the form to the CMS.

While the data is submitted, isLoading on the reply is set to true and after the request completes, isLoading is set to false again and the busyState is updated to BusyState IDLE.

onReplyErrorHide

function(replyId)

When pressing the "Hide" button in an error state of a reply with an error with recovery set to RecoveryOption ACKNOWLEDGEABLE, call this callback.

This removes the reply from the list of replies in the front-end, in the CMS the reply is usually already "removed" (actually, "archived") whenever this type or error occurs.

onReplyRefresh

function(replyId)

When pressing the "Refresh" button in an error state of a reply with an error with recoveryset to RecoveryOption REFRESHABLE, call this callback.

This gets new data from the CMS which could potentially solve the current error state.

onReplyRemove

function(replyId)

When pressing the "Remove" menu item, call this callback

This sends an edit request to the CMS to set the reply status to ReplyStatus ARCHIVED.

The ReviewAnnotation type

Name

Type

Description

id

string

The unique identifier of this annotation, set by the CMS after creating it, which happens after calling onReviewAnnotationFormSubmit in the annotation add/create form.

author

Author

The author of this annotation.

busyState

BusyState

The state of the card.

Whenever this is set to something other that BusyState IDLE, this means either an appropriate form should be shown for the current annotation. Or, if isLoading is also true, the form is being submitted and a loading state visualization is needed (like a spinner).

Some states do not use a form, like BusyState REFRESHING, in that case busyState is used to detect which state message to show in the loading visualization.

See the source of CommentCardContent.jsx and/or ProposalCardContent.jsx in the reference configuration for more information.

Also disable any other state change / data submission UI during a non-idle busyState, to prevent race conditions together with the CMS. See the source code for more information.

error

Error

Errors occur either as a result of a form submission or when the latest annotations are periodically retrieved from the CMS (this happens automatically).

In the second case the user might not be engaged with that particular annotation, therefore a more prominent error state might be considered.

If error is set and busyState is not BusyState IDLE, consider displaying the error inline with the appropriate form for the busyState.

If this is set and the busyState is set to BusyState IDLE, consider displaying the error state instead of the normal content, drawing more attention to it.

isLoading

boolean

True while data is being submitted to the CMS.

Use this to indicate loading states (spinners etc.). This works together with busyState.

isCreatedDocumentRevisionLoaded

boolean

If this is false, display a text link (or a button) to call onReviewAnnotationShowInCreatedContext to display the revision of the document when the current annotation was created, inside a Modal.

isSelected

boolean

Whether or not the annotation is selected.

If this is true, the matching squiggle in the content will also be displayed in its selected state.

The (FDS) Card is rendered by default and is also automatically displayed in its selected state (yellow background and border) based on this property, this cannot be customized.

metadata

Object

A mapping of a form component id/name to its current value or default value.

This starts out as an empty object for (the first render of) an annotation that is newly added.

It is filled by initializing the annotation (add) form. It is pre-filled when editing a pre-existing annotation.

Whatever you put in here while submitting the annotation form (using onReviewAnnotationFormSubmit), is send to the CMS as-is.

originalText

string

The text contained in the original selection that was made while creating the annotation.

This is useful to create some sort of a diff between the original content and proposed new content, see the example "proposal" annotation type in the source code.

proposalState

ProposalState

This property reflects the proposal state for this annotation.

See Configure change proposals for more information.

targetFoundForRevision

boolean

Whether or not a target is found in the (currently displayed revision of the) document in which this annotation was created.

A target means the location of the text that was selected while creating the annotation.

replies

Reply[]

The list of replies on this annotation.

resolvedMetadata

object

A mapping of a form component id/name to its current value or default value.

This starts out as an empty object for (the first render of) an annotation that is not resolved yet.

It is filled by initializing the annotation (resolve) form.

Whatever you put in here while submitting the annotation resolve form (using onReviewAnnotationFormSubmit), is send to the CMS as-is.

resolvedAuthor

Author

The user who was logged in while resolving the annotation, as determined by the CMS when an annotation is edited with a status set to AnnotationStatus RESOLVED.

resolvedTimestamp

string

An ISO-8601 timestamp indicating when this annotation was resolved.

This can be passed to a JavaScript Date object directly or used with fontoxml-localization to make the timestamp translatable and format it at the same time.

status

AnnotationStatus

The status of the annotation.

Note: The status of an annotation is set to AnnotationStatus ARCHIVED when the user presses the "Remove" menu item. An edit request is send to the CMS to set the annotation's status to AnnotationStatus ARCHIVED. This is for auditing purposes; data should never be deleted from the CMS.

The status is displayed as a Badge on the card and indicate a basic 'workflow' step/state.

Currently, an annotation has to be shared before the "Resolve" button is shown.

The "Remove" menu item is only shown if it is still private.

This can be changed in your own custom card UI/UX.

It's an (optional) responsibility of the CMS to filter out any archived annotations or private annotations that do not belong to the currently logged in user (which is implemented as such by Fonto's dev-cms).

timestamp

string

An ISO-8601 timestamp indicating when this annotation was created.

This can be passed to a JavaScript Date object directly or used with fontoxml-localization to make the timestamp translatable and format it at the same time.

type

string

When an annotation is created, this is set to the id of the registered annotation type.

The Author type

Name

Type

Description

id

string

The id of the user who was logged in while creating the annotation, as determined by the CMS when an annotation is created. This should match the id of the logged in user (at the time) as seen in the scope URL query variable. It can be used by the UI to show a special "You" label instead of the author's displayName.

displayName

string

The human readable name of the user who was logged in while creating the annotation, as determined by the CMS when it is created.

The Error type

Name

Type

Description

message

string

An error message provided by the fontoxml-feedback addon (can be translated with fontoxml-localization).

recovery

RecoveryOption

What recovery option is available.

Use this to determine what buttons to render (and couple to the appropriate callbacks, onReviewAnnotation* onReply*).

The Reply type

Name

Type

Description

id

string

The unique identifier of this reply, set by the CMS after creating the reply, which happens after calling onReplyFormSubmit in the reply add form.

busyState

BusyState

The state of the reply.

Can be one of: BusyState ADDING, EDITING, IDLE or REMOVING for a reply.

Whenever this is set to something other that BusyState IDLE, this means either an appropriate form should be shown for the current reply. Or, if isLoading is also true, the form is being submitted and a loading state visualization is needed (like a spinner).

Note: some states do not use a form, like BusyState REMOVING, in that case busyState is used to detect which state message to show in the loading visualization.

See the source of Replies.jsx for more information.

Also disable any other state change / data submission UI during a non-idle busyState, to prevent race conditions together with the CMS.

error

Error

Errors occur either as a result of a form submission or when the latest annotations and replies are periodically retrieved from the CMS (this happens automatically).

In the second case the user might not be engaged with that particular annotation reply, therefore a more prominent error state might be considered.

If error is set and busyState is not BusyState IDLE, consider displaying the error inline with the appropriate form for the busyState.

If error is set and the busyState is set to BusyState IDLE, consider displaying the error state instead of the normal content, drawing more attention to it.

isLoading

boolean

True while data is being submitted to the CMS, use this to indicate loading states (spinners etc.).

This works together with busyState.

metadata

object

A mapping of a form component id/name to its current value or default value.

This starts out as an empty object for (the first render of) a reply that is newly added.

It is filled by initializing the reply (add) form. It is pre-filled when editing a pre-existing reply.

Whatever you put in here while submitting the reply form (using onReplyFormSubmit), is send to the CMS as-is.

status

ReplyStatus

The status of the reply.

Replies are created with ReplyStatus SHARED by default.

Note: We set the reply to ReplyStatus ARCHIVED when the user presses the "Remove" menu item. We send an edit request to the CMS to edit the reply's status to this value. This is for auditing purposes; data should never be actually deleted from the CMS.

It's an (optional) responsibility of the CMS to filter out any archived replies (which is implemented as such by Fonto's dev-cms).

timestamp

number

An ISO-8601 timestamp indicating when this reply was created.

This can be passed to a JavaScript Date object directly or used with fontoxml-localization to make the timestamp translatable and format it at the same time.