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