Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clock displays and hides immediately after updating Chrome version to 73 #6312

Open
subashdbc opened this issue Mar 22, 2019 · 34 comments
Open

Comments

@subashdbc
Copy link

Hi,

When we click on the filed the clock modal opens and immediately close
https://codepen.io/anon/pen/evQxPy
This happens after I have updated my chrome version to 73

@subashdbc
Copy link
Author

Any quick fix on this?

@swforeman1978
Copy link

How to fix this error?

@luizpinheirodev
Copy link

The same here!! :( This problem happens only in Chrome, Edge works fine.

@Marzon
Copy link

Marzon commented Mar 22, 2019

It´s a race condition

https://bugs.chromium.org/p/chromium/issues/detail?id=941910

The workaround is a setTimeout on root focus.

@DanielRuf
Copy link
Contributor

Exactly. Either throttle / debounce (see pickadate 3.6.1) or use the setTimeout workaround.

@subashdbc
Copy link
Author

@Marzon We use materialize.js and where to use setTimeout?

@DavinderPRO
Copy link

I am also looking for workaround for time picker cause upgrading to new materialcss is time consuming. Please let us know workaround for time picker

For datepicker
comment this code in materialize.js file
P.close(target === P.$root.children()[0]);

@DavinderPRO
Copy link

It´s a race condition

https://bugs.chromium.org/p/chromium/issues/detail?id=941910

The workaround is a setTimeout on root focus.

Can please specify where to add setTimeout in the JS file. That would be really helpful

@DanielRuf
Copy link
Contributor

See amsul/pickadate.js#1140 with the right workaround.

The other proposed change breaks focus (a11y).

@subashdbc
Copy link
Author

@DanielRuf it's quite hard to find the places to change the logic based on github.com/amsul/pickadate.js/pull/1140/files these changes, on materialize.js file.
It would much be appreciated any solution on materialize.js

@Marzon
Copy link

Marzon commented Mar 25, 2019

Hi! On materialize.js, add a setTimeout (100 ms) in end of the

  open: function (dontGiveFocus) {

Move de $document.on('click.' . .... and the

P.$root.eq(0).focus();

to the setTimeOut function.

Leave document.on first and $root.focus() after document.on ..

I´m waiting the race condition bug to be fixed.. before to propose a PR..

@subashdbc
Copy link
Author

subashdbc commented Mar 25, 2019

Hi,
Not sure, if this is a bulletproof solution but this works for me especially with clockpicker.
The version should be materializecss (v0.100.2). In materialize.js file
Line No: 8913

ClockPicker.prototype.show = function (e) {

Just wrap setTimeout( 200 ms) inside this whole function, works well.

@DavinderPRO
Copy link

DavinderPRO commented Mar 25, 2019

Hi,
Not sure, if this is a bulletproof solution but this works for me especially with clockpicker.
The version should be materializecss (v0.100.2). In materialize.js file
Line No: 8913

ClockPicker.prototype.show = function (e) {

Just wrap setTimeout( 100 ms) inside this whole function, works well.

Now it works fine
`

ClockPicker.prototype.show = function (e) {
var _this = this;

setTimeout(function () {
// Not show again
if (_this.isShown) {
return;
}

raiseCallback(_this.options.beforeShow);
$(':input').each(function () {
  $(this).attr('tabindex', -1);
});
var self = _this; // Initialize

_this.input.blur();

_this.popover.addClass('picker--opened');

_this.input.addClass('picker__input picker__input--active');

$(document.body).css('overflow', 'hidden'); // Get the time

var value = ((_this.input.prop('value') || _this.options['default'] || '') + '').split(':');

if (_this.options.twelvehour && !(typeof value[1] === 'undefined')) {
  if (value[1].indexOf("AM") > 0) {
    _this.amOrPm = 'AM';
  } else {
    _this.amOrPm = 'PM';
  }

  value[1] = value[1].replace("AM", "").replace("PM", "");
}

if (value[0] === 'now') {
  var now = new Date(+new Date() + _this.options.fromnow);
  value = [now.getHours(), now.getMinutes()];

  if (_this.options.twelvehour) {
    _this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM';
  }
}

_this.hours = +value[0] || 0;
_this.minutes = +value[1] || 0;

_this.spanHours.html(_this.hours);

_this.spanMinutes.html(leadingZero(_this.minutes));

if (!_this.isAppended) {
  // Append popover to input by default
  var containerEl = document.querySelector(_this.options.container);

  if (_this.options.container && containerEl) {
    containerEl.appendChild(_this.popover[0]);
  } else {
    _this.popover.insertAfter(_this.input);
  }

  if (_this.options.twelvehour) {
    if (_this.amOrPm === 'PM') {
      _this.spanAmPm.children('#click-pm').addClass("text-primary");

      _this.spanAmPm.children('#click-am').removeClass("text-primary");
    } else {
      _this.spanAmPm.children('#click-am').addClass("text-primary");

      _this.spanAmPm.children('#click-pm').removeClass("text-primary");
    }
  } // Reset position when resize


  $win.on('resize.clockpicker' + _this.id, function () {
    if (self.isShown) {
      self.locate();
    }
  });
  _this.isAppended = true;
} // Toggle to hours view


_this.toggleView('hours'); // Set position


_this.locate();

_this.isShown = true; // Hide when clicking or tabbing on any element except the clock and input

$doc.on('click.clockpicker.' + _this.id + ' focusin.clockpicker.' + _this.id, function (e) {
  var target = $(e.target);

  if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0) {
    self.hide();
  }
}); // Hide when ESC is pressed

$doc.on('keyup.clockpicker.' + _this.id, function (e) {
  if (e.keyCode === 27) {
    self.hide();
  }
});
raiseCallback(_this.options.afterShow);

}, 200);
};

`

@subashdbc
Copy link
Author

subashdbc commented Mar 25, 2019

@DavinderPRO This is what I mean, does this work for you?

// Show popover
  ClockPicker.prototype.show = function (e) {
    setTimeout(() => {
      // Not show again
      if (this.isShown) {
        return;
      }
      raiseCallback(this.options.beforeShow);
      $(':input').each(function () {
        $(this).attr('tabindex', -1);
      });
      
      var self = this;
      // Initialize
      this.input.blur();
      this.popover.addClass('picker--opened');
      this.input.addClass('picker__input picker__input--active');
      $(document.body).css('overflow', 'hidden');
      // Get the time
      var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':');
      if (this.options.twelvehour && !(typeof value[1] === 'undefined')) {
        if (value[1].indexOf("AM") > 0) {
          this.amOrPm = 'AM';
        } else {
          this.amOrPm = 'PM';
        }
        value[1] = value[1].replace("AM", "").replace("PM", "");
      }
      if (value[0] === 'now') {
        var now = new Date(+new Date() + this.options.fromnow);
        value = [now.getHours(), now.getMinutes()];
        if (this.options.twelvehour) {
          this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM';
        }
      }
      this.hours = +value[0] || 0;
      this.minutes = +value[1] || 0;
      this.spanHours.html(this.hours);
      this.spanMinutes.html(leadingZero(this.minutes));
      if (!this.isAppended) {

        // Append popover to input by default
        var containerEl = document.querySelector(this.options.container);
        if (this.options.container && containerEl) {
          containerEl.appendChild(this.popover[0]);
        } else {
          this.popover.insertAfter(this.input);
        }

        if (this.options.twelvehour) {
          if (this.amOrPm === 'PM') {
            this.spanAmPm.children('#click-pm').addClass("text-primary");
            this.spanAmPm.children('#click-am').removeClass("text-primary");
          } else {
            this.spanAmPm.children('#click-am').addClass("text-primary");
            this.spanAmPm.children('#click-pm').removeClass("text-primary");
          }
        }
        // Reset position when resize
        $win.on('resize.clockpicker' + this.id, function () {
          if (self.isShown) {
            self.locate();
          }
        });
        this.isAppended = true;
      }
      // Toggle to hours view
      this.toggleView('hours');
      // Set position
      this.locate();
      this.isShown = true;
      // Hide when clicking or tabbing on any element except the clock and input
      $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function (e) {
        var target = $(e.target);
        if (target.closest(self.popover.find('.picker__wrap')).length === 0 && target.closest(self.input).length === 0) {
          self.hide();
        }
      });
      // Hide when ESC is pressed
      $doc.on('keyup.clockpicker.' + this.id, function (e) {
        if (e.keyCode === 27) {
          self.hide();
        }
      });
      raiseCallback(this.options.afterShow);
    }, 200);
  };

@markonose
Copy link

markonose commented Mar 26, 2019

To fix the date picker change the code from:

// Only bind keydown events if the element isn’t editable.
if (!SETTINGS.editable) {

	$ELEMENT.

		// On focus/click, focus onto the root to open it up.
		on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
			event.preventDefault();
			P.$root.eq(0).focus();
		}).

		// Handle keyboard event based on the picker being opened or not.
		on('keydown.' + STATE.id, handleKeydownEvent);
}

to:

// Only bind keydown events if the element isn’t editable.
if (!SETTINGS.editable) {

	$ELEMENT.

		// On focus/click, focus onto the root to open it up.
		on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
			setTimeout(function(){
				event.preventDefault();
				P.$root.eq(0).focus();
			}, 100);
		}).

		// Handle keyboard event based on the picker being opened or not.
		on('keydown.' + STATE.id, handleKeydownEvent);
}

@ivanhuay
Copy link

+1

blanchg added a commit to psnmc/materialize that referenced this issue Mar 27, 2019
Closes: Dogfalo#6312
Adds timeouts to user interactions to workaround chrome 73 bug
@free6k
Copy link

free6k commented Mar 27, 2019

+1

@ray007
Copy link
Contributor

ray007 commented Mar 27, 2019

@markonose Are you sure that event.preventDefault(); works as intended in a setTimout()?
I suspect you only want the .focus() call delayed.

@markonose
Copy link

markonose commented Mar 27, 2019

@ray007 You are indeed correct, but at least in my case the event.preventDefault(); does nothing.

// On focus/click, focus onto the root to open it up.
on('focus.' + STATE.id + ' click.' + STATE.id, function (event) {
	event.preventDefault();

	setTimeout(function(){
		P.$root.eq(0).focus();
	}, 100);
}).

would work more like the original code intended

@markonose
Copy link

If anyone stumbles uppon this thread here's how to fix the problem for the select dropdown

$newSelect.on({
	'focus': function () {
		var _this = this;

		setTimeout(function () {
			if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
				$('input.select-dropdown').trigger('close');
				$(window).off('click.select');
			}
			if (!options.is(':visible')) {
				$(_this).trigger('open', ['focus']);
				var label = $(_this).val();
				if (multiple && label.indexOf(',') >= 0) {
					label = label.split(',')[0];
				}

				var selectedOption = options.find('li').filter(function () {
					return $(_this).text().toLowerCase() === label.toLowerCase();
				})[0];
				activateOption(options, selectedOption, true);

				$(window).off('click.select').on('click.select', function () {
					multiple && (optionsHover || $newSelect.trigger('close'));
					$(window).off('click.select');
				});
			}
		}, 75);
	},
	'click': function (e) {
		e.stopPropagation();
	}
});

@Dogfalo
Copy link
Owner

Dogfalo commented Mar 31, 2019

1.0.0 does not have this problem so if you are able to upgrade, I would recommend that route. However if you can't, try one of the fixes in this thread. Potentially we may add a fix for this if chrome doesn't revert this behavior.

@Sebastriani
Copy link

@Dogfalo do you know what was the change introduced in Chrome that produces this behaviour?

@Dogfalo
Copy link
Owner

Dogfalo commented Apr 1, 2019

I think it has to do with the timing of events when clicking an input. Where before it was click -> focus, it seems to now be focus -> click. This is just a guess as I haven't looked deeply into the issue yet.

@DanielRuf
Copy link
Contributor

See https://bugs.chromium.org/p/chromium/issues/detail?id=941910#c6

@pratappp
Copy link

pratappp commented Apr 4, 2019

If anyone stumbles uppon this thread here's how to fix the problem for the select dropdown

$newSelect.on({
	'focus': function () {
		var _this = this;

		setTimeout(function () {
			if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
				$('input.select-dropdown').trigger('close');
				$(window).off('click.select');
			}
			if (!options.is(':visible')) {
				$(_this).trigger('open', ['focus']);
				var label = $(_this).val();
				if (multiple && label.indexOf(',') >= 0) {
					label = label.split(',')[0];
				}

				var selectedOption = options.find('li').filter(function () {
					return $(_this).text().toLowerCase() === label.toLowerCase();
				})[0];
				activateOption(options, selectedOption, true);

				$(window).off('click.select').on('click.select', function () {
					multiple && (optionsHover || $newSelect.trigger('close'));
					$(window).off('click.select');
				});
			}
		}, 75);
	},
	'click': function (e) {
		e.stopPropagation();
	}
});

Above fix was not showing the already selected item from drop-down hence i modified it little bit. below is changed code.

$newSelect.on({
'focus': function () {

                    if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
                        $('input.select-dropdown').trigger('close');
                    }
                    if (!options.is(':visible')) {       
               
                        setTimeout(function () {
                            $(this).trigger('open', ['focus']);
                        }, 70);

                        var label = $(this).val();
                        var selectedOption = options.find('li').filter(function () {
                            return $(this).text().toLowerCase() === label.toLowerCase();
                        })[0];
                        activateOption(options, selectedOption);
                    }
                
            },
            'click': function (e) {
                e.stopPropagation();
            },

@Sebastriani
Copy link

@Dogfalo Version 74 of Chrome is released and they didn't fix this, reading the comment 23 in https://bugs.chromium.org/p/chromium/issues/detail?id=941910#c6 it doesn't seem they are going to fix it, couldn't you please just fix it in materializecss?

@DanielRuf
Copy link
Contributor

@Dogfalo Version 74 of Chrome is released and they didn't fix this, reading the comment 23 in bugs.chromium.org/p/chromium/issues/detail?id=941910#c6 it doesn't seem they are going to fix it, couldn't you please just fix it in materializecss?

Well it will not fix old releases as 0.x is not actively developed anymore but 1.x.
Also this is opensource so anyone can provide a PR to fix this.
We had to do another workaround as the timeout / debouncing did not completely fix this bug in Chrome.

@armando-navarro-frequence
Copy link

I thought this may help some who stumbled on this page. I am using angular2-materialize and my materialize select input sometimes closes immediately after opening.

I solved this by adding a click listener on a div that wraps the select tag, with nothing but event.stopPropagation() in the listener. This fixed the issue for me.

@GalaxyShadesCat
Copy link

materialize.js

For anyone who is too lazy to edit the file yourself

@DanielRuf
Copy link
Contributor

@LemuelHui

Awesome =)

Is there also a minified patched version? If you need help with that, just let me know.

@DanielRuf
Copy link
Contributor

PS: the timeout does not really fix that (longpress click).

You can check how we have fixed it in pickadate.js.

@Sebastriani
Copy link

@DanielRuf could you provide a link to the commit with the fix that you did for pickadate?

@DanielRuf
Copy link
Contributor

@Sebastriani see amsul/pickadate.js@31789eb

My initial approach using timers (with setTimeout) did not work in all but many cases as it was added at the top of the counter stack of the VM.

@NavidZ
Copy link

NavidZ commented Jul 15, 2019

The quick fix in the original codepen example (https://codepen.io/anon/pen/evQxPy) in this issue would be a code snippet like this:
document.getElementById('birthdate').addEventListener('pointerdown', (e)=>{e.target.setPointerCapture(e.pointerId);})
I was going to send a pull request to fix this issue, but I'm having some trouble with this repo and understanding how I should get a local example with un-built files to work. I can see from the documentations that we should not modify materialize.js directly. But I'm not able to produce a local example similar to the codepen example that includes the unbuilt files to verify the fix locally before sending the pull request. Can someone guide me here on what files from js/ directory I should include + the html/css in the code pen to reproduce the issue locally? Alternatively if you could just attach a html file that include the local files from this repo and reproduce the issue and I can work on the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests