@@ -169,15 +169,9 @@ define([
169169 this . keyNavContainerNode = this . containerNode || this ;
170170 }
171171
172- // There are two cases when this.containerNode.focus() is called rather than this.focus():
173- // - When this is the first element in a Dialog (a11y.getFirstInTabbingOrder()).
174- // - When tabbing/shift-tabbing from one deliteful/List to another (a11y.getNextInTabbingOrder()).
175- // In either case, focus my first navigable descendant.
172+ // containerNode.focus() called when this is the first element in a Dialog (a11y.getFirstInTabbingOrder()).
176173 if ( this . containerNode && this . containerNode !== this ) {
177174 this . containerNode . focus = function ( ) {
178- // Avoid focusinHandler() making recursive call to focus().
179- this . _tabKeyJustPressed = false ;
180-
181175 // Focus first navigable descendant.
182176 this . focus ( ) ;
183177 } . bind ( this ) ;
@@ -187,6 +181,7 @@ define([
187181 this . on ( "keydown" , this . _keynavKeyDownHandler . bind ( this ) , this . keyNavContainerNode ) ;
188182
189183 this . on ( "pointerdown" , this . pointerdownHandler . bind ( this ) , this . keyNavContainerNode ) ;
184+ this . on ( "pointerup" , this . pointerupHandler . bind ( this ) , this . keyNavContainerNode ) ;
190185 this . on ( "focusin" , this . focusinHandler . bind ( this ) , this . keyNavContainerNode ) ;
191186 this . on ( "focusout" , this . focusoutHandler . bind ( this ) , this . keyNavContainerNode ) ;
192187 } ,
@@ -212,45 +207,42 @@ define([
212207 if ( this . focusDescendants && ! container . hasAttribute ( "tabindex" ) ) {
213208 container . tabIndex = "0" ;
214209 }
215-
216- // Keep track of if user just pressed tab, so we can have different focus behavior for mouse vs. keyboard.
217- this . _keynavTabKeyListener = on ( this . ownerDocument . body , "keydown" , function ( evt ) {
218- if ( evt . key === "Tab" ) {
219- this . _tabKeyJustPressed = true ;
220-
221- // Clear _tabKeyJustPressed after focusinHandler() has been called. Note that 0ms is not long
222- // enough in some cases on Firefox, although that problem doesn't reproduce in the delite tests.
223- this . defer ( function ( ) {
224- this . _tabKeyJustPressed = false ;
225- } , 10 ) ;
226- }
227- } . bind ( this ) , true ) ;
228210 } ) ,
229211
230- disconnectedCallback : function ( ) {
231- // Remove listener here rather than using this.own() so that there's no need to call destroy().
232- this . _keynavTabKeyListener . remove ( ) ;
233- } ,
234-
235212 /**
236213 * Called on pointerdown event (on container or child of container).
237- * Navigation occurs on pointerdown, to match behavior of native elements.
238- * Normally this handler isn't needed as it's redundant w/the focusin event.
239214 */
240215 pointerdownHandler : function ( evt ) {
216+ // Focusin handler needs to differentiate between focusin from pointer or tab/shift-tab.
217+ this . _pointerOperation = true ;
218+
219+ // Navigation occurs on pointerdown, to match behavior of native elements.
220+ // Normally this handler isn't needed as it's redundant w/the focusin event.
241221 var target = this . _getTargetElement ( evt ) ;
242222 if ( target ) {
243223 this . _descendantNavigateHandler ( target , evt ) ;
244224 }
245225 } ,
246226
227+ /**
228+ * Called on pointerup event (on container or child of container).
229+ */
230+ pointerupHandler : function ( ) {
231+ // Clear _pointerOperation after focusinHandler() has been called. Note that 0ms is not long
232+ // enough in some cases on Firefox, although that problem doesn't reproduce in the delite tests.
233+ this . defer ( function ( ) {
234+ delete this . _pointerOperation ;
235+ } , 10 ) ;
236+ } ,
237+
247238 /**
248239 * Called on focus of container or child of container.
249240 */
250241 focusinHandler : function ( evt ) {
251242 var container = this . keyNavContainerNode ;
252243 if ( this . focusDescendants ) {
253- if ( this . _tabKeyJustPressed && ! container . contains ( evt . relatedTarget ) ) {
244+ var focusByTab = ! this . _pointerOperation && ! this . _programmaticallyFocusing ;
245+ if ( focusByTab && ! container . contains ( evt . relatedTarget ) ) {
254246 // When tabbing/shift-tabbing into this widget, focus the first child but do it on a delay so that
255247 // activationTracker sees my "focus" event before seeing the "focus" event on the child widget.
256248 // Note that shift-tab (from outside this widget) might go to an embedded widget rather than
@@ -384,7 +376,9 @@ define([
384376 // If this._savedTabIndex is set, use it instead of this.tabIndex, because it means
385377 // the container's tabIndex has already been changed to -1.
386378 child . tabIndex = "_savedTabIndex" in this ? this . _savedTabIndex : this . keyNavContainerNode . tabIndex ;
379+ this . _programmaticallyFocusing = true ;
387380 child . focus ( ) ;
381+ delete this . _programmaticallyFocusing ;
388382
389383 // _descendantNavigateHandler() will be called automatically from child's focus event.
390384 } else {
0 commit comments