Page MenuHomec4science

crossref-editor-data-service.service.ts
No OneTemporary

File Metadata

Created
Mon, May 13, 22:03

crossref-editor-data-service.service.ts

import {EventEmitter, Injectable} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {BASEURL, NAMESPACES, RQ_CROSSREF_TREE_LINES, WRITEURL} 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<TextGenesis>;
textUnitDataBase: Map<string, any[]>;
textUnitDataBaseEmitter: EventEmitter<Map<string, any[]>>;
queryService: TlnQueryServiceInterface;
queryServiceEmitter: EventEmitter<TlnQueryServiceInterface>;
constructor(private activatedRoute: ActivatedRoute,
private qService: QueryService,
private pageViewService: PageViewService) {
this.textUnitDataBase = new Map<string, string[]>();
this.textUnitDataBaseEmitter = new EventEmitter<Map<string, any[]>>();
this.queryServiceEmitter = new EventEmitter<TlnQueryServiceInterface>();
this.textGenesisEmitter = new EventEmitter<TextGenesis>();
// subcribing at klicked lines to set them as selection
this.pageViewService.onClickedLine.subscribe((clickedLine: TlnLine) => {
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() )
) {
this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setStartLine(line.id, line.number);
} else { // endLine must be set
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<string[]> {
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(store: boolean) {
let textGeneseWriter = new N3.Writer();
await this.textGenesis.getQuads().then( quads => {
console.log('textGenesis', this.textGenesis);
console.log('allQuads', quads);
textGeneseWriter.addQuads(quads);
}).then(cool => {
textGeneseWriter.end((error, result) => {
this.textGenesis.ttl_export = result;
if (store) { // importing to store
this.qService.updateData(WRITEURL, result);
}
});
});
}
}
export class TlnTextGenesisThing {
iri: string;
id: string;
selfTerm: N3.Term; // iri as N3.Term
selfStatement: N3.Quad; // self representation in triples
statements: Map<string, TlnList>; // 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<string, TlnList>();
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) {
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) => {
quads.push(new N3.Quad(this.selfTerm, value.property(), new N3.Writer().list(value.objects()))); // list
//usual spo
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) {
quads.splice(0,0, this.selfStatement);
}
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;
public ttl_exportReady: EventEmitter<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 = [];
this.ttl_exportReady = new EventEmitter<string>();
}
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<N3.Quad[]> {
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 => {
if (!tUnit.wholePage) {
this.allQuads = [...this.allQuads, ...tUnit.quads(tUnit)];
}
});
});
return this.allQuads;
}
// check for completeness
isComplete() {
return this.textVersions().every( tVersion => tVersion.isComplete() ||
(tVersion.isExternalResource && tVersion.externalResourceHasUrl && tVersion.hasTitle));
}
}
export class TextVersion extends TlnTextGenesisThing{
private _identifiesAsVersion: TextUnit[];
private _pages: TlnEntity[];
isExternalResource: boolean;
externalResourceHasUrl: string;
hasTitle?: string;
constructor(label: string, parentIri, parentLabel?, checkOut = false, textUnits: TextUnit[] = [], pages: TlnEntity[] = [],
hasTitle?: string,
isExternalResource = false,
externalResourceHasUrl?: string) {
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;
this.isExternalResource = isExternalResource;
this.externalResourceHasUrl = externalResourceHasUrl;
this.hasTitle = hasTitle;
}
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];
}
// simple check for completeness
isComplete(){
return (this.textUnits().length && this.textUnits().every(u =>
u.startLine() !== undefined && u.endLine() !== undefined || u.wholePage ));
}
}
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,
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 = [];
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());
if (this.endLine()) {this.deleteEndLine();}
this.setStatement('startLine', startLine, 0);
}
setEndLine(endLine: string, lineNumber: number) {
this._endLine = endLine;
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;
}

Event Timeline