diff --git a/nietzsche-beta-app/package.json b/nietzsche-beta-app/package.json
index ff79cee..fbc020b 100644
--- a/nietzsche-beta-app/package.json
+++ b/nietzsche-beta-app/package.json
@@ -1,57 +1,60 @@
{
"name": "nietzsche-app-beta",
- "version": "0.5.2.1",
+ "version": "0.6.0.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",
- "n3":"^1.10.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.module.ts b/nietzsche-beta-app/src/app/app.module.ts
index a0f06b7..d402738 100644
--- a/nietzsche-beta-app/src/app/app.module.ts
+++ b/nietzsche-beta-app/src/app/app.module.ts
@@ -1,80 +1,82 @@
import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule} from '@angular/forms';
import { NgModule } from '@angular/core';
import {MatCardModule} from '@angular/material/card';
import { MatToolbarModule, MatButtonModule} from '@angular/material';
import {MatProgressBarModule} from '@angular/material/progress-bar';
import {MatTreeModule} from '@angular/material/tree';
import { MatExpansionModule } from '@angular/material/expansion';
import {MatIconModule} from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule} from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material';
import { MatSelectModule } from '@angular/material/select';
import {MatTabsModule} from '@angular/material/tabs';
import {MatTooltipModule} from '@angular/material';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { QueryService } from './services/query.service';
import {routing} from './app.routing';
import {HomeComponent} from './home.component';
import { ManuscriptViewComponentComponent } from './manuscript-view-component/manuscript-view-component.component';
import { ContentViewTabComponentComponent } from './content-view-tab-component/content-view-tab-component.component';
import { RhizomeViewComponentComponent } from './rhizome-view-component/rhizome-view-component.component';
import { MainMenuComponentComponent } from './main-menu-component/main-menu-component.component';
import { PageViewWrapperComponent } from './page-view-wrapper-component/page-view-wrapper.component';
import { NavigationListComponentComponent } from './navigation-list-component/navigation-list-component.component';
import {NavigationServiceService} from './services/navigation-service.service';
import { TlnEditionModule} from './tln-edition/tln-edition.module';
import { NavTree } from './navigation-list-component/navtree-directive.directive';
import { LazyImageLoadDirectiveDirective } from './content-view-tab-component/lazy-image-load-directive.directive';
import { ImpressumComponent } from './impressum.component';
import { ProjectComponent } from './project.component';
import { NavigationlistListComponentComponent } from './navigation-list-component/navigationlist-list-component/navigationlist-list-component.component';
+import { QuantComponent } from './quant/quant.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
ManuscriptViewComponentComponent,
ContentViewTabComponentComponent,
RhizomeViewComponentComponent,
MainMenuComponentComponent,
PageViewWrapperComponent,
NavigationListComponentComponent,
NavTree,
LazyImageLoadDirectiveDirective,
ImpressumComponent,
ProjectComponent,
- NavigationlistListComponentComponent
+ NavigationlistListComponentComponent,
+ QuantComponent
],
imports: [
routing,
BrowserModule,
BrowserAnimationsModule,
CommonModule,
HttpClientModule,
MatButtonModule,
MatCardModule,
MatExpansionModule,
MatIconModule,
MatListModule,
MatMenuModule,
MatProgressBarModule,
MatSelectModule, // for themes selection
MatSidenavModule,
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
MatTreeModule,
FormsModule,
TlnEditionModule,
ReactiveFormsModule
],
providers: [ NavigationServiceService, QueryService ],
bootstrap: [AppComponent]
})
export class AppModule { }
diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts
index b15cd32..bc7d26e 100644
--- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts
+++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-routes.ts
@@ -1,14 +1,16 @@
import { Routes } from '@angular/router';
import {ManuscriptViewComponentComponent} from "../manuscript-view-component/manuscript-view-component.component";
import {RhizomeViewComponentComponent} from "../rhizome-view-component/rhizome-view-component.component";
import {PageViewWrapperComponent} from "../page-view-wrapper-component/page-view-wrapper.component";
-import { TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, TLN_VIEWER_ROUTE, TLN_CROSSREF_EDITOR_ROUTE } from '../tln-edition/constants';
+import { TLN_QUANT_ROUTE, TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, TLN_VIEWER_ROUTE, TLN_CROSSREF_EDITOR_ROUTE } from '../tln-edition/constants';
import { TlnFulltextComponent } from '../tln-edition/tln-fulltext/tln-fulltext.component';
+import { QuantComponent } from '../quant/quant.component';
export const CONTENT_ROUTES: Routes = [
{ path: TLN_MANUSCRIPT_ROUTE, component: ManuscriptViewComponentComponent },
{ path: TLN_VIEWER_ROUTE, component: PageViewWrapperComponent },
{ path: TLN_CROSSREF_ROUTE, component: RhizomeViewComponentComponent },
{ path: TLN_SEARCH_ROUTE, component: TlnFulltextComponent},
+ { path: TLN_QUANT_ROUTE, component: QuantComponent},
{ path: '', redirectTo: TLN_MANUSCRIPT_ROUTE, pathMatch: 'prefix' }
];
diff --git a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts
index 7ae9fad..3e6041a 100644
--- a/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts
+++ b/nietzsche-beta-app/src/app/content-view-tab-component/content-view-tab-component.component.ts
@@ -1,137 +1,137 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, NavigationEnd, Params, Router} from '@angular/router';
import {Subscription} from "rxjs/index";
import {NavigationServiceService} from "../services/navigation-service.service";
import {
TLN_CROSSREF_EDITOR_ROUTE, TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE,
- TLN_VIEWER_ROUTE
+ TLN_VIEWER_ROUTE, TLN_QUANT_ROUTE
} from '../tln-edition/constants';
@Component({
selector: 'app-content-view-tab-component',
templateUrl: './content-view-tab-component.component.html',
styleUrls: ['./content-view-tab-component.component.scss'],
providers: [ NavigationServiceService ]
})
export class ContentViewTabComponentComponent implements OnInit {
// navigation tabs for the content view (manuscript view, page view, rhizome view)
navTabLinks: any[];
// navbar on th left for navigating
navBarOpenState = false;
fullscreen = false;
navBarOpenMode: string;
queryParams: Params = {};
queryParamSubscription: Subscription;
routeSubscription: Subscription;
constructor(private router: Router,
private activatedRoute: ActivatedRoute,
private naviService: NavigationServiceService) {
// The links/tabs for routing the correct view-component
this.navTabLinks = [
{
label: 'Manuskriptansicht',
link: TLN_MANUSCRIPT_ROUTE,
index: 0,
isActive: true,
context: 'manuscript', // in which context the viewers are opened
disabled: false
}, {
label: 'Seitenansicht',
link: TLN_VIEWER_ROUTE,
index: 1,
isActive: false,
context: 'page', // in which context the viewers are opened
disabled: false
}, {
label: 'Querverweise',
link: TLN_CROSSREF_ROUTE,
index: 2,
isActive: false,
disabled: false
}, {
label: 'Suche',
link: TLN_SEARCH_ROUTE,
index: 3,
isActive: false,
disabled: false
},
{
- label: 'Querverweis-Editor',
- link: TLN_CROSSREF_EDITOR_ROUTE,
+ label: 'Datenabfrage',
+ link: TLN_QUANT_ROUTE,
index: 4,
isActive: false,
- disabled: true
+ disabled: false
},
];
// subscribe to route event and for marking the active navTab as active
this.routeSubscription = this.router.events.subscribe((event) => {
if ( event instanceof NavigationEnd) {
// if the navigated link is not active, we set it acive
if ( !this.navTabLinks.find(nl => nl.link === this.activatedRoute.snapshot.children.pop().routeConfig.path).isActive ) {
this.setActiveLink(this.activatedRoute.snapshot.children.pop().routeConfig.path);
}
}
});
this.queryParamSubscription = this.activatedRoute.queryParams.subscribe( (queryParams: Params ) => {
this.queryParams = queryParams;
if (queryParams.navBarOpenState) {
this.navBarOpenState = JSON.parse(queryParams.navBarOpenState.toLowerCase());
}
if (queryParams.fullscreen) {
this.fullscreen = JSON.parse(queryParams.fullscreen.toLowerCase());
}
});
}
ngOnInit() {
this.navBarOpenMode = 'side'; // side || over || push
this.setParamsOnInit();
// If url pasted or page refreshed --> resetting this.queryparams to the query params of the url;
// needed for active routing in the nav tabs & for general use in the template
}
// Sets the isActive prop of a navTabLink to true and all others to false .
setActiveLink(link: string) {
this.navTabLinks.forEach((navTabLink, index ) => {
if (navTabLink.link === link) {
this.navTabLinks[index].isActive = true;
if (navTabLink.context) {
window.setTimeout(() => this.naviService.updateRoute({contextView : navTabLink.context}), 300);
}
} else {
this.navTabLinks[index].isActive = false;
}
});
}
/**
* setParamsOnInit checks if the page is loaded with query params. If a certain query param is missing, it will be set to a default value
*
*/
setParamsOnInit() {
const qParams: Params = {};
// Set the NavBarOpenstate to true if it is not defined explicitely as false in the url query param onInit.
if (this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState') !== 'false') {
qParams.navBarOpenState = 'true'; }
// viewMode
if (!this.activatedRoute.snapshot.queryParamMap.get('viewMode')) {
qParams.viewMode = 'Transkription/Faksimile';
}
// contextView
if (!this.activatedRoute.snapshot.queryParamMap.get('contextView')) {
qParams.contextView = 'manuscript';
}
// navTabIdx: if none default is null
if (!this.activatedRoute.snapshot.queryParamMap.get('navTabIdx')) {
if (this.activatedRoute.snapshot.queryParamMap.get('contextView') === 'manuscript' || qParams.contextView === 'manuscript') {
qParams.navTabIdx = '0'; } else {
qParams.navTabIdx = '1'; }
}
this.naviService.updateRoute(qParams);
}
}
diff --git a/nietzsche-beta-app/src/app/quant/quant.component.html b/nietzsche-beta-app/src/app/quant/quant.component.html
new file mode 100644
index 0000000..9fd4a7c
--- /dev/null
+++ b/nietzsche-beta-app/src/app/quant/quant.component.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/nietzsche-beta-app/src/app/quant/quant.component.scss b/nietzsche-beta-app/src/app/quant/quant.component.scss
new file mode 100644
index 0000000..296d0ec
--- /dev/null
+++ b/nietzsche-beta-app/src/app/quant/quant.component.scss
@@ -0,0 +1,18 @@
+.content-area {
+ height: 100%;
+ width: 80%;
+}
+
+.nav-container {
+ height:100%;
+ //min-width: unset; // needed because angular sets an own min width!?
+ width:50%;
+ display: table-cell;
+}
+
+.content-container {
+ height:100%;
+ // min-width: unset; // needed because angular sets an own min width!?
+ // width:20px;
+ display: table-cell;
+}
diff --git a/nietzsche-beta-app/src/app/quant/quant.component.spec.ts b/nietzsche-beta-app/src/app/quant/quant.component.spec.ts
new file mode 100644
index 0000000..cfc0656
--- /dev/null
+++ b/nietzsche-beta-app/src/app/quant/quant.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { QuantComponent } from './quant.component';
+
+describe('QuantComponent', () => {
+ let component: QuantComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ QuantComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(QuantComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/nietzsche-beta-app/src/app/quant/quant.component.ts b/nietzsche-beta-app/src/app/quant/quant.component.ts
new file mode 100644
index 0000000..18c41e3
--- /dev/null
+++ b/nietzsche-beta-app/src/app/quant/quant.component.ts
@@ -0,0 +1,21 @@
+import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
+import {ActivatedRoute, Params} from '@angular/router';
+
+@Component({
+ selector: 'app-quant',
+ templateUrl: './quant.component.html',
+ styleUrls: ['./quant.component.scss']
+})
+export class QuantComponent implements OnInit {
+ private readonly leftOffset = 361;
+ width: number = 1000;
+
+ constructor(private activatedRoute: ActivatedRoute) { }
+
+ ngOnInit() {
+ this.activatedRoute.queryParams.subscribe( (queryParams: Params) =>{
+ this.width = (queryParams.navBarOpenState === 'true') ? window.innerWidth - this.leftOffset : window.innerWidth - 20;
+ });
+ }
+
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/common/page-result-filter.pipe.ts b/nietzsche-beta-app/src/app/tln-edition/common/page-result-filter.pipe.ts
new file mode 100644
index 0000000..5c138b8
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/common/page-result-filter.pipe.ts
@@ -0,0 +1,16 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { ResultRange } from './paginator-result-status';
+
+@Pipe({
+ name: 'pageResultFilter'
+})
+export class PageResultFilterPipe implements PipeTransform {
+
+ transform(results: any[], range: ResultRange): any[] {
+ if (results.length <= range.start){
+ return results;
+ }
+ return results.slice(range.start, range.end);
+ }
+
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/common/paginator-result-status.ts b/nietzsche-beta-app/src/app/tln-edition/common/paginator-result-status.ts
new file mode 100644
index 0000000..bb041cf
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/common/paginator-result-status.ts
@@ -0,0 +1,38 @@
+import {PageEvent} from '@angular/material/paginator';
+import { FoundPage} from '../datatypes/search';
+import { PageIndexUpdater } from '../models';
+
+export interface ResultRange {
+ start: number;
+ end: number;
+}
+
+export class PaginatorResultStatus {
+ resultLength: number;
+ resultRange: ResultRange;
+ resultIndex: number = 0;
+ pageIndexUpdater: PageIndexUpdater;
+ pageSizeOptions: number[] = [5, 10, 25, 100];
+
+ constructor(resultLength: number, pageIndexUpdater?: PageIndexUpdater){
+ this.resultLength = resultLength;
+ this.resultRange = { start: 0, end: this.resultLength-1 };
+ this.pageIndexUpdater = pageIndexUpdater;
+ }
+ updateResultRange(index: number){
+ this.resultRange = null;
+ this.resultIndex = index;
+ let newStart = index*this.resultLength
+ let newEnd = newStart+this.resultLength;
+ this.resultRange = { start: newStart, end: newEnd };
+ console.log(this.resultRange);
+ }
+ showResults(event: PageEvent){
+ this.resultLength = event.pageSize;
+ this.updateResultRange(event.pageIndex);
+ if (this.pageIndexUpdater != null){
+ this.pageIndexUpdater.change.emit(event.pageIndex)
+ }
+ }
+
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts b/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts
new file mode 100644
index 0000000..988eacb
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts
@@ -0,0 +1,29 @@
+import { OnInit } from '@angular/core';
+import { DataProcessor } from '../models';
+
+export interface CompareMapping {
+ compareValueKey: string;
+ sourceArrayKey: string;
+ targetArrayKey: string[];
+ commonPropertyKey: string;
+}
+export class SelectFromArray implements DataProcessor {
+ constructor(private onInit: OnInit, private compareMapping: CompareMapping){}
+
+ private getItem(item: any, path: string[]): any {
+ if (path.length == 1){
+ return item[path[0]];
+ } else {
+ return this.getItem(item[path[0]], path.slice(1));
+ }
+ }
+ public processData(){
+ const target = this.getItem(this.onInit, this.compareMapping.targetArrayKey.slice());
+ const compareValue = this.onInit[this.compareMapping.compareValueKey]
+ this.onInit[this.compareMapping.sourceArrayKey].forEach(item =>{
+ if(item[this.compareMapping.commonPropertyKey] === compareValue && target.indexOf(item) == -1){
+ target.push(item)
+ }
+ });
+ }
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/constants.ts b/nietzsche-beta-app/src/app/tln-edition/constants.ts
index 4f092b1..ff23fa8 100644
--- a/nietzsche-beta-app/src/app/tln-edition/constants.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/constants.ts
@@ -1,83 +1,102 @@
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 TlnCrossrefComponent
**/
export const TLN_CROSSREF_EDITOR_ROUTE: string = 'tln-crossref-editor';
/**
* Route for TlnFulltextComponent
**/
export const TLN_SEARCH_ROUTE: string = 'tln-search';
/**
* Route for TlnManuscriptViewComponent
**/
export const TLN_MANUSCRIPT_ROUTE: string = 'tln-manuscript';
+/**
+ * Route for TlnQuantComponent
+ **/
+export const TLN_QUANT_ROUTE: string = 'tln-quant';
/**
* Route for TlnViewerComponent
**/
export const TLN_VIEWER_ROUTE: string = 'tln-viewer';
/**
* Param that refers to the context that should be shown, i.e. 'page' or 'manuscript'.
**/
export const TLN_CONTEXT_VIEW_PARAM: string = 'contextView';
/**
* 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 manuscript iri.
**/
export const TLN_MANUSCRIPT_PARAM: string = 'manuscript';
/**
* Param for navigation bar open state.
**/
export const TLN_NAV_BAR_OPEN_STATE_PARAM: string = 'navBarOpenState';
/**
* Param for page iri.
**/
export const TLN_PAGE_PARAM: string = 'page';
/**
* Param for result index, type: number.
**/
-export const TLN_RESULT_INDEX_PARAM: string = 'resutlIndex';
+export const TLN_QUERY_PARAM: string = 'query';
+/**
+ * Param for quant query params, type: complex.
+ **/
+export const TLN_QUANT_QUERY_PARAM: string = 'quantQuery';
+/**
+ * Param for result index, type: number.
+ **/
+export const TLN_QUANT_RESULT_INDEX_PARAM: string = 'quantResultIndex';
+/**
+ * Param for result index, type: number.
+ **/
+export const TLN_RESULT_INDEX_PARAM: string = 'resultIndex';
+/**
+ * Param for search query params, type: complex.
+ **/
+export const TLN_SEARCH_QUERY_PARAM: string = 'searchQuery';
/**
* 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 multi instance zoom (i.e. tln-crossref and tln-fulltext).
**/
export const TLN_MULTI_INSTANCE_ZOOM_PARAM: string = 'multiInstanceZoom';
/**
* Param for zoom in tln-viewer.
**/
export const TLN_ZOOM_PARAM: string = 'zoom';
diff --git a/nietzsche-beta-app/src/app/tln-edition/data_handler.ts b/nietzsche-beta-app/src/app/tln-edition/data_handler.ts
index b3a5a6c..16bd4cc 100644
--- a/nietzsche-beta-app/src/app/tln-edition/data_handler.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/data_handler.ts
@@ -1,163 +1,203 @@
import { OnInit, EventEmitter} from '@angular/core';
import { first, takeUntil } from 'rxjs/operators';
-import { BasicResultBindingElement, AskResult} from './datatypes/basic_datatype';
-import { DataProcessor, TlnQueryServiceInterface } from './models';
+import { BasicResultBindingElement, FusekiResults, AskResult} from './datatypes/basic_datatype';
+import { DataProcessor, StorageHandler, TlnQueryServiceInterface } from './models';
export interface KeyIriMapping {
key: string;
iri: string;
}
export interface ComplexKeyIriMapping {
idIndex: number;
mapping: KeyIriMapping[];
}
/**
* This interface can be used in order to handle data
* of type {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}.
**/
export interface Handler {
/**
* a class that instantiates data of type {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}
**/
handler: typeof BasicResultBindingElement;
/**
* data handler's next key for retrieving and instantiating data.
**/
next_key?: string;
/**
* a service that informs its listeners about its handler's data.
**/
service?: any;
process_data?: DataProcessor;
+ storage_handler?: StorageHandler;
}
/**
* This class retrieves data from a query service and instantiates it using
* corresponding handlers.
**/
export class DataHandler {
+ dataTimestamp: number = 0;
/**
* the query services with which data is retrieved
**/
queryService: TlnQueryServiceInterface;
debug: boolean = false;
/**
* whether or not DataHandler is ready to retrieve data
**/
ready: boolean = false;
stop_processing = new EventEmitter();
start_processing = new EventEmitter();
processing_finished = new EventEmitter();
/**
* @param component the component that uses this data handler
**/
- constructor(private component: OnInit){}
+ constructor(protected component: OnInit){}
/**
* add a {@link /interfaces/Handler.html|Handler}
* or an Array of handler keys to DataHandler.
**/
public addHandler(key: string, handler: Handler | string[]) {
this[key] = handler;
}
+ private processData(results: FusekiResults, handler: typeof BasicResultBindingElement, key: string, is_target_array: boolean, iri?: string, next_iri?: string){
+ if (is_target_array){
+ this.processArrayData(results, handler, key, iri, next_iri)
+ } else {
+ this.processObjectData(results, handler, key, iri, next_iri)
+ }
+ }
+ private processArrayData(results: FusekiResults, handler: typeof BasicResultBindingElement, key: string, iri?: string, next_iri?: string){
+ this.component[key] = (handler.use_id) ? handler.convertData(results, iri, this[key]['service']) : handler.convertData(results,null, this[key]['service']);
+ this.processing_finished.emit(true);
+ if (this.component[key].length > 0 && this[key]['next_key'] != null){
+ let use_next_iri = (next_iri != null) ? next_iri : this.component[key][0].id;
+ this.getData(this[key]['next_key'], use_next_iri);
+ } else if(this[key]['process_data'] != undefined && this[key]['process_data'] != null){
+ this[key]['process_data'].processData();
+ }
+ }
+ private processObjectData(results: FusekiResults, handler: typeof BasicResultBindingElement, key: string, iri?: string, next_iri?: string){
+ this.component[key] = handler.convertData(results, iri, this[key]['service'])[0];
+ this.processing_finished.emit(true);
+ if (next_iri != null && this[key]['next_key'] != null){
+ this.getData(this[key]['next_key'], next_iri);
+ } else if(this[key]['process_data'] != undefined && this[key]['process_data'] != null){
+ this[key]['process_data'].processData();
+ }
+ }
/**
* Retrieve and instantiate data
* @param key data handler key
* @param iri iri that should be passed to query
* @param next_iri use next_iri instead of the iri of the first item in the current data array.
**/
public getData(key: string, iri?: string, next_iri?: string) {
if (Array.isArray(this[key])){
this[key].forEach(value =>this.getData(value, iri));
if (next_iri != null && this[key]['next_key'] != null){
this.getData(this[key]['next_key'], next_iri);
}
} else {
this.start_processing.emit(true);
- let handler = this[key]['handler'];
+ const handler = this[key]['handler'];
if (this.debug && key == 'geneticOrders' ) {
//console.log(this[key]['handler'], key, iri);
console.log(handler.getQuery(iri, handler.query_key))
//console.log(this[key]['service']);
}
- let is_target_array = Array.isArray(this.component[key]);
- if (!is_target_array){
+ const is_target_array = Array.isArray(this.component[key]);
+ const query = handler.getQuery(iri, handler.query_key)
+ const queryKey = encodeURI(query).replace('+', '');
+ const results = null//this.retrieveLocalData(queryKey);
+ if (results != null) {
+ this.processData(results, handler, key, is_target_array, iri, next_iri);
+ } else {
this.queryService.getData(handler.getQuery(iri, handler.query_key)).pipe(takeUntil(this.stop_processing) || first()).subscribe(results => {
- this.component[key] = handler.convertData(results, iri, this[key]['service'])[0];
- if (next_iri != null && this[key]['next_key'] != null){
- this.getData(this[key]['next_key'], next_iri);
- } else if(this[key]['process_data'] != undefined && this[key]['process_data'] != null){
- this[key]['process_data'].processData();
- }
+ //this.storeDataLocally(results, queryKey);
+ this.processData(results, handler, key, is_target_array, iri, next_iri);
});
- } else {
- this.queryService.getData(handler.getQuery(iri, handler.query_key)).pipe(takeUntil(this.stop_processing)).subscribe(results => {
- this.component[key] = (handler.use_id) ? handler.convertData(results, iri, this[key]['service']) : handler.convertData(results,null, this[key]['service']);
- if (this.component[key].length > 0 && this[key]['next_key'] != null){
- let use_next_iri = (next_iri != null) ? next_iri : this.component[key][0].id;
- this.getData(this[key]['next_key'], use_next_iri);
- } else if(this[key]['process_data'] != undefined && this[key]['process_data'] != null){
- this[key]['process_data'].processData();
- }
- });
- }
- this.processing_finished.emit(true);
+ }
}
}
public getData4Keys(key: string, datatypeKeyIriMapping: ComplexKeyIriMapping) {
if (Array.isArray(this[key])){
this[key].forEach(value =>this.getData4Keys(value, datatypeKeyIriMapping));
} else {
let handler = this[key]['handler'];
if (this.debug) {
console.log(this[key]['handler'], datatypeKeyIriMapping);
}
let is_target_array = Array.isArray(this.component[key]);
let iri = datatypeKeyIriMapping.mapping[datatypeKeyIriMapping.idIndex];
if (!is_target_array){
this.queryService.getData(handler.getComplexQuery(datatypeKeyIriMapping.mapping)).pipe(takeUntil(this.stop_processing) || first()).subscribe(results => {
this.component[key] = handler.convertData(results, iri, this[key]['service'])[0];
});
} else {
this.queryService.getData(handler.getQuery(datatypeKeyIriMapping.mapping)).pipe(takeUntil(this.stop_processing)).subscribe(results => {
this.component[key] = (handler.use_id) ? handler.convertData(results, iri) : handler.convertData(results);
if (this.component[key].length > 0 && this[key]['next_key'] != null){
datatypeKeyIriMapping.mapping[datatypeKeyIriMapping.idIndex] = this.component[key][0].id;
this.getData4Keys(this[key]['next_key'], datatypeKeyIriMapping);
}
});
}
}
}
public getDataWithNewHandlerIf(key: string, subjectIri: string, typeIri: string, handlerTrue: Handler, handlerFalse: Handler, iri?: string, next_iri?: string) {
let complexMapping: KeyIriMapping[] = [ { key: 'id', iri: subjectIri }, { key: 'type', iri: typeIri } ]
this.queryService.getData(AskResult.getComplexQuery(complexMapping)).pipe(first()).subscribe(result => {
this[key] = (AskResult.getAnswer(result)) ? handlerTrue : handlerFalse;
console.log(key, subjectIri, typeIri, result, this[key]);
this.getData(key, iri, next_iri);
});
}
public conditionalAddHandler(askQuery: string, key: string, handlerTrue: Handler, handlerFalse: Handler) {
this.queryService.getData(askQuery).pipe(first()).subscribe(result => {
this[key] = (AskResult.getAnswer(result)) ? handlerTrue : handlerFalse;
});
}
-
+ protected retrieveLocalData(queryKey: string): FusekiResults {
+ const rawData = sessionStorage.getItem(queryKey)
+ if (rawData != null){
+ const data = JSON.parse(rawData);
+ if (data.timestamp > this.dataTimestamp){
+ return data.results;
+ }
+ }
+ return null;
+ }
+ protected storeDataLocally(results: FusekiResults, queryKey: string){
+ const data = { timestamp: Date.now(), results: results };
+ try {
+ sessionStorage.setItem(queryKey, JSON.stringify(data));
+ console.log(sessionStorage.length);
+ } catch(e){
+ console.log(e);
+ sessionStorage.clear();
+ }
+ }
/**
* reset all data belonging to key
**/
public resetData(key){
this.queryService.resetData(key)
if (Array.isArray(this[key])){
this[key].forEach(value =>this.resetData(value));
} else {
this.component[key] = (Array.isArray(this.component[key])) ? [] : null;
}
}
/**
* set a query service to DataHandler and switch status ready to true.
**/
public setQueryService(queryService: TlnQueryServiceInterface){
this.queryService = queryService;
this.ready = true;
+ this.queryService.error_emitter.subscribe(
+ error =>{this.processing_finished.emit(true);
+ });
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/basic_datatype.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/basic_datatype.ts
index 19f16cc..07e8a91 100644
--- a/nietzsche-beta-app/src/app/tln-edition/datatypes/basic_datatype.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/basic_datatype.ts
@@ -1,218 +1,239 @@
import { Parser, Generator } from 'sparqljs';
import { KeyIriMapping } from '../data_handler';
/**
* this interface specifies the head of {@link /interfaces/FusekiResults.html|FusekiResults}.
**/
interface FusekiVars {
vars: string[];
}
/**
* this interface specifies the bindings of {@link /interfaces/FusekiResults.html|FusekiResults}.
**/
-interface FusekiBindings {
+export interface FusekiBindings {
bindings: [];
}
/**
* this interface specifies the results as they are retrieved from an Apache Jena Fuseki server.
**/
export interface FusekiResults {
results: FusekiBindings;
head: FusekiVars
}
export interface FusekiBoolean {
head: any;
boolean: boolean;
}
+export class FusekiResultsInstance {
+ public static fixFusekiResults(fusekiResults: FusekiResults){
+ if (fusekiResults.results.bindings.length > 0
+ && Object.keys(Array.of(...fusekiResults.results.bindings)[0]).length < fusekiResults.head.vars.length) {
+ fusekiResults.head.vars = fusekiResults.head.vars.filter(key => Object.keys(Array.of(...fusekiResults.results.bindings)[0]).includes(key));
+ }
+ }
+}
/**
* This is the basic datatype that instantiates an element of {@link /interfaces/FusekiResults.html|FusekiResults}.
*
* All datatypes can be subclassed from this type in order to create SPARQL-queries, retrieve data and convert it
* to the corresponding datatypes.
**/
export class BasicResultBindingElement {
/**
* the internal default key for replacing {@link /classes/BasicResultBindingElement.html#query|query} by "id"
* in {@link /classes/BasicResultBindingElement.html#getQuery|getQuery} if "key" is omitted.
**/
protected static readonly default_key: string = 'id';
/**
* the SPARQL-query of this datatype.
**/
static readonly query: string = `SELECT ?id ?p ?o WHERE { ?id ?p ?o. }`;
/**
* the public key for replacing {@link /classes/BasicResultBindingElement.html#query|query} by "id".
**/
public static readonly query_key: string = null;
/**
* the id of this datatype.
**/
public id: string;
/**
* the raw data of this datatype, i.e. a singular bindings element of {@link /interfaces/FusekiBindings.html|FusekiBindings}.
**/
protected data: any;
/**
* whether or not to pass the id used for the query to the constructor and
* use it as the value of the property specified by query_key.
**/
public static readonly use_id: boolean = false;
/**
* a service that this datatype can use in order to communicate with its data holder.
**/
protected service: any;
/**
* 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){
this.data = data;
this.service = service;
if (id != undefined && id != null && id != ''){
let key = (Object.getPrototypeOf(this).constructor.use_id
&& Object.getPrototypeOf(this).constructor.query_key != null)
? Object.getPrototypeOf(this).constructor.query_key : 'id';
this[key] = id;
}
if (this.id == null){
this.id = this.getData4Key('id');
}
}
/**
* This function returns the value of the content specified by "key" from {@link /classes/BasicResultBindingElement.html#data|data}.
*
* @param key the key that specifies the content
*
* @returns {any} the value of the content if key exists else null
**/
protected getData4Key(key: string): any {
if (!this.data.hasOwnProperty(key)) {
return null;
}
if (this.data[key].datatype == 'http://www.w3.org/2001/XMLSchema#boolean'){
return JSON.parse(this.data[key].value);
} else if (this.data[key].datatype == 'http://www.w3.org/2001/XMLSchema#integer'){
return Number(this.data[key].value);
}
return this.data[key].value;
}
+ public removeService(){
+ this.service = null;
+ }
/**
* This method returns the SPARQL query of this BasicResultBindingElement.
* The query can be modified by providing an "id" and "key" such that every "key" in
* the query will be replaced by "id".
*
* If "key" is omitted {@link /classes/BasicResultBindingElement.html#default_key|default_key} will be used.
*
* @param id will replace key in query
* @param key will be replaced by id.
**/
public static getQuery(id?: string, key?: string): string {
if (typeof(id) === 'undefined' || id === null || id == ''){
return this.query;
} else {
if (key == null || key == ''){
key = this.default_key;
}
let parser = new Parser();
let sparqlGenerator = new Generator({});
let parsedQuery = parser.parse(this.query)
for (var k = 0; k < parsedQuery.where.length; k++){
if (parsedQuery.where[k].patterns != undefined){
for (var j = 0; j < parsedQuery.where[k].patterns.length; j++){
if (parsedQuery.where[k].patterns[j].triples != undefined) {
for (var i = 0; i < parsedQuery.where[k].patterns[j].triples.length; i++){
if(parsedQuery.where[k].patterns[j].triples[i]['subject']['value'] == key){
parsedQuery.where[k].patterns[j].triples[i]['subject'] = { termType: "NamedNode", value: id };
} else if(parsedQuery.where[k].patterns[j].triples[i]['object']['value'] == key){
parsedQuery.where[k].patterns[j].triples[i]['object'] = { termType: "NamedNode", value: id };
} else if(parsedQuery.where[k].patterns[j].triples[i]['predicate']['value'] == key){
parsedQuery.where[k].patterns[j].triples[i]['predicate'] = { termType: "NamedNode", value: id };
}
}
}
}
} else if (parsedQuery.where[k].triples != undefined){
for (var i = 0; i < parsedQuery.where[k].triples.length; i++){
if(parsedQuery.where[k].triples[i]['subject']['value'] == key){
parsedQuery.where[k].triples[i]['subject'] = { termType: "NamedNode", value: id };
} else if (parsedQuery.where[k].triples[i]['object']['value'] == key){
parsedQuery.where[k].triples[i]['object'] = { termType: "NamedNode", value: id };
} else if (parsedQuery.where[k].triples[i]['predicate']['value'] == key){
parsedQuery.where[k].triples[i]['predicate'] = { termType: "NamedNode", value: id };
}
}
}
}
return sparqlGenerator.stringify(parsedQuery);
}
}
+ public static contentConforms2Type(data: FusekiResults): boolean {
+ let parser = new Parser();
+ let parsedQuery = parser.parse(this.query)
+ let variableCounter = parsedQuery['variables'].length;
+ parsedQuery['variables'].forEach(item =>{
+ if(data.head.vars.includes(item.value)){
+ variableCounter--;
+ }
+ });
+ return variableCounter == 0;
+ }
public static getComplexQuery(keyIriMapping: KeyIriMapping[]): string {
let parser = new Parser();
let sparqlGenerator = new Generator({});
let parsedQuery = parser.parse(this.query)
for (let mapping of keyIriMapping){
let key = mapping.key;
let id = mapping.iri;
for (var i = 0; i < parsedQuery.where[0].triples.length; i++){
if(parsedQuery.where[0].triples[i]['subject']['value'] == key){
parsedQuery.where[0].triples[i]['subject'] = { termType: "NamedNode", value: id };
} else if (parsedQuery.where[0].triples[i]['object']['value'] == key){
parsedQuery.where[0].triples[i]['object'] = { termType: "NamedNode", value: id };
} else if (parsedQuery.where[0].triples[i]['predicate']['value'] == key){
parsedQuery.where[0].triples[i]['predicate'] = { termType: "NamedNode", value: id };
}
}
}
return sparqlGenerator.stringify(parsedQuery);
}
-
/**
* This function returns 'results.bindings' of {@link /interfaces/FusekiResults.html|FusekiResults}.
**/
public static getContent(data: FusekiResults): [] {
return data['results']['bindings'];
}
/**
* This static function instantiates the subclasses of {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement} from
* the data retrieved by executing the query that is provided by {@link /classes/BasicResultBindingElement.html#getQuery|getQuery}.
*
* @param this a subclass of BasicResultBindingElement
* @param data the fuseki result json
* @param id the id that has been used in order to retrieve the data and that will identify the instantiation of the subclass.
* @param service a means to communicate with the data holder.
*
* @returns Array of subclass instantiations
**/
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 this(content[i], id, service) as InstanceType;
elements.push(element);
}
return elements;
}
}
export class AskResult extends BasicResultBindingElement {
static readonly query: string = `
PREFIX tln:
ASK {
?id a ?type.
}`;
public static getAnswer(answer: FusekiBoolean): boolean {
return answer.boolean;
}
}
export class IsReconstructedKonvolut extends AskResult {
static readonly query: string = `
PREFIX tln:
ASK {
?id a tln:ReconstructedKonvolut.
}`;
public static readonly query_key: string = 'id';
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/earlier_version.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/earlier_version.ts
index 8a27dd7..cd8a220 100644
--- a/nietzsche-beta-app/src/app/tln-edition/datatypes/earlier_version.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/earlier_version.ts
@@ -1,54 +1,31 @@
import { BasicResultBindingElement } from './basic_datatype';
+import { WordStub } from './word';
/**
* This is the 'earlier version' stub instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}.
- * It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}.
**/
-export class TlnEarlierVersionStub extends BasicResultBindingElement {
- /**
- * the internal default key for replacing {@link /classes/TlnWord.html#query|query} by "id"
- * in {@link /classes/TlnWord.html#getQuery|getQuery} if "key" is omitted.
- **/
- static readonly default_key: string = 'word';
- /**
- * the public key for replacing {@link /classes/TlnWord.html#query|query} by "id".
- **/
- static readonly query_key: string = 'word';
+export class TlnEarlierVersionStub extends WordStub {
/**
* the SPARQL-query of this datatype.
**/
static readonly query: string = `
PREFIX tln:
PREFIX rdf:
SELECT ?id ?text WHERE {
?word tln:wordHasEarlierVersion ?id.
?id tln:hasText ?text.
}`;
- /**
- * text of earlier version
- **/
- text: string;
-
- /**
- * 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');
- }
}
export class TlnOverwrittenStub extends TlnEarlierVersionStub {
/**
* the SPARQL-query of this datatype.
**/
static readonly query: string = `
PREFIX tln:
PREFIX rdf:
SELECT ?id ?text WHERE {
?word (tln:wordHasWordParts/rdf:rest*/rdf:first/tln:overwritesWord|tln:overwritesWord) ?id.
?id tln:hasText ?text.
}`;
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/manuscript.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/manuscript.ts
index 9f78a48..b883ebc 100644
--- a/nietzsche-beta-app/src/app/tln-edition/datatypes/manuscript.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/manuscript.ts
@@ -1,237 +1,307 @@
import { BasicResultBindingElement, FusekiResults } from './basic_datatype';
import { Manuscript, Page } from '../models';
import { TlnPositionalStyleMarkup } from './positional-markup';
import { PageStub, TlnPage } from './page';
export class ManuscriptStub extends BasicResultBindingElement implements Manuscript {
static readonly query: string = `
PREFIX data:
PREFIX tln:
SELECT ?id ?title ?type WHERE {
?id a tln:ArchivalManuscriptUnity ;
tln:hasTitle ?title;
tln:hasManuscriptType ?type.
}`;
title: string;
type: string;
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.title = this.getData4Key('title');
this.type = this.getData4Key('type');
}
}
export class TlnExtManuscript extends ManuscriptStub {
/**
* the internal default key for replacing {@link /classes/TlnLine.html#query|query} by "id"
* in {@link /classes/TlnLine.html#getQuery|getQuery} if "key" is omitted.
**/
static readonly default_key: string = 'manuscript';
static readonly query: string = `
PREFIX data:
PREFIX tln:
PREFIX rdf:
PREFIX stoff:
SELECT DISTINCT ?gsaSignature ?title ?thumbImage ?type ?archivalicSignature WHERE {
?manuscript tln:hasPages/rdf:first/tln:hasFaksimileImage/tln:hasThumburl ?thumbImage;
tln:hasGsaSignature ?gsaSignature;
tln:hasTitle ?title;
tln:hasManuscriptType ?type.
OPTIONAL {
?manuscript tln:hasArchivalicSignature ?archivalicSignature.
}
}`;
/**
* the public key for replacing {@link /classes/TlnLine.html#query|query} by "id".
**/
static readonly query_key: string = 'manuscript';
thumbImage: string;
gsaSignature?: string;
archivalicSignature?: string;
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.thumbImage = this.getData4Key('thumbImage');
this.gsaSignature = this.getData4Key('gsaSignature');
this.archivalicSignature = this.getData4Key('archivalicSignature');
}
}
+export class Manuscript4Selection extends ManuscriptStub {
+ static readonly query: string = `
+ PREFIX data:
+ PREFIX tln:
+ PREFIX rdf:
+ PREFIX stoff:
+
+ SELECT DISTINCT ?id ?title ?type WHERE {
+ ?id a tln:ArchivalManuscriptUnity;
+ tln:hasTitle ?title;
+ tln:hasManuscriptType ?type.
+ FILTER (?type = "Mappe")
+ }`;
+}
+export class ManuscriptPages extends ManuscriptStub {
+ /**
+ * the internal default key for replacing {@link /classes/TlnLine.html#query|query} by "id"
+ * in {@link /classes/TlnLine.html#getQuery|getQuery} if "key" is omitted.
+ **/
+ static readonly default_key: string = 'id';
+ static readonly query: string = `
+ PREFIX data:
+ PREFIX tln:
+ PREFIX rdf:
+ PREFIX stoff:
+
+ SELECT DISTINCT ?id ?title ?type ?page ?number WHERE {
+ ?id a tln:ArchivalManuscriptUnity;
+ tln:hasTitle ?title;
+ tln:hasManuscriptType ?type;
+ tln:hasPages/rdf:rest*/rdf:first ?page.
+ ?page tln:hasNumber ?number.
+ FILTER (?type = "Mappe")
+ }`;
+ /**
+ * the public key for replacing {@link /classes/TlnLine.html#query|query} by "id".
+ **/
+ static readonly query_key: string = 'id';
+ pages: Page[] = [];
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ }
+ 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 ManuscriptPages(content[i], id, service);
+ let pages = [];
+ if (content[i]['page'] != undefined && content[i]['page'] != null){
+ pages = (content[i]['title'] != undefined && content[i]['title'] != null)
+ ? TlnPage.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['page']['value'])
+ : PageStub.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['page']['value']);
+ }
+ if (elements.length > 0 && elements[elements.length-1].id == element.id){
+ if (pages.length > 0){
+ elements[elements.length-1].pages.push(pages[0]);
+ }
+ } else {
+ if (pages.length > 0){
+ element.pages.push(pages[0]);
+ }
+ elements.push(element)
+ }
+ }
+ //console.log(elements)
+ return elements;
+ }
+
+}
export class ReconstructedKonvolut extends ManuscriptStub {
/**
* the internal default key for replacing {@link /classes/TlnLine.html#query|query} by "id"
* in {@link /classes/TlnLine.html#getQuery|getQuery} if "key" is omitted.
**/
static readonly default_key: string = 'manuscript';
static readonly query: string = `
PREFIX data:
PREFIX tln:
PREFIX rdf:
PREFIX stoff:
SELECT DISTINCT ?id ?manuscriptTitle ?title ?type ?page ?number ?description WHERE {
?manuscript tln:partsBelongToReconstructedKonvolut ?id.
?id tln:hasTitle ?manuscriptTitle;
tln:hasDescription/tln:textHasContent ?description;
tln:hasManuscriptType ?type;
tln:hasPages/rdf:rest*/rdf:first ?page.
OPTIONAL { ?page tln:hasNumber ?number.}
OPTIONAL {
?archivalicUnity a tln:ArchivalManuscriptUnity;
tln:hasPages/rdf:rest*/rdf:first ?page;
tln:hasTitle ?title.
}
}`;
/**
* the public key for replacing {@link /classes/TlnLine.html#query|query} by "id".
**/
static readonly query_key: string = 'manuscript';
pages: Page[] = [];
description: string;
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.title = this.getData4Key('manuscriptTitle');
this.description = this.getData4Key('description');
}
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 ReconstructedKonvolut(content[i], id, service);
let pages = [];
if (content[i]['page'] != undefined && content[i]['page'] != null){
pages = (content[i]['title'] != undefined && content[i]['title'] != null)
? TlnPage.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['page']['value'])
: PageStub.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['page']['value']);
}
if (elements.length > 0 && elements[elements.length-1].id == element.id){
if (pages.length > 0){
elements[elements.length-1].pages.push(pages[0]);
}
} else {
if (pages.length > 0){
element.pages.push(pages[0]);
}
elements.push(element)
}
}
//console.log(elements)
return elements;
}
}
export class ManuscriptDescription extends BasicResultBindingElement {
/**
* the internal default key for replacing {@link /classes/TlnLine.html#query|query} by "id"
* in {@link /classes/TlnLine.html#getQuery|getQuery} if "key" is omitted.
**/
static readonly default_key: string = 'manuscript';
static readonly query: string = `
PREFIX data:
PREFIX tln:
PREFIX rdf:
PREFIX stoff:
SELECT DISTINCT ?id ?text ?description_markup ?sStyle ?start ?end WHERE {
?manuscript tln:hasDescription ?id.
?id tln:textHasContent ?text.
OPTIONAL { ?id tln:textHasMarkup ?description_markup.
?description_markup stoff:hasCSS ?sStyle;
stoff:standoffMarkupHasStartIndex ?start;
stoff:standoffMarkupHasEndIndex ?end.}
}`;
/**
* the public key for replacing {@link /classes/TlnLine.html#query|query} by "id".
**/
static readonly query_key: string = 'manuscript';
text: string;
markups: TlnPositionalStyleMarkup[];
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.text = this.getData4Key('text');
this.markups = [];
}
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 ManuscriptDescription(content[i], id, service);
let markups = (content[i]['description_markup'] != undefined && content[i]['description_markup'] != null) ?
TlnPositionalStyleMarkup.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['description_markup']['value']) : [];
if (elements.length > 0 && elements[elements.length-1].id == element.id){
if (markups.length > 0){
elements[elements.length-1].markups.push(markups[0]);
}
} else {
if (markups.length > 0){
element.markups.push(markups[0]);
}
elements.push(element)
}
}
//console.log(elements)
return elements;
}
}
export class ManuscriptEarlierDescription extends BasicResultBindingElement {
/**
* the internal default key for replacing {@link /classes/TlnLine.html#query|query} by "id"
* in {@link /classes/TlnLine.html#getQuery|getQuery} if "key" is omitted.
**/
static readonly default_key: string = 'manuscript';
static readonly query: string = `
PREFIX data:
PREFIX tln:
PREFIX stoff:
SELECT ?id ?text ?author ?citation ?description_markup ?sStyle ?start ?end WHERE {
?manuscript tln:hasEarlierDescriptions ?id.
?id tln:textHasContent ?text;
tln:hasAuthor ?author;
tln:hasCitation ?citation.
OPTIONAL { ?id tln:textHasMarkup ?description_markup.
?description_markup stoff:hasCSS ?sStyle;
stoff:standoffMarkupHasStartIndex ?start;
stoff:standoffMarkupHasEndIndex ?end.}
}`;
/**
* the public key for replacing {@link /classes/TlnLine.html#query|query} by "id".
**/
static readonly query_key: string = 'manuscript';
text: string;
author: string;
citation: string;
markups: TlnPositionalStyleMarkup[];
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.text = this.getData4Key('text');
this.author = this.getData4Key('author');
this.citation = this.getData4Key('citation');
this.markups = [];
}
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 ManuscriptEarlierDescription(content[i], id, service);
let markups = (content[i]['description_markup'] != undefined && content[i]['description_markup'] != null) ?
TlnPositionalStyleMarkup.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['description_markup']['value']) : [];
if (elements.length > 0 && elements[elements.length-1].id == element.id){
if (markups.length > 0){
elements[elements.length-1].markups.push(markups[0]);
}
} else {
if (markups.length > 0){
element.markups.push(markups[0]);
}
elements.push(element)
}
}
//console.log(elements)
return elements;
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/quant.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/quant.ts
new file mode 100644
index 0000000..aebb29a
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/quant.ts
@@ -0,0 +1,251 @@
+import { Parser, Generator } from 'sparqljs';
+import { BasicResultBindingElement, FusekiResults} from './basic_datatype';
+import { ManuscriptPages } from './manuscript';
+import { TextQuality } from '../models';
+
+
+export class QueryJson {
+ public static createFilterObject(filters: Object[] ): Object{
+ let filterObject = { type: "filter", expression: null };
+ if (filters.length > 1){
+ filterObject.expression = { type: "operation", operator: "||", args: [] }
+ let filter = filters.pop()
+ this.pushFilter2Args(filters, filterObject.expression.args, filter);
+ } else {
+ filterObject.expression = filters[0];
+ }
+ return filterObject;
+ }
+ public static createOperation(id: string, variable_name: string): Object {
+ return { type: "operation", operator: "=", args: [
+ { termType: "Variable", value: variable_name},
+ { termType: "NamedNode", value: id }
+ ]};
+ }
+ private static pushFilter2Args(filters: Object[], args: Object[], latestFilter: Object){
+ if (filters.length > 1){
+ let filter = filters.pop();
+ let disjunction = { type: "operation", operator: "||", args: [] }
+ disjunction.args.push(filter);
+ disjunction.args.push(latestFilter);
+ this.pushFilter2Args(filters, args, disjunction);
+ } else {
+ args.push(latestFilter);
+ args.push(filters.pop());
+ }
+ }
+ public static hasSyntaxError(query: string): boolean {
+ const parser = new Parser();
+ try {
+ const parsedQuery = parser.parse(query);
+ } catch(e){
+ return true;
+ }
+ return false;
+ }
+ public static getSyntaxError(query: string): string {
+ const parser = new Parser();
+ try {
+ const parsedQuery = parser.parse(query);
+ } catch(e){
+ return String(e);
+ }
+ return '';
+ }
+
+}
+export class NumericResultRow extends BasicResultBindingElement {
+ static readonly hasText = "http://www.nie.org/ontology/nietzsche#hasText";
+ static readonly hasCleanText = "http://www.nie.org/ontology/nietzsche#hasCleanText";
+ static readonly hasEditedText = "http://www.nie.org/ontology/nietzsche#hasEditedText";
+ static readonly hasCleanEditedText = "http://www.nie.org/ontology/nietzsche#hasCleanEditedText";
+ static readonly manuscript_variable = "manuscript";
+ static readonly text_variable = "id";
+ static readonly raw_text_variable = "raw_text";
+ static readonly edited_text_variable = "edited_text";
+ static readonly word_variable = "word";
+ static readonly bindObject = { type: "bind", variable: { termType: "Variable", value: NumericResultRow.text_variable },
+ expression: { type: "operation", operator: "if", args: [
+ { type: "operation", operator: "bound", args: [ { termType: "Variable", value: NumericResultRow.edited_text_variable } ] },
+ { termType: "Variable", value: NumericResultRow.edited_text_variable },
+ { termType: "Variable", value: NumericResultRow.raw_text_variable },
+ ]}
+ };
+ static readonly orderObject = { expression: { termType: "Variable", value: NumericResultRow.text_variable }, descending: false };
+ static readonly punctuationPattern = /[.,!;:\-_–()“„]/g
+ static readonly query: string = `
+ PREFIX tln:
+ PREFIX rdf:
+
+ SELECT ?id ?word ?numText ?total WHERE {
+ ?manuscript a tln:ArchivalManuscriptUnity;
+ tln:hasManuscriptType "Mappe";
+ tln:hasPages/rdf:rest*/rdf:first ?page.
+ ?page a tln:Page;
+ tln:hasWords/rdf:rest*/rdf:first ?word.
+ }`;
+ wordIds: string[] = [];
+ numText: number;
+ numProperties: number = 1;
+ numPropertiesPercent: number = 1;
+ numPropertiesIncludeMulti: number = 1;
+ numTextPercent: number = 1;
+ numPropertyTextPercent: number = 1;
+ total: number;
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ this.numText = this.getData4Key('numText');
+ this.total = this.getData4Key('total');
+ this.wordIds.push(this.getData4Key('word'));
+ this.updatePercentages();
+ }
+ public updateResult(item: NumericResultRow) {
+ this.wordIds = this.wordIds.concat(item.wordIds);
+ this.numPropertiesIncludeMulti = this.wordIds.length
+ this.numProperties = (new Set(this.wordIds)).size;
+ this.updatePercentages();
+ }
+ private updatePercentages(){
+ this.numPropertiesPercent = Math.round((this.numProperties/this.total)*10000)/100;
+ this.numTextPercent = Math.round((this.numText/this.total)*10000)/100;
+ this.numPropertyTextPercent = Math.round((this.numProperties/this.numText)*10000)/100;
+ }
+ public static convertData(this: T, data: FusekiResults, id?: string, service?: any): Array> {
+ if (!this.contentConforms2Type(data)){
+ return [];
+ }
+ let elements = [];
+ let content = this.getContent(data);
+ for (var i = 0; i < content.length; i++){
+ let element = new NumericResultRow(content[i], service);
+ if (elements.length > 0 && elements[elements.length-1].id == element.id){
+ elements[elements.length-1].updateResult(element);
+ } else {
+ elements.push(element)
+ }
+ }
+ //console.log(elements)
+ return elements;
+ }
+ private static createGroup(whereItems: Object[], aggregate_variable: string, group?: string): Object {
+ if (group != undefined && group != null) {
+ return {
+ type: "group",
+ patterns: [
+ { queryType: "SELECT",
+ variables: [
+ { expression: { type: "aggregate", aggregation: "count", distinct: false, expression: { termType: "Variable", value: group }},
+ variable: { termType: "Variable", value: aggregate_variable } },
+ { termType: "Variable", value: group }
+ ],
+ where: whereItems,
+ type: "query",
+ group: [ { expression: { termType: "Variable", value: group }} ]
+ } ]
+ };
+ } else {
+ return {
+ type: "group",
+ patterns: [
+ { queryType: "SELECT",
+ variables: [
+ { expression: { type: "aggregate", aggregation: "count", distinct: false, expression: { termType: "Variable", value: this.word_variable }},
+ variable: { termType: "Variable", value: aggregate_variable } }
+ ],
+ where: [{ type: "bgp", triples: whereItems }],
+ type: "query"
+ } ]
+ };
+ }
+ }
+ private static hasTextObject(textQuality: TextQuality): Object {
+ const hasText = (textQuality.clean) ? NumericResultRow.hasCleanText : NumericResultRow.hasText;
+ const objectVariable = (textQuality.preferEditedText) ? NumericResultRow.raw_text_variable : NumericResultRow.text_variable;
+ return {
+ subject: { termType: "Variable", value: NumericResultRow.word_variable },
+ predicate: { termType: "NamedNode", value: hasText },
+ object: { termType: "Variable", value: objectVariable }
+ };
+ }
+ private static optionalEditedTextObject(textQuality: TextQuality): Object {
+ const hasEditedText = (textQuality.clean) ? NumericResultRow.hasCleanEditedText : NumericResultRow.hasEditedText;
+ return { type: "optional", patterns: [ { type: "bgp", triples: [ {
+ subject: { termType: "Variable", value: NumericResultRow.word_variable },
+ predicate: { termType: "NamedNode", value: hasEditedText },
+ object: { termType: "Variable", value: NumericResultRow.edited_text_variable }
+ } ] } ]
+ };
+ }
+ private static insertTextConditions(parsedQuery: Object, textQuality: TextQuality){
+ parsedQuery['where'][0].triples.push(this.hasTextObject(textQuality));
+ if(textQuality.preferEditedText){
+ parsedQuery['where'].push(this.optionalEditedTextObject(textQuality));
+ parsedQuery['where'].push(this.bindObject);
+ }
+ }
+ public static getSelectableQuery(selectableProperties: SelectableWordProperty[], scopus: ManuscriptPages[], textQuality: TextQuality, text?: string, ignoreCase?: boolean, orderDesc?: boolean): string {
+ let parser = new Parser();
+ let sparqlGenerator = new Generator({});
+ let parsedQuery = parser.parse(this.query)
+ let basicWhereTriples = parsedQuery.where[0].triples.slice();
+ this.insertTextConditions(parsedQuery, textQuality);
+ const whereBeforeProperties = JSON.parse(JSON.stringify(parsedQuery.where));//deep cloning
+ selectableProperties.forEach(selectableProperty =>{
+ parsedQuery.where[0].triples.push({
+ subject: { termType: "Variable", value: this.word_variable },
+ predicate: { termType: "NamedNode", value: selectableProperty.id },
+ object: { termType: "Variable", value: selectableProperty.id.substring(selectableProperty.id.indexOf('#')+1) }
+ })
+ });
+ if (text != undefined && text != null && text != '') {
+ let regexFilter = { type: "filter", expression: {
+ type: "operation", operator: "regex", args: [
+ { termType: "Variable", value: this.text_variable },
+ { termType: "Literal", value: text }
+ ]
+ }
+ }
+ if (ignoreCase != undefined && ignoreCase){
+ regexFilter.expression.args.push({ termType: "Literal", value: "i" });
+ }
+ parsedQuery.where.push(regexFilter);
+ }
+ let totalGroup = this.createGroup(basicWhereTriples, "total");
+ let numGroup = this.createGroup(whereBeforeProperties, "numText", this.text_variable);
+ if (scopus.length > 0){
+ let filters = scopus.map(manuscript =>QueryJson.createOperation(manuscript.id, this.manuscript_variable));
+ let filterObject = QueryJson.createFilterObject(filters);
+ parsedQuery.where.push(filterObject);
+ totalGroup['patterns'][0].where.push(filterObject);
+ numGroup['patterns'][0].where.push(filterObject);
+ }
+ parsedQuery.where.push(totalGroup);
+ parsedQuery.where.push(numGroup);
+ parsedQuery['order'] = [ this.orderObject ]
+ return sparqlGenerator.stringify(parsedQuery);
+ }
+}
+
+export class SelectableWordProperty extends BasicResultBindingElement{
+ static readonly query: string = `
+ PREFIX tln:
+ PREFIX rdfs:
+ PREFIX skos:
+
+ SELECT DISTINCT ?id ?label ?propName WHERE {
+ ?id rdfs:subPropertyOf tln:selectableWordProperty;
+ skos:prefLabel ?label.
+ #BIND(STRAFTER(STR(?id), STR(tln:)) as ?propName)
+ }`;
+ id: string;
+ label: string;
+ //propName: string;
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ this.id = this.getData4Key('id');
+ this.label = this.getData4Key('label');
+ //this.propName = this.getData4Key('propName');
+ }
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/search.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/search.ts
index 9210e46..82280e7 100644
--- a/nietzsche-beta-app/src/app/tln-edition/datatypes/search.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/search.ts
@@ -1,130 +1,132 @@
import { BasicResultBindingElement, FusekiResults} from './basic_datatype';
+import { TLN_SEARCH_ROUTE } from '../constants';
import { TlnWord } from './word';
export class TlnExtWord extends TlnWord {
startLine?: string;
endLine?: string;
constructor(data: any, id?: string, service?: any){
super(data, id, service)
this.startLine = this.getData4Key('startLine');
this.endLine = this.getData4Key('endLine');
}
}
export class PageResult {
words: TlnExtWord[] = [];
constructor(words: TlnExtWord[]){
this.words = words;
}
public getWords(): string[] {
return this.words.map(word =>word.id);
}
public getStartLine(): string {
let sortedWords = this.words.sort((word0, word1) =>word0.line_number - word1.line_number)
if (sortedWords.length == 0){
return '';
}
return (sortedWords[0].startLine != undefined && sortedWords[0].startLine != null) ? sortedWords[0].startLine : sortedWords[0].line;
}
public getEndLine(): string {
let sortedWords = this.words.sort((word0, word1) =>word0.line_number - word1.line_number)
if (sortedWords.length == 0){
return '';
}
return (sortedWords[sortedWords.length-1].endLine != undefined && sortedWords[sortedWords.length-1].endLine != null)
? sortedWords[sortedWords.length-1].endLine : sortedWords[sortedWords.length-1].line;
}
}
export class FoundPage extends BasicResultBindingElement{
+ static readonly storagePrefix = TLN_SEARCH_ROUTE + '_' + FoundPage.name
static readonly query: string = `
PREFIX tln:
PREFIX rdf:
SELECT DISTINCT ?id ?manuscript ?title ?number ?word ?text ?line ?line_number ?startLine ?endLine WHERE {
?id a tln:Page;
tln:hasNumber ?number;
tln:hasPseudoText ?fulltext.
FILTER regex(?fulltext, "#find#", "s").
?manuscript a tln:ArchivalManuscriptUnity;
tln:hasManuscriptType "Mappe";
tln:hasPages/rdf:rest*/rdf:first ?id;
tln:hasTitle ?title.
?id tln:hasWords/rdf:rest*/rdf:first ?word.
?word tln:hasOutputText ?text;
tln:wordBelongsToLine ?line.
?line tln:lineHasNumber ?line_number.
OPTIONAL{ ?previouseNode rdf:rest/rdf:first ?line;
rdf:first ?startLine.}
OPTIONAL{ ?myNode rdf:first ?line;
rdf:rest/rdf:first ?endLine.}
#FILTER().
} order by ?id ?line_number`;
title: string
number: string;
manuscript: string
results: PageResult[] = [];
constructor (data: any, id?: string, service?: any) {
super(data, id, service);
this.title = this.getData4Key('title');
this.number = this.getData4Key('number');
this.manuscript = this.getData4Key('manuscript');
}
public removeIncompleteResults(searchTerms: string[]) {
this.results = this.results.filter(result =>searchTerms.every(searchText =>result.words.filter(word =>word.text.match('^[^\w\s]*' + searchText + '.*')).length > 0))
}
/**
* This method returns the parametrized SPARQL query of this FoundPage
*
* If "key" is omitted {@link /classes/BasicResultBindingElement.html#default_key|default_key} will be used.
*
* @param find the search text
* @param key will be ignored.
**/
public static getQuery(find?: string, key?: string): string {
if(find == undefined || find == null){
return this.query;
}
let words = find.split(' ')
let find_regex = words.join('.*') + '.*'
let filter = 'FILTER regex(?text, "^[^\\\\w]?(' + words.join('.*|') + '.*)")';
let query = this.query.replace('#find#', find_regex).replace('#FILTER()', filter);
//console.log(query);
return query;
}
public static convertData(this: T, data: FusekiResults, id?: string, service?: any): Array> {
let elements = [];
let pages = [];
let searchTerms = service.getSearchTerms();
let content = this.getContent(data);
let currentResult: PageResult = null;
let currentPage: FoundPage = null;
for (var i = 0; i < content.length; i++){
let page = new FoundPage(content[i], id, service);
if(content[i]['word'] != undefined && content[i]['word'] != null) {
let words = TlnExtWord.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['word']['value']);
if (pages.length == 0 || pages.map(page =>page.id).indexOf(page.id) == -1){
currentResult = new PageResult(words);
currentPage = page;
currentPage.results.push(currentResult)
pages.push(currentPage)
} else {
if (currentResult.words.indexOf(words[0]) == -1){
if (currentResult.words.length > 0
&& (Math.abs(Math.min(...currentResult.words.map(word =>word.line_number)) - words[0].line_number) > 4
|| Math.abs(Math.max(...currentResult.words.map(word =>word.line_number)) - words[0].line_number) > 4)){
currentResult = new PageResult(words);
currentPage.results.push(currentResult);
} else {
currentResult.words.push(words[0]);
}
}
}
}
}
pages.forEach(page =>page.removeIncompleteResults(searchTerms));
return pages.filter(page =>page.results.length > 0);
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/word.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/word.ts
index 77d0247..2e8186f 100644
--- a/nietzsche-beta-app/src/app/tln-edition/datatypes/word.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/word.ts
@@ -1,98 +1,139 @@
+import { BasicResultBindingElement } from './basic_datatype';
import { TlnPositionalObject } from './positional_object';
import { Word } from '../models';
/**
* This is the word instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}.
* It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}.
**/
export class TlnWord extends TlnPositionalObject implements Word {
/**
* the SPARQL-query of this datatype.
**/
static readonly query: string = `
PREFIX tln:
PREFIX rdf:
SELECT ?id ?text ?edited_text ?left ?top ?width ?height ?transform ?line ?line_number ?deleted ?deletion_path WHERE {
?page tln:hasWords/rdf:rest*/rdf:first ?id.
?id tln:wordBelongsToLine ?line;
tln:hasText ?text;
tln:hasTranskriptionPosition ?tp.
?tp tln:hasLeft ?left; tln:hasTop ?top; tln:hasWidth ?width; tln:hasHeight ?height.
?line tln:lineHasNumber ?line_number.
BIND(exists{
{?id tln:wordIsDeletedByPath ?path}
UNION{ ?id tln:wordHasWordParts/rdf:rest*/rdf:first ?word_part.
?word_part tln:hasTranskriptionPosition ?tp; tln:wordIsDeletedByPath ?path}
} as ?deleted)
OPTIONAl { ?tp tln:hasTransform ?transform.}
OPTIONAl { ?id tln:hasEditedText ?edited_text.}
OPTIONAl { ?id tln:wordIsDeletedByPath/tln:hasDAttribute ?deletion_path.}
OPTIONAl { ?id tln:wordHasWordParts/rdf:rest*/rdf:first ?word_part.
?word_part tln:hasTranskriptionPosition ?tp; tln:wordIsDeletedByPath/tln:hasDAttribute ?deletion_path}
} `;
/**
* the text of this word
**/
text: string;
/**
* the text of this word as it has been edited by the editors.
**/
edited_text?: string;
/**
* the id of the line to which this word belongs.
**/
line: string;
/**
* 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;
/**
* 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.edited_text = this.getData4Key('edited_text');
this.line = this.getData4Key('line');
this.line_number = this.getData4Key('line_number');
this.deleted = this.getData4Key('deleted');
this.deletion_path = this.getData4Key('deletion_path');
}
}
/**
* This is the faksimile word instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}.
* It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}.
**/
export class FaksimileWord extends TlnWord {
/**
* the SPARQL-query of this datatype.
**/
static readonly query: string = `
PREFIX tln:
PREFIX rdf:
SELECT ?id ?text ?edited_text ?left ?top ?width ?height ?transform ?line ?line_number ?deleted WHERE {
?page tln:hasWords/rdf:rest*/rdf:first ?id.
?id tln:wordBelongsToLine ?line;
tln:hasText ?text;
tln:hasFaksimilePosition ?fp.
?fp tln:hasLeft ?left; tln:hasTop ?top; tln:hasWidth ?width; tln:hasHeight ?height.
?line tln:lineHasNumber ?line_number.
BIND(exists{{?id tln:wordIsDeletedByPath ?path} UNION { ?id tln:wordHasWordParts/rdf:rest*/rdf:first/tln:wordIsDeletedByPath ?path}
} as ?deleted)
OPTIONAl { ?fp tln:hasTransform ?transform.}
OPTIONAl { ?id tln:hasEditedText ?edited_text.}
} `;
}
+/**
+ * This is the word stub instantiation of an element of {@link /interfaces/FusekiResults.html|FusekiResults}.
+ * It extends {@link /classes/BasicResultBindingElement.html|BasicResultBindingElement}.
+ **/
+export class WordStub extends BasicResultBindingElement {
+ /**
+ * the internal default key for replacing {@link /classes/TlnWord.html#query|query} by "id"
+ * in {@link /classes/TlnWord.html#getQuery|getQuery} if "key" is omitted.
+ **/
+ static readonly default_key: string = 'word';
+ /**
+ * the public key for replacing {@link /classes/TlnWord.html#query|query} by "id".
+ **/
+ static readonly query_key: string = 'word';
+ /**
+ * the SPARQL-query of this datatype.
+ **/
+ static readonly query: string = `
+ PREFIX tln:
+ PREFIX rdf:
+
+ SELECT ?id ?text WHERE {
+ ?id a tln:Word;
+ tln:hasText ?text.
+ }`;
+ /**
+ * text of word
+ **/
+ text: string;
+
+ /**
+ * 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');
+ }
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/datatypes/word_presentation.ts b/nietzsche-beta-app/src/app/tln-edition/datatypes/word_presentation.ts
new file mode 100644
index 0000000..5357225
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/datatypes/word_presentation.ts
@@ -0,0 +1,82 @@
+import { Parser, Generator } from 'sparqljs';
+import { BasicResultBindingElement, FusekiResults} from './basic_datatype';
+import { ManuscriptStub } from './manuscript';
+import { PageStub } from './page';
+import { WordStub } from './word';
+import { QueryJson } from './quant';
+
+export class PresentationWord extends WordStub {
+ line_number: number;
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ this.line_number = this.getData4Key('line_number');
+ }
+}
+export class PageWords extends PageStub {
+ words: WordStub[] = [];
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ }
+}
+export class ManuscriptPageWords extends ManuscriptStub {
+ static readonly query_key: string = 'word';
+ static readonly default_key: string = 'word';
+ static readonly query: string = `
+ PREFIX tln:
+ PREFIX rdf:
+
+ SELECT ?id ?word ?title ?type ?page ?number ?text ?line_number WHERE {
+ ?word tln:hasText ?text;
+ tln:wordBelongsToLine/tln:lineHasNumber ?line_number.
+ ?page a tln:Page;
+ tln:hasWords/rdf:rest*/rdf:first ?word;
+ tln:hasNumber ?number.
+ ?id a tln:ArchivalManuscriptUnity;
+ tln:hasPages/rdf:rest*/rdf:first ?page;
+ tln:hasManuscriptType ?type;
+ tln:hasTitle ?title.
+ } ORDER BY ?id ?page`;
+ pages: PageWords[] = [];
+
+ constructor (data: any, id?: string, service?: any) {
+ super(data, id, service);
+ }
+ public static convertData(this: T, data: FusekiResults, id?: string, service?: any): Array> {
+ let manuscripts = [];
+ let content = this.getContent(data);
+ for (var i = 0; i < content.length; i++){
+ let manuscript = new ManuscriptPageWords(content[i], id, service);
+ let page = PageWords.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['page']['value'])[0]
+ let word = PresentationWord.convertData({ head: { vars: []}, results: { bindings: [ content[i] ] } }, content[i]['word']['value'])[0]
+ if (manuscripts.length > 0 && manuscript.id == manuscripts[manuscripts.length-1].id){
+ if (manuscripts[manuscripts.length-1].pages.length > 0
+ && page.id == manuscripts[manuscripts.length-1].pages[manuscripts[manuscripts.length-1].pages.length-1].id){
+ manuscripts[manuscripts.length-1].pages[manuscripts[manuscripts.length-1].pages.length-1].words.push(word);
+ } else {
+ if (manuscripts[manuscripts.length-1].pages.length > 0){
+ console.log(page)
+ }
+ page.words.push(word)
+ manuscripts[manuscripts.length-1].pages.push(page)
+ }
+ } else {
+ page.words.push(word)
+ manuscript.pages.push(page);
+ manuscripts.push(manuscript);
+ }
+ }
+ console.log(manuscripts);
+ return manuscripts;
+ }
+ public static getParameterizedQuery(wordIds: string[]): string {
+ let parser = new Parser();
+ let sparqlGenerator = new Generator({});
+ let parsedQuery = parser.parse(this.query)
+ let filters = wordIds.map(id =>QueryJson.createOperation(id, this.query_key));
+ let filterObject = QueryJson.createFilterObject(filters);
+ parsedQuery.where.push(filterObject);
+ return sparqlGenerator.stringify(parsedQuery);
+ }
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/models.ts b/nietzsche-beta-app/src/app/tln-edition/models.ts
index 8dbc037..8152adc 100644
--- a/nietzsche-beta-app/src/app/tln-edition/models.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/models.ts
@@ -1,64 +1,106 @@
import { Observable } from 'rxjs';
+import {HttpErrorResponse } from '@angular/common/http';
+import {Sort} from '@angular/material/sort';
import {EventEmitter} from '@angular/core';
import { Page } from '../page-view/models';
+import { Handler } from './data_handler';
+import { Manuscript4Selection} from './datatypes/manuscript';
+import { SelectableWordProperty} from './datatypes/quant';
export { externalAssignClass,
externalAssignStyle,
Configuration,
Continuation,
Copyright,
Identifier,
Image,
Line,
LineStub,
Reference,
Manuscript,
Page,
Point,
Position,
PositionalObject,
TextField,
TextByForeignHand,
Word,
USE_EXTERNAL_TOOLTIP } from '../page-view/models';
+export interface AccordionItemStatus {
+ expanded: boolean;
+ disabled: boolean;
+}
+export interface AccordionStatus {
+ [name: string]: AccordionItemStatus;
+}
export interface ManuscriptUnity {
numberOfPages: number;
title: string;
}
export interface NavigationPage extends Page {
title: string;
index?: number;
}
export interface TextVersion {
id: string;
title: string;
manuscript?: string;
textUnities: TextUnity[];
}
export interface TextUnity {
id: string;
number: string;
startLine?: number;
endLine?: number;
belongsToPage?: string;
hasFaksimileImage?: boolean;
}
/**
* This interface specifies a query service that returns
* the response from a HttpClient.post as an Observable.
* */
export interface TlnQueryServiceInterface {
- reset_data: EventEmitter;
+ error_emitter: EventEmitter;
/**
* @param query: The query to run.
* @returns response: the response as an Observable.
* */
getData(query: string): Observable;
resetData(key: string): void;
+ reset_data: EventEmitter;
+ baseUrl: string;
}
export interface TextGeneticOrder {
id: string;
textVersions: TextVersion[];
}
+export interface TextQuality {
+ clean: boolean;
+ preferEditedText: boolean;
+}
export interface DataProcessor {
processData(): void;
}
+export interface QueryProperties {
+ ignoreCase: boolean;
+ resultIndex?: number;
+ restrictKorpusOnContext: boolean;
+ selectedManuscripts: Manuscript4Selection[];
+}
+export interface QuantQuery extends QueryProperties {
+ altQuery?: string;
+ filterValue?: string;
+ selectedWordProperties: SelectableWordProperty[];
+ textQuality: TextQuality;
+ currentTable: number;
+ resultIndices: number[];
+ sortArray: Sort[];
+ text?: string;
+ dataKey?: string;
+}
+export interface StorageHandler {
+ getStorageKey(handler: Handler): string;
+ getStorageDuration(handler: Handler): number;
+}
+export interface PageIndexUpdater {
+ change: EventEmitter;
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/quant_data_handler.ts b/nietzsche-beta-app/src/app/tln-edition/quant_data_handler.ts
new file mode 100644
index 0000000..6e8deb7
--- /dev/null
+++ b/nietzsche-beta-app/src/app/tln-edition/quant_data_handler.ts
@@ -0,0 +1,36 @@
+import { OnInit, EventEmitter} from '@angular/core';
+import { first, takeUntil } from 'rxjs/operators';
+import { BasicResultBindingElement, AskResult} from './datatypes/basic_datatype';
+import { DataHandler, Handler } from './data_handler';
+
+/**
+ * This class retrieves quantitative data from a query service and instantiates it using
+ * corresponding handlers.
+ **/
+export class QuantitativeDataHandler extends DataHandler {
+ /**
+ * @param component the component that uses this data handler
+ **/
+ constructor(protected component: OnInit){
+ super(component)
+ }
+ /**
+ * Retrieve and instantiate data
+ * @param key data handler key
+ * @param query iri that should be passed to query
+ **/
+ public getData(key: string, query: string, raw_data_key?: string) {
+ this.start_processing.emit(true);
+ let handler = this[key]['handler'];
+ this.queryService.getData(query).pipe(takeUntil(this.stop_processing) || first()).subscribe(results => {
+ this.component[key] = handler.convertData(results);
+ if (raw_data_key != undefined && raw_data_key != null){
+ this.component[raw_data_key] = results;
+ }
+ this.processing_finished.emit(true);
+ if (this[key]['process_data'] != undefined && this[key]['process_data'] != null){
+ this[key]['process_data'].processData();
+ }
+ });
+ }
+}
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 c3b394f..482f5ee 100644
--- a/nietzsche-beta-app/src/app/tln-edition/route-reader.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/route-reader.ts
@@ -1,47 +1,51 @@
import { OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
export interface ParamContent {
param: string;
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)){
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 (this.mapping[key]['type'] == 'URI' || this.mapping[key]['type'] == 'URL'){
+ this[key] = decodeURI(this.routerParams[paramsKey])
+ } else if (this.mapping[key]['type'] == 'complex'){
+ this[key] = JSON.parse(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]);
}
}
}
}
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/route-updater.ts b/nietzsche-beta-app/src/app/tln-edition/route-updater.ts
index 569326c..df246ef 100644
--- a/nietzsche-beta-app/src/app/tln-edition/route-updater.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/route-updater.ts
@@ -1,56 +1,72 @@
import { Router, ActivatedRoute, Params } from '@angular/router';
import { Mapping, RouteReader } from './route-reader';
export class RouteUpdater extends RouteReader {
protected mapping: Mapping;
protected routerParams: Params;
protected currentRoute: string;
parentActivatedRoute: ActivatedRoute;
constructor(protected router: Router, protected activatedRoute: ActivatedRoute ) {
super(router, activatedRoute);
if(this.currentRoute == undefined || this.currentRoute == null){
this.currentRoute = (this.activatedRoute.snapshot.routeConfig != null)
? this.activatedRoute.snapshot.routeConfig.path : null;
}
}
+ public setParam(key: string, value: any){
+ if(this.mapping.hasOwnProperty(key)){
+ this[key] = value;
+ this.updateParams();
+ }
+ }
+ private removeData(dataBearer: any) {
+ if (typeof dataBearer != 'string' && typeof dataBearer != 'number' && typeof dataBearer != 'boolean'){
+ if (Array.isArray(dataBearer)){
+ dataBearer.forEach(data =>this.removeData(data));
+ } else {
+ dataBearer['data'] = null;
+ Object.values(dataBearer).forEach(item =>{
+ if (item != null){
+ this.removeData(item);
+ }
+ });
+ }
+ }
+ }
protected updateParams(launch?: boolean) {
let newRouterParam = {};
for(let key of Object.keys(this.mapping)){
let paramsKey = this.mapping[key]['param'];
if(this[key] != null){
- if (Array.isArray(this[key]) && this[key].length > 0){
+ if (this.mapping[key]['type'] == 'complex' || (Array.isArray(this[key]) && this[key].length > 0)){
+ this.removeData(this[key]);
newRouterParam[paramsKey] = JSON.stringify(this[key]);
+ } else if (this.mapping[key]['type'] == 'URI' || this.mapping[key]['type'] == 'URL') {
+ newRouterParam[paramsKey] = encodeURI(this[key]);
} else {
newRouterParam[paramsKey] = this[key];
}
}
}
- /*for(let key of Object.keys(this.routerParams)){
- if(newRouterParam[key] == null){
- newRouterParam[key] = this.routerParams[key];
- }
- }*/
let parentActivatedRoute = (this.activatedRoute.parent != null) ? this.activatedRoute.parent : this.parentActivatedRoute;
if(parentActivatedRoute != undefined && parentActivatedRoute != null){
parentActivatedRoute.url.subscribe(url=>{
let parentPath = url[0].path;
if (launch != undefined && launch){
- let link = this.router.createUrlTree([ parentPath + '/' + this.currentRoute], { queryParams: newRouterParam });
+ let link = this.router.createUrlTree([ parentPath + '/' + this.currentRoute], { queryParams: newRouterParam, queryParamsHandling: 'merge' });
window.open(link.toString(), '_blank')
} else {
- //this.router.navigate([ parentPath + '/' + this.currentRoute], { queryParams: newRouterParam });
this.router.navigate([parentPath + '/' + this.currentRoute], { queryParams: newRouterParam, queryParamsHandling: 'merge' });
}
});
} else {
if (launch != undefined && launch){
- let link = this.router.createUrlTree([ this.currentRoute], { queryParams: newRouterParam });
+ let link = this.router.createUrlTree([ this.currentRoute], { queryParams: newRouterParam, queryParamsHandling: 'merge' });
window.open(link.toString(), '_blank')
} else {
- //this.router.navigate([ this.currentRoute], { queryParams: newRouterParam });
this.router.navigate([this.currentRoute], { queryParams: newRouterParam, queryParamsHandling: 'merge' });
}
}
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/services.ts b/nietzsche-beta-app/src/app/tln-edition/services.ts
index 5cd2f3d..b614c15 100644
--- a/nietzsche-beta-app/src/app/tln-edition/services.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/services.ts
@@ -1,3 +1,4 @@
export { TlnQueryService } from './tln-query.service';
+export { TlnCacheQueryService } from './tln-query.service';
export { PageViewService } from '../page-view/page-view.service';
export { ConfigurableComponent } from '../page-view/configurable-component';
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/navigation/navigation.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/navigation/navigation.component.ts
index 358b874..a38728b 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/navigation/navigation.component.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/navigation/navigation.component.ts
@@ -1,107 +1,107 @@
import { Component, OnInit, Input } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { TlnQueryServiceInterface, Reference, ManuscriptUnity, NavigationPage } from '../../models';
import { TlnManuscriptUnity, TlnNavigationPage} from '../../datatypes/navigation';
import { DEFAULT_VIEW_OPTION, TLN_VIEWER_ROUTE, TLN_CROSSREF_ROUTE, TLN_CONTEXT_VIEW_PARAM, 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 { PageViewService, TlnCacheQueryService } from '../../services';
import { TlnInformationComponent, ParentInformation } from '../../tln-information/tln-information.component';
import { PageInformation } from '../../tln-information/page-information';
@Component({
selector: 'crossref-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.css']
})
export class NavigationComponent extends RouteUpdater {
/**
* 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;
current_iri: string;
current_manuscript_iri: string;
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 PAGE_CONTEXT_VIEW: string = TLN_PAGE_PARAM;
private readonly MANUSCRIPT_CONTEXT_VIEW: string = TLN_MANUSCRIPT_PARAM;
contextView: string = this.PAGE_CONTEXT_VIEW;
private readonly increment: number = 0.333;
private readonly decrement: number = this.increment*-1;
protected currentRoute: string = TLN_CROSSREF_ROUTE;
protected mapping: Mapping = {
contextView: { param: TLN_CONTEXT_VIEW_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" }
}
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 pageViewService: PageViewService, private localQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
+ constructor(private pageViewService: PageViewService, private localQueryService: TlnCacheQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
super(router, activatedRoute);
}
ngOnInit() {
let tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService;
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();
}
changeContext(){
this.contextView = (this.contextView == this.PAGE_CONTEXT_VIEW) ? this.MANUSCRIPT_CONTEXT_VIEW : this.PAGE_CONTEXT_VIEW;
//this.current_genetic_order_iri = 'none';
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;
}
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')
this.dataHandler.getData('navigation_page', this.current_iri);
}
}
private setCurrentIri(pageIri: string){
this.dataHandler.stop_processing.emit(true);
this.current_iri = pageIri;
this.currentRoute = TLN_VIEWER_ROUTE;
this.updateParams();
}
private toggleFullscreen(){
this.fullscreen = !this.fullscreen;
this.updateParams();
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/page-version-view/tln-page-version-view.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/page-version-view/tln-page-version-view.component.ts
index 429c8a4..a42fed8 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-crossref/page-version-view/tln-page-version-view.component.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-crossref/page-version-view/tln-page-version-view.component.ts
@@ -1,35 +1,35 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { TlnQueryServiceInterface} from '../../models';
-import { TlnQueryService } from '../../services';
+import { TlnCacheQueryService } from '../../services';
import { DataHandler } from '../../data_handler';
import { TlnTextGeneticOrder} from '../../datatypes/text_version';
@Component({
selector: 'tln-page-version-view',
templateUrl: './tln-page-version-view.component.html',
- providers: [ TlnQueryService ],
+ providers: [ TlnCacheQueryService],
styleUrls: ['./tln-page-version-view.component.css']
})
export class TlnPageVersionViewComponent implements OnInit {
/**
* OPTIONAL pass a queryService with method
* {@link /interfaces/TlnQueryServiceInterface.html#getData|getData}
* to TlnPageViewComponent.
**/
@Input() queryService: TlnQueryServiceInterface;
@Output() textGenesisSelected = new EventEmitter();
@Input() current_iri: string;
dataHandler: DataHandler = new DataHandler(this);
geneticOrders: TlnTextGeneticOrder[] = [];
- constructor(private localQueryService: TlnQueryService) { }
+ constructor(private localQueryService: TlnCacheQueryService) { }
ngOnInit() {
let tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService;
this.dataHandler.addHandler('geneticOrders', { 'handler': TlnTextGeneticOrder});
this.dataHandler.setQueryService(tlnQueryService);
this.dataHandler.getData('geneticOrders', this.current_iri);
}
}
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 4b4750d..508083c 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,223 +1,223 @@
import { Component, EventEmitter, OnInit, OnDestroy, Output, Input } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { DomSanitizer } from '@angular/platform-browser';
import { DataProcessor, TlnQueryServiceInterface, TextVersion, NavigationPage} from '../models';
import { TLN_CROSSREF_ROUTE, TLN_VIEWER_ROUTE, TLN_CONTEXT_VIEW_PARAM, TLN_FULLSCREEN_PARAM, 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 { TlnNavigationPage} from '../datatypes/navigation';
import { TlnLine} from '../datatypes/line';
import { TlnWord} from '../datatypes/word';
import { ManuscriptStub } from '../datatypes/manuscript';
import { TlnPageWithTextGeneticOrder, TlnTextGeneticOrder, 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 { PageViewService, TlnCacheQueryService } 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',
- providers: [ TlnQueryService ],
+ providers: [ TlnCacheQueryService],
styleUrls: ['./tln-crossref.component.css']
})
export class TlnCrossrefComponent extends RouteUpdater implements DataProcessor, OnDestroy {
/**
* OPTIONAL pass a queryService with method
* {@link /interfaces/TlnQueryServiceInterface.html#getData|getData}
* to TlnPageViewComponent.
**/
@Input() queryService: TlnQueryServiceInterface;
@Output() textGenesisSelected = new EventEmitter();
@Output() textVersionSelected = new EventEmitter();
@Output() textVersionUnselected = new EventEmitter();
tlnQueryService: TlnQueryServiceInterface;
private readonly PAGE_CONTEXT_VIEW: string = TLN_PAGE_PARAM;
private readonly MANUSCRIPT_CONTEXT_VIEW: string = TLN_MANUSCRIPT_PARAM;
zoomFactor: number = 1;
findText: string;
dataHandler: DataHandler = new DataHandler(this);
textVersions: TextVersion[] = [];
geneticOrders: TlnTextGeneticOrder[] = [];
contextView: string = this.PAGE_CONTEXT_VIEW;
current_genetic_order_iri: string;
current_manuscript_unity: string;
current_manuscript: ManuscriptStub;
current_iri: string;
current_page: NavigationPage;
fullscreen: boolean = false;
pagesWithGeneticOrder: TlnPageWithTextGeneticOrder[] = [];
max_width: number = -1;
max_height: number = -1;
next_page_iri: string;
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;
private readonly initialPreviewWidth : number = 400;
previewWidth: number = this.initialPreviewWidth;
//protected currentRoute: string = TLN_CROSSREF_ROUTE;
protected mapping: Mapping = { findText: { param: TLN_FIND_PARAM, type: "string" },
fullscreen: { param: TLN_FULLSCREEN_PARAM, type: "boolean" },
contextView: { param: TLN_CONTEXT_VIEW_PARAM, type: "string" },
current_iri: { param: TLN_PAGE_PARAM, type: "string" },
current_manuscript_unity: { param: TLN_MANUSCRIPT_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 ];
subscriptions: any[] = [];
- constructor(private pageViewService: PageViewService, private localQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
+ constructor(private pageViewService: PageViewService, private localQueryService: TlnCacheQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
super(router, activatedRoute);
}
ngOnInit() {
if (screen.availWidth - this.initialPreviewWidth - this.margin_width > 1000){
this.previewWidth = screen.availWidth - this.initialPreviewWidth - 1000;
}
this.max_width = screen.availWidth - this.previewWidth - this.margin_width;
this.max_height = screen.availHeight - 200;
this.tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService;
this.dataHandler.addHandler('page_content', ['current_page', 'geneticOrders'] );
this.dataHandler.addHandler('manuscript_content', ['current_manuscript', 'pagesWithGeneticOrder'] );
this.dataHandler.addHandler('current_manuscript', { 'handler': ManuscriptStub});
this.dataHandler.addHandler('current_page', { 'handler': TlnNavigationPage });
this.dataHandler.addHandler('geneticOrders', { 'handler': TlnTextGeneticOrder});
this.dataHandler.addHandler('pagesWithGeneticOrder', { 'handler': TlnPageWithTextGeneticOrder });
this.dataHandler.addHandler('textVersions', { 'handler': TlnStandaloneTextVersion, 'process_data': this });
this.dataHandler.setQueryService(this.tlnQueryService);
this.subscriptions.push(this.dataHandler.start_processing.subscribe(
(started: boolean) =>{ this.updating = true;
}));
this.subscriptions.push(this.dataHandler.processing_finished.subscribe(
(finished: boolean) =>{ this.updating = false;
}));
super.ngOnInit();
this.subscriptions.push(this.pageViewService.onClickedWord.subscribe(
(clickedWord: TlnWord) => {
this.addWordText2FindText(clickedWord)
}));
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
private addWordText2FindText(word: TlnWord){
let text = (word.edited_text != null && word.edited_text != '') ? word.edited_text : word.text;
if (this.findText == null || !this.findText.includes(text)){
this.findText = (this.findText == null || this.findText == '') ? text : this.findText + ' ' + text;
} else {
let index = this.findText.indexOf(text)
let startText = this.findText.substring(0, index)
let endText = (this.findText.length > index + text.length) ? this.findText.substring(index + text.length) : '';
let findText = startText + endText;
this.findText = findText.replace(' ', ' ').trim();
}
this.updateParams();
}
public processData(): void {
this.selectedTextVersions = [];
let index = 0;
while (index < this.textVersions.length && this.selectedTextVersions.length < 1){
if(this.textVersions[index].textUnities != undefined && this.textVersions[index].textUnities.length > 0){
this.selectedTextVersions.push(this.textVersions[index]);
}
index++
}
}
private addOrRemove(textVersion: TextVersion) {
let index = this.selectedTextVersions.indexOf(textVersion);
if (index == -1){
this.textVersionSelected.emit(textVersion.id);
this.selectedTextVersions.push(textVersion);
} else {
this.textVersionUnselected.emit(textVersion.id);
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';
}
private isNewPagePartOfOldTextVersions(): boolean {
if (this.current_manuscript_unity == undefined || this.current_manuscript_unity == null){
return false
}
for (let textVersion of this.textVersions){
if (textVersion.manuscript != undefined
&& textVersion.manuscript != null
&& textVersion.manuscript == this.current_manuscript_unity){
for (let textUnity of textVersion.textUnities){
if (textUnity.id == this.current_iri || textUnity.belongsToPage == this.current_iri){
console.log(textUnity.id, textUnity.belongsToPage, this.current_iri);
return true
}
}
}
}
return false
}
protected readParams(params: Params){
let old_genetic_order_iri = this.current_genetic_order_iri;
let old_current_iri = this.current_iri;
let old_manuscript_unity = this.current_manuscript_unity;
let old_context_view = this.contextView;
super.readParams(params);
if (this.dataHandler.ready){
if (old_current_iri != null
&& this.current_iri != old_current_iri && !this.isNewPagePartOfOldTextVersions()){
this.selectedTextVersions = [];
this.dataHandler.resetData('textVersions')
if (old_genetic_order_iri == this.current_genetic_order_iri){
this.current_genetic_order_iri = ''
this.updateParams()
}
}
if (this.contextView == this.PAGE_CONTEXT_VIEW
&& (this.contextView != old_context_view
|| (this.current_iri != null && this.current_iri != old_current_iri))){
this.dataHandler.resetData('page_content')
this.dataHandler.getData('page_content', this.current_iri);
}
if (this.current_manuscript_unity != old_manuscript_unity){
this.dataHandler.resetData('manuscript_content')
this.dataHandler.getData('manuscript_content', this.current_manuscript_unity);
}
if (this.contextView == this.PAGE_CONTEXT_VIEW
&& (this.contextView != old_context_view ||
(this.textVersions.length == 0 || this.current_genetic_order_iri != old_genetic_order_iri))){
this.dataHandler.resetData('textVersions')
if (this.current_genetic_order_iri != null && this.current_genetic_order_iri != ''){
this.dataHandler.getData('textVersions', this.current_genetic_order_iri);
}
}
}
}
private openInViewer(pageIri: string, belongsToPageIri?: string, manuscriptIri?: string, launch?: boolean){
this.current_iri = (belongsToPageIri != null) ? belongsToPageIri : pageIri;
if(manuscriptIri != null){
this.current_manuscript_unity = manuscriptIri;
}
this.currentRoute = TLN_VIEWER_ROUTE;
this.updateParams(launch);
}
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 892b383..65446ad 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,84 +1,103 @@
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 { MatSliderModule,MatProgressSpinnerModule,MatBottomSheetModule,MatButtonModule,MatCheckboxModule,MatDialogModule,MatExpansionModule,MatFormFieldModule,MatInputModule,MatListModule,MatPaginatorModule,MatRadioModule,MatSelectModule,MatSidenavModule,MatSortModule,MatTableModule,MatToolbarModule,MatButtonToggleModule,MatCardModule,MatIconModule,MatMenuModule,MatTabsModule,MatTooltipModule
+import { NgModule, ModuleWithProviders } from '@angular/core';
+import { MatBadgeModule, MatSnackBarModule, MatSlideToggleModule, MatTreeModule, MatSliderModule,MatProgressSpinnerModule,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 { CodemirrorModule } from '@ctrl/ngx-codemirror';
import { NgxMatStandoffMarkupModule} from "ngx-mat-standoff-markup";
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 { TlnQueryService, TlnCacheQueryService } 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';
import { NavigationComponent } from './tln-crossref/navigation/navigation.component';
import { GeneticOrderFilterPipe} from './tln-crossref/page-version-view/filter.pipe';
import { TlnPageVersionViewComponent } from './tln-crossref/page-version-view/tln-page-version-view.component';
import { TlnManuscriptViewComponent } from './tln-manuscript-view/tln-manuscript-view.component';
import { TlnFulltextComponent } from './tln-fulltext/tln-fulltext.component';
import { FulltextNavigationComponent } from './tln-fulltext/navigation/navigation.component';
import { ResultPipePipe } from './tln-fulltext/result-pipe.pipe';
+import { PageResultFilterPipe} from './common/page-result-filter.pipe';
import { SearchComponent } from './tln-navigation-elements/search.component';
import { ToggleNavigationComponent } from './tln-navigation-elements/toggle-navigation.component';
import { ZoomComponent } from './tln-navigation-elements/zoom.component';
import { ZoomPipe } from './tln-navigation-elements/zoom.pipe';
import { OpenInViewerComponent } from './tln-navigation-elements/open-in-viewer.component';
import { DebugPipe } from './debug.pipe';
import { TlnHeightDirective } from './tln-height.directive';
-import { PageResultFilterPipe } from './tln-fulltext/page-result-filter.pipe';
+import { TlnQuantComponent } from './tln-quant/tln-quant.component';
+import { TlnTableComponent } from './tln-quant/tln-table.component';
+import { ResultPipe } from './tln-quant/result.pipe';
+import { WordPresentationComponent } from './tln-quant/word-presentation.component';
+import { ToIdsPipe } from './tln-quant/2-ids.pipe';
+import { SortByLinePipe } from './tln-quant/sort-by-line.pipe';
+import { QueryErrorComponent } from './tln-quant/query-error.component';
+import { ExportComponent } from './tln-quant/export.component';
+import { FusekiTableComponent } from './tln-quant/fuseki-table.component';
@NgModule({
- declarations: [FulltextNavigationComponent, TlnPageViewComponent, ToolTipComponent, TlnViewerNavigation, TlnInformationComponent, TlnCrossrefComponent, VersionViewComponent, PageVersionViewComponent, NavigationComponent, GeneticOrderFilterPipe, TlnPageVersionViewComponent, TlnManuscriptViewComponent, TlnFulltextComponent, ResultPipePipe, SearchComponent, ToggleNavigationComponent, ZoomComponent, ZoomPipe, OpenInViewerComponent, DebugPipe, TlnHeightDirective, PageResultFilterPipe],
+ declarations: [FulltextNavigationComponent, TlnPageViewComponent, ToolTipComponent, TlnViewerNavigation, TlnInformationComponent, TlnCrossrefComponent, VersionViewComponent, PageVersionViewComponent, NavigationComponent, GeneticOrderFilterPipe, TlnPageVersionViewComponent, TlnManuscriptViewComponent, TlnFulltextComponent, PageResultFilterPipe, ResultPipePipe, SearchComponent, ToggleNavigationComponent, ZoomComponent, ZoomPipe, OpenInViewerComponent, DebugPipe, TlnHeightDirective, TlnQuantComponent, TlnTableComponent, ResultPipe, WordPresentationComponent, ToIdsPipe, SortByLinePipe, QueryErrorComponent, ExportComponent, FusekiTableComponent],
imports: [
+ CodemirrorModule,
+ MatBadgeModule,
+ MatSnackBarModule,
+ MatSlideToggleModule,
MatSliderModule,
MatBottomSheetModule,
MatButtonModule,
MatButtonToggleModule,
MatCardModule,
MatCheckboxModule,
MatDialogModule,
MatExpansionModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatProgressSpinnerModule,
MatPaginatorModule,
MatRadioModule,
MatSelectModule,
MatSidenavModule,
MatSortModule,
MatTableModule,
MatTabsModule,
+ MatTreeModule,
MatToolbarModule,
MatTooltipModule,
BrowserModule,
CommonModule,
FormsModule,
NgxMatStandoffMarkupModule,
PageViewModule
],
exports: [
DebugPipe,
FulltextNavigationComponent,
NavigationComponent,
+ ToggleNavigationComponent,
ToolTipComponent,
TlnCrossrefComponent,
TlnHeightDirective,
TlnManuscriptViewComponent,
TlnPageViewComponent,
- TlnViewerNavigation
+ TlnViewerNavigation,
+ TlnQuantComponent
],
providers: [
- PageViewService
+ PageViewService,
+ //TlnQueryService
],
- entryComponents: [TlnInformationComponent]
+ entryComponents: [TlnInformationComponent, QueryErrorComponent]
})
-export class TlnEditionModule { }
+export class TlnEditionModule {
+}
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.html b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.html
index 9907834..b319824 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.html
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.html
@@ -1,56 +1,56 @@
0" class="text" [style.left.px]="previewWidth+20" [style.width.px]="max_width+margin_width-25">
-
+
{{page.title}}, {{page.number}}
-
resultLength"
+ paginatorResultStatus.resultLength"
[length]="pages.length"
- [pageSize]="resultLength"
+ [pageSize]="paginatorResultStatus.resultLength"
[pageIndex]="resultIndex"
- (page)="showResults($event)">
+ (page)="paginatorResultStatus.showResults($event)">
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.ts
index 2776e04..a358459 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-fulltext/tln-fulltext.component.ts
@@ -1,110 +1,116 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import {PageEvent} from '@angular/material/paginator';
import { TLN_CROSSREF_ROUTE, TLN_SEARCH_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_VIEWER_ROUTE, TLN_CONTEXT_VIEW_PARAM, TLN_FULLSCREEN_PARAM, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_MANUSCRIPT_PARAM,
- TLN_RESULT_INDEX_PARAM,TLN_SELECTED_LINES_PARAM, TLN_TEXT_GENETIC_ORDER_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM, VIEW_OPTIONS, ONTOLOTY_PREFIX } from '../constants';
-import { DataHandler } from '../data_handler';
+ TLN_SEARCH_QUERY_PARAM, TLN_RESULT_INDEX_PARAM,TLN_SELECTED_LINES_PARAM, TLN_TEXT_GENETIC_ORDER_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM, VIEW_OPTIONS, ONTOLOTY_PREFIX } from '../constants';
+import { Handler, DataHandler } from '../data_handler';
import { FoundPage} from '../datatypes/search';
import { Mapping } from '../route-reader';
import { RouteUpdater } from '../route-updater';
-import { TlnQueryService } from '../services';
-import { ResultRange } from './page-result-filter.pipe';
+import { TlnCacheQueryService } from '../services';
+import { ResultRange, PaginatorResultStatus } from '../common/paginator-result-status';
+import { QueryProperties, StorageHandler, TlnQueryServiceInterface} from '../models';
//TODO: german language support for paginator, see: https://github.com/ngx-translate/core
@Component({
selector: 'tln-fulltext',
templateUrl: './tln-fulltext.component.html',
styleUrls: ['./tln-fulltext.component.css']
})
-export class TlnFulltextComponent extends RouteUpdater implements OnInit {
- protected currentRoute: string = TLN_SEARCH_ROUTE;
+export class TlnFulltextComponent extends RouteUpdater implements StorageHandler, OnInit {
+ /**
+ * OPTIONAL pass a queryService with method
+ * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData}
+ * to TlnPageViewComponent.
+ **/
+ @Input() queryService: TlnQueryServiceInterface;
+ tlnQueryService: TlnQueryServiceInterface;
+ //protected currentRoute: string = TLN_SEARCH_ROUTE;
current_page_iri: string;
current_manuscript_unity: string;
dataHandler: DataHandler = new DataHandler(this);
fullscreen: boolean;
max_width: number = -1;
max_height: number = -1;
searchTerm: string;
resultIndex: number = 0;
- resultLength: number = 5;
- resultRange: ResultRange = { start: 0, end: 4 };
+ paginatorResultStatus: PaginatorResultStatus = new PaginatorResultStatus(5);
resultsReceived: boolean = false;
selectedViewOption: string = VIEW_OPTIONS.TRANSKRIPTION
startSearch: boolean = false;
protected mapping: Mapping = {
current_page_iri: { param: TLN_PAGE_PARAM, type: "string" },
resultIndex: { param: TLN_RESULT_INDEX_PARAM, type: "number" },
searchTerm: { param: TLN_FIND_PARAM, type: "string" },
+ queryProps: { param: TLN_SEARCH_QUERY_PARAM, type: "complex" },
current_manuscript_unity: { param: TLN_MANUSCRIPT_PARAM, type: "string" },
fullscreen: { param: TLN_FULLSCREEN_PARAM, type: "boolean" },
}
pages: FoundPage[] = [];
+ queryProps: QueryProperties = { ignoreCase: false, selectedManuscripts: [], restrictKorpusOnContext: false }
private readonly margin_width: number = 280;
private readonly initialPreviewWidth : number = 300;
previewWidth: number = this.initialPreviewWidth;
- constructor(private tlnQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
+ constructor(private localQueryService: TlnCacheQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
super(router, activatedRoute);
}
ngOnInit() {
if (screen.availWidth - this.initialPreviewWidth - this.margin_width > 1000){
this.previewWidth = screen.availWidth - this.initialPreviewWidth - 1000;
}
+ this.tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService;
this.max_width = screen.availWidth - this.previewWidth - this.margin_width;
this.max_height = screen.availHeight - 200;
- this.dataHandler.addHandler('pages', { 'handler': FoundPage});
+ this.dataHandler.addHandler('pages', { 'handler': FoundPage, 'storage_handler': this });
this.dataHandler['pages']['service'] = this
this.dataHandler.setQueryService(this.tlnQueryService);
this.dataHandler.start_processing.subscribe(
(started: boolean) =>{
this.resultsReceived = false;
this.startSearch = true;
});
this.dataHandler.processing_finished.subscribe(
(finished: boolean) =>{
this.resultsReceived = true;
this.startSearch = false;
});
super.ngOnInit();
}
private clearFindText() {
this.searchTerm = '';
this.pages = [];
this.resultIndex = 0;
super.updateParams();
}
private search(){
this.resultIndex = 0;
- this.updateResultRange();
+ this.paginatorResultStatus.updateResultRange(this.resultIndex);
super.updateParams();
if (this.searchTerm != undefined && this.searchTerm != null && this.searchTerm != ''){
this.dataHandler.resetData('pages');
this.dataHandler.getData('pages', this.searchTerm);
}
}
- protected readParams(params: Params){
+ public getStorageDuration(handler: Handler): number {
+ return 28800000;
+ }
+ public getStorageKey(handler: Handler): string{
+ return TLN_SEARCH_ROUTE + '_' + handler.handler.name + '_' + this.searchTerm.replace(' ', '_');
+ }
+ protected readParams(params: Params){
let oldSearchTerm = this.searchTerm;
let oldResultIndex = this.resultIndex;
super.readParams(params);
if (this.searchTerm != undefined && this.searchTerm != null && this.searchTerm != '' && this.searchTerm != oldSearchTerm){
this.resultIndex = 0;
this.dataHandler.getData('pages', this.searchTerm);
}
- if(oldResultIndex != this.resultIndex){
- this.updateResultRange();
+ if(this.pages.length > 0 && this.resultIndex > 0 ){
+ this.paginatorResultStatus.updateResultRange(this.resultIndex);
}
}
getSearchTerms(): string[] {
return this.searchTerm.split(' ');
}
- showResults(event: PageEvent){
- this.resultIndex = event.pageIndex;
- this.updateResultRange();
- this.updateParams()
- }
- private updateResultRange(){
- let newStart = this.resultIndex*this.resultLength
- let newEnd = newStart+this.resultLength;
- this.resultRange = { start: newStart, end: newEnd };
- }
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-manuscript-view/tln-manuscript-view.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-manuscript-view/tln-manuscript-view.component.ts
index 0239414..cfc0a6e 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-manuscript-view/tln-manuscript-view.component.ts
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-manuscript-view/tln-manuscript-view.component.ts
@@ -1,69 +1,69 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_VIEWER_ROUTE, TLN_CONTEXT_VIEW_PARAM, TLN_FULLSCREEN_PARAM, 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 { DataHandler } from '../data_handler';
import { ReconstructedKonvolut, TlnExtManuscript, ManuscriptEarlierDescription, ManuscriptDescription } from '../datatypes/manuscript';
import { PageStub } from '../datatypes/page';
import { Mapping } from '../route-reader';
import { RouteUpdater } from '../route-updater';
-import { TlnQueryService } from '../services';
+import { TlnCacheQueryService } from '../services';
import { MarkupSettings, StandoffMarkup } from 'ngx-mat-standoff-markup';
@Component({
selector: 'tln-manuscript-view',
templateUrl: './tln-manuscript-view.component.html',
styleUrls: ['./tln-manuscript-view.component.css']
})
export class TlnManuscriptViewComponent extends RouteUpdater implements OnInit {
contextView: string = TLN_MANUSCRIPT_PARAM;
protected currentRoute: string = TLN_MANUSCRIPT_ROUTE;
current_manuscript: TlnExtManuscript;
current_manuscript_unity: string;
current_page_iri: string;
dataHandler: DataHandler = new DataHandler(this);
earlierDescriptions: ManuscriptEarlierDescription[] = [];
fullscreen: boolean;
manuscriptDescription?: ManuscriptDescription;
reconstructedKonvolut?: ReconstructedKonvolut;
protected mapping: Mapping = {
contextView: { param: TLN_CONTEXT_VIEW_PARAM, type: "string" },
current_page_iri: { param: TLN_PAGE_PARAM, type: "string" },
current_manuscript_unity: { param: TLN_MANUSCRIPT_PARAM, type: "string" },
fullscreen: { param: TLN_FULLSCREEN_PARAM, type: "boolean" },
}
mySettings: MarkupSettings = new MarkupSettings();
pages: PageStub[] = [];
- constructor(private tlnQueryService: TlnQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
+ constructor(private tlnQueryService: TlnCacheQueryService, protected router: Router, protected activatedRoute: ActivatedRoute ) {
super(router, activatedRoute);
}
ngOnInit() {
this.dataHandler.addHandler('manuscript_content', ['current_manuscript','manuscriptDescription', 'earlierDescriptions', 'pages', 'reconstructedKonvolut'] );
this.dataHandler.addHandler('current_manuscript', { 'handler': TlnExtManuscript });
this.dataHandler.addHandler('manuscriptDescription', { 'handler': ManuscriptDescription});
this.dataHandler.addHandler('earlierDescriptions', { 'handler': ManuscriptEarlierDescription});
this.dataHandler.addHandler('pages', { 'handler': PageStub });
this.dataHandler.addHandler('reconstructedKonvolut', { 'handler': ReconstructedKonvolut});
this.dataHandler.setQueryService(this.tlnQueryService);
super.ngOnInit();
}
protected readParams(params: Params){
let old_manuscript_unity = this.current_manuscript_unity;
super.readParams(params);
if (this.dataHandler.ready){
if (this.current_manuscript_unity != null && this.current_manuscript_unity != old_manuscript_unity){
this.dataHandler.resetData('manuscript_content')
this.dataHandler.getData('manuscript_content', this.current_manuscript_unity);
}
}
}
private openInViewer(pageIri: string, launch: boolean){
this.current_page_iri = pageIri;
this.currentRoute = TLN_VIEWER_ROUTE;
this.fullscreen = true;
this.updateParams(launch);
}
}
diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-navigation-elements/open-in-viewer.component.html b/nietzsche-beta-app/src/app/tln-edition/tln-navigation-elements/open-in-viewer.component.html
index 8d36d7f..25950f9 100644
--- a/nietzsche-beta-app/src/app/tln-edition/tln-navigation-elements/open-in-viewer.component.html
+++ b/nietzsche-beta-app/src/app/tln-edition/tln-navigation-elements/open-in-viewer.component.html
@@ -1,8 +1,5 @@
-
-