diff --git a/e2e/src/advanced/pluginApi.e2e-spec.js b/e2e/src/advanced/pluginApi.e2e-spec.js new file mode 100644 index 0000000000000000000000000000000000000000..1a4d5f2ba89f7c83208d5db5a9a4df92a7ab91d0 --- /dev/null +++ b/e2e/src/advanced/pluginApi.e2e-spec.js @@ -0,0 +1,68 @@ +const { AtlasPage } = require('../util') +const template = 'ICBM 2009c Nonlinear Asymmetric' + +const pluginName = `fzj.xg.testWidget` +const pluginDisplayName = `Test Widget Title` + +const prepareWidget = ({ template = 'hello world', script = `console.log('hello world')` } = {}) => { + + return ` +const jsSrc = \`${script.replace(/\`/, '\\`')}\` +const blob = new Blob([jsSrc], { type: 'text/javascript' }) +window.interactiveViewer.uiHandle.launchNewWidget({ + name: '${pluginName}', + displayName: '${pluginDisplayName}', + template: \`${template.replace(/\`/, '\\`')}\`, + scriptURL: URL.createObjectURL(blob) +})` +} + +describe('> plugin api', () => { + let iavPage + + beforeEach(async () => { + iavPage = new AtlasPage() + await iavPage.init() + await iavPage.goto() + await iavPage.selectTitleCard(template) + await iavPage.wait(500) + await iavPage.waitUntilAllChunksLoaded() + }) + + describe('> interactiveViewer', () => { + describe('> uiHandle', () => { + describe('> launchNewWidget', () => { + it('should launch new widget', async () => { + + const prevTitle = await iavPage.execScript(() => window.document.title) + await iavPage.execScript(prepareWidget({ script: `window.document.title = 'hello world ' + window.document.title` })) + + await iavPage.wait(500) + + const isDisplayed = await iavPage.widgetPanelIsDispalyed(`Test Widget Title`) + expect(isDisplayed).toEqual(true) + + const newTitle = await iavPage.execScript(() => window.document.title) + expect(newTitle).toEqual(`hello world ${prevTitle}`) + }) + }) + }) + }) + + describe('> pluginControl', () => { + describe('> onShutdown', () => { + it('> works', async () => { + const newTitle = `testing pluginControl onShutdown` + const script = `window.interactiveViewer.pluginControl['${pluginName}'].onShutdown(() => window.document.title = '${newTitle}')` + await iavPage.execScript(prepareWidget({ script })) + await iavPage.wait(500) + const oldTitle = await iavPage.execScript(() => window.document.title) + await iavPage.closeWidgetByname(pluginDisplayName) + await iavPage.wait(500) + const actualNewTitle = await iavPage.execScript(() => window.document.title) + expect(oldTitle).not.toEqual(actualNewTitle) + expect(actualNewTitle).toEqual(newTitle) + }) + }) + }) +}) diff --git a/e2e/src/util.js b/e2e/src/util.js index e8f4ece07b8c205a2d1ef967e8d2ab22aa076d40..00f524b8efafe85c114276d31988a51e6dad168c 100644 --- a/e2e/src/util.js +++ b/e2e/src/util.js @@ -210,6 +210,11 @@ class WdBase{ ) .perform() } + + async execScript(fn, ...arg){ + const result = await this._driver.executeScript(fn) + return result + } } class WdLayoutPage extends WdBase{ @@ -423,6 +428,59 @@ class WdLayoutPage extends WdBase{ await this._getFavDatasetIcon().click() await this.wait(500) } + + _getPinnedDatasetPanel(){ + return this._driver + .findElement( + By.css('[aria-label="Pinned datasets panel"]') + ) + } + + async getPinnedDatasetsFromOpenedPanel(){ + const list = await this._getPinnedDatasetPanel() + .findElements( + By.tagName('mat-list-item') + ) + + const returnArr = [] + for (const el of list) { + const text = await _getTextFromWebElement(el) + returnArr.push(text) + } + return returnArr + } + + async unpinNthDatasetFromOpenedPanel(index){ + const list = await this._getPinnedDatasetPanel() + .findElements( + By.tagName('mat-list-item') + ) + + if (!list[index]) throw new Error(`index out of bound: ${index} in list with size ${list.length}`) + await list[index] + .findElement( By.css('[aria-label="Toggle pinning this dataset"]') ) + .click() + } + + _getWidgetPanel(title){ + return this._driver.findElement( By.css(`[aria-label="Widget for ${title}"]`) ) + } + + async widgetPanelIsDispalyed(title){ + try { + const isDisplayed = await this._getWidgetPanel(title).isDisplayed() + return isDisplayed + } catch (e) { + console.warn(`widgetPanelIsDisplayed error`, e) + return false + } + } + + async closeWidgetByname(title){ + await this._getWidgetPanel(title) + .findElement( By.css(`[aria-label="close"]`) ) + .click() + } } class WdIavPage extends WdLayoutPage{ diff --git a/src/atlasViewer/atlasViewer.apiService.service.spec.ts b/src/atlasViewer/atlasViewer.apiService.service.spec.ts index 4f4d4c0de6d513a0ebad97e81bb8a9f107a201a7..e1164b83f9064702177f8763def8feeffdab47db 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.spec.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.spec.ts @@ -1,55 +1,60 @@ -import {} from 'jasmine' -import {AtlasViewerAPIServices} from "src/atlasViewer/atlasViewer.apiService.service"; -import {async, TestBed} from "@angular/core/testing"; -import {provideMockActions} from "@ngrx/effects/testing"; -import {provideMockStore} from "@ngrx/store/testing"; -import {defaultRootState} from "src/services/stateStore.service"; -import {Observable, of} from "rxjs"; -import {Action} from "@ngrx/store"; -import {AngularMaterialModule} from "src/ui/sharedModules/angularMaterial.module"; -const actions$: Observable<Action> = of({type: 'TEST'}) - +import { } from 'jasmine' +import { AtlasViewerAPIServices } from "src/atlasViewer/atlasViewer.apiService.service"; +import { async, TestBed } from "@angular/core/testing"; +import { provideMockActions } from "@ngrx/effects/testing"; +import { provideMockStore } from "@ngrx/store/testing"; +import { defaultRootState } from "src/services/stateStore.service"; +import { Observable, of } from "rxjs"; +import { Action } from "@ngrx/store"; +import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module"; +import { HttpClientModule } from '@angular/common/http'; +import { WidgetModule } from './widgetUnit/widget.module'; +import { PluginModule } from './pluginUnit/plugin.module'; +const actions$: Observable<Action> = of({ type: 'TEST' }) describe('atlasViewer.apiService.service.ts', () => { - describe('getUserToSelectARegion', () => { + describe('getUserToSelectARegion', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - AngularMaterialModule, - ], - providers: [ - AtlasViewerAPIServices, - provideMockActions(() => actions$), - provideMockStore({initialState: defaultRootState}) - ] - }) - })) + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + AngularMaterialModule, + HttpClientModule, + WidgetModule, + PluginModule, + ], + providers: [ + AtlasViewerAPIServices, + provideMockActions(() => actions$), + provideMockStore({ initialState: defaultRootState }) + ] + }).compileComponents() + })) - it('should return value on resolve', async () => { - const regionToSend = 'test-region' - let sentData: any - const apiService = TestBed.get(AtlasViewerAPIServices) - const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') - apiService.getUserToSelectARegionResolve(regionToSend) - await callApi.then(r => { - sentData = r - }) - expect(sentData).toEqual(regionToSend) - }) + it('should return value on resolve', async () => { + const regionToSend = 'test-region' + let sentData: any + const apiService = TestBed.get(AtlasViewerAPIServices) + const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') + apiService.getUserToSelectARegionResolve(regionToSend) + await callApi.then(r => { + sentData = r + }) + expect(sentData).toEqual(regionToSend) + }) - it('pluginRegionSelectionEnabled should false after resolve', async () => { - const { uiState } = defaultRootState - const regionToSend = 'test-region' - let sentData: any - const apiService = TestBed.get(AtlasViewerAPIServices) - const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') - apiService.getUserToSelectARegionResolve(regionToSend) - await callApi.then(r => { - sentData = r - }) - expect(uiState.pluginRegionSelectionEnabled).toBe(false) - }) + it('pluginRegionSelectionEnabled should false after resolve', async () => { + const { uiState } = defaultRootState + const regionToSend = 'test-region' + let sentData: any + const apiService = TestBed.get(AtlasViewerAPIServices) + const callApi = apiService.interactiveViewer.uiHandle.getUserToSelectARegion('selecting Region mode message') + apiService.getUserToSelectARegionResolve(regionToSend) + await callApi.then(r => { + sentData = r + }) + expect(uiState.pluginRegionSelectionEnabled).toBe(false) }) + }) }) \ No newline at end of file diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index 6ee20f5ab6abdde3c7304fcda9486523992b6ce2..b88de47aff1dfd79bff2e3df1d4b7dc1eb0f243f 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -1,9 +1,8 @@ import {Injectable, NgZone} from "@angular/core"; import { select, Store } from "@ngrx/store"; -import { Observable, Subscribable } from "rxjs"; +import { Observable } from "rxjs"; import { distinctUntilChanged, map, filter, startWith } from "rxjs/operators"; import { DialogService } from "src/services/dialogService.service"; -import { LoggingService } from "src/services/logging.service"; import { DISABLE_PLUGIN_REGION_SELECTION, getLabelIndexMap, @@ -13,8 +12,8 @@ import { } from "src/services/stateStore.service"; import { ModalHandler } from "../util/pluginHandlerClasses/modalHandler"; import { ToastHandler } from "../util/pluginHandlerClasses/toastHandler"; -import { IPluginManifest } from "./atlasViewer.pluginService.service"; -import {ENABLE_PLUGIN_REGION_SELECTION} from "src/services/state/uiState.store"; +import { IPluginManifest, PluginServices } from "./pluginUnit"; +import { ENABLE_PLUGIN_REGION_SELECTION } from "src/services/state/uiState.store"; declare let window @@ -36,8 +35,8 @@ export class AtlasViewerAPIServices { constructor( private store: Store<IavRootStoreInterface>, private dialogService: DialogService, - private log: LoggingService, private zone: NgZone, + private pluginService: PluginServices, ) { this.loadedTemplates$ = this.store.pipe( @@ -125,9 +124,14 @@ export class AtlasViewerAPIServices { /** * to be overwritten by atlas */ - launchNewWidget: (_manifest) => { - return Promise.reject('Needs to be overwritted') - }, + launchNewWidget: (manifest) => this.pluginService.launchNewWidget(manifest) + .then(() => { + // trigger change detection in Angular + // otherwise, model won't be updated until user input + + /* eslint-disable-next-line @typescript-eslint/no-empty-function */ + this.zone.run(() => { }) + }), getUserInput: config => this.dialogService.getUserInput(config) , getUserConfirmation: config => this.dialogService.getUserConfirm(config), @@ -156,13 +160,14 @@ export class AtlasViewerAPIServices { } }, - pluginControl : { - loadExternalLibraries : () => Promise.reject('load External Library method not over written') - , - unloadExternalLibraries : () => { - this.log.warn('unloadExternalLibrary method not overwritten by atlasviewer') - }, - }, + pluginControl: new Proxy({}, { + get: (_, prop) => { + if (prop === 'loadExternalLibraries') return this.pluginService.loadExternalLibraries + if (prop === 'unloadExternalLibraries') return this.pluginService.unloadExternalLibraries + if (typeof prop === 'string') return this.pluginService.pluginHandlersMap.get(prop) + return undefined + } + }) as any, } window.interactiveViewer = this.interactiveViewer this.init() diff --git a/src/atlasViewer/atlasViewer.constantService.service.ts b/src/atlasViewer/atlasViewer.constantService.service.ts index 0f4302f2eb877084511118620c525b0028172365..d198eaa62087796d64fd18e31bb829800022071d 100644 --- a/src/atlasViewer/atlasViewer.constantService.service.ts +++ b/src/atlasViewer/atlasViewer.constantService.service.ts @@ -3,7 +3,7 @@ import { Injectable, OnDestroy } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { merge, Observable, of, Subscription, throwError, fromEvent, forkJoin } from "rxjs"; import { catchError, map, shareReplay, switchMap, tap, filter, take } from "rxjs/operators"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { SNACKBAR_MESSAGE } from "src/services/state/uiState.store"; import { IavRootStoreInterface } from "../services/stateStore.service"; import { AtlasWorkerService } from "./atlasViewer.workerService.service"; diff --git a/src/atlasViewer/atlasViewer.pluginService.service.spec.ts b/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.spec.ts similarity index 100% rename from src/atlasViewer/atlasViewer.pluginService.service.spec.ts rename to src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.spec.ts diff --git a/src/atlasViewer/atlasViewer.pluginService.service.ts b/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts similarity index 89% rename from src/atlasViewer/atlasViewer.pluginService.service.ts rename to src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts index 3c02c791f16e49ca05e918594a2f77249d20ed87..aa46be49522122079e696d2f606629f8e3905032 100644 --- a/src/atlasViewer/atlasViewer.pluginService.service.ts +++ b/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts @@ -1,19 +1,18 @@ import { HttpClient } from '@angular/common/http' -import { ComponentFactory, ComponentFactoryResolver, Injectable, NgZone, ViewContainerRef } from "@angular/core"; +import { ComponentFactory, ComponentFactoryResolver, Injectable, ViewContainerRef } from "@angular/core"; import { PLUGINSTORE_ACTION_TYPES } from "src/services/state/pluginState.store"; import { IavRootStoreInterface, isDefined } from 'src/services/stateStore.service' -import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service"; -import { PluginUnit } from "./pluginUnit/pluginUnit.component"; -import { WidgetServices } from "./widgetUnit/widgetService.service"; - +import { PluginUnit } from "./pluginUnit.component"; +import { WidgetServices } from "../widgetUnit/widgetService.service"; import { select, Store } from "@ngrx/store"; import { BehaviorSubject, merge, Observable, of } from "rxjs"; import { filter, map, shareReplay } from "rxjs/operators"; -import { LoggingService } from 'src/services/logging.service'; +import { LoggingService } from 'src/logging'; import { PluginHandler } from 'src/util/pluginHandler'; -import '../res/css/plugin_styles.css' -import { AtlasViewerConstantsServices } from "./atlasViewer.constantService.service"; -import { WidgetUnit } from "./widgetUnit/widgetUnit.component"; +import { AtlasViewerConstantsServices } from "../atlasViewer.constantService.service"; +import { WidgetUnit } from "../widgetUnit/widgetUnit.component"; + +import './plugin_styles.css' @Injectable({ providedIn : 'root', @@ -21,6 +20,11 @@ import { WidgetUnit } from "./widgetUnit/widgetUnit.component"; export class PluginServices { + public pluginHandlersMap: Map<string, PluginHandler> = new Map() + + public loadExternalLibraries: (libraries: string[]) => Promise<any> = () => Promise.reject(`fail to overwritten`) + public unloadExternalLibraries: (libraries: string[]) => void = () => { throw new Error(`failed to be overwritten`) } + public fetchedPluginManifests: IPluginManifest[] = [] public pluginViewContainerRef: ViewContainerRef public appendSrc: (script: HTMLElement) => void @@ -34,13 +38,11 @@ export class PluginServices { public fetch: (url: string, httpOption?: any) => Promise<any> = (url, httpOption = {}) => this.http.get(url, httpOption).toPromise() constructor( - private apiService: AtlasViewerAPIServices, private constantService: AtlasViewerConstantsServices, private widgetService: WidgetServices, private cfr: ComponentFactoryResolver, private store: Store<IavRootStoreInterface>, private http: HttpClient, - zone: NgZone, private log: LoggingService, ) { @@ -52,18 +54,6 @@ export class PluginServices { ) this.pluginUnitFactory = this.cfr.resolveComponentFactory( PluginUnit ) - this.apiService.interactiveViewer.uiHandle.launchNewWidget = (arg) => { - - return this.launchNewWidget(arg) - .then(arg2 => { - // trigger change detection in Angular - // otherwise, model won't be updated until user input - - /* eslint-disable-next-line @typescript-eslint/no-empty-function */ - zone.run(() => { }) - return arg2 - }) - } /** * TODO convert to rxjs streams, instead of Promise.all @@ -216,7 +206,7 @@ export class PluginServices { */ const handler = new PluginHandler() - this.apiService.interactiveViewer.pluginControl[plugin.name] = handler + this.pluginHandlersMap.set(plugin.name, handler) /** * define the handler properties prior to appending plugin script @@ -289,7 +279,7 @@ export class PluginServices { handler.onShutdown(() => { unsubscribeOnPluginDestroy.forEach(s => s.unsubscribe()) - delete this.apiService.interactiveViewer.pluginControl[plugin.name] + this.pluginHandlersMap.delete(plugin.name) this.mapPluginNameToWidgetUnit.delete(plugin.name) }) diff --git a/src/atlasViewer/pluginUnit/index.ts b/src/atlasViewer/pluginUnit/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc1c5058b8b8133b2d2c1e8547b6c9c51404a752 --- /dev/null +++ b/src/atlasViewer/pluginUnit/index.ts @@ -0,0 +1 @@ +export { PluginServices, IPluginManifest } from './atlasViewer.pluginService.service' \ No newline at end of file diff --git a/src/atlasViewer/pluginUnit/plugin.module.ts b/src/atlasViewer/pluginUnit/plugin.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..88198bfe685c2613faee04332ae417ffd6e9ee1c --- /dev/null +++ b/src/atlasViewer/pluginUnit/plugin.module.ts @@ -0,0 +1,27 @@ +import { NgModule } from "@angular/core"; +import { PluginUnit } from "./pluginUnit.component"; +import { PluginServices } from "./atlasViewer.pluginService.service"; +import { PluginFactoryDirective } from "./pluginFactory.directive"; +import { LoggingModule } from "src/logging"; + +@NgModule({ + imports:[ + LoggingModule, + ], + declarations: [ + PluginUnit, + PluginFactoryDirective + ], + entryComponents: [ + PluginUnit + ], + exports: [ + PluginUnit, + PluginFactoryDirective + ], + providers: [ + PluginServices + ] +}) + +export class PluginModule{} \ No newline at end of file diff --git a/src/atlasViewer/pluginUnit/pluginFactory.directive.ts b/src/atlasViewer/pluginUnit/pluginFactory.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..65081f45eb78a0506b9997b171975f7026c31cb1 --- /dev/null +++ b/src/atlasViewer/pluginUnit/pluginFactory.directive.ts @@ -0,0 +1,80 @@ +import { Directive, Renderer2, ViewContainerRef } from "@angular/core"; +import { SUPPORT_LIBRARY_MAP } from "src/atlasViewer/atlasViewer.constantService.service"; +import { PluginServices } from "./atlasViewer.pluginService.service"; +import { LoggingService } from "src/logging"; + +@Directive({ + selector: '[pluginFactoryDirective]', +}) + +export class PluginFactoryDirective { + constructor( + pluginService: PluginServices, + viewContainerRef: ViewContainerRef, + private rd2: Renderer2, + private log: LoggingService, + ) { + pluginService.loadExternalLibraries = this.loadExternalLibraries.bind(this) + pluginService.unloadExternalLibraries = this.unloadExternalLibraries.bind(this) + pluginService.pluginViewContainerRef = viewContainerRef + pluginService.appendSrc = (src: HTMLElement) => rd2.appendChild(document.head, src) + pluginService.removeSrc = (src: HTMLElement) => rd2.removeChild(document.head, src) + } + + private loadedLibraries: Map<string, {counter: number, src: HTMLElement|null}> = new Map() + + loadExternalLibraries(libraries: string[]) { + const srcHTMLElement = libraries.map(libraryName => ({ + name: libraryName, + srcEl: SUPPORT_LIBRARY_MAP.get(libraryName), + })) + + const rejected = srcHTMLElement.filter(scriptObj => scriptObj.srcEl === null) + if (rejected.length > 0) { + return Promise.reject(`Some library names cannot be recognised. No libraries were loaded: ${rejected.map(srcObj => srcObj.name).join(', ')}`) + } + + return Promise.all(srcHTMLElement.map(scriptObj => new Promise((rs, rj) => { + /** + * if browser already support customElements, do not append polyfill + */ + if ('customElements' in window && scriptObj.name === 'webcomponentsLite') { + return rs() + } + const existingEntry = this.loadedLibraries.get(scriptObj.name) + if (existingEntry) { + this.loadedLibraries.set(scriptObj.name, { counter: existingEntry.counter + 1, src: existingEntry.src }) + rs() + } else { + const srcEl = scriptObj.srcEl + srcEl.onload = () => rs() + srcEl.onerror = (e: any) => rj(e) + this.rd2.appendChild(document.head, srcEl) + this.loadedLibraries.set(scriptObj.name, { counter: 1, src: srcEl }) + } + }))) + } + + unloadExternalLibraries(libraries: string[]) { + libraries + .filter((stringname) => SUPPORT_LIBRARY_MAP.get(stringname) !== null) + .forEach(libname => { + const ledger = this.loadedLibraries.get(libname) + if (!ledger) { + this.log.warn('unload external libraries error. cannot find ledger entry...', libname, this.loadedLibraries) + return + } + if (ledger.src === null) { + this.log.log('webcomponents is native supported. no library needs to be unloaded') + return + } + + if (ledger.counter - 1 == 0) { + this.rd2.removeChild(document.head, ledger.src) + this.loadedLibraries.delete(libname) + } else { + this.loadedLibraries.set(libname, { counter: ledger.counter - 1, src: ledger.src }) + } + }) + } +} diff --git a/src/res/css/plugin_styles.css b/src/atlasViewer/pluginUnit/plugin_styles.css similarity index 100% rename from src/res/css/plugin_styles.css rename to src/atlasViewer/pluginUnit/plugin_styles.css diff --git a/src/atlasViewer/widgetUnit/widget.module.ts b/src/atlasViewer/widgetUnit/widget.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff312e2f72b07d0cfa7ecd6473db542bef7763e4 --- /dev/null +++ b/src/atlasViewer/widgetUnit/widget.module.ts @@ -0,0 +1,28 @@ +import { NgModule } from "@angular/core"; +import { WidgetUnit } from "./widgetUnit.component"; +import { WidgetServices } from "./widgetService.service"; +import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module"; +import { CommonModule } from "@angular/common"; +import { ComponentsModule } from "src/components/components.module"; + +@NgModule({ + imports:[ + AngularMaterialModule, + CommonModule, + ComponentsModule, + ], + declarations: [ + WidgetUnit + ], + entryComponents: [ + WidgetUnit + ], + providers: [ + WidgetServices + ], + exports: [ + WidgetUnit + ] +}) + +export class WidgetModule{} \ No newline at end of file diff --git a/src/atlasViewer/widgetUnit/widgetService.service.ts b/src/atlasViewer/widgetUnit/widgetService.service.ts index b784a431b7753af0ce54ddfc0bc30bf9a1844136..9214e722159589e5a3ecd4371837b313a4776e96 100644 --- a/src/atlasViewer/widgetUnit/widgetService.service.ts +++ b/src/atlasViewer/widgetUnit/widgetService.service.ts @@ -1,6 +1,6 @@ import { ComponentFactory, ComponentFactoryResolver, ComponentRef, Injectable, Injector, OnDestroy, ViewContainerRef } from "@angular/core"; import { BehaviorSubject, Subscription } from "rxjs"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { AtlasViewerConstantsServices } from "../atlasViewer.constantService.service"; import { WidgetUnit } from "./widgetUnit.component"; @@ -92,8 +92,13 @@ export class WidgetServices implements OnDestroy { if (component.constructor === Error) { throw component } else { - const _component = (component as ComponentRef<WidgetUnit>); + const _component = (component as ComponentRef<WidgetUnit>) + + // guestComponentRef + // insert view _component.instance.container.insert( guestComponentRef.hostView ) + // on host destroy, destroy guest + _component.onDestroy(() => guestComponentRef.destroy()) /* programmatic DI */ _component.instance.widgetServices = this diff --git a/src/atlasViewer/widgetUnit/widgetUnit.template.html b/src/atlasViewer/widgetUnit/widgetUnit.template.html index de35f7f2a2ee8c0c57dcb50db74ce0521dfdce62..73a764fbc3d39199064a127e2b5b29c3ad73f906 100644 --- a/src/atlasViewer/widgetUnit/widgetUnit.template.html +++ b/src/atlasViewer/widgetUnit/widgetUnit.template.html @@ -1,4 +1,5 @@ <panel-component + [attr.aria-label]="'Widget for ' + title" widgetUnitPanel [ngClass]="{'blinkOn': blinkOn}" [bodyCollapsable] = "state === 'docked'" @@ -37,6 +38,7 @@ </ng-container> <i *ngIf="exitable" + aria-label="close" (click)="exit($event)" class="fas fa-times" [hoverable] ="hoverableConfig"></i> diff --git a/src/logging/index.ts b/src/logging/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..991cc7ba5496b778cc58b0c816e6bbdf46627e03 --- /dev/null +++ b/src/logging/index.ts @@ -0,0 +1,2 @@ +export { LoggingModule } from './logging.module' +export { LoggingService } from './logging.service' \ No newline at end of file diff --git a/src/logging/logging.module.ts b/src/logging/logging.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6725602fc209543040e17663c2804154bcf4e32 --- /dev/null +++ b/src/logging/logging.module.ts @@ -0,0 +1,10 @@ +import { NgModule } from "@angular/core"; +import { LoggingService } from "./logging.service"; + +@NgModule({ + providers:[ + LoggingService + ] +}) + +export class LoggingModule{} \ No newline at end of file diff --git a/src/services/logging.service.ts b/src/logging/logging.service.ts similarity index 100% rename from src/services/logging.service.ts rename to src/logging/logging.service.ts diff --git a/src/main.module.ts b/src/main.module.ts index d6900a592448a1150595b7c840dc5ee139b493c9..3b911d31fd2d5a0b27f52f69aed3d589c6288bd2 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -12,16 +12,13 @@ import { UIModule } from "./ui/ui.module"; import { GetNamePipe } from "./util/pipes/getName.pipe"; import { GetNamesPipe } from "./util/pipes/getNames.pipe"; -import {HttpClientModule} from "@angular/common/http"; +import { HttpClientModule } from "@angular/common/http"; import { EffectsModule } from "@ngrx/effects"; -import {CaptureClickListenerDirective} from "src/util/directives/captureClickListener.directive"; +import { CaptureClickListenerDirective } from "src/util/directives/captureClickListener.directive"; import { AtlasViewerAPIServices } from "./atlasViewer/atlasViewer.apiService.service"; import { AtlasWorkerService } from "./atlasViewer/atlasViewer.workerService.service"; import { ModalUnit } from "./atlasViewer/modalUnit/modalUnit.component"; import { TransformOnhoverSegmentPipe } from "./atlasViewer/onhoverSegment.pipe"; -import { PluginUnit } from "./atlasViewer/pluginUnit/pluginUnit.component"; -import { WidgetServices } from './atlasViewer/widgetUnit/widgetService.service' -import { WidgetUnit } from "./atlasViewer/widgetUnit/widgetUnit.component"; import { ConfirmDialogComponent } from "./components/confirmDialog/confirmDialog.component"; import { DialogComponent } from "./components/dialog/dialog.component"; import { AuthService } from "./services/auth.service"; @@ -39,21 +36,22 @@ import { DockedContainerDirective } from "./util/directives/dockedContainer.dire import { DragDropDirective } from "./util/directives/dragDrop.directive"; import { FloatingContainerDirective } from "./util/directives/floatingContainer.directive"; import { FloatingMouseContextualContainerDirective } from "./util/directives/floatingMouseContextualContainer.directive"; -import { PluginFactoryDirective } from "./util/directives/pluginFactory.directive"; import { NewViewerDisctinctViewToLayer } from "./util/pipes/newViewerDistinctViewToLayer.pipe"; import { UtilModule } from "./util/util.module"; -import 'hammerjs' +import { UiStateUseEffect } from "src/services/state/uiState.store"; +import { AtlasViewerHistoryUseEffect } from "./atlasViewer/atlasViewer.history.service"; +import { PluginServiceUseEffect } from './services/effect/pluginUseEffect'; +import { TemplateCoordinatesTransformation } from "src/services/templateCoordinatesTransformation.service"; +import { NewTemplateUseEffect } from './services/effect/newTemplate.effect'; +import { WidgetModule } from './atlasViewer/widgetUnit/widget.module'; +import { PluginModule } from './atlasViewer/pluginUnit/plugin.module'; +import { LoggingModule } from './logging/logging.module'; +import 'hammerjs' import 'src/res/css/extra_styles.css' import 'src/res/css/version.css' -import {UiStateUseEffect} from "src/services/state/uiState.store"; import 'src/theme.scss' -import { AtlasViewerHistoryUseEffect } from "./atlasViewer/atlasViewer.history.service"; -import { PluginServiceUseEffect } from './services/effect/pluginUseEffect'; -import { LoggingService } from "./services/logging.service"; -import {TemplateCoordinatesTransformation} from "src/services/templateCoordinatesTransformation.service"; -import { NewTemplateUseEffect } from './services/effect/newTemplate.effect'; @NgModule({ imports : [ @@ -66,6 +64,9 @@ import { NewTemplateUseEffect } from './services/effect/newTemplate.effect'; DatabrowserModule, AngularMaterialModule, UtilModule, + WidgetModule, + PluginModule, + LoggingModule, EffectsModule.forRoot([ DataBrowserUseEffect, @@ -92,14 +93,11 @@ import { NewTemplateUseEffect } from './services/effect/newTemplate.effect'; ], declarations : [ AtlasViewer, - WidgetUnit, ModalUnit, - PluginUnit, /* directives */ DockedContainerDirective, FloatingContainerDirective, - PluginFactoryDirective, FloatingMouseContextualContainerDirective, DragDropDirective, CaptureClickListenerDirective, @@ -111,21 +109,17 @@ import { NewTemplateUseEffect } from './services/effect/newTemplate.effect'; NewViewerDisctinctViewToLayer, ], entryComponents : [ - WidgetUnit, ModalUnit, - PluginUnit, DialogComponent, ConfirmDialogComponent, ], providers : [ - WidgetServices, AtlasViewerAPIServices, AtlasWorkerService, AuthService, LocalFileService, DialogService, UIService, - LoggingService, TemplateCoordinatesTransformation, /** diff --git a/src/services/effect/effect.ts b/src/services/effect/effect.ts index 21d0fa53fed58f5dcb7a3a6dfd5131dd5285d73d..500e42d8c03b79ca8328cb8b020a92360a6a074c 100644 --- a/src/services/effect/effect.ts +++ b/src/services/effect/effect.ts @@ -3,9 +3,9 @@ import { Actions, Effect, ofType } from "@ngrx/effects"; import { select, Store } from "@ngrx/store"; import { merge, Observable, Subscription } from "rxjs"; import { filter, map, shareReplay, switchMap, take, withLatestFrom, mapTo } from "rxjs/operators"; -import { LoggingService } from "../logging.service"; -import { ADD_TO_REGIONS_SELECTION_WITH_IDS, DESELECT_REGIONS, NEWVIEWER, CHANGE_NAVIGATION, SELECT_PARCELLATION, SELECT_REGIONS, SELECT_REGIONS_WITH_ID, SELECT_LANDMARKS } from "../state/viewerState.store"; -import { generateLabelIndexId, getNgIdLabelIndexFromId, IavRootStoreInterface, recursiveFindRegionWithLabelIndexId, getMultiNgIdsRegionsLabelIndexMap, GENERAL_ACTION_TYPES } from '../stateStore.service'; +import { LoggingService } from "src/logging"; +import { ADD_TO_REGIONS_SELECTION_WITH_IDS, DESELECT_REGIONS, NEWVIEWER, SELECT_PARCELLATION, SELECT_REGIONS, SELECT_REGIONS_WITH_ID, SELECT_LANDMARKS } from "../state/viewerState.store"; +import { generateLabelIndexId, getNgIdLabelIndexFromId, IavRootStoreInterface, recursiveFindRegionWithLabelIndexId } from '../stateStore.service'; @Injectable({ providedIn: 'root', diff --git a/src/services/effect/pluginUseEffect.spec.ts b/src/services/effect/pluginUseEffect.spec.ts index 0775ef163b96455b1d585fb5b5f0be46b9058d32..2bd9efda5c25597914f82dcaf0acbd38fa18f288 100644 --- a/src/services/effect/pluginUseEffect.spec.ts +++ b/src/services/effect/pluginUseEffect.spec.ts @@ -9,7 +9,7 @@ import { defaultRootState } from "../stateStore.service"; import { PLUGINSTORE_CONSTANTS, PLUGINSTORE_ACTION_TYPES } from '../state/pluginState.store' import { Injectable } from "@angular/core"; import { getRandomHex } from 'common/util' -import { PluginServices } from "src/atlasViewer/atlasViewer.pluginService.service"; +import { PluginServices } from "src/atlasViewer/pluginUnit"; import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module"; import { hot } from "jasmine-marbles"; diff --git a/src/services/effect/pluginUseEffect.ts b/src/services/effect/pluginUseEffect.ts index 4b65c4d3807d0d0a7df59d7c7a70bbcab8dd605a..5a28ace68c9c20e5867d70ebff2ad8e46e983e6e 100644 --- a/src/services/effect/pluginUseEffect.ts +++ b/src/services/effect/pluginUseEffect.ts @@ -4,9 +4,9 @@ import { select, Store } from "@ngrx/store" import { Observable, forkJoin } from "rxjs" import { filter, map, startWith, switchMap } from "rxjs/operators" import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service" -import { PluginServices } from "src/atlasViewer/atlasViewer.pluginService.service" +import { PluginServices } from "src/atlasViewer/pluginUnit" import { PLUGINSTORE_ACTION_TYPES, PLUGINSTORE_CONSTANTS } from 'src/services/state/pluginState.store' -import { LoggingService } from "../logging.service" +import { LoggingService } from "src/logging" import { IavRootStoreInterface } from "../stateStore.service" import { HttpClient } from "@angular/common/http" diff --git a/src/services/state/viewerState.store.ts b/src/services/state/viewerState.store.ts index 2c4089380ff0841dc8f82361f5ce6e53e3040eda..32aa245885a85a13db77008022d6e11834896c98 100644 --- a/src/services/state/viewerState.store.ts +++ b/src/services/state/viewerState.store.ts @@ -6,7 +6,7 @@ import { distinctUntilChanged, filter, map, shareReplay, startWith, withLatestFr import { IUserLandmark } from 'src/atlasViewer/atlasViewer.apiService.service'; import { INgLayerInterface } from 'src/atlasViewer/atlasViewer.component'; import { getViewer } from 'src/util/fn'; -import { LoggingService } from '../logging.service'; +import { LoggingService } from 'src/logging'; import { generateLabelIndexId, IavRootStoreInterface, viewerState } from '../stateStore.service'; import { GENERAL_ACTION_TYPES } from '../stateStore.service' import { MOUSEOVER_USER_LANDMARK, CLOSE_SIDE_PANEL } from './uiState.store'; diff --git a/src/ui/databrowserModule/databrowser.service.ts b/src/ui/databrowserModule/databrowser.service.ts index de480e44d03abed477e4df8a4699fd2de6f9a34a..2bb4c828b61241c778a4014834f2390766afc428 100644 --- a/src/ui/databrowserModule/databrowser.service.ts +++ b/src/ui/databrowserModule/databrowser.service.ts @@ -6,7 +6,7 @@ import { catchError, debounceTime, distinctUntilChanged, filter, map, shareRepla import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service"; import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service"; import { WidgetUnit } from "src/atlasViewer/widgetUnit/widgetUnit.component"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { DATASETS_ACTIONS_TYPES } from "src/services/state/dataStore.store"; import { SHOW_KG_TOS } from "src/services/state/uiState.store"; import { FETCHED_DATAENTRIES, FETCHED_SPATIAL_DATA, IavRootStoreInterface, IDataEntry, safeFilter } from "src/services/stateStore.service"; diff --git a/src/ui/databrowserModule/databrowser.useEffect.ts b/src/ui/databrowserModule/databrowser.useEffect.ts index b30394864e479998842c00434ed2157320ec9f44..add27a5bf5e2947a0ebc7bb25764cd7d20bcd6e8 100644 --- a/src/ui/databrowserModule/databrowser.useEffect.ts +++ b/src/ui/databrowserModule/databrowser.useEffect.ts @@ -3,7 +3,7 @@ import { Actions, Effect, ofType } from "@ngrx/effects"; import { select, Store } from "@ngrx/store"; import { from, merge, Observable, of, Subscription, forkJoin, combineLatest } from "rxjs"; import { filter, map, scan, switchMap, withLatestFrom, mapTo, shareReplay, startWith, distinctUntilChanged } from "rxjs/operators"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { DATASETS_ACTIONS_TYPES, IDataEntry, ViewerPreviewFile } from "src/services/state/dataStore.store"; import { IavRootStoreInterface, ADD_NG_LAYER, CHANGE_NAVIGATION } from "src/services/stateStore.service"; import { LOCAL_STORAGE_CONST, DS_PREVIEW_URL } from "src/util/constants"; @@ -75,7 +75,7 @@ export class DataBrowserUseEffect implements OnDestroy { ).subscribe(({ datasetId, filename }) => { // TODO replace with common/util/getIdFromFullId - + // TODO replace with widgetService.open const re = getKgSchemaIdFromFullId(datasetId) this.dialog.open( PreviewComponentWrapper, diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts index 2dd92a75a3889871bf8d00f6ec71b30f8011c630..39cfcff1dcc554485cb3d8ee267af93de7ac69f1 100644 --- a/src/ui/databrowserModule/databrowser/databrowser.component.ts +++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, ViewChild } from "@angular/core"; import { merge, Observable, Subscription } from "rxjs"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { IDataEntry } from "src/services/stateStore.service"; import { CountedDataModality, DatabrowserService } from "../databrowser.service"; import { ModalityPicker } from "../modalityPicker/modalityPicker.component"; diff --git a/src/ui/layerbrowser/layerbrowser.component.ts b/src/ui/layerbrowser/layerbrowser.component.ts index e4058dbe89db9ad207a30ff0941df5f6ce80af92..cc14ee88c2db83da83bb2e9daa5990a50fd77abc 100644 --- a/src/ui/layerbrowser/layerbrowser.component.ts +++ b/src/ui/layerbrowser/layerbrowser.component.ts @@ -3,12 +3,12 @@ import { select, Store } from "@ngrx/store"; import { combineLatest, Observable, Subscription } from "rxjs"; import { debounceTime, distinctUntilChanged, filter, map, shareReplay } from "rxjs/operators"; import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { NG_VIEWER_ACTION_TYPES } from "src/services/state/ngViewerState.store"; import { getViewer } from "src/util/fn"; import { INgLayerInterface } from "../../atlasViewer/atlasViewer.component"; import { FORCE_SHOW_SEGMENT, getNgIds, isDefined, REMOVE_NG_LAYER, safeFilter, ViewerStateInterface } from "../../services/stateStore.service"; -import {MatSliderChange} from "@angular/material/slider"; +import { MatSliderChange } from "@angular/material/slider"; @Component({ selector : 'layer-browser', diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts index 9dd4431b64b488c3cae0ce9725de120e050d2d12..c48e166f73673beee11964086742e44ac0330b19 100644 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ b/src/ui/nehubaContainer/nehubaContainer.component.ts @@ -21,17 +21,15 @@ import { throttleTime, withLatestFrom } from "rxjs/operators"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { FOUR_PANEL, H_ONE_THREE, NEHUBA_READY, NG_VIEWER_ACTION_TYPES, SINGLE_PANEL, V_ONE_THREE } from "src/services/state/ngViewerState.store"; -import { MOUSE_OVER_SEGMENTS } from "src/services/state/uiState.store"; -import { NEHUBA_LAYER_CHANGED, SELECT_REGIONS_WITH_ID, VIEWERSTATE_ACTION_TYPES } from "src/services/state/viewerState.store"; -import { ADD_NG_LAYER, CHANGE_NAVIGATION, generateLabelIndexId, getMultiNgIdsRegionsLabelIndexMap, getNgIds, ILandmark, IOtherLandmarkGeometry, IPlaneLandmarkGeometry, IPointLandmarkGeometry, isDefined, MOUSE_OVER_LANDMARK, NgViewerStateInterface, REMOVE_NG_LAYER, safeFilter, ViewerStateInterface } from "src/services/stateStore.service"; +import { SELECT_REGIONS_WITH_ID, VIEWERSTATE_ACTION_TYPES } from "src/services/state/viewerState.store"; +import { ADD_NG_LAYER, generateLabelIndexId, getMultiNgIdsRegionsLabelIndexMap, getNgIds, ILandmark, IOtherLandmarkGeometry, IPlaneLandmarkGeometry, IPointLandmarkGeometry, isDefined, MOUSE_OVER_LANDMARK, NgViewerStateInterface, REMOVE_NG_LAYER, safeFilter, ViewerStateInterface } from "src/services/stateStore.service"; import { getExportNehuba, isSame } from "src/util/fn"; import { AtlasViewerAPIServices, IUserLandmark } from "../../atlasViewer/atlasViewer.apiService.service"; import { AtlasViewerConstantsServices } from "../../atlasViewer/atlasViewer.constantService.service"; -import { timedValues } from "../../util/generator"; import { computeDistance, NehubaViewerUnit } from "./nehubaViewer/nehubaViewer.component"; -import { getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, getNavigationStateFromConfig, calculateSliceZoomFactor } from "./util"; +import { getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, calculateSliceZoomFactor } from "./util"; import { NehubaViewerContainerDirective } from "./nehubaViewerInterface/nehubaViewerInterface.directive"; const isFirstRow = (cell: HTMLElement) => { diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts index f35f83d03f7be8a942f6a33268a81e43f6a63e54..f86c403ce72df183cc704a283c059967bee5dca7 100644 --- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts +++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts @@ -8,7 +8,7 @@ import { StateInterface as ViewerConfiguration } from "src/services/state/viewer import { getNgIdLabelIndexFromId } from "src/services/stateStore.service"; import { takeOnePipe } from "../nehubaContainer.component"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { getExportNehuba, getViewer, setNehubaViewer } from "src/util/fn"; import 'third_party/export_nehuba/chunk_worker.bundle.js' import 'third_party/export_nehuba/main.bundle.js' diff --git a/src/ui/nehubaContainer/statusCard/statusCard.component.ts b/src/ui/nehubaContainer/statusCard/statusCard.component.ts index 6bd0f103a75687c934b7c173516e96d13bde0eb5..5dd2b1116da0cd8e70ff95add9b1db9cbdf82f74 100644 --- a/src/ui/nehubaContainer/statusCard/statusCard.component.ts +++ b/src/ui/nehubaContainer/statusCard/statusCard.component.ts @@ -1,10 +1,10 @@ -import {Component, Input, OnInit} from "@angular/core"; -import {select, Store} from "@ngrx/store"; -import { LoggingService } from "src/services/logging.service"; -import {CHANGE_NAVIGATION, IavRootStoreInterface, ViewerStateInterface} from "src/services/stateStore.service"; +import { Component, Input, OnInit } from "@angular/core"; +import { select, Store } from "@ngrx/store"; +import { LoggingService } from "src/logging"; +import { CHANGE_NAVIGATION, IavRootStoreInterface, ViewerStateInterface } from "src/services/stateStore.service"; import { NehubaViewerUnit } from "../nehubaViewer/nehubaViewer.component"; -import {Observable, Subscription} from "rxjs"; -import {distinctUntilChanged, shareReplay} from "rxjs/operators"; +import { Observable, Subscription } from "rxjs"; +import { distinctUntilChanged, shareReplay } from "rxjs/operators"; @Component({ selector : 'ui-status-card', diff --git a/src/ui/pluginBanner/pluginBanner.component.ts b/src/ui/pluginBanner/pluginBanner.component.ts index 930cec72eb9055a802842143dff7aa4fe2de1857..20b225c21ad0975620968c3d42b51b6c6f650e5a 100644 --- a/src/ui/pluginBanner/pluginBanner.component.ts +++ b/src/ui/pluginBanner/pluginBanner.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { IPluginManifest, PluginServices } from "src/atlasViewer/atlasViewer.pluginService.service"; +import { IPluginManifest, PluginServices } from "src/atlasViewer/pluginUnit"; @Component({ selector : 'plugin-banner', diff --git a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts index 01cdf6d3745179591209349a536e84073d79944c..f21d4f11f399b0f79ba28f2a5be9107981c392aa 100644 --- a/src/ui/viewerStateController/regionSearch/regionSearch.component.ts +++ b/src/ui/viewerStateController/regionSearch/regionSearch.component.ts @@ -8,9 +8,9 @@ import { VIEWER_STATE_ACTION_TYPES } from "src/services/effect/effect"; import { ADD_TO_REGIONS_SELECTION_WITH_IDS, CHANGE_NAVIGATION, SELECT_REGIONS } from "src/services/state/viewerState.store"; import { generateLabelIndexId, getMultiNgIdsRegionsLabelIndexMap, IavRootStoreInterface } from "src/services/stateStore.service"; import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "../viewerState.base"; -import { LoggingService } from "src/services/logging.service"; -import {MatDialog} from "@angular/material/dialog"; -import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; +import { LoggingService } from "src/logging"; +import { MatDialog } from "@angular/material/dialog"; +import { MatAutocompleteSelectedEvent } from "@angular/material/autocomplete"; const filterRegionBasedOnText = searchTerm => region => region.name.toLowerCase().includes(searchTerm.toLowerCase()) || (region.relatedAreas && region.relatedAreas.some(relatedArea => relatedArea.name && relatedArea.name.toLowerCase().includes(searchTerm.toLowerCase()))) diff --git a/src/ui/viewerStateController/viewerState.useEffect.spec.ts b/src/ui/viewerStateController/viewerState.useEffect.spec.ts index 8fc55ccd958cf7bcc5414662b822cf971022af17..42e006f8ca438a247ce8edf9f50678494bcd3774 100644 --- a/src/ui/viewerStateController/viewerState.useEffect.spec.ts +++ b/src/ui/viewerStateController/viewerState.useEffect.spec.ts @@ -1,6 +1,6 @@ import { ViewerStateControllerUseEffect } from './viewerState.useEffect' import { Observable, of } from 'rxjs' -import { TestBed } from '@angular/core/testing' +import { TestBed, async } from '@angular/core/testing' import { provideMockActions } from '@ngrx/effects/testing' import { provideMockStore } from '@ngrx/store/testing' import { defaultRootState, NEWVIEWER } from 'src/services/stateStore.service' @@ -10,6 +10,8 @@ import { hot } from 'jasmine-marbles' import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from './viewerState.base' import { AngularMaterialModule } from '../sharedModules/angularMaterial.module' import { HttpClientModule } from '@angular/common/http' +import { WidgetModule } from 'src/atlasViewer/widgetUnit/widget.module' +import { PluginModule } from 'src/atlasViewer/pluginUnit/plugin.module' const bigbrainJson = require('!json-loader!src/res/ext/bigbrain.json') const colinJson = require('!json-loader!src/res/ext/colin.json') @@ -49,7 +51,7 @@ describe('viewerState.useEffect.ts', () => { describe('ViewerStateControllerUseEffect', () => { let actions$: Observable<any> let spy: any - beforeEach(() => { + beforeEach(async(() => { const mock = new MockCoordXformService() spy = spyOn(mock, 'getPointCoordinatesForTemplate').and.callThrough() @@ -67,7 +69,9 @@ describe('viewerState.useEffect.ts', () => { TestBed.configureTestingModule({ imports: [ AngularMaterialModule, - HttpClientModule + HttpClientModule, + WidgetModule, + PluginModule, ], providers: [ ViewerStateControllerUseEffect, @@ -78,8 +82,8 @@ describe('viewerState.useEffect.ts', () => { useValue: mock } ] - }) - }) + }).compileComponents() + })) describe('selectTemplateWithName$', () => { diff --git a/src/util/directives/mouseOver.directive.ts b/src/util/directives/mouseOver.directive.ts index 56402863cc100ac51df759bf4a1529752de5d110..c3eccd363f7add28ae9630b12c8231466d3c412f 100644 --- a/src/util/directives/mouseOver.directive.ts +++ b/src/util/directives/mouseOver.directive.ts @@ -4,7 +4,7 @@ import { select, Store } from "@ngrx/store"; import { combineLatest, merge, Observable } from "rxjs"; import { distinctUntilChanged, filter, map, scan, shareReplay, startWith, withLatestFrom } from "rxjs/operators"; import { TransformOnhoverSegmentPipe } from "src/atlasViewer/onhoverSegment.pipe"; -import { LoggingService } from "src/services/logging.service"; +import { LoggingService } from "src/logging"; import { getNgIdLabelIndexFromId, IavRootStoreInterface } from "src/services/stateStore.service"; /** diff --git a/src/util/directives/pluginFactory.directive.ts b/src/util/directives/pluginFactory.directive.ts deleted file mode 100644 index eb40319fb85ad6028ddfa681540ff07b4813efef..0000000000000000000000000000000000000000 --- a/src/util/directives/pluginFactory.directive.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Directive, Renderer2, ViewContainerRef } from "@angular/core"; -import { AtlasViewerAPIServices } from "src/atlasViewer/atlasViewer.apiService.service"; -import { SUPPORT_LIBRARY_MAP } from "src/atlasViewer/atlasViewer.constantService.service"; -import { PluginServices } from "src/atlasViewer/atlasViewer.pluginService.service"; -import { LoggingService } from "src/services/logging.service"; - -@Directive({ - selector: '[pluginFactoryDirective]', -}) - -export class PluginFactoryDirective { - constructor( - pluginService: PluginServices, - viewContainerRef: ViewContainerRef, - rd2: Renderer2, - apiService: AtlasViewerAPIServices, - private log: LoggingService, - ) { - pluginService.pluginViewContainerRef = viewContainerRef - pluginService.appendSrc = (src: HTMLElement) => rd2.appendChild(document.head, src) - pluginService.removeSrc = (src: HTMLElement) => rd2.removeChild(document.head, src) - - apiService.interactiveViewer.pluginControl.loadExternalLibraries = (libraries: string[]) => new Promise((resolve, reject) => { - const srcHTMLElement = libraries.map(libraryName => ({ - name: libraryName, - srcEl: SUPPORT_LIBRARY_MAP.get(libraryName), - })) - - const rejected = srcHTMLElement.filter(scriptObj => scriptObj.srcEl === null) - if (rejected.length > 0) { - return reject(`Some library names cannot be recognised. No libraries were loaded: ${rejected.map(srcObj => srcObj.name).join(', ')}`) - } - - Promise.all(srcHTMLElement.map(scriptObj => new Promise((rs, rj) => { - /** - * if browser already support customElements, do not append polyfill - */ - if ('customElements' in window && scriptObj.name === 'webcomponentsLite') { - return rs() - } - const existingEntry = apiService.loadedLibraries.get(scriptObj.name) - if (existingEntry) { - apiService.loadedLibraries.set(scriptObj.name, { counter: existingEntry.counter + 1, src: existingEntry.src }) - rs() - } else { - const srcEl = scriptObj.srcEl - srcEl.onload = () => rs() - srcEl.onerror = (e: any) => rj(e) - rd2.appendChild(document.head, srcEl) - apiService.loadedLibraries.set(scriptObj.name, { counter: 1, src: srcEl }) - } - }))) - .then(() => resolve()) - .catch(e => (this.log.warn(e), reject(e))) - }) - - apiService.interactiveViewer.pluginControl.unloadExternalLibraries = (libraries: string[]) => - libraries - .filter((stringname) => SUPPORT_LIBRARY_MAP.get(stringname) !== null) - .forEach(libname => { - const ledger = apiService.loadedLibraries.get(libname) - if (!ledger) { - this.log.warn('unload external libraries error. cannot find ledger entry...', libname, apiService.loadedLibraries) - return - } - if (ledger.src === null) { - this.log.log('webcomponents is native supported. no library needs to be unloaded') - return - } - - if (ledger.counter - 1 == 0) { - rd2.removeChild(document.head, ledger.src) - apiService.loadedLibraries.delete(libname) - } else { - apiService.loadedLibraries.set(libname, { counter: ledger.counter - 1, src: ledger.src }) - } - }) - } -} diff --git a/src/util/util.module.ts b/src/util/util.module.ts index 5594549241c4bf0c48f0c95ad07813d6875717af..e8af338f0ab9d60806b3f190d4854152cd91499c 100644 --- a/src/util/util.module.ts +++ b/src/util/util.module.ts @@ -33,6 +33,8 @@ import { SafeResourcePipe } from "./pipes/safeResource.pipe"; IncludesPipe, SafeResourcePipe, ], + providers: [ + ] }) export class UtilModule {