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

Commit

Permalink
feat(list): add support for md-menu as proxied element
Browse files Browse the repository at this point in the history
- Allow md-menu to be a proxied element in a list
- Smart detection of being right or left aligned
- Allows md-menu to be a secondary element
- Adds aria label to menu triggerer if missing

Fixes #3339
  • Loading branch information
devversion committed Feb 2, 2016
1 parent 4fb92e3 commit 666308c
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 11 deletions.
32 changes: 32 additions & 0 deletions src/components/list/demoListControls/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,38 @@

<md-divider></md-divider>

<md-subheader class="md-no-sticky">Secondary Menus</md-subheader>
<md-list-item>
<p>Click anywhere to fire the secondary action</p>

<md-menu>
<md-button class="md-icon-button">
<md-icon md-svg-icon="communication:message"></md-icon>
</md-button>
<md-menu-content width="4">
<md-menu-item>
<md-button>
Redial
</md-button>
</md-menu-item>
<md-menu-item>
<md-button>
Check voicemail
</md-button>
</md-menu-item>
<md-menu-divider></md-menu-divider>
<md-menu-item>
<md-button>
Notifications
</md-button>
</md-menu-item>
</md-menu-content>
</md-menu>

</md-list-item>

<md-divider></md-divider>

<md-subheader class="md-no-sticky">Clickable Items with Secondary Controls</md-subheader>
<md-list-item ng-click="navigateTo(setting.extraScreen, $event)" ng-repeat="setting in settings">
<md-icon md-svg-icon="{{setting.icon}}"></md-icon>
Expand Down
42 changes: 31 additions & 11 deletions src/components/list/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ function mdListDirective($mdTheming) {
* that is inside the list, but does not wrap the contents._
*/
function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
var proxiedTypes = ['md-checkbox', 'md-switch'];
var proxiedTypes = ['md-checkbox', 'md-switch', 'md-menu'];
return {
restrict: 'E',
controller: 'MdListController',
Expand Down Expand Up @@ -112,7 +112,7 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
}
wrapSecondaryItems();
setupToggleAria();

if (hasProxiedElement && proxyElement.nodeName === "MD-MENU") setupProxiedMenu();

function setupToggleAria() {
var toggleTypes = ['md-switch', 'md-checkbox'];
Expand All @@ -129,6 +129,24 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
}
}

function setupProxiedMenu() {
var menuEl = angular.element(proxyElement);
var isLeftAligned = proxyElement.parentNode.firstElementChild == proxyElement;

// Set the position mode of the proxied menu
menuEl.attr('md-position-mode', (isLeftAligned ? 'target target' : 'target-right target'));

// Apply menu open binding to menu button
var menuOpenButton = menuEl.children().eq(0);
if (!hasClickEvent(menuOpenButton[0])) {
menuOpenButton.attr('ng-click', '$mdOpenMenu($event)');
}

if (!menuOpenButton.attr('aria-label')) {
menuOpenButton.attr('aria-label', 'Open Item Menu');
}
}

function wrapIn(type) {
var container;
if (type == 'div') {
Expand Down Expand Up @@ -177,14 +195,23 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
if ( secondaryItem && (
secondaryItem.hasAttribute('ng-click') ||
( tAttrs.ngClick &&
isProxiedElement(secondaryItem) )
isProxiedElement(secondaryItem) ) ||
secondaryItem.nodeName === 'MD-MENU'
)) {
secondaryItem.classList.remove('md-secondary');
tEl.addClass('md-with-secondary');
container.append(secondaryItem);
}
}

function hasClickEvent (element) {
var attr = element.attributes;
for (var i = 0; i < attr.length; i++) {
if (tAttrs.$normalize(attr[i].name) === 'ngClick') return true;
}
return false;
}

function copyAttributes(item, wrapper) {
var copiedAttrs = ['ng-if', 'ng-click', 'aria-label', 'ng-disabled',
'ui-sref', 'href', 'ng-href', 'ng-attr-ui-sref'];
Expand Down Expand Up @@ -238,14 +265,6 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
});
}

function hasClickEvent (element) {
var attr = element.attributes;
for (var i = 0; i < attr.length; i++) {
if ($attr.$normalize(attr[i].name) === 'ngClick') return true;
}
return false;
}

function computeProxies() {
var children = $element.children();
if (children.length && !children[0].hasAttribute('ng-click')) {
Expand Down Expand Up @@ -290,6 +309,7 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
if (!parentButton && firstChild.contains(e.target)) {
angular.forEach(proxies, function(proxy) {
if (e.target !== proxy && !proxy.contains(e.target)) {
if (proxy.nodeName === 'MD-MENU') proxy = proxy.children[0];
angular.element(proxy).triggerHandler('click');
}
});
Expand Down
14 changes: 14 additions & 0 deletions src/components/list/list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,20 @@ md-list-item, md-list-item .md-list-item-inner {
margin-right: -6px;
}

& > md-menu:first-child {
button.md-button.md-icon-button {
margin: 0 23px 0 -6px;
}
}

& > md-menu:not(:first-child),
md-menu.md-secondary {

button.md-button.md-icon-button {
margin: 0 -12px 0 0;
}
}

button.md-button.md-secondary-container {
background-color: transparent;
align-self: center;
Expand Down
21 changes: 21 additions & 0 deletions src/components/list/list.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ describe('mdListItem directive', function() {

});

it('should forward click events on the md-menu trigger button', function() {
var template =
'<md-list-item>' +
'<md-menu>' +
'<md-button ng-click="openMenu()"></md-button>' +
'</md-menu>' +
'</md-list-item>';

var listItem = setup(template);
var cntr = listItem[0].querySelector('div');
var openMenu = jasmine.createSpy('openMenu');

$rootScope.openMenu = openMenu;

if (cntr && cntr.click) {
cntr.click();
expect(openMenu).toHaveBeenCalled();
}

});

it('forwards click events for md-switch', function() {
var listItem = setup('<md-list-item><md-switch ng-model="modelVal"></md-switch></md-list-item>');
var cntr = listItem[0].querySelector('div');
Expand Down

0 comments on commit 666308c

Please sign in to comment.