@@ -104,23 +104,50 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in
104
104
* </md-list>
105
105
* </md-bottom-sheet>
106
106
*</hljs>
107
- *
108
107
**/
109
108
findFocusTarget : function ( containerEl , attributeVal ) {
110
- var elToFocus , items = containerEl [ 0 ] . querySelectorAll ( attributeVal || '[md-autofocus]' ) ;
109
+ var AUTO_FOCUS = '[md-autofocus]' ;
110
+ var elToFocus ;
111
111
112
- // Find the last child element with the focus attribute
113
- items . length && angular . forEach ( items , function ( it ) {
114
- it = angular . element ( it ) ;
112
+ elToFocus = scanForFocusable ( containerEl , attributeVal || AUTO_FOCUS ) ;
115
113
116
- // If the expression evaluates to FALSE, then it is not focusable target
117
- var focusExpression = it [ 0 ] . getAttribute ( 'md-autofocus' ) ;
118
- var isFocusable = focusExpression ? ( it . scope ( ) . $eval ( focusExpression ) !== false ) : true ;
114
+ if ( ! elToFocus && attributeVal != AUTO_FOCUS ) {
115
+ // Scan for deprecated attribute
116
+ elToFocus = scanForFocusable ( containerEl , '[md-auto-focus]' ) ;
119
117
120
- if ( isFocusable ) elToFocus = it ;
121
- } ) ;
118
+ if ( ! elToFocus ) {
119
+ // Scan for fallback to 'universal' API
120
+ elToFocus = scanForFocusable ( containerEl , AUTO_FOCUS ) ;
121
+ }
122
+ }
122
123
123
124
return elToFocus ;
125
+
126
+ /**
127
+ * Can target and nested children for specified Selector (attribute)
128
+ * whose value may be an expression that evaluates to True/False.
129
+ */
130
+ function scanForFocusable ( target , selector ) {
131
+ var elFound , items = target [ 0 ] . querySelectorAll ( selector ) ;
132
+
133
+ // Find the last child element with the focus attribute
134
+ if ( items && items . length ) {
135
+ var EXP_ATTR = / \s * \[ ? ( [ \- a - z ] * ) \] ? \s * / i;
136
+ var matches = EXP_ATTR . exec ( selector ) ;
137
+ var attribute = matches ? matches [ 1 ] : null ;
138
+
139
+ items . length && angular . forEach ( items , function ( it ) {
140
+ it = angular . element ( it ) ;
141
+
142
+ // If the expression evaluates to FALSE, then it is not focusable target
143
+ var focusExpression = it [ 0 ] . getAttribute ( attribute ) ;
144
+ var isFocusable = focusExpression ? ( it . scope ( ) . $eval ( focusExpression ) !== false ) : true ;
145
+
146
+ if ( isFocusable ) elFound = it ;
147
+ } ) ;
148
+ }
149
+ return elFound ;
150
+ }
124
151
} ,
125
152
126
153
// Disables scroll around the passed element.
@@ -168,11 +195,10 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in
168
195
// (arrow keys, spacebar, tab, etc).
169
196
function disableKeyNav ( e ) {
170
197
//-- temporarily removed this logic, will possibly re-add at a later date
171
- return ;
172
- if ( ! element [ 0 ] . contains ( e . target ) ) {
173
- e . preventDefault ( ) ;
174
- e . stopImmediatePropagation ( ) ;
175
- }
198
+ //if (!element[0].contains(e.target)) {
199
+ // e.preventDefault();
200
+ // e.stopImmediatePropagation();
201
+ //}
176
202
}
177
203
178
204
function preventDefault ( e ) {
@@ -455,16 +481,58 @@ function UtilFactory($document, $timeout, $compile, $rootScope, $$mdAnimate, $in
455
481
/**
456
482
* Functional equivalent for $element.filter(‘md-bottom-sheet’)
457
483
* useful with interimElements where the element and its container are important...
484
+ *
485
+ * @param {[] } elements to scan
486
+ * @param {string } name of node to find (e.g. 'md-dialog')
487
+ * @param {boolean= } optional flag to allow deep scans; defaults to 'false'.
458
488
*/
459
- extractElementByName : function ( element , nodeName ) {
460
- for ( var i = 0 , len = element . length ; i < len ; i ++ ) {
461
- if ( element [ i ] . nodeName . toLowerCase ( ) === nodeName ) {
462
- return angular . element ( element [ i ] ) ;
489
+ extractElementByName : function ( element , nodeName , scanDeep , warnNotFound ) {
490
+ var found = scanTree ( element ) ;
491
+ if ( ! found && ! ! warnNotFound ) {
492
+ $log . warn ( $mdUtil . supplant ( "Unable to find node '{0}' in element." , [ nodeName ] ) ) ;
493
+ }
494
+
495
+ return angular . element ( found || element ) ;
496
+
497
+ /**
498
+ * Breadth-First tree scan for element with matching `nodeName`
499
+ */
500
+ function scanTree ( element ) {
501
+ return scanLevel ( element ) || ( ! ! scanDeep ? scanChildren ( element ) : null ) ;
502
+ }
503
+
504
+ /**
505
+ * Case-insensitive scan of current elements only (do not descend).
506
+ */
507
+ function scanLevel ( element ) {
508
+ if ( element ) {
509
+ for ( var i = 0 , len = element . length ; i < len ; i ++ ) {
510
+ if ( element [ i ] . nodeName . toLowerCase ( ) === nodeName ) {
511
+ return element [ i ] ;
512
+ }
513
+ }
514
+ }
515
+ return null ;
516
+ }
517
+
518
+ /**
519
+ * Scan children of specified node
520
+ */
521
+ function scanChildren ( element ) {
522
+ var found ;
523
+ if ( element ) {
524
+ for ( var i = 0 , len = element . length ; i < len ; i ++ ) {
525
+ var target = element [ i ] ;
526
+ if ( ! found ) {
527
+ for ( var j = 0 , numChild = target . childNodes . length ; j < numChild ; j ++ ) {
528
+ found = found || scanTree ( [ target . childNodes [ j ] ] ) ;
529
+ }
530
+ }
531
+ }
463
532
}
533
+ return found ;
464
534
}
465
535
466
- $log . warn ( $mdUtil . supplant ( "Unable to find node '{0}' in element." , [ nodeName ] ) ) ;
467
- return element ;
468
536
} ,
469
537
470
538
/**
0 commit comments