From f2f21a090e7be90b28679b180b02ed32196b9996 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 31 Mar 2017 11:27:32 -0400 Subject: [PATCH] Allow combobox to nest under id-container instead of body (re: https://github.com/openstreetmap/iD/issues/3925#issuecomment-290718356) --- modules/lib/d3.combobox.js | 31 +++++++++++++++++++------------ test/spec/lib/d3.combobox.js | 22 +++++++++++++++++++--- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/modules/lib/d3.combobox.js b/modules/lib/d3.combobox.js index 7b4fe95cb..a5f238cfc 100644 --- a/modules/lib/d3.combobox.js +++ b/modules/lib/d3.combobox.js @@ -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); }; diff --git a/test/spec/lib/d3.combobox.js b/test/spec/lib/d3.combobox.js index a8def826a..cc604c68e 100644 --- a/test/spec/lib/d3.combobox.js +++ b/test/spec/lib/d3.combobox.js @@ -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);