nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / angular-material / modules / closure / icon / icon.js
1 /*!
2  * Angular Material Design
3  * https://github.com/angular/material
4  * @license MIT
5  * v0.9.8
6  */
7 goog.provide('ng.material.components.icon');
8 goog.require('ng.material.core');
9 /**
10  * @ngdoc module
11  * @name material.components.icon
12  * @description
13  * Icon
14  */
15 angular.module('material.components.icon', [
16     'material.core'
17   ])
18   .directive('mdIcon', mdIconDirective);
19
20 /**
21  * @ngdoc directive
22  * @name mdIcon
23  * @module material.components.icon
24  *
25  * @restrict E
26  *
27  * @description
28  * The `<md-icon>` directive is an markup element useful for showing an icon based on a font-icon
29  * or a SVG. Icons are view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`
30  * inside a `md-button` to add hover and click features.
31  *
32  * When using SVGs, both external SVGs (via URLs) or sets of SVGs [from icon sets] can be
33  * easily loaded and used.When use font-icons, developers must following three (3) simple steps:
34  *
35  * <ol>
36  * <li>Load the font library. e.g.<br/>
37  *    &lt;link href="https://fonts.googleapis.com/icon?family=Material+Icons"
38  *    rel="stylesheet"&gt;
39  * </li>
40  * <li> Use either (a) font-icon class names or (b) font ligatures to render the font glyph by using its textual name</li>
41  * <li> Use &lt;md-icon md-font-icon="classname" /&gt; or <br/>
42  *     use &lt;md-icon md-font-set="font library classname or alias"&gt; textual_name &lt;/md-icon&gt; or <br/>
43  *     use &lt;md-icon md-font-set="font library classname or alias"&gt; numerical_character_reference &lt;/md-icon&gt;
44  * </li>
45  * </ol>
46  *
47  * Full details for these steps can be found:
48  *
49  * <ul>
50  * <li>http://google.github.io/material-design-icons/</li>
51  * <li>http://google.github.io/material-design-icons/#icon-font-for-the-web</li>
52  * </ul>
53  *
54  * The Material Design icon style <code>.material-icons</code> and the icon font references are published in
55  * Material Design Icons:
56  *
57  * <ul>
58  * <li>http://www.google.com/design/icons/</li>
59  * <li>https://www.google.com/design/icons/#ic_accessibility</li>
60  * </ul>
61  *
62  * <h2 id="material_design_icons">Material Design Icons</h2>
63  * Using the Material Design Icon-Selector, developers can easily and quickly search for a Material Design font-icon and
64  * determine its textual name and character reference code. Click on any icon to see the slide-up information
65  * panel with details regarding a SVG download or information on the font-icon usage.
66  *
67  * <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank" style="border-bottom:none;">
68  * <img src="https://cloud.githubusercontent.com/assets/210413/7902490/fe8dd14c-0780-11e5-98fb-c821cc6475e6.png"
69  *      aria-label="Material Design Icon-Selector" style="max-width:75%;padding-left:10%">
70  * </a>
71  *
72  * <span class="image_caption">
73  *  Click on the image above to link to the
74  *  <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank">Material Design Icon-Selector</a>.
75  * </span>
76  *
77  * @param {string} md-font-icon Name of CSS icon associated with the font-face will be used
78  * to render the icon. Requires the fonts and the named CSS styles to be preloaded.
79  * @param {string} md-font-set CSS style name associated with the font library; which will be assigned as
80  * the class for the font-icon ligature. This value may also be an alias that is used to lookup the classname;
81  * internally use `$mdIconProvider.fontSet(<alias>)` to determine the style name.
82  * @param {string} md-svg-src URL [or expression ] used to load, cache, and display an external SVG.
83  * @param {string} md-svg-icon Name used for lookup of the icon from the internal cache; interpolated strings or
84  * expressions may also be used. Specific set names can be used with the syntax `<set name>:<icon name>`.<br/><br/>
85  * To use icon sets, developers are required to pre-register the sets using the `$mdIconProvider` service.
86  * @param {string=} aria-label Labels icon for accessibility. If an empty string is provided, icon
87  * will be hidden from accessibility layer with `aria-hidden="true"`. If there's no aria-label on the icon
88  * nor a label on the parent element, a warning will be logged to the console.
89  *
90  * @usage
91  * When using SVGs:
92  * <hljs lang="html">
93  *
94  *  <!-- Icon ID; may contain optional icon set prefix; icons must registered using $mdIconProvider -->
95  *  <md-icon md-svg-icon="social:android"    aria-label="android " ></md-icon>
96  *
97  *  <!-- Icon urls; may be preloaded in templateCache -->
98  *  <md-icon md-svg-src="/android.svg"       aria-label="android " ></md-icon>
99  *  <md-icon md-svg-src="{{ getAndroid() }}" aria-label="android " ></md-icon>
100  *
101  * </hljs>
102  *
103  * Use the <code>$mdIconProvider</code> to configure your application with
104  * svg iconsets.
105  *
106  * <hljs lang="js">
107  *  angular.module('appSvgIconSets', ['ngMaterial'])
108  *    .controller('DemoCtrl', function($scope) {})
109  *    .config(function($mdIconProvider) {
110  *      $mdIconProvider
111  *         .iconSet('social', 'img/icons/sets/social-icons.svg', 24)
112  *         .defaultIconSet('img/icons/sets/core-icons.svg', 24);
113  *     });
114  * </hljs>
115  *
116  *
117  * When using Font Icons with classnames:
118  * <hljs lang="html">
119  *
120  *  <md-icon md-font-icon="android" aria-label="android" ></md-icon>
121  *  <md-icon class="icon_home"      aria-label="Home"    ></md-icon>
122  *
123  * </hljs>
124  *
125  * When using Material Font Icons with ligatures:
126  * <hljs lang="html">
127  *  <!-- For Material Design Icons -->
128  *  <!-- The class '.material-icons' is auto-added. -->
129  *  <md-icon> face </md-icon>
130  *  <md-icon class="md-light md-48"> face </md-icon>
131  *  <md-icon md-font-set="material-icons"> face </md-icon>
132  *  <md-icon> #xE87C; </md-icon>
133  * </hljs>
134  *
135  * When using other Font-Icon libraries:
136  *
137  * <hljs lang="js">
138  *  // Specify a font-icon style alias
139  *  angular.config(function($mdIconProvider) {
140  *    $mdIconProvider.fontSet('fa', 'fontawesome');
141  *  });
142  * </hljs>
143  *
144  * <hljs lang="html">
145  *  <md-icon md-font-set="fa">email</md-icon>
146  * </hljs>
147  *
148  */
149 function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
150
151   return {
152     scope: {
153       fontSet : '@mdFontSet',
154       fontIcon: '@mdFontIcon',
155       svgIcon : '@mdSvgIcon',
156       svgSrc  : '@mdSvgSrc'
157     },
158     restrict: 'E',
159     transclude:true,
160     template: getTemplate,
161     link: postLink
162   };
163
164   function getTemplate(element, attr) {
165     var isEmptyAttr  = function(key) { return angular.isDefined(attr[key]) ? attr[key].length == 0 : false    },
166         hasAttrValue = function(key) { return attr[key] && attr[key].length > 0;     },
167         attrValue    = function(key) { return hasAttrValue(key) ? attr[key] : '' };
168
169     // If using the deprecated md-font-icon API
170     // If using ligature-based font-icons, transclude the ligature or NRCs
171
172     var tmplFontIcon = '<span class="md-font {{classNames}}" ng-class="fontIcon"></span>';
173     var tmplFontSet  = '<span class="{{classNames}}" ng-transclude></span>';
174
175     var tmpl = hasAttrValue('mdSvgIcon')     ? ''           :
176                hasAttrValue('mdSvgSrc')      ? ''           :
177                isEmptyAttr('mdFontIcon')     ? ''           :
178                hasAttrValue('mdFontIcon')    ? tmplFontIcon : tmplFontSet;
179
180     // If available, lookup the fontSet style and add to the list of classnames
181     // NOTE: Material Icons expects classnames like `.material-icons.md-48` instead of `.material-icons .md-48`
182
183     var names = (tmpl == tmplFontSet) ? $mdIcon.fontSet(attrValue('mdFontSet'))  + ' ' : '';
184         names = (names + attrValue('class')).trim();
185
186     return $interpolate( tmpl )({ classNames: names });
187   }
188
189
190   /**
191    * Directive postLink
192    * Supports embedded SVGs, font-icons, & external SVGs
193    */
194   function postLink(scope, element, attr) {
195     $mdTheming(element);
196
197     // If using a font-icon, then the textual name of the icon itself
198     // provides the aria-label.
199
200     var label = attr.alt || scope.fontIcon || scope.svgIcon || element.text();
201     var attrName = attr.$normalize(attr.$attr.mdSvgIcon || attr.$attr.mdSvgSrc || '');
202
203     if ( !attr['aria-label'] ) {
204
205       if (label != '' && !parentsHaveText() ) {
206
207         $mdAria.expect(element, 'aria-label', label);
208         $mdAria.expect(element, 'role', 'img');
209
210       } else if ( !element.text() ) {
211         // If not a font-icon with ligature, then
212         // hide from the accessibility layer.
213
214         $mdAria.expect(element, 'aria-hidden', 'true');
215       }
216     }
217
218     if (attrName) {
219       // Use either pre-configured SVG or URL source, respectively.
220       attr.$observe(attrName, function(attrVal) {
221
222         element.empty();
223         if (attrVal) {
224           $mdIcon(attrVal).then(function(svg) {
225             element.append(svg);
226           });
227         }
228
229       });
230     }
231     function parentsHaveText() {
232       var parent = element.parent();
233       if (parent.attr('aria-label') || parent.text()) {
234         return true;
235       }
236       else if(parent.parent().attr('aria-label') || parent.parent().text()) {
237         return true;
238       }
239       return false;
240     }
241   }
242 }
243 mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria", "$interpolate"];
244
245   angular
246     .module('material.components.icon' )
247     .provider('$mdIcon', MdIconProvider);
248
249   /**
250     * @ngdoc service
251     * @name $mdIconProvider
252     * @module material.components.icon
253     *
254     * @description
255     * `$mdIconProvider` is used only to register icon IDs with URLs. These configuration features allow
256     * icons and icon sets to be pre-registered and associated with source URLs **before** the `<md-icon />`
257     * directives are compiled.
258     *
259     * If using font-icons, the developer is repsonsible for loading the fonts.
260     *
261     * If using SVGs, loading of the actual svg files are deferred to on-demand requests and are loaded
262     * internally by the `$mdIcon` service using the `$http` service. When an SVG is requested by name/ID,
263     * the `$mdIcon` service searches its registry for the associated source URL;
264     * that URL is used to on-demand load and parse the SVG dynamically.
265     *
266     * @usage
267     * <hljs lang="js">
268     *   app.config(function($mdIconProvider) {
269     *
270     *     // Configure URLs for icons specified by [set:]id.
271     *
272     *     $mdIconProvider
273     *          .defaultFontSet( 'fontawesome' )
274     *          .defaultIconSet('my/app/icons.svg')       // Register a default set of SVG icons
275     *          .iconSet('social', 'my/app/social.svg')   // Register a named icon set of SVGs
276     *          .icon('android', 'my/app/android.svg')    // Register a specific icon (by name)
277     *          .icon('work:chair', 'my/app/chair.svg');  // Register icon in a specific set
278     *   });
279     * </hljs>
280     *
281     * SVG icons and icon sets can be easily pre-loaded and cached using either (a) a build process or (b) a runtime
282     * **startup** process (shown below):
283     *
284     * <hljs lang="js">
285     *   app.config(function($mdIconProvider) {
286     *
287     *     // Register a default set of SVG icon definitions
288     *     $mdIconProvider.defaultIconSet('my/app/icons.svg')
289     *
290     *   })
291     *   .run(function($http, $templateCache){
292     *
293     *     // Pre-fetch icons sources by URL and cache in the $templateCache...
294     *     // subsequent $http calls will look there first.
295     *
296     *     var urls = [ 'imy/app/icons.svg', 'img/icons/android.svg'];
297     *
298     *     angular.forEach(urls, function(url) {
299     *       $http.get(url, {cache: $templateCache});
300     *     });
301     *
302     *   });
303     *
304     * </hljs>
305     *
306     * NOTE: the loaded SVG data is subsequently cached internally for future requests.
307     *
308     */
309
310    /**
311     * @ngdoc method
312     * @name $mdIconProvider#icon
313     *
314     * @description
315     * Register a source URL for a specific icon name; the name may include optional 'icon set' name prefix.
316     * These icons  will later be retrieved from the cache using `$mdIcon( <icon name> )`
317     *
318     * @param {string} id Icon name/id used to register the icon
319     * @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
320     * data or as part of the lookup in `$templateCache` if pre-loading was configured.
321     * @param {string=} iconSize Number indicating the width and height of the icons in the set. All icons
322     * in the icon set must be the same size. Default size is 24.
323     *
324     * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
325     *
326     * @usage
327     * <hljs lang="js">
328     *   app.config(function($mdIconProvider) {
329     *
330     *     // Configure URLs for icons specified by [set:]id.
331     *
332     *     $mdIconProvider
333     *          .icon('android', 'my/app/android.svg')    // Register a specific icon (by name)
334     *          .icon('work:chair', 'my/app/chair.svg');  // Register icon in a specific set
335     *   });
336     * </hljs>
337     *
338     */
339    /**
340     * @ngdoc method
341     * @name $mdIconProvider#iconSet
342     *
343     * @description
344     * Register a source URL for a 'named' set of icons; group of SVG definitions where each definition
345     * has an icon id. Individual icons can be subsequently retrieved from this cached set using
346     * `$mdIcon(<icon set name>:<icon name>)`
347     *
348     * @param {string} id Icon name/id used to register the iconset
349     * @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
350     * data or as part of the lookup in `$templateCache` if pre-loading was configured.
351     * @param {string=} iconSize Number indicating the width and height of the icons in the set. All icons
352     * in the icon set must be the same size. Default size is 24.
353     *
354     * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
355     *
356     *
357     * @usage
358     * <hljs lang="js">
359     *   app.config(function($mdIconProvider) {
360     *
361     *     // Configure URLs for icons specified by [set:]id.
362     *
363     *     $mdIconProvider
364     *          .iconSet('social', 'my/app/social.svg')   // Register a named icon set
365     *   });
366     * </hljs>
367     *
368     */
369    /**
370     * @ngdoc method
371     * @name $mdIconProvider#defaultIconSet
372     *
373     * @description
374     * Register a source URL for the default 'named' set of icons. Unless explicitly registered,
375     * subsequent lookups of icons will failover to search this 'default' icon set.
376     * Icon can be retrieved from this cached, default set using `$mdIcon(<name>)`
377     *
378     * @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
379     * data or as part of the lookup in `$templateCache` if pre-loading was configured.
380     * @param {string=} iconSize Number indicating the width and height of the icons in the set. All icons
381     * in the icon set must be the same size. Default size is 24.
382     *
383     * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
384     *
385     * @usage
386     * <hljs lang="js">
387     *   app.config(function($mdIconProvider) {
388     *
389     *     // Configure URLs for icons specified by [set:]id.
390     *
391     *     $mdIconProvider
392     *          .defaultIconSet( 'my/app/social.svg' )   // Register a default icon set
393     *   });
394     * </hljs>
395     *
396     */
397   /**
398    * @ngdoc method
399    * @name $mdIconProvider#defaultFontSet
400    *
401    * @description
402    * When using Font-Icons, Angular Material assumes the the Material Design icons will be used and automatically
403    * configures the default font-set == 'material-icons'. Note that the font-set references the font-icon library
404    * class style that should be applied to the `<md-icon>`.
405    *
406    * Configuring the default means that the attributes
407    * `md-font-set="material-icons"` or `class="material-icons"` do not need to be explicitly declared on the
408    * `<md-icon>` markup. For example:
409    *
410    *  `<md-icon> face </md-icon>`
411    *  will render as
412    *  `<span class="material-icons"> face </span>`, and
413    *
414    *  `<md-icon md-font-set="fa"> face </md-icon>`
415    *  will render as
416    *  `<span class="fa"> face </span>`
417    *
418    * @param {string} name of the font-library style that should be applied to the md-icon DOM element
419    *
420    * @usage
421    * <hljs lang="js">
422    *   app.config(function($mdIconProvider) {
423    *     $mdIconProvider.defaultFontSet( 'fontawesome' );
424    *   });
425    * </hljs>
426    *
427    */
428
429    /**
430     * @ngdoc method
431     * @name $mdIconProvider#defaultIconSize
432     *
433     * @description
434     * While `<md-icon />` markup can also be style with sizing CSS, this method configures
435     * the default width **and** height used for all icons; unless overridden by specific CSS.
436     * The default sizing is (24px, 24px).
437     *
438     * @param {string} iconSize Number indicating the width and height of the icons in the set. All icons
439     * in the icon set must be the same size. Default size is 24.
440     *
441     * @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
442     *
443     * @usage
444     * <hljs lang="js">
445     *   app.config(function($mdIconProvider) {
446     *
447     *     // Configure URLs for icons specified by [set:]id.
448     *
449     *     $mdIconProvider
450     *          .defaultIconSize(36)   // Register a default icon size (width == height)
451     *   });
452     * </hljs>
453     *
454     */
455
456  var config = {
457    defaultIconSize: 24,
458    defaultFontSet: 'material-icons',
459    fontSets : [ ]
460  };
461
462  function MdIconProvider() { }
463
464  MdIconProvider.prototype = {
465
466    icon : function icon(id, url, iconSize) {
467      if ( id.indexOf(':') == -1 ) id = '$default:' + id;
468
469      config[id] = new ConfigurationItem(url, iconSize );
470      return this;
471    },
472    iconSet : function iconSet(id, url, iconSize) {
473      config[id] = new ConfigurationItem(url, iconSize );
474      return this;
475    },
476    defaultIconSet : function defaultIconSet(url, iconSize) {
477      var setName = '$default';
478
479      if ( !config[setName] ) {
480        config[setName] = new ConfigurationItem(url, iconSize );
481      }
482
483      config[setName].iconSize = iconSize || config.defaultIconSize;
484      return this;
485    },
486
487    /**
488     * Register an alias name associated with a font-icon library style ;
489     */
490    fontSet : function fontSet(alias, className) {
491     config.fontSets.push({
492       alias : alias,
493       fontSet : className || alias
494     });
495    },
496
497    /**
498     * Specify a default style name associated with a font-icon library
499     * fallback to Material Icons.
500     *
501     */
502    defaultFontSet : function defaultFontSet(className) {
503     config.defaultFontSet = !className ? '' : className;
504     return this;
505    },
506
507    defaultIconSize : function defaultIconSize(iconSize) {
508      config.defaultIconSize = iconSize;
509      return this;
510    },
511
512    preloadIcons: function ($templateCache) {
513      var iconProvider = this;
514      var svgRegistry = [
515        {
516          id : 'md-tabs-arrow',
517          url: 'md-tabs-arrow.svg',
518          svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><polygon points="15.4,7.4 14,6 8,12 14,18 15.4,16.6 10.8,12 "/></g></svg>'
519        },
520        {
521          id : 'md-close',
522          url: 'md-close.svg',
523          svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/></g></svg>'
524        },
525        {
526          id:  'md-cancel',
527          url: 'md-cancel.svg',
528          svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><path d="M12 2c-5.53 0-10 4.47-10 10s4.47 10 10 10 10-4.47 10-10-4.47-10-10-10zm5 13.59l-1.41 1.41-3.59-3.59-3.59 3.59-1.41-1.41 3.59-3.59-3.59-3.59 1.41-1.41 3.59 3.59 3.59-3.59 1.41 1.41-3.59 3.59 3.59 3.59z"/></g></svg>'
529        },
530        {
531          id:  'md-menu',
532          url: 'md-menu.svg',
533          svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 100 100"><path d="M 50 0 L 100 14 L 92 80 L 50 100 L 8 80 L 0 14 Z" fill="#b2b2b2"></path><path d="M 50 5 L 6 18 L 13.5 77 L 50 94 Z" fill="#E42939"></path><path d="M 50 5 L 94 18 L 86.5 77 L 50 94 Z" fill="#B72833"></path><path d="M 50 7 L 83 75 L 72 75 L 65 59 L 50 59 L 50 50 L 61 50 L 50 26 Z" fill="#b2b2b2"></path><path d="M 50 7 L 17 75 L 28 75 L 35 59 L 50 59 L 50 50 L 39 50 L 50 26 Z" fill="#fff"></path></svg>'
534        },
535        {
536          id:  'md-toggle-arrow',
537          url: 'md-toggle-arrow-svg',
538          svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 48 48"><path d="M24 16l-12 12 2.83 2.83 9.17-9.17 9.17 9.17 2.83-2.83z"/><path d="M0 0h48v48h-48z" fill="none"/></svg>'
539        }
540      ];
541
542      svgRegistry.forEach(function(asset){
543        iconProvider.icon(asset.id,  asset.url);
544        $templateCache.put(asset.url, asset.svg);
545      });
546
547    },
548
549    $get : ['$http', '$q', '$log', '$templateCache', function($http, $q, $log, $templateCache) {
550      this.preloadIcons($templateCache);
551      return MdIconService(config, $http, $q, $log, $templateCache);
552    }]
553  };
554
555    /**
556     *  Configuration item stored in the Icon registry; used for lookups
557     *  to load if not already cached in the `loaded` cache
558     */
559    function ConfigurationItem(url, iconSize) {
560      this.url = url;
561      this.iconSize = iconSize || config.defaultIconSize;
562    }
563
564  /**
565   * @ngdoc service
566   * @name $mdIcon
567   * @module material.components.icon
568   *
569   * @description
570   * The `$mdIcon` service is a function used to lookup SVG icons.
571   *
572   * @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
573   * 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
574   * performed. The Id may be a unique icon ID or may include an iconSet ID prefix.
575   *
576   * For the **id** query to work properly, this means that all id-to-URL mappings must have been previously configured
577   * using the `$mdIconProvider`.
578   *
579   * @returns {obj} Clone of the initial SVG DOM element; which was created from the SVG markup in the SVG data file.
580   *
581   * @usage
582   * <hljs lang="js">
583   * function SomeDirective($mdIcon) {
584   *
585   *   // See if the icon has already been loaded, if not
586   *   // then lookup the icon from the registry cache, load and cache
587   *   // it for future requests.
588   *   // NOTE: ID queries require configuration with $mdIconProvider
589   *
590   *   $mdIcon('android').then(function(iconEl)    { element.append(iconEl); });
591   *   $mdIcon('work:chair').then(function(iconEl) { element.append(iconEl); });
592   *
593   *   // Load and cache the external SVG using a URL
594   *
595   *   $mdIcon('img/icons/android.svg').then(function(iconEl) {
596   *     element.append(iconEl);
597   *   });
598   * };
599   * </hljs>
600   *
601   * NOTE: The `<md-icon />  ` directive internally uses the `$mdIcon` service to query, loaded, and instantiate
602   * SVG DOM elements.
603   */
604  function MdIconService(config, $http, $q, $log, $templateCache) {
605    var iconCache = {};
606    var urlRegex = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/i;
607
608    Icon.prototype = { clone : cloneSVG, prepare: prepareAndStyle };
609    getIcon.fontSet = findRegisteredFontSet;
610
611    // Publish service...
612    return getIcon;
613
614    /**
615     * Actual $mdIcon service is essentially a lookup function
616     */
617    function getIcon(id) {
618      id = id || '';
619
620      // If already loaded and cached, use a clone of the cached icon.
621      // Otherwise either load by URL, or lookup in the registry and then load by URL, and cache.
622
623      if ( iconCache[id]         ) return $q.when( iconCache[id].clone() );
624      if ( urlRegex.test(id)     ) return loadByURL(id).then( cacheIcon(id) );
625      if ( id.indexOf(':') == -1 ) id = '$default:' + id;
626
627      return loadByID(id)
628          .catch(loadFromIconSet)
629          .catch(announceIdNotFound)
630          .catch(announceNotFound)
631          .then( cacheIcon(id) );
632    }
633
634    /**
635     * Lookup registered fontSet style using its alias...
636     * If not found,
637     */
638    function findRegisteredFontSet(alias) {
639       var useDefault = angular.isUndefined(alias) || !(alias && alias.length);
640       if ( useDefault ) return config.defaultFontSet;
641
642       var result = alias;
643       angular.forEach(config.fontSets, function(it){
644         if ( it.alias == alias ) result = it.fontSet || result;
645       });
646
647       return result;
648    }
649
650    /**
651     * Prepare and cache the loaded icon for the specified `id`
652     */
653    function cacheIcon( id ) {
654
655      return function updateCache( icon ) {
656        iconCache[id] = isIcon(icon) ? icon : new Icon(icon, config[id]);
657
658        return iconCache[id].clone();
659      };
660    }
661
662    /**
663     * Lookup the configuration in the registry, if !registered throw an error
664     * otherwise load the icon [on-demand] using the registered URL.
665     *
666     */
667    function loadByID(id) {
668      var iconConfig = config[id];
669
670      return !iconConfig ? $q.reject(id) : loadByURL(iconConfig.url).then(function(icon) {
671        return new Icon(icon, iconConfig);
672      });
673    }
674
675    /**
676     *    Loads the file as XML and uses querySelector( <id> ) to find
677     *    the desired node...
678     */
679    function loadFromIconSet(id) {
680      var setName = id.substring(0, id.lastIndexOf(':')) || '$default';
681      var iconSetConfig = config[setName];
682
683      return !iconSetConfig ? $q.reject(id) : loadByURL(iconSetConfig.url).then(extractFromSet);
684
685      function extractFromSet(set) {
686        var iconName = id.slice(id.lastIndexOf(':') + 1);
687        var icon = set.querySelector('#' + iconName);
688        return !icon ? $q.reject(id) : new Icon(icon, iconSetConfig);
689      }
690    }
691
692    /**
693     * Load the icon by URL (may use the $templateCache).
694     * Extract the data for later conversion to Icon
695     */
696    function loadByURL(url) {
697      return $http
698        .get(url, { cache: $templateCache })
699        .then(function(response) {
700          return angular.element('<div>').append(response.data).find('svg')[0];
701        });
702    }
703
704    /**
705     * User did not specify a URL and the ID has not been registered with the $mdIcon
706     * registry
707     */
708    function announceIdNotFound(id) {
709      var msg;
710
711      if (angular.isString(id)) {
712        msg = 'icon ' + id + ' not found';
713        $log.warn(msg);
714      }
715
716      return $q.reject(msg || id);
717    }
718
719    /**
720     * Catch HTTP or generic errors not related to incorrect icon IDs.
721     */
722    function announceNotFound(err) {
723      var msg = angular.isString(err) ? err : (err.message || err.data || err.statusText);
724      $log.warn(msg);
725
726      return $q.reject(msg);
727    }
728
729    /**
730     * Check target signature to see if it is an Icon instance.
731     */
732    function isIcon(target) {
733      return angular.isDefined(target.element) && angular.isDefined(target.config);
734    }
735
736    /**
737     *  Define the Icon class
738     */
739    function Icon(el, config) {
740      if (el.tagName != 'svg') {
741        el = angular.element('<svg xmlns="http://www.w3.org/2000/svg">').append(el)[0];
742      }
743
744      // Inject the namespace if not available...
745      if ( !el.getAttribute('xmlns') ) {
746        el.setAttribute('xmlns', "http://www.w3.org/2000/svg");
747      }
748
749      this.element = el;
750      this.config = config;
751      this.prepare();
752    }
753
754    /**
755     *  Prepare the DOM element that will be cached in the
756     *  loaded iconCache store.
757     */
758    function prepareAndStyle() {
759      var iconSize = this.config ? this.config.iconSize : config.defaultIconSize;
760          angular.forEach({
761            'fit'   : '',
762            'height': '100%',
763            'width' : '100%',
764            'preserveAspectRatio': 'xMidYMid meet',
765            'viewBox' : this.element.getAttribute('viewBox') || ('0 0 ' + iconSize + ' ' + iconSize)
766          }, function(val, attr) {
767            this.element.setAttribute(attr, val);
768          }, this);
769
770          angular.forEach({
771            'pointer-events' : 'none',
772            'display' : 'block'
773          }, function(val, style) {
774            this.element.style[style] = val;
775          }, this);
776    }
777
778    /**
779     * Clone the Icon DOM element.
780     */
781    function cloneSVG(){
782      return this.element.cloneNode(true);
783    }
784
785  }
786
787 ng.material.components.icon = angular.module("material.components.icon");