From b34c99079c6045000117ef7194e13ab7747c5797 Mon Sep 17 00:00:00 2001 From: Navid Zolghadr Date: Mon, 13 May 2019 16:22:48 -0400 Subject: [PATCH 1/3] Set pointer capture on pointerdown on picker input Chrome 73 starts sending click even to the common ancestor of down and up events even when one was inside the input element and the other one was outside. This caused this library to fail in the following scenario: User presses down on the picker input which causes the date picker and overlay to be shown. When user releases the button the overlay gets the up event and the common ancestor of these elements will get the click. Since there is a click handler on the document to close the popup, the calendar popup immediately closes. Using pointercapture API to capture the rest of the pointerevents stream to the picker input it ensures the click event target is the picker input and that ensures the click handler doesn't dismiss the popup. --- lib/picker.js | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/lib/picker.js b/lib/picker.js index 8c6e111f..91424336 100644 --- a/lib/picker.js +++ b/lib/picker.js @@ -44,8 +44,7 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // The state of the picker. STATE = { - id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ), - handlingOpen: false, + id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) }, @@ -268,18 +267,6 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { // Bind the document events. $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { - // If the picker is currently midway through processing - // the opening sequence of events then don't handle clicks - // on any part of the DOM. This is caused by a bug in Chrome 73 - // where a click event is being generated with the incorrect - // path in it. - // In short, if someone does a click that finishes after the - // new element is created then the path contains only the - // parent element and not the input element itself. - if (STATE.handlingOpen) { - return; - } - var target = getRealEventTarget( event, ELEMENT ) // If the target of the event is not the element, close the picker picker. @@ -647,22 +634,15 @@ function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { event.preventDefault() P.open() } - ) + ). - // Mousedown handler to capture when the user starts interacting - // with the picker. This is used in working around a bug in Chrome 73. - .on('mousedown', function() { - STATE.handlingOpen = true; - var handler = function() { - // By default mouseup events are fired before a click event. - // By using a timeout we can force the mouseup to be handled - // after the corresponding click event is handled. - setTimeout(function() { - $(document).off('mouseup', handler); - STATE.handlingOpen = false; - }, 0); - }; - $(document).on('mouseup', handler); + // Pointerdown handler to capture the rest of the pointer stream + // with the picker. This is used to prevent click generated by + // this pointer stream closing the popup as the click goes the + // common ancestor of down and up event targets. + on('pointerdown', function(event) { + if (event.target.setPointerCapture) + event.target.setPointerCapture(event.originalEvent.pointerId); }); From d5c9dde1f5c78219261863c4c3eb121e0aab5132 Mon Sep 17 00:00:00 2001 From: Navid Zolghadr Date: Tue, 14 May 2019 11:17:20 -0400 Subject: [PATCH 2/3] Fix a test --- tests/units/base.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/units/base.js b/tests/units/base.js index 25761323..9f359928 100644 --- a/tests/units/base.js +++ b/tests/units/base.js @@ -448,9 +448,10 @@ test( 'Open and close', function() { }) asyncTest( 'Open with a slower click', function() { - // This test ensures that behaviour in chrome as described in PR 1145 + // This test ensures that behaviour in chrome as described in PR 1167 // https://github.com/amsul/pickadate.js/pull/1145 - // is handled correctly + // is handled correctly where the pointer stream is captured to the + // picker input. var picker = this.picker @@ -471,7 +472,7 @@ asyncTest( 'Open with a slower click', function() { picker.$node.trigger({ type: 'mouseup' }) - $DOM.trigger({ + picker.$DOM.trigger({ type: 'click' }) setTimeout(function () { From 549c343e74514e8606e02fcf02b1c6b4c77f3e91 Mon Sep 17 00:00:00 2001 From: Navid Zolghadr Date: Tue, 14 May 2019 11:28:15 -0400 Subject: [PATCH 3/3] Fix a typo --- tests/units/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/units/base.js b/tests/units/base.js index 9f359928..085da1a8 100644 --- a/tests/units/base.js +++ b/tests/units/base.js @@ -472,7 +472,7 @@ asyncTest( 'Open with a slower click', function() { picker.$node.trigger({ type: 'mouseup' }) - picker.$DOM.trigger({ + picker.$node.trigger({ type: 'click' }) setTimeout(function () {