#244 breadcrumb as a separate component (doclist only)

This commit is contained in:
Denys Vuika 2016-06-21 15:51:51 +01:00
parent bf7414fc85
commit e101f22e28
10 changed files with 175 additions and 138 deletions

View File

@ -3,6 +3,10 @@
[currentFolderPath]="currentPath" [currentFolderPath]="currentPath"
[uploaddirectory]="currentPath" [uploaddirectory]="currentPath"
(onSuccess)="documentList.reload()"> (onSuccess)="documentList.reload()">
<alfresco-document-list-breadcrumb
[currentFolderPath]="currentPath"
[target]="documentList">
</alfresco-document-list-breadcrumb>
<alfresco-document-list <alfresco-document-list
#documentList #documentList
[currentFolderPath]="currentPath" [currentFolderPath]="currentPath"

View File

@ -48,7 +48,14 @@ import {
<hr> <hr>
<div class="container"> <div class="container">
<alfresco-document-list #doclist> <alfresco-document-list-breadcrumb
[currentFolderPath]="currentPath"
[target]="documentList">
</alfresco-document-list-breadcrumb>
<alfresco-document-list
#documentList
[currentFolderPath]="currentPath"
(folderChange)="onFolderChanged($event)">
<content-columns> <content-columns>
<content-column source="$thumbnail" type="image"></content-column> <content-column source="$thumbnail" type="image"></content-column>
@ -144,6 +151,7 @@ import {
}) })
class DocumentListDemo implements OnInit { class DocumentListDemo implements OnInit {
currentPath: string = '/';
authenticated: boolean; authenticated: boolean;
public host: string = 'http://devproducts-platform.alfresco.me'; public host: string = 'http://devproducts-platform.alfresco.me';
@ -202,6 +210,12 @@ class DocumentListDemo implements OnInit {
this.authenticated = false; this.authenticated = false;
}); });
} }
onFolderChanged(event?: any) {
if (event) {
this.currentPath = event.path;
}
}
} }
bootstrap(DocumentListDemo, [ bootstrap(DocumentListDemo, [

View File

@ -21,6 +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 { 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';
@ -33,6 +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';
// models // models
export * from './src/models/column-sorting.model'; export * from './src/models/column-sorting.model';
@ -42,28 +44,14 @@ export * from './src/services/folder-actions.service';
export * from './src/services/document-actions.service'; export * from './src/services/document-actions.service';
export * from './src/services/alfresco.service'; export * from './src/services/alfresco.service';
export default {
directives: [
DocumentList,
ContentColumn,
ContentColumnList,
ContentAction,
ContentActionList
],
providers: [
AlfrescoService,
FolderActionsService,
DocumentActionsService
]
};
export const DOCUMENT_LIST_DIRECTIVES: [any] = [ export const DOCUMENT_LIST_DIRECTIVES: [any] = [
DocumentList, DocumentList,
ContentColumn, ContentColumn,
ContentColumnList, ContentColumnList,
ContentAction, ContentAction,
ContentActionList, ContentActionList,
EmptyFolderContent EmptyFolderContent,
DocumentListBreadcrumb
]; ];
export const DOCUMENT_LIST_PROVIDERS: [any] = [ export const DOCUMENT_LIST_PROVIDERS: [any] = [

View File

@ -0,0 +1,25 @@
/* breadcrumb */
:host .breadcrumb {
text-align: left;
padding: 8px 15px;
list-style: none;
background-color: #f5f5f5;
border-radius: 4px;
margin: 0 0 4px;
}
:host .breadcrumb > li {
display: inline-block;
box-sizing: border-box;
}
:host .breadcrumb > li+li:before {
content: "/\00a0";
padding: 0 0 0 5px;
color: #ccc;
}
:host .breadcrumb > .active {
color: #777;
}

View File

@ -0,0 +1,11 @@
<ol data-automation-id="breadcrumb" class="breadcrumb">
<li *ngFor="let r of route; let last = last" [class.active]="last" [ngSwitch]="last">
<span *ngSwitchCase="true">{{r.name}}</span>
<a *ngSwitchDefault
href="#"
[attr.data-automation-id]="'breadcrumb_' + r.name"
(click)="onRoutePathClick(r, $event)">
{{r.name}}
</a>
</li>
</ol>

View File

@ -0,0 +1,115 @@
/*!
* @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,
Output,
EventEmitter
} from '@angular/core';
import { DocumentList } from './document-list';
declare let __moduleName: string;
@Component({
moduleId: __moduleName,
selector: 'alfresco-document-list-breadcrumb',
templateUrl: './document-list-breadcrumb.component.html',
styleUrls: ['./document-list-breadcrumb.component.css']
})
export class DocumentListBreadcrumb {
private _currentFolderPath: string = '/';
get currentFolderPath(): string {
return this._currentFolderPath;
}
@Input()
set currentFolderPath(val: string) {
if (this._currentFolderPath !== val) {
this._currentFolderPath = val;
if (val) {
this.route = this.parsePath(val);
} else {
this.route = [ this.rootFolder ];
}
}
}
@Input()
target: DocumentList;
private rootFolder: PathNode = {
name: 'Root',
path: '/'
};
route: PathNode[] = [ this.rootFolder ];
@Output()
navigate: EventEmitter<any> = new EventEmitter();
onRoutePathClick(route: PathNode, e?: Event) {
if (e) {
e.preventDefault();
}
if (route) {
this.navigate.emit({
value: {
name: route.name,
path: route.path
}
});
if (this.target) {
this.target.changePath(route.path);
}
}
}
private parsePath(path: string): PathNode[] {
let parts = path.split('/').filter(val => val ? true : false);
let result = [
this.rootFolder
];
let parentPath: string = this.rootFolder.path;
for (let i = 0; i < parts.length; i++) {
if (!parentPath.endsWith('/')) {
parentPath += '/';
}
parentPath += parts[i];
result.push({
name: parts[i],
path: parentPath
});
}
return result;
};
}
export interface PathNode {
name: string;
path: string;
}

View File

@ -28,31 +28,7 @@
cursor: default; cursor: default;
} }
/* breadcrumb */ /* Empty folder */
:host .breadcrumb {
text-align: left;
padding: 8px 15px;
list-style: none;
background-color: #f5f5f5;
border-radius: 4px;
margin: 0 0 4px;
}
:host .breadcrumb > li {
display: inline-block;
box-sizing: border-box;
}
:host .breadcrumb > li+li:before {
content: "/\00a0";
padding: 0 0 0 5px;
color: #ccc;
}
:host .breadcrumb > .active {
color: #777;
}
:host .empty-folder-content { :host .empty-folder-content {
padding: 0 !important; padding: 0 !important;

View File

@ -1,9 +1,3 @@
<ol *ngIf="breadcrumb" data-automation-id="breadcrumb" class="breadcrumb">
<li *ngFor="let r of route; let last = last" [class.active]="last" [ngSwitch]="last">
<span *ngSwitchCase="true">{{r.name}}</span>
<a *ngSwitchDefault href="#" [attr.data-automation-id]="'breadcrumb_' + r.name" (click)="goToRoute(r, $event)">{{r.name}}</a>
</li>
</ol>
<table *ngIf="folder" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp full-width"> <table *ngIf="folder" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp full-width">
<thead> <thead>
<tr> <tr>

View File

@ -70,26 +70,6 @@ describe('DocumentList', () => {
expect(documentList.columns[0]).toBe(column); expect(documentList.columns[0]).toBe(column);
}); });
it('should setup default root for breadcrumb', () => {
documentList.ngOnInit();
expect(documentList.route.length).toBe(1);
expect(documentList.route[0]).toBe(documentList.rootFolder);
});
it('should display custom root path', () => {
spyOn(documentList, 'displayFolderContent').and.stub();
let root = {
name: '<root>',
path: '<path>'
};
documentList.currentFolderPath = root.path;
documentList.rootFolder = root;
documentList.ngOnInit();
expect(documentList.displayFolderContent).toHaveBeenCalledWith(root.path);
});
it('should fetch folder', () => { it('should fetch folder', () => {
let folder = { let folder = {
'nodeRef': 'workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28' 'nodeRef': 'workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28'
@ -156,15 +136,6 @@ describe('DocumentList', () => {
expect(action.handler).not.toHaveBeenCalled(); expect(action.handler).not.toHaveBeenCalled();
}); });
it('should update current folder path', () => {
expect(documentList.currentFolderPath).toBe(documentList.rootFolder.path);
let path = '<path>';
documentList.displayFolderContent(path);
expect(documentList.currentFolderPath).toBe(path);
});
it('should give no content actions for empty target', () => { it('should give no content actions for empty target', () => {
let actions = documentList.getContentActions(null, 'button'); let actions = documentList.getContentActions(null, 'button');
expect(actions.length).toBe(0); expect(actions.length).toBe(0);
@ -270,10 +241,6 @@ describe('DocumentList', () => {
documentList.onItemClick(node); documentList.onItemClick(node);
expect(documentList.displayFolderContent).toHaveBeenCalledWith(path); expect(documentList.displayFolderContent).toHaveBeenCalledWith(path);
let routeEntry = documentList.route.pop();
expect(routeEntry.name).toBe(node.entry.name);
expect(routeEntry.path).toBe(path);
}); });
it('should not display folder content when no target node provided', () => { it('should not display folder content when no target node provided', () => {

View File

@ -61,9 +61,6 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
@Input('navigation-mode') @Input('navigation-mode')
navigationMode: string = 'dblclick'; // click|dblclick navigationMode: string = 'dblclick'; // click|dblclick
@Input()
breadcrumb: boolean = true;
@Input() @Input()
thumbnails: boolean = false; thumbnails: boolean = false;
@ -79,16 +76,10 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
@Output() @Output()
preview: EventEmitter<any> = new EventEmitter(); preview: EventEmitter<any> = new EventEmitter();
rootFolder = {
name: 'Root',
path: '/'
};
@Input() @Input()
currentFolderPath: string = this.DEFAULT_ROOT_FOLDER; currentFolderPath: string = this.DEFAULT_ROOT_FOLDER;
errorMessage; errorMessage;
route: { name: string, path: string }[] = [];
actions: ContentActionModel[] = []; actions: ContentActionModel[] = [];
columns: ContentColumnModel[] = []; columns: ContentColumnModel[] = [];
@ -180,7 +171,6 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
changePath(path: string) { changePath(path: string) {
this.currentFolderPath = path || this.DEFAULT_ROOT_FOLDER; this.currentFolderPath = path || this.DEFAULT_ROOT_FOLDER;
this.route = this.parsePath(this.currentFolderPath);
this.displayFolderContent(this.currentFolderPath); this.displayFolderContent(this.currentFolderPath);
} }
@ -266,33 +256,10 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
private performNavigation(node: MinimalNodeEntity) { private performNavigation(node: MinimalNodeEntity) {
if (node && node.entry && node.entry.isFolder) { if (node && node.entry && node.entry.isFolder) {
let path = this.getNodePath(node); let path = this.getNodePath(node);
this.route.push({
name: node.entry.name,
path: path
});
this.displayFolderContent(path); this.displayFolderContent(path);
} }
} }
/**
* Invoked when a breadcrumb route is clicked.
* @param r Route to navigate to
* @param e DOM event
*/
goToRoute(r, e) {
if (e) {
e.preventDefault();
}
if (this.navigate) {
let idx = this.route.indexOf(r);
if (idx > -1) {
this.route.splice(idx + 1);
this.displayFolderContent(r.path);
}
}
}
/** /**
* Gets thumbnail URL for the given node. * Gets thumbnail URL for the given node.
* @param node Node to get URL for. * @param node Node to get URL for.
@ -483,30 +450,6 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
return val; return val;
} }
private parsePath(path: string): { name: string, path: string }[] {
let parts = path.split('/').filter(val => val ? true : false);
let result = [
this.rootFolder
];
let parentPath: string = this.rootFolder.path;
for (let i = 0; i < parts.length; i++) {
if (!parentPath.endsWith('/')) {
parentPath += '/';
}
parentPath += parts[i];
result.push({
name: parts[i],
path: parentPath
});
}
return result;
};
private _hasEntries(node: NodePaging): boolean { private _hasEntries(node: NodePaging): boolean {
return (node && node.list && node.list.entries && node.list.entries.length > 0); return (node && node.list && node.list.entries && node.list.entries.length > 0);
} }