diff --git a/nietzsche-beta-app/src/app/models/models.ts b/nietzsche-beta-app/src/app/models/models.ts index 493f417..3785c78 100644 --- a/nietzsche-beta-app/src/app/models/models.ts +++ b/nietzsche-beta-app/src/app/models/models.ts @@ -1,126 +1,127 @@ // class for Everything: extended by NavigationEntity, Manuscript, Page, Word with all common properties import {SafeUrl} from '@angular/platform-browser'; export class TlnEntity { id: string; // Short id, iri in most cases iri: string; // iri type: string; // rdfs:type navIndex: number; label?: string; constructor(id: string, iri: string, type: string, navIndex: number, label?: string) { this.id = id; this.iri = iri; this.type = type; this.navIndex = navIndex; this.label = label; } } export class TlnQueryParams { navBarOpenState: boolean; navTabIndex: number; manuscript: string; page: string; selectedLines: string; selectedWords: string; viewMode: string; // ' fullscreen: boolean; zoom: number; constructor(navBarOpenState: boolean, navTabIndex: number, manuscript: string, page: string, selectedLines: string, selectedWords: string, viewMode: string, fullscreen: boolean, zoom: number ) { - this.navBarOpenState = navBarOpenState; - this.navTabIndex = navTabIndex; + this.navBarOpenState = navBarOpenState; //proposed solution: JSON.parse(navBarOpenState) + this.navTabIndex = navTabIndex; // proposed solution: Number(navTabIndex) this.manuscript = manuscript; this.page = page; this.selectedLines = selectedLines; this.selectedWords = selectedWords; this.viewMode = viewMode; - this.fullscreen = fullscreen; - this.zoom = zoom; + this.fullscreen = fullscreen; // proposed solution: JSON.parse(fullscreen) + this.zoom = zoom; // proposed solution: Number(zoom) + console.log('TlnQueryParams.fullscreen typeof:', typeof this.fullscreen, 'TlnQueryParams.zoom typeof:', typeof this.zoom); } setParam(prop: string, val: string) { this[prop] = val; } } // The navigation entries in each tree for each viewtab (TlnManuscript, TlnPage, PositionalEntity) used by navigation // TODO: add several idxes? Or choosing another order will reload all, hence there is only one idx // export class NavigationEntity { idx: number; tlnEntity: TlnEntity; thumb?: SafeUrl; // url of image (Thumbnail) img?: SafeUrl; // full image url svg?: SafeUrl; // svg url constructor(idx: number, tlnEntity: TlnEntity, thumb?: string, img?, svg?: SafeUrl ) { this.idx = idx; this.tlnEntity = tlnEntity; this.thumb = thumb; this.img = img; this.svg = svg; } } export interface NavTreeDef { id: number; label: string; qParam: string; entries: NavigationEntity[]; description?: string; apiDef?: ApiDef; isActive?: boolean; } export class Annotation { id: string; text: string; styles: Array; } // Only relevant if we create an svg ourselves? export interface PositionalEntity { // used for word rectangles as well as for line numbering id: string; text: string; left: number; top: number; width: number; height: number; row?: number; iri?: string; // TODO, change this. will be the id later when change data source to rdf ... } export class ApiDef { type: number; // 0 === sparql 1.1., 1 === nietzscheSource API, 2 === existDB baseUrl: string; dataArray: string; query?: string; mapping?: TlnEntityMapping; // positive Filter ids: only these id's should be loaded into manuscript nav tree constructor( type: number, baseUrl: string, dataArray: string, query?: string, mapping?: TlnEntityMapping) { this.type = type; this.baseUrl = baseUrl; this.dataArray = dataArray; this.query = query; this.mapping = mapping; } } export class TlnEntityMapping { // Is used for mapping the response from any given apiDef/response to a TlnEntity Instance id: string; // Short id, iri in most cases iri?: string; // iri idx?: string; type?: string; // rdfs:type label?: string; img?: string; svg?: string; thumb?: string; constructor(id: string, iri?: string, idx?: string, type?: string, label?: string, img?: string, svg?: string, thumb?: string) { this.id = id; this.iri = iri; this.idx = idx; this.type = type; this.label = label; this.img = img; this.svg = svg, this.thumb = thumb; } } diff --git a/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.html b/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.html index 5a1182e..09ca040 100644 --- a/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.html +++ b/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.html @@ -1,5 +1,9 @@ - -
- +
+ +
+ +
+ +
diff --git a/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.ts b/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.ts index 7a6e0c7..0f89d3a 100644 --- a/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.ts +++ b/nietzsche-beta-app/src/app/page-view-wrapper-component/page-view-wrapper.component.ts @@ -1,14 +1,32 @@ import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute, Params, Router} from '@angular/router'; +import { TlnQueryParams} from '../models/models'; @Component({ selector: 'app-page-view-wrapper-component', templateUrl: './page-view-wrapper.component.html', styleUrls: ['./page-view-wrapper.component.scss'] }) export class PageViewWrapperComponent implements OnInit { + queryParams: TlnQueryParams; + constructor(private router: Router, + private activatedRoute: ActivatedRoute) { } - constructor() { } + ngOnInit() { + this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { + this.queryParams = new TlnQueryParams( + queryParams.navBarOpenState, + queryParams.navTabIndex, + queryParams.manuscript, + queryParams.page, + queryParams.selectedLines, + queryParams.selectedWords, + queryParams.viewMode, + queryParams.fullscreen, + queryParams.zoom + ); + }); - ngOnInit() { } + } } diff --git a/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.css b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.css new file mode 100644 index 0000000..e69de29 diff --git a/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.html b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.html new file mode 100644 index 0000000..8c33085 --- /dev/null +++ b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.html @@ -0,0 +1,10 @@ +
+

Copyright Information:

+
+
URL: {{copyright.originalUrl}}
+
Lizenz: + {{copyright.license}} + {{copyright.license}} +
+
+ diff --git a/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.spec.ts b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.spec.ts new file mode 100644 index 0000000..8b36141 --- /dev/null +++ b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CopyrightSheetComponent } from './copyright-sheet.component'; + +describe('CopyrightSheetComponent', () => { + let component: CopyrightSheetComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CopyrightSheetComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CopyrightSheetComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.ts b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.ts new file mode 100644 index 0000000..13bae55 --- /dev/null +++ b/nietzsche-beta-app/src/app/page-view/copyright/copyright-sheet/copyright-sheet.component.ts @@ -0,0 +1,17 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { MAT_BOTTOM_SHEET_DATA} from '@angular/material/bottom-sheet'; +import { Copyright } from '../../models'; + +@Component({ + selector: 'copyright-sheet', + templateUrl: './copyright-sheet.component.html', + styleUrls: ['./copyright-sheet.component.css'] +}) +export class CopyrightSheetComponent implements OnInit { + + constructor(@Inject(MAT_BOTTOM_SHEET_DATA) private copyright: Copyright) { } + + ngOnInit() { + } + +} diff --git a/nietzsche-beta-app/src/app/page-view/copyright/copyright.component.ts b/nietzsche-beta-app/src/app/page-view/copyright/copyright.component.ts index e6e4775..8fdc541 100644 --- a/nietzsche-beta-app/src/app/page-view/copyright/copyright.component.ts +++ b/nietzsche-beta-app/src/app/page-view/copyright/copyright.component.ts @@ -1,27 +1,33 @@ import { Component, OnInit, Input, ElementRef } from '@angular/core'; +import {MatBottomSheet, MatBottomSheetRef} from '@angular/material/bottom-sheet'; import { PageViewService } from '../page-view.service'; +import { CopyrightSheetComponent } from './copyright-sheet/copyright-sheet.component'; import { Copyright, Point } from '../models'; @Component({ selector: 'copyright', templateUrl: './copyright.component.html', styleUrls: ['./copyright.component.css'] }) export class CopyrightComponent implements OnInit { @Input() dimension: number; highlight: boolean = false; @Input() copyright: Copyright; - constructor(private pageViewService: PageViewService) { } + constructor(private bottomSheet: MatBottomSheet, private pageViewService: PageViewService) { } ngOnInit() { } private setHighlight(highlight: boolean){ this.highlight = highlight; } private showCopyrightInformation(e: MouseEvent){ - let point: Point = { visible: true, clientX: e.clientX, clientY: e.clientY, layerX: e.layerX, layerY: e.layerY } - this.pageViewService.copyrightService(this.copyright, point); + /*let point: Point = { visible: true, clientX: e.clientX, clientY: e.clientY, layerX: e.layerX, layerY: e.layerY } + this.pageViewService.copyrightService(this.copyright, point);*/ + this.bottomSheet.open(CopyrightSheetComponent, { + data: this.copyright + }); + } } diff --git a/nietzsche-beta-app/src/app/page-view/interacted.directive.ts b/nietzsche-beta-app/src/app/page-view/interacted.directive.ts index ce242bb..21fdd2c 100644 --- a/nietzsche-beta-app/src/app/page-view/interacted.directive.ts +++ b/nietzsche-beta-app/src/app/page-view/interacted.directive.ts @@ -1,145 +1,155 @@ import { Directive, HostListener, Input, ElementRef, OnInit} from '@angular/core'; import { PageViewService } from './page-view.service'; import { Interactable, Word, Line } from './models'; + +export interface XYOffset { + x: number; + y: number; +} /** * This directive informs the {@link /injectables/PageViewService.html|PageViewService} about * mouse events on interactable objects and scrolls interactable objects in view if they are * invisible. **/ @Directive({ selector: '[interactedObject]' }) export class InteractedDirective implements OnInit { /** * the object of this rect **/ @Input('interactedObject') interactedObject: Interactable; /** * the identification string of this Interactable's textfield (e.g. 'first textfield' or 'second textfield') **/ @Input() identity: string = 'first textfield'; /** * the scrollable HTML-container of this Interactable's textfield. **/ @Input() container: HTMLElement; /** * The time (in milliseconds) the timer should wait before * the element is scrolled in view. **/ delay: number = 500; /** * The ID of the timeout set by {@link /directives/InteractedDirective.html#timeoutScroll|timeoutScroll}. **/ timeoutID: number = -1; /** * Whether or not the element should scroll into view when the timer expires. **/ doScroll: boolean = false; + xyOffset: XYOffset = { x: 0, y: 0 }; constructor(private pageViewService: PageViewService, private el: ElementRef) {} /** * Subscribe to on/offHovered and onClicked methods of the {@link /injectables/PageViewService.html|PageViewService} * and scroll hovered object in view if it is invisible. **/ ngOnInit(){ + if (this.container != null && this.container != undefined){ + let containerRect: DOMRect = this.container.getBoundingClientRect(); + this.xyOffset = { x: containerRect.left, y: containerRect.top }; + } this.interactedObject.textfield_identity = this.identity; this.pageViewService.onClickedWord.subscribe( (clickedWord: Word) => { this.scrollIntoViewIfNeeded(clickedWord, 'Word', 0) }); this.pageViewService.onHoveredWord.subscribe( (hoveredWord: Word) => { this.scrollIntoViewIfNeeded(hoveredWord, 'Word') }); this.pageViewService.offHoveredWord.subscribe( (hoveredWord: Word) => { this.clearTimeout() }); this.pageViewService.offHoveredLine.subscribe( (hoveredLine: Line) => { this.clearTimeout() }); this.pageViewService.onHoveredLine.subscribe( (hoveredLine: Line) => { this.scrollIntoViewIfNeeded(hoveredLine, 'Line') }); this.pageViewService.onClickedLine.subscribe( (clickedLine: Line) => { this.scrollIntoViewIfNeeded(clickedLine, 'Line', 0) }); } /** * Clear timeout and prevent element from scrolling into view. **/ private clearTimeout(){ if(this.timeoutID != -1){ this.doScroll = false; clearTimeout(this.timeoutID); this.timeoutID = -1; } } /** * Scroll interactable object in view if it is invisible. * @param hoveredItem interactable object that is hovered * @param hoveredType string representation of object's type (i.e. 'Word' | 'Line') **/ private scrollIntoViewIfNeeded(hoveredItem: Interactable, hoveredType: String, delay: number= this.delay){ if (hoveredType == 'Word' && this.interactedObject.datatype == 'Word' && this.identity != hoveredItem.textfield_identity){ let hoveredWord = hoveredItem let currentWord = this.interactedObject if (currentWord.id == hoveredWord.id && currentWord.is_top_object && this.isElementInvisible()){ this.timeoutScroll(delay); } } else if (hoveredType =='Line' && this.interactedObject.datatype == 'Line'){ let hoveredLine = hoveredItem let currentLine = this.interactedObject if (currentLine !== hoveredLine && currentLine.id == hoveredLine.id && this.isElementInvisible()){ this.timeoutScroll(delay) } } } /** * Scroll element in view if timeout has not been canceled during its countdown. **/ private timeoutScroll(delay: number) { let behavior = (delay == 0) ? "instant" : "smooth"; this.doScroll = true; this.timeoutID = window.setTimeout(()=>{ if (this.doScroll){ this.el.nativeElement.scrollIntoView({ 'behavior': behavior}); } }, delay); } /** * Return whether interactable object is invisible, i.e. whether it is outside of * its scrollable container's viewport. **/ private isElementInvisible(): boolean { if (this.container == null || this.container == undefined || this.container.getAttribute('class') == 'inline'){ return false; } let myRect: DOMRect = this.el.nativeElement.getBoundingClientRect(); let containerRect: DOMRect = this.container.getBoundingClientRect(); return myRect.top < containerRect.top || myRect.bottom > containerRect.bottom || myRect.left < containerRect.left || myRect.right > containerRect.right; } /** * informs the {@link /injectables/PageViewService.html|PageViewService} about * click events on {@link #interactedObject|interactedObject}. **/ @HostListener('click', ['$event']) onMouseClick( e: MouseEvent) { this.pageViewService.onClickService(this.interactedObject, { visible: true, layerX: e.layerX, layerY: e.layerY, clientX: e.clientX, clientY: e.clientY }); } /** * informs the {@link /injectables/PageViewService.html|PageViewService} about * mouse enter events on {@link #interactedObject|interactedObject}. **/ @HostListener('mouseenter', ['$event']) onMouseEnter( e: MouseEvent) { this.pageViewService.onHoverService(this.interactedObject, { visible: true, layerX: e.layerX, layerY: e.layerY, clientX: e.clientX, clientY: e.clientY }); } /** * informs the {@link /injectables/PageViewService.html|PageViewService} about * mouse leave events on {@link #interactedObject|interactedObject}. **/ @HostListener('mouseleave') onMouseLeave() { this.pageViewService.offHoverService(this.interactedObject); } } diff --git a/nietzsche-beta-app/src/app/page-view/page-view.component.ts b/nietzsche-beta-app/src/app/page-view/page-view.component.ts index 6c82b72..43952f9 100644 --- a/nietzsche-beta-app/src/app/page-view/page-view.component.ts +++ b/nietzsche-beta-app/src/app/page-view/page-view.component.ts @@ -1,170 +1,173 @@ import { Component, Input, OnInit, OnChanges} from '@angular/core'; import { externalAssignClass, externalAssignStyle, Configuration, Identifier, Image, Line, TextField, TextByForeignHand, Word} from './models'; /** * This component displays one or two {@link /components/TextFieldComponent.html|TextFieldComponent(s)} * and its or their {@link /components/MarginFieldComponent.html|MarginFieldComponent(s)}. **/ @Component({ selector: 'page-view', templateUrl: './page-view.component.html', styleUrls: ['./page-view.component.css'] }) export class PageViewComponent implements OnInit, OnChanges { @Input() configuration: Configuration; /** * the search text of words that should be highlighted as {@link /miscellaneous/enumerations.html#HIGHTLIGHT_CASES|HIGHTLIGHT_CASES.SEARCHED_WORD}. **/ @Input() findText: string; /** * first texts written by foreign hand **/ @Input() first_foreign_texts: TextByForeignHand[] = []; /** * the first image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ @Input() first_image: Image; /** * the Array of lines of the first image that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ @Input() first_lines: Line[]; /** * Identification of first textfield. **/ first_textfield_id: string = 'first textfield' /** * the Array of words of the first image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ @Input() first_words: Word[]; /** * the (initial) maximum height of the image(s). **/ @Input() max_height: number = -1; /** * the (initial) maximum width of the image(s). **/ @Input() max_width: number = -1; /** * should primary Url be used for image. Use secondary Url if false. **/ @Input() preferPrimaryUrl: boolean = true; /** * second texts written by foreign hand **/ @Input() second_foreign_texts: TextByForeignHand[] = []; /** * the second image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ @Input() second_image: Image; /** * the Array of lines of the second image that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ @Input() second_lines: Line[]; /** * Identification of second textfield. **/ second_textfield_id: string = 'second textfield' /** * the Array of words of the second image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ @Input() second_words: Word[]; /** * An optional function that will be passed to {@link /components/TextFieldComponent.html|TextFieldComponent} * in order to return a further highlight class * to the word rects when the internal function would return 'textfield unhighlighted'. **/ @Input('assignClass') assignClass?: externalAssignClass; /** * An optional function that will be passed to {@link /components/TextFieldComponent.html|TextFieldComponent} * and {@link /components/MarginFieldComponent.html|MarginFieldComponent} * in order to return a (svg-)style object * to the word and line rects. This function allows the user to extend the style of this component. * E.g. by returning { fill: blue } the function overwrites the default behaviour and sets * the default highlight color to blue. **/ @Input('assignStyle') assignStyle?: externalAssignStyle; /** * global zoom factor. **/ @Input() zoomFactor: number = 1; /** * identifiers of selected words that should be highlighted. **/ @Input() selectedWords: Identifier[] = []; /** * identifiers of selected lines that should be highlighted. **/ @Input() selectedLines: Identifier[] = []; @Input('startLine') startLineId: Identifier; @Input('endLine') endLineId: Identifier; @Input() dontShowReference: boolean; showReferenceLeft: string = 'from'; showReferenceRight: string = 'to'; constructor() {} /** * sets {@link /components/PageViewComponent.html#max_height|max_height} if it is unset. **/ ngOnInit() { if (this.max_height == -1 && this.max_width == -1){ this.max_height = screen.availHeight; } + this.checkImages(); + } + ngOnChanges(){ if (this.dontShowReference != undefined && this.dontShowReference != null && this.dontShowReference){ this.showReferenceLeft = ''; this.showReferenceRight = ''; + } else { + this.showReferenceLeft = 'from'; + this.showReferenceRight = 'to'; } this.checkImages(); - } - ngOnChanges(){ - this.checkImages(); if (this.first_image != null && this.first_image != undefined && this.first_image.transform != null){ this.updateLines(this.first_words, this.first_lines) } if (this.second_image != null && this.second_image != undefined && this.second_image.transform != null){ this.updateLines(this.second_words, this.second_lines) } } private checkImages(){ if (this.first_image != null && this.first_image != undefined && this.startLineId != null && this.startLineId != undefined){ if(this.first_lines != null && this.first_lines != undefined && this.first_lines.length > 0){ this.first_image = this.updateTextField(this.first_image, this.first_lines); } if(this.second_lines != null && this.second_lines != undefined && this.second_lines.length > 0){ this.second_image = this.updateTextField(this.second_image, this.second_lines); } } } private updateLines(words: Word[], lines: Line[]) { for (var i = 0; i < lines.length; i++){ if (words.filter(word =>word.line == lines[i].id).length > 0){ lines[i].top = words.filter(word =>word.line == lines[i].id).map(word =>Number(word.top)).sort(function(a,b){ return a-b; })[0] lines[i].bottom = words.filter(word =>word.line == lines[i].id).map(word =>Number(word.top)+Number(word.height)).sort(function(a,b){ return b-a; })[0] } } } private updateTextField(image: Image, lines: Line[]): Image { let endLineId = (this.endLineId != null && this.endLineId != undefined) ? this.endLineId : this.startLineId; let startLines = lines.filter(line =>line.id == this.startLineId) let endLines = lines.filter(line =>line.id == endLineId) if (startLines.length > 0 && endLines.length > 0){ let top = (startLines[0].top > 10) ? startLines[0].top-10 : startLines[0].top; let height = (endLines[0].bottom-top)+10; let text_field: TextField = { top: top, left: image.text_field.left, width: image.text_field.width, height: height } return { x: image.x, y: image.y, width: image.width, height: image.height, filename: image.filename, URL: image.URL, secondaryURL: image.secondaryURL, text_field: text_field, transform: image.transform, copyright: image.copyright } } return image; } /** * Returns whether the two images can be displayed as columns. **/ private hasColumnStyle(): boolean { if (this.zoomFactor <= 1 || this.first_image == null || this.second_image == null){ return true } let newLeftWidth = this.max_height/this.first_image.text_field.height*this.zoomFactor*this.first_image.text_field.width; let newRightWidth = this.max_height/this.second_image.text_field.height*this.zoomFactor*this.second_image.text_field.width; return newLeftWidth + newRightWidth < screen.availWidth; } } diff --git a/nietzsche-beta-app/src/app/page-view/page-view.module.ts b/nietzsche-beta-app/src/app/page-view/page-view.module.ts index 5cc1d32..bfa1335 100644 --- a/nietzsche-beta-app/src/app/page-view/page-view.module.ts +++ b/nietzsche-beta-app/src/app/page-view/page-view.module.ts @@ -1,34 +1,37 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MarginFieldComponent } from './margin-field/margin-field.component'; import { TextFieldComponent} from './textfield-component/textfield.component'; import { InteractedDirective } from './interacted.directive'; import { PageViewComponent } from './page-view.component'; import { PageViewService } from './page-view.service'; import { CopyrightComponent } from './copyright/copyright.component'; import { LineReferenceComponent } from './margin-field/line-reference/line-reference.component'; +import { CopyrightSheetComponent } from './copyright/copyright-sheet/copyright-sheet.component'; @NgModule({ declarations: [ InteractedDirective, MarginFieldComponent, TextFieldComponent, PageViewComponent, CopyrightComponent, - LineReferenceComponent + LineReferenceComponent, + CopyrightSheetComponent ], imports: [ CommonModule ], providers: [ PageViewService ], exports: [ MarginFieldComponent, TextFieldComponent, PageViewComponent, CopyrightComponent - ] + ], + entryComponents: [CopyrightSheetComponent] }) export class PageViewModule { } diff --git a/nietzsche-beta-app/src/app/tln-edition/constants.ts b/nietzsche-beta-app/src/app/tln-edition/constants.ts index 7d2cf5e..e3a63d4 100644 --- a/nietzsche-beta-app/src/app/tln-edition/constants.ts +++ b/nietzsche-beta-app/src/app/tln-edition/constants.ts @@ -1,50 +1,54 @@ export {HIGHTLIGHT_CASES} from '../page-view/highlight_status'; export enum VIEW_OPTIONS { TRANSKRIPTION = 'Transkription', FAKSIMILE = 'Faksimile', SYNOPSIS = 'Transkription/Faksimile', SYNOPSIS_B = 'Faksimile/Transkription' } export const DEFAULT_VIEW_OPTION: string = VIEW_OPTIONS.SYNOPSIS_B; export const ONTOLOTY_PREFIX: string = 'http://www.nie.org/ontology/nietzsche#' /** * Route for TlnCrossrefComponent **/ export const TLN_CROSSREF_ROUTE: string = 'tln-crossref'; /** * Route for TlnViewerComponent **/ export const TLN_VIEWER_ROUTE: string = 'tln-viewer'; +/** + * Param that toggles fullscreen, value type: boolean. + **/ +export const TLN_FULLSCREEN_PARAM: string = 'fullscreen'; /** * Param for find text in page. **/ export const TLN_FIND_PARAM: string = 'find'; /** * Param for page iri. **/ export const TLN_PAGE_PARAM: string = 'page'; /** * Param for manuscript iri. **/ export const TLN_MANUSCRIPT_PARAM: string = 'manuscript'; /** * Param for selected lines. **/ export const TLN_SELECTED_LINES_PARAM: string = 'selectedLines'; /** * Param for selected lines. **/ export const TLN_SELECTED_WORDS_PARAM: string = 'selectedWords'; /** * Param for iri of a genetic order of text versions. **/ export const TLN_TEXT_GENETIC_ORDER_PARAM: string = 'geneticOrder'; /** * Param for selected view option, e.g. 'Transkription', 'Faksimile', etc. **/ export const TLN_VIEW_OPTION_PARAM: string = 'viewMode'; /** * Param for zoom. **/ export const TLN_ZOOM_PARAM: string = 'zoom'; diff --git a/nietzsche-beta-app/src/app/tln-edition/route-reader.ts b/nietzsche-beta-app/src/app/tln-edition/route-reader.ts index 23dfc90..c3b394f 100644 --- a/nietzsche-beta-app/src/app/tln-edition/route-reader.ts +++ b/nietzsche-beta-app/src/app/tln-edition/route-reader.ts @@ -1,42 +1,47 @@ import { OnInit } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; export interface ParamContent { param: string; - isNumber: boolean; + type: string; debug?: string; + ignore?: boolean; } export interface Mapping { [name: string]: ParamContent; } export class RouteReader implements OnInit { protected mapping: Mapping; protected routerParams: Params; constructor(protected router: Router, protected activatedRoute: ActivatedRoute ) { } ngOnInit() { this.activatedRoute.queryParams.subscribe(params => { this.readParams(params) }); } protected readParams(params: Params) { this.routerParams = params; for(let key of Object.keys(this.mapping)){ - let paramsKey = this.mapping[key]['param']; - if (this.routerParams[paramsKey] != null){ - if (this.mapping[key]['isNumber']){ - this[key] = Number(this.routerParams[paramsKey]) - } else if (Array.isArray(this[key]) && !Array.isArray(this.routerParams[paramsKey])) { - this[key] = JSON.parse(this.routerParams[paramsKey]) - } else { - this[key] = this.routerParams[paramsKey]; - } - if (this.mapping[key]['debug'] != null){ - console.log(this.mapping[key]['debug'], this[key]); - } + if (this.mapping[key]['ignore'] == undefined || !this.mapping[key]['ignore']){ + let paramsKey = this.mapping[key]['param']; + if (this.routerParams[paramsKey] != null){ + if (this.mapping[key]['type'] == 'number'){ + this[key] = Number(this.routerParams[paramsKey]) + } else if (this.mapping[key]['type'] == 'boolean'){ + this[key] = (this.routerParams[paramsKey] == 'true') + } else if (Array.isArray(this[key]) && !Array.isArray(this.routerParams[paramsKey])) { + this[key] = JSON.parse(this.routerParams[paramsKey]) + } else { + this[key] = this.routerParams[paramsKey]; + } + if (this.mapping[key]['debug'] != null){ + console.log(this.mapping[key]['debug'], this[key]); + } + } } } } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.html b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.html index ac0ba34..e34704f 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.html +++ b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.html @@ -1,52 +1,53 @@ -
+

Querverweise

south
+
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.ts index ce2ce19..83f8638 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/tln-crossref.component.ts @@ -1,115 +1,115 @@ import { Component, OnInit, Input } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { DomSanitizer } from '@angular/platform-browser'; import { TlnQueryServiceInterface, Reference, TextVersion} from '../models'; import { TlnManuscriptUnity, TlnNavigationPage} from '../datatypes/navigation'; import { TLN_CROSSREF_ROUTE, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_MANUSCRIPT_PARAM, TLN_SELECTED_LINES_PARAM, TLN_TEXT_GENETIC_ORDER_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM, VIEW_OPTIONS, ONTOLOTY_PREFIX } from '../constants'; import { IsReconstructedKonvolut } from '../datatypes/basic_datatype'; import { TlnLine} from '../datatypes/line'; import { TlnStandaloneTextVersion} from '../datatypes/text_version'; import { Mapping } from '../route-reader'; import { RouteUpdater } from '../route-updater'; import { ComplexKeyIriMapping, DataHandler, KeyIriMapping } from '../data_handler'; import { PageViewService, TlnQueryService } from '../services'; import { TlnInformationComponent, ParentInformation } from '../tln-information/tln-information.component'; import { PageInformation } from '../tln-information/page-information'; @Component({ selector: 'tln-crossref', templateUrl: './tln-crossref.component.html', styleUrls: ['./tln-crossref.component.css'] }) export class TlnCrossrefComponent extends RouteUpdater { /** * OPTIONAL pass a queryService with method * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData} * to TlnPageViewComponent. **/ @Input() queryService: TlnQueryServiceInterface; zoomFactor: number = 1; findText: string; dataHandler: DataHandler = new DataHandler(this); textVersions: TextVersion[] = []; current_genetic_order_iri: string; max_width: number = -1; max_height: number = -1; each_version_height: number = -1; selectedLines: string[] = []; selectedTextVersions: TextVersion[] = [] private readonly increment: number = 0.333; private readonly decrement: number = this.increment*-1; private readonly margin_width: number = 280; protected currentRoute: string = TLN_CROSSREF_ROUTE; - protected mapping: Mapping = { findText: { param: TLN_FIND_PARAM, isNumber: false }, - current_genetic_order_iri: { param: TLN_TEXT_GENETIC_ORDER_PARAM, isNumber: false }, - selectedLines: { param: TLN_SELECTED_LINES_PARAM, isNumber: false }, - zoomFactor: { param: TLN_ZOOM_PARAM, isNumber: true } } + protected mapping: Mapping = { findText: { param: TLN_FIND_PARAM, type: "string" }, + current_genetic_order_iri: { param: TLN_TEXT_GENETIC_ORDER_PARAM, type: "string" }, + selectedLines: { param: TLN_SELECTED_LINES_PARAM, type: "string" }, + zoomFactor: { param: TLN_ZOOM_PARAM, type: "number" } } routerParams: Params; selectedViewOption: string = VIEW_OPTIONS.TRANSKRIPTION updating: boolean = false; viewOptions: string[] = [ VIEW_OPTIONS.TRANSKRIPTION, VIEW_OPTIONS.FAKSIMILE ]; constructor(private pageViewService: PageViewService, private localQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) { super(router, activatedRoute); //this.localQueryService.baseUrl = 'http://localhost:3030/nietzsche/query'; } ngOnInit() { this.max_width = screen.availWidth - 400 - this.margin_width; this.max_height = screen.availHeight - 200; let tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService; this.dataHandler.addHandler('textVersions', { 'handler': TlnStandaloneTextVersion}); this.dataHandler.setQueryService(tlnQueryService); this.dataHandler.start_processing.subscribe( (started: boolean) =>{ this.updating = true; }); this.dataHandler.processing_finished.subscribe( (finished: boolean) =>{ this.updating = false; }); super.ngOnInit(); this.pageViewService.onClickedLine.subscribe( (clickedLine: TlnLine) => { let index = this.selectedLines.indexOf(clickedLine.id) if (index > -1){ this.selectedLines.splice(index, 1); } else { this.selectedLines.push(clickedLine.id); } this.updateParams(); }); } private addOrRemove(textVersion: TextVersion) { let index = this.selectedTextVersions.indexOf(textVersion); if (index == -1){ this.selectedTextVersions.push(textVersion); } else { this.selectedTextVersions.splice(index, 1); } this.each_version_height = (this.selectedTextVersions.length > 0) ? this.max_height/this.selectedTextVersions.length : this.max_height; } private clearFindText() { this.findText = ''; this.updateParams(); } private getButtonTitle(textVersion: TextVersion): string { return (this.selectedTextVersions.indexOf(textVersion) == -1) ? 'Textstelle anzeigen' : 'Textstelle ausblenden'; } protected readParams(params: Params){ let old_genetic_order_iri = this.current_genetic_order_iri super.readParams(params); if (this.dataHandler.ready && this.current_genetic_order_iri != null && (this.textVersions.length == 0 || this.current_genetic_order_iri != old_genetic_order_iri)){ this.dataHandler.resetData('textVersions') this.dataHandler.getData('textVersions', this.current_genetic_order_iri); } } private setZoomFactor(newZoomFactor: number){ if (newZoomFactor > 0){ this.zoomFactor = Math.round(newZoomFactor*100)/100; } else { this.zoomFactor = this.zoomFactor/2 } this.updateParams(); } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-edition.module.ts b/nietzsche-beta-app/src/app/tln-edition/tln-edition.module.ts index 601d9b4..7b00545 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-edition.module.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-edition.module.ts @@ -1,61 +1,62 @@ import { BrowserModule } from '@angular/platform-browser'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { HttpClientModule } from "@angular/common/http"; import { NgModule } from '@angular/core'; import { MatBottomSheetModule,MatButtonModule,MatCheckboxModule,MatDialogModule,MatExpansionModule,MatFormFieldModule,MatInputModule,MatListModule,MatPaginatorModule,MatRadioModule,MatSelectModule,MatSidenavModule,MatSortModule,MatTableModule,MatToolbarModule,MatButtonToggleModule,MatCardModule,MatIconModule,MatMenuModule,MatTabsModule,MatTooltipModule } from '@angular/material'; import { NgxMatStandoffMarkupModule } from '../lib/ngx-mat-standoff-markup.module'; import { PageViewService } from '../page-view/page-view.service'; import { PageViewModule } from '../page-view/page-view.module'; import { TlnPageViewComponent } from './tln-page-view.component'; import { TlnQueryService } from './tln-query.service'; import { ToolTipComponent } from './tooltip/tool-tip.component'; import { TlnViewerNavigation } from './tln-viewer-navigation/tln-viewer-navigation.component'; import { TlnInformationComponent } from './tln-information/tln-information.component'; import { TlnCrossrefComponent } from './tln-crossref/tln-crossref.component'; import { VersionViewComponent } from './tln-crossref/version-view/version-view.component'; import { PageVersionViewComponent } from './tln-crossref/page-version-view/page-version-view.component'; @NgModule({ declarations: [TlnPageViewComponent, ToolTipComponent, TlnViewerNavigation, TlnInformationComponent, TlnCrossrefComponent, VersionViewComponent, PageVersionViewComponent], imports: [ MatBottomSheetModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatDialogModule, MatExpansionModule, MatFormFieldModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatPaginatorModule, MatRadioModule, MatSelectModule, MatSidenavModule, MatSortModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, BrowserModule, CommonModule, FormsModule, NgxMatStandoffMarkupModule, PageViewModule ], exports: [ + ToolTipComponent, TlnPageViewComponent, TlnViewerNavigation ], providers: [ PageViewService, TlnQueryService ], entryComponents: [TlnInformationComponent] }) export class TlnEditionModule { } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.html b/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.html index cdbeb07..8fd3cb8 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.html +++ b/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.html @@ -1,13 +1,12 @@
-
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.ts index 66aee80..2f763e4 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-page-view.component.ts @@ -1,226 +1,240 @@ import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { TlnQueryServiceInterface } from './models'; import { TlnQueryService } from './tln-query.service'; import { TlnPage} from './datatypes/page'; import { FaksimileImage } from './datatypes/faksimile_image'; import { SVGImage, SVGImageClip } from './datatypes/svg_image'; import { TlnImage } from './datatypes/image'; import { TlnLine, FaksimileLine } from './datatypes/line'; import { TlnWord, FaksimileWord } from './datatypes/word'; import { TlnTextByForeignHand, FaksimileTextByForeignHand } from './datatypes/foreign_text'; import { externalAssignClass, externalAssignStyle, Configuration, Identifier, Image, Line, Word } from './models'; import { ConfigurableComponent } from './services'; import { ComplexKeyIriMapping, DataHandler } from './data_handler'; -import { DEFAULT_VIEW_OPTION, VIEW_OPTIONS, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_SELECTED_LINES_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM } from './constants'; +import { DEFAULT_VIEW_OPTION, VIEW_OPTIONS, TLN_FULLSCREEN_PARAM, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_SELECTED_LINES_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM } from './constants'; import { Mapping, RouteReader } from './route-reader'; /** * Given a page IRI, this component will request all relevant information and * display the data with {@link /components/PageViewComponent.html|PageViewComponent}. **/ @Component({ selector: 'tln-page-view', templateUrl: './tln-page-view.component.html', styleUrls: ['./tln-page-view.component.css'] }) export class TlnPageViewComponent extends RouteReader implements OnInit, OnChanges { @Input() configuration: Configuration = { '*': { 'useExtendedTooltip': true }}; /** * IRI of the current page, the component will ignore page iri's from params if set. **/ @Input('page') current_iri: string; /** * the search text of words that should be highlighted as {@link /miscellaneous/enumerations.html#HIGHTLIGHT_CASES|HIGHTLIGHT_CASES.SEARCHED_WORD}. **/ @Input() findText: string; /** * whether or not to ignore the params **/ private ignoreParams: boolean = false; /** * OPTIONAL pass a queryService with method * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData} * to TlnPageViewComponent. **/ @Input() queryService: TlnQueryServiceInterface; /** * global zoom factor. **/ @Input() zoomFactor: number = 1; /** * identifiers of selected words that should be highlighted. **/ @Input() selectedWords: Identifier[] = []; /** * identifiers of selected lines that should be highlighted. **/ @Input() selectedLines: Identifier[] = []; /** * the (initial) maximum height of the image. **/ - @Input() dontShowReference: boolean = false; - @Input() startLine: Identifier; - @Input() endLine: Identifier; @Input() max_height: number = -1; + /** + * the (initial) maximum width of the image, if both height and width are specified prefer width. + **/ @Input() max_width: number = -1; + dontShowReference: boolean = false; + @Input() startLine: Identifier; + @Input() endLine: Identifier; /** * should primary Url be used for image. Use secondary Url if false. **/ @Input() preferPrimaryUrl: boolean = true; /** * selected view option, i.e. one of the following * {@link /miscellaneous/enumerations.html#VIEW_OPTIONS|VIEW_OPTIONS}. * */ @Input() selectedViewOption: string = DEFAULT_VIEW_OPTION; /** * An optional function that will be passed to {@link /components/TextFieldComponent.html|TextFieldComponent} * in order to return a further highlight class * to the word rects when the internal function would return 'textfield unhighlighted'. **/ @Input('assignClass') assignClass?: externalAssignClass; /** * An optional function that will be passed to {@link /components/TextFieldComponent.html|TextFieldComponent} * and {@link /components/MarginFieldComponent.html|MarginFieldComponent} * in order to return a (svg-)style object * to the word and line rects. This function allows the user to extend the style of this component. * E.g. by returning { fill: blue } the function overwrites the default behaviour and sets * the default highlight color to blue. **/ @Input('assignStyle') assignStyle?: externalAssignStyle; /** * the data handler of this component that retrieves * data and instantiates it according to their proper * datatypes. **/ dataHandler: DataHandler = new DataHandler(this); + /** + * whether or not to show page view in fullscreen mode. + **/ + fullscreen: boolean = false; /** * texts written by foreign hand **/ foreignTexts: TlnTextByForeignHand[] = []; /** * the (first) image to be displayed by * {@link /components/PageViewComponent.html|PageViewComponent}. **/ image: Image; /** * the Array of lines of the first image that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ lines: Line[] = []; /** * texts written by foreign hand **/ second_foreignTexts: FaksimileTextByForeignHand[] = []; /** * the second image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ second_image: Image; /** * the Array of lines of the second image that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ second_lines: Line[] = []; /** * the Array of words of the second image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ second_words: Word[] = []; /** * the Array of words of the first image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ words: Word[] = []; + @Input() multiInstanceMode: boolean = false; protected mapping: Mapping = { - findText: { param: TLN_FIND_PARAM, isNumber: false }, - selectedViewOption: { param: TLN_VIEW_OPTION_PARAM, isNumber: false }, - selectedLines: { param: TLN_SELECTED_LINES_PARAM, isNumber: false }, - current_iri: { param: TLN_PAGE_PARAM, isNumber: false }, - zoomFactor: { param: TLN_ZOOM_PARAM, isNumber: true } + findText: { param: TLN_FIND_PARAM, type: "string" }, + fullscreen: { param: TLN_FULLSCREEN_PARAM, type: "boolean" }, + selectedViewOption: { param: TLN_VIEW_OPTION_PARAM, type: "string" }, + selectedLines: { param: TLN_SELECTED_LINES_PARAM, type: "string" }, + current_iri: { param: TLN_PAGE_PARAM, type: "string" }, + zoomFactor: { param: TLN_ZOOM_PARAM, type: "number" } } /** * @param localQueryService internal query service that will be used if no external queryService is passed * to input. **/ constructor(private localQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute){ super(router, activatedRoute); } ngOnInit() { - this.ignoreParams = (this.current_iri != null); - if (!this.ignoreParams){ - super.ngOnInit(); + if (this.multiInstanceMode){ + this.mapping['current_iri']['ignore'] = (this.current_iri != null); + this.dontShowReference = true; + //this.configuration['*']['useExtendedTooltip'] = false; } + super.ngOnInit(); let tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService; let queryConfiguration: Configuration = { '*': { 'tlnQueryService': tlnQueryService }} this.configuration = ConfigurableComponent.updateConfiguration(this.configuration, queryConfiguration) this.dataHandler.addHandler('image', { 'handler': SVGImage }); this.dataHandler.addHandler('words', { 'handler': TlnWord }); this.dataHandler.addHandler('foreignTexts', { 'handler': TlnTextByForeignHand}); this.dataHandler.addHandler('lines', { 'handler': TlnLine }); this.dataHandler.addHandler('second_image',{ 'handler': FaksimileImage }); this.dataHandler.addHandler('second_words',{ 'handler': FaksimileWord }); this.dataHandler.addHandler('second_lines',{ 'handler': FaksimileLine }); this.dataHandler.addHandler('second_foreignTexts', { 'handler': FaksimileTextByForeignHand}); this.dataHandler.addHandler('page_content',[ 'image', 'lines', 'words', 'foreignTexts' ]); this.dataHandler.addHandler('second_page_content', [ 'second_image', 'second_lines', 'second_words', 'second_foreignTexts' ] ); this.dataHandler.setQueryService(tlnQueryService); this.updatePageData(); } ngOnChanges(change: SimpleChanges) { if (this.dataHandler.ready && (change.current_iri != undefined && change.current_iri != null && !change.current_iri.firstChange) || (change.selectedViewOption != undefined && change.selectedViewOption != null && !change.selectedViewOption.firstChange)) { this.updatePageData(); } } protected readParams(params: Params){ - if (!this.ignoreParams){ - let old_page_iri = this.current_iri; - let old_selectedViewOption = this.selectedViewOption; - super.readParams(params); - if (this.dataHandler.ready - && (old_page_iri != this.current_iri || old_selectedViewOption != this.selectedViewOption)){ - this.updatePageData(); - } + let old_page_iri = this.current_iri; + let old_selectedViewOption = this.selectedViewOption; + let old_fullscreen = this.fullscreen + super.readParams(params); + if (this.dataHandler.ready + && (old_page_iri != this.current_iri || old_selectedViewOption != this.selectedViewOption)){ + this.updatePageData(); + } + if (old_fullscreen != this.fullscreen && !this.multiInstanceMode){ + //this.dontShowReference = !this.fullscreen; + //this.configuration['*']['useExtendedTooltip'] = this.fullscreen; } } /** * This function updates the page data by setting the handlers for the current * {@link #selectedViewOption|selectedViewOption} and by retrieving the data. **/ private updatePageData(){ this.dataHandler['image']['handler'] = (this.selectedViewOption != VIEW_OPTIONS.FAKSIMILE && this.selectedViewOption != VIEW_OPTIONS.SYNOPSIS_B) ? SVGImage : FaksimileImage ; this.dataHandler['words']['handler'] = (this.selectedViewOption != VIEW_OPTIONS.FAKSIMILE && this.selectedViewOption != VIEW_OPTIONS.SYNOPSIS_B) ? TlnWord : FaksimileWord ; this.dataHandler['lines']['handler'] = (this.selectedViewOption != VIEW_OPTIONS.FAKSIMILE && this.selectedViewOption != VIEW_OPTIONS.SYNOPSIS_B) ? TlnLine : FaksimileLine ; this.dataHandler['foreignTexts']['handler'] = (this.selectedViewOption != VIEW_OPTIONS.FAKSIMILE && this.selectedViewOption != VIEW_OPTIONS.SYNOPSIS_B) ? TlnTextByForeignHand : FaksimileTextByForeignHand ; if (this.dataHandler['page_content'][this.dataHandler['page_content'].length-1] == 'second_page_content'){ this.dataHandler['page_content'].pop(); this.second_image = null; this.second_foreignTexts = []; this.second_words = []; this.second_lines = []; } if (this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS || this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS_B){ this.dataHandler['second_image']['handler'] = (this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS_B) ? SVGImage : FaksimileImage ; this.dataHandler['second_words']['handler'] = (this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS_B) ? TlnWord : FaksimileWord ; this.dataHandler['second_lines']['handler'] = (this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS_B) ? TlnLine : FaksimileLine ; this.dataHandler['second_foreignTexts']['handler'] = (this.selectedViewOption == VIEW_OPTIONS.SYNOPSIS_B) ? TlnTextByForeignHand : FaksimileTextByForeignHand ; this.dataHandler['page_content'].push('second_page_content'); } if (this.current_iri != null){ this.dataHandler.resetData('page_content'); if (this.startLine != null && this.startLine != undefined){ this.dataHandler['image']['handler'] = SVGImageClip ; let endLine = (this.endLine != null && this.endLine != undefined) ? this.endLine : this.startLine; let complex: ComplexKeyIriMapping = { idIndex: 0, mapping: [ { key: 'page', iri: this.current_iri}, { key: 'startLine', iri: this.startLine}, {key: 'endLine', iri: endLine} ] } this.dataHandler['page_content'] = this.dataHandler['page_content'].filter(key =>key != 'image') this.dataHandler.getData4Keys('image', complex); } else if (this.dataHandler['page_content'].indexOf('image') == -1){ this.dataHandler['page_content'].splice(0, 0, 'image') } this.dataHandler.getData('page_content', this.current_iri); } } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-query.service.ts b/nietzsche-beta-app/src/app/tln-edition/tln-query.service.ts index c557b66..d056746 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-query.service.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-query.service.ts @@ -1,38 +1,38 @@ import { Injectable, EventEmitter } from '@angular/core'; import {HttpClient, HttpHeaders} from '@angular/common/http'; import { Observable } from 'rxjs'; import { TlnQueryServiceInterface } from './models'; /** * This is the internal query service * that communicates with the SPARQL-endpoint. * */ @Injectable() export class TlnQueryService implements TlnQueryServiceInterface { - //baseUrl = 'http://localhost:3030/nietzsche/query'; - baseUrl = 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche' //'http://fuseki.nie-ine.ch/nietzsche/query'; + //baseUrl = 'http://localhost:3030/nietzsche/query'; + baseUrl = 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche' reset_data = new EventEmitter(); constructor(private http: HttpClient) { } public resetData(key: string){ this.reset_data.emit(key); } /** * Gets the data from an endpoint via http post * * @param query: The query to run. * @returns response */ public getData(query: string): Observable { let httpOptions = { headers: new HttpHeaders( { 'Content-Type': 'application/sparql-query', 'Accept': 'application/sparql-results+json; charset=UTF-8'} ) }; return this.http.post(this.baseUrl, query, httpOptions); } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.html b/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.html index c507519..4d3633d 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.html +++ b/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.html @@ -1,46 +1,50 @@ diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.ts index 417e32a..cafd726 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-viewer-navigation/tln-viewer-navigation.component.ts @@ -1,152 +1,161 @@ import { Component, OnInit, Input } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import {MatBottomSheet, MatBottomSheetRef} from '@angular/material/bottom-sheet'; import { TlnQueryServiceInterface, Reference, ManuscriptUnity, NavigationPage } from '../models'; import { TlnManuscriptUnity, TlnNavigationPage} from '../datatypes/navigation'; -import { DEFAULT_VIEW_OPTION, TLN_VIEWER_ROUTE,TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_MANUSCRIPT_PARAM, +import { DEFAULT_VIEW_OPTION, TLN_VIEWER_ROUTE, TLN_FULLSCREEN_PARAM, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_MANUSCRIPT_PARAM, TLN_SELECTED_LINES_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM, VIEW_OPTIONS, ONTOLOTY_PREFIX } from '../constants'; import { IsReconstructedKonvolut } from '../datatypes/basic_datatype'; import { TlnLine} from '../datatypes/line'; import { TlnTextGeneticOrder} from '../datatypes/text_version'; import { Mapping } from '../route-reader'; import { RouteUpdater } from '../route-updater'; import { ComplexKeyIriMapping, DataHandler, KeyIriMapping } from '../data_handler'; import { PageViewService, TlnQueryService } from '../services'; import { TlnInformationComponent, ParentInformation } from '../tln-information/tln-information.component'; import { PageInformation } from '../tln-information/page-information'; @Component({ selector: 'tln-viewer-navigation', templateUrl: './tln-viewer-navigation.component.html', styleUrls: ['./tln-viewer-navigation.component.css'] }) export class TlnViewerNavigation extends RouteUpdater { - /** - * OPTIONAL pass a queryService with method - * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData} - * to TlnPageViewComponent. - **/ - @Input() queryService: TlnQueryServiceInterface; + /** + * OPTIONAL pass a queryService with method + * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData} + * to TlnPageViewComponent. + **/ + @Input() queryService: TlnQueryServiceInterface; + /** + * whether or not to show page view in fullscreen mode. + **/ + fullscreen: boolean = false; zoomFactor: number = 1; findText: string; current_iri: string; current_manuscript_iri: string; manuscript_unity: ManuscriptUnity; current_page: NavigationPage; pageInformation: PageInformation; previous_page: NavigationPage; next_page: NavigationPage; showArchivalManuscriptUnity: boolean = false; dataHandler: DataHandler = new DataHandler(this); geneticOrders: TlnTextGeneticOrder[] = []; selectedLines: string[] = []; private readonly increment: number = 0.333; private readonly decrement: number = this.increment*-1; protected currentRoute: string = TLN_VIEWER_ROUTE; - protected mapping: Mapping = { findText: { param: TLN_FIND_PARAM, isNumber: false }, - current_iri: { param: TLN_PAGE_PARAM, isNumber: false }, - current_manuscript_iri: { param: TLN_MANUSCRIPT_PARAM, isNumber: false }, - selectedViewOption: { param: TLN_VIEW_OPTION_PARAM, isNumber: false }, - selectedLines: { param: TLN_SELECTED_LINES_PARAM, isNumber: false }, - zoomFactor: { param: TLN_ZOOM_PARAM, isNumber: true } } + protected mapping: Mapping = { findText: { param: TLN_FIND_PARAM, type: "string" }, + current_iri: { param: TLN_PAGE_PARAM, type: "string" }, + current_manuscript_iri: { param: TLN_MANUSCRIPT_PARAM, type: "string" }, + fullscreen: { param: TLN_FULLSCREEN_PARAM, type: "boolean" }, + selectedViewOption: { param: TLN_VIEW_OPTION_PARAM, type: "string" }, + selectedLines: { param: TLN_SELECTED_LINES_PARAM, type: "string" }, + zoomFactor: { param: TLN_ZOOM_PARAM, type: "number" } } routerParams: Params; selectedViewOption: string = DEFAULT_VIEW_OPTION updating: boolean = false; viewOptions: string[] = [ VIEW_OPTIONS.TRANSKRIPTION, VIEW_OPTIONS.FAKSIMILE, VIEW_OPTIONS.SYNOPSIS, VIEW_OPTIONS.SYNOPSIS_B ]; constructor(private bottomSheet: MatBottomSheet, private pageViewService: PageViewService, private localQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) { super(router, activatedRoute); } ngOnInit() { let tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService; this.dataHandler.addHandler('manuscript_unity', { 'handler': TlnManuscriptUnity, 'next_key': 'navigation_page'}); this.dataHandler.addHandler('navigation_page', ['current_page', 'geneticOrders'] ); this.dataHandler.addHandler('current_page', { 'handler': TlnNavigationPage }); this.dataHandler.addHandler('geneticOrders', { 'handler': TlnTextGeneticOrder}); this.dataHandler.setQueryService(tlnQueryService); this.dataHandler.start_processing.subscribe( (started: boolean) =>{ this.updating = true; }); this.dataHandler.processing_finished.subscribe( (finished: boolean) =>{ this.updating = false; }); super.ngOnInit(); this.pageViewService.reference.subscribe( (newReference: Reference) => { this.updatePageToReference(newReference) }) this.pageViewService.onClickedLine.subscribe( (clickedLine: TlnLine) => { let index = this.selectedLines.indexOf(clickedLine.id) if (index > -1){ this.selectedLines.splice(index, 1); } else { this.selectedLines.push(clickedLine.id); } this.updateParams(); }); } private clearFindText() { this.findText = ''; this.updateParams(); } private getPageTitle(page?: NavigationPage, numPages?: number): string { if (page == null){ return ''; } let indexPrefix = (numPages != null) ? page.index + '/' + numPages : page.index; return indexPrefix + ': ' + page.title + ' ' + page.number; } private getZoomTitle(changeValue: number): string { if (this.zoomFactor+changeValue < 0){ return Math.round(this.zoomFactor*50) + '%'; } return Math.round((this.zoomFactor+changeValue)*100) + '%'; } protected readParams(params: Params){ super.readParams(params); if (this.dataHandler.ready && (this.current_page == null || this.current_page.id != this.current_iri)){ this.dataHandler.resetData('navigation_page') if(this.current_manuscript_iri != null){ //this.dataHandler.debug = true; this.dataHandler.conditionalAddHandler(IsReconstructedKonvolut.getQuery(this.current_manuscript_iri), 'current_page',{ handler: TlnNavigationPage}, { handler: TlnNavigationPage}); this.dataHandler.getData('manuscript_unity', this.current_manuscript_iri, this.current_iri); } else { this.dataHandler.getData('current_page', this.current_iri); } } } private setZoomFactor(newZoomFactor: number){ if (newZoomFactor > 0){ this.zoomFactor = Math.round(newZoomFactor*100)/100; } else { this.zoomFactor = this.zoomFactor/2 } this.updateParams(); } private setCurrentIri(pageIri: string, manuscriptIir?: string){ this.dataHandler.stop_processing.emit(true); this.current_iri = pageIri; this.updateParams(); } private showInformation() { let parentData: ParentInformation = { geneticOrders: this.geneticOrders, page: this.current_page, manuscript: this.manuscript_unity } this.bottomSheet.open(TlnInformationComponent, { data: parentData }); } private updatePageToReference(reference: Reference){ this.current_iri = reference.page.id; this.selectedLines = [ reference.line.id ] this.updateParams(); } + private toggleFullscreen(){ + this.fullscreen = !this.fullscreen; + this.updateParams(); + } public test(iri?: string){ this.bottomSheet.open(TlnInformationComponent); //this.dataHandler.isOfType('showArchivalManuscriptUnity', 'http://rdfh.ch/projects/0068#_Mp_XIV', 'http://www.nie.org/ontology/nietzsche#ArchivalManuscriptUnity') } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.html b/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.html index 8a5c0fd..f593f0c 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.html +++ b/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.html @@ -1,49 +1,50 @@
-
+ {{tooltipPosition.clientY+yOffset}}, {{topOffset}} +
0: {{earlier_version.text}}
1:  {{word.text}}
>{{word.edited_text}}
überschreibt: {{overwrittenWord.text}}
{{foreignHand.text}}, {{foreignHand.pen}}
-
+
{{continuation.source.line.number}} nach  {{continuation.reference.manuscript.title}} {{continuation.reference.page.number}}, {{continuation.reference.line.number}}  nach {{continuation.source.line.number}}
{{ (word.earlier_version) ? '[0:' + word.earlier_version + '|1:' : ''}} {{ (word.earlier_version) ? ']' : ''}}
diff --git a/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.ts b/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.ts index 09418ff..016b683 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tooltip/tool-tip.component.ts @@ -1,197 +1,218 @@ import { Component, Input, OnInit, OnChanges, ElementRef, ViewChild} from '@angular/core'; import { ConfigurableComponent, PageViewService, TlnQueryService } from '../services'; import { Configuration, Continuation, Copyright, Point, PositionalObject, Reference, TextByForeignHand, TlnQueryServiceInterface, Word } from '../models'; import { TlnEarlierVersionStub, TlnOverwrittenStub } from '../datatypes/earlier_version'; import { TlnLineReference } from '../datatypes/line_reference'; import { TlnPreviewWord } from '../datatypes/preview_data'; import { TlnPositionalStyleMarkup, TlnFilteredPositionalStyleMarkup } from '../datatypes/positional-markup'; import { DataHandler } from '../data_handler'; import { PositionalStyleMarkup, StyleSheetDef, StandoffMarkupSettings} from '../../lib/ngx-mat-standoff-markup.component'; /** * This component can be used to show extended tooltips, i.e. with deleted words and distinguished * words if they are by foreign hand. **/ @Component({ selector: 'tool-tip', templateUrl: './tool-tip.component.html', styleUrls: ['./tool-tip.component.css'] }) export class ToolTipComponent extends ConfigurableComponent implements OnInit, OnChanges { + @Input('fullscreen') fullscreen: boolean = false; + @Input() hasMenuIssues: boolean = false; @Input() container: HTMLElement; + //fullscreen: boolean = false; /** * content keys **/ private readonly contentKeys: string[] = [ 'word', 'foreignHand', 'copyright', 'continuation' ] /** * copyright information to be shown in the tooltip. **/ copyright: Copyright; /** * current key of contentKeys **/ currentKey: string; debug: boolean = false; + position: number = 0; /** * the data handler of this component that retrieves * data and instantiates it according to their proper * datatypes. **/ dataHandler: DataHandler = new DataHandler(this); /** * text by foreign hand to be shown in tooltip **/ foreignHand: TextByForeignHand; /** * earlier version of word **/ earlier_version: TlnEarlierVersionStub; /** * overwritten word **/ overwrittenWord: TlnOverwrittenStub; /** * a line continuation **/ continuation: Continuation; /** * a list of positional style markups. **/ positionalStyleMarkups: PositionalStyleMarkup[] = []; continuation_words: TlnPreviewWord[] = []; cssDef: StyleSheetDef = { type: 'text', css: '' } mySettings = new StandoffMarkupSettings(true, true, false, 1); width: number = 300; - - /** * line reference from **/ sourceLineReference: TlnLineReference; /** * actual tooltip position **/ tooltipPosition: Point = { visible: false, clientX: -1, clientY: -1, layerX: -1, layerY: -1 }; /** * whether or not to show extended tooltips **/ - useExtendedTooltip: boolean = false; + useExtendedTooltip: boolean = true; /** * word to be shown in tooltip **/ word: Word; /** * y offset for tooltip position relative to mouse position **/ - private readonly yOffset: number = 30; + private readonly yOffset: number = 25; + private readonly menuIssueOffset: number = 80; + private readonly menuIssueXOffset: number = 55; + topOffset: number = 0; + leftOffset: number = 0; constructor(protected pageViewService: PageViewService, private tlnQueryService: TlnQueryService) { super() } ngOnChanges(){ super.ngOnChanges(); + /*if((this.fullscreen && this.fullscreenString != 'true') || (!this.fullscreen && this.fullscreenString == 'true')){ + this.fullscreen = (this.fullscreenString == 'true') + }*/ if (this.tlnQueryService != null && !this.dataHandler.ready){ this.dataHandler.addHandler('earlier_version', { 'handler': TlnEarlierVersionStub }); this.dataHandler.addHandler('overwrittenWord', { 'handler': TlnOverwrittenStub}); this.dataHandler.addHandler('positionalStyleMarkups', { 'handler': TlnFilteredPositionalStyleMarkup }); this.dataHandler.addHandler('sourceLineReference', { 'handler': TlnLineReference}); this.dataHandler.addHandler('continuation_words', { 'handler': TlnPreviewWord}); this.dataHandler.addHandler('wordStubs', ['earlier_version', 'overwrittenWord', 'positionalStyleMarkups' ]); this.dataHandler.setQueryService(this.tlnQueryService); this.tlnQueryService.reset_data.subscribe( (data_key: string) =>{ if (data_key == 'page_content'){ this.resetData() } }); } } /** * listen on pageViewService **/ ngOnInit() { this.pageViewService.mousePosition.subscribe( - (newPoint: Point) => this.tooltipPosition = newPoint - ); + (newPoint: Point) =>{ this.tooltipPosition = newPoint; + //console.log(this.tooltipPosition); + }); this.pageViewService.onHoveredWord.subscribe( (newWord: Word) => { this.setContent('word', newWord);this.updateEarlierVersion() } ); this.pageViewService.offHoveredWord.subscribe( (newWord: Word) => this.word = null ); this.pageViewService.onHoveredTextByForeignHand.subscribe( (newTextByForeignHand: TextByForeignHand) => { this.setContent('foreignHand',newTextByForeignHand) } ); this.pageViewService.offHoveredTextByForeignHand.subscribe( (newTextByForeignHand: TextByForeignHand) => this.foreignHand = null ); this.pageViewService.copyright.subscribe( (copyright: Copyright) =>{ this.setContent('copyright', (this.copyright == null) ? copyright : null) }); this.pageViewService.onHoveredContinuation.subscribe( (newContinuation: Continuation) => { if(this.continuation == null){ this.updateLineContinuation(newContinuation) } }); this.pageViewService.offHoveredContinuation.subscribe( (newContinuation: Continuation) => { this.dataHandler.stop_processing.emit(true);this.continuation = null;this.updateLineContinuation(); } ); } /** * reset data **/ private resetData(){ this.dataHandler.resetData('wordStubs') this.contentKeys.forEach(key=>this[key] = null); } /** * update earlier version of word **/ private updateEarlierVersion(){ if (this.word != null && this.dataHandler.ready) { this.dataHandler.resetData('wordStubs') this.dataHandler.getData('wordStubs', this.word.id); } } private updateLineContinuation(continuation?: Continuation){ this.setContent('continuation', continuation); if(continuation != null && this.dataHandler.ready){ this.dataHandler.resetData('continuation_words') if (continuation.source.page != null){ this.dataHandler.getData('continuation_words', this.continuation.reference.line.id) } } } private getTop(key: string): number { - return (key == 'copyright') ? this.tooltipPosition.layerY : this.tooltipPosition.clientY - this.yOffset; + if (this.hasMenuIssues && this.container != null && this.container != undefined){ + let containerRect: DOMRect = this.container.getBoundingClientRect(); + this.topOffset = containerRect.top; + if (!this.fullscreen){ + this.topOffset = this.topOffset - this.menuIssueOffset; + } + } + return this.tooltipPosition.clientY - this.topOffset + this.yOffset; } private getLeft(width: number): number { + let containerRect: DOMRect = (this.container != null && this.container != undefined) + ? this.container.getBoundingClientRect() : null; + this.leftOffset = (this.hasMenuIssues && containerRect != null) ? containerRect.left : 0; + let left = this.tooltipPosition.clientX - this.leftOffset; + if (this.hasMenuIssues){ + left += this.menuIssueXOffset; + } if (!this.tooltipPosition.visible || this.continuation == null || this.continuation.show == null - || this.continuation.show != 'to' - || this.container == null || this.container == undefined ){ - return this.tooltipPosition.clientX; + || this.continuation.show != 'to'){ + return left; } - let containerRect: DOMRect = this.container.getBoundingClientRect(); - let left = this.tooltipPosition.clientX; return (left + width <= containerRect.right) ? left : left-(left+width-containerRect.right)-5; } /** * Set tooltip's content and remove prior content. * @param key key of content * @param content new content **/ private setContent(key: string, content: Continuation|Copyright|PositionalObject){ this.contentKeys.forEach(key=>this[key] = null); this[key] = content; this.currentKey = key; } /** * whether tooltip has any content (i.e. any content of {@link /components/ToolTipComponent.html#contentKeys|contentKeys}) **/ private hasAnyContent(): boolean { return this.contentKeys.filter(key =>this[key] != null).length > 0 } }