<commit_before>import * as React from 'react'
import Styles from './styles'
import * as Util from './util'
import * as Constants from './constants'

import * as actions from '../actions'
import SearchBar from './SearchBar'
import TabWindowList from './TabWindowList'

function matchingTabs (searchStr, filteredTabWindow) {
  var ret = (searchStr.length > 0) ? filteredTabWindow.itemMatches : filteredTabWindow.tabWindow.tabItems
  return ret
}

function matchingTabsCount (searchStr, filteredTabWindow) {
  return matchingTabs(searchStr, filteredTabWindow).count()
}

function selectedTab (filteredTabWindow, searchStr, tabIndex) {
  if (searchStr.length === 0) {
    var tabWindow = filteredTabWindow.tabWindow
    var tabItem = tabWindow.tabItems.get(tabIndex)
    return tabItem
  }
  var filteredItem = filteredTabWindow.itemMatches.get(tabIndex)
  return filteredItem.tabItem
}

/**
 * An element that manages the selection.
 *
 * We want this as a distinct element from its parent TabMan, because it does local state management
 * and validation that should happen with respect to the (already calculated) props containing
 * filtered windows that we receive from above
 */
const SelectablePopup = React.createClass({
  getInitialState () {
    return {
      selectedWindowIndex: 0,
      selectedTabIndex: 0,
      scrolledToWindowId: -1,
      scrolledToTabId: -1
    }
  },

  handlePrevSelection (byPage) {
    if (this.props.filteredWindows.length === 0) {
      return
    }
    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]

    // const tabCount = (this.props.searchStr.length > 0) ? selectedWindow.itemMatches.count() : selectedWindow.tabWindow.tabItems.count()

    if (selectedWindow.tabWindow.open && this.state.selectedTabIndex > 0 && !byPage) {
      this.setState({ selectedTabIndex: this.state.selectedTabIndex - 1 })
    } else {
      // Already on first tab, try to back up to previous window:
      if (this.state.selectedWindowIndex > 0) {
        const prevWindowIndex = this.state.selectedWindowIndex - 1
        const prevWindow = this.props.filteredWindows[prevWindowIndex]
        const prevTabCount = (this.props.searchStr.length > 0) ? prevWindow.itemMatches.count() : prevWindow.tabWindow.tabItems.count()

        this.setState({ selectedWindowIndex: prevWindowIndex, selectedTabIndex: prevTabCount - 1 })
      }
    }
  },

  handleNextSelection (byPage) {
    if (this.props.filteredWindows.length === 0) {
      return
    }
    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]
    const tabCount = (this.props.searchStr.length > 0) ? selectedWindow.itemMatches.count() : selectedWindow.tabWindow.tabItems.count()

    // We'd prefer to use expanded state of window rather then open/closed state,
    // but that's hidden in the component...
    if (selectedWindow.tabWindow.open && (this.state.selectedTabIndex + 1) < tabCount && !byPage) {
      this.setState({ selectedTabIndex: this.state.selectedTabIndex + 1 })
    } else {
      // Already on last tab, try to advance to next window:
      if ((this.state.selectedWindowIndex + 1) < this.props.filteredWindows.length) {
        this.setState({ selectedWindowIndex: this.state.selectedWindowIndex + 1, selectedTabIndex: 0 })
      }
    }
  },

  handleSelectionEnter (inputRef) {
    if (this.props.filteredWindows.length === 0) {
      return
    }

    // TODO: deal with this.state.selectedTabIndex==-1

    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]
    const selectedTabItem = selectedTab(selectedWindow, this.props.searchStr, this.state.selectedTabIndex)
    actions.activateTab(this.props.winStore.getCurrentWindow(), selectedWindow.tabWindow, selectedTabItem, this.state.selectedTabIndex, this.props.storeUpdateHandler)
    // And reset the search field:
    inputRef.value = ''
    this.props.onSearchInput('')
  },<commit_msg>Window / tab list now circular when navigating with keyboard. Fixes #61<commit_after>import * as React from 'react'
import Styles from './styles'
import * as Util from './util'
import * as Constants from './constants'

import * as actions from '../actions'
import SearchBar from './SearchBar'
import TabWindowList from './TabWindowList'

function matchingTabs (searchStr, filteredTabWindow) {
  var ret = (searchStr.length > 0) ? filteredTabWindow.itemMatches : filteredTabWindow.tabWindow.tabItems
  return ret
}

function matchingTabsCount (searchStr, filteredTabWindow) {
  return matchingTabs(searchStr, filteredTabWindow).count()
}

function selectedTab (filteredTabWindow, searchStr, tabIndex) {
  if (searchStr.length === 0) {
    var tabWindow = filteredTabWindow.tabWindow
    var tabItem = tabWindow.tabItems.get(tabIndex)
    return tabItem
  }
  var filteredItem = filteredTabWindow.itemMatches.get(tabIndex)
  return filteredItem.tabItem
}

/**
 * An element that manages the selection.
 *
 * We want this as a distinct element from its parent TabMan, because it does local state management
 * and validation that should happen with respect to the (already calculated) props containing
 * filtered windows that we receive from above
 */
const SelectablePopup = React.createClass({
  getInitialState () {
    return {
      selectedWindowIndex: 0,
      selectedTabIndex: 0,
      scrolledToWindowId: -1,
      scrolledToTabId: -1
    }
  },

  handlePrevSelection (byPage) {
    if (this.props.filteredWindows.length === 0) {
      return
    }
    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]

    // const tabCount = (this.props.searchStr.length > 0) ? selectedWindow.itemMatches.count() : selectedWindow.tabWindow.tabItems.count()

    if (selectedWindow.tabWindow.open && this.state.selectedTabIndex > 0 && !byPage) {
      this.setState({ selectedTabIndex: this.state.selectedTabIndex - 1 })
    } else {
      // Already on first tab, try to back up to previous window:
      let prevWindowIndex
      if (this.state.selectedWindowIndex > 0) {
        prevWindowIndex = this.state.selectedWindowIndex - 1
      } else {
        // ring style, move to last window:
        prevWindowIndex = this.props.filteredWindows.length - 1
      }
      const prevWindow = this.props.filteredWindows[prevWindowIndex]
      const prevTabCount = (this.props.searchStr.length > 0) ? prevWindow.itemMatches.count() : prevWindow.tabWindow.tabItems.count()

      this.setState({ selectedWindowIndex: prevWindowIndex, selectedTabIndex: prevTabCount - 1 })
    }
  },

  handleNextSelection (byPage) {
    if (this.props.filteredWindows.length === 0) {
      return
    }
    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]
    const tabCount = (this.props.searchStr.length > 0) ? selectedWindow.itemMatches.count() : selectedWindow.tabWindow.tabItems.count()

    // We'd prefer to use expanded state of window rather then open/closed state,
    // but that's hidden in the component...
    if (selectedWindow.tabWindow.open && (this.state.selectedTabIndex + 1) < tabCount && !byPage) {
      this.setState({ selectedTabIndex: this.state.selectedTabIndex + 1 })
    } else {
      // Already on last tab, try to advance to next window:
      if ((this.state.selectedWindowIndex + 1) < this.props.filteredWindows.length) {
        this.setState({ selectedWindowIndex: this.state.selectedWindowIndex + 1, selectedTabIndex: 0 })
      } else {
        // wrap the search:
        this.setState({ selectedWindowIndex: 0, selectedTabIndex: 0 })
      }
    }
  },

  handleSelectionEnter (inputRef) {
    if (this.props.filteredWindows.length === 0) {
      return
    }

    // TODO: deal with this.state.selectedTabIndex==-1

    const selectedWindow = this.props.filteredWindows[this.state.selectedWindowIndex]
    const selectedTabItem = selectedTab(selectedWindow, this.props.searchStr, this.state.selectedTabIndex)
    actions.activateTab(this.props.winStore.getCurrentWindow(), selectedWindow.tabWindow, selectedTabItem, this.state.selectedTabIndex, this.props.storeUpdateHandler)
    // And reset the search field:
    inputRef.value = ''
    this.props.onSearchInput('')
  },
{'fraction_non_alphanumeric': 0.10362504577077994, 'fraction_numerical': 0.006224826071036251, 'mean_word_length': 3.6662870159453305, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4315773', 'n_tokens_mistral': 2337, 'n_tokens_neox': 2282, 'n_words': 590}