mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
#82 datatable project cleanup
basic implementation of main features: - custom data sources - column types - sorting by columns - click events
This commit is contained in:
@@ -21,15 +21,16 @@ import {
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
AfterContentInit,
|
||||
AfterViewChecked
|
||||
} from 'angular2/core';
|
||||
|
||||
import { AlfrescoService } from './../services/alfresco.service';
|
||||
import { MinimalNodeEntity, NodePaging } from './../models/document-library.model';
|
||||
import { DataActionModel } from './../models/data-action.model';
|
||||
import { DataColumnModel } from './../models/data-column.model';
|
||||
import { ColumnSortingModel } from './../models/column-sorting.model';
|
||||
import {
|
||||
DataTableAdapter,
|
||||
DataRow,
|
||||
DataColumn,
|
||||
DataSorting
|
||||
} from './../data/datatable-adapter';
|
||||
import { ObjectDataTableAdapter } from '../data/object-datatable-adapter';
|
||||
|
||||
declare var componentHandler;
|
||||
declare let __moduleName: string;
|
||||
@@ -38,85 +39,21 @@ declare let __moduleName: string;
|
||||
moduleId: __moduleName,
|
||||
selector: 'alfresco-datatable',
|
||||
styleUrls: ['./datatable.component.css'],
|
||||
templateUrl: './datatable.component.html',
|
||||
providers: [AlfrescoService]
|
||||
templateUrl: './datatable.component.html'
|
||||
})
|
||||
export class DataTableComponent implements OnInit, AfterViewChecked, AfterContentInit {
|
||||
|
||||
DEFAULT_ROOT_FOLDER: string = '/Sites/swsdp/documentLibrary';
|
||||
export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
@Input()
|
||||
navigate: boolean = true;
|
||||
|
||||
@Input()
|
||||
breadcrumb: boolean = false;
|
||||
|
||||
@Input('folder-icon')
|
||||
folderIcon: string;
|
||||
data: DataTableAdapter;
|
||||
|
||||
@Output()
|
||||
itemClick: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
folderClick: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
rootFolder = {
|
||||
name: '',
|
||||
path: ''
|
||||
};
|
||||
|
||||
@Input()
|
||||
currentFolderPath: string = '';
|
||||
|
||||
folder: NodePaging;
|
||||
errorMessage;
|
||||
|
||||
route: any[] = [];
|
||||
|
||||
actions: DataActionModel[] = [];
|
||||
columns: DataColumnModel[] = [];
|
||||
|
||||
sorting: ColumnSortingModel = {
|
||||
key: 'name',
|
||||
direction: 'asc'
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether navigation to parent folder is available.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
canNavigateParent(): boolean {
|
||||
return this.navigate && !this.breadcrumb &&
|
||||
this.currentFolderPath !== this.rootFolder.path;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private _alfrescoService: AlfrescoService) {
|
||||
}
|
||||
|
||||
_createRootFolder(): any {
|
||||
let folderArray = this.currentFolderPath.split('/');
|
||||
let nameFolder = folderArray[folderArray.length - 1];
|
||||
return {
|
||||
name: nameFolder,
|
||||
path: this.currentFolderPath
|
||||
};
|
||||
}
|
||||
onRowClick: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
ngOnInit() {
|
||||
this.currentFolderPath = this.currentFolderPath || this.DEFAULT_ROOT_FOLDER;
|
||||
this.rootFolder = this._createRootFolder();
|
||||
this.route.push(this.rootFolder);
|
||||
this.displayFolderContent(this.rootFolder.path);
|
||||
}
|
||||
|
||||
ngOnChanges(change) {
|
||||
this.reload();
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
if (!this.columns || this.columns.length === 0) {
|
||||
this.setupDefaultColumns();
|
||||
if (this.data) {
|
||||
console.log(this.data);
|
||||
} else {
|
||||
this.data = new ObjectDataTableAdapter([], []);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,251 +64,34 @@ export class DataTableComponent implements OnInit, AfterViewChecked, AfterConten
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of content actions based on target and type.
|
||||
* @param target Target to filter actions by.
|
||||
* @param type Type to filter actions by.
|
||||
* @returns {ContentActionModel[]} List of actions filtered by target and type.
|
||||
*/
|
||||
getContentActions(target: string, type: string): DataActionModel[] {
|
||||
if (target && type) {
|
||||
|
||||
let ltarget = target.toLowerCase();
|
||||
let ltype = type.toLowerCase();
|
||||
|
||||
return this.actions.filter(entry => {
|
||||
return entry.target.toLowerCase() === ltarget &&
|
||||
entry.type.toLowerCase() === ltype;
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when 'parent folder' element is clicked.
|
||||
* @param e DOM event
|
||||
*/
|
||||
onNavigateParentClick(e) {
|
||||
onRowClicked(row: DataRow, e?) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (this.navigate) {
|
||||
this.route.pop();
|
||||
let parent = this.route.length > 0 ? this.route[this.route.length - 1] : this.rootFolder;
|
||||
if (parent) {
|
||||
this.folderClick.emit({
|
||||
value: parent.path
|
||||
});
|
||||
this.displayFolderContent(parent.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when list row is clicked.
|
||||
* @param item Underlying node item
|
||||
* @param e DOM event (optional)
|
||||
*/
|
||||
onItemClick(item: MinimalNodeEntity, e = null) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.itemClick.emit({
|
||||
value: item
|
||||
this.onRowClick.emit({
|
||||
value: row
|
||||
});
|
||||
}
|
||||
|
||||
if (this.navigate && item && item.entry) {
|
||||
if (item.entry.isFolder) {
|
||||
let path = this.getNodePath(item);
|
||||
|
||||
this.folderClick.emit({
|
||||
value: path
|
||||
});
|
||||
|
||||
this.route.push({
|
||||
name: item.entry.name,
|
||||
path: path
|
||||
});
|
||||
this.displayFolderContent(path);
|
||||
}
|
||||
onColumnHeaderClick(column: DataColumn) {
|
||||
if (column && column.sortable) {
|
||||
let current = this.data.getSorting();
|
||||
let newDirection = current.direction === 'asc' ? 'desc' : 'asc';
|
||||
this.data.setSorting(new DataSorting(column.key, newDirection));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
isIconValue(row: DataRow, col: DataColumn) {
|
||||
return row.getValue(col.key).startsWith('material-icons://');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets content URL for the given node.
|
||||
* @param node Node to get URL for.
|
||||
* @returns {string} URL address.
|
||||
*/
|
||||
getContentUrl(node: MinimalNodeEntity): string {
|
||||
if (this._alfrescoService) {
|
||||
return this._alfrescoService.getContentUrl(node);
|
||||
}
|
||||
return null;
|
||||
asIconValue(row: DataRow, col: DataColumn) {
|
||||
return row.getValue(col.key).replace('material-icons://', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets thumbnail URL for the given document node.
|
||||
* @param node Node to get URL for.
|
||||
* @returns {string} URL address.
|
||||
*/
|
||||
getDocumentThumbnailUrl(node: MinimalNodeEntity): string {
|
||||
if (this._alfrescoService) {
|
||||
return this._alfrescoService.getDocumentThumbnailUrl(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when executing content action for a document or folder.
|
||||
* @param node Node to be the context of the execution.
|
||||
* @param action Action to be executed against the context.
|
||||
*/
|
||||
executeContentAction(node: MinimalNodeEntity, action: DataActionModel) {
|
||||
if (action) {
|
||||
action.handler(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and displays folder content
|
||||
* @param path Node path
|
||||
*/
|
||||
displayFolderContent(path) {
|
||||
if (path !== null) {
|
||||
this.currentFolderPath = path;
|
||||
this._alfrescoService
|
||||
.getFolder(path)
|
||||
.subscribe(
|
||||
folder => this.folder = this.sort(folder, this.sorting),
|
||||
error => this.errorMessage = <any>error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
reload() {
|
||||
if (this.currentFolderPath) {
|
||||
this.displayFolderContent(this.currentFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a path for a given node.
|
||||
* @param node
|
||||
* @returns {string}
|
||||
*/
|
||||
getNodePath(node: MinimalNodeEntity): string {
|
||||
if (node) {
|
||||
let pathWithCompanyHome = node.entry.path.name;
|
||||
return pathWithCompanyHome.replace('/Company Home', '') + '/' + node.entry.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value from an object by composed key
|
||||
* documentList.getObjectValue({ item: { nodeType: 'cm:folder' }}, 'item.nodeType') ==> 'cm:folder'
|
||||
* @param target
|
||||
* @param key
|
||||
* @returns {string}
|
||||
*/
|
||||
getObjectValue(target: any, key: string): any {
|
||||
let keys = key.split('.');
|
||||
key = '';
|
||||
|
||||
do {
|
||||
key += keys.shift();
|
||||
let value = target[key];
|
||||
if (value !== undefined && (typeof value === 'object' || !keys.length)) {
|
||||
target = value;
|
||||
key = '';
|
||||
} else if (!keys.length) {
|
||||
target = undefined;
|
||||
} else {
|
||||
key += '.';
|
||||
}
|
||||
} while (keys.length);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of predefined columns.
|
||||
*/
|
||||
setupDefaultColumns(): void {
|
||||
let thumbnailCol = new DataColumnModel();
|
||||
thumbnailCol.source = '$thumbnail';
|
||||
|
||||
let nameCol = new DataColumnModel();
|
||||
nameCol.title = 'Name';
|
||||
nameCol.source = 'name';
|
||||
nameCol.cssClass = 'full-width name-column';
|
||||
|
||||
this.columns = [
|
||||
thumbnailCol,
|
||||
nameCol
|
||||
];
|
||||
}
|
||||
|
||||
onColumnHeaderClick(column: DataColumnModel) {
|
||||
if (column && this._isSortableColumn(column)) {
|
||||
if (this.sorting.key === column.source) {
|
||||
this.sorting.direction = this.sorting.direction === 'asc' ? 'desc' : 'asc';
|
||||
} else {
|
||||
this.sorting = <ColumnSortingModel> {
|
||||
key: column.source,
|
||||
direction: 'asc'
|
||||
};
|
||||
}
|
||||
this.sort(this.folder, this.sorting);
|
||||
}
|
||||
}
|
||||
|
||||
sort(node: NodePaging, options: ColumnSortingModel) {
|
||||
if (this._hasEntries(node)) {
|
||||
node.list.entries.sort((a: MinimalNodeEntity, b: MinimalNodeEntity) => {
|
||||
if (a.entry.isFolder !== b.entry.isFolder) {
|
||||
return options.direction === 'asc'
|
||||
? (a.entry.isFolder ? -1 : 1)
|
||||
: (a.entry.isFolder ? 1 : -1);
|
||||
}
|
||||
|
||||
let left = this.getObjectValue(a.entry, options.key).toString();
|
||||
let right = this.getObjectValue(b.entry, options.key).toString();
|
||||
|
||||
return options.direction === 'asc'
|
||||
? left.localeCompare(right)
|
||||
: right.localeCompare(left);
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private _hasEntries(node: NodePaging): boolean {
|
||||
return (node && node.list && node.list.entries && node.list.entries.length > 0);
|
||||
}
|
||||
|
||||
private _isSortableColumn(column: DataColumnModel) {
|
||||
return column && column.source && !column.source.startsWith('$');
|
||||
isColumnSorted(col: DataColumn, direction: string) {
|
||||
let sorting = this.data.getSorting();
|
||||
return sorting.key === col.key && sorting.direction === direction;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user