diff --git a/nietzsche-beta-app/package.json b/nietzsche-beta-app/package.json index 7cddba8..09b6a42 100644 --- a/nietzsche-beta-app/package.json +++ b/nietzsche-beta-app/package.json @@ -1,60 +1,60 @@ { "name": "nietzsche-app-beta", - "version": "0.9.4.1", + "version": "0.9.4.2", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "compodoc": "./node_modules/.bin/compodoc -p tsconfig.app.json", "sparqljs": "./node_modules/sparqljs/sparql.js" }, "private": true, "dependencies": { "@angular/animations": "~8.2.14", "@angular/cdk": "~8.2.3", "@angular/common": "~8.2.14", "@angular/compiler": "~8.2.14", "@angular/core": "~8.2.14", "@angular/forms": "~8.2.14", "@angular/material": "^8.2.3", "@angular/platform-browser": "~8.2.14", "@angular/platform-browser-dynamic": "~8.2.14", "@angular/router": "~8.2.14", "@ctrl/ngx-codemirror": "^5.0.0", "@types/rdf-js": "^2.0.11", "codemirror": "^5.62.0", "lodash": "^4.17.20", "n3": "^1.10.0", "ngx-csv": "^0.3.2", "ngx-mat-standoff-markup": "^0.7.3", "rdfjs": "^0.0.1", "rxjs": "~6.4.0", "sparqljs": "^3.0.1", "tslib": "^1.10.0", "zone.js": "~0.9.1" }, "devDependencies": { "@angular-devkit/build-angular": "^0.803.25", "@angular/cli": "~8.3.24", "@angular/compiler-cli": "~8.2.14", "@angular/language-service": "~8.2.14", "@types/jasmine": "~3.3.8", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "^5.0.0", "jasmine-core": "~3.4.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~4.1.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.0", "protractor": "~5.4.0", "ts-node": "~7.0.0", "tslint": "~5.15.0", "typescript": "~3.5.3" } } diff --git a/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts b/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts index 988eacb..1fb9863 100644 --- a/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts +++ b/nietzsche-beta-app/src/app/tln-edition/common/select-array.ts @@ -1,29 +1,32 @@ import { OnInit } from '@angular/core'; import { DataProcessor } from '../models'; + export interface CompareMapping { compareValueKey: string; sourceArrayKey: string; targetArrayKey: string[]; commonPropertyKey: string; + arrayUpdated: string; } export class SelectFromArray implements DataProcessor { constructor(private onInit: OnInit, private compareMapping: CompareMapping){} private getItem(item: any, path: string[]): any { if (path.length == 1){ return item[path[0]]; } else { return this.getItem(item[path[0]], path.slice(1)); } } public processData(){ const target = this.getItem(this.onInit, this.compareMapping.targetArrayKey.slice()); const compareValue = this.onInit[this.compareMapping.compareValueKey] this.onInit[this.compareMapping.sourceArrayKey].forEach(item =>{ if(item[this.compareMapping.commonPropertyKey] === compareValue && target.indexOf(item) == -1){ target.push(item) } }); + this.onInit[this.compareMapping.arrayUpdated](); } } diff --git a/nietzsche-beta-app/src/app/tln-edition/tln-quant/tln-quant.component.ts b/nietzsche-beta-app/src/app/tln-edition/tln-quant/tln-quant.component.ts index 5edba7b..42f869a 100644 --- a/nietzsche-beta-app/src/app/tln-edition/tln-quant/tln-quant.component.ts +++ b/nietzsche-beta-app/src/app/tln-edition/tln-quant/tln-quant.component.ts @@ -1,280 +1,281 @@ import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { Router, ActivatedRoute, Params } from '@angular/router'; import { HttpErrorResponse} from '@angular/common/http'; import {Sort} from '@angular/material/sort'; import {MatBottomSheet, MatBottomSheetRef} from '@angular/material/bottom-sheet'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {QueryErrorComponent} from './query-error.component'; import { CodemirrorComponent} from '@ctrl/ngx-codemirror'; import { DataHandler } from '../data_handler'; import { QuantitativeDataHandler } from '../quant_data_handler'; import { Manuscript4Selection} from '../datatypes/manuscript'; import { FusekiResults } from '../datatypes/basic_datatype'; import { NumericResultRow, SelectableWordProperty} from '../datatypes/quant'; import { QueryJson} from '../datatypes/query_json'; import { AccordionStatus, DataProcessor, QuantQuery, TlnQueryServiceInterface, TextQuality} from '../models'; import { TlnCacheQueryService } from '../services'; import { TLN_QUANT_ROUTE, TLN_MANUSCRIPT_ROUTE, TLN_VIEWER_ROUTE, TLN_CONTEXT_VIEW_PARAM, TLN_FULLSCREEN_PARAM, TLN_FIND_PARAM, TLN_PAGE_PARAM, TLN_MANUSCRIPT_PARAM, TLN_QUANT_QUERY_PARAM, TLN_QUERY_PARAM, TLN_RESULT_INDEX_PARAM,TLN_SELECTED_LINES_PARAM, TLN_TEXT_GENETIC_ORDER_PARAM, TLN_VIEW_OPTION_PARAM, TLN_ZOOM_PARAM, VIEW_OPTIONS, ONTOLOTY_PREFIX } from '../constants'; import { Mapping } from '../route-reader'; import { RouteUpdater } from '../route-updater'; import { CacheService } from '../common/cache.service'; -import { CompareMapping, SelectFromArray } from '../common/select-array'; +import { SelectFromArray } from '../common/select-array'; @Component({ selector: 'tln-quant', templateUrl: './tln-quant.component.html', providers: [ TlnCacheQueryService], styleUrls: ['./tln-quant.component.css'] }) -export class TlnQuantComponent extends RouteUpdater implements DataProcessor, OnInit { +export class TlnQuantComponent extends RouteUpdater implements DataProcessor, OnInit { /** * OPTIONAL pass a queryService with method * {@link /interfaces/TlnQueryServiceInterface.html#getData|getData} * to TlnPageViewComponent. **/ @Input() queryService: TlnQueryServiceInterface; @Input() restrictKorpusOnContext: boolean = false; @ViewChild(CodemirrorComponent,{static:false}) codemirror: CodemirrorComponent; tlnQueryService: TlnQueryServiceInterface; dataHandler: DataHandler = new DataHandler(this); fusekiResults: FusekiResults; current_manuscript_iri: string; select_manuscript_iri: string; displayedColumns: string[] = [ 'id', 'numProperties', 'numPropertyTextPercent', 'numPropertiesPercent', 'numPropertiesIncludeMulti', 'numText', 'numTextPercent' ]; errorLine: number = -1; quantDataHandler: QuantitativeDataHandler = new QuantitativeDataHandler(this); isLoadingResults: boolean = false; manuscriptPages: Manuscript4Selection[] = []; numResultRows: NumericResultRow[] = []; resultIndex: number = 0; quantAccordionStatus: AccordionStatus = { wordProperties: { expanded: true, disabled: false }, scopus: { expanded: false, disabled: false }, query: { expanded: false, disabled: false } }; query: string = ''; queryInput: string = ''; queryHasSyntaxError: boolean = false; curlQuery: string = ''; shareQuery: boolean = false; wordProperties: SelectableWordProperty[] = []; quantQuery: QuantQuery = { currentTable: 0, resultIndices: [ 0, 0 ], sortArray: [ { active: null, direction: '' }, { active: null, direction: '' }, { active: null, direction: '' }], ignoreCase: false, text: '', selectedManuscripts: [], selectedWordProperties: [], textQuality: { clean: true, preferEditedText: true }, restrictKorpusOnContext: false, filterValue: '' } protected mapping: Mapping = { current_manuscript_iri: { param: TLN_MANUSCRIPT_PARAM, type: "string" }, quantQuery: { param: TLN_QUANT_QUERY_PARAM, type: "complex" } } constructor(private cacheService: CacheService, private localQueryService: TlnCacheQueryService, protected router: Router, protected activatedRoute: ActivatedRoute, private _dialog: MatBottomSheet) { super(router, activatedRoute); } ngOnInit() { this.tlnQueryService = (this.queryService != null) ? this.queryService : this.localQueryService; this.dataHandler.addHandler('wordProperties', { 'handler': SelectableWordProperty}); this.dataHandler.addHandler('manuscriptPages', { 'handler': Manuscript4Selection}); this.quantDataHandler.addHandler('numResultRows', { 'handler': NumericResultRow, 'process_data': this }); this.dataHandler.setQueryService(this.tlnQueryService); this.quantDataHandler.setQueryService(this.tlnQueryService); this.quantDataHandler.start_processing.subscribe( (started: boolean) =>{ this.isLoadingResults = true; }); this.quantDataHandler.processing_finished.subscribe( (started: boolean) =>{ this.isLoadingResults = false; }); this.dataHandler.getData('wordProperties'); this.dataHandler.getData('manuscriptPages'); this.quantQuery.restrictKorpusOnContext = this.restrictKorpusOnContext if (this.restrictKorpusOnContext){ this.dataHandler['manuscriptPages']['process_data'] = new SelectFromArray(this, { compareValueKey: 'select_manuscript_iri', sourceArrayKey: 'manuscriptPages', targetArrayKey: ['quantQuery', 'selectedManuscripts'], - commonPropertyKey: 'id' + commonPropertyKey: 'id', + arrayUpdated: 'updateQuery', }) } super.ngOnInit(); } isManuscriptSelected(manuscript: Manuscript4Selection): boolean { return this.restrictKorpusOnContext && this.current_manuscript_iri == manuscript.id } isSelected = (o1: any, o2: any): boolean => { return o1.id == o2.id; } normalLineNumberFormatter = (line: number): string =>{ return String(line); } private markError(error: string){ if (this.quantQuery != null && this.quantQuery.dataKey != undefined && this.quantQuery.dataKey != null){ this.cacheService.removeItem(this.quantQuery.dataKey) this.quantQuery['dataKey'] = null; this.updateParams(); } const matches = error.match(/(.*line\s)([0-9]+)(:.*)/s) if (matches != null && matches.length == 4){ this.errorLine = Number(matches[2]); this.codemirror.codeMirror.setOption('lineNumberFormatter' as any, (line:number): string =>{ if (line == this.errorLine){ return 'E>'; } return String(line) }); this.quantAccordionStatus.query.expanded = true; } } private send() { const error = QueryJson.getSyntaxError(this.query); //console.log('error', error); if (error != ''){ this._dialog.open(QueryErrorComponent, { data: {error: error }}); this.markError(error); } else { this.numResultRows = []; Object.keys(this.quantAccordionStatus).forEach(key =>{this.quantAccordionStatus[key].expanded = false}); if (this.quantQuery.currentTable == 2){ this.quantQuery.currentTable = (this.query != this.getQuery()) ? 1 : 0; this.updateParams(); } this.quantDataHandler.getData4Query('numResultRows', this.query, 'fusekiResults'); } } private cancel(){ this.quantDataHandler.stop_processing.emit(true); this.isLoadingResults = false; } private copyToClipboard(curlQueryInput){ curlQueryInput.select(); curlQueryInput.setSelectionRange(0, 99999); /* For mobile devices */ /* Copy the text inside the text field */ document.execCommand("copy"); } protected readParams(params: Params){ const old_current_manuscript_iri = this.current_manuscript_iri super.readParams(params); if (this.current_manuscript_iri != null && old_current_manuscript_iri != this.current_manuscript_iri && this.quantQuery.restrictKorpusOnContext){ this.select_manuscript_iri = this.current_manuscript_iri; this.quantAccordionStatus.scopus.expanded = true; } if (this.quantQuery != null){ if (this.quantQuery.selectedManuscripts.length > 0){ this.select_manuscript_iri = null; } if (this.quantQuery.altQuery != null){ this.query = this.quantQuery.altQuery; this.curlQuery = 'curl ' + this.tlnQueryService.baseUrl + ' -X POST --data \'query=' + encodeURI(this.query) + '\'' this.quantAccordionStatus.wordProperties = { expanded: false, disabled: true }; this.quantAccordionStatus.query.expanded = true; } if (this.quantQuery.dataKey != undefined && this.quantQuery.dataKey != null){ const results = this.cacheService.getItem(this.quantQuery.dataKey); if (results != null){ this.fusekiResults = results; this.numResultRows = NumericResultRow.convertData(this.fusekiResults); if (this.quantQuery.sortArray[this.quantQuery.currentTable].active != null){ const sort = this.quantQuery.sortArray[this.quantQuery.currentTable] if (this.quantQuery.currentTable == 0){ this.numResultRows = this.numResultRows.sort((a, b) => { return this.compare(a[sort.active], b[sort.active], sort.direction === 'asc') }); } else { this.fusekiResults.results.bindings = this.fusekiResults.results.bindings.sort((a, b) => { return this.compare((a[sort.active]['value']), (b[sort.active]['value']), sort.direction === 'asc') }); } } if (this.quantQuery.filterValue != undefined && this.quantQuery.filterValue != null && this.quantQuery.filterValue != ''){ this.numResultRows = this.numResultRows.filter(result =>result.id.startsWith(this.quantQuery.filterValue)); } } } } if (this.query == ''){ this.updateQuery(); } } private compare(a: number | string, b: number | string, isAsc: boolean): number { return (a < b ? -1 : 1) * (isAsc ? 1: -1); } private toggleEnableSelectionList(updateQuery: boolean) { if (this.errorLine > -1){ this.errorLine = -1; this.codemirror.codeMirror.setOption('lineNumberFormatter' as any, (line:number): string =>{return String(line)}) } if (updateQuery) { this.updateQuery(); this.queryHasSyntaxError = false; this.quantAccordionStatus.wordProperties.disabled = false; } else { const queryChanged = this.query != this.getQuery(); this.queryHasSyntaxError = QueryJson.hasSyntaxError(this.query); this.quantAccordionStatus.wordProperties.disabled = queryChanged; this.updateQuery4Ext(queryChanged); if (this.quantAccordionStatus.wordProperties.disabled) { this.quantAccordionStatus.wordProperties.expanded = false; } } } private getQuery(): string { let selectedManuscripts = (this.quantQuery.selectedManuscripts.length == this.manuscriptPages.length) ? [] : this.quantQuery.selectedManuscripts; return this.quantDataHandler['numResultRows'].handler.getSelectableQuery( this.quantQuery.selectedWordProperties, selectedManuscripts, this.quantQuery.textQuality, this.quantQuery.text, this.quantQuery.ignoreCase); } public processData(){ if (this.quantQuery != null && this.quantQuery.dataKey != undefined && this.quantQuery.dataKey != null){ this.cacheService.removeItem(this.quantQuery.dataKey); } const dataKey = TLN_QUANT_ROUTE + Date.now().toString(); this.cacheService.setItem(dataKey, this.fusekiResults); this.quantQuery['dataKey'] = dataKey; this.updateParams(); } private tabChanged(tabChange: MatTabChangeEvent){ this.quantQuery.currentTable = tabChange.index; this.quantQuery.resultIndex = 0; this.updateParams(); } private updateTextQuality(clean: boolean, preferEditedText?: boolean){ this.quantQuery.textQuality = { clean: clean, preferEditedText: preferEditedText }; this.updateQuery(); } private updatePageIndex(pageIndex: number){ if (typeof pageIndex == 'number'){ this.quantQuery.resultIndices[this.quantQuery.currentTable] = pageIndex; this.updateParams(); } } private updateQuantQuery(quantQuery: QuantQuery){ console.log(quantQuery); this.quantQuery = quantQuery; this.updateParams(); } private updateQuery(source?: string) { this.query = this.getQuery(); this.updateQuery4Ext(false); } private updateQuery4Ext(setAltQuery: boolean) { this.curlQuery = 'curl ' + this.tlnQueryService.baseUrl + ' -X POST --data \'query=' + encodeURI(this.query) + '\'' if (setAltQuery) { this.quantQuery.altQuery = this.query } else { this.quantQuery.altQuery = null; } this.updateParams(); } }