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 86c1b22..c7a66ad 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,23 @@ // 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; + max-height: 100%; min-height: 90%; } .mat-card { width: 100%; } .mat-drawer-content { + min-height: 100vh; width: 100%; - height: 100vh; - overflow: hidden; + height: 100%; } 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 b08cde4..376af19 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,113 +1,113 @@ -import {AfterViewInit, Component, OnInit} from '@angular/core'; +import {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 { // 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, isActive: false, context: 'manuscript' }, { label: 'Seitenansicht', link: TLN_VIEWER_ROUTE, index: 1, isActive: false, context: 'page' }, { label: 'Querverweise', link: TLN_CROSSREF_ROUTE, index: 2, isActive: false }, { label: 'Suche', link: TLN_SEARCH_ROUTE, 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(); // 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 } // 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') { 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/navigation-list-component/navigation-list-component.component.html b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.html index bc7c678..3f5bdc3 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 @@ <div class="fixed-nav-container"> <mat-toolbar>Navigation</mat-toolbar> - <div *ngIf="navTrees"> + <div *ngIf="navTrees && navTabIndex !== -1"> <mat-tab-group [selectedIndex]="navTabIndex" (selectedTabChange)="changeNavTreeViaRoute($event.index)"> <mat-tab *ngFor="let tree of navigationTreeDefs" label={{tree.label}}> </mat-tab> </mat-tab-group> </div> </div> - <div id="navlist" class="navlist-container" *ngIf="navTrees && navTrees[navTabIndex].entries"> - <mat-nav-list *ngIf="navTrees"> + <div id="navlist" class="navlist-container" *ngIf="navTrees && navTabIndex !== -1"> + <mat-nav-list *ngIf="navTrees && navTrees[navTabIndex]"> <mat-list-item *ngFor="let item of navTrees[navTabIndex].entries" (click)="onSelectNavItem(item)" [id] = "item.tlnEntity.id" [class.active-item]="item.tlnEntity.id === navTrees[navTabIndex].selectedItem"> <mat-card class = "card-item"> <mat-card-header> <mat-card-title> <span>{{item.tlnEntity.label}}</span> </mat-card-title> <mat-card-subtitle *ngIf="item.tlnEntity.description">GSA-Signatur {{item.tlnEntity.description}}</mat-card-subtitle> <mat-card-subtitle *ngIf="navTrees[navTabIndex].parentLabel">{{navTrees[navTabIndex].parentLabel}}</mat-card-subtitle> <img mat-card-avatar *ngIf="item.avatar" [src]="item.avatar"/> </mat-card-header> <mat-card-content> <img class="thumbnail" *ngIf="item.thumb" [src]="item.thumb"/> <img class="thumbnail" *ngIf="item.svg" [src]="item.svg"/> </mat-card-content> </mat-card> </mat-list-item> </mat-nav-list> </div> 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 0177b54..a94b739 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,274 +1,272 @@ 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, 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 && 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); }); } }); // 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() { + ngAfterViewInit() { // TODO: Remove and scroll only after set intenally 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 offSetTop = document.getElementById(itemId).offsetTop; - document.getElementById('navlist').scrollTop = offSetTop - 100; + if (document.getElementById(itemId)) { + 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 + // If a new item is clicked 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 + // get new data for subTrees and set new params accordingly 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) { + // Only if context !== 'page', e.g. view is tln-viewer), we change to the second page tab + const navContext = this.activatedRoute.snapshot.queryParamMap.get('navContext'); + if (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 + } else { // if an already selected item is clicked again, it changes the tree/tab + this.changeNavTreeViaRoute(this.navTabIndex + 1); } } removeAllChildTreeQParams(tabId) { 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, index) => { if (tree.idx > parentIdx) { this.navTrees[index].entries = []; } }); } setSelectedItem(navItemId: string, tabId: number) { this.navTrees[tabId].selectedItem = navItemId; } // 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; 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 changeNavTreeViaRoute(idx: number) { - console.log('changing tab to', idx, this.navTrees) if (idx < this.navTrees.length) { 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); }); } } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.css b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.css index ebe194c..a625edb 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.css +++ b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.css @@ -1,53 +1,55 @@ #page { - width: 100%; + width: 98%; position: relative; top: 0px; left: 0px; + height: 100%; + overflow: visible; } .icon-button { width: 15px; margin-left: 3px; } .page-navi { float: left; margin-top: -3px; margin-bottom: 1px; height: 38px; background-color: lightblue; z-index: 2; } .default-mouse { cursor: default; } .small-grey { color: lightgrey; font-size: 80%; } .text { position: absolute; top: 10px; left: 500px; } .search { position: relative; top: 60px; width: 500px; height: 100%; text-align: center; margin-right: 20px; } .extra-space { margin-top: 45px; } .title { text-align: left; margin-left: 20px; } .form { width: 95%; } .full-width { min-width: 150px; max-width: 500px; width: 80%; }