mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
#70 pagination support for document list
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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>
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user