From 4d16703d58b99107a1089c5421fb82f1fc4567fc Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 2 Aug 2020 17:39:47 +0200
Subject: [PATCH 17/35] Narrow attributes to look for down to the bare minimum
of the umb-focus-lock
---
.../directives/components/forms/umbfocuslock.directive.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 7b5445cc4feb..bce58e3f603d 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -66,7 +66,7 @@
var observer = new MutationObserver(domChange);
// Options for the observer (which mutations to observe)
- var config = { attributes: true, attributeOldValue: true, childList: true, subtree: true};
+ var config = { attributes: true, attributeFilter: ['umb-focus-lock'], childList: true, subtree: true};
function domChange(mutationsList) {
if(!init){
From 051c8f9031c22aae49a526d87187e02a91898458 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 2 Aug 2020 17:45:03 +0200
Subject: [PATCH 18/35] Refactor to using good ol' for loop (Fastest)
---
.../directives/components/forms/umbfocuslock.directive.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index bce58e3f603d..3ebd8d89218e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -74,8 +74,9 @@
return;
}
- for (var mutation of mutationsList) {
-
+ for (let index = 0; index < mutationsList.length; index++) {
+ const mutation = mutationsList[index];
+
// Look at the attributes - If the disabled attribute changes we call the getFocusableElements method
// ensuring the enabled element can be tabbed into
if (mutation.type === 'attributes') {
From 64ffc49934045573f25837923573b305d36e4fa0 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 2 Aug 2020 18:39:26 +0200
Subject: [PATCH 19/35] Disconnect the observer once the init function has been
called - Massive performance improvement
---
.../directives/components/forms/umbfocuslock.directive.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 3ebd8d89218e..54a68efdcc7e 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -83,6 +83,9 @@
if(mutation.attributeName === 'umb-focus-lock') {
onInit(mutation.target);
+
+ // Disconnect the observer once onInit has been called again
+ observer.disconnect();
}
}
}
@@ -149,3 +152,7 @@
angular.module('umbraco.directives').directive('umbFocusLock', FocusLock);
})();
+
+
+// TODO: observer.disconnect() on destroy - Ensure it does not conflict with the eventlistener for the closed event!
+// TODO: removeEventHandlers on destroy - Be ware of the same as weith observer.disconnect();
From 1108a676663602bc16aec0712a402ac68930f1e0 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Mon, 3 Aug 2020 21:10:12 +0200
Subject: [PATCH 20/35] Event handler cleanup
---
.../forms/umbfocuslock.directive.js | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 54a68efdcc7e..3a0b65cb2ca8 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -95,8 +95,31 @@
observer.observe(targetToObserve, config);
}
+ function cleanupEventHandlers() {
+ const infiniteEditorsWrapper = document.querySelector('.umb-editors');
+ const infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor'));
+ const activeEditor = infiniteEditors[infiniteEditors.length - 1];
+ const inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
+
+ if(inactiveEditors.length > 0) {
+ for (let index = 0; index < inactiveEditors.length; index++) {
+ const inactiveEditor = inactiveEditors[index];
+
+ // Remove event handlers from inactive editors
+ inactiveEditor.removeEventListener('keydown', handleKeydown);
+ }
+ }
+ else {
+ // Remove event handlers from the active editor
+ activeEditor.removeEventListener('keydown', handleKeydown);
+ }
+ }
+
function onInit(targetElm) {
$timeout(function() {
+
+ cleanupEventHandlers();
+
getFocusableElements(targetElm);
if(focusableElements.length > 0) {
From f0239aabc6489daf001955bb70db1cda50db0553 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Tue, 4 Aug 2020 21:47:43 +0200
Subject: [PATCH 21/35] Refactor the code to re-initialize the init method on
destroy in case infinite editors still exists in the DOM
---
.../forms/umbfocuslock.directive.js | 82 +++++++++----------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 3a0b65cb2ca8..110b5dbcf4c9 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -20,11 +20,19 @@
var focusableElements;
var firstFocusableElement;
var lastFocusableElement;
+ var infiniteEditorsWrapper;
+ var infiniteEditors;
+ var disconnectObserver = false;
// List of elements that can be focusable within the focus lock
var focusableElementsSelector = 'a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
var bodyElement = document.querySelector('body');
+ function getDomNodes(){
+ infiniteEditorsWrapper = document.querySelector('.umb-editors');
+ infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor'));
+ }
+
function getFocusableElements(targetElm) {
var elm = targetElm ? targetElm : target;
focusableElements = elm.querySelectorAll(focusableElementsSelector);
@@ -66,38 +74,22 @@
var observer = new MutationObserver(domChange);
// Options for the observer (which mutations to observe)
- var config = { attributes: true, attributeFilter: ['umb-focus-lock'], childList: true, subtree: true};
-
- function domChange(mutationsList) {
- if(!init){
- getFocusableElements();
- return;
- }
-
- for (let index = 0; index < mutationsList.length; index++) {
- const mutation = mutationsList[index];
-
- // Look at the attributes - If the disabled attribute changes we call the getFocusableElements method
- // ensuring the enabled element can be tabbed into
- if (mutation.type === 'attributes') {
+ var config = { attributes: true, childList: true, subtree: true};
- if(mutation.attributeName === 'umb-focus-lock') {
- onInit(mutation.target);
-
- // Disconnect the observer once onInit has been called again
- observer.disconnect();
- }
- }
- }
+ function domChange() {
+ getFocusableElements();
}
// Start observing the target node for configured mutations
observer.observe(targetToObserve, config);
+
+ // Disconnect observer
+ if(disconnectObserver){
+ observer.disconnect();
+ }
}
function cleanupEventHandlers() {
- const infiniteEditorsWrapper = document.querySelector('.umb-editors');
- const infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor'));
const activeEditor = infiniteEditors[infiniteEditors.length - 1];
const inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
@@ -115,10 +107,17 @@
}
}
- function onInit(targetElm) {
- $timeout(function() {
+ function onInit(targetElm, delay) {
+ const timeout = delay ? delay : 500;
+
+ $timeout(() => {
- cleanupEventHandlers();
+ getDomNodes();
+
+ // Only do the cleanup if we're in infinite editing mode
+ if(infiniteEditors.length > 0){
+ cleanupEventHandlers();
+ }
getFocusableElements(targetElm);
@@ -144,22 +143,25 @@
target.addEventListener('keydown', handleKeydown);
}
- }, 500);
+ }, timeout);
}
onInit();
- // Reinitialize the onInit() method if it was not the last editor that was closed
- eventsService.on('appState.editors.close', (event, args) => {
- if(args && args.editors.length !== 0) {
- if(target.hasAttribute('umb-focus-lock')) {
- observeDomChanges(true);
- }
- }
- });
-
- // Remove the event listener
+ // If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
+ // Make sure to disconnect the observer so we potentially don't end up with having many active ones
+ disconnectObserver = true;
+
+ // Pass the correct editor in order to find the focusable elements
+ const newTarget = infiniteEditors[infiniteEditors.length - 2];
+
+ if(infiniteEditors.length > 1){
+ // Passing the timeout parameter as a string on purpose to bypass the falsy value that a number would give
+ onInit(newTarget, '0');
+ return;
+ }
+
target.removeEventListener('keydown', handleKeydown);
});
}
@@ -175,7 +177,3 @@
angular.module('umbraco.directives').directive('umbFocusLock', FocusLock);
})();
-
-
-// TODO: observer.disconnect() on destroy - Ensure it does not conflict with the eventlistener for the closed event!
-// TODO: removeEventHandlers on destroy - Be ware of the same as weith observer.disconnect();
From 538600d67fa0340b0adc54ca78b1b1fb1b69377a Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Tue, 4 Aug 2020 22:07:23 +0200
Subject: [PATCH 22/35] Align codestyle
---
.../components/forms/umbfocuslock.directive.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 110b5dbcf4c9..c6458ef81d90 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -90,12 +90,12 @@
}
function cleanupEventHandlers() {
- const activeEditor = infiniteEditors[infiniteEditors.length - 1];
- const inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
+ var activeEditor = infiniteEditors[infiniteEditors.length - 1];
+ var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
if(inactiveEditors.length > 0) {
- for (let index = 0; index < inactiveEditors.length; index++) {
- const inactiveEditor = inactiveEditors[index];
+ for (var index = 0; index < inactiveEditors.length; index++) {
+ var inactiveEditor = inactiveEditors[index];
// Remove event handlers from inactive editors
inactiveEditor.removeEventListener('keydown', handleKeydown);
@@ -108,7 +108,7 @@
}
function onInit(targetElm, delay) {
- const timeout = delay ? delay : 500;
+ var timeout = delay ? delay : 500;
$timeout(() => {
@@ -154,7 +154,7 @@
disconnectObserver = true;
// Pass the correct editor in order to find the focusable elements
- const newTarget = infiniteEditors[infiniteEditors.length - 2];
+ var newTarget = infiniteEditors[infiniteEditors.length - 2];
if(infiniteEditors.length > 1){
// Passing the timeout parameter as a string on purpose to bypass the falsy value that a number would give
From 4e7a5774a547e5fadaa1b3d29415ae1d20509d0e Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Thu, 6 Aug 2020 20:37:26 +0200
Subject: [PATCH 23/35] Add logic to deal with "lastKnowFocused" elements in
infinite editing mode
---
.../forms/umbfocuslock.directive.js | 77 ++++++++++++++++---
1 file changed, 67 insertions(+), 10 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index c6458ef81d90..af40e2204d69 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -1,7 +1,7 @@
(function() {
'use strict';
- function FocusLock($timeout, eventsService) {
+ function FocusLock($timeout, $rootScope) {
function getAutoFocusElement (elements) {
var elmentWithAutoFocus = null;
@@ -23,6 +23,13 @@
var infiniteEditorsWrapper;
var infiniteEditors;
var disconnectObserver = false;
+ var closingEditor = false;
+
+ if(!$rootScope.lastKnowFocusedElements){
+ $rootScope.lastKnowFocusedElements = [];
+ }
+
+ $rootScope.lastKnowFocusedElements.push(document.activeElement);
// List of elements that can be focusable within the focus lock
var focusableElementsSelector = 'a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
@@ -66,6 +73,55 @@
}
}
}
+
+ function clearLastKnownFocusedElements() {
+ $rootScope.lastKnowFocusedElements = [];
+ }
+
+ function setElementFocus() {
+ var defaultFocusedElement = getAutoFocusElement(focusableElements);
+ var lastknownElement;
+
+ if(closingEditor){
+ var lastItemIndex = $rootScope.lastKnowFocusedElements.length - 1;
+ var editorInfo = infiniteEditors[0].querySelector('.editor-info');
+
+ // If there is only one editor open, search for the "editor-info" inside it and set focus on it
+ // This is relevant when a property editor has been selected and the editor where we selected it from
+ // is closed taking us back to the first layer
+ // Otherwise set it to the last element in the lastKnownFocusedElements array
+ if(infiniteEditors.length === 1 && editorInfo !== null){
+ lastknownElement = editorInfo;
+
+ // Clear the array
+ clearLastKnownFocusedElements();
+ }
+ else {
+ lastknownElement = $rootScope.lastKnowFocusedElements[lastItemIndex];
+
+ // Remove the last item from the array so we always set the correct lastKnowFocus for each layer
+ $rootScope.lastKnowFocusedElements.splice(lastItemIndex, 1);
+ }
+
+ // Update the lastknowelement variable here
+ closingEditor = false;
+ }
+
+ // 1st - we check for any last known element - Usually the element the trigger the opening of a new layer
+ // If it exists it will receive fous
+ // 2nd - We check to see if a default focus has been set using the umb-auto-focus directive. If not we set focus on
+ // the first focusable element
+ // 3rd - Otherwise put the focus on the default focused element
+ if(lastknownElement){
+ lastknownElement.focus();
+ }
+ else if(defaultFocusedElement === null ){
+ firstFocusableElement.focus();
+ }
+ else {
+ defaultFocusedElement.focus();
+ }
+ }
function observeDomChanges(init) {
var targetToObserve = init ? document.querySelector('.umb-editors') : target;
@@ -124,20 +180,12 @@
if(focusableElements.length > 0) {
observeDomChanges();
-
- var defaultFocusedElement = getAutoFocusElement(focusableElements);
// 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();
- }
- else {
- defaultFocusedElement.focus();
- }
+ setElementFocus();
// Handle keydown
target.addEventListener('keydown', handleKeydown);
@@ -157,11 +205,20 @@
var newTarget = infiniteEditors[infiniteEditors.length - 2];
if(infiniteEditors.length > 1){
+ // Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes
+ // active
+ closingEditor = true;
+
// Passing the timeout parameter as a string on purpose to bypass the falsy value that a number would give
onInit(newTarget, '0');
+
return;
}
+ // Clear lastKnowFocusedElements
+ clearLastKnownFocusedElements();
+
+ // Cleanup event handler
target.removeEventListener('keydown', handleKeydown);
});
}
From 18bbe3489577681e9d0ecced0f682e1c6c5d43a6 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 23 Aug 2020 00:19:10 +0200
Subject: [PATCH 24/35] Re-add attributes after merge with contrib branch
---
.../src/views/components/editor/umb-editors.html | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editors.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editors.html
index 9bb5a6161d78..4d6ceb2ffca1 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editors.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editors.html
@@ -1,7 +1,9 @@
- 0) {
for (var index = 0; index < inactiveEditors.length; index++) {
var inactiveEditor = inactiveEditors[index];
-
+
// Remove event handlers from inactive editors
inactiveEditor.removeEventListener('keydown', handleKeydown);
}
@@ -169,7 +169,7 @@
$timeout(() => {
getDomNodes();
-
+
// Only do the cleanup if we're in infinite editing mode
if(infiniteEditors.length > 0){
cleanupEventHandlers();
@@ -180,13 +180,13 @@
if(focusableElements.length > 0) {
observeDomChanges();
-
+
// 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');
setElementFocus();
-
+
// Handle keydown
target.addEventListener('keydown', handleKeydown);
}
@@ -214,8 +214,8 @@
return;
}
-
- // Clear lastKnowFocusedElements
+
+ // Clear lastKnownFocusableElements
clearLastKnownFocusedElements();
// Cleanup event handler
From b69af2a5827f5f411fc456c7e984d980f0c8673e Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 26 Sep 2020 16:28:29 +0200
Subject: [PATCH 26/35] Move onInit into the $includeContentLoaded event and
set the timeout to 0
---
.../components/forms/umbfocuslock.directive.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 2c2f2fc6bec5..30edc6058c31 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -191,10 +191,16 @@
target.addEventListener('keydown', handleKeydown);
}
- }, timeout);
+ }, 0);
}
- onInit();
+ scope.$on('$includeContentLoaded', () => {
+ scope.$evalAsync();
+
+ onInit();
+ });
+
+ // onInit();
// If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
From e8c7156107a73c88e8729623ab0ad3de37415987 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 27 Sep 2020 21:01:18 +0200
Subject: [PATCH 27/35] Make sure to add focus to elements with role="button"
as well
---
.../directives/components/forms/umbfocuslock.directive.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 30edc6058c31..37a43efc7002 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -32,7 +32,7 @@
$rootScope.lastKnownFocusableElements.push(document.activeElement);
// List of elements that can be focusable within the focus lock
- var focusableElementsSelector = 'a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
+ var focusableElementsSelector = '[role="button"], a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
var bodyElement = document.querySelector('body');
function getDomNodes(){
From 664a586b426f648879a3c54824ad968109dc87cf Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 27 Sep 2020 22:17:09 +0200
Subject: [PATCH 28/35] Add comments and remove timeout / delay settings
---
.../components/forms/umbfocuslock.directive.js | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 37a43efc7002..9a03928e6e6b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -82,6 +82,7 @@
var defaultFocusedElement = getAutoFocusElement(focusableElements);
var lastknownElement;
+ // If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
if(closingEditor){
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
var editorInfo = infiniteEditors[0].querySelector('.editor-info');
@@ -163,8 +164,7 @@
}
}
- function onInit(targetElm, delay) {
- var timeout = delay ? delay : 500;
+ function onInit(targetElm) {
$timeout(() => {
@@ -191,7 +191,7 @@
target.addEventListener('keydown', handleKeydown);
}
- }, 0);
+ });
}
scope.$on('$includeContentLoaded', () => {
@@ -200,8 +200,6 @@
onInit();
});
- // onInit();
-
// If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
// Make sure to disconnect the observer so we potentially don't end up with having many active ones
@@ -215,8 +213,7 @@
// active
closingEditor = true;
- // Passing the timeout parameter as a string on purpose to bypass the falsy value that a number would give
- onInit(newTarget, '0');
+ onInit(newTarget);
return;
}
From 44c34e211c1289d32c090d7d054d40c8c1c88b61 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 27 Sep 2020 23:07:05 +0200
Subject: [PATCH 29/35] Debouce domObserver
---
.../directives/components/forms/umbfocuslock.directive.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 9a03928e6e6b..bc877f3e1967 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -128,7 +128,7 @@
var targetToObserve = init ? document.querySelector('.umb-editors') : target;
// Watch for DOM changes - so we can refresh the focusable elements if an element
// changes from being disabled to being enabled for instance
- var observer = new MutationObserver(domChange);
+ var observer = new MutationObserver(_.debounce(domChange, 200));
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true};
From 5c02d18760868eb5b4f235f22622e42f3865e7af Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sun, 27 Sep 2020 23:29:20 +0200
Subject: [PATCH 30/35] Wrap init function in safeApply
---
.../directives/components/forms/umbfocuslock.directive.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index bc877f3e1967..2355478a237f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -1,7 +1,7 @@
(function() {
'use strict';
- function FocusLock($timeout, $rootScope) {
+ function FocusLock($timeout, $rootScope, angularHelper) {
function getAutoFocusElement (elements) {
var elmentWithAutoFocus = null;
@@ -195,9 +195,9 @@
}
scope.$on('$includeContentLoaded', () => {
- scope.$evalAsync();
-
- onInit();
+ angularHelper.safeApply(scope, () => {
+ onInit();
+ });
});
// If more than one editor is still open then re-initialize otherwise remove the event listener
From 7fe763742b8b27bd178e1221f9224083a719388c Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 17 Oct 2020 14:31:27 +0200
Subject: [PATCH 31/35] Add comments to help remember / understand what things
are intended to be doing and add missing event param as well as getting rid
of some unused code
---
.../components/forms/umbfocuslock.directive.js | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 2355478a237f..7310abd8bc4f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -3,6 +3,7 @@
function FocusLock($timeout, $rootScope, angularHelper) {
+ // If the umb-auto-focus directive is in use we respect that by leaving the default focus on it instead of choosing the first focusable element using this function
function getAutoFocusElement (elements) {
var elmentWithAutoFocus = null;
@@ -33,6 +34,8 @@
// List of elements that can be focusable within the focus lock
var focusableElementsSelector = '[role="button"], a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
+
+ // Grab the body element so we can add the tabbing class on it when needed
var bodyElement = document.querySelector('body');
function getDomNodes(){
@@ -49,7 +52,7 @@
return focusableElements;
}
- function handleKeydown() {
+ function handleKeydown(event) {
var isTabPressed = (event.key === 'Tab' || event.keyCode === 9);
if (!isTabPressed){
@@ -124,8 +127,7 @@
}
}
- function observeDomChanges(init) {
- var targetToObserve = init ? document.querySelector('.umb-editors') : target;
+ function observeDomChanges() {
// Watch for DOM changes - so we can refresh the focusable elements if an element
// changes from being disabled to being enabled for instance
var observer = new MutationObserver(_.debounce(domChange, 200));
@@ -138,7 +140,7 @@
}
// Start observing the target node for configured mutations
- observer.observe(targetToObserve, config);
+ observer.observe(target, config);
// Disconnect observer
if(disconnectObserver){
@@ -200,6 +202,7 @@
});
});
+ // Only used for resetting the focus lock on infinite editors whenever a layer is closed and there is still one open
// If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
// Make sure to disconnect the observer so we potentially don't end up with having many active ones
@@ -237,3 +240,6 @@
angular.module('umbraco.directives').directive('umbFocusLock', FocusLock);
})();
+
+
+// TODO: Ensure the domObserver is NOT started when there is only one infinite overlay and it's being destroyed!
From 863fdff6fdc57149aea35c508d82b5764d283487 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 17 Oct 2020 14:54:17 +0200
Subject: [PATCH 32/35] Adding more comments
---
.../components/forms/umbfocuslock.directive.js | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 7310abd8bc4f..18f5881a11d9 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -46,6 +46,8 @@
function getFocusableElements(targetElm) {
var elm = targetElm ? targetElm : target;
focusableElements = elm.querySelectorAll(focusableElementsSelector);
+
+ // Maybe don't set these here but wait doing it until the observer has run?
firstFocusableElement = focusableElements[0];
lastFocusableElement = focusableElements[focusableElements.length -1];
@@ -83,7 +85,7 @@
function setElementFocus() {
var defaultFocusedElement = getAutoFocusElement(focusableElements);
- var lastknownElement;
+ var lastKnownElement;
// If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
if(closingEditor){
@@ -95,13 +97,13 @@
// is closed taking us back to the first layer
// Otherwise set it to the last element in the lastKnownFocusedElements array
if(infiniteEditors.length === 1 && editorInfo !== null){
- lastknownElement = editorInfo;
+ lastKnownElement = editorInfo;
// Clear the array
clearLastKnownFocusedElements();
}
else {
- lastknownElement = $rootScope.lastKnownFocusableElements[lastItemIndex];
+ lastKnownElement = $rootScope.lastKnownFocusableElements[lastItemIndex];
// Remove the last item from the array so we always set the correct lastKnowFocus for each layer
$rootScope.lastKnownFocusableElements.splice(lastItemIndex, 1);
@@ -116,8 +118,8 @@
// 2nd - We check to see if a default focus has been set using the umb-auto-focus directive. If not we set focus on
// the first focusable element
// 3rd - Otherwise put the focus on the default focused element
- if(lastknownElement){
- lastknownElement.focus();
+ if(lastKnownElement){
+ lastKnownElement.focus();
}
else if(defaultFocusedElement === null ){
firstFocusableElement.focus();
@@ -135,6 +137,8 @@
// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true};
+ // Whenever the DOM changes ensure the list of focused elements is updated
+ // TODO: Maybe track the first call for this function ensuring first and last focusable elements are detected initially and then just disover focusable elements
function domChange() {
getFocusableElements();
}
@@ -170,9 +174,10 @@
$timeout(() => {
+ // Fetch the DOM nodes we need
getDomNodes();
- // Only do the cleanup if we're in infinite editing mode
+ // Cleanup event handlers if we're in infinite editing mode
if(infiniteEditors.length > 0){
cleanupEventHandlers();
}
@@ -202,7 +207,6 @@
});
});
- // Only used for resetting the focus lock on infinite editors whenever a layer is closed and there is still one open
// If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
// Make sure to disconnect the observer so we potentially don't end up with having many active ones
From ce41333ec73f76c977adff8887737e46ae469f26 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 17 Oct 2020 17:07:54 +0200
Subject: [PATCH 33/35] Move setting of first and last focusable elements into
the setElement function
---
.../components/forms/umbfocuslock.directive.js | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 18f5881a11d9..b0138d3b95f8 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -46,12 +46,6 @@
function getFocusableElements(targetElm) {
var elm = targetElm ? targetElm : target;
focusableElements = elm.querySelectorAll(focusableElementsSelector);
-
- // Maybe don't set these here but wait doing it until the observer has run?
- firstFocusableElement = focusableElements[0];
- lastFocusableElement = focusableElements[focusableElements.length -1];
-
- return focusableElements;
}
function handleKeydown(event) {
@@ -87,6 +81,10 @@
var defaultFocusedElement = getAutoFocusElement(focusableElements);
var lastKnownElement;
+ // Set first and last focusable elements
+ firstFocusableElement = focusableElements[0];
+ lastFocusableElement = focusableElements[focusableElements.length - 1];
+
// If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
if(closingEditor){
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
From b75ab71eb4fdf4c9203ccc042faca466f3a9fdf1 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 17 Oct 2020 19:21:19 +0200
Subject: [PATCH 34/35] Remove todo
---
.../common/directives/components/forms/umbfocuslock.directive.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index b0138d3b95f8..9ed336390e91 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -136,7 +136,6 @@
var config = { attributes: true, childList: true, subtree: true};
// Whenever the DOM changes ensure the list of focused elements is updated
- // TODO: Maybe track the first call for this function ensuring first and last focusable elements are detected initially and then just disover focusable elements
function domChange() {
getFocusableElements();
}
From a408a387a2acefdea38fcd850b222cddddab23a1 Mon Sep 17 00:00:00 2001
From: BatJan <1932158+BatJan@users.noreply.github.com>
Date: Sat, 17 Oct 2020 20:03:12 +0200
Subject: [PATCH 35/35] Move the setup of first and last focusable elements
back to where they were...
---
.../directives/components/forms/umbfocuslock.directive.js | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 9ed336390e91..448f3fc8b1cf 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -46,6 +46,9 @@
function getFocusableElements(targetElm) {
var elm = targetElm ? targetElm : target;
focusableElements = elm.querySelectorAll(focusableElementsSelector);
+ // Set first and last focusable elements
+ firstFocusableElement = focusableElements[0];
+ lastFocusableElement = focusableElements[focusableElements.length - 1];
}
function handleKeydown(event) {
@@ -81,10 +84,6 @@
var defaultFocusedElement = getAutoFocusElement(focusableElements);
var lastKnownElement;
- // Set first and last focusable elements
- firstFocusableElement = focusableElements[0];
- lastFocusableElement = focusableElements[focusableElements.length - 1];
-
// If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
if(closingEditor){
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;