From 416a92f5f5f6ed0d6df3902090cfa721cab99982 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 11 Oct 2013 14:20:06 -0700 Subject: [PATCH] Don't show combobox menu with only one item --- js/lib/d3.combobox.js | 2 +- test/spec/lib/d3.combobox.js | 73 ++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/js/lib/d3.combobox.js b/js/lib/d3.combobox.js index 6dee1708f..0243daa19 100644 --- a/js/lib/d3.combobox.js +++ b/js/lib/d3.combobox.js @@ -189,7 +189,7 @@ d3.combobox = function() { } function render() { - if (suggestions.length && document.activeElement === input.node()) { + if (suggestions.length > 1 && document.activeElement === input.node()) { show(); } else { hide(); diff --git a/test/spec/lib/d3.combobox.js b/test/spec/lib/d3.combobox.js index e8893662e..8acf0c891 100644 --- a/test/spec/lib/d3.combobox.js +++ b/test/spec/lib/d3.combobox.js @@ -2,8 +2,9 @@ describe("d3.combobox", function() { var body, content, input, combobox; var data = [ - {title: 'abbot', value: 'abbot'}, - {title: 'costello', value: 'costello'} + {title: 'foo', value: 'foo'}, + {title: 'bar', value: 'bar'}, + {title: 'baz', value: 'baz'} ]; function simulateKeypress(key) { @@ -73,17 +74,25 @@ describe("d3.combobox", function() { expect(input).to.be.classed('combobox-input'); }); - it("creates entries for each datum", function() { + it("shows a menu of entries on focus", function() { input.call(combobox.data(data)); input.node().focus(); - expect(body.selectAll('.combobox-option').size()).to.equal(2); + expect(body.selectAll('.combobox-option').size()).to.equal(3); + expect(body.selectAll('.combobox-option').text()).to.equal('foo'); }); it("filters entries to those matching the value", function() { - input.property('value', 'c').call(combobox.data(data)); + input.property('value', 'b').call(combobox.data(data)); input.node().focus(); - expect(body.selectAll('.combobox-option').size()).to.equal(1); - expect(body.selectAll('.combobox-option').text()).to.equal('costello'); + expect(body.selectAll('.combobox-option').size()).to.equal(2); + expect(body.selectAll('.combobox-option')[0][0].text).to.equal('bar'); + expect(body.selectAll('.combobox-option')[0][1].text).to.equal('baz'); + }); + + it("shows no menu on focus if it would contain only one item", function() { + input.property('value', 'f').call(combobox.data(data)); + input.node().focus(); + expect(body.selectAll('.combobox-option').size()).to.equal(0); }); it("is initially shown with no selection", function() { @@ -95,27 +104,27 @@ describe("d3.combobox", function() { it("selects the first option matching the input", function() { input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('c'); + simulateKeypress('b'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(1); - expect(body.selectAll('.combobox-option.selected').text()).to.equal('costello'); + expect(body.selectAll('.combobox-option.selected').text()).to.equal('bar'); }); it("selects the completed portion of the value", function() { input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('c'); - expect(input.property('value')).to.equal('costello'); + simulateKeypress('b'); + expect(input.property('value')).to.equal('bar'); expect(input.property('selectionStart')).to.equal(1); - expect(input.property('selectionEnd')).to.equal(8); + expect(input.property('selectionEnd')).to.equal(3); }); it("preserves the case of the input portion of the value", function() { input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('C'); - expect(input.property('value')).to.equal('Costello'); + simulateKeypress('B'); + expect(input.property('value')).to.equal('Bar'); expect(input.property('selectionStart')).to.equal(1); - expect(input.property('selectionEnd')).to.equal(8); + expect(input.property('selectionEnd')).to.equal(3); }); it("does not select when value is empty", function() { @@ -128,30 +137,30 @@ describe("d3.combobox", function() { it("does not select when value is not a prefix of any suggestion", function() { input.call(combobox.fetcher(function(_, cb) { cb(data); })); input.node().focus(); - simulateKeypress('c'); - simulateKeypress('a'); + simulateKeypress('b'); + simulateKeypress('i'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(0); }); it("does not select or autocomplete after ⌫", function() { input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('c'); + simulateKeypress('b'); simulateKeypress('⌫'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(0); - expect(input.property('value')).to.equal('c'); + expect(input.property('value')).to.equal('b'); }); it("does not select or autocomplete after ⌦", function() { input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('a'); - simulateKeypress('c'); + simulateKeypress('f'); + simulateKeypress('b'); simulateKeypress('←'); simulateKeypress('←'); simulateKeypress('⌦'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(0); - expect(input.property('value')).to.equal('c'); + expect(input.property('value')).to.equal('b'); }); it("selects and autocompletes the next/prev suggestion on ↓/↑", function() { @@ -160,39 +169,39 @@ describe("d3.combobox", function() { simulateKeypress('↓'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(1); - expect(body.selectAll('.combobox-option.selected').text()).to.equal('abbot'); - expect(input.property('value')).to.equal('abbot'); + expect(body.selectAll('.combobox-option.selected').text()).to.equal('foo'); + expect(input.property('value')).to.equal('foo'); simulateKeypress('↓'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(1); - expect(body.selectAll('.combobox-option.selected').text()).to.equal('costello'); - expect(input.property('value')).to.equal('costello'); + expect(body.selectAll('.combobox-option.selected').text()).to.equal('bar'); + expect(input.property('value')).to.equal('bar'); simulateKeypress('↑'); expect(body.selectAll('.combobox-option.selected').size()).to.equal(1); - expect(body.selectAll('.combobox-option.selected').text()).to.equal('abbot'); - expect(input.property('value')).to.equal('abbot'); + expect(body.selectAll('.combobox-option.selected').text()).to.equal('foo'); + expect(input.property('value')).to.equal('foo'); }); it("emits accepted event with selected datum on ⇥", function(done) { combobox.on('accept', function(d) { - expect(d).to.eql({title: 'abbot', value: 'abbot'}); + expect(d).to.eql({title: 'bar', value: 'bar'}); done(); }); input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('a'); + simulateKeypress('b'); simulateKeypress('⇥'); }); it("emits accepted event with selected datum on ↩", function(done) { combobox.on('accept', function(d) { - expect(d).to.eql({title: 'abbot', value: 'abbot'}); + expect(d).to.eql({title: 'bar', value: 'bar'}); done(); }); input.call(combobox.data(data)); input.node().focus(); - simulateKeypress('a'); + simulateKeypress('b'); simulateKeypress('↩'); });