mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
Merge pull request #372 from Alfresco/dev-denys-340
Integrate datatable in the documentlist #340
This commit is contained in:
commit
3881faec42
@ -17,7 +17,8 @@ before_install:
|
||||
- export CHROME_BIN=/usr/bin/google-chrome
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- (cd ng2-components/ng2-alfresco-core; npm version patch; sed -i "s/0\\.0\\.0-PLACEHOLDER/^0.1.0/g" package.json; npm install; npm link)
|
||||
- (cd ng2-components/ng2-alfresco-core; npm install; npm link)
|
||||
- (cd ng2-components/ng2-alfresco-datatable; npm install; npm link)
|
||||
|
||||
env:
|
||||
matrix:
|
||||
@ -30,7 +31,7 @@ env:
|
||||
- MODULE=ng2-alfresco-viewer
|
||||
|
||||
before_script:
|
||||
- cd ng2-components/$MODULE; npm version patch; sed -i "s/0\\.0\\.0-PLACEHOLDER/^0.1.0/g" package.json; npm install; npm link ng2-alfresco-core; npm run travis
|
||||
- cd ng2-components/$MODULE; npm install; npm link ng2-alfresco-core; npm run travis
|
||||
- ls -ltrh ./node_modules/
|
||||
script: npm run test
|
||||
# Send coverage data to Coveralls
|
||||
|
6
demo-shell-ng2/.gitignore
vendored
6
demo-shell-ng2/.gitignore
vendored
@ -4,4 +4,8 @@ bower_components/
|
||||
app/**/*.js
|
||||
app/**/*.js.map
|
||||
.idea
|
||||
dist/
|
||||
dist/
|
||||
|
||||
# docker files
|
||||
docker-compose.yml
|
||||
Dockerfile
|
||||
|
@ -10,6 +10,8 @@
|
||||
<alfresco-document-list
|
||||
#documentList
|
||||
[currentFolderPath]="currentPath"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="true"
|
||||
(preview)="showFile($event)"
|
||||
(folderChange)="onFolderChanged($event)">
|
||||
<!--
|
||||
@ -20,10 +22,11 @@
|
||||
</empty-folder-content>
|
||||
-->
|
||||
<content-columns>
|
||||
<content-column source="$thumbnail" type="image"></content-column>
|
||||
<content-column key="$thumbnail" type="image"></content-column>
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.DISPLAY_NAME' | translate}}"
|
||||
source="name"
|
||||
key="name"
|
||||
sortable="true"
|
||||
class="full-width ellipsis-cell">
|
||||
</content-column>
|
||||
<!--
|
||||
@ -34,14 +37,16 @@
|
||||
-->
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
|
||||
source="createdByUser.displayName"
|
||||
key="createdByUser.displayName"
|
||||
sortable="true"
|
||||
class="desktop-only">
|
||||
</content-column>
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_ON' | translate}}"
|
||||
source="createdAt"
|
||||
key="createdAt"
|
||||
type="date"
|
||||
format="medium"
|
||||
sortable="true"
|
||||
class="desktop-only">
|
||||
</content-column>
|
||||
</content-columns>
|
||||
@ -50,25 +55,16 @@
|
||||
<!-- folder actions -->
|
||||
<content-action
|
||||
target="folder"
|
||||
type="button"
|
||||
icon="delete"
|
||||
handler="system1">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.SYSTEM_1' | translate}}"
|
||||
handler="system1">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.CUSTOM' | translate}}"
|
||||
(execute)="myFolderAction1($event)">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
@ -76,37 +72,21 @@
|
||||
<!-- document actions -->
|
||||
<content-action
|
||||
target="document"
|
||||
type="button"
|
||||
icon="account_circle"
|
||||
handler="my-handler">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="button"
|
||||
icon="cloud_download"
|
||||
handler="download">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DOWNLOAD' | translate}}"
|
||||
handler="download">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.SYSTEM_2' | translate}}"
|
||||
handler="system2">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.CUSTOM' | translate}}"
|
||||
(execute)="myCustomAction1($event)">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
|
@ -34,6 +34,7 @@ describe('ContextMenuDirective', () => {
|
||||
done();
|
||||
});
|
||||
|
||||
directive.links = [{}];
|
||||
directive.onShowContextMenu(null);
|
||||
});
|
||||
|
||||
|
@ -26,17 +26,20 @@ import { ContextMenuService } from './../services/context-menu.service';
|
||||
})
|
||||
export class ContextMenuDirective {
|
||||
@Input('context-menu')
|
||||
links;
|
||||
links: any[];
|
||||
|
||||
constructor(
|
||||
private _contextMenuService: ContextMenuService) {}
|
||||
|
||||
onShowContextMenu(event?: MouseEvent) {
|
||||
if (this._contextMenuService) {
|
||||
this._contextMenuService.show.next({event: event, obj: this.links});
|
||||
}
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (this.links && this.links.length > 0) {
|
||||
if (this._contextMenuService) {
|
||||
this._contextMenuService.show.next({event: event, obj: this.links});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,14 +16,17 @@
|
||||
*/
|
||||
|
||||
import { DataTableComponent } from './src/components/datatable.component';
|
||||
import { NoContentTemplateComponent } from './src/components/no-content-template.component';
|
||||
|
||||
// components
|
||||
export * from './src/components/datatable.component';
|
||||
export * from './src/components/no-content-template.component';
|
||||
|
||||
// data
|
||||
export * from './src/data/datatable-adapter';
|
||||
export * from './src/data/object-datatable-adapter';
|
||||
|
||||
export const ALFRESCO_DATATABLE_DIRECTIVES: [any] = [
|
||||
DataTableComponent
|
||||
DataTableComponent,
|
||||
NoContentTemplateComponent
|
||||
];
|
||||
|
@ -9,13 +9,15 @@ var map = {
|
||||
'app': 'base/dist',
|
||||
'rxjs': 'base/node_modules/rxjs',
|
||||
'@angular': 'base/node_modules/@angular',
|
||||
'ng2-alfresco-core/dist': '/base/node_modules/ng2-alfresco-core/dist'
|
||||
'ng2-alfresco-core': '/base/node_modules/ng2-alfresco-core/dist',
|
||||
'ng2-translate' : '/base/node_modules/ng2-translate'
|
||||
};
|
||||
|
||||
var packages = {
|
||||
'app': { main: 'main.js', defaultExtension: 'js' },
|
||||
'rxjs': { defaultExtension: 'js' },
|
||||
'ng2-alfresco-core/dist': { defaultExtension: 'js' }
|
||||
'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-translate': { defaultExtension: 'js' }
|
||||
};
|
||||
|
||||
var packageNames = [
|
||||
|
@ -16,6 +16,7 @@ module.exports = function (config) {
|
||||
{pattern: 'node_modules/@angular/**/*.js', included: false, watched: false},
|
||||
{pattern: 'node_modules/@angular/**/*.map', included: false, watched: false},
|
||||
{pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false},
|
||||
|
||||
{pattern: 'karma-test-shim.js', included: true, watched: true},
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
"posttest": "node_modules/.bin/remap-istanbul -i coverage/report/coverage-final.json -o coverage/report -t html",
|
||||
"coverage": "npm run test && wsrv -o -p 9875 ./coverage/report",
|
||||
"prepublish": "npm run build",
|
||||
"travis": "echo 'placeholder'"
|
||||
"travis": "npm link ng2-alfresco-core"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
@ -67,7 +67,9 @@
|
||||
"reflect-metadata": "0.1.3",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"zone.js": "0.6.12",
|
||||
"rimraf": "2.5.2"
|
||||
"rimraf": "2.5.2",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"material-design-icons": "^2.2.3",
|
||||
|
@ -14,11 +14,58 @@
|
||||
:host .data-cell {
|
||||
cursor: default;
|
||||
}
|
||||
:host .cell-value {}
|
||||
|
||||
:host .column-header {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
}
|
||||
|
||||
/* Empty folder */
|
||||
|
||||
:host .no-content-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
:host .no-content-container > img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:host .ellipsis-cell > div
|
||||
{
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
/*height: 1em;*/
|
||||
}
|
||||
|
||||
|
||||
/* visible content */
|
||||
:host .ellipsis-cell > div > span
|
||||
{
|
||||
display: block;
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1em; /* for vertical align of text */
|
||||
}
|
||||
|
||||
|
||||
/* cell stretching content */
|
||||
:host .ellipsis-cell > div:after
|
||||
{
|
||||
content: attr(title);
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/* Utils */
|
||||
|
||||
:host .non-selectable {
|
||||
@ -39,3 +86,22 @@
|
||||
clip: rect(0,0,0,0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* small desktop */
|
||||
@media all and (max-width: 1200px) {}
|
||||
|
||||
/* tablet */
|
||||
@media all and (max-width: 1024px) {}
|
||||
|
||||
/* mobile phone */
|
||||
@media all and (max-width: 768px) {
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-device-width: 768px){
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
</th>
|
||||
<th class="mdl-data-table__cell--non-numeric non-selectable {{col.cssClass}}"
|
||||
*ngFor="let col of data.getColumns()"
|
||||
[attr.data-automation-id]="'auto_id_' + col.key"
|
||||
[class.column-header]="col.title"
|
||||
[class.mdl-data-table__header--sorted-ascending]="isColumnSorted(col, 'asc')"
|
||||
[class.mdl-data-table__header--sorted-descending]="isColumnSorted(col, 'desc')"
|
||||
@ -41,22 +42,50 @@
|
||||
</td>
|
||||
<td *ngFor="let col of data.getColumns()" [ngSwitch]="col.type"
|
||||
class="mdl-data-table__cell--non-numeric non-selectable data-cell {{col.cssClass}}"
|
||||
(click)="onRowClick(row, $event)" (dblclick)="onRowDblClick(row, $event)">
|
||||
<div *ngSwitchCase="'image'">
|
||||
(click)="onRowClick(row, $event)"
|
||||
(dblclick)="onRowDblClick(row, $event)"
|
||||
[context-menu]="getContextMenuActions(row, col)">
|
||||
<div *ngSwitchCase="'image'" class="cell-value">
|
||||
<i *ngIf="isIconValue(row, col)" class="material-icons icon-cell">{{asIconValue(row, col)}}</i>
|
||||
<img *ngIf="!isIconValue(row, col)" class="image-cell" alt="" src="{{data.getValue(row, col)}}">
|
||||
</div>
|
||||
<div *ngSwitchCase="'text'">
|
||||
<div *ngSwitchCase="'date'" class="cell-value">
|
||||
{{data.getValue(row, col)}}
|
||||
</div>
|
||||
<span *ngSwitchDefault>
|
||||
<div *ngSwitchCase="'text'" class="cell-value">
|
||||
{{data.getValue(row, col)}}
|
||||
</div>
|
||||
<span *ngSwitchDefault class="cell-value">
|
||||
<!-- empty cell for unknown column type -->
|
||||
</span>
|
||||
|
||||
</td>
|
||||
|
||||
<td *ngIf="actions"><!-- todo: actions --></td>
|
||||
<td *ngIf="actions">
|
||||
<!-- action menu -->
|
||||
<button [id]="'action_menu_' + idx" class="mdl-button mdl-js-button mdl-button--icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
|
||||
[attr.for]="'action_menu_' + idx">
|
||||
<li class="mdl-menu__item"
|
||||
[attr.data-automation-id]="action.title"
|
||||
*ngFor="let action of getRowActions(row)"
|
||||
(click)="onExecuteRowAction(row, action)">
|
||||
{{action.title}}
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr *ngIf="data.getRows().length === 0">
|
||||
<td class="mdl-data-table__cell--non-numeric no-content-container"
|
||||
[attr.colspan]="1 + data.getColumns().length">
|
||||
<template *ngIf="noContentTemplate"
|
||||
ngFor [ngForOf]="[data]"
|
||||
[ngForTemplate]="noContentTemplate">
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -22,14 +22,18 @@ import {
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter,
|
||||
AfterViewChecked
|
||||
AfterViewChecked,
|
||||
TemplateRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core';
|
||||
|
||||
import {
|
||||
DataTableAdapter,
|
||||
DataRow,
|
||||
DataColumn,
|
||||
DataSorting
|
||||
DataSorting,
|
||||
DataRowEvent
|
||||
} from './../data/datatable-adapter';
|
||||
import { ObjectDataTableAdapter } from '../data/object-datatable-adapter';
|
||||
|
||||
@ -40,7 +44,8 @@ declare let __moduleName: string;
|
||||
moduleId: __moduleName,
|
||||
selector: 'alfresco-datatable',
|
||||
styleUrls: ['./datatable.component.css'],
|
||||
templateUrl: './datatable.component.html'
|
||||
templateUrl: './datatable.component.html',
|
||||
directives: [CONTEXT_MENU_DIRECTIVES]
|
||||
})
|
||||
export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
@ -54,13 +59,24 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
actions: boolean = false;
|
||||
|
||||
@Output()
|
||||
rowClick: EventEmitter<any> = new EventEmitter();
|
||||
rowClick: EventEmitter<DataRowEvent> = new EventEmitter<DataRowEvent>();
|
||||
|
||||
@Output()
|
||||
rowDblClick: EventEmitter<any> = new EventEmitter();
|
||||
rowDblClick: EventEmitter<DataRowEvent> = new EventEmitter<DataRowEvent>();
|
||||
|
||||
noContentTemplate: TemplateRef<any>;
|
||||
|
||||
isSelectAllChecked: boolean = false;
|
||||
|
||||
@Output()
|
||||
showRowContextMenu: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
showRowActionsMenu: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
executeRowAction: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
// TODO: left for reference, will be removed during future revisions
|
||||
constructor(/*private _ngZone?: NgZone*/) {
|
||||
}
|
||||
@ -84,7 +100,8 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
}
|
||||
|
||||
this.rowClick.emit({
|
||||
value: row
|
||||
value: row,
|
||||
event: e
|
||||
});
|
||||
}
|
||||
|
||||
@ -94,7 +111,8 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
}
|
||||
|
||||
this.rowDblClick.emit({
|
||||
value: row
|
||||
value: row,
|
||||
event: e
|
||||
});
|
||||
}
|
||||
|
||||
@ -134,14 +152,16 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
isIconValue(row: DataRow, col: DataColumn) {
|
||||
if (row && col) {
|
||||
return row.getValue(col.key).startsWith('material-icons://');
|
||||
let value = row.getValue(col.key);
|
||||
return value && value.startsWith('material-icons://');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
asIconValue(row: DataRow, col: DataColumn) {
|
||||
if (this.isIconValue(row, col)) {
|
||||
return row.getValue(col.key).replace('material-icons://', '');
|
||||
let value = row.getValue(col.key) || '';
|
||||
return value.replace('material-icons://', '');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -153,4 +173,21 @@ export class DataTableComponent implements OnInit, AfterViewChecked {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getContextMenuActions(row: DataRow, col: DataColumn) {
|
||||
let args = { row: row, col: col, actions: [] };
|
||||
this.showRowContextMenu.emit({ args: args });
|
||||
return args.actions;
|
||||
}
|
||||
|
||||
getRowActions(row: DataRow, col: DataColumn) {
|
||||
let args = { row: row, col: col, actions: [] };
|
||||
this.showRowActionsMenu.emit({ args: args });
|
||||
return args.actions;
|
||||
}
|
||||
|
||||
onExecuteRowAction(row: DataRow, action: any) {
|
||||
let args = { row: row, action: action };
|
||||
this.executeRowAction.emit({ args: args });
|
||||
}
|
||||
}
|
||||
|
@ -16,22 +16,26 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
it,
|
||||
describe,
|
||||
expect
|
||||
} from '@angular/core/testing';
|
||||
Directive,
|
||||
ContentChild,
|
||||
TemplateRef,
|
||||
AfterContentInit
|
||||
} from '@angular/core';
|
||||
import { DataTableComponent } from './datatable.component';
|
||||
|
||||
import { ContentColumnModel } from './content-column.model';
|
||||
@Directive({
|
||||
selector: 'no-content-template'
|
||||
})
|
||||
export class NoContentTemplateComponent implements AfterContentInit {
|
||||
|
||||
describe('ContentColumnModel', () => {
|
||||
@ContentChild(TemplateRef)
|
||||
template: any;
|
||||
|
||||
it('should init with text type from config object', () => {
|
||||
let model = new ContentColumnModel({});
|
||||
expect(model.type).toBe(ContentColumnModel.TYPE_TEXT);
|
||||
});
|
||||
constructor(
|
||||
private dataTable: DataTableComponent) {
|
||||
}
|
||||
|
||||
it('should return supported types', () => {
|
||||
expect(ContentColumnModel.getSupportedTypes().length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
});
|
||||
ngAfterContentInit() {
|
||||
this.dataTable.noContentTemplate = this.template;
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
export interface DataTableAdapter {
|
||||
|
||||
getRows(): Array<DataRow>;
|
||||
setRows(rows: Array<DataRow>): void;
|
||||
getColumns(): Array<DataColumn>;
|
||||
@ -25,33 +24,32 @@ export interface DataTableAdapter {
|
||||
getSorting(): DataSorting;
|
||||
setSorting(sorting: DataSorting): void;
|
||||
sort(key?: string, direction?: string): void;
|
||||
|
||||
}
|
||||
|
||||
export interface DataRow {
|
||||
|
||||
isSelected: boolean;
|
||||
hasValue(key: string): boolean;
|
||||
getValue(key: string): any;
|
||||
|
||||
}
|
||||
|
||||
export interface DataColumn {
|
||||
|
||||
key: string;
|
||||
type: string; // text|image
|
||||
type: string; // text|image|date
|
||||
format?: string;
|
||||
sortable?: boolean;
|
||||
title?: string;
|
||||
srTitle?: string;
|
||||
cssClass?: string;
|
||||
|
||||
}
|
||||
|
||||
export class DataSorting {
|
||||
|
||||
constructor(
|
||||
public key?: string,
|
||||
public direction?: string) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface DataRowEvent {
|
||||
value?: DataRow;
|
||||
event?: Event;
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
import {
|
||||
DataTableAdapter,
|
||||
DataRow,
|
||||
@ -78,7 +80,20 @@ export class ObjectDataTableAdapter implements DataTableAdapter {
|
||||
if (!col) {
|
||||
throw new Error('Column not found');
|
||||
}
|
||||
return row.getValue(col.key);
|
||||
|
||||
let value = row.getValue(col.key);
|
||||
|
||||
if (col.type === 'date') {
|
||||
let datePipe = new DatePipe();
|
||||
let format = col.format || 'medium';
|
||||
try {
|
||||
return datePipe.transform(value, format);
|
||||
} catch (err) {
|
||||
console.error(`DocumentList: error parsing date ${value} to format ${format}`);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
getSorting(): DataSorting {
|
||||
|
@ -9,7 +9,7 @@
|
||||
"typings": "typings install",
|
||||
"postinstall": "npm run typings && npm run build",
|
||||
"start": "concurrently \"npm run build:w\" \"npm run server\" ",
|
||||
"server": "wsrv -o -s",
|
||||
"server": "wsrv -o -s -l",
|
||||
"build": "npm run tslint && rimraf dist && tsc",
|
||||
"build:w": "npm run tslint && rimraf dist && tsc -w",
|
||||
"tslint": "npm run tslint-src && npm run tslint-root",
|
||||
@ -41,7 +41,8 @@
|
||||
|
||||
"alfresco-js-api": "^0.1.0",
|
||||
"ng2-alfresco-core": "^0.1.36",
|
||||
"ng2-alfresco-documentlist": "^0.1.34"
|
||||
"ng2-alfresco-documentlist": "^0.1.34",
|
||||
"ng2-alfresco-datatable": "^0.1.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "2.0.0",
|
||||
|
@ -38,9 +38,9 @@ import {
|
||||
selector: 'alfresco-documentlist-demo',
|
||||
template: `
|
||||
<label for="token"><b>Insert a valid access token / ticket:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateToken();doclist.reload()" [(ngModel)]="token"><br>
|
||||
<input id="token" type="text" size="48" (change)="updateToken();documentList.reload()" [(ngModel)]="token"><br>
|
||||
<label for="token"><b>Insert the ip of your Alfresco instance:</b></label><br>
|
||||
<input id="token" type="text" size="48" (change)="updateHost();doclist.reload()" [(ngModel)]="host"><br><br>
|
||||
<input id="token" type="text" size="48" (change)="updateHost();documentList.reload()" [(ngModel)]="host"><br><br>
|
||||
<div *ngIf="!authenticated" style="color:#FF2323">
|
||||
Authentication failed to ip {{ host }} with user: admin, admin, you can still try to add a valid token to perform
|
||||
operations.
|
||||
@ -52,28 +52,40 @@ import {
|
||||
[currentFolderPath]="currentPath"
|
||||
[target]="documentList">
|
||||
</alfresco-document-list-breadcrumb>
|
||||
<alfresco-document-list #doclist
|
||||
<alfresco-document-list
|
||||
#documentList
|
||||
[currentFolderPath]="currentPath"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="true"
|
||||
[multiselect]="true"
|
||||
(folderChange)="onFolderChanged($event)">
|
||||
|
||||
<!--
|
||||
<empty-folder-content>
|
||||
<template>
|
||||
<h1>Sorry, no content here</h1>
|
||||
</template>
|
||||
</empty-folder-content>
|
||||
-->
|
||||
<content-columns>
|
||||
<content-column source="$thumbnail" type="image"></content-column>
|
||||
<content-column key="$thumbnail" type="image"></content-column>
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.DISPLAY_NAME' | translate}}"
|
||||
source="name"
|
||||
key="name"
|
||||
sortable="true"
|
||||
class="full-width ellipsis-cell">
|
||||
</content-column>
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
|
||||
source="createdByUser.displayName"
|
||||
key="createdByUser.displayName"
|
||||
sortable="true"
|
||||
class="desktop-only">
|
||||
</content-column>
|
||||
<content-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_ON' | translate}}"
|
||||
source="createdAt"
|
||||
key="createdAt"
|
||||
type="date"
|
||||
format="medium"
|
||||
sortable="true"
|
||||
class="desktop-only">
|
||||
</content-column>
|
||||
</content-columns>
|
||||
@ -81,25 +93,16 @@ import {
|
||||
<!-- folder actions -->
|
||||
<content-action
|
||||
target="folder"
|
||||
type="button"
|
||||
icon="delete"
|
||||
handler="system1">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.SYSTEM_1' | translate}}"
|
||||
handler="system1">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.CUSTOM' | translate}}"
|
||||
(execute)="myFolderAction1($event)">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="folder"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
@ -107,37 +110,21 @@ import {
|
||||
<!-- document actions -->
|
||||
<content-action
|
||||
target="document"
|
||||
type="button"
|
||||
icon="account_circle"
|
||||
handler="my-handler">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="button"
|
||||
icon="cloud_download"
|
||||
handler="download">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DOWNLOAD' | translate}}"
|
||||
handler="download">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.SYSTEM_2' | translate}}"
|
||||
handler="system2">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.CUSTOM' | translate}}"
|
||||
(execute)="myCustomAction1($event)">
|
||||
</content-action>
|
||||
<content-action
|
||||
target="document"
|
||||
type="menu"
|
||||
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
|
||||
handler="delete">
|
||||
</content-action>
|
||||
@ -156,7 +143,8 @@ class DocumentListDemo implements OnInit {
|
||||
currentPath: string = '/';
|
||||
authenticated: boolean;
|
||||
|
||||
public host: string = 'http://devproducts-platform.alfresco.me';
|
||||
// host: string = 'http://devproducts-platform.alfresco.me';
|
||||
host: string = 'http://127.0.0.1:8080';
|
||||
|
||||
token: string;
|
||||
|
||||
@ -194,11 +182,13 @@ class DocumentListDemo implements OnInit {
|
||||
}
|
||||
|
||||
myCustomAction1(event) {
|
||||
alert('Custom document action for ' + event.value.displayName);
|
||||
let entry = event.value.entry;
|
||||
alert(`Custom document action for ${entry.name}`);
|
||||
}
|
||||
|
||||
myFolderAction1(event) {
|
||||
alert('Custom folder action for ' + event.value.displayName);
|
||||
let entry = event.value.entry;
|
||||
alert(`Custom folder action for ${entry.name}`);
|
||||
}
|
||||
|
||||
login() {
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
'ng2-translate': 'node_modules/ng2-translate',
|
||||
'ng2-alfresco-core': 'node_modules/ng2-alfresco-core/dist',
|
||||
'ng2-alfresco-datatable': 'node_modules/ng2-alfresco-datatable/dist',
|
||||
'ng2-alfresco-documentlist': 'node_modules/ng2-alfresco-documentlist/dist'
|
||||
};
|
||||
// packages tells the System loader how to load when no filename and/or no extension
|
||||
@ -22,6 +23,7 @@
|
||||
|
||||
'ng2-translate': { defaultExtension: 'js' },
|
||||
'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-alfresco-datatable': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-alfresco-documentlist': { main: 'index.js', defaultExtension: 'js' }
|
||||
};
|
||||
var ngPackageNames = [
|
||||
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"watch": [
|
||||
"node_modules/ng2-alfresco-datatable/dist/**/*.{html,htm,css,js}",
|
||||
"node_modules/ng2-alfresco-documentlist/dist/**/*.{html,htm,css,js}"
|
||||
]
|
||||
}
|
@ -25,7 +25,7 @@ import { DocumentListBreadcrumb } from './src/components/document-list-breadcrum
|
||||
|
||||
import { FolderActionsService } from './src/services/folder-actions.service';
|
||||
import { DocumentActionsService } from './src/services/document-actions.service';
|
||||
import { AlfrescoService } from './src/services/alfresco.service';
|
||||
import { DocumentListService } from './src/services/document-list.service';
|
||||
|
||||
// components
|
||||
export * from './src/components/document-list';
|
||||
@ -36,13 +36,10 @@ export * from './src/components/content-action-list';
|
||||
export * from './src/components/empty-folder-content';
|
||||
export * from './src/components/document-list-breadcrumb.component';
|
||||
|
||||
// models
|
||||
export * from './src/models/column-sorting.model';
|
||||
|
||||
// services
|
||||
export * from './src/services/folder-actions.service';
|
||||
export * from './src/services/document-actions.service';
|
||||
export * from './src/services/alfresco.service';
|
||||
export * from './src/services/document-list.service';
|
||||
|
||||
export const DOCUMENT_LIST_DIRECTIVES: [any] = [
|
||||
DocumentList,
|
||||
@ -55,7 +52,7 @@ export const DOCUMENT_LIST_DIRECTIVES: [any] = [
|
||||
];
|
||||
|
||||
export const DOCUMENT_LIST_PROVIDERS: [any] = [
|
||||
AlfrescoService,
|
||||
DocumentListService,
|
||||
FolderActionsService,
|
||||
DocumentActionsService
|
||||
];
|
||||
|
@ -9,15 +9,17 @@ var map = {
|
||||
'app': 'base/dist',
|
||||
'rxjs': 'base/node_modules/rxjs',
|
||||
'@angular': 'base/node_modules/@angular',
|
||||
'ng2-translate' : '/base/node_modules/ng2-translate',
|
||||
'ng2-alfresco-core': '/base/node_modules/ng2-alfresco-core/dist',
|
||||
'ng2-translate' : '/base/node_modules/ng2-translate'
|
||||
'ng2-alfresco-datatable': '/base/node_modules/ng2-alfresco-datatable/dist'
|
||||
};
|
||||
|
||||
var packages = {
|
||||
'app': { main: 'main.js', defaultExtension: 'js' },
|
||||
'rxjs': { defaultExtension: 'js' },
|
||||
'ng2-translate': { defaultExtension: 'js' },
|
||||
'ng2-alfresco-core': { main: 'index.js', defaultExtension: 'js' },
|
||||
'ng2-translate': { defaultExtension: 'js' }
|
||||
'ng2-alfresco-datatable': { main: 'index.js', defaultExtension: 'js' }
|
||||
};
|
||||
|
||||
var packageNames = [
|
||||
|
@ -16,6 +16,7 @@ module.exports = function (config) {
|
||||
{pattern: 'node_modules/@angular/**/*.js', included: false, watched: false},
|
||||
{pattern: 'node_modules/@angular/**/*.map', included: false, watched: false},
|
||||
{pattern: 'node_modules/ng2-alfresco-core/dist/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-alfresco-datatable/dist/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: 'node_modules/ng2-translate/**/*.js', included: false, served: true, watched: false},
|
||||
|
||||
{pattern: 'karma-test-shim.js', included: true, watched: true},
|
||||
@ -71,7 +72,7 @@ module.exports = function (config) {
|
||||
|
||||
// Coverage reporter generates the coverage
|
||||
reporters: ['mocha', 'coverage', 'coveralls', 'kjhtml'],
|
||||
|
||||
|
||||
// Source files that you wanna generate coverage for.
|
||||
// Do not include tests or libraries (these files will be instrumented by Istanbul)
|
||||
preprocessors: {
|
||||
|
@ -28,7 +28,7 @@
|
||||
"posttest": "node_modules/.bin/remap-istanbul -i coverage/report/coverage-final.json -o coverage/report -t html",
|
||||
"coverage": "npm run test && wsrv -o -p 9875 ./coverage/report",
|
||||
"prepublish": "npm run build",
|
||||
"travis": "npm link ng2-alfresco-core"
|
||||
"travis": "npm link ng2-alfresco-core ng2-alfresco-datatable"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
@ -75,6 +75,7 @@
|
||||
"rimraf": "2.5.2",
|
||||
"ng2-translate": "2.2.2",
|
||||
"ng2-alfresco-core": "0.2.0",
|
||||
"ng2-alfresco-datatable": "0.2.0",
|
||||
"alfresco-js-api": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -103,13 +104,7 @@
|
||||
},
|
||||
"license-check-config": {
|
||||
"src": [
|
||||
"**/*.js",
|
||||
"**/*.ts",
|
||||
"!/**/coverage/**/*",
|
||||
"!/**/demo/**/*",
|
||||
"!/**/node_modules/**/*",
|
||||
"!/**/typings/**/*",
|
||||
"!*.js"
|
||||
"./dist/**/*.js"
|
||||
],
|
||||
"path": "assets/license_header.txt",
|
||||
"blocking": true,
|
||||
|
@ -15,15 +15,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {AlfrescoService} from '../../src/services/alfresco.service';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { DocumentListService } from './../services/document-list.service';
|
||||
import {
|
||||
AlfrescoSettingsService,
|
||||
AlfrescoAuthenticationService,
|
||||
AlfrescoContentService
|
||||
} from 'ng2-alfresco-core';
|
||||
|
||||
export class AlfrescoServiceMock extends AlfrescoService {
|
||||
export class DocumentListServiceMock extends DocumentListService {
|
||||
|
||||
folderToReturn: any = {};
|
||||
getFolderReject: boolean = false;
|
@ -23,7 +23,7 @@ import {
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import { DocumentList } from './document-list';
|
||||
import { AlfrescoServiceMock } from '../assets/alfresco.service.mock';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
import { ContentActionModel } from './../models/content-action.model';
|
||||
import { ContentActionList } from './content-action-list';
|
||||
|
||||
@ -33,8 +33,8 @@ describe('ContentColumnList', () => {
|
||||
let actionList: ContentActionList;
|
||||
|
||||
beforeEach(() => {
|
||||
let alfrescoServiceMock = new AlfrescoServiceMock();
|
||||
documentList = new DocumentList(alfrescoServiceMock, null);
|
||||
let documentListService = new DocumentListServiceMock();
|
||||
documentList = new DocumentList(documentListService, null);
|
||||
actionList = new ContentActionList(documentList);
|
||||
});
|
||||
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
import { EventEmitter } from '@angular/core';
|
||||
|
||||
import { DocumentList } from './document-list';
|
||||
import { AlfrescoServiceMock } from '../assets/alfresco.service.mock';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
import { ContentActionList } from './content-action-list';
|
||||
import { ContentAction } from './content-action';
|
||||
import { DocumentActionsService } from '../services/document-actions.service';
|
||||
@ -40,11 +40,11 @@ describe('ContentAction', () => {
|
||||
let folderActions: FolderActionsService;
|
||||
|
||||
beforeEach(() => {
|
||||
let alfrescoServiceMock = new AlfrescoServiceMock();
|
||||
let documentServiceMock = new DocumentListServiceMock();
|
||||
documentActions = new DocumentActionsService(null, null);
|
||||
folderActions = new FolderActionsService(null);
|
||||
|
||||
documentList = new DocumentList(alfrescoServiceMock, null);
|
||||
documentList = new DocumentList(documentServiceMock, null);
|
||||
actionList = new ContentActionList(documentList);
|
||||
});
|
||||
|
||||
@ -59,7 +59,6 @@ describe('ContentAction', () => {
|
||||
|
||||
it('should setup and register model', () => {
|
||||
let action = new ContentAction(actionList, null, null);
|
||||
action.type = 'button';
|
||||
action.target = 'document';
|
||||
action.title = '<title>';
|
||||
action.icon = '<icon>';
|
||||
@ -70,7 +69,6 @@ describe('ContentAction', () => {
|
||||
expect(documentList.actions.length).toBe(1);
|
||||
|
||||
let model = documentList.actions[0];
|
||||
expect(model.type).toBe(action.type);
|
||||
expect(model.target).toBe(action.target);
|
||||
expect(model.title).toBe(action.title);
|
||||
expect(model.icon).toBe(action.icon);
|
||||
@ -82,7 +80,6 @@ describe('ContentAction', () => {
|
||||
spyOn(documentActions, 'getHandler').and.returnValue(handler);
|
||||
|
||||
let action = new ContentAction(actionList, documentActions, null);
|
||||
action.type = 'button';
|
||||
action.target = 'document';
|
||||
action.handler = '<handler>';
|
||||
action.ngOnInit();
|
||||
@ -99,7 +96,6 @@ describe('ContentAction', () => {
|
||||
spyOn(folderActions, 'getHandler').and.returnValue(handler);
|
||||
|
||||
let action = new ContentAction(actionList, null, folderActions);
|
||||
action.type = 'button';
|
||||
action.target = 'folder';
|
||||
action.handler = '<handler>';
|
||||
action.ngOnInit();
|
||||
@ -116,7 +112,6 @@ describe('ContentAction', () => {
|
||||
spyOn(documentActions, 'getHandler').and.stub();
|
||||
|
||||
let action = new ContentAction(actionList, documentActions, folderActions);
|
||||
action.type = 'button';
|
||||
action.handler = '<handler>';
|
||||
|
||||
action.ngOnInit();
|
||||
@ -138,7 +133,6 @@ describe('ContentAction', () => {
|
||||
|
||||
let action = new ContentAction(actionList, documentActions, null);
|
||||
action.target = 'DoCuMeNt';
|
||||
action.type = 'button';
|
||||
action.handler = '<handler>';
|
||||
|
||||
action.ngOnInit();
|
||||
@ -150,7 +144,6 @@ describe('ContentAction', () => {
|
||||
|
||||
let action = new ContentAction(actionList, null, folderActions);
|
||||
action.target = 'FoLdEr';
|
||||
action.type = 'button';
|
||||
action.handler = '<handler>';
|
||||
|
||||
action.ngOnInit();
|
||||
@ -167,7 +160,6 @@ describe('ContentAction', () => {
|
||||
|
||||
let action = new ContentAction(actionList, null, null);
|
||||
action.target = 'document';
|
||||
action.type = 'button';
|
||||
action.execute = emitter;
|
||||
|
||||
action.ngOnInit();
|
||||
|
@ -15,12 +15,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Component, OnInit, OnChanges, Input, Output, EventEmitter} from '@angular/core';
|
||||
import {ContentActionModel} from './../models/content-action.model';
|
||||
import {ContentActionList} from './content-action-list';
|
||||
import {DocumentActionsService} from '../services/document-actions.service';
|
||||
import {FolderActionsService} from '../services/folder-actions.service';
|
||||
import {ContentActionHandler} from '../models/content-action.model';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnChanges,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter
|
||||
} from '@angular/core';
|
||||
|
||||
import { ContentActionModel } from './../models/content-action.model';
|
||||
import { ContentActionList } from './content-action-list';
|
||||
import { DocumentActionsService } from '../services/document-actions.service';
|
||||
import { FolderActionsService } from '../services/folder-actions.service';
|
||||
import { ContentActionHandler } from '../models/content-action.model';
|
||||
|
||||
@Component({
|
||||
selector: 'content-action',
|
||||
@ -37,9 +45,6 @@ export class ContentAction implements OnInit, OnChanges {
|
||||
@Input()
|
||||
handler: string;
|
||||
|
||||
@Input()
|
||||
type: string;
|
||||
|
||||
@Input()
|
||||
target: string;
|
||||
|
||||
@ -57,7 +62,6 @@ export class ContentAction implements OnInit, OnChanges {
|
||||
|
||||
ngOnInit() {
|
||||
this.model = new ContentActionModel({
|
||||
type: this.type,
|
||||
title: this.title,
|
||||
icon: this.icon,
|
||||
target: this.target
|
||||
|
@ -22,10 +22,11 @@ import {
|
||||
beforeEach
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import {DocumentList} from './document-list';
|
||||
import {AlfrescoServiceMock} from '../assets/alfresco.service.mock';
|
||||
import {ContentColumnList} from './content-column-list';
|
||||
import {ContentColumnModel} from '../models/content-column.model';
|
||||
import { DataColumn } from 'ng2-alfresco-datatable';
|
||||
|
||||
import { DocumentList } from './document-list';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
import { ContentColumnList } from './content-column-list';
|
||||
|
||||
describe('ContentColumnList', () => {
|
||||
|
||||
@ -33,23 +34,26 @@ describe('ContentColumnList', () => {
|
||||
let columnList: ContentColumnList;
|
||||
|
||||
beforeEach(() => {
|
||||
let alfrescoServiceMock = new AlfrescoServiceMock();
|
||||
documentList = new DocumentList(alfrescoServiceMock, null);
|
||||
let service = new DocumentListServiceMock();
|
||||
documentList = new DocumentList(service, null);
|
||||
columnList = new ContentColumnList(documentList);
|
||||
});
|
||||
|
||||
it('should register column within parent document list', () => {
|
||||
expect(documentList.columns.length).toBe(0);
|
||||
let columns = documentList.data.getColumns();
|
||||
expect(columns.length).toBe(0);
|
||||
|
||||
let result = columnList.registerColumn(new ContentColumnModel());
|
||||
let column = <DataColumn> {};
|
||||
let result = columnList.registerColumn(column);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(documentList.columns.length).toBe(1);
|
||||
expect(columns.length).toBe(1);
|
||||
expect(columns[0]).toBe(column);
|
||||
});
|
||||
|
||||
it('should require document list instance to register action', () => {
|
||||
columnList = new ContentColumnList(null);
|
||||
let col = new ContentColumnModel();
|
||||
let col = <DataColumn> {};
|
||||
expect(columnList.registerColumn(col)).toBeFalsy();
|
||||
});
|
||||
|
||||
|
@ -15,9 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {DocumentList} from './document-list';
|
||||
import {ContentColumnModel} from './../models/content-column.model';
|
||||
import { Component } from '@angular/core';
|
||||
import { DocumentList } from './document-list';
|
||||
import { DataColumn } from 'ng2-alfresco-datatable';
|
||||
|
||||
@Component({
|
||||
selector: 'content-columns',
|
||||
@ -33,9 +33,10 @@ export class ContentColumnList {
|
||||
* Registers column model within the parent document list component.
|
||||
* @param column Column definition model to register.
|
||||
*/
|
||||
registerColumn(column: ContentColumnModel): boolean {
|
||||
registerColumn(column: DataColumn): boolean {
|
||||
if (this.documentList && column) {
|
||||
this.documentList.columns.push(column);
|
||||
let columns = this.documentList.data.getColumns();
|
||||
columns.push(column);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -22,10 +22,10 @@ import {
|
||||
beforeEach
|
||||
} from '@angular/core/testing';
|
||||
|
||||
import {DocumentList} from './document-list';
|
||||
import {ContentColumn} from './content-column';
|
||||
import {AlfrescoServiceMock} from '../assets/alfresco.service.mock';
|
||||
import {ContentColumnList} from './content-column-list';
|
||||
import { DocumentList } from './document-list';
|
||||
import { ContentColumn } from './content-column';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
import { ContentColumnList } from './content-column-list';
|
||||
|
||||
describe('ContentColumn', () => {
|
||||
|
||||
@ -33,8 +33,8 @@ describe('ContentColumn', () => {
|
||||
let columnList: ContentColumnList;
|
||||
|
||||
beforeEach(() => {
|
||||
let alfrescoServiceMock = new AlfrescoServiceMock();
|
||||
documentList = new DocumentList(alfrescoServiceMock, null);
|
||||
let service = new DocumentListServiceMock();
|
||||
documentList = new DocumentList(service, null);
|
||||
columnList = new ContentColumnList(documentList);
|
||||
});
|
||||
|
||||
@ -45,52 +45,18 @@ describe('ContentColumn', () => {
|
||||
column.ngOnInit();
|
||||
|
||||
expect(columnList.registerColumn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup model properties during registration', () => {
|
||||
|
||||
let column = new ContentColumn(columnList);
|
||||
column.title = '<title>';
|
||||
column.srTitle = '<sr-title>';
|
||||
column.source = '<source>';
|
||||
column.cssClass = '<css-class>';
|
||||
column.ngOnInit();
|
||||
|
||||
expect(documentList.columns.length).toBe(1);
|
||||
|
||||
let model = documentList.columns[0];
|
||||
expect(model.title).toBe(column.title);
|
||||
expect(model.srTitle).toBe(column.srTitle);
|
||||
expect(model.source).toBe(column.source);
|
||||
expect(model.cssClass).toBe(column.cssClass);
|
||||
let columns = documentList.data.getColumns();
|
||||
expect(columns.length).toBe(1);
|
||||
expect(columns[0]).toBe(column);
|
||||
});
|
||||
|
||||
it('should setup screen reader title for thumbnail column', () => {
|
||||
|
||||
let column = new ContentColumn(columnList);
|
||||
column.source = '$thumbnail';
|
||||
column.key = '$thumbnail';
|
||||
column.ngOnInit();
|
||||
|
||||
expect(documentList.columns.length).toBe(1);
|
||||
|
||||
let model = documentList.columns[0];
|
||||
expect(model.srTitle).toBe('Thumbnail');
|
||||
});
|
||||
|
||||
it('should sync localizable fields with model', () => {
|
||||
|
||||
let column = new ContentColumn(columnList);
|
||||
column.title = 'title1';
|
||||
column.srTitle = 'srTitle1';
|
||||
column.ngOnInit();
|
||||
|
||||
expect(column.model.title).toBe(column.title);
|
||||
expect(column.model.srTitle).toBe(column.srTitle);
|
||||
|
||||
column.title = 'title2';
|
||||
column.ngOnChanges(null);
|
||||
|
||||
expect(column.model.title).toBe('title2');
|
||||
expect(column.srTitle).toBe('Thumbnail');
|
||||
});
|
||||
|
||||
it('should register on init', () => {
|
||||
|
@ -15,15 +15,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, OnInit, Input, OnChanges } from '@angular/core';
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { ContentColumnList } from './content-column-list';
|
||||
import { ContentColumnModel } from './../models/content-column.model';
|
||||
import { DataColumn } from 'ng2-alfresco-datatable';
|
||||
|
||||
@Component({
|
||||
selector: 'content-column',
|
||||
template: ''
|
||||
})
|
||||
export class ContentColumn implements OnInit, OnChanges {
|
||||
export class ContentColumn implements OnInit, DataColumn {
|
||||
|
||||
@Input()
|
||||
key: string;
|
||||
|
||||
@Input()
|
||||
type: string = 'text';
|
||||
|
||||
@Input()
|
||||
format: string;
|
||||
|
||||
@Input()
|
||||
sortable: boolean = false;
|
||||
|
||||
@Input()
|
||||
title: string = '';
|
||||
@ -34,36 +46,14 @@ export class ContentColumn implements OnInit, OnChanges {
|
||||
@Input('sr-title')
|
||||
srTitle: string;
|
||||
|
||||
@Input()
|
||||
source: string;
|
||||
|
||||
@Input('class')
|
||||
cssClass: string;
|
||||
|
||||
@Input()
|
||||
type: string = 'text';
|
||||
|
||||
@Input()
|
||||
format: string;
|
||||
|
||||
model: ContentColumnModel;
|
||||
|
||||
constructor(private list: ContentColumnList) {
|
||||
this.model = new ContentColumnModel();
|
||||
}
|
||||
constructor(private list: ContentColumnList) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.model = new ContentColumnModel({
|
||||
title: this.title,
|
||||
srTitle: this.srTitle,
|
||||
source: this.source,
|
||||
cssClass: this.cssClass,
|
||||
type: this.type,
|
||||
format: this.format
|
||||
});
|
||||
|
||||
if (!this.model.srTitle && this.model.source === '$thumbnail') {
|
||||
this.model.srTitle = 'Thumbnail';
|
||||
if (!this.srTitle && this.key === '$thumbnail') {
|
||||
this.srTitle = 'Thumbnail';
|
||||
}
|
||||
|
||||
this.register();
|
||||
@ -71,14 +61,8 @@ export class ContentColumn implements OnInit, OnChanges {
|
||||
|
||||
register(): boolean {
|
||||
if (this.list) {
|
||||
return this.list.registerColumn(this.model);
|
||||
return this.list.registerColumn(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ngOnChanges(change) {
|
||||
// update localizable properties
|
||||
this.model.title = this.title;
|
||||
this.model.srTitle = this.srTitle;
|
||||
}
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
:host .full-width { width: 100%; }
|
||||
|
||||
:host .thumbnail {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
:host .column-header {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
}
|
||||
|
||||
:host .parent-folder-link { cursor: default; }
|
||||
:host .parent-folder-link > td { text-align: left; }
|
||||
|
||||
:host .data-cell {
|
||||
cursor: default;
|
||||
}
|
||||
:host .cell-value {}
|
||||
|
||||
/* Empty folder */
|
||||
|
||||
:host .empty-folder-content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
:host .empty-folder-content > img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Utils */
|
||||
|
||||
:host .non-selectable {
|
||||
user-select: none;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
}
|
||||
|
||||
:host .sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0,0,0,0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
:host .ellipsis-cell > div
|
||||
{
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* visible content */
|
||||
:host .ellipsis-cell > div > span
|
||||
{
|
||||
display: block;
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1em; /* for vertical align of text */
|
||||
}
|
||||
|
||||
|
||||
/* cell stretching content */
|
||||
:host .ellipsis-cell > div:after
|
||||
{
|
||||
content: attr(title);
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* small desktop */
|
||||
@media all and (max-width: 1200px) {}
|
||||
|
||||
/* tablet */
|
||||
@media all and (max-width: 1024px) {}
|
||||
|
||||
/* mobile phone */
|
||||
@media all and (max-width: 768px) {
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-device-width: 768px){
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
@ -1,103 +1,15 @@
|
||||
<table *ngIf="folder" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp full-width">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- Columns -->
|
||||
<th class="mdl-data-table__cell--non-numeric non-selectable {{col.cssClass}}"
|
||||
*ngFor="let col of columns"
|
||||
[class.column-header]="col.title"
|
||||
[attr.data-automation-id]="'auto_id_' + col.source"
|
||||
[class.mdl-data-table__header--sorted-ascending]="sorting.key === col.source && sorting.direction === 'asc'"
|
||||
[class.mdl-data-table__header--sorted-descending]="sorting.key === col.source && sorting.direction === 'desc'"
|
||||
(click)="onColumnHeaderClick(col)">
|
||||
<span *ngIf="col.srTitle" class="cell-value sr-only">{{col.srTitle}}</span>
|
||||
<span *ngIf="col.title" class="cell-value">{{col.title}}</span>
|
||||
</th>
|
||||
<!-- Actions -->
|
||||
<th>
|
||||
<span class="sr-only">Actions</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let content of folder.list.entries; let idx = index"
|
||||
[attr.data-automation-id]="getObjectValue(content.entry, 'name')">
|
||||
<!-- Columns -->
|
||||
<td *ngFor="let col of columns" [ngSwitch]="col.type"
|
||||
class="mdl-data-table__cell--non-numeric non-selectable data-cell {{col.cssClass}}"
|
||||
(click)="onItemClick(content, $event)"
|
||||
(dblclick)="onItemDblClick(content, $event)"
|
||||
[context-menu]="getContextActions(content)"
|
||||
[attr.data-automation-id]="col.source === '$thumbnail' ? '$thumbnail' : col.source + '_' + getObjectValue(content.entry, col.source)">
|
||||
<div *ngSwitchCase="'image'" class="cell-value">
|
||||
<img class="thumbnail" [src]="getCellValue(content, col)">
|
||||
</div>
|
||||
<div *ngSwitchCase="'date'" class="cell-value">
|
||||
<span>{{ getCellValue(content, col) }}</span>
|
||||
</div>
|
||||
<div *ngSwitchDefault class="cell-value">
|
||||
<span>{{ getCellValue(content, col) }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Actions: folder -->
|
||||
<td *ngIf="content.entry.isFolder">
|
||||
<!-- action buttons -->
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
*ngFor="let action of getContentActions('folder', 'button')"
|
||||
(click)="executeContentAction(content, action)">
|
||||
<i class="material-icons">{{action.icon}}</i>
|
||||
</button>
|
||||
|
||||
<!-- action menu -->
|
||||
<button [id]="'folder_action_menu_' + idx" class="mdl-button mdl-js-button mdl-button--icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
|
||||
[attr.for]="'folder_action_menu_' + idx">
|
||||
<li class="mdl-menu__item"
|
||||
[attr.data-automation-id]="action.title"
|
||||
*ngFor="let action of getContentActions('folder', 'menu')"
|
||||
(click)="executeContentAction(content, action)">
|
||||
{{action.title}}
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<!-- Actions: document -->
|
||||
<td *ngIf="!content.entry.isFolder">
|
||||
<!-- action buttons -->
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
*ngFor="let action of getContentActions('document', 'button')"
|
||||
(click)="executeContentAction(content, action)">
|
||||
<i class="material-icons">{{action.icon}}</i>
|
||||
</button>
|
||||
|
||||
<!-- action menu -->
|
||||
<button [id]="'document_action_menu_' + idx" class="mdl-button mdl-js-button mdl-button--icon">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</button>
|
||||
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
|
||||
[attr.for]="'document_action_menu_' + idx">
|
||||
<li class="mdl-menu__item"
|
||||
[attr.data-automation-id]="action.title"
|
||||
*ngFor="let action of getContentActions('document', 'menu')"
|
||||
(click)="executeContentAction(content, action)">
|
||||
{{action.title}}
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr *ngIf="folder?.list?.entries?.length === 0">
|
||||
<td class="mdl-data-table__cell--non-numeric empty-folder-content"
|
||||
[attr.colspan]="1 + columns?.length">
|
||||
<template *ngIf="emptyFolderTemplate"
|
||||
ngFor [ngForOf]="[folder]"
|
||||
[ngForTemplate]="emptyFolderTemplate">
|
||||
</template>
|
||||
<img *ngIf="!emptyFolderTemplate"
|
||||
[src]="baseComponentPath + '/img/document-list.empty-folder.png'">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
<alfresco-datatable
|
||||
[data]="data"
|
||||
[actions]="contentActions"
|
||||
[multiselect]="multiselect"
|
||||
(showRowContextMenu)="onShowRowContextMenu($event)"
|
||||
(showRowActionsMenu)="onShowRowActionsMenu($event)"
|
||||
(executeRowAction)="onExecuteRowAction($event)"
|
||||
(rowClick)="onRowClick($event)"
|
||||
(rowDblClick)="onRowDblClick($event)">
|
||||
<no-content-template>
|
||||
<template>
|
||||
<img [src]="baseComponentPath + '/img/document-list.empty-folder.png'">
|
||||
</template>
|
||||
</no-content-template>
|
||||
</alfresco-datatable>
|
||||
|
@ -15,35 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
it,
|
||||
describe,
|
||||
expect,
|
||||
beforeEach
|
||||
} from '@angular/core/testing';
|
||||
import { it, describe, expect, beforeEach } from '@angular/core/testing';
|
||||
import { NgZone } from '@angular/core';
|
||||
import { DataColumn } from 'ng2-alfresco-datatable';
|
||||
import { DocumentList } from './document-list';
|
||||
import { ContentColumnModel } from '../models/content-column.model';
|
||||
import { AlfrescoServiceMock } from '../assets/alfresco.service.mock';
|
||||
import { DocumentListServiceMock } from './../assets/document-list.service.mock';
|
||||
import { ContentActionModel } from '../models/content-action.model';
|
||||
import {
|
||||
PageNode,
|
||||
FileNode,
|
||||
FolderNode
|
||||
} from '../assets/document-library.model.mock';
|
||||
import { ColumnSortingModel } from '../models/column-sorting.model';
|
||||
import { FileNode, FolderNode } from '../assets/document-library.model.mock';
|
||||
import { MinimalNodeEntity } from '../models/document-library.model';
|
||||
|
||||
describe('DocumentList', () => {
|
||||
|
||||
let alfrescoServiceMock: AlfrescoServiceMock;
|
||||
let documentListService: DocumentListServiceMock;
|
||||
let documentList: DocumentList;
|
||||
let eventMock: any;
|
||||
let componentHandler;
|
||||
|
||||
beforeEach(() => {
|
||||
alfrescoServiceMock = new AlfrescoServiceMock();
|
||||
documentListService = new DocumentListServiceMock();
|
||||
let zone = new NgZone(false);
|
||||
documentList = new DocumentList(alfrescoServiceMock, zone);
|
||||
documentList = new DocumentList(documentListService, zone);
|
||||
|
||||
eventMock = {
|
||||
preventDefault: function () {
|
||||
@ -63,56 +54,67 @@ describe('DocumentList', () => {
|
||||
documentList.ngAfterContentInit();
|
||||
|
||||
expect(documentList.setupDefaultColumns).toHaveBeenCalled();
|
||||
expect(documentList.columns.length).not.toBe(0);
|
||||
expect(documentList.data.getColumns().length).not.toBe(0);
|
||||
});
|
||||
|
||||
it('should use custom columns instead of default ones', () => {
|
||||
let column: ContentColumnModel = {
|
||||
let column = <DataColumn> {
|
||||
title: 'title',
|
||||
source: 'source',
|
||||
key: 'source',
|
||||
cssClass: 'css',
|
||||
srTitle: '',
|
||||
type: 'text',
|
||||
format: ''
|
||||
};
|
||||
documentList.columns.push(column);
|
||||
|
||||
let columns = documentList.data.getColumns();
|
||||
columns.push(column);
|
||||
|
||||
documentList.ngAfterContentInit();
|
||||
expect(documentList.columns.length).toBe(1);
|
||||
expect(documentList.columns[0]).toBe(column);
|
||||
expect(columns.length).toBe(1);
|
||||
expect(columns[0]).toBe(column);
|
||||
});
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should fetch folder', () => {
|
||||
let folder = {
|
||||
'nodeRef': 'workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28'
|
||||
};
|
||||
alfrescoServiceMock.folderToReturn = folder;
|
||||
documentListService.folderToReturn = folder;
|
||||
documentList.ngOnInit();
|
||||
|
||||
expect(documentList.folder).toBe(folder);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should return thumbnail url for a file when thumbnails turned on', () => {
|
||||
let url = 'URL';
|
||||
spyOn(alfrescoServiceMock, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
|
||||
let node = new FileNode();
|
||||
documentList.thumbnails = true;
|
||||
let result = documentList.getThumbnailUrl(node);
|
||||
|
||||
expect(result).toBe(url);
|
||||
expect(alfrescoServiceMock.getDocumentThumbnailUrl).toHaveBeenCalled();
|
||||
expect(documentListService.getDocumentThumbnailUrl).toHaveBeenCalled();
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should return a null thumbnail url for a null item', () => {
|
||||
let url = 'URL';
|
||||
spyOn(alfrescoServiceMock, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
|
||||
let result = documentList.getThumbnailUrl(null);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(alfrescoServiceMock.getDocumentThumbnailUrl).not.toHaveBeenCalled();
|
||||
expect(documentListService.getDocumentThumbnailUrl).not.toHaveBeenCalled();
|
||||
});
|
||||
*/
|
||||
|
||||
it('should execute action with node', () => {
|
||||
let node = new FileNode();
|
||||
@ -139,100 +141,54 @@ describe('DocumentList', () => {
|
||||
expect(action.handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should give no content actions for empty target', () => {
|
||||
let actions = documentList.getContentActions(null, 'button');
|
||||
it('should not give node actions for empty target', () => {
|
||||
let actions = documentList.getNodeActions(null);
|
||||
expect(actions.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should give no content actions for empty type', () => {
|
||||
let actions = documentList.getContentActions('folder', null);
|
||||
expect(actions.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should filter content actions for various types and targets', () => {
|
||||
let folderButton = new ContentActionModel();
|
||||
folderButton.target = 'folder';
|
||||
folderButton.type = 'button';
|
||||
|
||||
it('should filter content actions for various targets', () => {
|
||||
let folderMenu = new ContentActionModel();
|
||||
folderMenu.target = 'folder';
|
||||
folderMenu.type = 'menu';
|
||||
|
||||
let documentButton = new ContentActionModel();
|
||||
documentButton.target = 'document';
|
||||
documentButton.type = 'button';
|
||||
|
||||
let documentMenu = new ContentActionModel();
|
||||
documentMenu.target = 'document';
|
||||
documentMenu.type = 'menu';
|
||||
|
||||
documentList.actions = [
|
||||
folderButton,
|
||||
folderMenu,
|
||||
documentButton,
|
||||
documentMenu
|
||||
];
|
||||
|
||||
let actions = documentList.getContentActions('folder', 'button');
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(folderButton);
|
||||
|
||||
actions = documentList.getContentActions('folder', 'menu');
|
||||
let actions = documentList.getNodeActions(new FolderNode());
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(folderMenu);
|
||||
|
||||
actions = documentList.getContentActions('document', 'button');
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(documentButton);
|
||||
|
||||
actions = documentList.getContentActions('document', 'menu');
|
||||
actions = documentList.getNodeActions(new FileNode());
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(documentMenu);
|
||||
});
|
||||
|
||||
it('should be case insensitive when filtering content actions', () => {
|
||||
let documentButton = new ContentActionModel();
|
||||
documentButton.target = 'document';
|
||||
documentButton.type = 'button';
|
||||
|
||||
documentList.actions = [documentButton];
|
||||
|
||||
let actions = documentList.getContentActions('DoCuMeNt', 'BUTTON');
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(documentButton);
|
||||
});
|
||||
|
||||
it('should find no content actions', () => {
|
||||
let documentButton = new ContentActionModel();
|
||||
documentButton.target = 'document';
|
||||
documentButton.type = 'button';
|
||||
|
||||
documentList.actions = [documentButton];
|
||||
|
||||
let actions = documentList.getContentActions('unknown', 'value');
|
||||
expect(actions.length).toBe(0);
|
||||
let node = new MinimalNodeEntity();
|
||||
expect(documentList.getNodeActions(node)).toEqual([]);
|
||||
|
||||
node = new FileNode();
|
||||
node.entry.isFile = false;
|
||||
node.entry.isFolder = false;
|
||||
expect(documentList.getNodeActions(node)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit itemClick event', (done) => {
|
||||
it('should emit nodeClick event', (done) => {
|
||||
let node = new FileNode();
|
||||
documentList.itemClick.subscribe(e => {
|
||||
documentList.nodeClick.subscribe(e => {
|
||||
expect(e.value).toBe(node);
|
||||
done();
|
||||
});
|
||||
documentList.onItemClick(node);
|
||||
});
|
||||
|
||||
it('should prevent default item single click event', () => {
|
||||
spyOn(eventMock, 'preventDefault').and.stub();
|
||||
|
||||
documentList.onItemClick(null, eventMock);
|
||||
expect(eventMock.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should prevent default item double click event', () => {
|
||||
spyOn(eventMock, 'preventDefault').and.stub();
|
||||
documentList.onItemDblClick(null, eventMock);
|
||||
expect(eventMock.preventDefault).toHaveBeenCalled();
|
||||
documentList.onNodeClick(node);
|
||||
});
|
||||
|
||||
it('should display folder content on click', () => {
|
||||
@ -244,7 +200,7 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.onItemClick(node);
|
||||
documentList.onNodeClick(node);
|
||||
|
||||
expect(documentList.currentFolderPath).toBe(path);
|
||||
});
|
||||
@ -253,7 +209,7 @@ describe('DocumentList', () => {
|
||||
expect(documentList.navigate).toBe(true);
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
|
||||
documentList.onItemClick(null);
|
||||
documentList.onNodeClick(null);
|
||||
expect(documentList.displayFolderContent).not.toHaveBeenCalled();
|
||||
|
||||
});
|
||||
@ -263,7 +219,7 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
|
||||
let node = new FileNode();
|
||||
documentList.onItemClick(node);
|
||||
documentList.onNodeClick(node);
|
||||
|
||||
expect(documentList.displayFolderContent).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -273,7 +229,7 @@ describe('DocumentList', () => {
|
||||
|
||||
let node = new FolderNode('<display name>');
|
||||
documentList.navigate = false;
|
||||
documentList.onItemClick(node);
|
||||
documentList.onNodeClick(node);
|
||||
|
||||
expect(documentList.displayFolderContent).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -282,33 +238,6 @@ describe('DocumentList', () => {
|
||||
expect(documentList.getNodePath(null)).toBe(null);
|
||||
});
|
||||
|
||||
it('should return root object value', () => {
|
||||
let target = {
|
||||
key1: 'value1'
|
||||
};
|
||||
|
||||
expect(documentList.getObjectValue(target, 'key1')).toBe('value1');
|
||||
});
|
||||
|
||||
it('should return no object value when key is missing', () => {
|
||||
let target = {
|
||||
key1: 'value1'
|
||||
};
|
||||
expect(documentList.getObjectValue(target, 'missing')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return nested object value', () => {
|
||||
let target = {
|
||||
key1: {
|
||||
key2: {
|
||||
key3: 'value1'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expect(documentList.getObjectValue(target, 'key1.key2.key3')).toBe('value1');
|
||||
});
|
||||
|
||||
it('should display folder content for new folder path', () => {
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
let newPath = '/some/new/path';
|
||||
@ -334,42 +263,44 @@ describe('DocumentList', () => {
|
||||
});
|
||||
|
||||
it('should emit folder changed event', (done) => {
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
documentList.folderChange.subscribe(e => {
|
||||
done();
|
||||
});
|
||||
documentList.folder = new PageNode();
|
||||
|
||||
documentList.currentFolderPath = '/some/new/path';
|
||||
});
|
||||
|
||||
it('should emit folder changed event with folder details', (done) => {
|
||||
let folder = new PageNode();
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
|
||||
let path = '/path';
|
||||
|
||||
documentList.folderChange.subscribe(e => {
|
||||
expect(e.value).toBe(folder);
|
||||
expect(e.path).toBe(path);
|
||||
done();
|
||||
});
|
||||
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
documentList.currentFolderPath = path;
|
||||
documentList.folder = folder;
|
||||
});
|
||||
|
||||
it('should not emit folder changed event', () => {
|
||||
let folder = new PageNode();
|
||||
it('should emit folder changed event only once', () => {
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
let path = '/new/path';
|
||||
let calls = 0;
|
||||
documentList.folderChange.subscribe(e => {
|
||||
calls++;
|
||||
});
|
||||
|
||||
documentList.folder = folder;
|
||||
documentList.folder = folder;
|
||||
documentList.currentFolderPath = path;
|
||||
documentList.currentFolderPath = path;
|
||||
documentList.currentFolderPath = path;
|
||||
expect(calls).toBe(1);
|
||||
});
|
||||
|
||||
it('should reload on binding changes', () => {
|
||||
spyOn(documentList, 'reload').and.stub();
|
||||
documentList.ngOnChanges(null);
|
||||
documentList.ngOnChanges();
|
||||
expect(documentList.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -396,8 +327,9 @@ describe('DocumentList', () => {
|
||||
});
|
||||
|
||||
it('should subscribe to context action handler', () => {
|
||||
let value = {};
|
||||
spyOn(documentList, 'displayFolderContent').and.stub();
|
||||
spyOn(documentList, 'contextActionCallback').and.stub();
|
||||
let value = {};
|
||||
documentList.ngOnInit();
|
||||
documentList.contextActionHandler.next(value);
|
||||
expect(documentList.contextActionCallback).toHaveBeenCalledWith(value);
|
||||
@ -416,7 +348,7 @@ describe('DocumentList', () => {
|
||||
done();
|
||||
});
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.onItemClick(file, null);
|
||||
documentList.onNodeClick(file);
|
||||
});
|
||||
|
||||
it('should emit file preview event on double click', (done) => {
|
||||
@ -426,7 +358,7 @@ describe('DocumentList', () => {
|
||||
done();
|
||||
});
|
||||
documentList.navigationMode = DocumentList.DOUBLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(file, null);
|
||||
documentList.onNodeDblClick(file);
|
||||
});
|
||||
|
||||
it('should perform folder navigation on single click', () => {
|
||||
@ -434,7 +366,7 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'performNavigation').and.stub();
|
||||
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.onItemClick(folder, null);
|
||||
documentList.onNodeClick(folder);
|
||||
expect(documentList.performNavigation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -443,7 +375,7 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'performNavigation').and.stub();
|
||||
|
||||
documentList.navigationMode = DocumentList.DOUBLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(folder, null);
|
||||
documentList.onNodeDblClick(folder);
|
||||
expect(documentList.performNavigation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -452,7 +384,7 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'performNavigation').and.stub();
|
||||
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(folder, null);
|
||||
documentList.onNodeDblClick(folder);
|
||||
|
||||
expect(documentList.performNavigation).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -463,15 +395,16 @@ describe('DocumentList', () => {
|
||||
|
||||
documentList.navigate = false;
|
||||
documentList.navigationMode = DocumentList.DOUBLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(folder, null);
|
||||
documentList.onNodeDblClick(folder);
|
||||
|
||||
expect(documentList.performNavigation).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should perform navigation for folder node only', () => {
|
||||
spyOn(documentList, 'getNodePath').and.returnValue('/path');
|
||||
|
||||
let folder = new FolderNode();
|
||||
let file = new FileNode();
|
||||
spyOn(documentList, 'getNodePath').and.returnValue('/path');
|
||||
|
||||
expect(documentList.performNavigation(folder)).toBeTruthy();
|
||||
expect(documentList.performNavigation(file)).toBeFalsy();
|
||||
@ -488,7 +421,6 @@ describe('DocumentList', () => {
|
||||
expect(documentList.getNodePath(file)).toBe('/folder1/file.txt');
|
||||
});
|
||||
|
||||
|
||||
it('should require valid node for file preview', () => {
|
||||
let file = new FileNode();
|
||||
file.entry = null;
|
||||
@ -497,11 +429,11 @@ describe('DocumentList', () => {
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.preview.subscribe(val => called = true);
|
||||
|
||||
documentList.onItemClick(file, null);
|
||||
documentList.onNodeClick(file);
|
||||
expect(called).toBeFalsy();
|
||||
|
||||
documentList.navigationMode = DocumentList.DOUBLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(file, null);
|
||||
documentList.onNodeDblClick(file);
|
||||
expect(called).toBeFalsy();
|
||||
});
|
||||
|
||||
@ -511,10 +443,10 @@ describe('DocumentList', () => {
|
||||
spyOn(documentList, 'performNavigation').and.stub();
|
||||
|
||||
documentList.navigationMode = DocumentList.SINGLE_CLICK_NAVIGATION;
|
||||
documentList.onItemClick(folder, null);
|
||||
documentList.onNodeClick(folder);
|
||||
|
||||
documentList.navigationMode = DocumentList.DOUBLE_CLICK_NAVIGATION;
|
||||
documentList.onItemDblClick(folder, null);
|
||||
documentList.onNodeDblClick(folder);
|
||||
|
||||
expect(documentList.performNavigation).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -525,6 +457,8 @@ describe('DocumentList', () => {
|
||||
expect(documentList.displayFolderContent).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should generate thumbnail for unknown content', () => {
|
||||
documentList.baseComponentPath = '/root';
|
||||
let node = new FileNode();
|
||||
@ -532,13 +466,19 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(documentList.getThumbnailUrl(node)).toBe('/root/img/ft_ic_miscellaneous.svg');
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should generate folder icon path', () => {
|
||||
documentList.baseComponentPath = '/root';
|
||||
let folder = new FolderNode();
|
||||
expect(documentList.getThumbnailUrl(folder)).toBe('/root/img/ft_ic_folder.svg');
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should generate file icon path based on mime type', () => {
|
||||
let fileName = 'custom-icon.svg';
|
||||
spyOn(alfrescoServiceMock, 'getMimeTypeIcon').and.returnValue(fileName);
|
||||
@ -549,9 +489,12 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(documentList.getThumbnailUrl(file)).toBe(`/root/img/${fileName}`);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should fallback to default icon for missing mime type', () => {
|
||||
spyOn(alfrescoServiceMock, 'getMimeTypeIcon').and.returnValue(null);
|
||||
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(null);
|
||||
documentList.baseComponentPath = '/root';
|
||||
|
||||
let file = new FileNode();
|
||||
@ -559,9 +502,12 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(documentList.getThumbnailUrl(file)).toBe('/root/img/ft_ic_miscellaneous.svg');
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should fallback to default icon for unknown mime type', () => {
|
||||
spyOn(alfrescoServiceMock, 'getMimeTypeIcon').and.returnValue(null);
|
||||
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(null);
|
||||
documentList.baseComponentPath = '/root';
|
||||
|
||||
let file = new FileNode();
|
||||
@ -569,17 +515,23 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(documentList.getThumbnailUrl(file)).toBe('/root/img/ft_ic_miscellaneous.svg');
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should resolve thumbnail url for a file', () => {
|
||||
let url = 'http://<some url>';
|
||||
spyOn(alfrescoServiceMock, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(url);
|
||||
|
||||
documentList.thumbnails = true;
|
||||
|
||||
let file = new FileNode();
|
||||
expect(documentList.getThumbnailUrl(file)).toBe(url);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should return no thumbnail url with missing service', () => {
|
||||
let list = new DocumentList(null, null);
|
||||
list.thumbnails = true;
|
||||
@ -587,76 +539,10 @@ describe('DocumentList', () => {
|
||||
let file = new FileNode();
|
||||
expect(list.getThumbnailUrl(file)).toBeNull();
|
||||
});
|
||||
*/
|
||||
|
||||
it('should sort on column header click', () => {
|
||||
let col = new ContentColumnModel();
|
||||
col.source = 'id';
|
||||
|
||||
spyOn(documentList, 'sort').and.callThrough();
|
||||
|
||||
documentList.onColumnHeaderClick(col);
|
||||
|
||||
expect(documentList.sorting).toEqual(
|
||||
jasmine.objectContaining({
|
||||
key: 'id',
|
||||
direction: 'asc'
|
||||
})
|
||||
);
|
||||
expect(documentList.sort).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should invert sorting on column header click', () => {
|
||||
let col = new ContentColumnModel();
|
||||
col.source = 'id';
|
||||
|
||||
spyOn(documentList, 'sort').and.callThrough();
|
||||
|
||||
documentList.sorting = <ColumnSortingModel> { key: 'id', direction: 'asc' };
|
||||
documentList.onColumnHeaderClick(col);
|
||||
|
||||
expect(documentList.sorting).toEqual(
|
||||
jasmine.objectContaining({
|
||||
key: 'id',
|
||||
direction: 'desc'
|
||||
})
|
||||
);
|
||||
|
||||
documentList.onColumnHeaderClick(col);
|
||||
expect(documentList.sorting).toEqual(
|
||||
jasmine.objectContaining({
|
||||
key: 'id',
|
||||
direction: 'asc'
|
||||
})
|
||||
);
|
||||
|
||||
expect(documentList.sort).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should use ascending direction for different column header click', () => {
|
||||
let col = new ContentColumnModel();
|
||||
col.source = 'id';
|
||||
|
||||
spyOn(documentList, 'sort').and.callThrough();
|
||||
|
||||
documentList.sorting = <ColumnSortingModel> { key: 'col1', direction: 'desc' };
|
||||
documentList.onColumnHeaderClick(col);
|
||||
|
||||
expect(documentList.sorting).toEqual(
|
||||
jasmine.objectContaining({
|
||||
key: 'id',
|
||||
direction: 'asc'
|
||||
})
|
||||
);
|
||||
|
||||
expect(documentList.sort).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not sort by column header when instance is missing', () => {
|
||||
spyOn(documentList, 'sort').and.callThrough();
|
||||
documentList.onColumnHeaderClick(null);
|
||||
expect(documentList.sort).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// TODO: move to DataTable
|
||||
/*
|
||||
it('should convert cell value to formatted date', () => {
|
||||
|
||||
let rawValue = new Date(2015, 6, 15, 21, 43, 11).toString(); // Wed Jul 15 2015 21:43:11 GMT+0100 (BST);
|
||||
@ -673,7 +559,10 @@ describe('DocumentList', () => {
|
||||
let value = documentList.getCellValue(file, col);
|
||||
expect(value).toBe(dateValue);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to DataTable
|
||||
/*
|
||||
it('should return date value as string', () => {
|
||||
let rawValue = new Date(2015, 6, 15, 21, 43, 11).toString(); // Wed Jul 15 2015 21:43:11 GMT+0100 (BST);
|
||||
|
||||
@ -687,7 +576,10 @@ describe('DocumentList', () => {
|
||||
let value = documentList.getCellValue(file, col);
|
||||
expect(value).toBe(rawValue);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should convert cell value to thumbnail', () => {
|
||||
let url = 'http://<address>';
|
||||
spyOn(documentList, 'getThumbnailUrl').and.returnValue(url);
|
||||
@ -701,14 +593,15 @@ describe('DocumentList', () => {
|
||||
let value = documentList.getCellValue(file, col);
|
||||
expect(value).toBe(url);
|
||||
});
|
||||
*/
|
||||
|
||||
it('should require path to display folder content', () => {
|
||||
spyOn(alfrescoServiceMock, 'getFolder').and.callThrough();
|
||||
spyOn(documentListService, 'getFolder').and.callThrough();
|
||||
|
||||
documentList.displayFolderContent(null);
|
||||
documentList.displayFolderContent('');
|
||||
|
||||
expect(alfrescoServiceMock.getFolder).not.toHaveBeenCalled();
|
||||
expect(documentListService.getFolder).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require node to resolve context menu actions', () => {
|
||||
@ -722,12 +615,12 @@ describe('DocumentList', () => {
|
||||
|
||||
it('should fetch context menu actions for a file node', () => {
|
||||
let actionModel = {};
|
||||
spyOn(documentList, 'getContentActions').and.returnValue([actionModel]);
|
||||
spyOn(documentList, 'getNodeActions').and.returnValue([actionModel]);
|
||||
|
||||
let file = new FileNode();
|
||||
let actions = documentList.getContextActions(file);
|
||||
|
||||
expect(documentList.getContentActions).toHaveBeenCalledWith('document', 'menu');
|
||||
expect(documentList.getNodeActions).toHaveBeenCalledWith(file);
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0].model).toBe(actionModel);
|
||||
expect(actions[0].node).toBe(file);
|
||||
@ -736,12 +629,12 @@ describe('DocumentList', () => {
|
||||
|
||||
it('should fetch context menu actions for a folder node', () => {
|
||||
let actionModel = {};
|
||||
spyOn(documentList, 'getContentActions').and.returnValue([actionModel]);
|
||||
spyOn(documentList, 'getNodeActions').and.returnValue([actionModel]);
|
||||
|
||||
let folder = new FolderNode();
|
||||
let actions = documentList.getContextActions(folder);
|
||||
|
||||
expect(documentList.getContentActions).toHaveBeenCalledWith('folder', 'menu');
|
||||
expect(documentList.getNodeActions).toHaveBeenCalledWith(folder);
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0].model).toBe(actionModel);
|
||||
expect(actions[0].node).toBe(folder);
|
||||
@ -749,51 +642,39 @@ describe('DocumentList', () => {
|
||||
});
|
||||
|
||||
it('should fetch no context menu actions for unknown type', () => {
|
||||
spyOn(documentList, 'getContentActions').and.stub();
|
||||
spyOn(documentList, 'getNodeActions').and.stub();
|
||||
|
||||
let node = new FileNode();
|
||||
node.entry.isFile = false;
|
||||
node.entry.isFolder = false;
|
||||
|
||||
let actions = documentList.getContextActions(node);
|
||||
|
||||
expect(documentList.getContentActions).not.toHaveBeenCalled();
|
||||
expect(actions).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null value when no content actions found', () => {
|
||||
spyOn(documentList, 'getContentActions').and.returnValue([]);
|
||||
spyOn(documentList, 'getNodeActions').and.returnValue([]);
|
||||
|
||||
let file = new FileNode();
|
||||
let actions = documentList.getContextActions(file);
|
||||
|
||||
expect(actions).toBeNull();
|
||||
expect(documentList.getContentActions).toHaveBeenCalled();
|
||||
expect(documentList.getNodeActions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
/*
|
||||
it('should update error message when folder content display fails', () => {
|
||||
let error = 'My Error';
|
||||
alfrescoServiceMock.getFolderReject = true;
|
||||
alfrescoServiceMock.getFolderRejectError = error;
|
||||
documentListService.getFolderReject = true;
|
||||
documentListService.getFolderRejectError = error;
|
||||
|
||||
documentList.displayFolderContent('/some/path');
|
||||
expect(documentList.errorMessage).toBe(error);
|
||||
});
|
||||
*/
|
||||
|
||||
it('should get object value via property path', () => {
|
||||
let obj = {
|
||||
name: {
|
||||
firstName: '<name>'
|
||||
}
|
||||
};
|
||||
|
||||
expect(documentList.getObjectValue(obj, 'name.firstName')).toBe('<name>');
|
||||
});
|
||||
|
||||
it('should not get object value via invalid path', () => {
|
||||
expect(documentList.getObjectValue({}, 'some.missing.path')).toBeUndefined();
|
||||
});
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should log error when having date conversion issues', () => {
|
||||
|
||||
let value = '<wrong-date>';
|
||||
@ -813,7 +694,10 @@ describe('DocumentList', () => {
|
||||
expect(result).toBe(value);
|
||||
expect(console.error).toHaveBeenCalledWith(`DocumentList: error parsing date ${value} to format ${col.format}`);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should convert thumbnail if column source defined', () => {
|
||||
let file = new FileNode();
|
||||
let col = new ContentColumnModel({
|
||||
@ -823,6 +707,7 @@ describe('DocumentList', () => {
|
||||
|
||||
expect(documentList.getCellValue(file, col)).toBe(file.entry.name);
|
||||
});
|
||||
*/
|
||||
|
||||
it('should require current folder path to reload', () => {
|
||||
|
||||
@ -839,6 +724,8 @@ describe('DocumentList', () => {
|
||||
expect(documentList.displayFolderContent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should not sort empty page', () => {
|
||||
let page = new PageNode();
|
||||
spyOn(page.list.entries, 'sort').and.stub();
|
||||
@ -846,7 +733,10 @@ describe('DocumentList', () => {
|
||||
documentList.sort(page, null);
|
||||
expect(page.list.entries.sort).not.toHaveBeenCalled();
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should put folders to top on sort', () => {
|
||||
let folder = new FolderNode();
|
||||
let file1 = new FileNode('file1');
|
||||
@ -873,7 +763,10 @@ describe('DocumentList', () => {
|
||||
expect(page.list.entries[1]).toBe(file2);
|
||||
expect(page.list.entries[2]).toBe(file1);
|
||||
});
|
||||
*/
|
||||
|
||||
// TODO: move to data adapter
|
||||
/*
|
||||
it('should sort by dates up to ms', () => {
|
||||
let file1 = new FileNode();
|
||||
file1.entry['dateProp'] = new Date(2016, 6, 30, 13, 14, 1);
|
||||
@ -901,5 +794,6 @@ describe('DocumentList', () => {
|
||||
expect(page.list.entries[0]).toBe(file1);
|
||||
expect(page.list.entries[1]).toBe(file2);
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
||||
|
@ -22,19 +22,27 @@ import {
|
||||
Output,
|
||||
EventEmitter,
|
||||
AfterContentInit,
|
||||
AfterViewInit,
|
||||
AfterViewChecked,
|
||||
OnChanges,
|
||||
TemplateRef,
|
||||
NgZone
|
||||
NgZone,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Subject } from 'rxjs/Rx';
|
||||
import { CONTEXT_MENU_DIRECTIVES } from 'ng2-alfresco-core';
|
||||
import { AlfrescoService } from './../services/alfresco.service';
|
||||
import { MinimalNodeEntity, NodePaging } from './../models/document-library.model';
|
||||
|
||||
import {
|
||||
ALFRESCO_DATATABLE_DIRECTIVES,
|
||||
DataRowEvent,
|
||||
DataTableComponent,
|
||||
ObjectDataColumn
|
||||
} from 'ng2-alfresco-datatable';
|
||||
|
||||
import { DocumentListService } from './../services/document-list.service';
|
||||
import { MinimalNodeEntity } from './../models/document-library.model';
|
||||
import { ContentActionModel } from './../models/content-action.model';
|
||||
import { ContentColumnModel } from './../models/content-column.model';
|
||||
import { ColumnSortingModel } from './../models/column-sorting.model';
|
||||
import { ShareDataTableAdapter, ShareDataRow } from './../data/share-datatable-adapter';
|
||||
|
||||
declare var componentHandler;
|
||||
declare let __moduleName: string;
|
||||
@ -44,13 +52,13 @@ declare let __moduleName: string;
|
||||
selector: 'alfresco-document-list',
|
||||
styleUrls: ['./document-list.css'],
|
||||
templateUrl: './document-list.html',
|
||||
providers: [AlfrescoService],
|
||||
directives: [CONTEXT_MENU_DIRECTIVES],
|
||||
providers: [DocumentListService],
|
||||
directives: [CONTEXT_MENU_DIRECTIVES, ALFRESCO_DATATABLE_DIRECTIVES],
|
||||
host: {
|
||||
'(contextmenu)': 'onShowContextMenu($event)'
|
||||
}
|
||||
})
|
||||
export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit, OnChanges {
|
||||
export class DocumentList implements OnInit, AfterViewInit, AfterViewChecked, AfterContentInit, OnChanges {
|
||||
|
||||
static SINGLE_CLICK_NAVIGATION: string = 'click';
|
||||
static DOUBLE_CLICK_NAVIGATION: string = 'dblclick';
|
||||
@ -62,17 +70,26 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
@Input()
|
||||
navigate: boolean = true;
|
||||
|
||||
@Input('navigation-mode')
|
||||
@Input()
|
||||
navigationMode: string = 'dblclick'; // click|dblclick
|
||||
|
||||
@Input()
|
||||
thumbnails: boolean = false;
|
||||
|
||||
@Output()
|
||||
itemClick: EventEmitter<any> = new EventEmitter();
|
||||
@Input()
|
||||
multiselect: boolean = false;
|
||||
|
||||
@Input()
|
||||
contentActions: boolean = false;
|
||||
|
||||
@Input()
|
||||
contextMenuActions: boolean = false;
|
||||
|
||||
@Output()
|
||||
itemDblClick: EventEmitter<any> = new EventEmitter();
|
||||
nodeClick: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
nodeDblClick: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@Output()
|
||||
folderChange: EventEmitter<any> = new EventEmitter();
|
||||
@ -80,6 +97,9 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
@Output()
|
||||
preview: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@ViewChild(DataTableComponent)
|
||||
dataTable: DataTableComponent;
|
||||
|
||||
private _path = this.DEFAULT_ROOT_FOLDER;
|
||||
|
||||
get currentFolderPath(): string {
|
||||
@ -91,66 +111,36 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
if (value !== this._path) {
|
||||
this._path = value || this.DEFAULT_ROOT_FOLDER;
|
||||
this.displayFolderContent(this._path);
|
||||
}
|
||||
}
|
||||
|
||||
errorMessage;
|
||||
|
||||
actions: ContentActionModel[] = [];
|
||||
columns: ContentColumnModel[] = [];
|
||||
emptyFolderTemplate: TemplateRef<any>;
|
||||
|
||||
private _folder: NodePaging;
|
||||
|
||||
get folder(): NodePaging {
|
||||
return this._folder;
|
||||
}
|
||||
|
||||
set folder(value: NodePaging) {
|
||||
let isChanged = this._folder !== value;
|
||||
this._folder = value;
|
||||
if (isChanged) {
|
||||
this.folderChange.emit({
|
||||
value: value,
|
||||
path: this.currentFolderPath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sorting: ColumnSortingModel = {
|
||||
key: 'name',
|
||||
direction: 'asc'
|
||||
};
|
||||
|
||||
errorMessage;
|
||||
actions: ContentActionModel[] = [];
|
||||
emptyFolderTemplate: TemplateRef<any>;
|
||||
contextActionHandler: Subject<any> = new Subject();
|
||||
data: ShareDataTableAdapter;
|
||||
|
||||
constructor(
|
||||
private alfrescoService: AlfrescoService,
|
||||
private ngZone: NgZone) {}
|
||||
private documentListService: DocumentListService,
|
||||
private ngZone: NgZone) {
|
||||
|
||||
this.data = new ShareDataTableAdapter(this.documentListService, this.baseComponentPath, []);
|
||||
}
|
||||
|
||||
getContextActions(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
let targetType;
|
||||
|
||||
if (node.entry.isFolder) {
|
||||
targetType = 'folder';
|
||||
}
|
||||
|
||||
if (node.entry.isFile) {
|
||||
targetType = 'document';
|
||||
}
|
||||
|
||||
if (targetType) {
|
||||
let actions = this.getContentActions(targetType, 'menu');
|
||||
if (actions && actions.length > 0) {
|
||||
return actions.map(a => {
|
||||
return {
|
||||
model: a,
|
||||
node: node,
|
||||
subject: this.contextActionHandler
|
||||
};
|
||||
});
|
||||
}
|
||||
let actions = this.getNodeActions(node);
|
||||
if (actions && actions.length > 0) {
|
||||
return actions.map(a => {
|
||||
return {
|
||||
model: a,
|
||||
node: node,
|
||||
subject: this.contextActionHandler
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -163,20 +153,31 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.data.thumbnails = this.thumbnails;
|
||||
this.displayFolderContent(this.currentFolderPath);
|
||||
this.contextActionHandler.subscribe(val => this.contextActionCallback(val));
|
||||
}
|
||||
|
||||
ngOnChanges(change) {
|
||||
ngOnChanges() {
|
||||
this.reload();
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
if (!this.columns || this.columns.length === 0) {
|
||||
let columns = this.data.getColumns();
|
||||
if (!columns || columns.length === 0) {
|
||||
this.setupDefaultColumns();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
if (this.dataTable) {
|
||||
if (this.emptyFolderTemplate) {
|
||||
this.dataTable.noContentTemplate = this.emptyFolderTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
// workaround for MDL issues with dynamic components
|
||||
if (componentHandler) {
|
||||
@ -185,79 +186,31 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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): ContentActionModel[] {
|
||||
if (target && type) {
|
||||
getNodeActions(node: MinimalNodeEntity): ContentActionModel[] {
|
||||
let target = null;
|
||||
|
||||
let ltarget = target.toLowerCase();
|
||||
let ltype = type.toLowerCase();
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
target = 'document';
|
||||
}
|
||||
|
||||
return this.actions.filter(entry => {
|
||||
return entry.target.toLowerCase() === ltarget &&
|
||||
entry.type.toLowerCase() === ltype;
|
||||
});
|
||||
if (node.entry.isFolder) {
|
||||
target = 'folder';
|
||||
}
|
||||
|
||||
if (target) {
|
||||
|
||||
let ltarget = target.toLowerCase();
|
||||
|
||||
return this.actions.filter(entry => {
|
||||
return entry.target.toLowerCase() === ltarget;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when list row is clicked.
|
||||
* @param item Underlying node item
|
||||
* @param e DOM event (optional)
|
||||
*/
|
||||
onItemClick(item: MinimalNodeEntity, e?: Event) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.itemClick.emit({
|
||||
value: item
|
||||
});
|
||||
|
||||
if (this.navigate && this.navigationMode === DocumentList.SINGLE_CLICK_NAVIGATION) {
|
||||
if (item && item.entry) {
|
||||
if (item.entry.isFile) {
|
||||
this.preview.emit({
|
||||
value: item
|
||||
});
|
||||
}
|
||||
|
||||
if (item.entry.isFolder) {
|
||||
this.performNavigation(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onItemDblClick(item: MinimalNodeEntity, e?: Event) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.itemDblClick.emit({
|
||||
value: item
|
||||
});
|
||||
|
||||
if (this.navigate && this.navigationMode === DocumentList.DOUBLE_CLICK_NAVIGATION) {
|
||||
if (item && item.entry) {
|
||||
if (item.entry.isFile) {
|
||||
this.preview.emit({
|
||||
value: item
|
||||
});
|
||||
}
|
||||
|
||||
if (item.entry.isFolder) {
|
||||
this.performNavigation(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onShowContextMenu(e?: Event) {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
@ -272,41 +225,6 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets thumbnail URL for the given node.
|
||||
* @param node Node to get URL for.
|
||||
* @returns {string} URL address.
|
||||
*/
|
||||
getThumbnailUrl(node: MinimalNodeEntity): string {
|
||||
if (node && node.entry) {
|
||||
let entry = node.entry;
|
||||
|
||||
if (entry.isFolder) {
|
||||
return `${this.baseComponentPath}/img/ft_ic_folder.svg`;
|
||||
}
|
||||
|
||||
if (entry.isFile) {
|
||||
if (this.thumbnails) {
|
||||
if (this.alfrescoService) {
|
||||
return this.alfrescoService.getDocumentThumbnailUrl(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry.content && entry.content.mimeType) {
|
||||
let icon = this.alfrescoService.getMimeTypeIcon(entry.content.mimeType);
|
||||
if (icon) {
|
||||
return `${this.baseComponentPath}/img/${icon}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `${this.baseComponentPath}/img/ft_ic_miscellaneous.svg`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when executing content action for a document or folder.
|
||||
* @param node Node to be the context of the execution.
|
||||
@ -319,14 +237,7 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
}
|
||||
|
||||
displayFolderContent(path: string) {
|
||||
if (path) {
|
||||
this.alfrescoService
|
||||
.getFolder(path)
|
||||
.subscribe(
|
||||
folder => this.folder = this.sort(folder, this.sorting),
|
||||
error => this.errorMessage = <any>error
|
||||
);
|
||||
}
|
||||
this.data.loadPath(path);
|
||||
}
|
||||
|
||||
reload() {
|
||||
@ -350,122 +261,109 @@ export class DocumentList implements OnInit, AfterViewChecked, AfterContentInit,
|
||||
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;
|
||||
}
|
||||
|
||||
getCellValue(row: MinimalNodeEntity, col: ContentColumnModel): any {
|
||||
let value = this.getObjectValueRaw(row.entry, col.source);
|
||||
|
||||
if (col.type === 'date') {
|
||||
let datePipe = new DatePipe();
|
||||
try {
|
||||
return datePipe.transform(value, col.format);
|
||||
} catch (err) {
|
||||
console.error(`DocumentList: error parsing date ${value} to format ${col.format}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (col.type === 'image') {
|
||||
|
||||
if (col.source === '$thumbnail') {
|
||||
return this.getThumbnailUrl(row);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a set of predefined columns.
|
||||
*/
|
||||
setupDefaultColumns(): void {
|
||||
let thumbnailCol = new ContentColumnModel();
|
||||
thumbnailCol.source = '$thumbnail';
|
||||
thumbnailCol.type = 'image';
|
||||
let colThumbnail = new ObjectDataColumn({
|
||||
type: 'image',
|
||||
key: '$thumbnail',
|
||||
title: '',
|
||||
srTitle: 'Thumbnail'
|
||||
});
|
||||
|
||||
let nameCol = new ContentColumnModel();
|
||||
nameCol.title = 'Name';
|
||||
nameCol.source = 'name';
|
||||
nameCol.cssClass = 'full-width name-column';
|
||||
let colName = new ObjectDataColumn({
|
||||
type: 'text',
|
||||
key: 'name',
|
||||
title: 'Name',
|
||||
cssClass: 'full-width',
|
||||
sortable: true
|
||||
});
|
||||
|
||||
this.columns = [
|
||||
thumbnailCol,
|
||||
nameCol
|
||||
];
|
||||
this.data.setColumns([colThumbnail, colName]);
|
||||
}
|
||||
|
||||
onColumnHeaderClick(column: ContentColumnModel) {
|
||||
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 a.entry.isFolder ? -1 : 1;
|
||||
}
|
||||
|
||||
let left = this.getObjectValueRaw(a.entry, options.key).toString();
|
||||
let right = this.getObjectValueRaw(b.entry, options.key).toString();
|
||||
|
||||
return options.direction === 'asc'
|
||||
? left.localeCompare(right)
|
||||
: right.localeCompare(left);
|
||||
onPreviewFile(node: MinimalNodeEntity) {
|
||||
if (node) {
|
||||
this.preview.emit({
|
||||
value: node
|
||||
});
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private getObjectValueRaw(target: any, key: string) {
|
||||
let val = this.getObjectValue(target, key);
|
||||
onNodeClick(node: MinimalNodeEntity) {
|
||||
this.nodeClick.emit({
|
||||
value: node
|
||||
});
|
||||
|
||||
if (val instanceof Date) {
|
||||
val = val.valueOf();
|
||||
if (this.navigate && this.navigationMode === DocumentList.SINGLE_CLICK_NAVIGATION) {
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
this.onPreviewFile(node);
|
||||
}
|
||||
|
||||
if (node.entry.isFolder) {
|
||||
this.performNavigation(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private hasEntries(node: NodePaging): boolean {
|
||||
return (node && node.list && node.list.entries && node.list.entries.length > 0);
|
||||
onRowClick(event: DataRowEvent) {
|
||||
let item = (<ShareDataRow> event.value).node;
|
||||
this.onNodeClick(item);
|
||||
}
|
||||
|
||||
private isSortableColumn(column: ContentColumnModel) {
|
||||
return column && column.source && !column.source.startsWith('$');
|
||||
onNodeDblClick(node: MinimalNodeEntity) {
|
||||
this.nodeDblClick.emit({
|
||||
value: node
|
||||
});
|
||||
|
||||
if (this.navigate && this.navigationMode === DocumentList.DOUBLE_CLICK_NAVIGATION) {
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
this.onPreviewFile(node);
|
||||
}
|
||||
|
||||
if (node.entry.isFolder) {
|
||||
this.performNavigation(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRowDblClick(event?: DataRowEvent) {
|
||||
let item = (<ShareDataRow> event.value).node;
|
||||
this.onNodeDblClick(item);
|
||||
}
|
||||
|
||||
onShowRowContextMenu(event) {
|
||||
if (this.contextMenuActions) {
|
||||
let args = event.args;
|
||||
let node = (<ShareDataRow> args.row).node;
|
||||
if (node) {
|
||||
args.actions = this.getContextActions(node) || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onShowRowActionsMenu(event) {
|
||||
if (this.contentActions) {
|
||||
let args = event.args;
|
||||
let node = (<ShareDataRow> args.row).node;
|
||||
if (node) {
|
||||
args.actions = this.getNodeActions(node) || [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExecuteRowAction(event) {
|
||||
if (this.contentActions) {
|
||||
let args = event.args;
|
||||
let node = (<ShareDataRow> args.row).node;
|
||||
let action = (<ContentActionModel> args.action);
|
||||
this.executeContentAction(node, action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,240 @@
|
||||
/*!
|
||||
* @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 { DatePipe } from '@angular/common';
|
||||
import {
|
||||
DataTableAdapter,
|
||||
DataRow, DataColumn, DataSorting
|
||||
} from 'ng2-alfresco-datatable';
|
||||
|
||||
import { NodePaging, MinimalNodeEntity } from './../models/document-library.model';
|
||||
import { DocumentListService } from './../services/document-list.service';
|
||||
|
||||
export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
|
||||
private sorting: DataSorting;
|
||||
private rows: DataRow[];
|
||||
private columns: DataColumn[];
|
||||
|
||||
thumbnails: boolean = false;
|
||||
|
||||
constructor(private documentListService: DocumentListService,
|
||||
private basePath: string,
|
||||
schema: DataColumn[]) {
|
||||
this.rows = [];
|
||||
this.columns = schema || [];
|
||||
}
|
||||
|
||||
getRows(): Array<DataRow> {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
setRows(rows: Array<DataRow>) {
|
||||
this.rows = rows || [];
|
||||
this.sort();
|
||||
}
|
||||
|
||||
getColumns(): Array<DataColumn> {
|
||||
return this.columns;
|
||||
}
|
||||
|
||||
setColumns(columns: Array<DataColumn>) {
|
||||
this.columns = columns || [];
|
||||
}
|
||||
|
||||
getValue(row: DataRow, col: DataColumn): any {
|
||||
if (!row) {
|
||||
throw new Error('Row not found');
|
||||
}
|
||||
if (!col) {
|
||||
throw new Error('Column not found');
|
||||
}
|
||||
let value = row.getValue(col.key);
|
||||
|
||||
if (col.type === 'date') {
|
||||
let datePipe = new DatePipe();
|
||||
let format = col.format || 'medium';
|
||||
try {
|
||||
return datePipe.transform(value, format);
|
||||
} catch (err) {
|
||||
console.error(`DocumentList: error parsing date ${value} to format ${format}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (col.type === 'image') {
|
||||
|
||||
if (col.key === '$thumbnail') {
|
||||
let node = (<ShareDataRow> row).node;
|
||||
|
||||
if (node.entry.isFolder) {
|
||||
return `${this.basePath}/img/ft_ic_folder.svg`;
|
||||
}
|
||||
|
||||
if (node.entry.isFile) {
|
||||
|
||||
if (this.thumbnails) {
|
||||
if (this.documentListService) {
|
||||
return this.documentListService.getDocumentThumbnailUrl(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node.entry.content && node.entry.content.mimeType) {
|
||||
let mimeType = node.entry.content.mimeType;
|
||||
if (mimeType) {
|
||||
let icon = this.documentListService.getMimeTypeIcon(mimeType);
|
||||
if (icon) {
|
||||
return `${this.basePath}/img/${icon}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `${this.basePath}/img/ft_ic_miscellaneous.svg`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
getSorting(): DataSorting {
|
||||
return this.sorting;
|
||||
}
|
||||
|
||||
setSorting(sorting: DataSorting): void {
|
||||
this.sorting = sorting;
|
||||
|
||||
if (sorting && sorting.key) {
|
||||
this.rows.sort((a: ShareDataRow, b: ShareDataRow) => {
|
||||
if (a.node.entry.isFolder !== b.node.entry.isFolder) {
|
||||
return a.node.entry.isFolder ? -1 : 1;
|
||||
}
|
||||
|
||||
let left = a.getValue(sorting.key);
|
||||
if (left) {
|
||||
left = (left instanceof Date) ? left.valueOf().toString() : left.toString();
|
||||
} else {
|
||||
left = '';
|
||||
}
|
||||
|
||||
let right = b.getValue(sorting.key);
|
||||
if (right) {
|
||||
right = (right instanceof Date) ? right.valueOf().toString() : right.toString();
|
||||
} else {
|
||||
right = '';
|
||||
}
|
||||
|
||||
return sorting.direction === 'asc'
|
||||
? left.localeCompare(right)
|
||||
: right.localeCompare(left);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sort(key?: string, direction?: string): void {
|
||||
let sorting = this.sorting || new DataSorting();
|
||||
if (key) {
|
||||
sorting.key = key;
|
||||
sorting.direction = direction || 'asc';
|
||||
}
|
||||
this.setSorting(sorting);
|
||||
}
|
||||
|
||||
loadPath(path: string) {
|
||||
if (path && this.documentListService) {
|
||||
this.documentListService
|
||||
.getFolder(path)
|
||||
.subscribe(val => {
|
||||
let page = <NodePaging>val;
|
||||
let rows = [];
|
||||
|
||||
if (page && page.list) {
|
||||
let data = page.list.entries;
|
||||
if (data && data.length > 0) {
|
||||
rows = data.map(item => new ShareDataRow(item));
|
||||
// Sort by first sortable or just first column
|
||||
let sortable = this.columns.filter(c => c.sortable);
|
||||
if (sortable.length > 0) {
|
||||
this.sort(sortable[0].key, 'asc');
|
||||
} else {
|
||||
this.sort(this.columns[0].key, 'asc');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.rows = rows;
|
||||
},
|
||||
error => console.log(error));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ShareDataRow implements DataRow {
|
||||
isSelected: boolean = false;
|
||||
|
||||
get node(): MinimalNodeEntity {
|
||||
return this.obj;
|
||||
}
|
||||
|
||||
constructor(private obj: MinimalNodeEntity) {
|
||||
if (!obj) {
|
||||
throw new Error('Object source not found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
getValue(key: string): any {
|
||||
return this.getObjectValue(this.obj.entry, key);
|
||||
}
|
||||
|
||||
hasValue(key: string): boolean {
|
||||
return this.getValue(key) ? true : false;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*!
|
||||
* @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 class ColumnSortingModel {
|
||||
|
||||
static DEFAULT_DIRECTION: string = 'asc';
|
||||
|
||||
key: string;
|
||||
direction: string = ColumnSortingModel.DEFAULT_DIRECTION;
|
||||
|
||||
constructor(opts?: any) {
|
||||
if (opts) {
|
||||
this.key = opts.key;
|
||||
this.direction = opts.direction || ColumnSortingModel.DEFAULT_DIRECTION;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,6 @@ export class ContentActionModel {
|
||||
icon: string;
|
||||
title: string;
|
||||
handler: ContentActionHandler;
|
||||
type: string;
|
||||
target: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
@ -27,7 +26,6 @@ export class ContentActionModel {
|
||||
this.icon = obj.icon;
|
||||
this.title = obj.title;
|
||||
this.handler = obj.handler;
|
||||
this.type = obj.type;
|
||||
this.target = obj.target;
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*!
|
||||
* @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 class ContentColumnModel {
|
||||
|
||||
static TYPE_TEXT: string = 'text';
|
||||
static TYPE_DATE: string = 'date';
|
||||
static TYPE_IMAGE: string = 'image';
|
||||
// static TYPE_NUMBER: string = 'number';
|
||||
|
||||
title: string;
|
||||
srTitle: string;
|
||||
source: string;
|
||||
cssClass: string;
|
||||
type: string = ContentColumnModel.TYPE_TEXT;
|
||||
format: string = 'medium';
|
||||
|
||||
constructor(obj?: any) {
|
||||
if (obj) {
|
||||
this.title = obj.title;
|
||||
this.srTitle = obj.srTitle;
|
||||
this.source = obj.source;
|
||||
this.cssClass = obj.cssClass;
|
||||
this.type = obj.type || ContentColumnModel.TYPE_TEXT;
|
||||
this.format = obj.format;
|
||||
}
|
||||
}
|
||||
|
||||
static getSupportedTypes(): string[] {
|
||||
return [
|
||||
ContentColumnModel.TYPE_TEXT,
|
||||
ContentColumnModel.TYPE_DATE,
|
||||
ContentColumnModel.TYPE_IMAGE
|
||||
// ContentColumnModel.TYPE_NUMBER
|
||||
];
|
||||
}
|
||||
}
|
@ -24,8 +24,8 @@ import {
|
||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
||||
import { ContentActionHandler } from '../models/content-action.model';
|
||||
import { DocumentActionsService } from './document-actions.service';
|
||||
import { AlfrescoServiceMock } from '../assets/alfresco.service.mock';
|
||||
import { AlfrescoService } from './alfresco.service';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
import { DocumentListService } from './document-list.service';
|
||||
import {
|
||||
FileNode,
|
||||
FolderNode
|
||||
@ -34,13 +34,13 @@ import {
|
||||
describe('DocumentActionsService', () => {
|
||||
|
||||
let service: DocumentActionsService;
|
||||
let alfrescoService: AlfrescoService;
|
||||
let documentListService: DocumentListService;
|
||||
let contentService: AlfrescoContentService;
|
||||
|
||||
beforeEach(() => {
|
||||
alfrescoService = new AlfrescoServiceMock();
|
||||
documentListService = new DocumentListServiceMock();
|
||||
contentService = new AlfrescoContentService(null, null);
|
||||
service = new DocumentActionsService(alfrescoService, contentService);
|
||||
service = new DocumentActionsService(documentListService, contentService);
|
||||
});
|
||||
|
||||
it('should register default download action', () => {
|
||||
@ -147,7 +147,7 @@ describe('DocumentActionsService', () => {
|
||||
});
|
||||
|
||||
it('should require content service for download action', () => {
|
||||
let actionService = new DocumentActionsService(alfrescoService, null);
|
||||
let actionService = new DocumentActionsService(documentListService, null);
|
||||
let file = new FileNode();
|
||||
let result = actionService.getHandler('download')(file);
|
||||
expect(result).toBeFalsy();
|
||||
@ -159,44 +159,44 @@ describe('DocumentActionsService', () => {
|
||||
});
|
||||
|
||||
it('should delete file node', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let file = new FileNode();
|
||||
service.getHandler('delete')(file);
|
||||
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalledWith(file.entry.id);
|
||||
expect(documentListService.deleteNode).toHaveBeenCalledWith(file.entry.id);
|
||||
});
|
||||
|
||||
it('should support deletion only file node', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let folder = new FolderNode();
|
||||
service.getHandler('delete')(folder);
|
||||
expect(alfrescoService.deleteNode).not.toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).not.toHaveBeenCalled();
|
||||
|
||||
let file = new FileNode();
|
||||
service.getHandler('delete')(file);
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require node id to delete', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let file = new FileNode();
|
||||
file.entry.id = null;
|
||||
service.getHandler('delete')(file);
|
||||
|
||||
expect(alfrescoService.deleteNode).not.toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload target upon node deletion', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let target = jasmine.createSpyObj('obj', ['reload']);
|
||||
let file = new FileNode();
|
||||
service.getHandler('delete')(file, target);
|
||||
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).toHaveBeenCalled();
|
||||
expect(target.reload).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -15,9 +15,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ContentActionHandler} from '../models/content-action.model';
|
||||
import {AlfrescoService} from './alfresco.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ContentActionHandler } from '../models/content-action.model';
|
||||
import { DocumentListService } from './document-list.service';
|
||||
import { AlfrescoContentService } from 'ng2-alfresco-core';
|
||||
|
||||
@Injectable()
|
||||
@ -25,7 +25,7 @@ export class DocumentActionsService {
|
||||
private handlers: { [id: string]: ContentActionHandler; } = {};
|
||||
|
||||
constructor(
|
||||
private alfrescoService?: AlfrescoService,
|
||||
private documentListService?: DocumentListService,
|
||||
private contentService?: AlfrescoContentService
|
||||
) {
|
||||
this.setupActionHandlers();
|
||||
@ -49,7 +49,7 @@ export class DocumentActionsService {
|
||||
}
|
||||
|
||||
canExecuteAction(obj: any): boolean {
|
||||
return this.alfrescoService && obj && obj.entry.isFile === true;
|
||||
return this.documentListService && obj && obj.entry.isFile === true;
|
||||
}
|
||||
|
||||
private setupActionHandlers() {
|
||||
@ -86,7 +86,7 @@ export class DocumentActionsService {
|
||||
|
||||
private deleteNode(obj: any, target?: any) {
|
||||
if (this.canExecuteAction(obj) && obj.entry && obj.entry.id) {
|
||||
this.alfrescoService.deleteNode(obj.entry.id).subscribe(() => {
|
||||
this.documentListService.deleteNode(obj.entry.id).subscribe(() => {
|
||||
if (target && typeof target.reload === 'function') {
|
||||
target.reload();
|
||||
}
|
||||
|
@ -27,12 +27,11 @@ import {
|
||||
AlfrescoContentService
|
||||
} from 'ng2-alfresco-core';
|
||||
import { FileNode } from '../assets/document-library.model.mock';
|
||||
import { AlfrescoService } from './alfresco.service';
|
||||
import { DocumentListService } from './document-list.service';
|
||||
|
||||
// TODO: rename to DocumentListService
|
||||
describe('AlfrescoService', () => {
|
||||
describe('DocumentListService', () => {
|
||||
|
||||
let service: AlfrescoService;
|
||||
let service: DocumentListService;
|
||||
let settingsService: AlfrescoSettingsService;
|
||||
let authService: AlfrescoAuthenticationService;
|
||||
let contentService: AlfrescoContentService;
|
||||
@ -42,7 +41,7 @@ describe('AlfrescoService', () => {
|
||||
settingsService = new AlfrescoSettingsService();
|
||||
authService = new AlfrescoAuthenticationService(settingsService);
|
||||
contentService = new AlfrescoContentService(settingsService, authService);
|
||||
service = new AlfrescoService(settingsService, authService, contentService);
|
||||
service = new DocumentListService(settingsService, authService, contentService);
|
||||
});
|
||||
|
||||
it('should require node to get thumbnail url', () => {
|
||||
@ -50,7 +49,7 @@ describe('AlfrescoService', () => {
|
||||
});
|
||||
|
||||
it('should require content service to get thumbnail url', () => {
|
||||
service = new AlfrescoService(settingsService, authService, null);
|
||||
service = new DocumentListService(settingsService, authService, null);
|
||||
let file = new FileNode();
|
||||
expect(service.getDocumentThumbnailUrl(file)).toBeNull();
|
||||
});
|
||||
@ -72,9 +71,9 @@ describe('AlfrescoService', () => {
|
||||
});
|
||||
|
||||
it('should resolve default icon for mime type', () => {
|
||||
expect(service.getMimeTypeIcon(null)).toBe(AlfrescoService.DEFAULT_MIME_TYPE_ICON);
|
||||
expect(service.getMimeTypeIcon('')).toBe(AlfrescoService.DEFAULT_MIME_TYPE_ICON);
|
||||
expect(service.getMimeTypeIcon('missing/type')).toBe(AlfrescoService.DEFAULT_MIME_TYPE_ICON);
|
||||
expect(service.getMimeTypeIcon(null)).toBe(DocumentListService.DEFAULT_MIME_TYPE_ICON);
|
||||
expect(service.getMimeTypeIcon('')).toBe(DocumentListService.DEFAULT_MIME_TYPE_ICON);
|
||||
expect(service.getMimeTypeIcon('missing/type')).toBe(DocumentListService.DEFAULT_MIME_TYPE_ICON);
|
||||
});
|
||||
|
||||
});
|
@ -27,12 +27,8 @@ import {
|
||||
|
||||
declare let AlfrescoApi: any;
|
||||
|
||||
// TODO: consider renaming to something like 'DocumentListService'
|
||||
/**
|
||||
* Internal service used by Document List component.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AlfrescoService {
|
||||
export class DocumentListService {
|
||||
|
||||
static DEFAULT_MIME_TYPE_ICON: string = 'ft_ic_miscellaneous.svg';
|
||||
|
||||
@ -120,7 +116,7 @@ export class AlfrescoService {
|
||||
|
||||
getMimeTypeIcon(mimeType: string): string {
|
||||
let icon = this.mimeTypeIcons[mimeType];
|
||||
return icon || AlfrescoService.DEFAULT_MIME_TYPE_ICON;
|
||||
return icon || DocumentListService.DEFAULT_MIME_TYPE_ICON;
|
||||
}
|
||||
|
||||
private handleError(error: Response) {
|
@ -27,17 +27,17 @@ import {
|
||||
FileNode,
|
||||
FolderNode
|
||||
} from '../assets/document-library.model.mock';
|
||||
import { AlfrescoService } from './alfresco.service';
|
||||
import { AlfrescoServiceMock } from '../assets/alfresco.service.mock';
|
||||
import { DocumentListService } from './document-list.service';
|
||||
import { DocumentListServiceMock } from '../assets/document-list.service.mock';
|
||||
|
||||
describe('FolderActionsService', () => {
|
||||
|
||||
let service: FolderActionsService;
|
||||
let alfrescoService: AlfrescoService;
|
||||
let documentListService: DocumentListService;
|
||||
|
||||
beforeEach(() => {
|
||||
alfrescoService = new AlfrescoServiceMock();
|
||||
service = new FolderActionsService(alfrescoService);
|
||||
documentListService = new DocumentListServiceMock();
|
||||
service = new FolderActionsService(documentListService);
|
||||
});
|
||||
|
||||
it('should register custom action handler', () => {
|
||||
@ -105,44 +105,44 @@ describe('FolderActionsService', () => {
|
||||
});
|
||||
|
||||
it('should delete folder node', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let folder = new FolderNode();
|
||||
service.getHandler('delete')(folder);
|
||||
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalledWith(folder.entry.id);
|
||||
expect(documentListService.deleteNode).toHaveBeenCalledWith(folder.entry.id);
|
||||
});
|
||||
|
||||
it('should support deletion only folder node', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let file = new FileNode();
|
||||
service.getHandler('delete')(file);
|
||||
expect(alfrescoService.deleteNode).not.toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).not.toHaveBeenCalled();
|
||||
|
||||
let folder = new FolderNode();
|
||||
service.getHandler('delete')(folder);
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require node id to delete', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let folder = new FolderNode();
|
||||
folder.entry.id = null;
|
||||
service.getHandler('delete')(folder);
|
||||
|
||||
expect(alfrescoService.deleteNode).not.toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reload target upon node deletion', () => {
|
||||
spyOn(alfrescoService, 'deleteNode').and.callThrough();
|
||||
spyOn(documentListService, 'deleteNode').and.callThrough();
|
||||
|
||||
let target = jasmine.createSpyObj('obj', ['reload']);
|
||||
let folder = new FolderNode();
|
||||
service.getHandler('delete')(folder, target);
|
||||
|
||||
expect(alfrescoService.deleteNode).toHaveBeenCalled();
|
||||
expect(documentListService.deleteNode).toHaveBeenCalled();
|
||||
expect(target.reload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -15,15 +15,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ContentActionHandler} from '../models/content-action.model';
|
||||
import {AlfrescoService} from './alfresco.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ContentActionHandler } from '../models/content-action.model';
|
||||
import { DocumentListService } from './document-list.service';
|
||||
|
||||
@Injectable()
|
||||
export class FolderActionsService {
|
||||
private handlers: { [id: string]: ContentActionHandler; } = {};
|
||||
|
||||
constructor(private _alfrescoService?: AlfrescoService) {
|
||||
constructor(private documentListService?: DocumentListService) {
|
||||
this.setupActionHandlers();
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ export class FolderActionsService {
|
||||
}
|
||||
|
||||
canExecuteAction(obj: any): boolean {
|
||||
return this._alfrescoService && obj && obj.entry.isFolder === true;
|
||||
return this.documentListService && obj && obj.entry.isFolder === true;
|
||||
}
|
||||
|
||||
private setupActionHandlers() {
|
||||
@ -68,7 +68,7 @@ export class FolderActionsService {
|
||||
|
||||
private deleteNode(obj: any, target?: any) {
|
||||
if (this.canExecuteAction(obj) && obj.entry && obj.entry.id) {
|
||||
this._alfrescoService.deleteNode(obj.entry.id).subscribe(() => {
|
||||
this.documentListService.deleteNode(obj.entry.id).subscribe(() => {
|
||||
if (target && typeof target.reload === 'function') {
|
||||
target.reload();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user