From c5ac798c5beec46d5d445680736a66d1346ae98e Mon Sep 17 00:00:00 2001 From: Vito Date: Thu, 4 Apr 2019 12:44:47 +0100 Subject: [PATCH] [ADF-4327] added templating for content dialog (#4549) * [ADF-4327] added templating for content dialog * [ADF-4327] added unit test and documentation --- demo-shell/resources/i18n/en.json | 3 +- demo-shell/src/app/app.module.ts | 4 +- demo-shell/src/app/app.routes.ts | 5 + .../app-layout/app-layout.component.ts | 1 + .../confirm-dialog-example.component.html | 18 +++ .../confirm-dialog-example.component.scss | 0 .../confirm-dialog-example.component.ts | 51 +++++++ .../dialogs/confirm.dialog.md | 28 ++++ .../dialogs/confirm.dialog.html | 17 +++ .../dialogs/confirm.dialog.scss | 7 + .../dialogs/confirm.dialog.spec.ts | 143 ++++++++++++++++++ .../dialogs/confirm.dialog.ts | 31 ++-- 12 files changed, 286 insertions(+), 22 deletions(-) create mode 100644 demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.html create mode 100644 demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.scss create mode 100644 demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.ts create mode 100644 lib/content-services/dialogs/confirm.dialog.html create mode 100644 lib/content-services/dialogs/confirm.dialog.scss create mode 100644 lib/content-services/dialogs/confirm.dialog.spec.ts diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json index b9e088971b..17e745dcd7 100644 --- a/demo-shell/resources/i18n/en.json +++ b/demo-shell/resources/i18n/en.json @@ -94,7 +94,8 @@ "ICONS": "Icons", "PEOPLE_GROUPS_CLOUD": "People/Group Cloud", "PEOPLE_CLOUD": "People Cloud Component", - "GROUPS_CLOUD": "Groups Cloud Component" + "GROUPS_CLOUD": "Groups Cloud Component", + "CONFIRM-DIALOG": "Confirmation Dialog" }, "TRASHCAN": { "ACTIONS": { diff --git a/demo-shell/src/app/app.module.ts b/demo-shell/src/app/app.module.ts index 8487d54fdc..2b06d1f38c 100644 --- a/demo-shell/src/app/app.module.ts +++ b/demo-shell/src/app/app.module.ts @@ -81,6 +81,7 @@ import { TemplateDemoComponent } from './components/template-list/template-demo. import { PeopleGroupCloudDemoComponent } from './components/cloud/people-groups-cloud-demo.component'; import { CloudSettingsComponent } from './components/cloud/cloud-settings.component'; import { NestedMenuPositionDirective } from './components/cloud/directives/nested-menu-position.directive'; +import { ConfirmDialogExampleComponent } from './components/confirm-dialog/confirm-dialog-example.component'; @NgModule({ imports: [ @@ -148,7 +149,8 @@ import { NestedMenuPositionDirective } from './components/cloud/directives/neste TemplateDemoComponent, PeopleGroupCloudDemoComponent, CloudSettingsComponent, - NestedMenuPositionDirective + NestedMenuPositionDirective, + ConfirmDialogExampleComponent ], providers: [ { diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts index 75f35e58ca..f3ab662b28 100644 --- a/demo-shell/src/app/app.routes.ts +++ b/demo-shell/src/app/app.routes.ts @@ -49,6 +49,7 @@ import { StartProcessCloudDemoComponent } from './components/cloud/start-process import { TaskDetailsCloudDemoComponent } from './components/cloud/task-details-cloud-demo.component'; import { ProcessDetailsCloudDemoComponent } from './components/cloud/process-details-cloud-demo.component'; import { TemplateDemoComponent } from './components/template-list/template-demo.component'; +import { ConfirmDialogExampleComponent } from './components/confirm-dialog/confirm-dialog-example.component'; export const appRoutes: Routes = [ { path: 'login', component: LoginComponent }, @@ -209,6 +210,10 @@ export const appRoutes: Routes = [ path: 'node-selector', loadChildren: 'app/components/content-node-selector/content-node-selector.module#AppContentNodeSelectorModule' }, + { + path: 'confirm-dialog', + component: ConfirmDialogExampleComponent + }, { path: 'settings-layout', loadChildren: 'app/components/settings/settings.module#AppSettingsModule' diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts index f1075cfbc9..e084b44383 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts @@ -41,6 +41,7 @@ export class AppLayoutComponent implements OnInit { { href: '/breadcrumb', icon: 'label', title: 'APP_LAYOUT.BREADCRUMB' }, { href: '/notifications', icon: 'alarm', title: 'APP_LAYOUT.NOTIFICATIONS' }, { href: '/card-view', icon: 'view_headline', title: 'APP_LAYOUT.CARD_VIEW' }, + { href: '/confirm-dialog', icon: 'view_headline', title: 'APP_LAYOUT.CONFIRM-DIALOG' }, { href: '/header-data', icon: 'edit', title: 'APP_LAYOUT.HEADER_DATA' }, { href: '/node-selector', icon: 'attachment', title: 'APP_LAYOUT.NODE-SELECTOR' }, { href: '/sites', icon: 'format_list_bulleted', title: 'APP_LAYOUT.SITES' }, diff --git a/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.html b/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.html new file mode 100644 index 0000000000..8aa5bc2bce --- /dev/null +++ b/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.html @@ -0,0 +1,18 @@ + + + + + Confirm Dialog Default Behaviour + + + + + + + + Confirm Dialog Custom Template + + + + + diff --git a/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.scss b/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.ts b/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.ts new file mode 100644 index 0000000000..66dc79ce91 --- /dev/null +++ b/demo-shell/src/app/components/confirm-dialog/confirm-dialog-example.component.ts @@ -0,0 +1,51 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { MatDialog } from '@angular/material'; +import { ConfirmDialogComponent } from '@alfresco/adf-content-services'; + +@Component({ + selector: 'app-confirm-dialog-example', + templateUrl: 'confirm-dialog-example.component.html', + styleUrls: ['confirm-dialog-example.component.scss'] +}) +export class ConfirmDialogExampleComponent { + + constructor(private dialog: MatDialog) { } + + openConfirmDefaultDialog() { + this.dialog.open(ConfirmDialogComponent, { + data: { + title: 'Upload', + message: `This is the default message` + }, + minWidth: '250px' + }); + } + + openConfirmCustomDialog() { + this.dialog.open(ConfirmDialogComponent, { + data: { + title: 'Upload', + message: `This is the default message`, + htmlContent: '

A

Custom

Content

' + }, + minWidth: '250px' + }); + } +} diff --git a/docs/content-services/dialogs/confirm.dialog.md b/docs/content-services/dialogs/confirm.dialog.md index 2e593e792a..5c5a4e7e45 100644 --- a/docs/content-services/dialogs/confirm.dialog.md +++ b/docs/content-services/dialogs/confirm.dialog.md @@ -37,6 +37,34 @@ dialogRef.afterClosed().subscribe((result) => { }); ``` +### Rendering custom html body +It is possible now to render a custom html instead of a plain message as confirm body via the attribute `htmlContent`. The html will be sanitized and then showed. + + +```ts +constructor(private dialog: MatDialog) {} + +... + +let files = [ + // Files defined here... +]; + +const dialogRef = this.dialog.open(ConfirmDialogComponent, { + data: { + title: 'Upload', + htmlContent: '

A

Custom

Content

' + }, + minWidth: '250px' +}); + +dialogRef.afterClosed().subscribe((result) => { + if (result === true) { + event.resumeUpload(); + } +}); +``` + ## Details This component lets the user make a yes/no choice to confirm an action. Use the diff --git a/lib/content-services/dialogs/confirm.dialog.html b/lib/content-services/dialogs/confirm.dialog.html new file mode 100644 index 0000000000..0d7869e587 --- /dev/null +++ b/lib/content-services/dialogs/confirm.dialog.html @@ -0,0 +1,17 @@ +

{{ title | translate }}

+ +

+ {{ message | translate }} +

+ + + + +
+ + + + + diff --git a/lib/content-services/dialogs/confirm.dialog.scss b/lib/content-services/dialogs/confirm.dialog.scss new file mode 100644 index 0000000000..2475496a16 --- /dev/null +++ b/lib/content-services/dialogs/confirm.dialog.scss @@ -0,0 +1,7 @@ +.adf-dialog-spacer { + flex: 1 1 auto; +} + +.adf-confirm-dialog .mat-dialog-actions .mat-button-wrapper { + text-transform: uppercase; +} diff --git a/lib/content-services/dialogs/confirm.dialog.spec.ts b/lib/content-services/dialogs/confirm.dialog.spec.ts new file mode 100644 index 0000000000..dba5684748 --- /dev/null +++ b/lib/content-services/dialogs/confirm.dialog.spec.ts @@ -0,0 +1,143 @@ +/*! + * @license + * Copyright 2019 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 { TestBed } from '@angular/core/testing'; +import { ComponentFixture } from '@angular/core/testing'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material'; +import { setupTestBed } from '@alfresco/adf-core'; +import { ConfirmDialogComponent } from './confirm.dialog'; +import { ContentTestingModule } from '../testing/content.testing.module'; +import { By } from '@angular/platform-browser'; + +describe('Confirm Dialog Component', () => { + let fixture: ComponentFixture; + let component: ConfirmDialogComponent; + const dialogRef = { + close: jasmine.createSpy('close') + }; + + const data = { + title: 'Fake Title', + message: 'Base Message', + yesLabel: 'TAKE THIS', + noLabel: 'MAYBE NO' + }; + + setupTestBed({ + imports: [ContentTestingModule], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA, useValue: data } + ] + }); + + beforeEach(() => { + dialogRef.close.calls.reset(); + fixture = TestBed.createComponent(ConfirmDialogComponent); + component = fixture.componentInstance; + }); + + afterEach(() => { + fixture.destroy(); + }); + + describe('When no html is given', () => { + beforeEach(() => { + fixture.detectChanges(); + }); + + it('should init form with folder name and description', () => { + expect(component.title).toBe('Fake Title'); + expect(component.message).toBe('Base Message'); + expect(component.yesLabel).toBe('TAKE THIS'); + expect(component.noLabel).toBe('MAYBE NO'); + }); + + it('should render the title', () => { + const titleElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-title"]') + ); + expect(titleElement).not.toBeNull(); + expect(titleElement.nativeElement.innerText).toBe('Fake Title'); + }); + + it('should render the message', () => { + const messageElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-base-message"]') + ); + expect(messageElement).not.toBeNull(); + expect(messageElement.nativeElement.innerText).toBe('Base Message'); + }); + + it('should render the YES label', () => { + const messageElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-confirmation"]') + ); + expect(messageElement).not.toBeNull(); + expect(messageElement.nativeElement.innerText).toBe('TAKE THIS'); + }); + + it('should render the NO label', () => { + const messageElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-reject"]') + ); + expect(messageElement).not.toBeNull(); + expect(messageElement.nativeElement.innerText).toBe('MAYBE NO'); + }); + }); + + describe('When custom html is given', () => { + beforeEach(() => { + component.htmlContent = `
I am about to do to you what Limp Bizkit did to music in the late ’90s.
`; + fixture.detectChanges(); + }); + + it('should render the title', () => { + const titleElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-title"]') + ); + expect(titleElement).not.toBeNull(); + expect(titleElement.nativeElement.innerText).toBe('Fake Title'); + }); + + it('should render the custom html', () => { + const customElement = fixture.nativeElement.querySelector( + '[data-automation-id="adf-confirm-dialog-custom-content"] div' + ); + expect(customElement).not.toBeNull(); + expect(customElement.innerText).toBe( + 'I am about to do to you what Limp Bizkit did to music in the late ’90s.' + ); + }); + + it('should render the YES label', () => { + const messageElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-confirmation"]') + ); + expect(messageElement).not.toBeNull(); + expect(messageElement.nativeElement.innerText).toBe('TAKE THIS'); + }); + + it('should render the NO label', () => { + const messageElement = fixture.debugElement.query( + By.css('[data-automation-id="adf-confirm-dialog-reject"]') + ); + expect(messageElement).not.toBeNull(); + expect(messageElement.nativeElement.innerText).toBe('MAYBE NO'); + }); + }); +}); diff --git a/lib/content-services/dialogs/confirm.dialog.ts b/lib/content-services/dialogs/confirm.dialog.ts index d2e89d7272..b2ffef01ac 100644 --- a/lib/content-services/dialogs/confirm.dialog.ts +++ b/lib/content-services/dialogs/confirm.dialog.ts @@ -15,29 +15,14 @@ * limitations under the License. */ -import { Component, Inject, ViewEncapsulation } from '@angular/core'; +import { Component, Inject, ViewEncapsulation, SecurityContext } from '@angular/core'; import { MAT_DIALOG_DATA } from '@angular/material'; +import { DomSanitizer } from '@angular/platform-browser'; @Component({ selector: 'adf-confirm-dialog', - template: ` -

{{ title | translate }}

- -

{{ message | translate }}

-
- - - - - - `, - styles: [` - .spacer { flex: 1 1 auto; } - - .adf-confirm-dialog .mat-dialog-actions .mat-button-wrapper { - text-transform: uppercase; - } - `], + templateUrl: './confirm.dialog.html', + styleUrls: ['./confirm.dialog.scss'], host: { 'class': 'adf-confirm-dialog' }, encapsulation: ViewEncapsulation.None }) @@ -47,12 +32,18 @@ export class ConfirmDialogComponent { message: string; yesLabel: string; noLabel: string; + htmlContent: string; - constructor(@Inject(MAT_DIALOG_DATA) data) { + constructor(@Inject(MAT_DIALOG_DATA) data, private sanitizer: DomSanitizer) { data = data || {}; this.title = data.title || 'ADF_CONFIRM_DIALOG.CONFIRM'; this.message = data.message || 'ADF_CONFIRM_DIALOG.MESSAGE'; this.yesLabel = data.yesLabel || 'ADF_CONFIRM_DIALOG.YES_LABEL'; this.noLabel = data.noLabel || 'ADF_CONFIRM_DIALOG.NO_LABEL'; + this.htmlContent = data.htmlContent; + } + + public sanitizedHtmlContent() { + return this.sanitizer.sanitize(SecurityContext.HTML, this.htmlContent); } }