From 765f16966b7bf3fe612a3fd11c703844c8e98e8d Mon Sep 17 00:00:00 2001
From: Willi Wehmeier <wwwehmeier@gmail.com>
Date: Tue, 21 Nov 2023 13:14:14 +0100
Subject: [PATCH] [TASK] Make pagetree toggle switch accessible via keyboard

This change makes the toggle button accessible via keyboard
and sets the focus manually, so that the pagetree can be toggled
via pressing space or enter on the keyboard.

Resolves: #102426
Releases: main, 12.4
Change-Id: I6916cf1f19de288e961ecb0dab85c76241097d33
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/81817
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de>
Tested-by: Benjamin Kott <benjamin.kott@outlook.com>
Reviewed-by: Benjamin Kott <benjamin.kott@outlook.com>
Tested-by: Andreas Kienast <a.fernandez@scripting-base.de>
---
 .../backend/viewport/resizable-navigation.ts       | 14 ++++++++------
 .../JavaScript/viewport/resizable-navigation.js    |  6 +++---
 2 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/Build/Sources/TypeScript/backend/viewport/resizable-navigation.ts b/Build/Sources/TypeScript/backend/viewport/resizable-navigation.ts
index 94ca1412c27b..5d20032b7d85 100644
--- a/Build/Sources/TypeScript/backend/viewport/resizable-navigation.ts
+++ b/Build/Sources/TypeScript/backend/viewport/resizable-navigation.ts
@@ -74,10 +74,10 @@ export class ResizableNavigation extends LitElement {
   protected render(): TemplateResult {
     return html`
       <div class="scaffold-content-navigation-switcher">
-        <button @mouseup="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-open" role="button" title="${lll('viewport_navigation_show')}">
+        <button @click="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-open" role="button" title="${lll('viewport_navigation_show')}">
           <typo3-backend-icon identifier="actions-chevron-right" size="small"></typo3-backend-icon>
         </button>
-        <button @mouseup="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-close" role="button" title="${lll('viewport_navigation_hide')}">
+        <button @click="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-close" role="button" title="${lll('viewport_navigation_hide')}">
           <typo3-backend-icon identifier="actions-chevron-left" size="small"></typo3-backend-icon>
         </button>
       </div>
@@ -85,12 +85,14 @@ export class ResizableNavigation extends LitElement {
     `;
   }
 
-  private readonly toggleNavigation = (event: MouseEvent | TouchEvent) => {
-    if (event instanceof MouseEvent && event.button === 2) {
-      return;
-    }
+  private readonly toggleNavigation = (event: MouseEvent | TouchEvent | KeyboardEvent) => {
     event.stopPropagation();
     this.parentContainer.classList.toggle('scaffold-content-navigation-expanded');
+
+    if (event.currentTarget instanceof HTMLElement) {
+      const sibling = (event.currentTarget.nextElementSibling ?? event.currentTarget.previousElementSibling) as HTMLElement;
+      sibling.focus();
+    }
   };
 
   private readonly fallbackNavigationSizeIfNeeded = (event: UIEvent) => {
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/viewport/resizable-navigation.js b/typo3/sysext/backend/Resources/Public/JavaScript/viewport/resizable-navigation.js
index a314950439c5..52e3c2441ff3 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/viewport/resizable-navigation.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/viewport/resizable-navigation.js
@@ -10,12 +10,12 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-var __decorate=function(t,e,i,n){var o,a=arguments.length,s=a<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(t,e,i,n);else for(var r=t.length-1;r>=0;r--)(o=t[r])&&(s=(a<3?o(s):a>3?o(e,i,s):o(e,i))||s);return a>3&&s&&Object.defineProperty(e,i,s),s};import{html,LitElement}from"lit";import{customElement,property,state}from"lit/decorators.js";import{lll}from"@typo3/core/lit-helper.js";import Persistent from"@typo3/backend/storage/persistent.js";import"@typo3/backend/element/icon-element.js";const selectorConverter={fromAttribute:t=>document.querySelector(t)};var ReadingModeDirection;!function(t){t.ltr="ltr",t.rtl="rtl"}(ReadingModeDirection||(ReadingModeDirection={}));class ReadingMode{static get(){return"rtl"===document.querySelector("html").dir?ReadingModeDirection.rtl:ReadingModeDirection.ltr}}let ResizableNavigation=class extends LitElement{constructor(){super(...arguments),this.minimumWidth=250,this.resizing=!1,this.toggleNavigation=t=>{t instanceof MouseEvent&&2===t.button||(t.stopPropagation(),this.parentContainer.classList.toggle("scaffold-content-navigation-expanded"))},this.fallbackNavigationSizeIfNeeded=t=>{const e=t.currentTarget;0!==this.getNavigationWidth()&&e.outerWidth<this.getNavigationWidth()+this.getNavigationPosition().left+this.minimumWidth&&this.autoNavigationWidth()},this.handleMouseMove=t=>{this.resizeNavigation(t.clientX)},this.handleTouchMove=t=>{this.resizeNavigation(t.changedTouches[0].clientX)},this.resizeNavigation=t=>{let e=0;e=ReadingMode.get()===ReadingModeDirection.ltr?Math.round(t)-Math.round(this.getNavigationPosition().left):Math.round(this.getNavigationPosition().right)-Math.round(t),this.setNavigationWidth(e)},this.startResizeNavigation=t=>{t instanceof MouseEvent&&2===t.button||(t.stopPropagation(),this.resizing=!0,document.addEventListener("mousemove",this.handleMouseMove,!1),document.addEventListener("mouseup",this.stopResizeNavigation,!1),document.addEventListener("touchmove",this.handleTouchMove,!1),document.addEventListener("touchend",this.stopResizeNavigation,!1))},this.stopResizeNavigation=()=>{this.resizing=!1,document.removeEventListener("mousemove",this.handleMouseMove,!1),document.removeEventListener("mouseup",this.stopResizeNavigation,!1),document.removeEventListener("touchmove",this.handleTouchMove,!1),document.removeEventListener("touchend",this.stopResizeNavigation,!1),Persistent.set(this.persistenceIdentifier,this.getNavigationWidth()),document.dispatchEvent(new CustomEvent("typo3:navigation:resized"))}}connectedCallback(){super.connectedCallback();const t=this.initialWidth||parseInt(Persistent.get(this.persistenceIdentifier),10);this.setNavigationWidth(t),window.addEventListener("resize",this.fallbackNavigationSizeIfNeeded,{passive:!0})}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("resize",this.fallbackNavigationSizeIfNeeded)}createRenderRoot(){return this}async firstUpdated(){await new Promise((t=>setTimeout(t,0))),this.querySelector(".scaffold-content-navigation-switcher-btn").addEventListener("touchstart",this.toggleNavigation,{passive:!0}),this.querySelector(".scaffold-content-navigation-drag").addEventListener("touchstart",this.startResizeNavigation,{passive:!0})}render(){return html`
+var __decorate=function(t,e,i,n){var o,a=arguments.length,s=a<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(t,e,i,n);else for(var r=t.length-1;r>=0;r--)(o=t[r])&&(s=(a<3?o(s):a>3?o(e,i,s):o(e,i))||s);return a>3&&s&&Object.defineProperty(e,i,s),s};import{html,LitElement}from"lit";import{customElement,property,state}from"lit/decorators.js";import{lll}from"@typo3/core/lit-helper.js";import Persistent from"@typo3/backend/storage/persistent.js";import"@typo3/backend/element/icon-element.js";const selectorConverter={fromAttribute:t=>document.querySelector(t)};var ReadingModeDirection;!function(t){t.ltr="ltr",t.rtl="rtl"}(ReadingModeDirection||(ReadingModeDirection={}));class ReadingMode{static get(){return"rtl"===document.querySelector("html").dir?ReadingModeDirection.rtl:ReadingModeDirection.ltr}}let ResizableNavigation=class extends LitElement{constructor(){super(...arguments),this.minimumWidth=250,this.resizing=!1,this.toggleNavigation=t=>{if(t.stopPropagation(),this.parentContainer.classList.toggle("scaffold-content-navigation-expanded"),t.currentTarget instanceof HTMLElement){(t.currentTarget.nextElementSibling??t.currentTarget.previousElementSibling).focus()}},this.fallbackNavigationSizeIfNeeded=t=>{const e=t.currentTarget;0!==this.getNavigationWidth()&&e.outerWidth<this.getNavigationWidth()+this.getNavigationPosition().left+this.minimumWidth&&this.autoNavigationWidth()},this.handleMouseMove=t=>{this.resizeNavigation(t.clientX)},this.handleTouchMove=t=>{this.resizeNavigation(t.changedTouches[0].clientX)},this.resizeNavigation=t=>{let e=0;e=ReadingMode.get()===ReadingModeDirection.ltr?Math.round(t)-Math.round(this.getNavigationPosition().left):Math.round(this.getNavigationPosition().right)-Math.round(t),this.setNavigationWidth(e)},this.startResizeNavigation=t=>{t instanceof MouseEvent&&2===t.button||(t.stopPropagation(),this.resizing=!0,document.addEventListener("mousemove",this.handleMouseMove,!1),document.addEventListener("mouseup",this.stopResizeNavigation,!1),document.addEventListener("touchmove",this.handleTouchMove,!1),document.addEventListener("touchend",this.stopResizeNavigation,!1))},this.stopResizeNavigation=()=>{this.resizing=!1,document.removeEventListener("mousemove",this.handleMouseMove,!1),document.removeEventListener("mouseup",this.stopResizeNavigation,!1),document.removeEventListener("touchmove",this.handleTouchMove,!1),document.removeEventListener("touchend",this.stopResizeNavigation,!1),Persistent.set(this.persistenceIdentifier,this.getNavigationWidth()),document.dispatchEvent(new CustomEvent("typo3:navigation:resized"))}}connectedCallback(){super.connectedCallback();const t=this.initialWidth||parseInt(Persistent.get(this.persistenceIdentifier),10);this.setNavigationWidth(t),window.addEventListener("resize",this.fallbackNavigationSizeIfNeeded,{passive:!0})}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("resize",this.fallbackNavigationSizeIfNeeded)}createRenderRoot(){return this}async firstUpdated(){await new Promise((t=>setTimeout(t,0))),this.querySelector(".scaffold-content-navigation-switcher-btn").addEventListener("touchstart",this.toggleNavigation,{passive:!0}),this.querySelector(".scaffold-content-navigation-drag").addEventListener("touchstart",this.startResizeNavigation,{passive:!0})}render(){return html`
       <div class="scaffold-content-navigation-switcher">
-        <button @mouseup="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-open" role="button" title="${lll("viewport_navigation_show")}">
+        <button @click="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-open" role="button" title="${lll("viewport_navigation_show")}">
           <typo3-backend-icon identifier="actions-chevron-right" size="small"></typo3-backend-icon>
         </button>
-        <button @mouseup="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-close" role="button" title="${lll("viewport_navigation_hide")}">
+        <button @click="${this.toggleNavigation}" class="btn btn-default btn-borderless scaffold-content-navigation-switcher-btn scaffold-content-navigation-switcher-close" role="button" title="${lll("viewport_navigation_hide")}">
           <typo3-backend-icon identifier="actions-chevron-left" size="small"></typo3-backend-icon>
         </button>
       </div>
-- 
GitLab