{"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"]}