import * as q from '../../../backend/src/Model' ; import { AppState } from '../reducers' ; import { Dispatch } from 'redux' ; import { selectTopic } from './Tree' ; import { SettingsState } from '../reducers/Settings' ; import { sortedNodes } from '../sortedNodes' ; import { TopicViewModel } from '../model/TopicViewModel' ; export const moveSelectionUpOrDownwards = ( direction ) => ( dispatch , getState ) : any => { const state = getState ( ) ; const selected = state . tree . get ( 'selectedTopic' ) ; const tree = state . tree . get ( 'tree' ) ; if ( ! selected || ! tree ) { if ( tree ) { dispatch ( selectTopic ( tree ) ) ; } return ; } const nextTreeNode = nextVisibleElementInTree ( state . settings , tree , selected , direction ) ; if ( nextTreeNode && nextTreeNode . viewModel ) { dispatch ( selectTopic ( nextTreeNode ) ) ; } } ; export const moveInward = ( ) => ( dispatch , getState ) : any => { const state = getState ( ) ; const selected = state . tree . get ( 'selectedTopic' ) ; if ( ! selected || ! selected . viewModel ) { return ; } if ( ! selected . viewModel . isExpanded ( ) && selected . edgeCount ( ) > 0 ) { selected . viewModel . setExpanded ( true , true ) ; } else { dispatch ( moveSelectionUpOrDownwards ( 'next' ) ) ; } } ; export const moveOutward = ( ) => ( dispatch , getState ) : any => { const state = getState ( ) ; const selected = state . tree . get ( 'selectedTopic' ) ; if ( ! selected || ! selected . viewModel ) { return ; } if ( selected . viewModel . isExpanded ( ) && selected . edgeCount ( ) > 0 ) { selected . viewModel . setExpanded ( false , true ) ; } else { dispatch ( moveSelectionUpOrDownwards ( 'previous' ) ) ; } } ; function isTreeNodeVisible ( treeNode ) { return Boolean ( treeNode . viewModel ) ; } function nextVisibleElementInTree ( settings , tree , node , direction ) { if ( direction === 'next' ) { return findNextNodeDownward ( settings , node ) ; } else { return findNextNodeUpward ( settings , node ) ; } } /** Not very efficient but easy to implement, complexity should not be an issue here  */ function findNextNodeUpward ( settings , treeNode ) { const parent = treeNode . sourceEdge && treeNode . sourceEdge . source ; if ( ! parent ) { return undefined ; } const neighborNodes = sortedNodes ( settings , parent ) ; const nodeIdx = neighborNodes . findIndex ( n => n . path ( ) === treeNode . path ( ) ) ; if ( nodeIdx === 0 ) { return parent ; } const upwardNeighbor = neighborNodes [ nodeIdx - 1 ] ; if ( upwardNeighbor ) { return lastVisibleChild ( settings , upwardNeighbor ) ; } else { return findNextNodeUpward ( settings , parent ) ; } } function lastVisibleChild ( settings , treeNode ) { const nodes = sortedNodes ( settings , treeNode ) . filter ( isTreeNodeVisible ) ; if ( nodes . length === 0 ) { return treeNode ; } return lastVisibleChild ( settings , nodes [ nodes . length - 1 ] ) ; } function findNextNodeDownward ( settings , treeNode ) { const children = sortedNodes ( settings , treeNode ) . filter ( isTreeNodeVisible ) ; const firstChild = children [ 0 ] ; if ( firstChild ) { return firstChild ; } return findNextNodeDownwardNeighbor ( settings , treeNode ) ; } function findNextNodeDownwardNeighbor ( settings , treeNode ) { const parent = treeNode . sourceEdge && treeNode . sourceEdge . source ; if ( ! parent ) { return undefined ; } const neighborNodes = sortedNodes ( settings , parent ) . filter ( isTreeNodeVisible ) ; const nodeIdx = neighborNodes . findIndex ( n => n . path ( ) === treeNode . path ( ) ) ; const downwardNeighbor = neighborNodes [ nodeIdx + 1 ] ; if ( downwardNeighbor ) { return downwardNeighbor ; } else { return findNextNodeDownwardNeighbor ( settings , parent ) ; } }