Skip to content

Commit

Permalink
Add focus-lock directive (#8141)
Browse files Browse the repository at this point in the history
  • Loading branch information
BatJan authored Jul 23, 2020
1 parent 1cd79d8 commit c95a7f2
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/Umbraco.Web.UI.Client/gulp/tasks/dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ function dependencies() {
"name": "underscore",
"src": ["node_modules/underscore/underscore-min.js"],
"base": "./node_modules/underscore"
},
{
"name": "wicg-inert",
"src": [
"./node_modules/wicg-inert/dist/inert.min.js",
"./node_modules/wicg-inert/dist/inert.min.js.map"
],
"base": "./node_modules/wicg-inert"
}
];

Expand Down
3 changes: 2 additions & 1 deletion src/Umbraco.Web.UI.Client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"spectrum-colorpicker": "1.8.0",
"tinymce": "4.9.10",
"typeahead.js": "0.11.1",
"underscore": "1.9.1"
"underscore": "1.9.1",
"wicg-inert": "^3.0.2"
},
"devDependencies": {
"@babel/core": "7.6.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
(function() {
'use strict';

function FocusLock($timeout) {

function getAutoFocusElement (elements) {
var elmentWithAutoFocus = null;

elements.forEach((element) => {
if(element.getAttribute('umb-auto-focus') === 'true') {
elmentWithAutoFocus = element;
}
});

return elmentWithAutoFocus;
}

function link(scope, element) {

function onInit() {
// List of elements that can be focusable within the focus lock
var focusableElementsSelector = 'a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled])';
var bodyElement = document.querySelector('body');

$timeout(function() {
var target = element[0];

var focusableElements = target.querySelectorAll(focusableElementsSelector);
var defaultFocusedElement = getAutoFocusElement(focusableElements);
var firstFocusableElement = focusableElements[0];
var lastFocusableElement = focusableElements[focusableElements.length -1];

// We need to add the tabbing-active class in order to highlight the focused button since the default style is
// outline: none; set in the stylesheet specifically
bodyElement.classList.add('tabbing-active');

// If there is no default focused element put focus on the first focusable element in the nodelist
if(defaultFocusedElement === null ){
firstFocusableElement.focus();
}

target.addEventListener('keydown', function(event){
var isTabPressed = (event.key === 'Tab' || event.keyCode === 9);

if (!isTabPressed){
return;
}

// If shift + tab key
if(event.shiftKey){
// Set focus on the last focusable element if shift+tab are pressed meaning we go backwards
if(document.activeElement === firstFocusableElement){
lastFocusableElement.focus();
event.preventDefault();
}
}
// Else only the tab key is pressed
else{
// Using only the tab key we set focus on the first focusable element mening we go forward
if (document.activeElement === lastFocusableElement) {
firstFocusableElement.focus();
event.preventDefault();
}
}
});
}, 250);
}

onInit();
}

var directive = {
restrict: 'A',
link: link
};

return directive;
}

angular.module('umbraco.directives').directive('umbFocusLock', FocusLock);

})();
26 changes: 26 additions & 0 deletions src/Umbraco.Web.UI.Client/src/common/services/focuslock.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(function () {
"use strict";

function focusLockService() {
var elementToInert = document.querySelector('#mainwrapper');

function addInertAttribute() {
elementToInert.setAttribute('inert', true);
}

function removeInertAttribute() {
elementToInert.removeAttribute('inert');
}

var service = {
addInertAttribute: addInertAttribute,
removeInertAttribute: removeInertAttribute
}

return service;

}

angular.module("umbraco.services").factory("focusLockService", focusLockService);

})();
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
(function () {
"use strict";

function overlayService(eventsService, backdropService) {
function overlayService(eventsService, backdropService, focusLockService) {

var currentOverlay = null;

Expand Down Expand Up @@ -43,12 +43,14 @@
}

overlay.show = true;
focusLockService.addInertAttribute();
backdropService.open(backdropOptions);
currentOverlay = overlay;
eventsService.emit("appState.overlay", overlay);
}

function close() {
focusLockService.removeInertAttribute();
backdropService.close();
currentOverlay = null;
eventsService.emit("appState.overlay", null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<umb-editor-container>
<umb-box>
<umb-box-content>
<div class="form-search" ng-hide="model.filter === false" style="margin-bottom: 15px;">
<div class="form-search" ng-if="model.filter" style="margin-bottom: 15px;">
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<div ng-controller="Umbraco.Overlays.ItemPickerOverlay" class="umb-itempicker">

<div class="form-search" ng-hide="model.filter === false" style="margin-bottom: 15px;">
<div class="form-search" ng-if="model.filter" style="margin-bottom: 15px;">
<i class="icon-search" aria-hidden="true"></i>
<input type="text"
ng-model="searchTerm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ <h5><localize key="user_yourHistory" /></h5>
</ul>
</div>

<div ng-show="showPasswordFields">
<div ng-if="showPasswordFields">

<h5>
<localize key="general_changePassword">Change password</localize>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
<div data-element="{{name}}" class="umb-overlay umb-overlay-{{position}} umb-overlay--{{size}}" on-outside-click="outSideClick()" role="dialog" aria-labelledby="umb-overlay-title" aria-describedby="umb-overlay-description">
<div
data-element="{{name}}"
class="umb-overlay umb-overlay-{{position}} umb-overlay--{{size}}"
on-outside-click="outSideClick()"
umb-focus-lock
role="dialog"
aria-labelledby="umb-overlay-title"
aria-describedby="umb-overlay-description">
<ng-form class="umb-overlay__form" name="overlayForm" novalidate val-form-manager>
<div data-element="overlay-header" class="umb-overlay-header" ng-show="!model.hideHeader">
<h1 class="umb-overlay__title" id="umb-overlay-title">{{model.title}}</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<div ng-switch-when="true">

<ng-form name="changePasswordForm">
<umb-control-group alias="resetPassword" label="@user_resetPassword" ng-show="vm.config.enableReset">
<umb-control-group alias="resetPassword" label="@user_resetPassword" ng-if="vm.config.enableReset">
<umb-checkbox model="vm.passwordValues.reset" server-validation-field="resetPassword"
on-change="vm.showReset = !vm.showReset" />
<span ng-messages="changePasswordForm.resetPassword.$error" show-validation-on-submit>
Expand Down
1 change: 1 addition & 0 deletions src/Umbraco.Web/JavaScript/JsInitialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

'lib/chart.js/chart.min.js',
'lib/angular-chart.js/angular-chart.min.js',
'lib/wicg-inert/dist/inert.min.js',

'lib/umbraco/Extensions.js',

Expand Down

0 comments on commit c95a7f2

Please sign in to comment.