import { TreeNode , GetPrevNextOptions } from './interface' ; export function getFirstAvailableNode < R , G , I > ( nodes ) { if ( nodes . length === 0 ) return null ; const node = nodes [ 0 ] ; if ( node . isGroup || node . ignored || node . disabled ) { return node . getNext ( ) ; } return ( node as unknown ) as TreeNode < R > ; } function rawGetNext ( node , loop ) { const sibs = node . siblings ; const l = sibs . length ; const { index } = node ; if ( loop ) { return sibs [ ( index + 1 ) % l ] ; } else { if ( index === sibs . length - 1 ) return null ; return sibs [ index + 1 ] ; } } function move ( fromNode , dir , { loop = false , includeDisabled = false } = { } ) { const iterate = dir === 'prev' ? rawGetPrev : rawGetNext ; const getChildOptions = { reverse : dir === 'prev' } ; let meet = false ; let endNode = null ; function traverse ( node ) { if ( node === null ) return ; if ( node === fromNode ) { if ( ! meet ) { meet = true ; } else if ( ! fromNode . disabled && ! fromNode . isGroup ) { endNode = fromNode ; return ; } } else { if ( ( ! node . disabled || includeDisabled ) && ! node . ignored && ! node . isGroup ) { endNode = node ; return ; } } if ( node . isGroup ) { const child = getChild ( node , getChildOptions ) ; if ( child !== null ) { endNode = child ; } else { traverse ( iterate ( node , loop ) ) ; } } else { const nextNode = iterate ( node , false ) ; if ( nextNode !== null ) { traverse ( nextNode ) ; } else { const parent = rawGetParent ( node ) ; if ( parent ?. isGroup ) { traverse ( iterate ( parent , loop ) ) ; } else if ( loop ) { traverse ( iterate ( node , true ) ) ; } } } } traverse ( fromNode ) ; return endNode ; } function rawGetPrev ( node , loop ) { const sibs = node . siblings ; const l = sibs . length ; const { index } = node ; if ( loop ) { return sibs [ ( index - 1 + l ) % l ] ; } else { if ( index === 0 ) return null ; return sibs [ index - 1 ] ; } } function rawGetParent ( node ) { return node . parent ; } function getChild ( node , options = { } ) { const { reverse = false } = options ; const { children } = node ; if ( children ) { const { length } = children ; const start = reverse ? length - 1 : 0 ; const end = reverse ? - 1 : length ; const delta = reverse ? - 1 : 1 ; for ( let i = start ; i !== end ; i += delta ) { const child = children [ i ] ; if ( ! child . disabled && ! child . ignored ) { if ( child . isGroup ) { const childInGroup = getChild ( child , options ) ; if ( childInGroup !== null ) return childInGroup ; } else { return child ; } } } } return null ; } export const moveMethods = { getChild ( this ) { if ( this . ignored ) return null ; return getChild ( this ) ; } , getParent ( this ) { const { parent } = this ; if ( parent ?. isGroup ) { return parent . getParent ( ) ; } return parent ; } , getNext ( this , options = { } ) { return move ( this , 'next' , options ) ; } , getPrev ( this , options = { } ) { return move ( this , 'prev' , options ) ; } } ;