diff --git a/nietzsche-beta-app/src/app/app.module.ts b/nietzsche-beta-app/src/app/app.module.ts index 16f0bff..ce10b8d 100644 --- a/nietzsche-beta-app/src/app/app.module.ts +++ b/nietzsche-beta-app/src/app/app.module.ts @@ -1,74 +1,84 @@ 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 { CrossRefTreeComponentComponent } from './crossref-editor-component/tln-tree-component/tln-tree-component.component'; +import { CrossrefEditorComponentComponent } from './crossref-editor-component/crossref-editor-component.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, ManuscriptViewComponentComponent, ContentViewTabComponentComponent, RhizomeViewComponentComponent, MainMenuComponentComponent, PageViewWrapperComponent, NavigationListComponentComponent, NavTree, LazyImageLoadDirectiveDirective, ImpressumComponent, ProjectComponent, - NavigationlistListComponentComponent + NavigationlistListComponentComponent, + CrossRefTreeComponentComponent, + CrossrefEditorComponentComponent ], 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/constants.ts b/nietzsche-beta-app/src/app/constants.ts index 17e6191..3f2aaf1 100644 --- a/nietzsche-beta-app/src/app/constants.ts +++ b/nietzsche-beta-app/src/app/constants.ts @@ -1,52 +1,313 @@ import {NavTreeDef} from './models/models'; export const CONTENT_VIEW_ROUTE: string = 'contentView'; export const DOCUMENTATION_ROUTE: string = 'doku'; export const HOME_ROUTE: string = 'home'; export const IMPRESSUM_ROUTE: string = 'impressum'; export const PROJECT_ROUTE: string = 'project'; export const NAVTREE_DEFS: NavTreeDef[] = [ { id: 'manuscript', idx: 0, isActive: true, label: 'Manuskripte', itemQParam: 'manuscript', entries: [], apiDef: { type: 0, // rdf baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', dataArray: 'results.bindings', query: 'manuscripts.rq', mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed id: 'manuscript.value', // Short id, iri in most cases iri: 'manuscript.value', // iri type: 'type.value', label: 'title.value', description: 'gsaSignature.value', avatar: 'thumbImage.value' } } }, { id: 'page', idx: 1, isActive: false, label: 'Seiten', itemQParam: 'page', entries: [], apiDef: { type: 0, // rdf baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', dataArray: 'results.bindings', query: 'getPageData.rq', mapping: { id: 'page.value', // Short id, iri in most cases iri: 'page.value', // iri label: 'pageNumber.value', thumb: 'thumb.value', idx: 'pageNumber.value', svg: 'svgUrl.value', } } } ]; + + +// Queries +export const RQ_CROSSREF_TREE_MANUSCRIPTS: string = ` +PREFIX data: +PREFIX tln: +PREFIX rdf: +SELECT ?manuscript ?title ?thumbImage ?gsaSignature WHERE { + ?manuscript a tln:ManuscriptUnity; + tln:hasTitle ?title; + tln:hasManuscriptType "Mappe"; + tln:hasPages/rdf:first/tln:hasFaksimileImage/tln:hasThumburl ?thumbImage ; + tln:hasGsaSignature ?gsaSignature . +}`; + +export const RQ_CROSSREF_TREE_PAGES: string = ` +PREFIX tln: +PREFIX rdf: +PREFIX xsd: +SELECT DISTINCT ?page ?pageNumber ?image ?svgUrl ?primaryUrl ?thumb ?medium ?manuscript WHERE { + ?s (tln:hasPages/(rdf:rest*)/rdf:first) ?page. + ?page tln:hasNumber ?pageNumber. + BIND (xsd:integer(REPLACE(?pageNumber, "\\\\D+", "")) AS ?sorting) + # BIND (COALESCE(?sorting, 0) AS ?number2) + OPTIONAL { + ?page tln:hasSvgImage ?svg. + ?svg tln:hasPrimaryurl ?svgUrl. + ?page tln:hasFaksimileImage ?image. + ?image tln:hasFileName ?imgLabel; + tln:hasPrimaryurl ?primaryUrl; + tln:hasThumburl ?thumb; + tln:hasMediumurl ?medium. + } + } + ORDER BY (?sorting) +`; + +export const RQ_CROSSREF_TREE_LINES: string = ` +PREFIX tln: +PREFIX rdf: +PREFIX xsd: +SELECT DISTINCT ?line ?lNumber WHERE { + ?s (tln:hasLines/(rdf:rest*)/rdf:first) ?line. + # BIND (COALESCE(?sorting, 0) AS ?number2) + OPTIONAL { + ?line tln:lineHasNumber ?lNumber. + } + } + ORDER BY (?lNumber) +`; + +export const RQ_CROSSREF_TREE_WORDS: string = ` +PREFIX tln: +PREFIX rdf: +PREFIX xsd: +PREFIX homotypic: +SELECT DISTINCT ?word ?line ?text WHERE { + ?word tln:wordBelongsToLine ?line. + OPTIONAL { + ?word homotypic:hasText ?text. + } + } + ORDER BY (?word) +`; + + +export const CROSSREF_TREE_DEFS: NavTreeDef[] = [ + { id: 'manuscript', + idx: 0, + isActive: true, + label: 'Manuskript ', + itemQParam: 'manuscript', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_CROSSREF_TREE_MANUSCRIPTS, + mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed + id: 'manuscript.value', // Short id, iri in most cases + iri: 'manuscript.value', // iri + type: 'type.value', + label: 'title.value', + description: 'gsaSignature.value', + avatar: 'thumbImage.value' + } + } + }, { + id: 'page', + idx: 1, + isActive: false, + label: 'S. ', + itemQParam: 'page', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_CROSSREF_TREE_PAGES, + mapping: { + id: 'page.value', // Short id, iri in most cases + iri: 'page.value', // iri + label: 'pageNumber.value', + thumb: 'thumb.value', + idx: 'pageNumber.value', + svg: 'svgUrl.value', + } + } + }, { + id: 'line', + idx: 2, + isActive: false, + label: 'Zeile ', + itemQParam: '', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_CROSSREF_TREE_LINES, + mapping: { + id: 'line.value', // Short id, iri in most cases + iri: 'line.value', // iri + label: 'lNumber.value', + thumb: '', + idx: '', + svg: '', + } + } + }, { + id: 'word', + idx: 3, + isActive: false, + label: '', + itemQParam: '', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_CROSSREF_TREE_WORDS, + mapping: { + id: 'word.value', // Short id, iri in most cases + iri: 'word.value', // iri + label: 'text.value', + thumb: '', + idx: '', + svg: '', + }, + paramTriple: 2 + } + } +]; + +// GENERIC TREES + +// Queries +export const RQ_GENERIC_TREE_ROOT: string = ` +PREFIX data: +PREFIX tln: +PREFIX rdf: +SELECT DISTINCT ?manuscript ?title ?type ?gsaSignature WHERE { + ?manuscript a tln:ManuscriptUnity; + tln:hasTitle ?title; + tln:hasManuscriptType "Mappe"; + tln:hasGsaSignature ?gsaSignature . + OPTIONAL { + tln:ManuscriptUnity a ?type + } +}`; + +export const RQ_GENERIC_RDF_PROPERTY_TREE: string = ` +PREFIX rdfs: +SELECT DISTINCT ?p ?type ?label ?comment WHERE { + ?s ?p ?o. + OPTIONAL { + ?p rdfs:label ?label. + ?p rdfs:comment ?comment. + ?p a ?sth. + } + } + ORDER BY (?label) + LIMIT 10 + `; + +export const RQ_GENERIC_OBJECT_TREE: string = ` +PREFIX rdfs: +SELECT DISTINCT ?o ?type ?label ?comment WHERE { + ?s ?p ?o. + OPTIONAL { + ?o rdfs:label ?label. + ?o rdfs:comment ?comment. + ?o a ?sth. + } + } + ORDER BY (?label) + LIMIT 10 + `; + +export const GENERIC_ROOT_TREE_DEF: NavTreeDef[] = [ + { id: 'root', + idx: 0, + isActive: true, + label: 'Manuskript ', + itemQParam: 'manuscript', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_GENERIC_TREE_ROOT, + mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed + id: 'manuscript.value', // Short id, iri in most cases + iri: 'manuscript.value', // iri + type: 'type.value', + label: 'title.value', + description: 'gsaSignature.value' + } + } + }, + { id: 'property', + idx: 1, + isActive: true, + label: 'Property ', + itemQParam: '', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_GENERIC_RDF_PROPERTY_TREE, + mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed + id: 'p.value', // Short id, iri in most cases + iri: 'p.value', // iri + type: 'type.value', + label: 'label.value', + description: 'comment.value' + } + } + }, + { id: 'object', + idx: 1, + isActive: true, + label: 'Object ', + itemQParam: '', + entries: [], + apiDef: { + type: 0, // rdf + baseUrl: 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche',//'http://fuseki.nie-ine.ch/nietzsche-rw/query', + dataArray: 'results.bindings', + query: RQ_GENERIC_OBJECT_TREE, + mapping: { // maps the properties of the reponse to tha NavTabDef properties, which are displayed + id: 'o.value', // Short id, iri in most cases + iri: 'o.value', // iri + type: 'type.value', + label: 'label.value', + description: 'comment.value' + } + } + } +]; 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 d24b050..dd9f776 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,17 @@ 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 } from '../tln-edition/constants'; +import { 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 {CrossRefTreeComponentComponent} from '../crossref-editor-component/tln-tree-component/tln-tree-component.component'; +import {CrossrefEditorComponentComponent} from '../crossref-editor-component/crossref-editor-component.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_CROSSREF_EDITOR_ROUTE, component: CrossrefEditorComponentComponent}, { 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 0994134..2310d32 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,123 +1,132 @@ 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_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, TLN_VIEWER_ROUTE } from '../tln-edition/constants'; +import { + TLN_CROSSREF_EDITOR_ROUTE, TLN_CROSSREF_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_SEARCH_ROUTE, + TLN_VIEWER_ROUTE +} from '../tln-edition/constants'; @Component({ selector: 'app-content-view-tab-component', templateUrl: './content-view-tab-component.component.html', styleUrls: ['./content-view-tab-component.component.scss'], providers: [ NavigationServiceService ] }) export class ContentViewTabComponentComponent implements OnInit { // navigation tabs for the content view (manuscript view, page view, rhizome view) navTabLinks: any[]; // navbar on th left for navigating navBarOpenState = false; fullscreen = false; navBarOpenMode: string; queryParams: Params = {}; queryParamSubscription: Subscription; 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 }, { label: 'Seitenansicht', link: TLN_VIEWER_ROUTE, index: 1, isActive: false, context: 'page' // in which context the viewers are opened }, { label: 'Querverweise', link: TLN_CROSSREF_ROUTE, index: 2, isActive: false }, { label: 'Suche', link: TLN_SEARCH_ROUTE, index: 3, isActive: false }, + { + label: 'Querverweis-Editor', + link: TLN_CROSSREF_EDITOR_ROUTE, + index: 4, + isActive: 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/crossref-editor-component/crossref-editor-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.html new file mode 100644 index 0000000..1db56dc --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.html @@ -0,0 +1,8 @@ +
+
+ +
+
+ hier reinziehen bald ... +
+
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.scss b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.scss new file mode 100644 index 0000000..81b9135 --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.scss @@ -0,0 +1,13 @@ +.container { + display: table; +} + +.crossref-selector { + display: table-cell; + width: 50vw; +} + +.basket-container { + display: table-cell; + width: 50vw; +} diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.spec.ts b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.spec.ts new file mode 100644 index 0000000..ea6fd33 --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CrossrefEditorComponentComponent } from './crossref-editor-component.component'; + +describe('CrossrefEditorComponentComponent', () => { + let component: CrossrefEditorComponentComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CrossrefEditorComponentComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CrossrefEditorComponentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts new file mode 100644 index 0000000..e99ef18 --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import {NavTreeDef} from '../models/models'; +import {CROSSREF_TREE_DEFS, GENERIC_ROOT_TREE_DEF} from '../constants'; +import {NavigationServiceService} from '../services/navigation-service.service'; + +@Component({ + selector: 'app-crossref-editor-component', + templateUrl: './crossref-editor-component.component.html', + styleUrls: ['./crossref-editor-component.component.scss'] +}) +export class CrossrefEditorComponentComponent implements OnInit { + + constructor(private naviService: NavigationServiceService) { } + + ngOnInit() { + this.naviService.updateRoute({['navBarOpenState'] : false}); + this.treeDefs = CROSSREF_TREE_DEFS; + this.generic = false; + } + + treeDefs: NavTreeDef[] = []; + generic: boolean; +} diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.html new file mode 100644 index 0000000..f9b172c --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.html @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.scss b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.spec.ts b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.spec.ts new file mode 100644 index 0000000..c8c817b --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CrossRefTreeComponentComponent } from './tln-tree-component.component'; + +describe('RhizomeEditorComponentComponent', () => { + let component: CrossRefTreeComponentComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CrossRefTreeComponentComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CrossRefTreeComponentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.ts new file mode 100644 index 0000000..02fa6ed --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/tln-tree-component/tln-tree-component.component.ts @@ -0,0 +1,203 @@ +import {Component, Injectable, Input, OnInit} from '@angular/core'; +import {CollectionViewer, SelectionChange, DataSource} from '@angular/cdk/collections'; +import {FlatTreeControl} from '@angular/cdk/tree'; +import {BehaviorSubject, merge, Observable} from 'rxjs'; +import {map} from 'rxjs/operators'; +import {NavTreeDef} from '../../models/models'; +import {QueryService} from '../../services/query.service'; +import * as _ from 'lodash'; + + +/** Flat node with expandable and level information */ +export class TlnTreeNode { + constructor(public label: string, public iri: string, public level = 1, public expandable = false, + public isLoading = false, public type? ) { + } +} + +/** + * Database for dynamic data. When expanding a node in the tree, the data source will need to fetch + * the descendants data from the database. + */ +@Injectable({providedIn: 'root'}) +export class DynamicDatabase { + + constructor() { + } + +} +/** + * File database, it can build a tree structured Json object from string. + * Each node in Json object represents a file or a directory. For a file, it has filename and type. + * For a directory, it has filename and children (a list of files or directories). + * The input will be a json object string, and the output is a list of `FileNode` with nested + * structure. + */ +export class DynamicDataSource implements DataSource { + + + dataChange = new BehaviorSubject([]); + genericLevel: number = 0; + + get data(): TlnTreeNode[] { return this.dataChange.value; } + set data(value: TlnTreeNode[]) { + this._treeControl.dataNodes = value; + this.dataChange.next(value); + } + + constructor(private _treeControl: FlatTreeControl, + private _database: DynamicDatabase, private queryService: QueryService, private treeDefs: NavTreeDef[], private generic: boolean) { + } + + expandable(level: number) { + if (this.generic) {return true} else { + return level < this.treeDefs.length-1 + } + } + + connect(collectionViewer: CollectionViewer): Observable { + this._treeControl.expansionModel.changed.subscribe(change => { + if ((change as SelectionChange).added || + (change as SelectionChange).removed) { + this.handleTreeControl(change as SelectionChange); + } + }); + + return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data)); + } + + disconnect(collectionViewer: CollectionViewer): void {} + + /** Handle expand/collapse behaviors */ + handleTreeControl(change: SelectionChange) { + if (change.added) { + change.added.forEach(node => this.toggleNode(node, this.expandable(node.level))); + } + if (change.removed) { + change.removed.slice().reverse().forEach(node => this.toggleNode(node, false)); + } + } + + toggleNode(node: TlnTreeNode, expand: boolean) { + node.isLoading = true; + const index = this.data.indexOf(node); + if (expand) { + this.getChildData(node).then(children => { + if (!children || index < 0) { // If no children, or cannot find the node, no op + return; } + this.data.splice(index + 1, 0, ...children); + // notify the change + this.dataChange.next(this.data); + }); + } else { + let count = 0; + for (let i = index + 1; i < this.data.length + && this.data[i].level > node.level; i++, count++) {} + this.data.splice(index + 1, count); + // notify the change + this.dataChange.next(this.data); + } + node.isLoading = false; + } + + getChildData(node: TlnTreeNode): Promise { + console.log('getting children'); + if (this.generic) { + return this.getGenericChildren(node); + } else { + return this.getChildNodesFromDef(node); + } + } + + getParent(node: TlnTreeNode): TlnTreeNode { + if (node.level < 1) { + return null; + } + const index= this.data.indexOf(node); + for (let i = index; i >= 0; i--) { + const currentNode = this.data[i]; + if (currentNode.level < node.level) { + return currentNode; + } + } + } + + async getGenericChildren(node: TlnTreeNode){ + let treeDef: NavTreeDef; + const parentNode = this.getParent(node); + let query: string; + console.log('node ', node); + if (node.level % 2 === 0 || 0 ) { // Then we are querying for properties + treeDef = this.treeDefs[1]; // we want to get resources/ objects of that clicked prop + query = await this.queryService.parametrizeQueryWithItem(treeDef.apiDef.query, node.iri); + } else { // we want all objects of the s&p + console.log(this.data); + treeDef = this.treeDefs[2]; + query = await this.queryService.parametrizeQueryWithItem(treeDef.apiDef.query, parentNode.iri, node.iri); + } + return this.getData(query, treeDef, node.level+1); + } + + async getChildNodesFromDef(node: TlnTreeNode): Promise { + const treeDef = this.treeDefs.filter(def => def.idx === node.level+1 )[0]; + let query: string; + if (treeDef.apiDef.paramTriple && treeDef.apiDef.paramTriple === 2) { + query = await this.queryService.parametrizeQueryWithItem(treeDef.apiDef.query, '', '', node.iri); + } else { query = await this.queryService.parametrizeQueryWithItem(treeDef.apiDef.query, node.iri);} + + return this.getData(query, treeDef); + } + + async getData(query: string, treeDef: NavTreeDef, level?: number): Promise { + let nodes: TlnTreeNode[] = []; + await this.queryService.getData(treeDef.apiDef.baseUrl, query, 'SELECT').then(res => { + const treeData: any[] = _.get(res, treeDef.apiDef.dataArray); + treeData.forEach(entry => { + const tlnNode = new TlnTreeNode(_.get(entry, treeDef.apiDef.mapping.label), + _.get(entry, treeDef.apiDef.mapping.iri), level || + treeDef.idx, this.expandable(treeDef.idx), false, _.get(entry, treeDef.apiDef.mapping.type) ); + nodes.push(tlnNode); + }); + }); + return nodes; + } +} + +@Component({ + selector: 'app-tln-tree-component', + templateUrl: './tln-tree-component.component.html', + styleUrls: ['./tln-tree-component.component.scss'] +}) +export class CrossRefTreeComponentComponent implements OnInit { + + @Input() treeDefs: NavTreeDef[]; + @Input() generic: boolean; + + + ngOnInit() { + this.treeControl = new FlatTreeControl(this.getLevel, this.isExpandable); + this.dataSource = new DynamicDataSource(this.treeControl, this.database, this.queryService, this.treeDefs, this.generic); + this.initRootLevelNodes(); + } + + constructor(public database: DynamicDatabase, private queryService: QueryService) { + } + + initRootLevelNodes() { + const rootTreeDef = this.treeDefs.filter(def => def.idx === 0)[0]; + const query = rootTreeDef.apiDef.query; + this.dataSource.getData(query, rootTreeDef).then(rootNodes => this.dataSource.data = rootNodes); + } + + + treeControl: FlatTreeControl; + + dataSource: DynamicDataSource; + + getLevel = (node: TlnTreeNode) => node.level; + + isExpandable = (node: TlnTreeNode) => node.expandable; + + hasChild = (_: number, _nodeData: TlnTreeNode) => _nodeData.expandable; + +} diff --git a/nietzsche-beta-app/src/app/models/models.ts b/nietzsche-beta-app/src/app/models/models.ts index dbda35c..5609ec6 100644 --- a/nietzsche-beta-app/src/app/models/models.ts +++ b/nietzsche-beta-app/src/app/models/models.ts @@ -1,92 +1,94 @@ // class for Everything: extended by NavigationEntity, Manuscript, Page, Word with all common properties import {SafeUrl} from '@angular/platform-browser'; export class TlnEntity { id: string; // Short id, iri in most cases iri: string; // iri type: string; // rdfs:type contextView: string; label?: string; description?: string; constructor(id: string, iri: string, type: string, contextView: string, label?: string, description?: string) { this.id = id; this.iri = iri; this.type = type; this.contextView = contextView; this.label = label; this.description = description; } } // The navigation entries in each tree for each viewtab (TlnManuscript, TlnPage, PositionalEntity) used by navigation // export class NavigationEntity { idx: number; tlnEntity: TlnEntity; thumb?: SafeUrl; // url of image (Thumbnail) img?: SafeUrl; // full image url svg?: SafeUrl; // svg url avatar?: SafeUrl; // img for avatar constructor(idx: number, tlnEntity: TlnEntity, thumb?: string, img?, svg?: SafeUrl, avatar?: SafeUrl) { this.idx = idx; this.tlnEntity = tlnEntity; this.thumb = thumb; this.img = img; this.svg = svg; this.avatar = avatar; } } export interface NavTreeDef { - id: string; // name of the tree, also set as queryParam + id: string; // name of the tree idx: number; // order label: string; itemQParam: string; entries: NavigationEntity[]; description?: string; apiDef?: ApiDef; isActive?: boolean; } export class ApiDef { type: number; // 0 === sparql 1.1., 1 === nietzscheSource API, 2 === existDB baseUrl: string; dataArray: string; query?: string; mapping?: TlnEntityMapping; // positive Filter ids: only these id's should be loaded into manuscript nav tree + paramTriple?: number; // Select which triple of the where clause will be parametrized: 1 === property, 2 === object; default === subject - constructor( type: number, baseUrl: string, dataArray: string, query?: string, mapping?: TlnEntityMapping) { + constructor( type: number, baseUrl: string, dataArray: string, query?: string, mapping?: TlnEntityMapping, paramTriple?) { this.type = type; this.baseUrl = baseUrl; this.dataArray = dataArray; this.query = query; this.mapping = mapping; + this.paramTriple = paramTriple; } } export class TlnEntityMapping { // Is used for mapping the response from any given apiDef/response to a TlnEntity Instance id: string; // Short id, iri in most cases iri?: string; // iri idx?: string; type?: string; // rdfs:type label?: string; description?: string; avatar?: string; svg?: string; thumb?: string; constructor(id: string, iri?: string, idx?: string, type?: string, label?: string, description?: string, avatar?: string, svg?: string, thumb?: string) { this.id = id; this.iri = iri; this.idx = idx; this.type = type; this.label = label; this.description = description; this.avatar = avatar; this.svg = svg; this.thumb = thumb; } } diff --git a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts index f193700..3fb9d8f 100644 --- a/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts +++ b/nietzsche-beta-app/src/app/navigation-list-component/navigation-list-component.component.ts @@ -1,276 +1,275 @@ import {NAVTREE_DEFS} from '../constants'; import {Component, EventEmitter, OnInit} from '@angular/core'; import {NavigationServiceService} from '../services/navigation-service.service'; import {NavigationEntity, NavTreeDef, TlnEntity} from '../models/models'; import {Subscription} from 'rxjs/index'; -import {ActivatedRoute, ParamMap, Router} from '@angular/router'; +import {ActivatedRoute, ParamMap} from '@angular/router'; import {QueryService} from '../services/query.service'; import {NavTree} from './navtree-directive.directive'; import * as _ from 'lodash'; @Component({ selector: 'app-navigation-list-component', templateUrl: './navigation-list-component.component.html', styleUrls: ['./navigation-list-component.component.scss'] }) /** * NavigationListComponent * Builds/rebuilds the navigation trees for populating the navigationlist-list-component and reacts on changes in the url */ export class NavigationListComponentComponent implements OnInit { navigationTreeDefs: NavTreeDef[]; // The definitions for buildling the navTrees navTrees: NavTree[]; // The actual Navtrees which are displayed activeTree: NavTree; // the tree which is displayed in the list component navTabIndex: number; // the index of the active tree in navTrees navTabIndexChange: EventEmitter; oldQueryParams: ParamMap; queryParamSubscription: Subscription; constructor(public naviService: NavigationServiceService, - private router: Router, private activatedRoute: ActivatedRoute, private queryService: QueryService) { this.navigationTreeDefs = NAVTREE_DEFS; this.navTabIndexChange = new EventEmitter(); } ngOnInit() { this.oldQueryParams = this.activatedRoute.snapshot.queryParamMap; this.queryParamSubscription = this.activatedRoute.queryParamMap.subscribe((queryParams: ParamMap) => { this.reactOnNewQParams(queryParams); }); // The navTabIndex and the activeTree are set accordingly on the emitted tabIndex this.navTabIndexChange.subscribe(tabIdx => { if (tabIdx !== this.navTabIndex && tabIdx < this.navTrees.length && tabIdx >= 0) { this.navTabIndex = tabIdx; this.activeTree = this.navTrees[tabIdx]; } }); this.initNavTrees(); } // // INITIAL METHODS, CORE METHODS // async initNavTrees() { await this.createTreesOnInit(); await this.populateNavTrees(); await this.setActiveTreeOnInit(); this.subscribeToSetSelectedItems(); } createTreesOnInit() { this.navTrees = []; this.navigationTreeDefs.forEach(def => this.navTrees.push(new NavTree(def.id, def.idx, def.label, [], def.itemQParam, def.description, def.apiDef))); } /** * populateNavTrees creates the first trees if no query params are available in the url: * It ceates the manuscripNavTree and the activePageNavTreeData of the first manuscript per default. * */ async populateNavTrees(tabIdx?: number, item?: TlnEntity) { const tabStartIndex = tabIdx || 0; // where to start refreshing navtrees downward for (const treeDef of this.navigationTreeDefs.sort(def => (def.idx))) { if (treeDef.idx >= tabStartIndex) { // only create trees if needed - this.queryService.getQueryfromFilename(treeDef.apiDef.query).subscribe(async query => { + this.queryService.getQueryfromFilename(treeDef.apiDef.query).then(async query => { let queryToRun: string; // If there is a selectedItem we have to parametrize the query if (treeDef.idx > 0) { // so we have to parametrize the query if (item) { queryToRun = this.queryService.parametrizeQueryWithItem(query, item.id); this.populateNavTree(treeDef, queryToRun); } else { // wait for selected item of the previous tab and parametrize then the query this.navTrees[treeDef.idx - 1].selectedItemSet.subscribe(selItem => { if (selItem.tabId === treeDef.idx - 1) { queryToRun = this.queryService.parametrizeQueryWithItem(query, selItem.itemId); this.populateNavTree(treeDef, queryToRun); } }); } } else { this.populateNavTree(treeDef, query); } }); } } } populateNavTree(def: NavTreeDef, query) { const idx = this.navTrees.findIndex(navTreeId => navTreeId.id === def.id); let parentLabel; if (idx > 0) { parentLabel = this.navTrees[idx - 1].selectedItemLabel; } if (idx !== -1) { - this.queryService.getData(def.apiDef.baseUrl, query, 'SELECT').subscribe(data => { + this.queryService.getData(def.apiDef.baseUrl, query, 'SELECT').then(data => { this.navTrees[idx].setNavTreeData(_.get(data, def.apiDef.dataArray), this.activatedRoute.snapshot.queryParams, parentLabel); }); } } /** * setActiveTreeOnInit listens to the initial queryParam and sets the navTabIdx accordingly. * gets the active navTabIndex either from a passed contextView, from active qParam or sets it to 0 */ private setActiveTreeOnInit() { const activeTab = parseInt(this.activatedRoute.snapshot.queryParamMap.get('navTabIdx'), 10); this.navTrees.forEach(tree => { // If the tree is the active one according to qParam 'navTabIdx, we change to that tree if (activeTab === tree.idx) { this.navTabIndexChange.emit(activeTab); } }); } /** * subscribeToSetSelectedItems * Subscribe to each tree's selectedItemSet and route/set the selectedItem in the qParams if the item is not yet set * This applies when the trees are built initially or rebuilt, i.e. in two cases: * 1) when no qParam for the trees is set in the route * 2) a selected item is changed in a parent tree and the childs qParams are nulled */ private subscribeToSetSelectedItems() { this.navTrees.forEach(tree => { if (!this.activatedRoute.snapshot.queryParamMap.get(tree.qParam)) { tree.selectedItemSet.subscribe(item => { // set qParam this.naviService.updateRoute({[tree.qParam]: item.itemId}); }); } }); } // // REACTING ON CHANGES MADE OUTSIDE OF THE COMPONENT // async reactOnNewQParams(qParams: ParamMap) { // iterating through all queryParams and react if one param has changed await qParams.keys.forEach(key => { if (qParams.get(key) !== this.oldQueryParams.get(key)) { this.reactOnParamChange(key, qParams.get(key)); } } ); this.oldQueryParams = this.activatedRoute.snapshot.queryParamMap; } reactOnParamChange(qParam: string, newValue: string) { // qParams of the navTrees, e.g. 'page' and 'manuscript' if (this.navTrees && this.navTrees.map(tree => tree.qParam).findIndex(param => param === qParam) !== -1) { // if a qParam is one of the params defined in navTrees this.reactOnItemChange(qParam, newValue); } if (qParam === 'contextView') { this.reactOnContextChange(newValue); } if (qParam === 'navTabIdx') { this.navTabIndexChange.emit(parseInt(newValue, 10)); } } reactOnItemChange(param: string, itemId: string) { // because it might be changed from outside via url update, we have to find the tree according to the changed param const parentIdx = this.navTrees.findIndex(tree => tree.qParam === param); if (itemId !== this.navTrees[parentIdx].selectedItem) { // only rebuild if it is not yet set. this.rebuildTrees(parentIdx, itemId); } } // gets the reactOnContextChange(context: string) { const newTabIndex = this.getActiveNavTabIdxFromContext(context); this.changeNavTreeViaRoute(newTabIndex); // must time out here hence document is not ready to scroll // window.setTimeout(() => this.scrollOnToSelectedItem(this.oldQueryParams[context]), 100); } async rebuildTrees(parentIdx, itemId) { const itemToSelect = await this.navTrees[parentIdx].getSelectedById(itemId); await this.navTrees[parentIdx].setSelectedItem(itemToSelect.tlnEntity.id, itemToSelect.tlnEntity.label); await this.rebuildChildNavTrees(itemToSelect, parentIdx); } async rebuildChildNavTrees(item: NavigationEntity, parentIdx) { // get new data for subTrees and set new params accordingly await this.emptyChildTrees(parentIdx); await this.removeAllChildTreeQParams(parentIdx); await this.populateChildren(parentIdx, item.tlnEntity); } removeAllChildTreeQParams(tabId) { this.navTrees.forEach((tree, index) => { if (tree.idx > tabId) { this.navTrees[index].selectedItem = null; this.naviService.updateRoute({[tree.qParam]: null}); } }); } emptyChildTrees(parentIdx) { this.navTrees.forEach((tree, index) => { if (tree.idx > parentIdx) { this.navTrees[index].entries = []; } }); } populateChildren(parentTab, item: TlnEntity) { if (parentTab + 1 < this.navigationTreeDefs.length) { // if an item in a tab with sub tabs is selected, the subtree should be loaded according to that selection and the tab should change this.populateNavTrees(parentTab + 1, item); } } /** * getActiveNavTabIndexOnInit * gets the active navTabIndex either from a passed contextView, from active qParam or sets it to 0 */ getActiveNavTabIdxFromContext(con: string) { let navTreeIndex; // the index of the navTree with the qParam corresponding to con let navTabIndex; if (con) { navTreeIndex = this.navigationTreeDefs.findIndex(tree => tree.itemQParam === con); } if (navTreeIndex >= 0) { // no -1/not found navTabIndex = this.navigationTreeDefs[navTreeIndex].idx; } return navTabIndex; } /** * changeNavTreeViaRoute * changes to a new tree/tab in the navtab of the navList. In case of displayed tln-search and tln-crossRef * within content-view-component, the contextView is set also corresponding to the trees qParam. */ changeNavTreeViaRoute(idx: number) { if (idx < this.navTrees.length && idx >= 0) { const qParams = {}; qParams['navTabIdx'] = idx; const activeView = this.activatedRoute.snapshot.children.pop().routeConfig.path; // If the tln-search or the tln-crossRef are active, then change the contextView, hence the app reacts // on context change and will set the navTabIdx accordingly if ( activeView === 'tln-search' || activeView === 'tln-crossref' ) { const newContext = this.navTrees[this.navTrees.findIndex(tree => tree.idx === idx)].qParam; if (newContext !== this.activatedRoute.snapshot.queryParamMap.get('contextView')) { qParams['contextView'] = newContext; } } this.naviService.updateRoute(qParams); } } } diff --git a/nietzsche-beta-app/src/app/services/query.service.ts b/nietzsche-beta-app/src/app/services/query.service.ts index c790a6f..ad8450a 100644 --- a/nietzsche-beta-app/src/app/services/query.service.ts +++ b/nietzsche-beta-app/src/app/services/query.service.ts @@ -1,78 +1,88 @@ import { Injectable } from '@angular/core'; import { Parser, Generator, Wildcard } from 'sparqljs'; import {HttpClient, HttpHeaders} from '@angular/common/http'; @Injectable() export class QueryService { constructor(private http: HttpClient) { } parser = new Parser(); sparqlGenerator = new Generator({}); /** * Gets the data from an endpoint via http post * * @param baseUrl: The url of the endpoint. * @param query: The query to run. * @param queryType: "CONSTRUCT" or "QUERY" * @returns the response. */ public getData(baseUrl: string, query: string, queryType?: string ) { let httpOptions; if (queryType === 'CONSTRUCT') { // A construct does contain a text as response, not a json, so responseType must be 'text' to avoid parse errors httpOptions = { headers: new HttpHeaders({'Content-Type': 'application/sparql-query', 'Accept': 'text/turtle'}), responseType: 'text'}; - return this.http.post(baseUrl, query, httpOptions); + return this.http.post(baseUrl, query, httpOptions).toPromise(); } else { httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/sparql-query', 'Accept': 'application/sparql-results+json; charset=UTF-8'})}; - return this.http.post(baseUrl, query, httpOptions); + return this.http.post(baseUrl, query, httpOptions).toPromise(); } } /** * Gets a text file by its name from the directory assets/queries. * * @param filename The name of the file + file name extension. * @returns the text of the file. */ public getQueryfromFilename(filename) { - return this.http.get('../assets/queries/' + filename, {responseType: 'text'}); + return this.http.get('../assets/queries/' + filename, {responseType: 'text'}).toPromise(); } /** * Gets a query string from a given file in the directory assets/queries. * * @param filename The name of the file + file name extension. * @returns The JSON equivalence of the parsed query. */ public parseQueryFromFile(filename) { return this.getQueryfromFilename(filename ) - .subscribe(query => { + .then(query => { this.parser.parse(query); } ); } /** * getQueryForItem() - * Parametrizes a given baseQuery with a iri passed, so the iri will be the subject of the where clause + * Parametrizes a given baseQuery with a iri passed, so the iri will be the resource of the where clause * - * @param itemIri: The iri of the selected resource + * @param subjectIri: The iri of the selected resource * @param baseQuery: name of the query to parametrize + * @param propertyIri: The iri of the selected property + * @param objectIri: The iri of the selected object * @returns the query for the resource. */ - public parametrizeQueryWithItem(baseQuery: string, itemIri: string) { - const parsedQuery = this.parser.parse(baseQuery); - // console.log('parsedQuery', parsedQuery); + public parametrizeQueryWithItem(baseQuery: string, subjectIri?: string, propertyIri?: string, objectIri?: string): string { + let parsedQuery = this.parser.parse(baseQuery); + console.log('heeeere') // parametrize/reset the subject iri to the word's iri we like to query for - const resourceOfInterest = {'termType': 'NamedNode', 'value': decodeURI(itemIri) }; - parsedQuery.where[0].triples[0].subject = resourceOfInterest; + if (subjectIri && subjectIri !== '') { + parsedQuery.where[0].triples[0].subject = {'termType': 'NamedNode', 'value': decodeURI(subjectIri) }; + } + + if (propertyIri && propertyIri !== '') { + parsedQuery.where[0].triples[0].predicate = {'termType': 'NamedNode', 'value': decodeURI(propertyIri) }; + } + + if (objectIri && objectIri !== '') { + parsedQuery.where[0].triples[0].object = {'termType': 'NamedNode', 'value': decodeURI(objectIri) }; + } // generate the new query string and return it - // console.log('parametrized query', this.sparqlGenerator.stringify(parsedQuery)); return this.sparqlGenerator.stringify(parsedQuery); } } diff --git a/nietzsche-beta-app/src/app/tln-edition/constants.ts b/nietzsche-beta-app/src/app/tln-edition/constants.ts index c68387d..4f092b1 100644 --- a/nietzsche-beta-app/src/app/tln-edition/constants.ts +++ b/nietzsche-beta-app/src/app/tln-edition/constants.ts @@ -1,78 +1,83 @@ export {HIGHTLIGHT_CASES} from '../page-view/highlight_status'; export enum VIEW_OPTIONS { - TRANSKRIPTION = 'Transkription', + 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 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'; /** * 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';