Skip to content

Commit 10103ac

Browse files
authored
feat(video-annotations): add default video location support (#733)
* feat(video-annotations): add default video location support * feat(video-annotations): add default video location support * feat(video-annotations): adding invalid location protection * feat(video-annotations): adding more tests * feat(video-annotations): adding more tests * feat(video-annotations): fixing TS issues * feat(video-annotations): addressing PR comments
1 parent 11c9581 commit 10103ac

File tree

3 files changed

+72
-17
lines changed

3 files changed

+72
-17
lines changed

src/media/MediaAnnotator.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,18 +120,19 @@ export default class MediaAnnotator extends BaseAnnotator {
120120
// the other annotators as the client calls this function when it wants to show an annoation on the
121121
// preview. The only difference is that we are using the video element's currentTime to scroll to the
122122
// annotation instead of the scrollLeft and scrollTop of the parent element.
123-
scrollToAnnotation(annotationId: string | null): void {
123+
scrollToAnnotation(annotationId: string | null | undefined, defaultLocation: number = -1 ): void {
124+
124125
if (!annotationId) {
125126
return;
126127
}
127-
128128
const annotation = getAnnotation(this.store.getState(), annotationId);
129-
const annotationLocation = annotation?.target.location.value ?? 0
129+
const annotationLocation = annotation?.target?.location?.value ?? defaultLocation;
130130
const video = this.getReference();
131-
if (!annotation || !video || !this.annotatedEl) {
131+
132+
if ( !video || !this.annotatedEl || annotationLocation === -1 ) {
132133
return;
133134
}
134-
135+
135136
video.pause();
136137
video.currentTime = annotationLocation / 1000;
137138

src/media/__tests__/MediaAnnotator-test.ts

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -268,30 +268,75 @@ describe('MediaAnnotator', () => {
268268
jest.restoreAllMocks();
269269
});
270270

271-
test('should call scrollToLocation for region annotations', () => {
272-
annotator.scrollToAnnotation('video_region_anno_1');
271+
test.each([
272+
{ type: 'region', ids: ['video_region_anno_1', 'video_region_anno_2', 'video_region_anno_3'] },
273+
{ type: 'drawing', ids: ['video_drawing_anno_1', 'video_drawing_anno_2', 'video_drawing_anno_3'] },
274+
])('should call scrollToLocation for $type annotations', ({ ids }) => {
275+
annotator.scrollToAnnotation(ids[0]);
273276
expect(mockVideo.currentTime).toBe(10);
274-
annotator.scrollToAnnotation('video_region_anno_2');
277+
annotator.scrollToAnnotation(ids[1]);
275278
expect(mockVideo.currentTime).toBe(20);
276-
annotator.scrollToAnnotation('video_region_anno_3');
279+
annotator.scrollToAnnotation(ids[2]);
277280
expect(mockVideo.currentTime).toBe(30);
278281
expect(mockVideo.pause).toHaveBeenCalledTimes(3);
279282
});
280283

281-
test('should call scrollToLocation for drawing anntotations', () => {
282-
annotator.scrollToAnnotation('video_drawing_anno_1');
284+
285+
286+
test('should do nothing if the annotation id is undefined or null' ,() => {
287+
annotator.scrollToAnnotation(undefined);
288+
expect(mockVideo.currentTime).toBe(0);
289+
expect(mockVideo.pause).not.toHaveBeenCalled();
290+
annotator.scrollToAnnotation(null);
291+
expect(mockVideo.currentTime).toBe(0);
292+
expect(mockVideo.pause).not.toHaveBeenCalled();
293+
});
294+
295+
test('should do nothing if the annotation is not available in the store and default location is not provided', () => {
296+
annotator.scrollToAnnotation('id_not_in_store');
297+
expect(mockVideo.currentTime).toBe(0);
298+
expect(mockVideo.pause).not.toHaveBeenCalled();
299+
});
300+
301+
test('should set correct video time if default location is provided but annotation is available in the store', () => {
302+
annotator.scrollToAnnotation('video_region_anno_1', 2100);
283303
expect(mockVideo.currentTime).toBe(10);
284-
annotator.scrollToAnnotation('video_drawing_anno_2');
304+
expect(mockVideo.pause).toHaveBeenCalled();
305+
});
306+
307+
test('should handle undefined and null default location', () => {
308+
309+
annotator.scrollToAnnotation('video_region_anno_1', undefined);
310+
expect(mockVideo.currentTime).toBe(10);
311+
expect(mockVideo.pause).toHaveBeenCalled();
312+
313+
annotator.scrollToAnnotation('video_region_anno_2', null as unknown as number);
285314
expect(mockVideo.currentTime).toBe(20);
286-
annotator.scrollToAnnotation('video_drawing_anno_3');
315+
expect(mockVideo.pause).toHaveBeenCalledTimes(2);
316+
});
317+
318+
test('should set correct video time if default location is provided and annotation is not available in the store', () => {
319+
annotator.scrollToAnnotation('id_not_in_store', 30000);
287320
expect(mockVideo.currentTime).toBe(30);
288-
expect(mockVideo.pause).toHaveBeenCalledTimes(3);
321+
expect(mockVideo.pause).toHaveBeenCalled();
289322
});
290323

291-
test('should do nothing if the annotation id is undefined or not available in the store', () => {
292-
annotator.scrollToAnnotation('video_drawing_anno_12');
324+
test('should do nothing if the video element is not defined', () => {
325+
annotator.getReference = jest.fn().mockReturnValue(null);
326+
annotator.scrollToAnnotation('video_region_anno_1');
293327
expect(mockVideo.currentTime).toBe(0);
294-
annotator.scrollToAnnotation(null);
328+
expect(mockVideo.pause).not.toHaveBeenCalled();
329+
});
330+
331+
test('should do nothing if the annotated element is not defined', () => {
332+
annotator.annotatedEl = undefined;
333+
annotator.scrollToAnnotation('video_region_anno_1');
334+
expect(mockVideo.currentTime).toBe(0);
335+
expect(mockVideo.pause).not.toHaveBeenCalled();
336+
});
337+
338+
test('should do nothing if the annotation target location is invalid', () => {
339+
annotator.scrollToAnnotation('annotation_with_invalid_target');
295340
expect(mockVideo.currentTime).toBe(0);
296341
expect(mockVideo.pause).not.toHaveBeenCalled();
297342
});

src/region/__mocks__/data.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,13 @@ export const videoAnnotations = [
9999
type: 'region',
100100
},
101101
},
102+
103+
{
104+
id: 'annotation_with_invalid_target',
105+
target: {
106+
location: { type: TARGET_TYPE.FRAME },
107+
shape: { height: 30, width: 30, x: 30, y: 30, type: 'rect' },
108+
type: 'region',
109+
},
110+
},
102111
];

0 commit comments

Comments
 (0)