mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-1918] added new search api service to search component (#2667)
* [ADF-1918] added new search api service to search component * [ADF-1918] fixed close panel on empty search word * [ADF-1918] added documentation for search changes * [ADF-1918] fixed closing of subscription on destroy
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# Search component
|
# Search control component
|
||||||
|
|
||||||
Displays a input text which shows find-as-you-type suggestions.
|
Displays a input text which shows find-as-you-type suggestions.
|
||||||
|
|
||||||
@@ -38,10 +38,8 @@ Displays a input text which shows find-as-you-type suggestions.
|
|||||||
| highlight | boolean | false | Use the true value if you want to see the searched word highlighted. |
|
| highlight | boolean | false | Use the true value if you want to see the searched word highlighted. |
|
||||||
| expandable | boolean | true | Whether to use an expanding search control, if false then a regular input is used. |
|
| expandable | boolean | true | Whether to use an expanding search control, if false then a regular input is used. |
|
||||||
| liveSearchEnabled | boolean | true | Whether find-as-you-type suggestions should be offered for matching content items. Set to false to disable. |
|
| liveSearchEnabled | boolean | true | Whether find-as-you-type suggestions should be offered for matching content items. Set to false to disable. |
|
||||||
| liveSearchRoot | string | "-root-" | NodeRef or node name where the search should start. |
|
|
||||||
| liveSearchResultType | string | | Node type to filter live search results by, e.g. 'cm:content'. |
|
|
||||||
| liveSearchMaxResults | number | 5 | Maximum number of results to show in the live search. |
|
| liveSearchMaxResults | number | 5 | Maximum number of results to show in the live search. |
|
||||||
| liveSearchResultSort | string | | Criteria to sort live search results by, must be one of "name" , "modifiedAt" or "createdAt" |
|
| customSearchNode | [QueryBody](https://github.com/Alfresco/alfresco-js-api/blob/1.6.0/src/alfresco-search-rest-api/docs/QueryBody.md) | | object which allow you to perform more elaborated query from the search api |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Search Results component
|
# Search component
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -29,11 +29,10 @@
|
|||||||
| Name | Type | Default | Description |
|
| Name | Type | Default | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| searchTerm | string | | Search term to use when executing the search. Updating this value will run a new search and update the results |
|
| searchTerm | string | | Search term to use when executing the search. Updating this value will run a new search and update the results |
|
||||||
| rootNodeId | string | "-root-" | NodeRef or node name where the search should start. |
|
|
||||||
| resultType | string | | Node type to filter search results by, e.g. 'cm:content', 'cm:folder' if you want only the files. |
|
|
||||||
| maxResults | number | 20 | Maximum number of results to show in the search. |
|
| maxResults | number | 20 | Maximum number of results to show in the search. |
|
||||||
| resultSort | string | | Criteria to sort search results by, must be one of "name" , "modifiedAt" or "createdAt" |
|
| skipResults | number | 0 | Number of results to skip from the results pagination. |
|
||||||
| displayWith | function | | Function that maps an option's value to its display value in the trigger |
|
| displayWith | function | | Function that maps an option's value to its display value in the trigger |
|
||||||
|
| searchNode | [QueryBody](https://github.com/Alfresco/alfresco-js-api/blob/1.6.0/src/alfresco-search-rest-api/docs/QueryBody.md) | | object which allow you to perform more elaborated query from the search api |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
import { Component, ViewChild } from '@angular/core';
|
import { Component, ViewChild } from '@angular/core';
|
||||||
import { SearchComponent } from '../search/components/search.component';
|
import { SearchComponent } from '../search/components/search.component';
|
||||||
|
import { QueryBody } from 'alfresco-js-api';
|
||||||
|
|
||||||
const entryItem = {
|
const entryItem = {
|
||||||
entry: {
|
entry: {
|
||||||
@@ -117,7 +118,7 @@ export let errorJson = {
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<adf-search [searchTerm]="searchedWord" [maxResults]="maxResults"
|
<adf-search [searchTerm]="searchedWord" [searchNode]="searchNode" [maxResults]="maxResults"
|
||||||
(error)="showSearchResult('ERROR')"
|
(error)="showSearchResult('ERROR')"
|
||||||
(success)="showSearchResult('success')" #search>
|
(success)="showSearchResult('success')" #search>
|
||||||
<ng-template let-data>
|
<ng-template let-data>
|
||||||
@@ -142,6 +143,7 @@ export let errorJson = {
|
|||||||
message: string = '';
|
message: string = '';
|
||||||
searchedWord= '';
|
searchedWord= '';
|
||||||
maxResults: number = 5;
|
maxResults: number = 5;
|
||||||
|
searchNode: QueryBody;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
@@ -158,6 +160,10 @@ export let errorJson = {
|
|||||||
this.searchedWord = str;
|
this.searchedWord = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSearchNodeTo(searchNode: QueryBody) {
|
||||||
|
this.searchNode = searchNode;
|
||||||
|
}
|
||||||
|
|
||||||
changeMaxResultTo(newMax: number) {
|
changeMaxResultTo(newMax: number) {
|
||||||
this.maxResults = newMax;
|
this.maxResults = newMax;
|
||||||
}
|
}
|
||||||
|
@@ -25,9 +25,7 @@
|
|||||||
|
|
||||||
<adf-search #auto="searchAutocomplete"
|
<adf-search #auto="searchAutocomplete"
|
||||||
class="adf-search-result-autocomplete"
|
class="adf-search-result-autocomplete"
|
||||||
[rootNodeId]="liveSearchRoot"
|
[searchNode]="customSearchNode"
|
||||||
[resultType]="liveSearchResultType"
|
|
||||||
[resultSort]="liveSearchResultSort"
|
|
||||||
[maxResults]="liveSearchMaxResults">
|
[maxResults]="liveSearchMaxResults">
|
||||||
<ng-template let-data>
|
<ng-template let-data>
|
||||||
<mat-list *ngIf="isSearchBarActive()" id="autocomplete-search-result-list">
|
<mat-list *ngIf="isSearchBarActive()" id="autocomplete-search-result-list">
|
||||||
|
@@ -19,7 +19,7 @@ import { DebugElement } from '@angular/core';
|
|||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { MaterialModule } from '../../material.module';
|
import { MaterialModule } from '../../material.module';
|
||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { AuthenticationService, SearchService } from '@alfresco/adf-core';
|
import { AuthenticationService, SearchApiService } from '@alfresco/adf-core';
|
||||||
import { ThumbnailService } from '@alfresco/adf-core';
|
import { ThumbnailService } from '@alfresco/adf-core';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { noResult, results } from '../../mock';
|
import { noResult, results } from '../../mock';
|
||||||
@@ -27,13 +27,13 @@ import { SearchControlComponent } from './search-control.component';
|
|||||||
import { SearchTriggerDirective } from './search-trigger.directive';
|
import { SearchTriggerDirective } from './search-trigger.directive';
|
||||||
import { SearchComponent } from './search.component';
|
import { SearchComponent } from './search.component';
|
||||||
|
|
||||||
xdescribe('SearchControlComponent', () => {
|
describe('SearchControlComponent', () => {
|
||||||
|
|
||||||
let fixture: ComponentFixture<SearchControlComponent>;
|
let fixture: ComponentFixture<SearchControlComponent>;
|
||||||
let component: SearchControlComponent;
|
let component: SearchControlComponent;
|
||||||
let element: HTMLElement;
|
let element: HTMLElement;
|
||||||
let debugElement: DebugElement;
|
let debugElement: DebugElement;
|
||||||
let searchService: SearchService;
|
let searchService: SearchApiService;
|
||||||
let authService: AuthenticationService;
|
let authService: AuthenticationService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
@@ -48,12 +48,12 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ThumbnailService,
|
ThumbnailService,
|
||||||
SearchService
|
SearchApiService
|
||||||
]
|
]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
fixture = TestBed.createComponent(SearchControlComponent);
|
fixture = TestBed.createComponent(SearchControlComponent);
|
||||||
debugElement = fixture.debugElement;
|
debugElement = fixture.debugElement;
|
||||||
searchService = TestBed.get(SearchService);
|
searchService = TestBed.get(SearchApiService);
|
||||||
authService = TestBed.get(AuthenticationService);
|
authService = TestBed.get(AuthenticationService);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
@@ -76,14 +76,14 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emit searchChange when search term input changed', async(() => {
|
it('should emit searchChange when search term input changed', async(() => {
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.callFake(() => {
|
spyOn(searchService, 'search').and.callFake(() => {
|
||||||
return Observable.of({ entry: { list: []}});
|
return Observable.of({ entry: { list: [] } });
|
||||||
});
|
});
|
||||||
component.searchChange.subscribe(value => {
|
component.searchChange.subscribe(value => {
|
||||||
expect(value).toBe('customSearchTerm');
|
expect(value).toBe('customSearchTerm');
|
||||||
});
|
});
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'customSearchTerm';
|
inputDebugElement.nativeElement.value = 'customSearchTerm';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -91,12 +91,12 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should update FAYT search when user inputs a valid term', async(() => {
|
it('should update FAYT search when user inputs a valid term', async(() => {
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'customSearchTerm';
|
inputDebugElement.nativeElement.value = 'customSearchTerm';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
@@ -107,13 +107,13 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should NOT update FAYT term when user inputs a search term less than 3 characters', async(() => {
|
it('should NOT update FAYT term when user inputs an empty string as search term ', async(() => {
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'cu';
|
inputDebugElement.nativeElement.value = '';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
@@ -126,7 +126,7 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
component.searchChange.subscribe(value => {
|
component.searchChange.subscribe(value => {
|
||||||
expect(value).toBe('cu');
|
expect(value).toBe('cu');
|
||||||
});
|
});
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'cu';
|
inputDebugElement.nativeElement.value = 'cu';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -184,10 +184,10 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -206,10 +206,10 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
it('should make autocomplete list control visible when search box has focus and there is a search result', (done) => {
|
it('should make autocomplete list control visible when search box has focus and there is a search result', (done) => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -224,10 +224,10 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
it('should show autocomplete list noe results when search box has focus and there is search result with length 0', async(() => {
|
it('should show autocomplete list noe results when search box has focus and there is search result with length 0', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(noResult));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(noResult));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'NO RES';
|
inputDebugElement.nativeElement.value = 'NO RES';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -241,10 +241,10 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
it('should hide autocomplete list results when the search box loses focus', (done) => {
|
it('should hide autocomplete list results when the search box loses focus', (done) => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'NO RES';
|
inputDebugElement.nativeElement.value = 'NO RES';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -264,10 +264,10 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
it('should keep autocomplete list control visible when user tabs into results', async(() => {
|
it('should keep autocomplete list control visible when user tabs into results', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -280,39 +280,89 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
inputDebugElement.nativeElement.dispatchEvent(new KeyboardEvent('keypress', { key: 'TAB' }));
|
inputDebugElement.nativeElement.dispatchEvent(new KeyboardEvent('keypress', { key: 'TAB' }));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(element.querySelector('#autocomplete-search-result-list') ).not.toBeNull();
|
expect(element.querySelector('#autocomplete-search-result-list')).not.toBeNull();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should close the autocomplete when user press ESCAPE', async(() => {
|
||||||
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
|
inputDebugElement.nativeElement.focus();
|
||||||
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let resultElement: HTMLElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(resultElement).not.toBeNull();
|
||||||
|
let escapeEvent: any = new Event('ESCAPE');
|
||||||
|
escapeEvent.keyCode = 27;
|
||||||
|
inputDebugElement.triggerEventHandler('keydown', escapeEvent);
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
resultElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(resultElement).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should close the autocomplete when user press ENTER on input', async(() => {
|
||||||
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
|
inputDebugElement.nativeElement.focus();
|
||||||
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let resultElement: HTMLElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(resultElement).not.toBeNull();
|
||||||
|
let escapeEvent: any = new Event('ENTER');
|
||||||
|
escapeEvent.keyCode = 13;
|
||||||
|
inputDebugElement.triggerEventHandler('keydown', escapeEvent);
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
resultElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(resultElement).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should focus input element when autocomplete list is cancelled', async(() => {
|
it('should focus input element when autocomplete list is cancelled', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
let escapeEvent: any = new Event('ESCAPE');
|
let escapeEvent: any = new Event('ESCAPE');
|
||||||
escapeEvent.keyCode = 27;
|
escapeEvent.keyCode = 27;
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(escapeEvent);
|
inputDebugElement.nativeElement.dispatchEvent(escapeEvent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
expect(element.querySelector('#result_name_0') ).toBeNull();
|
expect(element.querySelector('#result_name_0')).toBeNull();
|
||||||
expect(document.activeElement.id).toBe(inputDebugElement.nativeElement.id);
|
expect(document.activeElement.id).toBe(inputDebugElement.nativeElement.id);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should NOT display a autocomplete list control when configured not to', async(() => {
|
it('should NOT display a autocomplete list control when configured not to', async(() => {
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
component.liveSearchEnabled = false;
|
component.liveSearchEnabled = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(element.querySelector('#autocomplete-search-result-list') ).toBeNull();
|
expect(element.querySelector('#autocomplete-search-result-list')).toBeNull();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@@ -320,41 +370,58 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
describe('search button', () => {
|
describe('search button', () => {
|
||||||
|
|
||||||
it('should NOT display a autocomplete list control when configured not to', async(() => {
|
it('should NOT display a autocomplete list control when configured not to', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
|
||||||
component.subscriptAnimationState = 'active';
|
component.subscriptAnimationState = 'active';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
expect(component.subscriptAnimationState).toBe('active');
|
||||||
let searchButton: DebugElement = fixture.debugElement.query(By.css('#adf-search-button'));
|
|
||||||
searchButton.triggerEventHandler('click', null);
|
searchButton.triggerEventHandler('click', null);
|
||||||
fixture.whenStable().then(() => {
|
window.setTimeout(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.subscriptAnimationState).toBe('inactive');
|
expect(component.subscriptAnimationState).toBe('inactive');
|
||||||
});
|
}, 100);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('click on the search button should open the input box when is close', (done) => {
|
it('click on the search button should open the input box when is close', (done) => {
|
||||||
component.subscriptAnimationState = 'inactive';
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let searchButton: DebugElement = fixture.debugElement.query(By.css('#adf-search-button'));
|
let searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
|
||||||
searchButton.triggerEventHandler('click', null);
|
searchButton.triggerEventHandler('click', null);
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.subscriptAnimationState).toBe('active');
|
expect(component.subscriptAnimationState).toBe('active');
|
||||||
done();
|
done();
|
||||||
}, 200);
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Search button should not change the input state too often', async(() => {
|
it('Search button should not change the input state too often', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
|
||||||
component.subscriptAnimationState = 'active';
|
component.subscriptAnimationState = 'active';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let searchButton: DebugElement = fixture.debugElement.query(By.css('#adf-search-button'));
|
expect(component.subscriptAnimationState).toBe('active');
|
||||||
searchButton.triggerEventHandler('click', null);
|
searchButton.triggerEventHandler('click', null);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
searchButton.triggerEventHandler('click', null);
|
searchButton.triggerEventHandler('click', null);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
window.setTimeout(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
expect(component.subscriptAnimationState).toBe('inactive');
|
expect(component.subscriptAnimationState).toBe('inactive');
|
||||||
});
|
}, 100);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('Search bar should close when user press ESC button', async(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
|
component.subscriptAnimationState = 'active';
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.subscriptAnimationState).toBe('active');
|
||||||
|
|
||||||
|
inputDebugElement.triggerEventHandler('keyup.escape', {});
|
||||||
|
window.setTimeout(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(component.subscriptAnimationState).toBe('inactive');
|
||||||
|
}, 100);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -362,26 +429,26 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
it('should emit a option clicked event when item is clicked', async(() => {
|
it('should emit a option clicked event when item is clicked', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
component.optionClicked.subscribe((item) => {
|
component.optionClicked.subscribe((item) => {
|
||||||
expect(item.entry.id).toBe('123');
|
expect(item.entry.id).toBe('123');
|
||||||
});
|
});
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let firstOption: DebugElement = fixture.debugElement.query(By.css('#result_name_0'));
|
let firstOption: DebugElement = debugElement.query(By.css('#result_name_0'));
|
||||||
firstOption.triggerEventHandler('click', null);
|
firstOption.triggerEventHandler('click', null);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should set deactivate the search after element is clicked', async(() => {
|
it('should set deactivate the search after element is clicked', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
component.optionClicked.subscribe((item) => {
|
component.optionClicked.subscribe((item) => {
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
expect(component.subscriptAnimationState).toBe('inactive');
|
expect(component.subscriptAnimationState).toBe('inactive');
|
||||||
@@ -389,27 +456,27 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
});
|
});
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let firstOption: DebugElement = fixture.debugElement.query(By.css('#result_name_0'));
|
let firstOption: DebugElement = debugElement.query(By.css('#result_name_0'));
|
||||||
firstOption.triggerEventHandler('click', null);
|
firstOption.triggerEventHandler('click', null);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should NOT reset the search term after element is clicked', async(() => {
|
it('should NOT reset the search term after element is clicked', async(() => {
|
||||||
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
spyOn(component, 'isSearchBarActive').and.returnValue(true);
|
||||||
spyOn(searchService, 'getNodeQueryResults').and.returnValue(Observable.of(results));
|
spyOn(searchService, 'search').and.returnValue(Observable.of(results));
|
||||||
component.optionClicked.subscribe((item) => {
|
component.optionClicked.subscribe((item) => {
|
||||||
expect(component.searchTerm).not.toBeFalsy();
|
expect(component.searchTerm).not.toBeFalsy();
|
||||||
expect(component.searchTerm).toBe('TEST');
|
expect(component.searchTerm).toBe('TEST');
|
||||||
});
|
});
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let inputDebugElement = fixture.debugElement.query(By.css('#adf-control-input'));
|
let inputDebugElement = debugElement.query(By.css('#adf-control-input'));
|
||||||
inputDebugElement.nativeElement.value = 'TEST';
|
inputDebugElement.nativeElement.value = 'TEST';
|
||||||
inputDebugElement.nativeElement.focus();
|
inputDebugElement.nativeElement.focus();
|
||||||
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
inputDebugElement.nativeElement.dispatchEvent(new Event('input'));
|
||||||
@@ -417,7 +484,7 @@ xdescribe('SearchControlComponent', () => {
|
|||||||
|
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
let firstOption: DebugElement = fixture.debugElement.query(By.css('#result_name_0'));
|
let firstOption: DebugElement = debugElement.query(By.css('#result_name_0'));
|
||||||
firstOption.triggerEventHandler('click', null);
|
firstOption.triggerEventHandler('click', null);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core';
|
import { AuthenticationService, ThumbnailService } from '@alfresco/adf-core';
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
import { MinimalNodeEntity, QueryBody } from 'alfresco-js-api';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
|
||||||
@@ -55,18 +55,12 @@ export class SearchControlComponent implements OnInit, OnDestroy {
|
|||||||
@Input()
|
@Input()
|
||||||
liveSearchEnabled: boolean = true;
|
liveSearchEnabled: boolean = true;
|
||||||
|
|
||||||
@Input()
|
|
||||||
liveSearchRoot: string = '-root-';
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
liveSearchResultType: string = null;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
liveSearchResultSort: string = null;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
liveSearchMaxResults: number = 5;
|
liveSearchMaxResults: number = 5;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
customSearchNode: QueryBody;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
submit: EventEmitter<any> = new EventEmitter();
|
submit: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
|
@@ -46,8 +46,6 @@ export const SEARCH_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
|
|||||||
multi: true
|
multi: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIN_WORD_LENGTH_VALID = 3;
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: `input[searchAutocomplete], textarea[searchAutocomplete]`,
|
selector: `input[searchAutocomplete], textarea[searchAutocomplete]`,
|
||||||
host: {
|
host: {
|
||||||
@@ -82,6 +80,9 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.escapeEventStream.unsubscribe();
|
this.escapeEventStream.unsubscribe();
|
||||||
|
if ( this.closingActionsSubscription ) {
|
||||||
|
this.closingActionsSubscription.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get panelOpen(): boolean {
|
get panelOpen(): boolean {
|
||||||
@@ -160,11 +161,11 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
if (document.activeElement === event.target) {
|
if (document.activeElement === event.target) {
|
||||||
let inputValue: string = (event.target as HTMLInputElement).value;
|
let inputValue: string = (event.target as HTMLInputElement).value;
|
||||||
this.onChange(inputValue);
|
this.onChange(inputValue);
|
||||||
if (inputValue.length >= MIN_WORD_LENGTH_VALID) {
|
if (inputValue) {
|
||||||
this.searchPanel.keyPressedStream.next(inputValue);
|
this.searchPanel.keyPressedStream.next(inputValue);
|
||||||
this.openPanel();
|
this.openPanel();
|
||||||
} else {
|
} else {
|
||||||
this.searchPanel.resetResults();
|
this.closePanel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +194,6 @@ export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
|
|||||||
this.searchPanel.setVisibility();
|
this.searchPanel.setVisibility();
|
||||||
return this.panelClosingActions;
|
return this.panelClosingActions;
|
||||||
})
|
})
|
||||||
.first()
|
|
||||||
.subscribe(event => this.setValueAndClose(event));
|
.subscribe(event => this.setValueAndClose(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,27 +16,40 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { SearchService } from '@alfresco/adf-core';
|
import { SearchApiService } from '@alfresco/adf-core';
|
||||||
|
import { QueryBody } from 'alfresco-js-api';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { SearchModule } from '../../index';
|
import { SearchModule } from '../../index';
|
||||||
import { differentResult, result, SimpleSearchTestComponent } from '../../mock';
|
import { differentResult, folderResult, result, SimpleSearchTestComponent } from '../../mock';
|
||||||
|
|
||||||
|
function fakeNodeResultSearch(searchNode: QueryBody): Observable<any> {
|
||||||
|
if (searchNode.query.query === 'FAKE_SEARCH_EXMPL') {
|
||||||
|
return Observable.of(differentResult);
|
||||||
|
}
|
||||||
|
if (searchNode.filterQueries.length === 1 &&
|
||||||
|
searchNode.filterQueries[0].query === "TYPE:'cm:folder'") {
|
||||||
|
return Observable.of(folderResult);
|
||||||
|
}
|
||||||
|
return Observable.of(result);
|
||||||
|
}
|
||||||
|
|
||||||
describe('SearchComponent', () => {
|
describe('SearchComponent', () => {
|
||||||
|
|
||||||
let fixture: ComponentFixture<SimpleSearchTestComponent>, element: HTMLElement;
|
let fixture: ComponentFixture<SimpleSearchTestComponent>, element: HTMLElement;
|
||||||
let component: SimpleSearchTestComponent;
|
let component: SimpleSearchTestComponent;
|
||||||
let searchService: SearchService;
|
let searchService: SearchApiService;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
SearchModule
|
SearchModule
|
||||||
],
|
],
|
||||||
declarations: [ SimpleSearchTestComponent ]
|
declarations: [SimpleSearchTestComponent]
|
||||||
}).compileComponents().then(() => {
|
}).compileComponents().then(() => {
|
||||||
fixture = TestBed.createComponent(SimpleSearchTestComponent);
|
fixture = TestBed.createComponent(SimpleSearchTestComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
element = fixture.nativeElement;
|
element = fixture.nativeElement;
|
||||||
searchService = TestBed.get(SearchService);
|
searchService = TestBed.get(SearchApiService);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -47,8 +60,8 @@ describe('SearchComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should clear results straight away when a new search term is entered', async(() => {
|
it('should clear results straight away when a new search term is entered', async(() => {
|
||||||
spyOn(searchService, 'getQueryNodesPromise')
|
spyOn(searchService, 'search')
|
||||||
.and.returnValues(Promise.resolve(result), Promise.resolve(differentResult));
|
.and.returnValues(Observable.of(result), Observable.of(differentResult));
|
||||||
|
|
||||||
component.setSearchWordTo('searchTerm');
|
component.setSearchWordTo('searchTerm');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -67,8 +80,8 @@ describe('SearchComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display the returned search results', async(() => {
|
it('should display the returned search results', async(() => {
|
||||||
spyOn(searchService, 'getQueryNodesPromise')
|
spyOn(searchService, 'search')
|
||||||
.and.returnValue(Promise.resolve(result));
|
.and.returnValue(Observable.of(result));
|
||||||
|
|
||||||
component.setSearchWordTo('searchTerm');
|
component.setSearchWordTo('searchTerm');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -80,8 +93,8 @@ describe('SearchComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should emit error event when search call fail', async(() => {
|
it('should emit error event when search call fail', async(() => {
|
||||||
spyOn(searchService, 'getQueryNodesPromise')
|
spyOn(searchService, 'search')
|
||||||
.and.returnValue(Promise.reject({ status: 402 }));
|
.and.returnValue(Observable.fromPromise(Promise.reject({ status: 402 })));
|
||||||
component.setSearchWordTo('searchTerm');
|
component.setSearchWordTo('searchTerm');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
fixture.whenStable().then(() => {
|
fixture.whenStable().then(() => {
|
||||||
@@ -92,8 +105,8 @@ describe('SearchComponent', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should be able to hide the result panel', async(() => {
|
it('should be able to hide the result panel', async(() => {
|
||||||
spyOn(searchService, 'getQueryNodesPromise')
|
spyOn(searchService, 'search')
|
||||||
.and.returnValues(Promise.resolve(result), Promise.resolve(differentResult));
|
.and.returnValues(Observable.of(result), Observable.of(differentResult));
|
||||||
|
|
||||||
component.setSearchWordTo('searchTerm');
|
component.setSearchWordTo('searchTerm');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@@ -111,4 +124,70 @@ describe('SearchComponent', () => {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('search node', () => {
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should perform a search based on the query node given', async(() => {
|
||||||
|
spyOn(searchService, 'search')
|
||||||
|
.and.callFake((searchObj) => fakeNodeResultSearch(searchObj));
|
||||||
|
let fakeSearchNode: QueryBody = {
|
||||||
|
query: {
|
||||||
|
query: ''
|
||||||
|
},
|
||||||
|
filterQueries: [
|
||||||
|
{ 'query': "TYPE:'cm:folder'" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
component.setSearchNodeTo(fakeSearchNode);
|
||||||
|
component.setSearchWordTo('searchTerm');
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let optionShowed = element.querySelectorAll('#autocomplete-search-result-list > li').length;
|
||||||
|
expect(optionShowed).toBe(1);
|
||||||
|
let folderOption: HTMLElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(folderOption.textContent.trim()).toBe('MyFolder');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should perform a search with a defaultNode if no searchnode is given', async(() => {
|
||||||
|
spyOn(searchService, 'search')
|
||||||
|
.and.callFake((searchObj) => fakeNodeResultSearch(searchObj));
|
||||||
|
component.setSearchWordTo('searchTerm');
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let optionShowed = element.querySelectorAll('#autocomplete-search-result-list > li').length;
|
||||||
|
expect(optionShowed).toBe(1);
|
||||||
|
let folderOption: HTMLElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(folderOption.textContent.trim()).toBe('MyDoc');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should perform a search with the searchNode given', async(() => {
|
||||||
|
spyOn(searchService, 'search')
|
||||||
|
.and.callFake((searchObj) => fakeNodeResultSearch(searchObj));
|
||||||
|
let fakeSearchNode: QueryBody = {
|
||||||
|
query: {
|
||||||
|
query: 'FAKE_SEARCH_EXMPL'
|
||||||
|
},
|
||||||
|
filterQueries: [
|
||||||
|
{ 'query': "TYPE:'cm:folder'" }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
component.setSearchNodeTo(fakeSearchNode);
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.whenStable().then(() => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
let optionShowed = element.querySelectorAll('#autocomplete-search-result-list > li').length;
|
||||||
|
expect(optionShowed).toBe(1);
|
||||||
|
let folderOption: HTMLElement = <HTMLElement> element.querySelector('#result_option_0');
|
||||||
|
expect(folderOption.textContent.trim()).toBe('TEST_DOC');
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SearchOptions, SearchService } from '@alfresco/adf-core';
|
import { SearchApiService } from '@alfresco/adf-core';
|
||||||
import {
|
import {
|
||||||
AfterContentInit,
|
AfterContentInit,
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
ViewEncapsulation
|
ViewEncapsulation
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { NodePaging } from 'alfresco-js-api';
|
import { NodePaging, QueryBody } from 'alfresco-js-api';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -61,17 +61,14 @@ export class SearchComponent implements AfterContentInit, OnChanges {
|
|||||||
maxResults: number = 20;
|
maxResults: number = 20;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
resultSort: string = null;
|
skipResults: number = 0;
|
||||||
|
|
||||||
@Input()
|
|
||||||
rootNodeId: string = '-root-';
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
resultType: string = null;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
searchTerm: string = '';
|
searchTerm: string = '';
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
searchNode: QueryBody;
|
||||||
|
|
||||||
@Input('class')
|
@Input('class')
|
||||||
set classList(classList: string) {
|
set classList(classList: string) {
|
||||||
if (classList && classList.length) {
|
if (classList && classList.length) {
|
||||||
@@ -104,7 +101,7 @@ export class SearchComponent implements AfterContentInit, OnChanges {
|
|||||||
_classList: { [key: string]: boolean } = {};
|
_classList: { [key: string]: boolean } = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private searchService: SearchService,
|
private searchService: SearchApiService,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private _elementRef: ElementRef) {
|
private _elementRef: ElementRef) {
|
||||||
this.keyPressedStream.asObservable()
|
this.keyPressedStream.asObservable()
|
||||||
@@ -119,10 +116,13 @@ export class SearchComponent implements AfterContentInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes) {
|
ngOnChanges(changes) {
|
||||||
if (changes.searchTerm) {
|
|
||||||
this.resetResults();
|
this.resetResults();
|
||||||
|
if (changes.searchTerm && changes.searchTerm.currentValue) {
|
||||||
this.displaySearchResults(changes.searchTerm.currentValue);
|
this.displaySearchResults(changes.searchTerm.currentValue);
|
||||||
}
|
}
|
||||||
|
if (changes.searchNode && changes.searchNode.currentValue) {
|
||||||
|
this.displaySearchResults();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetResults() {
|
resetResults() {
|
||||||
@@ -140,18 +140,17 @@ export class SearchComponent implements AfterContentInit, OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private displaySearchResults(searchTerm) {
|
private hasValidSearchQuery(searchOpts: QueryBody) {
|
||||||
let searchOpts: SearchOptions = {
|
return searchOpts && searchOpts.query && searchOpts.query.query;
|
||||||
include: ['path', 'allowableOperations'],
|
}
|
||||||
rootNodeId: this.rootNodeId,
|
|
||||||
nodeType: this.resultType,
|
private displaySearchResults(searchTerm?: string) {
|
||||||
maxItems: this.maxResults,
|
let searchOpts: QueryBody = this.getSearchNode(searchTerm);
|
||||||
orderBy: this.resultSort
|
|
||||||
};
|
if (this.hasValidSearchQuery(searchOpts)) {
|
||||||
if (searchTerm !== null && searchTerm !== '') {
|
|
||||||
searchTerm = searchTerm + '*';
|
searchTerm = searchTerm + '*';
|
||||||
this.searchService
|
this.searchService
|
||||||
.getNodeQueryResults(searchTerm, searchOpts)
|
.search(searchOpts)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
results => {
|
results => {
|
||||||
this.results = <NodePaging> results;
|
this.results = <NodePaging> results;
|
||||||
@@ -165,9 +164,39 @@ export class SearchComponent implements AfterContentInit, OnChanges {
|
|||||||
this.error.emit(error);
|
this.error.emit(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.cleanResults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSearchNode(searchTerm: string): QueryBody {
|
||||||
|
if (this.searchNode) {
|
||||||
|
if (!this.searchNode.query.query && searchTerm) {
|
||||||
|
this.searchNode.query.query = searchTerm;
|
||||||
|
}
|
||||||
|
return this.searchNode;
|
||||||
|
} else {
|
||||||
|
return this.generateDefaultSearchNode(searchTerm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateDefaultSearchNode(searchTerm: string): QueryBody {
|
||||||
|
let defaultSearchNode: QueryBody = {
|
||||||
|
query: {
|
||||||
|
query: searchTerm ? `${searchTerm}* OR name:${searchTerm}*` : searchTerm
|
||||||
|
},
|
||||||
|
include: ['path', 'allowableOperations'],
|
||||||
|
paging: {
|
||||||
|
maxItems: this.maxResults.toString(),
|
||||||
|
skipCount: this.skipResults.toString()
|
||||||
|
},
|
||||||
|
filterQueries: [
|
||||||
|
{ query: "TYPE:'cm:folder' OR TYPE:'cm:content'" },
|
||||||
|
{ query: 'NOT cm:creator:System' }]
|
||||||
|
};
|
||||||
|
return defaultSearchNode;
|
||||||
|
}
|
||||||
|
|
||||||
hidePanel() {
|
hidePanel() {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
this._classList['adf-search-show'] = false;
|
this._classList['adf-search-show'] = false;
|
||||||
|
Reference in New Issue
Block a user