UNPKG

@microsoft/windows-admin-center-sdk

Version:

Microsoft - Windows Admin Center Shell

1 lines 49.7 kB
{"version":3,"sources":["../../../packages/core/dom/dom.ts"],"names":[],"mappings":"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","file":"dom.d.ts","sourcesContent":["export interface DomElementProperties {\r\n isForm: boolean;\r\n withinForm: boolean;\r\n isTrap: boolean;\r\n withinTrap: boolean;\r\n isZone: boolean;\r\n withinZone: boolean;\r\n withinZoneWithinForm: boolean;\r\n currentZone: HTMLElement;\r\n currentTrap: HTMLElement;\r\n currentForm: HTMLElement;\r\n}\r\n\r\n/**\r\n * DOM class\r\n * @dynamic\r\n */\r\nexport class Dom {\r\n public static getElementProperties(element: HTMLElement, properties?: DomElementProperties): DomElementProperties {\r\n\r\n if (MsftSme.isNullOrUndefined(properties)) {\r\n properties = {\r\n isForm: Dom.isForm(element),\r\n withinForm: false,\r\n isTrap: Dom.isTrap(element),\r\n withinTrap: false,\r\n isZone: Dom.isZone(element),\r\n withinZone: false,\r\n withinZoneWithinForm: false,\r\n currentZone: null,\r\n currentTrap: null,\r\n currentForm: null\r\n };\r\n }\r\n\r\n if (element === null) {\r\n return properties;\r\n }\r\n\r\n if (!properties.withinForm && Dom.isForm(element)) {\r\n properties.withinForm = true;\r\n properties.currentForm = element;\r\n if (properties.withinZone) {\r\n properties.withinZoneWithinForm = true;\r\n }\r\n }\r\n\r\n if (!properties.withinTrap && Dom.isTrap(element)) {\r\n properties.withinTrap = true;\r\n properties.currentTrap = element;\r\n }\r\n\r\n if (!properties.withinZone && !properties.isZone && Dom.isZone(element)) {\r\n properties.withinZone = true;\r\n properties.currentZone = element;\r\n }\r\n\r\n const parentElement = element.tagName === 'HTML' ?\r\n Dom.getParentIframe(element)\r\n :\r\n element.parentElement;\r\n\r\n return Dom.getElementProperties(parentElement, properties);\r\n }\r\n\r\n public static allowCustomArrowKeyFunctionality(properties: DomElementProperties) {\r\n return !properties.withinForm || properties.withinZoneWithinForm;\r\n }\r\n\r\n public static allowCustomHomeEndKeyFunctionality(element: HTMLElement, properties: DomElementProperties) {\r\n return !Dom.isSearchBox(element) && !Dom.isTextBoxInComboBox(element)\r\n && (!properties.withinForm || properties.withinZoneWithinForm);\r\n }\r\n\r\n /**\r\n * gets all body elements on the page\r\n */\r\n public static getAllBodys(): HTMLElement[] {\r\n const root = Dom.getRootElement();\r\n return Dom.getAllElements(root, Dom.isBody);\r\n }\r\n\r\n /**\r\n * Gets a CSS property value\r\n * @param element The Element\r\n * @param property - The CSS property name\r\n * @returns The value of the CSS property (type depends on property retrieved)\r\n */\r\n public static getStyle(element: HTMLElement, property: string): any {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n // first try to get the value directly from the element\r\n const value = element.style[property];\r\n if (!MsftSme.isNullOrWhiteSpace(value)) {\r\n return value;\r\n }\r\n\r\n // otherwise get the computed style\r\n return getComputedStyle(element)[property];\r\n }\r\n\r\n /**\r\n * Gets the classes applied to an element\r\n * @param element The Element\r\n * @returns The classes currently applied to the element\r\n */\r\n public static getClasses(element: HTMLElement): any {\r\n if (element) {\r\n const classes = element.className.trim();\r\n if (!MsftSme.isNullOrWhiteSpace(classes)) {\r\n return classes.split(' ');\r\n }\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Determines is an element is disabled via the 'disabled' attribute\r\n * @param element The element to start from.\r\n */\r\n public static isDisabled(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n return !!element['disabled'];\r\n }\r\n\r\n /**\r\n * Determines is an element is hidden via css with \"display: none\"\r\n * @param element The element to start from.\r\n */\r\n public static isNotDisplayed(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n return Dom.getStyle(element, 'display') === 'none';\r\n }\r\n\r\n /**\r\n * Determines is an element is hidden via css with \"visibility: hidden\"\r\n * @param element The element to start from.\r\n */\r\n public static isHidden(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n return Dom.getStyle(element, 'visibility') === 'hidden' || element['hidden'];\r\n }\r\n\r\n /**\r\n * Returns the first element in the current elements ancestory that is focusable.\r\n *\r\n * 'Focusable' is defined as the following:\r\n * - input, select, textarea, button, object\r\n * - anchor with href\r\n * - have a non-negative tab index\r\n *\r\n * An element is not focusable if any of the following is true (even if it meets a condition above)\r\n * - negative tab index\r\n * - disabled\r\n * - display: none\r\n * - visibility: hidden\r\n *\r\n * @param element The element to start from.\r\n * @return true if focus possible\r\n */\r\n public static isFocusable(element: HTMLElement, includeNegativeTabIndex: boolean = false): boolean {\r\n return Dom.checkFocusableConditions(element, includeNegativeTabIndex);\r\n }\r\n\r\n /**\r\n * Returns true if the element could be focusable.\r\n *\r\n * An element that can be focused is the following:\r\n * - input, select, textarea, button, object\r\n * - anchor with href\r\n * - have a non-negative tab index\r\n *\r\n * This method will determine if the element has one of these conditions even if the the element\r\n * is not displayed, visible, enabled, or having a positive z-index.\r\n *\r\n * @param element The element to start from.\r\n * @return true if focus possible.\r\n */\r\n public static isFocusPossible(element: HTMLElement, includeNegativeTabIndex: boolean = false): boolean {\r\n return Dom.checkFocusableConditions(element, includeNegativeTabIndex, true);\r\n }\r\n\r\n private static checkFocusableConditions(\r\n element: HTMLElement,\r\n includeNegativeTabIndex: boolean,\r\n skipDisabledHiddenOrNotDisplayed: boolean = false): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n // if the element or its ancestor is disabled or 'not displayed'/hidden, it is not focusable\r\n if (!skipDisabledHiddenOrNotDisplayed && Dom.getDisabledHiddenOrNotDisplayedAncestor(element)) {\r\n return false;\r\n }\r\n\r\n // if the tab index is set, let it determine focusability\r\n // have to check has attribute because\r\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4365703/\r\n if (element.hasAttribute('tabindex') && !MsftSme.isNullOrUndefined(element.tabIndex)) {\r\n return element.tabIndex >= 0 || (includeNegativeTabIndex && !element.classList.contains('sme-hidden-focus'));\r\n }\r\n\r\n // https://react.fluentui.dev/?path=/docs/preview-components-infobutton--default\r\n // The info bubble is focusable\r\n if (element.className.includes('sme-info-bubble')) {\r\n return true;\r\n }\r\n\r\n // anchors with an href are also focusable\r\n if (element.tagName === 'A' && element.hasAttribute('href')) {\r\n return true;\r\n }\r\n\r\n // Otherwise only naturally focusable elements can receive focus\r\n const focusableTags = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'OBJECT'];\r\n return focusableTags.some(tag => tag === element.tagName);\r\n }\r\n\r\n /**\r\n * Returns the first element in the current elements ancestry that is focusable.\r\n * Will return the element itself if it is focusable\r\n * @param element The element to start from.\r\n * @return the first focusable ancestor of the element\r\n */\r\n public static getFocusableAncestor(element: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n return Dom.isFocusable(element) ? element : Dom.getFocusableAncestor(element.parentElement);\r\n }\r\n\r\n /**\r\n * find an element in a particular position with a specific condition relative to input element\r\n * Does a DFS for this element relative the ancestor zone of input element\r\n * @param element The current element\r\n * @param condition The function to check the kind of element we are looking for\r\n * @param position The ElementPosition of the desired element relative to input element\r\n */\r\n public static findElementFromAncestorZoneDFS(element: HTMLElement, condition: (element: HTMLElement) => boolean,\r\n position: ElementPosition): HTMLElement {\r\n const ancestor = Dom.getAncestorZone(element);\r\n const allElements: HTMLElement[] = Dom.getAllElements(ancestor, condition);\r\n return Dom.getElement(allElements, element, position);\r\n }\r\n\r\n /**\r\n * find an element in a particular position with a specific condition relative to input element\r\n * Does a DFS for this element relative the ancestor trap of input element\r\n * @param element The current element\r\n * @param condition The function to check the kind of element we are looking for\r\n * @param position The ElementPosition of the desired element relative to input element\r\n */\r\n public static findElementFromAncestorTrapDFS(element: HTMLElement, condition: (element: HTMLElement) => boolean,\r\n position: ElementPosition): HTMLElement {\r\n const ancestor = Dom.getAncestorTrap(element);\r\n const allElements: HTMLElement[] = Dom.getAllElements(ancestor, condition);\r\n return Dom.getElement(allElements, element, position);\r\n }\r\n\r\n /**\r\n * find an element in a particular position with a specific condition relative to input element\r\n * Does a DFS for this element relative the root of the graph\r\n * @param element The current element\r\n * @param condition The function to check the kind of element we are looking for\r\n * @param position The ElementPosition of the desired element relative to input element\r\n */\r\n public static findElementFromRootDFS(element: HTMLElement, condition: (element: HTMLElement) => boolean,\r\n position: ElementPosition): HTMLElement {\r\n const root = Dom.getRootElement();\r\n const allElements: HTMLElement[] = Dom.getAllElements(root, condition);\r\n return Dom.getElement(allElements, element, position);\r\n }\r\n\r\n /**\r\n * find an element in a particular position with a specific condition relative to input element\r\n * Does a DFS for this element relative the input element\r\n * @param element The current element\r\n * @param condition The function to check the kind of element we are looking for\r\n * @param position The ElementPosition of the desired element relative to input element\r\n */\r\n public static findChildElementDFS(element: HTMLElement, condition: (element: HTMLElement) => boolean,\r\n position: ElementPosition): HTMLElement {\r\n const allElements: HTMLElement[] = Dom.getAllElements(element, condition);\r\n return Dom.getElement(allElements, element, position);\r\n }\r\n\r\n /**\r\n * gets a element from a list of elements in the position relative to the current element\r\n * @param elements the list of elements\r\n * @param currentElement the current element\r\n * @param position the ElementPosition we want relative to the current element\r\n */\r\n public static getElement(elements: HTMLElement[], currentElement: HTMLElement, position: ElementPosition): HTMLElement {\r\n if (elements && elements.length > 0) {\r\n let currentIndex = 0;\r\n switch (position) {\r\n case ElementPosition.Next:\r\n currentIndex = elements.findIndex(x => x.isSameNode(currentElement));\r\n return currentIndex + 1 < elements.length ? elements[currentIndex + 1] : currentElement;\r\n case ElementPosition.Previous:\r\n currentIndex = elements.findIndex(x => x.isSameNode(currentElement));\r\n return currentIndex - 1 >= 0 ? elements[currentIndex - 1] : currentElement;\r\n case ElementPosition.First:\r\n return elements.first();\r\n case ElementPosition.Last:\r\n return elements.last();\r\n default:\r\n return currentElement;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n public static getAllElements(element: HTMLElement, condition: (element: HTMLElement) => boolean) {\r\n return Dom.searchAllElements(element, condition);\r\n }\r\n\r\n /**\r\n * gets the first element that meets a condition\r\n * @param rootElement the element we start with\r\n * @param condition the condition we want to find an element meeting\r\n * @param stopLookingCondition a condition used to stop looking down a certain path\r\n * (ie stop looking down a particular path once we hit a zone)\r\n * @param includeRootElement a condition to include the root element in the search\r\n */\r\n public static getFirstElement(rootElement: HTMLElement,\r\n condition: (element: HTMLElement) => boolean,\r\n stopLookingCondition?: (element: HTMLElement) => boolean,\r\n includeRootElement = true): HTMLElement {\r\n const firstElements = Dom.searchAllElements(rootElement, condition, stopLookingCondition, true, includeRootElement);\r\n // return first element\r\n return MsftSme.first(firstElements);\r\n }\r\n\r\n /**\r\n * finds all elements starting at the input element that meet the given condition\r\n * @param rootElement the element from which to start the depth first search\r\n * @param condition the function that determines whether the desired condition has been met\r\n * @param stopLookingCondition a condition used to stop looking down a certain path\r\n * @param includeRootElement a condition to include the root element in the search\r\n */\r\n private static searchAllElements(\r\n rootElement: HTMLElement,\r\n condition: (element: HTMLElement) => boolean,\r\n stopLookingCondition?: (element: HTMLElement) => boolean,\r\n stopAtFirstResult = false,\r\n includeRootElement = true): HTMLElement[] {\r\n if (!rootElement) {\r\n return null;\r\n }\r\n\r\n // depth first search starting at the root element\r\n const allElements = [];\r\n const conditionalElements = [];\r\n allElements.push(rootElement);\r\n while (allElements.length > 0) {\r\n const currentElement = allElements.pop();\r\n if (currentElement.tagName !== 'SVG' && currentElement.tagName !== 'svg') {\r\n if (condition(currentElement)) {\r\n\r\n // If root element meets the condition, add to conditionalElements\r\n if ((currentElement === rootElement && includeRootElement) || currentElement !== rootElement) {\r\n conditionalElements.push(currentElement);\r\n\r\n if (stopAtFirstResult) {\r\n return conditionalElements;\r\n }\r\n }\r\n }\r\n\r\n if (currentElement === rootElement || !stopLookingCondition || !stopLookingCondition(currentElement)) {\r\n for (let i = currentElement.childElementCount - 1; i >= 0; i--) {\r\n const child = <HTMLElement>currentElement.children.item(i);\r\n allElements.push(child);\r\n }\r\n }\r\n // if the current element is an iframe, start traversing the iframe's body\r\n try {\r\n if (currentElement.contentDocument && currentElement.contentDocument.body) {\r\n allElements.push(currentElement.contentDocument.body);\r\n }\r\n } catch (error) {\r\n // if we can't grab the content document, then we are very likely sideloading a tool in chrome\r\n // you can disable same origin security policy to test accessibility or try in edge\r\n // if this happens, we want to just get as much information as we can about the available elements\r\n\r\n // TODO: log this when this code is moved to different file\r\n }\r\n }\r\n }\r\n\r\n // we need to reverse to get the actual order of elements on the page\r\n return conditionalElements;\r\n }\r\n\r\n /**\r\n * returns the root of the DOM graph\r\n */\r\n public static getRootElement(): HTMLElement {\r\n // we want to try to grab the document body from the window because document.body gives us the body of the current iframe only\r\n try {\r\n if (window.parent && window.parent.document && window.parent.document.body) {\r\n return window.parent.document.body;\r\n }\r\n } catch (error) {\r\n // if we can't grab the document from the window, then we are very likely sideloading a tool in chrome\r\n // you can disable same origin security policy to test accessibility or try in edge\r\n // if this happens, we want to just get as much information as we can about the available elements\r\n\r\n // TODO: log this when this code is moved to different file\r\n }\r\n\r\n return document.body;\r\n }\r\n\r\n /**\r\n * Finds the next zone\r\n * @param element the current zone or an element in the current zone\r\n */\r\n public static getNextZone(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromRootDFS(Dom.getAncestorZone(element) || element, Dom.isZone, ElementPosition.Next);\r\n }\r\n\r\n /**\r\n * gets the first focusable element in the next zone\r\n * if a zone has no focusable elements, it is skipped\r\n * @param element the current element\r\n */\r\n public static getNextZoneElement(element: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n // we are at the end of the page\r\n const nextZone = Dom.getNextZone(element);\r\n if (element.isSameNode(nextZone)) {\r\n return null;\r\n }\r\n\r\n const firstFocusableElement = Dom.getFirstFocusableDescendent(nextZone);\r\n return firstFocusableElement ? firstFocusableElement : Dom.getNextZoneElement(nextZone);\r\n }\r\n\r\n /**\r\n * Finds the previous zone\r\n * @param element the current zone or an element in the current zone\r\n */\r\n public static getPreviousZone(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromRootDFS(Dom.getAncestorZone(element), Dom.isZone, ElementPosition.Previous);\r\n }\r\n\r\n /**\r\n * gets the first focusable element in the previous zone\r\n * if a zone has no focusable elements, it is skipped\r\n * @param element the current element\r\n * @param originalElement the element from which we begin the search. Set automatically if unset by user\r\n */\r\n public static getPreviousZoneElement(element: HTMLElement, originalElement?: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n // save the first element we see so we can skip empty zones later on\r\n if (!originalElement) {\r\n return Dom.getPreviousZoneElement(element, element);\r\n }\r\n\r\n // we are at the beginning of the page\r\n const previousZone = Dom.getPreviousZone(element);\r\n if (element.isSameNode(previousZone)) {\r\n return null;\r\n }\r\n\r\n const firstFocusableElement = Dom.getFirstFocusableDescendent(previousZone);\r\n return firstFocusableElement && firstFocusableElement !== originalElement ?\r\n firstFocusableElement : Dom.getPreviousZoneElement(previousZone, originalElement);\r\n }\r\n\r\n /**\r\n * gets the first ancestor that is disabled\r\n * @param element the element\r\n */\r\n public static getAncestor(element: HTMLElement, condition: MsftSme.Func1<HTMLElement, boolean>): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n if (condition(element)) {\r\n return element;\r\n }\r\n\r\n if (element.tagName === 'HTML') {\r\n const iFrameElement = Dom.getParentIframe(element);\r\n return iFrameElement ? Dom.getAncestor(iFrameElement, condition) : null;\r\n }\r\n\r\n return Dom.getAncestor(element.parentElement, condition);\r\n }\r\n\r\n private static getParentIframe(element: HTMLElement): HTMLHtmlElement | null {\r\n const elementFrameName = element && element.getAttribute('sme-frame-name');\r\n if (!elementFrameName) {\r\n return null;\r\n }\r\n // we want to try to grab the document body from the window because document.body gives us the body of the current iframe only\r\n try {\r\n const iFrames = MsftSme.isShell() ?\r\n Array.from(document.getElementsByTagName('iframe'))\r\n :\r\n Array.from(window.parent.document.getElementsByTagName('iframe'));\r\n\r\n let iFrameElement;\r\n if (iFrames && elementFrameName) {\r\n iFrameElement = iFrames.first(frame => frame.id === elementFrameName);\r\n }\r\n return iFrameElement || null;\r\n } catch (error) {\r\n // if we can't grab the document from the window, then we are very likely side-loading a tool in chrome or chromium edge\r\n // you can disable same origin security policy to test accessibility or try in edge\r\n // if this happens, we want to just get as much information as we can about the available elements\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * gets all ancestors that match a given condition\r\n * @param element the element\r\n */\r\n public static getAllAncestors(element: HTMLElement, condition: MsftSme.Func1<HTMLElement, boolean>): HTMLElement[] {\r\n if (!element) {\r\n return [];\r\n }\r\n const ancestor = Dom.getAncestor(element, condition);\r\n if (!ancestor) {\r\n return [];\r\n }\r\n return [ancestor].concat(Dom.getAllAncestors(ancestor.parentElement, condition));\r\n }\r\n\r\n /**\r\n * gets the zone that the current element is in\r\n * @param element the element\r\n */\r\n public static getAncestorZone(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, e => Dom.isZone(e));\r\n }\r\n\r\n /**\r\n * determine if an element is in a trap, if so return the trap element\r\n * @param element HTML element to check\r\n */\r\n public static getAncestorTrap(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, e => Dom.isTrap(e));\r\n }\r\n\r\n /**\r\n * gets the ancestor form of an element\r\n * @param element the element\r\n */\r\n public static getAncestorForm(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, e => Dom.isForm(e));\r\n }\r\n\r\n /**\r\n * Find ancestors that are disabled, hidden, or not displayed\r\n * @param element the element\r\n */\r\n public static getDisabledHiddenOrNotDisplayedAncestor(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, x => Dom.isDisabled(x) || Dom.isNotDisplayed(x) || Dom.isHidden(x));\r\n }\r\n\r\n /**\r\n * gets the first ancestor that is disabled\r\n * @param element the element\r\n */\r\n public static getDisabledAncestor(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, e => Dom.isDisabled(e));\r\n }\r\n\r\n /**\r\n * returns ancestor table of current element\r\n * @param element the current element\r\n */\r\n public static getAncestorTable(element: HTMLElement): HTMLElement {\r\n return Dom.getAncestor(element, e => e.tagName === 'TABLE');\r\n }\r\n\r\n /**\r\n * gets the next child zone of the current zone\r\n * @param element the current zone or an element in the current zone\r\n */\r\n public static getDescendentZone(element: HTMLElement): HTMLElement {\r\n // if there is no parent zone, just look from the current element forward\r\n return Dom.findChildElementDFS(Dom.getAncestorZone(element) || element, Dom.isZone, ElementPosition.First);\r\n }\r\n\r\n /**\r\n * gets the first focusable descendent of the current element\r\n * @param element the current element\r\n */\r\n public static getFirstFocusableDescendent(element: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n return Dom.isFocusable(element) ?\r\n element : Dom.getFirstFocusableDescendent(Dom.findChildElementDFS(\r\n element,\r\n Dom.isFocusable || Dom.isZone,\r\n ElementPosition.First));\r\n }\r\n\r\n /**\r\n * gets the last element in a zone\r\n * @param element the element\r\n */\r\n public static getLastElementInZone(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isFocusable, ElementPosition.Last);\r\n }\r\n\r\n /**\r\n * gets the first element in a zone\r\n * @param element the element\r\n */\r\n public static getFirstElementInZone(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isFocusable, ElementPosition.First);\r\n }\r\n\r\n /**\r\n * gets the next focusable element in the current zone\r\n * @param element the current element\r\n */\r\n public static getNextFocusableElement(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isFocusable, ElementPosition.Next);\r\n }\r\n\r\n /**\r\n * gets the previous focusable element in the current zone\r\n * @param element the current element\r\n */\r\n public static getPreviousFocusableElement(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isFocusable, ElementPosition.Previous);\r\n }\r\n\r\n /**\r\n * gets the ancestor of an element that has overflow\r\n * @param element the current element\r\n */\r\n public static getOverflowAncestor(element: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n return element.clientHeight < element.scrollHeight || element.clientWidth < element.scrollWidth ?\r\n element : Dom.getOverflowAncestor(<HTMLElement>element.offsetParent);\r\n }\r\n\r\n /**\r\n * gets the ancestor of an element that meets the specified condition\r\n * @param element the current element\r\n * @param condition the function that will check if element meets the desired condition\r\n */\r\n public static getSpecificAncestor(element: HTMLElement, condition: (element: HTMLElement) => boolean): HTMLElement {\r\n if (!element) {\r\n return null;\r\n }\r\n\r\n return condition(element) ? element : Dom.getSpecificAncestor(element.parentElement, condition);\r\n }\r\n\r\n /**\r\n * gets the next focusable element in the current trap\r\n * @param element the current element\r\n */\r\n public static getNextFocusableElementInTrap(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorTrapDFS(element, Dom.isFocusable, ElementPosition.Next);\r\n }\r\n\r\n /**\r\n * gets the previous focusable element in the current trap\r\n * @param element the current element\r\n */\r\n public static getPreviousFocusableElementInTrap(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorTrapDFS(element, Dom.isFocusable, ElementPosition.Previous);\r\n }\r\n\r\n /**\r\n * true if given element is a body element\r\n * @param element the element\r\n */\r\n public static isBody(element: HTMLElement): boolean {\r\n return element.tagName === 'BODY';\r\n }\r\n\r\n /**\r\n * true if the given element is a zone\r\n * @param element the element\r\n */\r\n public static isZone(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n return Dom.hasZoneRole(element)\r\n || Dom.isSmeFocusZone(element)\r\n || Dom.hasZoneTag(element)\r\n || Dom.isGrowlWithChild(element)\r\n || (Dom.isFocusableFormElement(element) && !Dom.isInZoneWithinForm(element));\r\n }\r\n\r\n /**\r\n * true if the element is a focusable element that is not a zone\r\n * @param element the element\r\n */\r\n public static isFocusableNonZone(element: HTMLElement): boolean {\r\n return !Dom.isZone(element) && Dom.isFocusable(element);\r\n }\r\n\r\n /**\r\n * true if the element is an input, select, or textarea without a form parent\r\n * @param element the element\r\n */\r\n public static isInputWithoutForm(element: HTMLElement): boolean {\r\n const inputTags = ['INPUT', 'SELECT', 'TEXTAREA'];\r\n return inputTags.some(tag => tag === element.tagName) && Dom.getAncestorForm(element) === null;\r\n }\r\n\r\n /**\r\n * true if the element has a role that qualifies as a zone\r\n * @param element the element\r\n */\r\n public static hasZoneRole(element: HTMLElement): boolean {\r\n const role = element.getAttribute('role');\r\n const zoneRoles = ['grid', 'tablist', 'table', 'menubar', 'navigation', 'dialog'];\r\n return zoneRoles.some(zoneRole => zoneRole === role);\r\n }\r\n\r\n /**\r\n * true if the element has class=\"sme-focus-zone\"\r\n * @param element the element\r\n */\r\n public static isSmeFocusZone(element: HTMLElement): boolean {\r\n return element.classList.contains('sme-focus-zone');\r\n }\r\n\r\n /**\r\n * true if the element has a tag that is a zone\r\n * @param element the element\r\n */\r\n public static hasZoneTag(element: HTMLElement): boolean {\r\n // TODO: utilities should not know about specific sme tags.\r\n // These tags should instead use the appropriate roles to identify them as focus zones.\r\n const tag = element.tagName;\r\n const zoneTags = ['SME-BREADCRUMB-HEADER', 'SME-DETAILS', 'SME-SETTINGS-FOOTER'];\r\n return zoneTags.some(zoneTag => zoneTag === tag);\r\n }\r\n\r\n /**\r\n * true if element has role 'tablist'\r\n * @param element the html element\r\n */\r\n public static isTablist(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n const role = element.getAttribute('role');\r\n return role === 'tablist';\r\n }\r\n\r\n /**\r\n * Returns true if element is active\r\n * An element is active if it aria-selected attribute is set as true or has active or sme-active classes\r\n * @param element the html element\r\n */\r\n public static isActiveOrSelected(element: HTMLHtmlElement): boolean {\r\n const ariaSelected = element.getAttribute('aria-selected') === 'true';\r\n const activeClasses = ['active', 'sme-active'];\r\n return ariaSelected || activeClasses.some(className => element.classList.contains(className));\r\n }\r\n\r\n /**\r\n * Returns first active or selected descendant or null if none is found\r\n * @param element the html element\r\n */\r\n public static getFirstActiveOrSelectedDescendant(element: HTMLElement): HTMLElement | null {\r\n return Dom.findChildElementDFS(element, Dom.isActiveOrSelected, ElementPosition.First);\r\n }\r\n\r\n /**\r\n * true if the element is a growl with a child\r\n * @param element the element\r\n */\r\n public static isGrowlWithChild(element: HTMLElement): boolean {\r\n return element.classList.contains('sme-layout-notification-popup-list') && element.childElementCount > 0;\r\n }\r\n\r\n /**\r\n * true if element is focusable element within a form\r\n * @param element the element\r\n */\r\n public static isFocusableFormElement(element: HTMLElement): boolean {\r\n return !!Dom.getAncestorForm(element) && Dom.isFocusable(element);\r\n }\r\n\r\n /**\r\n * true is element is within a zone that is within a form\r\n * @param element the element\r\n */\r\n public static isInZoneWithinForm(element: HTMLElement) {\r\n return Dom.getAncestorForm(Dom.getAncestorZone(element.parentElement)) !== null;\r\n }\r\n\r\n /**\r\n * true is element is within a trap that is within a form\r\n * @param element the element\r\n */\r\n public static isInTrapWithinForm(element: HTMLElement) {\r\n return Dom.getAncestorForm(Dom.getAncestorTrap(element.parentElement)) !== null;\r\n }\r\n\r\n /**\r\n * true if the given element is a trap\r\n * @param element the element\r\n */\r\n public static isTrap(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n const role = element.getAttribute('role');\r\n const trapRoles = ['dialog', 'alertdialog'];\r\n return trapRoles.some(trapRole => trapRole === role) || element.classList.contains('sme-focus-trap');\r\n }\r\n\r\n /**\r\n * return true if element is a form\r\n * @param element the element\r\n */\r\n public static isForm(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n return element.tagName === 'FORM';\r\n }\r\n\r\n /**\r\n * return true if we are inside a search box that has its own arrow key controls\r\n * @param element the element\r\n * @param isRightArrow the right arrow was clicked\r\n */\r\n public static useArrowKeysWithinSearchbox(element: HTMLElement, isRightArrow: boolean): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n if (Dom.isSearchBox(element)) {\r\n const inputElement = element as any;\r\n const innerTextLength = inputElement.value ? inputElement.value.length : 0;\r\n return (!isRightArrow && inputElement.selectionStart !== null && inputElement.selectionStart > 0)\r\n || (isRightArrow && inputElement.selectionEnd !== null && inputElement.selectionEnd < innerTextLength);\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * true if given element is a search box\r\n * @param element the element\r\n */\r\n public static isSearchBox(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n const inputElement = element as HTMLInputElement;\r\n return element.tagName === 'INPUT' && inputElement && inputElement.type === 'search';\r\n }\r\n\r\n /**\r\n * true if given element is a textbox in a combobox\r\n * @param element the element\r\n */\r\n public static isTextBoxInComboBox(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n return !!(Dom.getAncestor(element, htmlElement => {\r\n return htmlElement.classList.contains('sme-combobox-header');\r\n }));\r\n }\r\n\r\n /**\r\n * returns the next row in the current table\r\n * @param element the current element\r\n */\r\n public static getNextRowInTable(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isTableRow, ElementPosition.Next);\r\n }\r\n\r\n /**\r\n * returns the previous row in the current table\r\n * @param element the current element\r\n */\r\n public static getPreviousRowInTable(element: HTMLElement): HTMLElement {\r\n return Dom.findElementFromAncestorZoneDFS(element, Dom.isTableRow, ElementPosition.Previous);\r\n }\r\n\r\n /**\r\n * returns true if the current element is a table row\r\n * @param element the current element\r\n */\r\n public static isTableRow(element: HTMLElement): boolean {\r\n return element.tagName === 'TR';\r\n }\r\n\r\n /**\r\n * returns true if the current element is a table cell\r\n * @param element the current element\r\n */\r\n public static isTableCell(element: HTMLElement): boolean {\r\n return element.tagName === 'TD';\r\n }\r\n\r\n /**\r\n * returns true if the current element is inside a table cell\r\n * @param element the current element\r\n */\r\n public static isInTableCell(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n\r\n return Dom.isTableCell(element) ? true : Dom.isInTableCell(element.parentElement);\r\n }\r\n\r\n /**\r\n * Gets the first action bar on the screen.\r\n * @param element The HTML element.\r\n * @returns The first action bar on the screen.\r\n */\r\n public static getFirstActionBar(element: HTMLElement): HTMLElement {\r\n return this.getActionBar(element, ElementPosition.First);\r\n }\r\n\r\n /**\r\n * Gets the next action bar on the screen.\r\n * @param element The HTML element.\r\n * @returns The first action bar on the screen.\r\n */\r\n public static getNextActionBar(element: HTMLElement): HTMLElement {\r\n return this.getActionBar(element, ElementPosition.Next);\r\n }\r\n\r\n /**\r\n * Gets a specified action bar.\r\n * @param element The HTML element.\r\n * @param position The position of the desired action bar.\r\n * @returns The specified action bar, if possible.\r\n */\r\n public static getActionBar(element: HTMLElement, position: ElementPosition): HTMLElement {\r\n const actionBar = Dom.findElementFromRootDFS(\r\n Dom.getAncestorZone(element),\r\n (x) => Dom.isActionBar(x) && !MsftSme.isNullOrUndefined(Dom.getFirstFocusableDescendent(x)),\r\n position\r\n );\r\n\r\n return Dom.getFirstFocusableDescendent(actionBar);\r\n }\r\n\r\n /**\r\n * Determines if the HTML element is inside of an action bar.\r\n * @param element The HTML element.\r\n * @returns True if the HTML element is in an action bar and false if not.\r\n */\r\n public static isInActionBar(element: HTMLElement): boolean {\r\n return MsftSme.isNullOrUndefined(Dom.getSpecificAncestor(element, (x) => Dom.isActionBar(x))) ? false : true;\r\n }\r\n\r\n /**\r\n * Determines if the HTML element is an action bar.\r\n * @param element The HTML element.\r\n * @returns True if the element is an action bar and false if not.\r\n */\r\n public static isActionBar(element: HTMLElement): boolean {\r\n return MsftSme.isNullOrUndefined(element) ? false : element.getAttribute('role') === 'menubar'\r\n && !MsftSme.isNullOrUndefined(element.parentElement) && element.parentElement.tagName === 'SME-ACTION-BAR';\r\n }\r\n\r\n /**\r\n * Determines if we should treat enter as click for a certain element\r\n * @param element The HTML element to check\r\n */\r\n public static shouldTreatEnterAsClick(element: HTMLElement): boolean {\r\n if (!element) {\r\n return false;\r\n }\r\n const inputElement = element as HTMLInputElement;\r\n // TODO: More types of elements may be added here\r\n const isFileUploadControl = element.tagName === 'INPUT' && inputElement && inputElement.type === 'file';\r\n const isInDataTable = !!Dom.getAncestor(element, e => e.tagName === 'SME-DATA-TABLE');\r\n\r\n return isFileUploadControl || isInDataTable;\r\n }\r\n\r\n /**\r\n * Check tab list aria-selected with active status\r\n */\r\n public static checkActiveTab(): void {\r\n const tablists = document.querySelectorAll('[role=\\'tablist\\']');\r\n for (const tablist of Array.from(tablists)) {\r\n // As all controls should, the <sme-pivot> handles accessibility internally.\r\n if (tablist.parentElement.tagName !== 'SME-PIVOT') {\r\n Dom.updateAriaSelect(tablist as HTMLElement, false);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Update tab aria-selected status\r\n * @param element The HTML element.\r\n * @param isActive The HTML element is active or inactive.\r\n */\r\n public static updateAriaSelect(currentElement: HTMLElement, isActive: boolean): void {\r\n if (!currentElement) {\r\n return;\r\n }\r\n if (currentElement.classList.contains('active') || currentElement.classList.contains('sme-active')) {\r\n isActive = true;\r\n }\r\n if (currentElement.getAttribute('aria-selected') && !isActive) {\r\n currentElement.setAttribute('aria-selected', 'false');\r\n }\r\n if (currentElement.getAttribute('role') === 'tab' && isActive) {\r\n currentElement.setAttribute('aria-selected', 'true');\r\n }\r\n for (const childElement of Array.from(currentElement.children)) {\r\n Dom.updateAriaSelect(childElement as HTMLElement, isActive);\r\n }\r\n }\r\n\r\n /**\r\n * @param element Element whose focus origin we are trying to determine\r\n * @returns The element to focus on\r\n */\r\n public static getFocusOrigin(element: HTMLElement): HTMLElement {\r\n if (!element) {\r\n return;\r\n }\r\n\r\n if (Dom.isFocusable(element)) {\r\n return element;\r\n }\r\n\r\n // return previous focusable element in zone if it exist\r\n return Dom.getPreviousFocusableElement(element) ||\r\n\r\n // return next focusable element in zone if it exists and there is no previous element\r\n Dom.getNextFocusableElement(element) ||\r\n\r\n // return the first focusable element in the previous zone if it exists and there is not a next zone\r\n Dom.getPreviousZoneElement(element) ||\r\n\r\n // return the first focusable element in the next zone if it exists\r\n Dom.getNextZoneElement(element);\r\n }\r\n}\r\n\r\n/**\r\n * describes the position of the desired element in a list of elements\r\n */\r\nexport enum ElementPosition {\r\n First = 0,\r\n Previous = 1,\r\n Next = 2,\r\n Last = 3\r\n}\r\n"]}