[ADF-4272] TaskListCloud - improvements on CopyClipboardDirective (#4547)

* [ADF-4272] DocumentList -  add Copy content tooltip directive

* [ADF-4272] - fix build issue

* [ADF-4272] - change directive name and add requested changes

* [ADF-4272] - reset task-list-cloud html content

* [ADF-4272] - fix build

* [AFG-4272] - change name to CopyClipboard

* [ADF-4272] - PR changes

* [ADF-4272] - fix tests

* [ADF-4272[] - lint

* [ADF-4272] - merge clipboard directive with copy-content directive

* [ADF-4272] - PR changes

* [ADF-4272] - change docs
This commit is contained in:
Silviu Popa 2019-04-08 18:37:37 +03:00 committed by Eugenio Romano
parent dee63e3f3b
commit a87d1ef002
19 changed files with 433 additions and 74 deletions

View File

@ -179,7 +179,9 @@
"REPLACE_COLUMNS": "Replace columns", "REPLACE_COLUMNS": "Replace columns",
"LOAD_NODE": "Load Node", "LOAD_NODE": "Load Node",
"MULTISELECT": "Multiselect", "MULTISELECT": "Multiselect",
"MULTISELECT_DESCRIPTION": "Use Cmd (Mac) or Ctrl (Windows) to toggle selection of multiple items" "MULTISELECT_DESCRIPTION": "Use Cmd (Mac) or Ctrl (Windows) to toggle selection of multiple items",
"CLICK_TO_COPY": "Click to copy",
"SUCCESS_COPY": "Text copied to clipboard"
}, },
"ANALYTICS_REPORT": { "ANALYTICS_REPORT": {
"NO_REPORT_MESSAGE": "No report selected. Choose a report from the list" "NO_REPORT_MESSAGE": "No report selected. Choose a report from the list"

View File

@ -11,8 +11,8 @@
</mat-slide-toggle> </mat-slide-toggle>
<div style="height: 310px; overflow-y: auto;"> <div style="height: 310px; overflow-y: auto;">
<adf-datatable <adf-datatable
#dataTable #dataTable
[data]="data" [data]="data"
[stickyHeader]="stickyHeader" [stickyHeader]="stickyHeader"
[selectionMode]="selectionMode" [selectionMode]="selectionMode"

View File

@ -35,7 +35,7 @@ See it live: [DataTable Quickstart](https://embed.plnkr.co/80qr4YFBeHjLMdAV0F6l/
**app.component.html** **app.component.html**
```html ```html
<adf-datatable <adf-datatable
[data]="data"> [data]="data">
</adf-datatable> </adf-datatable>
``` ```
@ -117,7 +117,7 @@ export class DataTableDemo {
``` ```
```html ```html
<adf-datatable <adf-datatable
[data]="data"> [data]="data">
</adf-datatable> </adf-datatable>
``` ```
@ -178,16 +178,16 @@ export class DataTableDemo {
// columns // columns
this.schema = this.schema =
[ [
{ {
type: 'text', type: 'text',
key: 'id', key: 'id',
title: 'Id', title: 'Id',
sortable: true sortable: true
}, },
{ {
type: 'text', type: 'text',
key: 'name', key: 'name',
title: 'Name', title: 'Name',
sortable: true sortable: true
} }
]; ];
@ -222,16 +222,16 @@ export class DataTableDemo {
// columns // columns
this.schema = this.schema =
[ [
{ {
type: 'text', type: 'text',
key: 'id', key: 'id',
title: 'Id', title: 'Id',
sortable: true sortable: true
}, },
{ {
type: 'text', type: 'text',
key: 'name', key: 'name',
title: 'Name', title: 'Name',
sortable: true sortable: true
} }
]; ];
@ -266,7 +266,7 @@ You can also supply a `<adf-no-content-template>` or an
``` ```
```html ```html
<adf-datatable ...> <adf-datatable ...>
<adf-empty-list> <adf-empty-list>
<adf-empty-list-header>"'My custom Header'"</adf-empty-list-header> <adf-empty-list-header>"'My custom Header'"</adf-empty-list-header>
<adf-empty-list-body>"'My custom body'"</adf-empty-list-body> <adf-empty-list-body>"'My custom body'"</adf-empty-list-body>
@ -296,7 +296,7 @@ while the data for the table is loading:
```js ```js
isLoading(): boolean { isLoading(): boolean {
//your custom logic to identify if you are in a loading state //your custom logic to identify if you are in a loading state
} }
``` ```
@ -403,7 +403,7 @@ Set the `display` property to "gallery" to enable Card View mode:
#### row-keyup DOM event #### row-keyup DOM event
Emitted on the 'keyup' event for the focused row. Emitted on the 'keyup' event for the focused row.
This is an instance of `CustomEvent` with the `details` property containing the following object: This is an instance of `CustomEvent` with the `details` property containing the following object:
@ -420,7 +420,7 @@ Emitted when the user clicks a row.
Event properties: Event properties:
```ts ```ts
sender: any // DataTable instance sender: any // DataTable instance
value: DataRow, // row clicked value: DataRow, // row clicked
event: Event // original HTML DOM event event: Event // original HTML DOM event
``` ```
@ -442,7 +442,7 @@ Emitted when the user double-clicks a row.
Event properties: Event properties:
```ts ```ts
sender: any // DataTable instance sender: any // DataTable instance
value: DataRow, // row clicked value: DataRow, // row clicked
event: Event // original HTML DOM event event: Event // original HTML DOM event
``` ```
@ -515,7 +515,7 @@ This event is cancellable. You can use `event.preventDefault()` to prevent the d
Emitted when the user executes a row action. Emitted when the user executes a row action.
This usually accompanies a `showRowActionsMenu` event. This usually accompanies a `showRowActionsMenu` event.
The DataTable itself does not execute actions but provides support for external The DataTable itself does not execute actions but provides support for external
integration. If actions are provided using the `showRowActionsMenu` event integration. If actions are provided using the `showRowActionsMenu` event
then `executeRowAction` will be automatically executed when the user clicks a then `executeRowAction` will be automatically executed when the user clicks a
@ -575,15 +575,15 @@ By default, the content of the cells is wrapped so you can see all the data insi
![](../../docassets/images/datatable-wrapped-text.png) ![](../../docassets/images/datatable-wrapped-text.png)
However, you can also truncate the text within these cells using the `adf-ellipsis-cell` class in the desired column: However, you can also truncate the text within these cells using the `adf-ellipsis-cell` class in the desired column:
```js ```js
{ {
type: 'text', type: 'text',
key: 'createdOn', key: 'createdOn',
title: 'Created On', title: 'Created On',
sortable: true, sortable: true,
cssClass: 'adf-ellipsis-cell' cssClass: 'adf-ellipsis-cell'
} }
``` ```
@ -603,14 +603,14 @@ widths according to your needs:
#### No-growing cells #### No-growing cells
As mentioned before, in the beginning, all cells have the same width. You can prevent cells from growing by using the `adf-no-grow-cell` class. As mentioned before, in the beginning, all cells have the same width. You can prevent cells from growing by using the `adf-no-grow-cell` class.
```js ```js
{ {
type: 'date', type: 'date',
key: 'created', key: 'created',
title: 'Created On', title: 'Created On',
cssClass: 'adf-ellipsis-cell adf-no-grow-cell' cssClass: 'adf-ellipsis-cell adf-no-grow-cell'
} }
``` ```
@ -623,11 +623,11 @@ Notice that this class is compatible with `adf-ellipsis-cell` and for that reaso
You can combine the CSS classes described above to customize the table as needed: You can combine the CSS classes described above to customize the table as needed:
```js ```js
{ {
type: 'text', type: 'text',
key: 'name', key: 'name',
title: 'Name', title: 'Name',
cssClass: 'adf-ellipsis-cell adf-expand-cell-3' cssClass: 'adf-ellipsis-cell adf-expand-cell-3'
} }
``` ```
@ -639,7 +639,7 @@ always visible. You can do this using the following steps.
First, set the `stickyHeader` property of your datatable to `true`: First, set the `stickyHeader` property of your datatable to `true`:
```html ```html
<adf-datatable <adf-datatable
[data]="data" [data]="data"
[stickyHeader]="true"> [stickyHeader]="true">
</adf-datatable> </adf-datatable>
@ -658,6 +658,27 @@ the total height of all rows exceeds the fixed height of the parent element.
</div> </div>
``` ```
### CopyClipboardDirective example
See the [Copy Content Directive ](../directives/clipboard.directive.md) page for full details of the directive
Json config file:
```json
[
{"type": "text", "key": "id", "title": "Id", "copyContent": "true"},
{"type": "text", "key": "name", "title": "name"},
]
```
HTML data-columns
```html
<adf-tasklist ...>
<data-columns>
<data-column [copyContent]="true" key="id" title="Id"></data-column>
<data-column key="created" title="Created" class="hidden"></data-column>
</data-columns>
</adf-tasklist>
```
Once set up, the sticky header behaves as shown in the image below: Once set up, the sticky header behaves as shown in the image below:
![](../../docassets/images/datatable-sticky-header.png) ![](../../docassets/images/datatable-sticky-header.png)

View File

@ -0,0 +1,36 @@
---
Title: Copy Clipboard directive
Added: v3.2.0
Status: Active
Last reviewed: 2019-04-01
---
# [Clipboard directive](../../../lib/core/clipboard/clipboard.directive.ts "Defined in clipboard.directive.ts")
Copy text to clipboard
## Basic Usage
```html
<span adf-clipboard="translate_key" [clipboard-notification]="notify message">
text to copy
</span>
<button adf-clipboard="translate_key" target="ref" [clipboard-notification]="notify message">
Copy
</button>
```
## Class members
### Properties
| Name | Type | Default value | Description |
| ---- | ---- | ------------- | ----------- |
| target | `HTMLElement ref` | false | HTMLElement reference |
| clipboard-notification | `string` | | Translation key message for toast notification |
## Details
When the user hover the directive element a tooltip will will show up to inform that, when you click on the current element, the content or the reference content will be copied into the clipboard.

View File

@ -31,7 +31,7 @@
readonly="readonly"> readonly="readonly">
<mat-icon class="adf-input-action" matSuffix <mat-icon class="adf-input-action" matSuffix
[clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate" [clipboard-notification]="'SHARE.CLIPBOARD-MESSAGE' | translate"
[adf-clipboard]="sharedLinkInput"> [adf-clipboard] target="sharedLinkInput">
link link
</mat-icon> </mat-icon>
</mat-form-field> </mat-form-field>

View File

@ -1,6 +1,8 @@
@mixin adf-document-list-theme($theme) { @mixin adf-document-list-theme($theme) {
$foreground: map-get($theme, foreground); $foreground: map-get($theme, foreground);
$background: map-get($theme, background);
$accent: map-get($theme, accent); $accent: map-get($theme, accent);
$primary: map-get($theme, primary);
.mat-icon.adf-datatable-selected { .mat-icon.adf-datatable-selected {
height: 100%; height: 100%;
@ -186,4 +188,14 @@
} }
} }
} }
.adf-datatable-copy-tooltip {
position: absolute;
background: mat-color($primary);
color: mat-color($primary, default-contrast) !important;
padding: 5px 10px;
border-radius: 5px;
bottom: 88%;
left:0;
}
} }

View File

@ -15,28 +15,30 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component } from '@angular/core'; import { Component, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed, tick, fakeAsync } from '@angular/core/testing';
import { setupTestBed } from '../testing/setupTestBed'; import { setupTestBed } from '../testing/setupTestBed';
import { CoreModule } from '../core.module'; import { CoreModule } from '../core.module';
import { ClipboardService } from './clipboard.service'; import { ClipboardService } from './clipboard.service';
import { ClipboardDirective } from './clipboard.directive';
import { RouterTestingModule } from '@angular/router/testing';
@Component({ @Component({
selector: 'adf-test-component', selector: 'adf-test-component',
template: ` template: `
<button <button
clipboard-notification="copy success" clipboard-notification="copy success"
[adf-clipboard]="ref"> [adf-clipboard] [target]="ref">
copy copy
</button> </button>
<input #ref /> <input #ref />
` `
}) })
class TestComponent {} class TestTargetClipboardComponent {}
describe('ClipboardDirective', () => { describe('ClipboardDirective', () => {
let fixture: ComponentFixture<TestComponent>; let fixture: ComponentFixture<TestTargetClipboardComponent>;
let clipboardService: ClipboardService; let clipboardService: ClipboardService;
setupTestBed({ setupTestBed({
@ -44,7 +46,7 @@ describe('ClipboardDirective', () => {
CoreModule.forRoot() CoreModule.forRoot()
], ],
declarations: [ declarations: [
TestComponent TestTargetClipboardComponent
], ],
providers: [ providers: [
ClipboardService ClipboardService
@ -52,7 +54,7 @@ describe('ClipboardDirective', () => {
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(TestComponent); fixture = TestBed.createComponent(TestTargetClipboardComponent);
clipboardService = TestBed.get(ClipboardService); clipboardService = TestBed.get(ClipboardService);
fixture.detectChanges(); fixture.detectChanges();
}); });
@ -65,3 +67,73 @@ describe('ClipboardDirective', () => {
expect(clipboardService.copyToClipboard).toHaveBeenCalled(); expect(clipboardService.copyToClipboard).toHaveBeenCalled();
}); });
}); });
describe('CopyClipboardDirective', () => {
@Component({
selector: 'adf-copy-conent-test-component',
template: `<span adf-clipboard='DOCUMENT_LIST.ACTIONS.DOCUMENT.CLICK_TO_COPY'>{{ mockText }}</span>`
})
class TestCopyClipboardComponent {
mockText = 'text to copy';
@ViewChild(ClipboardDirective)
clipboardDirective: ClipboardDirective;
}
let fixture: ComponentFixture<TestCopyClipboardComponent>;
let element: HTMLElement;
setupTestBed({
imports: [
CoreModule.forRoot(),
RouterTestingModule
],
declarations: [
TestCopyClipboardComponent
]
});
beforeEach(() => {
fixture = TestBed.createComponent(TestCopyClipboardComponent);
element = fixture.debugElement.nativeElement;
fixture.detectChanges();
});
it('should show tooltip when hover element', (() => {
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).not.toBeNull();
}));
it('should not show tooltip when element it is not hovered', (() => {
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
expect(fixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).not.toBeNull();
spanHTMLElement.dispatchEvent(new Event('mouseleave'));
expect(fixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).toBeNull();
}));
it('should copy the content of element when click it', fakeAsync(() => {
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span');
fixture.detectChanges();
spyOn(document, 'execCommand');
spanHTMLElement.dispatchEvent(new Event('click'));
tick();
fixture.detectChanges();
expect(document.execCommand).toHaveBeenCalledWith('copy');
}));
it('should not copy the content of element when click it', fakeAsync(() => {
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span');
fixture.detectChanges();
spyOn(document, 'execCommand');
spanHTMLElement.dispatchEvent(new Event('mouseleave'));
tick();
fixture.detectChanges();
expect(document.execCommand).not.toHaveBeenCalled();
}));
});

View File

@ -15,33 +15,78 @@
* limitations under the License. * limitations under the License.
*/ */
import { Directive, Input, HostListener } from '@angular/core'; import { Directive, Input, HostListener, Component, ViewContainerRef, ComponentFactoryResolver, AfterContentInit } from '@angular/core';
import { ClipboardService } from './clipboard.service'; import { ClipboardService } from './clipboard.service';
@Directive({ @Directive({
selector: '[adf-clipboard]', selector: '[adf-clipboard]',
exportAs: 'adfClipboard' exportAs: 'adfClipboard'
}) })
export class ClipboardDirective { export class ClipboardDirective implements AfterContentInit {
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@Input('adf-clipboard') target: HTMLInputElement | HTMLTextAreaElement; @Input('adf-clipboard')
placeholder: string;
@Input()
target: HTMLInputElement | HTMLTextAreaElement;
// tslint:disable-next-line:no-input-rename // tslint:disable-next-line:no-input-rename
@Input('clipboard-notification') message: string; @Input('clipboard-notification') message: string;
private value: string;
constructor(private clipboardService: ClipboardService,
public viewContainerRef: ViewContainerRef,
private resolver: ComponentFactoryResolver) {}
@HostListener('click', ['$event']) @HostListener('click', ['$event'])
handleClickEvent(event: MouseEvent) { handleClickEvent(event: MouseEvent) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
this.copyToClipboard(); this.copyToClipboard();
} }
constructor(private clipboardService: ClipboardService) {} @HostListener('mouseenter')
showTooltip() {
const componentFactory = this.resolver.resolveComponentFactory(ClipboardComponent);
const componentRef = this.viewContainerRef.createComponent(componentFactory).instance;
componentRef.copyText = this.value;
componentRef.placeholder = this.placeholder;
}
@HostListener('mouseleave')
closeTooltip() {
this.viewContainerRef.remove();
}
private copyToClipboard() { private copyToClipboard() {
const isValidTarget = this.clipboardService.isTargetValid(this.target); const isValidTarget = this.clipboardService.isTargetValid(this.target);
if (isValidTarget) { if (isValidTarget) {
this.clipboardService.copyToClipboard(this.target, this.message); this.clipboardService.copyToClipboard(this.target, this.message);
} else {
this.copyContentToClipboard(this.viewContainerRef.element.nativeElement.innerHTML);
} }
} }
private copyContentToClipboard(content) {
this.clipboardService.copyContentToClipboard(content, this.message);
}
ngAfterContentInit() {
setTimeout( () => {
this.value = this.viewContainerRef.element.nativeElement.innerHTML;
});
}
}
@Component({
selector: 'adf-datatable-highlight-tooltip',
template: `
<span class='adf-datatable-copy-tooltip'>{{ placeholder | translate }} <b> {{ copyText }} </b></span>
`
})
export class ClipboardComponent {
copyText: string;
placeholder: string;
} }

View File

@ -17,22 +17,26 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ClipboardDirective } from './clipboard.directive'; import { ClipboardDirective, ClipboardComponent } from './clipboard.directive';
import { ClipboardService } from './clipboard.service'; import { ClipboardService } from './clipboard.service';
import { TranslateModule } from '@ngx-translate/core';
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule CommonModule,
TranslateModule.forChild()
], ],
providers: [ providers: [
ClipboardService ClipboardService
], ],
declarations: [ declarations: [
ClipboardDirective ClipboardDirective,
ClipboardComponent
], ],
exports: [ exports: [
ClipboardDirective ClipboardDirective
] ],
entryComponents: [ClipboardComponent]
}) })
export class ClipboardModule {} export class ClipboardModule {}

View File

@ -32,8 +32,6 @@ export class ClipboardService {
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) { if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
return !target.hasAttribute('disabled'); return !target.hasAttribute('disabled');
} }
this.logService.error(`${target} should be input or textarea`);
return false; return false;
} }
@ -50,6 +48,20 @@ export class ClipboardService {
} }
} }
copyContentToClipboard(content: string, message: string) {
try {
document.addEventListener('copy', (e: ClipboardEvent) => {
e.clipboardData.setData('text/plain', (content));
e.preventDefault();
document.removeEventListener('copy', null);
});
document.execCommand('copy');
this.notify(message);
} catch (error) {
this.logService.error(error);
}
}
private notify(message) { private notify(message) {
if (message) { if (message) {
this.notificationService.openSnackMessage(message); this.notificationService.openSnackMessage(message);

View File

@ -66,6 +66,10 @@ export class DataColumnComponent implements OnInit {
@Input('class') @Input('class')
cssClass: string; cssClass: string;
/** flag to show the copy content directive */
@Input()
copyContent: boolean;
ngOnInit() { ngOnInit() {
if (!this.srTitle && this.key === '$thumbnail') { if (!this.srTitle && this.key === '$thumbnail') {
this.srTitle = 'Thumbnail'; this.srTitle = 'Thumbnail';

View File

@ -35,13 +35,21 @@ import { Node } from '@alfresco/js-api';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
template: ` template: `
<ng-container> <ng-container>
<span *ngIf="copyContent; else defaultCell"
adf-clipboard="DATATABLE.CLICK_TO_COPY"
[clipboard-notification]="'DATATABLE.SUCCESS_COPY'"
[attr.aria-label]="value$ | async"
[title]="tooltip"
class="adf-datatable-cell-value"
>{{ value$ | async }}</span>
</ng-container>
<ng-template #defaultCell>
<span <span
[attr.aria-label]="value$ | async" [attr.aria-label]="value$ | async"
[title]="tooltip" [title]="tooltip"
class="adf-datatable-cell-value" class="adf-datatable-cell-value"
>{{ value$ | async }}</span >{{ value$ | async }}</span>
> </ng-template>
</ng-container>
`, `,
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-datatable-cell' } host: { class: 'adf-datatable-cell' }
@ -58,6 +66,9 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
value$ = new BehaviorSubject<any>(''); value$ = new BehaviorSubject<any>('');
@Input()
copyContent: boolean;
@Input() @Input()
tooltip: string; tooltip: string;
@ -67,7 +78,6 @@ export class DataTableCellComponent implements OnInit, OnDestroy {
ngOnInit() { ngOnInit() {
this.updateValue(); this.updateValue();
this.sub = this.alfrescoApiService.nodeUpdated.subscribe((node: Node) => { this.sub = this.alfrescoApiService.nodeUpdated.subscribe((node: Node) => {
if (this.row) { if (this.row) {
const { entry } = this.row['node']; const { entry } = this.row['node'];

View File

@ -148,6 +148,7 @@
<div *ngSwitchCase="'text'" class="adf-cell-value" <div *ngSwitchCase="'text'" class="adf-cell-value"
[attr.data-automation-id]="'text_' + data.getValue(row, col)"> [attr.data-automation-id]="'text_' + data.getValue(row, col)">
<adf-datatable-cell <adf-datatable-cell
[copyContent]="col.copyContent"
[data]="data" [data]="data"
[column]="col" [column]="col"
[row]="row" [row]="row"

View File

@ -216,6 +216,7 @@
&--text { &--text {
text-align: left; text-align: left;
position: relative;
} }
&--date { &--date {

View File

@ -27,4 +27,5 @@ export interface DataColumn {
cssClass?: string; cssClass?: string;
template?: TemplateRef<any>; template?: TemplateRef<any>;
formatTooltip?: Function; formatTooltip?: Function;
copyContent?: boolean;
} }

View File

@ -29,6 +29,7 @@ export class ObjectDataColumn implements DataColumn {
srTitle: string; srTitle: string;
cssClass: string; cssClass: string;
template?: TemplateRef<any>; template?: TemplateRef<any>;
copyContent?: boolean;
constructor(input: any) { constructor(input: any) {
this.key = input.key; this.key = input.key;
@ -39,5 +40,6 @@ export class ObjectDataColumn implements DataColumn {
this.srTitle = input.srTitle; this.srTitle = input.srTitle;
this.cssClass = input.cssClass; this.cssClass = input.cssClass;
this.template = input.template; this.template = input.template;
this.copyContent = input.copyContent;
} }
} }

View File

@ -41,6 +41,7 @@ import { CustomEmptyContentTemplateDirective } from './directives/custom-empty-c
import { CustomLoadingContentTemplateDirective } from './directives/custom-loading-template.directive'; import { CustomLoadingContentTemplateDirective } from './directives/custom-loading-template.directive';
import { CustomNoPermissionTemplateDirective } from './directives/custom-no-permission-template.directive'; import { CustomNoPermissionTemplateDirective } from './directives/custom-no-permission-template.directive';
import { JsonCellComponent } from './components/datatable/json-cell.component'; import { JsonCellComponent } from './components/datatable/json-cell.component';
import { ClipboardModule } from '../clipboard/clipboard.module';
@NgModule({ @NgModule({
imports: [ imports: [
@ -50,7 +51,8 @@ import { JsonCellComponent } from './components/datatable/json-cell.component';
TranslateModule.forChild(), TranslateModule.forChild(),
ContextMenuModule, ContextMenuModule,
PipeModule, PipeModule,
DirectiveModule DirectiveModule,
ClipboardModule
], ],
declarations: [ declarations: [
DataTableComponent, DataTableComponent,
@ -88,5 +90,6 @@ import { JsonCellComponent } from './components/datatable/json-cell.component';
CustomLoadingContentTemplateDirective, CustomLoadingContentTemplateDirective,
CustomNoPermissionTemplateDirective CustomNoPermissionTemplateDirective
] ]
}) })
export class DataTableModule {} export class DataTableModule {}

View File

@ -36,10 +36,6 @@ describe('ClaimTaskDirective', () => {
@ViewChild(ClaimTaskDirective) @ViewChild(ClaimTaskDirective)
claimTaskDirective: ClaimTaskDirective; claimTaskDirective: ClaimTaskDirective;
onCompleteTask(event: any) {
return event;
}
} }
let fixture: ComponentFixture<TestComponent>; let fixture: ComponentFixture<TestComponent>;

View File

@ -55,6 +55,20 @@ class CustomTaskListComponent {
}) })
class EmptyTemplateComponent { class EmptyTemplateComponent {
} }
@Component({
template: `
<adf-cloud-task-list #taskListCloudCopy>
<data-columns>
<data-column [copyContent]="true" key="entry.id" title="ADF_CLOUD_TASK_LIST.PROPERTIES.ID"></data-column>
<data-column key="entry.name" title="ADF_CLOUD_TASK_LIST.PROPERTIES.NAME"></data-column>
</data-columns>
</adf-cloud-task-list>`
})
class CustomCopyContentTaskListComponent {
@ViewChild(TaskListCloudComponent)
taskList: TaskListCloudComponent;
}
describe('TaskListCloudComponent', () => { describe('TaskListCloudComponent', () => {
let component: TaskListCloudComponent; let component: TaskListCloudComponent;
let fixture: ComponentFixture<TaskListCloudComponent>; let fixture: ComponentFixture<TaskListCloudComponent>;
@ -228,21 +242,29 @@ describe('TaskListCloudComponent', () => {
describe('Injecting custom colums for tasklist - CustomTaskListComponent', () => { describe('Injecting custom colums for tasklist - CustomTaskListComponent', () => {
let fixtureCustom: ComponentFixture<CustomTaskListComponent>; let fixtureCustom: ComponentFixture<CustomTaskListComponent>;
let componentCustom: CustomTaskListComponent; let componentCustom: CustomTaskListComponent;
let customCopyComponent: CustomCopyContentTaskListComponent;
let element: any;
let copyFixture: ComponentFixture<CustomCopyContentTaskListComponent>;
setupTestBed({ setupTestBed({
imports: [CoreModule.forRoot()], imports: [CoreModule.forRoot()],
declarations: [TaskListCloudComponent, CustomTaskListComponent], declarations: [TaskListCloudComponent, CustomTaskListComponent, CustomCopyContentTaskListComponent],
providers: [TaskListCloudService] providers: [TaskListCloudService]
}); });
beforeEach(() => { beforeEach(() => {
spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTask));
fixtureCustom = TestBed.createComponent(CustomTaskListComponent); fixtureCustom = TestBed.createComponent(CustomTaskListComponent);
copyFixture = TestBed.createComponent(CustomCopyContentTaskListComponent);
fixtureCustom.detectChanges(); fixtureCustom.detectChanges();
componentCustom = fixtureCustom.componentInstance; componentCustom = fixtureCustom.componentInstance;
customCopyComponent = copyFixture.componentInstance;
element = copyFixture.debugElement.nativeElement;
}); });
afterEach(() => { afterEach(() => {
fixtureCustom.destroy(); fixtureCustom.destroy();
copyFixture.destroy();
}); });
it('should create instance of CustomTaskListComponent', () => { it('should create instance of CustomTaskListComponent', () => {
@ -257,6 +279,37 @@ describe('TaskListCloudComponent', () => {
expect(componentCustom.taskList.columns.length).toEqual(3); expect(componentCustom.taskList.columns.length).toEqual(3);
}); });
it('it should show copy tooltip when key is present in data-colunn', async(() => {
copyFixture.detectChanges();
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
copyFixture.whenStable().then(() => {
copyFixture.detectChanges();
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
copyFixture.detectChanges();
expect(copyFixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).not.toBeNull();
});
customCopyComponent.taskList.appName = appName.currentValue;
customCopyComponent.taskList.ngOnChanges({ 'appName': appName });
copyFixture.detectChanges();
}));
it('it should not show copy tooltip when key is not present in data-colunn', async(() => {
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
customCopyComponent.taskList.success.subscribe( () => {
copyFixture.whenStable().then(() => {
copyFixture.detectChanges();
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span[title="standalone-subtask"]');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
copyFixture.detectChanges();
expect(copyFixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).toBeNull();
});
});
customCopyComponent.taskList.appName = appName.currentValue;
customCopyComponent.taskList.ngOnChanges({ 'appName': appName });
copyFixture.detectChanges();
}));
}); });
describe('Creating an empty custom template - EmptyTemplateComponent', () => { describe('Creating an empty custom template - EmptyTemplateComponent', () => {
@ -285,4 +338,88 @@ describe('TaskListCloudComponent', () => {
}); });
})); }));
}); });
describe('Copy cell content directive from app.config specifications', () => {
let element: any;
let taskSpy: jasmine.Spy;
setupTestBed({
imports: [ProcessServiceCloudTestingModule, TaskListCloudModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
});
beforeEach( () => {
appConfig = TestBed.get(AppConfigService);
taskListCloudService = TestBed.get(TaskListCloudService);
appConfig.config = Object.assign(appConfig.config, {
'adf-cloud-task-list': {
'presets': {
'fakeCustomSchema': [
{
'key': 'entry.id',
'type': 'text',
'title': 'ADF_CLOUD_TASK_LIST.PROPERTIES.FAKE',
'sortable': true,
'copyContent': true
},
{
'key': 'entry.name',
'type': 'text',
'title': 'ADF_CLOUD_TASK_LIST.PROPERTIES.TASK_FAKE',
'sortable': true
}
]
}
}
});
fixture = TestBed.createComponent(TaskListCloudComponent);
component = fixture.componentInstance;
element = fixture.debugElement.nativeElement;
taskSpy = spyOn(taskListCloudService, 'getTaskByRequest').and.returnValue(of(fakeGlobalTask));
});
afterEach(() => {
fixture.destroy();
});
it('shoud show tooltip if config copyContent flag is true', async(() => {
taskSpy.and.returnValue(of(fakeGlobalTask));
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
component.success.subscribe( () => {
fixture.whenStable().then(() => {
fixture.detectChanges();
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span[title="11fe013d-c263-11e8-b75b-0a5864600540"]');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).not.toBeNull();
});
});
component.presetColumn = 'fakeCustomSchema';
component.appName = appName.currentValue;
component.ngOnChanges({ 'appName': appName });
component.ngAfterContentInit();
}));
it('shoud not show tooltip if config copyContent flag is true', async(() => {
taskSpy.and.returnValue(of(fakeGlobalTask));
const appName = new SimpleChange(null, 'FAKE-APP-NAME', true);
component.success.subscribe( () => {
fixture.whenStable().then(() => {
fixture.detectChanges();
const spanHTMLElement: HTMLInputElement = <HTMLInputElement> element.querySelector('span[title="standalone-subtask"]');
spanHTMLElement.dispatchEvent(new Event('mouseenter'));
fixture.detectChanges();
expect(fixture.debugElement.nativeElement.querySelector('.adf-datatable-copy-tooltip')).toBeNull();
});
});
component.presetColumn = 'fakeCustomSchema';
component.appName = appName.currentValue;
component.ngOnChanges({ 'appName': appName });
component.ngAfterContentInit();
}));
});
}); });