diff --git a/nietzsche-beta-app/package.json b/nietzsche-beta-app/package.json index 262b1af..ee28001 100644 --- a/nietzsche-beta-app/package.json +++ b/nietzsche-beta-app/package.json @@ -1,60 +1,60 @@ { "name": "nietzsche-app-beta", - "version": "0.7.2.4", + "version": "0.7.3.0", "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", "@ctrl/ngx-codemirror": "^5.0.0", "@types/rdf-js": "^2.0.11", "codemirror": "^5.62.0", "lodash": "^4.17.20", "n3": "^1.10.0", "ngx-csv": "^0.3.2", "ngx-mat-standoff-markup": "^0.7.3", "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/page-view/models.ts b/nietzsche-beta-app/src/app/page-view/models.ts index 6f66d01..23608f4 100644 --- a/nietzsche-beta-app/src/app/page-view/models.ts +++ b/nietzsche-beta-app/src/app/page-view/models.ts @@ -1,286 +1,290 @@ /** * This interface specifies a function that returns a style class string (e.g. 'textfield unhighlighted') * that can be passed to [ngClass]. **/ export interface externalAssignClass { (currentWord: Word, hoveredWord: Word, hoveredLine: Line): string; } /** * This interface specifies a function that returns a style Object (e.g. { fill: red }) * that can be passed to [ngStyle]. **/ export interface externalAssignStyle { (currentItem: Line | Word, hoveredWord: Word, hoveredLine: Line, hoverStatus: string): Object; } /** * This interface specifies a configuration * */ export interface Configuration { [name: string]: any; } /** * a text continuation **/ export interface Continuation extends Interactable { reference: Reference; source: Reference; show?: string; } /** * Copyright information **/ export interface Copyright { text: string; licenseTextUrl?: string; license: string; originalUrl?: string; } /** * This interface specifies an object that can interact with {@link /injectables/PageViewService.html|PageViewService}. **/ export interface Interactable { /** * the string representation of the Interactable's interface type * ({@link /interfaces/Word.html|Word}|{@link /interfaces/Line.html|Line}|{@link /interfaces/TextByForeignHand.html|TextByForeignHand}). **/ datatype?: string; /** * the identity of the textfield to which this Interactable belongs. **/ textfield_identity?: string; /** * is Interactable top object **/ is_top_object?: boolean; } /** * This interface specifies the image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ export interface Image { /** x coordinate of image **/ x: number; /** y coordinate of image **/ y: number; /** width of image **/ width: number; /** height of image **/ height: number; /** filename of image **/ filename: string; /** primary URL of image **/ URL: string; /** secondary URL of image **/ secondaryURL?: string; /** displayable area of image **/ text_field: TextField; /** matrix transformation string **/ transform?: string; /** * copyright information **/ copyright?: Copyright; } /** * This interface specifies a line that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ export interface LineStub extends Interactable { /** the line number **/ number: number; /** the (optional) IRI of this line **/ id: Identifier; } /** * This interface specifies a line that will be displayed by {@link /components/MarginFieldComponent.html|MarginFieldComponent}. **/ export interface Line extends LineStub { /** geometrical bottom position of this line **/ bottom: number; /** geometrical top position of this line **/ top: number; /** * reference to the line from which this line continues **/ continuesFrom?: Reference; /** * reference to the line on which this line continues **/ continuesTo?: Reference; source?: Reference; } /** * This interface specifies the area of an image that will be displayed by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ export interface TextField { /** the width of this textfield **/ width: number; /** the height of this textfield **/ height: number; /** the geometrical left position of this textfield **/ left: number; /** the geometrical top position of this textfield **/ top: number; } /** * This type specifies an identifier for words/lines (by its IRI string or its id number) **/ export type Identifier = string | number; /** * This interface specifies a page. **/ export interface Page { id: Identifier; number: string; } /** * Any svg path with an optional type. **/ export interface Path { id: Identifier; d: string; type?: string; } /** * geometrical Point **/ export interface Point { visible: boolean clientX: number; clientY: number; layerX: number; layerY: number; } /** * simple x,y-position **/ export interface Position { x: number; y: number; } /** * This interface specifies a postional object that can be displayed as a rect on the image by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ export interface PositionalObject extends Interactable { /** the identifier of a positional object (i.e. 'IRI' (string) or 'id' (number)) **/ id: Identifier; /** the geometrical left position of this word's rect. **/ left: number; /** the geometrical top position of this word's rect. **/ top: number; /** the width of this word's rect. **/ width: number; /** the height of this word's rect. **/ height: number; /** the matrix transformation string of the geometrical position of this word's rect. **/ transform?: string; } /** * This interface specifies a Line Reference that can be routed to. **/ export interface LineReference { /** * the title of the reference **/ manuscript?: Manuscript; /** * the page number of the reference **/ page?: string; /** * the line number of the reference **/ line_number?: number; /** * the line identifiaction of the reference **/ id: Identifier; } export interface Reference { /** * reference to the manuscript **/ manuscript?: Manuscript; /** * reference to the page **/ page?: Page; /** * reference to the line **/ line?: LineStub; /** * reference to the word **/ //word?: WordStub; } /** * This interface specifies a manuscript **/ export interface Manuscript { id: Identifier; title: string; type?: string; } /** * This interface specifies a text written by a foreign hand. **/ export interface TextByForeignHand extends PositionalObject { /** * pen used for writing text **/ pen: string; /** * text by foreign hand **/ text: string; /** * resolution of the abbrevation. **/ resolution?: string; + /** + * editor's comment about this text of foreign hand + **/ + comment?: string; } /** * This interface specifies a word that can be displayed as a rect on the image by {@link /components/TextFieldComponent.html|TextFieldComponent}. **/ export interface Word extends PositionalObject { /** the (raw) text of this word. **/ text: string; /** the text of this word as it has been edited by the editors. **/ edited_text?: string; /** the identification of the line to which this word belongs (iri or id). **/ line: string | number; /** the number of the line to which this word belongs. **/ line_number: number; /** is this word deleted. **/ deleted: boolean; /** a deletion path **/ deletion_path?: string; } export const USE_EXTERNAL_TOOLTIP: string = 'UseExternalTooltip'; diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/foreign_text.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/foreign_text.ts index 42f0d34..d734a19 100644 --- a/nietzsche-beta-app/src/app/tln-edition/datatypes/foreign_text.ts +++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/foreign_text.ts @@ -1,103 +1,110 @@ import { FusekiResults, BasicResultBindingElement } from './basic_datatype'; import { TlnPositionalObject } from './positional_object'; import { TextByForeignHand } from '../models'; import { TlnPositionalStyleMarkup } from './positional-markup'; /** * This is the 'text by foreign hand' instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}. * It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}. **/ export class TlnTextByForeignHand extends TlnPositionalObject implements TextByForeignHand { /** * the SPARQL-query of this datatype. **/ static readonly query: string = ` PREFIX tln: PREFIX rdf: - SELECT ?id ?text ?pen ?left ?top ?width ?height ?resolution ?transform ?markup ?sStyle ?start ?end WHERE { + SELECT ?id ?text ?pen ?left ?top ?width ?height ?resolution ?comment ?transform ?markup ?sStyle ?start ?end WHERE { ?page tln:hasMarkForeignHands/rdf:rest*/rdf:first ?id. ?id tln:textOfForeignHands ?textOfForeignHands; tln:penOfForeignHands ?pen; tln:hasTranskriptionPosition ?tp. ?textOfForeignHands tln:textHasContent ?text. ?tp tln:hasLeft ?left; tln:hasTop ?top; tln:hasWidth ?width; tln:hasHeight ?height. OPTIONAl { ?id tln:resolutionOfAbbreviation ?resolution.} + OPTIONAl { ?id tln:foreignHandHasCommentByEditors ?comment.} OPTIONAl { ?textOfForeignHands tln:textHasMarkup ?markup. ?markup tln:standoffTagHasEndIndex ?end; tln:standoffTagHasStartIndex ?start; tln:standoffTagHasCSS ?sStyle. } OPTIONAl { ?tp tln:hasTransform ?transform.} } `; /** * the text of this word **/ text: string; /** * the text of this word as it has been edited by the editors. **/ pen: string; /** * resolution of the abbrevation **/ resolution?: string; + /** + * editor's comment about this text of foreign hand + **/ + comment?: string; markups: TlnPositionalStyleMarkup[] = []; /** * The constructor creates a datatype from the data. * * @param id if omitted the id will be retrieved from data **/ constructor(data: any, id?: string, service?: any){ super(data, id, service) this.text = this.getData4Key('text'); this.pen = this.getData4Key('pen'); this.resolution = this.getData4Key('resolution'); + this.comment = this.getData4Key('comment'); } public static convertData(this: T, data: FusekiResults, id?: string, service?: any): Array> { let elements = []; let content = this.getContent(data); for (var i = 0; i < content.length; i++){ let element = new TlnTextByForeignHand(content[i], id, service); if (content[i]['markup'] != undefined && content[i]['markup']['value'] != null){ element.markups = TlnPositionalStyleMarkup.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['markup']['value']) } if (elements.length > 0 && elements[elements.length-1].id == element.id){ element.markups.forEach(markup =>{elements[elements.length-1].markups.push(markup)}); } else { elements.push(element) } } //console.log(elements) return elements; } } /** * This is the faksimile text by foreign hand instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}. * It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}. **/ export class FaksimileTextByForeignHand extends TlnTextByForeignHand { /** * the SPARQL-query of this datatype. **/ static readonly query: string = ` PREFIX tln: PREFIX rdf: - SELECT ?id ?text ?pen ?left ?top ?width ?height ?resolution ?transform ?markup ?sStyle ?start ?end WHERE { + SELECT ?id ?text ?pen ?left ?top ?width ?height ?resolution ?comment ?transform ?markup ?sStyle ?start ?end WHERE { ?page tln:hasMarkForeignHands/rdf:rest*/rdf:first ?id. ?id tln:textOfForeignHands ?textOfForeignHands; tln:penOfForeignHands ?pen; tln:hasFaksimilePosition ?fp. ?textOfForeignHands tln:textHasContent ?text. ?fp tln:hasLeft ?left; tln:hasTop ?top; tln:hasWidth ?width; tln:hasHeight ?height. OPTIONAl { ?id tln:resolutionOfAbbreviation ?resolution.} + OPTIONAl { ?id tln:foreignHandHasCommentByEditors ?comment.} OPTIONAl { ?textOfForeignHands tln:textHasMarkup ?markup. ?markup tln:standoffTagHasEndIndex ?end; tln:standoffTagHasStartIndex ?start; tln:standoffTagHasCSS ?sStyle. } OPTIONAl { ?fp tln:hasTransform ?transform.} } `; } 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 693efb3..d6e57bb 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,76 +1,76 @@ import { Injectable, EventEmitter, OnInit } from '@angular/core'; import {HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http'; import { EMPTY, Observable, throwError } from 'rxjs'; import { catchError, shareReplay } from 'rxjs/operators'; import { TlnQueryServiceInterface } from './models'; import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarVerticalPosition, } from '@angular/material/snack-bar'; import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; /** * This is the internal query service * that communicates with the SPARQL-endpoint. * */ @Injectable({ providedIn: 'root'}) export class TlnQueryService implements TlnQueryServiceInterface { - // baseUrl = 'http://localhost:3030/nietzsche/query'; - baseUrl = 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche' + // baseUrl = 'http://localhost:3030/nietzsche/query'; + baseUrl = 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche' reset_data = new EventEmitter(); error_emitter = new EventEmitter(); use_cache: boolean = false; cache = {}; constructor(private http: HttpClient, private _snackBar: MatSnackBar) { } 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'} ) }; if (this.use_cache && this.cache[query]){ console.log('Returning cached value!') return this.cache[query]; } if (!this.use_cache){ return this.http.post(this.baseUrl, query, httpOptions).pipe(catchError(this.handleError)); } this.cache[query] = this.http.post(this.baseUrl, query, httpOptions).pipe( shareReplay(1), catchError(error =>{ delete this.cache[query]; this.handleError(error); return EMPTY }) ); return this.cache[query] } private handleError(error: HttpErrorResponse) { this.error_emitter.emit(error); switch (error.status){ case 0: // A client-side or network error occurred. Handle it accordingly. console.error('The backend data server is offline:', error.error); this._snackBar.open('The backend data server ' + this.baseUrl + ' is offline!'); break; default: console.error( `Backend returned code ${error.status}, ` + `body was: ${error.error}`); } return throwError( 'Something bad happened; please try again later.'); } } @Injectable({ providedIn: 'root'}) export class TlnCacheQueryService extends TlnQueryService { use_cache: boolean = true; } 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 2ffdce8..d469c2a 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,45 +1,48 @@
{{tooltipPosition.clientY+yOffset}}, {{topOffset}}
0: {{earlier_version.text}}
1:  {{word.text}}
>{{word.edited_text}}
überschreibt: {{overwrittenWord.text}}
{{foreignHand.text}} - (={{foreignHand.resolution}}), {{foreignHand.pen}} + + (={{foreignHand.resolution}}) + {{foreignHand.comment}}, {{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 674437f..eb4a7a8 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,226 +1,227 @@ import { Component, Input, OnInit, OnChanges, ElementRef, ViewChild} from '@angular/core'; import { MarkupSettings, StandoffMarkup } from 'ngx-mat-standoff-markup'; import { ConfigurableComponent, PageViewService, TlnCacheQueryService } from '../services'; import { Configuration, Continuation, Copyright, Point, Position, 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 { TlnEditorCommentStub } from '../datatypes/editor_comment'; import { DataHandler } from '../data_handler'; /** * 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', providers: [ TlnCacheQueryService ], styleUrls: ['./tool-tip.component.css'] }) export class ToolTipComponent extends ConfigurableComponent implements OnInit, OnChanges { @Input('fullscreen') fullscreen: boolean = false; @Input() hasMenuIssues: boolean = false; @Input() menuOffsetPosition: Position; @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; /** * editor comments **/ editor_comments: TlnEditorCommentStub[] = []; /** * a line continuation **/ continuation: Continuation; /** * a list of positional style markups. **/ positionalStyleMarkups: StandoffMarkup[] = []; continuation_words: TlnPreviewWord[] = []; mySettings: MarkupSettings = new MarkupSettings(); 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 = true; /** * word to be shown in tooltip **/ word: Word; /** * y offset for tooltip position relative to mouse position **/ 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: TlnCacheQueryService) { 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('editor_comments', { 'handler': TlnEditorCommentStub}); this.dataHandler.addHandler('sourceLineReference', { 'handler': TlnLineReference}); this.dataHandler.addHandler('continuation_words', { 'handler': TlnPreviewWord}); this.dataHandler.addHandler('wordStubs', ['earlier_version', 'overwrittenWord', 'positionalStyleMarkups', 'editor_comments' ]); 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; //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.resetData() } ); 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('positionalStyleMarkups') 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.debug = true; 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 { if (this.menuOffsetPosition != undefined && this.menuOffsetPosition != null && this.container != null && this.container != undefined){ let containerRect: DOMRect = this.container.getBoundingClientRect(); this.topOffset = containerRect.top; if (!this.fullscreen){ this.topOffset = this.topOffset - this.menuOffsetPosition.y; } } 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.menuOffsetPosition != undefined && this.menuOffsetPosition != null && containerRect != null) ? containerRect.left : 0; let left = this.tooltipPosition.clientX - this.leftOffset; if (this.menuOffsetPosition != undefined && this.menuOffsetPosition != null){ left += this.menuOffsetPosition.x; } if (!this.tooltipPosition.visible || this.continuation == null || this.continuation.show == null || this.continuation.show != 'to'){ return left; } 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 } }