From 71a8ed05d17e30b973d2dc3100cf28d7b9ff6ade Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Fri, 24 Nov 2017 10:45:50 +0100 Subject: [PATCH 01/23] 46063: object list truncation start --- package.json | 1 + .../search-results.component.html | 2 +- ...-search-result-list-element.component.html | 4 ++- ...em-search-result-list-element.component.ts | 7 ++-- .../search-form/search-form.component.ts | 1 - src/app/shared/shared.module.ts | 8 +++-- .../truncatable/truncatable.component.html | 1 + .../truncatable/truncatable.component.ts | 26 +++++++++++++++ src/app/shared/utils/shave.directive.ts | 33 +++++++++++++++++++ src/app/typings.d.ts | 10 ++++++ yarn.lock | 4 +++ 11 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 src/app/shared/truncatable/truncatable.component.html create mode 100644 src/app/shared/truncatable/truncatable.component.ts create mode 100644 src/app/shared/utils/shave.directive.ts diff --git a/package.json b/package.json index 2f74dd6cb8..84060e61a2 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "pem": "1.12.3", "reflect-metadata": "0.1.10", "rxjs": "5.4.3", + "shave": "^2.1.3", "ts-md5": "1.2.2", "webfontloader": "1.6.28", "zone.js": "0.8.18" 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 70e315671b..e4fceb75d0 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 @@ -
+

{{ 'search.results.head' | translate }}

(, ) -
+
+ +
diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts index ef968db0b8..0d4ccff129 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts @@ -4,12 +4,15 @@ import { listElementFor } from '../../list-element-decorator'; import { ItemSearchResult } from './item-search-result.model'; import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Item } from '../../../core/shared/item.model'; +import { Observable } from 'rxjs/Observable'; @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', }) @listElementFor(ItemSearchResult) -export class ItemSearchResultListElementComponent extends SearchResultListElementComponent {} +export class ItemSearchResultListElementComponent extends SearchResultListElementComponent { + lines = Observable.of(3); +} diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts index 76b33a8fd6..fb3c6ba5a2 100644 --- a/src/app/shared/search-form/search-form.component.ts +++ b/src/app/shared/search-form/search-form.component.ts @@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { Router } from '@angular/router'; import { isNotEmpty, hasValue, isEmpty } from '../empty.util'; -import { Observable } from 'rxjs/Observable'; /** * This component renders a simple item page. diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 245d45ea4e..9710a4f2d1 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -31,6 +31,8 @@ import { SearchFormComponent } from './search-form/search-form.component'; import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component'; import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.component'; import { VarDirective } from './utils/var.directive'; +import { TruncatableComponent } from './truncatable/truncatable.component'; +import { ShaveDirective } from './utils/shave.directive'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -64,7 +66,8 @@ const COMPONENTS = [ SearchFormComponent, ThumbnailComponent, WrapperListElementComponent, - ViewModeSwitchComponent + ViewModeSwitchComponent, + TruncatableComponent ]; const ENTRY_COMPONENTS = [ @@ -76,7 +79,8 @@ const ENTRY_COMPONENTS = [ ]; const DIRECTIVES = [ - VarDirective + VarDirective, + ShaveDirective ]; @NgModule({ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html new file mode 100644 index 0000000000..1a778d1ea6 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts new file mode 100644 index 0000000000..cec9c287ac --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -0,0 +1,26 @@ + +import { + AfterViewChecked, + AfterViewInit, Component, ElementRef, Inject, Input, + OnInit +} from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { NativeWindowRef, NativeWindowService } from '../window.service'; + +@Component({ + selector: 'ds-truncatable', + templateUrl: './truncatable.component.html' +}) +export class TruncatableComponent implements AfterViewChecked { + + @Input() lines: Observable; + @Input() innerHTML; + @Input() height: Observable; + public constructor(private elementRef:ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { } + + ngAfterViewChecked(): void { + const lineHeight = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement).lineHeight.replace('px', ''); + this.height = this.lines.map((lines) => (lines * lineHeight)).startWith(0); + this.height.subscribe((h) => console.log('height: ', h)); + } +} diff --git a/src/app/shared/utils/shave.directive.ts b/src/app/shared/utils/shave.directive.ts new file mode 100644 index 0000000000..7a8403aef0 --- /dev/null +++ b/src/app/shared/utils/shave.directive.ts @@ -0,0 +1,33 @@ +import { Directive, ElementRef, Inject, Input, OnDestroy } from '@angular/core'; +import { default as shave } from 'shave'; +import { NativeWindowRef, NativeWindowService } from '../window.service'; +import { Observable } from 'rxjs/Observable'; + +@Directive({ + selector: '[dsShave]' +}) +export class ShaveDirective implements OnDestroy { + @Input() shave: IShaveOptions = {}; + @Input() shaveHeight: 100; + private sub; + + constructor(private ele: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { + this.subscribeForResizeEvent(); + } + + subscribeForResizeEvent() { + const obs = Observable.fromEvent(this._window.nativeWindow, 'resize'); + this.sub = obs.subscribe((e) => this.runShave()); + } + + private runShave() { + shave(this.ele.nativeElement, this.shaveHeight, this.shave); + } + + ngOnDestroy(): void { + if (this.sub) { + this.sub.unsubscribe(); + } + } + +} diff --git a/src/app/typings.d.ts b/src/app/typings.d.ts index f3b4a1a548..c256b0f09d 100644 --- a/src/app/typings.d.ts +++ b/src/app/typings.d.ts @@ -82,3 +82,13 @@ declare module '*.json' { } declare module 'reflect-metadata'; + +interface IShaveOptions { + classname?: string, + character?: string +} + +declare module 'shave' { + export default function shave(selector: string | Node, maxHeight: number, options?: IShaveOptions): void; + +} diff --git a/yarn.lock b/yarn.lock index 91b2a787e2..6088cf16f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6647,6 +6647,10 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" +shave@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/shave/-/shave-2.1.3.tgz#89c7df997d35a95bc31703c9150161bc98d3fa3b" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" From d7c2b09697e682bef8f731482a91214bfb0d1949 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Mon, 18 Dec 2017 13:57:01 +0100 Subject: [PATCH 02/23] print commit --- .../shared/truncatable/truncatable.component.html | 3 ++- src/app/shared/truncatable/truncatable.component.ts | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index 1a778d1ea6..7b5c540a50 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1 +1,2 @@ - \ No newline at end of file + +{{print(styles)}} \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index cec9c287ac..ab4ca21b71 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -11,16 +11,22 @@ import { NativeWindowRef, NativeWindowService } from '../window.service'; selector: 'ds-truncatable', templateUrl: './truncatable.component.html' }) -export class TruncatableComponent implements AfterViewChecked { +export class TruncatableComponent implements OnInit { @Input() lines: Observable; @Input() innerHTML; @Input() height: Observable; + styles: any; public constructor(private elementRef:ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { } - ngAfterViewChecked(): void { + ngOnInit(): void { const lineHeight = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement).lineHeight.replace('px', ''); + this.styles = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement); this.height = this.lines.map((lines) => (lines * lineHeight)).startWith(0); - this.height.subscribe((h) => console.log('height: ', h)); + this.print(this.styles); + } + + print(styles) { + console.log(styles); } } From 970b1f6b742e47078e414b52318e60c4009bfe6e Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 19 Dec 2017 11:54:20 +0100 Subject: [PATCH 03/23] 47063: truncation option with shave library --- src/app/app.module.ts | 2 +- .../item-list-element.component.html | 3 +- .../item-list-element.component.ts | 4 ++- ...em-search-result-list-element.component.ts | 3 +- .../truncatable/truncatable.component.html | 3 +- .../truncatable/truncatable.component.ts | 26 +++++++--------- src/app/shared/utils/shave.directive.ts | 30 +++++++++++++++++-- 7 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ef1e098f02..7ae394be32 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -38,7 +38,7 @@ export function getBase() { } export function getMetaReducers(config: GlobalConfig): Array> { - const metaReducers: Array> = config.production ? appMetaReducers : [...appMetaReducers, storeFreeze]; + const metaReducers: Array> = config.production ? appMetaReducers : [...appMetaReducers]; return config.debug ? [...metaReducers, ...debugMetaReducers] : metaReducers; } diff --git a/src/app/object-list/item-list-element/item-list-element.component.html b/src/app/object-list/item-list-element/item-list-element.component.html index cc24ba76b8..ef5cf8aec4 100644 --- a/src/app/object-list/item-list-element/item-list-element.component.html +++ b/src/app/object-list/item-list-element/item-list-element.component.html @@ -10,5 +10,6 @@ ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}}) -
{{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
+
+
diff --git a/src/app/object-list/item-list-element/item-list-element.component.ts b/src/app/object-list/item-list-element/item-list-element.component.ts index cc6c837bb7..b3eff81a47 100644 --- a/src/app/object-list/item-list-element/item-list-element.component.ts +++ b/src/app/object-list/item-list-element/item-list-element.component.ts @@ -11,4 +11,6 @@ import { listElementFor } from '../list-element-decorator'; }) @listElementFor(Item) -export class ItemListElementComponent extends ObjectListElementComponent {} +export class ItemListElementComponent extends ObjectListElementComponent { + private lines = 3; +} diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts index 0d4ccff129..79af7a82c9 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts @@ -4,7 +4,6 @@ import { listElementFor } from '../../list-element-decorator'; import { ItemSearchResult } from './item-search-result.model'; import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Item } from '../../../core/shared/item.model'; -import { Observable } from 'rxjs/Observable'; @Component({ selector: 'ds-item-search-result-list-element', @@ -14,5 +13,5 @@ import { Observable } from 'rxjs/Observable'; @listElementFor(ItemSearchResult) export class ItemSearchResultListElementComponent extends SearchResultListElementComponent { - lines = Observable.of(3); + lines = 3; } diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index 7b5c540a50..aa070c834b 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1,2 +1 @@ - -{{print(styles)}} \ No newline at end of file + \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index ab4ca21b71..ddece47fd9 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -1,10 +1,7 @@ - import { - AfterViewChecked, - AfterViewInit, Component, ElementRef, Inject, Input, + ChangeDetectorRef, Component, ElementRef, Inject, Input, OnInit } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; import { NativeWindowRef, NativeWindowService } from '../window.service'; @Component({ @@ -13,20 +10,19 @@ import { NativeWindowRef, NativeWindowService } from '../window.service'; }) export class TruncatableComponent implements OnInit { - @Input() lines: Observable; + @Input() lines: number; @Input() innerHTML; - @Input() height: Observable; + height; styles: any; - public constructor(private elementRef:ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { } + + public constructor(private elementRef: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef, private changeDetectorRef: ChangeDetectorRef) { + } ngOnInit(): void { - const lineHeight = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement).lineHeight.replace('px', ''); - this.styles = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement); - this.height = this.lines.map((lines) => (lines * lineHeight)).startWith(0); - this.print(this.styles); - } - - print(styles) { - console.log(styles); + this.styles = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement); + setTimeout(() => { + this.height = this.styles.lineHeight.replace('px', '') * this.lines; + this.changeDetectorRef.detectChanges(); + }, 0); } } diff --git a/src/app/shared/utils/shave.directive.ts b/src/app/shared/utils/shave.directive.ts index 7a8403aef0..0622b8bb0c 100644 --- a/src/app/shared/utils/shave.directive.ts +++ b/src/app/shared/utils/shave.directive.ts @@ -1,4 +1,7 @@ -import { Directive, ElementRef, Inject, Input, OnDestroy } from '@angular/core'; +import { + Directive, ElementRef, Inject, Input, OnChanges, OnDestroy, + OnInit +} from '@angular/core'; import { default as shave } from 'shave'; import { NativeWindowRef, NativeWindowService } from '../window.service'; import { Observable } from 'rxjs/Observable'; @@ -6,12 +9,33 @@ import { Observable } from 'rxjs/Observable'; @Directive({ selector: '[dsShave]' }) -export class ShaveDirective implements OnDestroy { +export class ShaveDirective implements OnDestroy, OnChanges { + @Input() shave: IShaveOptions = {}; - @Input() shaveHeight: 100; + + @Input() + set shaveHeight(value) { + if (value > 0) { + console.log(value); + this._shaveHeight = value; + } + }; + + get shaveHeight() { + return this._shaveHeight; + } + + private _shaveHeight = 72; private sub; constructor(private ele: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { + } + + ngOnChanges(): void { + console.log("onchange"); + if (this.shaveHeight > 0) { + this.runShave(); + } this.subscribeForResizeEvent(); } From eb2143d0a1b3585e318a4dd9ef513fce0b71bd21 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 20 Dec 2017 08:55:45 +0100 Subject: [PATCH 04/23] 46063: overflow-text-clamp wrapper attempt --- package.json | 1 + src/app/app.component.scss | 1 + ...-search-result-list-element.component.html | 6 ++--- ...em-search-result-list-element.component.ts | 16 +++++++++-- src/app/shared/shared.module.ts | 5 +++- src/app/shared/utils/clamp-directive.ts | 20 ++++++++++++++ src/app/shared/utils/shave.directive.ts | 1 - yarn.lock | 27 +++++++++++++++++++ 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 src/app/shared/utils/clamp-directive.ts diff --git a/package.json b/package.json index 84060e61a2..74bb10bfed 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,7 @@ "reflect-metadata": "0.1.10", "rxjs": "5.4.3", "shave": "^2.1.3", + "text-overflow-clamp": "^1.0.0", "ts-md5": "1.2.2", "webfontloader": "1.6.28", "zone.js": "0.8.18" diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 01c72ecef2..00a3e56121 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -23,6 +23,7 @@ body { display: flex; min-height: 100vh; flex-direction: column; + width: 100%; } .main-content { diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html index 48698b6b40..bce61e9036 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html @@ -8,7 +8,7 @@ (, ) -
- +
+
-
+ \ No newline at end of file diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts index 79af7a82c9..82d31ca33c 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts @@ -1,9 +1,10 @@ -import { Component } from '@angular/core'; +import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core'; import { listElementFor } from '../../list-element-decorator'; import { ItemSearchResult } from './item-search-result.model'; import { SearchResultListElementComponent } from '../search-result-list-element.component'; import { Item } from '../../../core/shared/item.model'; +import { ListableObject } from '../../listable-object/listable-object.model'; @Component({ selector: 'ds-item-search-result-list-element', @@ -12,6 +13,17 @@ import { Item } from '../../../core/shared/item.model'; }) @listElementFor(ItemSearchResult) -export class ItemSearchResultListElementComponent extends SearchResultListElementComponent { +export class ItemSearchResultListElementComponent extends SearchResultListElementComponent implements OnInit { lines = 3; + + constructor(@Inject('objectElementProvider') public listable: ListableObject, private changeDetectorRef: ChangeDetectorRef) { + super(listable); + } + + ngOnInit() { + setTimeout(() => { + this.lines = 4; + this.changeDetectorRef.detectChanges(); + }, 0); + } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 9710a4f2d1..16a7009ae6 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -33,6 +33,8 @@ import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.com import { VarDirective } from './utils/var.directive'; import { TruncatableComponent } from './truncatable/truncatable.component'; import { ShaveDirective } from './utils/shave.directive'; +import { TextOverflowClampDirective } from './utils/clamp-directive'; + const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -80,7 +82,8 @@ const ENTRY_COMPONENTS = [ const DIRECTIVES = [ VarDirective, - ShaveDirective + ShaveDirective, + TextOverflowClampDirective ]; @NgModule({ diff --git a/src/app/shared/utils/clamp-directive.ts b/src/app/shared/utils/clamp-directive.ts new file mode 100644 index 0000000000..0cac019dcb --- /dev/null +++ b/src/app/shared/utils/clamp-directive.ts @@ -0,0 +1,20 @@ +import { + Directive, + ElementRef, + Input, + OnChanges +} from '@angular/core'; + +import * as clampLib from 'text-overflow-clamp'; + +@Directive({selector: '[dsClamp]'}) +export class TextOverflowClampDirective implements OnChanges { + @Input('dsClamp') lines: number; + + constructor(private el: ElementRef) { + } + + ngOnChanges(): void { + clampLib(this.el.nativeElement, this.lines); + } +} diff --git a/src/app/shared/utils/shave.directive.ts b/src/app/shared/utils/shave.directive.ts index 0622b8bb0c..df37a9a8c5 100644 --- a/src/app/shared/utils/shave.directive.ts +++ b/src/app/shared/utils/shave.directive.ts @@ -32,7 +32,6 @@ export class ShaveDirective implements OnDestroy, OnChanges { } ngOnChanges(): void { - console.log("onchange"); if (this.shaveHeight > 0) { this.runShave(); } diff --git a/yarn.lock b/yarn.lock index 6088cf16f8..53cd4a6b72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1942,6 +1942,10 @@ dom-serializer@0: domelementtype "~1.1.1" entities "~1.1.1" +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2791,6 +2795,13 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, gl once "^1.3.0" path-is-absolute "^1.0.0" +global@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4432,6 +4443,12 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -5781,6 +5798,10 @@ process@^0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -7144,6 +7165,12 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" +text-overflow-clamp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-overflow-clamp/-/text-overflow-clamp-1.0.0.tgz#9327faec1b85bf0b293d8c8df32243cbee5c050e" + dependencies: + global "^4.3.1" + throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" From f38164911267c862cb2ee4c0a3603d901b51cb73 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 20 Dec 2017 12:38:59 +0100 Subject: [PATCH 05/23] 46063: css attempt to fix multiline clamping --- .../search-service/search.service.ts | 2 +- src/app/app.component.scss | 5 ++++ .../item-list-element.component.html | 11 +++++--- ...-search-result-list-element.component.html | 4 +-- ...-search-result-list-element.component.scss | 3 +- src/app/shared/shared.module.ts | 6 +--- .../truncatable/truncatable.component.html | 1 - .../truncatable/truncatable.component.ts | 28 ------------------- src/app/shared/utils/clamp-directive.ts | 20 ------------- src/styles/_custom_variables.scss | 2 +- src/styles/_mixins.scss | 24 +++++++++++++++- 11 files changed, 42 insertions(+), 64 deletions(-) delete mode 100644 src/app/shared/truncatable/truncatable.component.html delete mode 100644 src/app/shared/truncatable/truncatable.component.ts delete mode 100644 src/app/shared/utils/clamp-directive.ts diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 4b5ba7b702..77327ee219 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -39,7 +39,7 @@ export class SearchService implements OnDestroy { totalPages = 5; mockedHighlights: string[] = new Array( 'This is a sample abstract.', - 'This is a sample abstract. But, to fill up some space, here\'s "Hello" in several different languages : ', + 'This is a sample abstractabstractabstractabstractabstractabstractabstractabstract. But, to fill up some space, here\'s "Hello" in several different languages : ', 'This is a Sample HTML webpage including several images and styles (CSS).', 'This is really just a sample abstract. But, Í’vé thrown ïn a cõuple of spëciâl charactèrs för êxtrå fuñ!', 'This abstract is really quite great', diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 00a3e56121..29be537891 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,4 +1,5 @@ @import '../styles/variables.scss'; +@import '../styles/mixins.scss'; @import '../../node_modules/bootstrap/scss/bootstrap.scss'; @import "../../node_modules/font-awesome/scss/font-awesome.scss"; @@ -31,3 +32,7 @@ body { margin-top: $content-spacing; margin-bottom: $content-spacing; } + +.clamp-3 { + @include clamp(3); +} \ No newline at end of file diff --git a/src/app/object-list/item-list-element/item-list-element.component.html b/src/app/object-list/item-list-element/item-list-element.component.html index ef5cf8aec4..1e88cc4889 100644 --- a/src/app/object-list/item-list-element/item-list-element.component.html +++ b/src/app/object-list/item-list-element/item-list-element.component.html @@ -3,13 +3,16 @@
- + {{authorMd.value}} ; - ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}}) + ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}}) -
-
+
+ {{item.findMetadata("dc.description.abstract") | dsTruncate:[200] }} +
diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html index bce61e9036..b1af777bcb 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html @@ -8,7 +8,7 @@ (, ) -
- +
+
\ No newline at end of file diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss index 88eb98509a..5a1e457327 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss @@ -1 +1,2 @@ -@import '../../../../styles/variables.scss'; \ No newline at end of file +@import '../../../../styles/variables.scss'; + diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 16a7009ae6..89df25a38e 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -31,9 +31,7 @@ import { SearchFormComponent } from './search-form/search-form.component'; import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component'; import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.component'; import { VarDirective } from './utils/var.directive'; -import { TruncatableComponent } from './truncatable/truncatable.component'; import { ShaveDirective } from './utils/shave.directive'; -import { TextOverflowClampDirective } from './utils/clamp-directive'; const MODULES = [ @@ -69,7 +67,6 @@ const COMPONENTS = [ ThumbnailComponent, WrapperListElementComponent, ViewModeSwitchComponent, - TruncatableComponent ]; const ENTRY_COMPONENTS = [ @@ -82,8 +79,7 @@ const ENTRY_COMPONENTS = [ const DIRECTIVES = [ VarDirective, - ShaveDirective, - TextOverflowClampDirective + ShaveDirective ]; @NgModule({ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html deleted file mode 100644 index aa070c834b..0000000000 --- a/src/app/shared/truncatable/truncatable.component.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts deleted file mode 100644 index ddece47fd9..0000000000 --- a/src/app/shared/truncatable/truncatable.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - ChangeDetectorRef, Component, ElementRef, Inject, Input, - OnInit -} from '@angular/core'; -import { NativeWindowRef, NativeWindowService } from '../window.service'; - -@Component({ - selector: 'ds-truncatable', - templateUrl: './truncatable.component.html' -}) -export class TruncatableComponent implements OnInit { - - @Input() lines: number; - @Input() innerHTML; - height; - styles: any; - - public constructor(private elementRef: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef, private changeDetectorRef: ChangeDetectorRef) { - } - - ngOnInit(): void { - this.styles = this._window.nativeWindow.getComputedStyle(this.elementRef.nativeElement); - setTimeout(() => { - this.height = this.styles.lineHeight.replace('px', '') * this.lines; - this.changeDetectorRef.detectChanges(); - }, 0); - } -} diff --git a/src/app/shared/utils/clamp-directive.ts b/src/app/shared/utils/clamp-directive.ts deleted file mode 100644 index 0cac019dcb..0000000000 --- a/src/app/shared/utils/clamp-directive.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - Directive, - ElementRef, - Input, - OnChanges -} from '@angular/core'; - -import * as clampLib from 'text-overflow-clamp'; - -@Directive({selector: '[dsClamp]'}) -export class TextOverflowClampDirective implements OnChanges { - @Input('dsClamp') lines: number; - - constructor(private el: ElementRef) { - } - - ngOnChanges(): void { - clampLib(this.el.nativeElement, this.lines); - } -} diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 12ebfd6618..f52a99f014 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -1,3 +1,3 @@ $content-spacing: $spacer * 1.5; -$button-height: $input-btn-padding-y * 2 + $input-btn-line-height + calculateRem($input-btn-border-width*2); \ No newline at end of file +$button-height: $input-btn-padding-y * 2 + $input-btn-line-height + calculateRem($input-btn-border-width*2); diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 73aa27eccc..6c773e34a3 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -1,4 +1,26 @@ @import '../../node_modules/bootstrap/scss/functions.scss'; @import '../../node_modules/bootstrap/scss/mixins.scss'; +@import '../../node_modules/bootstrap/scss/variables.scss'; -/* Custom mixins go here */ +@mixin clamp($lines) { + max-height: $lines * $line-height-base * $font-size-base; + position: relative; + overflow: hidden; + line-height: $line-height-base; + overflow-wrap: break-word; + + &:after { + content: "..."; + color: $link-color; + text-align: right; + position: absolute; + padding-right: 15px; + top: ($lines - 1) * $line-height-base * $font-size-base; + right: 0; + width: 30%; + min-width: 75px; + max-width: 150px; + height: $line-height-base * $font-size-base; + background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); + } +} \ No newline at end of file From 33e04fd324fd29aa22c2cc7873ef02710bbaa5f1 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 23 Jan 2018 10:21:35 +0100 Subject: [PATCH 06/23] 46063: saved currect state --- package.json | 2 - src/app/app.component.scss | 5 -- src/app/app.reducer.ts | 5 +- src/app/core/cache/response-cache.service.ts | 2 +- ...-search-result-list-element.component.html | 2 +- src/app/shared/shared.module.ts | 17 ++++-- .../shared/truncatable/truncatable.actions.ts | 29 ++++++++++ .../truncatable/truncatable.component.html | 1 + .../truncatable/truncatable.component.scss | 41 ++++++++++++++ .../truncatable/truncatable.component.ts | 42 ++++++++++++++ .../shared/truncatable/truncatable.reducer.ts | 31 ++++++++++ .../shared/truncatable/truncatable.service.ts | 47 ++++++++++++++++ src/app/shared/utils/shave.directive.ts | 56 ------------------- src/styles/_mixins.scss | 25 +-------- yarn.lock | 31 ---------- 15 files changed, 210 insertions(+), 126 deletions(-) create mode 100644 src/app/shared/truncatable/truncatable.actions.ts create mode 100644 src/app/shared/truncatable/truncatable.component.html create mode 100644 src/app/shared/truncatable/truncatable.component.scss create mode 100644 src/app/shared/truncatable/truncatable.component.ts create mode 100644 src/app/shared/truncatable/truncatable.reducer.ts create mode 100644 src/app/shared/truncatable/truncatable.service.ts delete mode 100644 src/app/shared/utils/shave.directive.ts diff --git a/package.json b/package.json index 74bb10bfed..2f74dd6cb8 100644 --- a/package.json +++ b/package.json @@ -105,8 +105,6 @@ "pem": "1.12.3", "reflect-metadata": "0.1.10", "rxjs": "5.4.3", - "shave": "^2.1.3", - "text-overflow-clamp": "^1.0.0", "ts-md5": "1.2.2", "webfontloader": "1.6.28", "zone.js": "0.8.18" diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 29be537891..00a3e56121 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,5 +1,4 @@ @import '../styles/variables.scss'; -@import '../styles/mixins.scss'; @import '../../node_modules/bootstrap/scss/bootstrap.scss'; @import "../../node_modules/font-awesome/scss/font-awesome.scss"; @@ -32,7 +31,3 @@ body { margin-top: $content-spacing; margin-bottom: $content-spacing; } - -.clamp-3 { - @include clamp(3); -} \ No newline at end of file diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index 72b29519de..117710e3c0 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -11,6 +11,7 @@ import { filterReducer, SearchFiltersState } from './+search-page/search-filters/search-filter/search-filter.reducer'; +import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer'; export interface AppState { router: fromRouter.RouterReducerState; @@ -18,6 +19,7 @@ export interface AppState { header: HeaderState; searchSidebar: SearchSidebarState; searchFilter: SearchFiltersState; + truncatable: TruncatablesState; } export const appReducers: ActionReducerMap = { @@ -25,5 +27,6 @@ export const appReducers: ActionReducerMap = { hostWindow: hostWindowReducer, header: headerReducer, searchSidebar: sidebarReducer, - searchFilter: filterReducer + searchFilter: filterReducer, + truncatable: truncatableReducer }; diff --git a/src/app/core/cache/response-cache.service.ts b/src/app/core/cache/response-cache.service.ts index d734940496..eac76c519e 100644 --- a/src/app/core/cache/response-cache.service.ts +++ b/src/app/core/cache/response-cache.service.ts @@ -4,7 +4,7 @@ import { MemoizedSelector, Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; import { ResponseCacheEntry } from './response-cache.reducer'; -import { hasNoValue, hasValue } from '../../shared/empty.util'; +import { hasNoValue } from '../../shared/empty.util'; import { ResponseCacheRemoveAction, ResponseCacheAddAction } from './response-cache.actions'; import { RestResponse } from './response-cache.models'; import { CoreState } from '../core.reducers'; diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html index b1af777bcb..4e5d890b89 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html @@ -9,6 +9,6 @@ (, )
-
+
\ No newline at end of file diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 89df25a38e..0a20938f5d 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -12,7 +12,6 @@ import { NgxPaginationModule } from 'ngx-pagination'; import { EnumKeysPipe } from './utils/enum-keys-pipe'; import { FileSizePipe } from './utils/file-size-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'; @@ -31,8 +30,9 @@ import { SearchFormComponent } from './search-form/search-form.component'; import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component'; import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.component'; import { VarDirective } from './utils/var.directive'; -import { ShaveDirective } from './utils/shave.directive'; - +import { TruncatePipe } from './utils/truncate.pipe'; +import { TruncatableComponent } from './truncatable/truncatable.component'; +import { TruncatableService } from './truncatable/truncatable.service'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -67,6 +67,7 @@ const COMPONENTS = [ ThumbnailComponent, WrapperListElementComponent, ViewModeSwitchComponent, + TruncatableComponent ]; const ENTRY_COMPONENTS = [ @@ -77,9 +78,12 @@ const ENTRY_COMPONENTS = [ SearchResultListElementComponent ]; +const PROVIDERS = [ + TruncatableService +]; + const DIRECTIVES = [ - VarDirective, - ShaveDirective + VarDirective ]; @NgModule({ @@ -93,6 +97,9 @@ const DIRECTIVES = [ ...ENTRY_COMPONENTS, ...DIRECTIVES ], + providers: [ + ...PROVIDERS + ], exports: [ ...MODULES, ...PIPES, diff --git a/src/app/shared/truncatable/truncatable.actions.ts b/src/app/shared/truncatable/truncatable.actions.ts new file mode 100644 index 0000000000..bc9a7e2258 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.actions.ts @@ -0,0 +1,29 @@ +import { Action } from '@ngrx/store'; +import { type } from '../ngrx/type'; + +/** + * For each action type in an action group, make a simple + * enum object for all of this group's action types. + * + * The 'type' utility function coerces strings into string + * literal types and runs a simple check to guarantee all + * action types in the application are unique. + */ +export const TruncatableActionTypes = { + TOGGLE: type('dspace/truncatable/TOGGLE'), +}; + +export class TruncatableAction implements Action { + id: string; + type; + constructor(name: string) { + this.id = name; + } +} + +/* tslint:disable:max-classes-per-file */ +export class TruncatableToggleAction extends TruncatableAction { + type = TruncatableActionTypes.TOGGLE; +} + +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html new file mode 100644 index 0000000000..bf03d73eca --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.scss b/src/app/shared/truncatable/truncatable.component.scss new file mode 100644 index 0000000000..b68bfd1d6e --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.scss @@ -0,0 +1,41 @@ +@import '../../../styles/_variables.scss'; +@import '../../../styles/_mixins.scss'; + +@mixin clamp($lines) { + max-height: $lines * $line-height-base * $font-size-base; + position: relative; + overflow: hidden; + line-height: $line-height-base; + overflow-wrap: break-word; + + &:after { + content: "..."; + color: $link-color; + text-align: right; + position: absolute; + padding-right: 15px; + top: ($lines - 1) * $line-height-base * $font-size-base; + right: 0; + width: 30%; + min-width: 75px; + max-width: 150px; + height: $line-height-base * $font-size-base; + background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); + } + + +} +.clamp-1 { +@include clamp(1); +} +.clamp-2 { + @include clamp(2); + } +.clamp-3 { +@include clamp(3); +} +.clamp-15 { +@include clamp(15); +} + + diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts new file mode 100644 index 0000000000..88185140ed --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -0,0 +1,42 @@ +import { + Component, Input +} from '@angular/core'; +import { TruncatableService } from './truncatable.service'; + +@Component({ + selector: 'ds-truncatable', + templateUrl: './truncatable.component.html', + styleUrls: ['./truncatable.component.scss'] +}) +export class TruncatableComponent { + @Input() minLines: number; + @Input() maxLines: number; + @Input() initialExpand = false; + @Input() id: string; + @Input() content; + private lines: number; + + public constructor(private service: TruncatableService) { + + } + + ngOnInit() { + if (this.initialExpand) { + this.service.toggle(this.id); + } + this.setLines(); + } + + public toggleCollapse() { + this.service.toggle(this.id); + this.setLines(); + } + + private setLines() { + if (this.service.isCollapsed(this.id)) { + this.lines = this.minLines; + } else { + this.lines = this.maxLines; + } + } +} diff --git a/src/app/shared/truncatable/truncatable.reducer.ts b/src/app/shared/truncatable/truncatable.reducer.ts new file mode 100644 index 0000000000..f48d92f49c --- /dev/null +++ b/src/app/shared/truncatable/truncatable.reducer.ts @@ -0,0 +1,31 @@ +import { TruncatableAction, TruncatableActionTypes } from './truncatable.actions'; + +export interface TruncatableState { + collapsed: boolean; +} + +export interface TruncatablesState { + [id: string]: TruncatableState +} + +const initialState: TruncatablesState = Object.create(null); + +export function truncatableReducer(state = initialState, action: TruncatableAction): TruncatablesState { + + switch (action.type) { + + case TruncatableActionTypes.TOGGLE: { + if (!state[action.id]) { + state[action.id] = {collapsed: false}; + } + return Object.assign({}, state, { + [action.id]: { + collapsed: !state[action.id].collapsed, + } + }); + } + default: { + return state; + } + } +} diff --git a/src/app/shared/truncatable/truncatable.service.ts b/src/app/shared/truncatable/truncatable.service.ts new file mode 100644 index 0000000000..e2851a8a3b --- /dev/null +++ b/src/app/shared/truncatable/truncatable.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { createSelector, MemoizedSelector, Store } from '@ngrx/store'; +import { Observable } from 'rxjs/Observable'; +import { TruncatablesState, TruncatableState } from './truncatable.reducer'; +import { TruncatableToggleAction } from './truncatable.actions'; +import { hasValue } from '../empty.util'; + +const truncatableStateSelector = (state: TruncatablesState) => state.truncatable; + +@Injectable() +export class TruncatableService { + + constructor(private store: Store) { + } + + isCollapsed(id: string): Observable { + return this.store.select(truncatableByIdSelector(id)) + .map((object: TruncatableState) => { + console.log(object); + if (object) { + return object.collapsed; + } else { + return false; + } + }); + } + + public toggle(id: string): void { + this.store.dispatch(new TruncatableToggleAction(id)); + } +} + +function truncatableByIdSelector(id: string): MemoizedSelector { + return keySelector(id); +} + +export function keySelector(key: string): MemoizedSelector { + return createSelector(truncatableStateSelector, (state: TruncatableState) => { + console.log(state, 'test'); + + if (hasValue(state)) { + return state[key]; + } else { + return undefined; + } + }); +} diff --git a/src/app/shared/utils/shave.directive.ts b/src/app/shared/utils/shave.directive.ts deleted file mode 100644 index df37a9a8c5..0000000000 --- a/src/app/shared/utils/shave.directive.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - Directive, ElementRef, Inject, Input, OnChanges, OnDestroy, - OnInit -} from '@angular/core'; -import { default as shave } from 'shave'; -import { NativeWindowRef, NativeWindowService } from '../window.service'; -import { Observable } from 'rxjs/Observable'; - -@Directive({ - selector: '[dsShave]' -}) -export class ShaveDirective implements OnDestroy, OnChanges { - - @Input() shave: IShaveOptions = {}; - - @Input() - set shaveHeight(value) { - if (value > 0) { - console.log(value); - this._shaveHeight = value; - } - }; - - get shaveHeight() { - return this._shaveHeight; - } - - private _shaveHeight = 72; - private sub; - - constructor(private ele: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { - } - - ngOnChanges(): void { - if (this.shaveHeight > 0) { - this.runShave(); - } - this.subscribeForResizeEvent(); - } - - subscribeForResizeEvent() { - const obs = Observable.fromEvent(this._window.nativeWindow, 'resize'); - this.sub = obs.subscribe((e) => this.runShave()); - } - - private runShave() { - shave(this.ele.nativeElement, this.shaveHeight, this.shave); - } - - ngOnDestroy(): void { - if (this.sub) { - this.sub.unsubscribe(); - } - } - -} diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 6c773e34a3..564ffc7755 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -1,26 +1,3 @@ @import '../../node_modules/bootstrap/scss/functions.scss'; @import '../../node_modules/bootstrap/scss/mixins.scss'; -@import '../../node_modules/bootstrap/scss/variables.scss'; - -@mixin clamp($lines) { - max-height: $lines * $line-height-base * $font-size-base; - position: relative; - overflow: hidden; - line-height: $line-height-base; - overflow-wrap: break-word; - - &:after { - content: "..."; - color: $link-color; - text-align: right; - position: absolute; - padding-right: 15px; - top: ($lines - 1) * $line-height-base * $font-size-base; - right: 0; - width: 30%; - min-width: 75px; - max-width: 150px; - height: $line-height-base * $font-size-base; - background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); - } -} \ No newline at end of file +@import '../../node_modules/bootstrap/scss/variables.scss'; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 53cd4a6b72..91b2a787e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1942,10 +1942,6 @@ dom-serializer@0: domelementtype "~1.1.1" entities "~1.1.1" -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2795,13 +2791,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, gl once "^1.3.0" path-is-absolute "^1.0.0" -global@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4443,12 +4432,6 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -5798,10 +5781,6 @@ process@^0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -6668,10 +6647,6 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -shave@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/shave/-/shave-2.1.3.tgz#89c7df997d35a95bc31703c9150161bc98d3fa3b" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -7165,12 +7140,6 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -text-overflow-clamp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/text-overflow-clamp/-/text-overflow-clamp-1.0.0.tgz#9327faec1b85bf0b293d8c8df32243cbee5c050e" - dependencies: - global "^4.3.1" - throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" From 1b0fc45b6d745d4d3a5583fb089fb5e13a5b5182 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Wed, 24 Jan 2018 15:22:31 +0100 Subject: [PATCH 07/23] 46063: working CSS truncation, but were switching to JS again... --- src/app/shared/animations/overlay.ts | 10 +++ .../object-grid/object-grid.component.html | 4 +- .../object-grid/object-grid.component.scss | 29 ++++---- ...-search-result-grid-element.component.html | 67 ++++++++++--------- ...-search-result-grid-element.component.scss | 12 ++++ ...em-search-result-grid-element.component.ts | 5 +- .../search-result-grid-element.component.ts | 10 ++- .../object-list/object-list.component.html | 2 +- ...-search-result-list-element.component.html | 36 +++++++--- src/app/shared/shared.module.ts | 4 +- .../truncatable-part.component.html | 3 + .../truncatable-part.component.scss | 42 ++++++++++++ .../truncatable-part.component.ts | 42 ++++++++++++ .../shared/truncatable/truncatable.actions.ts | 10 +++ .../truncatable/truncatable.component.html | 4 +- .../truncatable/truncatable.component.scss | 41 ------------ .../truncatable/truncatable.component.ts | 38 +++++------ .../shared/truncatable/truncatable.reducer.ts | 14 +++- .../shared/truncatable/truncatable.service.ts | 13 ++-- src/styles/_functions.scss | 8 +++ 20 files changed, 262 insertions(+), 132 deletions(-) create mode 100644 src/app/shared/animations/overlay.ts create mode 100644 src/app/shared/truncatable/truncatable-part/truncatable-part.component.html create mode 100644 src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss create mode 100644 src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts 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-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..32ad2df187 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; } } + +.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/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..d1f37c952e 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,37 @@ -
- - - - -
-

+ +
+ +
+ + +
+
+
+
+ +

+
+

+ + {{dso.findMetadata("dc.date.issued")}} + , + + + +

+ +

+

+
+
+ View +
+
-

- - - , ... - - - - , - {{dso.findMetadata("dc.date.issued")}} - - -

-

-

- -
- View
-
- -
- + \ 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.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts index f9fe13cb88..ee03a8b545 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,14 @@ 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 { slide } from '../../../animations/slide'; +import { overlay } from '../../../animations/overlay'; @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: [slide, overlay], }) @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..9be2647cba 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,7 +17,7 @@ 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) { + public constructor(@Inject('objectElementProvider') public gridable: ListableObject, private truncatableService: TruncatableService) { super(gridable); 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/object-list.component.html b/src/app/shared/object-list/object-list.component.html index 8de695ae58..4a7221d3e6 100644 --- a/src/app/shared/object-list/object-list.component.html +++ b/src/app/shared/object-list/object-list.component.html @@ -10,7 +10,7 @@ (sortDirectionChange)="onSortDirectionChange($event)" (sortFieldChange)="onSortFieldChange($event)" (paginationChange)="onPaginationChange($event)"> -
    +
    • 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 4e5d890b89..104a6be716 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,14 +1,28 @@ - -
      + + + + +
      - - - - - - (, ) + + + (, ) + + + + + + -
      - +
      + + +
      -
      \ No newline at end of file +
      \ No newline at end of file diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index e05a086f60..202a4b0c23 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -43,6 +43,7 @@ import { VarDirective } from './utils/var.directive'; import { TruncatePipe } from './utils/truncate.pipe'; import { TruncatableComponent } from './truncatable/truncatable.component'; import { TruncatableService } from './truncatable/truncatable.service'; +import { TruncatablePartComponent } from './truncatable/truncatable-part/truncatable-part.component'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -82,7 +83,8 @@ const COMPONENTS = [ GridThumbnailComponent, WrapperListElementComponent, ViewModeSwitchComponent, - TruncatableComponent + TruncatableComponent, + TruncatablePartComponent, ]; const ENTRY_COMPONENTS = [ diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html new file mode 100644 index 0000000000..60c474395b --- /dev/null +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -0,0 +1,3 @@ +
      + +
      \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss new file mode 100644 index 0000000000..cd3d245f7f --- /dev/null +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -0,0 +1,42 @@ +@import '../../../../styles/variables'; +@import '../../../../styles/mixins'; + +@mixin clamp($lines, $size-factor: 1, $line-height: $line-height-base) { + $height: $line-height * $font-size-base * $size-factor; + max-height: $lines * $height; + position: relative; + overflow: hidden; + line-height: $line-height; + overflow-wrap: break-word; + &:after { + content: "..."; + color: $link-color; + text-align: right; + position: absolute; + padding-right: 15px; + top: ($lines - 1) * $height; + right: 0; + width: 30%; + min-width: 75px; + max-width: 150px; + height: $height; + background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); + } + +} + +$h4-factor: strip-unit($h4-font-size); +@for $i from 1 through 15 { + .clamp-#{$i} { + @include clamp($i); + &.title { + @include clamp($i, 1.25); + } + &.h4 { + @include clamp($i, $h4-factor, $headings-line-height); + + } + } +} + + diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts new file mode 100644 index 0000000000..83a5f04ba4 --- /dev/null +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -0,0 +1,42 @@ +import { + Component, Input, OnDestroy, OnInit, ElementRef, ViewChild +} from '@angular/core'; +import { TruncatableService } from '../truncatable.service'; + +@Component({ + selector: 'ds-truncatable-part', + templateUrl: './truncatable-part.component.html', + styleUrls: ['./truncatable-part.component.scss'] +}) + +export class TruncatablePartComponent implements OnInit, OnDestroy { + @Input() minLines: number; + @Input() maxLines: number; + @Input() initialExpand = false; + @Input() id: string; + @Input() type: string; + private lines: number; + private sub; + + public constructor(private service: TruncatableService) { + } + + ngOnInit() { + this.setLines(); + } + + private setLines() { + this.sub = this.service.isCollapsed(this.id).subscribe((collapsed: boolean) => { + if (collapsed) { + this.lines = this.minLines; + } else { + this.lines = this.maxLines; + } + }); + } + + ngOnDestroy(): void { + this.sub.unsubscribe(); + } + +} diff --git a/src/app/shared/truncatable/truncatable.actions.ts b/src/app/shared/truncatable/truncatable.actions.ts index bc9a7e2258..9d3a51219b 100644 --- a/src/app/shared/truncatable/truncatable.actions.ts +++ b/src/app/shared/truncatable/truncatable.actions.ts @@ -11,6 +11,8 @@ import { type } from '../ngrx/type'; */ export const TruncatableActionTypes = { TOGGLE: type('dspace/truncatable/TOGGLE'), + COLLAPSE: type('dspace/truncatable/COLLAPSE'), + EXPAND: type('dspace/truncatable/EXPAND'), }; export class TruncatableAction implements Action { @@ -26,4 +28,12 @@ export class TruncatableToggleAction extends TruncatableAction { type = TruncatableActionTypes.TOGGLE; } +export class TruncatableCollapseAction extends TruncatableAction { + type = TruncatableActionTypes.COLLAPSE; +} + +export class TruncatableExpandAction extends TruncatableAction { + type = TruncatableActionTypes.EXPAND; +} + /* tslint:enable:max-classes-per-file */ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index bf03d73eca..d3ed37e596 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1 +1,3 @@ -
      \ No newline at end of file +
      + +
      \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.scss b/src/app/shared/truncatable/truncatable.component.scss index b68bfd1d6e..e69de29bb2 100644 --- a/src/app/shared/truncatable/truncatable.component.scss +++ b/src/app/shared/truncatable/truncatable.component.scss @@ -1,41 +0,0 @@ -@import '../../../styles/_variables.scss'; -@import '../../../styles/_mixins.scss'; - -@mixin clamp($lines) { - max-height: $lines * $line-height-base * $font-size-base; - position: relative; - overflow: hidden; - line-height: $line-height-base; - overflow-wrap: break-word; - - &:after { - content: "..."; - color: $link-color; - text-align: right; - position: absolute; - padding-right: 15px; - top: ($lines - 1) * $line-height-base * $font-size-base; - right: 0; - width: 30%; - min-width: 75px; - max-width: 150px; - height: $line-height-base * $font-size-base; - background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); - } - - -} -.clamp-1 { -@include clamp(1); -} -.clamp-2 { - @include clamp(2); - } -.clamp-3 { -@include clamp(3); -} -.clamp-15 { -@include clamp(15); -} - - diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index 88185140ed..b7667f6f51 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -9,34 +9,34 @@ import { TruncatableService } from './truncatable.service'; styleUrls: ['./truncatable.component.scss'] }) export class TruncatableComponent { - @Input() minLines: number; - @Input() maxLines: number; @Input() initialExpand = false; @Input() id: string; - @Input() content; - private lines: number; + @Input() onHover = false; public constructor(private service: TruncatableService) { - } ngOnInit() { if (this.initialExpand) { - this.service.toggle(this.id); - } - this.setLines(); - } - - public toggleCollapse() { - this.service.toggle(this.id); - this.setLines(); - } - - private setLines() { - if (this.service.isCollapsed(this.id)) { - this.lines = this.minLines; + this.service.expand(this.id); } else { - this.lines = this.maxLines; + this.service.collapse(this.id); } } + + public hoverCollapse() { + if (this.onHover) { + this.service.collapse(this.id); + } + } + + public hoverExpand() { + if (this.onHover) { + this.service.expand(this.id); + } + } + + public toggle() { + this.service.toggle(this.id); + } } diff --git a/src/app/shared/truncatable/truncatable.reducer.ts b/src/app/shared/truncatable/truncatable.reducer.ts index f48d92f49c..d9a2111682 100644 --- a/src/app/shared/truncatable/truncatable.reducer.ts +++ b/src/app/shared/truncatable/truncatable.reducer.ts @@ -14,7 +14,19 @@ export function truncatableReducer(state = initialState, action: TruncatableActi switch (action.type) { - case TruncatableActionTypes.TOGGLE: { + case TruncatableActionTypes.COLLAPSE: { + return Object.assign({}, state, { + [action.id]: { + collapsed: true, + } + }); + } case TruncatableActionTypes.EXPAND: { + return Object.assign({}, state, { + [action.id]: { + collapsed: false, + } + }); + } case TruncatableActionTypes.TOGGLE: { if (!state[action.id]) { state[action.id] = {collapsed: false}; } diff --git a/src/app/shared/truncatable/truncatable.service.ts b/src/app/shared/truncatable/truncatable.service.ts index e2851a8a3b..5f36c6a60d 100644 --- a/src/app/shared/truncatable/truncatable.service.ts +++ b/src/app/shared/truncatable/truncatable.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { createSelector, MemoizedSelector, Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; import { TruncatablesState, TruncatableState } from './truncatable.reducer'; -import { TruncatableToggleAction } from './truncatable.actions'; +import { TruncatableExpandAction, TruncatableToggleAction, TruncatableCollapseAction } from './truncatable.actions'; import { hasValue } from '../empty.util'; const truncatableStateSelector = (state: TruncatablesState) => state.truncatable; @@ -16,7 +16,6 @@ export class TruncatableService { isCollapsed(id: string): Observable { return this.store.select(truncatableByIdSelector(id)) .map((object: TruncatableState) => { - console.log(object); if (object) { return object.collapsed; } else { @@ -28,6 +27,14 @@ export class TruncatableService { public toggle(id: string): void { this.store.dispatch(new TruncatableToggleAction(id)); } + + public collapse(id: string): void { + this.store.dispatch(new TruncatableCollapseAction(id)); + } + + public expand(id: string): void { + this.store.dispatch(new TruncatableExpandAction(id)); + } } function truncatableByIdSelector(id: string): MemoizedSelector { @@ -36,8 +43,6 @@ function truncatableByIdSelector(id: string): MemoizedSelector(key: string): MemoizedSelector { return createSelector(truncatableStateSelector, (state: TruncatableState) => { - console.log(state, 'test'); - if (hasValue(state)) { return state[key]; } else { diff --git a/src/styles/_functions.scss b/src/styles/_functions.scss index 16c5040e03..81de954285 100644 --- a/src/styles/_functions.scss +++ b/src/styles/_functions.scss @@ -1,4 +1,12 @@ @function calculateRem($size) { $remSize: $size / 16px; @return $remSize; +} + +@function strip-unit($number) { + @if type-of($number) == 'number' and not unitless($number) { + @return $number / ($number * 0 + 1); + } + + @return $number; } \ No newline at end of file From 58a26c03ccb4fafb41e6d7db387e143ab739573e Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 25 Jan 2018 14:01:02 +0100 Subject: [PATCH 08/23] 46063: removed ellipsis, added other animations.. --- src/app/shared/animations/focus.ts | 19 ++++++++++++++++ .../object-grid/object-grid.component.scss | 2 +- ...-search-result-grid-element.component.html | 16 +++++--------- ...em-search-result-grid-element.component.ts | 5 ++--- .../object-list/object-list.component.html | 2 +- .../object-list/object-list.component.scss | 2 +- ...-search-result-list-element.component.html | 22 +++++++++---------- ...em-search-result-list-element.component.ts | 19 +++++----------- .../search-result-list-element.component.ts | 8 ++++++- .../truncatable-part.component.scss | 4 +--- .../truncatable-part.component.ts | 8 +++---- 11 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 src/app/shared/animations/focus.ts diff --git a/src/app/shared/animations/focus.ts b/src/app/shared/animations/focus.ts new file mode 100644 index 0000000000..6458fd0d78 --- /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': '0 0 6px #777777' })), + + 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/object-grid/object-grid.component.scss b/src/app/shared/object-grid/object-grid.component.scss index 32ad2df187..1b9418be48 100644 --- a/src/app/shared/object-grid/object-grid.component.scss +++ b/src/app/shared/object-grid/object-grid.component.scss @@ -7,7 +7,7 @@ ds-wrapper-grid-element ::ng-deep { width: 100%; } div.card { - margin-bottom: 20px; + margin-bottom: $spacer; } } 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 d1f37c952e..e35e06ec03 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,28 +1,23 @@ -
      - +
      +
      -
      - -

      -
      +

      - + {{dso.findMetadata("dc.date.issued")}} ,

      - +

      @@ -32,6 +27,5 @@ class="lead btn btn-primary viewButton">View
      -
      \ 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.ts b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts index ee03a8b545..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,14 +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 { slide } from '../../../animations/slide'; -import { overlay } from '../../../animations/overlay'; +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', - animations: [slide, overlay], + animations: [focusShadow], }) @renderElementsFor(ItemSearchResult, ViewMode.Grid) diff --git a/src/app/shared/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html index 4a7221d3e6..6ccac35464 100644 --- a/src/app/shared/object-list/object-list.component.html +++ b/src/app/shared/object-list/object-list.component.html @@ -11,7 +11,7 @@ (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/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 104a6be716..9aa176fb08 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,11 @@ - - - -
      +
      + +
      - - + (, -
      - - +
      + + +
      \ 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.ts b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts index 76e8eb288f..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 @@ -6,25 +6,16 @@ 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 implements OnInit { - lines = 3; - - constructor(@Inject('objectElementProvider') public listable: ListableObject, private changeDetectorRef: ChangeDetectorRef) { - super(listable); - } - - ngOnInit() { - setTimeout(() => { - this.lines = 4; - this.changeDetectorRef.detectChanges(); - }, 0); - } +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/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index cd3d245f7f..b66eab7005 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -9,9 +9,7 @@ line-height: $line-height; overflow-wrap: break-word; &:after { - content: "..."; - color: $link-color; - text-align: right; + content: ""; position: absolute; padding-right: 15px; top: ($lines - 1) * $height; diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 83a5f04ba4..2d643f4a33 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -11,11 +11,11 @@ import { TruncatableService } from '../truncatable.service'; export class TruncatablePartComponent implements OnInit, OnDestroy { @Input() minLines: number; - @Input() maxLines: number; + @Input() maxLines = -1; @Input() initialExpand = false; @Input() id: string; @Input() type: string; - private lines: number; + private lines: string; private sub; public constructor(private service: TruncatableService) { @@ -28,9 +28,9 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { private setLines() { this.sub = this.service.isCollapsed(this.id).subscribe((collapsed: boolean) => { if (collapsed) { - this.lines = this.minLines; + this.lines = this.minLines.toString(); } else { - this.lines = this.maxLines; + this.lines = this.maxLines < 0 ? 'none' : this.maxLines.toString(); } }); } From 5f76bba05065bc6710080cbf79d3d7d78270a0f9 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Mon, 5 Feb 2018 11:32:26 +0100 Subject: [PATCH 09/23] 46063: truncation finished, still have to fix some existing tests --- src/app/shared/animations/focus.ts | 2 +- ...arch-result-grid-element.component.spec.ts | 21 ++-- ...arch-result-grid-element.component.spec.ts | 9 +- ...-search-result-grid-element.component.html | 16 +-- ...arch-result-grid-element.component.spec.ts | 24 +++-- .../collection-list-element.component.spec.ts | 59 +++++++++++ .../community-list-element.component.spec.ts | 65 ++++++++++++ .../item-list-element.component.spec.ts | 67 +++++++++++++ .../object-list/object-list.component.html | 2 +- ...arch-result-list-element.component.spec.ts | 68 +++++++++++++ ...arch-result-list-element.component.spec.ts | 69 +++++++++++++ ...-search-result-list-element.component.html | 4 - ...arch-result-list-element.component.spec.ts | 86 ++++++++++++++++ .../truncatable-part.component.html | 6 +- .../truncatable-part.component.scss | 42 ++++---- .../truncatable-part.component.spec.ts | 76 ++++++++++++++ .../truncatable-part.component.ts | 13 ++- .../truncatable/truncatable.component.spec.ts | 99 +++++++++++++++++++ .../truncatable/truncatable.component.ts | 6 +- .../truncatable/truncatable.reducer.spec.ts | 96 ++++++++++++++++++ .../truncatable/truncatable.service.spec.ts | 54 ++++++++++ 21 files changed, 826 insertions(+), 58 deletions(-) create mode 100644 src/app/shared/object-list/collection-list-element/collection-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/community-list-element/community-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.spec.ts create mode 100644 src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.spec.ts create mode 100644 src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts create mode 100644 src/app/shared/truncatable/truncatable.component.spec.ts create mode 100644 src/app/shared/truncatable/truncatable.reducer.spec.ts create mode 100644 src/app/shared/truncatable/truncatable.service.spec.ts diff --git a/src/app/shared/animations/focus.ts b/src/app/shared/animations/focus.ts index 6458fd0d78..33a5010629 100644 --- a/src/app/shared/animations/focus.ts +++ b/src/app/shared/animations/focus.ts @@ -2,7 +2,7 @@ import { animate, state, transition, trigger, style } from '@angular/animations' export const focusShadow = trigger('focusShadow', [ - state('focus', style({ 'box-shadow': '0 0 6px #777777' })), + state('focus', style({ 'box-shadow': 'rgba(119, 119, 119, 0.6) 0px 0px 6px' })), state('blur', style({ 'box-shadow': 'none' })), 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 a3b3710080..9eb65dbbdd 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,4 +1,4 @@ -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'; @@ -8,6 +8,7 @@ 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'; let fixture: ComponentFixture; const queryParam = 'test query'; @@ -18,29 +19,33 @@ const activatedRouteStub = { scope: scopeParam }) }; +const truncatableServiceStub: any = { + isCollapsed: (id: number) => Observable.of(true), +}; + const mockCollection: Collection = Object.assign(new Collection(), { metadata: [ { key: 'dc.description.abstract', language: 'en_US', value: 'Short description' - } ] + }] }); - -const createdGridElementComponent: CollectionSearchResultGridElementComponent = new CollectionSearchResultGridElementComponent(mockCollection); +const createdGridElementComponent: CollectionSearchResultGridElementComponent = new CollectionSearchResultGridElementComponent(mockCollection, truncatableServiceStub as TruncatableService); describe('CollectionSearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ], + declarations: [CollectionSearchResultGridElementComponent, TruncatePipe], providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, { provide: ActivatedRoute, useValue: activatedRouteStub }, { provide: Router, useClass: RouterStub }, { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } ], - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); // compile template and css })); @@ -52,12 +57,12 @@ describe('CollectionSearchResultGridElementComponent', () => { expect(fixture.debugElement.query(By.css('ds-collection-search-result-grid-element'))).toBeDefined(); }); - it('should only show the description if "short description" metadata is present',() => { + it('should only show the description if "short description" metadata is present', () => { const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text'))); if (mockCollection.shortDescription.length > 0) { expect(descriptionText).toBeDefined(); - }else { + } else { expect(descriptionText).not.toBeDefined(); } }); 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 dd9e16a120..6d70d08901 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 @@ -7,6 +7,8 @@ import { 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'; + let fixture: ComponentFixture; const queryParam = 'test query'; @@ -17,6 +19,10 @@ const activatedRouteStub = { scope: scopeParam }) }; +const truncatableServiceStub: any = { + isCollapsed: (id: number) => Observable.of(true), +}; + const mockCommunity: Community = Object.assign(new Community(), { metadata: [ { @@ -27,13 +33,14 @@ const mockCommunity: Community = Object.assign(new Community(), { }); -const createdGridElementComponent: CommunitySearchResultGridElementComponent = new CommunitySearchResultGridElementComponent(mockCommunity); +const createdGridElementComponent: CommunitySearchResultGridElementComponent = new CommunitySearchResultGridElementComponent(mockCommunity, truncatableServiceStub as TruncatableService); describe('CommunitySearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ], providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, { provide: ActivatedRoute, useValue: activatedRouteStub }, { provide: Router, useClass: RouterStub }, { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } 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 e35e06ec03..352ba4881d 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 @@ -7,21 +7,23 @@
      -

      + +

      +

      - + {{dso.findMetadata("dc.date.issued")}} ,

      - -

      -

      -
      +

      + + + +

      View 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 1a2ca908e2..172888e98c 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 @@ -7,6 +7,7 @@ import { 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 { TruncatableService } from '../../../truncatable/truncatable.service'; let itemSearchResultGridElementComponent: ItemSearchResultGridElementComponent; let fixture: ComponentFixture; @@ -18,6 +19,11 @@ const activatedRouteStub = { scope: scopeParam }) }; + +const truncatableServiceStub: any = { + isCollapsed: (id: number) => Observable.of(true), +}; + const mockItem: Item = Object.assign(new Item(), { metadata: [ { @@ -31,48 +37,48 @@ const mockItem: Item = Object.assign(new Item(), { value: '1650-06-26' }] }); -const createdGridElementComponent:ItemSearchResultGridElementComponent= new ItemSearchResultGridElementComponent(mockItem); +const createdGridElementComponent: ItemSearchResultGridElementComponent = new ItemSearchResultGridElementComponent(mockItem, truncatableServiceStub as TruncatableService); describe('ItemSearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ItemSearchResultGridElementComponent, TruncatePipe ], + declarations: [ItemSearchResultGridElementComponent, TruncatePipe], providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, { provide: ActivatedRoute, useValue: activatedRouteStub }, { provide: Router, useClass: RouterStub }, { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } ], - schemas: [ NO_ERRORS_SCHEMA ] + schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); // compile template and css })); beforeEach(async(() => { fixture = TestBed.createComponent(ItemSearchResultGridElementComponent); itemSearchResultGridElementComponent = fixture.componentInstance; - })); - it('should show the item result cards in the grid element',() => { + it('should show the item result cards in the grid element', () => { expect(fixture.debugElement.query(By.css('ds-item-search-result-grid-element'))).toBeDefined(); }); - it('should only show the author span if the author metadata is present',() => { + it('should only show the author span if the author metadata is present', () => { const itemAuthorField = expect(fixture.debugElement.query(By.css('p.item-authors'))); if (mockItem.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0) { expect(itemAuthorField).toBeDefined(); - }else { + } else { expect(itemAuthorField).not.toBeDefined(); } }); - it('should only show the date span if the issuedate is present',() => { + it('should only show the date span if the issuedate is present', () => { const dateField = expect(fixture.debugElement.query(By.css('span.item-list-date'))); if (mockItem.findMetadata('dc.date.issued').length > 0) { expect(dateField).toBeDefined(); - }else { + } else { expect(dateField).not.toBeDefined(); } }); 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..0f1b7c4444 --- /dev/null +++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.spec.ts @@ -0,0 +1,59 @@ +import { CollectionListElementComponent } from './collection-list-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 { By } from '@angular/platform-browser'; +import { Collection } from '../../../core/shared/collection.model'; +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(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + }] +}); +const createdListElementComponent:CollectionListElementComponent= new CollectionListElementComponent(mockCollection); + +describe('CollectionListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CollectionListElementComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdListElementComponent)} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CollectionListElementComponent); + })); + + it('should show the collection cards in the list element',() => { + expect(fixture.debugElement.query(By.css('ds-collection-list-element'))).toBeDefined(); + }); + + it('should only show the description if "short description" metadata is present',() => { + const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text'))); + + if (mockCollection.shortDescription.length > 0) { + expect(descriptionText).toBeDefined(); + }else { + expect(descriptionText).not.toBeDefined(); + } + }); +}) 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..ff5a7fa441 --- /dev/null +++ b/src/app/shared/object-list/community-list-element/community-list-element.component.spec.ts @@ -0,0 +1,65 @@ +import { CommunityListElementComponent } from './community-list-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 { By } from '@angular/platform-browser'; +import { Community } from '../../../core/shared/community.model'; + +let communityListElementComponent: CommunityListElementComponent; +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(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + }] +}); + +const createdListElementComponent:CommunityListElementComponent= new CommunityListElementComponent(mockCommunity); + +describe('CommunityListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CommunityListElementComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdListElementComponent)} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CommunityListElementComponent); + communityListElementComponent = fixture.componentInstance; + + })); + + it('should show the community cards in the list element',() => { + expect(fixture.debugElement.query(By.css('ds-community-list-element'))).toBeDefined(); + }) + + it('should only show the description if "short description" metadata is present',() => { + const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text'))); + + if (mockCommunity.shortDescription.length > 0) { + expect(descriptionText).toBeDefined(); + }else { + expect(descriptionText).not.toBeDefined(); + } + }); +}); 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..3383ed8454 --- /dev/null +++ b/src/app/shared/object-list/item-list-element/item-list-element.component.spec.ts @@ -0,0 +1,67 @@ +import { ItemListElementComponent } from './item-list-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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../utils/truncate.pipe'; +import { Item } from '../../../core/shared/item.model'; + +let itemListElementComponent: ItemListElementComponent; +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(), { + metadata: [ + { + key: 'dc.contributor.author', + language: 'en_US', + value: 'Smith, Donald' + }] +}); + +const createdListElementComponent:ItemListElementComponent= new ItemListElementComponent(mockItem); + +describe('ItemListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ItemListElementComponent , TruncatePipe], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: {createdListElementComponent}} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemListElementComponent); + itemListElementComponent = fixture.componentInstance; + + })); + + it('should show the item cards in the list element',() => { + expect(fixture.debugElement.query(By.css('ds-item-list-element'))).toBeDefined() + }); + + it('should only show the author span if the author metadata is present',() => { + const itemAuthorField = expect(fixture.debugElement.query(By.css('p.item-authors'))); + + if (mockItem.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0) { + expect(itemAuthorField).toBeDefined(); + }else { + expect(itemAuthorField).toBeDefined(); + } + }); + +}) diff --git a/src/app/shared/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html index 6ccac35464..420886668a 100644 --- a/src/app/shared/object-list/object-list.component.html +++ b/src/app/shared/object-list/object-list.component.html @@ -11,7 +11,7 @@ (sortFieldChange)="onSortFieldChange($event)" (paginationChange)="onPaginationChange($event)">
        -
      • +
      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..37756b5916 --- /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,68 @@ +import { CollectionSearchResultListElementComponent } from './collection-search-result-list-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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Collection } from '../../../../core/shared/collection.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; + +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(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + }] + +}); +const createdListElementComponent: CollectionSearchResultListElementComponent = new CollectionSearchResultListElementComponent(mockCollection, truncatableServiceStub as TruncatableService); + +describe('CollectionSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [CollectionSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CollectionSearchResultListElementComponent); + })); + + it('should show the item result cards in the list element', () => { + expect(fixture.debugElement.query(By.css('ds-collection-search-result-list-element'))).toBeDefined(); + }); + + it('should only show the description if "short description" metadata is present', () => { + const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text'))); + + if (mockCollection.shortDescription.length > 0) { + expect(descriptionText).toBeDefined(); + } else { + expect(descriptionText).not.toBeDefined(); + } + }); +}); 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..3e82e824ec --- /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,69 @@ +import { CommunitySearchResultListElementComponent } from './community-search-result-list-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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Community } from '../../../../core/shared/community.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; + +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(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + } ] + +}); + +const createdListElementComponent: CommunitySearchResultListElementComponent = new CommunitySearchResultListElementComponent(mockCommunity, truncatableServiceStub as TruncatableService); + +describe('CommunitySearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CommunitySearchResultListElementComponent, TruncatePipe ], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CommunitySearchResultListElementComponent); + })); + + it('should show the item result cards in the list element', () => { + expect(fixture.debugElement.query(By.css('ds-community-search-result-list-element'))).toBeDefined(); + }); + + it('should only show the description if "short description" metadata is present',() => { + const descriptionText = expect(fixture.debugElement.query(By.css('p.card-text'))); + + if (mockCommunity.shortDescription.length > 0) { + expect(descriptionText).toBeDefined(); + }else { + expect(descriptionText).not.toBeDefined(); + } + }); +}); 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 9aa176fb08..d7ef1c673c 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,9 +1,7 @@ -
      -
      (
      -
      -
      \ 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..c7bf09ea1e --- /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,86 @@ +import { ItemSearchResultListElementComponent } from './item-search-result-list-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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Item } from '../../../../core/shared/item.model'; +import { TruncatableService } from '../../../truncatable/truncatable.service'; + +let itemSearchResultListElementComponent: ItemSearchResultListElementComponent; +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(), { + metadata: [ + { + key: 'dc.contributor.author', + language: 'en_US', + value: 'Smith, Donald' + }, + { + key: 'dc.date.issued', + language: null, + value: '1650-06-26' + }] +}); +const createdListElementComponent: ItemSearchResultListElementComponent = new ItemSearchResultListElementComponent(mockItem, truncatableServiceStub as TruncatableService); + +describe('ItemSearchResultListElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ItemSearchResultListElementComponent, TruncatePipe], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + ], + + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemSearchResultListElementComponent); + itemSearchResultListElementComponent = fixture.componentInstance; + })); + + it('should show the item result cards in the list element', () => { + expect(fixture.debugElement.query(By.css('ds-item-search-result-list-element'))).toBeDefined(); + }); + + it('should only show the author span if the author metadata is present', () => { + const itemAuthorField = expect(fixture.debugElement.query(By.css('p.item-authors'))); + + if (mockItem.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']).length > 0) { + expect(itemAuthorField).toBeDefined(); + } else { + expect(itemAuthorField).not.toBeDefined(); + } + }); + + it('should only show the date span if the issuedate is present', () => { + const dateField = expect(fixture.debugElement.query(By.css('span.item-list-date'))); + + if (mockItem.findMetadata('dc.date.issued').length > 0) { + expect(dateField).toBeDefined(); + } else { + expect(dateField).not.toBeDefined(); + } + }); + +}); diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html index 60c474395b..964e52603f 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -1,3 +1,5 @@ -
      - +
      +
      + +
      \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index b66eab7005..698f1fb1aa 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -3,22 +3,27 @@ @mixin clamp($lines, $size-factor: 1, $line-height: $line-height-base) { $height: $line-height * $font-size-base * $size-factor; - max-height: $lines * $height; - position: relative; - overflow: hidden; - line-height: $line-height; - overflow-wrap: break-word; - &:after { - content: ""; - position: absolute; - padding-right: 15px; - top: ($lines - 1) * $height; - right: 0; - width: 30%; - min-width: 75px; - max-width: 150px; - height: $height; - background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); + &.fixedHeight { + height: $lines * $height; + } + .content { + max-height: $lines * $height; + position: relative; + overflow: hidden; + line-height: $line-height; + overflow-wrap: break-word; + &:after { + content: ""; + position: absolute; + padding-right: 15px; + top: ($lines - 1) * $height; + right: 0; + width: 30%; + min-width: 75px; + max-width: 150px; + height: $height; + background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 70%); + } } } @@ -26,15 +31,18 @@ $h4-factor: strip-unit($h4-font-size); @for $i from 1 through 15 { .clamp-#{$i} { + transition: height 1s; @include clamp($i); &.title { @include clamp($i, 1.25); } &.h4 { @include clamp($i, $h4-factor, $headings-line-height); - } } } +.clamp-none { + overflow: hidden; +} \ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts new file mode 100644 index 0000000000..4c3af4cd7d --- /dev/null +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.spec.ts @@ -0,0 +1,76 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Observable } from 'rxjs/Observable'; +import { TruncatablePartComponent } from './truncatable-part.component'; +import { TruncatableService } from '../truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +describe('TruncatablePartComponent', () => { + let comp: TruncatablePartComponent; + let fixture: ComponentFixture; + const id1 = '123'; + const id2 = '456'; + + let truncatableService; + const truncatableServiceStub: any = { + isCollapsed: (id: string) => { + if (id === id1) { + return Observable.of(true) + } else { + return Observable.of(false); + } + } + }; + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [TruncatablePartComponent], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(TruncatablePartComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(TruncatablePartComponent); + comp = fixture.componentInstance; // TruncatablePartComponent test instance + fixture.detectChanges(); + truncatableService = (comp as any).filterService; + }); + + describe('When the item is collapsed', () => { + beforeEach(() => { + comp.id = id1; + comp.minLines = 5; + (comp as any).setLines(); + fixture.detectChanges(); + }) + ; + + it('lines should equal minlines', () => { + expect((comp as any).lines).toEqual(comp.minLines.toString()); + }); + }); + + describe('When the item is expanded', () => { + beforeEach(() => { + comp.id = id2; + }) + ; + + it('lines should equal maxlines when maxlines has a value', () => { + comp.maxLines = 5; + (comp as any).setLines(); + fixture.detectChanges(); + expect((comp as any).lines).toEqual(comp.maxLines.toString()); + }); + + it('lines should equal \'none\' when maxlines has no value', () => { + (comp as any).setLines(); + fixture.detectChanges(); + expect((comp as any).lines).toEqual('none'); + }); + }); +}); diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 2d643f4a33..1392271db7 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -1,21 +1,21 @@ -import { - Component, Input, OnDestroy, OnInit, ElementRef, ViewChild -} from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { TruncatableService } from '../truncatable.service'; +import { cardExpand } from '../../animations/card-expand'; @Component({ selector: 'ds-truncatable-part', templateUrl: './truncatable-part.component.html', - styleUrls: ['./truncatable-part.component.scss'] + styleUrls: ['./truncatable-part.component.scss'], + animations: [cardExpand] }) export class TruncatablePartComponent implements OnInit, OnDestroy { @Input() minLines: number; @Input() maxLines = -1; - @Input() initialExpand = false; @Input() id: string; @Input() type: string; - private lines: string; + @Input() fixedHeight = false; + lines: string; private sub; public constructor(private service: TruncatableService) { @@ -38,5 +38,4 @@ export class TruncatablePartComponent implements OnInit, OnDestroy { ngOnDestroy(): void { this.sub.unsubscribe(); } - } diff --git a/src/app/shared/truncatable/truncatable.component.spec.ts b/src/app/shared/truncatable/truncatable.component.spec.ts new file mode 100644 index 0000000000..14a499f4e0 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.spec.ts @@ -0,0 +1,99 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Observable } from 'rxjs/Observable'; +import { TruncatableComponent } from './truncatable.component'; +import { TruncatableService } from './truncatable.service'; +import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; + +describe('TruncatableComponent', () => { + let comp: TruncatableComponent; + let fixture: ComponentFixture; + const identifier = '1234567890'; + let truncatableService; + const truncatableServiceStub: any = { + isCollapsed: (id: string) => { + if (id === '1') { + return Observable.of(true) + } else { + return Observable.of(false); + } + }, + expand: (id: string) => { + }, + collapse: (id: string) => { + }, + toggle: (id: string) => { + } + }; + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], + declarations: [TruncatableComponent], + providers: [ + { provide: TruncatableService, useValue: truncatableServiceStub }, + ], + schemas: [NO_ERRORS_SCHEMA] + }).overrideComponent(TruncatableComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(TruncatableComponent); + comp = fixture.componentInstance; // TruncatableComponent test instance + comp.id = identifier; + fixture.detectChanges(); + truncatableService = (comp as any).service; + }); + + describe('When the item is hoverable', () => { + beforeEach(() => { + comp.onHover = true; + fixture.detectChanges(); + }) + ; + + it('should call collapse on the TruncatableService', () => { + spyOn(truncatableService, 'collapse'); + comp.hoverCollapse(); + expect(truncatableService.collapse).toHaveBeenCalledWith(identifier); + }); + + it('should call expand on the TruncatableService', () => { + spyOn(truncatableService, 'expand'); + comp.hoverExpand(); + expect(truncatableService.expand).toHaveBeenCalledWith(identifier); + }); + }); + + describe('When the item is not hoverable', () => { + beforeEach(() => { + comp.onHover = false; + fixture.detectChanges(); + }) + ; + + it('should not call collapse on the TruncatableService', () => { + spyOn(truncatableService, 'collapse'); + comp.hoverCollapse(); + expect(truncatableService.collapse).not.toHaveBeenCalled(); + }); + + it('should not call expand on the TruncatableService', () => { + spyOn(truncatableService, 'expand'); + comp.hoverExpand(); + expect(truncatableService.expand).not.toHaveBeenCalled(); + }); + }); + + describe('When toggle is called', () => { + beforeEach(() => { + spyOn(truncatableService, 'toggle'); + comp.toggle(); + }); + + it('should call toggle on the TruncatableService', () => { + expect(truncatableService.toggle).toHaveBeenCalledWith(identifier); + }); + }); + +}); diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index b7667f6f51..64477389b9 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -2,11 +2,14 @@ import { Component, Input } from '@angular/core'; import { TruncatableService } from './truncatable.service'; +import { Observable } from 'rxjs/Observable'; +import { cardExpand } from '../animations/card-expand'; @Component({ selector: 'ds-truncatable', templateUrl: './truncatable.component.html', - styleUrls: ['./truncatable.component.scss'] + styleUrls: ['./truncatable.component.scss'], + }) export class TruncatableComponent { @Input() initialExpand = false; @@ -39,4 +42,5 @@ export class TruncatableComponent { public toggle() { this.service.toggle(this.id); } + } diff --git a/src/app/shared/truncatable/truncatable.reducer.spec.ts b/src/app/shared/truncatable/truncatable.reducer.spec.ts new file mode 100644 index 0000000000..00949d1113 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.reducer.spec.ts @@ -0,0 +1,96 @@ +import * as deepFreeze from 'deep-freeze'; + +import { truncatableReducer } from './truncatable.reducer'; +import { + TruncatableCollapseAction, TruncatableExpandAction, + TruncatableToggleAction +} from './truncatable.actions'; + +const id1 = '123'; +const id2 = '456'; +class NullAction extends TruncatableCollapseAction { + type = null; + constructor() { + super(undefined); + } +} + +describe('truncatableReducer', () => { + + it('should return the current state when no valid actions have been made', () => { + const state = { 123: { collapsed: true, page: 1 } }; + const action = new NullAction(); + const newState = truncatableReducer(state, action); + + expect(newState).toEqual(state); + }); + + it('should start with an empty object', () => { + const state = Object.create({}); + const action = new NullAction(); + const initialState = truncatableReducer(undefined, action); + + // The search filter starts collapsed + expect(initialState).toEqual(state); + }); + + it('should set collapsed to true in response to the COLLAPSE action', () => { + const state = {}; + state[id1] = { collapsed: false}; + const action = new TruncatableCollapseAction(id1); + const newState = truncatableReducer(state, action); + + expect(newState[id1].collapsed).toEqual(true); + }); + + it('should perform the COLLAPSE action without affecting the previous state', () => { + const state = {}; + state[id1] = { collapsed: false}; + deepFreeze([state]); + + const action = new TruncatableCollapseAction(id1); + truncatableReducer(state, action); + + // no expect required, deepFreeze will ensure an exception is thrown if the state + // is mutated, and any uncaught exception will cause the test to fail + }); + + it('should set filterCollapsed to false in response to the EXPAND action', () => { + const state = {}; + state[id1] = { collapsed: true }; + const action = new TruncatableExpandAction(id1); + const newState = truncatableReducer(state, action); + + expect(newState[id1].collapsed).toEqual(false); + }); + + it('should perform the EXPAND action without affecting the previous state', () => { + const state = {}; + state[id1] = { collapsed: true }; + deepFreeze([state]); + + const action = new TruncatableExpandAction(id1); + truncatableReducer(state, action); + }); + + it('should flip the value of filterCollapsed in response to the TOGGLE action', () => { + const state1 = {}; + state1[id1] = { collapsed: true }; + const action = new TruncatableToggleAction(id1); + + const state2 = truncatableReducer(state1, action); + const state3 = truncatableReducer(state2, action); + + expect(state2[id1].collapsed).toEqual(false); + expect(state3[id1].collapsed).toEqual(true); + }); + + it('should perform the TOGGLE action without affecting the previous state', () => { + const state = {}; + state[id2] = { collapsed: true }; + deepFreeze([state]); + + const action = new TruncatableToggleAction(id2); + truncatableReducer(state, action); + }); +}); diff --git a/src/app/shared/truncatable/truncatable.service.spec.ts b/src/app/shared/truncatable/truncatable.service.spec.ts new file mode 100644 index 0000000000..dafa889b87 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.service.spec.ts @@ -0,0 +1,54 @@ +import { Store } from '@ngrx/store'; +import { async, TestBed } from '@angular/core/testing'; +import { Observable } from 'rxjs/Observable'; +import { TruncatableService } from './truncatable.service'; +import { TruncatableCollapseAction, TruncatableExpandAction } from './truncatable.actions'; +import { TruncatablesState } from './truncatable.reducer'; + +describe('TruncatableService', () => { + const id1 = '123'; + const id2 = '456'; + let service: TruncatableService; + const store: Store = jasmine.createSpyObj('store', { + /* tslint:disable:no-empty */ + dispatch: {}, + /* tslint:enable:no-empty */ + select: Observable.of(true) + }); + beforeEach(async(() => { + TestBed.configureTestingModule({ + + providers: [ + { + provide: Store, useValue: store + } + ] + }).compileComponents(); + })); + + beforeEach(() => { + service = new TruncatableService(store); + }); + + describe('when the collapse method is triggered', () => { + beforeEach(() => { + service.collapse(id1); + }); + + it('TruncatableCollapseAction should be dispatched to the store', () => { + expect(store.dispatch).toHaveBeenCalledWith(new TruncatableCollapseAction(id1)); + }); + + }); + + describe('when the expand method is triggered', () => { + beforeEach(() => { + service.expand(id2); + }); + + it('TruncatableExpandAction should be dispatched to the store', () => { + expect(store.dispatch).toHaveBeenCalledWith(new TruncatableExpandAction(id2)); + }); + }); + +}); From 42b315f8fb541cdc1a6ac8cdaea18955f7229128 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Mon, 5 Feb 2018 12:51:36 +0100 Subject: [PATCH 10/23] 46063: clean up --- src/app/+search-page/search-service/search.service.ts | 2 +- src/app/app.module.ts | 2 +- .../item-list-element/item-list-element.component.html | 4 ++-- .../truncatable-part/truncatable-part.component.ts | 4 +--- src/app/shared/truncatable/truncatable.component.ts | 2 -- src/app/typings.d.ts | 10 ---------- 6 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 89efd1d15d..c70fe22ce0 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -40,7 +40,7 @@ export class SearchService implements OnDestroy { totalPages = 5; mockedHighlights: string[] = new Array( 'This is a sample abstract.', - 'This is a sample abstractabstractabstractabstractabstractabstractabstractabstract. But, to fill up some space, here\'s "Hello" in several different languages : ', + 'This is a sample abstract. But, to fill up some space, here\'s "Hello" in several different languages : ', 'This is a Sample HTML webpage including several images and styles (CSS).', 'This is really just a sample abstract. But, Í’vé thrown ïn a cõuple of spëciâl charactèrs för êxtrå fuñ!', 'This abstract is really quite great', diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 44092d373e..c2728941d0 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -38,7 +38,7 @@ export function getBase() { } export function getMetaReducers(config: GlobalConfig): Array> { - const metaReducers: Array> = config.production ? appMetaReducers : [...appMetaReducers]; + const metaReducers: Array> = config.production ? appMetaReducers : [...appMetaReducers, storeFreeze]; return config.debug ? [...metaReducers, ...debugMetaReducers] : metaReducers; } 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 1e88cc4889..e9bde67295 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 @@ -12,7 +12,7 @@ ({{object.findMetadata("dc.publisher")}}, {{object.findMetadata("dc.date.issued")}}) -
      - {{item.findMetadata("dc.description.abstract") | dsTruncate:[200] }} +
      + {{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
      diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts index 1392271db7..0f695625ec 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.ts @@ -1,12 +1,10 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { TruncatableService } from '../truncatable.service'; -import { cardExpand } from '../../animations/card-expand'; @Component({ selector: 'ds-truncatable-part', templateUrl: './truncatable-part.component.html', - styleUrls: ['./truncatable-part.component.scss'], - animations: [cardExpand] + styleUrls: ['./truncatable-part.component.scss'] }) export class TruncatablePartComponent implements OnInit, OnDestroy { diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts index 64477389b9..81ad2b3cff 100644 --- a/src/app/shared/truncatable/truncatable.component.ts +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -2,8 +2,6 @@ import { Component, Input } from '@angular/core'; import { TruncatableService } from './truncatable.service'; -import { Observable } from 'rxjs/Observable'; -import { cardExpand } from '../animations/card-expand'; @Component({ selector: 'ds-truncatable', diff --git a/src/app/typings.d.ts b/src/app/typings.d.ts index c256b0f09d..f3b4a1a548 100644 --- a/src/app/typings.d.ts +++ b/src/app/typings.d.ts @@ -82,13 +82,3 @@ declare module '*.json' { } declare module 'reflect-metadata'; - -interface IShaveOptions { - classname?: string, - character?: string -} - -declare module 'shave' { - export default function shave(selector: string | Node, maxHeight: number, options?: IShaveOptions): void; - -} From 7bf23d1b7a362a9bbf8ba4651d464679544f5fa9 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 8 Feb 2018 14:39:13 +0100 Subject: [PATCH 11/23] 466063: test fixes --- .../shared/collection-search-result.model.ts | 5 ++ .../shared/community-search-result.model.ts | 5 ++ .../community-grid-element.component.spec.ts | 2 +- .../item-grid-element.component.html | 1 - .../item-grid-element.component.spec.ts | 2 +- ...on-search-result-grid-element.component.ts | 2 +- .../collection-search-result.model.ts | 5 -- ...ty-search-result-grid-element.component.ts | 4 +- .../community-search-result.model.ts | 5 -- ...-search-result-grid-element.component.html | 4 +- ...arch-result-grid-element.component.spec.ts | 89 ++++++++++++++----- .../search-result-grid-element.component.ts | 2 + .../collection-list-element.component.spec.ts | 2 +- ...on-search-result-list-element.component.ts | 2 +- .../collection-search-result.model.ts | 5 -- ...ty-search-result-list-element.component.ts | 2 +- .../community-search-result.model.ts | 5 -- .../truncatable-part.component.html | 2 +- .../truncatable-part.component.scss | 17 +++- 19 files changed, 106 insertions(+), 55 deletions(-) create mode 100644 src/app/shared/object-collection/shared/collection-search-result.model.ts create mode 100644 src/app/shared/object-collection/shared/community-search-result.model.ts delete mode 100644 src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result.model.ts delete mode 100644 src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result.model.ts delete mode 100644 src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts delete mode 100644 src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result.model.ts 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/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 cb9e20449e..1fd98bf225 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 @@ -5,7 +5,6 @@ import { ActivatedRoute, Router } from '@angular/router'; import { RouterStub } from '../../testing/router-stub'; import { Observable } from 'rxjs/Observable'; 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; @@ -51,6 +50,7 @@ describe('CommunityGridElementComponent', () => { })); it('should show the community cards in the grid element',() => { + console.log(fixture.debugElement.query(By.css('ds-community-grid-element'))); expect(fixture.debugElement.query(By.css('ds-community-grid-element'))).toBeDefined(); }) 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..47b5a6b2e6 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,7 +6,6 @@

      {{object.findMetadata('dc.title')}}

      -

      {{authorMd.value}} ; 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 3be46965ee..8c7f856450 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 @@ -64,4 +64,4 @@ describe('ItemGridElementComponent', () => { } }); -}) +}); 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.ts b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts index 4876a784fc..d490560919 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', @@ -15,4 +15,4 @@ import { ViewMode } from '../../../../+search-page/search-options.model'; @renderElementsFor(CommunitySearchResult, ViewMode.Grid) export class CommunitySearchResultGridElementComponent extends SearchResultGridElementComponent { -} +} \ No newline at end of file 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 352ba4881d..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 @@ -10,10 +10,10 @@

      -

      - {{dso.findMetadata("dc.date.issued")}} + {{dso.findMetadata("dc.date.issued")}} , 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 172888e98c..fbb267b8e6 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 @@ -3,11 +3,13 @@ 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; @@ -24,7 +26,10 @@ 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', @@ -34,14 +39,33 @@ const mockItem: Item = Object.assign(new Item(), { { key: 'dc.date.issued', language: null, - value: '1650-06-26' + value: '2015-06-26' }] }); -const createdGridElementComponent: ItemSearchResultGridElementComponent = new ItemSearchResultGridElementComponent(mockItem, truncatableServiceStub as TruncatableService); + +const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult(); +mockItemWithoutAuthorAndDate.hitHighlights = []; +mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), { + bitstream: 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(mockItemWithAuthorAndDate, truncatableServiceStub as TruncatableService); describe('ItemSearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], declarations: [ItemSearchResultGridElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, @@ -49,9 +73,10 @@ describe('ItemSearchResultGridElementComponent', () => { { provide: Router, useClass: RouterStub }, { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } ], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); // compile template and css + }).overrideComponent(ItemSearchResultGridElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { @@ -59,28 +84,48 @@ describe('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(); + fdescribe('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; + }); - 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; + }); - 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; + }); + + 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/search-result-grid-element.component.ts b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts index 9be2647cba..c04c1d54f4 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 @@ -20,6 +20,7 @@ export class SearchResultGridElementComponent, K exten public constructor(@Inject('objectElementProvider') public gridable: ListableObject, private truncatableService: TruncatableService) { super(gridable); this.dso = this.object.dspaceObject; + console.log(JSON.stringify(this.object.hitHighlights)); } getValues(keys: string[]): string[] { @@ -43,6 +44,7 @@ export class SearchResultGridElementComponent, K exten getFirstValue(key: string): string { let result: string; + console.log(JSON.stringify(this.object.hitHighlights)); this.object.hitHighlights.some( (md: Metadatum) => { if (key === md.key) { 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 index 0f1b7c4444..fe54b8195e 100644 --- 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 @@ -56,4 +56,4 @@ describe('CollectionListElementComponent', () => { expect(descriptionText).not.toBeDefined(); } }); -}) +}); 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.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/truncatable/truncatable-part/truncatable-part.component.html b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html index 964e52603f..72f41cd770 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.html @@ -1,4 +1,4 @@ -

      +
      diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index 698f1fb1aa..bb26239c57 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -25,7 +25,11 @@ background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 70%); } } +} +@mixin min($lines, $size-factor: 1, $line-height: $line-height-base) { + $height: $line-height * $font-size-base * $size-factor; + min-height: $lines * $height; } $h4-factor: strip-unit($h4-font-size); @@ -42,7 +46,18 @@ $h4-factor: strip-unit($h4-font-size); } } - .clamp-none { overflow: hidden; + @for $i from 1 through 15 { + &.min-#{$i} { + transition: height 1s; + @include min($i); + &.title { + @include min($i, 1.25); + } + &.h4 { + @include min($i, $h4-factor, $headings-line-height); + } + } + } } \ No newline at end of file From 9fd7b0ab2eaee1272c3fdeb28ac630cd8dff246d Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 8 Feb 2018 14:42:13 +0100 Subject: [PATCH 12/23] tslint fixes --- .../community-search-result-grid-element.component.spec.ts | 1 - src/app/shared/truncatable/truncatable.component.spec.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) 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 6d70d08901..6d65466f4d 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 @@ -9,7 +9,6 @@ import { TruncatePipe } from '../../../utils/truncate.pipe'; import { Community } from '../../../../core/shared/community.model'; import { TruncatableService } from '../../../truncatable/truncatable.service'; - let fixture: ComponentFixture; const queryParam = 'test query'; const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; diff --git a/src/app/shared/truncatable/truncatable.component.spec.ts b/src/app/shared/truncatable/truncatable.component.spec.ts index 14a499f4e0..3c2ce7150a 100644 --- a/src/app/shared/truncatable/truncatable.component.spec.ts +++ b/src/app/shared/truncatable/truncatable.component.spec.ts @@ -11,6 +11,7 @@ describe('TruncatableComponent', () => { const identifier = '1234567890'; let truncatableService; const truncatableServiceStub: any = { + /* tslint:disable:no-empty */ isCollapsed: (id: string) => { if (id === '1') { return Observable.of(true) @@ -24,6 +25,7 @@ describe('TruncatableComponent', () => { }, toggle: (id: string) => { } + /* tslint:enable:no-empty */ }; beforeEach(async(() => { TestBed.configureTestingModule({ From 52781d02c448a04734af2eaabe2b946b77584afe Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 13 Feb 2018 11:50:35 +0100 Subject: [PATCH 13/23] drag/click differensiating directive + fix for fixedheight truncatable elements --- src/app/shared/shared.module.ts | 4 +++- .../truncatable-part.component.scss | 2 +- .../truncatable/truncatable.component.html | 2 +- src/app/shared/utils/drag-click.directive.ts | 23 +++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/app/shared/utils/drag-click.directive.ts diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 202a4b0c23..c78c218fa9 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -40,6 +40,7 @@ import { SearchResultGridElementComponent } from './object-grid/search-result-gr import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.component'; import { GridThumbnailComponent } from './object-grid/grid-thumbnail/grid-thumbnail.component'; import { VarDirective } from './utils/var.directive'; +import { DragClickDirective } from './utils/drag-click.directive'; import { TruncatePipe } from './utils/truncate.pipe'; import { TruncatableComponent } from './truncatable/truncatable.component'; import { TruncatableService } from './truncatable/truncatable.service'; @@ -104,7 +105,8 @@ const PROVIDERS = [ ]; const DIRECTIVES = [ - VarDirective + VarDirective, + DragClickDirective ]; @NgModule({ diff --git a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss index bb26239c57..ac3641df39 100644 --- a/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss +++ b/src/app/shared/truncatable/truncatable-part/truncatable-part.component.scss @@ -49,7 +49,7 @@ $h4-factor: strip-unit($h4-font-size); .clamp-none { overflow: hidden; @for $i from 1 through 15 { - &.min-#{$i} { + &.fixedHeight.min-#{$i} { transition: height 1s; @include min($i); &.title { diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html index d3ed37e596..c03e93c2ce 100644 --- a/src/app/shared/truncatable/truncatable.component.html +++ b/src/app/shared/truncatable/truncatable.component.html @@ -1,3 +1,3 @@ -
      +
      \ No newline at end of file diff --git a/src/app/shared/utils/drag-click.directive.ts b/src/app/shared/utils/drag-click.directive.ts new file mode 100644 index 0000000000..ec9b02dea5 --- /dev/null +++ b/src/app/shared/utils/drag-click.directive.ts @@ -0,0 +1,23 @@ +import { Directive, EventEmitter, HostListener, Output } from '@angular/core'; + +@Directive({ + selector: '[dsDragClick]' +}) +export class DragClickDirective { + private start; + @Output() actualClick = new EventEmitter(); + + @HostListener('mousedown', ['$event']) + mousedownEvent(event) { + this.start = new Date(); + } + + @HostListener('mouseup', ['$event']) + mouseupEvent(event) { + const end: any = new Date(); + const clickTime = end - this.start; + if (clickTime < 250) { + this.actualClick.emit(event) + } + } +} From 2895bb61e83fe01f164ea69aa11055efe162ab47 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 13 Feb 2018 15:06:07 +0100 Subject: [PATCH 14/23] fixed list element tests --- src/app/core/shared/community.model.ts | 1 + .../collection-grid-element.component.spec.ts | 67 ++++++----- .../community-grid-element.component.spec.ts | 64 ++++++----- .../item-grid-element.component.html | 4 +- .../item-grid-element.component.spec.ts | 99 ++++++++++++----- ...arch-result-grid-element.component.spec.ts | 76 +++++++------ ...arch-result-grid-element.component.spec.ts | 69 +++++++----- ...arch-result-grid-element.component.spec.ts | 23 +--- .../search-result-grid-element.component.ts | 6 +- .../collection-list-element.component.html | 2 +- .../collection-list-element.component.spec.ts | 65 ++++++----- .../community-list-element.component.html | 2 +- .../community-list-element.component.spec.ts | 65 ++++++----- .../item-list-element.component.html | 2 +- .../item-list-element.component.spec.ts | 101 ++++++++++++----- ...-search-result-list-element.component.html | 2 +- ...arch-result-list-element.component.spec.ts | 75 ++++++++----- ...-search-result-list-element.component.html | 2 +- ...arch-result-list-element.component.spec.ts | 68 +++++++----- ...-search-result-list-element.component.html | 2 +- ...arch-result-list-element.component.spec.ts | 104 ++++++++++++------ 21 files changed, 545 insertions(+), 354 deletions(-) diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts index c34666b0f0..ea80a02269 100644 --- a/src/app/core/shared/community.model.ts +++ b/src/app/core/shared/community.model.ts @@ -24,6 +24,7 @@ export class Community extends DSpaceObject { * Corresponds to the metadata field dc.description.abstract */ get shortDescription(): string { + debugger; return this.findMetadata('dc.description.abstract'); } 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 eaa6edc4d0..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 1fd98bf225..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,24 +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 { 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', @@ -27,40 +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',() => { - console.log(fixture.debugElement.query(By.css('ds-community-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 47b5a6b2e6..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,11 +6,11 @@

      {{object.findMetadata('dc.title')}}

      -

      +

      {{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 8c7f856450..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/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 9eb65dbbdd..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,69 +1,83 @@ 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 mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult(); +mockCollectionWithoutAbstract.hitHighlights = []; +mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), { + metadata: [ + { + key: 'dc.title', + language: 'en_US', + value: 'Test title' + } ] }); -const createdGridElementComponent: CollectionSearchResultGridElementComponent = new CollectionSearchResultGridElementComponent(mockCollection, truncatableServiceStub as TruncatableService); describe('CollectionSearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [CollectionSearchResultGridElementComponent, TruncatePipe], + declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { 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 + schemas: [ NO_ERRORS_SCHEMA ] + }).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/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 6d70d08901..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,39 +1,41 @@ 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, truncatableServiceStub as TruncatableService); +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(() => { @@ -41,30 +43,41 @@ describe('CommunitySearchResultGridElementComponent', () => { declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { 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(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/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 fbb267b8e6..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,8 +1,6 @@ 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, ChangeDetectionStrategy } from '@angular/core'; import { By } from '@angular/platform-browser'; import { TruncatePipe } from '../../../utils/truncate.pipe'; @@ -13,14 +11,6 @@ import { ItemSearchResult } from '../../../object-collection/shared/item-search- 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), @@ -46,7 +36,7 @@ mockItemWithAuthorAndDate.dspaceObject = Object.assign(new Item(), { const mockItemWithoutAuthorAndDate: ItemSearchResult = new ItemSearchResult(); mockItemWithoutAuthorAndDate.hitHighlights = []; mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), { - bitstream: Observable.of({}), + bitstreams: Observable.of({}), metadata: [ { key: 'dc.title', @@ -60,8 +50,6 @@ mockItemWithoutAuthorAndDate.dspaceObject = Object.assign(new Item(), { }] }); -const createdGridElementComponent: ItemSearchResultGridElementComponent = new ItemSearchResultGridElementComponent(mockItemWithAuthorAndDate, truncatableServiceStub as TruncatableService); - describe('ItemSearchResultGridElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ @@ -69,9 +57,7 @@ describe('ItemSearchResultGridElementComponent', () => { declarations: [ItemSearchResultGridElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } + { provide: 'objectElementProvider', useValue: (mockItemWithoutAuthorAndDate) } ], schemas: [NO_ERRORS_SCHEMA] }).overrideComponent(ItemSearchResultGridElementComponent, { @@ -84,7 +70,7 @@ describe('ItemSearchResultGridElementComponent', () => { itemSearchResultGridElementComponent = fixture.componentInstance; })); - fdescribe('When the item has an author', () => { + describe('When the item has an author', () => { beforeEach(() => { itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; fixture.detectChanges(); @@ -99,6 +85,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has no author', () => { beforeEach(() => { itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + fixture.detectChanges(); }); it('should not show the author paragraph', () => { @@ -110,6 +97,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has an issuedate', () => { beforeEach(() => { itemSearchResultGridElementComponent.dso = mockItemWithAuthorAndDate.dspaceObject; + fixture.detectChanges(); }); it('should show the issuedate span', () => { @@ -121,6 +109,7 @@ describe('ItemSearchResultGridElementComponent', () => { describe('When the item has no issuedate', () => { beforeEach(() => { itemSearchResultGridElementComponent.dso = mockItemWithoutAuthorAndDate.dspaceObject; + fixture.detectChanges(); }); it('should not show the issuedate span', () => { 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 c04c1d54f4..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 @@ -17,10 +17,9 @@ import { Observable } from 'rxjs/Observable'; export class SearchResultGridElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { dso: K; - public constructor(@Inject('objectElementProvider') public gridable: ListableObject, private truncatableService: TruncatableService) { - super(gridable); + public constructor(@Inject('objectElementProvider') public listableObject: ListableObject, private truncatableService: TruncatableService) { + super(listableObject); this.dso = this.object.dspaceObject; - console.log(JSON.stringify(this.object.hitHighlights)); } getValues(keys: string[]): string[] { @@ -44,7 +43,6 @@ export class SearchResultGridElementComponent, K exten getFirstValue(key: string): string { let result: string; - console.log(JSON.stringify(this.object.hitHighlights)); this.object.hitHighlights.some( (md: Metadatum) => { if (key === md.key) { 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 index fe54b8195e..a31af1e50c 100644 --- 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 @@ -1,21 +1,13 @@ import { CollectionListElementComponent } from './collection-list-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 collectionListElementComponent: CollectionListElementComponent; 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 createdListElementComponent:CollectionListElementComponent= new CollectionListElementComponent(mockCollection); + +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: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdListElementComponent)} + { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract)} ], schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css + }).overrideComponent(CollectionListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { fixture = TestBed.createComponent(CollectionListElementComponent); + collectionListElementComponent = fixture.componentInstance; })); - it('should show the collection cards in the list element',() => { - expect(fixture.debugElement.query(By.css('ds-collection-list-element'))).toBeDefined(); + 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(); + }); }); - 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(() => { + collectionListElementComponent.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('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 index ff5a7fa441..08147d8573 100644 --- 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 @@ -1,24 +1,13 @@ import { CommunityListElementComponent } from './community-list-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 { Community } from '../../../core/shared/community.model'; let communityListElementComponent: CommunityListElementComponent; 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', @@ -27,39 +16,55 @@ const mockCommunity: Community = Object.assign(new Community(), { }] }); -const createdListElementComponent:CommunityListElementComponent= new CommunityListElementComponent(mockCommunity); +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: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdListElementComponent)} + { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract)} ], - schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css + schemas: [ NO_ERRORS_SCHEMA ] + }).overrideComponent(CommunityListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { fixture = TestBed.createComponent(CommunityListElementComponent); communityListElementComponent = fixture.componentInstance; - })); - it('should show the community cards in the list element',() => { - expect(fixture.debugElement.query(By.css('ds-community-list-element'))).toBeDefined(); - }) + describe('When the community has an abstract', () => { + beforeEach(() => { + communityListElementComponent.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('div.abstract-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(() => { + 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 e9bde67295..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,7 +3,7 @@
      - {{authorMd.value}} ; 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 index 3383ed8454..fc40527693 100644 --- 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 @@ -1,47 +1,55 @@ import { ItemListElementComponent } from './item-list-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 itemListElementComponent: ItemListElementComponent; 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 createdListElementComponent:ItemListElementComponent= new ItemListElementComponent(mockItem); describe('ItemListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ ItemListElementComponent , TruncatePipe], providers: [ - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: {createdListElementComponent}} + { provide: 'objectElementProvider', useValue: {mockItemWithAuthorAndDate}} ], schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css + }).overrideComponent(ItemListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { @@ -50,18 +58,51 @@ describe('ItemListElementComponent', () => { })); - it('should show the item cards in the list element',() => { - expect(fixture.debugElement.query(By.css('ds-item-list-element'))).toBeDefined() + 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(); + }); }); - 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(() => { + itemListElementComponent.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('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/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 index 37756b5916..0395904070 100644 --- 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 @@ -1,68 +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 { 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 { 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 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 mockCollectionWithoutAbstract: CollectionSearchResult = new CollectionSearchResult(); +mockCollectionWithoutAbstract.hitHighlights = []; +mockCollectionWithoutAbstract.dspaceObject = Object.assign(new Collection(), { + metadata: [ + { + key: 'dc.title', + language: 'en_US', + value: 'Test title' + } ] }); -const createdListElementComponent: CollectionSearchResultListElementComponent = new CollectionSearchResultListElementComponent(mockCollection, truncatableServiceStub as TruncatableService); describe('CollectionSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [CollectionSearchResultListElementComponent, TruncatePipe], + declarations: [ CollectionSearchResultListElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + { provide: 'objectElementProvider', useValue: (mockCollectionWithAbstract) } ], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); // compile template and css + schemas: [ NO_ERRORS_SCHEMA ] + }).overrideComponent(CollectionSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { fixture = TestBed.createComponent(CollectionSearchResultListElementComponent); + collectionSearchResultListElementComponent = fixture.componentInstance; })); - it('should show the item result cards in the list element', () => { - expect(fixture.debugElement.query(By.css('ds-collection-search-result-list-element'))).toBeDefined(); + 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(); + }); }); - 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(() => { + collectionSearchResultListElementComponent.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('div.abstract-text')); + expect(collectionAbstractField).toBeNull(); + }); }); }); 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 index 3e82e824ec..54dde5dee6 100644 --- 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 @@ -1,38 +1,41 @@ import { CommunitySearchResultListElementComponent } from './community-search-result-list-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 communitySearchResultListElementComponent: CommunitySearchResultListElementComponent; 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 createdListElementComponent: CommunitySearchResultListElementComponent = new CommunitySearchResultListElementComponent(mockCommunity, truncatableServiceStub as TruncatableService); +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(() => { @@ -40,30 +43,41 @@ describe('CommunitySearchResultListElementComponent', () => { declarations: [ CommunitySearchResultListElementComponent, TruncatePipe ], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + { provide: 'objectElementProvider', useValue: (mockCommunityWithAbstract) } ], schemas: [ NO_ERRORS_SCHEMA ] - }).compileComponents(); // compile template and css + }).overrideComponent(CommunitySearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { fixture = TestBed.createComponent(CommunitySearchResultListElementComponent); + communitySearchResultListElementComponent = fixture.componentInstance; })); - it('should show the item result cards in the list element', () => { - expect(fixture.debugElement.query(By.css('ds-community-search-result-list-element'))).toBeDefined(); + 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(); + }); }); - 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(() => { + communitySearchResultListElementComponent.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('div.abstract-text')); + expect(communityAbstractField).toBeNull(); + }); }); }); 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 d7ef1c673c..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 @@ -8,7 +8,7 @@ [innerHTML]="getFirstValue('dc.publisher')">,
      ) - 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 index c7bf09ea1e..f492c58483 100644 --- 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 @@ -1,30 +1,25 @@ import { ItemSearchResultListElementComponent } from './item-search-result-list-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 itemSearchResultListElementComponent: ItemSearchResultListElementComponent; 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', @@ -34,24 +29,40 @@ 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 createdListElementComponent: ItemSearchResultListElementComponent = new ItemSearchResultListElementComponent(mockItem, truncatableServiceStub as TruncatableService); describe('ItemSearchResultListElementComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [NoopAnimationsModule], declarations: [ItemSearchResultListElementComponent, TruncatePipe], providers: [ { provide: TruncatableService, useValue: truncatableServiceStub }, - { provide: ActivatedRoute, useValue: activatedRouteStub }, - { provide: Router, useClass: RouterStub }, - { provide: 'objectElementProvider', useValue: (createdListElementComponent) } + { provide: 'objectElementProvider', useValue: (mockItemWithoutAuthorAndDate) } ], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); // compile template and css + }).overrideComponent(ItemSearchResultListElementComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } + }).compileComponents(); })); beforeEach(async(() => { @@ -59,28 +70,51 @@ describe('ItemSearchResultListElementComponent', () => { itemSearchResultListElementComponent = fixture.componentInstance; })); - it('should show the item result cards in the list element', () => { - expect(fixture.debugElement.query(By.css('ds-item-search-result-list-element'))).toBeDefined(); + 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(); + }); }); - 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(() => { + itemSearchResultListElementComponent.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('span.item-list-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(() => { + itemSearchResultListElementComponent.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-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(); + }); + }); }); From c9071bc0672a15ab331ccfe088ae8c61cadbbf07 Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Tue, 13 Feb 2018 15:47:06 +0100 Subject: [PATCH 15/23] ts lint fixes --- src/app/core/shared/community.model.ts | 1 - .../community-search-result-grid-element.component.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/core/shared/community.model.ts b/src/app/core/shared/community.model.ts index ea80a02269..c34666b0f0 100644 --- a/src/app/core/shared/community.model.ts +++ b/src/app/core/shared/community.model.ts @@ -24,7 +24,6 @@ export class Community extends DSpaceObject { * Corresponds to the metadata field dc.description.abstract */ get shortDescription(): string { - debugger; return this.findMetadata('dc.description.abstract'); } 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 d490560919..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 @@ -15,4 +15,4 @@ import { CommunitySearchResult } from '../../../object-collection/shared/communi @renderElementsFor(CommunitySearchResult, ViewMode.Grid) export class CommunitySearchResultGridElementComponent extends SearchResultGridElementComponent { -} \ No newline at end of file +} From 24d7980b9f1d6a92b0535673dc9e8b078869c2bb Mon Sep 17 00:00:00 2001 From: Lotte Hofstede Date: Thu, 15 Feb 2018 15:05:55 +0100 Subject: [PATCH 16/23] bootstrap upgrade to 4.0.0 --- package.json | 6 +++--- src/app/header/header.component.html | 2 +- src/styles/_bootstrap_variables.scss | 5 +++++ yarn.lock | 14 +++++++------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index b211892de9..22d7485684 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "@angular/platform-server": "5.2.1", "@angular/router": "5.2.1", "@angularclass/bootloader": "1.0.1", - "@ng-bootstrap/ng-bootstrap": "1.0.0-beta.9", + "@ng-bootstrap/ng-bootstrap": "^1.0.0", "@ngrx/effects": "4.1.1", "@ngrx/router-store": "4.1.1", "@ngrx/store": "4.1.1", @@ -88,7 +88,7 @@ "@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", @@ -162,7 +162,7 @@ "karma-webdriver-launcher": "1.0.5", "karma-webpack": "2.0.9", "ngrx-store-freeze": "0.2.0", - "node-sass": "4.7.2", + "node-sass": "^4.7.2", "nodemon": "1.14.11", "npm-run-all": "4.1.2", "postcss": "6.0.16", 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 @@
      -