#70 pagination support for document list

This commit is contained in:
Denys Vuika
2016-07-13 12:13:25 +01:00
parent 277f43538b
commit 7849ef4323
6 changed files with 104 additions and 34 deletions

View File

@@ -27,7 +27,8 @@ import {
OnChanges,
TemplateRef,
NgZone,
ViewChild
ViewChild,
HostListener
} from '@angular/core';
import { Subject } from 'rxjs/Rx';
import { CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core';
@@ -53,15 +54,13 @@ declare let __moduleName: string;
styleUrls: ['./document-list.css'],
templateUrl: './document-list.html',
providers: [DocumentListService],
directives: [CONTEXT_MENU_DIRECTIVES, ALFRESCO_DATATABLE_DIRECTIVES],
host: {
'(contextmenu)': 'onShowContextMenu($event)'
}
directives: [CONTEXT_MENU_DIRECTIVES, ALFRESCO_DATATABLE_DIRECTIVES]
})
export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit, OnChanges {
static SINGLE_CLICK_NAVIGATION: string = 'click';
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
static DEFAULT_PAGE_SIZE: number = 20;
DEFAULT_ROOT_FOLDER: string = '/';
@@ -85,6 +84,9 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
@Input()
contextMenuActions: boolean = false;
@Input()
pageSize: number = DocumentList.DEFAULT_PAGE_SIZE;
@Output()
nodeClick: EventEmitter<any> = new EventEmitter();
@@ -154,6 +156,7 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
ngOnInit() {
this.data.thumbnails = this.thumbnails;
this.data.maxItems = this.pageSize;
this.displayFolderContent(this.currentFolderPath);
this.contextActionHandler.subscribe(val => this.contextActionCallback(val));
}
@@ -211,6 +214,7 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
return [];
}
@HostListener('contextmenu', ['$event'])
onShowContextMenu(e?: Event) {
if (e) {
e.preventDefault();
@@ -365,5 +369,4 @@ export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, Af
this.executeContentAction(node, action);
}
}
}

View File

@@ -13,11 +13,15 @@
</li>
</ul>
</span>
<span class="mdl-paging__count">1-10 of 25</span>
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-paging__prev">
<span class="mdl-paging__count">{{summary}}</span>
<button (click)="showPrevPage()"
[disabled]="!prevPageAvail"
alfresco-mdl-button class="mdl-button--icon mdl-paging__prev">
<i class="material-icons">keyboard_arrow_left</i>
</button>
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-paging__next">
<button (click)="showNextPage()"
[disabled]="!nextPageAvail"
alfresco-mdl-button class="mdl-button--icon mdl-paging__next">
<i class="material-icons">keyboard_arrow_right</i>
</button>
</div>

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input } from '@angular/core';
import {
MATERIAL_DESIGN_DIRECTIVES,
PaginationProvider
@@ -30,7 +30,9 @@ declare let __moduleName: string;
styleUrls: ['./pagination.component.css'],
directives: [MATERIAL_DESIGN_DIRECTIVES]
})
export class DocumentListPagination implements OnInit {
export class DocumentListPagination {
DEFAULT_PAGE_SIZE: number = 20;
@Input()
supportedPageSizes: number[] = [5, 10, 20, 50, 100];
@@ -38,17 +40,47 @@ export class DocumentListPagination implements OnInit {
@Input()
provider: PaginationProvider;
@Input()
pageSize: number = 10;
get pageSize(): number {
if (this.provider) {
return this.provider.maxItems;
}
return this.DEFAULT_PAGE_SIZE;
}
constructor() {}
set pageSize(value: number) {
if (this.provider) {
this.provider.maxItems = value;
}
}
setPageSize(value: number) {
this.pageSize = value;
}
ngOnInit() {
console.info(this.provider);
get summary(): string {
let from = this.provider.skipCount;
if (from === 0) {
from = 1;
}
let to = this.provider.skipCount + this.provider.count;
let of = this.provider.totalItems;
return `${from}-${to} of ${of}`;
}
get nextPageAvail(): boolean {
return this.provider.hasMoreItems;
}
get prevPageAvail(): boolean {
return this.provider.skipCount > 0;
}
showNextPage() {
this.provider.skipCount += this.provider.maxItems;
}
showPrevPage() {
this.provider.skipCount -= this.provider.maxItems;
}
}

View File

@@ -94,13 +94,13 @@ describe('ShareDataTableAdapter', () => {
it('should fail when getting value for missing row', () => {
let adapter = new ShareDataTableAdapter(null, null, null);
let check = () => { return adapter.getValue(null, <DataColumn>{}); };
expect(check).toThrowError(ShareDataTableAdapter.ERR_ROW_NOT_FOUND);
expect(check).toThrowError(adapter.ERR_ROW_NOT_FOUND);
});
it('should fail when getting value for missing column', () => {
let adapter = new ShareDataTableAdapter(null, null, null);
let check = () => { return adapter.getValue(<DataRow>{}, null); };
expect(check).toThrowError(ShareDataTableAdapter.ERR_COL_NOT_FOUND);
expect(check).toThrowError(adapter.ERR_COL_NOT_FOUND);
});
it('should require path to load data', () => {
@@ -283,7 +283,7 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve file thumbnail', () => {
let imageUrl: 'http://<addresss>';
let imageUrl: string = 'http://<addresss>';
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
let adapter = new ShareDataTableAdapter(documentListService, basePath, null);

View File

@@ -27,22 +27,24 @@ import { DocumentListService } from './../services/document-list.service';
export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvider {
static ERR_ROW_NOT_FOUND: string = 'Row not found';
static ERR_COL_NOT_FOUND: string = 'Column not found';
ERR_ROW_NOT_FOUND: string = 'Row not found';
ERR_COL_NOT_FOUND: string = 'Column not found';
static DEFAULT_DATE_FORMAT: string = 'medium';
static DEFAULT_PAGE_SIZE: number = 100;
DEFAULT_DATE_FORMAT: string = 'medium';
DEFAULT_PAGE_SIZE: number = 20;
MIN_PAGE_SIZE: number = 5;
private sorting: DataSorting;
private rows: DataRow[];
private columns: DataColumn[];
private page: NodePaging;
private currentPath: string;
private _count: number = 0;
private _hasMoreItems: boolean = false;
private _totalItems: number = 0;
private _skipCount: number = 0;
private _maxItems: number = ShareDataTableAdapter.DEFAULT_PAGE_SIZE;
private _maxItems: number = this.DEFAULT_PAGE_SIZE;
thumbnails: boolean = false;
@@ -70,10 +72,24 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
return this._skipCount;
}
set skipCount(value: number) {
if (value !== this._skipCount) {
this._skipCount = value > 0 ? value : 0;
this.loadPath(this.currentPath);
}
}
get maxItems(): number {
return this._maxItems;
}
set maxItems(value: number) {
if (value !== this._maxItems) {
this._maxItems = value > this.MIN_PAGE_SIZE ? value : this.MIN_PAGE_SIZE;
this.loadPath(this.currentPath);
}
}
getRows(): Array<DataRow> {
return this.rows;
}
@@ -94,16 +110,16 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
getValue(row: DataRow, col: DataColumn): any {
if (!row) {
throw new Error(ShareDataTableAdapter.ERR_ROW_NOT_FOUND);
throw new Error(this.ERR_ROW_NOT_FOUND);
}
if (!col) {
throw new Error(ShareDataTableAdapter.ERR_COL_NOT_FOUND);
throw new Error(this.ERR_COL_NOT_FOUND);
}
let value = row.getValue(col.key);
if (col.type === 'date') {
let datePipe = new DatePipe();
let format = col.format || ShareDataTableAdapter.DEFAULT_DATE_FORMAT;
let format = col.format || this.DEFAULT_DATE_FORMAT;
try {
return datePipe.transform(value, format);
} catch (err) {
@@ -193,8 +209,12 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
loadPath(path: string) {
if (path && this.documentListService) {
this.currentPath = path;
this.documentListService
.getFolder(path)
.getFolder(path, {
maxItems: this._maxItems,
skipCount: this._skipCount
})
.subscribe(val => this.loadPage(<NodePaging>val),
error => console.error(error));
}
@@ -240,7 +260,7 @@ export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvid
this._hasMoreItems = false;
this._totalItems = 0;
this._skipCount = 0;
this._maxItems = ShareDataTableAdapter.DEFAULT_PAGE_SIZE;
this._maxItems = this.DEFAULT_PAGE_SIZE;
}
}

View File

@@ -72,15 +72,25 @@ export class DocumentListService {
return AlfrescoApi.getClientWithTicket(this.settings.getApiBaseUrl(), this.authService.getToken());
}
private getNodesPromise(folder: string) {
private getNodesPromise(folder: string, opts?: any) {
let alfrescoClient = this.getAlfrescoClient();
let apiInstance = new AlfrescoApi.Core.NodesApi(alfrescoClient);
let nodeId = '-root-';
let opts = {
let params: any = {
relativePath: folder,
include: ['path']
};
return apiInstance.getNodeChildren(nodeId, opts);
if (opts) {
if (opts.maxItems) {
params.maxItems = opts.maxItems;
}
if (opts.skipCount) {
params.skipCount = opts.skipCount;
}
}
return apiInstance.getNodeChildren(nodeId, params);
}
deleteNode(nodeId: string) {
let client = this.getAlfrescoClient();
@@ -93,10 +103,11 @@ export class DocumentListService {
/**
* Gets the folder node with the content.
* @param folder Path to folder.
* @param opts Options
* @returns {Observable<NodePaging>} Folder entity.
*/
getFolder(folder: string): Observable<NodePaging> {
return Observable.fromPromise(this.getNodesPromise(folder))
getFolder(folder: string, opts?: any): Observable<NodePaging> {
return Observable.fromPromise(this.getNodesPromise(folder, opts))
.map(res => <NodePaging> res)
// .do(data => console.log('Node data', data)) // eyeball results in the console
.catch(this.handleError);