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

Commit d04dfc5

Browse files
devversionThomasBurleson
authored andcommitted
feat(list): support md-no-focus class
* Refactors `md-no-focus-style` attribute into the `md-no-focus` class. * Adds support for `md-no-focus` class forwarding for the list item. * Add documentation for `md-menu` as proxy item * Enhance tests for `md-menu` inside of `md-list-item` BREAKING CHANGE: `md-no-focus-style` attribute on `md-button` is now a class (`.md-no-focus`) Closes #8691. Closes #8734
1 parent d6996b7 commit d04dfc5

File tree

4 files changed

+135
-5
lines changed

4 files changed

+135
-5
lines changed

src/components/button/button.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,30 @@ function MdAnchorDirective($mdTheming) {
5353
* the FAB button background is filled with the accent color [by default]. The primary color palette may be used with
5454
* the `md-primary` class.
5555
*
56+
* Developers can also change the color palette of the button, by using the following classes
57+
* - `md-primary`
58+
* - `md-accent`
59+
* - `md-warn`
60+
*
61+
* See for example
62+
*
63+
* <hljs lang="html">
64+
* <md-button class="md-primary">Primary Button</md-button>
65+
* </hljs>
66+
*
67+
* Button can be also raised, which means that they will use the current color palette to fill the button.
68+
*
69+
* <hljs lang="html">
70+
* <md-button class="md-accent md-raised">Raised and Accent Button</md-button>
71+
* </hljs>
72+
*
73+
* It is also possible to disable the focus effect on the button, by using the following markup.
74+
*
75+
* <hljs lang="html">
76+
* <md-button class="md-no-focus">No Focus Style</md-button>
77+
* </hljs>
78+
*
5679
* @param {boolean=} md-no-ink If present, disable ripple ink effects.
57-
* @param {boolean=} md-no-focus-style If present, disable focus style on button
5880
* @param {expression=} ng-disabled En/Disable based on the expression
5981
* @param {string=} md-ripple-size Overrides the default ripple size logic. Options: `full`, `partial`, `auto`
6082
* @param {string=} aria-label Adds alternative text to button for accessibility, useful for icon buttons.
@@ -138,7 +160,7 @@ function MdButtonDirective($mdButtonInkRipple, $mdTheming, $mdAria, $timeout) {
138160
}
139161
});
140162

141-
if (!angular.isDefined(attr.mdNoFocusStyle)) {
163+
if (!element.hasClass('md-no-focus')) {
142164
// restrict focus styles to the keyboard
143165
scope.mouseActive = false;
144166
element.on('mousedown', function() {
@@ -156,6 +178,7 @@ function MdButtonDirective($mdButtonInkRipple, $mdTheming, $mdAria, $timeout) {
156178
element.removeClass('md-focused');
157179
});
158180
}
181+
159182
}
160183

161184
}

src/components/button/button.spec.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ describe('md-button', function() {
7575
expect(button[0]).not.toHaveClass('md-focused');
7676
}));
7777

78+
it('should not set the focus state if focus is disabled', inject(function($compile, $rootScope) {
79+
var button = $compile('<md-button class="md-no-focus">')($rootScope.$new());
80+
$rootScope.$apply();
81+
82+
button.triggerHandler('focus');
83+
84+
expect(button).not.toHaveClass('md-focused');
85+
}));
86+
7887
describe('with href or ng-href', function() {
7988

8089
it('should be anchor if href attr', inject(function($compile, $rootScope) {

src/components/list/list.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ function mdListDirective($mdTheming) {
113113
* Currently supported proxy items are
114114
* - `md-checkbox` (Toggle)
115115
* - `md-switch` (Toggle)
116+
* - `md-menu` (Open)
116117
*
117118
* This means, when using a supported proxy item inside of `md-list-item`, the list item will
118119
* become clickable and executes the associated action of the proxy element on click.
@@ -135,6 +136,41 @@ function mdListDirective($mdTheming) {
135136
*
136137
* The recognized `md-switch` will toggle its state, when the user clicks on the `md-list-item`.
137138
*
139+
* It is also possible to have a `md-menu` inside of a `md-list-item`.
140+
* <hljs lang="html">
141+
* <md-list-item>
142+
* <p>Click anywhere to fire the secondary action</p>
143+
* <md-menu class="md-secondary">
144+
* <md-button class="md-icon-button">
145+
* <md-icon md-svg-icon="communication:message"></md-icon>
146+
* </md-button>
147+
* <md-menu-content width="4">
148+
* <md-menu-item>
149+
* <md-button>
150+
* Redial
151+
* </md-button>
152+
* </md-menu-item>
153+
* <md-menu-item>
154+
* <md-button>
155+
* Check voicemail
156+
* </md-button>
157+
* </md-menu-item>
158+
* <md-menu-divider></md-menu-divider>
159+
* <md-menu-item>
160+
* <md-button>
161+
* Notifications
162+
* </md-button>
163+
* </md-menu-item>
164+
* </md-menu-content>
165+
* </md-menu>
166+
* </md-list-item>
167+
* </hljs>
168+
*
169+
* The menu will automatically open, when the users clicks on the `md-list-item`.<br/>
170+
*
171+
* If the developer didn't specify any position mode on the menu, the `md-list-item` will automatically detect the
172+
* position mode and applies it to the `md-menu`.
173+
*
138174
* ### Avatars
139175
* Sometimes you may want to have some avatars inside of the `md-list-item `.<br/>
140176
* You are able to create a optimized icon for the list item, by applying the `.md-avatar` class on the `<img>` element.
@@ -281,8 +317,16 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
281317
);
282318

283319
buttonWrap[0].setAttribute('aria-label', tEl[0].textContent);
320+
284321
copyAttributes(tEl[0], buttonWrap[0]);
285322

323+
// We allow developers to specify the `md-no-focus` class, to disable the focus style
324+
// on the button executor. Once more classes should be forwarded, we should probably make the
325+
// class forward more generic.
326+
if (tEl.hasClass('md-no-focus')) {
327+
buttonWrap.addClass('md-no-focus');
328+
}
329+
286330
// Append the button wrap before our list-item content, because it will overlay in relative.
287331
itemContainer.prepend(buttonWrap);
288332
itemContainer.children().eq(1).append(tEl.contents());

src/components/list/list.spec.js

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,27 @@ describe('mdListItem directive', function() {
230230
expect(innerContent.firstElementChild.nodeName).toBe('P');
231231
});
232232

233+
it('should forward the md-no-focus class', function() {
234+
var listItem = setup(
235+
'<md-list-item ng-click="null" class="md-no-focus">' +
236+
'<p>Clickable - Without Focus Style</p>' +
237+
'</md-list-item>');
238+
239+
// List items, which are clickable always contain a button wrap at the top level.
240+
var buttonWrap = listItem.children().eq(0);
241+
expect(listItem).toHaveClass('_md-button-wrap');
242+
243+
// The button wrap should contain the button executor, the inner content and the
244+
// secondary item container as children.
245+
expect(buttonWrap.children().length).toBe(3);
246+
247+
var buttonExecutor = buttonWrap.children();
248+
249+
// The list item should forward the href and md-no-focus-style attribute.
250+
expect(buttonExecutor.attr('ng-click')).toBeTruthy();
251+
expect(buttonExecutor.hasClass('md-no-focus')).toBe(true);
252+
});
253+
233254
it('moves aria-label to primary action', function() {
234255
var listItem = setup('<md-list-item ng-click="sayHello()" aria-label="Hello"></md-list-item>');
235256

@@ -328,12 +349,13 @@ describe('mdListItem directive', function() {
328349
});
329350

330351
describe('with a md-menu', function() {
352+
331353
it('should forward click events on the md-menu trigger button', function() {
332354
var template =
333355
'<md-list-item>' +
334-
'<md-menu>' +
335-
'<md-button ng-click="openMenu()"></md-button>' +
336-
'</md-menu>' +
356+
'<md-menu>' +
357+
'<md-button ng-click="openMenu()"></md-button>' +
358+
' </md-menu>' +
337359
'</md-list-item>';
338360

339361
var listItem = setup(template);
@@ -380,6 +402,38 @@ describe('mdListItem directive', function() {
380402

381403
expect(mdMenu.attr('md-position-mode')).toBe('left target');
382404
});
405+
406+
it('should apply an aria-label if not specified', function() {
407+
var template =
408+
'<md-list-item>' +
409+
'<span>Aria Label Menu</span>' +
410+
'<md-menu>' +
411+
'<md-button ng-click="openMenu()"></md-button>' +
412+
'</md-menu>' +
413+
'</md-list-item>';
414+
415+
var listItem = setup(template);
416+
417+
var mdMenuButton = listItem[0].querySelector('md-menu > md-button');
418+
419+
expect(mdMenuButton.getAttribute('aria-label')).toBe('Open List Menu');
420+
});
421+
422+
it('should apply $mdMenuOpen to the button if not present', function() {
423+
var template =
424+
'<md-list-item>' +
425+
'<span>Aria Label Menu</span>' +
426+
'<md-menu>' +
427+
'<md-button>Should Open the Menu</md-button>' +
428+
'</md-menu>' +
429+
'</md-list-item>';
430+
431+
var listItem = setup(template);
432+
433+
var mdMenuButton = listItem[0].querySelector('md-menu > md-button');
434+
435+
expect(mdMenuButton.getAttribute('ng-click')).toBe('$mdOpenMenu($event)');
436+
});
383437
});
384438

385439
describe('with a clickable item', function() {

0 commit comments

Comments
 (0)