Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 4580dcf

Browse files
update(autocomplete, bottomsheet, dialog, sidenav): add support for md-auto-focus
Provide a consistent approach to optionally specify child element that should be focused for any component. When the owning component is ready, use `$mdUtil.findFocusTarget()` * Bottomsheet and sideNav allows any child element to be the auto-focus target; using `md-auto-focus` * Sidenav Basic Usage demo specifies `md-auto-focus` on the input form element. * Bottomsheet Basic Usage demo shows expression use with `md-auto-focus` to conditional focus an element within ng-repeat. * Dialog allows custom dialog content to specify an `md-auto-focus` target for any content element. * Basic Demo uses `md-auto-focus` on first action button BREAKING CHANGE: md-autocomplete's `md-autofocus` has changed to `md-enable-autofocus`; to differentiate use with the new `md-auto-focus` indicator. Change your code from this: ```html <md-autocomplete md-autofocus> ``` To this: ```html <md-autocomplete md-enable-autofocus> ``` Fixes #1190.
1 parent f6af02c commit 4580dcf

File tree

17 files changed

+704
-558
lines changed

17 files changed

+704
-558
lines changed

src/components/autocomplete/demoBasicUsage/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<p>Use <code>md-autocomplete</code> to search for matches from local or remote data sources.</p>
55
<md-autocomplete
66
ng-disabled="ctrl.isDisabled"
7+
md-enable-autofocus="true"
78
md-no-cache="ctrl.noCache"
89
md-selected-item="ctrl.selectedItem"
910
md-search-text-change="ctrl.searchTextChange(ctrl.searchText)"

src/components/autocomplete/js/autocompleteController.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
6161
configureWatchers();
6262
$mdUtil.nextTick(function () {
6363
gatherElements();
64-
focusElement();
6564
moveDropdown();
65+
focusElement();
6666
});
6767
}
6868

@@ -124,7 +124,10 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
124124
* Sends focus to the input element.
125125
*/
126126
function focusElement () {
127-
if ($scope.autofocus) elements.input.focus();
127+
if ($scope.enableAutofocus) {
128+
$mdUtil.findFocusTarget($element);
129+
}
130+
//elements.input.focus();
128131
}
129132

130133
/**

src/components/autocomplete/js/autocompleteDirective.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ angular
4949
* make suggestions
5050
* @param {number=} md-delay Specifies the amount of time (in milliseconds) to wait before looking
5151
* for results
52-
* @param {boolean=} md-autofocus If true, will immediately focus the input element
52+
* @param {boolean=} md-enable-autofocus If true, will immediately focus the input element
5353
* @param {boolean=} md-autoselect If true, the first item will be selected by default
5454
* @param {string=} md-menu-class This will be applied to the dropdown menu for styling
5555
* @param {string=} md-floating-label This will add a floating label to autocomplete and wrap it in
@@ -136,7 +136,7 @@ function MdAutocomplete () {
136136
textChange: '&?mdSearchTextChange',
137137
minLength: '=?mdMinLength',
138138
delay: '=?mdDelay',
139-
autofocus: '=?mdAutofocus',
139+
enableAutofocus:'=?mdEnableAutofocus',
140140
floatingLabel: '@?mdFloatingLabel',
141141
autoselect: '=?mdAutoselect',
142142
menuClass: '@?mdMenuClass',
@@ -219,7 +219,8 @@ function MdAutocomplete () {
219219
aria-autocomplete="list"\
220220
aria-haspopup="true"\
221221
aria-activedescendant=""\
222-
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
222+
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"\
223+
md-auto-focus/>\
223224
<div md-autocomplete-parent-scope md-autocomplete-replace>' + leftover + '</div>\
224225
</md-input-container>';
225226
} else {
@@ -241,7 +242,8 @@ function MdAutocomplete () {
241242
aria-autocomplete="list"\
242243
aria-haspopup="true"\
243244
aria-activedescendant=""\
244-
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
245+
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"\
246+
md-auto-focus/>\
245247
<button\
246248
type="button"\
247249
tabindex="-1"\

src/components/bottomSheet/bottomSheet.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function MdBottomSheetDirective() {
1717
};
1818
}
1919

20+
2021
/**
2122
* @ngdoc service
2223
* @name $mdBottomSheet
@@ -138,7 +139,7 @@ function MdBottomSheetProvider($$interimElementProvider) {
138139
};
139140

140141

141-
function onShow(scope, element, options) {
142+
function onShow(scope, element, options, controller) {
142143

143144
element = $mdUtil.extractElementByName(element, 'md-bottom-sheet');
144145

@@ -165,7 +166,7 @@ function MdBottomSheetProvider($$interimElementProvider) {
165166

166167
return $animate.enter(bottomSheet.element, options.parent)
167168
.then(function() {
168-
var focusable = angular.element(
169+
var focusable = $mdUtil.findFocusTarget(element) || angular.element(
169170
element[0].querySelector('button') ||
170171
element[0].querySelector('a') ||
171172
element[0].querySelector('[ng-click]')

src/components/bottomSheet/bottomSheet.spec.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ describe('$mdBottomSheet service', function() {
1515

1616
expect(parent.find('md-bottom-sheet').length).toBe(1);
1717

18-
$rootElement.triggerHandler({type: 'keyup',
18+
$rootElement.triggerHandler({
19+
type: 'keyup',
1920
keyCode: $mdConstant.KEY_CODE.ESCAPE
2021
});
2122

@@ -36,9 +37,38 @@ describe('$mdBottomSheet service', function() {
3637

3738
expect(parent.find('md-bottom-sheet').length).toBe(1);
3839

39-
$rootElement.triggerHandler({ type: 'keyup', keyCode: $mdConstant.KEY_CODE.ESCAPE });
40+
$rootElement.triggerHandler({type: 'keyup', keyCode: $mdConstant.KEY_CODE.ESCAPE});
4041

4142
expect(parent.find('md-bottom-sheet').length).toBe(1);
4243
}));
44+
45+
it('should focus child with md-auto-focus', inject(function($rootScope, $animate, $document, $mdBottomSheet) {
46+
jasmine.mockElementFocus(this);
47+
var parent = angular.element('<div>');
48+
var markup = '' +
49+
'<md-bottom-sheet>' +
50+
' <md-input-container><label>Label</label>' +
51+
' <input type="text" md-auto-focus>' +
52+
' </md-input-container>' +
53+
' <md-input-container><label>Label</label>' +
54+
' <input type="text" md-auto-focus>' +
55+
' </md-input-container>' +
56+
'<md-bottom-sheet>';
57+
58+
$mdBottomSheet.show({
59+
template: '<md-bottom-sheet>',
60+
parent: parent,
61+
escapeToClose: false
62+
});
63+
$rootScope.$apply();
64+
$animate.triggerCallbacks();
65+
66+
var sheet = parent.find('md-bottom-sheet');
67+
expect(sheet.length).toBe(1);
68+
var focusEl = sheet.find('input');
69+
70+
// Focus should be on the last md-auto-focus element
71+
expect($document.activeElement).toBe(focusEl[1]);
72+
}));
4373
});
4474
});

src/components/bottomSheet/demoBasicUsage/bottom-sheet-list-template.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
<md-list>
44
<md-list-item ng-repeat="item in items">
55

6-
<md-button class="md-list-item-content" ng-click="listItemClick($index)">
6+
<md-button
7+
ng-click="listItemClick($index)"
8+
md-auto-focus="$index == 2"
9+
class="md-list-item-content" >
710
<md-icon md-svg-src="{{item.icon}}"></md-icon>
811
<span class="md-inline-list-icon-label">{{ item.name }}</span>
912
</md-button>

src/components/bottomSheet/demoBasicUsage/style.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,19 @@
1919
.md-grid-text {
2020
padding-bottom: 5px;
2121
}
22+
23+
24+
md-list-item, md-list-item .md-list-item-inner {
25+
min-height: 48px;
26+
27+
}
28+
29+
h2 {
30+
line-height: 36px;
31+
padding-top: 10px;
32+
}
33+
34+
35+
.md-subheader .md-subheader-inner {
36+
padding: 0px;
37+
}

src/components/dialog/demoBasicUsage/dialog1.tmpl.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<div class="md-toolbar-tools">
55
<h2>Mango (Fruit)</h2>
66
<span flex></span>
7-
<md-button class="md-icon-button" ng-click="answer('not applicable')">
7+
<md-button class="md-icon-button" ng-click="answer('not applicable')" >
88
<md-icon md-svg-src="img/icons/ic_close_24px.svg" aria-label="Close dialog"></md-icon>
99
</md-button>
1010
</div>
@@ -27,14 +27,14 @@ <h2>Mango (Fruit)</h2>
2727
</md-dialog-content>
2828

2929
<div class="md-actions" layout="row">
30-
<md-button href="http://en.wikipedia.org/wiki/Mango" target="_blank" hide show-md>
30+
<md-button href="http://en.wikipedia.org/wiki/Mango" target="_blank" md-auto-focus>
3131
More on Wikipedia
3232
</md-button>
3333
<span flex></span>
34-
<md-button ng-click="answer('not useful')">
34+
<md-button ng-click="answer('not useful')" >
3535
Not Useful
3636
</md-button>
37-
<md-button ng-click="answer('useful')" style="margin-right:20px;">
37+
<md-button ng-click="answer('useful')" style="margin-right:20px;" >
3838
Useful
3939
</md-button>
4040
</div>

src/components/dialog/demoBasicUsage/script.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ angular.module('dialogDemo1', ['ngMaterial'])
2525
.title('Would you like to delete your debt?')
2626
.content('All of the banks have agreed to forgive you your debts.')
2727
.ariaLabel('Lucky day')
28+
.targetEvent(ev)
2829
.ok('Please do it!')
29-
.cancel('Sounds like a scam')
30-
.targetEvent(ev);
30+
.cancel('Sounds like a scam');
3131

3232
$mdDialog.show(confirm).then(function() {
3333
$scope.status = 'You decided to get rid of your debt.';

src/components/dialog/dialog.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ function MdDialogDirective($$rAF, $mdTheming) {
3232
};
3333
}
3434

35+
36+
3537
/**
3638
* @ngdoc service
3739
* @name $mdDialog
@@ -413,7 +415,7 @@ function MdDialogProvider($$interimElementProvider) {
413415
' ng-click="dialog.abort()" class="md-primary">',
414416
' {{ dialog.cancel }}',
415417
' </md-button>',
416-
' <md-button ng-click="dialog.hide()" class="md-primary">',
418+
' <md-button ng-click="dialog.hide()" class="md-primary" md-auto-focus="dialog.$type!=\'confirm\'">',
417419
' {{ dialog.ok }}',
418420
' </md-button>',
419421
' </div>',
@@ -453,7 +455,7 @@ function MdDialogProvider($$interimElementProvider) {
453455
/**
454456
* Show method for dialogs
455457
*/
456-
function onShow(scope, element, options) {
458+
function onShow(scope, element, options, controller) {
457459
element = $mdUtil.extractElementByName(element, 'md-dialog');
458460
angular.element($document[0].body).addClass('md-dialog-is-showing');
459461

@@ -474,13 +476,15 @@ function MdDialogProvider($$interimElementProvider) {
474476
*/
475477
function focusOnOpen() {
476478
if (options.focusOnOpen) {
477-
var target = (options.$type === 'alert') ? element.find('md-dialog-content') : findCloseButton();
479+
var target = $mdUtil.findFocusTarget(element) || findCloseButton();
478480
target.focus();
479481
}
480482

483+
/**
484+
* If no element with class dialog-close, try to find the last
485+
* button child in md-actions and assume it is a close button
486+
*/
481487
function findCloseButton() {
482-
//If no element with class dialog-close, try to find the last
483-
//button child in md-actions and assume it is a close button
484488
var closeButton = element[0].querySelector('.dialog-close');
485489
if (!closeButton) {
486490
var actionButtons = element[0].querySelectorAll('.md-actions button');
@@ -534,6 +538,8 @@ function MdDialogProvider($$interimElementProvider) {
534538
// In case the user provides a raw dom element, always wrap it in jqLite
535539
options.parent = angular.element(options.parent || $rootElement);
536540

541+
542+
537543
}
538544

539545
/**

0 commit comments

Comments
 (0)