Merge "Show hovercard with a delay of 500 ms"
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
index a77f5f7..1ba3c23 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.js
@@ -30,6 +30,12 @@
const DIAGONAL_OVERFLOW = 15;
/**
+ * How long should be wait before showing the hovercard when the user hovers
+ * over the element?
+ */
+const SHOW_DELAY_MS = 500;
+
+/**
* The mixin for gr-hovercard-behavior.
*
* @example
@@ -118,8 +124,8 @@
attached() {
super.attached();
if (!this._target) { this._target = this.target; }
- this.listen(this._target, 'mouseenter', 'show');
- this.listen(this._target, 'focus', 'show');
+ this.listen(this._target, 'mouseenter', 'showDelayed');
+ this.listen(this._target, 'focus', 'showDelayed');
this.listen(this._target, 'mouseleave', 'hide');
this.listen(this._target, 'blur', 'hide');
this.listen(this._target, 'click', 'hide');
@@ -184,6 +190,10 @@
* @param {Event} e DOM Event (e.g. `mouseleave` event)
*/
hide(e) {
+ this._isScheduledToShow = false;
+ if (!this._isShowing) {
+ return;
+ }
const targetRect = this._target.getBoundingClientRect();
const x = e.clientX;
const y = e.clientY;
@@ -195,10 +205,10 @@
return;
}
- // If the hovercard is already hidden or the user is now hovering over the
- // hovercard or the user is returning from the hovercard but now hovering
- // over the target (to stop an annoying flicker effect), just return.
- if (!this._isShowing || e.toElement === this ||
+ // If the user is now hovering over the hovercard or the user is returning
+ // from the hovercard but now hovering over the target (to stop an annoying
+ // flicker effect), just return.
+ if (e.toElement === this ||
(e.fromElement === this && e.toElement === this._target)) {
return;
}
@@ -221,12 +231,31 @@
}
/**
+ * Shows/opens the hovercard with a fixed delay.
+ */
+ showDelayed() {
+ this.showDelayedBy(SHOW_DELAY_MS);
+ }
+
+ /**
+ * Shows/opens the hovercard with the given delay.
+ */
+ showDelayedBy(delayMs) {
+ if (this._isShowing || this._isScheduledToShow) return;
+ this._isScheduledToShow = true;
+ setTimeout(() => {
+ // This happens when the mouse leaves the target before the delay is over.
+ if (!this._isScheduledToShow) return;
+ this._isScheduledToShow = false;
+ this.show();
+ }, delayMs);
+ }
+
+ /**
* Shows/opens the hovercard. This occurs when the user triggers the
* `mousenter` event on the hovercard's `target` element.
- *
- * @param {Event} e DOM Event (e.g., `mouseenter` event)
*/
- show(e) {
+ show() {
if (this._isShowing) {
return;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
index 1ffed0a..99791e7 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard_test.html
@@ -109,14 +109,31 @@
}, TRANSITION_TIME);
});
- test('card shows on enter and hides on leave', done => {
+ test('showDelayed does not show immediately', done => {
+ element.showDelayedBy(100);
+ setTimeout(() => {
+ assert.isFalse(element._isShowing);
+ done();
+ }, 0);
+ });
+
+ test('showDelayed shows after delay', done => {
+ element.showDelayedBy(1);
+ setTimeout(() => {
+ assert.isTrue(element._isShowing);
+ done();
+ }, 10);
+ });
+
+ test('card is scheduled to show on enter and hides on leave', done => {
const button = dom(document).querySelector('button');
assert.isFalse(element._isShowing);
button.addEventListener('mouseenter', event => {
- assert.isTrue(element._isShowing);
+ assert.isTrue(element._isScheduledToShow);
button.dispatchEvent(new CustomEvent('mouseleave'));
});
button.addEventListener('mouseleave', event => {
+ assert.isFalse(element._isScheduledToShow);
assert.isFalse(element._isShowing);
done();
});