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

Commit

Permalink
fix(icons): support for ngDirectives using compile phase
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasBurleson authored and Robert Messerle committed Jun 8, 2015
1 parent 3f6b4af commit 9521a1e
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 38 deletions.
44 changes: 16 additions & 28 deletions src/components/icon/iconDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,36 +148,9 @@ function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
svgSrc : '@mdSvgSrc'
},
restrict: 'E',
transclude:true,
template: getTemplate,
link: postLink
link : postLink
};

function getTemplate(element, attr) {
var isEmptyAttr = function(key) { return angular.isDefined(attr[key]) ? attr[key].length == 0 : false },
hasAttrValue = function(key) { return attr[key] && attr[key].length > 0; },
attrValue = function(key) { return hasAttrValue(key) ? attr[key] : '' };

// If using the deprecated md-font-icon API
// If using ligature-based font-icons, transclude the ligature or NRCs

var tmplFontIcon = '<span class="md-font {{classNames}}" ng-class="fontIcon"></span>';
var tmplFontSet = '<span class="{{classNames}}" ng-transclude></span>';

var tmpl = hasAttrValue('mdSvgIcon') ? '' :
hasAttrValue('mdSvgSrc') ? '' :
isEmptyAttr('mdFontIcon') ? '' :
hasAttrValue('mdFontIcon') ? tmplFontIcon : tmplFontSet;

// If available, lookup the fontSet style and add to the list of classnames
// NOTE: Material Icons expects classnames like `.material-icons.md-48` instead of `.material-icons .md-48`

var names = (tmpl == tmplFontSet) ? $mdIcon.fontSet(attrValue('mdFontSet')) + ' ' : '';
names = (names + attrValue('class')).trim();

return $interpolate( tmpl )({ classNames: names });
}


/**
* Directive postLink
Expand All @@ -186,6 +159,8 @@ function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
function postLink(scope, element, attr) {
$mdTheming(element);

prepareForFontIcon();

// If using a font-icon, then the textual name of the icon itself
// provides the aria-label.

Expand Down Expand Up @@ -220,6 +195,7 @@ function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {

});
}

function parentsHaveText() {
var parent = element.parent();
if (parent.attr('aria-label') || parent.text()) {
Expand All @@ -230,5 +206,17 @@ function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
}
return false;
}

function prepareForFontIcon () {
if (!scope.svgIcon && !scope.svgSrc) {
if (scope.fontIcon) {
element.addClass('md-font');
element.addClass(scope.fontIcon);
} else {
element.addClass($mdIcon.fontSet(scope.fontSet));
}
}

}
}
}
76 changes: 66 additions & 10 deletions src/components/icon/iconDirective.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,67 +25,112 @@ describe('mdIcon directive', function() {

it('should render correct HTML with md-font-icon value as class', function() {
el = make( '<md-icon md-font-icon="android"></md-icon>');
expect(el.html()).toEqual('<span class="md-font android" ng-class="fontIcon"></span>');

expect(el.html()).toEqual('');
expect( clean(el.attr('class')) ).toEqual("md-font android");

});

it('should transclude class specifiers', function() {
el = make( '<md-icon md-font-icon="android" class="material-icons"></md-icon>');
expect(el.html()).toEqual('<span class="md-font material-icons android" ng-class="fontIcon"></span>');

expect(el.html()).toEqual('');
expect(el.hasClass('md-font')).toBe(true);
expect(el.hasClass('android')).toBe(true);
expect(el.hasClass('material-icons')).toBe(true);
});

it('should not render any inner content if the md-font-icon value is empty', function() {
el = make( '<md-icon md-font-icon=""></md-icon>' );
expect(el.html()).toEqual('');
});

it('',function() {
el = make('\
<md-icon \
md-font-icon="{{ font.name }}" \
aria-label="{{ font.name + font.size }}" \
class="step" > \
</md-icon> \
');

$scope.$apply(function(){
$scope.font = {
name: 'icon-home',
color: "#777",
size: 48
};
});

expect(el.attr('md-font-icon')).toBe($scope.font.name);
expect(el.hasClass('step')).toBe(true);
expect(el.hasClass('material-icons')).toBe(true);
expect(el.attr('aria-label')).toBe($scope.font.name + $scope.font.size);
expect(el.attr('role')).toBe('img');
})

});

describe('using font-icons with ligatures: md-font-set=""', function() {

it('should render correct HTML with ligatures', function() {
el = make( '<md-icon class="md-48">face</md-icon>');
expect(el.html()).toEqual('<span class="material-icons md-48" ng-transclude=""><span class="ng-scope">face</span></span>');

expect(el.text()).toEqual('face');
expect(el.hasClass('material-icons')).toBeTruthy();
expect(el.hasClass('md-48')).toBeTruthy();
});

it('should render correctly using a md-font-set alias', function() {
$mdIconProvider.fontSet('fa', 'fontawesome');

el = make( '<md-icon md-font-set="fa">email</md-icon>');
expect(el.html()).toEqual('<span class="fontawesome" ng-transclude=""><span class="ng-scope">email</span></span>');

expect(el.text()).toEqual('email');
expect( clean(el.attr('class')) ).toEqual("fontawesome");
});

it('should render correctly using md-font-set value as class', function() {

el = make( '<md-icon md-font-set="fontawesome">email</md-icon>');
expect(el.html()).toEqual('<span class="fontawesome" ng-transclude=""><span class="ng-scope">email</span></span>');

expect(el.text()).toEqual('email');
expect( clean(el.attr('class')) ).toEqual("fontawesome");
});
});

describe('using font-icons with classnames', function() {

it('should render with icon classname', function() {
el = make( '<md-icon class="custom-cake"></md-icon>');
expect(el.html()).toEqual('<span class="material-icons custom-cake" ng-transclude=""></span>');

expect(el.text()).toEqual('');
expect(el.hasClass('material-icons')).toBeTruthy();
expect(el.hasClass('custom-cake')).toBeTruthy();
});

it('should support clearing default fontset', function() {
$mdIconProvider.defaultFontSet('');

el = make( '<md-icon class="custom-cake"></md-icon>');
expect(el.html()).toEqual('<span class="custom-cake" ng-transclude=""></span>');
expect( clean(el.attr('class')) ).toEqual("custom-cake");

el = make( '<md-icon class="custom-cake">apple</md-icon>');
expect(el.html()).toEqual('<span class="custom-cake" ng-transclude=""><span class="ng-scope">apple</span></span>');
expect(el.text()).toEqual('apple');
expect( clean(el.attr('class')) ).toEqual("custom-cake");

});

it('should support clearing an invalid font alias', function() {

el = make( '<md-icon md-font-set="none" class="custom-cake"></md-icon>');
expect(el.html()).toEqual('<span class="none custom-cake" ng-transclude=""></span>');
expect(el.hasClass('none')).toBeTruthy();
expect(el.hasClass('custom-cake')).toBeTruthy();

el = make( '<md-icon md-font-set="none" class="custom-cake">apple</md-icon>');
expect(el.html()).toEqual('<span class="none custom-cake" ng-transclude=""><span class="ng-scope">apple</span></span>');
expect(el.text()).toEqual('apple');
expect(el.hasClass('none')).toBeTruthy();
expect(el.hasClass('custom-cake')).toBeTruthy();

});
});
Expand Down Expand Up @@ -224,5 +269,16 @@ describe('mdIcon directive', function() {
return el;
}

/**
* Utility to remove extra attributes to the specs are easy to compare
*/
function clean(style) {
return style
.replace(/ng-scope|ng-isolate-scope|md-default-theme/gi,'')
.replace(/\s\s+/g,' ')
.replace(/\s+\"/g,'"')
.trim();
}


});

0 comments on commit 9521a1e

Please sign in to comment.