From b9444ab9911b6935a01d3d2d024744328e7d884c Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sat, 26 Jan 2019 13:22:31 -0500 Subject: [PATCH] Restore hand cursor on dropdown carat (closes #5769) This change allows pointer events to flow to the caret, and forwards them back to the combo input. Also renames several event handlers for clarity, and increases the double-click detection threshold. --- css/80_app.css | 1 - modules/ui/combobox.js | 84 +++++++++++++++++++++------------------- test/spec/ui/combobox.js | 4 +- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index dacc04ae1..530e7cf64 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1949,7 +1949,6 @@ div.combobox { margin-left: -30px; vertical-align: top; cursor: pointer; - pointer-events: none; } [dir='rtl'] .combobox-caret { margin-left: 0; diff --git a/modules/ui/combobox.js b/modules/ui/combobox.js index be9702244..cc98f4ca1 100644 --- a/modules/ui/combobox.js +++ b/modules/ui/combobox.js @@ -47,43 +47,49 @@ export function uiCombobox(context, klass) { input .classed('combobox-input', true) - .on('focus.combobox', focus) - .on('blur.combobox', blur) - .on('keydown.combobox', keydown) - .on('keyup.combobox', keyup) - .on('input.combobox', change) - .on('mousedown.combobox', mousedown) - .each(addCaret); + .on('focus.combo-input', focus) + .on('blur.combo-input', blur) + .on('keydown.combo-input', keydown) + .on('keyup.combo-input', keyup) + .on('input.combo-input', change) + .on('mousedown.combo-input', mousedown) + .each(function() { + var parent = this.parentNode; + var sibling = this.nextSibling; - - function addCaret() { - var parent = this.parentNode; - var sibling = this.nextSibling; - - d3_select(parent).selectAll('.combobox-caret') - .filter(function(d) { return d === input.node(); }) - .data([input.node()]) - .enter() - .insert('div', function() { return sibling; }) - .attr('class', 'combobox-caret'); - } + d3_select(parent).selectAll('.combobox-caret') + .filter(function(d) { return d === input.node(); }) + .data([input.node()]) + .enter() + .insert('div', function() { return sibling; }) + .attr('class', 'combobox-caret') + .on('mousedown.combo-caret mouseup.combo-caret', function() { + var e2 = new MouseEvent(d3_event.type, d3_event); + d3_event.preventDefault(); // don't steal focus from input + input.node().dispatchEvent(e2); // send events to the input instead + }); + }); function mousedown() { if (d3_event.button !== 0) return; // left click only + _tDown = +new Date(); + // clear selection var start = input.property('selectionStart'); var end = input.property('selectionEnd'); - if (start !== end) return; // exit if user is deselecting + if (start !== end) { + var val = utilGetSetValue(input); + input.node().setSelectionRange(val.length, val.length); + return; + } - _tDown = +new Date(); - input.on('mouseup.combobox', mouseup); + input.on('mouseup.combo-input', mouseup); } function mouseup() { - input.on('mouseup.combobox', null); - + input.on('mouseup.combo-input', null); if (d3_event.button !== 0) return; // left click only var start = input.property('selectionStart'); @@ -100,7 +106,7 @@ export function uiCombobox(context, klass) { show(); render(); }); - }, 75); + }, 250); } else { hide(); @@ -131,13 +137,13 @@ export function uiCombobox(context, klass) { .style('position', 'absolute') .style('display', 'block') .style('left', '0px') - .on('mousedown.combobox', function () { + .on('mousedown.combo-container', function () { // prevent moving focus out of the input field d3_event.preventDefault(); }); d3_select('body') - .on('scroll.combobox', render, true); + .on('scroll.combo-scroll', render, true); } @@ -151,7 +157,7 @@ export function uiCombobox(context, klass) { .remove(); d3_select('body') - .on('scroll.combobox', null); + .on('scroll.combo-scroll', null); } @@ -165,10 +171,10 @@ export function uiCombobox(context, klass) { d3_event.stopPropagation(); _selected = null; render(); - input.on('input.combobox', function() { + input.on('input.combo-input', function() { var start = input.property('selectionStart'); input.node().setSelectionRange(start, start); - input.on('input.combobox', change); + input.on('input.combo-input', change); }); break; @@ -378,7 +384,7 @@ export function uiCombobox(context, klass) { .text(function(d) { return d.display || d.value; }) .merge(options) .classed('selected', function(d) { return d.value === _selected; }) - .on('click.combobox', accept) + .on('click.combo-option', accept) .order(); var node = attachTo ? attachTo.node() : input.node(); @@ -481,15 +487,15 @@ export function uiCombobox(context, klass) { uiCombobox.off = function(input) { input - .on('focus.combobox', null) - .on('blur.combobox', null) - .on('keydown.combobox', null) - .on('keyup.combobox', null) - .on('input.combobox', null) - .on('mousedown.combobox', null) - .on('mouseup.combobox', null); + .on('focus.combo-input', null) + .on('blur.combo-input', null) + .on('keydown.combo-input', null) + .on('keyup.combo-input', null) + .on('input.combo-input', null) + .on('mousedown.combo-input', null) + .on('mouseup.combo-input', null); d3_select('body') - .on('scroll.combobox', null); + .on('scroll.combo-scroll', null); }; diff --git a/test/spec/ui/combobox.js b/test/spec/ui/combobox.js index 20a0fe965..978ff62c8 100644 --- a/test/spec/ui/combobox.js +++ b/test/spec/ui/combobox.js @@ -18,7 +18,7 @@ describe('uiCombobox', function() { iD.d3.customEvent(happen.makeEvent({ type: 'keydown', keyCode: keyCode - }), input.on('keydown.combobox')); + }), input.on('keydown.combo-input')); switch (key) { case '⇥': @@ -80,7 +80,7 @@ describe('uiCombobox', function() { function focusTypeahead(input) { input.node().focus(); - d3.customEvent(happen.makeEvent('focus'), input.on('focus.combobox')); + d3.customEvent(happen.makeEvent('focus'), input.on('focus.combo-input')); } it('adds the combobox-input class', function() {