mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-08 02:24:11 +00:00
Merge branch 'master' into improve-support-for-hal-links
This commit is contained in:
53
e2e/search-page/search-page.e2e-spec.ts
Normal file
53
e2e/search-page/search-page.e2e-spec.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { ProtractorPage } from './search-page.po';
|
||||||
|
import { browser } from 'protractor';
|
||||||
|
import { promise } from 'selenium-webdriver';
|
||||||
|
|
||||||
|
describe('protractor SearchPage', () => {
|
||||||
|
let page: ProtractorPage;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
page = new ProtractorPage();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain query value when navigating to page with query parameter', () => {
|
||||||
|
const queryString = 'Interesting query string';
|
||||||
|
page.navigateToSearchWithQueryParameter(queryString);
|
||||||
|
page.getCurrentQuery().then((query: string) => {
|
||||||
|
expect<string>(query).toEqual(queryString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have right scope selected when navigating to page with scope parameter', () => {
|
||||||
|
const scope: promise.Promise<string> = page.getRandomScopeOption();
|
||||||
|
scope.then((scopeString: string) => {
|
||||||
|
page.navigateToSearchWithScopeParameter(scopeString);
|
||||||
|
page.getCurrentScope().then((s: string) => {
|
||||||
|
expect<string>(s).toEqual(scopeString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect to the correct url when scope was set and submit button was triggered', () => {
|
||||||
|
const scope: promise.Promise<string> = page.getRandomScopeOption();
|
||||||
|
scope.then((scopeString: string) => {
|
||||||
|
page.setCurrentScope(scopeString);
|
||||||
|
page.submitSearchForm();
|
||||||
|
browser.wait(() => {
|
||||||
|
return browser.getCurrentUrl().then((url: string) => {
|
||||||
|
return url.indexOf('scope=' + encodeURI(scopeString)) !== -1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect to the correct url when query was set and submit button was triggered', () => {
|
||||||
|
const queryString = 'Another interesting query string';
|
||||||
|
page.setCurrentQuery(queryString);
|
||||||
|
page.submitSearchForm();
|
||||||
|
browser.wait(() => {
|
||||||
|
return browser.getCurrentUrl().then((url: string) => {
|
||||||
|
return url.indexOf('query=' + encodeURI(queryString)) !== -1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
47
e2e/search-page/search-page.po.ts
Normal file
47
e2e/search-page/search-page.po.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { browser, element, by } from 'protractor';
|
||||||
|
import { promise } from 'selenium-webdriver';
|
||||||
|
|
||||||
|
export class ProtractorPage {
|
||||||
|
SEARCH = '/search';
|
||||||
|
|
||||||
|
navigateToSearch() {
|
||||||
|
return browser.get(this.SEARCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToSearchWithQueryParameter(query: string) {
|
||||||
|
return browser.get(this.SEARCH + '?query=' + query);
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToSearchWithScopeParameter(scope: string) {
|
||||||
|
return browser.get(this.SEARCH + '?scope=' + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentScope(): promise.Promise<string> {
|
||||||
|
return element(by.tagName('select')).getAttribute('value');
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentQuery(): promise.Promise<string> {
|
||||||
|
return element(by.tagName('input')).getAttribute('value');
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentScope(scope: string) {
|
||||||
|
element(by.css('option[value="' + scope + '"]')).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentQuery(query: string) {
|
||||||
|
element(by.css('input[name="query"]')).sendKeys(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
submitSearchForm() {
|
||||||
|
element(by.css('button.search-button')).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomScopeOption(): promise.Promise<string> {
|
||||||
|
const options = element(by.css('select[name="scope"]')).all(by.tagName('option'));
|
||||||
|
return options.count().then((c: number) => {
|
||||||
|
const index: number = Math.floor(Math.random() * (c - 1));
|
||||||
|
return options.get(index + 1).getAttribute('value');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -27,18 +27,18 @@ module.exports = function (config) {
|
|||||||
frameworks: ['jasmine'],
|
frameworks: ['jasmine'],
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
require('karma-webpack'),
|
require("istanbul-instrumenter-loader"),
|
||||||
require('karma-jasmine'),
|
|
||||||
require('karma-chrome-launcher'),
|
require('karma-chrome-launcher'),
|
||||||
require('karma-phantomjs-launcher'),
|
|
||||||
require('karma-webdriver-launcher'),
|
|
||||||
require('karma-coverage'),
|
require('karma-coverage'),
|
||||||
require('karma-remap-coverage'),
|
require("karma-istanbul-preprocessor"),
|
||||||
|
require('karma-jasmine'),
|
||||||
require('karma-mocha-reporter'),
|
require('karma-mocha-reporter'),
|
||||||
|
require('karma-phantomjs-launcher'),
|
||||||
|
require('karma-remap-coverage'),
|
||||||
require('karma-remap-istanbul'),
|
require('karma-remap-istanbul'),
|
||||||
require('karma-sourcemap-loader'),
|
require('karma-sourcemap-loader'),
|
||||||
require("istanbul-instrumenter-loader"),
|
require('karma-webdriver-launcher'),
|
||||||
require("karma-istanbul-preprocessor")
|
require('karma-webpack')
|
||||||
],
|
],
|
||||||
|
|
||||||
// list of files to exclude
|
// list of files to exclude
|
||||||
@@ -59,7 +59,11 @@ module.exports = function (config) {
|
|||||||
* available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
* available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||||
*/
|
*/
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
'./spec-bundle.js': ['istanbul', 'webpack', 'sourcemap']
|
'./spec-bundle.js': [
|
||||||
|
'istanbul',
|
||||||
|
'webpack',
|
||||||
|
'sourcemap'
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Webpack Config at ./webpack.test.js
|
// Webpack Config at ./webpack.test.js
|
||||||
@@ -79,9 +83,9 @@ module.exports = function (config) {
|
|||||||
remapIstanbulReporter: {
|
remapIstanbulReporter: {
|
||||||
remapOptions: {}, //additional remap options
|
remapOptions: {}, //additional remap options
|
||||||
reports: {
|
reports: {
|
||||||
json: 'coverage/coverage.json',
|
json: './coverage/coverage.json',
|
||||||
lcovonly: 'coverage/lcov.info',
|
lcovonly: './coverage/lcov.info',
|
||||||
html: 'coverage/html/',
|
html: './coverage/html/',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -111,7 +115,12 @@ module.exports = function (config) {
|
|||||||
* possible values: 'dots', 'progress'
|
* possible values: 'dots', 'progress'
|
||||||
* available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
* available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
*/
|
*/
|
||||||
reporters: ['mocha', 'coverage', 'remap-coverage', 'karma-remap-istanbul'],
|
reporters: [
|
||||||
|
'mocha',
|
||||||
|
'coverage',
|
||||||
|
'remap-coverage',
|
||||||
|
'karma-remap-istanbul'
|
||||||
|
],
|
||||||
|
|
||||||
// Karma web server port
|
// Karma web server port
|
||||||
port: 9876,
|
port: 9876,
|
||||||
|
15
package.json
15
package.json
@@ -12,14 +12,15 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"global": "npm install -g @angular/cli marked node-gyp nodemon node-nightly npm-check-updates npm-run-all rimraf typescript ts-node typedoc webpack webpack-bundle-analyzer pm2 rollup",
|
"global": "npm install -g @angular/cli marked node-gyp nodemon node-nightly npm-check-updates npm-run-all rimraf typescript ts-node typedoc webpack webpack-bundle-analyzer pm2 rollup",
|
||||||
"clean:coverage": "rimraf coverage",
|
"clean:coverage": "yarn run rimraf coverage",
|
||||||
"clean:dist": "rimraf dist",
|
"clean:dist": "yarn run rimraf dist",
|
||||||
"clean:doc": "rimraf doc",
|
"clean:doc": "yarn run rimraf doc",
|
||||||
"clean:log": "rimraf *.log*",
|
"clean:log": "yarn run rimraf *.log*",
|
||||||
"clean:json": "rimraf *.records.json",
|
"clean:json": "yarn run rimraf *.records.json",
|
||||||
"clean:node": "rimraf node_modules",
|
"clean:node": "yarn run rimraf node_modules",
|
||||||
"clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json",
|
"clean:prod": "yarn run clean:coverage && yarn run clean:doc && yarn run clean:dist && yarn run clean:log && yarn run clean:json",
|
||||||
"clean": "yarn run clean:prod && yarn run clean:node",
|
"clean": "yarn run clean:prod && yarn run clean:node",
|
||||||
|
"rimraf": "rimraf",
|
||||||
"prebuild": "yarn run clean:dist",
|
"prebuild": "yarn run clean:dist",
|
||||||
"prebuild:aot": "yarn run prebuild",
|
"prebuild:aot": "yarn run prebuild",
|
||||||
"prebuild:prod": "yarn run prebuild",
|
"prebuild:prod": "yarn run prebuild",
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
"@angular/compiler": "4.4.4",
|
"@angular/compiler": "4.4.4",
|
||||||
"@angular/compiler-cli": "4.4.4",
|
"@angular/compiler-cli": "4.4.4",
|
||||||
"@ngrx/store-devtools": "4.0.0",
|
"@ngrx/store-devtools": "4.0.0",
|
||||||
"@ngtools/webpack": "1.7.3",
|
"@ngtools/webpack": "1.7.2",
|
||||||
"@types/cookie-parser": "1.4.1",
|
"@types/cookie-parser": "1.4.1",
|
||||||
"@types/deep-freeze": "0.1.1",
|
"@types/deep-freeze": "0.1.1",
|
||||||
"@types/express": "4.0.37",
|
"@types/express": "4.0.37",
|
||||||
|
@@ -78,5 +78,25 @@
|
|||||||
"results": {
|
"results": {
|
||||||
"title": "Search Results"
|
"title": "Search Results"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"default": "Loading...",
|
||||||
|
"top-level-communities": "Loading top level communities...",
|
||||||
|
"community": "Loading community...",
|
||||||
|
"collection": "Loading collection...",
|
||||||
|
"sub-collections": "Loading sub-collections...",
|
||||||
|
"items": "Loading items...",
|
||||||
|
"item": "Loading item...",
|
||||||
|
"objects": "Loading..."
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"default": "Error",
|
||||||
|
"top-level-communities": "Error fetching top level communities",
|
||||||
|
"community": "Error fetching community",
|
||||||
|
"collection": "Error fetching collection",
|
||||||
|
"sub-collections": "Error fetching sub-collections",
|
||||||
|
"items": "Error fetching items",
|
||||||
|
"item": "Error fetching item",
|
||||||
|
"objects": "Error fetching objects"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,10 +3,12 @@ import commonjs from 'rollup-plugin-commonjs';
|
|||||||
import uglify from 'rollup-plugin-uglify'
|
import uglify from 'rollup-plugin-uglify'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
entry: 'dist/client.js',
|
input: 'dist/client.js',
|
||||||
dest: 'dist/client.js',
|
output: {
|
||||||
|
file: 'dist/client.js',
|
||||||
|
format: 'iife',
|
||||||
|
},
|
||||||
sourceMap: false,
|
sourceMap: false,
|
||||||
format: 'iife',
|
|
||||||
plugins: [
|
plugins: [
|
||||||
nodeResolve({
|
nodeResolve({
|
||||||
jsnext: true,
|
jsnext: true,
|
||||||
|
@@ -38,25 +38,11 @@ testing.TestBed.initTestEnvironment(
|
|||||||
browser.platformBrowserDynamicTesting()
|
browser.platformBrowserDynamicTesting()
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
var tests = require.context('./src', true, /\.spec\.ts$/);
|
||||||
* Ok, this is kinda crazy. We can use the context method on
|
|
||||||
* require that webpack created in order to tell webpack
|
|
||||||
* what files we actually want to require or import.
|
|
||||||
* Below, context will be a function/object with file names as keys.
|
|
||||||
* Using that regex we are saying look in ../src then find
|
|
||||||
* any file that ends with spec.ts and get its path. By passing in true
|
|
||||||
* we say do this recursively
|
|
||||||
*/
|
|
||||||
var testContext = require.context('./src', true, /\.spec\.ts/);
|
|
||||||
|
|
||||||
/*
|
tests.keys().forEach(tests);
|
||||||
* get all the files, for each file, call the context function
|
|
||||||
* that will require the file and load it up here. Context will
|
|
||||||
* loop and require those spec files here
|
|
||||||
*/
|
|
||||||
function requireAll(requireContext) {
|
|
||||||
return requireContext.keys().map(requireContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// requires and returns all modules that match
|
// includes all modules into test coverage
|
||||||
var modules = requireAll(testContext);
|
const modules = require.context('./src/app', true, /\.module\.ts$/);
|
||||||
|
|
||||||
|
modules.keys().forEach(modules);
|
||||||
|
@@ -1,40 +1,50 @@
|
|||||||
<div class="collection-page">
|
<div class="collection-page">
|
||||||
<div *ngIf="collectionData.hasSucceeded | async">
|
<div *ngIf="collectionData.hasSucceeded | async" @fadeInOut>
|
||||||
<!-- Collection Name -->
|
<div *ngIf="collectionData.payload | async; let collectionPayload">
|
||||||
<ds-comcol-page-header
|
<!-- Collection Name -->
|
||||||
[name]="(collectionData.payload | async)?.name">
|
<ds-comcol-page-header
|
||||||
</ds-comcol-page-header>
|
[name]="collectionPayload.name">
|
||||||
<!-- Collection logo -->
|
</ds-comcol-page-header>
|
||||||
<ds-comcol-page-logo *ngIf="logoData"
|
<!-- Collection logo -->
|
||||||
[logo]="logoData.payload | async"
|
<ds-comcol-page-logo *ngIf="logoData"
|
||||||
[alternateText]="'Collection Logo'">
|
[logo]="logoData.payload | async"
|
||||||
</ds-comcol-page-logo>
|
[alternateText]="'Collection Logo'">
|
||||||
<!-- Introductionary text -->
|
</ds-comcol-page-logo>
|
||||||
<ds-comcol-page-content
|
<!-- Introductionary text -->
|
||||||
[content]="(collectionData.payload | async)?.introductoryText"
|
<ds-comcol-page-content
|
||||||
[hasInnerHtml]="true">
|
[content]="collectionPayload.introductoryText"
|
||||||
</ds-comcol-page-content>
|
[hasInnerHtml]="true">
|
||||||
<!-- News -->
|
</ds-comcol-page-content>
|
||||||
<ds-comcol-page-content
|
<!-- News -->
|
||||||
[content]="(collectionData.payload | async)?.sidebarText"
|
<ds-comcol-page-content
|
||||||
[hasInnerHtml]="true"
|
[content]="collectionPayload.sidebarText"
|
||||||
[title]="'community.page.news'">
|
[hasInnerHtml]="true"
|
||||||
</ds-comcol-page-content>
|
[title]="'community.page.news'">
|
||||||
<!-- Copyright -->
|
</ds-comcol-page-content>
|
||||||
<ds-comcol-page-content
|
<!-- Copyright -->
|
||||||
[content]="(collectionData.payload | async)?.copyrightText"
|
<ds-comcol-page-content
|
||||||
[hasInnerHtml]="true">
|
[content]="collectionPayload.copyrightText"
|
||||||
</ds-comcol-page-content>
|
[hasInnerHtml]="true">
|
||||||
<!-- Licence -->
|
</ds-comcol-page-content>
|
||||||
<ds-comcol-page-content
|
<!-- Licence -->
|
||||||
[content]="(collectionData.payload | async)?.license"
|
<ds-comcol-page-content
|
||||||
[title]="'collection.page.license'">
|
[content]="collectionPayload.license"
|
||||||
</ds-comcol-page-content>
|
[title]="'collection.page.license'">
|
||||||
|
</ds-comcol-page-content>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="collectionData.hasFailed | async" message="{{'error.collection' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="collectionData.isLoading | async" message="{{'loading.collection' | translate}}"></ds-loading>
|
||||||
<br>
|
<br>
|
||||||
<div *ngIf="(itemData.hasSucceeded | async)">
|
<div *ngIf="itemData.hasSucceeded | async" @fadeIn>
|
||||||
<h2>{{'collection.page.browse.recent.head' | translate}}</h2>
|
<h2>{{'collection.page.browse.recent.head' | translate}}</h2>
|
||||||
<ds-object-list [config]="paginationConfig" [sortConfig]="sortConfig"
|
<ds-object-list
|
||||||
[objects]="itemData" [hideGear]="false"></ds-object-list>
|
[config]="paginationConfig"
|
||||||
|
[sortConfig]="sortConfig"
|
||||||
|
[objects]="itemData"
|
||||||
|
[hideGear]="false">
|
||||||
|
</ds-object-list>
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="itemData.hasFailed | async" message="{{'error.items' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="itemData.isLoading | async" message="{{'loading.items' | translate}}"></ds-loading>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,28 +1,30 @@
|
|||||||
import {
|
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy,
|
import { ActivatedRoute } from '@angular/router';
|
||||||
OnInit
|
import { Observable } from 'rxjs/Observable';
|
||||||
} from '@angular/core';
|
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
|
||||||
|
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { SortOptions } from '../core/cache/models/sort-options.model';
|
||||||
import { Collection } from '../core/shared/collection.model';
|
|
||||||
import { Bitstream } from '../core/shared/bitstream.model';
|
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
|
||||||
import { CollectionDataService } from '../core/data/collection-data.service';
|
import { CollectionDataService } from '../core/data/collection-data.service';
|
||||||
import { ItemDataService } from '../core/data/item-data.service';
|
import { ItemDataService } from '../core/data/item-data.service';
|
||||||
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
|
import { Bitstream } from '../core/shared/bitstream.model';
|
||||||
|
|
||||||
|
import { Collection } from '../core/shared/collection.model';
|
||||||
import { Item } from '../core/shared/item.model';
|
import { Item } from '../core/shared/item.model';
|
||||||
import { SortOptions, SortDirection } from '../core/cache/models/sort-options.model';
|
|
||||||
|
import { fadeIn, fadeInOut } from '../shared/animations/fade';
|
||||||
|
import { hasValue, isNotEmpty } from '../shared/empty.util';
|
||||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
import { hasValue, isNotEmpty, isUndefined } from '../shared/empty.util';
|
|
||||||
import { PageInfo } from '../core/shared/page-info.model';
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-collection-page',
|
selector: 'ds-collection-page',
|
||||||
styleUrls: ['./collection-page.component.scss'],
|
styleUrls: ['./collection-page.component.scss'],
|
||||||
templateUrl: './collection-page.component.html',
|
templateUrl: './collection-page.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
animations: [
|
||||||
|
fadeIn,
|
||||||
|
fadeInOut
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class CollectionPageComponent implements OnInit, OnDestroy {
|
export class CollectionPageComponent implements OnInit, OnDestroy {
|
||||||
collectionData: RemoteData<Collection>;
|
collectionData: RemoteData<Collection>;
|
||||||
|
@@ -1,26 +1,30 @@
|
|||||||
<div class="community-page" *ngIf="communityData.hasSucceeded | async">
|
<div class="community-page" *ngIf="communityData.hasSucceeded | async" @fadeInOut>
|
||||||
<!-- Community name -->
|
<div *ngIf="communityData.payload | async; let communityPayload">
|
||||||
<ds-comcol-page-header [name]="(communityData.payload | async)?.name"></ds-comcol-page-header>
|
<!-- Community name -->
|
||||||
<!-- Community logo -->
|
<ds-comcol-page-header [name]="communityPayload.name"></ds-comcol-page-header>
|
||||||
<ds-comcol-page-logo *ngIf="logoData"
|
<!-- Community logo -->
|
||||||
|
<ds-comcol-page-logo *ngIf="logoData"
|
||||||
[logo]="logoData.payload | async"
|
[logo]="logoData.payload | async"
|
||||||
[alternateText]="'Community Logo'">
|
[alternateText]="'Community Logo'">
|
||||||
</ds-comcol-page-logo>
|
</ds-comcol-page-logo>
|
||||||
<!-- Introductionary text -->
|
<!-- Introductionary text -->
|
||||||
<ds-comcol-page-content
|
<ds-comcol-page-content
|
||||||
[content]="(communityData.payload | async)?.introductoryText"
|
[content]="communityPayload.introductoryText"
|
||||||
[hasInnerHtml]="true">
|
[hasInnerHtml]="true">
|
||||||
</ds-comcol-page-content>
|
</ds-comcol-page-content>
|
||||||
<!-- News -->
|
<!-- News -->
|
||||||
<ds-comcol-page-content
|
<ds-comcol-page-content
|
||||||
[content]="(communityData.payload | async)?.sidebarText"
|
[content]="communityPayload.sidebarText"
|
||||||
[hasInnerHtml]="true"
|
[hasInnerHtml]="true"
|
||||||
[title]="'community.page.news'">
|
[title]="'community.page.news'">
|
||||||
</ds-comcol-page-content>
|
</ds-comcol-page-content>
|
||||||
<!-- Copyright -->
|
<!-- Copyright -->
|
||||||
<ds-comcol-page-content
|
<ds-comcol-page-content
|
||||||
[content]="(communityData.payload | async)?.copyrightText"
|
[content]="communityPayload.copyrightText"
|
||||||
[hasInnerHtml]="true">
|
[hasInnerHtml]="true">
|
||||||
</ds-comcol-page-content>
|
</ds-comcol-page-content>
|
||||||
<ds-community-page-sub-collection-list></ds-community-page-sub-collection-list>
|
<ds-community-page-sub-collection-list></ds-community-page-sub-collection-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="communityData.hasFailed | async" message="{{'error.community' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="communityData.isLoading | async" message="{{'loading.community' | translate}}"></ds-loading>
|
||||||
|
@@ -2,18 +2,21 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/
|
|||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
import { Subscription } from 'rxjs/Subscription';
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
import { CommunityDataService } from '../core/data/community-data.service';
|
||||||
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
|
import { Bitstream } from '../core/shared/bitstream.model';
|
||||||
|
|
||||||
import { Community } from '../core/shared/community.model';
|
import { Community } from '../core/shared/community.model';
|
||||||
import { Bitstream } from '../core/shared/bitstream.model';
|
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
import { fadeInOut } from '../shared/animations/fade';
|
||||||
import { CommunityDataService } from '../core/data/community-data.service';
|
|
||||||
import { hasValue } from '../shared/empty.util';
|
import { hasValue } from '../shared/empty.util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-page',
|
selector: 'ds-community-page',
|
||||||
styleUrls: ['./community-page.component.scss'],
|
styleUrls: ['./community-page.component.scss'],
|
||||||
templateUrl: './community-page.component.html',
|
templateUrl: './community-page.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
animations: [fadeInOut]
|
||||||
})
|
})
|
||||||
export class CommunityPageComponent implements OnInit, OnDestroy {
|
export class CommunityPageComponent implements OnInit, OnDestroy {
|
||||||
communityData: RemoteData<Community>;
|
communityData: RemoteData<Community>;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div *ngIf="subCollections.hasSucceeded | async">
|
<div *ngIf="subCollections.hasSucceeded | async" @fadeIn>
|
||||||
<h2>{{'community.sub-collection-list.head' | translate}}</h2>
|
<h2>{{'community.sub-collection-list.head' | translate}}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngFor="let collection of (subCollections.payload | async)">
|
<li *ngFor="let collection of (subCollections.payload | async)">
|
||||||
@@ -9,3 +9,5 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="subCollections.hasFailed | async" message="{{'error.sub-collections' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="subCollections.isLoading | async" message="{{'loading.sub-collections' | translate}}"></ds-loading>
|
||||||
|
@@ -4,10 +4,13 @@ import { CollectionDataService } from '../../core/data/collection-data.service';
|
|||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Collection } from '../../core/shared/collection.model';
|
import { Collection } from '../../core/shared/collection.model';
|
||||||
|
|
||||||
|
import { fadeIn } from '../../shared/animations/fade';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-page-sub-collection-list',
|
selector: 'ds-community-page-sub-collection-list',
|
||||||
styleUrls: ['./community-page-sub-collection-list.component.scss'],
|
styleUrls: ['./community-page-sub-collection-list.component.scss'],
|
||||||
templateUrl: './community-page-sub-collection-list.component.html',
|
templateUrl: './community-page-sub-collection-list.component.html',
|
||||||
|
animations:[fadeIn]
|
||||||
})
|
})
|
||||||
export class CommunityPageSubCollectionListComponent implements OnInit {
|
export class CommunityPageSubCollectionListComponent implements OnInit {
|
||||||
subCollections: RemoteData<Collection[]>;
|
subCollections: RemoteData<Collection[]>;
|
||||||
|
13
src/app/+home-page/home-page-routing.module.ts
Normal file
13
src/app/+home-page/home-page-routing.module.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
import { HomePageComponent } from './home-page.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild([
|
||||||
|
{ path: '', component: HomePageComponent, pathMatch: 'full' }
|
||||||
|
])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class HomePageRoutingModule { }
|
10
src/app/+home-page/home-page.component.ts
Normal file
10
src/app/+home-page/home-page.component.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-home-page',
|
||||||
|
styleUrls: ['./home-page.component.scss'],
|
||||||
|
templateUrl: './home-page.component.html'
|
||||||
|
})
|
||||||
|
export class HomePageComponent {
|
||||||
|
|
||||||
|
}
|
@@ -1,24 +1,24 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
|
|
||||||
import { HomeComponent } from './home.component';
|
|
||||||
import { HomeRoutingModule } from './home-routing.module';
|
|
||||||
import { TopLevelCommunityListComponent } from './top-level-community-list/top-level-community-list.component';
|
|
||||||
import { HomeNewsComponent } from './home-news/home-news.component';
|
import { HomeNewsComponent } from './home-news/home-news.component';
|
||||||
|
import { HomePageRoutingModule } from './home-page-routing.module';
|
||||||
|
|
||||||
|
import { HomePageComponent } from './home-page.component';
|
||||||
|
import { TopLevelCommunityListComponent } from './top-level-community-list/top-level-community-list.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
HomeRoutingModule
|
HomePageRoutingModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
HomeComponent,
|
HomePageComponent,
|
||||||
TopLevelCommunityListComponent,
|
TopLevelCommunityListComponent,
|
||||||
HomeNewsComponent
|
HomeNewsComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class HomeModule {
|
export class HomePageModule {
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
<div *ngIf="topLevelCommunities.hasSucceeded | async" @fadeInOut>
|
||||||
|
<h2>{{'home.top-level-communities.head' | translate}}</h2>
|
||||||
|
<p class="lead">{{'home.top-level-communities.help' | translate}}</p>
|
||||||
|
<ds-object-list
|
||||||
|
[config]="config"
|
||||||
|
[sortConfig]="sortConfig"
|
||||||
|
[objects]="topLevelCommunities"
|
||||||
|
[hideGear]="true"
|
||||||
|
(paginationChange)="updatePage($event)">
|
||||||
|
</ds-object-list>
|
||||||
|
</div>
|
||||||
|
<ds-error *ngIf="topLevelCommunities.hasFailed | async" message="{{'error.top-level-communites' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="topLevelCommunities.isLoading | async" message="{{'loading.top-level-communities' | translate}}"></ds-loading>
|
@@ -1,18 +1,20 @@
|
|||||||
import { Component, OnInit, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
|
import { SortOptions } from '../../core/cache/models/sort-options.model';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
|
||||||
|
import { fadeInOut } from '../../shared/animations/fade';
|
||||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||||
import { SortOptions, SortDirection } from '../../core/cache/models/sort-options.model';
|
|
||||||
import { ActivatedRoute } from '@angular/router';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-top-level-community-list',
|
selector: 'ds-top-level-community-list',
|
||||||
styleUrls: ['./top-level-community-list.component.scss'],
|
styleUrls: ['./top-level-community-list.component.scss'],
|
||||||
templateUrl: './top-level-community-list.component.html',
|
templateUrl: './top-level-community-list.component.html',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
animations: [fadeInOut]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class TopLevelCommunityListComponent {
|
export class TopLevelCommunityListComponent {
|
||||||
topLevelCommunities: RemoteData<Community[]>;
|
topLevelCommunities: RemoteData<Community[]>;
|
||||||
config: PaginationComponentOptions;
|
config: PaginationComponentOptions;
|
||||||
@@ -21,8 +23,7 @@ export class TopLevelCommunityListComponent {
|
|||||||
constructor(private cds: CommunityDataService) {
|
constructor(private cds: CommunityDataService) {
|
||||||
this.config = new PaginationComponentOptions();
|
this.config = new PaginationComponentOptions();
|
||||||
this.config.id = 'top-level-pagination';
|
this.config.id = 'top-level-pagination';
|
||||||
this.config.pageSizeOptions = [4];
|
this.config.pageSize = 5;
|
||||||
this.config.pageSize = 4;
|
|
||||||
this.config.currentPage = 1;
|
this.config.currentPage = 1;
|
||||||
this.sortConfig = new SortOptions();
|
this.sortConfig = new SortOptions();
|
||||||
|
|
@@ -1,13 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
|
|
||||||
import { HomeComponent } from './home.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
RouterModule.forChild([
|
|
||||||
{ path: '', component: HomeComponent, pathMatch: 'full' }
|
|
||||||
])
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class HomeRoutingModule { }
|
|
@@ -1,11 +0,0 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ds-home',
|
|
||||||
styleUrls: ['./home.component.scss'],
|
|
||||||
templateUrl: './home.component.html',
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
|
||||||
export class HomeComponent {
|
|
||||||
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
<div *ngIf="topLevelCommunities.hasSucceeded | async">
|
|
||||||
<h2>{{'home.top-level-communities.head' | translate}}</h2>
|
|
||||||
<p class="lead">{{'home.top-level-communities.help' | translate}}</p>
|
|
||||||
<ds-object-list [config]="config" [sortConfig]="sortConfig"
|
|
||||||
[objects]="topLevelCommunities" [hideGear]="true" (paginationChange)="updatePage($event)"></ds-object-list>
|
|
||||||
</div>
|
|
@@ -1,25 +1,23 @@
|
|||||||
<div class="item-page" *ngIf="item.hasSucceeded | async">
|
<div class="item-page" *ngIf="item.hasSucceeded | async" @fadeInOut>
|
||||||
<ds-item-page-title-field [item]="item.payload | async"></ds-item-page-title-field>
|
<div *ngIf="item.payload | async; let itemPayload">
|
||||||
|
<ds-item-page-title-field [item]="itemPayload"></ds-item-page-title-field>
|
||||||
<div class="simple-view-link">
|
<div class="simple-view-link">
|
||||||
<a class="btn btn-outline-primary col-4" [routerLink]="['/items/' + (item.payload | async)?.id]">
|
<a class="btn btn-outline-primary col-4" [routerLink]="['/items/' + itemPayload.id]">
|
||||||
{{"item.page.link.simple" | translate}}
|
{{"item.page.link.simple" | translate}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="table table-responsive table-striped">
|
<table class="table table-responsive table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let metadatum of (metadata | async)">
|
<tr *ngFor="let metadatum of (metadata | async)">
|
||||||
<td>{{metadatum.key}}</td>
|
<td>{{metadatum.key}}</td>
|
||||||
<td>{{metadatum.value}}</td>
|
<td>{{metadatum.value}}</td>
|
||||||
<td>{{metadatum.language}}</td>
|
<td>{{metadatum.language}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<ds-item-page-full-file-section [item]="itemPayload"></ds-item-page-full-file-section>
|
||||||
<ds-item-page-full-file-section [item]="item.payload | async"></ds-item-page-full-file-section>
|
<ds-item-page-collections [item]="itemPayload"></ds-item-page-collections>
|
||||||
|
</div>
|
||||||
<ds-item-page-collections [item]="item.payload | async"></ds-item-page-collections>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="item.hasFailed | async" message="{{'error.item' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="item.isLoading | async" message="{{'loading.item' | translate}}"></ds-loading>
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { animate, state, transition, trigger, style, keyframes } from '@angular/animations';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
import { ItemPageComponent } from '../simple/item-page.component';
|
import { ItemPageComponent } from '../simple/item-page.component';
|
||||||
@@ -8,6 +10,8 @@ import { ActivatedRoute } from '@angular/router';
|
|||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Item } from '../../core/shared/item.model';
|
import { Item } from '../../core/shared/item.model';
|
||||||
|
|
||||||
|
import { fadeInOut } from '../../shared/animations/fade';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
* The route parameter 'id' is used to request the item it represents.
|
* The route parameter 'id' is used to request the item it represents.
|
||||||
@@ -18,6 +22,7 @@ import { Item } from '../../core/shared/item.model';
|
|||||||
selector: 'ds-full-item-page',
|
selector: 'ds-full-item-page',
|
||||||
styleUrls: ['./full-item-page.component.scss'],
|
styleUrls: ['./full-item-page.component.scss'],
|
||||||
templateUrl: './full-item-page.component.html',
|
templateUrl: './full-item-page.component.html',
|
||||||
|
animations: [fadeInOut]
|
||||||
})
|
})
|
||||||
export class FullItemPageComponent extends ItemPageComponent implements OnInit {
|
export class FullItemPageComponent extends ItemPageComponent implements OnInit {
|
||||||
|
|
||||||
|
@@ -1,26 +1,27 @@
|
|||||||
<div class="item-page" *ngIf="item.hasSucceeded | async">
|
<div class="item-page" *ngIf="item.hasSucceeded | async" @fadeInOut>
|
||||||
<ds-item-page-title-field [item]="item.payload | async"></ds-item-page-title-field>
|
<div *ngIf="item.payload | async; let itemPayload">
|
||||||
|
<ds-item-page-title-field [item]="itemPayload"></ds-item-page-title-field>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 col-md-4">
|
<div class="col-xs-12 col-md-4">
|
||||||
<ds-metadata-field-wrapper>
|
<ds-metadata-field-wrapper>
|
||||||
<ds-thumbnail [thumbnail]="thumbnail | async"></ds-thumbnail>
|
<ds-thumbnail [thumbnail]="thumbnail | async"></ds-thumbnail>
|
||||||
</ds-metadata-field-wrapper>
|
</ds-metadata-field-wrapper>
|
||||||
<ds-item-page-file-section [item]="item.payload | async"></ds-item-page-file-section>
|
<ds-item-page-file-section [item]="itemPayload"></ds-item-page-file-section>
|
||||||
<ds-item-page-date-field [item]="item.payload | async"></ds-item-page-date-field>
|
<ds-item-page-date-field [item]="itemPayload"></ds-item-page-date-field>
|
||||||
<ds-item-page-author-field [item]="item.payload | async"></ds-item-page-author-field>
|
<ds-item-page-author-field [item]="itemPayload"></ds-item-page-author-field>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-md-6">
|
||||||
|
<ds-item-page-abstract-field [item]="itemPayload"></ds-item-page-abstract-field>
|
||||||
|
<ds-item-page-uri-field [item]="itemPayload"></ds-item-page-uri-field>
|
||||||
|
<ds-item-page-collections [item]="itemPayload"></ds-item-page-collections>
|
||||||
|
<div>
|
||||||
|
<a class="btn btn-outline-primary" [routerLink]="['/items/' + itemPayload.id + '/full']">
|
||||||
|
{{"item.page.link.full" | translate}}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-6">
|
</div>
|
||||||
<ds-item-page-abstract-field
|
|
||||||
[item]="item.payload | async"></ds-item-page-abstract-field>
|
|
||||||
<ds-item-page-uri-field [item]="item.payload | async"></ds-item-page-uri-field>
|
|
||||||
<ds-item-page-collections [item]="item.payload | async"></ds-item-page-collections>
|
|
||||||
<div>
|
|
||||||
<a class="btn btn-outline-primary" [routerLink]="['/items/' + (item.payload | async)?.id + '/full']">
|
|
||||||
{{"item.page.link.full" | translate}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ds-error *ngIf="item.hasFailed | async" message="{{'error.item' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="item.isLoading | async" message="{{'loading.item' | translate}}"></ds-loading>
|
||||||
|
@@ -1,12 +1,15 @@
|
|||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable } from 'rxjs/Observable';
|
|
||||||
|
|
||||||
import { Item } from '../../core/shared/item.model';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { ItemDataService } from '../../core/data/item-data.service';
|
import { ItemDataService } from '../../core/data/item-data.service';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Bitstream } from '../../core/shared/bitstream.model';
|
import { Bitstream } from '../../core/shared/bitstream.model';
|
||||||
|
|
||||||
|
import { Item } from '../../core/shared/item.model';
|
||||||
|
|
||||||
|
import { fadeInOut } from '../../shared/animations/fade';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
* The route parameter 'id' is used to request the item it represents.
|
* The route parameter 'id' is used to request the item it represents.
|
||||||
@@ -16,7 +19,8 @@ import { Bitstream } from '../../core/shared/bitstream.model';
|
|||||||
selector: 'ds-item-page',
|
selector: 'ds-item-page',
|
||||||
styleUrls: ['./item-page.component.scss'],
|
styleUrls: ['./item-page.component.scss'],
|
||||||
templateUrl: './item-page.component.html',
|
templateUrl: './item-page.component.html',
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
animations: [fadeInOut]
|
||||||
})
|
})
|
||||||
export class ItemPageComponent implements OnInit {
|
export class ItemPageComponent implements OnInit {
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ import { SearchPageComponent } from './search-page.component';
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'search', component: SearchPageComponent }
|
{ path: '', component: SearchPageComponent }
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
9
src/app/+search-page/search-page.component.html
Normal file
9
src/app/+search-page/search-page.component.html
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<div class="search-page">
|
||||||
|
<ds-search-form
|
||||||
|
[query]="query"
|
||||||
|
[scope]="scopeObject?.payload | async"
|
||||||
|
[currentParams]="currentParams"
|
||||||
|
[scopes]="scopeList?.payload">
|
||||||
|
</ds-search-form>
|
||||||
|
<ds-search-results [searchResults]="results" [searchConfig]="searchOptions"></ds-search-results>
|
||||||
|
</div>
|
110
src/app/+search-page/search-page.component.spec.ts
Normal file
110
src/app/+search-page/search-page.component.spec.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { CommunityDataService } from '../core/data/community-data.service';
|
||||||
|
import { SearchPageComponent } from './search-page.component';
|
||||||
|
import { SearchService } from './search-service/search.service';
|
||||||
|
import { Community } from '../core/shared/community.model';
|
||||||
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
|
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||||
|
|
||||||
|
describe('SearchPageComponent', () => {
|
||||||
|
let comp: SearchPageComponent;
|
||||||
|
let fixture: ComponentFixture<SearchPageComponent>;
|
||||||
|
let searchServiceObject: SearchService;
|
||||||
|
const mockResults = ['test', 'data'];
|
||||||
|
const searchServiceStub = {
|
||||||
|
search: () => mockResults
|
||||||
|
};
|
||||||
|
const queryParam = 'test query';
|
||||||
|
const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
|
||||||
|
const activatedRouteStub = {
|
||||||
|
queryParams: Observable.of({
|
||||||
|
query: queryParam,
|
||||||
|
scope: scopeParam
|
||||||
|
})
|
||||||
|
};
|
||||||
|
const mockCommunityList = [];
|
||||||
|
const communityDataServiceStub = {
|
||||||
|
findAll: () => mockCommunityList,
|
||||||
|
findById: () => new Community()
|
||||||
|
};
|
||||||
|
|
||||||
|
class RouterStub {
|
||||||
|
navigateByUrl(url: string) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
// imports: [ SearchPageModule ],
|
||||||
|
declarations: [SearchPageComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: SearchService, useValue: searchServiceStub },
|
||||||
|
{ provide: ActivatedRoute, useValue: activatedRouteStub },
|
||||||
|
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
||||||
|
{ provide: Router, useClass: RouterStub }
|
||||||
|
],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SearchPageComponent);
|
||||||
|
comp = fixture.componentInstance; // SearchPageComponent test instance
|
||||||
|
fixture.detectChanges();
|
||||||
|
searchServiceObject = (comp as any).service;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the scope and query based on the route parameters', () => {
|
||||||
|
expect(comp.query).toBe(queryParam);
|
||||||
|
expect((comp as any).scope).toBe(scopeParam);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when update search results is called', () => {
|
||||||
|
let pagination;
|
||||||
|
let sort;
|
||||||
|
beforeEach(() => {
|
||||||
|
pagination = Object.assign(
|
||||||
|
{},
|
||||||
|
new PaginationComponentOptions(),
|
||||||
|
{
|
||||||
|
currentPage: 5,
|
||||||
|
pageSize: 15
|
||||||
|
}
|
||||||
|
);
|
||||||
|
sort = Object.assign({},
|
||||||
|
new SortOptions(),
|
||||||
|
{
|
||||||
|
direction: SortDirection.Ascending,
|
||||||
|
field: 'test-field'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the search function of the search service with the right parameters', () => {
|
||||||
|
spyOn(searchServiceObject, 'search').and.callThrough();
|
||||||
|
|
||||||
|
(comp as any).updateSearchResults({
|
||||||
|
pagination: pagination,
|
||||||
|
sort: sort
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(searchServiceObject.search).toHaveBeenCalledWith(queryParam, scopeParam, {
|
||||||
|
pagination: pagination,
|
||||||
|
sort: sort
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the results', () => {
|
||||||
|
spyOn(searchServiceObject, 'search').and.callThrough();
|
||||||
|
|
||||||
|
(comp as any).updateSearchResults({});
|
||||||
|
|
||||||
|
expect(comp.results as any).toBe(mockResults);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@@ -1,12 +1,12 @@
|
|||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
|
||||||
import { SearchService } from '../search/search.service';
|
import { SearchService } from './search-service/search.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
import { SearchResult } from '../search/search-result.model';
|
import { SearchResult } from './search-result.model';
|
||||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||||
import { SortOptions } from '../core/cache/models/sort-options.model';
|
import { SortOptions } from '../core/cache/models/sort-options.model';
|
||||||
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
import { SearchOptions } from '../search/search-options.model';
|
import { SearchOptions } from './search-options.model';
|
||||||
import { CommunityDataService } from '../core/data/community-data.service';
|
import { CommunityDataService } from '../core/data/community-data.service';
|
||||||
import { isNotEmpty } from '../shared/empty.util';
|
import { isNotEmpty } from '../shared/empty.util';
|
||||||
import { Community } from '../core/shared/community.model';
|
import { Community } from '../core/shared/community.model';
|
||||||
@@ -21,20 +21,25 @@ import { Community } from '../core/shared/community.model';
|
|||||||
selector: 'ds-search-page',
|
selector: 'ds-search-page',
|
||||||
styleUrls: ['./search-page.component.scss'],
|
styleUrls: ['./search-page.component.scss'],
|
||||||
templateUrl: './search-page.component.html',
|
templateUrl: './search-page.component.html',
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SearchPageComponent implements OnInit, OnDestroy {
|
export class SearchPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
private sub;
|
private sub;
|
||||||
query: string;
|
|
||||||
private scope: string;
|
private scope: string;
|
||||||
|
|
||||||
|
query: string;
|
||||||
scopeObject: RemoteData<DSpaceObject>;
|
scopeObject: RemoteData<DSpaceObject>;
|
||||||
results: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
results: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
||||||
currentParams = {};
|
currentParams = {};
|
||||||
searchOptions: SearchOptions;
|
searchOptions: SearchOptions;
|
||||||
scopeList: RemoteData<Community[]>;
|
scopeList: RemoteData<Community[]>;
|
||||||
|
|
||||||
constructor(private service: SearchService,
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private service: SearchService,
|
||||||
private communityService: CommunityDataService,) {
|
private route: ActivatedRoute,
|
||||||
|
private communityService: CommunityDataService
|
||||||
|
) {
|
||||||
this.scopeList = communityService.findAll();
|
this.scopeList = communityService.findAll();
|
||||||
// Initial pagination config
|
// Initial pagination config
|
||||||
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
const pagination: PaginationComponentOptions = new PaginationComponentOptions();
|
||||||
@@ -53,8 +58,8 @@ export class SearchPageComponent implements OnInit, OnDestroy {
|
|||||||
this.currentParams = params;
|
this.currentParams = params;
|
||||||
this.query = params.query || '';
|
this.query = params.query || '';
|
||||||
this.scope = params.scope;
|
this.scope = params.scope;
|
||||||
const page = +params.page || this.searchOptions.pagination.currentPage;
|
const page = +params.page || this.searchOptions.pagination.currentPage;
|
||||||
const pageSize = +params.pageSize || this.searchOptions.pagination.pageSize;
|
const pageSize = +params.pageSize || this.searchOptions.pagination.pageSize;
|
||||||
const sortDirection = +params.sortDirection || this.searchOptions.sort.direction;
|
const sortDirection = +params.sortDirection || this.searchOptions.sort.direction;
|
||||||
const pagination = Object.assign({},
|
const pagination = Object.assign({},
|
||||||
this.searchOptions.pagination,
|
this.searchOptions.pagination,
|
||||||
@@ -80,7 +85,6 @@ export class SearchPageComponent implements OnInit, OnDestroy {
|
|||||||
private updateSearchResults(searchOptions) {
|
private updateSearchResults(searchOptions) {
|
||||||
// Resolve search results
|
// Resolve search results
|
||||||
this.results = this.service.search(this.query, this.scope, searchOptions);
|
this.results = this.service.search(this.query, this.scope, searchOptions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
@@ -7,11 +7,11 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||||||
import { SharedModule } from '../shared/shared.module';
|
import { SharedModule } from '../shared/shared.module';
|
||||||
import { SearchPageRoutingModule } from './search-page-routing.module';
|
import { SearchPageRoutingModule } from './search-page-routing.module';
|
||||||
import { SearchPageComponent } from './search-page.component';
|
import { SearchPageComponent } from './search-page.component';
|
||||||
import { SearchResultsComponent } from './search-results/search-results.compontent';
|
import { SearchResultsComponent } from './search-results/search-results.component';
|
||||||
import { SearchModule } from '../search/search.module';
|
|
||||||
import { ItemSearchResultListElementComponent } from '../object-list/search-result-list-element/item-search-result/item-search-result-list-element.component';
|
import { ItemSearchResultListElementComponent } from '../object-list/search-result-list-element/item-search-result/item-search-result-list-element.component';
|
||||||
import { CollectionSearchResultListElementComponent } from '../object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component';
|
import { CollectionSearchResultListElementComponent } from '../object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component';
|
||||||
import { CommunitySearchResultListElementComponent } from '../object-list/search-result-list-element/community-search-result/community-search-result-list-element.component';
|
import { CommunitySearchResultListElementComponent } from '../object-list/search-result-list-element/community-search-result/community-search-result-list-element.component';
|
||||||
|
import { SearchService } from './search-service/search.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -19,8 +19,7 @@ import { CommunitySearchResultListElementComponent } from '../object-list/search
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
SharedModule,
|
SharedModule
|
||||||
SearchModule
|
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
SearchPageComponent,
|
SearchPageComponent,
|
||||||
@@ -29,6 +28,9 @@ import { CommunitySearchResultListElementComponent } from '../object-list/search
|
|||||||
CollectionSearchResultListElementComponent,
|
CollectionSearchResultListElementComponent,
|
||||||
CommunitySearchResultListElementComponent
|
CommunitySearchResultListElementComponent
|
||||||
],
|
],
|
||||||
|
providers: [
|
||||||
|
SearchService
|
||||||
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
ItemSearchResultListElementComponent,
|
ItemSearchResultListElementComponent,
|
||||||
CollectionSearchResultListElementComponent,
|
CollectionSearchResultListElementComponent,
|
@@ -0,0 +1,7 @@
|
|||||||
|
<h2 *ngIf="(searchResults.payload | async)?.length > 0">{{ 'search.results.title' | translate }}</h2>
|
||||||
|
<ds-object-list
|
||||||
|
[config]="searchConfig.pagination"
|
||||||
|
[sortConfig]="searchConfig.sort"
|
||||||
|
[objects]="searchResults"
|
||||||
|
[hideGear]="false">
|
||||||
|
</ds-object-list>
|
@@ -0,0 +1,142 @@
|
|||||||
|
import { ComponentFixture, TestBed, async, tick, fakeAsync } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { SearchResultsComponent } from './search-results.component';
|
||||||
|
|
||||||
|
describe('SearchResultsComponent', () => {
|
||||||
|
let comp: SearchResultsComponent;
|
||||||
|
let fixture: ComponentFixture<SearchResultsComponent>;
|
||||||
|
let heading: DebugElement;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot()],
|
||||||
|
declarations: [SearchResultsComponent],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SearchResultsComponent);
|
||||||
|
comp = fixture.componentInstance; // SearchFormComponent test instance
|
||||||
|
heading = fixture.debugElement.query(By.css('heading'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display heading when results are not empty', fakeAsync(() => {
|
||||||
|
(comp as any).searchResults = 'test';
|
||||||
|
(comp as any).searchConfig = {pagination: ''};
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
expect(heading).toBeDefined();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should not display heading when results is empty', () => {
|
||||||
|
expect(heading).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export const objects = [
|
||||||
|
Object.assign(new Community(), {
|
||||||
|
handle: '10673/11',
|
||||||
|
logo: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/10b636d0-7890-4968-bcd6-0d83bf4e2b42',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collections: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: '1506937433727',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
type: ResourceType.Community,
|
||||||
|
name: 'OR2017 - Demonstration',
|
||||||
|
metadata: [
|
||||||
|
{
|
||||||
|
key: 'dc.description',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.abstract',
|
||||||
|
language: null,
|
||||||
|
value: 'This is a test community to hold content for the OR2017 demostration'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.tableofcontents',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.rights',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.title',
|
||||||
|
language: null,
|
||||||
|
value: 'OR2017 - Demonstration'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Object.assign(new Community(),
|
||||||
|
{
|
||||||
|
handle: '10673/1',
|
||||||
|
logo: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/f446c17d-6d51-45ea-a610-d58a73642d40',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collections: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: '1506937433727',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
id: '9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
type: ResourceType.Community,
|
||||||
|
name: 'Sample Community',
|
||||||
|
metadata: [
|
||||||
|
{
|
||||||
|
key: 'dc.description',
|
||||||
|
language: null,
|
||||||
|
value: '<p>This is the introductory text for the <em>Sample Community</em> on the DSpace Demonstration Site. It is editable by System or Community Administrators (of this Community).</p>\r\n<p><strong>DSpace Communities may contain one or more Sub-Communities or Collections (of Items).</strong></p>\r\n<p>This particular Community has its own logo (the <a href=\'http://www.duraspace.org/\'>DuraSpace</a> logo).</p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.abstract',
|
||||||
|
language: null,
|
||||||
|
value: 'This is a sample top-level community'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.tableofcontents',
|
||||||
|
language: null,
|
||||||
|
value: '<p>This is the <em>news section</em> for this <em>Sample Community</em>. System or Community Administrators (of this Community) can edit this News field.</p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.rights',
|
||||||
|
language: null,
|
||||||
|
value: '<p><em>If this Community had special copyright text to display, it would be displayed here.</em></p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.title',
|
||||||
|
language: null,
|
||||||
|
value: 'Sample Community'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
@@ -1,20 +1,18 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { SearchResult } from '../../search/search-result.model';
|
import { SearchResult } from '../search-result.model';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { SearchOptions } from '../../search/search-options.model';
|
import { SearchOptions } from '../search-options.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
* The route parameter 'id' is used to request the item it represents.
|
* The route parameter 'id' is used to request the item it represents.
|
||||||
* All fields of the item that should be displayed, are defined in its template.
|
* All fields of the item that should be displayed, are defined in its template.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-results',
|
selector: 'ds-search-results',
|
||||||
templateUrl: './search-results.component.html',
|
templateUrl: './search-results.component.html',
|
||||||
})
|
})
|
||||||
|
|
||||||
export class SearchResultsComponent {
|
export class SearchResultsComponent {
|
||||||
@Input() searchResults: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
@Input() searchResults: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
||||||
@Input() searchConfig: SearchOptions;
|
@Input() searchConfig: SearchOptions;
|
7
src/app/+search-page/search-service/facet-value.model.ts
Normal file
7
src/app/+search-page/search-service/facet-value.model.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
export class FacetValue {
|
||||||
|
|
||||||
|
value: string;
|
||||||
|
count: number;
|
||||||
|
search: string;
|
||||||
|
}
|
5
src/app/+search-page/search-service/filter-type.model.ts
Normal file
5
src/app/+search-page/search-service/filter-type.model.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum FilterType {
|
||||||
|
text,
|
||||||
|
range,
|
||||||
|
hierarchy
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
import { FilterType } from './filter-type.model';
|
||||||
|
|
||||||
|
export class SearchFilterConfig {
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
type: FilterType;
|
||||||
|
hasFacets: boolean;
|
||||||
|
isOpenByDefault: boolean;
|
||||||
|
/**
|
||||||
|
* Name of this configuration that can be used in a url
|
||||||
|
* @returns Parameter name
|
||||||
|
*/
|
||||||
|
get paramName(): string {
|
||||||
|
return 'f.' + this.name;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,15 +1,18 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { RemoteData } from '../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { SearchResult } from './search-result.model';
|
import { SearchResult } from '../search-result.model';
|
||||||
import { ItemDataService } from '../core/data/item-data.service';
|
import { ItemDataService } from '../../core/data/item-data.service';
|
||||||
import { PageInfo } from '../core/shared/page-info.model';
|
import { PageInfo } from '../../core/shared/page-info.model';
|
||||||
import { DSpaceObject } from '../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { SearchOptions } from './search-options.model';
|
import { SearchOptions } from '../search-options.model';
|
||||||
import { hasValue, isNotEmpty } from '../shared/empty.util';
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { Metadatum } from '../core/shared/metadatum.model';
|
import { Metadatum } from '../../core/shared/metadatum.model';
|
||||||
import { Item } from '../core/shared/item.model';
|
import { Item } from '../../core/shared/item.model';
|
||||||
import { ItemSearchResult } from '../object-list/search-result-list-element/item-search-result/item-search-result.model';
|
import { ItemSearchResult } from '../../object-list/search-result-list-element/item-search-result/item-search-result.model';
|
||||||
|
import { SearchFilterConfig } from './search-filter-config.model';
|
||||||
|
import { FilterType } from './filter-type.model';
|
||||||
|
import { FacetValue } from './facet-value.model';
|
||||||
|
|
||||||
function shuffle(array: any[]) {
|
function shuffle(array: any[]) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
@@ -42,6 +45,37 @@ export class SearchService {
|
|||||||
'<em>The QSAR DataBank (QsarDB) repository</em>',
|
'<em>The QSAR DataBank (QsarDB) repository</em>',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
config: SearchFilterConfig[] = [
|
||||||
|
Object.assign(new SearchFilterConfig(),
|
||||||
|
{
|
||||||
|
name: 'scope',
|
||||||
|
type: FilterType.hierarchy,
|
||||||
|
hasFacets: true,
|
||||||
|
isOpenByDefault: true
|
||||||
|
}),
|
||||||
|
Object.assign(new SearchFilterConfig(),
|
||||||
|
{
|
||||||
|
name: 'author',
|
||||||
|
type: FilterType.text,
|
||||||
|
hasFacets: true,
|
||||||
|
isOpenByDefault: false
|
||||||
|
}),
|
||||||
|
Object.assign(new SearchFilterConfig(),
|
||||||
|
{
|
||||||
|
name: 'date',
|
||||||
|
type: FilterType.range,
|
||||||
|
hasFacets: true,
|
||||||
|
isOpenByDefault: false
|
||||||
|
}),
|
||||||
|
Object.assign(new SearchFilterConfig(),
|
||||||
|
{
|
||||||
|
name: 'subject',
|
||||||
|
type: FilterType.text,
|
||||||
|
hasFacets: false,
|
||||||
|
isOpenByDefault: false
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
constructor(private itemDataService: ItemDataService) {
|
constructor(private itemDataService: ItemDataService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,8 +97,7 @@ export class SearchService {
|
|||||||
if (isNotEmpty(searchOptions) && hasValue(searchOptions.sort.field)) {
|
if (isNotEmpty(searchOptions) && hasValue(searchOptions.sort.field)) {
|
||||||
self += `&sortField=${searchOptions.sort.field}`;
|
self += `&sortField=${searchOptions.sort.field}`;
|
||||||
}
|
}
|
||||||
const requestPending = Observable.of(false);
|
|
||||||
const responsePending = Observable.of(false);
|
|
||||||
const errorMessage = Observable.of(undefined);
|
const errorMessage = Observable.of(undefined);
|
||||||
const statusCode = Observable.of('200');
|
const statusCode = Observable.of('200');
|
||||||
const returningPageInfo = new PageInfo();
|
const returningPageInfo = new PageInfo();
|
||||||
@@ -84,8 +117,8 @@ export class SearchService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const pageInfo = itemsRD.pageInfo.map((info: PageInfo) => {
|
const pageInfo = itemsRD.pageInfo.map((info: PageInfo) => {
|
||||||
info.totalElements = info.totalElements > 20 ? 20 : info.totalElements;
|
const totalElements = info.totalElements > 20 ? 20 : info.totalElements;
|
||||||
return info;
|
return Object.assign({}, info, { totalElements: totalElements });
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload = itemsRD.payload.map((items: Item[]) => {
|
const payload = itemsRD.payload.map((items: Item[]) => {
|
||||||
@@ -103,8 +136,8 @@ export class SearchService {
|
|||||||
|
|
||||||
return new RemoteData(
|
return new RemoteData(
|
||||||
Observable.of(self),
|
Observable.of(self),
|
||||||
requestPending,
|
itemsRD.isRequestPending,
|
||||||
responsePending,
|
itemsRD.isResponsePending,
|
||||||
itemsRD.hasSucceeded,
|
itemsRD.hasSucceeded,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
statusCode,
|
statusCode,
|
||||||
@@ -112,4 +145,51 @@ export class SearchService {
|
|||||||
payload
|
payload
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getConfig(): RemoteData<SearchFilterConfig[]> {
|
||||||
|
const requestPending = Observable.of(false);
|
||||||
|
const responsePending = Observable.of(false);
|
||||||
|
const isSuccessful = Observable.of(true);
|
||||||
|
const errorMessage = Observable.of(undefined);
|
||||||
|
const statusCode = Observable.of('200');
|
||||||
|
const returningPageInfo = Observable.of(new PageInfo());
|
||||||
|
return new RemoteData(
|
||||||
|
Observable.of('https://dspace7.4science.it/dspace-spring-rest/api/search'),
|
||||||
|
requestPending,
|
||||||
|
responsePending,
|
||||||
|
isSuccessful,
|
||||||
|
errorMessage,
|
||||||
|
statusCode,
|
||||||
|
returningPageInfo,
|
||||||
|
Observable.of(this.config)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFacetValuesFor(searchFilterConfigName: string): RemoteData<FacetValue[]> {
|
||||||
|
const values: FacetValue[] = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const value = searchFilterConfigName + ' ' + (i + 1);
|
||||||
|
values.push({
|
||||||
|
value: value,
|
||||||
|
count: Math.floor(Math.random() * 20) + 20 * (5 - i), // make sure first results have the highest (random) count
|
||||||
|
search: 'https://dspace7.4science.it/dspace-spring-rest/api/search?f.' + searchFilterConfigName + '=' + encodeURI(value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const requestPending = Observable.of(false);
|
||||||
|
const responsePending = Observable.of(false);
|
||||||
|
const isSuccessful = Observable.of(true);
|
||||||
|
const errorMessage = Observable.of(undefined);
|
||||||
|
const statusCode = Observable.of('200');
|
||||||
|
const returningPageInfo = Observable.of(new PageInfo());
|
||||||
|
return new RemoteData(
|
||||||
|
Observable.of('https://dspace7.4science.it/dspace-spring-rest/api/search'),
|
||||||
|
requestPending,
|
||||||
|
responsePending,
|
||||||
|
isSuccessful,
|
||||||
|
errorMessage,
|
||||||
|
statusCode,
|
||||||
|
returningPageInfo,
|
||||||
|
Observable.of(values)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -7,10 +7,11 @@ import { PageNotFoundComponent } from './pagenotfound/pagenotfound.component';
|
|||||||
imports: [
|
imports: [
|
||||||
RouterModule.forRoot([
|
RouterModule.forRoot([
|
||||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||||
{ path: 'home', loadChildren: './+home/home.module#HomeModule' },
|
{ path: 'home', loadChildren: './+home-page/home-page.module#HomePageModule' },
|
||||||
{ path: 'communities', loadChildren: './+community-page/community-page.module#CommunityPageModule' },
|
{ path: 'communities', loadChildren: './+community-page/community-page.module#CommunityPageModule' },
|
||||||
{ path: 'collections', loadChildren: './+collection-page/collection-page.module#CollectionPageModule' },
|
{ path: 'collections', loadChildren: './+collection-page/collection-page.module#CollectionPageModule' },
|
||||||
{ path: 'items', loadChildren: './+item-page/item-page.module#ItemPageModule' },
|
{ path: 'items', loadChildren: './+item-page/item-page.module#ItemPageModule' },
|
||||||
|
{ path: 'search', loadChildren: './+search-page/search-page.module#SearchPageModule' },
|
||||||
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
||||||
import { HttpModule } from '@angular/http';
|
import { HttpModule } from '@angular/http';
|
||||||
import { FormsModule } from '@angular/forms';
|
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
|
@@ -49,12 +49,20 @@ export class RemoteDataBuildService {
|
|||||||
requestHrefObs.flatMap((requestHref) => this.responseCache.get(requestHref)).filter((entry) => hasValue(entry))
|
requestHrefObs.flatMap((requestHref) => this.responseCache.get(requestHref)).filter((entry) => hasValue(entry))
|
||||||
);
|
);
|
||||||
|
|
||||||
const requestPending = requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged();
|
const requestPending = requestObs
|
||||||
|
.map((entry: RequestEntry) => entry.requestPending)
|
||||||
|
.startWith(true)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const responsePending = requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged();
|
const responsePending = requestObs
|
||||||
|
.map((entry: RequestEntry) => entry.responsePending)
|
||||||
|
.startWith(false)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const isSuccessFul = responseCacheObs
|
const isSuccessFul = responseCacheObs
|
||||||
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged();
|
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
|
.startWith(false)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const errorMessage = responseCacheObs
|
const errorMessage = responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
||||||
@@ -133,12 +141,20 @@ export class RemoteDataBuildService {
|
|||||||
const responseCacheObs = hrefObs.flatMap((href: string) => this.responseCache.get(href))
|
const responseCacheObs = hrefObs.flatMap((href: string) => this.responseCache.get(href))
|
||||||
.filter((entry) => hasValue(entry));
|
.filter((entry) => hasValue(entry));
|
||||||
|
|
||||||
const requestPending = requestObs.map((entry: RequestEntry) => entry.requestPending).distinctUntilChanged();
|
const requestPending = requestObs
|
||||||
|
.map((entry: RequestEntry) => entry.requestPending)
|
||||||
|
.startWith(true)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const responsePending = requestObs.map((entry: RequestEntry) => entry.responsePending).distinctUntilChanged();
|
const responsePending = requestObs
|
||||||
|
.map((entry: RequestEntry) => entry.responsePending)
|
||||||
|
.startWith(false)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const isSuccessFul = responseCacheObs
|
const isSuccessFul = responseCacheObs
|
||||||
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful).distinctUntilChanged();
|
.map((entry: ResponseCacheEntry) => entry.response.isSuccessful)
|
||||||
|
.startWith(false)
|
||||||
|
.distinctUntilChanged();
|
||||||
|
|
||||||
const errorMessage = responseCacheObs
|
const errorMessage = responseCacheObs
|
||||||
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
.filter((entry: ResponseCacheEntry) => !entry.response.isSuccessful)
|
||||||
|
@@ -18,7 +18,7 @@ export abstract class DataService<TNormalized extends CacheableObject, TDomain>
|
|||||||
protected abstract rdbService: RemoteDataBuildService;
|
protected abstract rdbService: RemoteDataBuildService;
|
||||||
protected abstract store: Store<CoreState>;
|
protected abstract store: Store<CoreState>;
|
||||||
protected abstract linkName: string;
|
protected abstract linkName: string;
|
||||||
protected abstract EnvConfig: GlobalConfig
|
protected abstract EnvConfig: GlobalConfig;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private normalizedResourceType: GenericConstructor<TNormalized>,
|
private normalizedResourceType: GenericConstructor<TNormalized>,
|
||||||
|
@@ -1,18 +1,20 @@
|
|||||||
<ds-pagination [paginationOptions]="config"
|
<ds-pagination
|
||||||
[pageInfoState]="pageInfo"
|
[paginationOptions]="config"
|
||||||
[collectionSize]="(pageInfo | async)?.totalElements"
|
[pageInfoState]="pageInfo"
|
||||||
[sortOptions]="sortConfig"
|
[collectionSize]="(pageInfo | async)?.totalElements"
|
||||||
[hideGear]="hideGear"
|
[sortOptions]="sortConfig"
|
||||||
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
[hideGear]="hideGear"
|
||||||
(pageChange)="onPageChange($event)"
|
[hidePagerWhenSinglePage]="hidePagerWhenSinglePage"
|
||||||
(pageSizeChange)="onPageSizeChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(sortDirectionChange)="onSortDirectionChange($event)"
|
(pageSizeChange)="onPageSizeChange($event)"
|
||||||
(sortFieldChange)="onSortDirectionChange($event)"
|
(sortDirectionChange)="onSortDirectionChange($event)"
|
||||||
(paginationChange)="onPaginationChange($event)">
|
(sortFieldChange)="onSortDirectionChange($event)"
|
||||||
<ul *ngIf="objects.hasSucceeded | async"> <!--class="list-unstyled"-->
|
(paginationChange)="onPaginationChange($event)">
|
||||||
<li *ngFor="let object of (objects.payload | async) | paginate: { itemsPerPage: (pageInfo | async)?.elementsPerPage, currentPage: (pageInfo | async)?.currentPage, totalItems: (pageInfo | async)?.totalElements }">
|
<ul *ngIf="objects.hasSucceeded | async" @fadeIn> <!--class="list-unstyled"-->
|
||||||
<ds-wrapper-list-element [object]="object"></ds-wrapper-list-element>
|
<li *ngFor="let object of (objects.payload | async) | paginate: { itemsPerPage: (pageInfo | async)?.elementsPerPage, currentPage: (pageInfo | async)?.currentPage, totalItems: (pageInfo | async)?.totalElements }">
|
||||||
</li>
|
<ds-wrapper-list-element [object]="object"></ds-wrapper-list-element>
|
||||||
</ul>
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ds-error *ngIf="objects.hasFailed | async" message="{{'error.objects' | translate}}"></ds-error>
|
||||||
|
<ds-loading *ngIf="objects.isLoading | async" message="{{'loading.objects' | translate}}"></ds-loading>
|
||||||
</ds-pagination>
|
</ds-pagination>
|
||||||
|
@@ -1,29 +1,35 @@
|
|||||||
import {
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
ViewEncapsulation,
|
OnChanges,
|
||||||
ChangeDetectionStrategy,
|
|
||||||
OnInit,
|
OnInit,
|
||||||
Output, SimpleChanges, OnChanges, ChangeDetectorRef, DoCheck
|
Output,
|
||||||
|
SimpleChanges,
|
||||||
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model';
|
||||||
import { PageInfo } from '../../core/shared/page-info.model';
|
|
||||||
|
|
||||||
import { PaginationComponentOptions } from '../pagination/pagination-component-options.model';
|
import { RemoteData } from '../core/data/remote-data';
|
||||||
|
import { PageInfo } from '../core/shared/page-info.model';
|
||||||
|
import { ListableObject } from '../object-list/listable-object/listable-object.model';
|
||||||
|
|
||||||
import { SortOptions, SortDirection } from '../../core/cache/models/sort-options.model';
|
import { fadeIn } from '../shared/animations/fade';
|
||||||
import { ListableObject } from '../../object-list/listable-object/listable-object.model';
|
|
||||||
|
import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
changeDetection: ChangeDetectionStrategy.Default,
|
changeDetection: ChangeDetectionStrategy.Default,
|
||||||
encapsulation: ViewEncapsulation.Emulated,
|
encapsulation: ViewEncapsulation.Emulated,
|
||||||
selector: 'ds-object-list',
|
selector: 'ds-object-list',
|
||||||
styleUrls: ['../../object-list/object-list.component.scss'],
|
styleUrls: ['./object-list.component.scss'],
|
||||||
templateUrl: '../../object-list/object-list.component.html'
|
templateUrl: './object-list.component.html',
|
||||||
|
animations: [fadeIn]
|
||||||
})
|
})
|
||||||
export class ObjectListComponent implements OnChanges, OnInit {
|
export class ObjectListComponent implements OnChanges, OnInit {
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
import { SearchResult } from '../../../search/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
import { Collection } from '../../../core/shared/collection.model';
|
import { Collection } from '../../../core/shared/collection.model';
|
||||||
|
|
||||||
export class CollectionSearchResult extends SearchResult<Collection> {
|
export class CollectionSearchResult extends SearchResult<Collection> {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { SearchResult } from '../../../search/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
import { Community } from '../../../core/shared/community.model';
|
import { Community } from '../../../core/shared/community.model';
|
||||||
|
|
||||||
export class CommunitySearchResult extends SearchResult<Community> {
|
export class CommunitySearchResult extends SearchResult<Community> {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { SearchResult } from '../../../search/search-result.model';
|
import { SearchResult } from '../../../+search-page/search-result.model';
|
||||||
import { Item } from '../../../core/shared/item.model';
|
import { Item } from '../../../core/shared/item.model';
|
||||||
|
|
||||||
export class ItemSearchResult extends SearchResult<Item> {
|
export class ItemSearchResult extends SearchResult<Item> {
|
||||||
|
@@ -2,7 +2,7 @@ import { Component, Inject } from '@angular/core';
|
|||||||
|
|
||||||
import { ObjectListElementComponent } from '../object-list-element/object-list-element.component';
|
import { ObjectListElementComponent } from '../object-list-element/object-list-element.component';
|
||||||
import { ListableObject } from '../listable-object/listable-object.model';
|
import { ListableObject } from '../listable-object/listable-object.model';
|
||||||
import { SearchResult } from '../../search/search-result.model';
|
import { SearchResult } from '../../+search-page/search-result.model';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { Metadatum } from '../../core/shared/metadatum.model';
|
import { Metadatum } from '../../core/shared/metadatum.model';
|
||||||
import { isEmpty, hasNoValue } from '../../shared/empty.util';
|
import { isEmpty, hasNoValue } from '../../shared/empty.util';
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
<div class="search-page">
|
|
||||||
<ds-search-form [query]="query" [scope]="scopeObject?.payload | async" [currentParams]="currentParams" [scopes]="scopeList?.payload"></ds-search-form>
|
|
||||||
<ds-search-results [searchResults]="results" [searchConfig]="searchOptions"></ds-search-results>
|
|
||||||
</div>
|
|
@@ -1,3 +0,0 @@
|
|||||||
<h2 *ngIf="(searchResults.payload | async)?.length > 0">{{ 'search.results.title' | translate }}</h2>
|
|
||||||
<ds-object-list [config]="searchConfig.pagination" [sortConfig]="searchConfig.sort"
|
|
||||||
[objects]="searchResults" [hideGear]="false"></ds-object-list>
|
|
@@ -1,17 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { CoreModule } from '../core/core.module';
|
|
||||||
import { SearchService } from './search.service';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [
|
|
||||||
|
|
||||||
],
|
|
||||||
declarations: [
|
|
||||||
],
|
|
||||||
exports: [
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
SearchService
|
|
||||||
]
|
|
||||||
})
|
|
||||||
export class SearchModule { }
|
|
24
src/app/shared/animations/fade.ts
Normal file
24
src/app/shared/animations/fade.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { animate, style, transition, trigger } from '@angular/animations';
|
||||||
|
|
||||||
|
const fadeEnter = transition(':enter', [
|
||||||
|
style({ opacity: 0 }),
|
||||||
|
animate(300, style({ opacity: 1 }))
|
||||||
|
]);
|
||||||
|
|
||||||
|
const fadeLeave = transition(':leave', [
|
||||||
|
style({ opacity: 1 }),
|
||||||
|
animate(400, style({ opacity: 0 }))
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const fadeIn = trigger('fadeIn', [
|
||||||
|
fadeEnter
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const fadeOut = trigger('fadeOut', [
|
||||||
|
fadeLeave
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const fadeInOut = trigger('fadeInOut', [
|
||||||
|
fadeEnter,
|
||||||
|
fadeLeave
|
||||||
|
]);
|
3
src/app/shared/error/error.component.html
Normal file
3
src/app/shared/error/error.component.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
<label>{{ message }}</label>
|
||||||
|
</div>
|
0
src/app/shared/error/error.component.scss
Normal file
0
src/app/shared/error/error.component.scss
Normal file
58
src/app/shared/error/error.component.spec.ts
Normal file
58
src/app/shared/error/error.component.spec.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { MockTranslateLoader } from '../testing/mock-translate-loader';
|
||||||
|
|
||||||
|
import { ErrorComponent } from './error.component';
|
||||||
|
|
||||||
|
describe('ErrorComponent (inline template)', () => {
|
||||||
|
|
||||||
|
let comp: ErrorComponent;
|
||||||
|
let fixture: ComponentFixture<ErrorComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
let el: HTMLElement;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useClass: MockTranslateLoader
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
declarations: [ ErrorComponent ], // declare the test component
|
||||||
|
providers: [ TranslateService ]
|
||||||
|
}).compileComponents(); // compile template and css
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ErrorComponent);
|
||||||
|
|
||||||
|
comp = fixture.componentInstance; // ErrorComponent test instance
|
||||||
|
|
||||||
|
// query for the message <label> by CSS element selector
|
||||||
|
de = fixture.debugElement.query(By.css('label'));
|
||||||
|
el = de.nativeElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(comp).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display default message', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(el.textContent).toContain(comp.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display input message', () => {
|
||||||
|
comp.message = 'Test Message';
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(el.textContent).toContain('Test Message');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
36
src/app/shared/error/error.component.ts
Normal file
36
src/app/shared/error/error.component.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-error',
|
||||||
|
styleUrls: ['./error.component.scss'],
|
||||||
|
templateUrl: './error.component.html'
|
||||||
|
})
|
||||||
|
export class ErrorComponent {
|
||||||
|
|
||||||
|
@Input() message = 'Error...';
|
||||||
|
|
||||||
|
private subscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private translate: TranslateService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.message === undefined) {
|
||||||
|
this.subscription = this.translate.get('error.default').subscribe((message: string) => {
|
||||||
|
this.message = message;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.subscription !== undefined) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
15
src/app/shared/loading/loading.component.html
Normal file
15
src/app/shared/loading/loading.component.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<div>
|
||||||
|
<label>{{ message }}</label>
|
||||||
|
<div class="loader">
|
||||||
|
<span class="l-1"></span>
|
||||||
|
<span class="l-2"></span>
|
||||||
|
<span class="l-3"></span>
|
||||||
|
<span class="l-4"></span>
|
||||||
|
<span class="l-5"></span>
|
||||||
|
<span class="l-6"></span>
|
||||||
|
<span class="l-7"></span>
|
||||||
|
<span class="l-8"></span>
|
||||||
|
<span class="l-9"></span>
|
||||||
|
<span class="l-10"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
73
src/app/shared/loading/loading.component.scss
Normal file
73
src/app/shared/loading/loading.component.scss
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
.loader {
|
||||||
|
margin: 0px 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
span[class*="l-"] {
|
||||||
|
height: 4px;
|
||||||
|
width: 4px;
|
||||||
|
background: #000;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 12px 2px;
|
||||||
|
|
||||||
|
border-radius: 100%;
|
||||||
|
-webkit-border-radius: 100%;
|
||||||
|
-moz-border-radius: 100%;
|
||||||
|
|
||||||
|
-webkit-animation: loader 2s infinite;
|
||||||
|
-webkit-animation-timing-function: cubic-bezier(0.030, 0.615, 0.995, 0.415);
|
||||||
|
-webkit-animation-fill-mode: both;
|
||||||
|
-moz-animation: loader 2s infinite;
|
||||||
|
-moz-animation-timing-function: cubic-bezier(0.030, 0.615, 0.995, 0.415);
|
||||||
|
-moz-animation-fill-mode: both;
|
||||||
|
-ms-animation: loader 2s infinite;
|
||||||
|
-ms-animation-timing-function: cubic-bezier(0.030, 0.615, 0.995, 0.415);
|
||||||
|
-ms-animation-fill-mode: both;
|
||||||
|
animation: loader 2s infinite;
|
||||||
|
animation-timing-function: cubic-bezier(0.030, 0.615, 0.995, 0.415);
|
||||||
|
animation-fill-mode: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.l-1 {-webkit-animation-delay: 1s;animation-delay: 1s;-ms-animation-delay: 1s;-moz-animation-delay: 1s;}
|
||||||
|
span.l-2 {-webkit-animation-delay: 0.9s;animation-delay: 0.9s;-ms-animation-delay: 0.9s;-moz-animation-delay: 0.9s;}
|
||||||
|
span.l-3 {-webkit-animation-delay: 0.8s;animation-delay: 0.8s;-ms-animation-delay: 0.8s;-moz-animation-delay: 0.8s;}
|
||||||
|
span.l-4 {-webkit-animation-delay: 0.7s;animation-delay: 0.7s;-ms-animation-delay: 0.7s;-moz-animation-delay: 0.7s;}
|
||||||
|
span.l-5 {-webkit-animation-delay: 0.6s;animation-delay: 0.6s;-ms-animation-delay: 0.6s;-moz-animation-delay: 0.6s;}
|
||||||
|
span.l-6 {-webkit-animation-delay: 0.5s;animation-delay: 0.5s;-ms-animation-delay: 0.5s;-moz-animation-delay: 0.5s;}
|
||||||
|
span.l-7 {-webkit-animation-delay: 0.4s;animation-delay: 0.4s;-ms-animation-delay: 0.4s;-moz-animation-delay: 0.4s;}
|
||||||
|
span.l-8 {-webkit-animation-delay: 0.3s;animation-delay: 0.3s;-ms-animation-delay: 0.3s;-moz-animation-delay: 0.3s;}
|
||||||
|
span.l-9 {-webkit-animation-delay: 0.2s;animation-delay: 0.2s;-ms-animation-delay: 0.2s;-moz-animation-delay: 0.2s;}
|
||||||
|
span.l-9 {-webkit-animation-delay: 0.1s;animation-delay: 0.1s;-ms-animation-delay: 0.1s;-moz-animation-delay: 0.1s;}
|
||||||
|
span.l-10 {-webkit-animation-delay: 0s;animation-delay: 0s;-ms-animation-delay: 0s;-moz-animation-delay: 0s;}
|
||||||
|
|
||||||
|
@-webkit-keyframes loader {
|
||||||
|
0% {-webkit-transform: translateX(-30px); opacity: 0;}
|
||||||
|
25% {opacity: 1;}
|
||||||
|
50% {-webkit-transform: translateX(30px); opacity: 0;}
|
||||||
|
100% {opacity: 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes loader {
|
||||||
|
0% {-moz-transform: translateX(-30px); opacity: 0;}
|
||||||
|
25% {opacity: 1;}
|
||||||
|
50% {-moz-transform: translateX(30px); opacity: 0;}
|
||||||
|
100% {opacity: 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-keyframes loader {
|
||||||
|
0% {-transform: translateX(-30px); opacity: 0;}
|
||||||
|
25% {opacity: 1;}
|
||||||
|
50% {-transform: translateX(30px); opacity: 0;}
|
||||||
|
100% {opacity: 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-ms-keyframes loader {
|
||||||
|
0% {-ms-transform: translateX(-30px); opacity: 0;}
|
||||||
|
25% {opacity: 1;}
|
||||||
|
50% {-ms-transform: translateX(30px); opacity: 0;}
|
||||||
|
100% {opacity: 0;}
|
||||||
|
}
|
58
src/app/shared/loading/loading.component.spec.ts
Normal file
58
src/app/shared/loading/loading.component.spec.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateModule, TranslateLoader, TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { MockTranslateLoader } from '../testing/mock-translate-loader';
|
||||||
|
|
||||||
|
import { LoadingComponent } from './loading.component';
|
||||||
|
|
||||||
|
describe('LoadingComponent (inline template)', () => {
|
||||||
|
|
||||||
|
let comp: LoadingComponent;
|
||||||
|
let fixture: ComponentFixture<LoadingComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
let el: HTMLElement;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useClass: MockTranslateLoader
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
declarations: [ LoadingComponent ], // declare the test component
|
||||||
|
providers: [ TranslateService ]
|
||||||
|
}).compileComponents(); // compile template and css
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(LoadingComponent);
|
||||||
|
|
||||||
|
comp = fixture.componentInstance; // LoadingComponent test instance
|
||||||
|
|
||||||
|
// query for the message <label> by CSS element selector
|
||||||
|
de = fixture.debugElement.query(By.css('label'));
|
||||||
|
el = de.nativeElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(comp).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display default message', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(el.textContent).toContain(comp.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display input message', () => {
|
||||||
|
comp.message = 'Test Message';
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(el.textContent).toContain('Test Message');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
36
src/app/shared/loading/loading.component.ts
Normal file
36
src/app/shared/loading/loading.component.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { Subscription } from 'rxjs/Subscription';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-loading',
|
||||||
|
styleUrls: ['./loading.component.scss'],
|
||||||
|
templateUrl: './loading.component.html'
|
||||||
|
})
|
||||||
|
export class LoadingComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
@Input() message: string;
|
||||||
|
|
||||||
|
private subscription: Subscription;
|
||||||
|
|
||||||
|
constructor(private translate: TranslateService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.message === undefined) {
|
||||||
|
this.subscription = this.translate.get('loading.default').subscribe((message: string) => {
|
||||||
|
this.message = message;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.subscription !== undefined) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
204
src/app/shared/search-form/search-form.component.spec.ts
Normal file
204
src/app/shared/search-form/search-form.component.spec.ts
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
import { ComponentFixture, TestBed, async, tick, fakeAsync } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
import { SearchFormComponent } from './search-form.component';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
describe('SearchFormComponent', () => {
|
||||||
|
let comp: SearchFormComponent;
|
||||||
|
let fixture: ComponentFixture<SearchFormComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
let el: HTMLElement;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [FormsModule, RouterTestingModule, TranslateModule.forRoot()],
|
||||||
|
declarations: [SearchFormComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SearchFormComponent);
|
||||||
|
comp = fixture.componentInstance; // SearchFormComponent test instance
|
||||||
|
de = fixture.debugElement.query(By.css('form'));
|
||||||
|
el = de.nativeElement;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display scopes when available with default and all scopes', () => {
|
||||||
|
comp.scopes = Observable.of(objects);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const select: HTMLElement = de.query(By.css('select')).nativeElement;
|
||||||
|
expect(select).toBeDefined();
|
||||||
|
const options: HTMLCollection = select.children;
|
||||||
|
const defOption: Element = options.item(0);
|
||||||
|
expect(defOption.getAttribute('value')).toBe('');
|
||||||
|
|
||||||
|
let index = 1;
|
||||||
|
objects.forEach((object) => {
|
||||||
|
expect(options.item(index).textContent).toBe(object.name);
|
||||||
|
expect(options.item(index).getAttribute('value')).toBe(object.uuid);
|
||||||
|
index++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display scopes when empty', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
const select = de.query(By.css('select'));
|
||||||
|
expect(select).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display set query value in input field', fakeAsync(() => {
|
||||||
|
const testString = 'This is a test query';
|
||||||
|
comp.query = testString;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
const queryInput = de.query(By.css('input')).nativeElement;
|
||||||
|
|
||||||
|
expect(queryInput.value).toBe(testString);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should select correct scope option in scope select', fakeAsync(() => {
|
||||||
|
comp.scopes = Observable.of(objects);
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const testCommunity = objects[1];
|
||||||
|
comp.scope = testCommunity;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
const scopeSelect = de.query(By.css('select')).nativeElement;
|
||||||
|
|
||||||
|
expect(scopeSelect.value).toBe(testCommunity.id);
|
||||||
|
}));
|
||||||
|
// it('should call updateSearch when clicking the submit button with correct parameters', fakeAsync(() => {
|
||||||
|
// comp.query = 'Test String'
|
||||||
|
// fixture.detectChanges();
|
||||||
|
// spyOn(comp, 'updateSearch').and.callThrough();
|
||||||
|
// fixture.detectChanges();
|
||||||
|
//
|
||||||
|
// const submit = de.query(By.css('button.search-button')).nativeElement;
|
||||||
|
// const scope = '123456';
|
||||||
|
// const query = 'test';
|
||||||
|
// const select = de.query(By.css('select')).nativeElement;
|
||||||
|
// const input = de.query(By.css('input')).nativeElement;
|
||||||
|
//
|
||||||
|
// tick();
|
||||||
|
// select.value = scope;
|
||||||
|
// input.value = query;
|
||||||
|
//
|
||||||
|
// fixture.detectChanges();
|
||||||
|
//
|
||||||
|
// submit.click();
|
||||||
|
//
|
||||||
|
// expect(comp.updateSearch).toHaveBeenCalledWith({ scope: scope, query: query });
|
||||||
|
// }));
|
||||||
|
});
|
||||||
|
|
||||||
|
export const objects = [
|
||||||
|
Object.assign(new Community(), {
|
||||||
|
handle: '10673/11',
|
||||||
|
logo: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/10b636d0-7890-4968-bcd6-0d83bf4e2b42',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collections: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: '1506937433727',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
id: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
uuid: '7669c72a-3f2a-451f-a3b9-9210e7a4c02f',
|
||||||
|
type: ResourceType.Community,
|
||||||
|
name: 'OR2017 - Demonstration',
|
||||||
|
metadata: [
|
||||||
|
{
|
||||||
|
key: 'dc.description',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.abstract',
|
||||||
|
language: null,
|
||||||
|
value: 'This is a test community to hold content for the OR2017 demostration'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.tableofcontents',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.rights',
|
||||||
|
language: null,
|
||||||
|
value: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.title',
|
||||||
|
language: null,
|
||||||
|
value: 'OR2017 - Demonstration'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
Object.assign(new Community(),
|
||||||
|
{
|
||||||
|
handle: '10673/1',
|
||||||
|
logo: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: 'https://dspace7.4science.it/dspace-spring-rest/api/core/bitstreams/f446c17d-6d51-45ea-a610-d58a73642d40',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
collections: {
|
||||||
|
self: {
|
||||||
|
_isScalar: true,
|
||||||
|
value: '1506937433727',
|
||||||
|
scheduler: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
self: 'https://dspace7.4science.it/dspace-spring-rest/api/core/communities/9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
id: '9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
uuid: '9076bd16-e69a-48d6-9e41-0238cb40d863',
|
||||||
|
type: ResourceType.Community,
|
||||||
|
name: 'Sample Community',
|
||||||
|
metadata: [
|
||||||
|
{
|
||||||
|
key: 'dc.description',
|
||||||
|
language: null,
|
||||||
|
value: '<p>This is the introductory text for the <em>Sample Community</em> on the DSpace Demonstration Site. It is editable by System or Community Administrators (of this Community).</p>\r\n<p><strong>DSpace Communities may contain one or more Sub-Communities or Collections (of Items).</strong></p>\r\n<p>This particular Community has its own logo (the <a href=\'http://www.duraspace.org/\'>DuraSpace</a> logo).</p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.abstract',
|
||||||
|
language: null,
|
||||||
|
value: 'This is a sample top-level community'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.description.tableofcontents',
|
||||||
|
language: null,
|
||||||
|
value: '<p>This is the <em>news section</em> for this <em>Sample Community</em>. System or Community Administrators (of this Community) can edit this News field.</p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.rights',
|
||||||
|
language: null,
|
||||||
|
value: '<p><em>If this Community had special copyright text to display, it would be displayed here.</em></p>'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'dc.title',
|
||||||
|
language: null,
|
||||||
|
value: 'Sample Community'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { isNotEmpty, hasValue, isEmpty } from '../empty.util';
|
import { isNotEmpty, hasValue, isEmpty } from '../empty.util';
|
||||||
@@ -13,16 +13,14 @@ import { Observable } from 'rxjs/Observable';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-form',
|
selector: 'ds-search-form',
|
||||||
styleUrls: ['./search-form.component.scss'],
|
styleUrls: ['./search-form.component.scss'],
|
||||||
templateUrl: './search-form.component.html',
|
templateUrl: './search-form.component.html'
|
||||||
})
|
})
|
||||||
export class SearchFormComponent implements OnInit, OnDestroy {
|
export class SearchFormComponent {
|
||||||
@Input() query: string;
|
@Input() query: string;
|
||||||
selectedId = '';
|
selectedId = '';
|
||||||
// Optional existing search parameters
|
// Optional existing search parameters
|
||||||
@Input() currentParams: {};
|
@Input() currentParams: {};
|
||||||
@Input() scopes: Observable<DSpaceObject[]>;
|
@Input() scopes: Observable<DSpaceObject[]>;
|
||||||
scopeOptions: string[] = [];
|
|
||||||
sub;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set scope(dso: DSpaceObject) {
|
set scope(dso: DSpaceObject) {
|
||||||
@@ -31,19 +29,6 @@ export class SearchFormComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
if (this.scopes) {
|
|
||||||
this.sub =
|
|
||||||
this.scopes
|
|
||||||
.filter((scopes: DSpaceObject[]) => isEmpty(scopes))
|
|
||||||
.subscribe((scopes: DSpaceObject[]) => {
|
|
||||||
this.scopeOptions = scopes
|
|
||||||
.map((scope: DSpaceObject) => scope.id);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private router: Router) {
|
constructor(private router: Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,9 +60,4 @@ export class SearchFormComponent implements OnInit, OnDestroy {
|
|||||||
return id1 === id2;
|
return id1 === id2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
if (this.sub) {
|
|
||||||
this.sub.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -9,24 +9,26 @@ import { TranslateModule } from '@ngx-translate/core';
|
|||||||
|
|
||||||
import { NgxPaginationModule } from 'ngx-pagination';
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
|
||||||
import { PaginationComponent } from './pagination/pagination.component';
|
import { EnumKeysPipe } from './utils/enum-keys-pipe';
|
||||||
import { FileSizePipe } from './utils/file-size-pipe';
|
import { FileSizePipe } from './utils/file-size-pipe';
|
||||||
import { ThumbnailComponent } from '../thumbnail/thumbnail.component';
|
|
||||||
import { SafeUrlPipe } from './utils/safe-url-pipe';
|
import { SafeUrlPipe } from './utils/safe-url-pipe';
|
||||||
|
import { TruncatePipe } from './utils/truncate.pipe';
|
||||||
|
|
||||||
|
import { CollectionListElementComponent } from '../object-list/collection-list-element/collection-list-element.component';
|
||||||
import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component';
|
import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component';
|
||||||
import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component';
|
import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component';
|
||||||
import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component';
|
import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component';
|
||||||
import { EnumKeysPipe } from './utils/enum-keys-pipe';
|
|
||||||
import { ObjectListComponent } from './object-list/object-list.component';
|
|
||||||
import { ObjectListElementComponent } from '../object-list/object-list-element/object-list-element.component';
|
|
||||||
import { ItemListElementComponent } from '../object-list/item-list-element/item-list-element.component';
|
|
||||||
import { CommunityListElementComponent } from '../object-list/community-list-element/community-list-element.component';
|
import { CommunityListElementComponent } from '../object-list/community-list-element/community-list-element.component';
|
||||||
import { CollectionListElementComponent } from '../object-list/collection-list-element/collection-list-element.component';
|
import { ErrorComponent } from './error/error.component';
|
||||||
import { TruncatePipe } from './utils/truncate.pipe';
|
import { LoadingComponent } from './loading/loading.component';
|
||||||
import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component';
|
import { ItemListElementComponent } from '../object-list/item-list-element/item-list-element.component';
|
||||||
|
import { ObjectListComponent } from '../object-list/object-list.component';
|
||||||
|
import { ObjectListElementComponent } from '../object-list/object-list-element/object-list-element.component';
|
||||||
|
import { PaginationComponent } from './pagination/pagination.component';
|
||||||
|
import { ThumbnailComponent } from '../thumbnail/thumbnail.component';
|
||||||
import { SearchResultListElementComponent } from '../object-list/search-result-list-element/search-result-list-element.component';
|
import { SearchResultListElementComponent } from '../object-list/search-result-list-element/search-result-list-element.component';
|
||||||
import { SearchFormComponent } from './search-form/search-form.component';
|
import { SearchFormComponent } from './search-form/search-form.component';
|
||||||
|
import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -41,30 +43,32 @@ const MODULES = [
|
|||||||
|
|
||||||
const PIPES = [
|
const PIPES = [
|
||||||
// put shared pipes here
|
// put shared pipes here
|
||||||
|
EnumKeysPipe,
|
||||||
FileSizePipe,
|
FileSizePipe,
|
||||||
SafeUrlPipe,
|
SafeUrlPipe,
|
||||||
EnumKeysPipe,
|
|
||||||
TruncatePipe
|
TruncatePipe
|
||||||
];
|
];
|
||||||
|
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
// put shared components here
|
// put shared components here
|
||||||
PaginationComponent,
|
|
||||||
ThumbnailComponent,
|
|
||||||
ComcolPageContentComponent,
|
ComcolPageContentComponent,
|
||||||
ComcolPageHeaderComponent,
|
ComcolPageHeaderComponent,
|
||||||
ComcolPageLogoComponent,
|
ComcolPageLogoComponent,
|
||||||
|
ErrorComponent,
|
||||||
|
LoadingComponent,
|
||||||
ObjectListComponent,
|
ObjectListComponent,
|
||||||
ObjectListElementComponent,
|
ObjectListElementComponent,
|
||||||
WrapperListElementComponent,
|
PaginationComponent,
|
||||||
SearchFormComponent
|
SearchFormComponent,
|
||||||
|
ThumbnailComponent,
|
||||||
|
WrapperListElementComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENTRY_COMPONENTS = [
|
const ENTRY_COMPONENTS = [
|
||||||
// put shared entry components (components that are created dynamically) here
|
// put shared entry components (components that are created dynamically) here
|
||||||
ItemListElementComponent,
|
|
||||||
CollectionListElementComponent,
|
CollectionListElementComponent,
|
||||||
CommunityListElementComponent,
|
CommunityListElementComponent,
|
||||||
|
ItemListElementComponent,
|
||||||
SearchResultListElementComponent
|
SearchResultListElementComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ import { bootloader } from '@angularclass/bootloader';
|
|||||||
|
|
||||||
import { load as loadWebFont } from 'webfontloader';
|
import { load as loadWebFont } from 'webfontloader';
|
||||||
|
|
||||||
import { BrowserAppModule } from './app/browser-app.module';
|
import { BrowserAppModule } from './modules/app/browser-app.module';
|
||||||
|
|
||||||
import { ENV_CONFIG } from './config';
|
import { ENV_CONFIG } from './config';
|
||||||
|
|
||||||
|
@@ -8,18 +8,14 @@ import * as https from 'https';
|
|||||||
import * as morgan from 'morgan';
|
import * as morgan from 'morgan';
|
||||||
import * as express from 'express';
|
import * as express from 'express';
|
||||||
import * as bodyParser from 'body-parser';
|
import * as bodyParser from 'body-parser';
|
||||||
import * as session from 'express-session';
|
|
||||||
import * as compression from 'compression';
|
import * as compression from 'compression';
|
||||||
import * as cookieParser from 'cookie-parser';
|
import * as cookieParser from 'cookie-parser';
|
||||||
|
|
||||||
import { platformServer, renderModuleFactory } from '@angular/platform-server';
|
|
||||||
import { enableProdMode } from '@angular/core';
|
import { enableProdMode } from '@angular/core';
|
||||||
|
|
||||||
import { ngExpressEngine } from '@nguniversal/express-engine';
|
import { ngExpressEngine } from '@nguniversal/express-engine';
|
||||||
|
|
||||||
import { ServerAppModule } from './app/server-app.module';
|
import { ServerAppModule } from './modules/app/server-app.module';
|
||||||
|
|
||||||
import { serverApi, createMockApi } from './backend/api';
|
|
||||||
|
|
||||||
import { ROUTES } from './routes';
|
import { ROUTES } from './routes';
|
||||||
import { ENV_CONFIG } from './config';
|
import { ENV_CONFIG } from './config';
|
||||||
|
@@ -1,24 +1,24 @@
|
|||||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||||
import { HttpClientModule, HttpClient } from '@angular/common/http';
|
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { IdlePreload, IdlePreloadModule } from '@angularclass/idle-preload';
|
import { IdlePreload, IdlePreloadModule } from '@angularclass/idle-preload';
|
||||||
|
|
||||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
|
||||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
||||||
|
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
|
|
||||||
import { TransferState } from '../modules/transfer-state/transfer-state';
|
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
import { BrowserTransferStateModule } from '../modules/transfer-state/browser-transfer-state.module';
|
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||||
import { BrowserTransferStoreEffects } from '../modules/transfer-store/browser-transfer-store.effects';
|
|
||||||
import { BrowserTransferStoreModule } from '../modules/transfer-store/browser-transfer-store.module';
|
|
||||||
|
|
||||||
import { AppModule } from './app.module';
|
import { AppComponent } from '../../app/app.component';
|
||||||
import { CoreModule } from './core/core.module';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppModule } from '../../app/app.module';
|
||||||
|
import { BrowserTransferStateModule } from '../transfer-state/browser-transfer-state.module';
|
||||||
|
|
||||||
|
import { TransferState } from '../transfer-state/transfer-state';
|
||||||
|
import { BrowserTransferStoreEffects } from '../transfer-store/browser-transfer-store.effects';
|
||||||
|
import { BrowserTransferStoreModule } from '../transfer-store/browser-transfer-store.module';
|
||||||
|
|
||||||
export function init(cache: TransferState) {
|
export function init(cache: TransferState) {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -45,6 +45,7 @@ export function createTranslateLoader(http: HttpClient) {
|
|||||||
preloadingStrategy:
|
preloadingStrategy:
|
||||||
IdlePreload
|
IdlePreload
|
||||||
}),
|
}),
|
||||||
|
BrowserAnimationsModule,
|
||||||
BrowserTransferStateModule,
|
BrowserTransferStateModule,
|
||||||
BrowserTransferStoreModule,
|
BrowserTransferStoreModule,
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
@@ -5,6 +5,7 @@ import { ApplicationRef, NgModule, APP_BOOTSTRAP_LISTENER } from '@angular/core'
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { ServerModule } from '@angular/platform-server';
|
import { ServerModule } from '@angular/platform-server';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
|
|
||||||
@@ -15,21 +16,21 @@ import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
|||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
|
|
||||||
import { TranslateUniversalLoader } from '../modules/translate-universal-loader';
|
import { TranslateUniversalLoader } from '../translate-universal-loader';
|
||||||
|
|
||||||
import { ServerTransferStateModule } from '../modules/transfer-state/server-transfer-state.module';
|
import { ServerTransferStateModule } from '../transfer-state/server-transfer-state.module';
|
||||||
import { TransferState } from '../modules/transfer-state/transfer-state';
|
import { TransferState } from '../transfer-state/transfer-state';
|
||||||
|
|
||||||
import { ServerTransferStoreEffects } from '../modules/transfer-store/server-transfer-store.effects';
|
import { ServerTransferStoreEffects } from '../transfer-store/server-transfer-store.effects';
|
||||||
import { ServerTransferStoreModule } from '../modules/transfer-store/server-transfer-store.module';
|
import { ServerTransferStoreModule } from '../transfer-store/server-transfer-store.module';
|
||||||
|
|
||||||
import { AppState } from './app.reducer';
|
import { AppState } from '../../app/app.reducer';
|
||||||
|
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from '../../app/app.module';
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from '../../app/app.component';
|
||||||
|
|
||||||
import { GLOBAL_CONFIG, GlobalConfig } from '../config';
|
import { GLOBAL_CONFIG, GlobalConfig } from '../../config';
|
||||||
|
|
||||||
export function boot(cache: TransferState, appRef: ApplicationRef, store: Store<AppState>, request: Request, config: GlobalConfig) {
|
export function boot(cache: TransferState, appRef: ApplicationRef, store: Store<AppState>, request: Request, config: GlobalConfig) {
|
||||||
// authentication mechanism goes here
|
// authentication mechanism goes here
|
||||||
@@ -53,6 +54,7 @@ export function createTranslateLoader() {
|
|||||||
RouterModule.forRoot([], {
|
RouterModule.forRoot([], {
|
||||||
useHash: false
|
useHash: false
|
||||||
}),
|
}),
|
||||||
|
NoopAnimationsModule,
|
||||||
ServerTransferStateModule,
|
ServerTransferStateModule,
|
||||||
ServerTransferStoreModule,
|
ServerTransferStoreModule,
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"entryModule": "./app/browser-app.module#BrowserAppModule"
|
"entryModule": "./modules/app/browser-app.module#BrowserAppModule"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"extends": "../tsconfig.json",
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"entryModule": "./app/server-app.module#ServerAppModule"
|
"entryModule": "./modules/app/server-app.module#ServerAppModule"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
"sourceMap": true
|
"sourceMap": true
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"entryModule": "./app/browser-app.module#BrowserAppModule"
|
"entryModule": "./modules/app/browser-app.module#BrowserAppModule"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,9 +5,10 @@ const {
|
|||||||
/**
|
/**
|
||||||
* Webpack Plugins
|
* Webpack Plugins
|
||||||
*/
|
*/
|
||||||
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
|
const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');
|
||||||
const DefinePlugin = require('webpack/lib/DefinePlugin');
|
const DefinePlugin = require('webpack/lib/DefinePlugin');
|
||||||
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
|
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
|
||||||
|
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Webpack Constants
|
* Webpack Constants
|
||||||
@@ -75,8 +76,9 @@ module.exports = function (options) {
|
|||||||
loader: 'source-map-loader',
|
loader: 'source-map-loader',
|
||||||
exclude: [
|
exclude: [
|
||||||
// these packages have problems with their sourcemaps
|
// these packages have problems with their sourcemaps
|
||||||
root('node_modules/rxjs'),
|
root('node_modules/@angular'),
|
||||||
root('node_modules/@angular')
|
root('node_modules/@nguniversal'),
|
||||||
|
root('node_modules/rxjs')
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -221,6 +223,11 @@ module.exports = function (options) {
|
|||||||
*/
|
*/
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|
||||||
|
new ContextReplacementPlugin(
|
||||||
|
/angular(\\|\/)core(\\|\/)@angular/,
|
||||||
|
root('./src'), {}
|
||||||
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin: DefinePlugin
|
* Plugin: DefinePlugin
|
||||||
* Description: Define free variables.
|
* Description: Define free variables.
|
||||||
|
@@ -106,9 +106,9 @@
|
|||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-4.0.3.tgz#36abacdfa19bfb8506e40de80bae06050a1e15e9"
|
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-4.0.3.tgz#36abacdfa19bfb8506e40de80bae06050a1e15e9"
|
||||||
|
|
||||||
"@ngtools/webpack@1.7.3":
|
"@ngtools/webpack@1.7.2":
|
||||||
version "1.7.3"
|
version "1.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.7.3.tgz#20d5bcca0d902e1f3e5accf4922f482539c93a3b"
|
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.7.2.tgz#3fc4de01786dcc2f50d8cbaaa117311e56799977"
|
||||||
dependencies:
|
dependencies:
|
||||||
enhanced-resolve "^3.1.0"
|
enhanced-resolve "^3.1.0"
|
||||||
loader-utils "^1.0.2"
|
loader-utils "^1.0.2"
|
||||||
|
Reference in New Issue
Block a user