UNPKG

labo-components

Version:
275 lines (244 loc) 10.7 kB
import ComponentUtil from "../../../util/ComponentUtil"; import MediaEvents from "../_MediaEvents"; import { ANNOTATION_TARGET } from "../../../util/AnnotationConstants"; import Strings from "../_Strings"; /* This component handles the keyboard interactions for - navigating the current player position - creating/modifying segments destroy() should be called manually to remove the listeners */ export default class KeyboardInteraction { constructor({ context }) { this.context = context; this.currentPosition = 0; this.listen(); } listen = () => { this.context.mediaEvents.bind( MediaEvents.PLAYER_POS, this.updateCurrentPosition ); this.context.mediaEvents.bind( MediaEvents.SET_PLAYER_POS, this.updateCurrentPosition ); document.addEventListener("keydown", this.onKeyPressed); }; destroy = () => { this.context.mediaEvents.unbind( MediaEvents.PLAYER_POS, this.updateCurrentPosition ); this.context.mediaEvents.unbind( MediaEvents.SET_PLAYER_POS, this.updateCurrentPosition ); document.removeEventListener("keydown", this.onKeyPressed); }; updateCurrentPosition = (pos) => { this.currentPosition = pos; }; updatePlayerPos = (pos) => { this.context.mediaEvents.trigger(MediaEvents.SET_PLAYER_POS, pos); }; /** * Update Segment data */ // Update segment with given selection async saveActiveSelection() { // When the selection is null: exit if (!this.context.annotationClient.activeSelection) { return; } // Update the segment await this.context.annotationClient.saveSelection( this.context.annotationClient.activeSelection ); } // Update segment with given selection async saveNewActiveSelection(layerId = undefined) { // When the selection is null: exit if (!this.context.annotationClient.activeSelection) { return; } // Update the segment await this.context.annotationClient.saveSelection( this.context.annotationClient.activeSelection, true, true, layerId ); } onKeyPressed = (e) => { switch (e.keyCode) { case 68: // d e.shiftKey && // shift+d // Duplicate active annotation ComponentUtil.checkFocusAndExec(async () => { const annotationClient = this.context.annotationClient; const annotation = annotationClient.activeAnnotation; // require valid segment annotation if ( !annotation || !annotation.target || annotationClient.activeAnnotation.target.type !== ANNOTATION_TARGET.SEGMENT || !annotation.target.selector || !annotation.target.selector.refinedBy ) { return; } // create new selection const temporal = annotation.target.selector.refinedBy; const selection = annotationClient.newTemporalSegment( temporal.end, temporal.end + (temporal.end - temporal.start) ); // Create and activate a new segment, provide layerId annotationClient.activeAnnotation = null; await annotationClient.saveSelection( selection, true, !annotation.body, // only notify if there is no annotation body // else the notify will be called while saving the new annotation (body) annotation.target.layerId ); // duplicate / copy body if (annotation.body) { // Build annotationClient.activeAnnotation body based on the duplicated annotation body annotationClient.activeAnnotation.body = annotation.body.map( (origAnnotation) => { const newAnnotation = Object.assign( {}, origAnnotation ); // delete the annotation Id delete newAnnotation.annotationId; return newAnnotation; } ); await annotationClient.save(true, true); } }); break; case 88: // x case 46: // delete e.shiftKey && // shift + (x || delete) // shift + ctrl/meta + (x || delete) => no confirmation // Delete active annotation ComponentUtil.checkFocusAndExec(() => { if ( e.ctrlKey || e.metaKey || confirm(Strings.SEGMENT_DELETE_CONFIRM) ) { this.context.annotationClient.activeAnnotation && this.context.annotationClient.delete( this.context.annotationClient .activeAnnotation ); } }); break; case 73: // i e.shiftKey ? // shift+i // Set player position to active annotation start ComponentUtil.checkFocusAndExec(this.playStart) : // i // Set active annotation start to current position ComponentUtil.checkFocusAndExec(() => { this.context.annotationClient.setStart( this.currentPosition ); this.saveActiveSelection(); }); break; case 79: //o e.shiftKey ? // shift+o // Set player position to active annotation end ComponentUtil.checkFocusAndExec(this.playEnd) : // o // Set active annotation end to current position ComponentUtil.checkFocusAndExec(() => { this.context.annotationClient.setEnd( this.currentPosition ); this.saveActiveSelection(); }); break; case 67: // shift+c // Concat new temporal segment from the end of the previous segment (or 0) // to the current playback position // only include segments from same layer e.shiftKey && ComponentUtil.checkFocusAndExec(() => { const annotationClient = this.context.annotationClient; const currentLayerId = annotationClient.activeAnnotation && annotationClient.activeAnnotation.target && annotationClient.activeAnnotation.target.layerId ? annotationClient.activeAnnotation.target .layerId : 0; const prevSectionEnd = annotationClient.getSegmentEndBefore( this.currentPosition, currentLayerId ); annotationClient.newTemporalSegment( prevSectionEnd, this.currentPosition ); this.saveNewActiveSelection(currentLayerId); }); break; case 78: // n e.shiftKey && // shift+n // Create new temporal segment of 1 second length ComponentUtil.checkFocusAndExec(() => { const annotationClient = this.context.annotationClient; let layerId = annotationClient.activeAnnotation && annotationClient.activeAnnotation.target ? annotationClient.activeAnnotation.target .layerId : undefined; // if no current layer id is found, get first layer available (if any) if (!layerId) { layerId = this.context.annotationClient.segmentLayers.getFirstLayerId(); } // if still no current layer id is found, fallback to 0 if (!layerId) { layerId = 0; } annotationClient.newTemporalSegment( this.currentPosition, this.currentPosition + 1 ); this.saveNewActiveSelection(layerId); }); break; } }; /* ------------------------------ SEGMENTATION FUNCTIONS (POSSIBLY MOVE TO STAN) ------------------------------ */ playStart = () => { if (this.context.annotationClient.activeSelection) { this.updatePlayerPos( this.context.annotationClient.activeSelection.start ); } }; playEnd = () => { if (this.context.annotationClient.activeSelection) { this.updatePlayerPos( this.context.annotationClient.activeSelection.end ); } }; }