license import { Platform } from '@angular/cdk/platform' ; import { Injectable } from '@angular/core' ; /**
 * Configuration for the isFocusable method.
 */ export class IsFocusableConfig { /**
     * Whether to count an element as focusable even if it is not currently visible.
     */ ignoreVisibility : boolean = false ; } /**
 * Utility for checking the interactivity of an element, such as whether is is focusable or
 * tabbable.
 */ @ Injectable ( { providedIn : 'root' } ) export class InteractivityChecker { constructor ( private _platform ) { } param element returns isDisabled ( element ) { return element . hasAttribute ( 'disabled' ) ; } returns isVisible ( element ) { return hasGeometry ( element ) && getComputedStyle ( element ) . visibility === 'visible' ; } param element returns isTabbable ( element ) { if ( ! this . _platform . isBrowser ) { return false ; } const frameElement = getFrameElement ( getWindow ( element ) ) ; if ( frameElement ) { if ( getTabIndexValue ( frameElement ) === - 1 ) { return false ; } if ( ! this . isVisible ( frameElement ) ) { return false ; } } let nodeName = element . nodeName . toLowerCase ( ) ; let tabIndexValue = getTabIndexValue ( element ) ; if ( element . hasAttribute ( 'contenteditable' ) ) { return tabIndexValue !== - 1 ; } if ( nodeName === 'iframe' || nodeName === 'object' ) { return false ; } if ( this . _platform . WEBKIT && this . _platform . IOS && ! isPotentiallyTabbableIOS ( element ) ) { return false ; } if ( nodeName === 'audio' ) { if ( ! element . hasAttribute ( 'controls' ) ) { return false ; } return tabIndexValue !== - 1 ; } if ( nodeName === 'video' ) { if ( tabIndexValue === - 1 ) { return false ; } if ( tabIndexValue !== null ) { return true ; } return this . _platform . FIREFOX || element . hasAttribute ( 'controls' ) ; } return element . tabIndex >= 0 ; } param element param config returns isFocusable ( element , config ? ) { return ( isPotentiallyFocusable ( element ) && ! this . isDisabled ( element ) && ( config ?. ignoreVisibility || this . isVisible ( element ) ) ) ; } } /**
 * Returns the frame element from a window object. Since browsers like MS Edge throw errors if
 * the frameElement property is being accessed from a different host address, this property
 * should be accessed carefully.
 */ function getFrameElement ( window ) { try { return window . frameElement as HTMLElement ; } catch { return null ; } } /** Checks whether the specified element has any geometry / rectangles. */ function hasGeometry ( element ) { return ! ! ( element . offsetWidth || element . offsetHeight || ( typeof element . getClientRects === 'function' && element . getClientRects ( ) . length ) ) ; } /** Gets whether an element's  */ function isNativeFormElement ( element ) { let nodeName = element . nodeName . toLowerCase ( ) ; return ( nodeName === 'input' || nodeName === 'select' || nodeName === 'button' || nodeName === 'textarea' ) ; } /** Gets whether an element is an `<input type="hidden">`. */ function isHiddenInput ( element ) { return isInputElement ( element ) && element . type == 'hidden' ; } /** Gets whether an element is an anchor that has an href attribute. */ function isAnchorWithHref ( element ) { return isAnchorElement ( element ) && element . hasAttribute ( 'href' ) ; } /** Gets whether an element is an input element. */ function isInputElement ( element ) { return element . nodeName . toLowerCase ( ) == 'input' ; } /** Gets whether an element is an anchor element. */ function isAnchorElement ( element ) { return element . nodeName . toLowerCase ( ) == 'a' ; } /** Gets whether an element has a valid tabindex. */ function hasValidTabIndex ( element ) { if ( ! element . hasAttribute ( 'tabindex' ) || element . tabIndex === undefined ) { return false ; } let tabIndex = element . getAttribute ( 'tabindex' ) ; return ! ! ( tabIndex && ! isNaN ( parseInt ( tabIndex , 10 ) ) ) ; } /**
 * Returns the parsed tabindex from the element attributes instead of returning the
 * evaluated tabindex from the browsers defaults.
 */ function getTabIndexValue ( element ) { if ( ! hasValidTabIndex ( element ) ) { return null ; } const tabIndex = parseInt ( element . getAttribute ( 'tabindex' ) || '' , 10 ) ; return isNaN ( tabIndex ) ? - 1 : tabIndex ; } /** Checks whether the specified element is potentially tabbable on iOS */ function isPotentiallyTabbableIOS ( element ) { let nodeName = element . nodeName . toLowerCase ( ) ; let inputType = nodeName === 'input' && ( element as HTMLInputElement ) . type ; return ( inputType === 'text' || inputType === 'password' || nodeName === 'select' || nodeName === 'textarea' ) ; } /**
 * Gets whether an element is potentially focusable without taking current visible/disabled state
 * into account.
 */ function isPotentiallyFocusable ( element ) { if ( isHiddenInput ( element ) ) { return false ; } return ( isNativeFormElement ( element ) || isAnchorWithHref ( element ) || element . hasAttribute ( 'contenteditable' ) || hasValidTabIndex ( element ) ) ; } /** Gets the parent window of a DOM node with regards of being inside of an iframe. */ function getWindow ( node ) { return ( node . ownerDocument && node . ownerDocument . defaultView ) || window ; }