Made overrideId work for long delays

This commit is contained in:
Rainer Simon 2020-05-01 11:44:01 +02:00
parent 5554a54df8
commit 2ca27b285d
3 changed files with 61 additions and 27 deletions

View File

@ -14,8 +14,6 @@ export default class TextAnnotator extends Component {
state = {
selectionBounds: null,
selectedAnnotation: null,
showRelationEditor: false,
selectedRelation: null,
applyTemplate: null,
@ -77,22 +75,59 @@ export default class TextAnnotator extends Component {
/**
* A convenience method that allows the external application to
* override the autogenerated Id.
* override the autogenerated Id for an annotation.
*
* Usually, the override will happen almost immediately after
* the annotation is created. But we need to be defensive and assume
* that the override might come in with considerable delay, thus
* the user might have made further edits already.
*
* A key challenge here is that there may be dependencies between
* the original annotation and relations that were created meanwhile.
*/
overrideId = originalId => forcedId => {
// Force the editors to close, otherwise their annotations will be orphaned
overrideAnnotationId = originalAnnotation => forcedId => {
const { id } = originalAnnotation;
// After the annotation update, we need to update dependencies
// on the annotation layer, if any
const updateDependentRelations = updatedAnnotation => {
// Wait until the highlighter update has come into effect
requestAnimationFrame(() => {
this.relationsLayer.overrideTargetAnnotation(originalAnnotation, updatedAnnotation);
})
};
// Force the editors to close first, otherwise their annotations will be orphaned
if (this.state.selectedAnnotation || this.state.selectedRelation) {
this.relationsLayer.resetDrawing();
this.setState({
selectedAnnotation: null,
selectedRelation: null
}, () => this.highlighter.overrideId(originalId, forcedId));
}, () => {
const updated = this.highlighter.overrideId(id, forcedId);
updateDependentRelations(updated);
});
} else {
this.highlighter.overrideId(originalId, forcedId);
const updated = this.highlighter.overrideId(id, forcedId);
updateDependentRelations(updated);
}
}
/**
* A convenience method that allows the external application to
* override the autogenerated Id for a relation.
*
* This operation is less problematic than .overrideAnnotation().
* We just need to make sure the RelationEditor is closed, so that
* the annotation doesn't become orphaned. Otherwise, there are
* no dependencies.
*/
overrideRelationId = originalId => forcedId => {
if (this.state.selectedRelation) {
this.setState({ selectedRelation: null }, () =>
this.relationsLayer.overrideId(originalId, forcedId));
} else {
this.relationsLayer.overrideId(originalId, forcedId);
}
}
@ -107,7 +142,7 @@ export default class TextAnnotator extends Component {
if (previous)
this.props[method](annotation.clone(), previous.clone());
else
this.props[method](annotation.clone(), this.overrideId(annotation.id));
this.props[method](annotation.clone(), this.overrideAnnotationId(annotation));
}
onDeleteAnnotation = annotation => {
@ -133,7 +168,7 @@ export default class TextAnnotator extends Component {
// Shorthand
closeRelationsEditor = () => {
this.setState({ showRelationEditor: false });
this.setState({ selectedRelation: null });
this.relationsLayer.resetDrawing();
}
@ -143,7 +178,6 @@ export default class TextAnnotator extends Component {
*/
onEditRelation = relation => {
this.setState({
showRelationEditor: true,
selectedRelation: relation
});
}
@ -158,13 +192,8 @@ export default class TextAnnotator extends Component {
// otherwise, fire 'update'
const isNew = previous.annotation.bodies.length === 0;
// A convenience method that allows the external application to
// override the autogenerated Id
const overrideId = originalId => forcedId =>
this.relationsLayer.overrideId(originalId, forcedId);
if (isNew)
this.props.onAnnotationCreated(relation.annotation.clone(), overrideId(relation.annotation.id));
this.props.onAnnotationCreated(relation.annotation.clone(), this.overrideRelationId(relation.annotation.id));
else
this.props.onAnnotationUpdated(relation.annotation.clone(), previous.annotation.clone());
}
@ -214,7 +243,7 @@ export default class TextAnnotator extends Component {
this.relationsLayer.readOnly = false;
this.relationsLayer.startDrawing();
} else {
this.setState({ showRelationEditor: false });
this.setState({ selectedRelation: null });
this.selectionHandler.enabled = true;
@ -247,7 +276,7 @@ export default class TextAnnotator extends Component {
</Editor>
}
{ this.state.showRelationEditor &&
{ this.state.selectedRelation &&
<RelationEditor
relation={this.state.selectedRelation}
onRelationCreated={this.onCreateOrUpdateRelation}

View File

@ -95,10 +95,8 @@ export default class Highlighter {
*
* @returns the updated annotation for convenience
*/
overrideId = (annotationOrId, forcedId) => {
const id = annotationOrId.id ? annotationOrId.id : annotationOrId;
const allSpans = document.querySelectorAll(`.r6o-annotation[data-id="${id}"]`);
overrideId = (originalId, forcedId) => {
const allSpans = document.querySelectorAll(`.r6o-annotation[data-id="${originalId}"]`);
const annotation = allSpans[0].annotation;
const updatedAnnotation = annotation.clone({ id : forcedId });

View File

@ -93,16 +93,23 @@ export default class RelationsLayer extends EventEmitter {
}
}
overrideId = (annotationOrId, forcedId) => {
const id = annotationOrId.id ? annotationOrId.id : annotationOrId;
const conn = this.connections.find(c => c.annotation.id == id);
/** Overrides the ID for an existing relation **/
overrideRelationId = (originalId, forcedId) => {
const conn = this.connections.find(c => c.annotation.id == originalId);
const updatedAnnotation = conn.annotation.clone({ id : forcedId });
conn.annotation = updatedAnnotation;
return conn;
}
/** Overrides the given source or target annotation **/
overrideTargetAnnotation = (originalAnnotation, forcedAnnotation) => {
const affectedFrom = this.connections.filter(c => c.fromNode.annotation == originalAnnotation);
affectedFrom.forEach(c => c.fromNode.annotation = forcedAnnotation);
const affectedTo = this.connections.filter(c => c.toNode.annotation == originalAnnotation);
affectedTo.forEach(c => c.toNode.annotation = forcedAnnotation);
}
getAllRelations = () => {
return this.connections.map(c => c.annotation);
}