diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts index 6feb92b..d24b050 100644 --- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts +++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts @@ -1,14 +1,14 @@ import { Routes } from '@angular/router'; import {ManuscriptViewComponentComponent} from "../manuscript-view-component/manuscript-view-component.component"; import {RhizomeViewComponentComponent} from "../rhizome-view-component/rhizome-view-component.component"; import {PageViewWrapperComponent} from "../page-view-wrapper-component/page-view-wrapper.component"; import { TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, TLN_VIEWER_ROUTE } from '../tln-edition/constants'; import { TlnFulltextComponent } from '../tln-edition/tln-fulltext/tln-fulltext.component'; export const CONTENT_ROUTES: Routes = [ { path: TLN_MANUSCRIPT_ROUTE, component: ManuscriptViewComponentComponent }, { path: TLN_VIEWER_ROUTE, component: PageViewWrapperComponent }, { path: TLN_CROSSREF_ROUTE, component: RhizomeViewComponentComponent }, { path: TLN_SEARCH_ROUTE, component: TlnFulltextComponent}, - { path: '', redirectTo: TLN_VIEWER_ROUTE, pathMatch: 'prefix' } + { path: '', redirectTo: TLN_MANUSCRIPT_ROUTE, pathMatch: 'prefix' } ]; diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.html b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.html index ac7bcd0..7fefad1 100644 --- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.html +++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.html @@ -1,22 +1,22 @@
diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.scss b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.scss index 7b482f1..86c1b22 100644 --- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.scss +++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.scss @@ -1,22 +1,22 @@ // the navigation drawer on the very left containing the items to choose from .mat-drawer-container { width: 100%; } .mat-drawer { overflow: hidden; padding: 10px; margin-right: 10px; - height: 100vh; - min-height: 100vh; + max-height: 100%; + min-height: 90%; } .mat-card { width: 100%; } .mat-drawer-content { width: 100%; height: 100vh; overflow: hidden; } diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts index 308df06..b08cde4 100644 --- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts +++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts @@ -1,90 +1,113 @@ import {AfterViewInit, Component, OnInit} from '@angular/core'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {Subscription} from "rxjs/index"; import {NavigationServiceService} from "../services/navigation-service.service"; import { TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, TLN_VIEWER_ROUTE } from '../tln-edition/constants'; @Component({ selector: 'app-content-view-tab-component', templateUrl: './content-view-tab-component.component.html', styleUrls: ['./content-view-tab-component.component.scss'], providers: [ NavigationServiceService ] }) -export class ContentViewTabComponentComponent implements OnInit, AfterViewInit { +export class ContentViewTabComponentComponent implements OnInit { // navigation tabs for the content view (manuscript view, page view, rhizome view) navTabLinks: any[]; // navbar on th left for navigating navBarOpenState = false; fullscreen = false; navBarOpenMode: string; queryParams: Params = {}; queryParamSubscription: Subscription; constructor(private router: Router, private activatedRoute: ActivatedRoute, private naviService: NavigationServiceService) { // The links/tabs for routing the correct view-component this.navTabLinks = [ { label: 'Manuskriptansicht', link: TLN_MANUSCRIPT_ROUTE, - index: 0 + index: 0, + isActive: false, + context: 'manuscript' }, { label: 'Seitenansicht', link: TLN_VIEWER_ROUTE, - index: 1 + index: 1, + isActive: false, + context: 'page' }, { label: 'Querverweise', link: TLN_CROSSREF_ROUTE, - index: 2 - },{ + index: 2, + isActive: false + }, { label: 'Suche', link: TLN_SEARCH_ROUTE, - index: 3 + index: 3, + isActive: false }, ]; - + this.queryParamSubscription = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { + this.queryParams = queryParams; + if (queryParams.navBarOpenState) { + this.navBarOpenState = JSON.parse(queryParams.navBarOpenState.toLowerCase()); + } + if (queryParams.fullscreen) { + this.fullscreen = JSON.parse(queryParams.fullscreen.toLowerCase()); + } + }); } ngOnInit() { // this.mesurePerformance(); this.navBarOpenMode = 'side'; // side || over || push - // this.setParamsOnInit(); + this.setParamsOnInit(); // If url pasted or page refreshed --> resetting this.queryparams to the query params of the url; // needed for active routing in the nav tabs & for general use in the template - this.queryParamSubscription = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { - console.log('new qParams in contentview', queryParams); - this.queryParams = queryParams; - this.navBarOpenState = JSON.parse(queryParams.navBarOpenState.toLowerCase()); - this.fullscreen = JSON.parse(queryParams.fullscreen.toLowerCase()); - }); - } - ngAfterViewInit() { - this.navBarOpenState = JSON.parse(this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState')); + // Sets the isActive prop of a navTabLink to true and all others to false . + setActiveLink(link: string) { + this.navTabLinks.forEach((navTabLink, index ) => { + if (navTabLink.link === link) { + this.navTabLinks[index].isActive = true; + if (navTabLink.context) { + window.setTimeout(() => this.naviService.updateRoute({navContext : navTabLink.context}), 300); + } + } else { + this.navTabLinks[index].isActive = false; + } + }); } + mesurePerformance() { const perfData = window.performance.timing; const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; console.log('content load performance is: ', pageLoadTime); } setParamsOnInit() { const qParams: Params = {}; // Set the NavBarOpenstate to true if it is not defined explicitely as false in the url query param onInit. if (this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState') !== 'false') { - // console.log('setQParamsOnInit', this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState')) - this.navBarOpenState = true; qParams.navBarOpenState = 'true'; } // viewMode if (!this.activatedRoute.snapshot.queryParamMap.get('viewMode')) { qParams.viewMode = 'Transkription/Faksimile'; } + if (!this.activatedRoute.snapshot.queryParamMap.get('navContext')) { + qParams.navContext = 'manuscript'; + this.setActiveLink('tln-manuscript'); + } else { + if (this.activatedRoute.snapshot.queryParamMap.get('navContext') === 'manuscript') { + this.setActiveLink('tln-manuscript'); + } else {this.setActiveLink('tln-viewer'); } } this.naviService.updateRoute(qParams); } } diff --git a/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.html b/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.html index 19cfcdb..a7a5b7d 100644 --- a/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.html +++ b/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.html @@ -1,13 +1,16 @@
- - +
diff --git a/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.ts b/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.ts index d90f5ed..31a0bf5 100644 --- a/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.ts +++ b/nietzsche-beta-app/src/app/main-menu-component/main-menu-component.component.ts @@ -1,25 +1,28 @@ import { Component, OnInit } from '@angular/core'; import {MatButtonModule} from '@angular/material/button'; import {Subscription} from 'rxjs'; import {ActivatedRoute, Params} from '@angular/router'; @Component({ selector: 'app-main-menu-component', templateUrl: './main-menu-component.component.html', styleUrls: ['./main-menu-component.component.scss'] }) export class MainMenuComponentComponent implements OnInit { fullScreen: string; queryParamSub: Subscription; + queryParams: Params; constructor(private activatedRoute: ActivatedRoute) { } ngOnInit() { this.queryParamSub = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { this.fullScreen = queryParams.fullscreen; + this.queryParams = queryParams; + }); } } diff --git a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.html b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.html index e640631..bc7c678 100644 --- a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.html +++ b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.html @@ -1,35 +1,35 @@ - +
Navigation - - +
+ - - - +
+
+ diff --git a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.scss b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.scss index 1c6d004..8ca6cc3 100644 --- a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.scss +++ b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.scss @@ -1,39 +1,40 @@ -.fixed-nav-header { +.fixed-nav-container { position: sticky; + max-height: 15vh; } .navlist-container { + position: sticky; + max-height: 85vh; overflow-x: hidden; -} - -#navlist { + overflow-y: auto; scroll-behavior: smooth; } -.mat-list-base .mat-list-item .mat-list-item-content, .mat-list-base .mat-list-option .mat-list-item-content { - padding: 0 !important; +.mat-nav-list { + scroll-behavior: smooth; } .mat-nav-list .mat-list-item { width: 100%; min-height: 72px; height: 100%; /* default is 72px */ padding: 0 !important;; margin: 0 !important; } .thumbnail { max-width: 100px; max-height: 100px; } .card-item { width: 100%; min-width: 100%; margin-top: 5px; background-color: rgba(255, 255, 255, 0) !important; } .active-item { background: linear-gradient(to right, rgba(255, 255, 255, 0) , #dadada); } diff --git a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts index 335e5c2..0177b54 100644 --- a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts +++ b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts @@ -1,271 +1,274 @@ -import {Component, ElementRef, EventEmitter, OnInit, ViewChildren} from '@angular/core'; +import {AfterViewInit, Component, ElementRef, EventEmitter, OnInit, ViewChildren} from '@angular/core'; import {NavigationServiceService} from '../services/navigation-service.service'; import {NavigationEntity, NavTreeDef, TlnQueryParams} from '../models/models'; import {Subscription} from 'rxjs/index'; import {ActivatedRoute, Params, Router} from '@angular/router'; import {QueryService} from '../services/query.service'; import {NavTree} from './navtree-directive.directive'; import * as _ from 'lodash'; @Component({ selector: 'app-navigation-list-component', templateUrl: './navigation-list-component.component.html', styleUrls: ['./navigation-list-component.component.scss'] }) /** * NavigationListComponent * Does sinply consume data coming from naviservice && activated route. triggers click event to service. */ -export class NavigationListComponentComponent implements OnInit { +export class NavigationListComponentComponent implements OnInit, AfterViewInit { navigationTreeDefs: NavTreeDef[]; navTrees: NavTree[]; // The actual Navtrees which are displayed oldQueryParams: Params; queryParams: Params; queryParamSubscription: Subscription; navTabIndex: number; constructor( public naviService: NavigationServiceService, private router: Router, private activatedRoute: ActivatedRoute, private queryService: QueryService) { this.navigationTreeDefs = [ { id: 'manuscript', idx: 0, isActive: true, label: 'Manuskripte', itemQParam: 'manuscript', entries: [], apiDef: { type: 0, // rdf baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', dataArray: 'results.bindings', query: 'manuscripts.rq', mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed id: 'manuscript.value', // Short id, iri in most cases iri: 'manuscript.value', // iri type: 'type.value', label: 'title.value', description: 'gsaSignature.value', avatar: 'thumbImage.value' } } }, { id: 'page', idx: 1, isActive: false, label: 'Seiten', itemQParam: 'page', entries: [], apiDef: { type: 0, // rdf baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', dataArray: 'results.bindings', query: 'getPageData.rq', mapping: { id: 'page.value', // Short id, iri in most cases iri: 'page.value', // iri label: 'pageNumber.value', thumb: 'thumb.value', idx: 'pageNumber.value', svg: 'svgFileName.value', } } } ]; // If url pasted or page refreshed --> resetting this.queryparams to the query params of the url; // needed for the template hence service instances can not be accessed in the template this.queryParamSubscription = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { const navTabIndex = this.getActiveNavTabIndex(queryParams.navContext); - if (this.oldQueryParams) { // only if there are any oldParams + if (this.oldQueryParams && queryParams.navContext) { // only if there are any oldParams this.reactOnContextChange(queryParams.navContext, this.oldQueryParams.navContext, navTabIndex ); this.reactOnItemChange('page', queryParams.page, this.oldQueryParams.page); this.reactOnItemChange('manuscript', queryParams.manuscript, this.oldQueryParams.manuscript); } this.oldQueryParams = queryParams; }); } async ngOnInit() { await this.createTreesOnInit(); this.navTabIndex = await this.getActiveNavTabIndex(); await this.populateNavTrees(); // set selected things in url this.navTrees.forEach(tree => { // if there is no selected item for each tree, we have to listen to the selectedItemSet/tree population and set them per default if (!this.activatedRoute.snapshot.queryParamMap.get(tree.qParam)) { tree.selectedItemSet.subscribe(item => { - this.setSelectedItemAndRoute(item.itemId, item.tabId, 'this.ngOnInit()'); + this.setSelectedItemAndRoute(item.itemId, item.tabId); }); } }); // change navTree according to chosen route per default // set NavContext if unset according to selected component: manuscriptView, tln-page view if (this.activatedRoute.snapshot.firstChild.url[0].path === 'tln-viewer' && !this.activatedRoute.snapshot.queryParamMap.get('navContext')) { this.naviService.updateRoute({navContext: 'page'}); } } + ngAfterViewInit() { + const selectedItem = this.activatedRoute.snapshot.queryParamMap.get(this.activatedRoute.snapshot.queryParamMap.get('navContext')); + this.scrollOnToSelectedItem(selectedItem); + } + reactOnItemChange(param: string, itemId: string, oldItemId) { if (itemId && itemId !== '' && oldItemId) { if (itemId !== oldItemId) { const tab = this.navTrees.findIndex(tree => tree.id === param); this.setSelectedItem(itemId, tab); if (tab === this.navTabIndex) { window.setTimeout(() => this.scrollOnToSelectedItem(itemId), 100); } } } } reactOnContextChange(context: string, oldContext: string, activeTab: number) { if (context !== oldContext) { this.navTabIndex = activeTab; + console.log('contextChange: ', oldContext, context, activeTab); // must time out here hence document is not ready to scroll window.setTimeout(() => this.scrollOnToSelectedItem(this.oldQueryParams[context]), 100); } } scrollOnToSelectedItem(itemId: string ) { - const itemToScrollTo = document.getElementById(itemId); - const topPos = itemToScrollTo.offsetTop; - if (topPos) { - if (document.getElementById('navlist')) { - document.getElementById('navlist').scrollTop = topPos; - } - } + const offSetTop = document.getElementById(itemId).offsetTop; + document.getElementById('navlist').scrollTop = offSetTop - 100; } /** * getActiveNavTabIndexOnInit * gets the active navTabIndex either from a passed navConText, from active qParam or or from definition */ getActiveNavTabIndex(con?: string) { let navConText; if (!con || con === '') { navConText = this.activatedRoute.snapshot.queryParamMap.get('navContext'); } else { navConText = con; } let navTabIndex = 0; if (navConText && navConText !== '') { const nIndex = this.navigationTreeDefs.findIndex(tree => tree.id === navConText); navTabIndex = this.navigationTreeDefs[nIndex].idx; } else { navTabIndex = 0; } return navTabIndex; } createTreesOnInit() { this.navTrees = []; this.navigationTreeDefs.forEach( def => this.navTrees.push(new NavTree(def.id, def.idx, def.label, [], def.itemQParam, def.description, def.apiDef))); } async onSelectNavItem(item: NavigationEntity) { // For scrolling to the selected item (manuscript, page) into view - const activeTab = this.getActiveNavTabIndex(); - if (this.navTrees[activeTab].selectedItem !== item.tlnEntity.id) { + if (this.navTrees[this.navTabIndex].selectedItem !== item.tlnEntity.id) { + console.log('item clicked: ', item) // only get new data for subTrees and set new params if the clicked item is not already the selected item - this.emptyChildTrees(activeTab); - this.setSelectedItemAndRoute(item.tlnEntity.id, activeTab, 'RRRRRRRRRRRRRRRRR onSelectNavItem'); - this.removeAllChildTreeQParams(activeTab); - this.populateChildren(activeTab, item.tlnEntity.id); - } - this.changeNavTreeAndRoute(activeTab + 1); - window.setTimeout(() => this.scrollOnToSelectedItem(item.tlnEntity.id), 100); + await this.emptyChildTrees(this.navTabIndex); + await this.removeAllChildTreeQParams(this.navTabIndex); + await this.setSelectedItemAndRoute(item.tlnEntity.id, this.navTabIndex); + await this.populateChildren(this.navTabIndex, item.tlnEntity.id); + // Only if view is tln-viewer, we change to the second page tab + if (this.activatedRoute.snapshot.queryParamMap.get('navContext') !== this.navTrees[this.getActiveNavTabIndex()].qParam) { + this.changeNavTreeViaRoute(this.navTabIndex + 1); + } + } else { + console.log('clicked selectedItem'); + this.changeNavTreeViaRoute(this.navTabIndex + 1); } // if an already selected item is clicked again, it changes the tree/tab } removeAllChildTreeQParams(tabId) { - this.navigationTreeDefs.forEach(tree => { - if (tree.id > tabId) { - const qParam = this.navigationTreeDefs[tabId].itemQParam; - this.naviService.updateRoute({[qParam]: null}); + this.navTrees.forEach((tree, index) => { + if (tree.idx > tabId) { + this.navTrees[index].selectedItem = null; + this.naviService.updateRoute({[tree.qParam]: null}); } }); } emptyChildTrees(parentIdx) { - this.navTrees.forEach(tree => { + this.navTrees.forEach((tree, index) => { if (tree.idx > parentIdx) { - tree.entries = []; + this.navTrees[index].entries = []; } }); } setSelectedItem(navItemId: string, tabId: number) { this.navTrees[tabId].selectedItem = navItemId; } - setSelectedItemAndRoute(navItemId: string, tabId: number, me?: string) { + // Will route, the qParamSubscription reacts and trees are built further + async setSelectedItemAndRoute(navItemId: string, tabId: number) { + console.log('set new selected item: ', navItemId, 'in tab: ', tabId); this.navTrees[tabId].selectedItem = navItemId; const idx = this.navigationTreeDefs.findIndex(tree => tree.idx === tabId); // set new qParam const newParams = {}; const qParam = this.navigationTreeDefs[idx].itemQParam; newParams[qParam] = navItemId; - // null all childrens qParams, e-g. if another manuscript is selected, the selectedPage must be nulled - this.navigationTreeDefs.forEach(def => { - if (def.idx > idx) { - newParams[def.itemQParam] = null; } - }); this.naviService.updateRoute(newParams); } populateChildren(activeTab, itemId?: string) { if (activeTab + 1 < this.navigationTreeDefs.length) { // if an item in a tab with sub tabs is selected, the subtree should be loaded according to that selection and the tab should change this.populateNavTrees(activeTab + 1, itemId ); } } // switches tabs in navtab ov navigation bar - changeNavTreeAndRoute(idx: number) { + changeNavTreeViaRoute(idx: number) { + console.log('changing tab to', idx, this.navTrees) if (idx < this.navTrees.length) { - this.naviService.updateRoute({navContext: this.navigationTreeDefs[idx].id}); } + this.naviService.updateRoute({navContext: this.navTrees[idx].qParam}); } } /** * populateNavTrees creates the first trees if no query params are available in the url: * It ceates the manuscripNavTree and the activePageNavTreeData of the first manuscript per default. * */ async populateNavTrees(tabIdx?: number, itemId?: string) { const tabStartIndex = tabIdx || 0; // where to start refreshing navtrees for ( const treeDef of this.navigationTreeDefs.sort(def => (def.idx ))) { if (treeDef.idx >= tabStartIndex) { // only create trees if needed this.queryService.getQueryfromFilename(treeDef.apiDef.query).subscribe(async query => { let queryToRun: string; // If there is a selectedItem we have to parametrize the query if (treeDef.idx > 0) { // so we have to parametrize the query if (itemId) { queryToRun = this.queryService.parametrizeQueryWithItem(query, itemId); this.populateNavTree(treeDef, queryToRun); } else { // wait for selected item of the previous tab and parametrize then the query this.navTrees[treeDef.idx - 1].selectedItemSet.subscribe(item => { if (item.tabId === treeDef.idx - 1) { queryToRun = this.queryService.parametrizeQueryWithItem(query, item.itemId); this.populateNavTree(treeDef, queryToRun); } }); } } else { this.populateNavTree(treeDef, query); } }); } } } populateNavTree(def: NavTreeDef, query) { const idx = this.navTrees.findIndex(item => item.id === def.id); let parentLabel; if (idx > 0) { parentLabel = this.navTrees[idx - 1].selectedItemLabel; } if (idx !== -1) { this.queryService.getData(def.apiDef.baseUrl, query, 'SELECT').subscribe(data => { this.navTrees[idx].setNavTreeData(_.get(data, def.apiDef.dataArray), this.activatedRoute.snapshot.queryParams, parentLabel); }); } } }