diff --git a/nietzsche-beta-app/package.json b/nietzsche-beta-app/package.json index ff5698a..ff79cee 100644 --- a/nietzsche-beta-app/package.json +++ b/nietzsche-beta-app/package.json @@ -1,56 +1,57 @@ { "name": "nietzsche-app-beta", "version": "0.5.2.1", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "compodoc": "./node_modules/.bin/compodoc -p tsconfig.app.json", "sparqljs": "./node_modules/sparqljs/sparql.js" }, "private": true, "dependencies": { "@angular/animations": "~8.2.14", "@angular/cdk": "~8.2.3", "@angular/common": "~8.2.14", "@angular/compiler": "~8.2.14", "@angular/core": "~8.2.14", "@angular/forms": "~8.2.14", "@angular/material": "^8.2.3", "@angular/platform-browser": "~8.2.14", "@angular/platform-browser-dynamic": "~8.2.14", "@angular/router": "~8.2.14", "@types/rdf-js": "^2.0.11", "lodash": "^4.17.20", "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 ce10b8d..48b9ae2 100644 --- a/nietzsche-beta-app/src/app/app.module.ts +++ b/nietzsche-beta-app/src/app/app.module.ts @@ -1,84 +1,86 @@ 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'; +import { RdfEditorComponentComponent } from './crossref-editor-component/rdf-editor-component/rdf-editor-component.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, ManuscriptViewComponentComponent, ContentViewTabComponentComponent, RhizomeViewComponentComponent, MainMenuComponentComponent, PageViewWrapperComponent, NavigationListComponentComponent, NavTree, LazyImageLoadDirectiveDirective, ImpressumComponent, ProjectComponent, NavigationlistListComponentComponent, CrossRefTreeComponentComponent, - CrossrefEditorComponentComponent + CrossrefEditorComponentComponent, + RdfEditorComponentComponent ], 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 3f2aaf1..93cd374 100644 --- a/nietzsche-beta-app/src/app/constants.ts +++ b/nietzsche-beta-app/src/app/constants.ts @@ -1,313 +1,303 @@ 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 { +SELECT DISTINCT ?page ?pageNumber ?type WHERE { ?s (tln:hasPages/(rdf:rest*)/rdf:first) ?page. - ?page tln:hasNumber ?pageNumber. + ?page tln:hasNumber ?pageNumber. + ?page a tln:Page. + BIND (tln:page AS ?type) 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 { +SELECT DISTINCT ?line ?lNumber ?type WHERE { ?s (tln:hasLines/(rdf:rest*)/rdf:first) ?line. - # BIND (COALESCE(?sorting, 0) AS ?number2) + ?line a tln:Line. + BIND (tln:line AS ?type) 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 { +SELECT DISTINCT ?word ?line ?text ?type WHERE { ?word tln:wordBelongsToLine ?line. + ?word a tln:SimpleWord. + BIND(tln:SimpleWord AS ?type) 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', + type: 'type.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: '', + type: 'type.value' } } }, { 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: '', + type: 'type.value' }, 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/crossref-editor-component/crossref-editor-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.html index 1db56dc..cb49cbb 100644 --- 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 @@ -1,8 +1,8 @@
- hier reinziehen bald ... +
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.html new file mode 100644 index 0000000..d4cb65a --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.html @@ -0,0 +1 @@ +

rdf-editor-component works!

diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.scss b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.spec.ts b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.spec.ts new file mode 100644 index 0000000..f4feefc --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RdfEditorComponentComponent } from './rdf-editor-component.component'; + +describe('RdfEditorComponentComponent', () => { + let component: RdfEditorComponentComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RdfEditorComponentComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RdfEditorComponentComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.ts new file mode 100644 index 0000000..20eac42 --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/rdf-editor-component/rdf-editor-component.component.ts @@ -0,0 +1,59 @@ +import { Component, OnInit } from '@angular/core'; +import * as N3 from "node_modules/n3/src"; + +@Component({ + selector: 'app-rdf-editor-component', + templateUrl: './rdf-editor-component.component.html', + styleUrls: ['./rdf-editor-component.component.scss'] +}) +export class RdfEditorComponentComponent implements OnInit { + + constructor() { + } + + ngOnInit() { + + const {DataFactory} = N3; + const {namedNode, literal, defaultGraph, quad} = DataFactory; + const myQuad = quad( + namedNode('https://ruben.verborgh.org/profile/#me'), + namedNode('http://xmlns.com/foaf/0.1/givenName'), + literal('Ruben', 'en'), + defaultGraph(), + ); + console.log(myQuad.termType); // Quad + console.log(myQuad.value); // '' + console.log(myQuad.subject.value); // https://ruben.verborgh.org/profile/#me + console.log(myQuad.object.value); // Ruben + console.log(myQuad.object.datatype.value); // http://www.w3.org/1999/02/22-rdf-syntax-ns#langString + console.log(myQuad.object.language); // en + + this.writeSth(); + } + + interLinkTextUnits(textA: string, textB: string): string { + let ttlString: string; + return ttlString; + } + + + + writeSth() { + const {DataFactory} = N3; + const {namedNode, literal, defaultGraph, quad} = DataFactory; + const writer = new N3.Writer({ prefixes: { c: 'http://example.org/cartoons#' } }); + writer.addQuad( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), + namedNode('http://example.org/cartoons#Cat') + ); + writer.addQuad(quad( + namedNode('http://example.org/cartoons#Tom'), + namedNode('http://example.org/cartoons#name'), + literal('Tom') + )); + writer.end((error, result) => console.log('typeof ', typeof result, ' result ', result)); + } +} + + 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 index f9b172c..e547244 100644 --- 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 @@ -1,20 +1,32 @@ + + 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 index 02fa6ed..0052ef8 100644 --- 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 @@ -1,203 +1,207 @@ 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); } + onClick(node:TlnTreeNode): void { + console.log('clicked node', node) + } + 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 5609ec6..5eb2e69 100644 --- a/nietzsche-beta-app/src/app/models/models.ts +++ b/nietzsche-beta-app/src/app/models/models.ts @@ -1,94 +1,93 @@ -// 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 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, 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/services/query.service.ts b/nietzsche-beta-app/src/app/services/query.service.ts index ad8450a..328e318 100644 --- a/nietzsche-beta-app/src/app/services/query.service.ts +++ b/nietzsche-beta-app/src/app/services/query.service.ts @@ -1,88 +1,87 @@ 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).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).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'}).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 ) .then(query => { this.parser.parse(query); } ); } /** * getQueryForItem() * Parametrizes a given baseQuery with a iri passed, so the iri will be the resource of the where clause * * @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, 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 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 return this.sparqlGenerator.stringify(parsedQuery); } }