arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
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> &#xE87C; </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">&#xf0f3</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);