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 855b7a9..59f463f 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,904 +1,919 @@ import {EventEmitter, Injectable} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import { BASEURL, 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} from '../models/models'; import {TlnLine} from '../tln-edition/datatypes/line'; import {PageViewService} from '../page-view/page-view.service'; import {TlnQueryServiceInterface} from '../tln-edition/models'; import {SafeUrl} from '@angular/platform-browser'; import {ChangeMgmntDef, TlnPredicate} from '../rdf-editor-module/statement-handler'; import {RdfData, RdfStoredData} from '../rdf-editor-module/rdf-editor-DataSets'; import {TlnResource, TlnTransaction} from '../rdf-editor-module/editor-resources'; @Injectable({ providedIn: 'root' }) export class CrossrefEditorDataServiceService { textGenesis: TextGenesis; // the one textGenesis used by all components textGenesisEmitter: EventEmitter; transaction = new TlnTransaction(); def: ChangeMgmntDef; queryService: TlnQueryServiceInterface; queryServiceEmitter: EventEmitter; constructor(private activatedRoute: ActivatedRoute, private qService: QueryService, private pageViewService: PageViewService) { this.queryServiceEmitter = new EventEmitter(); this.textGenesisEmitter = new EventEmitter(); // creating a def: keep the patient statements as they got deleted by their agents anyway this.def = new ChangeMgmntDef( true, true, false, false, true, [], [], [], [], false, {keepAgentLists: false, keepAgentStatements: false, keepPatientLists: true, keepPatientStatements: true} ); // subcribing at klicked lines to set them as selection this.pageViewService.onClickedLine.subscribe((clickedLine: TlnLine) => { if (clickedLine.page === this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().textUnit.pageData.pageIri) { this.setLine(clickedLine); this.updateAll(this.textGenesis); } }); } readInTextGenesis(textGenesisIri: string) { textGenesisIri = 'http://rdfh.ch/projects/0068#_Mp_XIV_TextGenesis0' ; // Todo: make generic TextGenesis.buildAsyncFromStore(this.qService, textGenesisIri).then(textGenesis => this.updateAll(textGenesis)); } resetFromStore() { TextGenesis.buildAsyncFromStore(this.qService, this.textGenesis.iri()).then(textGenesis => this.updateAll(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().internalTextVersion.checkedOutTextUnit().textUnit.hasStartLine() || ( this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().textUnit.hasStartLine() && this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().textUnit.hasEndLine() ) ) { this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().textUnit.setStartLine(line.id, line.number); } else { // endLine must be set this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().textUnit.setEndLine(line.id, line.number); } } updateAll(textGenesis: TextGenesis) { this.textGenesis = textGenesis; this.textGenesisEmitter.emit(textGenesis); } // sets the textVersion to external/internal and checksout/unchecks the active one. setExternityOfTextVersion(setToExternal: boolean) { this.textGenesis.checkedOutTextVersion().changeExternity(setToExternal); this.updateAll(this.textGenesis); } public deleteGuiTextVersion(iri) { this.textGenesis.deleteTextVersion(iri); this.updateAll(this.textGenesis); } public unDeleteGuiTextVersion(iri) { this.textGenesis.unDeleteTextVersion(iri); this.updateAll(this.textGenesis); } // builds a GuiTextUnit with the added and queried pages data and adds it to the textVersion - onAddingPage(navItem: NavigationEntity, index: number){ - // Todo: Change to nonStore constructor!!! instore = false + onAddingPage(navItem: NavigationEntity, index: number) { GuiTextUnit.createNewGuiTextUnit(this.qService, navItem.tlnEntity.iri, 'Texteinheit', this.textGenesis.checkedOutTextVersion().iri()) .then(guiTextUnit => { + if (this.wholePageIsPresent(guiTextUnit)) { // guard if page is already as wholePage in the textversion + return; } + // if the given guitextUnit (its iri) is not yet in the guitextUnits array of the textVersion we add it this.textGenesis.checkedOutTextVersion().internalTextVersion.addNewGuiTextUnit(guiTextUnit, index); this.updateAll(this.textGenesis); - }); + }); } movePageInArray(previousIndex: number, index: number) { this.textGenesis.checkedOutTextVersion().internalTextVersion.moveTextUnitInArray(previousIndex, index); this.updateAll(this.textGenesis); } onRemovePage(iri: string) { this.textGenesis.checkedOutTextVersion().internalTextVersion.deleteGuiTextUnit(iri); this.updateAll(this.textGenesis); } undeleteGuiTextUnit(iri: string) { this.textGenesis.checkedOutTextVersion().internalTextVersion.unDeleteGuiTextUnit(iri); this.updateAll(this.textGenesis); } // resets wholepage: boolean to the desired truthVal - changeWholePage(textUnit: TextUnit, truthVal: boolean) { - if (this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().wholePage === truthVal ) { return } // guard - // getting the idx of the guitextUnit (may be a page or a textUnit) - this.textGenesis.checkedOutTextVersion().changeWholePage(textUnit, truthVal); - this.updateAll(this.textGenesis) + changeWholePage(guiTextUnit: GuiTextUnit, truthVal) { + if (this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().wholePage === truthVal ) { + return; } // guard if truthval is already set accordingly + if (this.wholePageIsPresent(guiTextUnit)) { // guard if the page is not yet present as whole page + return; } + this.textGenesis.checkedOutTextVersion().changeWholePage(guiTextUnit.textUnit, truthVal); + this.updateAll(this.textGenesis); + } + + // checks whether a given guiTextUnits is already as whole page in the checked out list + wholePageIsPresent(guiTextUnit: GuiTextUnit): boolean { + let present = false; + if (this.textGenesis.checkedOutTextVersion().internalTextVersion.guiTextUnits().findIndex(u => + u.iri() === guiTextUnit.iri() || u.iri() === guiTextUnit.textUnit._belongsToPage) !== -1 ) { + // guard if Iri already in, i.e. there is already a wholePage of that page within the guitextUnits + const errMsg = `Seite ${guiTextUnit.textUnit._belongsToPage} (ganze Seite) befindet sich bereits in der Textversion.`; + console.warn(errMsg); + window.alert(errMsg); + present = true; + } + return present; } // collects all tlnResources into one array update/delete/create collectResources(): TlnResource[] { - let resources: TlnResource[] = []; + const resources: TlnResource[] = []; resources.push(this.textGenesis.resource); this.textGenesis.childResources.forEach(child => { resources.push(child.externalTextVersion.resource); // add ext resource resources.push(child.internalTextVersion.resource); // int resource child.internalTextVersion.childResources.forEach(iChild => { resources.push(iChild.textUnit.resource); console.log('iChild', iChild) }); }); return resources; } writeOut(store: boolean) { let resources = this.collectResources(); console.log('resources', resources); console.log('del Resources ', resources.filter(res => res.isDeleted() && !res.ignore()).map(res => res.iri)); console.log('stored Resources ', resources.filter(res => res.isInStore()).map( res => res.iri)); console.log('irgnored Resources ', resources.filter(res => res.ignore()).map( res => res.iri)); this.transaction = new TlnTransaction(); this.transaction.commit(resources, '', '', this.def ).then(committed => { this.transaction.committed = committed; console.log('committed', committed); if (committed === false) { console.log('Nothing to commit. No changes made.')} else { console.log('committed', committed); console.log('TRANSACTION', this.transaction) this.transaction.preview(); } }); } readInTtl (ttlData: string) { const parser = new N3.Parser(), store = new N3.Store(); parser.parse(ttlData, function (error, triple, prefixes) { if (triple) store.addTriple(triple); else // is complete onComplete(); return store; }); function onComplete() { const republic = store.find('http://example.org/library/the-republic', null, null)[0]; console.log(store); } parser.parse(this.textGenesis.ttl_export, (error, quad, prefixes) => { if (quad) { store.addQuad(quad); } else console.log('# That\'s all, folks!', prefixes); }); console.log('my store ', store); } } // main super class with basic functionality inherited by all gui classes export class CrossRefEditorElement { protected _iri: string; private _checkedOut: boolean; // wether the thing is checked out for editing atm or not. protected _paerentIri: string; protected label: string; protected parentLabel: string; resource: TlnResource; // the equivalent rdf resource from store and for editing childsPredicate: TlnPredicate; childResources: any[]; // Other CrossrefEditorElements or a subclass/extension public deleted = false; public displayedPredicates: string[]; public mutablePredicates: string[]; // Todo: refactor: set label inside subclasses - not via passing a parameter? constructor(iri?: string, label?: string, parentIri?: string, checkOut = false, parentLabel?: string){ if (iri !== '') { this._iri = iri; } else {// any random iri - does not matter this._iri = RdfData.createIri(label, parentIri); } this._paerentIri = parentIri; this._checkedOut = checkOut; this.parentLabel = parentLabel; this.resource = new TlnResource(this._iri, label); } checkOut(val: boolean) { this._checkedOut = val; } isCheckedOut() { return this._checkedOut; } iri() { return this._iri; } public rdfTypeInStore(): string { return this.resource._rdfDatasetFromStore.rdfType(); } // sets itself to deleted, deletes all statements and runs deletion of each child setDeleted() { this.deleted = true; this.resource.setDeleted(); // set the whole resource to deleted = true if (!this.childResources || !this.childResources.length) {return} // guard; else deletes also all children recursively this.childResources.forEach(child => { child.setDeleted(); // run deletion also for children }); } setUndeleted() { this.deleted = false; this.resource.setUndeleted(); if (!this.childResources || !this.childResources.length) {return} // guard; else deletes also all children recursively this.childResources.forEach(child => { child.setUndeleted(); // run also for children }); } } export class TextGenesis extends CrossRefEditorElement{ public childResources: GuiTextVersion[] = []; // setting childresources to GuiTextVersion[] // for writing out ttl allQuads: N3.Quad[]; public ttl_export: string; public ttl_exportReady: EventEmitter; constructor(iri: string, label?: string, parentIri?: string, checkOut = false) { super(iri, label, parentIri, checkOut); const ranges = new Set(); ranges.add('http://www.w3.org/1999/02/22-rdf-syntax-ns#List'); this.childsPredicate = new TlnPredicate('http://www.nie.org/ontology/nietzsche#hasGeneticOrder', ranges); this.allQuads = []; this.ttl_exportReady = new EventEmitter(); } public static async buildAsyncFromStore(qService: QueryService, iri: string): Promise { let textGenesis = new TextGenesis(iri, 'Textgenese'); textGenesis.resource = await TlnResource.buildFromStoreAsync(qService, iri, 'TextGenesis'); let children = await textGenesis.resource.getChildIris(textGenesis.childsPredicate.iri()); if (!children) {return textGenesis} // guard; else we create children children.forEach((child, index) => { GuiTextVersion.buildAsyncFromStore(qService, child, iri).then(guiTV => textGenesis.childResources.splice(index,0, guiTV)) }); return textGenesis; } public textVersions(): GuiTextVersion[] { return this.childResources; } public addTextVersion(textVersion: GuiTextVersion, index: number = this.childResources.length){ this.childResources.splice(index, 0, textVersion); this.resource._rdfDatasetToEdit.putStatementInListAsStatement(this.childsPredicate, textVersion.iri(), index); } public setTextVersion(textVersion: GuiTextVersion) { const idx = this.getTextVersionIndex(textVersion.iri()); if (this.childResources[idx].isCheckedOut()) { this.childResources[idx] = textVersion; this.resource._rdfDatasetToEdit.setStatementInListAsStatement(this.childsPredicate, textVersion.iri(), idx); } } deleteTextVersion(iri) { const idx = this.childResources.findIndex(tUnit => tUnit.iri() === iri); // setting both to deleted - no matter whats the type this.childResources[idx].onDelete(); this.resource._rdfDatasetToEdit.deleteAllStatementsWithObject(iri) } unDeleteTextVersion(iri) { const idx = this.childResources.findIndex(tUnit => tUnit.iri() === iri); this.childResources[idx].unDelete(); this.resource._rdfDatasetToEdit.putStatementInListAsStatement(this.childsPredicate, iri, idx); } getTextVersionIndex(iri: string): number { return this.textVersions().findIndex(t => t.iri() === iri) } // CHecks out one TextVersion and unchecks all others. checkoutTextVersion(iri: string) { let idx = this.getTextVersionIndex(iri); for (let i = 0; i <= this.childResources.length-1; i++) { if (i === idx) { this.childResources[i].checkOut(true); } else { this.childResources[i].checkOut(false); } } } checkedOutTextVersion(): GuiTextVersion { return this.childResources[this.checkedOutTextVersionIdx()]; } checkedOutTextVersionIdx(): number { return this.childResources.findIndex(tVersion => tVersion.isCheckedOut()); } // // returns an array of all quads contained // async getQuads(): Promise { // this.allQuads = []; // // adding the textGenesis quads // const textGenesisQuads: N3.Quad[] = await this.resource.buildRdfTransaction(); // this.allQuads = await [... this.allQuads, ... textGenesisQuads] // // adding the textVersion quads // await this.textVersions().forEach(async tVersion => { // let versionQuads = await tVersion.internalTextVersion.resource.buildRdfTransaction(); // this.allQuads = [...this.allQuads, ...versionQuads]; // tVersion.internalTextVersion.guiTextUnits().forEach(async tUnit => { // if (!tUnit.wholePage) { // let textUnitQuads = await tUnit.textUnit.resource.buildRdfTransaction(); // // only if it is not a whole page, i.e. there is a textUnit we get also its quads & its properties as quads TODO: Ontology // this.allQuads = [...this.allQuads, ...textUnitQuads]; // } // }); // }); // return this.allQuads; // } // check for completeness isComplete() { return this.textVersions().every( tVersion => tVersion.isComplete()); } } export class GuiTextVersion extends CrossRefEditorElement{ label: string; private isExternalResource: boolean; private changedExternity: boolean; internalTextVersion: InternalTextVersion; // the internal TextVersion Resource with its properties from RDF externalTextVersion: ExternalTextVersion; // the internal TextVersion Resource with its properties from RDF constructor(iri: string, // iri of internal or external resource label: string, parentIri: string, checkOut = false, inStore = false, isExternalResource = false, parentLabel?) { super(iri, label, parentIri, checkOut); this.isExternalResource = isExternalResource; this.changedExternity = false; this.label = label; this.parentLabel = parentLabel; } public static async buildAsyncFromStore(qService: QueryService, iri: string, parentIri?: string): Promise { const guiTextVersion = new GuiTextVersion(iri, 'TextVersion', parentIri); // guiTextVersion.resource = await TlnResource.buildFromStoreAsync(qService, iri, 'TextVersion'); guiTextVersion.isExternalResource = await guiTextVersion.isExternalAsync(qService, iri); if (guiTextVersion.isExternalResource) { guiTextVersion.externalTextVersion = await ExternalTextVersion.buildAsyncFromStore(qService, iri, parentIri); // creating also an internal one, but set it to deleted for switching easily guiTextVersion.internalTextVersion = new InternalTextVersion('', 'Textversion', parentIri); // set the resource to deleted because it should be ignored if not switched to internal guiTextVersion.internalTextVersion.setDeleted(); } else { guiTextVersion.internalTextVersion = await InternalTextVersion.buildAsyncFromStore(qService, iri, parentIri); // building also a new external one and set it to deleted guiTextVersion.externalTextVersion = new ExternalTextVersion('', 'TextVersion', parentIri); guiTextVersion.externalTextVersion.setDeleted(); // set to deleted because we like to ignore it unless switched to externaö } return guiTextVersion; } public static buildNew(parentIri: string) { const guiTextVersion = new GuiTextVersion('', 'Textversion', parentIri, true); guiTextVersion.externalTextVersion = new ExternalTextVersion(guiTextVersion.iri(), 'TextVersion', parentIri); guiTextVersion.internalTextVersion = new InternalTextVersion(guiTextVersion.iri(), 'Textversion', parentIri ); return guiTextVersion; } public async isExternalAsync(qService, iri) { const type = await RdfStoredData.getRdfTypeFromStore(qService, iri); return type === 'http://www.nie.org/ontology/nietzsche#ExternalTextUnit'; } isComplete() { if (this.isExternalResource) { return this.externalTextVersion.isComplete() } else { return this.internalTextVersion.isComplete(); } } changeExternity(isExternal: boolean) { this.isExternalResource = isExternal; if (isExternal) { // changed to external // change deletions this.internalTextVersion.setDeleted(); if (this.externalTextVersion.resource.isInStore()) { this.externalTextVersion.setUndeleted(); } this.externalTextVersion.checkOut(true); this.internalTextVersion.checkOut(false); } else { // chenged to internal this.externalTextVersion.setDeleted(); if (this.internalTextVersion.resource.isInStore()) { this.internalTextVersion.setUndeleted() } this.internalTextVersion.checkOut(true); this.externalTextVersion.checkOut(false); } this.changedExternity = !this.changedExternity; } changeWholePage(textUnit: TextUnit, truthVal: boolean) { this.internalTextVersion.checkedOutTextUnit().setWholePage(truthVal); const idx = this.internalTextVersion.getGuiTextUnitIdxByIri(textUnit.iri()); const predicate = this.internalTextVersion.childsPredicate; // If wholePage Changes we have to change the the list statements because of the ontology: if (truthVal) { // If wholePage = true, there is the page iri to store in the list // resetting link to child this.internalTextVersion.resource._rdfDatasetToEdit.setStatementInListAsStatement(predicate, textUnit._belongsToPage, idx); // setting wholePage of child //this.internalTextVersion.childResources[idx].setWholePage(truthVal) } else { // resetting link to child this.internalTextVersion.resource._rdfDatasetToEdit.setStatementInListAsStatement(predicate, textUnit.iri(), idx); } //console.log('changing wholePage ', textUnit.iri(), truthVal) //this.internalTextVersion.childResources[idx].setWholePage(truthVal); } // simply set everything to deleted - no matter if in use or not onDelete() { this.setDeleted(); this.internalTextVersion.setDeleted(); this.externalTextVersion.setDeleted(); } unDelete() { this.setUndeleted(); if (this.isExternalResource) { this.externalTextVersion.setUndeleted(); } else { this.internalTextVersion.setUndeleted(); } } hasChangedExternity(): boolean { return this.changedExternity; } } export class InternalTextVersion extends CrossRefEditorElement{ childResources: GuiTextUnit[] = []; - _pagesCollection: TlnCrossrefPage[]= []; constructor(iri: string, label?: string, parentIri?: string, checkOut = false) { // iri?: string, label?: string, parentIri?: string, checkOut = false super(iri, label, parentIri, checkOut); const ranges = new Set(); ranges.add('http://www.w3.org/1999/02/22-rdf-syntax-ns#List'); this.childsPredicate = new TlnPredicate('http://www.nie.org/ontology/nietzsche#identifiesAsVersion', ranges); } // builds an internalTextVersion public static async buildAsyncFromStore(qService: QueryService, iri: string, parentIri?: string): Promise { const intVersion = new InternalTextVersion(iri, 'Interne TextVersion', parentIri); intVersion.resource = await TlnResource.buildFromStoreAsync(qService, iri, 'TextVersion'); const children = await intVersion.resource.getChildIris(intVersion.childsPredicate.iri()); if (!children || children.length === 0 ) {return intVersion} // guard children.forEach((child, index) => { GuiTextUnit.buildAsyncFromStore(qService, child, 'Texteinheit', parentIri).then( guiTextUnit => { - intVersion._pagesCollection.splice(index,0, guiTextUnit.textUnit.pageData); // adding/changing _pagescollection intVersion.childResources.splice(index, 0, guiTextUnit); }); } ); return intVersion; } guiTextUnits(): GuiTextUnit[] { return this.childResources; } hasTextUnits(): boolean { return this.guiTextUnits().length > 0; } async getPagesCollection() { const pagesCollection: TlnCrossrefPage[] = []; for (let unit of this.guiTextUnits()) { pagesCollection.push(unit.textUnit.pageData); } return pagesCollection; } // overwrites an existig textUnit or simply adds it depending on the delete // to _pages, _versions, and to the statements setTextUnit(guiTextUnit: GuiTextUnit, index) { - this._pagesCollection.splice(index,1, guiTextUnit.textUnit.pageData); // changing _pagescollection this.childResources.splice(index, 1, guiTextUnit); this.resource._rdfDatasetToEdit.setStatementInListAsStatement(this.childsPredicate, guiTextUnit.iri(), index); } // adds a new guiTextUnit addNewGuiTextUnit(guiTextUnit: GuiTextUnit, index?: number) { if (index === null || index === undefined) {index = this.childResources.length} // if no index passed it will be added at the end // setting the list entry at the textVersion - this._pagesCollection.splice(index,0, guiTextUnit.textUnit.pageData); // adding/changing _pagescollection this.childResources.splice(index, 0, guiTextUnit); this.resource._rdfDatasetToEdit.putStatementInListAsStatement(this.childsPredicate, guiTextUnit.iri(), index); } deleteGuiTextUnit(textUnitIri: string) { const idx = this.childResources.findIndex(tUnit => tUnit.iri() === textUnitIri); - this._pagesCollection[idx].deleted = true; this.childResources[idx].setDeleted(); this.childResources[idx].textUnit.setDeleted(); // deleting also the statement connecting the textUnit this.resource._rdfDatasetToEdit.deleteAllStatementsWithObject(textUnitIri); } unDeleteGuiTextUnit(textUnitIri: string) { const idx = this.childResources.findIndex(tUnit => tUnit.iri() === textUnitIri); - this._pagesCollection[idx].deleted = false; this.childResources[idx].setUndeleted(); this.childResources[idx].textUnit.setUndeleted(); // resetting also the statement connecting the textUnit this.resource._rdfDatasetToEdit.putStatementInListAsStatement(this.childsPredicate, textUnitIri, idx) } // Todo: 1) Refactor so everything is in superclass; 2) remove children if not needed except onInit, remove pagesCollection if same moveTextUnitInArray(previousIndex: number, newIndex: number) { moveItemInArray(this.childResources, previousIndex, newIndex); - moveItemInArray(this._pagesCollection, previousIndex, newIndex); this.resource._rdfDatasetToEdit.moveObjectInListAsStatement(this.childsPredicate.iri(), previousIndex, newIndex); } getGuiTextUnitIdxByIri(iri: string) { return this.guiTextUnits().findIndex(tUnit => tUnit.iri() === iri); } getTextUnitByIri(iri: string) { const idx = this.getGuiTextUnitIdxByIri(iri); return this.childResources[idx]; } checkedOutTextUnit(): GuiTextUnit { return this.childResources[this.checkedOutTextVersionIdx()]; } checkedOutTextVersionIdx(): number { return this.childResources.findIndex(tUnit => tUnit.isCheckedOut()); } checkOutTextUnit(iri: string): GuiTextUnit { let idx = this.childResources.findIndex(t => t.iri() === iri); for (let i = 0; i <= this.childResources.length-1; i++) { if (i === idx) { this.childResources[i].checkOut(true); } else { this.childResources[i].checkOut(false); } } return this.childResources[idx]; } + pagesCollection() { + return this.childResources.map(guiTextUnit => guiTextUnit.textUnit.pageData); + } + // simple check for completeness isComplete() { return true; //return (this.textUnits().length && this.textUnits().every(u => // u.startLine() !== undefined && u.endLine() !== undefined || u.wholePage )); } } export class ExternalTextVersion extends CrossRefEditorElement{ hasUrl: string; hasTitle: string; hasTitleP: TlnPredicate; hasUrlP: TlnPredicate; constructor(iri?: string, label?: string, parentIri?: string, checkOut = false ) { super(iri, label, parentIri, checkOut); this.hasTitleP = new TlnPredicate('http://www.nie.org/ontology/nietzsche#textUnitHasTitle', new Set(['http://www.w3.org/2001/XMLSchema#string'])); this.hasUrlP = new TlnPredicate('http://www.nie.org/ontology/nietzsche#textUnitHasUrl', new Set(['http://www.w3.org/2001/XMLSchema#anyURI'])); } public static async buildAsyncFromStore(qService: QueryService, iri: string, parentIri): Promise { - let extVersion = new ExternalTextVersion(iri, 'TextVersion', parentIri); + const extVersion = new ExternalTextVersion(iri, 'TextVersion', parentIri); extVersion.resource = await TlnResource.buildFromStoreAsync(qService, iri, 'Externe Textversion'); extVersion.hasTitle = extVersion.resource.rdfDatasetFromStore().getFirstObject('http://www.nie.org/ontology/nietzsche#textUnitHasTitle'); extVersion.hasUrl = extVersion.resource.rdfDatasetFromStore().getFirstObject('http://www.nie.org/ontology/nietzsche#textUnitHasUrl'); return extVersion; } // simple check for basic completeness isComplete(){ return this.hasUrl && this.hasTitle } setTitle(title: string) { this.resource._rdfDatasetToEdit.setStatement(this.hasTitleP, title, 0) } setUrl(url: string) { this.resource._rdfDatasetToEdit.setStatement(this.hasUrlP, url, 0) } } // wrapper class export class GuiTextUnit extends CrossRefEditorElement{ textUnit: TextUnit; wholePage: boolean; deleted = false; constructor(iri, label: string, parentIri?: string, checkOut = true, wholePage = true, parentLabel?: string) { super(iri, label, parentIri, checkOut); this.wholePage = wholePage; this.parentLabel = parentLabel; this.displayedPredicates = ['http://www.nie.org/ontology/nietzsche#belongsToPage']; // } // async builder static async buildAsyncFromStore(qService: QueryService, iri: string, label, parentIri?: string) { const guiTextUnit: GuiTextUnit = new GuiTextUnit(iri, label, parentIri, false); if (!await GuiTextUnit.isPageAysnc(qService, iri)) { // if the thing is a textUnit guiTextUnit.textUnit = await TextUnit.buildFromStoreAsync(qService, iri); guiTextUnit.wholePage = false; // default is true, so we have to set it here } if (await GuiTextUnit.isPageAysnc(qService, iri)) { // if the thing is a page // the thing is a page, the iri passed a pages iri, but we already add a new textUnit // in every case so it can be switched easily to that created one const pageData = await TlnCrossrefPage.buildFromStoreAsync(qService, iri); guiTextUnit.textUnit = TextUnit.createNewTextUnit(pageData.pageIri, pageData, parentIri); guiTextUnit.textUnit.setDeleted(); // set the textUnit to deleted hence there is no textUnit if it is wholepage } return guiTextUnit; } static async createNewGuiTextUnit(qService, pageIri, label, parentIri, checkOut = true) { const guiTextUnit: GuiTextUnit = new GuiTextUnit(pageIri, label, parentIri, checkOut); const pageData = await TlnCrossrefPage.buildFromStoreAsync(qService, pageIri); guiTextUnit.textUnit = TextUnit.createNewTextUnit(pageIri, pageData, parentIri); guiTextUnit.textUnit.setDeleted(); // set the textUnit to deleted hence there is no textUnit if it is wholepage return guiTextUnit; } static async isPageAysnc(qService, iri) { const type = await RdfStoredData.getRdfTypeFromStore(qService, iri); return type === 'http://www.nie.org/ontology/nietzsche#Page'; } // resets the wholePage boolean and changes the iri according to the chosen state (wholepage means that there is not a textUnit - // it is a page) setWholePage(truthVal: boolean) { this.wholePage = truthVal; if (truthVal) { // if wholePage === true then there is only a link to the page and no textUnit at all. So we set the iri to the pages Iri and the // textUnit to deleted this._iri = this.textUnit.pageData.pageIri; this.textUnit.setDeleted(); } else { this._iri = this.textUnit.iri(); this.textUnit.setUndeleted(); } } } export class TextUnit extends CrossRefEditorElement { _belongsToPage: string; private _startLine?: string; private _endLine?: string; pageData: TlnCrossrefPage; displayedLabel: string; displayedStartLine: number; displayedEndLine: number; selectedLines: string[]; startLinePredicate: TlnPredicate; endLinePredicate: TlnPredicate; belongsToPagePredicate: TlnPredicate; constructor(iri: string, label: string, pageData?: TlnCrossrefPage, parentIri: string = '', checkOut = false, parentLabel?: string, startLine?: string, endLine?: string, startLineNumber?: number, endLineNumber?: number) { super(iri, label, parentIri, checkOut, parentLabel); // this.rdfsType= 'http://www.nie.org/ontology/nietzsche#PartOfPageTextUnit'; this.startLinePredicate = new TlnPredicate('http://www.nie.org/ontology/nietzsche#startLine', new Set(['http://www.w3.org/2001/XMLSchema#anyURI'])); this.endLinePredicate = new TlnPredicate('http://www.nie.org/ontology/nietzsche#endLine', new Set(['http://www.w3.org/2001/XMLSchema#anyURI']) ); this.belongsToPagePredicate = new TlnPredicate('http://www.nie.org/ontology/nietzsche#belongsToPage', new Set(['http://www.w3.org/2001/XMLSchema#anyURI'])) this.pageData = pageData; this._startLine = startLine; this._endLine = endLine; this.selectedLines = []; this.setLines(startLine, startLineNumber, endLine, endLineNumber); } static async buildFromStoreAsync(qService: QueryService, iri) { const textUnit = new TextUnit(iri, 'Texteinheit' ); textUnit.resource = await TlnResource.buildFromStoreAsync(qService, iri); textUnit._belongsToPage = textUnit.resource.rdfDatasetFromStore().getFirstObject(textUnit.belongsToPagePredicate.iri()); textUnit.pageData = await TlnCrossrefPage.buildFromStoreAsync(qService, textUnit._belongsToPage); textUnit._startLine = textUnit.resource.rdfDatasetFromStore().getFirstObject(textUnit.startLinePredicate.iri()); textUnit.displayedStartLine = textUnit.getLineNumber(textUnit._startLine); textUnit._endLine = textUnit.resource.rdfDatasetFromStore().getFirstObject(textUnit.endLinePredicate.iri()); textUnit.displayedEndLine = textUnit.getLineNumber(textUnit._endLine); textUnit.setSelectedLines(textUnit._startLine, textUnit._endLine); return textUnit; } // creates a new TextUnit which is not yet in store static createNewTextUnit(pageIri: string, pageData: TlnCrossrefPage, parentIri: string) { const textUnit = new TextUnit('', 'Texteinheit', pageData, parentIri); textUnit._belongsToPage = pageIri; const a = new TlnPredicate('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'); textUnit.resource._rdfDatasetToEdit.statements().putAgentStatement(a, 'http://www.nie.org/ontology/nietzsche#PartOfPageTextUnit'); textUnit.resource._rdfDatasetToEdit.statements().putAgentStatement(textUnit.belongsToPagePredicate, pageIri); return textUnit; } // returns the lineNumber for a given lineIri getLineNumber(lineIri: string) { return this.pageData.lineData[this.pageData.lineData.findIndex(l => l.line === lineIri)].lNumber; } setLines(sLine: string, sLineNo: number, eLine: string, eLineNo: number){ if (sLine && sLineNo && eLine && eLineNo) { this.setStartLine(sLine, sLineNo); this.setEndLine(eLine, eLineNo); this.setSelectedLines(sLine, eLine); } } startLine() { return this._startLine } hasStartLine() { return this._startLine !== undefined && this._startLine !== null } endLine() { return this._endLine } hasEndLine() { return this._endLine !== undefined && this._endLine !== null } // sets the selected lines for highlighting/passing to tln-page-view only public setSelectedLines(startLine: string, endLine?: string) { if (!endLine || endLine === undefined) { this.selectedLines = [this.startLine()] } else { let started = false; let ended = false; this.pageData.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); } }); } } // sets or resets the startLine depending on its existance setStartLine(startLine: string, lineNumber: number) { this._startLine = startLine; this.displayedStartLine = lineNumber; this.setSelectedLines(this.startLine()); if (this.endLine()) {this.deleteEndLine();}// resetting the startline must delete the selected endline if (this.resource._rdfDatasetToEdit.hasStatementEntriesForPredicate(this.startLinePredicate.iri())) { this.resource._rdfDatasetToEdit.setStatement(this.startLinePredicate, startLine, 0); } else {this.resource._rdfDatasetToEdit.putStatement(this.startLinePredicate, startLine);} } setEndLine(endLine: string, lineNumber: number) { this._endLine = endLine; this.displayedEndLine = lineNumber; this.setSelectedLines(this.startLine(), endLine); if (this.resource._rdfDatasetToEdit.hasStatementEntriesForPredicate(this.endLinePredicate.iri())) { this.resource._rdfDatasetToEdit.setStatement(this.endLinePredicate, endLine, 0); } else {this.resource._rdfDatasetToEdit.putStatement(this.endLinePredicate, endLine);} } deleteEndLine() { this._endLine = null; this.displayedEndLine = null; } } export interface Line { line: string; lNumber: number; } export class TlnCrossrefPage { lineData: Line[]; deleted = false; constructor(public pageIri: string, public pageNumber?: Number, public thumb?: SafeUrl, public svg?: SafeUrl) { } // async builder public static async buildFromStoreAsync(qService: QueryService, pageIri: string): Promise { const query = QueryService.bindVariableWithIri(PAGE_PREVIEW_RQ, 'page', pageIri); const crossRefPage = await qService.getData(BASEURL, query,'SELECT') .then( pageData => { let page = pageData['results']['bindings'][0]; let pageNumber = page['pageNumber'] && page['pageNumber']['value']? page['pageNumber']['value']: ''; let thumb = page['thumb'] && page['thumb']['value']? page['thumb']['value']: ''; let svg = page['svgUrl'] && page['svgUrl']['value']? page['svgUrl']['value']: ''; return new TlnCrossrefPage(pageIri, pageNumber, thumb, svg); }); crossRefPage.lineData = await TlnCrossrefPage.getLineData(pageIri, qService); return crossRefPage; } // sets the lineData available for the checked out textUnit public static async getLineData(pageIri: string, qService: QueryService) { const lines = await TlnCrossrefPage.getLinesFromStore(pageIri, qService); return lines.map(line => { return {line: line['line']['value'], lNumber: line['lNumber']['value']} }); } public static async getLinesFromStore(pageIri: string, qService: QueryService): Promise { const query = await qService.parametrizeWhereClauseWithItems(RQ_CROSSREF_TREE_LINES, pageIri, '', ''); return await qService.getData(BASEURL, query, 'SELECT').then(res => { return res['results']['bindings']; }); } } export const PAGE_PREVIEW_RQ = ` PREFIX tln: PREFIX rdf: PREFIX xsd: SELECT DISTINCT ?page ?pageNumber ?image ?svgUrl ?thumb WHERE { ?page ?p ?o. OPTIONAL { ?page tln:hasNumber ?pageNumber. ?page tln:hasSvgImage ?svg. ?svg tln:hasPrimaryurl ?svgUrl. ?page tln:hasFaksimileImage ?image. ?image tln:hasFileName ?imgLabel; tln:hasPrimaryurl ?primaryUrl; tln:hasThumburl ?thumb; } }`; diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.html index c431d7d..de9f899 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.html +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.html @@ -1,40 +1,40 @@ Textauswahl taskgesamte Seite ruleZeilenauswahl

Erfassen sie hier den Textbereich innerhalb der ausgewählten Seiten. Klicken Sie hierzu per Mausklick auf die entsprechende Zeilennummer der Start- und Endeile der Textversion.

Startzeile: {{guiTextUnit.textUnit.displayedStartLine}}*

Endzeile: {{guiTextUnit.textUnit.displayedEndLine}}*

GESAMTE SEITE
- +
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.ts index 7282357..7bd84f7 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component.ts @@ -1,55 +1,55 @@ import {Component, OnChanges, forwardRef, Inject} from '@angular/core'; import {CrossrefEditorDataServiceService, GuiTextUnit, TextUnit} from '../../crossref-editor-data-service.service'; import {TlnQueryServiceInterface} from '../../../tln-edition/models'; import {NavigationServiceService} from '../../../services/navigation-service.service'; import {MatButtonToggleChange} from '@angular/material'; import {NG_VALUE_ACCESSOR} from '@angular/forms'; import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; @Component({ selector: 'app-line-selector-component', templateUrl: './line-selector-component.component.html', styleUrls: ['./line-selector-component.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => LineSelectorComponentComponent), } ] }) export class LineSelectorComponentComponent implements OnChanges { // subscribe to page selections linesOfPages: Map; // The page data with all the lines // For passing into TlnPageView ... max_width: number; queryService: TlnQueryServiceInterface; preferPrimaryUrl = true; constructor(private naviService: NavigationServiceService, private dataService: CrossrefEditorDataServiceService, private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public guiTextUnit: GuiTextUnit) { this.linesOfPages = new Map(); this.setLinesOfPages(this.guiTextUnit.textUnit.pageData); this.linesOfPages.set(this.guiTextUnit.textUnit.pageData.pageIri, this.guiTextUnit.textUnit.pageData.lineData); this.max_width = window.innerWidth/1.5; } ngOnChanges() { } public changeWholePage({ value }: MatButtonToggleChange) { const isTrue = (value === 'true'); - this.dataService.changeWholePage(this.guiTextUnit.textUnit, isTrue); + this.dataService.changeWholePage(this.guiTextUnit, isTrue); } setLinesOfPages(pageData) { console.log(pageData); } closeDialog() { this.dialogRef.close(); } } diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.html index ba614b0..7a9ed2f 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.html +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.html @@ -1,59 +1,59 @@

Ziehen Sie die Manuskriptseiten der Textversion von der Navigationsleiste links per Drag'n drop in das Feld "Texteinheiten". Die Reihenfolge der erfassten Seiten lässt sich ebenfalls per Drag'n drop ändern.

-
{{internalTextVersion.iri()}}
+
{{internalTextVersion.iri()}}
Seiten/Texteinheiten check * Texteinheit S. {{unit.textUnit.pageData.pageNumber}}: (gesamte Seite) Zeilen {{unit.textUnit.displayedStartLine}}-{{unit.textUnit.displayedEndLine}}
{{unit.iri()}}
hier Seiten ablegen ...
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.ts index 5b63ccb..2c47747 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component.ts @@ -1,92 +1,92 @@ import {Component, Input, OnChanges} from '@angular/core'; import {CdkDragDrop} from '@angular/cdk/drag-drop'; import {NavigationEntity} from '../../../models/models'; import {NavigationServiceService} from '../../../services/navigation-service.service'; import {ActivatedRoute} from '@angular/router'; import { CrossrefEditorDataServiceService, InternalTextVersion, GuiTextVersion, TlnCrossrefPage } from '../../crossref-editor-data-service.service'; import {TlnQueryServiceInterface} from '../../../tln-edition/models'; import {MatDialog} from '@angular/material/dialog'; import {LineSelectorComponentComponent} from '../line-selector-component/line-selector-component.component'; @Component({ selector: 'app-page-collector-component', templateUrl: './page-collector-component.component.html', styleUrls: ['./page-collector-component.component.scss'] }) export class PageCollectorComponentComponent implements OnChanges { @Input() instanceIdx: number; // the number of the instance @Input() internalTextVersion: InternalTextVersion; @Input() pages: TlnCrossrefPage[] = []; instanceId: string; // lines ... linesOfPages: Map; // The page data with all the lines // For passing to TlnPageView ... max_width: number; queryService: TlnQueryServiceInterface; preferPrimaryUrl = true; // selected start and endLine ... startLine: string; endLine: string; constructor(private naviService: NavigationServiceService, private activatedRoute: ActivatedRoute, private dataService: CrossrefEditorDataServiceService, public dialog: MatDialog) { this.linesOfPages = new Map(); } ngOnChanges() { this.instanceId = `crossref-editor-drop-list-${this.instanceIdx}`; if ( this.internalTextVersion.hasTextUnits() ) { this.internalTextVersion.guiTextUnits().forEach(tUnit => { if (!tUnit.wholePage && tUnit.textUnit && tUnit.textUnit._belongsToPage) { this.linesOfPages.set(tUnit.textUnit._belongsToPage, tUnit.textUnit.pageData.lineData); } }); } this.max_width = window.innerWidth / 2; } itemDropped(event: CdkDragDrop) { if (event.previousContainer === event.container) { - this.dataService.movePageInArray(event.previousIndex, event.currentIndex) + this.dataService.movePageInArray(event.previousIndex, event.currentIndex); } else { this.dataService.onAddingPage(event.item.data, event.currentIndex); } } removeFromCollection(itemToRemove: string) { this.dataService.onRemovePage(itemToRemove); } unDelete(iri: string) { this.dataService.undeleteGuiTextUnit(iri); } openLineSelectorDialog(textUnitIri): void { this.checkoutTextUnit(textUnitIri); console.log('opening dialoge with ', this.internalTextVersion.checkedOutTextUnit()) const dialogRef = this.dialog.open(LineSelectorComponentComponent, { width: '90vw', height: '90vh', data: this.internalTextVersion.checkedOutTextUnit() }); dialogRef.afterClosed().subscribe(result => { console.log('The dialog was closed'); }); } checkoutTextUnit(textUnitIri) { this.dataService.textGenesis.checkedOutTextVersion().internalTextVersion.checkOutTextUnit(textUnitIri); } } 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 0941580..5f26220 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,44 +1,44 @@ import {Component, Input, OnChanges, OnDestroy} from '@angular/core'; import { CrossrefEditorDataServiceService, InternalTextVersion, TextGenesis, GuiTextVersion, TlnCrossrefPage } from '../../crossref-editor-data-service.service'; import {NavigationServiceService} from '../../../services/navigation-service.service'; import {Subscription} from 'rxjs'; import {TlnEntity} from '../../../models/models'; @Component({ selector: 'app-text-version-editor-component', templateUrl: './text-version-editor-component.html', styleUrls: ['./text-version-editor-component.scss'] }) export class TextVersionEditorComponent implements OnChanges, OnDestroy { @Input() versionIdx: number; @Input() textVersion: GuiTextVersion; pages: TlnCrossrefPage[] = []; extTitle: string; // the external textversions Title constructor(private naviService: NavigationServiceService, private dataService: CrossrefEditorDataServiceService) { } ngOnChanges() { // updating title this.extTitle = this.textVersion.externalTextVersion.resource._rdfDatasetToEdit.getFirstObject('http://www.nie.org/ontology/nietzsche#textUnitHasTitle') } ngOnDestroy() { // this.textGenesisSubscription.unsubscribe(); } resetPagesAfterChanges(tGenesis: TextGenesis) { console.log('reset Pages with:', tGenesis); this.textVersion = tGenesis.checkedOutTextVersion(); - if (tGenesis.checkedOutTextVersion().internalTextVersion._pagesCollection) { - this.pages = tGenesis.checkedOutTextVersion().internalTextVersion._pagesCollection; + if (tGenesis.checkedOutTextVersion().internalTextVersion.pagesCollection()) { + this.pages = tGenesis.checkedOutTextVersion().internalTextVersion.pagesCollection(); } } updateExtTitle() { this.dataService.textGenesis.checkedOutTextVersion().externalTextVersion.setTitle(this.extTitle) } }