Add focus-lock directive (#8141)

This commit is contained in:
Jan Skovgaard
2020-07-23 17:50:50 +02:00
committed by GitHub
parent 1cd79d81af
commit c95a7f2ef4
11 changed files with 134 additions and 8 deletions

View File

@@ -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"
}
];

View File

@@ -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",

View File

@@ -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);
})();

View File

@@ -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);
})();

View File

@@ -8,7 +8,7 @@
(function () {
"use strict";
function overlayService(eventsService, backdropService) {
function overlayService(eventsService, backdropService, focusLockService) {
var currentOverlay = null;
@@ -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);

View File

@@ -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"

View File

@@ -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"

View File

@@ -86,7 +86,7 @@
</ul>
</div>
<div ng-show="showPasswordFields">
<div ng-if="showPasswordFields">
<h5>
<localize key="general_changePassword">Change password</localize>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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',