Allow combobox to nest under id-container instead of body

(re: https://github.com/openstreetmap/iD/issues/3925#issuecomment-290718356)
This commit is contained in:
Bryan Housel
2017-03-31 11:27:32 -04:00
parent ad5c9760c2
commit f2f21a090e
2 changed files with 38 additions and 15 deletions
+19 -12
View File
@@ -4,6 +4,7 @@ import { utilRebind } from '../../modules/util/rebind';
export function d3combobox() {
var event = d3.dispatch('accept'),
container = d3.select(document.body),
data = [],
suggestions = [],
minItems = 2,
@@ -20,10 +21,10 @@ export function d3combobox() {
var combobox = function(input, attachTo) {
var idx = -1,
container = d3.select(document.body)
wrapper = container
.selectAll('div.combobox')
.filter(function(d) { return d === input.node(); }),
shown = !container.empty();
shown = !wrapper.empty();
input
.classed('combobox-input', true)
@@ -70,7 +71,7 @@ export function d3combobox() {
function show() {
if (!shown) {
container = d3.select(document.body)
wrapper = container
.insert('div', ':first-child')
.datum(input.node())
.attr('class', 'combobox')
@@ -82,7 +83,7 @@ export function d3combobox() {
d3.event.preventDefault();
});
d3.select(document.body)
d3.select('body')
.on('scroll.combobox', render, true);
shown = true;
@@ -92,9 +93,9 @@ export function d3combobox() {
function hide() {
if (shown) {
idx = -1;
container.remove();
wrapper.remove();
d3.select(document.body)
d3.select('body')
.on('scroll.combobox', null);
shown = false;
@@ -116,7 +117,7 @@ export function d3combobox() {
break;
// tab
case 9:
container.selectAll('a.selected').each(function (d) {
wrapper.selectAll('a.selected').each(function (d) {
event.call('accept', this, d);
});
hide();
@@ -147,7 +148,7 @@ export function d3combobox() {
break;
// return
case 13:
container.selectAll('a.selected').each(function (d) {
wrapper.selectAll('a.selected').each(function (d) {
event.call('accept', this, d);
});
hide();
@@ -217,7 +218,7 @@ export function d3combobox() {
return;
}
var options = container
var options = wrapper
.selectAll('a.combobox-option')
.data(suggestions, function(d) { return d.value; });
@@ -239,7 +240,7 @@ export function d3combobox() {
var node = attachTo ? attachTo.node() : input.node(),
rect = node.getBoundingClientRect();
container
wrapper
.style('left', rect.left + 'px')
.style('width', rect.width + 'px')
.style('top', rect.height + rect.top + 'px');
@@ -251,7 +252,7 @@ export function d3combobox() {
}
function ensureVisible() {
var node = container.selectAll('a.selected').node();
var node = wrapper.selectAll('a.selected').node();
if (node) node.scrollIntoView();
}
@@ -289,6 +290,12 @@ export function d3combobox() {
return combobox;
};
combobox.container = function(_) {
if (!arguments.length) return container;
container = _;
return combobox;
};
return utilRebind(combobox, event, 'on');
}
@@ -306,6 +313,6 @@ d3combobox.off = function(input) {
.on('mousedown', null);
});
d3.select(document.body)
d3.select('body')
.on('scroll.combobox', null);
};
+19 -3
View File
@@ -1,5 +1,5 @@
describe('d3.combobox', function() {
var body, content, input, combobox;
var body, container, content, input, combobox;
var data = [
{title: 'foo', value: 'foo'},
@@ -62,14 +62,16 @@ describe('d3.combobox', function() {
beforeEach(function() {
body = d3.select('body');
content = body.append('div');
container = body.append('div').attr('class', 'id-container');
content = container.append('div');
input = content.append('input');
combobox = iD.lib.d3combobox();
});
afterEach(function() {
content.remove();
body.selectAll('.combobox').remove();
content.remove();
container.remove();
});
function focusTypeahead(input) {
@@ -82,6 +84,20 @@ describe('d3.combobox', function() {
expect(input).to.be.classed('combobox-input');
});
it('adds combobox under body by default', function() {
input.call(combobox.data(data));
focusTypeahead(input);
expect(d3.select('body > div.combobox').nodes().length).to.equal(1);
expect(d3.select('.id-container > div.combobox').nodes().length).to.equal(0);
});
it('adds combobox under container with container option', function() {
input.call(combobox.container(container).data(data));
focusTypeahead(input);
expect(d3.select('body > div.combobox').nodes().length).to.equal(0);
expect(d3.select('.id-container > div.combobox').nodes().length).to.equal(1);
});
it('shows a menu of entries on focus', function() {
input.call(combobox.data(data));
focusTypeahead(input);