From c57fef7b1e616a077c82cde883a3ade188a8ac16 Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 6 Sep 2018 19:05:10 +0300 Subject: [PATCH 1/5] suppress focus outline when invoked via mouse fixes #495 --- js/dom.js | 2 ++ msgbox/msgbox.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/js/dom.js b/js/dom.js index 1034542b..495cff8f 100644 --- a/js/dom.js +++ b/js/dom.js @@ -329,6 +329,7 @@ function focusAccessibility() { if (focusables.includes(el.localName)) { if (el.dataset.focusedViaClick === undefined) { el.dataset.focusedViaClick = ''; + focusAccessibility.lastFocusedViaClick = true; } return; } @@ -337,6 +338,7 @@ function focusAccessibility() { function keepOutlineOnTab(event) { if (event.which === 9) { + focusAccessibility.lastFocusedViaClick = false; setTimeout(keepOutlineOnTab, 0, true); return; } else if (event !== true) { diff --git a/msgbox/msgbox.js b/msgbox/msgbox.js index 7a6ba81e..1a236c41 100644 --- a/msgbox/msgbox.js +++ b/msgbox/msgbox.js @@ -36,6 +36,10 @@ function messageBox({ messageBox.originalFocus = document.activeElement; moveFocus(messageBox.element, 1); + if (focusAccessibility.lastFocusedViaClick && document.activeElement) { + document.activeElement.dataset.focusedViaClick = ''; + } + if (typeof onshow === 'function') { onshow(messageBox.element); } From 373fe5f510606005454d9e439c7bd142da481b6a Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 6 Sep 2018 19:08:56 +0300 Subject: [PATCH 2/5] code cosmetics --- js/dom.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/js/dom.js b/js/dom.js index 495cff8f..a19b637a 100644 --- a/js/dom.js +++ b/js/dom.js @@ -313,20 +313,30 @@ function initCollapsibles({bindClickOn = 'h2'} = {}) { } } - +// Makes the focus outline appear on keyboard tabbing, but not on mouse clicks. function focusAccessibility() { - // Makes the focus outline appear on keyboard tabbing, but not on mouse clicks. - // Since we don't want full layout recalc, we modify only the closest focusable element, - // which we try to find in DOM for this many parentElement jumps: - const focusables = focusAccessibility.ELEMENTS = - ['a', 'button', 'input', 'textarea', 'label', 'select', 'summary']; + // last event's focusedViaClick + focusAccessibility.lastFocusedViaClick = false; + // tags of focusable elements; + // to avoid a full layout recalc we modify the closest one + focusAccessibility.ELEMENTS = [ + 'a', + 'button', + 'input', + 'textarea', + 'label', + 'select', + 'summary', + ]; + // try to find a focusable parent for this many parentElement jumps: const GIVE_UP_DEPTH = 4; + addEventListener('mousedown', suppressOutlineOnClick, {passive: true}); addEventListener('keydown', keepOutlineOnTab, {passive: true}); function suppressOutlineOnClick({target}) { for (let el = target, i = 0; el && i++ < GIVE_UP_DEPTH; el = el.parentElement) { - if (focusables.includes(el.localName)) { + if (focusAccessibility.ELEMENTS.includes(el.localName)) { if (el.dataset.focusedViaClick === undefined) { el.dataset.focusedViaClick = ''; focusAccessibility.lastFocusedViaClick = true; @@ -345,7 +355,7 @@ function focusAccessibility() { return; } let el = document.activeElement; - if (!el || !focusables.includes(el.localName)) { + if (!el || !focusAccessibility.ELEMENTS.includes(el.localName)) { return; } if (el.dataset.focusedViaClick !== undefined) { From 26d7c2677069ff0fdef28d288aea32a0c0de237f Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 6 Sep 2018 19:33:10 +0300 Subject: [PATCH 3/5] notify embedder on closing colorpicker fixup 7fea2cfc: messageBox's Esc handler wasn't restored --- vendor-overwrites/colorpicker/colorpicker.js | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/vendor-overwrites/colorpicker/colorpicker.js b/vendor-overwrites/colorpicker/colorpicker.js index 2617b5e9..38f4af75 100644 --- a/vendor-overwrites/colorpicker/colorpicker.js +++ b/vendor-overwrites/colorpicker/colorpicker.js @@ -222,11 +222,9 @@ } } - function hide({notify = true} = {}) { + function hide() { if (shown) { - if (notify) { - colorpickerCallback(''); - } + colorpickerCallback(''); unregisterEvents(); focusNoScroll(prevFocusedElement); $root.remove(); @@ -623,7 +621,7 @@ case 27: e.preventDefault(); e.stopPropagation(); - hide({notify: false}); + hide(); break; } } @@ -643,17 +641,20 @@ //region Event utilities function colorpickerCallback(colorString = currentColorToString()) { - // Esc pressed? - if (!colorString) { + const isCallable = typeof options.callback === 'function'; + // hiding + if (!colorString && isCallable) { options.callback(''); + return; } if ( userActivity && - $inputs[currentFormat].every(el => el.checkValidity()) && - typeof options.callback === 'function' + $inputs[currentFormat].every(el => el.checkValidity()) ) { lastOutputColor = colorString.replace(/\b0\./g, '.'); - options.callback(lastOutputColor); + if (isCallable) { + options.callback(lastOutputColor); + } } } From 4a877ad27b6f3314e0a8f96bdfa2faaf27169771 Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 6 Sep 2018 20:42:48 +0300 Subject: [PATCH 4/5] fixup c57fef7b: always set lastFocusedViaClick #495 --- js/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/dom.js b/js/dom.js index a19b637a..825d1e78 100644 --- a/js/dom.js +++ b/js/dom.js @@ -337,9 +337,9 @@ function focusAccessibility() { function suppressOutlineOnClick({target}) { for (let el = target, i = 0; el && i++ < GIVE_UP_DEPTH; el = el.parentElement) { if (focusAccessibility.ELEMENTS.includes(el.localName)) { + focusAccessibility.lastFocusedViaClick = true; if (el.dataset.focusedViaClick === undefined) { el.dataset.focusedViaClick = ''; - focusAccessibility.lastFocusedViaClick = true; } return; } From b90f7bfce51c308b7965f8f44d7b066227e8f24a Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 6 Sep 2018 20:59:04 +0300 Subject: [PATCH 5/5] don't autofocus external links like feedback #495 --- js/dom.js | 7 ++++++- msgbox/msgbox.js | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/js/dom.js b/js/dom.js index 825d1e78..c956d729 100644 --- a/js/dom.js +++ b/js/dom.js @@ -372,18 +372,23 @@ function focusAccessibility() { * Switches to the next/previous keyboard-focusable element * @param {HTMLElement} rootElement * @param {Number} step - for exmaple 1 or -1 + * @returns {HTMLElement|false|undefined} - + * HTMLElement: focus changed, + * false: focus unchanged, + * undefined: nothing to focus */ function moveFocus(rootElement, step) { const elements = [...rootElement.getElementsByTagName('*')]; const activeIndex = Math.max(0, elements.indexOf(document.activeElement)); const num = elements.length; + const {activeElement} = document; for (let i = 1; i < num; i++) { const elementIndex = (activeIndex + i * step + num) % num; // we don't use positive tabindex so we stop at any valid value const el = elements[elementIndex]; if (!el.disabled && el.tabIndex >= 0) { el.focus(); - return; + return activeElement !== el && el; } } } diff --git a/msgbox/msgbox.js b/msgbox/msgbox.js index 1a236c41..9d04c143 100644 --- a/msgbox/msgbox.js +++ b/msgbox/msgbox.js @@ -34,8 +34,9 @@ function messageBox({ document.body.appendChild(messageBox.element); messageBox.originalFocus = document.activeElement; - moveFocus(messageBox.element, 1); - + // skip external links like feedback + while ((moveFocus(messageBox.element, 1) || {}).target === '_blank') {/*NOP*/} + // suppress focus outline when invoked via click if (focusAccessibility.lastFocusedViaClick && document.activeElement) { document.activeElement.dataset.focusedViaClick = ''; }