From 189a4c8f8e8da3bbec0e6988fd578ce18649e6e3 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Mon, 2 Nov 2020 09:33:05 +0800 Subject: [PATCH] MDL-70075 core: Listen for `change` in accessibleChange event The accessibleChange custom interaction event was only listening for blur and focus, however some OS/browser combinations do not emit these events until the element is explicitly blurred. This is notably different on Firefox on some Operating Systems. Recent changes in MDL-68167 explicitly moved the user participants page filter module to use the accessibleChange event, which means that the selections are now only triggered on an explicit blur when using Firefox. This highlight a bug whereby, when the mouse is used to make a selection, the event is not triggered until the element is blurred. This change modifies the accessibleChange event to ignore the `change` event where it was triggered by the keyboard and where that keybaord event was not a [return] or [escape] keypress, but to otherwise respect the native change event. --- .../build/custom_interaction_events.min.js | Bin 4401 -> 4551 bytes .../custom_interaction_events.min.js.map | Bin 30666 -> 34725 bytes lib/amd/src/custom_interaction_events.js | 88 +++++++++++++++--- 3 files changed, 74 insertions(+), 14 deletions(-) diff --git a/lib/amd/build/custom_interaction_events.min.js b/lib/amd/build/custom_interaction_events.min.js index 2e6312a9df8862d2c8240c8a5c601bd418f7cde8..00d449bd8c358c8490dbd53b0bd66ac5c5185aad 100644 GIT binary patch delta 679 zcmZ{hu};G<5QfD>1!)ngD#S#SF0~YeZVbf}69X#)h`}V+#%<(6>J*{W%0qbP0hmBM z1T$~Kz{JEkEosuil*sr0-`)N9>b!Se_N^Kt>5RqgKp$GiTcFRatL zCD*;1{z!jWofc-Z>P(bt_Xt)l>P`bI9HU!2G5uLT&`-Oyqlb|DA*J-z10f+^iXfUo z+w7q48_g^%b|L-EL5E@z!&%705UAZ##`?!PYbs?(cuU96jgDKsZaF+mHd`FJL|Daa lHu^=4;W4?Zk^+c80-k(5-4d+u`w{oYRezq?+sWSd)(;hu@w@;4 delta 477 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 delta 1712 zcmb7EOK%fb6jm%piqvF^#Ka}EmB%*NGx1=^JCW*$J9oyZLm?#LArJx_dmN8rdx&3& ztE#YU7X`%m3ACGT8Yz3k0ybT-VOJy;RfX78k-CR-?!+O3l2-NN%$;w}<2&CuzP~&O z{Qh^()}KN6rdK;v$Tf3OJ=)GyS~fnNn$x_pd#>A6w{4rA!$!%;m$rZG-5%=UkPdgw z&6|3bWfyeL_}BUzW7%;N&-f#oBQrO}=|L`xPjhlwB9kYeK<18t)?!eOYVwQ-zeMmg zG`wVv8Ib)X{<%wq*me5g82VMl$`r+>jngKKoESW|ZtCY4Yf~*`!dZsi=h!^FjH=0x zvz`_-vW`V5Jg&=hoSVo{G3AhAB`V3;h;RzGO#SjMqn2RQHgpR=3mGaFv5I=EE)i5U zgbwJ0h1LYm8DqkPPIzp9&m(w&7%wmzSU3dpv5`d8qLwlgd~GU2VT)uq_K$dzsz29=WJO>AMzCOCcjPr zyljmLxs@(O&K77@#A{`xLAs2t)Jzv9<18?ffh|dfpW?FQ2*o_{5&kW%Nl7uxJ?O8v zD&cPLjR?KINT|}JA6i0a)DQiDP{$8FL1@Dd{ew`;4-KoTRP{r*5fY2FyC+EE>~R@> zRb^>XY+aY`qmT@*5q13W0Zo-w{m?W*>%Lg1AyoB4KWmzVOS!-Mcaae6XhZ6%fW=>o zUqO#@LCAc@#w|S07!HXBW0qlj_-&5^;bc_$R!mo10j@C)3&~@FDGQwBsew`P#k)y1 z;c?Ok%-Gv+lFw(Mztazs->LARD8v1=4CFWdfO}u{D|D}^iM{JAp(}Q(nX9kb&6K$7 z;Ob^oZ|CaDo{N%JPN-ccE%k8%ID1Q`%%Kn0;{N>N^N~gn7F$RAx;bIzMhITq4(_sx z!M%nIrOgnsz8qBIafQ6U{I{waj5LnJ!{SkFj>3Ckt23MGvh-T{58@iEH)4>w+Yf!6 zBk=P3#Q$&m>CGS{n}dUHEnji+Ys!jUbnCX_)>bO5IxID_fSu1aJ9liixKGeXI;|vH dwSrxAYIY$(4R@8Xl}Oq@k%P3_PTk$;dk>X^{aye7 diff --git a/lib/amd/src/custom_interaction_events.js b/lib/amd/src/custom_interaction_events.js index c429e926341..ca22b7275c2 100644 --- a/lib/amd/src/custom_interaction_events.js +++ b/lib/amd/src/custom_interaction_events.js @@ -427,35 +427,95 @@ define(['jquery', 'core/key_codes'], function($, keyCodes) { var onMac = navigator.userAgent.indexOf('Macintosh') !== -1; var touchEnabled = ('ontouchstart' in window) || (('msMaxTouchPoints' in navigator) && (navigator.msMaxTouchPoints > 0)); if (onMac || touchEnabled) { + // On Mac devices, and touch-enabled devices, the change event seems to be handled correctly and + // consistently at this time. element.on('change', function(e) { triggerEvent(events.accessibleChange, e); }); } else { + // Some browsers have non-normalised behaviour for handling the selection of values in a boxes as a single-select, + // and make use of a dropdown of action links like the Bootstrap Dropdown menu. + var setInitialValue = function(target) { + target.dataset.initValue = target.value; + }; + var resetToInitialValue = function(target) { + if ('initValue' in target.dataset) { + target.value = target.dataset.initValue; + } + }; + var checkAndTriggerAccessibleChange = function(e) { + if (!('initValue' in e.target.dataset)) { + // Some browsers trigger click before focus, therefore it is possible that initValue is undefined. + // In this case it's likely that it's being focused for the first time and we should therefore not submit. + return; + } + + if (e.target.value !== e.target.dataset.initValue) { + // Update the initValue when the event is triggered. + // This means that if the click handler fires before the focus handler on a subsequent interaction + // with the element, the currently dispalyed value will be the best guess current value. + e.target.dataset.initValue = e.target.value; + triggerEvent(events.accessibleChange, e); + } + }; var nativeElement = element.get()[0]; // The `focus` and `blur` events do not support bubbling. Use Event Capture instead. nativeElement.addEventListener('focus', function(e) { - $(e.target).data('initValue', e.target.value); + setInitialValue(e.target); }, true); nativeElement.addEventListener('blur', function(e) { - var initValue = $(e.target).data('initValue'); - $(e.target).removeData('initValue'); - if (e.target.value !== initValue) { - triggerEvent(events.accessibleChange, e); - } + checkAndTriggerAccessibleChange(e); }, true); element.on('keydown', function(e) { - if ((e.which === keyCodes.enter) && e.target.value !== $(e.target).data('initValue')) { - triggerEvent(events.accessibleChange, e); + if ((e.which === keyCodes.enter)) { + checkAndTriggerAccessibleChange(e); } else if (e.which === keyCodes.escape) { - e.target.value = $(e.target).data('initValue'); + resetToInitialValue(e.target); + e.target.dataset.ignoreChange = true; + } else { + // Firefox triggers a change event when using the keyboard to scroll through the selection. + // Set a data- attribute that the change listener can use to ignore the change event where it was + // generated from a keyboard change such as typing to complete a value, or using arrow keys. + e.target.dataset.ignoreChange = true; + } }); - element.on('click', function(e) { - var initValue = $(e.target).data('initValue'); - // Some browsers trigger onclick before onblur, therefore it is possible that initValue is undefined. - if (typeof initValue !== 'undefined' && initValue != e.target.value) { - triggerEvent(events.accessibleChange, e); + element.on('change', function(e) { + if (e.target.dataset.ignoreChange) { + // This change event was triggered from a keyboard change which is not yet complete. + // Do not trigger the accessibleChange event until the selection is completed using the [return] + // key. + return; } + + checkAndTriggerAccessibleChange(e); + }); + element.on('keyup', function(e) { + // The key has been lifted. Stop ignoring the change event. + delete e.target.dataset.ignoreChange; + }); + element.on('click', function(e) { + checkAndTriggerAccessibleChange(e); }); } }; -- 2.43.0