diff --git a/.gitignore b/.gitignore index f8395956f5..dd5f5fa391 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ npm-debug.log /coverage/ .idea +*.iml *.ngfactory.ts *.css.shim.ts *.scss.shim.ts diff --git a/src/app/+collection-page/collection-page.component.html b/src/app/+collection-page/collection-page.component.html index fe5b2a1f16..05b4d6f11e 100644 --- a/src/app/+collection-page/collection-page.component.html +++ b/src/app/+collection-page/collection-page.component.html @@ -41,13 +41,13 @@ {{'collection.page.browse.recent.head' | translate}} - - + diff --git a/src/app/+home-page/top-level-community-list/top-level-community-list.component.html b/src/app/+home-page/top-level-community-list/top-level-community-list.component.html index a34951afe0..934bb3933c 100644 --- a/src/app/+home-page/top-level-community-list/top-level-community-list.component.html +++ b/src/app/+home-page/top-level-community-list/top-level-community-list.component.html @@ -1,15 +1,13 @@ - - {{'home.top-level-communities.head' | translate}} - {{'home.top-level-communities.help' | translate}} - - - - - - + + {{'home.top-level-communities.head' | translate}} + {{'home.top-level-communities.help' | translate}} + + + + + diff --git a/src/app/+search-page/search-page.component.html b/src/app/+search-page/search-page.component.html index 08fae7d19a..81f0c78527 100644 --- a/src/app/+search-page/search-page.component.html +++ b/src/app/+search-page/search-page.component.html @@ -29,8 +29,8 @@ | translate}} - + diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts index 3dcd0ccccf..e3426fc96b 100644 --- a/src/app/+search-page/search-page.component.ts +++ b/src/app/+search-page/search-page.component.ts @@ -1,17 +1,19 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs/Observable'; +import { SortOptions } from '../core/cache/models/sort-options.model'; import { CommunityDataService } from '../core/data/community-data.service'; import { PaginatedList } from '../core/data/paginated-list'; import { RemoteData } from '../core/data/remote-data'; import { Community } from '../core/shared/community.model'; import { DSpaceObject } from '../core/shared/dspace-object.model'; +import { pushInOut } from '../shared/animations/push'; import { isNotEmpty } from '../shared/empty.util'; -import { SearchOptions } from './search-options.model'; +import { HostWindowService } from '../shared/host-window.service'; +import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; +import { SearchOptions, ViewMode } from './search-options.model'; import { SearchResult } from './search-result.model'; import { SearchService } from './search-service/search.service'; -import { pushInOut } from '../shared/animations/push'; -import { HostWindowService } from '../shared/host-window.service'; import { SearchSidebarService } from './search-sidebar/search-sidebar.service'; /** @@ -37,6 +39,7 @@ export class SearchPageComponent implements OnInit, OnDestroy { resultsRDObs: Observable>>>; currentParams = {}; searchOptions: SearchOptions; + sortConfig: SortOptions; scopeListRDObs: Observable>>; isMobileView: Observable; @@ -52,6 +55,13 @@ export class SearchPageComponent implements OnInit, OnDestroy { ); this.scopeListRDObs = communityService.findAll(); // Initial pagination config + const pagination: PaginationComponentOptions = new PaginationComponentOptions(); + pagination.id = 'search-results-pagination'; + pagination.currentPage = 1; + pagination.pageSize = 10; + + const sort: SortOptions = new SortOptions(); + this.sortConfig = sort; this.searchOptions = this.service.searchOptions; } @@ -64,16 +74,31 @@ export class SearchPageComponent implements OnInit, OnDestroy { this.query = params.query || ''; this.scope = params.scope; const page = +params.page || this.searchOptions.pagination.currentPage; - const pageSize = +params.pageSize || this.searchOptions.pagination.pageSize; + let pageSize = +params.pageSize || this.searchOptions.pagination.pageSize; + let pageSizeOptions: number[] = [5, 10, 20, 40, 60, 80, 100]; + + if (isNotEmpty(params.view) && params.view === ViewMode.Grid) { + pageSizeOptions = [12, 24, 36, 48 , 50, 62, 74, 84]; + if (pageSizeOptions.indexOf(pageSize) === -1) { + pageSize = 12; + } + } + if (isNotEmpty(params.view) && params.view === ViewMode.List) { + if (pageSizeOptions.indexOf(pageSize) === -1) { + pageSize = 10; + } + } + const sortDirection = +params.sortDirection || this.searchOptions.sort.direction; const pagination = Object.assign({}, this.searchOptions.pagination, - { currentPage: page, pageSize: pageSize } + { currentPage: page, pageSize: pageSize, pageSizeOptions: pageSizeOptions} ); const sort = Object.assign({}, this.searchOptions.sort, { direction: sortDirection, field: params.sortField } ); + this.updateSearchResults({ pagination: pagination, sort: sort @@ -89,6 +114,7 @@ export class SearchPageComponent implements OnInit, OnDestroy { private updateSearchResults(searchOptions) { this.resultsRDObs = this.service.search(this.query, this.scope, searchOptions); + this.searchOptions = searchOptions; } ngOnDestroy() { diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts index 6519d1e92a..7c2001c909 100644 --- a/src/app/+search-page/search-page.module.ts +++ b/src/app/+search-page/search-page.module.ts @@ -4,9 +4,12 @@ import { SharedModule } from '../shared/shared.module'; import { SearchPageRoutingModule } from './search-page-routing.module'; import { SearchPageComponent } from './search-page.component'; import { SearchResultsComponent } from './search-results/search-results.component'; -import { ItemSearchResultListElementComponent } from '../object-list/search-result-list-element/item-search-result/item-search-result-list-element.component'; -import { CollectionSearchResultListElementComponent } from '../object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component'; -import { CommunitySearchResultListElementComponent } from '../object-list/search-result-list-element/community-search-result/community-search-result-list-element.component'; +import { ItemSearchResultListElementComponent } from '../shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component'; +import { CollectionSearchResultListElementComponent } from '../shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component'; +import { CommunitySearchResultListElementComponent } from '../shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component'; +import { ItemSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component'; +import { CommunitySearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component' +import { CollectionSearchResultGridElementComponent } from '../shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component'; import { SearchService } from './search-service/search.service'; import { SearchSidebarComponent } from './search-sidebar/search-sidebar.component'; import { SearchSidebarService } from './search-sidebar/search-sidebar.service'; @@ -37,6 +40,10 @@ const effects = [ ItemSearchResultListElementComponent, CollectionSearchResultListElementComponent, CommunitySearchResultListElementComponent, + ItemSearchResultGridElementComponent, + CollectionSearchResultGridElementComponent, + CommunitySearchResultGridElementComponent, + CommunitySearchResultListElementComponent, SearchFiltersComponent, SearchFilterComponent, SearchFacetFilterComponent @@ -49,7 +56,11 @@ const effects = [ entryComponents: [ ItemSearchResultListElementComponent, CollectionSearchResultListElementComponent, - CommunitySearchResultListElementComponent + CommunitySearchResultListElementComponent, + ItemSearchResultGridElementComponent, + CollectionSearchResultGridElementComponent, + CommunitySearchResultGridElementComponent, ] }) -export class SearchPageModule { } +export class SearchPageModule { +} diff --git a/src/app/+search-page/search-result.model.ts b/src/app/+search-page/search-result.model.ts index 2dd9130ee8..cc2bd8cd58 100644 --- a/src/app/+search-page/search-result.model.ts +++ b/src/app/+search-page/search-result.model.ts @@ -1,6 +1,6 @@ import { DSpaceObject } from '../core/shared/dspace-object.model'; import { Metadatum } from '../core/shared/metadatum.model'; -import { ListableObject } from '../object-list/listable-object/listable-object.model'; +import { ListableObject } from '../shared/object-collection/shared/listable-object.model'; export class SearchResult implements ListableObject { 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..1b9bd7d52a 100644 --- a/src/app/+search-page/search-results/search-results.component.html +++ b/src/app/+search-page/search-results/search-results.component.html @@ -1,10 +1,10 @@ 0">{{ 'search.results.head' | translate }} - - + diff --git a/src/app/+search-page/search-results/search-results.component.ts b/src/app/+search-page/search-results/search-results.component.ts index 4733699f95..4b3fec4565 100644 --- a/src/app/+search-page/search-results/search-results.component.ts +++ b/src/app/+search-page/search-results/search-results.component.ts @@ -2,7 +2,8 @@ import { Component, Input } from '@angular/core'; import { RemoteData } from '../../core/data/remote-data'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { fadeIn, fadeInOut } from '../../shared/animations/fade'; -import { SearchOptions } from '../search-options.model'; +import { SearchOptions, ViewMode } from '../search-options.model'; +import { SortOptions } from '../../core/cache/models/sort-options.model'; import { SearchResult } from '../search-result.model'; /** @@ -21,4 +22,6 @@ import { SearchResult } from '../search-result.model'; export class SearchResultsComponent { @Input() searchResults: RemoteData>>; @Input() searchConfig: SearchOptions; + @Input() sortConfig: SortOptions; + @Input() viewMode: ViewMode; } diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 64d76afc54..c70fe22ce0 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -1,25 +1,24 @@ import { Injectable, OnDestroy } from '@angular/core'; +import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import { ViewMode } from '../../+search-page/search-options.model'; +import { SortOptions } from '../../core/cache/models/sort-options.model'; +import { ItemDataService } from '../../core/data/item-data.service'; import { PaginatedList } from '../../core/data/paginated-list'; import { RemoteData } from '../../core/data/remote-data'; -import { Observable } from 'rxjs/Observable'; -import { RemoteDataError } from '../../core/data/remote-data-error'; -import { SearchResult } from '../search-result.model'; -import { ItemDataService } from '../../core/data/item-data.service'; -import { PageInfo } from '../../core/shared/page-info.model'; import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { SearchOptions } from '../search-options.model'; -import { hasValue, isNotEmpty } from '../../shared/empty.util'; -import { Metadatum } from '../../core/shared/metadatum.model'; import { Item } from '../../core/shared/item.model'; -import { ItemSearchResult } from '../../object-list/search-result-list-element/item-search-result/item-search-result.model'; -import { SearchFilterConfig } from './search-filter-config.model'; -import { FilterType } from './filter-type.model'; -import { FacetValue } from './facet-value.model'; -import { ViewMode } from '../../+search-page/search-options.model'; -import { Router, NavigationExtras, ActivatedRoute } from '@angular/router'; -import { RouteService } from '../../shared/route.service'; +import { Metadatum } from '../../core/shared/metadatum.model'; +import { PageInfo } from '../../core/shared/page-info.model'; +import { hasValue, isNotEmpty } from '../../shared/empty.util'; +import { ItemSearchResult } from '../../shared/object-collection/shared/item-search-result.model'; import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model'; -import { SortOptions } from '../../core/cache/models/sort-options.model'; +import { RouteService } from '../../shared/route.service'; +import { SearchOptions } from '../search-options.model'; +import { SearchResult } from '../search-result.model'; +import { FacetValue } from './facet-value.model'; +import { FilterType } from './filter-type.model'; +import { SearchFilterConfig } from './search-filter-config.model'; function shuffle(array: any[]) { let i = 0; @@ -102,6 +101,24 @@ export class SearchService implements OnDestroy { } search(query: string, scopeId?: string, searchOptions?: SearchOptions): Observable>>> { + this.searchOptions = searchOptions; + let self = `https://dspace7.4science.it/dspace-spring-rest/api/search?query=${query}`; + if (hasValue(scopeId)) { + self += `&scope=${scopeId}`; + } + if (isNotEmpty(searchOptions) && hasValue(searchOptions.pagination.currentPage)) { + self += `&page=${searchOptions.pagination.currentPage}`; + } + if (isNotEmpty(searchOptions) && hasValue(searchOptions.pagination.pageSize)) { + self += `&pageSize=${searchOptions.pagination.pageSize}`; + } + if (isNotEmpty(searchOptions) && hasValue(searchOptions.sort.direction)) { + self += `&sortDirection=${searchOptions.sort.direction}`; + } + if (isNotEmpty(searchOptions) && hasValue(searchOptions.sort.field)) { + self += `&sortField=${searchOptions.sort.field}`; + } + const error = undefined; const returningPageInfo = new PageInfo(); diff --git a/src/app/+search-page/search-settings/search-settings.component.html b/src/app/+search-page/search-settings/search-settings.component.html index d5a4d412ff..4ee0812602 100644 --- a/src/app/+search-page/search-settings/search-settings.component.html +++ b/src/app/+search-page/search-settings/search-settings.component.html @@ -14,7 +14,7 @@ {{ 'search.sidebar.settings.rpp' | translate}} - {{item}} diff --git a/src/app/+search-page/search-settings/search-settings.component.ts b/src/app/+search-page/search-settings/search-settings.component.ts index 7b8bb8eb6e..ad6aeb21dd 100644 --- a/src/app/+search-page/search-settings/search-settings.component.ts +++ b/src/app/+search-page/search-settings/search-settings.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { SearchService } from '../search-service/search.service'; -import { SearchOptions } from '../search-options.model'; +import { SearchOptions, ViewMode } from '../search-options.model'; import { SortDirection } from '../../core/cache/models/sort-options.model'; import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'; @@ -20,6 +20,9 @@ export class SearchSettingsComponent implements OnInit { * Number of items per page. */ public pageSize; + @Input() public pageSizeOptions; + public listPageSizeOptions: number[] = [5, 10, 20, 40, 60, 80, 100]; + public gridPageSizeOptions: number[] = [12, 24, 36, 48 , 50, 62, 74, 84]; private sub; private scope: string; @@ -36,6 +39,7 @@ export class SearchSettingsComponent implements OnInit { ngOnInit(): void { this.searchOptions = this.service.searchOptions; this.pageSize = this.searchOptions.pagination.pageSize; + this.pageSizeOptions = this.searchOptions.pagination.pageSizeOptions; this.sub = this.route .queryParams .subscribe((params) => { @@ -45,6 +49,11 @@ export class SearchSettingsComponent implements OnInit { this.page = +params.page || this.searchOptions.pagination.currentPage; this.pageSize = +params.pageSize || this.searchOptions.pagination.pageSize; this.direction = +params.sortDirection || this.searchOptions.sort.direction; + if (params.view === ViewMode.Grid) { + this.pageSizeOptions = this.gridPageSizeOptions; + } else { + this.pageSizeOptions = this.listPageSizeOptions; + } }); } diff --git a/src/app/core/data/browse-response-parsing.service.spec.ts b/src/app/core/data/browse-response-parsing.service.spec.ts index 6579621610..3e3d2190f7 100644 --- a/src/app/core/data/browse-response-parsing.service.spec.ts +++ b/src/app/core/data/browse-response-parsing.service.spec.ts @@ -2,6 +2,7 @@ import { BrowseResponseParsingService } from './browse-response-parsing.service' import { BrowseEndpointRequest } from './request.models'; import { BrowseSuccessResponse, ErrorResponse } from '../cache/response-cache.models'; import { BrowseDefinition } from '../shared/browse-definition.model'; +import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; describe('BrowseResponseParsingService', () => { let service: BrowseResponseParsingService; @@ -48,7 +49,7 @@ describe('BrowseResponseParsingService', () => { _links: { self: { href: 'https://rest.api/discover/browses' } }, page: { size: 20, totalElements: 2, totalPages: 1, number: 0 } }, statusCode: '200' - }; + } as DSpaceRESTV2Response; const invalidResponse1 = { payload: { @@ -71,22 +72,21 @@ describe('BrowseResponseParsingService', () => { _links: { self: { href: 'https://rest.api/discover/browses' } }, page: { size: 20, totalElements: 2, totalPages: 1, number: 0 } }, statusCode: '200' - }; + } as DSpaceRESTV2Response; const invalidResponse2 = { payload: { - browses: [{}, {}], _links: { self: { href: 'https://rest.api/discover/browses' } }, page: { size: 20, totalElements: 2, totalPages: 1, number: 0 } }, statusCode: '200' - }; + } as DSpaceRESTV2Response ; const invalidResponse3 = { payload: { _links: { self: { href: 'https://rest.api/discover/browses' } }, page: { size: 20, totalElements: 2, totalPages: 1, number: 0 } }, statusCode: '500' - }; + } as DSpaceRESTV2Response; const definitions = [ Object.assign(new BrowseDefinition(), { diff --git a/src/app/core/shared/dspace-object.model.ts b/src/app/core/shared/dspace-object.model.ts index 572efecada..8f96f2485a 100644 --- a/src/app/core/shared/dspace-object.model.ts +++ b/src/app/core/shared/dspace-object.model.ts @@ -3,7 +3,7 @@ import { isEmpty, isNotEmpty } from '../../shared/empty.util'; import { CacheableObject } from '../cache/object-cache.reducer'; import { RemoteData } from '../data/remote-data'; import { ResourceType } from './resource-type'; -import { ListableObject } from '../../object-list/listable-object/listable-object.model'; +import { ListableObject } from '../../shared/object-collection/shared/listable-object.model'; import { Observable } from 'rxjs/Observable'; /** diff --git a/src/app/object-list/collection-list-element/collection-list-element.component.scss b/src/app/object-list/collection-list-element/collection-list-element.component.scss deleted file mode 100644 index ad84b72f8c..0000000000 --- a/src/app/object-list/collection-list-element/collection-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/collection-list-element/collection-list-element.component.ts b/src/app/object-list/collection-list-element/collection-list-element.component.ts deleted file mode 100644 index a99e64a27f..0000000000 --- a/src/app/object-list/collection-list-element/collection-list-element.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Inject } from '@angular/core'; - -import { Collection } from '../../core/shared/collection.model'; -import { ObjectListElementComponent } from '../object-list-element/object-list-element.component'; -import { listElementFor } from '../list-element-decorator'; - -@Component({ - selector: 'ds-collection-list-element', - styleUrls: ['./collection-list-element.component.scss'], - templateUrl: './collection-list-element.component.html' -}) - -@listElementFor(Collection) -export class CollectionListElementComponent extends ObjectListElementComponent {} diff --git a/src/app/object-list/community-list-element/community-list-element.component.scss b/src/app/object-list/community-list-element/community-list-element.component.scss deleted file mode 100644 index ad84b72f8c..0000000000 --- a/src/app/object-list/community-list-element/community-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/community-list-element/community-list-element.component.ts b/src/app/object-list/community-list-element/community-list-element.component.ts deleted file mode 100644 index c05915e8d7..0000000000 --- a/src/app/object-list/community-list-element/community-list-element.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Input, Inject } from '@angular/core'; - -import { Community } from '../../core/shared/community.model'; -import { ObjectListElementComponent } from '../object-list-element/object-list-element.component'; -import { listElementFor } from '../list-element-decorator'; - -@Component({ - selector: 'ds-community-list-element', - styleUrls: ['./community-list-element.component.scss'], - templateUrl: './community-list-element.component.html' -}) - -@listElementFor(Community) -export class CommunityListElementComponent extends ObjectListElementComponent {} diff --git a/src/app/object-list/item-list-element/item-list-element.component.scss b/src/app/object-list/item-list-element/item-list-element.component.scss deleted file mode 100644 index ad84b72f8c..0000000000 --- a/src/app/object-list/item-list-element/item-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../styles/variables.scss'; \ No newline at end of file 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 deleted file mode 100644 index cc6c837bb7..0000000000 --- a/src/app/object-list/item-list-element/item-list-element.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Input, Inject } from '@angular/core'; - -import { Item } from '../../core/shared/item.model'; -import { ObjectListElementComponent } from '../object-list-element/object-list-element.component'; -import { listElementFor } from '../list-element-decorator'; - -@Component({ - selector: 'ds-item-list-element', - styleUrls: ['./item-list-element.component.scss'], - templateUrl: './item-list-element.component.html' -}) - -@listElementFor(Item) -export class ItemListElementComponent extends ObjectListElementComponent {} diff --git a/src/app/object-list/list-element-decorator.ts b/src/app/object-list/list-element-decorator.ts deleted file mode 100644 index 64a747d4a5..0000000000 --- a/src/app/object-list/list-element-decorator.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ListableObject } from './listable-object/listable-object.model'; -import { GenericConstructor } from '../core/shared/generic-constructor'; - -const listElementMap = new Map(); -export function listElementFor(listable: GenericConstructor) { - return function decorator(objectElement: any) { - if (!objectElement) { - return; - } - listElementMap.set(listable, objectElement); - }; -} - -export function getListElementFor(listable: GenericConstructor) { - return listElementMap.get(listable); -} diff --git a/src/app/object-list/object-list-element/object-list-element.component.scss b/src/app/object-list/object-list-element/object-list-element.component.scss deleted file mode 100644 index 1a22768fe8..0000000000 --- a/src/app/object-list/object-list-element/object-list-element.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -@import '../../../styles/variables.scss'; - -:host { - display: block; - margin-bottom: $spacer; -} diff --git a/src/app/object-list/object-list-element/object-list-element.component.ts b/src/app/object-list/object-list-element/object-list-element.component.ts deleted file mode 100644 index df39a7d18d..0000000000 --- a/src/app/object-list/object-list-element/object-list-element.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { ListableObject } from '../listable-object/listable-object.model'; - -@Component({ - selector: 'ds-object-list-element', - styleUrls: ['./object-list-element.component.scss'], - templateUrl: './object-list-element.component.html' -}) -export class ObjectListElementComponent { - object: T; - public constructor(@Inject('objectElementProvider') public listable: ListableObject) { - this.object = listable as T; - } -} diff --git a/src/app/object-list/object-list.component.scss b/src/app/object-list/object-list.component.scss deleted file mode 100644 index b14c7376e3..0000000000 --- a/src/app/object-list/object-list.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss b/src/app/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss deleted file mode 100644 index 88eb98509a..0000000000 --- a/src/app/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts b/src/app/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts deleted file mode 100644 index fa7945dedd..0000000000 --- a/src/app/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/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss b/src/app/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss deleted file mode 100644 index 88eb98509a..0000000000 --- a/src/app/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/search-result-list-element/community-search-result/community-search-result.model.ts b/src/app/object-list/search-result-list-element/community-search-result/community-search-result.model.ts deleted file mode 100644 index 79ea34b6cd..0000000000 --- a/src/app/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/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 deleted file mode 100644 index 88eb98509a..0000000000 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss +++ /dev/null @@ -1 +0,0 @@ -@import '../../../../styles/variables.scss'; \ No newline at end of file diff --git a/src/app/object-list/wrapper-list-element/wrapper-list-element.component.scss b/src/app/object-list/wrapper-list-element/wrapper-list-element.component.scss deleted file mode 100644 index 6f997644cc..0000000000 --- a/src/app/object-list/wrapper-list-element/wrapper-list-element.component.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import '../../../styles/variables.scss'; - diff --git a/src/app/shared/object-collection/object-collection.component.html b/src/app/shared/object-collection/object-collection.component.html new file mode 100644 index 0000000000..c9b1cb92f5 --- /dev/null +++ b/src/app/shared/object-collection/object-collection.component.html @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/app/shared/object-collection/object-collection.component.scss b/src/app/shared/object-collection/object-collection.component.scss new file mode 100644 index 0000000000..48e6526dff --- /dev/null +++ b/src/app/shared/object-collection/object-collection.component.scss @@ -0,0 +1 @@ +@import '../../../styles/variables'; diff --git a/src/app/shared/object-collection/object-collection.component.spec.ts b/src/app/shared/object-collection/object-collection.component.spec.ts new file mode 100644 index 0000000000..b27a342eac --- /dev/null +++ b/src/app/shared/object-collection/object-collection.component.spec.ts @@ -0,0 +1,54 @@ +import { ObjectCollectionComponent } from './object-collection.component'; +import { ViewMode } from '../../+search-page/search-options.model'; +import { element } from 'protractor'; +import { By } from '@angular/platform-browser'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Config } from '../../../config/config.interface'; +import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import { RouterStub } from '../testing/router-stub'; + +describe('ObjectCollectionComponent', () => { + let fixture: ComponentFixture; + let objectCollectionComponent: ObjectCollectionComponent; + + const queryParam = 'test query'; + const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; + const activatedRouteStub = { + queryParams: Observable.of({ + query: queryParam, + scope: scopeParam + }) + }; + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ObjectCollectionComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub } + ], + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ObjectCollectionComponent); + objectCollectionComponent = fixture.componentInstance; + + })); + it('should only show the grid component when the viewmode is set to grid', () => { + objectCollectionComponent.currentMode = ViewMode.Grid; + + expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeDefined(); + expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeNull(); + }); + + it('should only show the list component when the viewmode is set to list', () => { + objectCollectionComponent.currentMode = ViewMode.List; + + expect(fixture.debugElement.query(By.css('ds-object-list'))).toBeDefined(); + expect(fixture.debugElement.query(By.css('ds-object-grid'))).toBeNull(); + }) + +}); diff --git a/src/app/shared/object-collection/object-collection.component.ts b/src/app/shared/object-collection/object-collection.component.ts new file mode 100644 index 0000000000..3af92443c1 --- /dev/null +++ b/src/app/shared/object-collection/object-collection.component.ts @@ -0,0 +1,119 @@ +import { Component, EventEmitter, + Input, + OnInit, + Output, SimpleChanges, OnChanges, ChangeDetectorRef } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { Observable } from 'rxjs/Observable'; + +import { RemoteData } from '../../core/data/remote-data'; +import { PageInfo } from '../../core/shared/page-info.model'; + +import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; + +import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; + +import { ListableObject } from './shared/listable-object.model'; +import { ViewMode } from '../../+search-page/search-options.model'; +import { hasValue, isNotEmpty } from '../empty.util'; + +@Component({ + selector: 'ds-viewable-collection', + styleUrls: ['./object-collection.component.scss'], + templateUrl: './object-collection.component.html', +}) +export class ObjectCollectionComponent implements OnChanges, OnInit { + + @Input() objects: RemoteData; + @Input() config?: PaginationComponentOptions; + @Input() sortConfig: SortOptions; + @Input() hideGear = false; + pageInfo: Observable; + private sub; + /** + * An event fired when the page is changed. + * Event's payload equals to the newly selected page. + */ + @Output() pageChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the page wsize is changed. + * Event's payload equals to the newly selected page size. + */ + @Output() pageSizeChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the sort direction is changed. + * Event's payload equals to the newly selected sort direction. + */ + @Output() sortDirectionChange: EventEmitter = new EventEmitter(); + + @Output() paginationChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the sort field is changed. + * Event's payload equals to the newly selected sort field. + */ + @Output() sortFieldChange: EventEmitter = new EventEmitter(); + data: any = {}; + currentMode: ViewMode = ViewMode.List; + viewModeEnum = ViewMode; + + ngOnChanges(changes: SimpleChanges) { + if (changes.objects && !changes.objects.isFirstChange()) { + // this.pageInfo = this.objects.pageInfo; + } + } + + ngOnInit(): void { + // this.pageInfo = this.objects.pageInfo; + + this.sub = this.route + .queryParams + .subscribe((params) => { + if (isNotEmpty(params.view)) { + this.currentMode = params.view; + } + }); + } + + /** + * @param route + * Route is a singleton service provided by Angular. + * @param router + * Router is a singleton service provided by Angular. + */ + constructor(private cdRef: ChangeDetectorRef, private route: ActivatedRoute, + private router: Router) { + } + + getViewMode(): ViewMode { + this.route.queryParams.map((params) => { + if (isNotEmpty(params.view) && hasValue(params.view)) { + this.currentMode = params.view; + } + }); + return this.currentMode; + } + + onPageChange(event) { + this.pageChange.emit(event); + } + + onPageSizeChange(event) { + this.pageSizeChange.emit(event); + } + + onSortDirectionChange(event) { + this.sortDirectionChange.emit(event); + } + + onSortFieldChange(event) { + this.sortFieldChange.emit(event); + } + + onPaginationChange(event) { + this.paginationChange.emit(event); + } + +} diff --git a/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts b/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts new file mode 100644 index 0000000000..9f54bebed9 --- /dev/null +++ b/src/app/shared/object-collection/shared/dso-element-decorator.spec.ts @@ -0,0 +1,16 @@ +import { ViewMode } from '../../../+search-page/search-options.model'; +import { renderElementsFor } from './dso-element-decorator'; +import { Item } from '../../../core/shared/item.model'; + +describe('ElementDecorator', () => { + const gridDecorator = renderElementsFor(Item, ViewMode.Grid); + const listDecorator = renderElementsFor(Item, ViewMode.List); + it('should have a decorator for both list and grid', () => { + expect(listDecorator.length).not.toBeNull(); + expect(gridDecorator.length).not.toBeNull(); + }); + it('should have 2 separate decorators for grid and list', () => { + expect(listDecorator).not.toEqual(gridDecorator); + }); + +}); diff --git a/src/app/shared/object-collection/shared/dso-element-decorator.ts b/src/app/shared/object-collection/shared/dso-element-decorator.ts new file mode 100644 index 0000000000..51aa57bc50 --- /dev/null +++ b/src/app/shared/object-collection/shared/dso-element-decorator.ts @@ -0,0 +1,20 @@ +import { GenericConstructor } from '../../../core/shared/generic-constructor'; +import { ListableObject } from './listable-object.model'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +const dsoElementMap = new Map(); +export function renderElementsFor(listable: GenericConstructor, viewMode: ViewMode) { + return function decorator(objectElement: any) { + if (!objectElement) { + return; + } + if (!dsoElementMap.get(viewMode)) { + dsoElementMap.set(viewMode, new Map()); + } + dsoElementMap.get(viewMode).set(listable, objectElement); + }; +} + +export function rendersDSOType(listable: GenericConstructor, viewMode: ViewMode) { + return dsoElementMap.get(viewMode).get(listable); +} diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result.model.ts b/src/app/shared/object-collection/shared/item-search-result.model.ts similarity index 100% rename from src/app/object-list/search-result-list-element/item-search-result/item-search-result.model.ts rename to src/app/shared/object-collection/shared/item-search-result.model.ts diff --git a/src/app/object-list/listable-object/listable-object.model.ts b/src/app/shared/object-collection/shared/listable-object.model.ts similarity index 100% rename from src/app/object-list/listable-object/listable-object.model.ts rename to src/app/shared/object-collection/shared/listable-object.model.ts diff --git a/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts new file mode 100644 index 0000000000..d52036b5dc --- /dev/null +++ b/src/app/shared/object-collection/shared/object-collection-element/abstract-listable-element.component.ts @@ -0,0 +1,13 @@ +import { Component, Inject } from '@angular/core'; +import { ListableObject } from '../listable-object.model'; + +@Component({ + selector: 'ds-abstract-object-element', + template: ``, +}) +export class AbstractListableElementComponent { + object: T; + public constructor(@Inject('objectElementProvider') public listableObject: ListableObject) { + this.object = listableObject as T; + } +} diff --git a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html new file mode 100644 index 0000000000..b1287212a3 --- /dev/null +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.html @@ -0,0 +1,14 @@ + + + + + + + {{object.name}} + {{object.shortDescription}} + + View + + + + diff --git a/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.scss b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.scss new file mode 100644 index 0000000000..51a7fc6a55 --- /dev/null +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../styles/variables'; + 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 new file mode 100644 index 0000000000..eaa6edc4d0 --- /dev/null +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.spec.ts @@ -0,0 +1,59 @@ +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 { 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 createdGridElementComponent:CollectionGridElementComponent= new CollectionGridElementComponent(mockCollection); + +describe('CollectionGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CollectionGridElementComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdGridElementComponent)} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CollectionGridElementComponent); + })); + + it('should show the collection cards in the grid element',() => { + expect(fixture.debugElement.query(By.css('ds-collection-grid-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-grid/collection-grid-element/collection-grid-element.component.ts b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts new file mode 100644 index 0000000000..f383367e3f --- /dev/null +++ b/src/app/shared/object-grid/collection-grid-element/collection-grid-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Inject } from '@angular/core'; + +import { Collection } from '../../../core/shared/collection.model'; +import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; +import { ViewMode } from '../../../+search-page/search-options.model'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; + +@Component({ + selector: 'ds-collection-grid-element', + styleUrls: ['./collection-grid-element.component.scss'], + templateUrl: './collection-grid-element.component.html' +}) + +@renderElementsFor(Collection, ViewMode.Grid) +export class CollectionGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html new file mode 100644 index 0000000000..b6f4c5c5d9 --- /dev/null +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.html @@ -0,0 +1,14 @@ + + + + + + + + {{object.name}} + {{object.shortDescription}} + + View + + + diff --git a/src/app/shared/object-grid/community-grid-element/community-grid-element.component.scss b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.scss new file mode 100644 index 0000000000..51a7fc6a55 --- /dev/null +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../styles/variables'; + 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 new file mode 100644 index 0000000000..cb9e20449e --- /dev/null +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.spec.ts @@ -0,0 +1,66 @@ +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 { By } from '@angular/platform-browser'; +import { ListableObject } from '../../object-collection/shared/listable-object.model'; +import { Community } from '../../../core/shared/community.model'; + +let communityGridElementComponent: CommunityGridElementComponent; +let fixture: ComponentFixture; +const queryParam = 'test query'; +const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; +const activatedRouteStub = { + queryParams: Observable.of({ + query: queryParam, + scope: scopeParam + }) +}; + +const mockCommunity: Community = Object.assign(new Community(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + }] +}); + +const createdGridElementComponent:CommunityGridElementComponent= new CommunityGridElementComponent(mockCommunity); + +describe('CommunityGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CommunityGridElementComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdGridElementComponent)} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CommunityGridElementComponent); + communityGridElementComponent = fixture.componentInstance; + + })); + + it('should show the community cards in the grid element',() => { + expect(fixture.debugElement.query(By.css('ds-community-grid-element'))).toBeDefined(); + }) + + 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-grid/community-grid-element/community-grid-element.component.ts b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts new file mode 100644 index 0000000000..21d73ff0fa --- /dev/null +++ b/src/app/shared/object-grid/community-grid-element/community-grid-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Input, Inject } from '@angular/core'; + +import { Community } from '../../../core/shared/community.model'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +@Component({ + selector: 'ds-community-grid-element', + styleUrls: ['./community-grid-element.component.scss'], + templateUrl: './community-grid-element.component.html' +}) + +@renderElementsFor(Community, ViewMode.Grid) +export class CommunityGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.html b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.html new file mode 100644 index 0000000000..c0c3c1f65f --- /dev/null +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.html @@ -0,0 +1,4 @@ + + + + diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.scss b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.scss new file mode 100644 index 0000000000..45a533cd01 --- /dev/null +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.scss @@ -0,0 +1 @@ +@import '../../../../styles/variables'; diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts new file mode 100644 index 0000000000..2d2bd6305a --- /dev/null +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.spec.ts @@ -0,0 +1,42 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { GridThumbnailComponent } from './grid-thumbnail.component'; +import { Bitstream } from '../../../core/shared/bitstream.model'; +import { SafeUrlPipe } from '../../utils/safe-url-pipe'; + +describe('ThumbnailComponent', () => { + let comp: GridThumbnailComponent; + let fixture: ComponentFixture; + let de: DebugElement; + let el: HTMLElement; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [GridThumbnailComponent, SafeUrlPipe] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GridThumbnailComponent); + comp = fixture.componentInstance; // BannerComponent test instance + de = fixture.debugElement.query(By.css('div.thumbnail')); + el = de.nativeElement; + }); + + it('should display image', () => { + comp.thumbnail = new Bitstream(); + comp.thumbnail.content = 'test.url'; + fixture.detectChanges(); + const image: HTMLElement = de.query(By.css('img')).nativeElement; + expect(image.getAttribute('src')).toBe(comp.thumbnail.content); + }); + + it('should display placeholder', () => { + fixture.detectChanges(); + const image: HTMLElement = de.query(By.css('img')).nativeElement; + expect(image.getAttribute('src')).toBe(comp.holderSource); + }); + +}); diff --git a/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts new file mode 100644 index 0000000000..8ca93470da --- /dev/null +++ b/src/app/shared/object-grid/grid-thumbnail/grid-thumbnail.component.ts @@ -0,0 +1,30 @@ +import { Component, Input } from '@angular/core'; +import { Bitstream } from '../../../core/shared/bitstream.model'; + +/** + * This component renders a given Bitstream as a thumbnail. + * One input parameter of type Bitstream is expected. + * If no Bitstream is provided, a holderjs image will be rendered instead. + */ + +@Component({ + selector: 'ds-grid-thumbnail', + styleUrls: ['./grid-thumbnail.component.scss'], + templateUrl: './grid-thumbnail.component.html' +}) +export class GridThumbnailComponent { + + @Input() thumbnail: Bitstream; + + data: any = {}; + + /** + * The default 'holder.js' image + */ + holderSource = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjYwIiBoZWlnaHQ9IjE4MCIgdmlld0JveD0iMCAwIDI2MCAxODAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjwhLS0KU291cmNlIFVSTDogaG9sZGVyLmpzLzEwMCV4MTgwL3RleHQ6Tm8gVGh1bWJuYWlsCkNyZWF0ZWQgd2l0aCBIb2xkZXIuanMgMi42LjAuCkxlYXJuIG1vcmUgYXQgaHR0cDovL2hvbGRlcmpzLmNvbQooYykgMjAxMi0yMDE1IEl2YW4gTWFsb3BpbnNreSAtIGh0dHA6Ly9pbXNreS5jbwotLT48ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWyNob2xkZXJfMTVmNzJmMmFlMGIgdGV4dCB7IGZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxM3B0IH0gXV0+PC9zdHlsZT48L2RlZnM+PGcgaWQ9ImhvbGRlcl8xNWY3MmYyYWUwYiI+PHJlY3Qgd2lkdGg9IjI2MCIgaGVpZ2h0PSIxODAiIGZpbGw9IiNFRUVFRUUiLz48Zz48dGV4dCB4PSI3Mi4yNDIxODc1IiB5PSI5NiI+Tm8gVGh1bWJuYWlsPC90ZXh0PjwvZz48L2c+PC9zdmc+'; + + errorHandler(event) { + event.currentTarget.src = this.holderSource; + } + +} 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 new file mode 100644 index 0000000000..b8bacfaf2e --- /dev/null +++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.html @@ -0,0 +1,23 @@ + + + + + + + + {{object.findMetadata('dc.title')}} + + + {{authorMd.value}} + ; + + {{object.findMetadata("dc.date.issued")}} + + + {{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }} + + + View + + + diff --git a/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss new file mode 100644 index 0000000000..51a7fc6a55 --- /dev/null +++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../styles/variables'; + 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 new file mode 100644 index 0000000000..3be46965ee --- /dev/null +++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.spec.ts @@ -0,0 +1,67 @@ +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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../utils/truncate.pipe'; +import { Item } from '../../../core/shared/item.model'; + +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(), { + metadata: [ + { + key: 'dc.contributor.author', + language: 'en_US', + value: 'Smith, Donald' + }] +}); + +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}} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(ItemGridElementComponent); + itemGridElementComponent = fixture.componentInstance; + + })); + + it('should show the item cards in the grid element',() => { + expect(fixture.debugElement.query(By.css('ds-item-grid-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-grid/item-grid-element/item-grid-element.component.ts b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.ts new file mode 100644 index 0000000000..5a8d46f1f2 --- /dev/null +++ b/src/app/shared/object-grid/item-grid-element/item-grid-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Input, Inject } from '@angular/core'; + +import { Item } from '../../../core/shared/item.model'; +import { renderElementsFor} from '../../object-collection/shared/dso-element-decorator'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +@Component({ + selector: 'ds-item-grid-element', + styleUrls: ['./item-grid-element.component.scss'], + templateUrl: './item-grid-element.component.html' +}) + +@renderElementsFor(Item, ViewMode.Grid) +export class ItemGridElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/shared/object-grid/object-grid.component.html b/src/app/shared/object-grid/object-grid.component.html new file mode 100644 index 0000000000..8040a99552 --- /dev/null +++ b/src/app/shared/object-grid/object-grid.component.html @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/src/app/shared/object-grid/object-grid.component.scss b/src/app/shared/object-grid/object-grid.component.scss new file mode 100644 index 0000000000..a85e38d26f --- /dev/null +++ b/src/app/shared/object-grid/object-grid.component.scss @@ -0,0 +1,27 @@ +@import '../../../styles/variables'; + +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; + } +} diff --git a/src/app/object-list/object-list-element/object-list-element.component.html b/src/app/shared/object-grid/object-grid.component.spec.ts similarity index 100% rename from src/app/object-list/object-list-element/object-list-element.component.html rename to src/app/shared/object-grid/object-grid.component.spec.ts diff --git a/src/app/shared/object-grid/object-grid.component.ts b/src/app/shared/object-grid/object-grid.component.ts new file mode 100644 index 0000000000..a8f8ebb183 --- /dev/null +++ b/src/app/shared/object-grid/object-grid.component.ts @@ -0,0 +1,100 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, + ViewEncapsulation +} from '@angular/core'; + +import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; +import { PaginatedList } from '../../core/data/paginated-list'; + +import { RemoteData } from '../../core/data/remote-data'; +import { fadeIn } from '../animations/fade'; +import { ListableObject } from '../object-collection/shared/listable-object.model'; + +import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; + +@Component({ + changeDetection: ChangeDetectionStrategy.Default, + encapsulation: ViewEncapsulation.Emulated, + selector: 'ds-object-grid', + styleUrls: [ './object-grid.component.scss' ], + templateUrl: './object-grid.component.html', + animations: [fadeIn] +}) + +export class ObjectGridComponent { + + @Input() config: PaginationComponentOptions; + @Input() sortConfig: SortOptions; + @Input() hideGear = false; + @Input() hidePagerWhenSinglePage = true; + private _objects: RemoteData>; + @Input() set objects(objects: RemoteData>) { + this._objects = objects; + } + get objects() { + return this._objects; + } + + /** + * An event fired when the page is changed. + * Event's payload equals to the newly selected page. + */ + @Output() change: EventEmitter<{ + pagination: PaginationComponentOptions, + sort: SortOptions + }> = new EventEmitter<{ + pagination: PaginationComponentOptions, + sort: SortOptions + }>(); + + /** + * An event fired when the page is changed. + * Event's payload equals to the newly selected page. + */ + @Output() pageChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the page wsize is changed. + * Event's payload equals to the newly selected page size. + */ + @Output() pageSizeChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the sort direction is changed. + * Event's payload equals to the newly selected sort direction. + */ + @Output() sortDirectionChange: EventEmitter = new EventEmitter(); + + @Output() paginationChange: EventEmitter = new EventEmitter(); + + /** + * An event fired when the sort field is changed. + * Event's payload equals to the newly selected sort field. + */ + @Output() sortFieldChange: EventEmitter = new EventEmitter(); + data: any = {}; + onPageChange(event) { + this.pageChange.emit(event); + } + + onPageSizeChange(event) { + this.pageSizeChange.emit(event); + } + + onSortDirectionChange(event) { + this.sortDirectionChange.emit(event); + } + + onSortFieldChange(event) { + this.sortFieldChange.emit(event); + } + + onPaginationChange(event) { + this.paginationChange.emit(event); + } + +} diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html new file mode 100644 index 0000000000..d6b1bfb5f4 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.html @@ -0,0 +1,13 @@ + + + + + + + {{dso.name}} + {{dso.shortDescription}} + + View + + + diff --git a/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.scss new file mode 100644 index 0000000000..1d0786105c --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.scss @@ -0,0 +1 @@ +@import '../../../../../styles/variables'; 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 new file mode 100644 index 0000000000..a3b3710080 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.spec.ts @@ -0,0 +1,64 @@ +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 { 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'; + +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 createdGridElementComponent: CollectionSearchResultGridElementComponent = new CollectionSearchResultGridElementComponent(mockCollection); + +describe('CollectionSearchResultGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CollectionSearchResultGridElementComponent, TruncatePipe ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CollectionSearchResultGridElementComponent); + })); + + it('should show the item result cards in the grid element', () => { + 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',() => { + 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-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 new file mode 100644 index 0000000000..0228107a57 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result-grid-element.component.ts @@ -0,0 +1,17 @@ +import { Component } from '@angular/core'; + +import { renderElementsFor} from '../../../object-collection/shared/dso-element-decorator'; + +import { CollectionSearchResult } from './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'; + +@Component({ + selector: 'ds-collection-search-result-grid-element', + styleUrls: ['../search-result-grid-element.component.scss', 'collection-search-result-grid-element.component.scss'], + templateUrl: 'collection-search-result-grid-element.component.html' +}) + +@renderElementsFor(CollectionSearchResult, ViewMode.Grid) +export class CollectionSearchResultGridElementComponent extends SearchResultGridElementComponent {} 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 new file mode 100644 index 0000000000..ad48247e70 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/collection-search-result/collection-search-result.model.ts @@ -0,0 +1,5 @@ +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.html b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html new file mode 100644 index 0000000000..8ff6874bff --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.html @@ -0,0 +1,14 @@ + + + + + + + + {{dso.name}} + {{dso.shortDescription}} + + View + + + diff --git a/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.scss new file mode 100644 index 0000000000..bd63aa6a3a --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../../styles/variables'; + 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 new file mode 100644 index 0000000000..dd9e16a120 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.spec.ts @@ -0,0 +1,63 @@ +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 { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Community } from '../../../../core/shared/community.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 mockCommunity: Community = Object.assign(new Community(), { + metadata: [ + { + key: 'dc.description.abstract', + language: 'en_US', + value: 'Short description' + } ] + +}); + +const createdGridElementComponent: CommunitySearchResultGridElementComponent = new CommunitySearchResultGridElementComponent(mockCommunity); + +describe('CommunitySearchResultGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CommunitySearchResultGridElementComponent, TruncatePipe ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(CommunitySearchResultGridElementComponent); + })); + + it('should show the item result cards in the grid element', () => { + expect(fixture.debugElement.query(By.css('ds-community-search-result-grid-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-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 new file mode 100644 index 0000000000..4876a784fc --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/community-search-result-grid-element.component.ts @@ -0,0 +1,18 @@ +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'; + +@Component({ + selector: 'ds-community-search-result-grid-element', + styleUrls: ['../search-result-grid-element.component.scss', 'community-search-result-grid-element.component.scss'], + templateUrl: 'community-search-result-grid-element.component.html' +}) + +@renderElementsFor(CommunitySearchResult, ViewMode.Grid) +export class CommunitySearchResultGridElementComponent extends SearchResultGridElementComponent { + +} 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 new file mode 100644 index 0000000000..efeb328e11 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/community-search-result/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/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 new file mode 100644 index 0000000000..ce9324477f --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.html @@ -0,0 +1,34 @@ + + + + + + + + + + + + 1">, ... + + + + 1">, + {{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.scss b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss new file mode 100644 index 0000000000..bd63aa6a3a --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../../styles/variables'; + 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 new file mode 100644 index 0000000000..1a2ca908e2 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.spec.ts @@ -0,0 +1,80 @@ +import { ItemSearchResultGridElementComponent } from './item-search-result-grid-element.component'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Observable } from 'rxjs/Observable'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RouterStub } from '../../../testing/router-stub'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { By } from '@angular/platform-browser'; +import { TruncatePipe } from '../../../utils/truncate.pipe'; +import { Item } from '../../../../core/shared/item.model'; + +let itemSearchResultGridElementComponent: ItemSearchResultGridElementComponent; +let fixture: ComponentFixture; +const queryParam = 'test query'; +const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; +const activatedRouteStub = { + queryParams: Observable.of({ + query: queryParam, + scope: scopeParam + }) +}; +const 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 createdGridElementComponent:ItemSearchResultGridElementComponent= new ItemSearchResultGridElementComponent(mockItem); + +describe('ItemSearchResultGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ItemSearchResultGridElementComponent, TruncatePipe ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useValue: (createdGridElementComponent) } + ], + + 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',() => { + 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',() => { + 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/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 new file mode 100644 index 0000000000..f9fe13cb88 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/item-search-result/item-search-result-grid-element.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; + +import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; +import { SearchResultGridElementComponent } from '../search-result-grid-element.component'; +import { Item } from '../../../../core/shared/item.model'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; +import { ViewMode } from '../../../../+search-page/search-options.model'; + +@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' +}) + +@renderElementsFor(ItemSearchResult, ViewMode.Grid) +export class ItemSearchResultGridElementComponent extends SearchResultGridElementComponent {} diff --git a/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss new file mode 100644 index 0000000000..e8d681fb32 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.scss @@ -0,0 +1,7 @@ + @import '../../../../styles/variables'; +:host { + /deep/ em { + font-weight: bold; + font-style: normal; + } +} 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 new file mode 100644 index 0000000000..8e1d7e0647 --- /dev/null +++ b/src/app/shared/object-grid/search-result-grid-element/search-result-grid-element.component.ts @@ -0,0 +1,57 @@ +import { Component, Inject } from '@angular/core'; + +import { SearchResult } from '../../../+search-page/search-result.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +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'; + +@Component({ + selector: 'ds-search-result-grid-element', + template: `` +}) + +export class SearchResultGridElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { + dso: K; + + public constructor(@Inject('objectElementProvider') public gridable: ListableObject) { + super(gridable); + this.dso = this.object.dspaceObject; + } + + getValues(keys: string[]): string[] { + const results: string[] = new Array(); + this.object.hitHighlights.forEach( + (md: Metadatum) => { + if (keys.indexOf(md.key) > -1) { + results.push(md.value); + } + } + ); + if (isEmpty(results)) { + this.dso.filterMetadata(keys).forEach( + (md: Metadatum) => { + results.push(md.value); + } + ); + } + return results; + } + + getFirstValue(key: string): string { + let result: string; + this.object.hitHighlights.some( + (md: Metadatum) => { + if (key === md.key) { + result = md.value; + return true; + } + } + ); + if (hasNoValue(result)) { + result = this.dso.findMetadata(key); + } + return result; + } +} diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html new file mode 100644 index 0000000000..b613b16055 --- /dev/null +++ b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.html @@ -0,0 +1 @@ + diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss new file mode 100644 index 0000000000..51a7fc6a55 --- /dev/null +++ b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../styles/variables'; + diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts new file mode 100644 index 0000000000..390b003e2e --- /dev/null +++ b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.spec.ts @@ -0,0 +1,43 @@ +import { WrapperGridElementComponent } from './wrapper-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 { By } from '@angular/platform-browser'; + +let wrapperGridElementComponent: WrapperGridElementComponent; +let fixture: ComponentFixture; +const queryParam = 'test query'; +const scopeParam = '7669c72a-3f2a-451f-a3b9-9210e7a4c02f'; +const activatedRouteStub = { + queryParams: Observable.of({ + query: queryParam, + scope: scopeParam + }) +}; + +describe('WrapperGridElementComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ WrapperGridElementComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRouteStub }, + { provide: Router, useClass: RouterStub }, + { provide: 'objectElementProvider', useFactory: (wrapperGridElementComponent)} + ], + + schemas: [ NO_ERRORS_SCHEMA ] + }).compileComponents(); // compile template and css + })); + + beforeEach(async(() => { + fixture = TestBed.createComponent(WrapperGridElementComponent); + wrapperGridElementComponent = fixture.componentInstance; + + })); + + it('should show the wrapper element containing the cards',() => { + expect(fixture.debugElement.query(By.css('ds-collection-grid-element'))).toBeDefined(); + }) +}) diff --git a/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts new file mode 100644 index 0000000000..912df16786 --- /dev/null +++ b/src/app/shared/object-grid/wrapper-grid-element/wrapper-grid-element.component.ts @@ -0,0 +1,28 @@ +import { Component, Input, Injector, ReflectiveInjector, OnInit } from '@angular/core'; +import { GenericConstructor } from '../../../core/shared/generic-constructor'; +import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator'; +import { ListableObject } from '../../object-collection/shared/listable-object.model'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +@Component({ + selector: 'ds-wrapper-grid-element', + styleUrls: ['./wrapper-grid-element.component.scss'], + templateUrl: './wrapper-grid-element.component.html' +}) +export class WrapperGridElementComponent implements OnInit { + @Input() object: ListableObject; + objectInjector: Injector; + + constructor(private injector: Injector) {} + + ngOnInit(): void { + this.objectInjector = ReflectiveInjector.resolveAndCreate( + [{provide: 'objectElementProvider', useFactory: () => (this.object) }], this.injector); + + } + + getGridElement(): string { + const f: GenericConstructor = this.object.constructor as GenericConstructor; + return rendersDSOType(f, ViewMode.Grid); + } +} diff --git a/src/app/object-list/collection-list-element/collection-list-element.component.html b/src/app/shared/object-list/collection-list-element/collection-list-element.component.html similarity index 100% rename from src/app/object-list/collection-list-element/collection-list-element.component.html rename to src/app/shared/object-list/collection-list-element/collection-list-element.component.html diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.scss b/src/app/shared/object-list/collection-list-element/collection-list-element.component.scss new file mode 100644 index 0000000000..45a533cd01 --- /dev/null +++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../styles/variables'; diff --git a/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts b/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts new file mode 100644 index 0000000000..f95c087d5c --- /dev/null +++ b/src/app/shared/object-list/collection-list-element/collection-list-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Inject } from '@angular/core'; + +import { Collection } from '../../../core/shared/collection.model'; +import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; +import { ViewMode } from '../../../+search-page/search-options.model'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; + +@Component({ + selector: 'ds-collection-list-element', + styleUrls: ['./collection-list-element.component.scss'], + templateUrl: './collection-list-element.component.html' +}) + +@renderElementsFor(Collection, ViewMode.List) +export class CollectionListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/object-list/community-list-element/community-list-element.component.html b/src/app/shared/object-list/community-list-element/community-list-element.component.html similarity index 100% rename from src/app/object-list/community-list-element/community-list-element.component.html rename to src/app/shared/object-list/community-list-element/community-list-element.component.html diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.scss b/src/app/shared/object-list/community-list-element/community-list-element.component.scss new file mode 100644 index 0000000000..45a533cd01 --- /dev/null +++ b/src/app/shared/object-list/community-list-element/community-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../styles/variables'; diff --git a/src/app/shared/object-list/community-list-element/community-list-element.component.ts b/src/app/shared/object-list/community-list-element/community-list-element.component.ts new file mode 100644 index 0000000000..e92c080a31 --- /dev/null +++ b/src/app/shared/object-list/community-list-element/community-list-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Input, Inject } from '@angular/core'; + +import { Community } from '../../../core/shared/community.model'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +@Component({ + selector: 'ds-community-list-element', + styleUrls: ['./community-list-element.component.scss'], + templateUrl: './community-list-element.component.html' +}) + +@renderElementsFor(Community, ViewMode.List) +export class CommunityListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/object-list/item-list-element/item-list-element.component.html b/src/app/shared/object-list/item-list-element/item-list-element.component.html similarity index 100% rename from src/app/object-list/item-list-element/item-list-element.component.html rename to src/app/shared/object-list/item-list-element/item-list-element.component.html diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.scss b/src/app/shared/object-list/item-list-element/item-list-element.component.scss new file mode 100644 index 0000000000..45a533cd01 --- /dev/null +++ b/src/app/shared/object-list/item-list-element/item-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../styles/variables'; diff --git a/src/app/shared/object-list/item-list-element/item-list-element.component.ts b/src/app/shared/object-list/item-list-element/item-list-element.component.ts new file mode 100644 index 0000000000..e4efbd6b08 --- /dev/null +++ b/src/app/shared/object-list/item-list-element/item-list-element.component.ts @@ -0,0 +1,15 @@ +import { Component, Input, Inject } from '@angular/core'; + +import { Item } from '../../../core/shared/item.model'; +import { AbstractListableElementComponent } from '../../object-collection/shared/object-collection-element/abstract-listable-element.component'; +import { renderElementsFor } from '../../object-collection/shared/dso-element-decorator'; +import { ViewMode } from '../../../+search-page/search-options.model'; + +@Component({ + selector: 'ds-item-list-element', + styleUrls: ['./item-list-element.component.scss'], + templateUrl: './item-list-element.component.html' +}) + +@renderElementsFor(Item, ViewMode.List) +export class ItemListElementComponent extends AbstractListableElementComponent {} diff --git a/src/app/object-list/object-list.component.html b/src/app/shared/object-list/object-list.component.html similarity index 88% rename from src/app/object-list/object-list.component.html rename to src/app/shared/object-list/object-list.component.html index 897342ae0d..8de695ae58 100644 --- a/src/app/object-list/object-list.component.html +++ b/src/app/shared/object-list/object-list.component.html @@ -12,7 +12,7 @@ (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 new file mode 100644 index 0000000000..48e6526dff --- /dev/null +++ b/src/app/shared/object-list/object-list.component.scss @@ -0,0 +1 @@ +@import '../../../styles/variables'; diff --git a/src/app/object-list/object-list.component.spec.ts b/src/app/shared/object-list/object-list.component.spec.ts similarity index 100% rename from src/app/object-list/object-list.component.spec.ts rename to src/app/shared/object-list/object-list.component.spec.ts diff --git a/src/app/object-list/object-list.component.ts b/src/app/shared/object-list/object-list.component.ts similarity index 84% rename from src/app/object-list/object-list.component.ts rename to src/app/shared/object-list/object-list.component.ts index b298522ebc..b0296d5ae1 100644 --- a/src/app/object-list/object-list.component.ts +++ b/src/app/shared/object-list/object-list.component.ts @@ -6,16 +6,12 @@ import { Output, ViewEncapsulation } from '@angular/core'; - -import { SortDirection, SortOptions } from '../core/cache/models/sort-options.model'; -import { PaginatedList } from '../core/data/paginated-list'; - -import { RemoteData } from '../core/data/remote-data'; -import { ListableObject } from './listable-object/listable-object.model'; - -import { fadeIn } from '../shared/animations/fade'; - -import { PaginationComponentOptions } from '../shared/pagination/pagination-component-options.model'; +import { SortDirection, SortOptions } from '../../core/cache/models/sort-options.model'; +import { PaginatedList } from '../../core/data/paginated-list'; +import { RemoteData } from '../../core/data/remote-data'; +import { fadeIn } from '../animations/fade'; +import { ListableObject } from '../object-collection/shared/listable-object.model'; +import { PaginationComponentOptions } from '../pagination/pagination-component-options.model'; @Component({ changeDetection: ChangeDetectionStrategy.Default, @@ -35,6 +31,7 @@ export class ObjectListComponent { @Input() set objects(objects: RemoteData>) { this._objects = objects; } + get objects() { return this._objects; } diff --git a/src/app/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 similarity index 100% rename from src/app/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html rename to src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.html diff --git a/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss new file mode 100644 index 0000000000..1d0786105c --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../../styles/variables'; diff --git a/src/app/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 similarity index 67% rename from src/app/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts rename to src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result-list-element.component.ts index 9bea14e9a1..5545ea17ec 100644 --- a/src/app/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,9 +1,10 @@ import { Component } from '@angular/core'; -import { listElementFor } from '../../list-element-decorator'; +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 { Collection } from '../../../../core/shared/collection.model'; +import { ViewMode } from '../../../../+search-page/search-options.model'; @Component({ selector: 'ds-collection-search-result-list-element', @@ -11,5 +12,5 @@ import { Collection } from '../../../core/shared/collection.model'; templateUrl: 'collection-search-result-list-element.component.html' }) -@listElementFor(CollectionSearchResult) +@renderElementsFor(CollectionSearchResult, ViewMode.List) export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent {} 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 new file mode 100644 index 0000000000..ad48247e70 --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/collection-search-result/collection-search-result.model.ts @@ -0,0 +1,5 @@ +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/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 similarity index 100% rename from src/app/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html rename to src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.html diff --git a/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss new file mode 100644 index 0000000000..1d0786105c --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../../styles/variables'; diff --git a/src/app/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 similarity index 67% rename from src/app/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts rename to src/app/shared/object-list/search-result-list-element/community-search-result/community-search-result-list-element.component.ts index 741b4b4f65..2d96f61833 100644 --- a/src/app/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,9 +1,10 @@ import { Component } from '@angular/core'; -import { listElementFor } from '../../list-element-decorator'; +import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { CommunitySearchResult } from './community-search-result.model'; import { SearchResultListElementComponent } from '../search-result-list-element.component'; -import { Community } from '../../../core/shared/community.model'; +import { Community } from '../../../../core/shared/community.model'; +import { ViewMode } from '../../../../+search-page/search-options.model'; @Component({ selector: 'ds-community-search-result-list-element', @@ -11,7 +12,7 @@ import { Community } from '../../../core/shared/community.model'; templateUrl: 'community-search-result-list-element.component.html' }) -@listElementFor(CommunitySearchResult) +@renderElementsFor(CommunitySearchResult, ViewMode.List) export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent { } 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 new file mode 100644 index 0000000000..efeb328e11 --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/community-search-result/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/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 similarity index 100% rename from src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html rename to src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html diff --git a/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss new file mode 100644 index 0000000000..1d0786105c --- /dev/null +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.scss @@ -0,0 +1 @@ +@import '../../../../../styles/variables'; diff --git a/src/app/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 similarity index 57% rename from src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts rename to src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts index ef968db0b8..d1011c8c45 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts +++ b/src/app/shared/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.ts @@ -1,9 +1,10 @@ import { Component } from '@angular/core'; -import { listElementFor } from '../../list-element-decorator'; -import { ItemSearchResult } from './item-search-result.model'; +import { renderElementsFor } from '../../../object-collection/shared/dso-element-decorator'; import { SearchResultListElementComponent } from '../search-result-list-element.component'; -import { Item } from '../../../core/shared/item.model'; +import { Item } from '../../../../core/shared/item.model'; +import { ItemSearchResult } from '../../../object-collection/shared/item-search-result.model'; +import { ViewMode } from '../../../../+search-page/search-options.model'; @Component({ selector: 'ds-item-search-result-list-element', @@ -11,5 +12,5 @@ import { Item } from '../../../core/shared/item.model'; templateUrl: 'item-search-result-list-element.component.html' }) -@listElementFor(ItemSearchResult) +@renderElementsFor(ItemSearchResult, ViewMode.List) export class ItemSearchResultListElementComponent extends SearchResultListElementComponent {} diff --git a/src/app/object-list/search-result-list-element/search-result-list-element.component.scss b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.scss similarity index 67% rename from src/app/object-list/search-result-list-element/search-result-list-element.component.scss rename to src/app/shared/object-list/search-result-list-element/search-result-list-element.component.scss index 5ec8b5d81b..7134c43dad 100644 --- a/src/app/object-list/search-result-list-element/search-result-list-element.component.scss +++ b/src/app/shared/object-list/search-result-list-element/search-result-list-element.component.scss @@ -1,7 +1,7 @@ -@import '../../../styles/variables.scss'; +@import '../../../../styles/variables'; :host { ::ng-deep em { font-weight: bold; font-style: normal; } -} \ No newline at end of file +} diff --git a/src/app/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 similarity index 66% rename from src/app/object-list/search-result-list-element/search-result-list-element.component.ts rename to src/app/shared/object-list/search-result-list-element/search-result-list-element.component.ts index 4119bc3c2e..6c79eaad53 100644 --- a/src/app/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 @@ -1,18 +1,18 @@ import { Component, Inject } from '@angular/core'; -import { ObjectListElementComponent } from '../object-list-element/object-list-element.component'; -import { ListableObject } from '../listable-object/listable-object.model'; -import { SearchResult } from '../../+search-page/search-result.model'; -import { DSpaceObject } from '../../core/shared/dspace-object.model'; -import { Metadatum } from '../../core/shared/metadatum.model'; -import { isEmpty, hasNoValue } from '../../shared/empty.util'; +import { SearchResult } from '../../../+search-page/search-result.model'; +import { DSpaceObject } from '../../../core/shared/dspace-object.model'; +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'; @Component({ selector: 'ds-search-result-list-element', template: `` }) -export class SearchResultListElementComponent, K extends DSpaceObject> extends ObjectListElementComponent { +export class SearchResultListElementComponent, K extends DSpaceObject> extends AbstractListableElementComponent { dso: K; public constructor(@Inject('objectElementProvider') public listable: ListableObject) { diff --git a/src/app/object-list/wrapper-list-element/wrapper-list-element.component.html b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.html similarity index 100% rename from src/app/object-list/wrapper-list-element/wrapper-list-element.component.html rename to src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.html diff --git a/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss new file mode 100644 index 0000000000..51a7fc6a55 --- /dev/null +++ b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.scss @@ -0,0 +1,2 @@ +@import '../../../../styles/variables'; + diff --git a/src/app/object-list/wrapper-list-element/wrapper-list-element.component.ts b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts similarity index 67% rename from src/app/object-list/wrapper-list-element/wrapper-list-element.component.ts rename to src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts index 443b9681d1..6450babae8 100644 --- a/src/app/object-list/wrapper-list-element/wrapper-list-element.component.ts +++ b/src/app/shared/object-list/wrapper-list-element/wrapper-list-element.component.ts @@ -1,7 +1,8 @@ import { Component, Input, Injector, ReflectiveInjector, OnInit } from '@angular/core'; -import { ListableObject } from '../listable-object/listable-object.model'; -import { getListElementFor } from '../list-element-decorator' -import { GenericConstructor } from '../../core/shared/generic-constructor'; +import { rendersDSOType } from '../../object-collection/shared/dso-element-decorator' +import { GenericConstructor } from '../../../core/shared/generic-constructor'; +import { ListableObject } from '../../object-collection/shared/listable-object.model'; +import { ViewMode } from '../../../+search-page/search-options.model'; @Component({ selector: 'ds-wrapper-list-element', @@ -17,11 +18,10 @@ export class WrapperListElementComponent implements OnInit { ngOnInit(): void { this.objectInjector = ReflectiveInjector.resolveAndCreate( [{provide: 'objectElementProvider', useFactory: () => (this.object) }], this.injector); - } getListElement(): string { const f: GenericConstructor = this.object.constructor as GenericConstructor; - return getListElementFor(f); + return rendersDSOType(f, ViewMode.List); } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 245d45ea4e..ca13067851 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -14,22 +14,32 @@ 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 { CollectionListElementComponent } from './object-list/collection-list-element/collection-list-element.component'; +import { CommunityListElementComponent } from './object-list/community-list-element/community-list-element.component'; +import { ItemListElementComponent } from './object-list/item-list-element/item-list-element.component'; +import { SearchResultListElementComponent } from './object-list/search-result-list-element/search-result-list-element.component'; +import { WrapperListElementComponent } from './object-list/wrapper-list-element/wrapper-list-element.component'; +import { ObjectListComponent } from './object-list/object-list.component'; + +import { CollectionGridElementComponent} from './object-grid/collection-grid-element/collection-grid-element.component' +import { CommunityGridElementComponent} from './object-grid/community-grid-element/community-grid-element.component' +import { ItemGridElementComponent} from './object-grid/item-grid-element/item-grid-element.component' +import { AbstractListableElementComponent} from './object-collection/shared/object-collection-element/abstract-listable-element.component' +import { WrapperGridElementComponent} from './object-grid/wrapper-grid-element/wrapper-grid-element.component' +import { ObjectGridComponent } from './object-grid/object-grid.component'; +import { ObjectCollectionComponent } from './object-collection/object-collection.component'; import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component'; import { ComcolPageHeaderComponent } from './comcol-page-header/comcol-page-header.component'; import { ComcolPageLogoComponent } from './comcol-page-logo/comcol-page-logo.component'; -import { CommunityListElementComponent } from '../object-list/community-list-element/community-list-element.component'; import { ErrorComponent } from './error/error.component'; import { LoadingComponent } from './loading/loading.component'; -import { ItemListElementComponent } from '../object-list/item-list-element/item-list-element.component'; -import { ObjectListComponent } from '../object-list/object-list.component'; -import { ObjectListElementComponent } from '../object-list/object-list-element/object-list-element.component'; + import { PaginationComponent } from './pagination/pagination.component'; import { ThumbnailComponent } from '../thumbnail/thumbnail.component'; -import { SearchResultListElementComponent } from '../object-list/search-result-list-element/search-result-list-element.component'; import { SearchFormComponent } from './search-form/search-form.component'; -import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component'; +import { SearchResultGridElementComponent } from './object-grid/search-result-grid-element/search-result-grid-element.component'; 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'; const MODULES = [ @@ -59,20 +69,29 @@ const COMPONENTS = [ ErrorComponent, LoadingComponent, ObjectListComponent, - ObjectListElementComponent, + AbstractListableElementComponent, + WrapperListElementComponent, + ObjectGridComponent, + WrapperGridElementComponent, + ObjectCollectionComponent, PaginationComponent, SearchFormComponent, ThumbnailComponent, + GridThumbnailComponent, WrapperListElementComponent, ViewModeSwitchComponent ]; const ENTRY_COMPONENTS = [ // put shared entry components (components that are created dynamically) here + ItemListElementComponent, CollectionListElementComponent, CommunityListElementComponent, - ItemListElementComponent, - SearchResultListElementComponent + SearchResultListElementComponent, + ItemGridElementComponent, + CollectionGridElementComponent, + CommunityGridElementComponent, + SearchResultGridElementComponent ]; const DIRECTIVES = [ diff --git a/src/styles/_custom_variables.scss b/src/styles/_custom_variables.scss index 12ebfd6618..4dcc161cc4 100644 --- a/src/styles/_custom_variables.scss +++ b/src/styles/_custom_variables.scss @@ -1,3 +1,6 @@ $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); +$card-height-percentage:98%; +$card-thumbnail-height:240px; + diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 73aa27eccc..7d05343152 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -2,3 +2,4 @@ @import '../../node_modules/bootstrap/scss/mixins.scss'; /* Custom mixins go here */ +
{{'home.top-level-communities.help' | translate}}
{{object.shortDescription}}
+ {{authorMd.value}} + ; + + {{object.findMetadata("dc.date.issued")}} +
{{object.findMetadata("dc.description.abstract") | dsTruncate:[200] }}
{{dso.shortDescription}}
+ + + 1">, ... + + + + 1">, + {{dso.findMetadata("dc.date.issued")}} + + +
+