diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/console/components/console.jsx | 8 | ||||
| -rw-r--r-- | src/console/components/console/completion.jsx | 55 | ||||
| -rw-r--r-- | src/console/reducers/index.js | 70 | 
3 files changed, 79 insertions, 54 deletions
diff --git a/src/console/components/console.jsx b/src/console/components/console.jsx index 23c93e3..7994f78 100644 --- a/src/console/components/console.jsx +++ b/src/console/components/console.jsx @@ -6,6 +6,8 @@ import Completion from './console/completion';  import Message from './console/message';  import * as consoleActions from '../../console/actions/console'; +const COMPLETION_MAX_ITEMS = 33; +  class ConsoleComponent extends Component {    onBlur() {      if (this.props.mode === 'command' || this.props.mode === 'find') { @@ -105,7 +107,11 @@ class ConsoleComponent extends Component {      case 'command':      case 'find':        return <div className='vimvixen-console-command-wrapper'> -        <Completion /> +        <Completion +          size={COMPLETION_MAX_ITEMS} +          completions={this.props.completions} +          select={this.props.select} +        />          <Input            ref={(c) => { this.input = c; }}            mode={this.props.mode} diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index c60543b..d836cec 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/completion.jsx @@ -1,5 +1,4 @@  import { Component, h } from 'preact'; -import { connect } from 'preact-redux';  const CompletionTitle = (props) => {    return <li className='vimvixen-console-completion-title' >{props.title}</li>; @@ -25,25 +24,60 @@ const CompletionItem = (props) => {  class CompletionComponent extends Component { +  constructor() { +    super(); +    this.state = { viewOffset: 0, select: -1 }; +  } + +  static getDerivedStateFromProps(nextProps, prevState) { +    if (prevState.select === nextProps.select) { +      return null; +    } + +    let viewSelect = (() => { +      let index = 0; +      for (let i = 0; i < nextProps.completions.length; ++i) { +        ++index; +        let g = nextProps.completions[i]; +        if (nextProps.select + i + 1 < index + g.items.length) { +          return nextProps.select + i + 1; +        } +        index += g.items.length; +      } +    })(); + +    let viewOffset = 0; +    if (nextProps.select < 0) { +      viewOffset = 0; +    } else if (prevState.select < nextProps.select) { +      viewOffset = Math.max(prevState.viewOffset, +        viewSelect - nextProps.size + 1); +    } else if (prevState.select > nextProps.select) { +      viewOffset = Math.min(prevState.viewOffset, viewSelect); +    } +    return { viewOffset, select: nextProps.select }; +  } +    render() {      let eles = []; -    for (let i = 0; i < this.props.completions.length; ++i) { -      let group = this.props.completions[i]; +    let index = 0; + +    for (let group of this.props.completions) {        eles.push(<CompletionTitle title={ group.name }/>); -      for (let j = 0; j < group.items.length; ++j) { -        let item = group.items[j]; -        let selected = -          i === this.props.groupSelection && -          j === this.props.itemSelection; +      for (let item of group.items) {          eles.push(<CompletionItem            icon={item.icon}            caption={item.caption}            url={item.url} -          highlight={selected} +          highlight={index === this.props.select}          / >); +        ++index;        }      } +    let viewOffset = this.state.viewOffset; +    eles = eles.slice(viewOffset, viewOffset + this.props.size); +      return (        <ul className='vimvixen-console-completion'>          { eles } @@ -52,5 +86,4 @@ class CompletionComponent extends Component {    }  } -const mapStateToProps = state => state; -export default connect(mapStateToProps)(CompletionComponent); +export default CompletionComponent; diff --git a/src/console/reducers/index.js b/src/console/reducers/index.js index 7dcad17..614a72f 100644 --- a/src/console/reducers/index.js +++ b/src/console/reducers/index.js @@ -6,52 +6,43 @@ const defaultState = {    consoleText: '',    completionSource: '',    completions: [], -  groupSelection: -1, -  itemSelection: -1, +  select: -1, +  viewIndex: 0,  };  const nextSelection = (state) => {    if (state.completions.length === 0) { -    return [-1, -1]; +    return -1;    } -  if (state.groupSelection < 0) { -    return [0, 0]; +  if (state.select < 0) { +    return 0;    } -  let group = state.completions[state.groupSelection]; -  if (state.groupSelection + 1 >= state.completions.length && -    state.itemSelection + 1 >= group.items.length) { -    return [-1, -1]; +  let length = state.completions +    .map(g => g.items.length) +    .reduce((x, y) => x + y); +  if (state.select + 1 < length) { +    return state.select + 1;    } -  if (state.itemSelection + 1 >= group.items.length) { -    return [state.groupSelection + 1, 0]; -  } -  return [state.groupSelection, state.itemSelection + 1]; +  return -1;  };  const prevSelection = (state) => { -  if (state.groupSelection < 0) { -    return [ -      state.completions.length - 1, -      state.completions[state.completions.length - 1].items.length - 1 -    ]; -  } -  if (state.groupSelection === 0 && state.itemSelection === 0) { -    return [-1, -1]; -  } else if (state.itemSelection === 0) { -    return [ -      state.groupSelection - 1, -      state.completions[state.groupSelection - 1].items.length - 1 -    ]; +  let length = state.completions +    .map(g => g.items.length) +    .reduce((x, y) => x + y); +  if (state.select < 0) { +    return length - 1;    } -  return [state.groupSelection, state.itemSelection - 1]; +  return state.select - 1;  }; -const nextConsoleText = (completions, group, item, defaults) => { -  if (group < 0 || item < 0) { +const nextConsoleText = (completions, select, defaults) => { +  if (select < 0) {      return defaults;    } -  return completions[group].items[item].content; +  let items = completions.map(g => g.items).reduce((g1, g2) => g1.concat(g2)); +  return items[select].content;  };  // eslint-disable-next-line max-lines-per-function @@ -90,25 +81,20 @@ export default function reducer(state = defaultState, action = {}) {      return { ...state,        completions: action.completions,        completionSource: action.completionSource, -      groupSelection: -1, -      itemSelection: -1, }; +      select: -1 };    case actions.CONSOLE_COMPLETION_NEXT: { -    let next = nextSelection(state); +    let select = nextSelection(state);      return { ...state, -      groupSelection: next[0], -      itemSelection: next[1], +      select: select,        consoleText: nextConsoleText( -        state.completions, next[0], next[1], -        state.completionSource), }; +        state.completions, select, state.completionSource) };    }    case actions.CONSOLE_COMPLETION_PREV: { -    let next = prevSelection(state); +    let select = prevSelection(state);      return { ...state, -      groupSelection: next[0], -      itemSelection: next[1], +      select: select,        consoleText: nextConsoleText( -        state.completions, next[0], next[1], -        state.completionSource), }; +        state.completions, select, state.completionSource) };    }    default:      return state;  | 
