commonroutesApp/www/lib/angular-material/modules/closure/icon/icon.js
www/lib/angular-material/modules/closure/icon/icon.jsRaw
1/*!
2 * Angular Material Design
3 * https://github.com/angular/material
4 * @license MIT
5 * v1.1.1
6 */
7goog.provide('ngmaterial.components.icon');
8goog.require('ngmaterial.core');
9/**
10 * @ngdoc module
11 * @name material.components.icon
12 * @description
13 * Icon
14 */
15angular.module('material.components.icon', ['material.core']);
16
17angular
18 .module('material.components.icon')
19 .directive('mdIcon', ['$mdIcon', '$mdTheming', '$mdAria', '$sce', mdIconDirective]);
20
21/**
22 * @ngdoc directive
23 * @name mdIcon
24 * @module material.components.icon
25 *
26 * @restrict E
27 *
28 * @description
29 * The `md-icon` directive makes it easier to use vector-based icons in your app (as opposed to
30 * raster-based icons types like PNG). The directive supports both icon fonts and SVG icons.
31 *
32 * Icons should be considered view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`
33 * inside a `md-button` to add hover and click features.
34 *
35 * ### Icon fonts
36 * Icon fonts are a technique in which you use a font where the glyphs in the font are
37 * your icons instead of text. Benefits include a straightforward way to bundle everything into a
38 * single HTTP request, simple scaling, easy color changing, and more.
39 *
40 * `md-icon` lets you consume an icon font by letting you reference specific icons in that font
41 * by name rather than character code.
42 *
43 * ### SVG
44 * For SVGs, the problem with using `<img>` or a CSS `background-image` is that you can't take
45 * advantage of some SVG features, such as styling specific parts of the icon with CSS or SVG
46 * animation.
47 *
48 * `md-icon` makes it easier to use SVG icons by *inlining* the SVG into an `<svg>` element in the
49 * document. The most straightforward way of referencing an SVG icon is via URL, just like a
50 * traditional `<img>`. `$mdIconProvider`, as a convenience, lets you _name_ an icon so you can
51 * reference it by name instead of URL throughout your templates.
52 *
53 * Additionally, you may not want to make separate HTTP requests for every icon, so you can bundle
54 * your SVG icons together and pre-load them with $mdIconProvider as an icon set. An icon set can
55 * also be given a name, which acts as a namespace for individual icons, so you can reference them
56 * like `"social:cake"`.
57 *
58 * When using SVGs, both external SVGs (via URLs) or sets of SVGs [from icon sets] can be
59 * easily loaded and used.When use font-icons, developers must following three (3) simple steps:
60 *
61 * <ol>
62 * <li>Load the font library. e.g.<br/>
63 * `<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
64 * rel="stylesheet">`
65 * </li>
66 * <li>
67 * Use either (a) font-icon class names or (b) font ligatures to render the font glyph by using
68 * its textual name
69 * </li>
70 * <li>
71 * Use `<md-icon md-font-icon="classname" />` or <br/>
72 * use `<md-icon md-font-set="font library classname or alias"> textual_name </md-icon>` or <br/>
73 * use `<md-icon md-font-set="font library classname or alias"> numerical_character_reference </md-icon>`
74 * </li>
75 * </ol>
76 *
77 * Full details for these steps can be found:
78 *
79 * <ul>
80 * <li>http://google.github.io/material-design-icons/</li>
81 * <li>http://google.github.io/material-design-icons/#icon-font-for-the-web</li>
82 * </ul>
83 *
84 * The Material Design icon style <code>.material-icons</code> and the icon font references are published in
85 * Material Design Icons:
86 *
87 * <ul>
88 * <li>https://design.google.com/icons/</li>
89 * <li>https://design.google.com/icons/#ic_accessibility</li>
90 * </ul>
91 *
92 * <h2 id="material_design_icons">Material Design Icons</h2>
93 * Using the Material Design Icon-Selector, developers can easily and quickly search for a Material Design font-icon and
94 * determine its textual name and character reference code. Click on any icon to see the slide-up information
95 * panel with details regarding a SVG download or information on the font-icon usage.
96 *
97 * <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank" style="border-bottom:none;">
98 * <img src="https://cloud.githubusercontent.com/assets/210413/7902490/fe8dd14c-0780-11e5-98fb-c821cc6475e6.png"
99 * aria-label="Material Design Icon-Selector" style="max-width:75%;padding-left:10%">
100 * </a>
101 *
102 * <span class="image_caption">
103 * Click on the image above to link to the
104 * <a href="https://design.google.com/icons/#ic_accessibility" target="_blank">Material Design Icon-Selector</a>.
105 * </span>
106 *
107 * @param {string} md-font-icon String name of CSS icon associated with the font-face will be used
108 * to render the icon. Requires the fonts and the named CSS styles to be preloaded.
109 * @param {string} md-font-set CSS style name associated with the font library; which will be assigned as
110 * the class for the font-icon ligature. This value may also be an alias that is used to lookup the classname;
111 * internally use `$mdIconProvider.fontSet(<alias>)` to determine the style name.
112 * @param {string} md-svg-src String URL (or expression) used to load, cache, and display an
113 * external SVG.
114 * @param {string} md-svg-icon md-svg-icon String name used for lookup of the icon from the internal cache;
115 * interpolated strings or expressions may also be used. Specific set names can be used with
116 * the syntax `<set name>:<icon name>`.<br/><br/>
117 * To use icon sets, developers are required to pre-register the sets using the `$mdIconProvider` service.
118 * @param {string=} aria-label Labels icon for accessibility. If an empty string is provided, icon
119 * will be hidden from accessibility layer with `aria-hidden="true"`. If there's no aria-label on the icon
120 * nor a label on the parent element, a warning will be logged to the console.
121 * @param {string=} alt Labels icon for accessibility. If an empty string is provided, icon
122 * will be hidden from accessibility layer with `aria-hidden="true"`. If there's no alt on the icon
123 * nor a label on the parent element, a warning will be logged to the console.
124 *
125 * @usage
126 * When using SVGs:
127 * <hljs lang="html">
128 *
129 * <!-- Icon ID; may contain optional icon set prefix; icons must registered using $mdIconProvider -->
130 * <md-icon md-svg-icon="social:android" aria-label="android " ></md-icon>
131 *
132 * <!-- Icon urls; may be preloaded in templateCache -->
133 * <md-icon md-svg-src="/android.svg" aria-label="android " ></md-icon>
134 * <md-icon md-svg-src="{{ getAndroid() }}" aria-label="android " ></md-icon>
135 *
136 * </hljs>
137 *
138 * Use the <code>$mdIconProvider</code> to configure your application with
139 * svg iconsets.
140 *
141 * <hljs lang="js">
142 * angular.module('appSvgIconSets', ['ngMaterial'])
143 * .controller('DemoCtrl', function($scope) {})
144 * .config(function($mdIconProvider) {
145 * $mdIconProvider
146 * .iconSet('social', 'img/icons/sets/social-icons.svg', 24)
147 * .defaultIconSet('img/icons/sets/core-icons.svg', 24);
148 * });
149 * </hljs>
150 *
151 *
152 * When using Font Icons with classnames:
153 * <hljs lang="html">
154 *
155 * <md-icon md-font-icon="android" aria-label="android" ></md-icon>
156 * <md-icon class="icon_home" aria-label="Home" ></md-icon>
157 *
158 * </hljs>
159 *
160 * When using Material Font Icons with ligatures:
161 * <hljs lang="html">
162 * <!--
163 * For Material Design Icons
164 * The class '.material-icons' is auto-added if a style has NOT been specified
165 * since `material-icons` is the default fontset. So your markup:
166 * -->
167 * <md-icon> face </md-icon>
168 * <!-- becomes this at runtime: -->
169 * <md-icon md-font-set="material-icons"> face </md-icon>
170 * <!-- If the fontset does not support ligature names, then we need to use the ligature unicode.-->
171 * <md-icon>  </md-icon>
172 * <!-- The class '.material-icons' must be manually added if other styles are also specified-->
173 * <md-icon class="material-icons md-light md-48"> face </md-icon>
174 * </hljs>
175 *
176 * When using other Font-Icon libraries:
177 *
178 * <hljs lang="js">
179 * // Specify a font-icon style alias
180 * angular.config(function($mdIconProvider) {
181 * $mdIconProvider.fontSet('md', 'material-icons');
182 * });
183 * </hljs>
184 *
185 * <hljs lang="html">
186 * <md-icon md-font-set="md">favorite</md-icon>
187 * </hljs>
188 *
189 */
190function mdIconDirective($mdIcon, $mdTheming, $mdAria, $sce) {
191
192 return {
193 restrict: 'E',
194 link : postLink
195 };
196
197
198 /**
199 * Directive postLink
200 * Supports embedded SVGs, font-icons, & external SVGs
201 */
202 function postLink(scope, element, attr) {
203 $mdTheming(element);
204 var lastFontIcon = attr.mdFontIcon;
205 var lastFontSet = $mdIcon.fontSet(attr.mdFontSet);
206
207 prepareForFontIcon();
208
209 attr.$observe('mdFontIcon', fontIconChanged);
210 attr.$observe('mdFontSet', fontIconChanged);
211
212 // Keep track of the content of the svg src so we can compare against it later to see if the
213 // attribute is static (and thus safe).
214 var originalSvgSrc = element[0].getAttribute(attr.$attr.mdSvgSrc);
215
216 // If using a font-icon, then the textual name of the icon itself
217 // provides the aria-label.
218
219 var label = attr.alt || attr.mdFontIcon || attr.mdSvgIcon || element.text();
220 var attrName = attr.$normalize(attr.$attr.mdSvgIcon || attr.$attr.mdSvgSrc || '');
221
222 if ( !attr['aria-label'] ) {
223
224 if (label !== '' && !parentsHaveText() ) {
225
226 $mdAria.expect(element, 'aria-label', label);
227 $mdAria.expect(element, 'role', 'img');
228
229 } else if ( !element.text() ) {
230 // If not a font-icon with ligature, then
231 // hide from the accessibility layer.
232
233 $mdAria.expect(element, 'aria-hidden', 'true');
234 }
235 }
236
237 if (attrName) {
238 // Use either pre-configured SVG or URL source, respectively.
239 attr.$observe(attrName, function(attrVal) {
240 element.empty();
241 if (attrVal) {
242 $mdIcon(attrVal)
243 .then(function(svg) {
244 element.empty();
245 element.append(svg);
246 });
247 }
248
249 });
250 }
251
252 function parentsHaveText() {
253 var parent = element.parent();
254 if (parent.attr('aria-label') || parent.text()) {
255 return true;
256 }
257 else if(parent.parent().attr('aria-label') || parent.parent().text()) {
258 return true;
259 }
260 return false;
261 }
262
263 function prepareForFontIcon() {
264 if (!attr.mdSvgIcon && !attr.mdSvgSrc) {
265 if (attr.mdFontIcon) {
266 element.addClass('md-font ' + attr.mdFontIcon);
267 }
268
269 element.addClass(lastFontSet);
270 }
271 }
272
273 function fontIconChanged() {
274 if (!attr.mdSvgIcon && !attr.mdSvgSrc) {
275 if (attr.mdFontIcon) {
276 element.removeClass(lastFontIcon);
277 element.addClass(attr.mdFontIcon);
278
279 lastFontIcon = attr.mdFontIcon;
280 }
281
282 var fontSet = $mdIcon.fontSet(attr.mdFontSet);
283
284 if (lastFontSet !== fontSet) {
285 element.removeClass(lastFontSet);
286 element.addClass(fontSet);
287
288 lastFontSet = fontSet;
289 }
290 }
291 }
292 }
293}
294
295
296MdIconService.$inject = ["config", "$templateRequest", "$q", "$log", "$mdUtil", "$sce"];angular
297 .module('material.components.icon')
298 .constant('$$mdSvgRegistry', {
299 'mdTabsArrow': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwb2x5Z29uIHBvaW50cz0iMTUuNCw3LjQgMTQsNiA4LDEyIDE0LDE4IDE1LjQsMTYuNiAxMC44LDEyICIvPjwvZz48L3N2Zz4=',
300 'mdClose': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik0xOSA2LjQxbC0xLjQxLTEuNDEtNS41OSA1LjU5LTUuNTktNS41OS0xLjQxIDEuNDEgNS41OSA1LjU5LTUuNTkgNS41OSAxLjQxIDEuNDEgNS41OS01LjU5IDUuNTkgNS41OSAxLjQxLTEuNDEtNS41OS01LjU5eiIvPjwvZz48L3N2Zz4=',
301 'mdCancel': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik0xMiAyYy01LjUzIDAtMTAgNC40Ny0xMCAxMHM0LjQ3IDEwIDEwIDEwIDEwLTQuNDcgMTAtMTAtNC40Ny0xMC0xMC0xMHptNSAxMy41OWwtMS40MSAxLjQxLTMuNTktMy41OS0zLjU5IDMuNTktMS40MS0xLjQxIDMuNTktMy41OS0zLjU5LTMuNTkgMS40MS0xLjQxIDMuNTkgMy41OSAzLjU5LTMuNTkgMS40MSAxLjQxLTMuNTkgMy41OSAzLjU5IDMuNTl6Ii8+PC9nPjwvc3ZnPg==',
302 'mdMenu': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zLDZIMjFWOEgzVjZNMywxMUgyMVYxM0gzVjExTTMsMTZIMjFWMThIM1YxNloiIC8+PC9zdmc+',
303 'mdToggleArrow': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNDggNDgiPjxwYXRoIGQ9Ik0yNCAxNmwtMTIgMTIgMi44MyAyLjgzIDkuMTctOS4xNyA5LjE3IDkuMTcgMi44My0yLjgzeiIvPjxwYXRoIGQ9Ik0wIDBoNDh2NDhoLTQ4eiIgZmlsbD0ibm9uZSIvPjwvc3ZnPg==',
304 'mdCalendar': 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgM2gtMVYxaC0ydjJIOFYxSDZ2Mkg1Yy0xLjExIDAtMS45OS45LTEuOTkgMkwzIDE5YzAgMS4xLjg5IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTZINVY4aDE0djExek03IDEwaDV2NUg3eiIvPjwvc3ZnPg==',
305 'mdChecked': 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxnPjxwYXRoIGQ9Ik05IDE2LjE3TDQuODMgMTJsLTEuNDIgMS40MUw5IDE5IDIxIDdsLTEuNDEtMS40MXoiLz48L2c+PC9zdmc+'
306 })
307 .provider('$mdIcon', MdIconProvider);
308
309/**
310 * @ngdoc service
311 * @name $mdIconProvider
312 * @module material.components.icon
313 *
314 * @description
315 * `$mdIconProvider` is used only to register icon IDs with URLs. These configuration features allow
316 * icons and icon sets to be pre-registered and associated with source URLs **before** the `<md-icon />`
317 * directives are compiled.
318 *
319 * If using font-icons, the developer is responsible for loading the fonts.
320 *
321 * If using SVGs, loading of the actual svg files are deferred to on-demand requests and are loaded
322 * internally by the `$mdIcon` service using the `$templateRequest` service. When an SVG is
323 * requested by name/ID, the `$mdIcon` service searches its registry for the associated source URL;
324 * that URL is used to on-demand load and parse the SVG dynamically.
325 *
326 * The `$templateRequest` service expects the icons source to be loaded over trusted URLs.<br/>
327 * This means, when loading icons from an external URL, you have to trust the URL in the `$sceDelegateProvider`.
328 *
329 * <hljs lang="js">
330 * app.config(function($sceDelegateProvider) {
331 * $sceDelegateProvider.resourceUrlWhitelist([
332 * // Adding 'self' to the whitelist, will allow requests from the current origin.
333 * 'self',
334 * // Using double asterisks here, will allow all URLs to load.
335 * // We recommend to only specify the given domain you want to allow.
336 * '**'
337 * ]);
338 * });
339 * </hljs>
340 *
341 * Read more about the [$sceDelegateProvider](https://docs.angularjs.org/api/ng/provider/$sceDelegateProvider).
342 *
343 * **Notice:** Most font-icons libraries do not support ligatures (for example `fontawesome`).<br/>
344 * In such cases you are not able to use the icon's ligature name - Like so:
345 *
346 * <hljs lang="html">
347 * <md-icon md-font-set="fa">fa-bell</md-icon>
348 * </hljs>
349 *
350 * You should instead use the given unicode, instead of the ligature name.
351 *
352 * <p ng-hide="true"> ##// Notice we can't use a hljs element here, because the characters will be escaped.</p>
353 * ```html
354 * <md-icon md-font-set="fa"></md-icon>
355 * ```
356 *
357 * All unicode ligatures are prefixed with the `&#x` string.
358 *
359 * @usage
360 * <hljs lang="js">
361 * app.config(function($mdIconProvider) {
362 *
363 * // Configure URLs for icons specified by [set:]id.
364 *
365 * $mdIconProvider
366 * .defaultFontSet( 'fa' ) // This sets our default fontset className.
367 * .defaultIconSet('my/app/icons.svg') // Register a default set of SVG icons
368 * .iconSet('social', 'my/app/social.svg') // Register a named icon set of SVGs
369 * .icon('android', 'my/app/android.svg') // Register a specific icon (by name)
370 * .icon('work:chair', 'my/app/chair.svg'); // Register icon in a specific set
371 * });
372 * </hljs>
373 *
374 * SVG icons and icon sets can be easily pre-loaded and cached using either (a) a build process or (b) a runtime
375 * **startup** process (shown below):
376 *
377 * <hljs lang="js">
378 * app.config(function($mdIconProvider) {
379 *
380 * // Register a default set of SVG icon definitions
381 * $mdIconProvider.defaultIconSet('my/app/icons.svg')
382 *
383 * })
384 * .run(function($templateRequest){
385 *
386 * // Pre-fetch icons sources by URL and cache in the $templateCache...
387 * // subsequent $templateRequest calls will look there first.
388 *
389 * var urls = [ 'imy/app/icons.svg', 'img/icons/android.svg'];
390 *
391 * angular.forEach(urls, function(url) {
392 * $templateRequest(url);
393 * });
394 *
395 * });
396 *
397 * </hljs>
398 *
399 * > <b>Note:</b> The loaded SVG data is subsequently cached internally for future requests.
400 *
401 */
402
403/**
404 * @ngdoc method
405 * @name $mdIconProvider#icon
406 *
407 * @description
408 * Register a source URL for a specific icon name; the name may include optional 'icon set' name prefix.
409 * These icons will later be retrieved from the cache using `$mdIcon( <icon name> )`
410 *
411 * @param {string} id Icon name/id used to register the icon
412 * @param {string} url specifies the external location for the data file. Used internally by
413 * `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading
414 * was configured.
415 * @param {number=} viewBoxSize Sets the width and height the icon's viewBox.
416 * It is ignored for icons with an existing viewBox. Default size is 24.
417 *
418 * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
419 *
420 * @usage
421 * <hljs lang="js">
422 * app.config(function($mdIconProvider) {
423 *
424 * // Configure URLs for icons specified by [set:]id.
425 *
426 * $mdIconProvider
427 * .icon('android', 'my/app/android.svg') // Register a specific icon (by name)
428 * .icon('work:chair', 'my/app/chair.svg'); // Register icon in a specific set
429 * });
430 * </hljs>
431 *
432 */
433/**
434 * @ngdoc method
435 * @name $mdIconProvider#iconSet
436 *
437 * @description
438 * Register a source URL for a 'named' set of icons; group of SVG definitions where each definition
439 * has an icon id. Individual icons can be subsequently retrieved from this cached set using
440 * `$mdIcon(<icon set name>:<icon name>)`
441 *
442 * @param {string} id Icon name/id used to register the iconset
443 * @param {string} url specifies the external location for the data file. Used internally by
444 * `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading
445 * was configured.
446 * @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.
447 * It is ignored for icons with an existing viewBox. All icons in the icon set should be the same size.
448 * Default value is 24.
449 *
450 * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
451 *
452 *
453 * @usage
454 * <hljs lang="js">
455 * app.config(function($mdIconProvider) {
456 *
457 * // Configure URLs for icons specified by [set:]id.
458 *
459 * $mdIconProvider
460 * .iconSet('social', 'my/app/social.svg') // Register a named icon set
461 * });
462 * </hljs>
463 *
464 */
465/**
466 * @ngdoc method
467 * @name $mdIconProvider#defaultIconSet
468 *
469 * @description
470 * Register a source URL for the default 'named' set of icons. Unless explicitly registered,
471 * subsequent lookups of icons will failover to search this 'default' icon set.
472 * Icon can be retrieved from this cached, default set using `$mdIcon(<name>)`
473 *
474 * @param {string} url specifies the external location for the data file. Used internally by
475 * `$templateRequest` to load the data or as part of the lookup in `$templateCache` if pre-loading
476 * was configured.
477 * @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.
478 * It is ignored for icons with an existing viewBox. All icons in the icon set should be the same size.
479 * Default value is 24.
480 *
481 * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
482 *
483 * @usage
484 * <hljs lang="js">
485 * app.config(function($mdIconProvider) {
486 *
487 * // Configure URLs for icons specified by [set:]id.
488 *
489 * $mdIconProvider
490 * .defaultIconSet( 'my/app/social.svg' ) // Register a default icon set
491 * });
492 * </hljs>
493 *
494 */
495/**
496 * @ngdoc method
497 * @name $mdIconProvider#defaultFontSet
498 *
499 * @description
500 * When using Font-Icons, Angular Material assumes the the Material Design icons will be used and automatically
501 * configures the default font-set == 'material-icons'. Note that the font-set references the font-icon library
502 * class style that should be applied to the `<md-icon>`.
503 *
504 * Configuring the default means that the attributes
505 * `md-font-set="material-icons"` or `class="material-icons"` do not need to be explicitly declared on the
506 * `<md-icon>` markup. For example:
507 *
508 * `<md-icon> face </md-icon>`
509 * will render as
510 * `<span class="material-icons"> face </span>`, and
511 *
512 * `<md-icon md-font-set="fa"> face </md-icon>`
513 * will render as
514 * `<span class="fa"> face </span>`
515 *
516 * @param {string} name of the font-library style that should be applied to the md-icon DOM element
517 *
518 * @usage
519 * <hljs lang="js">
520 * app.config(function($mdIconProvider) {
521 * $mdIconProvider.defaultFontSet( 'fa' );
522 * });
523 * </hljs>
524 *
525 */
526
527/**
528 * @ngdoc method
529 * @name $mdIconProvider#fontSet
530 *
531 * @description
532 * When using a font set for `<md-icon>` you must specify the correct font classname in the `md-font-set`
533 * attribute. If the fonset className is really long, your markup may become cluttered... an easy
534 * solution is to define an `alias` for your fontset:
535 *
536 * @param {string} alias of the specified fontset.
537 * @param {string} className of the fontset.
538 *
539 * @usage
540 * <hljs lang="js">
541 * app.config(function($mdIconProvider) {
542 * // In this case, we set an alias for the `material-icons` fontset.
543 * $mdIconProvider.fontSet('md', 'material-icons');
544 * });
545 * </hljs>
546 *
547 */
548
549/**
550 * @ngdoc method
551 * @name $mdIconProvider#defaultViewBoxSize
552 *
553 * @description
554 * While `<md-icon />` markup can also be style with sizing CSS, this method configures
555 * the default width **and** height used for all icons; unless overridden by specific CSS.
556 * The default sizing is (24px, 24px).
557 * @param {number=} viewBoxSize Sets the width and height of the viewBox for an icon or an icon set.
558 * All icons in a set should be the same size. The default value is 24.
559 *
560 * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
561 *
562 * @usage
563 * <hljs lang="js">
564 * app.config(function($mdIconProvider) {
565 *
566 * // Configure URLs for icons specified by [set:]id.
567 *
568 * $mdIconProvider
569 * .defaultViewBoxSize(36) // Register a default icon size (width == height)
570 * });
571 * </hljs>
572 *
573 */
574
575var config = {
576 defaultViewBoxSize: 24,
577 defaultFontSet: 'material-icons',
578 fontSets: []
579};
580
581function MdIconProvider() {
582}
583
584MdIconProvider.prototype = {
585 icon: function(id, url, viewBoxSize) {
586 if (id.indexOf(':') == -1) id = '$default:' + id;
587
588 config[id] = new ConfigurationItem(url, viewBoxSize);
589 return this;
590 },
591
592 iconSet: function(id, url, viewBoxSize) {
593 config[id] = new ConfigurationItem(url, viewBoxSize);
594 return this;
595 },
596
597 defaultIconSet: function(url, viewBoxSize) {
598 var setName = '$default';
599
600 if (!config[setName]) {
601 config[setName] = new ConfigurationItem(url, viewBoxSize);
602 }
603
604 config[setName].viewBoxSize = viewBoxSize || config.defaultViewBoxSize;
605
606 return this;
607 },
608
609 defaultViewBoxSize: function(viewBoxSize) {
610 config.defaultViewBoxSize = viewBoxSize;
611 return this;
612 },
613
614 /**
615 * Register an alias name associated with a font-icon library style ;
616 */
617 fontSet: function fontSet(alias, className) {
618 config.fontSets.push({
619 alias: alias,
620 fontSet: className || alias
621 });
622 return this;
623 },
624
625 /**
626 * Specify a default style name associated with a font-icon library
627 * fallback to Material Icons.
628 *
629 */
630 defaultFontSet: function defaultFontSet(className) {
631 config.defaultFontSet = !className ? '' : className;
632 return this;
633 },
634
635 defaultIconSize: function defaultIconSize(iconSize) {
636 config.defaultIconSize = iconSize;
637 return this;
638 },
639
640 $get: ['$templateRequest', '$q', '$log', '$mdUtil', '$sce', function($templateRequest, $q, $log, $mdUtil, $sce) {
641 return MdIconService(config, $templateRequest, $q, $log, $mdUtil, $sce);
642 }]
643};
644
645/**
646 * Configuration item stored in the Icon registry; used for lookups
647 * to load if not already cached in the `loaded` cache
648 */
649function ConfigurationItem(url, viewBoxSize) {
650 this.url = url;
651 this.viewBoxSize = viewBoxSize || config.defaultViewBoxSize;
652}
653
654/**
655 * @ngdoc service
656 * @name $mdIcon
657 * @module material.components.icon
658 *
659 * @description
660 * The `$mdIcon` service is a function used to lookup SVG icons.
661 *
662 * @param {string} id Query value for a unique Id or URL. If the argument is a URL, then the service will retrieve the icon element
663 * from its internal cache or load the icon and cache it first. If the value is not a URL-type string, then an ID lookup is
664 * performed. The Id may be a unique icon ID or may include an iconSet ID prefix.
665 *
666 * For the **id** query to work properly, this means that all id-to-URL mappings must have been previously configured
667 * using the `$mdIconProvider`.
668 *
669 * @returns {angular.$q.Promise} A promise that gets resolved to a clone of the initial SVG DOM element; which was
670 * created from the SVG markup in the SVG data file. If an error occurs (e.g. the icon cannot be found) the promise
671 * will get rejected.
672 *
673 * @usage
674 * <hljs lang="js">
675 * function SomeDirective($mdIcon) {
676 *
677 * // See if the icon has already been loaded, if not
678 * // then lookup the icon from the registry cache, load and cache
679 * // it for future requests.
680 * // NOTE: ID queries require configuration with $mdIconProvider
681 *
682 * $mdIcon('android').then(function(iconEl) { element.append(iconEl); });
683 * $mdIcon('work:chair').then(function(iconEl) { element.append(iconEl); });
684 *
685 * // Load and cache the external SVG using a URL
686 *
687 * $mdIcon('img/icons/android.svg').then(function(iconEl) {
688 * element.append(iconEl);
689 * });
690 * };
691 * </hljs>
692 *
693 * > <b>Note:</b> The `<md-icon>` directive internally uses the `$mdIcon` service to query, loaded,
694 * and instantiate SVG DOM elements.
695 */
696
697/* ngInject */
698function MdIconService(config, $templateRequest, $q, $log, $mdUtil, $sce) {
699 var iconCache = {};
700 var svgCache = {};
701 var urlRegex = /[-\w@:%\+.~#?&//=]{2,}\.[a-z]{2,4}\b(\/[-\w@:%\+.~#?&//=]*)?/i;
702 var dataUrlRegex = /^data:image\/svg\+xml[\s*;\w\-\=]*?(base64)?,(.*)$/i;
703
704 Icon.prototype = {clone: cloneSVG, prepare: prepareAndStyle};
705 getIcon.fontSet = findRegisteredFontSet;
706
707 // Publish service...
708 return getIcon;
709
710 /**
711 * Actual $mdIcon service is essentially a lookup function
712 */
713 function getIcon(id) {
714 id = id || '';
715
716 // If the "id" provided is not a string, the only other valid value is a $sce trust wrapper
717 // over a URL string. If the value is not trusted, this will intentionally throw an error
718 // because the user is attempted to use an unsafe URL, potentially opening themselves up
719 // to an XSS attack.
720 if (!angular.isString(id)) {
721 id = $sce.getTrustedUrl(id);
722 }
723
724 // If already loaded and cached, use a clone of the cached icon.
725 // Otherwise either load by URL, or lookup in the registry and then load by URL, and cache.
726
727 if (iconCache[id]) {
728 return $q.when(transformClone(iconCache[id]));
729 }
730
731 if (urlRegex.test(id) || dataUrlRegex.test(id)) {
732 return loadByURL(id).then(cacheIcon(id));
733 }
734
735 if (id.indexOf(':') == -1) {
736 id = '$default:' + id;
737 }
738
739 var load = config[id] ? loadByID : loadFromIconSet;
740 return load(id)
741 .then(cacheIcon(id));
742 }
743
744 /**
745 * Lookup registered fontSet style using its alias...
746 * If not found,
747 */
748 function findRegisteredFontSet(alias) {
749 var useDefault = angular.isUndefined(alias) || !(alias && alias.length);
750 if (useDefault) return config.defaultFontSet;
751
752 var result = alias;
753 angular.forEach(config.fontSets, function(it) {
754 if (it.alias == alias) result = it.fontSet || result;
755 });
756
757 return result;
758 }
759
760 function transformClone(cacheElement) {
761 var clone = cacheElement.clone();
762 var cacheSuffix = '_cache' + $mdUtil.nextUid();
763
764 // We need to modify for each cached icon the id attributes.
765 // This is needed because SVG id's are treated as normal DOM ids
766 // and should not have a duplicated id.
767 if (clone.id) clone.id += cacheSuffix;
768 angular.forEach(clone.querySelectorAll('[id]'), function(item) {
769 item.id += cacheSuffix;
770 });
771
772 return clone;
773 }
774
775 /**
776 * Prepare and cache the loaded icon for the specified `id`
777 */
778 function cacheIcon(id) {
779
780 return function updateCache(icon) {
781 iconCache[id] = isIcon(icon) ? icon : new Icon(icon, config[id]);
782
783 return iconCache[id].clone();
784 };
785 }
786
787 /**
788 * Lookup the configuration in the registry, if !registered throw an error
789 * otherwise load the icon [on-demand] using the registered URL.
790 *
791 */
792 function loadByID(id) {
793 var iconConfig = config[id];
794 return loadByURL(iconConfig.url).then(function(icon) {
795 return new Icon(icon, iconConfig);
796 });
797 }
798
799 /**
800 * Loads the file as XML and uses querySelector( <id> ) to find
801 * the desired node...
802 */
803 function loadFromIconSet(id) {
804 var setName = id.substring(0, id.lastIndexOf(':')) || '$default';
805 var iconSetConfig = config[setName];
806
807 return !iconSetConfig ? announceIdNotFound(id) : loadByURL(iconSetConfig.url).then(extractFromSet);
808
809 function extractFromSet(set) {
810 var iconName = id.slice(id.lastIndexOf(':') + 1);
811 var icon = set.querySelector('#' + iconName);
812 return icon ? new Icon(icon, iconSetConfig) : announceIdNotFound(id);
813 }
814
815 function announceIdNotFound(id) {
816 var msg = 'icon ' + id + ' not found';
817 $log.warn(msg);
818
819 return $q.reject(msg || id);
820 }
821 }
822
823 /**
824 * Load the icon by URL (may use the $templateCache).
825 * Extract the data for later conversion to Icon
826 */
827 function loadByURL(url) {
828 /* Load the icon from embedded data URL. */
829 function loadByDataUrl(url) {
830 var results = dataUrlRegex.exec(url);
831 var isBase64 = /base64/i.test(url);
832 var data = isBase64 ? window.atob(results[2]) : results[2];
833
834 return $q.when(angular.element(data)[0]);
835 }
836
837 /* Load the icon by URL using HTTP. */
838 function loadByHttpUrl(url) {
839 return $q(function(resolve, reject) {
840 // Catch HTTP or generic errors not related to incorrect icon IDs.
841 var announceAndReject = function(err) {
842 var msg = angular.isString(err) ? err : (err.message || err.data || err.statusText);
843 $log.warn(msg);
844 reject(err);
845 },
846 extractSvg = function(response) {
847 if (!svgCache[url]) {
848 svgCache[url] = angular.element('<div>').append(response)[0].querySelector('svg');
849 }
850 resolve(svgCache[url]);
851 };
852
853 $templateRequest(url, true).then(extractSvg, announceAndReject);
854 });
855 }
856
857 return dataUrlRegex.test(url)
858 ? loadByDataUrl(url)
859 : loadByHttpUrl(url);
860 }
861
862 /**
863 * Check target signature to see if it is an Icon instance.
864 */
865 function isIcon(target) {
866 return angular.isDefined(target.element) && angular.isDefined(target.config);
867 }
868
869 /**
870 * Define the Icon class
871 */
872 function Icon(el, config) {
873 if (el && el.tagName != 'svg') {
874 el = angular.element('<svg xmlns="http://www.w3.org/2000/svg">').append(el.cloneNode(true))[0];
875 }
876
877 // Inject the namespace if not available...
878 if (!el.getAttribute('xmlns')) {
879 el.setAttribute('xmlns', "http://www.w3.org/2000/svg");
880 }
881
882 this.element = el;
883 this.config = config;
884 this.prepare();
885 }
886
887 /**
888 * Prepare the DOM element that will be cached in the
889 * loaded iconCache store.
890 */
891 function prepareAndStyle() {
892 var viewBoxSize = this.config ? this.config.viewBoxSize : config.defaultViewBoxSize;
893 angular.forEach({
894 'fit': '',
895 'height': '100%',
896 'width': '100%',
897 'preserveAspectRatio': 'xMidYMid meet',
898 'viewBox': this.element.getAttribute('viewBox') || ('0 0 ' + viewBoxSize + ' ' + viewBoxSize),
899 'focusable': false // Disable IE11s default behavior to make SVGs focusable
900 }, function(val, attr) {
901 this.element.setAttribute(attr, val);
902 }, this);
903 }
904
905 /**
906 * Clone the Icon DOM element.
907 */
908 function cloneSVG() {
909 // If the element or any of its children have a style attribute, then a CSP policy without
910 // 'unsafe-inline' in the style-src directive, will result in a violation.
911 return this.element.cloneNode(true);
912 }
913
914}
915
916ngmaterial.components.icon = angular.module("material.components.icon");