diff --git a/nietzsche-beta-app/src/app/app.module.ts b/nietzsche-beta-app/src/app/app.module.ts index b8b7e78..d57f6dc 100644 --- a/nietzsche-beta-app/src/app/app.module.ts +++ b/nietzsche-beta-app/src/app/app.module.ts @@ -1,103 +1,105 @@ import { AppComponent } from './app.component'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import {DragDropModule} from '@angular/cdk/drag-drop'; import { FormsModule, ReactiveFormsModule} from '@angular/forms'; import { NgModule } from '@angular/core'; import {MatCardModule} from '@angular/material/card'; import {MatButtonToggleModule, MatChipsModule} from '@angular/material'; import {MatFormFieldModule} from '@angular/material/form-field'; 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 {MatRadioModule} from '@angular/material/radio'; 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 { CrossrefEditorComponentComponent } from './crossref-editor-component/crossref-editor-component.component'; import { PageCollectorComponentComponent } from './crossref-editor-component/text-genesis-editor/page-collector-component/page-collector-component.component'; import { LineSelectorComponentComponent } from './crossref-editor-component/text-genesis-editor/line-selector-component/line-selector-component.component'; import { TextVersionEditorComponent } from './crossref-editor-component/text-genesis-editor/text-version-editor-component/text-version-editor-component'; import { TextGenesisEditorComponent } from './crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component'; -import { TextGeneseSelectorComponentComponent } from './crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component'; -import { TextgeneseSelectorDialogueComponentComponent } from './crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component'; +import { TextGeneseSelectorComponentComponent } from './crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component'; +import { TextgeneseSelectorDialogueComponentComponent } from './crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component'; +import { ExistingTextGenesisWorkflowComponentComponent } from './crossref-editor-component/existing-text-genesis-workflow-component/existing-text.genesis-workflow-component.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, CrossrefEditorComponentComponent, PageCollectorComponentComponent, LineSelectorComponentComponent, TextVersionEditorComponent, TextGenesisEditorComponent, ManuscriptViewComponentComponent, ContentViewTabComponentComponent, RhizomeViewComponentComponent, MainMenuComponentComponent, PageViewWrapperComponent, NavigationListComponentComponent, NavTree, LazyImageLoadDirectiveDirective, ImpressumComponent, ProjectComponent, NavigationlistListComponentComponent, TextGeneseSelectorComponentComponent, - TextgeneseSelectorDialogueComponentComponent + TextgeneseSelectorDialogueComponentComponent, + ExistingTextGenesisWorkflowComponentComponent ], imports: [ routing, BrowserModule, BrowserAnimationsModule, CommonModule, DragDropModule, HttpClientModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatChipsModule, MatExpansionModule, MatFormFieldModule, MatIconModule, MatListModule, MatMenuModule, MatProgressBarModule, MatRadioModule, MatSelectModule, // for themes selection MatSidenavModule, MatTabsModule, MatToolbarModule, MatTooltipModule, MatTreeModule, FormsModule, TlnEditionModule, ReactiveFormsModule ], providers: [ NavigationServiceService, QueryService ], bootstrap: [AppComponent], entryComponents: [LineSelectorComponentComponent, TextgeneseSelectorDialogueComponentComponent] }) export class AppModule { } diff --git a/nietzsche-beta-app/src/app/constants.ts b/nietzsche-beta-app/src/app/constants.ts index edd0c21..a7159fb 100644 --- a/nietzsche-beta-app/src/app/constants.ts +++ b/nietzsche-beta-app/src/app/constants.ts @@ -1,313 +1,396 @@ 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'; // endpoint && rdf related constants export const BASEURL: string = 'https://nietzsche.fuseki.services.dasch.swiss/nietzsche'; -export const EDITINGURL: string = 'http://localhost:3030/nietzsche-rw'; +export const EDITINGURL: string = 'http://localhost:3030/nietzsche-rw/query'; export const WRITEURL: string = 'http://localhost:3030/nietzsche-rw/update'; export const NAMESPACES: {} = { data: 'http://rdfh.ch/projects/0068#', tln: 'http://www.nie.org/ontology/nietzsche#' -} +}; 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', } } } ]; +export const RQ_AVAILABLE_PROPERTIES = ` +PREFIX rdfs: + +select DISTINCT ?prop ?range { + ?prop rdfs:domain ?anyClassToParametrize . + ?prop rdfs:range ?range . +}`; + +export const RQ_ASK_EXISTS_IN_STORE = ` +ASK WHERE { + ?subjectToParametrize ?p ?o +}`; + +export const RQ_ASK_IF_CLASS_INSTANCE = ` +PREFIX rdf: +PREFIX rdfs: +PREFIX owl: + +ASK WHERE { + ?iriToReplace rdf:type ?rdfType . + ?rdfType rdf:type/rdfs:subClassOf* owl:Class . + } +`; + +export const RQ_ASK_IF_PROPERTY = ` +PREFIX rdf: +PREFIX rdfs: +PREFIX owl: + +ASK WHERE { + ?thingToReplace rdf:type/rdfs:subClassOf* owl:ObjectProperty . +}`; + +export const RQ_RDF_Type = ` +PREFIX rdf: +PREFIX rdfs: + +SELECT ?rdf_type ?typeoftype WHERE { + ?thingToParametrize rdf:type ?rdf_type . + ?rdf_type rdf:type ?typeoftype . +}`; + +export const RQ_GET_PROPERTY_VALUE = ` +PREFIX rdfs: + +select ?value { + ?s ?p ?value +}`; + +export const RQ_GET_DOMAIN = ` +PREFIX rdfs: +PREFIX tln: + +select ?domain WHERE { + ?predicateToExchange rdfs:domain ?domain .} +`; + +export const RQ_GET_RANGE = ` +PREFIX rdfs: +PREFIX tln: + +select ?range WHERE { + ?predicateToExchange rdfs:range ?range . } +`; + + + +export const RQ_CONSTRUCT_LISTS = ` +prefix rdf: +PREFIX tln: + +CONSTRUCT { + ?thingToReplace ?propertyToReplace ?list . + ?listRest rdf:first ?head ; + rdf:rest ?tail . +} WHERE { + ?thing tln:hasGeneticOrder ?list . + + ?list rdf:rest* ?listRest . + ?listRest rdf:first ?head ; + rdf:rest ?tail . +} +`; // 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 ?type WHERE { ?s (tln:hasPages/(rdf:rest*)/rdf:first) ?page. ?page tln:hasNumber ?pageNumber. ?page a tln:Page. BIND (tln:page AS ?type) BIND (xsd:integer(REPLACE(?pageNumber, "\\\\D+", "")) AS ?sorting) } ORDER BY (?sorting) `; export const RQ_CROSSREF_TREE_LINES: string = ` PREFIX tln: PREFIX rdf: PREFIX xsd: SELECT DISTINCT ?line ?lNumber ?type WHERE { ?s (tln:hasLines/(rdf:rest*)/rdf:first) ?line. ?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 ?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', 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', 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', 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 663e3f5..683b451 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,25 +1,25 @@ - +
- +
-
- +
+
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts index c3b5c56..cf6727f 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/crossref-editor-component.component.ts @@ -1,37 +1,41 @@ import {Component, OnChanges} from '@angular/core'; import {CrossrefEditorDataServiceService, TextGenesis, TextVersion} from './crossref-editor-data-service.service'; import {ActivatedRoute} from '@angular/router'; import {TlnQueryService} from '../tln-edition/tln-query.service'; +import {QueryService} from '../services/query.service'; @Component({ selector: 'app-crossref-editor-component', templateUrl: './crossref-editor-component.component.html', styleUrls: ['./crossref-editor-component.component.scss'] }) export class CrossrefEditorComponentComponent implements OnChanges { textGenesis: TextGenesis; editExistingTextGenesis = false; // whether an existing Textgenesis should be edited + addNewTextGenesis = false; // whether an existing Textgenesis should be edited constructor(private dataService: CrossrefEditorDataServiceService, - private activatedRoute: ActivatedRoute) { + private activatedRoute: ActivatedRoute, + private queryService: QueryService) { } ngOnChanges() { } initNewTextgenesis() { - this.textGenesis = new TextGenesis('TextGenesis', this.activatedRoute.snapshot.queryParamMap.get('manuscript')); + this.addNewTextGenesis = true; + this.textGenesis = new TextGenesis( this.queryService, 'TextGenesis', '', true, this.activatedRoute.snapshot.queryParamMap.get('manuscript')); this.textGenesis.checkOut(true); // also adding new text version - let version = new TextVersion('TextVersion', this.textGenesis.iri); + let version = new TextVersion(this.queryService, '', this.textGenesis.iri, false, false, this.textGenesis.iri ); this.textGenesis.addTextVersion(version, 0); // emit to service this.dataService.updateAll(this.textGenesis); } editExisting() { this.editExistingTextGenesis = true; } } 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 39c81e7..96d1011 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,570 +1,1150 @@ -import {EventEmitter, Injectable} from '@angular/core'; +import {EventEmitter, Injectable, Predicate} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; -import {BASEURL, NAMESPACES, RQ_CROSSREF_TREE_LINES, WRITEURL} from '../constants'; +import { + BASEURL, EDITINGURL, NAMESPACES, RQ_ASK_EXISTS_IN_STORE, RQ_ASK_IF_CLASS_INSTANCE, RQ_ASK_IF_PROPERTY, RQ_AVAILABLE_PROPERTIES, + RQ_CONSTRUCT_LISTS, + RQ_CROSSREF_TREE_LINES, RQ_GET_DOMAIN, + RQ_GET_PROPERTY_VALUE, RQ_GET_RANGE, RQ_RDF_Type, + 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'; +import {NamedNode} from 'rdf-js'; +import {Subscription} from 'rxjs'; +import {__await} from 'tslib'; @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) => { - if (clickedLine.page === this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().belongsToPage) { + if (clickedLine.page === this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().belongsToPage) { this.setLine(clickedLine); this.updateAll(this.textGenesis); } }) } + readInTextGenesis(textGenesisIri: string) { + textGenesisIri = 'http://rdfh.ch/projects/0068#_Mp_XIV_TextGenesis0' ; // Todo: make generic + const textGenesis = new TextGenesis(this.qService, 'Textgenese', textGenesisIri, true ); + 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().checkedOutTextUnit().hasStartLine() || ( - this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().hasStartLine() && - this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().hasEndLine() ) + if (!this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().hasStartLine() || ( + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().hasStartLine() && + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().hasEndLine() ) ) { - this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setStartLine(line.id, line.number); + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().setStartLine(line.id, line.number); } else { // endLine must be set - this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setEndLine(line.id, line.number); + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().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().isExternalResource = setToExternal; + // uncheckout + !setToExternal ? this.textGenesis.checkedOutTextVersion().externalTextVersion.checkOut(false) : + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkOut(false); + // checkout + setToExternal ? this.textGenesis.checkedOutTextVersion().externalTextVersion.checkOut(true) : + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkOut(true); + this.updateAll(this.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); + const textUnit = new TextUnit( + this.qService, + 'textResource', + '', + false, + 'http://www.nie.org/ontology/nietzsche#PartOfPageTextUnit', + navItem.tlnEntity.iri, + true, + navItem.tlnEntity.description, + navItem.tlnEntity.label, + navItem); + this.textGenesis.checkedOutTextVersion().internalTextVersion.setTextUnit(textUnit, index); this.updateAll(this.textGenesis); } movePageInArray(previousIndex: number, index: number) { - this.textGenesis.checkedOutTextVersion().moveTextUnitInArray(previousIndex, index) + this.textGenesis.checkedOutTextVersion().internalTextVersion.moveTextUnitInArray(previousIndex, index) this.updateAll(this.textGenesis); } - - removePage(pageIri: string) { - this.textGenesis.checkedOutTextVersion().deleteTextUnit(pageIri); + removeTextUnit(textUnitIri: string) { + this.textGenesis.checkedOutTextVersion().internalTextVersion.deleteTextUnit(textUnitIri); this.updateAll(this.textGenesis); } setWholePage(textUnit: TextUnit, truthVal: boolean) { - this.textGenesis.checkedOutTextVersion().checkedOutTextUnit().setWholePage(truthVal); - const idx = this.textGenesis.checkedOutTextVersion().getTextUnitIdxByIri(textUnit.iri); + this.textGenesis.checkedOutTextVersion().internalTextVersion.checkedOutTextUnit().setWholePage(truthVal); + const idx = this.textGenesis.checkedOutTextVersion().internalTextVersion.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.textGenesis.checkedOutTextVersion().internalTextVersion._rdfDatasetToEdit.setStatement('identifiesAsVersion', textUnit.belongsToPage, idx); + } else { this.textGenesis.checkedOutTextVersion().internalTextVersion._rdfDatasetToEdit.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(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); } }); }); } + + readInTtl (ttlData: string, prefixes?) { + + 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); + } } -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. +export class CrossRefEditorElement { + private checkedOut: boolean; // wether the thing is checked out for editing atm or not. + constructor(){ + + } + + checkOut(val: boolean) { + this.checkedOut = val; + } + + isCheckedOut() { + return this.checkedOut; + } + + // builds an unique iri with the given iri, its parent and a generated hash + static createIri(label: string, parentIri?: string) { + const hash = `${Date.now().valueOf().toString(36)}-${(Math.random()).toString(36).replace('.', '')}`; // unique hash: + return `${parentIri}_${label}_${hash}`; + } +} + +// RdfData +export class RdfData { + protected _iri: string; // the subjects iri + protected _selfStatement: N3.NamedNode; + protected _rdfType: string; // rdfs type uf the subject + protected _rootType: string; // owl:Class or owl:ObjectProperty + protected _domain: string; // For predicates only: rdfs domain; assuming there is only one (the first) + protected _range: string; // For predicates only: rdfs range; assuming there is only one (the first) + protected _exists: boolean; // exists in store + protected _availablePredicates: TlnPredicate[] = []; // For Resources as subject: all the available predicates eith its range + protected _statements = new Map(); // all the properties && their objects extracted from lists + protected _listStatements = new Map(); // For Resources/Subjects all the statements as lists + + constructor() { + } 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; + + // protected Methods + + protected setStmt(property: string, objectIri:string, index?) { + if (!this._statements.has(property)) {// if there is not yet a key for that property + this._statements.set(property, new TlnStatements(property)) + } + this._statements.get(property).setObject(objectIri, index); } - // 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}` + // returns whether the thing is a resource or not + protected setResourceRootType() { + this._rootType = 'http://www.w3.org/2002/07/owl#Class'; + } + + // returns whether the thing is a predicate or not + protected setPredicateRootType() { + this._rootType = 'http://www.w3.org/2002/07/owl#ObjectProperty'; + } + + // public methods + + public iri() { + return this._iri; + } + + public exists() { + return this._exists; + } + + public rdfType() { + return this._rdfType; + } + + public rootType() { + return this._rootType; + } + + public domain() { + return this._domain; + } + + public range() { + return this._range; + } + + // returns whether the thing is a resource or not + isResource(): boolean { + return this._rootType === 'http://www.w3.org/2002/07/owl#Class'; + } + + // returns whether the thing is a predicate or not + isPredicate(): boolean { + return this._rootType === 'http://www.w3.org/2002/07/owl#ObjectProperty'; } - hasStatement(property: string) { - return this.statements.get(property) !== undefined && this.statements.get(property) !== null; + public selfStatement() { + return this._selfStatement; } - hasStatementEntries(property) { - return this.statements.get(property).objects().length > 0; + public availablePredicates(): TlnPredicate[] { + return this._availablePredicates; } - getStatementIdx(property: string, iri: string) { - return this.statements.get(property).objects().findIndex(obj => obj === iri) + public hasStatement(property: string) { + return this._statements.get(property) !== undefined && this._statements.get(property) !== null; } - setStatement(property: string, objectIri:string, index) { - this.statements.get(property).setObject(objectIri, index); + public hasStatementEntries(property) { + return this._statements.get(property).objects().length > 0; } - deleteStatement(property: string, index: number) { + //Todo: delete? + public getStatementIdx(property: string, iri: string) { + return this._statements.get(property).objects().findIndex(obj => obj === iri) + } + + public statements() { + return this._statements; + } +} + + +// RdfStoredData represents the data which is stored in the triple store. It gets and contains then all necessary data for any given iri +// from the triple store. +export class RdfStoredData extends RdfData{ + + constructor(private qService: QueryService) { + super(); + } + // async rdfDataFactory, execution waits until the instance is ready + static async rdfDataFactory(queryService: QueryService, iri) { + const rdfStoredData = await new RdfStoredData(queryService); + if (!await rdfStoredData.askIfInStore(iri)) {return null} // guard if iri not living in store + await rdfStoredData.setExistingRdfData(iri); + return rdfStoredData; + } + + // wrapper method for constructing the data + private async setExistingRdfData(iri: string) { + this._iri = iri; + this._exists = true; + this._selfStatement = new N3.NamedNode(iri); + if (await this.askIfResource(iri)) { // if it is a resource + await this.setResource(iri) } + else if (await this.askIfPredicate(iri)) { // if it is a predicate + await this.setPredicate(iri) } + } + + private async setResource(iri: string) { + this.setResourceRootType(); // root type of instances is always owlClass + this._rdfType = await this.getRdfTypeFromStore(iri); + this._selfStatement = RdfData.selfStatement(iri, this._rdfType) + this._availablePredicates = await this.getAvailablePredicatesFromStore(this._rdfType); + this.setStatementsFromStore(this._availablePredicates); + } + + private setPredicate(predicateIri: string) { + this.setPredicateRootType(); + this._rdfType = predicateIri; + this.getDomainFromStore(predicateIri).then(domain => this._domain = domain); + this.getRangeFromStore(predicateIri).then(range => this._range = range) + } + + // sets all statements for all given predicates as ttl list + private setAllListStatementsFromSore(predicates: TlnPredicate[]){ + predicates.forEach(p => { + if (p.takesList()) { + this.setListStatement(p.iri); + } + }) + } + + private setStatementsFromStore(availablePredicates?: TlnPredicate[]) { + availablePredicates.forEach(p => { + if (p.takesList()) { // if the predicate expects a list as object + this.setListStatement(p.iri); + } else {console.log('my property has range: ', p.iri, p.range)} // Todo: set for other cases + }); + } + + // sets all the statements of a given predicate as list to _statementsAsTtlList + private setListStatement(predicateIri: string) { + this.getListDataFromStore(predicateIri).then( + list => this._listStatements.set(predicateIri, list.toString() )); + } + + // asks wether an iri is an instance of a Class + private async askIfResource(iri: string): Promise { + const query = this.qService.parametrizeQueryWithItem(RQ_ASK_IF_CLASS_INSTANCE, iri); + return await this.qService.getData(EDITINGURL, query, 'ASK') + .then(isResource => (isResource['boolean'])); + } + + private async askIfPredicate(iri: string): Promise { + const query = this.qService.parametrizeQueryWithItem(RQ_ASK_IF_PROPERTY, iri); + return await this.qService.getData(EDITINGURL, query, 'ASK') + .then(isPredicate => (isPredicate['boolean'])); + } + + private async getRdfTypeFromStore(iri: string) { + const query = this.qService.parametrizeQueryWithItem(RQ_RDF_Type, iri); + return await this.qService.getData(EDITINGURL, query, 'SELECT') + .then( result => result['results']['bindings'].map(p => p['rdf_type'].value)[0]) + } + + private async getDomainFromStore(owlPropertyIri: string) { + const query = this.qService.parametrizeQueryWithItem(RQ_GET_DOMAIN, owlPropertyIri); + return await this.qService.getData(EDITINGURL, query, 'SELECT') + .then(result => result['results']['bindings'].map(p => p['domain'].value)[0]) + } + + private async getRangeFromStore(owlPropertyIri: string) { + const query = this.qService.parametrizeQueryWithItem(RQ_GET_RANGE, owlPropertyIri); + return await this.qService.getData(EDITINGURL, query, 'SELECT') + .then(result => this._range = result['results']['bindings'].map(p => p['range'].value)[0]) + } + + private async getAvailablePredicatesFromStore(rdfType: string): Promise { + const query = this.qService.parametrizeQueryWithItem(RQ_AVAILABLE_PROPERTIES, + '' , '', rdfType); + return await this.qService.getData(EDITINGURL, query, 'SELECT').then( + result => { + return result['results']['bindings'].map(p => new TlnPredicate(p['prop'].value, p['range'].value) ); + } + ) + } + + // gets the list as ttl for a given predicate + private getListDataFromStore(propertyIri: string): Promise { + let query = this.qService.parametrizeQueryWithItem(RQ_CONSTRUCT_LISTS, this._iri, propertyIri); + return this.qService.getData(EDITINGURL, query, 'CONSTRUCT' ); + } + + // public methods + + public async askIfInStore(iri: string): Promise{ + const query = this.qService.parametrizeQueryWithItem(RQ_ASK_EXISTS_IN_STORE, iri); + return await this.qService.getData(EDITINGURL, query, 'ASK') + .then(exists => (exists['boolean'])); + } + + public async exportAsEditorData(): Promise { + const editorData = new RdfEditorData(this._iri, this._rdfType, this._rootType, this._exists, this._domain, this._range); + await editorData.resetAvailablePredicates(this._availablePredicates); + await editorData.resetListStatements(this._listStatements); + await editorData.resetStatements(this._statements); + return editorData; + } +} + + +// RdfEditorData Contains the rdf data to edit which will be stored in the end +export class RdfEditorData extends RdfData { + + // _listsAsStatements = new Map(); // all the list entries as individual statements + constructor(iri: string, rdfType: string, rootType: string, exists = false, domain?: string, range?: string) { + super(); + this._iri = iri; + this._rdfType = rdfType; + this._rootType = rootType; + this._exists = exists; + this._domain = domain; + this._range = range; + } + + // public methods + + // makes setStm() available to RdfEditorData Instances + public setStatement(property: string, objectIri:string, index?) { + this.setStmt(property, objectIri, index); + } + + public deleteStatement(property: string, index: number) { if (this.hasStatement(property) && this.hasStatementEntries(property)) { - this.statements.get(property).deleteObject(index); + this._statements.get(property).deleteObject(index); } } - moveObjectInStatement(property: string, previousIndex, newIndex) { - this.statements.get(property).moveObject(previousIndex, newIndex); + public moveObjectInStatement(property: string, previousIndex, newIndex) { + this._statements.get(property).moveObject(previousIndex, newIndex); + } + + public createStatementsFromLists() { + this._listStatements.forEach((value, key )=> { + this.setStatementsFromList(key); + }) + } + + // adds proper statements from a list + public setStatementsFromList(predicate){ + const parser = new N3.Parser(); + parser.parse(this._listStatements.get(predicate).toString(), + (error, quad) => { + if (quad && quad.object.termType === 'NamedNode' && quad.object.value) { + console.log('setting statement: ', predicate, ' ', quad); + //setting statements + this.setStmt(predicate, quad.object.value); + } + }); + } + + // sets or resets all _availablePredicates + public resetAvailablePredicates(predicates: TlnPredicate[] = []) { + this._availablePredicates = predicates; } - //returns all statements as n3 quad array + // sets or resets all _statements + public resetStatements(statements: Map = new Map()) { + this._statements = statements; + } + + // sets or resets all _statements + public resetListStatements(listStatements: Map = new Map()) { + this._listStatements = listStatements; + } + + public createListFromStatements() { + } + + public createListsFromStatements() { + } +} + +// The main super class for every thing which has to be added/edited or deleted in the triple store +export class TlnResource extends CrossRefEditorElement{ + iri: string; + _rdfDatasetFromStore: RdfStoredData; + _rdfDatasetToEdit: RdfEditorData; + _rdfDatasetToDepricate: RdfEditorData; + parentIri: string; + parentLabel: string; + private _inStore: boolean; // exists in Store or in memory/JS only + private _depricated: boolean; + private _edited: boolean; // whether an existing thing has been edited or not + private _deleted: boolean; // whether a thing has been deleted in the frontend + private _depricatedBy: string; // user who deleted/exchanged/depricated + private _depricatedAt: string; // timestamp of deletion + childsPredicate: string; // the predicate to join children + children: any[] = []; + createChildren: boolean; // whether children will be created or not + _createChild: EventEmitter; + _childToCreate: Subscription; // subscribing to _creatChild of parent + + constructor(public qService: QueryService, + label: string, + existingIri: string, + createChildren = false, + rdfsType?: string, + parentIri?: string, + parentLabel?: string, + checkedOut = false) { + super(); + this.createChildren = createChildren; + this._createChild = new EventEmitter(); + + if (existingIri && existingIri !== '') { // if we like to edit sth existing in the store. + this.loadExistingThing(existingIri); + } else {// for newly generated things which are not yet existing in the store + this.iri = CrossRefEditorElement.createIri(label, parentIri); + this._inStore = false; + } + this.parentIri = parentIri; + this.parentLabel = parentLabel; + this.checkOut(checkedOut); + } + +// loads ab existing resource or predicate + async loadExistingThing(existingIri: string){ + this._inStore = true; + this.iri = existingIri; // TODO needed? + await RdfStoredData.rdfDataFactory(this.qService, existingIri).then( + rdfStoredData => { + this._rdfDatasetFromStore = rdfStoredData; + // creating the rdfDataToEdit from the data in store + rdfStoredData.exportAsEditorData().then(editorData => { + this._rdfDatasetToEdit = editorData; + }); + } + ); + + } + + + // creates/populates all statements from store data for a given property - only available for existing things loaded from store + async getAllChildrenFromStore() { + // get all available properties + this._rdfDatasetFromStore.availablePredicates().forEach(predicate => { + if (predicate.takesList()) { + // if the range of the predicate is a list ... + if (this.createChildren) { + // creating children, i.e. emitting the iri of the child, so the subsciption will create those for us. + this._createChild.emit(predicate.iri); + } + if ((predicate.range !== 'http://www.w3.org/1999/02/22-rdf-syntax-ns#List')) { + console.log('predicate.range', predicate.range); + // it is a NamedNode, so we set the statements + // Todo: get the objects data and setStatement + //this.setStatement(predicate, quad.object.value); + // and create new children if needed + + } + + } + + }); + } + + + moveChildInChildren(previousIndex: number, newIndex: number) { + moveItemInArray(this.children, previousIndex, newIndex); + this._rdfDatasetToEdit.moveObjectInStatement(this.childsPredicate, previousIndex, newIndex); + } + + public addChild(child: any, index?){ + this.children.push(child); + //this.setStatement(this.childsPredicate, this.iri, index); + } + + isInStore() { + return this._inStore; + } + + isEdited() { + return this._edited; + } + + isDepricated() { + return this._depricated; + } + + isDeleted() { + return this._deleted; + } + + rdfDatasetFromStore() { + return this._rdfDatasetFromStore; + } + + rdfDatasetToDepricate() { + return this._rdfDatasetToDepricate; + } + + depricate(iri: string) { + // Todo: TimeStamp concat to iri + const newIri: string = iri.concat(iri, 'depricated'); + this._depricatedBy = new N3.Quad(); // user + this._depricated = true; + } + + // marks an existing thing as deleted and depricates it in the rdf world + deleteExisting(iri: string) { + this.depricate(iri); + this._deleted = true; + } + + // resets the editorData with the data gathered from the triple store + async resetFromStore(){ + this._rdfDatasetToEdit = await this._rdfDatasetFromStore.exportAsEditorData(); + } + + + // returns all statements of a thing as n3.Quad[]; + // (properties with object) as n3 quad array in which there are both: the usual spo as well as a list containing all o's 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)); + if (this._rdfDatasetToEdit.statements().size > 0) { + this._rdfDatasetToEdit.statements().forEach((stm) => { + // adding objects to a list + quads.push(new N3.Quad(this._rdfDatasetToEdit.iri(), stm.property(), new N3.Writer().list(stm.objects()))); // list + // usual spo + stm.objects().forEach(object => { + // if there is an iri created for the thing, i.e. it is a new thing, we create new things + // TODO: Ontlogy + if (this.iri && stm.property() && object) { + quads.push(new N3.Quad(new N3.Term(this.iri), stm.property(), object)); } }); }); } return quads; } - // returns the thing with all statements as N3-quads/lists - quads(self?) { + // returns the thing with all its statements as N3-quads/lists + quads() { let quads: N3.Quads[] = [].concat(this.getStatementsAsQuads()); // concadinating so never undefined - - if (this.selfStatement !== undefined && this.selfStatement !== null) { - quads.splice(0,0, this.selfStatement); + // Sometimes there is none e.g. an existing page is part of identifiesAsVersion so we don't have to create iris & properties + // TODO Ontology + if (this._rdfDatasetToEdit.selfStatement() !== undefined && this._rdfDatasetToEdit.selfStatement() !== null) { + quads.splice(0,0, this._rdfDatasetToEdit.selfStatement()); } return quads; } - - checkOut(val: boolean) { - this.checkedOut = val; - } - - isCheckedOut() { - return this.checkedOut; - } } -export class TextGenesis extends TlnTextGenesisThing{ - private _textVersions: TextVersion[]; +export class TextGenesis extends TlnResource{ + childsPredicate = 'http://www.nie.org/ontology/nietzsche#hasGeneticOrder'; + private _textVersions: TextVersion[] = []; allQuads: N3.Quad[]; public ttl_export: string; public ttl_exportReady: EventEmitter; - 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; + constructor(qService: QueryService, + label: string, + existingIri: string = '', + createChildren = true, + rdfsType?: string, + parentIri?: string, + parentLabel?: string, + checkout = false) { + super(qService, label, existingIri, createChildren, rdfsType, parentIri, parentLabel, checkout); + console.log('createChildren', createChildren) + // const textVersionsList = new TlnList('http://www.nie.org/ontology/nietzsche#hasGeneticOrder', textVersions.map(t => t.iri)); + // this.statements.set('hasGeneticOrder', textVersionsList); + // this.rdfsType = 'http://www.nie.org/ontology/nietzsche#TextGenesis'; // used in TlnTextGenesisThing-methods + + if (this.isInStore()) { + this._childToCreate = this._createChild.subscribe(childIriToCreate => { + // creating an existing TextVersion + console.log('childIriToCreate', childIriToCreate) + let textVersion = new TextVersion(this.qService, childIriToCreate, this.iri); + this.addTextVersion(textVersion); + }); + } this.allQuads = []; this.ttl_exportReady = new EventEmitter(); } - public addTextVersion(textVersion: TextVersion, index){ + public addTextVersion(textVersion: TextVersion, index?){ this._textVersions.push(textVersion); - this.setStatement('hasGeneticOrder', textVersion.iri, index); + this._rdfDatasetToEdit.setStatement(this.childsPredicate, 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); + this._rdfDatasetToEdit.setStatement(this.childsPredicate, textVersion.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._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) + this._rdfDatasetToEdit.deleteStatement('hasGeneticOrder', delIndex) } // returns an array of all quads contained async getQuads(): Promise { this.allQuads = []; - const textGenesisQuads: N3.Quad[] = this.quads(this); + // adding the textGenesis quads + const textGenesisQuads: N3.Quad[] = this.quads(); this.allQuads = await [... this.allQuads, ... textGenesisQuads] + // adding the textVersion quads await this.textVersions().forEach(tVersion => { - this.allQuads = [...this.allQuads, ...tVersion.quads(tVersion)]; - tVersion.textUnits().forEach(tUnit => { + this.allQuads = [...this.allQuads, ...tVersion.internalTextVersion.quads()]; + tVersion.internalTextVersion.textUnits().forEach(tUnit => { if (!tUnit.wholePage) { - this.allQuads = [...this.allQuads, ...tUnit.quads(tUnit)]; + // 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, ...tUnit.quads()]; } }); }); return this.allQuads; } // check for completeness isComplete() { - return this.textVersions().every( tVersion => tVersion.isComplete() || - (tVersion.isExternalResource && tVersion.externalResourceHasUrl && tVersion.hasTitle)); + return this.textVersions().every( tVersion => tVersion.isComplete()); } } -export class TextVersion extends TlnTextGenesisThing{ - private _identifiesAsVersion: TextUnit[]; - private _pages: TlnEntity[]; +export class TextVersion extends CrossRefEditorElement{ + + iri: string; + label: string; + parentIri: string; // the textGenesis it belongs to + parentLabel: string; 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; + internalTextVersion: InternalTextVersion; // the internal TextVersion Resource with its properties from RDF + externalTextVersion: ExternalTextVersion; // the internal TextVersion Resource with its properties from RDF + + constructor(qService: QueryService, + iri: string, // iri of internal or external resource + parentIri: string, + inStore: boolean = false, + isExternalResource: boolean = false, + label?: string, + parentLabel?, + checkedOut = false) { + super(); + + if (iri !== '') { + this.iri = iri; + } else {// any random iri - does not matter + this.iri = CrossRefEditorElement.createIri(label, parentIri); } this.isExternalResource = isExternalResource; - this.externalResourceHasUrl = externalResourceHasUrl; - this.hasTitle = hasTitle; + this.label = label; + this.parentIri = parentIri; + this.parentLabel = parentLabel; + this.checkOut(checkedOut); + // creating both no matter what it is, so switching in the editing process is possible + this.externalTextVersion = new ExternalTextVersion(qService, label, iri, false, '', parentIri, parentLabel); + this.internalTextVersion = new InternalTextVersion(qService, label, iri, true, '', parentIri, parentLabel); + } + + isComplete() { + if (this.isExternalResource) { return this.externalTextVersion.isComplete() } else { + return this.internalTextVersion.isComplete(); + } + } +} + +export class InternalTextVersion extends TlnResource{ + children: TextUnit[] = []; + _pagesCollection: TlnEntity[]= []; + + + constructor(qService: QueryService, + label: string, + existingIri: string, + createChildren = true, + rdfsType?: string, + parentIri?: string, + parentLabel?: string, + checkOut = false, + textUnits: TextUnit[] = []) { + super(qService, label, existingIri, createChildren, rdfsType, parentIri, parentLabel, checkOut); + // this.rdfsType = 'http://www.nie.org/ontology/nietzsche#IdentifiedTextVersion'; + this.childsPredicate = 'http://www.nie.org/ontology/nietzsche#identifiesAsVersion'; + this.children = textUnits; + const textUnitList = new TlnStatements(this.childsPredicate, textUnits.map(t => t.iri)); + // this.setSelfOfTextVersion(); + if (this.isInStore()) { + console.log('textVersion in store', existingIri) + this._childToCreate = this._createChild.subscribe(childIriToCreate => { + console.log('child to create: ', childIriToCreate); + let textUnit = new TextUnit(this.qService,'TextUnit', childIriToCreate, this.iri ) + this.setTextUnit(textUnit); + this.addChild(textUnit); + }); + } } + textUnits(): TextUnit[] { - return this._identifiesAsVersion; + return this.children; + } + + hasTextUnits(): boolean { + return this.textUnits().length > 0; } - pages() { - return this._pages; + + pagesCollection() { + return this._pagesCollection; } // 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; + // to _pages, _versions, and to the statements + setTextUnit(textUnit: TextUnit, index?) { + if (!index) {index = this.children.length} // if no index passed it will be added at the end + this._pagesCollection.splice(index,0, textUnit.navItem.tlnEntity); + this.children.splice(index, 0, textUnit); + let identifiesAsVersionEntry: string; if (textUnit.wholePage) { - identifiesAsVersionThing = textUnit.belongsToPage; } else { - identifiesAsVersionThing = textUnit.iri } - this.setStatement('identifiesAsVersion', identifiesAsVersionThing, index); + identifiesAsVersionEntry = textUnit.belongsToPage; } else { + identifiesAsVersionEntry = textUnit.iri } + this._rdfDatasetToEdit.setStatement(this.childsPredicate, identifiesAsVersionEntry, 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); + const idx = this.children.findIndex(tUnit => tUnit.iri === textUnitIri); + this._pagesCollection.splice(idx, 1); + this.children.splice(idx,1); + this._rdfDatasetToEdit.deleteStatement(this.childsPredicate, idx); } moveTextUnitInArray(previousIndex: number, newIndex: number) { - moveItemInArray(this._identifiesAsVersion, previousIndex, newIndex); - moveItemInArray(this._pages, previousIndex, newIndex); - this.moveObjectInStatement('identifiesAsVersion', previousIndex, newIndex); + moveItemInArray(this._pagesCollection, previousIndex, newIndex); + this.moveChildInChildren(previousIndex, newIndex); } setTextUnits(textUnits: TextUnit[]) { - this._identifiesAsVersion = textUnits; + this.children = textUnits; // ... } getTextUnitIdxByIri(iri: string) { return this.textUnits().findIndex(tUnit => tUnit.iri === iri); } getTextUnitByIri(iri: string) { const idx = this.getTextUnitIdxByIri(iri); - return this._identifiesAsVersion[idx]; + return this.children[idx]; } checkedOutTextUnit(): TextUnit { - return this._identifiesAsVersion[this.checkedOutTextVersionIdx()]; + return this.children[this.checkedOutTextVersionIdx()]; } checkedOutTextVersionIdx(): number { - return this._identifiesAsVersion.findIndex(tUnit => tUnit.isCheckedOut()); + return this.children.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); + checkOutTextUnit(iri: string):TextUnit { + let idx = this.children.findIndex(t => t.iri === iri); + for (let i = 0; i <= this.children.length-1; i++) { + if (i === idx) { this.children[i].checkOut(true); } else { + this.children[i].checkOut(false); } } - return this._identifiesAsVersion[idx]; + return this.children[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 { + +export class ExternalTextVersion extends TlnResource{ + externalResourceHasUrl: string; + hasTitle: string; + + constructor(qService: QueryService, + label: string, + existingIri: string, + createChildren = false, + rdfsType?, + parentIri?, + parentLabel?, + hasTitle?: string) { + super(qService, label, existingIri, createChildren, rdfsType, parentIri, parentLabel); + //this.rdfsType = 'http://www.nie.org/ontology/nietzsche#ExternalTextUnit'; + this.childsPredicate = 'http://www.nie.org/ontology/nietzsche#textUnitHasUrl'; + this.hasTitle = hasTitle; + + // TODO: let generic properties of RdfEditClassdo the properties. + } + + // simple check for basic completeness + isComplete(){ + return this.externalResourceHasUrl && this.hasTitle + } +} + + +export class TextUnit extends TlnResource { 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, + // _availableProperties = [ + // 'http://www.nie.org/ontology/nietzsche#belongsToPage', + // 'http://www.nie.org/ontology/nietzsche#startLine', + // 'http://www.nie.org/ontology/nietzsche#endLine']; + + + constructor(qService: QueryService, + label:string, + existingIri: string = '', + createChildren, + rdfsType?: 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); + super(qService, label, existingIri, createChildren, rdfsType, parentIri, parentLabel); + // this.rdfsType= 'http://www.nie.org/ontology/nietzsche#PartOfPageTextUnit'; this.belongsToPage = parentIri; this.wholePage = wholePage; this.displayedLabel = displayedLabel; this.navItem = navItem; + this.getLineData(); 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])); + this.setLines(startLine, startLineNumber, endLine, endLineNumber); + //this.statements.set('belongsToPage', new TlnStatements('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)); + //this.statements.set('startLine', new TlnStatements('http://www.nie.org/ontology/nietzsche#startLine', startLineArr)); + //this.statements.set('endLine', new TlnStatements('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); + this._rdfDatasetToEdit.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); + this._rdfDatasetToEdit.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); + //TODO: change oder hide rdfData in case of wholePageChange + } + + // sets the lineData available for the checked out textUnit + getLineData() { + this.getLinesFromStore().then(lines => { + this.lineData = lines.map(line => { + return {line: line['line']['value'], lNumber: line['lNumber']['value']} + }); + }); + } + + // TODO: Generalize/Parametrize + async getLinesFromStore(): Promise { + const query = await this.qService.parametrizeQueryWithItem(RQ_CROSSREF_TREE_LINES, this.belongsToPage, '', ''); + return await this.qService.getData(BASEURL, query, 'SELECT').then(res => { + return res['results']['bindings']; + }); } } -export class TlnList { - protected _property: N3.NamedNode; // property NamedNode - protected _objects: N3.NamedNode[]; +export class TlnStatements { + protected _property: N3.NamedNode; + protected _objects: N3.Term[]; 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) { + public async setObject(objectIri: string, index?) { + if (!index || index === undefined) { + index = this.objects().length + } this._objects.splice(index, 0, new N3.NamedNode(objectIri)); } + // deletes a thing completely 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; } +export class TlnPredicate { + constructor(public iri: string, public range: string) { + } + + // returns whether a the range is a list or not + public takesList(): boolean { + return this.range ==='http://www.w3.org/1999/02/22-rdf-syntax-ns#List'; + } +} + diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.html similarity index 52% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.html rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.html index b07788e..bc7a09f 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.html +++ b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.html @@ -1,17 +1,11 @@ -
+

Wählen Sie ein Manuscript in der Navigationsleiste Links per Mausklick aus

-
+
Gewähltes Manuskript: {{selectedManuscript}}
-
- Gewählte Textgenese{{selectedTextGenesis}} -
- - {{textgenesis}} -
diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.scss b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.scss similarity index 100% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.scss rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.scss diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.spec.ts b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.spec.ts similarity index 100% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.spec.ts rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.spec.ts diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.ts similarity index 74% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.ts rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.ts index 75499af..97e8650 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/text-genese-selector-component.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/text-genese-selector-component.component.ts @@ -1,53 +1,53 @@ import {Component, OnChanges, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute, ParamMap, Router} from '@angular/router'; import {Subscription} from 'rxjs'; -import {NavigationServiceService} from '../../services/navigation-service.service'; -import {QueryService} from '../../services/query.service'; +import {NavigationServiceService} from '../../../services/navigation-service.service'; +import {QueryService} from '../../../services/query.service'; import {MatDialog} from '@angular/material/dialog'; import {TextgeneseSelectorDialogueComponentComponent} from './textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component'; +import {CrossrefEditorDataServiceService} from '../../crossref-editor-data-service.service'; @Component({ selector: 'app-text-genese-selector-component', templateUrl: './text-genese-selector-component.component.html', styleUrls: ['./text-genese-selector-component.component.scss'] }) export class TextGeneseSelectorComponentComponent implements OnInit, OnDestroy { manuscripts: string[]; selectedManuscript: string; queryParamSubscription: Subscription; - textgeneses: string[]; selectedTextGenesis: string; constructor(private activatedRoute: ActivatedRoute, - private naviService: NavigationServiceService, - private queryService: QueryService, + private dataService: CrossrefEditorDataServiceService, public dialog: MatDialog) { } ngOnInit() { this.queryParamSubscription = this.activatedRoute.queryParamMap.subscribe((queryParams: ParamMap) => { this.selectedManuscript = queryParams.get('manuscript'); this.selectedTextGenesis = queryParams.get('geneticOrder'); }); } ngOnDestroy() { this.queryParamSubscription.unsubscribe(); } openRhizomeDialogue() { - console.log('opening dialogue to select'); const dialogRef = this.dialog.open(TextgeneseSelectorDialogueComponentComponent, { width: '90vw', height: '90vh', data: this.selectedManuscript }); dialogRef.afterClosed().subscribe(result => { - console.log('The dialog was closed'); + this.selectedTextGenesis = result.event; + console.log('The dialog was closed and we have chosen a textgenesis: ', result.event); + this.dataService.readInTextGenesis(result.event); }); } } diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html new file mode 100644 index 0000000..ed0ef3d --- /dev/null +++ b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html @@ -0,0 +1,11 @@ + + gewählte Textgenesis: {{selectedTextGenesis}} + + + + + diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.scss b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.scss similarity index 100% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.scss rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.scss diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.spec.ts b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.spec.ts similarity index 100% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.spec.ts rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.spec.ts diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts similarity index 75% rename from nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts rename to nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts index 79309df..3fe8e67 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/existing-text-genesis-workflow-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.ts @@ -1,42 +1,42 @@ -import {Component, forwardRef, Inject, OnInit} from '@angular/core'; +import {Component, forwardRef, Inject, OnChanges} from '@angular/core'; import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; import {NG_VALUE_ACCESSOR} from '@angular/forms'; import {ActivatedRoute, ParamMap} from '@angular/router'; import {Subscription} from 'rxjs'; -import {TlnPageWithTextGeneticOrder} from '../../../tln-edition/datatypes/text_version'; -import {TlnQueryService} from '../../../tln-edition/services'; +import {TlnQueryService} from '../../../../tln-edition/services'; @Component({ selector: 'app-textgenese-selector-dialogue-component', templateUrl: './textgenese-selector-dialogue-component.component.html', styleUrls: ['./textgenese-selector-dialogue-component.component.scss'], providers: [TlnQueryService, { provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => TextgeneseSelectorDialogueComponentComponent), } ] }) -export class TextgeneseSelectorDialogueComponentComponent implements OnInit { +export class TextgeneseSelectorDialogueComponentComponent implements OnChanges { selectedTextGenesis: string; - pagesWithGeneticOrder: TlnPageWithTextGeneticOrder[] = []; queryParamSubscription: Subscription; max_width: number; constructor(private queryService: TlnQueryService, private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public selectedManuscript: string, public activatedRoute: ActivatedRoute) { this.max_width = window.innerWidth/1.5; + + this.selectedTextGenesis = 'http://rdfh.ch/projects/0068#_Mp_XIV_TextGenesis0'; // TODO: Read Output } - ngOnInit() { + ngOnChanges() { this.queryParamSubscription = this.activatedRoute.queryParamMap.subscribe((queryParams: ParamMap) => { this.selectedManuscript = queryParams.get('manuscript'); - this.selectedTextGenesis = queryParams.get('geneticOrder'); + // this.selectedTextGenesis = queryParams.get('geneticOrder'); }); } - closeDialog() { - this.dialogRef.close(); + apply() { + this.dialogRef.close({event: this.selectedTextGenesis}); } } diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html deleted file mode 100644 index a6a70ba..0000000 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genese-selector-component/textgenese-selector-dialogue-component/textgenese-selector-dialogue-component.component.html +++ /dev/null @@ -1 +0,0 @@ - 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 ce23ff4..fe4041e 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,44 +1,46 @@

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.

-
- Seiten check* +
{{internalTextVersion._pagesCollection[0].iri}}
+
+ Seiten check + * - + {{textUnit.navItem.parentLabel}} - {{textUnit.displayedLabel}}: gesamte Seite {{textUnit.displayedLabel}} Zeilen {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}}
hier 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 23b6b6b..bbce134 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,81 +1,82 @@ import {Component, Input, OnChanges} from '@angular/core'; import {CdkDragDrop} from '@angular/cdk/drag-drop'; -import {NavigationEntity} from '../../../models/models'; +import {NavigationEntity, TlnEntity} from '../../../models/models'; import {NavigationServiceService} from '../../../services/navigation-service.service'; import {ActivatedRoute} from '@angular/router'; -import {CrossrefEditorDataServiceService, TextVersion} from '../../crossref-editor-data-service.service'; +import {CrossrefEditorDataServiceService, InternalTextVersion, TextVersion} 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() textVersion: TextVersion; + @Input() internalTextVersion: InternalTextVersion; + @Input() pages: TlnEntity[] = []; 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.textVersion && this.textVersion.textUnits() && this.textVersion.textUnits().length) { - this.textVersion.textUnits().forEach(tUnit => { + if ( this.internalTextVersion.hasTextUnits() ){ + this.internalTextVersion.textUnits().forEach(tUnit => { this.linesOfPages.set(tUnit.belongsToPage,tUnit.lineData) }); } this.max_width = window.innerWidth/2; } itemDropped(event: CdkDragDrop) { if (event.previousContainer === event.container) { this.dataService.movePageInArray(event.previousIndex, event.currentIndex) } else { this.dataService.addPage(event.item.data, event.currentIndex); } } removeFromCollection(itemToRemove: string) { - this.dataService.removePage(itemToRemove); + this.dataService.removeTextUnit(itemToRemove); } openLineSelectorDialog(textUnitIri): void { - this.checkoutTextVersion(textUnitIri); + this.checkoutTextUnit(textUnitIri); const dialogRef = this.dialog.open(LineSelectorComponentComponent, { width: '90vw', height: '90vh', - data: this.textVersion.checkedOutTextUnit() + data: this.internalTextVersion.checkedOutTextUnit() }); dialogRef.afterClosed().subscribe(result => { console.log('The dialog was closed'); }); } - checkoutTextVersion(textUnitIri) { - this.dataService.textGenesis.checkedOutTextVersion().checkoutTextUnit(textUnitIri); + checkoutTextUnit(textUnitIri) { + this.dataService.textGenesis.checkedOutTextVersion().internalTextVersion.checkOutTextUnit(textUnitIri); } } diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.html b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.html index 4c878c9..0c48a51 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.html +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.html @@ -1,99 +1,97 @@ - Textgenese: {{textGenesis.id}} + Textgenese: {{textGenesis.iri}} - + - - + + {{textUnit.navItem.parentLabel}}: {{textUnit.displayedLabel}} {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} - ; + ; -> + + {{tVersion.externalTextVersion.hasTitle}} (ext. Resource) + - +
{{i+1}}. Textversion: - - - {{textUnit.navItem.parentLabel}}: {{textUnit.displayedLabel}} - {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} - ; + + + + {{textUnit.navItem.parentLabel}}: {{textUnit.displayedLabel}} + {{textUnit.displayedStartLine}}-{{textUnit.displayedEndLine}} + ; + + + externe Textversion: {{textVersion.externalTextVersion.hasTitle}} +
{{textVersion.isCheckedOut()? '' : 'Panel ausklappen zum Bearbeiten ...'}}
+ (change)="setExternity(false)" > Interne Textversion + (change)="setExternity(true)" > Externe Textversion -
-
- Titel/Beschreibung - -
-
- Link zur Resource - -
-
- +
+
{{textGenesis.ttl_export}} diff --git a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.ts b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.ts index f364814..9c79ff6 100644 --- a/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.ts +++ b/nietzsche-beta-app/src/app/crossref-editor-component/text-genesis-editor/text-genesis-editor-component/text-genesis-editor.component.ts @@ -1,66 +1,71 @@ import {Component, Input, OnChanges, OnDestroy} from '@angular/core'; import {CrossrefEditorDataServiceService, TextGenesis, TextVersion} from '../../crossref-editor-data-service.service'; import {Subscription} from 'rxjs'; import {ActivatedRoute} from '@angular/router'; import {NavigationServiceService} from '../../../services/navigation-service.service'; +import * as N3 from "node_modules/n3/src"; +import {QueryService} from '../../../services/query.service'; @Component({ selector: 'app-text-genesis-editor', templateUrl: './text-genesis-editor.component.html', styleUrls: ['./text-genesis-editor.component.scss'] }) export class TextGenesisEditorComponent implements OnChanges, OnDestroy { - @Input() textGenesisIri: string; textGenesis: TextGenesis; textGenesisSubscription: Subscription; + n3Parser = new N3.Parser(); + n3Store = new N3.Store(); constructor(private dataService: CrossrefEditorDataServiceService, private naviService: NavigationServiceService, - private activatedRoute: ActivatedRoute) { + private activatedRoute: ActivatedRoute, + private queryService: QueryService) { if (this.activatedRoute.snapshot.queryParamMap.get('navBarOpenState') === 'false' || '') { this.naviService.updateRoute({['navBarOpenState']: 'true'}); } this.textGenesisSubscription = this.dataService.textGenesisEmitter.subscribe(tGenesis => { + console.log('textGenesis: ', tGenesis); this.textGenesis = tGenesis; }) } ngOnChanges() { } ngOnDestroy(){ this.textGenesisSubscription.unsubscribe(); } createTextVersion() { - let version = new TextVersion('TextVersion', this.textGenesis.iri); + let version = new TextVersion(this.queryService,'', this.textGenesis.iri, false, false, 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); + } deleteTextVersion(iri: string) { this.dataService.textGenesis.deleteTextVersion(iri); } preview() { this.dataService.writeOut(false) // import somewhere } saveToTripleStore() { this.dataService.writeOut(true) } - setExternal(external: boolean) { - console.log('setting external to ', external); - // this.dataService.textGenesis.checkedOutTextVersion().isExternalResource = external; + setExternity(external: boolean) { + this.dataService.setExternityOfTextVersion(external); } } 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 1970d31..3c51d77 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 +1,13 @@ - +
+
+ Titel/Beschreibung + +
+
+ Link zur Resource + +
+
+
+ +
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 6b6c6c4..667770d 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,38 +1,39 @@ import {Component, Input, OnChanges, OnDestroy} from '@angular/core'; -import {CrossrefEditorDataServiceService, TextGenesis, TextVersion} from '../../crossref-editor-data-service.service'; +import {CrossrefEditorDataServiceService, InternalTextVersion, TextGenesis, TextVersion} 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; - textVersion: TextVersion; + @Input() textVersion: TextVersion; textGenesisSubscription: Subscription; pages: TlnEntity[] = []; constructor(private naviService: NavigationServiceService, private dataService: CrossrefEditorDataServiceService) { this.textGenesisSubscription = this.dataService.textGenesisEmitter.subscribe(tGenesis => { + if (!tGenesis.checkedOutTextVersion()) {return} this.resetPages(tGenesis); }); } ngOnChanges() { } ngOnDestroy() { this.textGenesisSubscription.unsubscribe(); } resetPages(tGenesis: TextGenesis) { - if (!tGenesis || !tGenesis.checkedOutTextVersion()) {return} + console.log('reset Pages with:', tGenesis); this.textVersion = tGenesis.checkedOutTextVersion(); - if (tGenesis.checkedOutTextVersion().pages()) { - this.pages = tGenesis.checkedOutTextVersion().pages(); + if (tGenesis.checkedOutTextVersion().internalTextVersion._pagesCollection) { + this.pages = tGenesis.checkedOutTextVersion().internalTextVersion._pagesCollection; } } } diff --git a/nietzsche-beta-app/src/app/services/query.service.ts b/nietzsche-beta-app/src/app/services/query.service.ts index f3df8ed..237d73d 100644 --- a/nietzsche-beta-app/src/app/services/query.service.ts +++ b/nietzsche-beta-app/src/app/services/query.service.ts @@ -1,96 +1,115 @@ 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(); - } if (queryType === 'SELECT') { + } if (queryType === 'SELECT' || queryType === 'ASK') { 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(); } } public updateData(baseUrl: string, data: string) { let query = `INSERT DATA {${data}}`; console.log('query', query); let httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/sparql-update', 'Authorization': 'Basic bmlldHpzY2hlX3VzZXI6bmlldHpzY2hl', 'Accept': 'application/sparql-results+json; charset=UTF-8'}), method: 'POST', body: query}; this.http.post(baseUrl, query, httpOptions).toPromise().then(fuu => console.log(fuu) ); } /** * 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); - // 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) }; - } + let qParametrizer = new TlnQueryParametrizer(baseQuery); + qParametrizer.parametrize(subjectIri, propertyIri, objectIri); + return qParametrizer.writeOut(); + } +} - if (propertyIri && propertyIri !== '') { - parsedQuery.where[0].triples[0].predicate = {'termType': 'NamedNode', 'value': decodeURI(propertyIri) }; - } +export class TlnQueryParametrizer { - 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); + parsedQuery; + parser: Parser; + sparqlGenerator = new Generator({}); + + constructor(baseQuery: string) { + this.parser = new Parser(); + this.parsedQuery = this.parser.parse(baseQuery); + console.log(this.parsedQuery); + } + + parametrize(subjectIri?: string, predicateIri?: string, objectIri?: string) { + this.setSubject(subjectIri); + this.setPredicate(predicateIri); + this.setObject(objectIri); + } + + setSubject(subjectIri: string): void { + if (!subjectIri || subjectIri === '') { return } + this.parsedQuery.where[0].triples[0].subject = {'termType': 'NamedNode', 'value': decodeURI(subjectIri) }; + if (this.parsedQuery.queryType === 'CONSTRUCT') { // in case of constructs we also change the property + this.parsedQuery.template[0].subject = {'termType': 'NamedNode', 'value': decodeURI(subjectIri) }; } + } + setPredicate(predicateIri: string): void { + if (!predicateIri || predicateIri === '') { return } + this.parsedQuery.where[0].triples[0].predicate = {'termType': 'NamedNode', 'value': decodeURI(predicateIri) }; + if (this.parsedQuery.queryType === 'CONSTRUCT') { // in case of constructs we also change the property + this.parsedQuery.template[0].predicate = {'termType': 'NamedNode', 'value': decodeURI(predicateIri) }; + } + } + + setObject(objectIri: string): void { + if (!objectIri || objectIri === '') { return } + this.parsedQuery.where[0].triples[0].object = {'termType': 'NamedNode', 'value': decodeURI(objectIri) }; + if (this.parsedQuery.queryType === 'CONSTRUCT') { // in case of constructs we also change the property + this.parsedQuery.template[0].object = {'termType': 'NamedNode', 'value': decodeURI(objectIri) }; + } + } + + writeOut() { + return this.sparqlGenerator.stringify(this.parsedQuery); + } }