From b7d09d7e247d3055e53f438b5528ce9e36ecbc66 Mon Sep 17 00:00:00 2001 From: Tony Childs Date: Mon, 9 Feb 2015 07:36:40 -0600 Subject: [PATCH] feat(icon): implemented md-icon for font-faces and svgs Closes #1438. --- docs/app/fonts/icomoon.eot | Bin 0 -> 3908 bytes docs/app/fonts/icomoon.svg | 16 ++ docs/app/fonts/icomoon.ttf | Bin 0 -> 3744 bytes docs/app/fonts/icomoon.woff | Bin 0 -> 3820 bytes docs/app/img/icons/addShoppingCart.svg | 1 + docs/app/img/icons/android.svg | 1 + docs/app/img/icons/cake.svg | 1 + .../img/icons/ic_insert_drive_file_24px.svg | 27 +- docs/app/img/icons/sets/core-icons.svg | 26 ++ docs/app/img/icons/sets/social-icons.svg | 26 ++ src/components/icon/demoFontIcons/index.html | 39 +++ src/components/icon/demoFontIcons/script.js | 15 ++ src/components/icon/demoFontIcons/style.css | 127 +++++++++ .../icon/demoSvgIconSets/assets/cake.svg | 1 + .../demoSvgIconSets/assets/core-icons.svg | 26 ++ .../demoSvgIconSets/assets/social-icons.svg | 26 ++ .../icon/demoSvgIconSets/index.html | 13 + src/components/icon/demoSvgIconSets/script.js | 13 + src/components/icon/demoSvgIconSets/style.css | 19 ++ .../img/icons/addShoppingCart.svg | 1 + .../demoSvgIconsFromURL/img/icons/android.svg | 1 + .../demoSvgIconsFromURL/img/icons/cake.svg | 1 + .../icon/demoSvgIconsFromURL/index.html | 16 ++ .../icon/demoSvgIconsFromURL/script.js | 5 + .../icon/demoSvgIconsFromURL/style.css | 37 +++ src/components/icon/icon.js | 247 +++++++++++++++++- src/components/icon/icon.scss | 59 +++-- src/components/icon/icon.spec.js | 112 ++++++++ 28 files changed, 800 insertions(+), 56 deletions(-) create mode 100755 docs/app/fonts/icomoon.eot create mode 100755 docs/app/fonts/icomoon.svg create mode 100755 docs/app/fonts/icomoon.ttf create mode 100755 docs/app/fonts/icomoon.woff create mode 100644 docs/app/img/icons/addShoppingCart.svg create mode 100644 docs/app/img/icons/android.svg create mode 100644 docs/app/img/icons/cake.svg create mode 100644 docs/app/img/icons/sets/core-icons.svg create mode 100644 docs/app/img/icons/sets/social-icons.svg create mode 100644 src/components/icon/demoFontIcons/index.html create mode 100644 src/components/icon/demoFontIcons/script.js create mode 100644 src/components/icon/demoFontIcons/style.css create mode 100644 src/components/icon/demoSvgIconSets/assets/cake.svg create mode 100644 src/components/icon/demoSvgIconSets/assets/core-icons.svg create mode 100644 src/components/icon/demoSvgIconSets/assets/social-icons.svg create mode 100644 src/components/icon/demoSvgIconSets/index.html create mode 100644 src/components/icon/demoSvgIconSets/script.js create mode 100644 src/components/icon/demoSvgIconSets/style.css create mode 100644 src/components/icon/demoSvgIconsFromURL/img/icons/addShoppingCart.svg create mode 100644 src/components/icon/demoSvgIconsFromURL/img/icons/android.svg create mode 100644 src/components/icon/demoSvgIconsFromURL/img/icons/cake.svg create mode 100644 src/components/icon/demoSvgIconsFromURL/index.html create mode 100644 src/components/icon/demoSvgIconsFromURL/script.js create mode 100644 src/components/icon/demoSvgIconsFromURL/style.css diff --git a/docs/app/fonts/icomoon.eot b/docs/app/fonts/icomoon.eot new file mode 100755 index 0000000000000000000000000000000000000000..0dabedb2e47d6eed3ee2c25fb10432d439ee85db GIT binary patch literal 3908 zcmahMTWl29^`5yicOE-CJNugP8t;3(Ya4d$-Syh$;k9`f6U@Wd=Gm0s2QdVUDVPE& zRV_uS)F2cT(pNqriqxu+T0Yt;i4t15Qj|)hkx=Oe?N_8eB#4@{idt1_uzT*zI<}!n z?>z1~=bm%!IcM%YXYLjsA=eE;fCyw|19BBOWyj!3I_GuUh4WYFqho{^tk~3^GKHl1XxooFt><3{otz4=HEJS>)wB2~s2l(&q3!Dvd-wp@+;8O4@c0x0ZYX z`5mO(!sp2N)adD7j=l8~GBqGRGdX(pH1;OqSFu+nPhNcb^>?jT5&s?`+Mkad9i8x` zzB@pOehJ4rjv>MOp89*le}Q=B*woC0gi0jD?;+lFa(aAJ{kt3@#EU4grbaKECKh}f z@jAp4r$(oa?vMQFBgDIKj=s~=XJ^n(Y{o1fCsgE?pg!UI!f%oCqT9oVqzo$J%NwBC zD_bui4_={j3v;BG;)8>W!RLGl{&GGXpD~2<^3f0x$q}bFk%H5c#9zsMa(~zTvk$)Y z;FX1k3kx`k(vMML;ZOCVEm?0`FNePop04S0m{+`j0P65Lv$+GfcskcQrY+g`#WY69 z!kkFZtCQppNvdJG13Ft2MM0DhTtN z+gMZVQhK0_^SHM&n~mCBG!9`IQic!?#e{OHDpcAFLfW4yAW%g@3as1gUMReg!F7 zKpC!fsZg|u=?K^~v_A;(Y}xv94ABvMaW32Dsv%VC@T-_;AV2RhhvashYcD|7NGLj_6erL=}Nj% zu9U;&FwCa9_m*^nWp-`bwkyL1DtoR>u7@j3h9et}@5<+Qar4~%`fTqk-XE-;+_x#v zupzcc-~P>5h2=NzZ?oGXkXSCkIp*iM&}=W7O_p*OBR1KAMeP{DYSP)Bt%R&_(CWw) zXfDg_7`4%tY&w}@auv$!Xi-kb05>!y2HfeG8#tWA4ewv(3?{8II^5pT$x`W5HW$To zRhC`dlADvVOva3sJsm1Xrlk&zOCcJnwg&Dg|F@#{7TpQ zuKeoA*1G-T$~ww%l8hpU)J z1%VzCL;-Io3SU2z-@PFX!n23+gWVZ`%HIBo(Y{>gX6xMMuBXzeT(qt)P&~dT39GJY?XSD%P-4Lppmh5JNj&^V@VZGOdUO_3cpo#ac<}9%8lim zV;PnY)PS~>8?kcnisg3=l;Xw+agm){RbF8gBJ*3Q(?5 zrZTROwk)m=f370gX~0c^E6$l!W;{0CP!2nR!5Mo1_qxPO9v?xjD5Q~sMW@a2tYdLa zHoCSrY4 zzqP60A3SlXdSd?H|Mz_*92O+@f-Qx&7Oc^ z2sC7QEkorY!%y_FFxt>$ghjvJ62ltjDQ-WrF;bsGW2l_5HB^21SzuVfgJyK7tM~GYS2nHP9S=q&tmFJ^gFx|f3WDjk23psA=itCZZxcLx59x)S zPp^YII0y&kZ+#N+c@*XiN~#v{Z~n>McVFscibw^;6M*xd-0_B~V%W0g@mRvu6Ki@j z*))NsviiEI=PUN8v5F<~s<*MpDoq`1)6;of6f+4c*Zl+(+nY5R6vd9jl9-Qb|FiVU z`3q0^HvE%#L|y^NorkYYF7*p@n6c&%SDe3bK7ex0e>>5fzkGbxH1R>FX^Q~w@n;#U z`{NJFNqn4W_+KA`*Wr&sLbya*Bz}zI8a23vIg>Z8;?ZW1o3(j?|25QL0pb1{OcBo1 zU=iWHHCVz!no)xpkx8irYgnnr`N=@!9&w#6?CNx3SEmcRI$hY+>B0 + + +Generated by IcoMoon + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/app/fonts/icomoon.ttf b/docs/app/fonts/icomoon.ttf new file mode 100755 index 0000000000000000000000000000000000000000..e89d526fe0cb61a8256e6afe50c5faad6346973a GIT binary patch literal 3744 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 MOXvR_2mX8eH!)}*O8@`> literal 0 HcmV?d00001 diff --git a/docs/app/fonts/icomoon.woff b/docs/app/fonts/icomoon.woff new file mode 100755 index 0000000000000000000000000000000000000000..4a90296cc6cd995946d821ee7e30b155df755cfc GIT binary patch literal 3820 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 literal 0 HcmV?d00001 diff --git a/docs/app/img/icons/addShoppingCart.svg b/docs/app/img/icons/addShoppingCart.svg new file mode 100644 index 00000000000..b374b9019d9 --- /dev/null +++ b/docs/app/img/icons/addShoppingCart.svg @@ -0,0 +1 @@ + diff --git a/docs/app/img/icons/android.svg b/docs/app/img/icons/android.svg new file mode 100644 index 00000000000..306b4e1a4f6 --- /dev/null +++ b/docs/app/img/icons/android.svg @@ -0,0 +1 @@ + diff --git a/docs/app/img/icons/cake.svg b/docs/app/img/icons/cake.svg new file mode 100644 index 00000000000..512fae048aa --- /dev/null +++ b/docs/app/img/icons/cake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/app/img/icons/ic_insert_drive_file_24px.svg b/docs/app/img/icons/ic_insert_drive_file_24px.svg index 29597708d95..4c074e00b27 100644 --- a/docs/app/img/icons/ic_insert_drive_file_24px.svg +++ b/docs/app/img/icons/ic_insert_drive_file_24px.svg @@ -1,25 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/docs/app/img/icons/sets/core-icons.svg b/docs/app/img/icons/sets/core-icons.svg new file mode 100644 index 00000000000..5f52b2d8100 --- /dev/null +++ b/docs/app/img/icons/sets/core-icons.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/app/img/icons/sets/social-icons.svg b/docs/app/img/icons/sets/social-icons.svg new file mode 100644 index 00000000000..3b39255310d --- /dev/null +++ b/docs/app/img/icons/sets/social-icons.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/icon/demoFontIcons/index.html b/src/components/icon/demoFontIcons/index.html new file mode 100644 index 00000000000..640dcb43096 --- /dev/null +++ b/src/components/icon/demoFontIcons/index.html @@ -0,0 +1,39 @@ +
+ + +
+
+ + +
+
+ {{ size }}px +
+
+ +
+ + + diff --git a/src/components/icon/demoFontIcons/script.js b/src/components/icon/demoFontIcons/script.js new file mode 100644 index 00000000000..4ead6d51af9 --- /dev/null +++ b/src/components/icon/demoFontIcons/script.js @@ -0,0 +1,15 @@ + +angular.module('appDemoFontIcons', ['ngMaterial']) +.controller('DemoCtrl', function( $scope ) { + var iconData = [ + {name: 'icon-home' , color: "#777" }, + {name: 'icon-user-plus' , color: "rgb(89, 226, 168)" }, + {name: 'icon-google-plus2', color: "#A00" }, + {name: 'icon-youtube4' , color:"#00A" }, + {name: 'icon-settings' , color:"black" } + ]; + + $scope.sizes = [12, 21, 36, 48]; + $scope.fonts = [].concat(iconData); + +}); diff --git a/src/components/icon/demoFontIcons/style.css b/src/components/icon/demoFontIcons/style.css new file mode 100644 index 00000000000..2eda125dc2f --- /dev/null +++ b/src/components/icon/demoFontIcons/style.css @@ -0,0 +1,127 @@ + +.appDemoFontIcons { + padding:25px; + width: 100%; +} + + /* Bootstrap Overrides */ + [class^="icon-"]:before, + [class*=" icon-"]:before { + font-family:"icomoon"; + display:inline-block; + vertical-align:middle; + line-height:1; + font-weight:normal; + font-style:normal; + speak:none; + text-decoration:inherit; + text-transform:none; + text-rendering:optimizeLegibility; + -webkit-font-smoothing:antialiased; + -moz-osx-font-smoothing:grayscale; + } + + + .icon-home:before { + content: "\e900"; + } + + .icon-clock:before { + content: "\e94e"; + } + + .icon-user-plus:before { + content: "\e973"; + } + + .icon-google-plus2:before { + content: "\ea89"; + } + + .icon-youtube4:before { + content: "\ea9a"; + } + + .icon-settings:before { + content: "\e600"; + } + + md-progress-circular { + margin-bottom:20px; + } +/* OLD STYLES */ + +header { + overflow: hidden; +} + +header h1 { + color: #888; + font-size: 36px; + font-weight: 300; +} + +.container { + margin: 0 auto; + max-width: 1200px; + min-width: 960px; + padding: 40px 40px; + font: 14px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +.glyph { + border-bottom: 1px dotted #ccc; + padding: 10px 0 20px; + margin-bottom: 20px; +} + +.preview-scale, +.preview-glyphs { + display: flex; + flex-direction: row; +} + +.preview-scale { + color: #888; + font-size: 12px; + margin-top: 24px; +} + +.step { + flex-grow: 1; + line-height: 0.5; +} + +.usage { margin-top: 10px; } +.usage input { + font-family: monospace; + text-align: center; +} +.usage .point { width: 150px; } +.usage .class { width: 250px; } + +md-radio-button { + display: inline-block; +} + +.loading { + background-color: black; + filter: alpha(opacity=40); + height: 100%; + left: 0; + opacity: .40; + position: fixed; + top: 0; + width: 100%; + z-index: 90; +} + +.loading md-progress-circular { + left: 50%; + position: fixed; + top: 48%; + z-index: 100; +} + + + diff --git a/src/components/icon/demoSvgIconSets/assets/cake.svg b/src/components/icon/demoSvgIconSets/assets/cake.svg new file mode 100644 index 00000000000..512fae048aa --- /dev/null +++ b/src/components/icon/demoSvgIconSets/assets/cake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/icon/demoSvgIconSets/assets/core-icons.svg b/src/components/icon/demoSvgIconSets/assets/core-icons.svg new file mode 100644 index 00000000000..5f52b2d8100 --- /dev/null +++ b/src/components/icon/demoSvgIconSets/assets/core-icons.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/icon/demoSvgIconSets/assets/social-icons.svg b/src/components/icon/demoSvgIconSets/assets/social-icons.svg new file mode 100644 index 00000000000..3b39255310d --- /dev/null +++ b/src/components/icon/demoSvgIconSets/assets/social-icons.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/icon/demoSvgIconSets/index.html b/src/components/icon/demoSvgIconSets/index.html new file mode 100644 index 00000000000..5aa3ce74088 --- /dev/null +++ b/src/components/icon/demoSvgIconSets/index.html @@ -0,0 +1,13 @@ +
+ +

Display an icon from a pre-registered set of icons:

+ +

+ + + +

+ +
+ + diff --git a/src/components/icon/demoSvgIconSets/script.js b/src/components/icon/demoSvgIconSets/script.js new file mode 100644 index 00000000000..efde60b0516 --- /dev/null +++ b/src/components/icon/demoSvgIconSets/script.js @@ -0,0 +1,13 @@ + +angular.module('appSvgIconSets', ['ngMaterial']) + .controller('DemoCtrl', function($scope) { + $scope.sizes = [12, 14, 16, 18, 21, 24, 36, 48, 60, 72]; + $scope.limit = 10; + $scope.color = '#00bcd4'; + $scope.iconType = 'Font'; + $scope.loading = false; + }) + .config(function($mdIconProvider) { + $mdIconProvider.iconSet('social', 'img/icons/sets/social-icons.svg') + .defaultIconSet('img/icons/sets/core-icons.svg'); + }); diff --git a/src/components/icon/demoSvgIconSets/style.css b/src/components/icon/demoSvgIconSets/style.css new file mode 100644 index 00000000000..40d0c704ea1 --- /dev/null +++ b/src/components/icon/demoSvgIconSets/style.css @@ -0,0 +1,19 @@ + +md-progress-circular { + margin-bottom:20px; +} + +md-icon { + margin: 20px; + margin-top:0px; + width: 24px; + height: 24px; +} + +.demo-content { + min-height: 210px; +} + +.appSvgIconSets { + padding:25px; +} diff --git a/src/components/icon/demoSvgIconsFromURL/img/icons/addShoppingCart.svg b/src/components/icon/demoSvgIconsFromURL/img/icons/addShoppingCart.svg new file mode 100644 index 00000000000..b374b9019d9 --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/img/icons/addShoppingCart.svg @@ -0,0 +1 @@ + diff --git a/src/components/icon/demoSvgIconsFromURL/img/icons/android.svg b/src/components/icon/demoSvgIconsFromURL/img/icons/android.svg new file mode 100644 index 00000000000..306b4e1a4f6 --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/img/icons/android.svg @@ -0,0 +1 @@ + diff --git a/src/components/icon/demoSvgIconsFromURL/img/icons/cake.svg b/src/components/icon/demoSvgIconsFromURL/img/icons/cake.svg new file mode 100644 index 00000000000..512fae048aa --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/img/icons/cake.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/icon/demoSvgIconsFromURL/index.html b/src/components/icon/demoSvgIconsFromURL/index.html new file mode 100644 index 00000000000..d1c7c87b8c3 --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/index.html @@ -0,0 +1,16 @@ +
+

The simplest way to display a single SVG icon is by referencing it by URL:

+

+ + +

+ +

Style the icon size and color with CSS:

+

+ + + +

+
+ diff --git a/src/components/icon/demoSvgIconsFromURL/script.js b/src/components/icon/demoSvgIconsFromURL/script.js new file mode 100644 index 00000000000..37b3ab9ef10 --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/script.js @@ -0,0 +1,5 @@ + +angular.module('appDemoSvgIcons', ['ngMaterial']) +.controller('DemoCtrl', function( $scope ) { + +}); diff --git a/src/components/icon/demoSvgIconsFromURL/style.css b/src/components/icon/demoSvgIconsFromURL/style.css new file mode 100644 index 00000000000..a491599e2c2 --- /dev/null +++ b/src/components/icon/demoSvgIconsFromURL/style.css @@ -0,0 +1,37 @@ + + + + +md-progress-circular { + margin-bottom:20px; +} + +md-icon { + margin: 20px; + margin-top:0px; + width: 24px; + height: 24px; +} + + + +.demo-content { + min-height: 210px; +} + + +.appDemoSvgIcons { + padding:25px; +} + +.s24 { + width: 24px;height: 24px; +} + +.s36 { + width: 36px;height: 36px; +} + +.s48 { + width: 48px;height: 48px; +} diff --git a/src/components/icon/icon.js b/src/components/icon/icon.js index e43b8d1c55b..4e68dcd4365 100644 --- a/src/components/icon/icon.js +++ b/src/components/icon/icon.js @@ -8,9 +8,10 @@ * Icon */ angular.module('material.components.icon', [ - 'material.core' -]) - .directive('mdIcon', mdIconDirective); + 'material.core' + ]) + .directive('mdIcon', mdIconDirective) + .provider('$mdIcon', MdIconProvider); /* * @ngdoc directive @@ -20,25 +21,243 @@ angular.module('material.components.icon', [ * @restrict E * * @description - * The `` directive is an element useful for SVG icons + * The `` directive is an element useful for showing an icon * * @usage * - * - * + * + * + * * - * */ -function mdIconDirective() { +function mdIconDirective($mdIcon, $mdAria, $log) { return { + scope: { + fontIcon: '@', + svgIcon: '@', + svgSrc: '@' + }, restrict: 'E', - template: '', - compile: function(element, attr) { - var object = angular.element(element[0].children[0]); - if(angular.isDefined(attr.icon)) { - object.attr('data', attr.icon); - } + template: getTemplate, + link: postLink + }; + + function getTemplate(element, attr) { + return attr.fontIcon ? '' : ''; + } + + /** + * Directive postLink + * Supports embeded SVGs, font-icons, & external SVGs + */ + function postLink(scope, element, attr) { + var ariaLabel = attr.alt || scope.fontIcon || scope.svgIcon; + var attrName = attr.$normalize(attr.$attr.svgIcon || attr.$attr.svgSrc || ''); + + if (attr.alt == '') { + // Hide from the accessibility layer. + $mdAria.expect(element, 'aria-hidden', 'true'); + } else { + $mdAria.expect(element, 'aria-label', ariaLabel); + $mdAria.expect(element, 'role', 'img'); + } + + if (attrName) { + // Use either pre-configured SVG or URL source, respectively. + attr.$observe(attrName, function(attrVal) { + + element.empty(); // TODO: possible race condition with promise callback below? + if (attrVal) { + $mdIcon(attrVal).then(function(svg) { + element.append(svg); + }); + } + + }); + } + } +} + +/** + * @ngdoc service + * @name $mdIconProvider + * @module material.components.icon + * + * @description + * `$mdIconProvider` is a factory that provides the $mdIcon service based on a + * given configuruation. + * + * + * var app = angular.module('app', ['ngMaterial']); + * app.config(function($mdIconProvider) { + * $mdIconProvider.iconSet('social', 'my/app/social.svg') + * $mdIconProvider.defaultIconSet('my/app/icons.svg') + * $mdIconProvider.icon('android', 'my/app/android.svg') + * $mdIconProvider.icon('work:chair', 'my/app/chair.svg') + * }); + * + */ +var config = { + defaultIconSize: 24 +}; + +function ConfigurationItem(url, iconSize) { + this.url = url; + this.iconSize = iconSize || config.defaultIconSize; +} + +function MdIconProvider() { } + +MdIconProvider.prototype = { + icon : function icon(id, url, iconSize) { + if ( id.indexOf(':') == -1 ) id = '$default:' + id; + + config[id] = new ConfigurationItem(url, iconSize ); + return this; + }, + + iconSet : function iconSet(id, url, iconSize) { + config[id] = new ConfigurationItem(url, iconSize ); + return this; + }, + + defaultIconSet : function defaultIconSet(url, iconSize) { + var setName = '$default'; + + if ( !config[setName] ) { + config[setName] = new ConfigurationItem(url, iconSize ); } + return this; + }, + + defaultIconSize : function defaultIconSize(iconSize) { + config.defaultIconSize = iconSize; + return this; + }, + + $get : ['$http', '$q', '$log', '$templateCache', function($http, $q, $log, $templateCache) { + return new MdIconService(config, $http, $q, $log, $templateCache); + }] +}; + + +/** + * @ngdoc service + * @name $mdIcon + * @module material.components.icon + * + * @description + * `$mdIcon` is a service used to retrieve SVG icons configured via $mdIconProvider + * or a URL. The service returns a promise which resolves to a DOM element. + * + * + * function SomeDirective($mdIcon) { + * $mdIcon('android').then(function(android) { + * element.append(android); + * }); + * $mdIcon('work:chair').then(function(chair) { + * element.append(chair); + * }); + * }; + * + */ +function MdIconService(config, $http, $q, $log, $templateCache) { + var iconCache = {}; + var urlRegex = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/i; + + return function getIcon(id) { + + id = id || ''; + if ( urlRegex.test(id) ) return loadByURL(id); // Get SVG from URL + if ( id.indexOf(':') == -1 ) id = '$default:' + id; + if ( iconCache[id] ) return $q.when(iconCache[id].cloneNode(true)); + + return loadByID(id) + .catch(loadFromIconSet) + .catch(announceNotFound) + .then(function(icon) { + icon = prepareAndStyle(icon.element, icon.config.iconSize); + iconCache[id] = icon; + return icon; + }); }; + + /** + * + */ + function loadByID(id) { + var iconConfig = config[id]; + + return !iconConfig ? $q.reject(id) : loadByURL(iconConfig.url).then(function(icon) { + return new Icon(icon, iconConfig); + }); + } + + /** + * + */ + function loadFromIconSet(id) { + var setName = id.substring(0, id.lastIndexOf(':')) || '$default'; + var iconSetConfig = config[setName]; + + return !iconSetConfig ? $q.reject(id) : loadByURL(iconSetConfig.url).then(extractFromSet); + + function extractFromSet(set) { + var iconName = id.slice(id.lastIndexOf(':') + 1); + var icon = set.querySelector('#' + iconName); + return !icon ? $q.reject(id) : new Icon(icon, iconSetConfig); + } + } + + /** + * + */ + function announceNotFound(id) { + var msg = 'icon ' + id + ' not found'; + $log.warn(msg); + throw new Error(msg); + } + + /** + * + */ + function prepareAndStyle(svg, iconSize) { + svg = angular.element(svg); + + return svg.attr({ + 'fit' : '', + 'height': '100%', + 'width' : '100%', + 'preserveAspectRatio': 'xMidYMid meet', + 'viewBox' : svg.attr('viewBox') || ('0 0 ' + iconSize + ' ' + iconSize) + }) + .css( { + 'pointer-events' : 'none', + 'display' : 'block' + }); + } + + /** + * + */ + function loadByURL(url) { + return $http + .get(url, { cache: $templateCache }) + .then(function(response) { + return angular.element(response.data)[0]; + }); + } + + /** + * + */ + function Icon(el, config) { + if (el.tagName != 'svg') { + el = angular.element('').append(el)[0]; + } + this.element = el; + this.config = config; + } + } })(); diff --git a/src/components/icon/icon.scss b/src/components/icon/icon.scss index 9263645486c..1eb45ac204d 100644 --- a/src/components/icon/icon.scss +++ b/src/components/icon/icon.scss @@ -1,24 +1,45 @@ - md-icon { margin: auto; - padding: 0; - display: inline-block; - margin-top: 5px; background-repeat: no-repeat no-repeat; - pointer-events: none; - display: flex; - z-index: 0; - - object.md-icon { - display: inline-block; - } -} -svg, object { - fill: currentColor; - color: currentColor; + display: inline-block; + vertical-align: middle; + fill: currentcolor; + height: 3 * $baseline-grid; + width: 3 * $baseline-grid; } -md-class-icon { - // display: block; - // margin: 0 auto; -} +// +//@font-face { +// font-family:"material"; +// src:url("/dist/material-font/material.eot"); +// font-weight:normal; +// font-style:normal; +//} +// +//@font-face { +// font-family:"material"; +// src:url("/dist/material-font/material.eot"); +// src:url("/dist/material-font/material.eot?#iefix") format("embedded-opentype"), +// url("/dist/material-font/material.woff") format("woff"), +// url("/dist/material-font/material.ttf") format("truetype"), +// url("/dist/material-font/material.svg?#material") format("svg"); +// font-weight:normal; +// font-style:normal; +//} +// +///* Bootstrap Overrides */ +//[class^="icon-"]:before, +//[class*=" icon-"]:before { +// font-family:"material"; +// display:inline-block; +// vertical-align:middle; +// line-height:1; +// font-weight:normal; +// font-style:normal; +// speak:none; +// text-decoration:inherit; +// text-transform:none; +// text-rendering:optimizeLegibility; +// -webkit-font-smoothing:antialiased; +// -moz-osx-font-smoothing:grayscale; +//} diff --git a/src/components/icon/icon.spec.js b/src/components/icon/icon.spec.js index 9de75b49c70..f9a661892ef 100644 --- a/src/components/icon/icon.spec.js +++ b/src/components/icon/icon.spec.js @@ -1,2 +1,114 @@ describe('mdIcon directive', function() { + var provider, el; + + beforeEach(module('material.components.icon',function($mdIconProvider){ + provider = $mdIconProvider; + provider + .icon('android' , 'android.svg') + .iconSet('social', 'social.svg' ) + .defaultIconSet('core.svg'); + })); + + beforeEach(inject(function($templateCache){ + + $templateCache.put('android.svg', ''); + $templateCache.put('social.svg' , ''); + $templateCache.put('core.svg' , ''); + + })); + + + describe('using font-icon=""', function() { + it('should render correct HTML with font-icon value as class', function() { + el = make( ''); + expect(el.html()).toEqual(''); + }); + }); + + + describe('using svg-icon=""', function() { + + it('should append configured SVG single icon', function() { + el = make(''); + var expected = updateDefaults(''); + expect(el.html()).toEqual(expected); + }); + + it('should append configured SVG icon from named group', function() { + el = make(''); + var expected = updateDefaults(''); + expect(el.html()).toEqual(expected); + }); + + it('should append configured SVG icon from default group', function() { + el = make(''); + var expected = updateDefaults(''); + expect(el.html()).toEqual(expected); + }); + + }); + + + describe('using svg-src=""', function() { + + it('should append SVG from URL to md-icon', function() { + el = make(''); + expect(el.html()).toEqual(''); + }); + + }); + + describe('with ARIA support', function() { + + it('should apply aria-hidden="true" when alt is empty string', function() { + el = make(''); + expect(el.attr('aria-hidden')).toEqual('true'); + }); + + it('should apply alt value to aria-label when set', function() { + el = make(''); + expect(el.attr('aria-label')).toEqual('my android icon'); + }); + + it('should apply font-icon value to aria-label when alt not set', function() { + el = make(''); + expect(el.attr('aria-label')).toEqual('android'); + }); + + it('should apply svg-icon value to aria-label when alt not set', function() { + el = make(''); + expect(el.attr('aria-label')).toEqual('android'); + }); + + }); + + + function make(html) { + var el; + inject(function($compile, $rootScope) { + el = $compile(html)($rootScope); + $rootScope.$digest(); + }); + + return el; + } + + function updateDefaults(svg) { + svg = angular.element(svg); + + svg.attr({ + 'fit' : '', + 'height': '100%', + 'width' : '100%', + 'preserveAspectRatio': 'xMidYMid meet', + 'viewBox' : svg.attr('viewBox') || '0 0 24 24' + }) + .css( { + 'pointer-events' : 'none', + 'display' : 'block' + }); + + return svg[0].outerHTML; + } + });