mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 21:13:07 +00:00
44024: simple search UI with working search results
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, Inject } from '@angular/core';
|
||||
|
||||
import { Collection } from '../../core/shared/collection.model';
|
||||
import { ObjectListElementComponent } from '../object-list-element/object-list-element.component';
|
||||
@@ -11,4 +11,4 @@ import { listElementFor } from '../list-element-decorator';
|
||||
})
|
||||
|
||||
@listElementFor(Collection)
|
||||
export class CollectionListElementComponent extends ObjectListElementComponent {}
|
||||
export class CollectionListElementComponent extends ObjectListElementComponent<Collection> {}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input, Inject } from '@angular/core';
|
||||
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { ObjectListElementComponent } from '../object-list-element/object-list-element.component';
|
||||
@@ -11,4 +11,4 @@ import { listElementFor } from '../list-element-decorator';
|
||||
})
|
||||
|
||||
@listElementFor(Community)
|
||||
export class CommunityListElementComponent extends ObjectListElementComponent {}
|
||||
export class CommunityListElementComponent extends ObjectListElementComponent<Community> {}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input, Inject } from '@angular/core';
|
||||
|
||||
import { Item } from '../../core/shared/item.model';
|
||||
import { ObjectListElementComponent } from '../object-list-element/object-list-element.component';
|
||||
@@ -11,4 +11,4 @@ import { listElementFor } from '../list-element-decorator';
|
||||
})
|
||||
|
||||
@listElementFor(Item)
|
||||
export class ItemListElementComponent extends ObjectListElementComponent {}
|
||||
export class ItemListElementComponent extends ObjectListElementComponent<Item> {}
|
||||
|
@@ -1,12 +1,16 @@
|
||||
import { ListableObject } from './listable-object/listable-object.model';
|
||||
import { GenericConstructor } from '../core/shared/generic-constructor';
|
||||
|
||||
const listElementForMetadataKey = Symbol('listElementFor');
|
||||
|
||||
export function listElementFor(value: GenericConstructor<ListableObject>) {
|
||||
return Reflect.metadata(listElementForMetadataKey, value);
|
||||
const listElementMap = new Map();
|
||||
export function listElementFor(listable: GenericConstructor<ListableObject>) {
|
||||
return function decorator(objectElement: any) {
|
||||
if (!objectElement) {
|
||||
return;
|
||||
}
|
||||
listElementMap.set(listable, objectElement);
|
||||
};
|
||||
}
|
||||
|
||||
export function getListElementFor(target: any) {
|
||||
return Reflect.getOwnMetadata(listElementForMetadataKey, target);
|
||||
export function getListElementFor(listable: GenericConstructor<ListableObject>) {
|
||||
return listElementMap.get(listable);
|
||||
}
|
||||
|
@@ -1,3 +1 @@
|
||||
export interface ListableObject {
|
||||
|
||||
}
|
||||
export interface ListableObject {}
|
||||
|
@@ -6,8 +6,9 @@ import { ListableObject } from '../listable-object/listable-object.model';
|
||||
styleUrls: ['./object-list-element.component.scss'],
|
||||
templateUrl: './object-list-element.component.html'
|
||||
})
|
||||
export class ObjectListElementComponent {
|
||||
|
||||
// In the current version of Angular4, @Input is not supported by the NgComponentOutlet - instead we're using DI
|
||||
constructor(@Inject('objectElementProvider') public object: ListableObject) { }
|
||||
export class ObjectListElementComponent <T extends ListableObject> {
|
||||
object: T;
|
||||
public constructor(@Inject('objectElementProvider') public listable: ListableObject) {
|
||||
this.object = listable as T;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,6 @@
|
||||
<a [routerLink]="['/collections/' + dso.id]" class="lead">
|
||||
{{dso.name}}
|
||||
</a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted">
|
||||
{{dso.shortDescription}}
|
||||
</div>
|
@@ -0,0 +1 @@
|
||||
@import '../../../../styles/variables.scss';
|
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { listElementFor } from '../../list-element-decorator';
|
||||
import { CollectionSearchResult } from './collection-search-result.model';
|
||||
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-collection-search-result-list-element',
|
||||
styleUrls: ['collection-search-result-list-element.component.scss'],
|
||||
templateUrl: 'collection-search-result-list-element.component.html'
|
||||
})
|
||||
|
||||
@listElementFor(CollectionSearchResult)
|
||||
export class CollectionSearchResultListElementComponent extends SearchResultListElementComponent<CollectionSearchResult, Collection> {}
|
@@ -0,0 +1,5 @@
|
||||
import { SearchResult } from '../../../search/search-result.model';
|
||||
import { Collection } from '../../../core/shared/collection.model';
|
||||
|
||||
export class CollectionSearchResult extends SearchResult<Collection> {
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
<a [routerLink]="['/communities/' + dso.id]" class="lead">
|
||||
{{dso.name}}
|
||||
</a>
|
||||
<div *ngIf="dso.shortDescription" class="text-muted">
|
||||
{{dso.shortDescription}}
|
||||
</div>
|
@@ -0,0 +1 @@
|
||||
@import '../../../../styles/variables.scss';
|
@@ -0,0 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { listElementFor } from '../../list-element-decorator';
|
||||
import { CommunitySearchResult } from './community-search-result.model';
|
||||
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-community-search-result-list-element',
|
||||
styleUrls: ['community-search-result-list-element.component.scss'],
|
||||
templateUrl: 'community-search-result-list-element.component.html'
|
||||
})
|
||||
|
||||
@listElementFor(CommunitySearchResult)
|
||||
export class CommunitySearchResultListElementComponent extends SearchResultListElementComponent<CommunitySearchResult, Community> {
|
||||
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
import { SearchResult } from '../../../search/search-result.model';
|
||||
import { Community } from '../../../core/shared/community.model';
|
||||
|
||||
export class CommunitySearchResult extends SearchResult<Community> {
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
<a [routerLink]="['/items/' + dso.id]" class="lead">
|
||||
{{dso.findMetadata("dc.title")}}
|
||||
</a>
|
||||
<div>
|
||||
<span class="text-muted">
|
||||
<span *ngIf="dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']);" class="item-list-authors">
|
||||
<span *ngFor="let authorMd of dso.filterMetadata(['dc.contributor.author', 'dc.creator', 'dc.contributor.*']); let last=last;">{{authorMd.value}}
|
||||
<span *ngIf="!last">; </span>
|
||||
</span>
|
||||
</span>
|
||||
(<span *ngIf="dso.findMetadata('dc.publisher')" class="item-list-publisher">{{dso.findMetadata("dc.publisher")}}, </span><span *ngIf="dso.findMetadata('dc.date.issued')" class="item-list-date">{{dso.findMetadata("dc.date.issued")}}</span>)
|
||||
</span>
|
||||
<div *ngIf="dso.findMetadata('dc.description.abstract')" class="item-list-abstract">{{dso.findMetadata("dc.description.abstract") | dsTruncate:[200] }}</div>
|
||||
</div>
|
@@ -0,0 +1 @@
|
||||
@import '../../../../styles/variables.scss';
|
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { listElementFor } from '../../list-element-decorator';
|
||||
import { ItemSearchResult } from './item-search-result.model';
|
||||
import { SearchResultListElementComponent } from '../search-result-list-element.component';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-item-search-result-list-element',
|
||||
styleUrls: ['item-search-result-list-element.component.scss'],
|
||||
templateUrl: 'item-search-result-list-element.component.html'
|
||||
})
|
||||
|
||||
@listElementFor(ItemSearchResult)
|
||||
export class ItemSearchResultListElementComponent extends SearchResultListElementComponent<ItemSearchResult, Item> {}
|
@@ -0,0 +1,5 @@
|
||||
import { SearchResult } from '../../../search/search-result.model';
|
||||
import { Item } from '../../../core/shared/item.model';
|
||||
|
||||
export class ItemSearchResult extends SearchResult<Item> {
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
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/search-result.model';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search-result-list-element',
|
||||
template: ``
|
||||
})
|
||||
|
||||
export class SearchResultListElementComponent<T extends SearchResult<K>, K extends DSpaceObject> extends ObjectListElementComponent<T> {
|
||||
dso: K;
|
||||
public constructor(@Inject('objectElementProvider') public listable: ListableObject) {
|
||||
super(listable);
|
||||
this.dso = this.object.dspaceObject;
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
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';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-wrapper-list-element',
|
||||
@@ -15,11 +16,12 @@ export class WrapperListElementComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.objectInjector = ReflectiveInjector.resolveAndCreate(
|
||||
[{provide: 'objectElementProvider', useFactory: () => ({ providedObject: this.object }) }], this.injector);
|
||||
[{provide: 'objectElementProvider', useFactory: () => (this.object) }], this.injector);
|
||||
|
||||
}
|
||||
|
||||
private getListElement(): string {
|
||||
return getListElementFor(this.object.constructor).constructor.name;
|
||||
getListElement(): string {
|
||||
const f: GenericConstructor<ListableObject> = this.object.constructor as GenericConstructor<ListableObject>;
|
||||
return getListElementFor(f);
|
||||
}
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ import { DSpaceObject } from '../core/shared/dspace-object.model';
|
||||
})
|
||||
export class SearchPageComponent implements OnInit {
|
||||
private sub;
|
||||
private results: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
||||
results: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
||||
|
||||
constructor(
|
||||
private service: SearchService,
|
||||
|
@@ -9,6 +9,10 @@ import { SearchPageRoutingModule } from './search-page-routing.module';
|
||||
import { SearchPageComponent } from './search-page.component';
|
||||
import { SearchFormComponent } from '../shared/search-form/search-form.component';
|
||||
import { SearchResultsComponent } from './search-results/search-results.compontent';
|
||||
import { SearchModule } from '../search/search.module';
|
||||
import { ItemSearchResultListElementComponent } from '../object-list/search-result-list-element/item-search-result/item-search-result-list-element.component';
|
||||
import { 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';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -17,11 +21,20 @@ import { SearchResultsComponent } from './search-results/search-results.componte
|
||||
TranslateModule,
|
||||
RouterModule,
|
||||
SharedModule,
|
||||
SearchModule
|
||||
],
|
||||
declarations: [
|
||||
SearchPageComponent,
|
||||
SearchFormComponent,
|
||||
SearchResultsComponent
|
||||
SearchResultsComponent,
|
||||
ItemSearchResultListElementComponent,
|
||||
CollectionSearchResultListElementComponent,
|
||||
CommunitySearchResultListElementComponent
|
||||
],
|
||||
entryComponents: [
|
||||
ItemSearchResultListElementComponent,
|
||||
CollectionSearchResultListElementComponent,
|
||||
CommunitySearchResultListElementComponent
|
||||
]
|
||||
})
|
||||
export class SearchPageModule { }
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { RemoteData } from '../../core/data/remote-data';
|
||||
import { SearchResult } from '../../search/search-result.model';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
|
||||
/**
|
||||
@@ -14,7 +15,7 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
})
|
||||
|
||||
export class SearchResultsComponent implements OnInit {
|
||||
@Input() searchResults: RemoteData<DSpaceObject[]>;
|
||||
@Input() searchResults: RemoteData<Array<SearchResult<DSpaceObject>>>;
|
||||
|
||||
ngOnInit(): void {
|
||||
// onInit
|
||||
|
@@ -9,6 +9,7 @@ import { SearchOptions } from './search.models';
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class SearchService {
|
||||
@@ -67,7 +68,7 @@ export class SearchService {
|
||||
return values[Math.floor(Math.random() * values.length)];
|
||||
})
|
||||
.map((item: Item, index: number) => {
|
||||
const mockResult: SearchResult<DSpaceObject> = new SearchResult();
|
||||
const mockResult: SearchResult<DSpaceObject> = new ItemSearchResult();
|
||||
mockResult.dspaceObject = item;
|
||||
const highlight = new Metadatum();
|
||||
highlight.key = 'dc.description.abstract';
|
||||
|
@@ -1,15 +1,19 @@
|
||||
<form [formGroup]="searchFormGroup">
|
||||
<form [formGroup]="searchFormGroup" action="/search">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" aria-label="Search input">
|
||||
<div ngbDropdown class="input-group-btn">
|
||||
<button type="submit" class="btn btn-secondary" id="searchDropdown" ngbDropdownToggle>
|
||||
Go
|
||||
|
||||
<div class="input-group-btn" ngbDropdown>
|
||||
<button type="submit" class="btn btn-secondary">Search DSpace</button>
|
||||
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false" id="searchDropdown" ngbDropdownToggle>
|
||||
<span class="sr-only">Toggle Dropdown</span>
|
||||
</button>
|
||||
<div ngbDropdownMenu aria-labelledby="searchDropdown">
|
||||
<div ngbDropdownMenu class="dropdown-menu dropdown-menu-right" aria-labelledby="searchDropdown">
|
||||
<a class="dropdown-item" href="#">Search DSpace</a>
|
||||
<a class="dropdown-item" href="#">Search this collection</a>
|
||||
<a class="dropdown-item" href="#">Search this Collection</a>
|
||||
<a class="dropdown-item" href="#">Search this Community</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@@ -25,6 +25,7 @@ import { CommunityListElementComponent } from '../object-list/community-list-ele
|
||||
import { CollectionListElementComponent } from '../object-list/collection-list-element/collection-list-element.component';
|
||||
import { TruncatePipe } from './utils/truncate.pipe';
|
||||
import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component';
|
||||
import { SearchResultListElementComponent } from '../object-list/search-result-list-element/search-result-list-element.component';
|
||||
|
||||
const MODULES = [
|
||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||
@@ -54,10 +55,15 @@ const COMPONENTS = [
|
||||
ComcolPageLogoComponent,
|
||||
ObjectListComponent,
|
||||
ObjectListElementComponent,
|
||||
WrapperListElementComponent,
|
||||
WrapperListElementComponent
|
||||
];
|
||||
|
||||
const ENTRY_COMPONENTS = [
|
||||
// put shared entry components (components that are created dynamically) here
|
||||
ItemListElementComponent,
|
||||
CollectionListElementComponent,
|
||||
CommunityListElementComponent
|
||||
CommunityListElementComponent,
|
||||
SearchResultListElementComponent
|
||||
];
|
||||
|
||||
const PROVIDERS = [
|
||||
@@ -72,7 +78,8 @@ const PROVIDERS = [
|
||||
],
|
||||
declarations: [
|
||||
...PIPES,
|
||||
...COMPONENTS
|
||||
...COMPONENTS,
|
||||
...ENTRY_COMPONENTS
|
||||
],
|
||||
exports: [
|
||||
...MODULES,
|
||||
@@ -81,6 +88,9 @@ const PROVIDERS = [
|
||||
],
|
||||
providers: [
|
||||
...PROVIDERS
|
||||
],
|
||||
entryComponents: [
|
||||
...ENTRY_COMPONENTS
|
||||
]
|
||||
})
|
||||
export class SharedModule {
|
||||
|
Reference in New Issue
Block a user