diff --git a/nietzsche-beta-app/package.json b/nietzsche-beta-app/package.json index dfe72be..64b30e5 100644 --- a/nietzsche-beta-app/package.json +++ b/nietzsche-beta-app/package.json @@ -1,55 +1,55 @@ { - "name": "svg-test-app", - "version": "0.0.0", + "name": "nietzsche-app-beta", + "version": "0.4.1.2", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "compodoc": "./node_modules/.bin/compodoc -p tsconfig.app.json", "sparqljs": "./node_modules/sparqljs/sparql.js" }, "private": true, "dependencies": { "@angular/animations": "~8.2.14", "@angular/cdk": "~8.2.3", "@angular/common": "~8.2.14", "@angular/compiler": "~8.2.14", "@angular/core": "~8.2.14", "@angular/forms": "~8.2.14", "@angular/material": "^8.2.3", "@angular/platform-browser": "~8.2.14", "@angular/platform-browser-dynamic": "~8.2.14", "@angular/router": "~8.2.14", "@types/rdf-js": "^2.0.11", "lodash": "^4.17.20", "rdfjs": "^0.0.1", "rxjs": "~6.4.0", "sparqljs": "^3.0.1", "tslib": "^1.10.0", "zone.js": "~0.9.1" }, "devDependencies": { "@angular-devkit/build-angular": "^0.803.25", "@angular/cli": "~8.3.24", "@angular/compiler-cli": "~8.2.14", "@angular/language-service": "~8.2.14", "@types/jasmine": "~3.3.8", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "^5.0.0", "jasmine-core": "~3.4.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~4.1.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.0", "protractor": "~5.4.0", "ts-node": "~7.0.0", "tslint": "~5.15.0", "typescript": "~3.5.3" } } diff --git a/nietzsche-beta-app/src/app/app.component.html b/nietzsche-beta-app/src/app/app.component.html index 6e343ba..c4cf044 100644 --- a/nietzsche-beta-app/src/app/app.component.html +++ b/nietzsche-beta-app/src/app/app.component.html @@ -1,16 +1,17 @@
- Standard + Digitale Manuskriptedition: Der späte Nietzsche - Version {{version}} Green -

Der späte Nietzsche, Manuskripte 1885-1889 (beta version)

+

Der späte Nietzsche, Manuskripte 1885-1889

diff --git a/nietzsche-beta-app/src/app/app.component.ts b/nietzsche-beta-app/src/app/app.component.ts index e29ef17..52ca66f 100644 --- a/nietzsche-beta-app/src/app/app.component.ts +++ b/nietzsche-beta-app/src/app/app.component.ts @@ -1,32 +1,35 @@ import {Component, OnInit} from '@angular/core'; import { OverlayContainer} from '@angular/cdk/overlay'; import {Subscription} from 'rxjs'; import {ActivatedRoute, Params} from '@angular/router'; +declare var require: any; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { - title = 'nietzsche app'; + title = 'Digitale Manuskriptedition: Der späte Nietzsche'; theme = 'standard-theme'; + version: string; fullScreen: string; queryParamSub: Subscription; constructor(private overlayContainer: OverlayContainer, private activatedRoute: ActivatedRoute) { + this.version = require( '../../package.json').version; } ngOnInit() { this.overlayContainer.getContainerElement().classList.add(this.theme); this.queryParamSub = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => { this.fullScreen = queryParams.fullscreen; }); } onThemeChange() { this.overlayContainer.getContainerElement().classList.add(this.theme); } } 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 a94b739..6e4398f 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,272 +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() { // TODO: Remove and scroll only after set intenally + 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; // must time out here hence document is not ready to scroll window.setTimeout(() => this.scrollOnToSelectedItem(this.oldQueryParams[context]), 100); } } scrollOnToSelectedItem(itemId: string ) { 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) { // If a new item is clicked if (this.navTrees[this.navTabIndex].selectedItem !== item.tlnEntity.id) { // 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 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 { // 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) { 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) { 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/page-view/textfield-component/textfield.component.ts b/nietzsche-beta-app/src/app/page-view/textfield-component/textfield.component.ts index d091a4a..1783f14 100644 --- a/nietzsche-beta-app/src/app/page-view/textfield-component/textfield.component.ts +++ b/nietzsche-beta-app/src/app/page-view/textfield-component/textfield.component.ts @@ -1,348 +1,348 @@ import { Component, ElementRef, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { externalAssignClass, externalAssignStyle, Configuration, Continuation, Identifier, Image, Line, Position, PositionalObject, TextByForeignHand, Word, USE_EXTERNAL_TOOLTIP} from '../models'; import { PageViewService } from '../page-view.service'; import { HIGHTLIGHT_CASES } from '../highlight_status'; import { ConfigurableComponent } from '../configurable-component'; import { Matrix } from './matrix'; /** * This component displays an image with word hovers. **/ @Component({ selector: 'text-field', templateUrl: './textfield.component.html', styleUrls: ['./textfield.component.css'] }) export class TextFieldComponent extends ConfigurableComponent implements OnInit, OnChanges { /** * scrollable HTML-container of this textfield **/ @Input() container: HTMLElement; /** * the currently clicked word * */ clickedWord?: Word; /** * Debug mode. **/ debug: boolean = false; /** * the search text of words that should be highlighted as {@link /miscellaneous/enumerations.html#HIGHTLIGHT_CASES|HIGHTLIGHT_CASES.SEARCHED_WORD}. **/ @Input() findText: string; /** - * texts written by foreign hand + * texts written by foreign hand **/ @Input() foreign_texts: TextByForeignHand[] = []; /** * the currently hovered line * */ hoveredLine?: Line; /** - * the currently hovered text by foreign hand + * the currently hovered text by foreign hand * */ hoveredTextByForeignHand?: TextByForeignHand; /** * the currently hovered word * */ hoveredWord?: Word; /** * the image that will be displayed. **/ @Input() image: Image; /** * textfield's identity. **/ @Input() identity: string = 'first textfield'; /** - * The (unzoomed) height of the root svg. + * The (unzoomed) height of the root svg. * * (The actual height is 'image_height*local_zoom*zoomFactor' * */ image_height: number = 400; /** * image properties for the svg-image. * */ imageSpec = { x: 0, y: 0, height: 973.91998, width: 2038.5601, URL: null, secondaryURL: null, transform: 'matrix(1 0 0 1 0 0)' }; /** - * The (unzoomed) width of the root svg. + * The (unzoomed) width of the root svg. * * (The actual width is 'image_width*local_zoom*zoomFactor' * */ image_width: number = 300; /** * the viewBox of the root svg specifying the area of the svg that will be shown. * */ viewBox: string = ''; /** * the (initial) maximum height of the image. **/ @Input() max_height: number = -1; /** * the (initial) maximum width of the image. **/ @Input() max_width: number = -1; /** * should primary Url be used for image. Use secondary Url if false. **/ @Input() preferPrimaryUrl: boolean = true; /** * Use extended tooltip. **/ @Input() useExtendedTooltip: boolean = false; /** * the words that will be displayed as rects on the image. **/ @Input() words: Word[]; /** * global zoom factor. **/ @Input() zoomFactor: number = 1; /** - * local zoom factor that sets the height and width of the image according to {@link #max_height|max_height}. + * local zoom factor that sets the height and width of the image according to {@link #max_height|max_height}. * */ local_zoom: number = 1; /** * An optional function that can be passed to this component in order to return a further highlight class - * to the word rects when the internal function would return 'textfield unhighlighted'. + * to the word rects when the internal function would return 'textfield unhighlighted'. **/ @Input('assignClass') externalAssignClassAfter?: externalAssignClass; /** - * An optional function that can be passed to this component in order to return a (svg-)style object + * An optional function that can be passed to this component in order to return a (svg-)style object * to the word 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') extAssignStyle?: externalAssignStyle; /** * identifiers of selected words that should be highlighted. **/ @Input() selectedWords: Identifier[] = []; /** * identifiers of selected lines that should be highlighted. **/ @Input() selectedLines: Identifier[] = []; /** * @param pageViewService an information source about (un-)hovered and clicked Lines/Words. * */ - constructor( protected pageViewService: PageViewService) { + constructor( protected pageViewService: PageViewService) { super() } ngOnInit() { if (this.max_height == -1 && this.max_width == -1){ this.max_height = screen.availHeight; } if (this.image.text_field != null) { this.updateImageProperties(); } else if (this.imageSpec != null) { this.image_width = this.imageSpec.width; this.image_height = this.imageSpec.height; this.viewBox = '0 0 ' + this.image_width + ' ' + this.image_height; } this.pageViewService.onClickedWord.subscribe( (changedWord: Word ) => this.clickedWord = changedWord ); this.pageViewService.onHoveredWord.subscribe( (changedWord: Word) => this.hoveredWord = changedWord ); this.pageViewService.offHoveredWord.subscribe( (changedWord: Word) => { this.hoveredWord = null; } ); this.pageViewService.onHoveredLine.subscribe( (changedLine: Line) => { this.hoveredLine = changedLine} ); this.pageViewService.offHoveredLine.subscribe( (changedLine: Line) => { this.hoveredLine = null; } ); this.pageViewService.onHoveredTextByForeignHand.subscribe( (changedForeignText: TextByForeignHand) => { this.hoveredTextByForeignHand = changedForeignText;} ); this.pageViewService.offHoveredTextByForeignHand.subscribe( (changedForeignText: TextByForeignHand) => { this.hoveredTextByForeignHand = null; } ); } ngOnChanges() { super.ngOnChanges() if (this.image.text_field != null) { this.updateImageProperties(); } if(this.debug && this.findText != null && this.findText != ''){ let words = this.words.filter(word =>word.text == this.findText) if (words.length > 0){ this.pageViewService.onHoverService(words[0], {visible: true, clientX: 100, clientY: 100, layerX: -1, layerY: -1 }) } } } /** * Update image properties: use textfield in order to specify the area of the image that will be shown. * * @param URL set alternative image url. This will be used on image load error (see Template) **/ private updateImageProperties(URL?: string){ let previous_word: Word = null; for (var i = 0; i < this.words.length; i++){ this.words[i].datatype = "Word"; if (previous_word == null || previous_word.id != this.words[i].id){ previous_word = this.words[i] previous_word.is_top_object = true; } else if (previous_word.top > this.words[i].top){ previous_word.is_top_object = false; previous_word = this.words[i] previous_word.is_top_object = true; } else { this.words[i].is_top_object = false; } } this.foreign_texts.forEach(foreignText =>foreignText.datatype = "TextByForeignHand"); let image_left = this.image.text_field.left; let image_top = this.image.text_field.top; this.image_width = this.image.text_field.width; this.image_height = this.image.text_field.height; - this.local_zoom = (this.max_height != -1 && this.max_width == -1) + this.local_zoom = (this.max_height != -1 && this.max_width == -1) ? this.max_height/this.image.text_field.height : this.max_width/this.image.text_field.width; if (this.max_width == -1 && this.image_height < this.image_width){ this.local_zoom = (window.innerWidth/2-100)/this.image.text_field.width; } this.imageSpec.x = this.image.x; this.imageSpec.y = this.image.y; this.imageSpec.height = this.image.height; this.imageSpec.width = this.image.width; this.imageSpec.URL = (this.preferPrimaryUrl) ? this.image.URL : this.image.secondaryURL; this.imageSpec.secondaryURL = (this.preferPrimaryUrl) ? this.image.URL : this.image.URL; if (URL != null){ this.imageSpec.secondaryURL = this.imageSpec.URL this.imageSpec.URL = URL; } if(this.image.transform != null){ this.local_zoom = this.max_height/this.image.text_field.width; let matrix = new Matrix(this.image.transform, this.local_zoom*this.zoomFactor); this.imageSpec.transform = matrix.toString() } this.viewBox = image_left + ' ' + image_top + ' ' + this.image_width + ' ' + this.image_height; } /** * Return the position (i.e. '{ x: x, y: y }') for the copyright symbol. * @param dimension dimension of the copyright symbol. **/ private getCopyrightPosition(dimension: number): Object { if (this.image.text_field != null && this.image.text_field != undefined){ let positions: Position[] = [ { x: Number(this.image.text_field.left) +10/this.zoomFactor, y: Number(this.image.text_field.top) +10/this.zoomFactor }, { x: Number(this.image.text_field.left), y: Number(this.image.text_field.top)}, { x: Number(this.image.text_field.width) + Number(this.image.text_field.left) -15/this.zoomFactor - dimension, y: Number(this.image.text_field.height) + Number(this.image.text_field.top) -15/this.zoomFactor - dimension }, { x: Number(this.image.text_field.width) + Number(this.image.text_field.left) - dimension, y: Number(this.image.text_field.height) + Number(this.image.text_field.top) - dimension }, { x: Number(this.image.text_field.left) +10/this.zoomFactor, y: Number(this.image.text_field.height) + Number(this.image.text_field.top) -10/this.zoomFactor - dimension }, { x: Number(this.image.text_field.width) + Number(this.image.text_field.left) -10/this.zoomFactor - dimension, y: Number(this.image.text_field.top) +10/this.zoomFactor}, { x: Number(this.image.text_field.width) + Number(this.image.text_field.left) - dimension, y: Number(this.image.text_field.top)} ] let default_index = 1 let index = 0; let position_found = false; while (!position_found && index < positions.length){ let left = positions[index].x let top = positions[index].y if(!this.doesPositionConflict(left, top, dimension, this.words) && !this.doesPositionConflict(left, top, dimension, this.foreign_texts)){ - position_found = true; + position_found = true; } else { - index++ + index++ } } let left = (index < positions.length) ? positions[index].x : positions[default_index].x; let top = (index < positions.length) ? positions[index].y : positions[default_index].y; return { x: `${left}px`, y: `${top}px` } } else { return { x: '0px', y: '0px' } } } /** * Return whether position specified by left, top and dimension does conflict with one of the positional objects' position. * * @param left left of position * @param top top of position * @param dimension dimension of position * @param positionalObjects Array of positions **/ private doesPositionConflict(left: number, top: number, dimension: number, positionalObjects: PositionalObject[]): boolean { let conflicts = positionalObjects.filter(positionalObject => - !(Number(positionalObject.left) + Number(positionalObject.width) < left || Number(positionalObject.left) > left + dimension + !(Number(positionalObject.left) + Number(positionalObject.width) < left || Number(positionalObject.left) > left + dimension || Number(positionalObject.top) > top + dimension || Number(positionalObject.top) + Number(positionalObject.height) < top) ) return conflicts.length > 0 } /** * Get the hover status of the word as one of the {@link /miscellaneous/enumerations.html#HIGHTLIGHT_CASES|HIGHTLIGHT_CASES}. **/ private getHoverStatus(word: Word, skipFindText: boolean = false): string { if (this.selectedWords.indexOf(word.id) > -1 || this.selectedLines.indexOf(word.line) > -1){ return HIGHTLIGHT_CASES.SELECTED_WORD; } if (!skipFindText && this.findText != null && this.findText != ''){ let findRegex = '^[^\\w]*(' + this.findText.split(' ').join('|') + ')' - return (word.text.match(findRegex) + return (word.text.match(findRegex) || (word.edited_text != null && word.edited_text.match(findRegex)) - ) ? HIGHTLIGHT_CASES.SEARCHED_WORD : this.getHoverStatus(word, true); + ) ? HIGHTLIGHT_CASES.SEARCHED_WORD : this.getHoverStatus(word, true); } if (typeof this.hoveredLine !== 'undefined' && this.hoveredLine !== null) { - return (this.hoveredLine.id == word.line + return (this.hoveredLine.id == word.line || (this.hoveredLine.continuesTo != undefined && this.hoveredLine.continuesTo != null && this.hoveredLine.continuesTo.line.id == word.line) || (this.hoveredLine.continuesFrom != undefined && this.hoveredLine.continuesFrom != null && this.hoveredLine.continuesFrom.line.id == word.line)) - ? HIGHTLIGHT_CASES.LINE_HOVERED : HIGHTLIGHT_CASES.DEFAULT; + ? HIGHTLIGHT_CASES.LINE_HOVERED : HIGHTLIGHT_CASES.DEFAULT; } else if (typeof this.hoveredWord !== 'undefined' && this.hoveredWord !== null){ return (this.hoveredWord.id == word.id) ? HIGHTLIGHT_CASES.WORD_HOVERED : HIGHTLIGHT_CASES.DEFAULT; - } + } return HIGHTLIGHT_CASES.DEFAULT; } /** - * Return a css class for word that will be used with [ngClass] in order to (un-)highlight the word's rect. + * Return a css class for word that will be used with [ngClass] in order to (un-)highlight the word's rect. * * If a function has been passed to Input {@link #assignClass|assignClass}, * this function will call it if {@link #getHoverStatus|getHoverStatus(word)} == {@link /miscellaneous/enumerations.html#HIGHTLIGHT_CASES|HIGHTLIGHT_CASES.DEFAULT}. **/ private assignClass(positionalObject: PositionalObject, elementName?: string): string { if (positionalObject.datatype == 'TextByForeignHand'){ - return (this.hoveredTextByForeignHand != null && this.hoveredTextByForeignHand.id == positionalObject.id) ? + return (this.hoveredTextByForeignHand != null && this.hoveredTextByForeignHand.id == positionalObject.id) ? 'text_field highlight_foreign_text' : 'text_field unhighlighted' } let word = positionalObject; if (elementName != null) { return (this.getHoverStatus(word) == HIGHTLIGHT_CASES.DEFAULT) ? `text_field unhighlighted_${elementName}` : `text_field highlight_${elementName}`; } switch(this.getHoverStatus(word)) { case HIGHTLIGHT_CASES.SELECTED_WORD: { return 'textfield highlight_magenta'; } case HIGHTLIGHT_CASES.SEARCHED_WORD: { return 'textfield highlight_red'; } case HIGHTLIGHT_CASES.LINE_HOVERED: { return (word.deleted) ? 'textfield deleted' : 'textfield highlight_yellow'; } case HIGHTLIGHT_CASES.WORD_HOVERED: { return (word.deleted) ? 'textfield deleted' : 'textfield highlight_yellow'; } case HIGHTLIGHT_CASES.DEFAULT: { return (this.externalAssignClassAfter != null) ? this.externalAssignClassAfter(word, this.hoveredWord, this.hoveredLine) : 'textfield unhighlighted'; } } } /** * Assign a style to the rects of a line. **/ private assignStyle(word: Word, hoveredWord: Word, hoveredLine: Line, hoverStatus: string): Object { return (this.extAssignStyle != null) ? this.extAssignStyle(word, hoveredWord, hoveredLine, hoverStatus) : {}; } private msg(URL: string){ if(this.preferPrimaryUrl){ - console.log(URL + ' TODO: show smaller image during loading'); + // console.log(URL + ' TODO: show smaller image during loading'); } } } diff --git a/nietzsche-beta-app/src/index.html b/nietzsche-beta-app/src/index.html index 06955f7..9292d10 100644 --- a/nietzsche-beta-app/src/index.html +++ b/nietzsche-beta-app/src/index.html @@ -1,18 +1,18 @@ - Nietzsche beta app + Der späte Nietzsche