evt-status.service.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { Injectable } from '@angular/core';
  2. import { ActivatedRoute, NavigationStart, Router } from '@angular/router';
  3. import { BehaviorSubject, combineLatest, merge, Observable, Subject, timer } from 'rxjs';
  4. import { distinctUntilChanged, filter, first, map, shareReplay, switchMap } from 'rxjs/operators';
  5. import { AppConfig, EditionLevelType } from '../app.config';
  6. import { Page, ViewMode } from '../models/evt-models';
  7. import { EVTModelService } from './evt-model.service';
  8. export type URLParamsKeys = 'd' | 'p' | 'el' | 'ws' | 'vs';
  9. export type URLParams = { [T in URLParamsKeys]: string };
  10. @Injectable({
  11. providedIn: 'root',
  12. })
  13. export class EVTStatusService {
  14. public availableEditionLevels = AppConfig.evtSettings.edition.availableEditionLevels?.filter((e => !e.disabled)) || [];
  15. get defaultEditionLevelId(): EditionLevelType {
  16. const defaultConfig = AppConfig.evtSettings.edition.defaultEdition;
  17. const availableEditionLevels = AppConfig.evtSettings.edition.availableEditionLevels?.filter((e => !e.disabled)) ?? [];
  18. let defaultEdition = availableEditionLevels[0];
  19. if (defaultConfig) {
  20. defaultEdition = availableEditionLevels.find(e => e.id === defaultConfig) ?? defaultEdition;
  21. }
  22. return defaultEdition?.id;
  23. }
  24. get availableViewModes() {
  25. return AppConfig.evtSettings.edition.availableViewModes?.filter((e => !e.disabled)) ?? [];
  26. }
  27. get defaultViewMode(): ViewMode {
  28. const defaultConfig = AppConfig.evtSettings.edition.defaultViewMode;
  29. let defaultViewMode = this.availableViewModes[0];
  30. if (defaultConfig) {
  31. defaultViewMode = this.availableViewModes.find(e => e.id === defaultConfig) ?? defaultViewMode;
  32. }
  33. return defaultViewMode;
  34. }
  35. public updateViewMode$: BehaviorSubject<ViewMode> = new BehaviorSubject(undefined);
  36. public updateDocument$: BehaviorSubject<string> = new BehaviorSubject('');
  37. public updatePage$: Subject<Page> = new Subject();
  38. public updateEditionLevels$: Subject<EditionLevelType[]> = new Subject();
  39. public updateWitnesses$: BehaviorSubject<string[]> = new BehaviorSubject([]);
  40. public updateVersions$: BehaviorSubject<string[]> = new BehaviorSubject([]);
  41. public currentViewMode$ = this.updateViewMode$.asObservable();
  42. public currentDocument$ = merge(
  43. this.route.queryParams.pipe(map((params: URLParams) => params.d)),
  44. this.updateDocument$,
  45. );
  46. public currentPage$ = combineLatest([
  47. merge(
  48. this.route.queryParams.pipe(map((params: URLParams) => params.p)),
  49. this.updatePage$.pipe(map(p => p.id)),
  50. ),
  51. this.evtModelService.pages$.pipe(
  52. filter((pages) => !!pages && pages.length > 0),
  53. ),
  54. ]).pipe(
  55. map(([id, pages]) => !id ? pages[0] : pages.find((p) => p.id === id) || pages[0]),
  56. );
  57. public currentEditionLevels$ = merge(
  58. this.route.queryParams.pipe(
  59. map((params: URLParams) => (params.el?.split(',') ?? [])),
  60. map((editionLevels) => editionLevels?.length > 0 ? editionLevels : [this.defaultEditionLevelId]),
  61. map((editionLevels: EditionLevelType[]) => editionLevels.filter(el => !!el)),
  62. ),
  63. this.updateEditionLevels$,
  64. );
  65. public currentWitnesses$ = merge(
  66. this.route.queryParams.pipe(map((params: URLParams) => params.ws?.split(',') ?? [])),
  67. this.updateWitnesses$,
  68. );
  69. public currentVersions$ = merge(
  70. this.route.queryParams.pipe(map((params: URLParams) => params.vs?.split(',') ?? [])),
  71. this.updateVersions$,
  72. );
  73. public currentStatus$: Observable<AppStatus> = combineLatest([
  74. this.updateViewMode$,
  75. this.currentDocument$,
  76. this.currentPage$,
  77. this.currentEditionLevels$,
  78. this.currentWitnesses$,
  79. this.currentVersions$,
  80. ]).pipe(
  81. distinctUntilChanged((x, y) => JSON.stringify(x) === JSON.stringify(y)),
  82. shareReplay(1),
  83. map(([
  84. viewMode,
  85. document,
  86. page,
  87. editionLevels,
  88. witnesses,
  89. versions,
  90. ]) => {
  91. if (viewMode.id === 'textText') {
  92. if (editionLevels.length === 1) {
  93. editionLevels.push(this.availableEditionLevels.filter(e => e.id !== editionLevels[0])[0].id);
  94. }
  95. } else if (viewMode.id === 'collation') {
  96. editionLevels = [];
  97. } else if (editionLevels.length > 1) {
  98. editionLevels = editionLevels.slice(0, 1);
  99. }
  100. return {
  101. viewMode,
  102. document,
  103. page,
  104. editionLevels,
  105. witnesses,
  106. versions,
  107. };
  108. }),
  109. );
  110. public currentUrl$: Observable<{ view: string; params: URLParams }> = this.currentStatus$.pipe(
  111. map(currentStatus => this.getUrlFromStatus(currentStatus)),
  112. );
  113. public currentNamedEntityId$: BehaviorSubject<string> = new BehaviorSubject(undefined);
  114. public currentLemmatizedEntityId$: BehaviorSubject<string> = new BehaviorSubject(undefined);
  115. constructor(
  116. private evtModelService: EVTModelService,
  117. private router: Router,
  118. private route: ActivatedRoute,
  119. ) {
  120. this.currentStatus$.subscribe(currentStatus => {
  121. const { view, params } = this.getUrlFromStatus(currentStatus);
  122. if (Object.keys(params).length > 0) {
  123. this.router.navigate([`/${view}`], { queryParams: params });
  124. } else {
  125. this.router.navigate([`/${view}`]);
  126. }
  127. });
  128. this.router.events.pipe(
  129. filter(event => event instanceof NavigationStart),
  130. first(),
  131. ).subscribe((event: NavigationStart) => {
  132. const currentViewMode = this.updateViewMode$.getValue();
  133. if (!currentViewMode) {
  134. const pathMatch = event.url.match(/(?<!\?.+)(?<=\/)[\w-]+(?=[/\r\n?]|$)/gm);
  135. if (pathMatch) {
  136. this.updateViewMode$.next(this.availableViewModes.find(vm => vm.id === pathMatch[0]));
  137. } else {
  138. this.updateViewMode$.next(this.defaultViewMode);
  139. }
  140. }
  141. });
  142. this.currentNamedEntityId$.pipe(
  143. filter(id => !!id),
  144. switchMap(id => timer(5000).pipe(map(() => id))),
  145. ).subscribe(() => this.currentNamedEntityId$.next(undefined));
  146. this.currentLemmatizedEntityId$.pipe(
  147. filter(id => !!id),
  148. switchMap(id => timer(5000).pipe(map(() => id))),
  149. ).subscribe(() => this.currentLemmatizedEntityId$.next(undefined));
  150. }
  151. // add by FS
  152. getUrlFromStatus(status: AppStatus) {
  153. const params = {
  154. d: status.document || '',
  155. p: status.page?.id ?? '',
  156. el: status.editionLevels.join(','),
  157. ws: status.witnesses.join(','),
  158. vs: status.versions.join(','),
  159. };
  160. Object.keys(params).forEach((key) => (params[key] === '') && delete params[key]);
  161. return {
  162. view: status.viewMode.id,
  163. params,
  164. };
  165. }
  166. }
  167. export interface AppStatus {
  168. viewMode: ViewMode;
  169. document: string;
  170. page: Page;
  171. editionLevels: EditionLevelType[];
  172. witnesses: string[];
  173. versions: string[];
  174. }