diff --git a/angular.json b/angular.json index 23675b8..8f8c4fe 100644 --- a/angular.json +++ b/angular.json @@ -1,129 +1,129 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "svg-test-app": { "projectType": "application", "schematics": { "@schematics/angular:component": { "style": "scss" } }, "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/svg-test-app", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "aot": false, "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "src/styles.scss" ], "scripts": [] }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "budgets": [ { "type": "initial", "maximumWarning": "2mb", "maximumError": "5mb" }, { "type": "anyComponentStyle", "maximumWarning": "6kb", "maximumError": "10kb" } ] } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "svg-test-app:build" }, "configurations": { "production": { "browserTarget": "svg-test-app:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "svg-test-app:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "src/styles.scss" ], "scripts": [] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json" ], "exclude": [ "**/node_modules/**" ] } }, "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "svg-test-app:serve" }, "configurations": { "production": { "devServerTarget": "svg-test-app:serve:production" } } } } }}, "defaultProject": "svg-test-app" -} \ No newline at end of file +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 11f002c..18e4186 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,73 +1,73 @@ import { AppComponent } from './app.component'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { CdkTableModule } from '@angular/cdk/table'; import { DragDropModule } from '@angular/cdk/drag-drop'; import { FormsModule, ReactiveFormsModule} from '@angular/forms'; import { NgModule } from '@angular/core'; import { ngxCsv } from 'ngx-csv/ngx-csv'; import { MatDialogModule } from '@angular/material'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatInputModule } from '@angular/material/input'; import { MatListModule } from '@angular/material/list'; import { MatPaginatorModule, MatSortModule, MatSidenavModule, MatCheckboxModule } from '@angular/material'; import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; -import { DataListView } from './data-list-view/data-list-view.component'; +import { DataListViewComponent } from './data-list-view/data-list-view.component'; import { DataListViewTableComponent, HighlightPipe } from './data-list-view/data-list-view-table/data-list-view-table.component'; import { DialogComponent } from './dialog-component/dialog.component'; import { DataListViewSettings} from './data-list-view/data-list-view-settings/data-list-view-settings'; import { InfoBoxComponent } from './info-box-component/info-box.component'; import { TextFieldComponent} from './textfield-component/textfield.component'; import { WordPositionDirective } from './textfield-component/word-position.directive'; import { TextfieldOptionsComponentComponent } from './textfield-options-component/textfield-options-component.component'; import { CommonModule } from '@angular/common'; import {HttpClientModule} from '@angular/common/http'; import { RdfDataBrowserComponentComponent } from './rdf-data-browser-component/rdf-data-browser-component.component'; import { DataService } from './services/resources.service'; import { QueryService } from './services/query.service'; -import { TableDataService } from './data-list-view/data-list-view-services/table-data.service'; +import { DisplayedCollumnsService } from './data-list-view/data-list-view-services/table-data.service'; @NgModule({ declarations: [ AppComponent, TextFieldComponent, WordPositionDirective, InfoBoxComponent, TextfieldOptionsComponentComponent, - DataListView, + DataListViewComponent, DataListViewTableComponent, DialogComponent, DataListViewSettings, HighlightPipe, RdfDataBrowserComponentComponent ], imports: [ BrowserModule, BrowserAnimationsModule, CdkTableModule, CommonModule, DragDropModule, HttpClientModule, MatCheckboxModule, MatDialogModule, MatExpansionModule, MatInputModule, MatListModule, MatPaginatorModule, MatSelectModule, MatSidenavModule, MatSortModule, MatTableModule, FormsModule, ReactiveFormsModule ], - providers: [DataService, QueryService, TableDataService], + providers: [DataService, QueryService, DisplayedCollumnsService], bootstrap: [AppComponent], entryComponents: [DialogComponent] }) export class AppModule { } diff --git a/src/app/data-list-view/assets/settings.json b/src/app/data-list-view/assets/settings.json new file mode 100644 index 0000000..3769621 --- /dev/null +++ b/src/app/data-list-view/assets/settings.json @@ -0,0 +1,71 @@ + { "inputMode":"query", + "jsonType":"sparql", + "columns":{ + "genericColumns":false, + "columnMapping":[ + { + "name":"predicate", + "path":[ + "p", + "value" + ], + "displayed":true, + "filtered":true + }, + { + "name":"object", + "path":[ + "o", + "value" + ], + "displayed":true, + "filtered":true + } + ], + "stickyColumn":0 + }, + "filter":{ + "showFilter":false, + "caseSensitive":false + }, + "paginator":{ + "paginate":true, + "pageIndex":"0", + "pageSize":"5", + "pageSizeOptions":[ + 5, + 10, + 25, + 50, + 100, + 250 + ] + }, + "export":{ + "showExport":false + }, + "sort":{ + "disallowSorting":true + }, + "styles":{ + "cellStyle":{ + "cursor":"pointer" + } + }, + "actions":{ + "actions":true, + "_comment":{ + "cursorstyle":"use custom css properties", + "intLink":"opens another app", + "extLink":"opens another webpage" + }, + "actionMode":"object", + "actionType":"dialog", + "actionRange":"cell", + "baseUrl":"http://localhost:4200/page?actionID=5c8a6300b4438759d237b246", + "urlParams":{ + "label":"label.value", + "highlight":"authorsname.value" + } + } + } diff --git a/src/app/data-list-view/data-list-view-services/table-data.service.ts b/src/app/data-list-view/data-list-view-services/table-data.service.ts index fb0e651..fb819ab 100644 --- a/src/app/data-list-view/data-list-view-services/table-data.service.ts +++ b/src/app/data-list-view/data-list-view-services/table-data.service.ts @@ -1,8 +1,45 @@ import { Injectable } from '@angular/core'; @Injectable() -export class TableDataService { +export class DisplayedCollumnsService { + public getDisplayedColumns(dataListSettings, data?) { + let displayedColumns: Array = []; + if (dataListSettings.columns.genericColumns) { + if (dataListSettings.jsonType === 'sparql') { + for (const entry of data.head.vars) { + displayedColumns.push(entry + '.value'); + displayedColumns.push(entry + '.type'); + } + } else if (dataListSettings.jsonType === 'knora-extended') { + displayedColumns = [this.generateDisplayedColumnsForKnora(data)]; + return displayedColumns; + } else { + console.log('Wrong datalistSettings: this.dataListSettings.columns.genericColumns = ' + + dataListSettings.columns.genericColumns + ' but this.dataListSettings.jsonType "' + + dataListSettings.jsonType + '" is not applicable to a generic column definition ' + + 'or not yet implemented)'); } + // if not using generic columns + } else { + for (const column of dataListSettings.columns.columnMapping) { + if (column.displayed === true) { + displayedColumns.push(column.name); + } + } + console.log('got displayed comlumns by definition in comlumnMapping: ' + displayedColumns); + return displayedColumns; + } + } + + private generateDisplayedColumnsForKnora(data) { + const cols = new Set(); + for (const obj of data) { + for (const key of Object.getOwnPropertyNames(obj)) { + cols.add(key); + } + } + return cols; + } } diff --git a/src/app/data-list-view/data-list-view-table/data-list-view-table.component.ts b/src/app/data-list-view/data-list-view-table/data-list-view-table.component.ts index 69845f6..8409337 100644 --- a/src/app/data-list-view/data-list-view-table/data-list-view-table.component.ts +++ b/src/app/data-list-view/data-list-view-table/data-list-view-table.component.ts @@ -1,231 +1,230 @@ import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { MatPaginator, MatSort, MatTable, MatTableDataSource } from '@angular/material'; import { MatDialog } from '@angular/material'; import { DialogComponent } from '../../dialog-component/dialog.component'; import { DataService } from '../../services/resources.service'; import { PipeTransform, Pipe } from '@angular/core'; import { ngxCsv } from 'ngx-csv/ngx-csv'; @Component({ selector: 'data-list-view-table', templateUrl: './data-list-view-table.component.html' }) export class DataListViewTableComponent implements OnInit { @Input() dataListSettings: any; @Input() dataToDisplay: any; @Input() displayedColumns?: any; @ViewChild(MatTable, { static: true } ) table: MatTable; @ViewChild(MatPaginator, { static: true } ) paginator: MatPaginator; @ViewChild(MatSort, { static: true } ) sort: MatSort; // cssUrl: string; dataSource: MatTableDataSource ; dataSourceForExport: MatTableDataSource ; // TODO: highlight filter results in table cells by pipe toHighlightByFilter: string = ''; // For highlighting Filter results // Export variables renderedData: any; renderedDisplayedData: any; exportSelection = 'displayed'; UMLAUT_REPLACEMENTS = '{[{ "Ä", "Ae" }, { "Ü", "Ue" }, { "Ö", "Oe" }, { "ä", "ae" }, { "ü", "ue" }, { "ö", "oe" }]}'; constructor(private dialog: MatDialog, private dataService: DataService) { } ngOnInit() { - // console.log('this.dataToDisplay: ' + this.dataToDisplay ); - // console.log('displayed columns:' + this.displayedColumns); + console.log('this.dataToDisplay: ' + this.dataToDisplay ); + console.log('displayed columns:' + this.displayedColumns); this.populateByDatastream(); this.setFilter(); } // // DATA STREAM // private populateByDatastream() { // INSTANTIATE the datasource of the table - // TODO: if (jsonType === extendedSearch ) { ... } this.dataSource = new MatTableDataSource(this.dataToDisplay); this.dataSource.connect().subscribe(data => { this.renderedDisplayedData = data; } ); if (this.dataListSettings.paginator.paginate) { this.dataSource.paginator = this.paginator; } // SUBSCRIBE to the tabledata for exporting this rendered data this.dataSourceForExport = new MatTableDataSource(this.dataToDisplay); this.dataSourceForExport.connect().subscribe(data => this.renderedData = data); if (this.dataSource) { if (this.dataListSettings.columns.nestedDatasource) { // IF the dataSource is nested sort must sort the table for subproperties (item.poperty.value) // and not for properties (standard sort). Therefore changing the sortingDataAccessor. this.dataSource.sortingDataAccessor = (item, property) => { switch (property) { default: return item[property].value; }}; } /*else { this.dataSource.sortingDataAccessor = (item, property) => { switch (property) { default: return this.replaceUmlaute(item[property]); }};*/ this.dataSource.sort = this.sort; } // } public replaceUmlaute(input) { console.log(input); for (const i of this.UMLAUT_REPLACEMENTS) { console.log(i[0], i[1]); input = input.replace(i[0], i[1]); } // console.log(input); return input; } // FILTERING THE datasource acc to settings private doFilter(value: string) { if (this.dataListSettings.filter.caseSensitive) { this.dataSource.filter = value; // TODO: highlighting this.toHighlightByFilter = value; } else { this.dataSource.filter = value.toLowerCase(); // TODO: highlighting this.toHighlightByFilter = value; } } // // FILTER // private setFilter() { // setting Filter predicate acc. to settings this.dataSource.filterPredicate = (data, filter) => { // console.log("resetting filter predicate for Filter term " + filter); const dataStr: string = this.joinFilteredColumns(data); // applying case sensitivity/insensitivity from settings if (this.dataListSettings.filter.caseSensitive) { return dataStr.indexOf(filter) !== -1; } else { return dataStr.toLowerCase().indexOf(filter) !== -1; } }; } private joinFilteredColumns(data) { let dataStr = ''; if ( this.dataListSettings.columns.genericColumns === false ) { // JOINING all columns to be searched by filter (defined in the settings) together. // NOTE: If the datasource would be nested we have to set filtered data from data to sth like data.[column].value // so the object property value is compared by filtering and not the object itself. for (const column of this.dataListSettings.columns.columnMapping) { if (column.filtered) { dataStr = dataStr + data[column.name]; } } } else {for (const column of this.displayedColumns) { dataStr = dataStr + data[column]; } } return dataStr; } private onThisClick(val, object) { console.log('val: ' + val + '; object: ' + object); // SIMPLE METHOD TO DO SOMETHING WITH THE clicked cell/object like passing it to somewhere if (this.dataListSettings.actions.actions && this.dataListSettings.actions.actionMode === 'object') { if (this.dataListSettings.actions.actionType === 'dialog') { console.log('opening detail dialog with object with property value ' + val); this.openDetailsDialog(val); } else { console.log('actions disabled or no action defined'); } } } // TODO: maybe outsource this private openDetailsDialog(msg) { this.dialog.open(DialogComponent, { data: { message: msg, buttonText: {cancel: 'close' } }, }); } // TODO: maybe implement features from events by hostlistener ... /* @HostListener('click', ['$event']) onClick(event) { if (this.dataListSettings.actions.actions && this.dataListSettings.actions.actionMode === 'host' && event.target.parentElement.classList[0] === 'fuuws') { // HERE THINGS CAN BE ADDED § console.log('opening detail dialog with ' + event.target.firstChild.data ); console.log( event.target ); this.openDetailsDialog(event.target.firstChild.data); } // else {console.log('actions on cells disabled or no action defined')} }*/ // // EXPORT TO CSV public exportToCsv() { var options = { fieldSeparator: ',', quoteStrings: '"', decimalseparator: '.', showLabels: true, showTitle: true, title: 'data export', useBom: true, noDownload: false, headers: this.displayedColumns }; let exportData = this.getExportData(); new ngxCsv(exportData, options.title, options); } public getExportData() { if (this.exportSelection === 'displayed') { return this.renderedDisplayedData; } else { return this.renderedData; } } /*public flatten(data) { // FLATTENS the data so the actual values of the nested objects are exported - not whole objects. let flattenedData = []; for (let obj in data) { let flattenobject = []; if (obj < data.length) { for (let property in data[obj]) { const prop = data[obj][property].value; flattenobject.push(prop); } flattenedData.push(flattenobject); } } return flattenedData; }*/ // // Display / Design stuff // private isColumnSticky (column: number): boolean { // Returns for each column whether/which column should be sticky when scrolling horizontally // (this.dataListSettings.columns.stickyColumn ? true : false) return !!this.dataListSettings.columns.stickyColumn; } } // TODO: highlighting filter results in cells by pipe @Pipe({ name: 'highlight' }) export class HighlightPipe implements PipeTransform { transform(text: string, search): string { const pattern = search .replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") .split(' ') .filter(t => t.length > 0) .join('|'); const regex = new RegExp(pattern, 'gi'); return search ? text.replace(regex, match => `${match}`) : text; } } diff --git a/src/app/data-list-view/data-list-view.component.html b/src/app/data-list-view/data-list-view.component.html index 4db9afc..037aa6b 100644 --- a/src/app/data-list-view/data-list-view.component.html +++ b/src/app/data-list-view/data-list-view.component.html @@ -1,8 +1,7 @@
- diff --git a/src/app/data-list-view/data-list-view.component.ts b/src/app/data-list-view/data-list-view.component.ts index 04263ba..4f84c88 100644 --- a/src/app/data-list-view/data-list-view.component.ts +++ b/src/app/data-list-view/data-list-view.component.ts @@ -1,237 +1,137 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, Output, OnInit, OnChanges } from '@angular/core'; import { DataService } from '../services/resources.service'; -import { TableDataService } from './data-list-view-services/table-data.service'; +import { DisplayedCollumnsService } from './data-list-view-services/table-data.service'; +import fallbackSettings from './assets/settings.json'; +import { QueryService } from '../services/query.service'; @Component({ - selector: 'data-list-view', - templateUrl: './data-list-view.component.html', - providers: [] + selector: 'app-data-list-view', + templateUrl: './data-list-view.component.html' }) -export class DataListView implements OnInit { - @Input() queryResponse?: any; +export class DataListViewComponent implements OnInit { + @Input() dataToDisplay?: Array; @Input() settings?: any; @Input() query?: any; + @Output() displayedColumns: Array = []; dataListSettings: any; resData: any; - displayedColumns: any = []; tableData: Array = []; - constructor(private dataService: DataService, private tableDataService: TableDataService) { + constructor(private dataService: DataService, private displayedCollumnsService: DisplayedCollumnsService, + private queryService: QueryService) { } ngOnInit() { - this.dataListSettings = this.getSettings(this.settings); + this.getSettings(); this.onGetData(); } - generateTableData( response: any, depth: number ) { - if (this.queryResponse === undefined ) { - this.queryResponse = response; - } - console.log('this.queryResponse: ' + this.queryResponse); + generateTableData(responseData: Array, depth: number) { if (this.dataListSettings.columns.genericColumns) { let length = 0; - for (const entry of response) { + for (const entry of responseData) { this.flattenObjects(entry, length); length += 1; } this.resData = this.tableData; - console.log(this.resData); + // console.log(this.resData); } else { let length = -1; - for (const responseEntry of response) { + for (const responseEntry of responseData) { length += 1; this.appendEntryToTabledata(responseEntry, 0, length); } } } - appendEntryToTabledata( ResponseEntry: any, depth: number, length: number, pathCompare?: Array ) { + appendEntryToTabledata(ResponseEntry: any, depth: number, length: number, pathCompare?: Array) { // recursive method for getting the actual values from nested jsons // and appending them to the tabledata. Allowed values are strings, // numbers, symbols and booleans (so no objects allowed here). - for ( const column of this.dataListSettings.columns.columnMapping ) { - if ( typeof ResponseEntry[ column.path[ depth ]] === 'string' || - typeof ResponseEntry[ column.path[ depth ]] === 'number' || - typeof ResponseEntry[ column.path[ depth ]] === 'symbol' || - typeof ResponseEntry[ column.path[ depth ]] === 'boolean') { - // checks if the path of a recursive function call is the same as the column - // generated by the for loop, this is necessary if more than one column has in the same depths the same segment names - if ( pathCompare === undefined || pathCompare === column.path ) { - this.append( ResponseEntry[ column.path[ depth ]], column.name, length ); - } - } else if (typeof ResponseEntry[ column.path[ depth ]] === 'object') { - this.appendEntryToTabledata( ResponseEntry[column.path[ depth ]] , depth + 1, length, column.path ); + for (const column of this.dataListSettings.columns.columnMapping) { + if (typeof ResponseEntry[column.path[depth]] === 'string' || + typeof ResponseEntry[column.path[depth]] === 'number' || + typeof ResponseEntry[column.path[depth]] === 'symbol' || + typeof ResponseEntry[column.path[depth]] === 'boolean') { + // checks if the path of a recursive function call is the same as the column + // generated by the for loop, this is necessary if more than one column has in the same depths the same segment names + if (pathCompare === undefined || pathCompare === column.path) { + this.append(ResponseEntry[column.path[depth]], column.name, length); } + } else if (typeof ResponseEntry[column.path[depth]] === 'object') { + this.appendEntryToTabledata(ResponseEntry[column.path[depth]], depth + 1, length, column.path); } + } } - append( entry: string, name: string, length: number ) { + append(entry: string, name: string, length: number) { // is appending the collected values to the tabledata - if ( this.tableData[ length ] === undefined ) { - this.tableData[ length ] = {}; + if (this.tableData[length] === undefined) { + this.tableData[length] = {}; } - this.tableData[ length ][ name ] = entry; - if ( this.tableData.length === this.queryResponse.length ) { + this.tableData[length][name] = entry; + if (this.tableData.length === this.dataToDisplay.length) { this.resData = this.tableData; + console.log('this.tableData: ' + this.tableData); } } flattenObjects(input, length, reference?, output?) { // FLATTENS the response completely and assigns the result to tableData. output = output || {}; for (let key of Object.keys(input)) { const value = input[key]; if (reference) { key = reference + '.' + key; } if (typeof value === 'object' && value !== null) { - this.flattenObjects(value, length, key, output); + this.flattenObjects(value, length, key, output); } else { output[key] = value; // renesting with name and types // output[key]['value'] = value; // if (reference['type'] || reference['whatever']) { // output[key]['type'] = reference['type']; // } } } - this.tableData[ length ] = output; - } - - generateDisplayedColumnsForKnora() { - console.log( this.tableData ); - const cols = new Set(); - for (const obj of this.tableData) { - for (const key of Object.getOwnPropertyNames(obj)) { - cols.add(key); - } - } - this.displayedColumns = cols; + this.tableData[length] = output; } - getDisplayedColumns(headers?) { - if (this.dataListSettings.columns.genericColumns) { - if (this.dataListSettings.jsonType === 'sparql') { - for (const entry of headers.head.vars) { - this.displayedColumns.push(entry + '.type'); - this.displayedColumns.push(entry + '.value'); - } - } else if (this.dataListSettings.jsonType === 'knora-extended') - { - this.generateDisplayedColumnsForKnora(); - } else { - console.log('Wrong datalistSettings: this.dataListSettings.columns.genericColumns = ' + - this.dataListSettings.columns.genericColumns + ' but this.dataListSettings.jsonType "' + - this.dataListSettings.jsonType + '" is not applicable to a generic column definition ' + - 'or not yet implemented)'); } - // if not using generic columns - } else { - for (const column of this.dataListSettings.columns.columnMapping) - { - if (column.displayed === true) { - this.displayedColumns.push(column.name); - } - } - console.log('got displayed comlumns by definition in comlumnMapping: ' + this.displayedColumns); - } - } // GET the data - either from running a query itself or by the input from another app/service (jsonResponse) private onGetData() { - if (this.dataListSettings && this.dataListSettings.inputMode === 'query') { + if ( this.dataListSettings.inputMode === 'query' ) { console.log('getting data by running a SPARQL query.'); - this.dataService.getData( this.query ).subscribe(data => { - const responseData: any = data; - this.generateTableData(responseData.results.bindings, 0); - this.getDisplayedColumns(responseData); - }); - - } else if (this.dataListSettings && this.dataListSettings.inputMode === 'queryResponse') { - console.log('getting data by a Resonse input.'); - if ( this.queryResponse && this.dataListSettings) { - this.generateTableData(this.queryResponse, 0); - this.getDisplayedColumns(); - } else { - console.log('no data by input available yet. Please choose data input·'); - } - } else { - console.log('missing or wrong settings definition for data source.'); - } + this.getTableDataFromQuery(this.query); + } else if ( this.dataListSettings.inputMode === 'input') { + console.log('getting data by input.'); + if (this.dataToDisplay ) { + this.generateTableData(this.dataToDisplay, 0); + this.displayedColumns = this.displayedCollumnsService.getDisplayedColumns(this.dataListSettings, this.dataToDisplay); + } else { console.log('No dataToDisplay passed by input as defined in dataListSettings.inputMode: ' + this.dataListSettings.inputMode); } + } else { console.log('Wrong settings definition for --> \"inputmode: ' + this.dataListSettings.inputMode + '\" allowed are: input, query'); } + } + private getTableDataFromQuery(query) { + this.dataService.getData( this.query ).subscribe(data => { + const responseData: any = data; + this.dataToDisplay = responseData.results.bindings; + this.generateTableData(this.dataToDisplay, 0); + this.displayedColumns = this.displayedCollumnsService.getDisplayedColumns(this.dataListSettings, this.dataToDisplay); + }); } - getSettings(settings?) { - if ((settings === undefined || settings === null || Object.keys(settings).length === 0)) { - console.log('Input for settings is undefined/null or contains no data. loading default settings.'); - return { - "inputMode": "query", - "jsonType": "sparql", - "columns": { - "genericColumns": false, - "columnMapping" : [ - { - name: 'subject', - path: ["s", "value" ], - displayed: true, - filtered: true - }, - { - name: 'predicate', - path: [ "p", "value" ], - displayed: true, - filtered: true - }, - { - name: 'object', - path: [ "o", "value" ], - displayed: true, - filtered: true - }], - "stickyColumn": 0, - "nestedDatasource": false - }, - "filter": { - "showFilter": false, - "caseSensitive": false - }, - "paginator": { - "paginate": true, - "pageIndex": "0", - "pageSize": "5", - "pageSizeOptions": [5, 10, 25, 50, 100, 250] - }, - "export": { - "showExport": false - }, - "sort": { - "disallowSorting": true - }, - "styles": { - "cellStyle": { - "cursor": "pointer" - } - }, - "actions": { - "actions": true, - "_comment": { - "cursorstyle": "use custom css properties", - "intLink": "opens another app", - "extLink": "opens another webpage" - }, - "actionMode": "object", - "actionType": "dialog", - "actionRange": "cell", - "baseUrl": "http://localhost:4200/page?actionID=5c8a6300b4438759d237b246", - "urlParams": { - "label": "label.value", - "highlight": "authorsname.value" - } + private getSettings() { + if ( this.settings ) { + this.dataListSettings = this.settings; + console.log('Got settings by input.'); + } else { + console.log('No settings input. Loading default settings.'); + this.dataListSettings = fallbackSettings; } - }; - } else {return settings;} - } + } } diff --git a/src/app/dialog-component/dialog.component.ts b/src/app/dialog-component/dialog.component.ts index 4dede4f..b7c8ad6 100644 --- a/src/app/dialog-component/dialog.component.ts +++ b/src/app/dialog-component/dialog.component.ts @@ -1,32 +1,32 @@ import {Component, Inject, Injectable} from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; @Component({ selector: 'dialog-component', templateUrl: './dialog.component.html' }) @Injectable() export class DialogComponent { // DEFAULT values in case there is no initialContent or button text passed from app - initialContent = ''; + initialContent = 'Loading data for entity ...'; cancelButtonText = 'close'; constructor( @Inject(MAT_DIALOG_DATA) private data: any, private dialogRef: MatDialogRef) { // // in case there is no data/initialContent passed the default this.initialContent will be displayed- Same for button text. // if (data) { this.initialContent = data.message || this.initialContent; if (data.buttonText) { this.cancelButtonText = data.buttonText.cancel || this.cancelButtonText; } } this.dialogRef.updateSize('1200vw', '800vw'); } onConfirmClick(): void { this.dialogRef.close(true); } } diff --git a/src/app/info-box-component/info-box.component.html b/src/app/info-box-component/info-box.component.html index 4904784..b319972 100644 --- a/src/app/info-box-component/info-box.component.html +++ b/src/app/info-box-component/info-box.component.html @@ -1,45 +1,45 @@
{{manuscript.title}}
{{word.text}}
- +
{{word.text}}

{{word.id}}

Informationen zu Seite {{page.number}} {{metadata.head.description}}
{{content.reference}}:
{{content.quote}}]
{{content.text}}
diff --git a/src/app/info-box-component/info-box.component.ts b/src/app/info-box-component/info-box.component.ts index 6070844..b97bc3d 100644 --- a/src/app/info-box-component/info-box.component.ts +++ b/src/app/info-box-component/info-box.component.ts @@ -1,45 +1,113 @@ import {Component, Input, OnInit, Output} from '@angular/core'; import { MatExpansionModule } from '@angular/material/expansion'; import { Subscription } from 'rxjs'; import { WordService} from '../services/field-interaction.service'; import { Word } from '../models/word'; import { QueryService } from '../services/query.service'; +import { DataService } from '../services/resources.service'; @Component({ selector: 'app-info-box', templateUrl: './info-box.component.html', styleUrls: ['./info-box.component.css'] }) export class InfoBoxComponent implements OnInit { @Input() manuscript: any; - @Output() query: string; - information: string = "test"; + @Output() queryResponse: any; + @Output() dataListSettings = { + "inputMode": "query", + "jsonType": "sparql", + "columns": { + "genericColumns": false, + "columnMapping" : [ + { + name: 'predicate', + path: [ "p", "value" ], + displayed: true, + filtered: true + }, + { + name: 'object', + path: [ "o", "value" ], + displayed: true, + filtered: true + }], + "stickyColumn": 0, + "nestedDatasource": false + }, + "filter": { + "showFilter": false, + "caseSensitive": true + }, + "paginator": { + "paginate": false, + "pageIndex": "0", + "pageSize": "5", + "pageSizeOptions": [5, 10, 25, 50, 100, 250] + }, + "export": { + "showExport": false + }, + "sort": { + "disallowSorting": true + }, + "styles": { + "cellStyle": { + "cursor": "pointer" + } + }, + "actions": { + "actions": true, + "_comment": { + "cursorstyle": "use custom css properties", + "intLink": "opens another app", + "extLink": "opens another webpage" + }, + "actionMode": "object", + "actionType": "dialog", + "actionRange": "cell", + "baseUrl": "http://localhost:4200/page?actionID=5c8a6300b4438759d237b246", + "urlParams": { + "label": "label.value", + "highlight": "authorsname.value" + } + } + }; word: Word; subscription: Subscription; showInfo: boolean = false; expansion: boolean = true; - constructor(private infoService: WordService, private matExpansionModule: MatExpansionModule, private queryService: QueryService) { + constructor(private infoService: WordService, + private matExpansionModule: MatExpansionModule, + private queryService: QueryService, + private dataService: DataService) { this.subscription = infoService.wordChange$.subscribe( word => { if (this.word === word) { this.toggleShowInfo(); this.word = null; } else { this.word = word; if (!this.showInfo) { this.toggleShowInfo(); - console.log('this.word: ' + this.word); - this.query = this.queryService.assemble_resource_data( encodeURI('http://rdfh.ch/projects/0068#_W_II_1_Page131_Word206'), 'subject'); - console.log('this.query: ' + this.query); + this.updateRDFData(word); } } }); } - ngOnInit() { - } - toggleShowInfo() { + ngOnInit() { + + } + + private toggleShowInfo() { this.showInfo = !this.showInfo; } + public updateRDFData(word) { + const query = this.queryService.assemble_resource_data( encodeURI('http://rdfh.ch/projects/0068#_W_II_1_Page131_Word206'), 'subject'); + this.dataService.getData(query).subscribe(data => { + this.queryResponse = data; + console.log('response for new ' + word + ': ' + data); }); + } } diff --git a/src/app/rdf-data-browser-component/rdf-data-browser-component.component.html b/src/app/rdf-data-browser-component/rdf-data-browser-component.component.html index c0d42ce..9bfa540 100644 --- a/src/app/rdf-data-browser-component/rdf-data-browser-component.component.html +++ b/src/app/rdf-data-browser-component/rdf-data-browser-component.component.html @@ -1,3 +1,3 @@
- +
diff --git a/src/app/rdf-data-browser-component/rdf-data-browser-component.component.ts b/src/app/rdf-data-browser-component/rdf-data-browser-component.component.ts index b5807ec..0fdaa4e 100644 --- a/src/app/rdf-data-browser-component/rdf-data-browser-component.component.ts +++ b/src/app/rdf-data-browser-component/rdf-data-browser-component.component.ts @@ -1,88 +1,94 @@ import {Component, Input, OnInit, Output} from '@angular/core'; import {QueryService} from '../services/query.service'; +import { DataService } from '../services/resources.service'; @Component({ selector: 'app-rdf-data-browser-component', templateUrl: './rdf-data-browser-component.component.html', styleUrls: ['./rdf-data-browser-component.component.scss'] }) export class RdfDataBrowserComponentComponent implements OnInit { @Input() resourceOfInterest?: string; - @Output() query: string; + @Output() queryResponse: any; @Output() dataListSettings = { "inputMode": "query", "jsonType": "sparql", "columns": { "genericColumns": false, "columnMapping" : [ { name: 'subject', path: ["s", "value" ], - displayed: true, - filtered: true + displayed: false, + filtered: false }, { name: 'predicate', path: [ "p", "value" ], displayed: true, filtered: true }, { name: 'object', path: [ "o", "value" ], displayed: true, filtered: true }], "stickyColumn": 0, "nestedDatasource": false }, "filter": { "showFilter": true, "caseSensitive": true }, "paginator": { "paginate": true, "pageIndex": "0", "pageSize": "25", "pageSizeOptions": [5, 10, 25, 50, 100, 250] }, "export": { "showExport": true }, "sort": { "disallowSorting": false }, "styles": { "cellStyle": { "cursor": "pointer" } }, "actions": { "actions": true, "_comment": { "cursorstyle": "use custom css properties", "intLink": "opens another app", "extLink": "opens another webpage" }, "actionMode": "object", "actionType": "dialog", "actionRange": "cell", "baseUrl": "http://localhost:4200/page?actionID=5c8a6300b4438759d237b246", "urlParams": { "label": "label.value", "highlight": "authorsname.value" } } }; + query: string; - constructor( private queryservice: QueryService ) { } + constructor( private queryservice: QueryService, private dataService: DataService ) { } ngOnInit() { if ( this.resourceOfInterest ) { console.log('this.resourceOfInterest: ' + this.resourceOfInterest) this.query = this.queryservice.assemble_resource_data(encodeURI(this.resourceOfInterest), 'subject'); console.log('query assembled: ' + this.query); + + this.dataService.getData( this.query ).subscribe(data => { + this.queryResponse = data; + console.log('response: ' + data); }); } else { console.log('No resource of interest passed.'); } } } diff --git a/src/app/services/query.service.ts b/src/app/services/query.service.ts index 2910c46..2c28ce1 100644 --- a/src/app/services/query.service.ts +++ b/src/app/services/query.service.ts @@ -1,43 +1,44 @@ import { Injectable } from '@angular/core'; +import { DataService } from './resources.service'; @Injectable() export class QueryService { query: string; - select = 'SELECT ?s ?p ?o ' + select = 'SELECT ?p ?o ' whereSubject: string; whereObject: string; wherePredicate: string; Optional = ''; queryLimit = ' LIMIT 200'; - constructor() { + constructor(private dataService: DataService ) { } public assemble_resource_data(resourceValue: string, resourceOwlClass?: string) { switch (resourceOwlClass) { case 'subject': { this.whereSubject = ' <' + decodeURI(resourceValue) + '> '; this.wherePredicate = ' ?p '; this.whereObject = ' ?o '; break; } case 'object': { this.whereObject = ' <' + decodeURI(resourceValue) + '> '; this.wherePredicate = ' ?p '; this.whereSubject = ' ?s '; break; } case 'predicate': { this.wherePredicate = ' <' + decodeURI(resourceValue) + '> '; this.whereObject = ' ?o '; this.whereSubject = ' ?s '; break; } - } + this.query = this.select + 'WHERE { ' + this.whereSubject + this.wherePredicate + this.whereObject + this.Optional + ' } ' + this.queryLimit; return this.query; } } diff --git a/src/app/services/resources.service.ts b/src/app/services/resources.service.ts index b2724b7..21344a6 100644 --- a/src/app/services/resources.service.ts +++ b/src/app/services/resources.service.ts @@ -1,36 +1,37 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class DataService { constructor(private http: HttpClient) { } readonly httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/sparql-query', 'Accept': 'application/sparql-results+json; charset=UTF-8' }) }; baseUrl = 'http://localhost:3030/nietzsche/query'; prefix = 'http://www.nie.org/ontology/nietzsche#' prefix2 = 'http://rdfh.ch/projects/0068#' - fallBackQuery = 'prefix tln: <' + this.prefix + '> prefix data: <' + this.prefix2 + '> ' + ' SELECT ?subject ?predicate ?object WHERE' + - ' { ?subject a tln:Word . ?subject tln:hasText ?o ' + - 'OPTIONAL { ?subject ?predicate ?object } } LIMIT 50'; + fallBackQuery = 'prefix tln: <' + this.prefix + '> prefix data: <' + this.prefix2 + '> ' + ' SELECT ?s ?p ?o WHERE' + + ' { ?s a tln:Word . ?s tln:hasText ?o ' + + ' OPTIONAL { ?s ?p ?o } ' + + ' } LIMIT 50'; public getData(query: string) { if (this.baseUrl && query && this.httpOptions.headers) { return this.http.post(this.baseUrl, query, this.httpOptions); } - if (this.baseUrl && this.httpOptions.headers && (query === undefined || query === null ) ) { - console.log('fallback to static query as there is no query: ' + this.fallBackQuery) - return this.http.post(this.baseUrl, this.fallBackQuery, this.httpOptions); - } else { - console.log('url, body (query) or headers missing.'); + if (this.baseUrl && this.httpOptions.headers && (query === undefined || query === null || query === '') ) { + console.log('fallback to static query as there is no query passed: ' + this.fallBackQuery); + const fuu = this.http.post(this.baseUrl, this.fallBackQuery, this.httpOptions); + console.log(fuu) + return fuu; } } }