diff --git a/build.sh b/build.sh index 2faee4c41..814089ccc 100644 --- a/build.sh +++ b/build.sh @@ -582,6 +582,8 @@ bundleWebLibs() { ./node_modules/angular-imask/bundles/angular-imask.umd.js \ ./node_modules/@metrichor/jmespath/dist/jmespath.umd.js \ ./dist/tmp/libs/ngx-bootstrap/ngx-bootstrap.umd.js \ + ./node_modules/tabbable/dist/index.umd.js \ + ./node_modules/focus-trap/dist/focus-trap.umd.js \ -o ./dist/bundles/wmapp/scripts/wm-libs.js -b ./node_modules/.bin/terser ./dist/bundles/wmapp/scripts/wm-libs.js \ @@ -651,6 +653,8 @@ bundleMobileLibs() { ./node_modules/imask/dist/imask.min.js \ ./node_modules/@metrichor/jmespath/dist/jmespath.umd.js \ ./node_modules/angular-imask/bundles/angular-imask.umd.js \ + ./node_modules/tabbable/dist/index.umd.js \ + ./node_modules/focus-trap/dist/focus-trap.umd.js \ -o ./dist/bundles/wmmobile/scripts/wm-libs.js -b ./node_modules/.bin/terser ./dist/bundles/wmmobile/scripts/wm-libs.js \ diff --git a/package.json b/package.json index 3f47138c3..5db70525f 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "angular2-websocket": "0.9.7", "core-js": "2.5.4", "d3": "3.5.17", + "focus-trap": "^7.0.0", "fullcalendar": "5.3.1", "hammerjs": "2.0.8", "he": "1.2.0", diff --git a/projects/components/widgets/dialogs/default/src/base-dialog.ts b/projects/components/widgets/dialogs/default/src/base-dialog.ts index b72dd1751..41703c172 100644 --- a/projects/components/widgets/dialogs/default/src/base-dialog.ts +++ b/projects/components/widgets/dialogs/default/src/base-dialog.ts @@ -1,4 +1,4 @@ -import { Injector, OnDestroy, TemplateRef, Injectable } from '@angular/core'; +import { Injector, OnDestroy, TemplateRef, Injectable, ViewChild } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; import { BsModalRef, BsModalService, ModalOptions } from 'ngx-bootstrap/modal'; @@ -7,11 +7,16 @@ import { Subscription } from 'rxjs'; import {AbstractDialogService, closePopover, findRootContainer, generateGUId} from '@wm/core'; import { BaseComponent, IDialog, IWidgetConfig } from '@wm/components/base'; +import {createFocusTrap} from 'focus-trap'; + declare const _; let eventsRegistered = false; +let focusTrapObj = { +}; + const invokeOpenedCallback = (ref) => { if (ref) { setTimeout(() => { @@ -21,6 +26,14 @@ const invokeOpenedCallback = (ref) => { $('body > modal-container > div').wrap('<' + root + '/>'); } ref.invokeEventCallback('opened', {$event: {type: 'opened'}}); + // focusTrapObj will create focus trap for the respective dialog according to the titleId assigned to them which is unique. + const container = $("[aria-labelledby= "+ ref.titleId + "]")[0]; + focusTrapObj[ref.titleId] = createFocusTrap(container, { + onActivate: () => container.classList.add('is-active'), + onDeactivate: () => container.classList.remove('is-active'), + escapeDeactivates : false, + }); + focusTrapObj[ref.titleId].activate(); }); } }; @@ -43,6 +56,9 @@ export abstract class BaseDialog extends BaseComponent implements IDialog, OnDes private dialogRef: BsModalRef; public titleId:string = 'wmdialog-' + generateGUId(); + dialogOpenSubscription; + dialogCloseSubscription; + protected constructor( inj: Injector, widgetConfig: IWidgetConfig, @@ -73,6 +89,13 @@ export abstract class BaseDialog extends BaseComponent implements IDialog, OnDes } } }), + this.bsModal.onHide.subscribe(() => { + // Will de-activate focus trap for the respective dialog when they are closed. + const ref = this.dialogService.getLastOpenedDialog(); + if (focusTrapObj[ref.titleId] !== undefined) { + focusTrapObj[ref.titleId].deactivate(); + } + }), router.events.subscribe(e => { if (e instanceof NavigationEnd) { this.close();