EmbyCrackedClient/web/modules/focusmanager.js
2025-06-25 11:46:04 +08:00

1 line
No EOL
11 KiB
JavaScript

import layoutManager from"./layoutmanager.js";import events from"./emby-apiclient/events.js";let defaultScope=document.body,scopes=[],_currentScope=defaultScope;function pushScope(elem){scopes.includes(elem)||(scopes.push(elem),_currentScope=elem)}function removeItemOnce(arr,value){value=arr.indexOf(value);return-1<value&&arr.splice(value,1),arr}function popScope(elem){removeItemOnce(scopes,elem),_currentScope=findCurrentScope()}function findCurrentScope(){return scopes[scopes.length-1]||defaultScope}function getCurrentScope(){return _currentScope}function hasExclusiveFocusScope(){return scopes.length}function isAutoFocusEnabled(elem){if(layoutManager.tv)return!0;if(elem)switch(elem.tagName){case"INPUT":switch(elem.type){case"checkbox":case"radio":case"file":case"hidden":case"range":return!1;default:return!0}case"TEXTAREA":return!0}return!1}function getElementToAutoFocus(view,options){var element;return options&&!1===options.findAutoFocusElement||!(element=view.querySelector(".autofocus"))||!isCurrentlyFocusableInternal(element,!0)?getFocusableElements(view,1,".noautofocus",options)[0]||getFocusableElements(view,1,null,options)[0]:element}function autoFocus(view,options){view=getElementToAutoFocus(view,options);return view&&focus(view,options)}function focus(element,options){for(;element.classList.contains("focusable");){var autoFocusElement=getElementToAutoFocus(element,options);if(!autoFocusElement)break;element=autoFocusElement}return options?.skipIfNotEnabled&&!isAutoFocusEnabled(element)?null:(focusInternal(element,options),element)}let lastFocusInfo={};function focusInternal(element,options){try{lastFocusInfo={element:element,options:options},element.focus({preventScroll:!0})}catch(err){console.log("Error in focusManager.focusInternal: "+err)}}let focusableTagNames=["INPUT","TEXTAREA","SELECT","BUTTON","A","DIV[tabindex]"],focusableQuerySelectors=focusableTagNames.map(function(t){return"A"===t&&(t+="[href]"),t+':not([tabindex="-1"]):not(:disabled)'}),focusableQuery=(focusableQuerySelectors.push(".focusable"),focusableQuerySelectors.join(","));function buildFocusableQuery(excludeSelector){if(!excludeSelector)return focusableQuery;var newQuerySelectors=[focusableQuerySelectors.length];for(let i=0,length=focusableQuerySelectors.length;i<length;i++)newQuerySelectors[i]=focusableQuerySelectors[i]+":not("+excludeSelector+")";return newQuerySelectors.join(",")}let focusableTagNameQuery=focusableTagNames.join(","),focusableParentQuery=focusableTagNames.join(",")+",.focusable";function focusableParent(elem,includeGroups){return!1===includeGroups?elem.closest(focusableTagNameQuery):elem.closest(focusableParentQuery)}function isCurrentlyFocusableInternal(elem,checkOffsetParent){return!(checkOffsetParent&&null===elem.offsetParent||elem.disabled)}function isCurrentlyFocusable(elem){return!!elem.matches(focusableQuery)&&isCurrentlyFocusableInternal(elem,!0)}function getFocusableElements(parent,limit,excludeSelector,options){var fn=(parent=parent||_currentScope).getFocusableElements;let elems;var focusableElements=[];for(let i=0,length=(elems=(elems=fn?fn(parent,document.activeElement,null,options):elems)||parent.querySelectorAll(buildFocusableQuery(excludeSelector))).length;i<length;i++){var elem=elems[i];if(isCurrentlyFocusableInternal(elem,limit)&&(focusableElements.push(elem),limit)&&limit<=focusableElements.length)break}return focusableElements}let focusContainerQueries=[".focuscontainer,.focuscontainer-x",".focuscontainer,.focuscontainer-x",".focuscontainer,.focuscontainer-y,.focuscontainer-up",".focuscontainer,.focuscontainer-y,.focuscontainer-down"];function getFocusContainer(elem,direction){var defaultScopeResult,direction=focusContainerQueries[direction],direction=elem.closest(direction);return direction||((direction=_currentScope)===(defaultScopeResult=defaultScope)||direction.contains(elem)?direction:defaultScopeResult)}function getNearestElement(activeElement,activeElementRect,direction,focusableElements,enableSingleElementOptimization,focusableContainer){if(enableSingleElementOptimization)return{element:enableSingleElementOptimization=focusableElements[0],rect:enableSingleElementOptimization?.getBoundingClientRect()};let nearestElement,nearestElementRect;var activeElementTop=activeElementRect.top,activeElementLeft=activeElementRect.left,point1x=parseFloat(activeElementLeft)||0,point1y=parseFloat(activeElementTop)||0,point2x=parseFloat(point1x+activeElementRect.width-1)||point1x,point2y=parseFloat(point1y+activeElementRect.height-1)||point1y;let minDistance=1/0;for(let i=0,length=focusableElements.length;i<length;i++){var curr=focusableElements[i];if(curr!==activeElement&&curr!==focusableContainer){var elementRect=curr.getBoundingClientRect(),elementRectWidth=elementRect.width,elementRectHeight=elementRect.height;if(elementRectWidth&&elementRectHeight){var elementRectLeft=elementRect.left,elementRectTop=elementRect.top;switch(direction){case 0:if(activeElementLeft<=elementRectLeft)continue;if(elementRect.right===activeElementRect.right)continue;break;case 1:if(elementRect.right<=activeElementRect.right)continue;if(elementRectLeft===activeElementLeft)continue;break;case 2:if(activeElementTop<=elementRectTop)continue;if(elementRect.bottom>=activeElementRect.bottom)continue;break;case 3:if(elementRect.bottom<=activeElementRect.bottom)continue;if(elementRectTop<=activeElementTop)continue}var x2=elementRectLeft+elementRectWidth-1,y2=elementRectTop+elementRectHeight-1;let distX,distY;switch(direction){case 0:var intersectY=intersection(point1y,point2y,elementRectTop,y2);distX=Math.abs(point1x-Math.min(point1x,x2)),distY=intersectY||1+Math.min(Math.abs(point1y-y2),Math.abs(point2y-elementRectTop));break;case 1:{let intersectY=intersection(point1y,point2y,elementRectTop,y2);distX=Math.abs(point2x-Math.max(point2x,elementRectLeft)),distY=intersectY||1+Math.min(Math.abs(point1y-y2),Math.abs(point2y-elementRectTop));break}case 2:intersectY=intersection(point1x,point2x,elementRectLeft,x2);distY=Math.abs(point1y-Math.min(point1y,y2)),distX=intersectY||1+Math.min(Math.abs(point1x-x2),Math.abs(point2x-elementRectLeft));break;case 3:{let intersectX=intersection(point1x,point2x,elementRectLeft,x2);distY=Math.abs(point2y-Math.max(point2y,elementRectTop)),distX=intersectX||1+Math.min(Math.abs(point1x-x2),Math.abs(point2x-elementRectLeft));break}}elementRectWidth=Math.sqrt(distX*distX+distY*distY);elementRectWidth<minDistance&&(nearestElement=curr,nearestElementRect=elementRect,minDistance=elementRectWidth)}}}return{element:nearestElement,rect:nearestElementRect}}function nav(activeElement,direction,container){if(!(activeElement=(activeElement=activeElement||document.activeElement)&&(parent=focusableParent(activeElement))?parent:activeElement))return autoFocus(container,{findAutoFocusElement:!1,preventScroll:!1});var parent=activeElement.closest(".focusable");let nearestElement,activeElementRect,fn=container.getFocusableElements,enableSingleElementOptimization,focusable;fn&&(focusable=fn(nearestElement,activeElement,direction))&&(enableSingleElementOptimization=focusable.length<2),focusable||(focusable=container.querySelectorAll(focusableQuery),enableSingleElementOptimization=0===focusable.length),enableSingleElementOptimization||(activeElementRect=activeElement.getBoundingClientRect());container=getNearestElement(activeElement,activeElementRect,direction,focusable,enableSingleElementOptimization,parent);if(nearestElement=container.element){var nearestElementFocusableParent=(nearestElement=activeElement&&(nearestElementFocusableParent=nearestElement.closest(".focusable"))&&nearestElementFocusableParent!==nearestElement&&parent!==nearestElementFocusableParent?nearestElementFocusableParent:nearestElement).getAttribute("data-focusabletype");if("autofocus"===nearestElementFocusableParent)return autoFocus(nearestElement,{preventScroll:!1,itemBoundingClientRect:container.rect});if("nearest"!==nearestElementFocusableParent)return focusInternal(nearestElement,{preventScroll:!1,itemBoundingClientRect:container.rect,direction:direction}),nearestElement;{let fn=nearestElement.getFocusableElements,enableSingleElementOptimization,elems;fn&&(elems=fn(nearestElement,activeElement,direction))&&(enableSingleElementOptimization=elems.length<2),elems||(elems=nearestElement.querySelectorAll(focusableQuery),enableSingleElementOptimization=0===elems.length),enableSingleElementOptimization||(activeElementRect=activeElementRect||activeElement.getBoundingClientRect());nearestElementFocusableParent=getNearestElement(activeElement,activeElementRect,direction,elems,enableSingleElementOptimization,parent),container=nearestElementFocusableParent.element;return container?(focusInternal(container,{preventScroll:!1,itemBoundingClientRect:nearestElementFocusableParent.rect,direction:direction}),container):autoFocus(nearestElement,{preventScroll:!1})}}}function intersection(a1,a2,b1,b2){b1=Math.max(a1,b1),b2=Math.min(a2,b2);return b2<=b1?null:1e-9+(1-(b2-b1)/(a2-a1))}function sendText(text){document.activeElement.value=text}function canNavOut(container,direction){var classList=container.classList;switch(direction){case 0:case 1:return classList.contains("navout-x");case 2:return classList.contains("navout-up");case 3:return classList.contains("navout-down");default:return!1}}function navOuter(sourceElement,direction){let container=sourceElement?getFocusContainer(sourceElement,direction):_currentScope;if(container===sourceElement)return container.controller?.autoFocus?container.controller.autoFocus({skipIfNotEnabled:!1,preventScroll:!1}):autoFocus(container,{preventScroll:!1});let newElement;for(;container&&!(newElement=nav(sourceElement,direction,container))&&canNavOut(container,direction);){var newContainerParent=(container.getNavOutDestination?container.getNavOutDestination(direction):null)||container.parentNode;if(!newContainerParent)break;container=getFocusContainer(newContainerParent,direction)}return newElement}let Directions={left:0,right:1,up:2,down:3},focusManager={autoFocus:autoFocus,focus:focus,focusableParent:focusableParent,moveLeft:function(sourceElement){sourceElement=navOuter(sourceElement,0);return sourceElement&&events.trigger(focusManager,"move"),sourceElement},moveRight:function(sourceElement){sourceElement=navOuter(sourceElement,1);return sourceElement&&events.trigger(focusManager,"move"),sourceElement},moveUp:function(sourceElement){sourceElement=navOuter(sourceElement,2);return sourceElement&&events.trigger(focusManager,"move"),sourceElement},moveDown:function(sourceElement){sourceElement=navOuter(sourceElement,3);return sourceElement&&events.trigger(focusManager,"move"),sourceElement},sendText:sendText,isCurrentlyFocusable:isCurrentlyFocusable,pushScope:pushScope,popScope:popScope,hasExclusiveFocusScope:hasExclusiveFocusScope,getCurrentScope:getCurrentScope,isAutoFocusEnabled:isAutoFocusEnabled,getLastFocusInfo:function(){return lastFocusInfo},directions:Directions};export default focusManager;