Merge pull request #809 from Alfresco/dev-wabson-737

Fix search page navigation from search box
This commit is contained in:
Mario Romano
2016-10-05 11:57:48 +02:00
committed by GitHub
17 changed files with 698 additions and 289 deletions

View File

@@ -91,7 +91,8 @@ Also make sure you include these dependencies in your .html page:
```html
<alfresco-search-control [searchTerm]="searchTerm"
inputType="search"
(searchChange)="customMethod($event);">
(searchChange)="onSearchChange($event);"
(searchSubmit)="onSearchSubmit($event);">
</alfresco-search-control>
```
@@ -116,7 +117,7 @@ import {
@Component({
selector: 'alfresco-search-demo',
template: `
<alfresco-search-control *ngIf="authenticated" [searchTerm]="searchTerm" (searchChange)="searchTermChange($event);">
<alfresco-search-control *ngIf="authenticated" [searchTerm]="searchTerm" (searchChange)="onSearchChange($event);" (searchSubmit)="onSearchSubmit($event)">
</alfresco-search-control>
<div *ngIf="!authenticated">
Authentication failed to ip {{ host }}
@@ -141,11 +142,15 @@ class SearchDemo implements OnInit {
translation.addTranslationFolder();
}
searchTermChange(event) {
onSearchChange(event) {
console.log('Search term changed', event);
this.searchTerm = event.value;
}
onSearchSubmit(event) {
console.log('Search submitted', event);
}
ngOnInit() {
this.login();
}
@@ -165,7 +170,8 @@ bootstrap(SearchDemo, [
```
#### Events
**searchChange**: Emitted when the search term is changed and the form submitted, provided that the term is at least three characters in length<br />
**searchChange**: Emitted when the search term is changed. The search term is provided in the 'value' property of the returned object. If the term is at less than three characters in length then the term is truncated to an empty string.<br />
**searchSubmit**: Emitted when the search form is submitted. The search term is provided in the 'value' property of the returned object.<br />
#### Options
@@ -173,6 +179,7 @@ bootstrap(SearchDemo, [
**inputType**: {string} (optional) default "text". Type of the input field to render, e.g. "search" or "text" (default)<br />
**expandable** {boolean} (optional) default true. Whether to use an expanding search control, if false then a regular input is used.
**autocomplete** {boolean} (optional) default true. Whether the browser should offer field auto-completion for the input field to the user.
**autocompleteEnabled** {boolean} (optional) default true. Whether find-as-you-type suggestions should be offered for matching content items. Set to false to disable.
### Search results
@@ -220,7 +227,7 @@ Also make sure you include these dependencies in your .html page:
```
Example of an component that displays search results, using the Angular2 router to supply a 'q' parameter containing the
search term. If no router is present pon the page of if the router does not provide such a parameter then an empty
search term. If no router is present on the page of if the router does not provide such a parameter then an empty
results page will be shown.
```ts
@@ -242,7 +249,7 @@ import {
@Component({
selector: 'alfresco-search-demo',
template: `
<alfresco-search *ngIf="authenticated" [searchTerm]="searchTerm"></alfresco-search>
<alfresco-search *ngIf="authenticated"></alfresco-search>
<div *ngIf="!authenticated">
Authentication failed to ip {{ host }}
</div>
@@ -266,11 +273,6 @@ class SearchDemo implements OnInit {
translation.addTranslationFolder();
}
searchTermChange(event) {
console.log('Search term changed', event);
this.searchTerm = event.value;
}
ngOnInit() {
this.login();
}

View File

@@ -16,6 +16,7 @@
*/
import { NgModule, ModuleWithProviders } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CoreModule } from 'ng2-alfresco-core';
import { AlfrescoSearchService } from './src/services/alfresco-search.service';
@@ -29,6 +30,7 @@ export * from './src/services/alfresco-search.service';
export * from './src/services/alfresco-thumbnail.service';
export * from './src/components/alfresco-search.component';
export * from './src/components/alfresco-search-control.component';
export * from './src/components/alfresco-search-autocomplete.component';
export const ALFRESCO_SEARCH_DIRECTIVES: [any] = [
AlfrescoSearchComponent,
@@ -43,7 +45,9 @@ export const ALFRESCO_SEARCH_PROVIDERS: [any] = [
@NgModule({
imports: [
CoreModule
CoreModule,
FormsModule,
ReactiveFormsModule
],
declarations: [
...ALFRESCO_SEARCH_DIRECTIVES

View File

@@ -34,7 +34,6 @@ module.exports = function (config) {
'node_modules/alfresco-js-api/dist/alfresco-js-api.js',
{pattern: 'node_modules/ng2-translate/**/*.js', included: false, watched: false},
{pattern: 'node_modules/ng2-translate/**/*.js.map', included: false, watched: false},
'karma-test-shim.js',
@@ -44,18 +43,8 @@ module.exports = function (config) {
{pattern: 'dist/**/*.css', included: true, served: true, watched: true},
// ng2-components
{ pattern: 'node_modules/ng2-activiti-form/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-activiti-processlist/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-activiti-tasklist/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-documentlist/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-login/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-search/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-tag/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-upload/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-viewer/dist/**/*.js', included: false, served: true, watched: false },
{ pattern: 'node_modules/ng2-alfresco-webscript/dist/**/*.js', included: false, served: true, watched: false },
// paths to support debugging with source maps in dev tools
{pattern: 'src/**/*.ts', included: false, watched: false},

View File

@@ -21,5 +21,13 @@
</tr>
</tbody>
</table>
<table data-automation-id="autocomplete_error_message" *ngIf="errorMessage"
class="mdl-data-table mdl-js-data-table mdl-shadow--2dp full-width">
<tbody>
<tr>
<td>{{ 'SEARCH.RESULTS.ERROR' | translate:{errorMessage: errorMessage} }}</td>
</tr>
</tbody>
</table>
<p data-automation-id="autocomplete_error_message" *ngIf="errorMessage">{{ 'SEARCH.RESULTS.ERROR' |
translate:{errorMessage: errorMessage} }}</p>

View File

@@ -15,10 +15,7 @@
* limitations under the License.
*/
/*
import { it, describe, expect, inject, beforeEachProviders, beforeEach, afterEach } from '@angular/core/testing';
import { PLATFORM_PIPES } from '@angular/core';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { AlfrescoSearchAutocompleteComponent } from './alfresco-search-autocomplete.component';
import { AlfrescoThumbnailService } from './../services/alfresco-thumbnail.service';
import { TranslationMock } from './../assets/translation.service.mock';
@@ -29,14 +26,13 @@ import {
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoTranslationService,
AlfrescoPipeTranslate
CoreModule
} from 'ng2-alfresco-core';
declare let jasmine: any;
describe('AlfrescoSearchAutocompleteComponent', () => {
let alfrescoSearchComponentFixture, element, component;
let fixture: ComponentFixture<AlfrescoSearchAutocompleteComponent>, element: HTMLElement;
let component: AlfrescoSearchAutocompleteComponent;
let result = {
list: {
@@ -47,7 +43,7 @@ describe('AlfrescoSearchAutocompleteComponent', () => {
name: 'MyDoc',
isFile : true,
content: {
mimetype: 'text/plain'
mimeType: 'text/plain'
},
createdByUser: {
displayName: 'John Doe'
@@ -61,132 +57,235 @@ describe('AlfrescoSearchAutocompleteComponent', () => {
}
};
let folderResult = {
list: {
entries: [
{
entry: {
id: '123',
name: 'MyFolder',
isFile : false,
isFolder : true,
createdByUser: {
displayName: 'John Doe'
},
modifiedByUser: {
displayName: 'John Doe'
}
}
}
]
}
};
let noResult = {
list: {
entries: []
}
};
beforeEachProviders(() => {
return [
{ provide: PLATFORM_PIPES, useValue: AlfrescoPipeTranslate, multi: true },
{provide: AlfrescoTranslationService, useClass: TranslationMock},
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoSearchService
];
});
let errorJson = {
error: {
errorKey: 'Search failed',
statusCode: 400,
briefSummary: '08220082 search failed',
stackTrace: 'For security reasons the stack trace is no longer displayed, but the property is kept for previous versions.',
descriptionURL: 'https://api-explorer.alfresco.com'
}
};
beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.createAsync(AlfrescoSearchAutocompleteComponent)
.then(fixture => {
jasmine.Ajax.install();
alfrescoSearchComponentFixture = fixture;
element = alfrescoSearchComponentFixture.nativeElement;
component = alfrescoSearchComponentFixture.componentInstance;
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
],
declarations: [ AlfrescoSearchAutocompleteComponent ], // declare the test component
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock},
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoSearchService
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AlfrescoSearchAutocompleteComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
});
}));
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should setup i18n folder', () => {
let translation = jasmine.createSpyObj('AlfrescoTranslationService', [
'addTranslationFolder'
]);
let search = new AlfrescoSearchAutocompleteComponent(null, translation, null);
expect(search).toBeDefined();
let translationService = fixture.debugElement.injector.get(AlfrescoTranslationService);
spyOn(translationService, 'addTranslationFolder');
fixture.detectChanges();
expect(translationService.addTranslationFolder).toHaveBeenCalledWith('node_modules/ng2-alfresco-search/dist/src');
});
it('should display search results when a search term is provided', () => {
let searchTerm = { currentValue: 'customSearchTerm', previousValue: ''};
spyOn(component, 'displaySearchResults').and.stub();
component.searchTerm = searchTerm;
component.searchTerm = 'searchTerm';
component.ngOnChanges({
searchTerm: searchTerm
});
alfrescoSearchComponentFixture.detectChanges();
fixture.detectChanges();
expect(component.displaySearchResults).toHaveBeenCalledWith(searchTerm.currentValue);
});
it('should display the returned search results', (done) => {
it('should clear results straight away when a new search term is entered', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(x => {
alfrescoSearchComponentFixture.detectChanges();
fixture.detectChanges();
component.searchTerm = 'searchTerm2';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm2', previousValue: 'searchTerm'} });
fixture.detectChanges();
expect(element.querySelectorAll('table[data-automation-id="autocomplete_results"] tbody tr').length).toBe(0);
done();
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''} });
});
it('should display the returned search results', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(x => {
fixture.detectChanges();
expect( element.querySelector('#result_user_0').innerHTML).toBe('John Doe');
expect( element.querySelector('#result_name_0').innerHTML).toBe('<b _ngcontent-a-1="">MyDoc</b>');
done();
});
component.searchTerm = { currentValue: 'searchTerm', previousValue: ''};
component.ngOnChanges({searchTerm: component.searchTerm });
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: result
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''} });
});
it('should display no result if no result are returned', (done) => {
component.resultsEmitter.subscribe(x => {
alfrescoSearchComponentFixture.detectChanges();
expect( element.querySelector('#search_no_result')).not.toBe(null);
it('should display the correct thumbnail for result items', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.baseComponentPath = 'http://localhost';
let thumbnailService = fixture.debugElement.injector.get(AlfrescoThumbnailService);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue('fake-type-icon.svg');
spyOn(thumbnailService, 'getMimeTypeKey').and.returnValue('FAKE_TYPE');
component.resultsEmitter.subscribe(() => {
fixture.detectChanges();
let imgEl = <any> element.querySelector('#result_row_0 img');
expect(imgEl).not.toBeNull();
expect(imgEl.src).toBe('http://localhost/img/fake-type-icon.svg');
expect(imgEl.alt).toBe('SEARCH.ICONS.FAKE_TYPE');
done();
});
component.searchTerm = { currentValue: 'searchTerm', previousValue: ''};
component.ngOnChanges({searchTerm: component.searchTerm});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''} });
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: noResult
it('should display no result if no result are returned', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(noResult));
component.resultsEmitter.subscribe(x => {
fixture.detectChanges();
expect(element.querySelector('#search_no_result')).not.toBeNull();
done();
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''}});
});
it('should display an error if an error is encountered running the search', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.reject(errorJson));
component.errorEmitter.subscribe(() => {
fixture.detectChanges();
let resultsEl = element.querySelector('[data-automation-id="autocomplete_results"]');
let errorEl = <any> element.querySelector('[data-automation-id="autocomplete_error_message"]');
expect(resultsEl).toBeNull();
expect(errorEl).not.toBeNull();
expect(errorEl.innerText.trim()).toBe('SEARCH.RESULTS.ERROR');
done();
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''}});
});
it('should clear errors straight away when a new search is performed', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.reject(errorJson));
component.errorEmitter.subscribe(() => {
fixture.detectChanges();
component.searchTerm = 'searchTerm2';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm2', previousValue: 'searchTerm'} });
fixture.detectChanges();
let errorEl = <any> element.querySelector('[data-automation-id="autocomplete_error_message"]');
expect(errorEl).toBeNull();
done();
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''}});
});
it('should emit preview when file item clicked', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(x => {
alfrescoSearchComponentFixture.detectChanges();
element.querySelector('#result_row_0').click();
fixture.detectChanges();
(<any> element.querySelector('#result_row_0')).click();
});
component.searchTerm = { currentValue: 'searchTerm', previousValue: ''};
component.ngOnChanges({searchTerm: component.searchTerm});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: result
});
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''}});
component.preview.subscribe(e => {
done();
});
});
it('should not emit preview when non-file item is clicked', () => {
spyOn(component, 'onItemClick').and.stub();
it('should not emit preview if a non-file item is clicked', (done) => {
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''} });
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(folderResult));
component.preview.subscribe(e => {
expect(e.value).toBe(component.results[0]);
spyOn(component.preview, 'emit');
component.resultsEmitter.subscribe(x => {
fixture.detectChanges();
(<any> element.querySelector('#result_row_0')).click();
expect(component.preview.emit).not.toHaveBeenCalled();
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: result
});
expect(component.onItemClick).not.toHaveBeenCalled();
component.searchTerm = 'searchTerm';
component.ngOnChanges({searchTerm: { currentValue: 'searchTerm', previousValue: ''}});
});
});
*/

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { Component, EventEmitter, Input, OnInit, OnChanges, Output } from '@angular/core';
import { AlfrescoSearchService } from './../services/alfresco-search.service';
import { AlfrescoThumbnailService } from './../services/alfresco-thumbnail.service';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
@@ -28,14 +28,14 @@ declare let __moduleName: string;
templateUrl: './alfresco-search-autocomplete.component.html',
styleUrls: ['./alfresco-search-autocomplete.component.css']
})
export class AlfrescoSearchAutocompleteComponent implements OnChanges {
export class AlfrescoSearchAutocompleteComponent implements OnInit, OnChanges {
baseComponentPath = __moduleName.replace('/components/alfresco-search-autocomplete.component.js', '');
@Input()
searchTerm: string = '';
results: any;
results: any = null;
errorMessage;
@@ -48,17 +48,24 @@ export class AlfrescoSearchAutocompleteComponent implements OnChanges {
@Output()
resultsEmitter = new EventEmitter();
@Output()
errorEmitter = new EventEmitter();
constructor(private alfrescoSearchService: AlfrescoSearchService,
private translate: AlfrescoTranslationService,
private alfrescoThumbnailService: AlfrescoThumbnailService) {
if (translate) {
translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
}
ngOnInit(): void {
if (this.translate) {
this.translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
}
this.results = null;
}
ngOnChanges(changes) {
if (changes.searchTerm) {
this.results = null;
this.errorMessage = null;
this.displaySearchResults(changes.searchTerm.currentValue);
}
}
@@ -70,8 +77,8 @@ export class AlfrescoSearchAutocompleteComponent implements OnChanges {
public displaySearchResults(searchTerm) {
if (searchTerm !== null && searchTerm !== '') {
this.alfrescoSearchService
.getLiveSearchResults(searchTerm)
.subscribe(
.getSearchNodesPromise(searchTerm)
.then(
results => {
this.results = results.list.entries;
this.errorMessage = null;
@@ -80,6 +87,7 @@ export class AlfrescoSearchAutocompleteComponent implements OnChanges {
error => {
this.results = null;
this.errorMessage = <any>error;
this.errorEmitter.emit(error);
}
);
}

View File

@@ -1,4 +1,4 @@
<form (submit)="onSearch($event)">
<form #f="ngForm" (ngSubmit)="onSearch(f.value)">
<div [class]="getTextFieldClassName()">
<label *ngIf="expandable" class="mdl-button mdl-js-button mdl-button--icon" for="searchControl">
<i mdl-upgrade class="material-icons">search</i>
@@ -11,15 +11,17 @@
data-automation-id="search_input"
#searchInput
id="searchControl"
ngControl="searchControl"
[formControl]="searchControl"
[(ngModel)]="searchTerm"
name="searchControl"
(focus)="onFocus($event)"
(blur)="onBlur($event)"
(keyup.escape)="onEscape($event)"
(keyup.arrowdown)="onArrowDown($event)"
aria-labelledby="searchLabel">
<label id="searchLabel" class="mdl-textfield__label" for="searchControl">{{'SEARCH.CONTROL.LABEL' | translate}}</label>
</div>
</div>
</form>
<alfresco-search-autocomplete [searchTerm]="autocompleteSearchTerm" [ngClass]="{active: searchActive, valid: searchValid}"
<alfresco-search-autocomplete *ngIf="autocompleteEnabled"
[searchTerm]="autocompleteSearchTerm" [ngClass]="{active: searchActive, valid: searchValid}"
(preview)="onFileClicked($event)"></alfresco-search-autocomplete>

View File

@@ -15,11 +15,9 @@
* limitations under the License.
*/
/*
import { provide, PLATFORM_PIPES } from '@angular/core';
import { it, describe, expect, inject, beforeEachProviders, beforeEach } from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { AlfrescoSearchControlComponent } from './alfresco-search-control.component';
import { AlfrescoSearchAutocompleteComponent } from './alfresco-search-autocomplete.component';
import { AlfrescoThumbnailService } from './../services/alfresco-thumbnail.service';
import { TranslationMock } from './../assets/translation.service.mock';
import {
@@ -28,95 +26,262 @@ import {
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoTranslationService,
AlfrescoPipeTranslate
CoreModule
} from 'ng2-alfresco-core';
import { AlfrescoSearchService } from '../services/alfresco-search.service';
describe('AlfrescoSearchControlComponent', () => {
let alfrescoSearchControlComponentFixture, element, component;
let fixture: ComponentFixture<AlfrescoSearchControlComponent>;
let component: AlfrescoSearchControlComponent, element: HTMLElement;
beforeEachProviders(() => {
return [
{ provide: PLATFORM_PIPES, useValue: AlfrescoPipeTranslate, multi: true },
AlfrescoSearchService,
provide(AlfrescoTranslationService, {useClass: TranslationMock}),
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService
];
});
beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.createAsync(AlfrescoSearchControlComponent)
.then(fixture => {
alfrescoSearchControlComponentFixture = fixture;
element = alfrescoSearchControlComponentFixture.nativeElement;
component = alfrescoSearchControlComponentFixture.componentInstance;
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
],
declarations: [
AlfrescoSearchControlComponent,
AlfrescoSearchAutocompleteComponent
],
providers: [
{provide: AlfrescoTranslationService, useClass: TranslationMock},
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoSearchService
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AlfrescoSearchControlComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
});
}));
it('should setup i18n folder', () => {
let translation = jasmine.createSpyObj('AlfrescoTranslationService', [
'addTranslationFolder'
]);
let alfrescoSearchControlComponent = new AlfrescoSearchControlComponent(translation);
expect(alfrescoSearchControlComponent).toBeDefined();
let translationService = fixture.debugElement.injector.get(AlfrescoTranslationService);
spyOn(translationService, 'addTranslationFolder');
fixture.detectChanges();
expect(translationService.addTranslationFolder)
.toHaveBeenCalledWith('node_modules/ng2-alfresco-search/dist/src');
});
it('should emit searchChange when search term changed', () => {
alfrescoSearchControlComponentFixture.componentInstance.searchTerm = 'customSearchTerm';
alfrescoSearchControlComponentFixture.detectChanges();
alfrescoSearchControlComponentFixture.componentInstance.searchChange.subscribe(e => {
it('should emit searchChange when search term input changed', (done) => {
fixture.componentInstance.searchChange.subscribe(e => {
expect(e.value).toBe('customSearchTerm');
done();
});
fixture.detectChanges();
fixture.componentInstance.searchTerm = 'customSearchTerm';
fixture.detectChanges();
});
it('should emit searchChange when search term changed by user', (done) => {
fixture.detectChanges();
fixture.componentInstance.searchChange.subscribe(e => {
expect(e.value).toBe('customSearchTerm211');
done();
});
component.searchControl.setValue('customSearchTerm211', true);
fixture.detectChanges();
});
describe('Component rendering', () => {
it('should display a text input field by default', () => {
alfrescoSearchControlComponentFixture.detectChanges();
fixture.detectChanges();
expect(element.querySelectorAll('input[type="text"]').length).toBe(1);
});
it('should display a search input field when specified', () => {
alfrescoSearchControlComponentFixture.componentInstance.inputType = 'search';
alfrescoSearchControlComponentFixture.detectChanges();
fixture.componentInstance.inputType = 'search';
fixture.detectChanges();
expect(element.querySelectorAll('input[type="search"]').length).toBe(1);
});
it('should set browser autocomplete to off by default', () => {
alfrescoSearchControlComponentFixture.detectChanges();
fixture.detectChanges();
let attr = element.querySelectorAll('input[type="text"]')[0].getAttribute('autocomplete');
expect(attr).toBe('off');
});
it('should set browser autocomplete to on when configured', () => {
alfrescoSearchControlComponentFixture.componentInstance.autocomplete = true;
alfrescoSearchControlComponentFixture.detectChanges();
fixture.componentInstance.autocomplete = true;
fixture.detectChanges();
expect(element.querySelectorAll('input[type="text"]')[0].getAttribute('autocomplete')).toBe('on');
});
it('should show an expanding control by default', () => {
alfrescoSearchControlComponentFixture.detectChanges();
fixture.detectChanges();
expect(element.querySelectorAll('div.mdl-textfield--expandable').length).toBe(1);
expect(element.querySelectorAll('div.mdl-textfield__expandable-holder').length).toBe(1);
expect(element.querySelectorAll('label.mdl-button--icon').length).toBe(1);
});
it('should show a normal non-expanding control when configured', () => {
alfrescoSearchControlComponentFixture.detectChanges();
alfrescoSearchControlComponentFixture.componentInstance.expandable = false;
alfrescoSearchControlComponentFixture.detectChanges();
fixture.detectChanges();
fixture.componentInstance.expandable = false;
fixture.detectChanges();
expect(element.querySelectorAll('div.mdl-textfield--expandable').length).toBe(0);
expect(element.querySelectorAll('div.mdl-textfield__expandable-holder').length).toBe(0);
expect(element.querySelectorAll('label.mdl-button--icon').length).toBe(0);
});
});
describe('Find as you type', () => {
let inputEl: HTMLInputElement;
beforeEach(() => {
inputEl = element.querySelector('input');
});
it('should display a find-as-you-type control by default', () => {
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete).not.toBeNull();
});
it('should make find-as-you-type control hidden initially', () => {
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete.classList.contains('active')).toBe(false);
});
it('should make find-as-you-type control visible when search box has focus', () => {
fixture.detectChanges();
inputEl.dispatchEvent(new Event('focus'));
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete.classList.contains('active')).toBe(true);
});
it('should hide find-as-you-type results when the search box loses focus', (done) => {
fixture.detectChanges();
inputEl.dispatchEvent(new Event('focus'));
inputEl.dispatchEvent(new Event('blur'));
window.setTimeout(() => {
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete.classList.contains('active')).toBe(false);
done();
}, 250);
});
it('should hide find-as-you-type results when escape key pressed', () => {
fixture.detectChanges();
inputEl.dispatchEvent(new Event('focus'));
inputEl.dispatchEvent(new KeyboardEvent('keyup', {
key: 'Escape'
}));
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete.classList.contains('active')).toBe(false);
});
it('should make find-as-you-type control visible again when down arrow is pressed', () => {
fixture.detectChanges();
inputEl.dispatchEvent(new Event('focus'));
inputEl.dispatchEvent(new KeyboardEvent('keyup', {
key: 'Escape'
}));
inputEl.dispatchEvent(new KeyboardEvent('keyup', {
key: 'ArrowDown'
}));
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete.classList.contains('active')).toBe(true);
});
it('should NOT display a find-as-you-type control when configured not to', () => {
fixture.componentInstance.autocompleteEnabled = false;
fixture.detectChanges();
let autocomplete: Element = element.querySelector('alfresco-search-autocomplete');
expect(autocomplete).toBeNull();
});
});
describe('search submit', () => {
it('should fire a search when a term has been entered', () => {
spyOn(component.searchSubmit, 'emit');
fixture.detectChanges();
let formEl: HTMLElement = element.querySelector('form');
component.searchTerm = 'searchTerm1';
component.searchControl.setValue('searchTerm1', true);
fixture.detectChanges();
formEl.dispatchEvent(new Event('submit'));
fixture.detectChanges();
expect(component.searchSubmit.emit).toHaveBeenCalledWith({
'value': 'searchTerm1'
});
});
it('should not fire a search when no term has been entered', () => {
spyOn(component.searchSubmit, 'emit');
fixture.detectChanges();
let inputEl: HTMLInputElement = <HTMLInputElement> element.querySelector('input[type="text"]');
let formEl: HTMLElement = element.querySelector('form');
inputEl.value = '';
formEl.dispatchEvent(new Event('submit'));
fixture.detectChanges();
expect(component.searchSubmit.emit).not.toHaveBeenCalled();
});
});
describe('component focus', () => {
it('should fire an event when the search box receives focus', () => {
spyOn(component.expand, 'emit');
let inputEl: HTMLElement = element.querySelector('input');
inputEl.dispatchEvent(new Event('focus'));
expect(component.expand.emit).toHaveBeenCalledWith({
expanded: true
});
});
it('should fire an event when the search box loses focus', () => {
spyOn(component.expand, 'emit');
let inputEl: HTMLElement = element.querySelector('input');
inputEl.dispatchEvent(new Event('blur'));
expect(component.expand.emit).toHaveBeenCalledWith({
expanded: false
});
});
it('should NOT fire an event when the search box receives/loses focus but the component is not expandable',
() => {
spyOn(component.expand, 'emit');
component.expandable = false;
let inputEl: HTMLElement = element.querySelector('input');
inputEl.dispatchEvent(new Event('focus'));
inputEl.dispatchEvent(new Event('blur'));
expect(component.expand.emit).not.toHaveBeenCalled();
});
});
describe('file preview', () => {
it('should emit a preview event when onFileClicked is called', () => {
spyOn(component.preview, 'emit');
component.onFileClicked({
value: 'node12345'
});
expect(component.preview.emit).toHaveBeenCalledWith({
'value': 'node12345'
});
});
});
});
*/

View File

@@ -16,7 +16,7 @@
*/
import { FormControl, Validators } from '@angular/forms';
import { Component, Input, Output, ElementRef, EventEmitter, ViewChild } from '@angular/core';
import { Component, Input, Output, OnInit, ElementRef, EventEmitter, ViewChild } from '@angular/core';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
import { SearchTermValidator } from './../forms/search-term-validator';
@@ -28,7 +28,7 @@ declare let __moduleName: string;
templateUrl: './alfresco-search-control.component.html',
styleUrls: ['./alfresco-search-control.component.css']
})
export class AlfrescoSearchControlComponent {
export class AlfrescoSearchControlComponent implements OnInit {
@Input()
searchTerm = '';
@@ -45,6 +45,9 @@ export class AlfrescoSearchControlComponent {
@Output()
searchChange = new EventEmitter();
@Output()
searchSubmit = new EventEmitter();
@Output()
preview = new EventEmitter();
@@ -55,6 +58,9 @@ export class AlfrescoSearchControlComponent {
@ViewChild('searchInput', {}) searchInput: ElementRef;
@Input()
autocompleteEnabled = true;
@Input()
autocompleteSearchTerm = '';
@@ -68,16 +74,26 @@ export class AlfrescoSearchControlComponent {
this.searchTerm,
Validators.compose([Validators.required, SearchTermValidator.minAlphanumericChars(3)])
);
}
this.searchControl.valueChanges.map(value => this.searchControl.valid ? value : '')
.debounceTime(400).distinctUntilChanged().subscribe(
(value: string) => {
this.autocompleteSearchTerm = value;
this.searchValid = this.searchControl.valid;
ngOnInit(): void {
this.searchControl.valueChanges.debounceTime(400).distinctUntilChanged()
.subscribe((value: string) => {
this.onSearchTermChange(value);
}
);
this.translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
}
translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
private onSearchTermChange(value: string): void {
this.searchActive = true;
this.autocompleteSearchTerm = value;
this.searchControl.setValue(value, true);
this.searchValid = this.searchControl.valid;
this.searchChange.emit({
value: value,
valid: this.searchValid
});
}
getTextFieldClassName(): string {
@@ -98,11 +114,9 @@ export class AlfrescoSearchControlComponent {
* @param event Submit event that was fired
*/
onSearch(event): void {
if (event) {
event.preventDefault();
}
this.searchControl.setValue(this.searchTerm, true);
if (this.searchControl.valid) {
this.searchChange.emit({
this.searchSubmit.emit({
value: this.searchTerm
});
this.searchInput.nativeElement.blur();
@@ -135,4 +149,12 @@ export class AlfrescoSearchControlComponent {
}
}
onEscape(): void {
this.searchActive = false;
}
onArrowDown(): void {
this.searchActive = true;
}
}

View File

@@ -3,7 +3,6 @@
text-align: left;
}
:host .mdl-data-table td {
max-width: 0;
white-space: nowrap;
}
:host .mdl-data-table td.col-mimetype-icon {

View File

@@ -31,9 +31,7 @@
class="mdl-data-table mdl-js-data-table mdl-shadow--2dp full-width">
<tbody>
<tr>
<td>
<div class="truncate"><b> {{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}</b></div>
</td>
<td class="mdl-data-table__cell--non-numeric">{{ 'SEARCH.RESULTS.NONE' | translate:{searchTerm: searchTerm} }}</td>
</tr>
</tbody>
</table>

View File

@@ -15,11 +15,10 @@
* limitations under the License.
*/
/*
import { PLATFORM_PIPES } from '@angular/core';
import { it, describe, expect, inject, beforeEachProviders, beforeEach } from '@angular/core/testing';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { RouteParams } from '@angular/router-deprecated';
import { ReflectiveInjector, SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/Rx';
import { AlfrescoSearchComponent } from './alfresco-search.component';
import { AlfrescoThumbnailService } from './../services/alfresco-thumbnail.service';
import { TranslationMock } from './../assets/translation.service.mock';
@@ -30,14 +29,13 @@ import {
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoTranslationService,
AlfrescoPipeTranslate
CoreModule
} from 'ng2-alfresco-core';
declare let jasmine: any;
describe('AlfrescoSearchComponent', () => {
let alfrescoSearchComponentFixture, element, component;
let fixture: ComponentFixture<AlfrescoSearchComponent>, element: HTMLElement;
let component: AlfrescoSearchComponent;
let result = {
list: {
@@ -48,7 +46,7 @@ describe('AlfrescoSearchComponent', () => {
name: 'MyDoc',
isFile: true,
content: {
mimetype: 'text/plain'
mimeType: 'text/plain'
},
createdByUser: {
displayName: 'John Doe'
@@ -62,40 +60,65 @@ describe('AlfrescoSearchComponent', () => {
}
};
let folderResult = {
list: {
entries: [
{
entry: {
id: '123',
name: 'MyFolder',
isFile : false,
isFolder : true,
createdByUser: {
displayName: 'John Doe'
},
modifiedByUser: {
displayName: 'John Doe'
}
}
}
]
}
};
let noResult = {
list: {
entries: []
}
};
beforeEachProviders(() => {
return [
{ provide: PLATFORM_PIPES, useValue: AlfrescoPipeTranslate, multi: true },
AlfrescoSearchService,
{provide: AlfrescoTranslationService, useClass: TranslationMock},
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService
];
});
let errorJson = {
error: {
errorKey: 'Search failed',
statusCode: 400,
briefSummary: '08220082 search failed',
stackTrace: 'For security reasons the stack trace is no longer displayed, but the property is kept for previous versions.',
descriptionURL: 'https://api-explorer.alfresco.com'
}
};
beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
return tcb
.createAsync(AlfrescoSearchComponent)
.then(fixture => {
jasmine.Ajax.install();
alfrescoSearchComponentFixture = fixture;
element = alfrescoSearchComponentFixture.nativeElement;
component = alfrescoSearchComponentFixture.componentInstance;
});
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
CoreModule
],
declarations: [ AlfrescoSearchComponent ], // declare the test component
providers: [
AlfrescoSearchService,
{provide: AlfrescoTranslationService, useClass: TranslationMock},
AlfrescoThumbnailService,
AlfrescoSettingsService,
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AlfrescoSearchComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
});
}));
afterEach(() => {
jasmine.Ajax.uninstall();
});
it('should not have a search term by default', () => {
let search = new AlfrescoSearchComponent(null, null, null, null);
expect(search).toBeDefined();
@@ -103,92 +126,148 @@ describe('AlfrescoSearchComponent', () => {
});
it('should take the provided search term from query param provided via RouteParams', () => {
let search = new AlfrescoSearchComponent(null, null, null, new RouteParams({q: 'exampleTerm692'}));
let injector = ReflectiveInjector.resolveAndCreate([
{ provide: ActivatedRoute, useValue: { params: Observable.from([{ q: 'exampleTerm692' }]) } }
]);
let search = new AlfrescoSearchComponent(null, null, null, injector.get(ActivatedRoute));
search.ngOnInit();
expect(search.searchTerm).toBe('exampleTerm692');
});
it('should have a null search term if no query param provided via RouteParams', () => {
let search = new AlfrescoSearchComponent(null, null, null, new RouteParams({}));
let injector = ReflectiveInjector.resolveAndCreate([
AlfrescoSearchService,
AlfrescoAuthenticationService,
AlfrescoSettingsService,
AlfrescoApiService,
{ provide: ActivatedRoute, useValue: { params: Observable.from([{}]) } }
]);
let search = new AlfrescoSearchComponent(injector.get(AlfrescoSearchService), null, null, injector.get(ActivatedRoute));
search.ngOnInit();
expect(search.searchTerm).toBeNull();
});
it('should setup i18n folder', () => {
let translation = jasmine.createSpyObj('AlfrescoTranslationService', [
'addTranslationFolder'
]);
let search = new AlfrescoSearchComponent(null, translation, null, null);
expect(search).toBeDefined();
expect(translation.addTranslationFolder).toHaveBeenCalledWith('node_modules/ng2-alfresco-search/dist/src');
let translationService = fixture.debugElement.injector.get(AlfrescoTranslationService);
spyOn(translationService, 'addTranslationFolder');
fixture.detectChanges();
expect(translationService.addTranslationFolder).toHaveBeenCalledWith('node_modules/ng2-alfresco-search/dist/src');
});
describe('Rendering search results', () => {
it('should display search results when a search term is provided', (done) => {
component.searchTerm = { currentValue: 'searchTerm', previousValue: ''};
component.ngOnChanges({searchTerm: component.searchTerm});
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(x => {
alfrescoSearchComponentFixture.detectChanges();
fixture.detectChanges();
expect(searchService.getSearchNodesPromise).toHaveBeenCalled();
expect(element.querySelector('#result_user_0')).not.toBeNull();
expect(element.querySelector('#result_user_0').innerHTML).toBe('John Doe');
expect(element.querySelector('#result_name_0').innerHTML).toBe('MyDoc');
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: result
});
component.searchTerm = 'searchTerm';
component.ngOnInit();
});
it('should display no result if no result are returned', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(noResult));
component.resultsEmitter.subscribe(x => {
alfrescoSearchComponentFixture.detectChanges();
expect(element.querySelector('#search_no_result')).not.toBe(null);
fixture.detectChanges();
expect(element.querySelector('#search_no_result')).not.toBeNull();
done();
});
component.searchTerm = { currentValue: 'searchTerm', previousValue: ''};
component.ngOnChanges({searchTerm: component.searchTerm});
component.searchTerm = 'searchTerm';
component.ngOnInit();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'json',
responseText: noResult
it('should display an error if an error is encountered running the search', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.reject(errorJson));
component.errorEmitter.subscribe(() => {
fixture.detectChanges();
let resultsEl = element.querySelector('[data-automation-id="search_result_table"]');
let errorEl = element.querySelector('[data-automation-id="search_error_message"]');
expect(resultsEl).toBeNull();
expect(errorEl).not.toBeNull();
expect((<any>errorEl).innerText).toBe('SEARCH.RESULTS.ERROR');
done();
});
component.searchTerm = 'searchTerm';
component.ngOnInit();
});
it('should update search results when the search term input is changed', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(x => {
fixture.detectChanges();
expect(searchService.getSearchNodesPromise).toHaveBeenCalledWith('searchTerm2');
expect(element.querySelector('#result_user_0')).not.toBeNull();
expect(element.querySelector('#result_user_0').innerHTML).toBe('John Doe');
expect(element.querySelector('#result_name_0').innerHTML).toBe('MyDoc');
done();
});
component.ngOnChanges({searchTerm: new SimpleChange('', 'searchTerm2')});
});
});
describe('search result actions', () => {
it('should emit preview when file item clicked', () => {
component.results = [{
entry: {
id: '123',
name: 'MyDoc',
content: {
mimetype: 'text/plain'
},
isFile: true
}
}];
it('should emit preview when file item clicked', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(result));
component.resultsEmitter.subscribe(() => {
fixture.detectChanges();
(<HTMLTableRowElement> element.querySelector('#result_row_0')).click();
});
component.searchTerm = 'searchTerm';
component.ngOnInit();
alfrescoSearchComponentFixture.detectChanges(component.results[0]);
component.preview.subscribe(e => {
expect(e.value).toBe(component.results[0]);
done();
});
});
it('should not emit preview when non-file item is clicked', (done) => {
let searchService = fixture.debugElement.injector.get(AlfrescoSearchService);
spyOn(searchService, 'getSearchNodesPromise')
.and.returnValue(Promise.resolve(folderResult));
spyOn(component.preview, 'emit');
component.resultsEmitter.subscribe(x => {
fixture.detectChanges();
(<HTMLTableRowElement> element.querySelector('#result_row_0')).click();
expect(component.preview.emit).not.toHaveBeenCalled();
done();
});
jasmine.Ajax.requests.mostRecent().respondWith({
status: 200,
contentType: 'text/plain',
responseText: '<div></div>'
});
component.searchTerm = 'searchTerm';
component.ngOnInit();
});
});
});
*/

View File

@@ -15,8 +15,8 @@
* limitations under the License.
*/
import { Component, EventEmitter, Input, Output, OnChanges, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Component, EventEmitter, Input, Output, Optional, OnChanges, SimpleChanges, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { AlfrescoSearchService } from './../services/alfresco-search.service';
import { AlfrescoThumbnailService } from './../services/alfresco-thumbnail.service';
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
@@ -42,34 +42,39 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
@Output()
resultsEmitter = new EventEmitter();
results: any;
@Output()
errorEmitter = new EventEmitter();
results: any = null;
errorMessage;
route: any[] = [];
queryParamName = 'q';
constructor(private alfrescoSearchService: AlfrescoSearchService,
private translate: AlfrescoTranslationService,
private _alfrescoThumbnailService: AlfrescoThumbnailService,
private activatedRoute: ActivatedRoute) {
if (translate !== null) {
translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
}
this.results = null;
@Optional() private route: ActivatedRoute) {
}
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => {
this.searchTerm = params['q'];
if (this.translate !== null) {
this.translate.addTranslationFolder('node_modules/ng2-alfresco-search/dist/src');
}
if (this.route) {
this.route.params.forEach((params: Params) => {
this.searchTerm = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
this.displaySearchResults(this.searchTerm);
});
} else {
this.displaySearchResults(this.searchTerm);
});
}
}
ngOnChanges(changes): void {
if (changes.searchTerm) {
this.displaySearchResults(changes.searchTerm.currentValue);
ngOnChanges(changes: SimpleChanges): void {
if (changes['searchTerm']) {
this.searchTerm = changes['searchTerm'].currentValue;
this.displaySearchResults(this.searchTerm);
}
}
@@ -103,7 +108,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
* @param searchTerm Search query entered by user
*/
public displaySearchResults(searchTerm): void {
if (searchTerm !== null) {
if (searchTerm !== null && this.alfrescoSearchService !== null) {
this.alfrescoSearchService
.getLiveSearchResults(searchTerm)
.subscribe(
@@ -115,6 +120,7 @@ export class AlfrescoSearchComponent implements OnChanges, OnInit {
error => {
this.results = null;
this.errorMessage = <any>error;
this.errorEmitter.emit(error);
}
);
}

View File

@@ -15,14 +15,25 @@
* limitations under the License.
*/
import { ReflectiveInjector } from '@angular/core';
import { AlfrescoThumbnailService } from './alfresco-thumbnail.service';
import { AlfrescoApiService, AlfrescoAuthenticationService, AlfrescoContentService, AlfrescoSettingsService } from 'ng2-alfresco-core';
describe('AlfrescoThumbnailService', () => {
let injector: ReflectiveInjector;
let service: AlfrescoThumbnailService;
beforeEach(() => {
service = new AlfrescoThumbnailService(null);
injector = ReflectiveInjector.resolveAndCreate([
AlfrescoApiService,
AlfrescoAuthenticationService,
AlfrescoContentService,
AlfrescoSettingsService,
AlfrescoThumbnailService
]);
service = injector.get(AlfrescoThumbnailService);
});
it('should return the correct icon for a plain text file', () => {
@@ -41,4 +52,9 @@ describe('AlfrescoThumbnailService', () => {
expect(service.getMimeTypeIcon('x-unknown/yyy')).toBe('ft_ic_miscellaneous.svg');
});
it('should return the thumbnail URL for a content item', () => {
spyOn(service.contentService, 'getDocumentThumbnailUrl').and.returnValue('/fake-thumbnail.png');
expect(service.getDocumentThumbnailUrl({})).toBe('/fake-thumbnail.png');
});
});

View File

@@ -50,7 +50,7 @@ export class AlfrescoThumbnailService {
'application/vnd.apple.numbers': 'ft_ic_spreadsheet'
};
constructor(private contentService: AlfrescoContentService) {
constructor(public contentService: AlfrescoContentService) {
}
/**