diff --git a/src/glue.spec.ts b/src/glue.spec.ts index 02e5c00049375fd3c0100bfd0f2ca1f86d5ee944..92466c534536e6df36120aa565b7355639cbf7da 100644 --- a/src/glue.spec.ts +++ b/src/glue.spec.ts @@ -1,5 +1,5 @@ import { TestBed, tick, fakeAsync, discardPeriodicTasks } from "@angular/core/testing" -import { DatasetPreviewGlue, glueSelectorGetUiStatePreviewingFiles, glueActionRemoveDatasetPreview, datasetPreviewMetaReducer, glueActionAddDatasetPreview, GlueEffects } from "./glue" +import { DatasetPreviewGlue, glueSelectorGetUiStatePreviewingFiles, glueActionRemoveDatasetPreview, datasetPreviewMetaReducer, glueActionAddDatasetPreview, GlueEffects, ClickInterceptorService } from "./glue" import { ACTION_TO_WIDGET_TOKEN, EnumActionToWidget } from "./widget" import { provideMockStore, MockStore } from "@ngrx/store/testing" import { getRandomHex } from 'common/util' @@ -1211,65 +1211,101 @@ describe('> glue.ts', () => { /** * TODO finish writing the test for ClickInterceptorService */ + let interceptorService: ClickInterceptorService - it('can obtain override fn', () => { - + beforeEach(() => { + interceptorService = new ClickInterceptorService() }) - describe('> if getUserToSelectRegion.length === 0', () => { - - it('by default, next fn will be called', () => { - + describe('> #addInterceptor', () => { + it('> adds interceptor fn', () => { + const fn = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toBeGreaterThanOrEqual(0) }) - - it('if apiService.getUserToSelectRegion.length === 0, and mouseoversegment.length > 0 calls next', () => { + it('> when config not supplied, or last not present, will add fn to the first of the queue', () => { - }) - }) - describe('> if getUserToSelectRegion.length > 0', () => { - it('if both apiService.getUserToSelectRegion.length > 0 and mouseoverSegment.length >0, then next will not be called, but rs will be', () => { + const dummy = (ev: any, next: Function) => {} + interceptorService.addInterceptor(dummy) + const fn = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toEqual(0) + + const fn2 = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn2, {}) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toEqual(1) + expect(interceptorService['clickInterceptorStack'].indexOf(fn2)).toEqual(0) }) - it('if multiple getUserToSelectRegion handler exists, it resolves in a LIFO manner', () => { + it('> when last is supplied as a config param, will add the fn at the end', () => { - }) + const dummy = (ev: any, next: Function) => {} + interceptorService.addInterceptor(dummy) - describe('> if spec is not set (defaults to parcellation region mode)', () => { + const fn = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn, { last: true }) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toEqual(1) - it('if apiService.getUserToSelectRegion.length > 0, but mouseoversegment.length ===0, will not call next, will not rs, will not call rj', () => { - - }) }) + }) - describe('> if spec is set', () => { - describe('> if spec is set to PARCELLATION_REGION', () => { + describe('> deregister', () => { + it('> if the fn exist in the register, it will be removed', () => { - it('> mouseoversegment.length === 0, will not call next, will not rs, will not call rj', () => { + const fn = (ev: any, next: Function) => {} + const fn2 = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toBeGreaterThanOrEqual(0) + expect(interceptorService['clickInterceptorStack'].length).toEqual(1) - }) - - it('> mouseoversegment.length > 0, will not call next, will call rs', () => { - - }) - }) - - describe('> if spec is set to POINT', () => { - it('> rs is called if mouseoversegment.length === 0', () => { + interceptorService.removeInterceptor(fn) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toBeLessThan(0) + expect(interceptorService['clickInterceptorStack'].length).toEqual(0) + }) - }) - it('> rs is called with correct arg if mouseoversegment.length > 0', () => { + it('> if fn does not exist in register, it will not be removed', () => { + + const fn = (ev: any, next: Function) => {} + const fn2 = (ev: any, next: Function) => {} + interceptorService.addInterceptor(fn) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toBeGreaterThanOrEqual(0) + expect(interceptorService['clickInterceptorStack'].length).toEqual(1) + + interceptorService.removeInterceptor(fn2) + expect(interceptorService['clickInterceptorStack'].indexOf(fn)).toBeGreaterThanOrEqual(0) + expect(interceptorService['clickInterceptorStack'].length).toEqual(1) + }) + }) - }) - }) + describe('> # run', () => { + it('> will run fns from first idx to last idx', () => { + const callNext = (ev: any, next: Function) => next() + const fn = jasmine.createSpy().and.callFake(callNext) + const fn2 = jasmine.createSpy().and.callFake(callNext) - describe('> if multiple getUserToSelectRegion exist', () => { - it('> only the last Promise will be evaluated', () => { + interceptorService.addInterceptor(fn) + interceptorService.addInterceptor(fn2) + interceptorService.run({}) - - }) - }) + expect(fn2).toHaveBeenCalledBefore(fn) + }) + it('> will stop at when next is not called', () => { + + const callNext = (ev: any, next: Function) => next() + const halt = (ev: any, next: Function) => {} + const fn = jasmine.createSpy().and.callFake(callNext) + const fn2 = jasmine.createSpy().and.callFake(halt) + const fn3 = jasmine.createSpy().and.callFake(callNext) + + interceptorService.addInterceptor(fn) + interceptorService.addInterceptor(fn2) + interceptorService.addInterceptor(fn3) + interceptorService.run({}) + + expect(fn3).toHaveBeenCalled() + expect(fn2).toHaveBeenCalled() + expect(fn).not.toHaveBeenCalled() }) }) - }) }) diff --git a/src/glue.ts b/src/glue.ts index f0d9430a1a4bf6bf90bad761b6ca7946aaf65fee..c982af2d5ddf5ae7d712a95cb7e9fce1bc4717b9 100644 --- a/src/glue.ts +++ b/src/glue.ts @@ -18,6 +18,7 @@ import { viewerStateSelectedRegionsSelector, viewerStateSelectedTemplateSelector import { ngViewerSelectorClearView } from "./services/state/ngViewerState/selectors" import { ngViewerActionClearView } from './services/state/ngViewerState/actions' import { generalActionError } from "./services/stateStore.helper" +import { TClickInterceptorConfig } from "./util/injectionTokens" const PREVIEW_FILE_TYPES_NO_UI = [ EnumPreviewFileTypes.NIFTI, @@ -737,8 +738,8 @@ export class ClickInterceptorService{ this.clickInterceptorStack.splice(idx, 1) } } - addInterceptor(fn: Function, atTheEnd?: boolean) { - if (atTheEnd) { + addInterceptor(fn: Function, config?: TClickInterceptorConfig) { + if (config?.last) { this.clickInterceptorStack.push(fn) } else { this.clickInterceptorStack.unshift(fn) diff --git a/src/util/injectionTokens.ts b/src/util/injectionTokens.ts index c910f15350fec0dd087c674d54688dd4ccfe882f..acd5142e83ad88f25f76622c2b53bf282b53cce1 100644 --- a/src/util/injectionTokens.ts +++ b/src/util/injectionTokens.ts @@ -2,7 +2,11 @@ import { InjectionToken } from "@angular/core"; export const CLICK_INTERCEPTOR_INJECTOR = new InjectionToken<ClickInterceptor>('CLICK_INTERCEPTOR_INJECTOR') +export type TClickInterceptorConfig = { + last?: boolean +} + export interface ClickInterceptor{ - register: (interceptorFunction: (ev: any, next: Function) => void) => void + register: (interceptorFunction: (ev: any, next: Function) => void, config?: TClickInterceptorConfig) => void deregister: (interceptorFunction: Function) => void } diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts index 60364768746e4b061108558dcd48c7918b0959cf..042b97bc443d9edede37fc2473a3bdc6f372e044 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts @@ -277,7 +277,7 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ if (clickInterceptor) { const { deregister, register } = clickInterceptor const selOnhoverRegion = this.selectHoveredRegion.bind(this) - register(selOnhoverRegion) + register(selOnhoverRegion, { last: true }) this.onDestroyCb.push(() => deregister(selOnhoverRegion)) }