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