@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
1 lines • 23.6 kB
Source Map (JSON)
{"version":3,"sources":["../../../packages/core/data/accessibility-manager.ts"],"names":[],"mappings":"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","file":"accessibility-manager.d.ts","sourcesContent":["import { LogLevel } from '../diagnostics/log-level';\r\nimport { LogRecord } from '../diagnostics/log-record';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { Dom } from '../dom/dom';\r\n\r\n/**\r\n * Class for accessibility manager\r\n */\r\nexport class AccessibilityManager {\r\n /**\r\n * Indicates that body focus class handlers have already been setup and should not be setup again\r\n */\r\n private hiddenFocusHandlersInitialized = false;\r\n\r\n /**\r\n * The set of events for element focusing.\r\n */\r\n private elementFocusingEvents: ((event: ElementFocusingEvent) => void)[] = [];\r\n\r\n /**\r\n * The CSS class to disable the focus rectangle even in keyboard mode\r\n */\r\n public hiddenFocusClass = 'sme-hidden-focus';\r\n\r\n /**\r\n * The CSS class to enable mouse specific accessibility styles\r\n */\r\n public mouseNavigationModeClass = 'sme-accessibility-mode-mouse';\r\n\r\n /**\r\n * The CSS class to enable keyboard specific accessibility styles\r\n */\r\n public keyboardNavigationModeClass = 'sme-accessibility-mode-keyboard';\r\n\r\n /**\r\n * The set of elements that have had the hiddenFocusClass applied\r\n */\r\n public hiddenFocusElements: HTMLElement[] = [];\r\n\r\n /**\r\n * The object of ctrl+alt+a key.\r\n */\r\n private ctrlAltAShortKey: KeyResolver;\r\n\r\n constructor() {\r\n // hookup global handlers\r\n this.hookupGlobalHandlers();\r\n this.ctrlAltAShortKey = new KeyResolver('Ctrl+Alt+A');\r\n }\r\n\r\n /**\r\n * Registers the event handler for ElementFocusingEvent\r\n */\r\n public registerElementFocusingEvent(handler: (event: ElementFocusingEvent) => void): () => void {\r\n const unregisterEventFunction = () => {\r\n const index = this.elementFocusingEvents.indexOf(handler);\r\n if (index !== -1) {\r\n this.elementFocusingEvents.splice(index, 1);\r\n }\r\n };\r\n this.elementFocusingEvents.push(handler);\r\n\r\n return unregisterEventFunction;\r\n }\r\n\r\n /**\r\n * focus on given element and prevent the default of the event\r\n * @param element the element to focus on\r\n * @param event the event that triggered the focus\r\n * @param allowBrowserFocusHandling it indicates whether to allow browser to handle focus.\r\n */\r\n private focusOnElement(element: HTMLElement, event: KeyboardEvent, allowBrowserFocusHandling?: boolean) {\r\n if (element) {\r\n // this change needs to be taken in any snap-in implementations\r\n // use param {preventScroll: true} if element is in an extension iframe\r\n // TODO: try below code with snap-ins that use new snap-in listener code\r\n element.focus();\r\n if (!allowBrowserFocusHandling) {\r\n event.preventDefault();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Find the first focusable descendant of an element and focus on it\r\n * @param element the element to work with\r\n * @param event the event that triggered the focus\r\n */\r\n private focusOnFirstFocusableDescendant(element: HTMLElement, event: KeyboardEvent) {\r\n const firstFocusableDescendant = Dom.getFirstFocusableDescendent(element);\r\n this.focusOnElement(firstFocusableDescendant, event);\r\n }\r\n\r\n /**\r\n * Handlers the element focusing in either the default way or custom ways based on ElementFocusingEvent handler.\r\n */\r\n public processElementFocusing(event: KeyboardEvent, elementToFocus: HTMLElement,\r\n sourceZone: HTMLElement, targetZone: HTMLElement, allowBrowserFocusHandling?: boolean) {\r\n let useCustomFocusHandling = false;\r\n let preventDefaultEvent = false;\r\n this.elementFocusingEvents.forEach(focusEvent => {\r\n focusEvent({\r\n nativeEvent: event,\r\n sourceZone: sourceZone,\r\n targetZone: targetZone,\r\n targetElement: elementToFocus,\r\n preventDefaultFocusBehavior: () => {\r\n useCustomFocusHandling = true;\r\n },\r\n preventDefaultEvent: () => {\r\n preventDefaultEvent = true;\r\n }\r\n });\r\n });\r\n if (useCustomFocusHandling) {\r\n if (preventDefaultEvent) {\r\n event.stopPropagation();\r\n event.preventDefault();\r\n }\r\n } else {\r\n this.focusOnElement(elementToFocus, event, allowBrowserFocusHandling);\r\n }\r\n }\r\n\r\n /**\r\n * click on given element and prevent the default of the event\r\n * @param element the element to click\r\n * @param event the event that triggered the click\r\n */\r\n private clickOnElement(element: HTMLElement, event: KeyboardEvent) {\r\n if (element) {\r\n element.click();\r\n event.preventDefault();\r\n }\r\n }\r\n\r\n /**\r\n * Changes the Accessibility Mode to mouse or keyboard\r\n * @param keyboardMode indicates that keyboard mode should be set\r\n */\r\n public changeAccessibilityMode(keyboardMode: boolean) {\r\n // toggle accessibility mode across all iframes in the document\r\n // only works for same origin iframes\r\n // TODO: support cross origin iframes and replace this with RPC broadcasting to all iframes\r\n const allBodys = Dom.getAllBodys();\r\n\r\n for (let i = 0; i < allBodys.length; i++) {\r\n const currentBody = allBodys[i];\r\n currentBody.classList.toggle(this.mouseNavigationModeClass, !keyboardMode);\r\n currentBody.classList.toggle(this.keyboardNavigationModeClass, keyboardMode);\r\n }\r\n\r\n // register accessibility mode with self so RPC can use it\r\n const self = MsftSme.self();\r\n self.Resources.accessibilityMode = keyboardMode;\r\n }\r\n\r\n /**\r\n * Query the accessibility mode of parent\r\n */\r\n private queryAccessibilityMode(): boolean {\r\n return !MsftSme.isNullOrUndefined(\r\n Dom.getSpecificAncestor(\r\n document.body,\r\n (x: HTMLElement) => Dom.isBody(x) && x.classList.contains(this.keyboardNavigationModeClass)\r\n )\r\n );\r\n }\r\n\r\n /**\r\n * Hooks up the global event handlers\r\n */\r\n private hookupGlobalHandlers() {\r\n // hookup body focus class handlers.\r\n // We do not need to unhook these as they last the entire applications lifecycle.\r\n if (!this.hiddenFocusHandlersInitialized) {\r\n // ensure this is only called once\r\n this.hiddenFocusHandlersInitialized = true;\r\n // apply the mouse navigation class to the body of the document as default\r\n this.changeAccessibilityMode(false);\r\n\r\n // when the user clicks on the page, we need to exit keyboard mode and enter mouse mode again\r\n document.body.addEventListener('mousedown', (event) => {\r\n // If event.buttons is 0, it means this mouse action is triggered by narrator.\r\n // If event.buttons is greater than 0, it means this mouse action is triggered by actual mouse device.\r\n // Then exit accessibility mode.\r\n if (event.buttons) {\r\n this.changeAccessibilityMode(false);\r\n setTimeout(() => Dom.checkActiveTab(), 0);\r\n }\r\n });\r\n document.body.addEventListener('keydown', (event) => {\r\n const isKeyboardMode = this.queryAccessibilityMode();\r\n this.changeAccessibilityMode(isKeyboardMode);\r\n const currentElement = <HTMLElement>event.target;\r\n const currentElementProperties = Dom.getElementProperties(currentElement);\r\n const currentTrap = currentElementProperties.currentTrap;\r\n const allowCustomArrowKeyFunctionality =\r\n Dom.allowCustomArrowKeyFunctionality(currentElementProperties);\r\n const allowCustomHomeEndKeyFunctionality =\r\n Dom.allowCustomHomeEndKeyFunctionality(currentElement, currentElementProperties);\r\n const currentZone = currentElementProperties.currentZone;\r\n const keyCode = event.keyCode;\r\n\r\n setTimeout(() => Dom.checkActiveTab(), 0);\r\n\r\n if (event.shiftKey && keyCode === KeyCode.Tab) {\r\n // shift tab - go back to previous zone\r\n let focusOn = Dom.getPreviousZoneElement(currentElement);\r\n const targetZone = Dom.getAncestorZone(focusOn);\r\n\r\n if (Dom.isTablist(targetZone)) {\r\n focusOn = Dom.getFirstActiveOrSelectedDescendant(targetZone) || focusOn;\r\n }\r\n if (!currentElementProperties.withinTrap || Dom.getAncestorTrap(targetZone) === currentElementProperties.currentTrap) {\r\n this.processElementFocusing(event, focusOn, currentZone, targetZone);\r\n } else {\r\n event.preventDefault();\r\n }\r\n // else we are at the beginning of the page and want shift tab to perform its default action\r\n\r\n } else if (keyCode === KeyCode.Tab) {\r\n // when the user presses 'tab' we will enter keyboard mode\r\n this.changeAccessibilityMode(true);\r\n\r\n const focusOn = Dom.getNextZoneElement(currentElement);\r\n const targetZone = Dom.getAncestorZone(focusOn);\r\n\r\n if (focusOn && targetZone !== currentZone) {\r\n // go to next zone\r\n let newFocusOn = focusOn;\r\n if (Dom.isTablist(targetZone)) {\r\n newFocusOn = Dom.getFirstActiveOrSelectedDescendant(targetZone);\r\n }\r\n if (!currentElementProperties.withinTrap\r\n || Dom.getAncestorTrap(targetZone) === currentElementProperties.currentTrap) {\r\n this.processElementFocusing(event, newFocusOn, currentZone, targetZone);\r\n } else {\r\n // we are at the end of the trap so go back to the beginning of the trap\r\n this.focusOnFirstFocusableDescendant(currentTrap, event);\r\n event.preventDefault();\r\n }\r\n } else if (!currentElementProperties.withinTrap) {\r\n // else we are at the end of the page and want tab to perform its default action\r\n const lastElement = Dom.getLastElementInZone(currentElement);\r\n if (lastElement) {\r\n this.processElementFocusing(event, lastElement, currentZone, targetZone, true);\r\n }\r\n } else {\r\n // we are at the end of the trap so go back to the beginning of the trap\r\n this.focusOnFirstFocusableDescendant(currentTrap, event);\r\n }\r\n\r\n } else if (keyCode === KeyCode.RightArrow && allowCustomArrowKeyFunctionality) {\r\n // use default if the cursor is in the middle of search box text\r\n const useArrowKeys = Dom.useArrowKeysWithinSearchbox(currentElement, true);\r\n if (!useArrowKeys && isKeyboardMode) {\r\n // go to next focusable element within current zone\r\n this.focusOnElement(Dom.getNextFocusableElement(currentElement), event);\r\n }\r\n } else if (keyCode === KeyCode.DownArrow && allowCustomArrowKeyFunctionality) {\r\n // go to next focusable element within current zone\r\n this.focusOnElement(Dom.getNextFocusableElement(currentElement), event);\r\n } else if (keyCode === KeyCode.UpArrow && allowCustomArrowKeyFunctionality) {\r\n // go to previous focusable element within current zone\r\n this.focusOnElement(Dom.getPreviousFocusableElement(currentElement), event);\r\n } else if (event.keyCode === KeyCode.LeftArrow && allowCustomArrowKeyFunctionality) {\r\n // use default if the cursor is in the middle of search box text\r\n const useArrowKeys = Dom.useArrowKeysWithinSearchbox(currentElement, false);\r\n if (!useArrowKeys && isKeyboardMode) {\r\n // go to previous focusable element within current zone\r\n this.focusOnElement(Dom.getPreviousFocusableElement(currentElement), event);\r\n }\r\n } else if (event.keyCode === KeyCode.Enter) {\r\n if (document.body.classList.contains(this.keyboardNavigationModeClass)) {\r\n if ((currentZone || currentElementProperties.isZone)\r\n && (!currentElementProperties.withinForm || Dom.shouldTreatEnterAsClick(currentElement))) {\r\n this.clickOnElement(currentElement, event);\r\n }\r\n }\r\n } else if (event.keyCode === KeyCode.End && allowCustomHomeEndKeyFunctionality) {\r\n this.focusOnElement(Dom.getLastElementInZone(currentElement), event);\r\n } else if (event.keyCode === KeyCode.Home && allowCustomHomeEndKeyFunctionality) {\r\n this.focusOnElement(Dom.getFirstElementInZone(currentElement), event);\r\n } else if (this.ctrlAltAShortKey.matchesWith(event)) {\r\n let targetElement: HTMLElement;\r\n if (Dom.isInActionBar(currentElement)) {\r\n targetElement = Dom.getNextActionBar(currentElement);\r\n } else {\r\n targetElement = Dom.getFirstActionBar(currentElement);\r\n }\r\n\r\n if (!MsftSme.isNullOrUndefined(targetElement)) {\r\n this.changeAccessibilityMode(true);\r\n this.focusOnElement(targetElement, event, false);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Class to resolve keys.\r\n */\r\nexport class KeyResolver {\r\n\r\n /**\r\n * Whether has shift key.\r\n */\r\n public hasShiftKey = false;\r\n\r\n /**\r\n * Whether has alt key.\r\n */\r\n public hasAltKey = false;\r\n\r\n /**\r\n * Whether has ctrl key.\r\n */\r\n public hasCtrlKey = false;\r\n\r\n /**\r\n * The main key code for key combination.\r\n */\r\n public keyCode: KeyCode;\r\n\r\n /**\r\n * Initializes an instance of KeyLocalizer\r\n * @param inputkeys Input keys.\r\n */\r\n constructor(inputkeys: string) {\r\n if (!MsftSme.isNullOrWhiteSpace(inputkeys)) {\r\n this.resolveKeys(inputkeys);\r\n }\r\n }\r\n\r\n /**\r\n * Resolves localized keys in to this class structure.\r\n * @param inputKeys Input keys.\r\n */\r\n private resolveKeys(inputKeys: string) {\r\n\r\n if (inputKeys === '+') {\r\n this.keyCode = KeyCode.Add;\r\n return;\r\n }\r\n const keys = inputKeys.split('+');\r\n if (keys.length > 0 && keys.length === 1) {\r\n this.setModifierKeyFlags(keys[0]);\r\n this.setKeycode(keys[0]);\r\n } else {\r\n for (let i = 0; i < keys.length - 1; i++) {\r\n this.setModifierKeyFlags(keys[i]);\r\n }\r\n this.setKeycode(keys[keys.length - 1]);\r\n }\r\n }\r\n\r\n /**\r\n * Sets modifier key flags if found in key combinations.\r\n * @param key The key.\r\n */\r\n private setModifierKeyFlags(key: string) {\r\n\r\n // These should always be passed as english keys.\r\n if (key === 'Ctrl') {\r\n this.hasCtrlKey = true;\r\n } else if (key === 'Alt') {\r\n this.hasAltKey = true;\r\n } else if (key === 'Shift') {\r\n this.hasShiftKey = true;\r\n }\r\n }\r\n\r\n /**\r\n * Set the key code extracted from the input key.\r\n * @param key the key string.\r\n */\r\n private setKeycode(key: string) {\r\n const keyCode: KeyCode = (<any>KeyCode)[key];\r\n this.keyCode = keyCode;\r\n if (this.keyCode === undefined) {\r\n Logging.log(<LogRecord>{\r\n level: LogLevel.Error,\r\n message: 'Could not resolve key ' + key,\r\n source: KeyResolver.name\r\n });\r\n }\r\n\r\n }\r\n\r\n /**\r\n * Checks if keyboard event matches with resolved keys.\r\n * @param event The keyboard event containing pressed key information.\r\n */\r\n public matchesWith(event: KeyboardEvent): boolean {\r\n return this.hasCtrlKey === event.ctrlKey &&\r\n this.hasAltKey === event.altKey &&\r\n this.hasShiftKey === event.shiftKey &&\r\n this.keyCode === event.keyCode;\r\n }\r\n}\r\n\r\n/**\r\n * Interface for ElementFocusingEvent.\r\n */\r\nexport interface ElementFocusingEvent {\r\n /**\r\n * It indicates the source focus zone.\r\n */\r\n sourceZone: HTMLElement;\r\n\r\n /**\r\n * It indicates the target focus zone.\r\n */\r\n targetZone: HTMLElement;\r\n\r\n /**\r\n * It indicates the target focus element.\r\n */\r\n targetElement: HTMLElement;\r\n\r\n /**\r\n * If this function is called in the event handler, it cancels the default behavior of focusing\r\n */\r\n preventDefaultFocusBehavior: () => void;\r\n\r\n /**\r\n * If this function is called in the event handler, it cancels the default event of focusing\r\n */\r\n preventDefaultEvent: () => void;\r\n\r\n nativeEvent: KeyboardEvent;\r\n}\r\n\r\n// Keyboard codes\r\nexport enum KeyCode {\r\n Backspace = 8,\r\n Tab = 9,\r\n Enter = 13,\r\n Shift = 16,\r\n Ctrl = 17,\r\n Alt = 18,\r\n Pause = 19,\r\n CapsLock = 20,\r\n Escape = 27,\r\n Space = 32,\r\n PageUp = 33,\r\n PageDown = 34,\r\n End = 35,\r\n Home = 36,\r\n LeftArrow = 37,\r\n UpArrow = 38,\r\n RightArrow = 39,\r\n DownArrow = 40,\r\n Insert = 45,\r\n Delete = 46,\r\n Num0 = 48,\r\n Num1 = 49,\r\n Num2 = 50,\r\n Num3 = 51,\r\n Num4 = 52,\r\n Num5 = 53,\r\n Num6 = 54,\r\n Num7 = 55,\r\n Num8 = 56,\r\n Num9 = 57,\r\n A = 65,\r\n B = 66,\r\n C = 67,\r\n D = 68,\r\n E = 69,\r\n F = 70,\r\n G = 71,\r\n H = 72,\r\n I = 73,\r\n J = 74,\r\n K = 75,\r\n L = 76,\r\n M = 77,\r\n N = 78,\r\n O = 79,\r\n P = 80,\r\n Q = 81,\r\n R = 82,\r\n S = 83,\r\n T = 84,\r\n U = 85,\r\n V = 86,\r\n W = 87,\r\n X = 88,\r\n Y = 89,\r\n Z = 90,\r\n LeftWindows = 91,\r\n RightWindows = 92,\r\n Select = 93,\r\n Numpad0 = 96,\r\n Numpad1 = 97,\r\n Numpad2 = 98,\r\n Numpad3 = 99,\r\n Numpad4 = 100,\r\n Numpad5 = 101,\r\n Numpad6 = 102,\r\n Numpad7 = 103,\r\n Numpad8 = 104,\r\n Numpad9 = 105,\r\n Multiply = 106,\r\n Add = 107,\r\n Subtract = 109,\r\n DecimaPoint = 110,\r\n Divide = 111,\r\n F1 = 112,\r\n F2 = 113,\r\n F3 = 114,\r\n F4 = 115,\r\n F5 = 116,\r\n F6 = 117,\r\n F7 = 118,\r\n F8 = 119,\r\n F9 = 120,\r\n F10 = 121,\r\n F11 = 122,\r\n F12 = 123,\r\n NumLock = 144,\r\n ScrollLock = 145,\r\n SemiColon = 186,\r\n EqualSign = 187,\r\n Comma = 188,\r\n Dash = 189,\r\n Period = 190,\r\n ForwardSlash = 191,\r\n GraveAccent = 192,\r\n OpenBracket = 219,\r\n BackSlash = 220,\r\n CloseBraket = 221,\r\n SingleQuote = 222\r\n}\r\n"]}