diff --git a/.travis.yml b/.travis.yml
index 0a9ae4754f..ce1213f483 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,11 @@
sudo: required
dist: trusty
addons:
- - chrome: stable
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
language: node_js
@@ -21,6 +25,8 @@ install:
- travis_retry yarn install
script:
+ # Use Chromium instead of Chrome.
+ - export CHROME_BIN=chromium-browser
- yarn run build
- yarn run ci
- cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
diff --git a/README.md b/README.md
index 22efa882f0..a241f72910 100644
--- a/README.md
+++ b/README.md
@@ -137,17 +137,32 @@ yarn run clean:dist
Testing
-------
-### Unit Test
+### Test a Pull Request
-Unit tests use Karma. You can find the configuration file at the same level of this README file:`./karma.conf.js` If you are going to use a remote test enviroment you need to edit the './karma.conf.js'. Follow the instructions you will find inside it. To executing tests whenever any file changes you can modify the 'autoWatch' option to 'true' and 'singleRun' option to 'false'. A coverage report is also available at: http://localhost:9876/ after you run:`yarn run coverage`.
+If you would like to contribute by testing a Pull Request (PR), here's how to do so. Keep in mind, you **do not need to have a DSpace backend / REST API installed locally to test a PR**. By default, the dspace-angular project points at our demo REST API
-To correctly run the tests you need to run the build once with:`yarn run build`.
+1. Pull down the branch that the Pull Request was built from. Easy instructions for doing so can be found on the Pull Request itself.
+ * Next to the "Merge" button, you'll see a link that says "command line instructions".
+ * Click it, and follow "Step 1" of those instructions to checkout the pull down the PR branch.
+2. `yarn run clean` (This resets your local dependencies to ensure you are up-to-date with this PR)
+3. `yarn install` (Updates your local dependencies to those in the PR)
+4. `yarn start` (Rebuilds the project, and deploys to localhost:3000, by default)
+5. At this point, the code from the PR will be deployed to http://localhost:3000. Test it out, and ensure that it does what is described in the PR (or fixes the bug described in the ticket linked to the PR).
+
+Once you have tested the Pull Request, please add a comment and/or approval to the PR to let us know whether you found it to be successful (or not). Thanks!
+
+
+### Unit Tests
+
+Unit tests use Karma. You can find the configuration file at the same level of this README file:`./karma.conf.js` If you are going to use a remote test enviroment you need to edit the `./karma.conf.js`. Follow the instructions you will find inside it. To executing tests whenever any file changes you can modify the 'autoWatch' option to 'true' and 'singleRun' option to 'false'. A coverage report is also available at: http://localhost:9876/ after you run: `yarn run coverage`.
+
+To correctly run the tests you need to run the build once with: `yarn run build`.
The default browser is Google Chrome.
Place your tests in the same location of the application source code files that they test.
-and run:`yarn run test`
+and run: `yarn run test`
### E2E test
@@ -161,15 +176,18 @@ Protractor needs a functional instance of the DSpace interface to run the E2E te
or any command that bring up the DSpace interface.
-Place your tests at the following path:`./e2e`
+Place your tests at the following path: `./e2e`
-and run:`yarn run e2e`
+and run: `yarn run e2e`
### Continuous Integration (CI) Test
To run all the tests (e.g.: to run tests with Continuous Integration software) you can execute:`yarn run ci` Keep in mind that this command prerequisites are the sum of unit test and E2E tests.
-##Documentation To build the code documentation we use [TYPEDOC](http://typedoc.org). TYPEDOC is a documentation generator for TypeScript projects. It extracts informations from properly formatted comments that can be written within the code files. Follow the instructions [here](http://typedoc.org/guides/doccomments/) to know how to make those comments.
+Documentation
+--------------
+
+To build the code documentation we use [TYPEDOC](http://typedoc.org). TYPEDOC is a documentation generator for TypeScript projects. It extracts informations from properly formatted comments that can be written within the code files. Follow the instructions [here](http://typedoc.org/guides/doccomments/) to know how to make those comments.
Run:`yarn run docs` to produce the documentation that will be available in the 'doc' folder.
@@ -322,8 +340,8 @@ Install your library via `yarn add lib-name --save` and import it in your code.
If the library does not include typings, you can install them using yarn:
```bash
-yarn add d3 --save
-yarn add @types/d3 --save-dev
+yarn add d3
+yarn add @types/d3 --dev
```
If the library doesn't have typings available at `@types/`, you can still use it by manually adding typings for it:
@@ -349,14 +367,18 @@ If you're importing a module that uses CommonJS you need to import as
import * as _ from 'lodash';
```
-yarn lockfile
+Managing Dependencies (via yarn)
-------------
-This project makes use of yarn to ensure that the exact same dependency versions are used every time you install it.
+This project makes use of [`yarn`](https://yarnpkg.com/en/) to ensure that the exact same dependency versions are used every time you install it.
-yarn creates the file [`yarn.lock`](https://yarnpkg.com/en/docs/yarn-lock) to track those versions. That file is updated automatically every time you install a new dependency from the commandline (by using `yarn add some-lib --save` or `yarn add some-lib --save-dev`).
+* `yarn` creates a [`yarn.lock`](https://yarnpkg.com/en/docs/yarn-lock) to track those versions. That file is updated automatically by whenever dependencies are added/updated/removed via yarn.
+* **Adding new dependencies**: To install/add a new dependency (third party library), use [`yarn add`](https://yarnpkg.com/en/docs/cli/add). For example: `yarn add some-lib`.
+ * If you are adding a new build tool dependency (to `devDependencies`), use `yarn add some-lib --dev`
+* **Upgrading existing dependencies**: To upgrade existing dependencies, you can use [`yarn upgrade`](https://yarnpkg.com/en/docs/cli/upgrade). For example: `yarn upgrade some-lib` or `yarn upgrade some-lib@version`
+* **Removing dependencies**: If a dependency is no longer needed, or replaced, use [`yarn remove`](https://yarnpkg.com/en/docs/cli/remove) to remove it.
-If you manually add a package or change a version in `package.json` you'll have to update yarn's lock file as well. You can do so by running `yarn upgrade`
+As you can see above, using `yarn` commandline tools means that you should never need to modify the `package.json` manually. *We recommend always using `yarn` to keep dependencies updated / in sync.*
Frequently asked questions
--------------------------
diff --git a/package.json b/package.json
index b211892de9..710f62a257 100644
--- a/package.json
+++ b/package.json
@@ -69,26 +69,26 @@
"coverage": "http-server -c-1 -o -p 9875 ./coverage"
},
"dependencies": {
- "@angular/animations": "5.2.1",
- "@angular/common": "5.2.1",
- "@angular/core": "5.2.1",
- "@angular/forms": "5.2.1",
- "@angular/http": "5.2.1",
- "@angular/platform-browser": "5.2.1",
- "@angular/platform-browser-dynamic": "5.2.1",
- "@angular/platform-server": "5.2.1",
- "@angular/router": "5.2.1",
+ "@angular/animations": "^5.2.5",
+ "@angular/common": "^5.2.5",
+ "@angular/core": "^5.2.5",
+ "@angular/forms": "^5.2.5",
+ "@angular/http": "^5.2.5",
+ "@angular/platform-browser": "^5.2.5",
+ "@angular/platform-browser-dynamic": "^5.2.5",
+ "@angular/platform-server": "^5.2.5",
+ "@angular/router": "^5.2.5",
"@angularclass/bootloader": "1.0.1",
- "@ng-bootstrap/ng-bootstrap": "1.0.0-beta.9",
- "@ngrx/effects": "4.1.1",
- "@ngrx/router-store": "4.1.1",
- "@ngrx/store": "4.1.1",
+ "@ng-bootstrap/ng-bootstrap": "^1.0.0",
+ "@ngrx/effects": "^5.1.0",
+ "@ngrx/router-store": "^5.0.1",
+ "@ngrx/store": "^5.1.0",
"@nguniversal/express-engine": "5.0.0-beta.5",
"@ngx-translate/core": "9.1.1",
"@ngx-translate/http-loader": "2.0.1",
"angular-idle-preload": "2.0.4",
"body-parser": "1.18.2",
- "bootstrap": "4.0.0-beta",
+ "bootstrap": "^4.0.0",
"cerialize": "0.1.18",
"compression": "1.7.1",
"cookie-parser": "1.4.3",
@@ -106,45 +106,45 @@
"pem": "1.12.3",
"reflect-metadata": "0.1.12",
"rxjs": "5.5.6",
- "ts-md5": "1.2.3",
+ "ts-md5": "^1.2.4",
"uuid": "^3.2.1",
"webfontloader": "1.6.28",
"zone.js": "0.8.20"
},
"devDependencies": {
- "@angular/compiler": "^5.2.1",
- "@angular/compiler-cli": "^5.2.1",
- "@ngrx/store-devtools": "4.1.1",
- "@ngtools/webpack": "1.9.5",
+ "@angular/compiler": "^5.2.5",
+ "@angular/compiler-cli": "^5.2.5",
+ "@ngrx/store-devtools": "^5.1.0",
+ "@ngtools/webpack": "^1.10.0",
"@types/cookie-parser": "1.4.1",
"@types/deep-freeze": "0.1.1",
- "@types/express": "4.11.0",
+ "@types/express": "^4.11.1",
"@types/express-serve-static-core": "4.11.1",
"@types/hammerjs": "2.0.35",
- "@types/jasmine": "2.8.4",
+ "@types/jasmine": "^2.8.6",
"@types/memory-cache": "0.2.0",
"@types/mime": "2.0.0",
- "@types/node": "^9.3.0",
+ "@types/node": "^9.4.6",
"@types/serve-static": "1.13.1",
"@types/uuid": "^3.4.3",
"@types/webfontloader": "1.6.29",
- "ajv": "6.0.1",
- "ajv-keywords": "3.0.0",
+ "ajv": "^6.1.1",
+ "ajv-keywords": "^3.1.0",
"angular2-template-loader": "0.6.2",
- "autoprefixer": "7.2.5",
+ "autoprefixer": "^8.0.0",
"awesome-typescript-loader": "3.4.1",
- "caniuse-lite": "1.0.30000792",
+ "caniuse-lite": "^1.0.30000697",
"codelyzer": "^4.1.0",
- "compression-webpack-plugin": "1.1.3",
- "copy-webpack-plugin": "4.3.1",
+ "compression-webpack-plugin": "^1.1.6",
+ "copy-webpack-plugin": "^4.4.1",
"coveralls": "3.0.0",
"css-loader": "0.28.9",
"deep-freeze": "0.0.1",
- "exports-loader": "0.6.4",
+ "exports-loader": "^0.7.0",
"html-webpack-plugin": "2.30.1",
"imports-loader": "0.7.1",
"istanbul-instrumenter-loader": "3.0.0",
- "jasmine-core": "2.9.1",
+ "jasmine-core": "^2.99.1",
"jasmine-marbles": "0.2.0",
"jasmine-spec-reporter": "4.2.1",
"json-loader": "0.5.7",
@@ -156,31 +156,31 @@
"karma-jasmine": "1.1.1",
"karma-mocha-reporter": "2.2.5",
"karma-phantomjs-launcher": "1.0.4",
- "karma-remap-coverage": "0.1.4",
+ "karma-remap-coverage": "^0.1.5",
"karma-remap-istanbul": "0.6.0",
"karma-sourcemap-loader": "0.3.7",
"karma-webdriver-launcher": "1.0.5",
"karma-webpack": "2.0.9",
- "ngrx-store-freeze": "0.2.0",
- "node-sass": "4.7.2",
- "nodemon": "1.14.11",
+ "ngrx-store-freeze": "^0.2.1",
+ "node-sass": "^4.7.2",
+ "nodemon": "^1.15.0",
"npm-run-all": "4.1.2",
- "postcss": "6.0.16",
+ "postcss": "^6.0.18",
"postcss-apply": "0.8.0",
- "postcss-cli": "4.1.1",
+ "postcss-cli": "^5.0.0",
"postcss-cssnext": "3.1.0",
- "postcss-loader": "2.0.10",
+ "postcss-loader": "^2.1.0",
"postcss-responsive-type": "1.0.0",
"postcss-smart-import": "0.7.6",
- "protractor": "5.2.2",
+ "protractor": "^5.3.0",
"protractor-istanbul-plugin": "2.0.0",
"raw-loader": "0.5.1",
"resolve-url-loader": "2.2.1",
"rimraf": "2.6.2",
- "rollup": "0.54.1",
- "rollup-plugin-commonjs": "8.2.6",
+ "rollup": "^0.56.0",
+ "rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-node-globals": "1.1.0",
- "rollup-plugin-node-resolve": "3.0.2",
+ "rollup-plugin-node-resolve": "^3.0.3",
"rollup-plugin-uglify": "3.0.0",
"sass-loader": "6.0.6",
"script-ext-html-webpack-plugin": "1.8.8",
@@ -191,11 +191,11 @@
"ts-helpers": "1.1.2",
"ts-node": "4.1.0",
"tslint": "5.9.1",
- "typedoc": "0.9.0",
+ "typedoc": "^0.9.0",
"typescript": "2.6.2",
- "webpack": "^3.10.0",
- "webpack-bundle-analyzer": "2.9.2",
- "webpack-dev-middleware": "2.0.4",
+ "webpack": "^3.11.0",
+ "webpack-bundle-analyzer": "^2.10.0",
+ "webpack-dev-middleware": "^2.0.5",
"webpack-dev-server": "2.11.1",
"webpack-merge": "4.1.1",
"webpack-node-externals": "1.6.0"
diff --git a/src/app/+search-page/search-results/search-results.component.html b/src/app/+search-page/search-results/search-results.component.html
index 1b9bd7d52a..7d7c169380 100644
--- a/src/app/+search-page/search-results/search-results.component.html
+++ b/src/app/+search-page/search-results/search-results.component.html
@@ -1,4 +1,4 @@
-
+
0">{{ 'search.results.head' | translate }}
= {
@@ -28,5 +30,6 @@ export const appReducers: ActionReducerMap = {
header: headerReducer,
notifications: notificationsReducer,
searchSidebar: sidebarReducer,
- searchFilter: filterReducer
+ searchFilter: filterReducer,
+ truncatable: truncatableReducer
};
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
index 0cdb443b8a..953d1ba922 100644
--- a/src/app/header/header.component.html
+++ b/src/app/header/header.component.html
@@ -1,5 +1,5 @@
-
+
diff --git a/src/app/shared/animations/focus.ts b/src/app/shared/animations/focus.ts
new file mode 100644
index 0000000000..33a5010629
--- /dev/null
+++ b/src/app/shared/animations/focus.ts
@@ -0,0 +1,19 @@
+import { animate, state, transition, trigger, style } from '@angular/animations';
+
+export const focusShadow = trigger('focusShadow', [
+
+ state('focus', style({ 'box-shadow': 'rgba(119, 119, 119, 0.6) 0px 0px 6px' })),
+
+ state('blur', style({ 'box-shadow': 'none' })),
+
+ transition('focus <=> blur', animate(250))
+]);
+
+export const focusBackground = trigger('focusBackground', [
+
+ state('focus', style({ 'background-color': 'rgba(119, 119, 119, 0.1)' })),
+
+ state('blur', style({ 'background-color': 'transparent' })),
+
+ transition('focus <=> blur', animate(250))
+]);
diff --git a/src/app/shared/animations/overlay.ts b/src/app/shared/animations/overlay.ts
new file mode 100644
index 0000000000..15d6bf79de
--- /dev/null
+++ b/src/app/shared/animations/overlay.ts
@@ -0,0 +1,10 @@
+import { animate, state, transition, trigger, style } from '@angular/animations';
+
+export const overlay = trigger('overlay', [
+
+ state('show', style({ opacity: 0.5 })),
+
+ state('hide', style({ opacity: 0 })),
+
+ transition('show <=> hide', animate(250))
+]);
diff --git a/src/app/shared/object-collection/shared/collection-search-result.model.ts b/src/app/shared/object-collection/shared/collection-search-result.model.ts
new file mode 100644
index 0000000000..63b6a0d37a
--- /dev/null
+++ b/src/app/shared/object-collection/shared/collection-search-result.model.ts
@@ -0,0 +1,5 @@
+import { Collection } from '../../../core/shared/collection.model';
+import { SearchResult } from '../../../+search-page/search-result.model';
+
+export class CollectionSearchResult extends SearchResult {
+}
diff --git a/src/app/shared/object-collection/shared/community-search-result.model.ts b/src/app/shared/object-collection/shared/community-search-result.model.ts
new file mode 100644
index 0000000000..79ea34b6cd
--- /dev/null
+++ b/src/app/shared/object-collection/shared/community-search-result.model.ts
@@ -0,0 +1,5 @@
+import { SearchResult } from '../../../+search-page/search-result.model';
+import { Community } from '../../../core/shared/community.model';
+
+export class CommunitySearchResult extends SearchResult {
+}
diff --git a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.spec.ts b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.spec.ts
index 217f357bcf..cc72ff3043 100644
--- a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.spec.ts
@@ -1,21 +1,13 @@
import { CollectionGridElementComponent } from './collection-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../testing/router-stub';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { Collection } from '../../../core/shared/collection.model';
+
+let collectionGridElementComponent: CollectionGridElementComponent;
let fixture: ComponentFixture;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
-};
-const mockCollection: Collection = Object.assign(new Collection(), {
+
+const mockCollectionWithAbstract: Collection = Object.assign(new Collection(), {
metadata: [
{
key: 'dc.description.abstract',
@@ -23,37 +15,56 @@ const mockCollection: Collection = Object.assign(new Collection(), {
value: 'Short description'
}]
});
-const createdGridElementComponent:CollectionGridElementComponent= new CollectionGridElementComponent(mockCollection);
+
+const mockCollectionWithoutAbstract: Collection = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ }]
+});
describe('CollectionGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CollectionGridElementComponent ],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: (createdGridElementComponent)}
+ { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract)}
],
schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ }).overrideComponent(CollectionGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CollectionGridElementComponent);
+ collectionGridElementComponent = fixture.componentInstance;
}));
- it('should show the collection cards in the grid element',() => {
- expect(fixture.debugElement.query(By.css('ds-collection-grid-element'))).toBeDefined();
+ describe('When the collection has an abstract', () => {
+ beforeEach(() => {
+ collectionGridElementComponent.object = mockCollectionWithAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(collectionAbstractField).not.toBeNull();
+ });
});
- it('should only show the description if "short description" metadata is present',() => {
- const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text')));
+ describe('When the collection has no abstract', () => {
+ beforeEach(() => {
+ collectionGridElementComponent.object = mockCollectionWithoutAbstract;
+ fixture.detectChanges();
+ });
- if (mockCollection.shortDescription.length > 0) {
- expect(descriptionText).toBeDefined();
- } else {
- expect(descriptionText).not.toBeDefined();
- }
+ it('should not show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(collectionAbstractField).toBeNull();
+ });
});
-})
+});
diff --git a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.spec.ts b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.spec.ts
index cc07beec62..dabb137ea7 100644
--- a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.spec.ts
@@ -1,25 +1,13 @@
import { CommunityGridElementComponent } from './community-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../testing/router-stub';
-import { Observable } from 'rxjs/Observable';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
-import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { Community } from '../../../core/shared/community.model';
let communityGridElementComponent: CommunityGridElementComponent;
let fixture: ComponentFixture;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
-};
-const mockCommunity: Community = Object.assign(new Community(), {
+const mockCommunityWithAbstract: Community = Object.assign(new Community(), {
metadata: [
{
key: 'dc.description.abstract',
@@ -28,39 +16,55 @@ const mockCommunity: Community = Object.assign(new Community(), {
}]
});
-const createdGridElementComponent:CommunityGridElementComponent= new CommunityGridElementComponent(mockCommunity);
+const mockCommunityWithoutAbstract: Community = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ }]
+});
describe('CommunityGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CommunityGridElementComponent ],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: (createdGridElementComponent)}
+ { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract)}
],
schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ }).overrideComponent(CommunityGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CommunityGridElementComponent);
communityGridElementComponent = fixture.componentInstance;
-
}));
- it('should show the community cards in the grid element',() => {
- expect(fixture.debugElement.query(By.css('ds-community-grid-element'))).toBeDefined();
- })
+ describe('When the community has an abstract', () => {
+ beforeEach(() => {
+ communityGridElementComponent.object = mockCommunityWithAbstract;
+ fixture.detectChanges();
+ });
- it('should only show the description if "short description" metadata is present',() => {
- const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text')));
+ it('should show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(communityAbstractField).not.toBeNull();
+ });
+ });
- if (mockCommunity.shortDescription.length > 0) {
- expect(descriptionText).toBeDefined();
- } else {
- expect(descriptionText).not.toBeDefined();
- }
+ describe('When the community has no abstract', () => {
+ beforeEach(() => {
+ communityGridElementComponent.object = mockCommunityWithoutAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should not show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(communityAbstractField).toBeNull();
+ });
});
});
diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
index b8bacfaf2e..328bfc3bc9 100644
--- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
+++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html
@@ -6,12 +6,11 @@
{{object.findMetadata('dc.title')}}
-
-
+
0" class="item-authors card-text text-muted">
{{authorMd.value}}
;
- {{object.findMetadata("dc.date.issued")}}
+ {{object.findMetadata("dc.date.issued")}}
{{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts
index 06b3a04f9f..0dd7f0be0a 100644
--- a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts
@@ -1,47 +1,55 @@
import { ItemGridElementComponent } from './item-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../testing/router-stub';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TruncatePipe } from '../../utils/truncate.pipe';
import { Item } from '../../../core/shared/item.model';
+import { Observable } from 'rxjs/Observable';
let itemGridElementComponent: ItemGridElementComponent;
let fixture: ComponentFixture
;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
-};
-/* tslint:disable:no-shadowed-variable */
-const mockItem: Item = Object.assign(new Item(), {
+
+const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
metadata: [
{
key: 'dc.contributor.author',
language: 'en_US',
value: 'Smith, Donald'
+ },
+ {
+ key: 'dc.date.issued',
+ language: null,
+ value: '2015-06-26'
+ }]
+});
+const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'This is just another title'
+ },
+ {
+ key: 'dc.type',
+ language: null,
+ value: 'Article'
}]
});
-
-const createdGridElementComponent:ItemGridElementComponent= new ItemGridElementComponent(mockItem);
describe('ItemGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ItemGridElementComponent , TruncatePipe],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: {createdGridElementComponent}}
+ { provide: 'objectElementProvider', useValue: {mockItemWithAuthorAndDate}}
],
schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ }).overrideComponent(ItemGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
@@ -50,18 +58,51 @@ describe('ItemGridElementComponent', () => {
}));
- it('should show the item cards in the grid element',() => {
- expect(fixture.debugElement.query(By.css('ds-item-grid-element'))).toBeDefined()
+ describe('When the item has an author', () => {
+ beforeEach(() => {
+ itemGridElementComponent.object = mockItemWithAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors'));
+ expect(itemAuthorField).not.toBeNull();
+ });
});
- it('should only show the author span if the author metadata is present',() => {
- const itemAuthorField = expect(fixture.debugElement.query(By.css('p.item-authors')));
+ describe('When the item has no author', () => {
+ beforeEach(() => {
+ itemGridElementComponent.object = mockItemWithoutAuthorAndDate;
+ fixture.detectChanges();
+ });
- if (mockItem.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0) {
- expect(itemAuthorField).toBeDefined();
- } else {
- expect(itemAuthorField).toBeDefined();
- }
+ it('should not show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors'));
+ expect(itemAuthorField).toBeNull();
+ });
});
-})
+ describe('When the item has an issuedate', () => {
+ beforeEach(() => {
+ itemGridElementComponent.object = mockItemWithAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should show the issuedate span', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-date'));
+ expect(itemAuthorField).not.toBeNull();
+ });
+ });
+
+ describe('When the item has no issuedate', () => {
+ beforeEach(() => {
+ itemGridElementComponent.object = mockItemWithoutAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should not show the issuedate span', () => {
+ const dateField = fixture.debugElement.query(By.css('span.item-date'));
+ expect(dateField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-grid/object-grid.component.html b/src/app/shared/object-grid/object-grid.component.html
index 8040a99552..fcf3a42662 100644
--- a/src/app/shared/object-grid/object-grid.component.html
+++ b/src/app/shared/object-grid/object-grid.component.html
@@ -10,8 +10,8 @@
(sortDirectionChange)="onSortDirectionChange($event)"
(sortFieldChange)="onSortFieldChange($event)"
(paginationChange)="onPaginationChange($event)">
-
-
+
diff --git a/src/app/shared/object-grid/object-grid.component.scss b/src/app/shared/object-grid/object-grid.component.scss
index a85e38d26f..1b9418be48 100644
--- a/src/app/shared/object-grid/object-grid.component.scss
+++ b/src/app/shared/object-grid/object-grid.component.scss
@@ -1,27 +1,24 @@
@import '../../../styles/variables';
+@import '../../../styles/mixins';
ds-wrapper-grid-element ::ng-deep {
div.thumbnail > img {
height: $card-thumbnail-height;
width: 100%;
}
- .card-title {
- line-height: $headings-line-height;
- height: ($headings-line-height*3) +em;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .item-abstract {
- line-height: $line-height-base;
- height: ($line-height-base*5)+em;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .item-authors{
- line-height: $line-height-base;
- height: ($line-height-base*1.5)+em;
- }
div.card {
- margin-bottom: 20px;
+ margin-bottom: $spacer;
}
}
+
+.card-columns {
+ @include media-breakpoint-only(lg) {
+ column-count: 3;
+ }
+ @include media-breakpoint-only(sm) {
+ column-count: 2;
+ }
+ @include media-breakpoint-only(xs) {
+ column-count: 1;
+ }
+}
\ No newline at end of file
diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
index 9dcfe784a7..f3220baaa3 100644
--- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts
@@ -1,64 +1,83 @@
-import {CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component';
+import { CollectionSearchResultGridElementComponent } from './collection-search-result-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../../testing/router-stub';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TruncatePipe } from '../../../utils/truncate.pipe';
-import { Community } from '../../../../core/shared/community.model';
import { Collection } from '../../../../core/shared/collection.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
+let collectionSearchResultGridElementComponent: CollectionSearchResultGridElementComponent;
let fixture: ComponentFixture
;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
};
-const mockCollection: Collection = Object.assign(new Collection(), {
+
+const mockCollectionWithAbstract: CollectionSearchResult = new CollectionSearchResult();
+mockCollectionWithAbstract.hitHighlights = [];
+mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), {
metadata: [
{
key: 'dc.description.abstract',
language: 'en_US',
value: 'Short description'
} ]
-
});
-const createdGridElementComponent: CollectionSearchResultGridElementComponent = new CollectionSearchResultGridElementComponent(mockCollection);
+const mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult();
+mockCollectionWithoutAbstract.hitHighlights = [];
+mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ } ]
+});
describe('CollectionSearchResultGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: (createdGridElementComponent) }
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) }
],
schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ }).overrideComponent(CollectionSearchResultGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CollectionSearchResultGridElementComponent);
+ collectionSearchResultGridElementComponent = fixture.componentInstance;
}));
- it('should show the item result cards in the grid element', () => {
- expect(fixture.debugElement.query(By.css('ds-collection-search-result-grid-element'))).toBeDefined();
+ describe('When the collection has an abstract', () => {
+ beforeEach(() => {
+ collectionSearchResultGridElementComponent.dso = mockCollectionWithAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(collectionAbstractField).not.toBeNull();
+ });
});
- it('should only show the description if "short description" metadata is present',() => {
- const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text')));
+ describe('When the collection has no abstract', () => {
+ beforeEach(() => {
+ collectionSearchResultGridElementComponent.dso = mockCollectionWithoutAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
- if (mockCollection.shortDescription.length > 0) {
- expect(descriptionText).toBeDefined();
- } else {
- expect(descriptionText).not.toBeDefined();
- }
+ it('should not show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(collectionAbstractField).toBeNull();
+ });
});
});
diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts
index 0228107a57..e5747a1243 100644
--- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts
@@ -2,7 +2,7 @@ import { Component } from '@angular/core';
import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator';
-import { CollectionSearchResult } from './collection-search-result.model';
+import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
import { Collection } from '../../../../core/shared/collection.model';
import { ViewMode } from '../../../../+search-page/search-options.model';
diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result.model.ts b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result.model.ts
deleted file mode 100644
index ad48247e70..0000000000
--- a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { SearchResult } from '../../../../+search-page/search-result.model';
-import { Collection } from '../../../../core/shared/collection.model';
-
-export class CollectionSearchResult extends SearchResult {
-}
diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
index 6c5bace810..aa62baadc9 100644
--- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts
@@ -1,63 +1,83 @@
import { CommunitySearchResultGridElementComponent } from './community-search-result-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../../testing/router-stub';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TruncatePipe } from '../../../utils/truncate.pipe';
import { Community } from '../../../../core/shared/community.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
+let communitySearchResultGridElementComponent: CommunitySearchResultGridElementComponent;
let fixture: ComponentFixture;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
};
-const mockCommunity: Community = Object.assign(new Community(), {
+
+const mockCommunityWithAbstract: CommunitySearchResult = new CommunitySearchResult();
+mockCommunityWithAbstract.hitHighlights = [];
+mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), {
metadata: [
{
key: 'dc.description.abstract',
language: 'en_US',
value: 'Short description'
} ]
-
});
-const createdGridElementComponent: CommunitySearchResultGridElementComponent = new CommunitySearchResultGridElementComponent(mockCommunity);
+const mockCommunityWithoutAbstract: CommunitySearchResult = new CommunitySearchResult();
+mockCommunityWithoutAbstract.hitHighlights = [];
+mockCommunityWithoutAbstract.dspaceObject = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ } ]
+});
describe('CommunitySearchResultGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: (createdGridElementComponent) }
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) }
],
schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ }).overrideComponent(CommunitySearchResultGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(CommunitySearchResultGridElementComponent);
+ communitySearchResultGridElementComponent = fixture.componentInstance;
}));
- it('should show the item result cards in the grid element', () => {
- expect(fixture.debugElement.query(By.css('ds-community-search-result-grid-element'))).toBeDefined();
+ describe('When the community has an abstract', () => {
+ beforeEach(() => {
+ communitySearchResultGridElementComponent.dso = mockCommunityWithAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(communityAbstractField).not.toBeNull();
+ });
});
- it('should only show the description if "short description" metadata is present',() => {
- const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text')));
+ describe('When the community has no abstract', () => {
+ beforeEach(() => {
+ communitySearchResultGridElementComponent.dso = mockCommunityWithoutAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
- if (mockCommunity.shortDescription.length > 0) {
- expect(descriptionText).toBeDefined();
- } else {
- expect(descriptionText).not.toBeDefined();
- }
+ it('should not show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('p.card-text'));
+ expect(communityAbstractField).toBeNull();
+ });
});
});
diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts
index 4876a784fc..d08286ff2e 100644
--- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts
@@ -1,10 +1,10 @@
import { Component } from '@angular/core';
-import { CommunitySearchResult } from './community-search-result.model';
import { Community } from '../../../../core/shared/community.model';
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
import { SearchResultGridElementComponent } from '../search-result-grid-element.component';
import { ViewMode } from '../../../../+search-page/search-options.model';
+import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
@Component({
selector: 'ds-community-search-result-grid-element',
diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result.model.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result.model.ts
deleted file mode 100644
index efeb328e11..0000000000
--- a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { SearchResult } from '../../../../+search-page/search-result.model';
-import { Community } from '../../../../core/shared/community.model';
-
-export class CommunitySearchResult extends SearchResult {
-}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
index ce9324477f..b185caa18f 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html
@@ -1,34 +1,33 @@
-
-
-
-
-
-
-
-
-
-
-
- 1">, ...
-
-
-
- 1">,
- {{dso.findMetadata("dc.date.issued")}}
-
-
-
-
-
-
-
-
View
+
+
+
+
+
+
+
+
+
+
+
+
+
0"
+ class="item-authors card-text text-muted">
+
+ 0" class="item-date">{{dso.findMetadata("dc.date.issued")}}
+ ,
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
\ No newline at end of file
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss
index bd63aa6a3a..e2751279b6 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss
@@ -1,2 +1,14 @@
@import '../../../../../styles/variables';
+.card {
+ a > div {
+ position: relative;
+ .thumbnail-overlay {
+ height: 100%;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ background-color: map-get($theme-colors, primary);
+ }
+ }
+}
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts
index 7e460439ac..cf8a097ddb 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts
@@ -1,24 +1,25 @@
import { ItemSearchResultGridElementComponent } from './item-search-result-grid-element.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
-import { ActivatedRoute, Router } from '@angular/router';
-import { RouterStub } from '../../../testing/router-stub';
-import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { NO_ERRORS_SCHEMA, ChangeDetectionStrategy } from '@angular/core';
import { By } from '@angular/platform-browser';
import { TruncatePipe } from '../../../utils/truncate.pipe';
import { Item } from '../../../../core/shared/item.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
let itemSearchResultGridElementComponent: ItemSearchResultGridElementComponent;
let fixture: ComponentFixture
;
-const queryParam = 'test query';
-const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f';
-const activatedRouteStub = {
- queryParams: Observable.of({
- query: queryParam,
- scope: scopeParam
- })
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
};
-const mockItem: Item = Object.assign(new Item(), {
+
+const mockItemWithAuthorAndDate: ItemSearchResult = new ItemSearchResult();
+mockItemWithAuthorAndDate.hitHighlights = [];
+mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
metadata: [
{
key: 'dc.contributor.author',
@@ -28,53 +29,92 @@ const mockItem: Item = Object.assign(new Item(), {
{
key: 'dc.date.issued',
language: null,
- value: '1650-06-26'
+ value: '2015-06-26'
+ }]
+});
+
+const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult();
+mockItemWithoutAuthorAndDate.hitHighlights = [];
+mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'This is just another title'
+ },
+ {
+ key: 'dc.type',
+ language: null,
+ value: 'Article'
}]
});
-const createdGridElementComponent:ItemSearchResultGridElementComponent= new ItemSearchResultGridElementComponent(mockItem);
describe('ItemSearchResultGridElementComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ ItemSearchResultGridElementComponent, TruncatePipe ],
+ imports: [NoopAnimationsModule],
+ declarations: [ItemSearchResultGridElementComponent, TruncatePipe],
providers: [
- { provide: ActivatedRoute, useValue: activatedRouteStub },
- { provide: Router, useClass: RouterStub },
- { provide: 'objectElementProvider', useValue: (createdGridElementComponent) }
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockItemWithoutAuthorAndDate) }
],
-
- schemas: [ NO_ERRORS_SCHEMA ]
- }).compileComponents(); // compile template and css
+ schemas: [NO_ERRORS_SCHEMA]
+ }).overrideComponent(ItemSearchResultGridElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
}));
beforeEach(async(() => {
fixture = TestBed.createComponent(ItemSearchResultGridElementComponent);
itemSearchResultGridElementComponent = fixture.componentInstance;
-
}));
- it('should show the item result cards in the grid element',() => {
- expect(fixture.debugElement.query(By.css('ds-item-search-result-grid-element'))).toBeDefined();
+ describe('When the item has an author', () => {
+ beforeEach(() => {
+ itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors'));
+ expect(itemAuthorField).not.toBeNull();
+ });
});
- it('should only show the author span if the author metadata is present',() => {
- const itemAuthorField = expect(fixture.debugElement.query(By.css('p.item-authors')));
+ describe('When the item has no author', () => {
+ beforeEach(() => {
+ itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
- if (mockItem.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0) {
- expect(itemAuthorField).toBeDefined();
- } else {
- expect(itemAuthorField).not.toBeDefined();
- }
+ it('should not show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('p.item-authors'));
+ expect(itemAuthorField).toBeNull();
+ });
});
- it('should only show the date span if the issuedate is present',() => {
- const dateField = expect(fixture.debugElement.query(By.css('span.item-list-date')));
+ describe('When the item has an issuedate', () => {
+ beforeEach(() => {
+ itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
- if (mockItem.findMetadata('dc.date.issued').length > 0) {
- expect(dateField).toBeDefined();
- } else {
- expect(dateField).not.toBeDefined();
- }
+ it('should show the issuedate span', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-date'));
+ expect(itemAuthorField).not.toBeNull();
+ });
});
+ describe('When the item has no issuedate', () => {
+ beforeEach(() => {
+ itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should not show the issuedate span', () => {
+ const dateField = fixture.debugElement.query(By.css('span.item-date'));
+ expect(dateField).toBeNull();
+ });
+ });
});
diff --git a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts
index f9fe13cb88..518fc23a44 100644
--- a/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts
@@ -5,11 +5,13 @@ import { SearchResultGridElementComponent } from '../search-result-grid-element.
import { Item } from '../../../../core/shared/item.model';
import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
import { ViewMode } from '../../../../+search-page/search-options.model';
+import { focusShadow } from '../../../../shared/animations/focus';
@Component({
selector: 'ds-item-search-result-grid-element',
styleUrls: ['../search-result-grid-element.component.scss', 'item-search-result-grid-element.component.scss'],
- templateUrl: 'item-search-result-grid-element.component.html'
+ templateUrl: 'item-search-result-grid-element.component.html',
+ animations: [focusShadow],
})
@renderElementsFor(ItemSearchResult, ViewMode.Grid)
diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
index 8e1d7e0647..e6217eb0bb 100644
--- a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
+++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts
@@ -6,6 +6,8 @@ import { Metadatum } from '../../../core/shared/metadatum.model';
import { isEmpty, hasNoValue } from '../../empty.util';
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
import { ListableObject } from '../../object-collection/shared/listable-object.model';
+import { TruncatableService } from '../../truncatable/truncatable.service';
+import { Observable } from 'rxjs/Observable';
@Component({
selector: 'ds-search-result-grid-element',
@@ -15,8 +17,8 @@ import { ListableObject } from '../../object-collection/shared/listable-object.m
export class SearchResultGridElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent {
dso: K;
- public constructor(@Inject('objectElementProvider') public gridable: ListableObject) {
- super(gridable);
+ public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, private truncatableService: TruncatableService) {
+ super(listableObject);
this.dso = this.object.dspaceObject;
}
@@ -44,7 +46,7 @@ export class SearchResultGridElementComponent, K exten
this.object.hitHighlights.some(
(md: Metadatum) => {
if (key === md.key) {
- result = md.value;
+ result = md.value;
return true;
}
}
@@ -54,4 +56,8 @@ export class SearchResultGridElementComponent, K exten
}
return result;
}
+
+ isCollapsed(): Observable {
+ return this.truncatableService.isCollapsed(this.dso.id);
+ }
}
diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.html b/src/app/shared/object-list/collection-list-element/collection-list-element.component.html
index 8fb498d474..dec2794dca 100644
--- a/src/app/shared/object-list/collection-list-element/collection-list-element.component.html
+++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.html
@@ -1,6 +1,6 @@
{{object.name}}
-
+
{{object.shortDescription}}
diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.spec.ts b/src/app/shared/object-list/collection-list-element/collection-list-element.component.spec.ts
new file mode 100644
index 0000000000..a31af1e50c
--- /dev/null
+++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.spec.ts
@@ -0,0 +1,70 @@
+import { CollectionListElementComponent } from './collection-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { Collection } from '../../../core/shared/collection.model';
+
+let collectionListElementComponent: CollectionListElementComponent;
+let fixture: ComponentFixture
;
+
+const mockCollectionWithAbstract: Collection = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.description.abstract',
+ language: 'en_US',
+ value: 'Short description'
+ }]
+});
+
+const mockCollectionWithoutAbstract: Collection = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ }]
+});
+
+describe('CollectionListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CollectionListElementComponent ],
+ providers: [
+ { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract)}
+ ],
+
+ schemas: [ NO_ERRORS_SCHEMA ]
+ }).overrideComponent(CollectionListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(CollectionListElementComponent);
+ collectionListElementComponent = fixture.componentInstance;
+ }));
+
+ describe('When the collection has an abstract', () => {
+ beforeEach(() => {
+ collectionListElementComponent.object = mockCollectionWithAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(collectionAbstractField).not.toBeNull();
+ });
+ });
+
+ describe('When the collection has no abstract', () => {
+ beforeEach(() => {
+ collectionListElementComponent.object = mockCollectionWithoutAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should not show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(collectionAbstractField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.html b/src/app/shared/object-list/community-list-element/community-list-element.component.html
index d39995de40..7582680fb2 100644
--- a/src/app/shared/object-list/community-list-element/community-list-element.component.html
+++ b/src/app/shared/object-list/community-list-element/community-list-element.component.html
@@ -1,6 +1,6 @@
{{object.name}}
-
+
{{object.shortDescription}}
diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.spec.ts b/src/app/shared/object-list/community-list-element/community-list-element.component.spec.ts
new file mode 100644
index 0000000000..08147d8573
--- /dev/null
+++ b/src/app/shared/object-list/community-list-element/community-list-element.component.spec.ts
@@ -0,0 +1,70 @@
+import { CommunityListElementComponent } from './community-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { Community } from '../../../core/shared/community.model';
+
+let communityListElementComponent: CommunityListElementComponent;
+let fixture: ComponentFixture
;
+
+const mockCommunityWithAbstract: Community = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.description.abstract',
+ language: 'en_US',
+ value: 'Short description'
+ }]
+});
+
+const mockCommunityWithoutAbstract: Community = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ }]
+});
+
+describe('CommunityListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CommunityListElementComponent ],
+ providers: [
+ { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract)}
+ ],
+
+ schemas: [ NO_ERRORS_SCHEMA ]
+ }).overrideComponent(CommunityListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(CommunityListElementComponent);
+ communityListElementComponent = fixture.componentInstance;
+ }));
+
+ describe('When the community has an abstract', () => {
+ beforeEach(() => {
+ communityListElementComponent.object = mockCommunityWithAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(communityAbstractField).not.toBeNull();
+ });
+ });
+
+ describe('When the community has no abstract', () => {
+ beforeEach(() => {
+ communityListElementComponent.object = mockCommunityWithoutAbstract;
+ fixture.detectChanges();
+ });
+
+ it('should not show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(communityAbstractField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.html b/src/app/shared/object-list/item-list-element/item-list-element.component.html
index cc24ba76b8..b4259c25c2 100644
--- a/src/app/shared/object-list/item-list-element/item-list-element.component.html
+++ b/src/app/shared/object-list/item-list-element/item-list-element.component.html
@@ -3,12 +3,16 @@
-
+ 0"
+ class="item-list-authors">
{{authorMd.value}}
;
- ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}} )
+ ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}} )
- {{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
+
+ {{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
+
diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts b/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts
new file mode 100644
index 0000000000..fc40527693
--- /dev/null
+++ b/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts
@@ -0,0 +1,108 @@
+import { ItemListElementComponent } from './item-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { TruncatePipe } from '../../utils/truncate.pipe';
+import { Item } from '../../../core/shared/item.model';
+import { Observable } from 'rxjs/Observable';
+
+let itemListElementComponent: ItemListElementComponent;
+let fixture: ComponentFixture;
+
+const mockItemWithAuthorAndDate: Item = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.contributor.author',
+ language: 'en_US',
+ value: 'Smith, Donald'
+ },
+ {
+ key: 'dc.date.issued',
+ language: null,
+ value: '2015-06-26'
+ }]
+});
+const mockItemWithoutAuthorAndDate: Item = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'This is just another title'
+ },
+ {
+ key: 'dc.type',
+ language: null,
+ value: 'Article'
+ }]
+});
+
+describe('ItemListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ItemListElementComponent , TruncatePipe],
+ providers: [
+ { provide: 'objectElementProvider', useValue: {mockItemWithAuthorAndDate}}
+ ],
+
+ schemas: [ NO_ERRORS_SCHEMA ]
+ }).overrideComponent(ItemListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(ItemListElementComponent);
+ itemListElementComponent = fixture.componentInstance;
+
+ }));
+
+ describe('When the item has an author', () => {
+ beforeEach(() => {
+ itemListElementComponent.object = mockItemWithAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors'));
+ expect(itemAuthorField).not.toBeNull();
+ });
+ });
+
+ describe('When the item has no author', () => {
+ beforeEach(() => {
+ itemListElementComponent.object = mockItemWithoutAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should not show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors'));
+ expect(itemAuthorField).toBeNull();
+ });
+ });
+
+ describe('When the item has an issuedate', () => {
+ beforeEach(() => {
+ itemListElementComponent.object = mockItemWithAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should show the issuedate span', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-date'));
+ expect(itemAuthorField).not.toBeNull();
+ });
+ });
+
+ describe('When the item has no issuedate', () => {
+ beforeEach(() => {
+ itemListElementComponent.object = mockItemWithoutAuthorAndDate;
+ fixture.detectChanges();
+ });
+
+ it('should not show the issuedate span', () => {
+ const dateField = fixture.debugElement.query(By.css('span.item-list-date'));
+ expect(dateField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html
index 8de695ae58..420886668a 100644
--- a/src/app/shared/object-list/object-list.component.html
+++ b/src/app/shared/object-list/object-list.component.html
@@ -10,8 +10,8 @@
(sortDirectionChange)="onSortDirectionChange($event)"
(sortFieldChange)="onSortFieldChange($event)"
(paginationChange)="onPaginationChange($event)">
-
-
+
diff --git a/src/app/shared/object-list/object-list.component.scss b/src/app/shared/object-list/object-list.component.scss
index 48e6526dff..3d2af4d023 100644
--- a/src/app/shared/object-list/object-list.component.scss
+++ b/src/app/shared/object-list/object-list.component.scss
@@ -1 +1 @@
-@import '../../../styles/variables';
+@import '../../../styles/variables';
\ No newline at end of file
diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html
index 914fb49487..be549b2b76 100644
--- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html
+++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html
@@ -1,2 +1,2 @@
-
+
diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts
new file mode 100644
index 0000000000..0395904070
--- /dev/null
+++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts
@@ -0,0 +1,83 @@
+import { CollectionSearchResultListElementComponent } from './collection-search-result-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Observable } from 'rxjs/Observable';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Collection } from '../../../../core/shared/collection.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
+
+let collectionSearchResultListElementComponent: CollectionSearchResultListElementComponent;
+let fixture: ComponentFixture;
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
+};
+
+const mockCollectionWithAbstract: CollectionSearchResult = new CollectionSearchResult();
+mockCollectionWithAbstract.hitHighlights = [];
+mockCollectionWithAbstract.dspaceObject = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.description.abstract',
+ language: 'en_US',
+ value: 'Short description'
+ } ]
+});
+
+const mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult();
+mockCollectionWithoutAbstract.hitHighlights = [];
+mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ } ]
+});
+
+describe('CollectionSearchResultListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CollectionSearchResultListElementComponent, TruncatePipe ],
+ providers: [
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) }
+ ],
+
+ schemas: [ NO_ERRORS_SCHEMA ]
+ }).overrideComponent(CollectionSearchResultListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(CollectionSearchResultListElementComponent);
+ collectionSearchResultListElementComponent = fixture.componentInstance;
+ }));
+
+ describe('When the collection has an abstract', () => {
+ beforeEach(() => {
+ collectionSearchResultListElementComponent.dso = mockCollectionWithAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(collectionAbstractField).not.toBeNull();
+ });
+ });
+
+ describe('When the collection has no abstract', () => {
+ beforeEach(() => {
+ collectionSearchResultListElementComponent.dso = mockCollectionWithoutAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should not show the description paragraph', () => {
+ const collectionAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(collectionAbstractField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts
index 5545ea17ec..9a462c124e 100644
--- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts
@@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
-import { CollectionSearchResult } from './collection-search-result.model';
import { SearchResultListElementComponent } from '../search-result-list-element.component';
import { Collection } from '../../../../core/shared/collection.model';
import { ViewMode } from '../../../../+search-page/search-options.model';
+import { CollectionSearchResult } from '../../../object-collection/shared/collection-search-result.model';
@Component({
selector: 'ds-collection-search-result-list-element',
diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts
deleted file mode 100644
index ad48247e70..0000000000
--- a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { SearchResult } from '../../../../+search-page/search-result.model';
-import { Collection } from '../../../../core/shared/collection.model';
-
-export class CollectionSearchResult extends SearchResult {
-}
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html
index d09ef7d668..150ca503cc 100644
--- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html
+++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html
@@ -1,2 +1,2 @@
-
+
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts
new file mode 100644
index 0000000000..54dde5dee6
--- /dev/null
+++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts
@@ -0,0 +1,83 @@
+import { CommunitySearchResultListElementComponent } from './community-search-result-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Observable } from 'rxjs/Observable';
+import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Community } from '../../../../core/shared/community.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
+
+let communitySearchResultListElementComponent: CommunitySearchResultListElementComponent;
+let fixture: ComponentFixture;
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
+};
+
+const mockCommunityWithAbstract: CommunitySearchResult = new CommunitySearchResult();
+mockCommunityWithAbstract.hitHighlights = [];
+mockCommunityWithAbstract.dspaceObject = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.description.abstract',
+ language: 'en_US',
+ value: 'Short description'
+ } ]
+});
+
+const mockCommunityWithoutAbstract: CommunitySearchResult = new CommunitySearchResult();
+mockCommunityWithoutAbstract.hitHighlights = [];
+mockCommunityWithoutAbstract.dspaceObject = Object.assign(new Community(), {
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'Test title'
+ } ]
+});
+
+describe('CommunitySearchResultListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ CommunitySearchResultListElementComponent, TruncatePipe ],
+ providers: [
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) }
+ ],
+
+ schemas: [ NO_ERRORS_SCHEMA ]
+ }).overrideComponent(CommunitySearchResultListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(CommunitySearchResultListElementComponent);
+ communitySearchResultListElementComponent = fixture.componentInstance;
+ }));
+
+ describe('When the community has an abstract', () => {
+ beforeEach(() => {
+ communitySearchResultListElementComponent.dso = mockCommunityWithAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(communityAbstractField).not.toBeNull();
+ });
+ });
+
+ describe('When the community has no abstract', () => {
+ beforeEach(() => {
+ communitySearchResultListElementComponent.dso = mockCommunityWithoutAbstract.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should not show the description paragraph', () => {
+ const communityAbstractField = fixture.debugElement.query(By.css('div.abstract-text'));
+ expect(communityAbstractField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts
index 2d96f61833..5664e840e3 100644
--- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
-import { CommunitySearchResult } from './community-search-result.model';
+import { CommunitySearchResult } from '../../../object-collection/shared/community-search-result.model';
import { SearchResultListElementComponent } from '../search-result-list-element.component';
import { Community } from '../../../../core/shared/community.model';
import { ViewMode } from '../../../../+search-page/search-options.model';
diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result.model.ts b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result.model.ts
deleted file mode 100644
index efeb328e11..0000000000
--- a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import { SearchResult } from '../../../../+search-page/search-result.model';
-import { Community } from '../../../../core/shared/community.model';
-
-export class CommunitySearchResult extends SearchResult {
-}
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
index 27b40eeeeb..b8f3197a7c 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html
@@ -1,12 +1,24 @@
-
-
+
+
-
-
-
-
-
- (, )
+
+ (, )
+ 0"
+ class="item-list-authors">
+
+
+
+
+
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts
new file mode 100644
index 0000000000..f492c58483
--- /dev/null
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts
@@ -0,0 +1,120 @@
+import { ItemSearchResultListElementComponent } from './item-search-result-list-element.component';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Observable } from 'rxjs/Observable';
+import { NO_ERRORS_SCHEMA, ChangeDetectionStrategy } from '@angular/core';
+import { By } from '@angular/platform-browser';
+import { TruncatePipe } from '../../../utils/truncate.pipe';
+import { Item } from '../../../../core/shared/item.model';
+import { TruncatableService } from '../../../truncatable/truncatable.service';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
+
+let itemSearchResultListElementComponent: ItemSearchResultListElementComponent;
+let fixture: ComponentFixture;
+
+const truncatableServiceStub: any = {
+ isCollapsed: (id: number) => Observable.of(true),
+};
+
+const mockItemWithAuthorAndDate: ItemSearchResult = new ItemSearchResult();
+mockItemWithAuthorAndDate.hitHighlights = [];
+mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.contributor.author',
+ language: 'en_US',
+ value: 'Smith, Donald'
+ },
+ {
+ key: 'dc.date.issued',
+ language: null,
+ value: '2015-06-26'
+ }]
+});
+
+const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult();
+mockItemWithoutAuthorAndDate.hitHighlights = [];
+mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), {
+ bitstreams: Observable.of({}),
+ metadata: [
+ {
+ key: 'dc.title',
+ language: 'en_US',
+ value: 'This is just another title'
+ },
+ {
+ key: 'dc.type',
+ language: null,
+ value: 'Article'
+ }]
+});
+
+describe('ItemSearchResultListElementComponent', () => {
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [NoopAnimationsModule],
+ declarations: [ItemSearchResultListElementComponent, TruncatePipe],
+ providers: [
+ { provide: TruncatableService, useValue: truncatableServiceStub },
+ { provide: 'objectElementProvider', useValue: (mockItemWithoutAuthorAndDate) }
+ ],
+ schemas: [NO_ERRORS_SCHEMA]
+ }).overrideComponent(ItemSearchResultListElementComponent, {
+ set: { changeDetection: ChangeDetectionStrategy.Default }
+ }).compileComponents();
+ }));
+
+ beforeEach(async(() => {
+ fixture = TestBed.createComponent(ItemSearchResultListElementComponent);
+ itemSearchResultListElementComponent = fixture.componentInstance;
+ }));
+
+ describe('When the item has an author', () => {
+ beforeEach(() => {
+ itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors'));
+ expect(itemAuthorField).not.toBeNull();
+ });
+ });
+
+ describe('When the item has no author', () => {
+ beforeEach(() => {
+ itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should not show the author paragraph', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-authors'));
+ expect(itemAuthorField).toBeNull();
+ });
+ });
+
+ describe('When the item has an issuedate', () => {
+ beforeEach(() => {
+ itemSearchResultListElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should show the issuedate span', () => {
+ const itemAuthorField = fixture.debugElement.query(By.css('span.item-list-date'));
+ expect(itemAuthorField).not.toBeNull();
+ });
+ });
+
+ describe('When the item has no issuedate', () => {
+ beforeEach(() => {
+ itemSearchResultListElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject;
+ fixture.detectChanges();
+ });
+
+ it('should not show the issuedate span', () => {
+ const dateField = fixture.debugElement.query(By.css('span.item-list-date'));
+ expect(dateField).toBeNull();
+ });
+ });
+});
diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts
index d1011c8c45..b776abc214 100644
--- a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts
@@ -1,16 +1,21 @@
-import { Component } from '@angular/core';
+import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator';
import { SearchResultListElementComponent } from '../search-result-list-element.component';
import { Item } from '../../../../core/shared/item.model';
import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model';
import { ViewMode } from '../../../../+search-page/search-options.model';
+import { ListableObject } from '../../../object-collection/shared/listable-object.model';
+import { focusBackground } from '../../../animations/focus';
@Component({
selector: 'ds-item-search-result-list-element',
styleUrls: ['../search-result-list-element.component.scss', 'item-search-result-list-element.component.scss'],
- templateUrl: 'item-search-result-list-element.component.html'
+ templateUrl: 'item-search-result-list-element.component.html',
+ animations: [focusBackground],
+
})
@renderElementsFor(ItemSearchResult, ViewMode.List)
-export class ItemSearchResultListElementComponent extends SearchResultListElementComponent {}
+export class ItemSearchResultListElementComponent extends SearchResultListElementComponent {
+}
diff --git a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
index 6c79eaad53..9675a58a1e 100644
--- a/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
+++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts
@@ -6,6 +6,8 @@ import { Metadatum } from '../../../core/shared/metadatum.model';
import { isEmpty, hasNoValue } from '../../empty.util';
import { ListableObject } from '../../object-collection/shared/listable-object.model';
import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component';
+import { Observable } from 'rxjs/Observable';
+import { TruncatableService } from '../../truncatable/truncatable.service';
@Component({
selector: 'ds-search-result-list-element',
@@ -15,7 +17,7 @@ import { AbstractListableElementComponent } from '../../object-collection/shared
export class SearchResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent {
dso: K;
- public constructor(@Inject('objectElementProvider') public listable: ListableObject) {
+ public constructor(@Inject('objectElementProvider') public listable: ListableObject, private truncatableService: TruncatableService) {
super(listable);
this.dso = this.object.dspaceObject;
}
@@ -54,4 +56,8 @@ export class SearchResultListElementComponent, K exten
}
return result;
}
+
+ isCollapsed(): Observable {
+ return this.truncatableService.isCollapsed(this.dso.id);
+ }
}
diff --git a/src/app/shared/search-form/search-form.component.html b/src/app/shared/search-form/search-form.component.html
index 18469f686a..a4e8cddc1e 100644
--- a/src/app/shared/search-form/search-form.component.html
+++ b/src/app/shared/search-form/search-form.component.html
@@ -1,4 +1,4 @@
-