Angular4 frontend added

This commit is contained in:
sosguns2002 2018-02-28 13:41:06 +02:00
parent ed9faef7c8
commit bf94c324ef
101 changed files with 18065 additions and 1 deletions

@ -1 +0,0 @@
Subproject commit 1300909bca20fa744bde85d3f44fda559f43eb93

View File

@ -0,0 +1,64 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "interactiveminingv3"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
"../node_modules/uikit/dist/js/uikit.min.js",
"../node_modules/uikit/dist/js/uikit-icons.min.js"
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}

View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -0,0 +1,43 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
yarn-error.log
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db

View File

@ -0,0 +1,28 @@
# Interactiveminingv3
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.3.0.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Before running the tests make sure you are serving the app via `ng serve`.
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).

View File

@ -0,0 +1,14 @@
import { AppPage } from './app.po';
describe('interactiveminingv3 App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('Welcome to app!');
});
});

View File

@ -0,0 +1,11 @@
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}

View File

@ -0,0 +1,14 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}

View File

@ -0,0 +1,33 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -0,0 +1,55 @@
{
"name": "interactiveminingv3",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^4.2.4",
"@angular/common": "^4.2.4",
"@angular/compiler": "^4.2.4",
"@angular/core": "^4.2.4",
"@angular/forms": "^4.2.4",
"@angular/http": "^4.2.4",
"@angular/platform-browser": "^4.2.4",
"@angular/platform-browser-dynamic": "^4.2.4",
"@angular/router": "^4.2.4",
"core-js": "^2.4.1",
"file-saver": "^1.3.3",
"jquery": "^3.2.1",
"ngx-cookie-service": "^1.0.10",
"ngx-pagination": "^3.1.0",
"ngx-textarea-autosize": "^1.1.1",
"rxjs": "^5.4.2",
"uikit": "^3.0.0-beta.38",
"zone.js": "^0.8.14"
},
"devDependencies": {
"@angular/cli": "1.3.0",
"@angular/compiler-cli": "^4.2.4",
"@angular/language-service": "^4.2.4",
"@types/jasmine": "~2.5.53",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "~3.1.1",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "~1.7.0",
"karma-chrome-launcher": "~2.1.1",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.2.0",
"tslint": "~5.3.2",
"typescript": "~2.3.3"
}
}

View File

@ -0,0 +1,28 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {ContentComponent} from './contents/contents.component';
import {ConfigurationComponent} from './configuration/configuration.component';
import {SaveprofileComponent} from './saveprofile/saveprofile.component';
import {ManageprofilesComponent} from './manageprofiles/manageprofiles.component';
const routes: Routes = [
{ path: '', redirectTo: '/manage-profiles', pathMatch: 'full' },
{ path: 'manage-profiles', component: ManageprofilesComponent },
{ path: 'upload-content', component: ContentComponent },
{ path: 'configure-profile', component: ConfigurationComponent },
{ path: 'save-profile', component: SaveprofileComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule { }

View File

@ -0,0 +1,2 @@
<app-stepsnvabar></app-stepsnvabar>
<router-outlet></router-outlet>

View File

@ -0,0 +1,32 @@
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
}));
});

View File

@ -0,0 +1,10 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}

View File

@ -0,0 +1,33 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { CookieService } from 'ngx-cookie-service';
import { ContentModule } from './contents/contents.module';
import { AppRoutingModule } from './app-routing.module';
import { StepsnvabarComponent } from './stepsnvabar/stepsnvabar.component';
import {ConfigurationModule} from './configuration/configuration.module';
import {SaveprofileModule} from './saveprofile/saveprofile.module';
import {ManagprofilesModule} from './manageprofiles/manageprofiles.module';
import {HttpModule} from '@angular/http';
@NgModule({
declarations: [
AppComponent,
StepsnvabarComponent
],
imports: [
BrowserModule,
ManagprofilesModule,
ContentModule,
ConfigurationModule,
SaveprofileModule,
HttpClientModule,
HttpModule,
AppRoutingModule
],
providers: [CookieService],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,11 @@
<div id="parent">
<app-settings id="child1" class="cm-config-settings-section"></app-settings>
<app-resultspreview id="child2"></app-resultspreview>
<div style="clear: both;"></div>
</div>
<div id="wait-spinner-modal-center" class="uk-flex-top" esc-close="false" bg-close="false" uk-modal>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<p class="uk-text-center uk-text-middle uk-text-large">Working on it, please wait... <span uk-spinner></span></p>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfigurationComponent } from './configuration.component';
describe('ConfigurationComponent', () => {
let component: ConfigurationComponent;
let fixture: ComponentFixture<ConfigurationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConfigurationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfigurationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,52 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-configuration',
templateUrl: './configuration.component.html',
styleUrls: ['./configuration.component.css']
})
export class ConfigurationComponent implements OnInit {
constructor() { }
ngOnInit() {
// initialize settings
if (!localStorage.getItem('docname') || localStorage.getItem('docname') === 'undefined') {
localStorage.setItem('docname', '');
}
if (!localStorage.getItem('docsnumber') || localStorage.getItem('docsnumber') === 'undefined') {
localStorage.setItem('docsnumber', '0');
}
if (!localStorage.getItem('profileid') || localStorage.getItem('profileid') === 'undefined') {
localStorage.setItem('profileid', '');
}
if (!localStorage.getItem('precision') || localStorage.getItem('precision') === 'undefined') {
localStorage.setItem('precision', '1');
}
if (!localStorage.getItem('poswords') || localStorage.getItem('poswords') === 'undefined') {
localStorage.setItem('poswords', '{}');
}
if (!localStorage.getItem('negwords') || localStorage.getItem('negwords') === 'undefined') {
localStorage.setItem('negwords', '{}');
}
if (!localStorage.getItem('contextprev') || localStorage.getItem('contextprev') === 'undefined') {
localStorage.setItem('contextprev', '10');
}
if (!localStorage.getItem('contextnext') || localStorage.getItem('contextnext') === 'undefined') {
localStorage.setItem('contextnext', '5');
}
if (!localStorage.getItem('wordssplitnum') || localStorage.getItem('wordssplitnum') === 'undefined') {
localStorage.setItem('wordssplitnum', '2');
}
if (!localStorage.getItem('punctuation') || localStorage.getItem('punctuation') === 'undefined') {
localStorage.setItem('punctuation', '0');
}
if (!localStorage.getItem('stopwords') || localStorage.getItem('stopwords') === 'undefined') {
localStorage.setItem('stopwords', '0');
}
if (!localStorage.getItem('lettercase') || localStorage.getItem('lettercase') === 'undefined') {
localStorage.setItem('lettercase', 'None');
}
}
}

View File

@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ConfigurationComponent } from './configuration.component';
import { SettingsComponent } from './settings/settings.component';
import { ResultspreviewComponent } from './resultspreview/resultspreview.component';
import {ConfigurationService} from './configuration.service';
@NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule
],
exports: [
ConfigurationComponent
],
providers: [
ConfigurationService
],
declarations: [ConfigurationComponent, SettingsComponent, ResultspreviewComponent]
})
export class ConfigurationModule { }

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { ConfigurationService } from './configuration.service';
describe('ConfigurationService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ConfigurationService]
});
});
it('should be created', inject([ConfigurationService], (service: ConfigurationService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,74 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import {Util} from '../util';
import {Observable} from 'rxjs/Observable';
import {ProfileData} from '../manageprofiles/profile-data';
import {Settings} from './settings/settings';
import {DocSamplesMetadata} from './doc-samples-metadata';
@Injectable()
export class ConfigurationService {
private util: Util = new Util();
private getDocSamplesUrl = 'http://localhost:8080/getdocsamples';
private uploadDocumentsUrl = 'http://localhost:8080/uploaddocuments';
private chooseSampleUrl = 'http://localhost:8080/choosedocsample';
private alreadyDocumentsUrl = 'http://localhost:8080/alreadydocuments';
private runMiningUrl = 'http://localhost:8080/runmining';
private prepareSavedProfileUrl = 'http://localhost:8080/preparesavedprofile';
constructor(private http: HttpClient) { }
private _getHeaders(): Headers {
const header = new Headers({
'Content-Type': 'application/json'
});
return header;
}
getDocSamples(): Observable<DocSamplesMetadata[]> {
return this.http.get(this.getDocSamplesUrl, { withCredentials: true })
.map(data => data['documents'])
.catch(this.util.handleError);
}
uploadDocuments(file: File): Observable<number> {
const formData: FormData = new FormData();
formData.append('upload', file, file.name);
const params = new HttpParams();
const options = {
headers: new HttpHeaders().set('Accept', 'application/json').delete('Content-Type'),
params: params,
reportProgress: true,
withCredentials: true,
};
return this.http.post(this.uploadDocumentsUrl, formData, options)
.map(res => res['data'])
.catch(this.util.handleError);
}
chooseDocumentsSample(choise: string): Observable<number> {
return this.http.post(this.chooseSampleUrl, {docsample: choise}, { withCredentials: true })
.map(res => res['data'])
.catch(this.util.handleError);
}
getLoadedDocumentsNumber(): Observable<any> {
return this.http.get(this.alreadyDocumentsUrl, { withCredentials: true })
.catch(this.util.handleError);
}
runMining(parameters: string): Observable<any> {
return this.http.post(this.runMiningUrl,
parameters, { withCredentials: true })
.catch(this.util.handleError);
}
saveProfileParameters(parameters: Settings): Observable<any> {
return this.http.post(this.prepareSavedProfileUrl, parameters, { withCredentials: true })
.catch(this.util.handleError);
}
}

View File

@ -0,0 +1,4 @@
export interface DocSamplesMetadata {
name: string;
documents: number;
}

View File

@ -0,0 +1,6 @@
import {Match} from './match';
export class DocumentResult {
docTitle: string;
matches: Array<Match>;
}

View File

@ -0,0 +1,6 @@
export class Match {
match: string;
context: string;
extraprev: string;
extranext: string;
}

View File

@ -0,0 +1,62 @@
<div class="cm-results-section">
<header id="cm-results-section-header" class="uk-container uk-container-expand">
<div class="cm-results-controls">
<div class="uk-margin">
<h4>Matching test area <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></h4>
<p class="uk-text-middle">Choose a document sample to test your matchin results!</p>
<div class="uk-grid-collapse uk-child-width-expand@s" uk-grid>
<form class="uk-search uk-search-default uk-width-1-5@m">
<span class="uk-search-icon-flip" uk-search-icon></span>
<input class="uk-search-input" type="search" placeholder="Search..." style="background-color: white;">
</form>
<button *ngIf="documentsLoaded" class="uk-button uk-button-primary uk-width-auto cm-doc-selected" style="padding-left: 25px">{{docNameLoaded}}<span uk-icon="icon: check; ratio: 1"></span></button>
<div class="uk-width-expand" uk-slider>
<div class="uk-position-relative">
<div class="uk-slider-container">
<ul class="uk-slider-items uk-grid-small">
<li *ngFor="let doc of docSamples">
<button class="uk-button uk-button-primary" (click)="chooseSample(doc.name)">{{doc.name}}</button>
</li>
</ul>
</div>
<div >
<a class="uk-position-center-left uk-position-small cm-slidenav cm-slidenav-left" href="#" uk-slidenav-previous uk-slider-item="previous"></a>
<a class="uk-position-center-right uk-position-small cm-slidenav cm-slidenav-right" href="#" uk-slidenav-next uk-slider-item="next"></a>
</div>
</div>
</div>
</div>
<div class="uk-text-right uk-margin-small-top">
<span class="uk-text-middle">or</span>
<div uk-form-custom>
<input #docupload type="file" (change)="fileChangeUpload($event);docupload.value=''" accept=".txt,.pdf">
<span class="uk-link">Upload your documents</span>
</div>
</div>
</div>
<h4>Test results <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></h4>
<button id="run-mining-btn" class="uk-button uk-button-primary" [disabled]="!documentsLoaded" (click)="runMining()">Apply rules to sleected documents</button>
</div>
<div class="cm-results-count-section">
<div id="results-count">
<span id="results-number" class="uk-text-primary uk-margin-right">{{matches_number}}</span>
<span id="results-number-previous" class="cm-text-muted">{{prev_matches_number}}</span>
</div>
</div>
</header>
<div id="results-section" class="cm-results-rows">
<ul id="docs-results" uk-accordion="multiple: true">
<li *ngFor="let result of resultsArray;" class="uk-card uk-card-default uk-card-small uk-card-body uk-open">
<h3 class="uk-accordion-title">{{result.docTitle}}</h3>
<div class="uk-accordion-content" aria-hidden="false">
<div *ngFor="let match of result.matches">
<div class="match">Match 1: {{match.match}}</div>
<p class="cm-document-result">
{{match.extraprev}} <span class="textwindow" [innerHTML]="match.context"></span> {{match.extranext}}
</p>
</div>
</div>
</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ResultspreviewComponent } from './resultspreview.component';
describe('ResultspreviewComponent', () => {
let component: ResultspreviewComponent;
let fixture: ComponentFixture<ResultspreviewComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ResultspreviewComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ResultspreviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,173 @@
import { Component, OnInit } from '@angular/core';
import {ConfigurationService} from '../configuration.service';
import {Settings} from '../settings/settings';
import {DocumentResult} from './document-result';
import {Match} from './match';
import {DocSamplesMetadata} from '../doc-samples-metadata';
@Component({
selector: 'app-resultspreview',
templateUrl: './resultspreview.component.html',
styleUrls: ['./resultspreview.component.css']
})
export class ResultspreviewComponent implements OnInit {
public docSamples: Array<DocSamplesMetadata> = [];
public docNameLoaded = '';
public documentsLoaded = 0;
public resultsArray: Array<DocumentResult> = [];
public matches_number = '';
public prev_matches_number = '';
constructor(private configurationService: ConfigurationService) { }
ngOnInit() {
this.getDocSamples();
this.getLoadedDocuments();
this.docNameLoaded = localStorage.getItem('docname');
}
getDocSamples(): void {
this.configurationService.getDocSamples()
.subscribe(res => this.docSamples = res);
}
getLoadedDocuments(): void {
this.configurationService.getLoadedDocumentsNumber()
.subscribe(res => {
this.documentsLoaded = res.data;
localStorage.setItem('docsnumber', res.toString());
if (res.data > 0) {
} else {
}
});
}
chooseSample(choice: string): void {
this.configurationService.chooseDocumentsSample(choice)
.subscribe(res => {
this.documentsLoaded = res;
this.docNameLoaded = choice;
localStorage.setItem('docname', choice);
localStorage.setItem('docsnumber', res.toString());
});
}
fileChangeUpload(event): void {
const fileList: FileList = event.target.files;
if (fileList && fileList.length === 1) {
const file: File = fileList[0];
// get new profile data
this.configurationService.uploadDocuments(file)
.subscribe(res => {
this.documentsLoaded = res;
this.docNameLoaded = file.name;
localStorage.setItem('docname', file.name);
localStorage.setItem('docsnumber', res.toString());
});
}
}
getSettingsFromLocalStorage(): Settings {
return {
precision: 4,
docname: localStorage.getItem('docname'),
docsnumber: Number.parseInt(localStorage.getItem('docsnumber')),
profileid: localStorage.getItem('profileid'),
poswords: localStorage.getItem('poswords'),
negwords: localStorage.getItem('negwords'),
contextprev: Number.parseInt(localStorage.getItem('contextprev')),
contextnext: Number.parseInt(localStorage.getItem('contextnext')),
wordssplitnum: Number.parseInt(localStorage.getItem('wordssplitnum')),
punctuation: Number.parseInt(localStorage.getItem('punctuation')),
stopwords: Number.parseInt(localStorage.getItem('stopwords')),
lettercase: localStorage.getItem('lettercase')
};
}
highlightInElement(element: string, text: string): string {
var elementHtml = element;
var tags = [];
var tagLocations = [];
var htmlTagRegEx = /<{1}\/{0,1}\w+>{1}/;
// Strip the tags from the elementHtml and keep track of them
var htmlTag;
while (htmlTag = elementHtml.match(htmlTagRegEx)) {
tagLocations[tagLocations.length] = elementHtml.search(htmlTagRegEx);
tags[tags.length] = htmlTag;
elementHtml = elementHtml.replace(htmlTag, '');
}
// Search for the text in the stripped html
var textLocation = elementHtml.search(text);
if (textLocation) {
//Add the highlight
var highlightHTMLStart = '<span class="highlight">';
var highlightHTMLEnd = '</span>';
elementHtml = elementHtml.replace(text, highlightHTMLStart + text + highlightHTMLEnd);
// Plug back in the HTML tags
var textEndLocation = textLocation + text.length;
for(let i = tagLocations.length - 1; i >= 0; i--) {
var location = tagLocations[i];
if(location > textEndLocation){
location += highlightHTMLStart.length + highlightHTMLEnd.length;
} else if (location > textLocation) {
location += highlightHTMLStart.length;
}
elementHtml = elementHtml.substring(0, location) + tags[i] + elementHtml.substring(location);
}
}
// Update the innerHTML of the element
element = elementHtml;
return element;
}
runMining(): void {
if (this.documentsLoaded) {
this.configurationService.runMining(JSON.stringify(this.getSettingsFromLocalStorage()))
.subscribe( res => {
console.log(res.matches);
this.resultsArray.length = 0;
Object.entries(res.matches).forEach(
([title, matches]) => {
let resultClass: DocumentResult = new DocumentResult();
resultClass.docTitle = title;
let matchesArray: Array<Match> = [];
resultClass.matches = matchesArray;
for (let values of matches) {
let match: Match = new Match();
match.match = values.match;
match.extraprev = values.extraprev;
match.extranext = values.extranext;
let context = values.prev + ' ' + values.middle + ' ' + values.next;
// hightlight positive words
for (let posword of JSON.parse(localStorage.getItem('poswords'))) {
const search_regexp = new RegExp(posword, 'g');
context = context.replace(search_regexp, '<span class="positive">' + posword + '</span>');
}
// hightlight acknowledgment keywords
for (let ackn of values.acknmatch) {
const search_regexp = new RegExp(ackn, 'g');
context = context.replace(search_regexp, '<span class="positive">' + ackn + '</span>');
}
// hightlight negative words
for (let negword of JSON.parse(localStorage.getItem('negwords'))) {
const search_regexp = new RegExp(negword, 'g');
context = context.replace(search_regexp, '<span class="negative">' + negword + '</span>');
}
context = this.highlightInElement(context, values.match);
match.context = context;
matchesArray.push(match);
}
this.resultsArray.push(resultClass);
});
});
}
}
}

View File

@ -0,0 +1,4 @@
export class Phrase {
phrase: string;
weight: number;
}

View File

@ -0,0 +1,217 @@
<div id="child1-inner" >
<div class="cm-easy-config-section">
<h4>Preconfigured rules <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></h4>
<div class="cm-config-options-container">
<div class="cm-config-options-connect-line"></div>
<div class="uk-child-width-expand@s uk-text-center" uk-grid uk-switcher="animation: uk-animation-fade">
<div>
<a class="cm-config-option cm-config-light" id="1-level" [ngClass]="{'active':precision===1}" (click)="precisionChange(1)">
<div class="cm-outer-circle-button">
<div class="cm-circle-button">
<div class="cm-circle-button-fill"><span uk-icon="icon: check" class="cm-config-option-check"></span></div>
</div>
</div>
<span>Loose</span>
</a>
</div>
<div>
<a class="cm-config-option cm-config-medium" id="2-level" [ngClass]="{'active':precision===2}" (click)="precisionChange(2)">
<div class="cm-outer-circle-button">
<div class="cm-circle-button">
<div class="cm-circle-button-fill"><span uk-icon="icon: check" class="cm-config-option-check"></span></div>
</div>
</div>
<span>Medium</span>
</a>
</div>
<div>
<a class="cm-config-option cm-config-hard" id="3-level" [ngClass]="{'active':precision===3}" (click)="precisionChange(3)">
<div class="cm-outer-circle-button">
<div class="cm-circle-button">
<div class="cm-circle-button-fill"><span uk-icon="icon: check" class="cm-config-option-check"></span></div>
</div>
</div>
<span>Tight</span>
</a>
</div>
<!-- <div>
<a class="cm-config-option cm-config-advance" id="c-level">
<div class="cm-circle-button">
<div class="cm-circle-button-fill"></div>
</div>
<span>Advanced</span>
</a>
</div> -->
</div>
<ul class="uk-switcher uk-margin-small-top uk-text-small">
<li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li>
<li>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</li>
<li>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur, sed do eiusmod.</li>
</ul>
</div>
</div>
<hr>
<div class="cm-advanced-tools-section">
<label class="uk-form-label cm-advaned-tools-label" for="advaned-tools-label">
<input [checked]="precision===4" (click)="advancedCheckboxChange()" id="advaned-tools-label" class="uk-checkbox" type="checkbox"> Customized rules <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span>
</label>
<div *ngIf="precision===4" id="advaned-tools" style="margin-top: 20px;">
<ul uk-accordion="multiple: true">
<li>
<h6 class="uk-accordion-title">Positive phrases</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<div class="cm-phrases-container">
<header>
<form [formGroup]="positivePhraseForm" id="word-form-pos" class="uk-grid-collapse uk-child-width-expand@s uk-text-center" uk-grid (ngSubmit)="phraseSubmit(true)">
<!-- <div class="cm-number-space uk-width-1-5@m">#</div> -->
<input class="uk-width-expand uk-text-left cm-text-input cm-text-input-phrase" type="text" id="text-pos" placeholder="Phrase" formControlName="phrase"/>
<input class="uk-width-1-5@m uk-text-left cm-text-input cm-text-input-weight" type="number" name="weight" min="0" max="100" id="weight-pos" placeholder="Weight" formControlName="weight"/>
<input type="submit" class="btn uk-width-1-4@m cm-main-button cm-phrases-button" value="Add" [disabled]="!positivePhraseForm.valid"/>
</form>
<div class="scroll_holder">
<div class="scroller"></div>
</div>
</header>
<div style="position: relative;"><!--
<div style="position: absolute; left: 0; top: 0; height: 100%; width: 40px; background-color: #fafafa; border-right: 1px solid #e8e8e8;"></div> -->
<ul id="word-pos">
<li class="uk-grid-collapse uk-child-width-expand@s" uk-grid *ngFor="let phrase of positivePhrasesArray; let i = index" [ngClass]="{'editing':i===positiveSelectedRow}">
<div class="uk-width-expand uk-text-left cm-text-input phrase">
<input class="uk-textarea" style="word-break: break-word; width:100%" type="text" [(ngModel)]="phrase.phrase" (change)="phrasesChanged(true)" (focus)="selectPhraseRow(i, true)" (focusout)="unselectPhraseRow(true)">
</div>
<div class="uk-width-1-4@m uk-text-left cm-text-input weight">
<input style="width:100%" type="number" min="0" max="100" [(ngModel)]="phrase.weight" (change)="phrasesChanged(true)" (focus)="selectPhraseRow(i, true)" (focusout)="unselectPhraseRow(true)">
</div>
<div class="uk-width-1-4@m uk-text-center erase"><a class="uk-icon-link" uk-icon="icon: trash" contenteditable="false" (click)="deletePhrase(i,true)"></a></div>
</li>
</ul>
</div>
<footer class="positive">
<div class="uk-grid-collapse uk-child-width-expand@s" uk-grid>
<div>
<span class="count uk-text-middle" id="count-pos">{{positivePhrasesArray.length}}</span>
<span class="uk-text-middle"> positive word{{positivePhrasesArray.length!==1 ? 's' : ''}}</span>
</div>
</div>
</footer>
</div>
</div>
</li>
<li>
<h6 class="uk-accordion-title">Negative phrases</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<div class="word-container">
<div class="cm-phrases-container">
<header>
<form [formGroup]="negativePhraseForm" class="uk-grid-collapse uk-child-width-expand@s uk-text-center" id="word-form-neg" uk-grid (ngSubmit)="phraseSubmit(false)">
<!-- <div class="cm-number-space uk-width-1-5@m">#</div> -->
<input class="uk-width-expand uk-text-left cm-text-input cm-text-input-phrase" type="text" id="text-neg" placeholder="Phrase" formControlName="phrase"/>
<input class="uk-width-1-5@m uk-text-left cm-text-input cm-text-input-weight" type="number" name="weight" min="0" max="100" id="weight-neg" placeholder="Weight" formControlName="weight"/>
<input type="submit" class="btn uk-width-1-4@m cm-main-button cm-phrases-button" value="Add" [disabled]="!negativePhraseForm.valid"/>
</form>
<div class="scroll_holder">
<div class="scroller"></div>
</div>
</header>
<div style="position: relative;">
<!-- <div style="position: absolute; left: 0; top: 0; height: 100%; width: 40px; background-color: #fafafa; border-right: 1px solid #e8e8e8;"></div> -->
<ul id="word-neg">
<li class="uk-grid-collapse uk-child-width-expand@s" uk-grid *ngFor="let phrase of negativePhrasesArray; let i = index" [ngClass]="{'editing':i===negativeSelectedRow}">
<div class="uk-width-expand uk-text-left cm-text-input phrase">
<input class="uk-textarea" style="word-break: break-word; width:100%" type="text" [(ngModel)]="phrase.phrase" (change)="phrasesChanged(false)" (focus)="selectPhraseRow(i, false)" (focusout)="unselectPhraseRow(false)">
</div>
<div class="uk-width-1-4@m uk-text-left cm-text-input weight">
<input style="width:100%" type="number" min="0" max="100" [(ngModel)]="phrase.weight" (change)="phrasesChanged(false)" (focus)="selectPhraseRow(i, false)" (focusout)="unselectPhraseRow(false)">
</div>
<div class="uk-width-1-4@m uk-text-center erase"><a class="uk-icon-link" uk-icon="icon: trash" contenteditable="false" (click)="deletePhrase(i,false)"></a></div>
</li>
</ul>
</div>
<footer class="negative">
<div class="uk-grid-collapse uk-child-width-expand@s" uk-grid>
<div>
<span class="count uk-text-middle" id="count-neg">{{negativePhrasesArray.length}}</span>
<span class="uk-text-middle"> negative word{{negativePhrasesArray.length!==1 ? 's' : ''}}</span>
</div>
<div>
<button class="cm-white-button cm-phrases-button uk-float-right uk-button uk-button-default" disabled id="clear-all-neg">Delete All</button>
</div>
</div>
</footer>
</div>
</div>
</div>
</li>
<li>
<h6 class="uk-accordion-title">Acknowledgement statement proccess</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<form class="uk-form-horizontal">
<div>
<label class="uk-form-label" for="word-split">Length of N-grams <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></label>
<div class="uk-form-controls">
<input class="uk-input" type="number" name="word-split" min="0" max="10" id="word-split" placeholder="Word pairs" value="2" [value]="settings.wordssplitnum" (change)="wordssplitnumChange($event.target.value)"/>
</div>
</div>
</form>
</div>
</li>
<li>
<h6 class="uk-accordion-title">Matching area size</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<form class="uk-form-horizontal">
<div class="cm-match-area left">
<label class="uk-form-label" for="context-prev-words">Words left of the match <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></label>
<div class="uk-form-controls">
<input class="uk-input" type="number" name="context-prev-words" min="0" max="20" id="context-prev-words" placeholder="Prev words number" value="10" [value]="settings.contextprev" (change)="contextprevChange($event.target.value)"/>
</div>
</div>
<div class="cm-match-area right">
<label class="uk-form-label" for="context-next-words">Words right of the match <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></label>
<div class="uk-form-controls">
<input class="uk-input" type="number" name="context-next-words" min="0" max="20" id="context-next-words" placeholder="Next words number" value="5" [value]="settings.contextnext" (change)="contextnextChange($event.target.value)"/>
</div>
</div>
</form>
</div>
</li>
<li>
<h6 class="uk-accordion-title">Text proccess</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<form class="uk-form-stacked">
<div class="uk-margin">
<label class="uk-form-label" for="stop-words-filter"><input id="stop-words-filter" class="uk-checkbox" type="checkbox" [checked]="settings.stopwords===1" (change)="stopwordsCheckBoxChange($event.target.checked)"> Remove stop words <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></label>
</div>
<div class="uk-margin">
<label class="uk-form-label" for="punctuation-filter"><input id="punctuation-filter" class="uk-checkbox" type="checkbox" [checked]="settings.punctuation===1" (change)="punctuationCheckBoxChange($event.target.checked)"> Remove punctuation <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></label>
</div>
</form>
</div>
</li>
<li>
<h6 class="uk-accordion-title">Letter case</h6>
<div class="uk-accordion-content">
<p class="uk-text-small">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<div class="uk-form-controls" id="letter-case-radio">
<div *ngFor="let case of lettercases">
<label>
<input class="uk-radio none" type="radio" name="letter-case" [checked]="case.value === settings.lettercase" [value]="case.value" (change)="letterCaseChange(case.value)">
{{case.display}}
</label>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
<hr>
<div class="uk-flex uk-flex-center@m uk-flex-right@l uk-margin-top uk-margin-right cm-save-profile-step">
<span class="uk-text-primary uk-text-middle uk-text-middle">Satisfied with the results?</span>
<button id="next-button" class="uk-button uk-button-primary uk-margin-left" (click)="saveProfile()">Save your profile</button>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SettingsComponent } from './settings.component';
describe('SettingsComponent', () => {
let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SettingsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,241 @@
import { Component, OnInit } from '@angular/core';
import {Settings} from './settings';
import {Phrase} from './phrase';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {ConfigurationService} from '../configuration.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.css']
})
export class SettingsComponent implements OnInit {
private oldPrecision = 1;
public precision = 1;
public positivePhrasesArray: Array<Phrase> = [];
public negativePhrasesArray: Array<Phrase> = [];
public positiveSelectedRow = -1;
public negativeSelectedRow = -1;
positivePhraseForm: FormGroup;
negativePhraseForm: FormGroup;
public settings: Settings;
public lettercases = [
{ value: 'none', display: ' As it is' },
{ value: 'uppercase', display: ' UPPERCASE' },
{ value: 'lowercase', display: ' lowercase' }
];
constructor(private formBuilder: FormBuilder, private router: Router, private configurationService: ConfigurationService) { }
ngOnInit() {
this.positivePhraseForm = this.formBuilder.group({
phrase: [null, Validators.required],
weight: [null, [Validators.required, Validators.min(0), Validators.max(100)]],
});
this.negativePhraseForm = this.formBuilder.group({
phrase: [null, Validators.required],
weight: [null, [Validators.required, Validators.min(0), Validators.max(100)]],
});
this.precision = Number.parseInt(localStorage.getItem('precision'));
this.settings = {
docname: localStorage.getItem('docname'),
docsnumber: Number.parseInt(localStorage.getItem('docsnumber')),
profileid: localStorage.getItem('profileid'),
precision: Number.parseInt(localStorage.getItem('precision')),
poswords: localStorage.getItem('poswords'),
negwords: localStorage.getItem('negwords'),
contextprev: Number.parseInt(localStorage.getItem('contextprev')),
contextnext: Number.parseInt(localStorage.getItem('contextnext')),
wordssplitnum: Number.parseInt(localStorage.getItem('wordssplitnum')),
punctuation: Number.parseInt(localStorage.getItem('punctuation')),
stopwords: Number.parseInt(localStorage.getItem('stopwords')),
lettercase: localStorage.getItem('lettercase')
};
// show positive phrases
this.positivePhrasesArray.length = 0;
Object.entries(JSON.parse(localStorage.getItem('poswords'))).forEach(
([key, value]) => {
const content = new Phrase();
content.phrase = key;
content.weight = value;
this.positivePhrasesArray.push(content);
}
);
// show negative phrases
this.negativePhrasesArray.length = 0;
Object.entries(JSON.parse(localStorage.getItem('negwords'))).forEach(
([key, value]) => {
const content = new Phrase();
content.phrase = key;
content.weight = value;
this.negativePhrasesArray.push(content);
}
);
}
getSettingsFromLocalStorage(): Settings {
return this.settings = {
docname: localStorage.getItem('docname'),
docsnumber: Number.parseInt(localStorage.getItem('docsnumber')),
profileid: localStorage.getItem('profileid'),
precision: Number.parseInt(localStorage.getItem('precision')),
poswords: localStorage.getItem('poswords'),
negwords: localStorage.getItem('negwords'),
contextprev: Number.parseInt(localStorage.getItem('contextprev')),
contextnext: Number.parseInt(localStorage.getItem('contextnext')),
wordssplitnum: Number.parseInt(localStorage.getItem('wordssplitnum')),
punctuation: Number.parseInt(localStorage.getItem('punctuation')),
stopwords: Number.parseInt(localStorage.getItem('stopwords')),
lettercase: localStorage.getItem('lettercase')
};
}
phraseSubmit(positive: boolean): void {
const phrase = new Phrase();
if (positive) {
phrase.phrase = this.positivePhraseForm.get('phrase').value;
phrase.weight = this.positivePhraseForm.get('weight').value;
this.positivePhrasesArray.push(phrase);
this.positivePhraseForm.reset();
} else {
phrase.phrase = this.negativePhraseForm.get('phrase').value;
phrase.weight = this.negativePhraseForm.get('weight').value;
this.negativePhrasesArray.push(phrase);
this.negativePhraseForm.reset();
}
this.phrasesChanged(positive);
}
bulkPutPrhases(phrases: string, positive: boolean): void {
if (positive) {
localStorage.setItem('poswords', phrases);
this.positivePhrasesArray.length = 0;
Object.entries(JSON.parse(localStorage.getItem('poswords'))).forEach(
([key, value]) => {
const content = new Phrase();
content.phrase = key;
content.weight = value;
this.positivePhrasesArray.push(content);
}
);
} else {
localStorage.setItem('negwords', phrases);
this.negativePhrasesArray.length = 0;
Object.entries(JSON.parse(localStorage.getItem('negwords'))).forEach(
([key, value]) => {
const content = new Phrase();
content.phrase = key;
content.weight = value;
this.negativePhrasesArray.push(content);
}
);
}
}
deletePhrase(index, positive: boolean): void {
if (positive) {
this.positivePhrasesArray.splice(index, 1);
} else {
this.negativePhrasesArray.splice(index, 1);
}
this.phrasesChanged(positive);
}
selectPhraseRow(row: number, positive: boolean) {
if (positive) {
this.positiveSelectedRow = row;
} else {
this.negativeSelectedRow = row;
}
}
unselectPhraseRow(positive: boolean) {
if (positive) {
this.positiveSelectedRow = -1;
} else {
this.negativeSelectedRow = -1;
}
}
phrasesChanged(positive: boolean): void {
const hashmap = {};
if (positive) {
this.positivePhrasesArray.forEach(function(element) {
hashmap[element.phrase] = element.weight;
});
localStorage.setItem('poswords', JSON.stringify(hashmap));
} else {
this.negativePhrasesArray.forEach(function(element) {
hashmap[element.phrase] = element.weight;
});
localStorage.setItem('negwords', JSON.stringify(hashmap));
}
}
precisionChange(precision: number) {
this.precision = precision;
localStorage.setItem('precision', this.precision.toString());
this.oldPrecision = precision;
if (this.precision === 1) {
this.bulkPutPrhases('{"European Grid Initiative":"1","European Grid Infrastructure":"1","EGI":"1"}', true);
} else if (this.precision === 2) {
this.bulkPutPrhases('{}', true);
} else if (this.precision === 3) {
this.bulkPutPrhases('{}', true);
}
}
advancedCheckboxChange(): void {
if (this.precision === 4) {
this.precision = this.oldPrecision;
} else {
this.precision = 4;
}
localStorage.setItem('precision', this.precision.toString());
}
contextprevChange(value): void {
if (value < 0 || value > 20) {
return;
}
localStorage.setItem('contextprev', value);
}
contextnextChange(value): void {
if (value < 0 || value > 20) {
return;
}
localStorage.setItem('contextnext', value);
}
wordssplitnumChange(value): void {
if (value < 0 || value > 10) {
return;
}
localStorage.setItem('wordssplitnum', value);
}
stopwordsCheckBoxChange(value: boolean): void {
localStorage.setItem('stopwords', value ? '1' : '0');
}
punctuationCheckBoxChange(value: boolean): void {
localStorage.setItem('punctuation', value ? '1' : '0');
}
letterCaseChange(lettercase): void {
localStorage.setItem('lettercase', lettercase);
}
saveProfile(): void {
this.configurationService.saveProfileParameters(this.getSettingsFromLocalStorage())
.subscribe(() => this.router.navigate(['/save-profile']));
}
}

View File

@ -0,0 +1,14 @@
export interface Settings {
docname: string;
docsnumber: number;
profileid: string;
precision: number;
poswords: string;
negwords: string;
contextprev: number;
contextnext: number;
wordssplitnum: number;
punctuation: number;
stopwords: number;
lettercase: string;
}

View File

@ -0,0 +1,4 @@
export class Content {
keyword: string;
context: string;
}

View File

@ -0,0 +1,7 @@
<div class="uk-section uk-section-default uk-margin-medium-top uk-padding-remove-top">
<div class="uk-container uk-container-small">
<h4>Content to match</h4>
<p class="uk-text-small">Fill the table below, with your content you want to match!</p>
<app-contentstable></app-contentstable>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentComponent } from './contents.component';
describe('ContentComponent', () => {
let component: ContentComponent;
let fixture: ComponentFixture<ContentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContentComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-contents',
templateUrl: './contents.component.html',
styleUrls: ['./contents.component.css']
})
export class ContentComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1,28 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ContentstableComponent } from './contentstable/contentstable.component';
import { ContentComponent } from './contents.component';
import {ContentsService} from './contents.service';
import { TextareaAutosizeModule } from 'ngx-textarea-autosize';
import {FileUploadDirective} from '../file-upload.directive';
@NgModule({
exports: [
ContentComponent
],
providers: [
ContentsService
],
imports: [
CommonModule,
FormsModule,
TextareaAutosizeModule
],
declarations: [
ContentstableComponent,
ContentComponent,
FileUploadDirective
]
})
export class ContentModule { }

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { ContentsService } from './contents.service';
describe('ContentsService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ContentsService]
});
});
it('should be created', inject([ContentsService], (service: ContentsService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,70 @@
import { Injectable } from '@angular/core';
import { Content } from './content';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import {Observable} from 'rxjs/Observable';
import {Util} from '../util';
import UIkit from 'uikit';
import {ProfileData} from '../manageprofiles/profile-data';
@Injectable()
export class ContentsService {
private util: Util = new Util();
private getContentUrl = 'http://localhost:8080/alreadyconcept';
private uploadContentFileUrl = 'http://localhost:8080/uploadcontentfile';
private updateContentUrl = 'http://localhost:8080/updateconcept';
constructor(private http: HttpClient) { }
getContent(): Observable<Content[]> {
return this.http.get(this.getContentUrl, { withCredentials: true })
.map((data) => this.contentsJsonToArray(data['data']))
.catch(this.util.handleError);
}
contentsJsonToArray(json): Content[] {
const contentArray: Array<Content> = [];
Object.entries(json).forEach(
([key, value]) => {
const content = new Content();
content.keyword = key;
content.context = value;
contentArray.push(content);
}
);
return contentArray;
}
uploadFile(file: File): Observable<Content[]> {
const formData: FormData = new FormData();
formData.append('upload', file, file.name);
const params = new HttpParams();
const options = {
headers: new HttpHeaders().set('Accept', 'application/json').delete('Content-Type'),
params: params,
reportProgress: true,
withCredentials: true,
};
return this.http.post(this.uploadContentFileUrl, formData, options)
.map((data) => this.contentsJsonToArray(data['data']))
.catch(this.util.handleError);
}
updateContent(content: Array<Content>): Observable<any> {
// transform data to json string
var hashmap = {};
content.forEach(function(element) {
hashmap[element.keyword] = element.context;
});
console.log(JSON.stringify(hashmap));
return this.http.post(this.updateContentUrl, {
concepts: JSON.stringify(hashmap)
}, { withCredentials: true })
.catch(this.util.handleError);
}
}

View File

@ -0,0 +1,60 @@
<table id="data-table" class="uk-table uk-table-hover cm-table">
<thead>
<tr>
<!-- <th class="uk-table-shrink cm-table-number">#</th> -->
<th class="uk-width-small">Keyword</th>
<th class="uk-table-expand">Context</th>
<th class="uk-table-shrink"></th>
</tr>
</thead>
<tfoot>
<tr>
<!-- <td class="cm-table-number"></td> -->
<td colspan="3" class="cm-table-footer" style="padding: 14px;">
<button (click)="addRow()" [disabled]="!isAnyContent()" id="add-row-below" class="uk-button uk-button-small uk-button-default uk-width-1-1 uk-text-center cm-main-button">
<span class="uk-text-middle"><span uk-icon="icon: plus-circle"></span> Create new</span>
</button>
</td>
</tr>
<tr *ngIf="contentArray.length<2 && !isAnyContent()">
<td colspan="3" class="cm-table-footer" style="padding: 70px 80px 50px;">
<div appDropFileUpload (filesChange)="onFilesChange($event)" (filesInvalid)="onFileInvalid($event)" [allowedExtensions]="['tsv', 'txt']" [maxFileSize]="51200" class="uk-placeholder cm-file-drop-area cm-coloured-text">
<div class="uk-flex uk-flex-middle uk-grid-collapse uk-child-width-expand@s" uk-grid>
<div>
<div class="cm-coloured-text">
<span uk-icon="icon: cloud-upload"></span>
<span class="uk-text-middle"> Drop file with content here to fill the table!</span>
</div>
<div>
<span class="cm-label">TSV</span>
<span class="uk-text uk-text-small">file type, maximum 50kB</span>
<span class="cm-tooltip" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom" uk-icon="icon: info"></span>
</div>
</div>
<div uk-form-custom>
<input type="file" name="upload" id="codes-file-input" class="inputfile" (change)="onFilesChange($event.srcElement.files[0])" />
<button class="uk-button uk-button-default cm-main-button" type="button" tabindex="-1">Choose file</button>
</div>
</div>
</div>
<progress id="js-progressbar" class="uk-progress" value="0" max="100" hidden></progress>
</td>
</tr>
</tfoot>
<tbody>
<tr *ngFor="let field of contentArray; let i = index" [ngClass]="{'editing':i===selectedRow}">
<td class="keyword" [ngClass]="{'editing':i===selectedRow && 0===selectedCollumn}">
<input #focusOnNew [(ngModel)]="field.keyword" class="form-control" type="text" style="width:100%" (focus)="selectRowColumn(i, 0)" (focusout)="unselectRow()"/>
</td>
<td class="context" [ngClass]="{'editing':i===selectedRow && 1===selectedCollumn}">
<textarea autosize [(ngModel)]="field.context" class="form-control uk-textarea" data-min-rows='3' type="text" (focus)="selectRowColumn(i, 1)" (focusout)="unselectRow()">
</textarea>
</td>
<td class="delete">
<a class="uk-icon-link uk-icon" uk-icon="icon: trash" contenteditable="false" (click)="deleteFieldValue(i)"></a>
</td>
</tr>
</tbody>
</table>
<button id="next-button" class="uk-button uk-button-primary uk-margin-top uk-float-right" [disabled]="!isAnyContent()" (click)="saveAndContinue()">Next</button>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentstableComponent } from './contentstable.component';
describe('ContentstableComponent', () => {
let component: ContentstableComponent;
let fixture: ComponentFixture<ContentstableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContentstableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContentstableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,100 @@
import {Component, OnInit, ViewChildren} from '@angular/core';
import { Content } from '../content';
import {ContentsService} from '../contents.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-contentstable',
templateUrl: './contentstable.component.html',
styleUrls: ['./contentstable.component.css']
})
export class ContentstableComponent implements OnInit {
public contentArray: Array<Content> = [];
public selectedRow = -1;
public selectedCollumn = 0;
results = '';
@ViewChildren('focusOnNew') focusOnNewInputs;
constructor(private contentsService: ContentsService, private router: Router) { }
ngOnInit() {
this.getContent();
}
getContent(): void {
this.contentsService.getContent()
.subscribe(contents => {
this.contentArray = contents;
if (!this.contentArray.length) {
this.addRow();
}
});
}
selectRowColumn(row, column) {
this.selectedRow = row;
this.selectedCollumn = column;
}
unselectRow() {
this.selectedRow = -1;
}
addRow(): void {
const content = new Content();
content.keyword = '';
content.context = '';
this.contentArray.push(content);
setTimeout( () => {
this.focusOnNewInputs.toArray()[this.contentArray.length - 1].nativeElement.focus();
}, 100);
}
isAnyContent(): boolean {
let checked = false;
this.contentArray.forEach(function(element) {
if (element.keyword !== '') {
checked = true;
return;
}
});
return checked;
}
deleteFieldValue(index) {
this.contentArray.splice(index, 1);
if (!this.contentArray.length) {
this.addRow();
}
}
onFilesChange(file: File) {
if (file !== null && file !== undefined) {
console.log(file);
let ext = file.name.split('.')[file.name.split('.').length - 1];
let allowedExtensions = ['tsv', 'txt'];
if (allowedExtensions.lastIndexOf(ext) !== -1 && file.size <= 51200) {
this.contentsService.uploadFile(file)
.subscribe(contents => {
if (contents.length !== 0) {
this.contentArray = contents;
}
});
} else {
this.onFileInvalid(file);
}
}
}
onFileInvalid(file: File) {
if (file !== null && file !== undefined) {
console.log('ERROR', file);
}
}
saveAndContinue(): void {
this.contentsService.updateContent(this.contentArray).subscribe(value => this.router.navigate(['/configure-profile']));
}
}

View File

@ -0,0 +1,3 @@
export interface GetContentsResponse {
data: string;
}

View File

@ -0,0 +1,8 @@
import { FileUploadDirective } from './file-upload.directive';
describe('FileUploadDirective', () => {
it('should create an instance', () => {
const directive = new FileUploadDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,48 @@
import {Directive, EventEmitter, HostBinding, HostListener, Input, Output} from '@angular/core';
@Directive({
selector: '[appDropFileUpload]'
})
export class FileUploadDirective {
@Input() private allowedExtensions: Array<string> = [];
@Input() private maxFileSize = 104857600;
@Output() private filesChange: EventEmitter<File> = new EventEmitter();
@Output() private filesInvalid: EventEmitter<File> = new EventEmitter();
@HostBinding('class') private background = 'uk-placeholder cm-file-drop-area cm-coloured-text';
constructor() { }
@HostListener('dragover', ['$event']) public onDragOver(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = 'uk-placeholder cm-file-drop-area cm-coloured-text uk-dragover';
}
@HostListener('dragleave', ['$event']) public onDragLeave(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = 'uk-placeholder cm-file-drop-area cm-coloured-text';
}
@HostListener('drop', ['$event']) public onDrop(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = 'uk-placeholder cm-file-drop-area cm-coloured-text';
let files: Array<File> = evt.dataTransfer.files;
let valid_file: File = null;
let invalid_file: File = null;
if (files.length === 1) {
let file = files[0];
let ext = file.name.split('.')[file.name.split('.').length - 1];
if (this.allowedExtensions.lastIndexOf(ext) !== -1 && file.size <= this.maxFileSize) {
valid_file = file;
} else {
invalid_file = file;
}
this.filesChange.emit(valid_file);
this.filesInvalid.emit(invalid_file);
}
}
}

View File

@ -0,0 +1,5 @@
export interface ExampleProfilesMetadata {
name: string;
contents: number;
documents: number;
}

View File

@ -0,0 +1,112 @@
<div class="uk-section uk-section-default">
<div class="uk-container uk-container-large">
<h4>Your mining profiles <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></h4>
<div uk-grid>
<div class="uk-width-expand@m">
<div class="uk-overflow-auto">
<table class="uk-table uk-table-hover uk-table-middle uk-table-divider">
<thead>
<tr>
<th class="uk-table-shrink"></th>
<th class="uk-table-expand">Name</th>
<th class="uk-table-small">Created</th>
<th class="uk-width-small">Status</th>
<th class="uk-table-shrink uk-text-nowrap">Matches found</th>
<th></th>
</tr>
</thead>
<tfoot>
</tfoot>
<tbody>
<tr *ngIf="!userSavedProfiles.length">
<!-- <td class="cm-table-number"></td> -->
<td colspan="5">
<div class="uk-text-center uk-padding uk-padding-remove-bottom">
<h3>Not created your profile yet?</h3>
<p>
Try to play with a ready example profile below!
</p>
</div>
</td>
</tr>
<tr *ngFor="let profile of userSavedProfiles | paginate: config; let i = index">
<td class="download">
<a class="uk-icon-link uk-icon" uk-icon="icon: download" contenteditable="false" (click)="downloadProfile(profile.id, profile.name)"></a>
</td>
<td class="uk-table-link">
<a class="uk-link-reset" (click)="loadSavedProfile(profile.id, profile.name)">{{profile.name}}</a>
</td>
<td class="uk-text-muted">{{profile.datecreated}}</td>
<td class="uk-text-nowrap uk-text-warning">{{profile.status}}</td>
<td class="uk-text-nowrap">{{profile.matches}}</td>
<td class="delete">
<a class="uk-icon-link uk-icon" uk-icon="icon: trash" contenteditable="false" (click)="deleteProfilePrompt(i)"></a>
</td>
</tr>
</tbody>
</table>
<pagination-template #p="paginationApi"
[id]="config.id"
(pageChange)="config.currentPage = $event">
<ul class="uk-pagination uk-flex-center" uk-margin>
<li [class.uk-disabled]="p.isFirstPage()"><a (click)="p.previous()"><span uk-pagination-previous></span></a></li>
<li *ngFor="let page of p.pages" [class.uk-active]="p.getCurrent() === page.value">
<a (click)="p.setCurrent(page.value)" *ngIf="p.getCurrent() !== page.value">
<span>{{ page.label }}</span>
</a>
<span *ngIf="p.getCurrent() === page.value">{{ page.label }}</span>
</li>
<li [class.uk-disabled]="p.isLastPage()"><a (click)="p.next()"><span uk-pagination-next></span></a></li>
</ul>
</pagination-template>
</div>
</div>
<div class="uk-width-1-3@m">
<a class="test-upload uk-button uk-button-default uk-width-1-1 uk-text-center uk-margin-small-bottom cm-main-button" (click)="createNewProfile()">
<span class="uk-text-middle">Create a new mining profile</span>
</a>
<div class="test-upload uk-button uk-button-link uk-width-1-1 uk-text-center uk-margin-small-top">
<div uk-form-custom>
<form id="profile-input-form" method="post" enctype="multipart/form-data" accept-charset="UTF-8">
<input type="file" name="upload" id="profile-file-input" class="inputfile" (change)="fileChangeUpload($event)" accept=".oamp">
</form>
<span class="uk-text-middle">UPLOAD an .oamp profile file</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="uk-section uk-section-secondary">
<div class="uk-container uk-container-large">
<h4>Start with a ready example <span class="cm-tooltip" uk-icon="icon: info" title="If you want the tooltip to appear with a little delay, just add the delay option to the uk-tooltip attribute with your value in milliseconds." uk-tooltip="pos: bottom"></span></h4>
<div uk-slider="autoplay: true">
<div class="uk-position-relative">
<div class="uk-slider-container uk-light">
<ul class="uk-slider-items uk-child-width-1-2 uk-child-width-1-5@m uk-grid">
<li *ngFor="let profile of exampleProfiles">
<a (click)="loadExampleProfile(profile.name)">
<div class="uk-card uk-card-default uk-card-hover uk-card-body uk-text-center uk-margin-medium-top uk-margin-medium-bottom">
<h3 class="uk-card-title">{{profile.name | uppercase}}</h3>
<h4 class="uk-card-title uk-margin-remove-bottom">{{profile.contents}}</h4>
<p class="uk-text-meta uk-margin-remove-top">contents</p>
<h4 class="uk-card-title uk-margin-remove-bottom">{{profile.documents}}</h4>
<p class="uk-text-meta uk-margin-remove-top">documents</p>
</div>
</a>
</li>
</ul>
</div>
<div class="uk-hidden@s">
<a class="uk-position-center-left uk-position-small" href="#" uk-slidenav-previous uk-slider-item="previous"></a>
<a class="uk-position-center-right uk-position-small" href="#" uk-slidenav-next uk-slider-item="next"></a>
</div>
<div class="uk-visible@s">
<a class="uk-position-center-left-out uk-position-small" href="#" uk-slidenav-previous uk-slider-item="previous"></a>
<a class="uk-position-center-right-out uk-position-small" href="#" uk-slidenav-next uk-slider-item="next"></a>
</div>
</div>
<ul class="uk-slider-nav uk-dotnav uk-flex-center uk-margin"></ul>
</div>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ManageprofilesComponent } from './manageprofiles.component';
describe('ManageprofilesComponent', () => {
let component: ManageprofilesComponent;
let fixture: ComponentFixture<ManageprofilesComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ManageprofilesComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ManageprofilesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,158 @@
import { Component, OnInit } from '@angular/core';
import {ManageprofilesService} from './manageprofiles.service';
import {Router} from '@angular/router';
import UIkit from 'uikit';
import {CookieService} from 'ngx-cookie-service';
import {PaginationInstance} from 'ngx-pagination';
import {ProfileMetadata} from './profile-metadata';
import {ExampleProfilesMetadata} from './example-profiles-metadata';
import {getFileNameFromResponseContentDisposition, saveFile} from '../util';
@Component({
selector: 'app-manageprofiles',
templateUrl: './manageprofiles.component.html',
styleUrls: ['./manageprofiles.component.css']
})
export class ManageprofilesComponent implements OnInit {
// TODO profile table sorting: https://ciphertrick.com/2017/08/01/search-sort-pagination-in-angular/
public userSavedProfiles: Array<ProfileMetadata> = [];
public exampleProfiles: Array<ExampleProfilesMetadata> = [];
public config: PaginationInstance = {
id: 'custom',
itemsPerPage: 5,
currentPage: 1
};
constructor(private manageProfilesService: ManageprofilesService, private router: Router, private cookieService: CookieService) { }
ngOnInit() {
this.getUserId();
}
getUserId(): void {
this.manageProfilesService.getUserIdToLocalStorage()
.subscribe(() => {
localStorage.setItem('user_id', this.cookieService.get('madgikmining'));
this.getSavedProfiles();
this.getExampleProfiles();
});
}
getSavedProfiles(): void {
this.manageProfilesService.getSavedProfiles()
.subscribe(res => this.userSavedProfiles = res);
}
loadSavedProfile(id: string, name: string): void {
this.manageProfilesService.loadSavedProfile(id)
.subscribe(res => {
console.log(res);
// backup user_id from localstorage and clear all storage data
const userId: string = localStorage.getItem('user_id');
localStorage.clear();
localStorage.setItem('user_id', userId);
// store to client all profile data
localStorage.setItem('profilename', name);
localStorage.setItem('profileid', id);
localStorage.setItem('docname', res.docname);
localStorage.setItem('docsnumber', res.docsnumber);
localStorage.setItem('precision', res.precision);
localStorage.setItem('concepts', res.concepts);
localStorage.setItem('poswords', JSON.stringify(res.poswords));
localStorage.setItem('negwords', JSON.stringify(res.negwords));
localStorage.setItem('contextprev', res.contextprev);
localStorage.setItem('contextmiddle', res.contextmiddle);
localStorage.setItem('contextnext', res.contextnext);
localStorage.setItem('wordssplitnum', res.wordssplitnum);
localStorage.setItem('punctuation', res.punctuation);
localStorage.setItem('stopwords', res.stopwords);
localStorage.setItem('lettercase', res.lettercase);
this.router.navigate(['/upload-content']);
});
}
downloadProfile(profileId: string, profileName: string): void {
this.manageProfilesService.downloadProfile(profileId)
.subscribe(res => {
saveFile(res, profileName.replace(/ /g, '_') + '.oamp');
});
}
deleteProfilePrompt(index) {
UIkit.modal.confirm('<span class="uk-text-bold uk-text-danger">' +
'Are you sure you want to delete this profile? This action cannot be undone!</span>', {escClose: true}).then(() => {
this.manageProfilesService.deleteProfile(this.userSavedProfiles[index].id)
.subscribe(() => this.userSavedProfiles.splice(index, 1));
});
}
createNewProfile(): void {
// backup user_id from localstorage and clear all storage data
const userId: string = localStorage.getItem('user_id');
localStorage.clear();
localStorage.setItem('user_id', userId);
this.manageProfilesService.createNewProfile()
.subscribe(() => this.router.navigate(['/upload-content']));
}
fileChangeUpload(event): void {
// backup user_id from localstorage and clear all storage data
const userId: string = localStorage.getItem('user_id');
localStorage.clear();
localStorage.setItem('user_id', userId);
const fileList: FileList = event.target.files;
if (fileList && fileList.length === 1) {
const file: File = fileList[0];
// get new profile data
this.manageProfilesService.uploadFile(file)
.subscribe(res => {
console.log(res);
localStorage.setItem('precision', res.precision);
localStorage.setItem('concepts', res.concepts);
localStorage.setItem('poswords', JSON.stringify(res.poswords));
localStorage.setItem('negwords', JSON.stringify(res.negwords));
localStorage.setItem('contextprev', res.contextprev);
localStorage.setItem('contextmiddle', res.contextmiddle);
localStorage.setItem('contextnext', res.contextnext);
localStorage.setItem('wordssplitnum', res.wordssplitnum);
localStorage.setItem('punctuation', res.punctuation);
localStorage.setItem('stopwords', res.stopwords);
localStorage.setItem('lettercase', res.lettercase);
this.router.navigate(['/upload-content']);
});
}
}
getExampleProfiles(): void {
this.manageProfilesService.getExampleProfiles()
.subscribe(res => this.exampleProfiles = res);
}
loadExampleProfile(name: string): void {
// backup user_id from localstorage and clear all storage data
const userId: string = localStorage.getItem('user_id');
localStorage.clear();
localStorage.setItem('user_id', userId);
// get new profile data
this.manageProfilesService.loadExampleProfile(name)
.subscribe(res => {
console.log(res);
localStorage.setItem('precision', res.precision);
localStorage.setItem('concepts', res.concepts);
localStorage.setItem('poswords', JSON.stringify(res.poswords));
localStorage.setItem('negwords', JSON.stringify(res.negwords));
localStorage.setItem('contextprev', res.contextprev);
localStorage.setItem('contextmiddle', res.contextmiddle);
localStorage.setItem('contextnext', res.contextnext);
localStorage.setItem('wordssplitnum', res.wordssplitnum);
localStorage.setItem('punctuation', res.punctuation);
localStorage.setItem('stopwords', res.stopwords);
localStorage.setItem('lettercase', res.lettercase);
this.router.navigate(['/upload-content']);
});
}
}

View File

@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ManageprofilesComponent } from './manageprofiles.component';
import { NgxPaginationModule } from 'ngx-pagination';
import { ManageprofilesService } from './manageprofiles.service';
@NgModule({
imports: [
CommonModule,
FormsModule,
NgxPaginationModule
],
exports: [
ManageprofilesComponent
],
providers: [
ManageprofilesService
],
declarations: [ManageprofilesComponent]
})
export class ManagprofilesModule { }

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { ManageprofilesService } from './manageprofiles.service';
describe('ManageprofilesService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ManageprofilesService]
});
});
it('should be created', inject([ManageprofilesService], (service: ManageprofilesService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,85 @@
import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import {ProfileData} from './profile-data';
import {Util} from '../util';
import {Observable} from 'rxjs/Observable';
import {ProfileMetadata} from './profile-metadata';
import {ExampleProfilesMetadata} from './example-profiles-metadata';
import {RequestOptions, ResponseContentType} from '@angular/http';
@Injectable()
export class ManageprofilesService {
private util: Util = new Util();
private getUserIdUrl = 'http://localhost:8080/getuserid';
private getSavedProfilesUrl = 'http://localhost:8080/getuserprofiles';
private downloadProfileUrl = 'http://localhost:8080/downloadprofile';
private DeleteuserProfileUrl = 'http://localhost:8080/deleteuserprofile';
private createNewProfileUrl = 'http://localhost:8080/createnewprofile';
private loadSavedProfileUrl = 'http://localhost:8080/loaduserprofile';
private getExampleProfilesUrl = 'http://localhost:8080/getexampleprofiles';
private loadExampleProfileUrl = 'http://localhost:8080/loadexampleprofile';
private uploadProfileUrl = 'http://localhost:8080/uploadprofile';
constructor(private http: HttpClient) { }
getUserIdToLocalStorage(): Observable<any> {
return this.http.get(this.getUserIdUrl, { withCredentials: true })
.catch(this.util.handleError);
}
downloadProfile(profileId: string): Observable<any> {
return this.http.post(this.downloadProfileUrl, {id: profileId}, { responseType: 'blob', withCredentials: true })
.catch(this.util.handleError);
}
deleteProfile(profileId: string): Observable<any> {
return this.http.post(this.DeleteuserProfileUrl, {id: profileId}, { withCredentials: true })
.catch(this.util.handleError);
}
createNewProfile(): Observable<any> {
return this.http.get(this.createNewProfileUrl, { withCredentials: true })
.catch(this.util.handleError);
}
loadSavedProfile(profileId: string): Observable<ProfileData> {
return this.http.post<ProfileData>(this.loadSavedProfileUrl, {
id: profileId
}, { withCredentials: true })
.catch(this.util.handleError);
}
loadExampleProfile(name: string): Observable<ProfileData> {
return this.http.get<ProfileData>(this.loadExampleProfileUrl, { withCredentials: true })
.catch(this.util.handleError);
}
uploadFile(file: File): Observable<ProfileData> {
const formData: FormData = new FormData();
formData.append('upload', file, file.name);
const params = new HttpParams();
const options = {
headers: new HttpHeaders().set('Accept', 'application/json').delete('Content-Type'),
params: params,
reportProgress: true,
withCredentials: true,
};
return this.http.post<ProfileData>(this.uploadProfileUrl, formData, options)
.catch(this.util.handleError);
}
getSavedProfiles(): Observable<ProfileMetadata[]> {
return this.http.get(this.getSavedProfilesUrl, { withCredentials: true })
.map(data => data['profiles'])
.catch(this.util.handleError);
}
getExampleProfiles(): Observable<ExampleProfilesMetadata[]> {
return this.http.get(this.getExampleProfilesUrl, { withCredentials: true })
.map(data => data['profiles'])
.catch(this.util.handleError);
}
}

View File

@ -0,0 +1,15 @@
export interface ProfileData {
docname: string;
docsnumber: string;
precision: string;
concepts: string;
poswords: string;
negwords: string;
contextprev: string;
contextmiddle: string;
contextnext: string;
wordssplitnum: string;
punctuation: string;
stopwords: string;
lettercase: string;
}

View File

@ -0,0 +1,8 @@
export class ProfileMetadata {
name: string;
id: string;
datecreated: string;
status: string;
matches: string;
}

View File

@ -0,0 +1,8 @@
<div class="uk-section uk-section-default uk-margin-medium-top uk-padding-remove-top">
<div class="uk-container uk-container-small">
<label for="profile-name" [ngClass]="{'uk-text-danger':!profileName}">Current name:</label>
<input [(ngModel)]="profileName" class="uk-input" [ngClass]="{'uk-form-danger':!profileName}" id="profile-name" type="text" autofocus="">
<span *ngIf="!profileName" class="uk-text-danger">Profile name cannot be empty!</span>
<button class="uk-button uk-button-default uk-margin-medium-top uk-width-1-1 uk-button-medium uk-text-center cm-main-button" [disabled]="!profileName" (click)="saveProfile()">Save profile to your account</button>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SaveprofileComponent } from './saveprofile.component';
describe('SaveprofileComponent', () => {
let component: SaveprofileComponent;
let fixture: ComponentFixture<SaveprofileComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SaveprofileComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SaveprofileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import UIkit from 'uikit';
import {SaveprofileService} from './saveprofile.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-saveprofile',
templateUrl: './saveprofile.component.html',
styleUrls: ['./saveprofile.component.css']
})
export class SaveprofileComponent implements OnInit {
public profileName = 'New profile name';
public docnName = '';
public docsNumber = 0;
constructor(private saveprofileService: SaveprofileService, private router: Router) { }
ngOnInit() {
if (localStorage.getItem('profilename') && localStorage.getItem('profilename') !== 'undefined') {
this.profileName = localStorage.getItem('profilename');
}
if (localStorage.getItem('docname') && localStorage.getItem('docname') !== 'undefined') {
this.docnName = localStorage.getItem('docname');
}
if (localStorage.getItem('docsnumber') && localStorage.getItem('docsnumber') !== 'undefined') {
this.docsNumber = Number.parseInt(localStorage.getItem('docsnumber'));
}
}
saveProfile(): void {
if (this.profileName === '') {
UIkit.notification({
message: 'You have to provide a name to your new profile',
status: 'danger',
pos: 'top-center',
timeout: 4000
});
return;
} else {
this.saveprofileService.saveProfile(this.profileName, localStorage.getItem('profileid'), this.docnName, this.docsNumber)
.subscribe(() => this.router.navigate(['/manage-profiles']));
}
}
}

View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { SaveprofileComponent } from './saveprofile.component';
import {SaveprofileService} from './saveprofile.service';
@NgModule({
imports: [
CommonModule,
FormsModule
],
exports: [
SaveprofileComponent
],
providers: [
SaveprofileService
],
declarations: [SaveprofileComponent]
})
export class SaveprofileModule { }

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { SaveprofileService } from './saveprofile.service';
describe('SaveprofileService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [SaveprofileService]
});
});
it('should be created', inject([SaveprofileService], (service: SaveprofileService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {HttpClient} from '@angular/common/http';
import {Util} from '../util';
@Injectable()
export class SaveprofileService {
private util: Util = new Util();
private saveProfileUrl = 'http://localhost:8080/saveprofile';
constructor(private http: HttpClient) { }
saveProfile(name: string, id: string, docName: string, dosNumber: number): Observable<any> {
return this.http.post(this.saveProfileUrl, {name: name, id: id, docname: docName, docsnumber: dosNumber }, { withCredentials: true })
.catch(this.util.handleError);
}
}

View File

@ -0,0 +1,25 @@
<div *ngIf="proccessStep>0" class="uk-flex-inline cm-nav-container">
<div class="cm-left-box"><a href="/manage-profiles"><button id="cancel-main-btn" class="uk-close-large cm-close-btn" type="button" uk-close></button></a></div>
<div class="cm-navigation cm-nav-toolbar">
<ul class="uk-subnav uk-subnav-line">
<li class="cm-nav-li" [ngClass]="{'cm-nav-active':proccessStep===1, 'cm-nav-disabled':proccessStep<1}">
<a class="cm-nav-a" [routerLink]="proccessStep>1 ? ['/upload-content'] : []">
<div class="cm-nav-number-container"><span class="cm-nav-number uk-text-middle">1</span></div>
<span class="cm-nav-title uk-text-middle">Matching context<br>definition</span>
</a>
</li>
<li class="cm-nav-li" [ngClass]="{'cm-nav-active':proccessStep===2, 'cm-nav-disabled':proccessStep<2}">
<a class="cm-nav-a" [routerLink]="proccessStep>2 ? ['/configure-profile'] : []">
<div class="cm-nav-number-container"><span class="cm-nav-number uk-text-middle">2</span></div>
<span class="cm-nav-title uk-text-middle">Matching proccess<br>configuration</span>
</a>
</li>
<li class="cm-nav-li" [ngClass]="{'cm-nav-active':proccessStep===3, 'cm-nav-disabled':proccessStep<3}">
<a class="cm-nav-a" [routerLink]="proccessStep>3 ? ['/save-profile'] : []">
<div class="cm-nav-number-container"><span class="cm-nav-number uk-text-middle">3</span></div>
<span class="cm-nav-title uk-text-middle">Save your<br>matching profile</span>
</a>
</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StepsnvabarComponent } from './stepsnvabar.component';
describe('StepsnvabarComponent', () => {
let component: StepsnvabarComponent;
let fixture: ComponentFixture<StepsnvabarComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ StepsnvabarComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StepsnvabarComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,36 @@
import { Component, OnInit } from '@angular/core';
import {NavigationEnd, Router} from '@angular/router';
@Component({
selector: 'app-stepsnvabar',
templateUrl: './stepsnvabar.component.html',
styleUrls: ['./stepsnvabar.component.css']
})
export class StepsnvabarComponent implements OnInit {
private proccessStep = 0;
constructor(private router: Router) {
router.events.subscribe((val) => {
// see also
if (val instanceof NavigationEnd) {
this.changeStep(val.urlAfterRedirects);
}
});
}
ngOnInit() {}
changeStep(url: string): void {
if (url === '/upload-content') {
this.proccessStep = 1;
} else if (url === '/configure-profile') {
this.proccessStep = 2;
} else if (url === '/save-profile') {
this.proccessStep = 3;
} else {
this.proccessStep = 0;
}
}
}

View File

@ -0,0 +1,46 @@
import {Observable} from 'rxjs/Observable';
import UIkit from 'uikit';
import {HttpErrorResponse} from '@angular/common/http';
import { saveAs } from 'file-saver/FileSaver';
import { Response } from '@angular/http';
export class Util {
public handleError (err: HttpErrorResponse) {
if (err.error instanceof Error) {
console.error('Client-side error occured.');
} else {
console.error('Server-side error occured.');
}
UIkit.notification({
message: err.message,
status: 'danger',
pos: 'top-center',
timeout: 0
});
return Observable.throw(err || 'Server error');
}
}
/**
* Saves a file by opening file-save-as dialog in the browser
* using file-save library.
* @param blobContent file content as a Blob
* @param fileName name file should be saved as
*/
export const saveFile = (blobContent: Blob, fileName: string) => {
const blob = new Blob([blobContent], { type: 'application/octet-stream' });
saveAs(blob, fileName);
};
/**
* Derives file name from the http response
* by looking inside content-disposition
* @param res http Response
*/
export const getFileNameFromResponseContentDisposition = (res: Response) => {
const contentDisposition = res.headers.get('content-disposition') || '';
const matches = /filename=([^;]+)/ig.exec(contentDisposition);
const fileName = (matches[1] || 'untitled').trim();
return fileName;
};

View File

@ -0,0 +1,102 @@
/*ANIMATIONS*/
tr.new-item, li.new-item {
opacity:0;
-webkit-animation:fadeIn .1s linear forwards;
-o-animation:fadeIn .1s linear forwards;
animation:fadeIn .1s linear forwards
}
@keyframes fadeIn {
to {
opacity:1
}
}
@keyframes openspace {
to {
height: auto
}
}
tr.removed-item, li.removed-item {
-webkit-animation: removed-item-animation .3s cubic-bezier(.55,-0.04,.91,.94) forwards;
-o-animation: removed-item-animation .3s cubic-bezier(.55,-0.04,.91,.94) forwards;
animation: removed-item-animation .3s cubic-bezier(.55,-0.04,.91,.94) forwards
}
@keyframes removed-item-animation {
from {
opacity: 1;
}
to {
opacity: 0
}
}
@-webkit-keyframes new-item-animation {
from {
opacity: 0;
-webkit-transform: scale(0);
transform: scale(0)
}
to {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1)
}
}
@-o-keyframes new-item-animation {
from {
opacity: 0;
-o-transform: scale(0);
transform: scale(0)
}
to {
opacity: 1;
-o-transform: scale(1);
transform: scale(1)
}
}
@-webkit-keyframes openspace {
to {
height: auto
}
}
@-o-keyframes openspace {
to {
height: auto
}
}
@-webkit-keyframes removed-item-animation {
from {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1)
}
to {
-webkit-transform: scale(0);
transform: scale(0);
opacity: 0
}
}
@-o-keyframes removed-item-animation {
from {
opacity: 1;
-o-transform: scale(1);
transform: scale(1)
}
to {
-o-transform: scale(0);
transform: scale(0);
opacity: 0
}
}

View File

@ -0,0 +1,163 @@
.tm-toolbar .uk-subnav-line .custom-discover-li {
color:#05007A !important;
background:#fff;
display: block;
}
.tm-toolbar .uk-subnav-line .custom-discover-li a{
color:#05007A !important;
}
.tm-toolbar .uk-subnav-line .custom-connect-li {
color:#05007A !important;
background:#fff;
display: block;
}
.tm-toolbar .uk-subnav-line .custom-connect-li a{
color:#05007A !important;
}
.custom-discover-toolbar ul.uk-subnav.uk-subnav-line{
background-color: #f25f30 !important;
}
.custom-discover-toolbar .inner {
background-color: #f25f30 !important;
}
.custom-discover-toolbar{
border-top-color:#f25f30 !important;
}
.custom-connect-toolbar ul.uk-subnav.uk-subnav-line{
background-color: #ffc800 !important;
}
.custom-connect-toolbar .inner {
background-color: #ffc800 !important;
}
.custom-connect-toolbar{
border-top-color:#ffc800 !important;
}
.custom-footer{
position:relative;
bottom:0;
left:0;
}
.custom-external {
background: rgba(0, 0, 0, 0) url("/assets/icon_external.png") no-repeat scroll left center;
padding: 0 0 0 16px;
}
.custom-navbar-toggle-icon, .custom-user-mini-panel{
color:#444 !important
}
.custom-user-mini-panel a{
color:rgb(36, 91, 204);
}
.custom-main-content{
min-height: 550px;
}
.custom-autocomplete .uk-nav-autocomplete > li > a:hover {
background: #00a8e6 none repeat scroll 0 0;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.05) inset;
color: #FFF;
outline: medium none;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.1);
}
.custom-autocomplete .uk-nav-navbar > li > a {
color: #444;
}
.custom-description-list-horizontal{ line-height:200%}
.uk-alert-default {
background: #fff none repeat scroll 0 0;
border: 1px solid #ddd;
border-radius: 4px;
color: #444;
height: 30px;
max-width: 100%;
padding: 4px 6px;
}
.custom-hidden-dropdown-menu {position:static !important;}
.searchFilterBoxValues {overflow:auto; max-height:200px; }
.selected-filters-box {margin:5px; background-color:#F8F8F8; }
.search-form {margin:5px; }
.clickable { cursor:pointer; }
.search-filters .uk-accordion-title{
font-size: 14px;
line-height: 18px;
}
.OPEN {
background: rgba(0, 0, 0, 0) url("/static/openAccess.png") no-repeat scroll right center;
padding-right: 18px;
min-height: 18px;
}
.EMBARGO, .CLOSED, .RESTRICTED {
background: rgba(0, 0, 0, 0) url("/static/closedAccess.png") no-repeat scroll right center;
padding-right: 18px;
}
.sc39 {
background: rgba(0, 0, 0, 0) url("/static/sc39.png") no-repeat scroll right center;
padding-right: 24px;
}
.projectIcon {
display: inline-table;
}
.dateFilter .mydp{
margin-top:5px;
}
.tooltip {
max-width: none;
background: rgba(100, 100, 100, 1);
}
.custom-select-mini{
max-width:170px !important;
}
.custom-icon {
line-height: unset;
}
/*.custom-tab-content-large{
min-height: 800px;
}
*/
.custom-tab-content {
min-height: 250px;
}
.custom-dataTable-content {
min-height: 600px;
}
.filterItem span {
display: inline-flex;
}
.filterItem .filterName {
max-width: 71%;
}
.browseFilters .filterItem .filterName {
max-width: 68%;
}
.filterItem .filterNumber {
width: 20%;
}
.filterItem span {
white-space: nowrap;
}
.filterItem span div {
overflow: hidden;
text-overflow: ellipsis;
}
.browseFilters{
overflow-y: auto;
overflow-x: hidden;
max-height:265px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,214 @@
/**
* Copyright Marc J. Schmidt. See the LICENSE file at the top-level
* directory of this distribution and at
* https://github.com/marcj/css-element-queries/blob/master/LICENSE.
*/
;
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define(factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.ResizeSensor = factory();
}
}(typeof window !== 'undefined' ? window : this, function () {
// Make sure it does not throw in a SSR (Server Side Rendering) situation
if (typeof window === "undefined") {
return null;
}
// Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor.
// In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
// would generate too many unnecessary events.
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function (fn) {
return window.setTimeout(fn, 20);
};
/**
* Iterate over each of the provided element(s).
*
* @param {HTMLElement|HTMLElement[]} elements
* @param {Function} callback
*/
function forEachElement(elements, callback){
var elementsType = Object.prototype.toString.call(elements);
var isCollectionTyped = ('[object Array]' === elementsType
|| ('[object NodeList]' === elementsType)
|| ('[object HTMLCollection]' === elementsType)
|| ('[object Object]' === elementsType)
|| ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
|| ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
);
var i = 0, j = elements.length;
if (isCollectionTyped) {
for (; i < j; i++) {
callback(elements[i]);
}
} else {
callback(elements);
}
}
/**
* Class for dimension change detection.
*
* @param {Element|Element[]|Elements|jQuery} element
* @param {Function} callback
*
* @constructor
*/
var ResizeSensor = function(element, callback) {
/**
*
* @constructor
*/
function EventQueue() {
var q = [];
this.add = function(ev) {
q.push(ev);
};
var i, j;
this.call = function() {
for (i = 0, j = q.length; i < j; i++) {
q[i].call();
}
};
this.remove = function(ev) {
var newQueue = [];
for(i = 0, j = q.length; i < j; i++) {
if(q[i] !== ev) newQueue.push(q[i]);
}
q = newQueue;
}
this.length = function() {
return q.length;
}
}
/**
*
* @param {HTMLElement} element
* @param {Function} resized
*/
function attachResizeEvent(element, resized) {
if (!element) return;
if (element.resizedAttached) {
element.resizedAttached.add(resized);
return;
}
element.resizedAttached = new EventQueue();
element.resizedAttached.add(resized);
element.resizeSensor = document.createElement('div');
element.resizeSensor.className = 'resize-sensor';
var style = 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;';
var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;';
element.resizeSensor.style.cssText = style;
element.resizeSensor.innerHTML =
'<div class="resize-sensor-expand" style="' + style + '">' +
'<div style="' + styleChild + '"></div>' +
'</div>' +
'<div class="resize-sensor-shrink" style="' + style + '">' +
'<div style="' + styleChild + ' width: 200%; height: 200%"></div>' +
'</div>';
element.appendChild(element.resizeSensor);
if (element.resizeSensor.offsetParent !== element) {
element.style.position = 'relative';
}
var expand = element.resizeSensor.childNodes[0];
var expandChild = expand.childNodes[0];
var shrink = element.resizeSensor.childNodes[1];
var dirty, rafId, newWidth, newHeight;
var lastWidth = element.offsetWidth;
var lastHeight = element.offsetHeight;
var reset = function() {
expandChild.style.width = '100000px';
expandChild.style.height = '100000px';
expand.scrollLeft = 100000;
expand.scrollTop = 100000;
shrink.scrollLeft = 100000;
shrink.scrollTop = 100000;
};
reset();
var onResized = function() {
rafId = 0;
if (!dirty) return;
lastWidth = newWidth;
lastHeight = newHeight;
if (element.resizedAttached) {
element.resizedAttached.call();
}
};
var onScroll = function() {
newWidth = element.offsetWidth;
newHeight = element.offsetHeight;
dirty = newWidth != lastWidth || newHeight != lastHeight;
if (dirty && !rafId) {
rafId = requestAnimationFrame(onResized);
}
reset();
};
var addEvent = function(el, name, cb) {
if (el.attachEvent) {
el.attachEvent('on' + name, cb);
} else {
el.addEventListener(name, cb);
}
};
addEvent(expand, 'scroll', onScroll);
addEvent(shrink, 'scroll', onScroll);
}
forEachElement(element, function(elem){
attachResizeEvent(elem, callback);
});
this.detach = function(ev) {
ResizeSensor.detach(element, ev);
};
};
ResizeSensor.detach = function(element, ev) {
forEachElement(element, function(elem){
if (!elem) return
if(elem.resizedAttached && typeof ev == "function"){
elem.resizedAttached.remove(ev);
if(elem.resizedAttached.length()) return;
}
if (elem.resizeSensor) {
if (elem.contains(elem.resizeSensor)) {
elem.removeChild(elem.resizeSensor);
}
delete elem.resizeSensor;
delete elem.resizedAttached;
}
});
};
return ResizeSensor;
}));

View File

@ -0,0 +1,745 @@
/**
* Sticky Sidebar JavaScript Plugin.
* @version 3.3.0
* @author Ahmed Bouhuolia <a.bouhuolia@gmail.com>
* @license The MIT License (MIT)
*/
const StickySidebar = (() => {
// ---------------------------------
// # Define Constants
// ---------------------------------
//
const EVENT_KEY = '.stickySidebar';
const VERSION = '3.2.0';
const DEFAULTS = {
/**
* Additional top spacing of the element when it becomes sticky.
* @type {Numeric|Function}
*/
topSpacing: 0,
/**
* Additional bottom spacing of the element when it becomes sticky.
* @type {Numeric|Function}
*/
bottomSpacing: 0,
/**
* Container sidebar selector to know what the beginning and end of sticky element.
* @type {String|False}
*/
containerSelector: false,
/**
* Inner wrapper selector.
* @type {String}
*/
innerWrapperSelector: '.inner-wrapper-sticky',
/**
* The name of CSS class to apply to elements when they have become stuck.
* @type {String|False}
*/
stickyClass: 'is-affixed',
/**
* Detect when sidebar and its container change height so re-calculate their dimensions.
* @type {Boolean}
*/
resizeSensor: true,
/**
* The sidebar returns to its normal position if its width below this value.
* @type {Numeric}
*/
minWidth: false
};
// ---------------------------------
// # Class Definition
// ---------------------------------
//
/**
* Sticky Sidebar Class.
* @public
*/
class StickySidebar{
/**
* Sticky Sidebar Constructor.
* @constructor
* @param {HTMLElement|String} sidebar - The sidebar element or sidebar selector.
* @param {Object} options - The options of sticky sidebar.
*/
constructor(sidebar, options = {}){
this.options = StickySidebar.extend(DEFAULTS, options);
// Sidebar element query if there's no one, throw error.
this.sidebar = ('string' === typeof sidebar ) ? document.querySelector(sidebar) : sidebar;
if( 'undefined' === typeof this.sidebar )
throw new Error("There is no specific sidebar element.");
this.sidebarInner = false;
this.container = this.sidebar.parentElement;
// Current Affix Type of sidebar element.
this.affixedType = 'STATIC';
this.direction = 'down';
this.support = {
transform: false,
transform3d: false
};
this._initialized = false;
this._reStyle = false;
this._breakpoint = false;
this._resizeListeners = [];
// Dimensions of sidebar, container and screen viewport.
this.dimensions = {
translateY: 0,
topSpacing: 0,
lastTopSpacing: 0,
bottomSpacing: 0,
lastBottomSpacing: 0,
sidebarHeight: 0,
sidebarWidth: 0,
containerTop: 0,
containerHeight: 0,
viewportHeight: 0,
viewportTop: 0,
lastViewportTop: 0,
};
// Bind event handlers for referencability.
['handleEvent'].forEach( (method) => {
this[method] = this[method].bind(this);
});
// Initialize sticky sidebar for first time.
this.initialize();
}
/**
* Initializes the sticky sidebar by adding inner wrapper, define its container,
* min-width breakpoint, calculating dimensions, adding helper classes and inline style.
* @private
*/
initialize(){
this._setSupportFeatures();
// Get sticky sidebar inner wrapper, if not found, will create one.
if( this.options.innerWrapperSelector ){
this.sidebarInner = this.sidebar.querySelector(this.options.innerWrapperSelector);
if( null === this.sidebarInner )
this.sidebarInner = false;
}
if( ! this.sidebarInner ){
let wrapper = document.createElement('div');
wrapper.setAttribute('class', 'inner-wrapper-sticky');
this.sidebar.appendChild(wrapper);
while( this.sidebar.firstChild != wrapper )
wrapper.appendChild(this.sidebar.firstChild);
this.sidebarInner = this.sidebar.querySelector('.inner-wrapper-sticky');
}
// Container wrapper of the sidebar.
if( this.options.containerSelector ){
let containers = document.querySelectorAll(this.options.containerSelector);
containers = Array.prototype.slice.call(containers);
containers.forEach((container, item) => {
if( ! container.contains(this.sidebar) ) return;
this.container = container;
});
if( ! containers.length )
throw new Error("The container does not contains on the sidebar.");
}
// If top/bottom spacing is not function parse value to integer.
if( 'function' !== typeof this.options.topSpacing )
this.options.topSpacing = parseInt(this.options.topSpacing) || 0;
if( 'function' !== typeof this.options.bottomSpacing )
this.options.bottomSpacing = parseInt(this.options.bottomSpacing) || 0;
// Breakdown sticky sidebar if screen width below `options.minWidth`.
this._widthBreakpoint();
// Calculate dimensions of sidebar, container and viewport.
this.calcDimensions();
// Affix sidebar in proper position.
this.stickyPosition();
// Bind all events.
this.bindEvents();
// Inform other properties the sticky sidebar is initialized.
this._initialized = true;
}
/**
* Bind all events of sticky sidebar plugin.
* @protected
*/
bindEvents(){
window.addEventListener('resize', this, {passive: true});
window.addEventListener('scroll', this, {passive: true});
this.sidebar.addEventListener('update' + EVENT_KEY, this);
if( this.options.resizeSensor && 'undefined' !== typeof ResizeSensor ){
new ResizeSensor(this.sidebarInner, this.handleEvent);
new ResizeSensor(this.container, this.handleEvent);
}
}
/**
* Handles all events of the plugin.
* @param {Object} event - Event object passed from listener.
*/
handleEvent(event){
this.updateSticky(event);
}
/**
* Calculates dimensions of sidebar, container and screen viewpoint
* @public
*/
calcDimensions(){
if( this._breakpoint ) return;
var dims = this.dimensions;
// Container of sticky sidebar dimensions.
dims.containerTop = StickySidebar.offsetRelative(this.container).top;
dims.containerHeight = this.container.clientHeight;
dims.containerBottom = dims.containerTop + dims.containerHeight;
// Sidebar dimensions.
dims.sidebarHeight = this.sidebarInner.offsetHeight;
dims.sidebarWidth = this.sidebar.offsetWidth;
// Screen viewport dimensions.
dims.viewportHeight = window.innerHeight;
this._calcDimensionsWithScroll();
}
/**
* Some dimensions values need to be up-to-date when scrolling the page.
* @private
*/
_calcDimensionsWithScroll(){
var dims = this.dimensions;
dims.sidebarLeft = StickySidebar.offsetRelative(this.sidebar).left;
dims.viewportTop = document.documentElement.scrollTop || document.body.scrollTop;
dims.viewportBottom = dims.viewportTop + dims.viewportHeight;
dims.viewportLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
dims.topSpacing = this.options.topSpacing;
dims.bottomSpacing = this.options.bottomSpacing;
if( 'function' === typeof dims.topSpacing )
dims.topSpacing = parseInt(dims.topSpacing(this.sidebar)) || 0;
if( 'function' === typeof dims.bottomSpacing )
dims.bottomSpacing = parseInt(dims.bottomSpacing(this.sidebar)) || 0;
if( 'VIEWPORT-TOP' === this.affixedType ){
// Adjust translate Y in the case decrease top spacing value.
if( dims.topSpacing < dims.lastTopSpacing ){
dims.translateY += dims.lastTopSpacing - dims.topSpacing;
this._reStyle = true;
}
} else if( 'VIEWPORT-BOTTOM' === this.affixedType ){
// Adjust translate Y in the case decrease bottom spacing value.
if( dims.bottomSpacing < dims.lastBottomSpacing ){
dims.translateY += dims.lastBottomSpacing - dims.bottomSpacing;
this._reStyle = true;
}
}
dims.lastTopSpacing = dims.topSpacing;
dims.lastBottomSpacing = dims.bottomSpacing;
}
/**
* Determine whether the sidebar is bigger than viewport.
* @public
* @return {Boolean}
*/
isSidebarFitsViewport(){
return this.dimensions.sidebarHeight < this.dimensions.viewportHeight;
}
/**
* Observe browser scrolling direction top and down.
*/
observeScrollDir(){
var dims = this.dimensions;
if( dims.lastViewportTop === dims.viewportTop ) return;
var furthest = 'down' === this.direction ? Math.min : Math.max;
// If the browser is scrolling not in the same direction.
if( dims.viewportTop === furthest(dims.viewportTop, dims.lastViewportTop) )
this.direction = 'down' === this.direction ? 'up' : 'down';
}
/**
* Gets affix type of sidebar according to current scrollTop and scrollLeft.
* Holds all logical affix of the sidebar when scrolling up and down and when sidebar
* is bigger than viewport and vice versa.
* @public
* @return {String|False} - Proper affix type.
*/
getAffixType(){
var dims = this.dimensions, affixType = false;
this._calcDimensionsWithScroll();
var sidebarBottom = dims.sidebarHeight + dims.containerTop;
var colliderTop = dims.viewportTop + dims.topSpacing;
var colliderBottom = dims.viewportBottom - dims.bottomSpacing;
// When browser is scrolling top.
if( 'up' === this.direction ){
if( colliderTop <= dims.containerTop ){
dims.translateY = 0;
affixType = 'STATIC';
} else if( colliderTop <= dims.translateY + dims.containerTop ){
dims.translateY = colliderTop - dims.containerTop;
affixType = 'VIEWPORT-TOP';
} else if( ! this.isSidebarFitsViewport() && dims.containerTop <= colliderTop ){
affixType = 'VIEWPORT-UNBOTTOM';
}
// When browser is scrolling up.
} else {
// When sidebar element is not bigger than screen viewport.
if( this.isSidebarFitsViewport() ){
if( dims.sidebarHeight + colliderTop >= dims.containerBottom ){
dims.translateY = dims.containerBottom - sidebarBottom;
affixType = 'CONTAINER-BOTTOM';
} else if( colliderTop >= dims.containerTop ){
dims.translateY = colliderTop - dims.containerTop;
affixType = 'VIEWPORT-TOP';
}
// When sidebar element is bigger than screen viewport.
} else {
if( dims.containerBottom <= colliderBottom ){
dims.translateY = dims.containerBottom - sidebarBottom;
affixType = 'CONTAINER-BOTTOM';
} else if( sidebarBottom + dims.translateY <= colliderBottom ){
dims.translateY = colliderBottom - sidebarBottom;
affixType = 'VIEWPORT-BOTTOM';
} else if( dims.containerTop + dims.translateY <= colliderTop ){
affixType = 'VIEWPORT-UNBOTTOM';
}
}
}
// Make sure the translate Y is not bigger than container height.
dims.translateY = Math.max(0, dims.translateY);
dims.translateY = Math.min(dims.containerHeight, dims.translateY);
dims.lastViewportTop = dims.viewportTop;
return affixType;
}
/**
* Gets inline style of sticky sidebar wrapper and inner wrapper according
* to its affix type.
* @private
* @param {String} affixType - Affix type of sticky sidebar.
* @return {Object}
*/
_getStyle(affixType){
if( 'undefined' === typeof affixType ) return;
var style = {inner: {}, outer: {}};
var dims = this.dimensions;
switch( affixType ){
case 'VIEWPORT-TOP':
style.inner = {position: 'fixed', top: dims.topSpacing,
left: dims.sidebarLeft - dims.viewportLeft, width: dims.sidebarWidth};
break;
case 'VIEWPORT-BOTTOM':
style.inner = {position: 'fixed', top: 'auto', left: dims.sidebarLeft,
bottom: dims.bottomSpacing, width: dims.sidebarWidth};
break;
case 'CONTAINER-BOTTOM':
case 'VIEWPORT-UNBOTTOM':
let translate = this._getTranslate(0, dims.translateY + 'px');
if( translate )
style.inner = {transform: translate};
else
style.inner = {position: 'absolute', top: dims.translateY, width: dims.sidebarWidth};
break;
}
switch( affixType ){
case 'VIEWPORT-TOP':
case 'VIEWPORT-BOTTOM':
case 'VIEWPORT-UNBOTTOM':
case 'CONTAINER-BOTTOM':
style.outer = {height: dims.sidebarHeight, position: 'relative'};
break;
}
style.outer = StickySidebar.extend({height: '', position: ''}, style.outer);
style.inner = StickySidebar.extend({position: 'relative', top: '', left: '',
bottom: '', width: '', transform: this._getTranslate()}, style.inner);
return style;
}
/**
* Cause the sidebar to be sticky according to affix type by adding inline
* style, adding helper class and trigger events.
* @function
* @protected
* @param {string} force - Update sticky sidebar position by force.
*/
stickyPosition(force){
if( this._breakpoint ) return;
force = this._reStyle || force || false;
var offsetTop = this.options.topSpacing;
var offsetBottom = this.options.bottomSpacing;
var affixType = this.getAffixType();
var style = this._getStyle(affixType);
if( (this.affixedType != affixType || force) && affixType ){
let affixEvent = 'affix.' + affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
StickySidebar.eventTrigger(this.sidebar, affixEvent);
if( 'STATIC' === affixType )
StickySidebar.removeClass(this.sidebar, this.options.stickyClass);
else
StickySidebar.addClass(this.sidebar, this.options.stickyClass);
for( let key in style.outer ){
let _unit = ('number' === typeof style.outer[key]) ? 'px' : '';
this.sidebar.style[key] = style.outer[key];
}
for( let key in style.inner ){
let _unit = ('number' === typeof style.inner[key]) ? 'px' : '';
this.sidebarInner.style[key] = style.inner[key] + _unit;
}
let affixedEvent = 'affixed.'+ affixType.toLowerCase().replace('viewport-', '') + EVENT_KEY;
StickySidebar.eventTrigger(this.sidebar, affixedEvent);
} else {
if( this._initialized ) this.sidebarInner.style.left = style.inner.left;
}
this.affixedType = affixType;
}
/**
* Breakdown sticky sidebar when window width is below `options.minWidth` value.
* @protected
*/
_widthBreakpoint(){
if( window.innerWidth <= this.options.minWidth ){
this._breakpoint = true;
this.affixedType = 'STATIC';
this.sidebar.removeAttribute('style');
StickySidebar.removeClass(this.sidebar, this.options.stickyClass);
this.sidebarInner.removeAttribute('style');
} else {
this._breakpoint = false;
}
}
/**
* Switches between functions stack for each event type, if there's no
* event, it will re-initialize sticky sidebar.
* @public
*/
updateSticky(event = {}){
if( this._running ) return;
this._running = true;
((eventType) => {
requestAnimationFrame(() => {
switch( eventType ){
// When browser is scrolling and re-calculate just dimensions
// within scroll.
case 'scroll':
this._calcDimensionsWithScroll();
this.observeScrollDir();
this.stickyPosition();
break;
// When browser is resizing or there's no event, observe width
// breakpoint and re-calculate dimensions.
case 'resize':
default:
this._widthBreakpoint();
this.calcDimensions();
this.stickyPosition(true);
break;
}
this._running = false;
});
})(event.type);
}
/**
* Set browser support features to the public property.
* @private
*/
_setSupportFeatures(){
var support = this.support;
support.transform = StickySidebar.supportTransform();
support.transform3d = StickySidebar.supportTransform(true);
}
/**
* Get translate value, if the browser supports transfrom3d, it will adopt it.
* and the same with translate. if browser doesn't support both return false.
* @param {Number} y - Value of Y-axis.
* @param {Number} x - Value of X-axis.
* @param {Number} z - Value of Z-axis.
* @return {String|False}
*/
_getTranslate(y = 0, x = 0, z = 0){
if( this.support.transform3d ) return 'translate3d(' + y +', '+ x +', '+ z +')';
else if( this.support.translate ) return 'translate('+ y +', '+ x +')';
else return false;
}
/**
* Destroy sticky sidebar plugin.
* @public
*/
destroy(){
window.removeEventListener('resize', this);
window.removeEventListener('scroll', this);
this.sidebar.classList.remove(this.options.stickyClass);
this.sidebar.style.minHeight = '';
this.sidebar.removeEventListener('update' + EVENT_KEY, this);
var styleReset = {inner: {}, outer: {}};
styleReset.inner = {position: '', top: '', left: '', bottom: '', width: '', transform: ''};
styleReset.outer = {height: '', position: ''};
for( let key in styleReset.outer )
this.sidebar.style[key] = styleReset.outer[key];
for( let key in styleReset.inner )
this.sidebarInner.style[key] = styleReset.inner[key];
if( this.options.resizeSensor && 'undefined' !== typeof ResizeSensor ){
ResizeSensor.detach(this.sidebarInner, this.handleEvent);
ResizeSensor.detach(this.container, this.handleEvent);
}
}
/**
* Determine if the browser supports CSS transform feature.
* @function
* @static
* @param {Boolean} transform3d - Detect transform with translate3d.
* @return {String}
*/
static supportTransform(transform3d){
var result = false,
property = (transform3d) ? 'perspective' : 'transform',
upper = property.charAt(0).toUpperCase() + property.slice(1),
prefixes = ['Webkit', 'Moz', 'O', 'ms'],
support = document.createElement('support'),
style = support.style;
(property + ' ' + prefixes.join(upper + ' ') + upper).split(' ').forEach(function(property, i) {
if (style[property] !== undefined) {
result = property;
return false;
}
});
return result;
}
/**
* Trigger custom event.
* @static
* @param {DOMObject} element - Target element on the DOM.
* @param {String} eventName - Event name.
* @param {Object} data -
*/
static eventTrigger(element, eventName, data){
try{
var event = new CustomEvent(eventName, {detail: data});
} catch(e){
var event = document.createEvent('CustomEvent');
event.initCustomEvent(eventName, true, true, data);
}
element.dispatchEvent(event);
}
/**
* Extend options object with defaults.
* @function
* @static
*/
static extend(defaults, options){
var results = {};
for( let key in defaults ){
if( 'undefined' !== typeof options[key] ) results[key] = options[key];
else results[key] = defaults[key];
}
return results;
}
/**
* Get current coordinates left and top of specific element.
* @static
*/
static offsetRelative(element){
var result = {left: 0, top: 0};
do{
let offsetTop = element.offsetTop;
let offsetLeft = element.offsetLeft;
if( ! isNaN(offsetTop) )
result.top += offsetTop;
if( ! isNaN(offsetLeft) )
result.left += offsetLeft;
element = ( 'BODY' === element.tagName ) ?
element.parentElement : element.offsetParent;
} while(element)
return result;
}
/**
* Add specific class name to specific element.
* @static
* @param {ObjectDOM} element
* @param {String} className
*/
static addClass(element, className){
if( ! StickySidebar.hasClass(element, className) ){
if (element.classList)
element.classList.add(className);
else
element.className += ' ' + className;
}
}
/**
* Remove specific class name to specific element
* @static
* @param {ObjectDOM} element
* @param {String} className
*/
static removeClass(element, className){
if( StickySidebar.hasClass(element, className) ){
if (element.classList)
element.classList.remove(className);
else
element.className = element.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
/**
* Determine weather the element has specific class name.
* @static
* @param {ObjectDOM} element
* @param {String} className
*/
static hasClass(element, className){
if (element.classList)
return element.classList.contains(className);
else
return new RegExp('(^| )' + className + '( |$)', 'gi').test(element.className);
}
}
return StickySidebar;
})();
// Global
// -------------------------
window.StickySidebar = StickySidebar;
(() => {
if( 'undefined' === typeof window ) return;
const plugin = window.$ || window.jQuery || window.Zepto;
const DATA_NAMESPACE = 'stickySidebar';
// Make sure the site has jquery or zepto plugin.
if( plugin ){
/**
* Sticky Sidebar Plugin Defintion.
* @param {Object|String} - config
*/
function _jQueryPlugin(config){
return this.each(function(){
var $this = plugin(this),
data = plugin(this).data(DATA_NAMESPACE);
if( ! data ){
data = new StickySidebar(this, typeof config == 'object' && config);
$this.data(DATA_NAMESPACE, data);
}
if( 'string' === typeof config){
if (data[config] === undefined && ['destroy', 'updateSticky'].indexOf(config) === -1)
throw new Error('No method named "'+ config +'"');
data[config]();
}
});
}
plugin.fn.stickySidebar = _jQueryPlugin;
plugin.fn.stickySidebar.Constructor = StickySidebar;
const old = plugin.fn.stickySidebar;
/**
* Sticky Sidebar No Conflict.
*/
plugin.fn.stickySidebar.noConflict = function(){
plugin.fn.stickySidebar = old;
return this;
};
}
})();

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: false
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,222 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>BETA Interactive Minin</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="assets/css/dl119_files/theme.css">
<link rel="stylesheet" href="assets/css/dl119_files/custom.css">
<link rel="stylesheet" href="assets/css/custom.css">
<link rel="stylesheet" href="assets/css/animations.css">
<script src="assets/js/ResizeSensor.js" type="text/javascript"></script>
<script src="assets/js/jquery.sticky-sidebar.js" type="text/javascript"></script>
</head>
<body class="" cz-shortcut-listen="true" style="">
<div class="uk-offcanvas-content uk-height-viewport">
<app _nghost-dc20-1="">
<navbar _ngcontent-dc20-1="">
<div class="tm-header-mobile uk-hidden@m">
<nav class="uk-navbar-container uk-navbar" uk-navbar="">
<div class="uk-navbar-left">
<a class="uk-navbar-toggle" href="#tm-mobile" uk-toggle="">
<div class="uk-navbar-toggle-icon uk-icon custom-navbar-toggle-icon" uk-navbar-toggle-icon=""> <svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" icon="navbar-toggle-icon" ratio="1"><rect y="9" width="20" height="2"></rect><rect y="3" width="20" height="2"></rect><rect y="15" width="20" height="2"></rect></svg></div>
</a>
</div>
<div class="uk-navbar-center">
<a class="uk-logo uk-navbar-item" routerlink="/search/find" routerlinkactive="router-link-active" href="/search/find">
<img alt="OpenAIRE" class="uk-responsive-height" src="/static/OA CONNECT_B.png">
</a>
</div>
<div class="uk-navbar-right">
<user-mini>
<!--template bindings={}--><div class=" custom-user-mini-panel uk-margin-top uk-margin-right uk-float-right">
<!--template bindings={}-->
<!--template bindings={}--><a class="loginLink">Sign in</a>
</div>
</user-mini>
</div>
</nav>
<div class="uk-offcanvas" id="tm-mobile" mode="slide" overlay="" uk-offcanvas="">
<div class="uk-offcanvas-bar">
<button class="uk-offcanvas-close uk-close uk-icon" type="button" uk-close=""><svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg" icon="close-icon" ratio="1"><line fill="none" stroke="#000" stroke-width="1.1" x1="1" y1="1" x2="13" y2="13"></line><line fill="none" stroke="#000" stroke-width="1.1" x1="13" y1="1" x2="1" y2="13"></line></svg></button>
</div>
</div>
</div>
<div class="tm-toolbar custom-connect-toolbar uk-visible@m">
<div class="uk-container uk-flex uk-flex-middle uk-container-expand">
<div class="uk-margin-auto-left">
<div class="uk-grid-medium uk-child-width-auto uk-flex-middle uk-grid uk-grid-stack" uk-grid="margin: uk-margin-small-top">
<div class="uk-first-column">
<div class="uk-panel inner" id="module-119">
<ul class="uk-subnav uk-subnav-line">
<li class="uk-active"><a href="http://dl119.madgik.di.uoa.gr/"><img alt="home" class="uk-responsive-height" src="/static/dl119_files/Home-icon.png"></a></li>
<li><a href="#">Discover/Share</a></li>
<li><a href="#">Join</a></li>
<li class="custom-connect-li"><a class="router-link-active" href="#">Connect</a></li>
<li><a href="#">Monitor_</a></li>
<li><a href="#">Develop</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="tm-header uk-visible@m tm-header-transparent" uk-header="">
<div animation="uk-animation-slide-top" class="uk-navbar-container uk-navbar-transparent uk-light" cls-active="uk-active uk-navbar-sticky" cls-inactive="uk-navbar-transparent uk-light" media="768" style="" top=".tm-header + [class*=&quot;uk-section&quot;]" >
<div class="uk-container uk-container-expand">
<nav class="uk-navbar" uk-navbar="{&quot;align&quot;:&quot;left&quot;}">
<div class="uk-navbar-left uk-visible@l ">
<a class="uk-logo uk-navbar-item router-link-active" routerlink="/search/find" routerlinkactive="router-link-active" href="/search/find">
<img alt="OpenAIRE" class="uk-responsive-height" src="/static/OA CONNECT_B.png"></a>
</div>
<div class="uk-navbar-left uk-visible@m uk-hidden@l">
<a class="uk-logo uk-navbar-item router-link-active" routerlink="/search/find" routerlinkactive="router-link-active" href="/search/find">
<img alt="OpenAIRE" class="uk-responsive-height" src="/static/OA CONNECT_A.png"></a>
</div>
<div class="uk-navbar-right">
<user-mini>
<!--template bindings={}--><div class=" custom-user-mini-panel uk-margin-top uk-margin-right uk-float-right">
<!--template bindings={}-->
<!--template bindings={}--><a class="loginLink">Sign in</a>
</div>
</user-mini>
</div>
</nav>
</div>
</div><div class="uk-sticky-placeholder" style="height: 84px; margin: 0px;" hidden="hidden"></div>
<div class="uk-sticky-placeholder" style="height: 80px; margin: 0px;" hidden="hidden"></div>
<div class="uk-sticky-placeholder" style="height: 84px; margin: 0px;" hidden="hidden"></div>
</div>
<div class="first_page_section uk-section-default uk-section uk-padding-remove-vertical">
<div class="first_page_banner_headline uk-grid-collapse uk-flex-middle uk-margin-remove-vertical uk-grid uk-grid-stack" uk-grid="">
</div>
</div>
<div></div>
</navbar>
<div _ngcontent-dc20-1="" class=" uk-section uk-margin-large-top tm-middle custom-main-content" id="tm-main">
<!-- <div _ngcontent-dc20-1="" class="uk-container uk-container-expand">
<div _ngcontent-dc20-1="" uk-grid="">
<div _ngcontent-dc20-1="" class="tm-main uk-width-1-1@s uk-width-1-1@m uk-width-1-1@l uk-row-first "> -->
<main _ngcontent-dc20-1="">
<app-root></app-root>
</main>
<!-- </div>
</div>
</div> -->
</div>
<cookie-law _ngcontent-dc20-1="" position="bottom" _nghost-dc20-4="" seen="true">
<!--template bindings={}--><div _ngcontent-9e3d-4="" class="cookie-law-wrapper" style="transform: translateY(100%);">
<div _ngcontent-9e3d-4="" class="copy">
<span _ngcontent-9e3d-4="">
OpenAIRE uses cookies in order to function properly.<br _ngcontent-9e3d-1="">
Cookies are small pieces of data that websites store in your browser to allow us to give you the best browsing experience possible.
By using the OpenAIRE portal you accept our use of cookies. <a _ngcontent-9e3d-1="" href="//ec.europa.eu/ipg/basics/legal/cookies/index_en.htm" target="_blank"> Read more <span _ngcontent-9e3d-1="" uk-icon="icon: chevron-right" class="uk-icon"><svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" icon="chevron-right" ratio="1"><polyline fill="none" stroke="#000" stroke-width="1.03" points="7 4 13 10 7 16"></polyline></svg></span></a>
</span>
<!--template bindings={}-->
<a _ngcontent-9e3d-4="" class="dismiss" href="#" role="button"><span _ngcontent-9e3d-4="" class="uk-icon" uk-icon="icon: close"><svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" icon="close" ratio="1"><path fill="none" stroke="#000" stroke-width="1.06" d="M16,16 L4,4"></path><path fill="none" stroke="#000" stroke-width="1.06" d="M16,4 L4,16"></path></svg></span></a>
</div>
</div>
</cookie-law>
<bottom _ngcontent-dc20-1="">
<div class="custom-footer">
<div class="uk-section-primary uk-section uk-section-small uk-padding-remove-bottom">
<div class="uk-container">
<div class="uk-grid-margin uk-grid" uk-grid="">
<div class="uk-width-expand@m uk-light uk-first-column">
<div class="uk-margin">
<div uk-grid="" class="uk-child-width-auto uk-grid-small uk-grid">
<div class="uk-first-column">
<a class="el-link uk-icon-link uk-icon" href="http://www.facebook.com/groups/openaire/" target="_blank" uk-icon="icon: facebook"></a>
</div><div>
<a class="el-link uk-icon-link uk-icon" href="http://www.twitter.com/OpenAIRE_eu" target="_blank" uk-icon="icon: twitter"></a>
</div>
<div>
<a class="el-link uk-icon-link uk-icon" href="http://www.linkedin.com/groups/OpenAIRE-3893548" target="_blank" uk-icon="icon: linkedin"></a>
</div>
<div>
<a class="el-link uk-icon-link uk-icon" href="http://www.slideshare.net/OpenAIRE_eu" target="_blank" uk-icon="icon: social"></a>
</div>
<div>
<a class="el-link uk-icon-link uk-icon" href="http://vimeo.com/openaire" target="_blank" uk-icon="icon: vimeo"></a>
</div>
</div>
</div>
<div class="uk-margin uk-margin-remove-top uk-margin-remove-bottom uk-text-left">
<img alt="European Commission" class="el-image" src="/static/dl119_files/ec_logo_inv_small.png">
</div>
</div>
<div class="uk-width-expand@m uk-light">
<div>
<ul class="uk-subnav uk-margin-remove-bottom uk-subnav-divider" uk-margin="">
<li class="el-item uk-first-column">
<a class="el-link" href="http://dl119.madgik.di.uoa.gr/www.cnn.com">About</a>
</li>
<li class="el-item">
<a class="el-content uk-disabled">Services</a>
</li>
<li class="el-item">
<a class="el-content uk-disabled">News</a>
</li>
<li class="el-item">
<a class="el-content uk-disabled">Events</a>
</li>
<li class="el-item">
<a class="el-content uk-disabled">Blog</a>
</li>
<li class="el-item">
<a class="el-content uk-disabled">Contact us</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="uk-section-primary uk-section uk-section-small">
<div class="uk-container">
<div class="uk-grid-margin uk-grid uk-grid-stack" uk-grid="">
<div class="uk-width-1-1@m uk-first-column">
<div class="uk-margin uk-margin-remove-top uk-margin-remove-bottom uk-text-center">
<img alt="OpenAIRE" class="el-image" src="/static/dl119_files/Logo_Horizontal_white_small.png">
</div>
<div class="footer-license uk-margin uk-margin-remove-bottom uk-text-center uk-text-lead">
<div><a href="http://creativecommons.org/licenses/by/4.0/" rel="license"><img alt="Creative" src="/static/dl119_files/80x15.png" style="height: auto; max-width: 100%; vertical-align: middle;"></a>&nbsp;UNLESS OTHERWISE INDICATED, ALL MATERIALS CREATED BY THE OPENAIRE CONSORTIUM ARE LICENSED UNDER A&nbsp;<a href="http://creativecommons.org/licenses/by/4.0/" rel="license">CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL LICENSE</a>.</div>
<div>OPENAIRE IS POWERED BY&nbsp;<a href="http://www.d-net.research-infrastructures.eu/">D-NET</a>.</div>
</div>
<div class="uk-margin uk-margin-remove-top uk-margin-remove-bottom uk-text-right">
<a class="uk-totop uk-icon" href="#" uk-scroll="" uk-totop=""><svg width="15" height="20" viewBox="0 0 15 20" xmlns="http://www.w3.org/2000/svg" icon="totop" ratio="1"><polyline fill="none" stroke="#0000" stroke-width="1.1" points="1,8 7.5,1.5 14,8 "></polyline><rect fill="000" x="7" y="2" width="1" height="20"></rect></svg></a>
</div>
</div>
</div>
</div>
</div>
</div>
</bottom>
</app>
</div>
<script type="text/javascript">
function loadAltmetrics(e,t,n){
var d="createElement",c="getElementsByTagName",m="setAttribute",n=document.getElementById(e);
return n&&n.parentNode&&n.parentNode.removeChild(n),n=document[d+"NS"]&&document.documentElement.namespaceURI,n=n?document[d+"NS"](n,"script"):document[d]("script"),n[m]("id",e),n[m]("src",t),(document[c]("head")[0]||document[c]("body")[0]).appendChild(n),n=new Image,void n[m]("src","https://d1uo4w7k31k5mn.cloudfront.net/donut/0.png")
};
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,72 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/** Evergreen browsers require these. **/
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
/**
* Required to support Web Animations `@angular/animation`.
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/***************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/**
* Date, currency, decimal and percent pipes.
* Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
*/
// import 'intl'; // Run `npm install --save intl`.
/**
* Need to import at least one locale-data with intl.
*/
// import 'intl/locale-data/jsonp/en';

View File

@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@ -0,0 +1,32 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare const __karma__: any;
declare const require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();

View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "./",
"module": "es2015",
"types": []
},
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}

View File

@ -0,0 +1,20 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/spec",
"baseUrl": "./",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"node"
]
},
"files": [
"test.ts"
],
"include": [
"**/*.spec.ts",
"**/*.d.ts"
]
}

View File

@ -0,0 +1,5 @@
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
id: string;
}

View File

@ -0,0 +1,19 @@
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}

Some files were not shown because too many files have changed in this diff Show More