diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-data-service.service.ts b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-data-service.service.ts index 4fc31af..5e86ea3 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-data-service.service.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-data-service.service.ts @@ -1,501 +1,543 @@ import {EventEmitter, Injectable} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {BASEURL, NAMESPACES, RQ_CROSSREF_TREE_LINES} from '../constants'; import {QueryService} from '../services/query.service'; import * as N3 from "node_modules/n3/src"; import {moveItemInArray} from '@angular/cdk/drag-drop'; import {NavigationEntity, TlnEntity} from '../models/models'; import {TlnLine} from '../tln-edition/datatypes/line'; import {PageViewService} from '../page-view/page-view.service'; import {TlnQueryServiceInterface} from '../tln-edition/models'; @Injectable({ providedIn: 'root' }) export class CrossrefEditorDataServiceService { textGenesis: TextGenesis; // the one textGenesis used by all components textGenesisEmitter: EventEmitter; textUnitDataBase: Map; textUnitDataBaseEmitter: EventEmitter>; queryService: TlnQueryServiceInterface; queryServiceEmitter: EventEmitter; constructor(private activatedRoute: ActivatedRoute, private qService: QueryService, private pageViewService: PageViewService) { this.textUnitDataBase = new Map(); this.textUnitDataBaseEmitter = new EventEmitter>(); this.queryServiceEmitter = new EventEmitter(); this.textGenesisEmitter = new EventEmitter(); // subcribing at klicked lines to set them as selection this.pageViewService.onClickedLine.subscribe((clickedLine: TlnLine) => { - console.log(clickedLine); if (clickedLine.page === this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().belongsToPage) { this.setLine(clickedLine); + this.updateAll(this.textGenesis); } }) } // sets the lines: if start and end are existing it resets the startline else sets the endline setLine(line: TlnLine) { // get the active page ... if (!this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().hasStartLine() || ( this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().hasStartLine() && this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().hasEndLine() ) ) { - console.log('SETTING startline to', line.number); this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setStartLine(line.id, line.number); } else { // endLine must be set - console.log('SETTING endline to', line.number); this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setEndLine(line.id, line.number); } } updateAll(textGenesis:TextGenesis) { this.textGenesis = textGenesis; this.textGenesisEmitter.emit(textGenesis); } addPage(navItem: NavigationEntity, index: number){ const textUnit = new TextUnit('textUnit', navItem.tlnEntity.iri, true, navItem.tlnEntity.description, navItem.tlnEntity.label, navItem); this.textGenesis.checkedOutTextVersion().setTextUnit(textUnit, index); this.setLineData(textUnit); this.updateAll(this.textGenesis); } movePageInArray(previousIndex: number, index: number) { this.textGenesis.checkedOutTextVersion().moveTextUnitInArray(previousIndex, index) this.updateAll(this.textGenesis); } removePage(pageIri: string) { this.textGenesis.checkedOutTextVersion().deleteTextUnit(pageIri); this.updateAll(this.textGenesis); } setWholePage(textUnit: TextUnit, truthVal: boolean) { this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setWholePage(truthVal); const idx = this.textGenesis.checkedOutTextVersion().getTextUnitIdxByIri(textUnit.iri); // Have to change statements because of ontology: if (truthVal) { // If wholePage = true, there is no textUnit to store - it is the page itself this.textGenesis.checkedOutTextVersion().setStatement('identifiesAsVersion', textUnit.belongsToPage, idx); } else { this.textGenesis.checkedOutTextVersion().setStatement('identifiesAsVersion', textUnit.iri, idx); } this.updateAll(this.textGenesis) } // sets the lineData available for the checked out textUnit setLineData(textUnit: TextUnit) { this.getLinesFromStore(textUnit.belongsToPage).then(lines => { let linesOfPage = lines.map(line => { return {line: line['line']['value'], lNumber: line['lNumber']['value']} }); const textVersionIdx = this.textGenesis.checkedOutTextVersionIdx(); const textUnitIdx = this.textGenesis.checkedOutTextVersion().getTextUnitIdxByIri(textUnit.iri); this.textGenesis.textVersions()[textVersionIdx].textUnits()[textUnitIdx].lineData= linesOfPage; }); } async getLinesFromStore(pageIri: string): Promise { const query = await this.qService.parametrizeQueryWithItem(RQ_CROSSREF_TREE_LINES, pageIri, '', ''); return await this.qService.getData(BASEURL, query, 'SELECT').then(res => { return res['results']['bindings']; }); } async writeOut() { let textGeneseWriter = new N3.Writer({ prefixes: NAMESPACES}); await this.textGenesis.getQuads().then( quads => { - console.log('allQuads', quads); + //console.log('allQuads', quads); textGeneseWriter.addQuads(quads); }).then(cool => { textGeneseWriter.end((error, result) => { this.textGenesis.ttl_export = result; console.log('Here are the n3 results', result); // import somewhere // pass QueryService??? }); }); } } export class TlnTextGenesisThing { iri: string; id: string; selfTerm: N3.Term; // iri as N3.Term selfStatement: N3.Quad; // self representation in triples statements: Map; // all the properties && their objects parentIri: string; parentLabel: string; private checkedOut: boolean; // wether the thing is checked out for editing atm. static selfStatement(s: string, o:string) { return new N3.Quad( new N3.NamedNode(s), new N3.NamedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), new N3.NamedNode(o)) } constructor(label: string, parentIri?: string, parentLabel?: string, checkedOut = false) { this.setIri(label, parentIri); this.selfTerm = new N3.NamedNode(this.iri); this.statements = new Map(); this.parentIri = parentIri; this.parentLabel = parentLabel; this.checkedOut = checkedOut; } // builds the unique iri with the given iri, its parent and a generated hash setIri(label: string, parentIri?: string) { const hash = `${Date.now().valueOf().toString(36)}-${(Math.random()).toString(36).replace('.', '')}`; // unique hash: this.iri = `${parentIri}_${label}_${hash}`; this.id = `${label}_${hash}` } + hasStatement(property: string) { + return this.statements.get(property) !== undefined && this.statements.get(property) !== null; + } + + hasStatementEntries(property) { + return this.statements.get(property).objects().length > 0; + } + + getStatementIdx(property: string, iri: string) { + return this.statements.get(property).objects().findIndex(obj => obj === iri) + } + setStatement(property: string, objectIri:string, index) { this.statements.get(property).setObject(objectIri, index); } deleteStatement(property: string, index: number) { - console.log('deleting: ', property, index) - this.statements.get(property).deleteObject(index); + if (this.hasStatement(property) && this.hasStatementEntries(property)) { + this.statements.get(property).deleteObject(index); + } } moveObjectInStatement(property: string, previousIndex, newIndex) { this.statements.get(property).moveObject(previousIndex, newIndex); } //returns all statements as n3 quad array getStatementsAsQuads(): N3.Quad[] { let quads: N3.Quad[] = []; if (this.statements.size > 0) { this.statements.forEach((value) => { value.objects().forEach(object => { if (this.selfTerm && value.property() && object) { quads.push(new N3.Quad(this.selfTerm, value.property(), object)); } }); }); } return quads; } // returns the thing with all statements as N3-quads/lists quads(self?) { let quads: N3.Quads[] = [].concat(this.getStatementsAsQuads()); // concadinating so never undefined if (this.selfStatement !== undefined && this.selfStatement !== null) { - console.log('adding', self.iri); quads.splice(0,0, this.selfStatement); - console.log('quads are now',quads); - } else {console.log('empty ', self)} + } return quads; } checkOut(val: boolean) { this.checkedOut = val; } isCheckedOut() { return this.checkedOut; } } export class TextGenesis extends TlnTextGenesisThing{ private _textVersions: TextVersion[]; allQuads: N3.Quad[]; public ttl_export: string; constructor(label: string, parentIri?: string, textVersions: TextVersion[] = []) { super(label, parentIri); this.selfStatement = TextGenesis.selfStatement(this.iri, 'http://www.nie.org/ontology/nietzsche#TextGenesis'); const textVersionsList = new TlnList('http://www.nie.org/ontology/nietzsche#hasGeneticOrder', textVersions.map(t => t.iri)); this.statements.set('hasGeneticOrder', textVersionsList); this._textVersions = textVersions; this.allQuads = []; } public addTextVersion(textVersion: TextVersion, index){ this._textVersions.push(textVersion); this.setStatement('hasGeneticOrder', textVersion.iri, index); } public textVersions(): TextVersion[] { return this._textVersions; } setTextVersion(textVersion: TextVersion) { const idx = this.getTextVersionIndex(textVersion.iri); if (this._textVersions[idx].isCheckedOut()) { this._textVersions[idx] = textVersion; this.setStatement('hasGeneticOrder', textVersion.iri, idx); } } getTextVersionIndex(iri: string): number { return this.textVersions().findIndex(t => t.iri === iri) } checkoutTextVersion(iri: string) { let idx = this.getTextVersionIndex(iri); for (let i = 0; i <= this._textVersions.length-1; i++) { if (i === idx) { this._textVersions[i].checkOut(true); } else { this._textVersions[i].checkOut(false); } } } checkedOutTextVersion(): TextVersion { return this._textVersions[this.checkedOutTextVersionIdx()]; } checkedOutTextVersionIdx(): number { return this._textVersions.findIndex(tVersion => tVersion.isCheckedOut()); } deleteTextVersion(iri: string) { const delIndex = this._textVersions.findIndex(tVersion => tVersion.iri === iri); this._textVersions.splice(delIndex, 1); this.deleteStatement('hasGeneticOrder', delIndex) } // returns an array of all quads contained async getQuads(): Promise { this.allQuads = []; const textGenesisQuads: N3.Quad[] = this.quads(this); this.allQuads = await [... this.allQuads, ... textGenesisQuads] await this.textVersions().forEach(tVersion => { this.allQuads = [...this.allQuads, ...tVersion.quads(tVersion)]; tVersion.textUnits().forEach(tUnit => { - this.allQuads = [...this.allQuads, ...tUnit.quads(tUnit)]; + if (!tUnit.wholePage) { + this.allQuads = [...this.allQuads, ...tUnit.quads(tUnit)]; + } }); }); return this.allQuads; } } export class TextVersion extends TlnTextGenesisThing{ private _identifiesAsVersion: TextUnit[]; private _pages: TlnEntity[]; constructor(label: string, parentIri, parentLabel?, checkOut = false, textUnits: TextUnit[] = [], pages: TlnEntity[] = []) { super(label, parentIri, parentLabel, checkOut); this.selfTerm = new N3.NamedNode(this.iri); this._identifiesAsVersion = textUnits; this.selfStatement = TextGenesis.selfStatement(this.iri, 'http://www.nie.org/ontology/nietzsche#IdentifiedTextVersion'); const textUnitList = new TlnList('http://www.nie.org/ontology/nietzsche#identifiesAsVersion', textUnits.map(t => t.iri)); this.statements.set('identifiesAsVersion', textUnitList); this._pages = pages; } textUnits(): TextUnit[] { return this._identifiesAsVersion; } pages() { return this._pages; } // overwrites an existig textUnit or simply adds it // adds it to _pages, _versions, and to the statements setTextUnit(textUnit: TextUnit, index) { if (!this.isCheckedOut()) { return } this._pages.splice(index,0, textUnit.navItem.tlnEntity); this._identifiesAsVersion.splice(index, 0, textUnit); let identifiesAsVersionThing: string; if (textUnit.wholePage) { identifiesAsVersionThing = textUnit.belongsToPage; } else { identifiesAsVersionThing = textUnit.iri } this.setStatement('identifiesAsVersion', identifiesAsVersionThing, index); } deleteTextUnit(textUnitIri: string) { const idx = this._identifiesAsVersion.findIndex(tUnit => tUnit.iri === textUnitIri); this._identifiesAsVersion.splice(idx,1); this._pages.splice(idx, 1); this.deleteStatement('identifiesAsVersion', idx); } moveTextUnitInArray(previousIndex: number, newIndex: number) { moveItemInArray(this._identifiesAsVersion, previousIndex, newIndex); moveItemInArray(this._pages, previousIndex, newIndex); this.moveObjectInStatement('identifiesAsVersion', previousIndex, newIndex); } setTextUnits(textUnits: TextUnit[]) { this._identifiesAsVersion = textUnits; // ... } getTextUnitIdxByIri(iri: string) { return this.textUnits().findIndex(tUnit => tUnit.iri === iri); } getTextUnitByIri(iri: string) { const idx = this.getTextUnitIdxByIri(iri); return this._identifiesAsVersion[idx]; } checkedOutTextUnit(): TextUnit { return this._identifiesAsVersion[this.checkedOutTextVersionIdx()]; } checkedOutTextVersionIdx(): number { return this._identifiesAsVersion.findIndex(tUnit => tUnit.isCheckedOut()); } checkoutTextUnit(iri: string):TextUnit { let idx = this._identifiesAsVersion.findIndex(t => t.iri === iri); for (let i = 0; i <= this._identifiesAsVersion.length-1; i++) { if (i === idx) { this._identifiesAsVersion[i].checkOut(true); } else { this._identifiesAsVersion[i].checkOut(false); } } return this._identifiesAsVersion[idx]; } } export class TextUnit extends TlnTextGenesisThing { belongsToPage: string; wholePage: boolean; // If true it IS an existing page in the List of "identifiesAsVersion" and there is no TextUnit to write! private _startLine?: string; private _endLine?: string; lineData: Line[]; displayedLabel: string; displayedStartLine: number; displayedEndLine: number; selectedLines: string[]; navItem?: NavigationEntity; - constructor(label:string, parentIri: string, wholePage = true, parentLabel?: string, displayedLabel?: string, navItem?: NavigationEntity, startLine?: string, endLine?: string) { + constructor(label:string, + parentIri: string, + wholePage = true, + parentLabel?: string, + displayedLabel?: string, + navItem?: NavigationEntity, + startLine?: string, + endLine?: string, + startLineNumber?: number, + endLineNumber?: number) { super(label, parentIri, parentLabel); this.setSelfOfIdentifiedVersion(wholePage); this.belongsToPage = parentIri; this.wholePage = wholePage; this.displayedLabel = displayedLabel; this.navItem = navItem; this._startLine = startLine; this._endLine = endLine; this.selectedLines = []; - if (this.startLine()) { - this.setSelectedLines(startLine, endLine); + this.setLines(startLine, startLineNumber, endLine, endLineNumber) + this.statements.set('belongsToPage', new TlnList('http://www.nie.org/ontology/nietzsche#belongsToPage', [parentIri])); + } + + setLines(sLine: string, sLineNo: number, eLine: string, eLineNo: number){ + let startLineArr = []; + let endLineArr = []; + if (sLine) {startLineArr.push(sLine)} + if (eLine) {endLineArr.push(eLine)} + this.statements.set('startLine', new TlnList('http://www.nie.org/ontology/nietzsche#startLine', startLineArr)); + this.statements.set('endLine', new TlnList('http://www.nie.org/ontology/nietzsche#endLine', endLineArr)); + if (sLine && sLineNo && eLine && eLineNo) { + this.setStartLine(sLine, sLineNo); + this.setEndLine(eLine, eLineNo); + this.setSelectedLines(sLine, eLine); } } startLine() { return this._startLine } // Hence the ontology allows both: a textUnit as well as an existing page in the identifiesAsVersion list we have to through in this ... setSelfOfIdentifiedVersion(wholePage: boolean) { if (wholePage) { this.selfTerm = null; this.selfStatement = null; } else { this.selfTerm = new N3.NamedNode(this.iri); this.selfStatement = TlnTextGenesisThing.selfStatement(this.iri, 'http://www.nie.org/ontology/nietzsche#PartOfPageTextUnit'); } } hasStartLine() { return this._startLine !== undefined && this._startLine !== null } endLine() { return this._endLine } hasEndLine() { return this._endLine !== undefined && this._endLine !== null } + // sets the select6ed lines for highlighting/passing to tln-page-view only public setSelectedLines(startLine, endLine?) { if (!endLine || endLine === undefined) { this.selectedLines = [this.startLine()] } else { let started = false; let ended = false; this.lineData.forEach(line => { if (line.line === startLine) { started = true; } if (line.line === endLine) { this.selectedLines.push(line.line); ended = true; } if (started && !ended) { this.selectedLines.push(line.line); } }); } } setStartLine(startLine: string, lineNumber: number) { this._startLine = startLine; this.displayedStartLine = lineNumber; this.setSelectedLines(this.startLine()); - this._endLine = null; - this.displayedEndLine = null; + if (this.endLine()) {this.deleteEndLine();} + this.setStatement('startLine', startLine, 0); } setEndLine(endLine: string, lineNumber: number) { this._endLine = endLine; + this.deleteEndLine(); this.displayedEndLine = lineNumber; this.setSelectedLines(this.startLine(), endLine); + this.setStatement('endLine', endLine, 0); + } + + deleteEndLine() { + this._endLine = null; + this.displayedEndLine = null; + // this.deleteStatement('endline', 0) } setWholePage(truthVal: boolean) { this.selectedLines = []; this.wholePage = truthVal; this.setSelfOfIdentifiedVersion(this.wholePage); } } export class TlnList { protected _property: N3.NamedNode; // property NamedNode protected _objects: N3.NamedNode[]; constructor(property: string, objects: string[] = []) { this._property = new N3.NamedNode(property); this._objects = objects.map(val => new N3.NamedNode(val)); } public setObject(objectIri: string, index) { this._objects.splice(index, 0, new N3.NamedNode(objectIri)); } public deleteObject(index) { this._objects.splice(index, 1); } public moveObject(previousIndex, newIndex) { moveItemInArray(this._objects, previousIndex, newIndex); } public addObjects(objectIris: string[]) { objectIris.map(iri => new N3.NamedNode(iri)).forEach(object => this._objects.push(object)); } public setObjects(objectIris: string[]) { this._objects = objectIris.map(iri => new N3.NamedNode(iri)); } public property() { return this._property; } public objects() { return this._objects; } } export interface Line { line: string; lNumber: number; } diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.html index c6c09ee..04e4955 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.html +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.html @@ -1,74 +1,74 @@ Textgenese: {{textGenesis.id}} {{textUnit.navItem.parentLabel}}: {{textUnit.displayedLabel}} {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} ; ->
{{i+1}}. Textversion {{textUnit.navItem.parentLabel}}: {{textUnit.displayedLabel}} - {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} + {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} ;
{{textVersion.isCheckedOut()? '' : 'Panel ausklappen zum Bearbeiten ...'}}
{{textVersion.id}}
{{textGenesis.ttl_export}} diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.ts index 333e203..fd89b44 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor.component.ts @@ -1,67 +1,67 @@ import {Component, OnChanges, OnDestroy } from '@angular/core'; import {CrossrefEditorDataServiceService, TextGenesis, TextUnit, TextVersion} from '../../crossref-editor-data-service.service'; import {Subscription} from 'rxjs'; import {ActivatedRoute} from '@angular/router'; import {NavigationServiceService} from '../../../services/navigation-service.service'; @Component({ selector: 'app-text-version-editor', templateUrl: './text-version-editor.component.html', styleUrls: ['./text-version-editor.component.scss'] }) export class TextVersionEditorComponent implements OnChanges, OnDestroy { textGenesis: TextGenesis; textGenesisSubscription: Subscription; constructor(private dataService: CrossrefEditorDataServiceService, private naviService: NavigationServiceService, private activatedRoute: ActivatedRoute) { if (this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState') === 'false' || '') { this.naviService.updateRoute({['navBarOpenState']: 'true'}); } this.textGenesisSubscription = this.dataService.textGenesisEmitter.subscribe(tGenesis => { this.textGenesis = tGenesis; - console.log('new TextGenesis: ', this.textGenesis); }) } ngOnChanges() { } ngOnDestroy(){ this.textGenesisSubscription.unsubscribe(); } createTextVersion() { let version = new TextVersion('TextVersion', this.textGenesis.iri); this.textGenesis.addTextVersion(version, this.textGenesis.textVersions().length-1); this.dataService.updateAll(this.textGenesis); } checkoutTextVersion(iri: string) { this.textGenesis.checkoutTextVersion(iri); this.dataService.updateAll(this.textGenesis); } // simple check for completeness versionComplete(textUnits: TextUnit[]){ if (textUnits.length && ( (textUnits.some(u => u.startLine() !== undefined) && textUnits.some(u => u.endLine() !== undefined) || textUnits.some(u => u.wholePage)) ) ){ return true } } deleteTextVersion(iri: string) { this.dataService.textGenesis.deleteTextVersion(iri); } preview() { + console.log(this.textGenesis) this.dataService.writeOut() // import somewhere } }