From 0c2fcf74bbb49727163ea64486da2a611feebbe7 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 12 Feb 2019 21:16:38 +0900 Subject: Use single index on completions of the console --- src/console/components/console/completion.jsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/console/components') diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index c60543b..5f128d7 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/completion.jsx @@ -27,19 +27,17 @@ const CompletionItem = (props) => { class CompletionComponent extends Component { render() { let eles = []; + let index = 0; for (let i = 0; i < this.props.completions.length; ++i) { let group = this.props.completions[i]; eles.push(); - for (let j = 0; j < group.items.length; ++j) { + for (let j = 0; j < group.items.length; ++j, ++index) { let item = group.items[j]; - let selected = - i === this.props.groupSelection && - j === this.props.itemSelection; eles.push(); } } -- cgit v1.2.3 From 014963b32700d251bbb6991ce150025f578ea971 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Wed, 13 Feb 2019 22:11:35 +0900 Subject: Implement completion scroll --- .eslintrc | 1 + src/console/components/console/completion.jsx | 51 ++++++++++++++++++++++++--- src/console/reducers/index.js | 1 + 3 files changed, 49 insertions(+), 4 deletions(-) (limited to 'src/console/components') diff --git a/.eslintrc b/.eslintrc index cf11670..0f41e10 100644 --- a/.eslintrc +++ b/.eslintrc @@ -40,6 +40,7 @@ "no-alert": "off", "no-bitwise": "off", "no-console": ["error", { "allow": ["warn", "error"] }], + "no-continue": "off", "no-empty-function": "off", "no-magic-numbers": "off", "no-mixed-operators": "off", diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index 5f128d7..096653b 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/completion.jsx @@ -1,6 +1,8 @@ import { Component, h } from 'preact'; import { connect } from 'preact-redux'; +const COMPLETION_MAX_ITEMS = 33; + const CompletionTitle = (props) => { return
  • {props.title}
  • ; }; @@ -25,23 +27,64 @@ 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 view = 0; + let index = 0; + for (let group of nextProps.completions) { + ++view; + // TODO refactor + for (let _ of group.items) { + if (index === nextProps.select) { + return view; + } + ++view; + ++index; + } + } + })(); + + let viewOffset = 0; + if (nextProps.select < 0) { + viewOffset = 0; + } else if (prevState.select < nextProps.select) { + viewOffset = Math.max(prevState.viewOffset, + viewSelect - COMPLETION_MAX_ITEMS + 1); + } else if (prevState.select > nextProps.select) { + viewOffset = Math.min(prevState.viewOffset, viewSelect); + } + return { viewOffset, select: nextProps.select }; + } + render() { let eles = []; let index = 0; - for (let i = 0; i < this.props.completions.length; ++i) { - let group = this.props.completions[i]; + + for (let group of this.props.completions) { eles.push(); - for (let j = 0; j < group.items.length; ++j, ++index) { - let item = group.items[j]; + for (let item of group.items) { eles.push(); + ++index; } } + let viewOffset = this.state.viewOffset; + eles = eles.slice(viewOffset, viewOffset + COMPLETION_MAX_ITEMS); + return (
      { eles } diff --git a/src/console/reducers/index.js b/src/console/reducers/index.js index bcc7a2e..614a72f 100644 --- a/src/console/reducers/index.js +++ b/src/console/reducers/index.js @@ -7,6 +7,7 @@ const defaultState = { completionSource: '', completions: [], select: -1, + viewIndex: 0, }; const nextSelection = (state) => { -- cgit v1.2.3 From f43a2d2a9eda2a56709dca59bd003beec889d557 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Thu, 14 Feb 2019 20:55:55 +0900 Subject: Clean completion component --- src/console/components/console.jsx | 4 +++- src/console/components/console/completion.jsx | 22 ++++++++-------------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'src/console/components') diff --git a/src/console/components/console.jsx b/src/console/components/console.jsx index 23c93e3..f8213db 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,7 @@ class ConsoleComponent extends Component { case 'command': case 'find': return
      - + { this.input = c; }} mode={this.props.mode} diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index 096653b..ae081e6 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/completion.jsx @@ -1,8 +1,6 @@ import { Component, h } from 'preact'; import { connect } from 'preact-redux'; -const COMPLETION_MAX_ITEMS = 33; - const CompletionTitle = (props) => { return
    • {props.title}
    • ; }; @@ -38,18 +36,14 @@ class CompletionComponent extends Component { } let viewSelect = (() => { - let view = 0; let index = 0; - for (let group of nextProps.completions) { - ++view; - // TODO refactor - for (let _ of group.items) { - if (index === nextProps.select) { - return view; - } - ++view; - ++index; + 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; } })(); @@ -58,7 +52,7 @@ class CompletionComponent extends Component { viewOffset = 0; } else if (prevState.select < nextProps.select) { viewOffset = Math.max(prevState.viewOffset, - viewSelect - COMPLETION_MAX_ITEMS + 1); + viewSelect - nextProps.size + 1); } else if (prevState.select > nextProps.select) { viewOffset = Math.min(prevState.viewOffset, viewSelect); } @@ -83,7 +77,7 @@ class CompletionComponent extends Component { } let viewOffset = this.state.viewOffset; - eles = eles.slice(viewOffset, viewOffset + COMPLETION_MAX_ITEMS); + eles = eles.slice(viewOffset, viewOffset + this.props.size); return (
        -- cgit v1.2.3 From bc327e87a816beb6834a1d79c95c94ba34651ab3 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Fri, 15 Feb 2019 20:37:02 +0900 Subject: Fix Completion interface and add test --- src/console/components/console.jsx | 6 +- src/console/components/console/completion.jsx | 3 +- .../console/components/console/completion.test.jsx | 138 +++++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 test/console/components/console/completion.test.jsx (limited to 'src/console/components') diff --git a/src/console/components/console.jsx b/src/console/components/console.jsx index f8213db..7994f78 100644 --- a/src/console/components/console.jsx +++ b/src/console/components/console.jsx @@ -107,7 +107,11 @@ class ConsoleComponent extends Component { case 'command': case 'find': return
        - + { this.input = c; }} mode={this.props.mode} diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index ae081e6..be6b93f 100644 --- a/src/console/components/console/completion.jsx +++ b/src/console/components/console/completion.jsx @@ -87,5 +87,4 @@ class CompletionComponent extends Component { } } -const mapStateToProps = state => state; -export default connect(mapStateToProps)(CompletionComponent); +export default CompletionComponent; diff --git a/test/console/components/console/completion.test.jsx b/test/console/components/console/completion.test.jsx new file mode 100644 index 0000000..0b48fe2 --- /dev/null +++ b/test/console/components/console/completion.test.jsx @@ -0,0 +1,138 @@ +import { h, render } from 'preact'; +import Completion from 'console/components/console/completion' + +describe("console/components/console/completion", () => { + let completions = [{ + name: "Fruit", + items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], + }, { + name: "Element", + items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], + }]; + + beforeEach(() => { + document.body.innerHTML = ''; + }); + + it('renders Completion component', () => { + let ul = render(, document.body); + + expect(ul.children).to.have.lengthOf(8); + expect(ul.children[0].textContent).to.equal('Fruit'); + expect(ul.children[1].textContent).to.equal('apple'); + expect(ul.children[2].textContent).to.equal('banana'); + expect(ul.children[3].textContent).to.equal('cherry'); + expect(ul.children[4].textContent).to.equal('Element'); + expect(ul.children[5].textContent).to.equal('argon'); + expect(ul.children[6].textContent).to.equal('boron'); + expect(ul.children[7].textContent).to.equal('carbon'); + }); + + it('highlight current item', () => { + let ul = render(, document.body); + expect(ul.children[5].className.split(' ')).to.include('vimvixen-completion-selected'); + }); + + it('does not highlight any items', () => { + let ul = render(, document.body); + for (let li of ul.children) { + expect(li.className.split(' ')).not.to.include('vimvixen-completion-selected'); + } + }); + + + it('limits completion items', () => { + let ul = render(, document.body); + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); + expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); + }) + + it('scrolls up to down with select', () => { + let ul = render(, document.body); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); + expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['apple', 'banana', 'cherry']); + expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); + expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); + }); + + it('scrolls up to down with select', () => { + let ul = render(, document.body); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); + expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); + expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); + expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); + + ul = render(, document.body, ul); + + expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); + expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); + }); +}); -- cgit v1.2.3 From 9868da1ac479ee75a4abe8142a9b406a18b5ac52 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Fri, 15 Feb 2019 20:42:40 +0900 Subject: Remove unused import --- src/console/components/console/completion.jsx | 1 - 1 file changed, 1 deletion(-) (limited to 'src/console/components') diff --git a/src/console/components/console/completion.jsx b/src/console/components/console/completion.jsx index be6b93f..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
      • {props.title}
      • ; -- cgit v1.2.3