Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions src/components/list/demoListControls/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,4 @@ md-list-item ._md-list-item-inner > ._md-list-item-inner > p {
-moz-user-select: none; /* Firefox all */
-ms-user-select: none; /* IE 10+ */
user-select: none; /* Likely future */
}

/* Add some right padding so that the text doesn't overlap the buttons */
.secondary-button-padding p {
padding-right: 100px;
}
}
113 changes: 55 additions & 58 deletions src/components/list/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
restrict: 'E',
controller: 'MdListController',
compile: function(tEl, tAttrs) {

// Check for proxy controls (no ng-click on parent, and a control inside)
var secondaryItems = tEl[0].querySelectorAll('.md-secondary');
var hasProxiedElement;
var proxyElement;
var itemContainer = tEl;

tEl[0].setAttribute('role', 'listitem');

Expand Down Expand Up @@ -130,14 +132,13 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
}

function wrapIn(type) {
var container;
if (type == 'div') {
container = angular.element('<div class="_md-no-style _md-list-item-inner">');
container.append(tEl.contents());
itemContainer = angular.element('<div class="_md-no-style _md-list-item-inner">');
itemContainer.append(tEl.contents());
tEl.addClass('_md-proxy-focus');
} else {
// Element which holds the default list-item content.
container = angular.element(
itemContainer = angular.element(
'<div class="md-button _md-no-style">'+
' <div class="_md-list-item-inner"></div>'+
'</div>'
Expand All @@ -152,58 +153,48 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
copyAttributes(tEl[0], buttonWrap[0]);

// Append the button wrap before our list-item content, because it will overlay in relative.
container.prepend(buttonWrap);
container.children().eq(1).append(tEl.contents());
itemContainer.prepend(buttonWrap);
itemContainer.children().eq(1).append(tEl.contents());

tEl.addClass('_md-button-wrap');
}

tEl[0].setAttribute('tabindex', '-1');
tEl.append(container);
tEl.append(itemContainer);
}

function wrapSecondaryItems() {
if (secondaryItems.length === 1) {
wrapSecondaryItem(secondaryItems[0], tEl);
} else if (secondaryItems.length > 1) {
var secondaryItemsWrapper = angular.element('<div class="_md-secondary-container">');
angular.forEach(secondaryItems, function(secondaryItem) {
wrapSecondaryItem(secondaryItem, secondaryItemsWrapper, true);
});
tEl.append(secondaryItemsWrapper);
}
var secondaryItemsWrapper = angular.element('<div class="_md-secondary-container">');

angular.forEach(secondaryItems, function(secondaryItem) {
wrapSecondaryItem(secondaryItem, secondaryItemsWrapper);
});

// Since the secondary item container is static we need to fill the remaing space.
var spaceFiller = angular.element('<div class="flex"></div>');
itemContainer.append(spaceFiller);

itemContainer.append(secondaryItemsWrapper);
}

function wrapSecondaryItem(secondaryItem, container, hasSecondaryItemsWrapper) {
function wrapSecondaryItem(secondaryItem, container) {
if (secondaryItem && !isButton(secondaryItem) && secondaryItem.hasAttribute('ng-click')) {
$mdAria.expect(secondaryItem, 'aria-label');
var buttonWrapper;
if (hasSecondaryItemsWrapper) {
buttonWrapper = angular.element('<md-button class="md-icon-button">');
} else {
buttonWrapper = angular.element('<md-button class="_md-secondary-container md-icon-button">');
}
var buttonWrapper = angular.element('<md-button class="md-secondary md-icon-button">');
copyAttributes(secondaryItem, buttonWrapper[0]);
secondaryItem.setAttribute('tabindex', '-1');
secondaryItem.classList.remove('md-secondary');
buttonWrapper.append(secondaryItem);
secondaryItem = buttonWrapper[0];
}

// Check for a secondary item and move it outside
if ( secondaryItem && (
secondaryItem.hasAttribute('ng-click') ||
( tAttrs.ngClick &&
isProxiedElement(secondaryItem) )
)) {
// When using multiple secondary items we need to remove their secondary class to be
// orderd correctly in the list-item
if (hasSecondaryItemsWrapper) {
secondaryItem.classList.remove('md-secondary');
}
tEl.addClass('md-with-secondary');
container.append(secondaryItem);
if (secondaryItem && (!hasClickEvent(secondaryItem) || (!tAttrs.ngClick && isProxiedElement(secondaryItem)))) {
// In this case we remove the secondary class, so we can identify it later, when we searching for the
// proxy items.
angular.element(secondaryItem).removeClass('md-secondary');
}

tEl.addClass('md-with-secondary');
container.append(secondaryItem);
}

function copyAttributes(item, wrapper) {
Expand All @@ -227,14 +218,23 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
return nodeName == "MD-BUTTON" || nodeName == "BUTTON";
}

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;
}

return postLink;

function postLink($scope, $element, $attr, ctrl) {

var proxies = [],
firstChild = $element[0].firstElementChild,
hasClick = firstChild && firstChild.firstElementChild &&
hasClickEvent(firstChild.firstElementChild);
var proxies = [],
firstElement = $element[0].firstElementChild,
isButtonWrap = $element.hasClass('_md-button-wrap'),
clickChild = isButtonWrap ? firstElement.firstElementChild : firstElement,
hasClick = clickChild && hasClickEvent(clickChild);

computeProxies();
computeClickable();
Expand All @@ -260,22 +260,19 @@ 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')) {
if (firstElement && firstElement.children && !hasClick) {

angular.forEach(proxiedTypes, function(type) {
angular.forEach(firstChild.querySelectorAll(type), function(child) {

// All elements which are not capable for being used a proxy have the .md-secondary class
// applied. These items had been sorted out in the secondary wrap function.
angular.forEach(firstElement.querySelectorAll(type + ':not(.md-secondary)'), function(child) {
proxies.push(child);
});
});

}
}
function computeClickable() {
Expand All @@ -288,12 +285,12 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
}
}

var firstChildKeypressListener = function(e) {
var clickChildKeypressListener = function(e) {
if (e.target.nodeName != 'INPUT' && e.target.nodeName != 'TEXTAREA' && !e.target.isContentEditable) {
var keyCode = e.which || e.keyCode;
if (keyCode == $mdConstant.KEY_CODE.SPACE) {
if (firstChild) {
firstChild.click();
if (clickChild) {
clickChild.click();
e.preventDefault();
e.stopPropagation();
}
Expand All @@ -302,16 +299,16 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
};

if (!hasClick && !proxies.length) {
firstChild && firstChild.addEventListener('keypress', firstChildKeypressListener);
clickChild && clickChild.addEventListener('keypress', clickChildKeypressListener);
}

$element.off('click');
$element.off('keypress');

if (proxies.length == 1 && firstChild) {
if (proxies.length == 1 && clickChild) {
$element.children().eq(0).on('click', function(e) {
var parentButton = $mdUtil.getClosest(e.target, 'BUTTON');
if (!parentButton && firstChild.contains(e.target)) {
if (!parentButton && clickChild.contains(e.target)) {
angular.forEach(proxies, function(proxy) {
if (e.target !== proxy && !proxy.contains(e.target)) {
angular.element(proxy).triggerHandler('click');
Expand All @@ -322,7 +319,7 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
}

$scope.$on('$destroy', function () {
firstChild && firstChild.removeEventListener('keypress', firstChildKeypressListener);
clickChild && clickChild.removeEventListener('keypress', clickChildKeypressListener);
});
}
}
Expand Down
80 changes: 31 additions & 49 deletions src/components/list/list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,6 @@ md-list-item {
outline: none
}
}
&.md-with-secondary {
position: relative;
}
&.md-clickable:hover {
cursor: pointer;
}
Expand Down Expand Up @@ -263,12 +260,7 @@ md-list-item {
& > md-icon:first-child:not(.md-avatar-icon) {
@include rtl-prop(margin-right, margin-left, $list-item-primary-width - $list-item-primary-icon-width);
}
& > md-checkbox {
width: 3 * $baseline-grid;
@include rtl(margin-left, 3px, 29px);
@include rtl(margin-right, 29px,3px);
margin-top: 16px;
}

& .md-avatar, .md-avatar-icon {
margin-top: $baseline-grid;
margin-bottom: $baseline-grid;
Expand All @@ -284,57 +276,47 @@ md-list-item {
padding: 8px;
}

md-checkbox.md-secondary,
md-switch.md-secondary {
margin-top: 0;
margin-bottom: 0;
}

md-checkbox.md-secondary {
@include rtl-prop(margin-right, margin-left, 0);
& > md-checkbox {
width: 3 * $baseline-grid;
@include rtl(margin-left, 3px, 29px);
@include rtl(margin-right, 29px, 3px);
margin-top: 16px;
}

md-switch.md-secondary {
@include rtl-prop(margin-right, margin-left, -6px);
}
._md-secondary-container {
display: flex;
align-items: center;

button.md-button._md-secondary-container {
background-color: transparent;
align-self: center;
border-radius: 50%;
margin: 0px;
min-width: 0px;
height: 100%;
margin: auto;

.md-ripple,
.md-ripple-container {
border-radius: 50%;
.md-button, .md-icon-button {
&:last-of-type {
// Reset 6px margin for the button.
@include rtl-prop(margin-right, margin-left, 0px);
}
}
}

._md-secondary-container {
@include rtl-prop(margin-right, margin-left, -12px);
md-checkbox {
margin-top: 0;
margin-bottom: 0;

&.md-icon-button {
@include rtl-prop(margin-right, margin-left, -6px);
&:last-child {
width: 3 * $baseline-grid;
@include rtl-prop(margin-right, margin-left, 0);
}
}
}

._md-secondary-container,
.md-secondary {
position: absolute;
top: 50%;
margin: 0;
@include rtl-prop(right, left, $list-item-padding-horizontal);
transform: translate3d(0, -50%, 0);
}
md-switch {
margin-top: 0;
margin-bottom: 0;

& > .md-button._md-secondary-container > .md-secondary {
@include rtl-prop(margin-left, margin-right, 0);
position: static;
@include rtl-prop(margin-right, margin-left, -6px);
}
}

& > p, & > ._md-list-item-inner > p {
flex: 1;
flex: 1 1 auto;
margin: 0;
}
}
Expand All @@ -351,7 +333,7 @@ md-list-item {
}

.md-list-item-text {
flex: 1;
flex: 1 1 auto;
margin: auto;
text-overflow: ellipsis;
overflow: hidden;
Expand Down Expand Up @@ -405,7 +387,7 @@ md-list-item {
align-self: flex-start;
}
.md-list-item-text {
flex: 1;
flex: 1 1 auto;
}
}
}
Expand Down
Loading