Merge pull request #423 from Alfresco/dev-denys-70

Pagination for document list Component #70
This commit is contained in:
Mario Romano 2016-07-14 14:13:12 +01:00 committed by GitHub
commit 4c01dd4d34
36 changed files with 625 additions and 97 deletions

View File

@ -92,6 +92,10 @@
</content-action> </content-action>
</content-actions> </content-actions>
</alfresco-document-list> </alfresco-document-list>
<alfresco-pagination
[provider]="documentList.data"
[supportedPageSizes]="[5, 10, 15, 20]">
</alfresco-pagination>
</alfresco-upload-drag-area> </alfresco-upload-drag-area>
</div> </div>

View File

@ -25,8 +25,10 @@ import {
MDL, MDL,
AlfrescoContentService, AlfrescoContentService,
CONTEXT_MENU_DIRECTIVES, CONTEXT_MENU_DIRECTIVES,
AlfrescoPipeTranslate AlfrescoPipeTranslate/*,
PaginationComponent*/
} from 'ng2-alfresco-core'; } from 'ng2-alfresco-core';
import { PaginationComponent } from 'ng2-alfresco-core';
import { ALFRESCO_ULPOAD_COMPONENTS } from 'ng2-alfresco-upload'; import { ALFRESCO_ULPOAD_COMPONENTS } from 'ng2-alfresco-upload';
import { VIEWERCOMPONENT } from 'ng2-alfresco-viewer'; import { VIEWERCOMPONENT } from 'ng2-alfresco-viewer';
@ -42,7 +44,8 @@ declare let __moduleName: string;
MDL, MDL,
ALFRESCO_ULPOAD_COMPONENTS, ALFRESCO_ULPOAD_COMPONENTS,
VIEWERCOMPONENT, VIEWERCOMPONENT,
CONTEXT_MENU_DIRECTIVES CONTEXT_MENU_DIRECTIVES,
PaginationComponent
], ],
providers: [DOCUMENT_LIST_PROVIDERS], providers: [DOCUMENT_LIST_PROVIDERS],
pipes: [AlfrescoPipeTranslate] pipes: [AlfrescoPipeTranslate]

View File

@ -11,5 +11,5 @@ demo/**/*.js
demo/**/*.js.map demo/**/*.js.map
demo/**/*.d.ts demo/**/*.d.ts
index.js index.js
index.map index.js.map
!systemjs.config.js !systemjs.config.js

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;;;;;QAwBU,uBAAuB,EAUvB,sBAAsB,EAItB,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAdvB,qCAAA,uBAAuB,GAAU;gBAC1C,qEAA6B;gBAC7B,uDAAsB;gBACtB,yDAAuB;gBACvB,6DAAyB;gBACzB,+DAA0B;gBAC1B,qDAAqB;gBACrB,yCAAkB;aACrB,CAAA,CAAC;YAEW,oCAAA,sBAAsB,GAAU;gBACzC,yCAAkB;aACrB,CAAA,CAAC;YAEW,qCAAA,uBAAuB,GAAU;gBAC1C,0DAA0B;gBAC1B,6CAAoB;aACvB,CAAA,CAAC"}

View File

@ -15,29 +15,20 @@
* limitations under the License. * limitations under the License.
*/ */
import { AlfrescoSettingsService } from './src/services/AlfrescoSettingsService.service'; import {
import { AlfrescoTranslationLoader } from './src/services/AlfrescoTranslationLoader.service'; AlfrescoSettingsService,
import { AlfrescoTranslationService } from './src/services/AlfrescoTranslationService.service'; AlfrescoTranslationLoader,
import { AlfrescoPipeTranslate } from './src/services/AlfrescoPipeTranslate.service'; AlfrescoTranslationService,
import { AlfrescoAuthenticationService } from './src/services/AlfrescoAuthenticationService.service'; AlfrescoPipeTranslate,
import { AlfrescoContentService } from './src/services/AlfrescoContentService.service'; AlfrescoAuthenticationService,
import { ContextMenuService } from './src/services/context-menu.service'; AlfrescoContentService
import { ContextMenuHolderComponent } from './src/components/context-menu-holder.component'; } from './src/services/index';
import { ContextMenuDirective } from './src/components/context-menu.directive';
export * from './src/services/AlfrescoSettingsService.service'; import { ContextMenuService } from './src/components/context-menu/context-menu.service';
export * from './src/services/AlfrescoTranslationLoader.service';
export * from './src/services/AlfrescoTranslationService.service';
export * from './src/services/AlfrescoPipeTranslate.service';
export * from './src/material/MaterialDesignLiteUpgradeElement';
export * from './src/services/AlfrescoAuthenticationService.service';
export * from './src/services/AlfrescoContentService.service';
export * from './src/services/context-menu.service'; export * from './src/services/index';
export * from './src/components/context-menu-holder.component'; export * from './src/components/index';
export * from './src/components/context-menu.directive'; export * from './src/utils/index';
export * from './src/utils/object-utils';
export const ALFRESCO_CORE_PROVIDERS: [any] = [ export const ALFRESCO_CORE_PROVIDERS: [any] = [
AlfrescoAuthenticationService, AlfrescoAuthenticationService,
@ -49,12 +40,3 @@ export const ALFRESCO_CORE_PROVIDERS: [any] = [
ContextMenuService ContextMenuService
]; ];
export const CONTEXT_MENU_PROVIDERS: [any] = [
ContextMenuService
];
export const CONTEXT_MENU_DIRECTIVES: [any] = [
ContextMenuHolderComponent,
ContextMenuDirective
];

View File

@ -6,13 +6,15 @@
"scripts": { "scripts": {
"clean": "rimraf dist node_modules typings", "clean": "rimraf dist node_modules typings",
"typings": "typings install", "typings": "typings install",
"build": "npm run tslint && typings install && rimraf dist && tsc && license-check", "build": "npm run tslint && typings install && rimraf dist && tsc && npm run copy-static && license-check",
"build:w": "npm run tslint && typings install && rimraf dist && npm run watch-task", "build:w": "npm run tslint && typings install && rimraf dist && tsc && npm run copy-static:w && npm run watch-task",
"watch-task": "concurrently \"npm run tsc:w\" \"license-check\"", "watch-task": "concurrently \"npm run tsc:w\" \"license-check\"",
"tslint": "npm run tslint-src && npm run tslint-root", "tslint": "npm run tslint-src && npm run tslint-root",
"tslint-src": "tslint -c tslint.json src/{,**/}**.ts", "tslint-src": "tslint -c tslint.json src/{,**/}**.ts",
"tslint-root": "tslint -c tslint.json *.ts", "tslint-root": "tslint -c tslint.json *.ts",
"licensecheck": "license-check", "licensecheck": "license-check",
"copy-static": "cpx \"./src/**/*.{html,css}\" ./dist/src",
"copy-static:w": "cpx \"./src/**/*.{html,css}\" ./dist/src -w",
"tsc": "tsc", "tsc": "tsc",
"tsc:w": "tsc -w", "tsc:w": "tsc -w",
"pretest": "npm run build", "pretest": "npm run build",

View File

@ -16,7 +16,7 @@
*/ */
import { describe, it, beforeEach } from '@angular/core/testing'; import { describe, it, beforeEach } from '@angular/core/testing';
import { ContextMenuService } from './../services/context-menu.service'; import { ContextMenuService } from './context-menu.service';
import { ContextMenuHolderComponent } from './context-menu-holder.component'; import { ContextMenuHolderComponent } from './context-menu-holder.component';
describe('ContextMenuHolderComponent', () => { describe('ContextMenuHolderComponent', () => {

View File

@ -16,7 +16,7 @@
*/ */
import { Component, HostListener } from '@angular/core'; import { Component, HostListener } from '@angular/core';
import { ContextMenuService } from './../services/context-menu.service'; import { ContextMenuService } from './context-menu.service';
@Component({ @Component({
selector:'context-menu-holder', selector:'context-menu-holder',

View File

@ -17,7 +17,7 @@
import { describe, it, beforeEach } from '@angular/core/testing'; import { describe, it, beforeEach } from '@angular/core/testing';
import { ContextMenuDirective } from './context-menu.directive'; import { ContextMenuDirective } from './context-menu.directive';
import { ContextMenuService } from './../services/context-menu.service'; import { ContextMenuService } from './context-menu.service';
describe('ContextMenuDirective', () => { describe('ContextMenuDirective', () => {

View File

@ -16,7 +16,7 @@
*/ */
import { Directive, Input, HostListener } from '@angular/core'; import { Directive, Input, HostListener } from '@angular/core';
import { ContextMenuService } from './../services/context-menu.service'; import { ContextMenuService } from './context-menu.service';
@Directive({ @Directive({
selector:'[context-menu]' selector:'[context-menu]'

View File

@ -0,0 +1,33 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ContextMenuService } from './context-menu.service';
import { ContextMenuHolderComponent } from './context-menu-holder.component';
import { ContextMenuDirective } from './context-menu.directive';
export * from './context-menu.service';
export * from './context-menu-holder.component';
export * from './context-menu.directive';
export const CONTEXT_MENU_PROVIDERS: [any] = [
ContextMenuService
];
export const CONTEXT_MENU_DIRECTIVES: [any] = [
ContextMenuHolderComponent,
ContextMenuDirective
];

View File

@ -0,0 +1,20 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './context-menu/index';
export * from './material/index';
export * from './pagination/index';

View File

@ -0,0 +1,30 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { MDL } from './MaterialDesignLiteUpgradeElement';
import { AlfrescoMdlButtonDirective } from './mdl-button.directive';
import { AlfrescoMdlMenuDirective } from './mdl-menu.directive';
export * from './MaterialDesignLiteUpgradeElement';
export * from './mdl-button.directive';
export * from './mdl-menu.directive';
export const MATERIAL_DESIGN_DIRECTIVES: [any] = [
MDL,
AlfrescoMdlButtonDirective,
AlfrescoMdlMenuDirective
];

View File

@ -0,0 +1,38 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Directive, ElementRef, AfterViewInit } from '@angular/core';
declare var componentHandler;
@Directive({
selector: '[alfresco-mdl-button]'
})
export class AlfrescoMdlButtonDirective implements AfterViewInit {
constructor(private element: ElementRef) {}
ngAfterViewInit() {
if (componentHandler) {
let el = this.element.nativeElement;
el.classList.add('mdl-button');
el.classList.add('mdl-js-button');
el.classList.add('mdl-js-ripple-effect');
componentHandler.upgradeElement(el, 'MaterialButton');
}
}
}

View File

@ -0,0 +1,38 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Directive, ElementRef, AfterViewInit } from '@angular/core';
declare var componentHandler;
@Directive({
selector: '[alfresco-mdl-menu]'
})
export class AlfrescoMdlMenuDirective implements AfterViewInit {
constructor(private element: ElementRef) {}
ngAfterViewInit() {
if (componentHandler) {
let el = this.element.nativeElement;
el.classList.add('mdl-menu');
el.classList.add('mdl-js-menu');
el.classList.add('mdl-js-ripple-effect');
componentHandler.upgradeElement(el, 'MaterialMenu');
}
}
}

View File

@ -0,0 +1,19 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './pagination-provider';
export * from './pagination.component';

View File

@ -0,0 +1,47 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export interface PaginationProvider {
/**
* The number of objects in the collection.
*/
count: number;
/**
* A boolean value which is true if there are more entities in the collection beyond those in this response.
* A true value means a request with a larger value for the skipCount or the maxItems parameter will return more entities.
*/
hasMoreItems: boolean;
/**
* An integer describing the total number of entities in the collection.
* The API might not be able to determine this value, in which case this property will not be present.
*/
totalItems?: number;
/**
* An integer describing how many entities exist in the collection before those included in this list.
*/
skipCount: number;
/**
* The value of the maxItems parameter used to generate this list,
* or if there was no maxItems parameter the default value is 100.
*/
maxItems: number;
}

View File

@ -0,0 +1,64 @@
.mdl-paging {
color: rgba(0, 0, 0, 0.54);
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
height: 56px;
-webkit-flex-flow: row wrap;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.mdl-paging > * {
-webkit-flex: none;
-ms-flex: none;
flex: none;
}
.mdl-list + .mdl-paging {
margin: 0;
}
.mdl-paging__per-page {
position: relative;
}
.mdl-paging__per-page-label {
margin-right: 40px;
}
.mdl-paging__per-page-value {
position: absolute;
right: 36px;
top: 6px;
}
.mdl-paging__per-page + .mdl-paging__count {
margin-left: 24px;
}
.mdl-paging .mdl-menu {
min-width: 64px;
}
.mdl-paging__prev:last-child {
margin-right: 44px;
}
.mdl-paging__count + .mdl-paging__prev {
margin-left: 24px;
}
.mdl-paging__prev + .mdl-paging__next {
margin-left: 12px;
}
.mdl-paging__count + .mdl-paging__next {
margin-left: 68px;
}

View File

@ -0,0 +1,27 @@
<div *ngIf="provider" class="mdl-paging">
<span class="mdl-paging__per-page">
<span class="mdl-paging__per-page-label">Rows per page:</span>
<span class="mdl-paging__per-page-value">{{pageSize}}</span>
<button alfresco-mdl-button id="pageSizePicker" class="mdl-button--icon mdl-paging__per-page-dropdown">
<i class="material-icons">arrow_drop_down</i>
</button>
<ul alfresco-mdl-menu for="pageSizePicker" class="mdl-menu--bottom-right">
<li *ngFor="let size of supportedPageSizes"
tabindex="-1" [attr.data-value]="size" class="mdl-menu__item"
(click)="setPageSize(size)">
<span>{{size}}</span>
</li>
</ul>
</span>
<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 (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

@ -0,0 +1,86 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input } from '@angular/core';
import { MATERIAL_DESIGN_DIRECTIVES } from './../material/index';
import { PaginationProvider } from './pagination-provider';
declare let __moduleName: string;
@Component({
moduleId: __moduleName,
selector: 'alfresco-pagination',
templateUrl: './pagination.component.html',
styleUrls: ['./pagination.component.css'],
directives: [MATERIAL_DESIGN_DIRECTIVES]
})
export class PaginationComponent {
DEFAULT_PAGE_SIZE: number = 20;
@Input()
supportedPageSizes: number[] = [5, 10, 20, 50, 100];
@Input()
provider: PaginationProvider;
get pageSize(): number {
if (this.provider) {
return this.provider.maxItems;
}
return this.DEFAULT_PAGE_SIZE;
}
set pageSize(value: number) {
if (this.provider) {
this.provider.maxItems = value;
}
}
setPageSize(value: number) {
this.pageSize = value;
}
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

@ -0,0 +1,23 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './AlfrescoSettingsService.service';
export * from './AlfrescoTranslationLoader.service';
export * from './AlfrescoTranslationService.service';
export * from './AlfrescoPipeTranslate.service';
export * from './AlfrescoAuthenticationService.service';
export * from './AlfrescoContentService.service';

View File

@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './object-utils';

View File

@ -1,13 +1,13 @@
:host .full-width { width: 100%; } :host .full-width { width: 100%; }
:host .icon-cell { :host .icon-cell {
font-size: 48px; font-size: 24px;
cursor: default; cursor: default;
} }
:host .image-cell { :host .image-cell {
width: 48px; width: 24px;
height: 48px; height: 24px;
cursor: default; cursor: default;
} }

View File

@ -21,7 +21,7 @@ import { ContentColumnList } from './src/components/content-column-list';
import { ContentAction } from './src/components/content-action'; import { ContentAction } from './src/components/content-action';
import { ContentActionList } from './src/components/content-action-list'; import { ContentActionList } from './src/components/content-action-list';
import { EmptyFolderContent } from './src/components/empty-folder-content'; import { EmptyFolderContent } from './src/components/empty-folder-content';
import { DocumentListBreadcrumb } from './src/components/document-list-breadcrumb.component'; import { DocumentListBreadcrumb } from './src/components/breadcrumb/breadcrumb.component';
import { FolderActionsService } from './src/services/folder-actions.service'; import { FolderActionsService } from './src/services/folder-actions.service';
import { DocumentActionsService } from './src/services/document-actions.service'; import { DocumentActionsService } from './src/services/document-actions.service';
@ -34,7 +34,7 @@ export * from './src/components/content-column-list';
export * from './src/components/content-action'; export * from './src/components/content-action';
export * from './src/components/content-action-list'; export * from './src/components/content-action-list';
export * from './src/components/empty-folder-content'; export * from './src/components/empty-folder-content';
export * from './src/components/document-list-breadcrumb.component'; export * from './src/components/breadcrumb/breadcrumb.component';
// services // services
export * from './src/services/folder-actions.service'; export * from './src/services/folder-actions.service';

View File

@ -25,8 +25,8 @@ import {
import { import {
DocumentListBreadcrumb, DocumentListBreadcrumb,
PathNode PathNode
} from './document-list-breadcrumb.component'; } from './breadcrumb.component';
import { DocumentList } from './document-list'; import { DocumentList } from '../document-list';
describe('DocumentListBreadcrumb', () => { describe('DocumentListBreadcrumb', () => {

View File

@ -21,15 +21,15 @@ import {
Output, Output,
EventEmitter EventEmitter
} from '@angular/core'; } from '@angular/core';
import { DocumentList } from './document-list'; import { DocumentList } from '../document-list';
declare let __moduleName: string; declare let __moduleName: string;
@Component({ @Component({
moduleId: __moduleName, moduleId: __moduleName,
selector: 'alfresco-document-list-breadcrumb', selector: 'alfresco-document-list-breadcrumb',
templateUrl: './document-list-breadcrumb.component.html', templateUrl: './breadcrumb.component.html',
styleUrls: ['./document-list-breadcrumb.component.css'] styleUrls: ['./breadcrumb.component.css']
}) })
export class DocumentListBreadcrumb { export class DocumentListBreadcrumb {

View File

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

View File

@ -94,13 +94,13 @@ describe('ShareDataTableAdapter', () => {
it('should fail when getting value for missing row', () => { it('should fail when getting value for missing row', () => {
let adapter = new ShareDataTableAdapter(null, null, null); let adapter = new ShareDataTableAdapter(null, null, null);
let check = () => { return adapter.getValue(null, <DataColumn>{}); }; 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', () => { it('should fail when getting value for missing column', () => {
let adapter = new ShareDataTableAdapter(null, null, null); let adapter = new ShareDataTableAdapter(null, null, null);
let check = () => { return adapter.getValue(<DataRow>{}, 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', () => { it('should require path to load data', () => {
@ -123,7 +123,7 @@ describe('ShareDataTableAdapter', () => {
let adapter = new ShareDataTableAdapter(documentListService, null, null); let adapter = new ShareDataTableAdapter(documentListService, null, null);
adapter.loadPath(path); adapter.loadPath(path);
expect(documentListService.getFolder).toHaveBeenCalledWith(path); expect(documentListService.getFolder).toHaveBeenCalledWith(path, jasmine.anything());
let rows = adapter.getRows(); let rows = adapter.getRows();
expect(rows.length).toBe(1); expect(rows.length).toBe(1);
@ -283,7 +283,7 @@ describe('ShareDataTableAdapter', () => {
}); });
it('should resolve file thumbnail', () => { it('should resolve file thumbnail', () => {
let imageUrl: 'http://<addresss>'; let imageUrl: string = 'http://<addresss>';
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl); spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
let adapter = new ShareDataTableAdapter(documentListService, basePath, null); let adapter = new ShareDataTableAdapter(documentListService, basePath, null);

View File

@ -16,7 +16,7 @@
*/ */
import { DatePipe } from '@angular/common'; import { DatePipe } from '@angular/common';
import { ObjectUtils } from 'ng2-alfresco-core'; import { PaginationProvider, ObjectUtils } from 'ng2-alfresco-core';
import { import {
DataTableAdapter, DataTableAdapter,
DataRow, DataColumn, DataSorting DataRow, DataColumn, DataSorting
@ -25,16 +25,26 @@ import {
import { NodePaging, MinimalNodeEntity } from './../models/document-library.model'; import { NodePaging, MinimalNodeEntity } from './../models/document-library.model';
import { DocumentListService } from './../services/document-list.service'; import { DocumentListService } from './../services/document-list.service';
export class ShareDataTableAdapter implements DataTableAdapter { export class ShareDataTableAdapter implements DataTableAdapter, PaginationProvider {
static ERR_ROW_NOT_FOUND: string = 'Row not found'; ERR_ROW_NOT_FOUND: string = 'Row not found';
static ERR_COL_NOT_FOUND: string = 'Column not found'; ERR_COL_NOT_FOUND: string = 'Column not found';
static DEFAULT_DATE_FORMAT: string = 'medium'; DEFAULT_DATE_FORMAT: string = 'medium';
DEFAULT_PAGE_SIZE: number = 20;
MIN_PAGE_SIZE: number = 5;
private sorting: DataSorting; private sorting: DataSorting;
private rows: DataRow[]; private rows: DataRow[];
private columns: DataColumn[]; 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 = this.DEFAULT_PAGE_SIZE;
thumbnails: boolean = false; thumbnails: boolean = false;
@ -43,12 +53,48 @@ export class ShareDataTableAdapter implements DataTableAdapter {
schema: DataColumn[]) { schema: DataColumn[]) {
this.rows = []; this.rows = [];
this.columns = schema || []; this.columns = schema || [];
this.resetPagination();
}
get count(): number {
return this._count;
}
get hasMoreItems(): boolean {
return this._hasMoreItems;
}
get totalItems(): number {
return this._totalItems;
}
get skipCount(): number {
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> { getRows(): Array<DataRow> {
return this.rows; return this.rows;
} }
// TODO: disable this api
setRows(rows: Array<DataRow>) { setRows(rows: Array<DataRow>) {
this.rows = rows || []; this.rows = rows || [];
this.sort(); this.sort();
@ -64,16 +110,16 @@ export class ShareDataTableAdapter implements DataTableAdapter {
getValue(row: DataRow, col: DataColumn): any { getValue(row: DataRow, col: DataColumn): any {
if (!row) { if (!row) {
throw new Error(ShareDataTableAdapter.ERR_ROW_NOT_FOUND); throw new Error(this.ERR_ROW_NOT_FOUND);
} }
if (!col) { if (!col) {
throw new Error(ShareDataTableAdapter.ERR_COL_NOT_FOUND); throw new Error(this.ERR_COL_NOT_FOUND);
} }
let value = row.getValue(col.key); let value = row.getValue(col.key);
if (col.type === 'date') { if (col.type === 'date') {
let datePipe = new DatePipe(); let datePipe = new DatePipe();
let format = col.format || ShareDataTableAdapter.DEFAULT_DATE_FORMAT; let format = col.format || this.DEFAULT_DATE_FORMAT;
try { try {
return datePipe.transform(value, format); return datePipe.transform(value, format);
} catch (err) { } catch (err) {
@ -163,10 +209,21 @@ export class ShareDataTableAdapter implements DataTableAdapter {
loadPath(path: string) { loadPath(path: string) {
if (path && this.documentListService) { if (path && this.documentListService) {
this.currentPath = path;
this.documentListService this.documentListService
.getFolder(path) .getFolder(path, {
.subscribe(val => { maxItems: this._maxItems,
let page = <NodePaging>val; skipCount: this._skipCount
})
.subscribe(val => this.loadPage(<NodePaging>val),
error => console.error(error));
}
}
private loadPage(page: NodePaging) {
this.page = page;
this.resetPagination();
let rows = []; let rows = [];
if (page && page.list) { if (page && page.list) {
@ -184,14 +241,27 @@ export class ShareDataTableAdapter implements DataTableAdapter {
} }
} }
} }
let pagination = page.list.pagination;
if (pagination) {
this._count = pagination.count;
this._hasMoreItems = pagination.hasMoreItems;
this._maxItems = pagination.maxItems;
this._skipCount = pagination.skipCount;
this._totalItems = pagination.totalItems;
}
} }
this.rows = rows; this.rows = rows;
},
error => console.error(error));
}
} }
private resetPagination() {
this._count = 0;
this._hasMoreItems = false;
this._totalItems = 0;
this._skipCount = 0;
this._maxItems = this.DEFAULT_PAGE_SIZE;
}
} }
export class ShareDataRow implements DataRow { export class ShareDataRow implements DataRow {

View File

@ -22,13 +22,24 @@ export class NodePaging {
} }
export class NodePagingList { export class NodePagingList {
pagination: Pagination;
entries: MinimalNodeEntity[]; entries: MinimalNodeEntity[];
} }
// TODO: rename to NodeMinimalEntry
export class MinimalNodeEntity { export class MinimalNodeEntity {
entry: MinimalNodeEntryEntity; entry: MinimalNodeEntryEntity;
} }
export class Pagination {
count: number;
hasMoreItems: boolean;
totalItems: number;
skipCount: number;
maxItems: number;
}
// TODO: rename to NodeMinimal
export class MinimalNodeEntryEntity { export class MinimalNodeEntryEntity {
id: string; id: string;
parentId: string; parentId: string;

View File

@ -70,13 +70,23 @@ export class DocumentListService {
return this.authService.getAlfrescoApi(); return this.authService.getAlfrescoApi();
} }
private getNodesPromise(folder: string) { private getNodesPromise(folder: string, opts?: any) {
let nodeId = '-root-'; let nodeId = '-root-';
let opts = { let params: any = {
relativePath: folder, relativePath: folder,
include: ['path'] include: ['path']
}; };
return this.getAlfrescoApi().node.getNodeChildren(nodeId, opts);
if (opts) {
if (opts.maxItems) {
params.maxItems = opts.maxItems;
}
if (opts.skipCount) {
params.skipCount = opts.skipCount;
}
}
return this.getAlfrescoApi().node.getNodeChildren(nodeId, params);
} }
deleteNode(nodeId: string) { deleteNode(nodeId: string) {
@ -86,10 +96,11 @@ export class DocumentListService {
/** /**
* Gets the folder node with the content. * Gets the folder node with the content.
* @param folder Path to folder. * @param folder Path to folder.
* @param opts Options.
* @returns {Observable<NodePaging>} Folder entity. * @returns {Observable<NodePaging>} Folder entity.
*/ */
getFolder(folder: string) { getFolder(folder: string, opts?: any) {
return Observable.fromPromise(this.getNodesPromise(folder)) return Observable.fromPromise(this.getNodesPromise(folder, opts))
.map(res => <NodePaging> res) .map(res => <NodePaging> res)
// .do(data => console.log('Node data', data)) // eyeball results in the console // .do(data => console.log('Node data', data)) // eyeball results in the console
.catch(this.handleError); .catch(this.handleError);