Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
fix(ripple): Re-flow logic to avoid crashing Edge
Browse files Browse the repository at this point in the history
  • Loading branch information
Kenneth G. Franqueiro committed Apr 9, 2018
1 parent 8c4fbdc commit 7d25012
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
42 changes: 29 additions & 13 deletions packages/mdc-ripple/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,25 +330,41 @@ class MDCRippleFoundation extends MDCFoundation {
this.registerDeactivationHandlers_(e);
}

requestAnimationFrame(() => {
// This needs to be wrapped in an rAF call b/c web browsers
// report active states inconsistently when they're called within
// event handling code:
// - https://bugs.chromium.org/p/chromium/issues/detail?id=635971
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1293741
activationState.wasElementMadeActive = (e && e.type === 'keydown') ? this.adapter_.isSurfaceActive() : true;
if (activationState.wasElementMadeActive) {
this.animateActivation_();
} else {
// Reset activation state immediately if element was not made active.
this.activationState_ = this.defaultActivationState_();
}
activationState.wasElementMadeActive = this.checkElementMadeActive_(e);
if (activationState.wasElementMadeActive) {
this.animateActivation_();
}

requestAnimationFrame(() => {
// Reset array on next frame after the current event has had a chance to bubble to prevent ancestor ripples
activatedTargets = [];

if (!activationState.wasElementMadeActive && e && e.type === 'keydown' && (e.key === ' ' || e.keyCode === 32)) {
// If space was pressed, try again within an rAF call to detect :active, because different UAs report
// active states inconsistently when they're called within event handling code:
// - https://bugs.chromium.org/p/chromium/issues/detail?id=635971
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1293741
// We try first outside rAF to support Edge, which does not exhibit this problem, but will crash if a CSS
// variable is set within a rAF callback for a submit button interaction (#2241).
activationState.wasElementMadeActive = this.checkElementMadeActive_(e);
if (activationState.wasElementMadeActive) {
this.animateActivation_();
} else {
// Reset activation state immediately if element was not made active.
this.activationState_ = this.defaultActivationState_();
}
}
});
}

/**
* @param {?Event} e
* @private
*/
checkElementMadeActive_(e) {
return (e && e.type === 'keydown') ? this.adapter_.isSurfaceActive() : true;
}

/**
* @param {?Event=} event Optional event containing position information.
*/
Expand Down
29 changes: 27 additions & 2 deletions test/unit/mdc-ripple/foundation-activation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,42 @@ testFoundation('sets FG position from the coords to the center within surface on
));
});

testFoundation('adds activation classes on keydown when surface is made active',
testFoundation('adds activation classes on keydown when surface is made active on same frame',
({foundation, adapter, mockRaf}) => {
const handlers = captureHandlers(adapter, 'registerInteractionHandler');
td.when(adapter.isSurfaceActive()).thenReturn(true);
foundation.init();
mockRaf.flush();

handlers.keydown();
td.verify(adapter.addClass(cssClasses.FG_ACTIVATION));
});

testFoundation('adds activation classes on keydown when surface only reflects :active on next frame for space keydown',
({foundation, adapter, mockRaf}) => {
const handlers = captureHandlers(adapter, 'registerInteractionHandler');
td.when(adapter.isSurfaceActive()).thenReturn(false, true);
foundation.init();
mockRaf.flush();

td.verify(adapter.addClass(cssClasses.FG_ACTIVATION));
handlers.keydown({key: ' '});
td.verify(adapter.addClass(cssClasses.FG_ACTIVATION), {times: 0});

mockRaf.flush();
td.verify(adapter.addClass(cssClasses.FG_ACTIVATION), {times: 1});
});

testFoundation('does not add activation classes on keydown when surface is not made active',
({foundation, adapter, mockRaf}) => {
const handlers = captureHandlers(adapter, 'registerInteractionHandler');
td.when(adapter.isSurfaceActive()).thenReturn(false, false);
foundation.init();
mockRaf.flush();

handlers.keydown({key: ' '});
mockRaf.flush();

td.verify(adapter.addClass(cssClasses.FG_ACTIVATION), {times: 0});
});

testFoundation('sets FG position to center on non-pointer activation', ({foundation, adapter, mockRaf}) => {
Expand Down

0 comments on commit 7d25012

Please sign in to comment.