cd52921e2aaabb0d66fd2880be5b4fa29e2bdb91
[vnfsdk/refrepo.git] /
1 /*!
2  * Angular Material Design
3  * https://github.com/angular/material
4  * @license MIT
5  * v1.1.3
6  */
7 goog.provide('ngmaterial.components.colors');
8 goog.require('ngmaterial.core');
9 (function () {
10   "use strict";
11
12   /**
13    *  Use a RegExp to check if the `md-colors="<expression>"` is static string
14    *  or one that should be observed and dynamically interpolated.
15    */
16   MdColorsDirective['$inject'] = ["$mdColors", "$mdUtil", "$log", "$parse"];
17   MdColorsService['$inject'] = ["$mdTheming", "$mdUtil", "$log"];
18   var STATIC_COLOR_EXPRESSION = /^{((\s|,)*?["'a-zA-Z-]+?\s*?:\s*?('|")[a-zA-Z0-9-.]*('|"))+\s*}$/;
19   var colorPalettes = null;
20
21   /**
22    * @ngdoc module
23    * @name material.components.colors
24    *
25    * @description
26    * Define $mdColors service and a `md-colors=""` attribute directive
27    */
28   angular
29     .module('material.components.colors', ['material.core'])
30     .directive('mdColors', MdColorsDirective)
31     .service('$mdColors', MdColorsService);
32
33   /**
34    * @ngdoc service
35    * @name $mdColors
36    * @module material.components.colors
37    *
38    * @description
39    * With only defining themes, one couldn't get non ngMaterial elements colored with Material colors,
40    * `$mdColors` service is used by the md-color directive to convert the 1..n color expressions to RGBA values and will apply
41    * those values to element as CSS property values.
42    *
43    *  @usage
44    *  <hljs lang="js">
45    *    angular.controller('myCtrl', function ($mdColors) {
46    *      var color = $mdColors.getThemeColor('myTheme-red-200-0.5');
47    *      ...
48    *    });
49    *  </hljs>
50    *
51    */
52   function MdColorsService($mdTheming, $mdUtil, $log) {
53     colorPalettes = colorPalettes || Object.keys($mdTheming.PALETTES);
54
55     // Publish service instance
56     return {
57       applyThemeColors: applyThemeColors,
58       getThemeColor: getThemeColor,
59       hasTheme: hasTheme
60     };
61
62     // ********************************************
63     // Internal Methods
64     // ********************************************
65
66     /**
67      * @ngdoc method
68      * @name $mdColors#applyThemeColors
69      *
70      * @description
71      * Gets a color json object, keys are css properties and values are string of the wanted color
72      * Then calculate the rgba() values based on the theme color parts
73      *
74      * @param {DOMElement} element the element to apply the styles on.
75      * @param {object} colorExpression json object, keys are css properties and values are string of the wanted color,
76      * for example: `{color: 'red-A200-0.3'}`.
77      *
78      * @usage
79      * <hljs lang="js">
80      *   app.directive('myDirective', function($mdColors) {
81      *     return {
82      *       ...
83      *       link: function (scope, elem) {
84      *         $mdColors.applyThemeColors(elem, {color: 'red'});
85      *       }
86      *    }
87      *   });
88      * </hljs>
89      */
90     function applyThemeColors(element, colorExpression) {
91       try {
92         if (colorExpression) {
93           // Assign the calculate RGBA color values directly as inline CSS
94           element.css(interpolateColors(colorExpression));
95         }
96       } catch (e) {
97         $log.error(e.message);
98       }
99
100     }
101
102     /**
103      * @ngdoc method
104      * @name $mdColors#getThemeColor
105      *
106      * @description
107      * Get parsed color from expression
108      *
109      * @param {string} expression string of a color expression (for instance `'red-700-0.8'`)
110      *
111      * @returns {string} a css color expression (for instance `rgba(211, 47, 47, 0.8)`)
112      *
113      * @usage
114      *  <hljs lang="js">
115      *    angular.controller('myCtrl', function ($mdColors) {
116      *      var color = $mdColors.getThemeColor('myTheme-red-200-0.5');
117      *      ...
118      *    });
119      *  </hljs>
120      */
121     function getThemeColor(expression) {
122       var color = extractColorOptions(expression);
123
124       return parseColor(color);
125     }
126
127     /**
128      * Return the parsed color
129      * @param color hashmap of color definitions
130      * @param contrast whether use contrast color for foreground
131      * @returns rgba color string
132      */
133     function parseColor(color, contrast) {
134       contrast = contrast || false;
135       var rgbValues = $mdTheming.PALETTES[color.palette][color.hue];
136
137       rgbValues = contrast ? rgbValues.contrast : rgbValues.value;
138
139       return $mdUtil.supplant('rgba({0}, {1}, {2}, {3})',
140         [rgbValues[0], rgbValues[1], rgbValues[2], rgbValues[3] || color.opacity]
141       );
142     }
143
144     /**
145      * Convert the color expression into an object with scope-interpolated values
146      * Then calculate the rgba() values based on the theme color parts
147      *
148      * @results Hashmap of CSS properties with associated `rgba( )` string vales
149      *
150      *
151      */
152     function interpolateColors(themeColors) {
153       var rgbColors = {};
154
155       var hasColorProperty = themeColors.hasOwnProperty('color');
156
157       angular.forEach(themeColors, function (value, key) {
158         var color = extractColorOptions(value);
159         var hasBackground = key.indexOf('background') > -1;
160
161         rgbColors[key] = parseColor(color);
162         if (hasBackground && !hasColorProperty) {
163           rgbColors.color = parseColor(color, true);
164         }
165       });
166
167       return rgbColors;
168     }
169
170     /**
171      * Check if expression has defined theme
172      * e.g.
173      * 'myTheme-primary' => true
174      * 'red-800' => false
175      */
176     function hasTheme(expression) {
177       return angular.isDefined($mdTheming.THEMES[expression.split('-')[0]]);
178     }
179
180     /**
181      * For the evaluated expression, extract the color parts into a hash map
182      */
183     function extractColorOptions(expression) {
184       var parts = expression.split('-');
185       var hasTheme = angular.isDefined($mdTheming.THEMES[parts[0]]);
186       var theme = hasTheme ? parts.splice(0, 1)[0] : $mdTheming.defaultTheme();
187
188       return {
189         theme: theme,
190         palette: extractPalette(parts, theme),
191         hue: extractHue(parts, theme),
192         opacity: parts[2] || 1
193       };
194     }
195
196     /**
197      * Calculate the theme palette name
198      */
199     function extractPalette(parts, theme) {
200       // If the next section is one of the palettes we assume it's a two word palette
201       // Two word palette can be also written in camelCase, forming camelCase to dash-case
202
203       var isTwoWord = parts.length > 1 && colorPalettes.indexOf(parts[1]) !== -1;
204       var palette = parts[0].replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
205
206       if (isTwoWord)  palette = parts[0] + '-' + parts.splice(1, 1);
207
208       if (colorPalettes.indexOf(palette) === -1) {
209         // If the palette is not in the palette list it's one of primary/accent/warn/background
210         var scheme = $mdTheming.THEMES[theme].colors[palette];
211         if (!scheme) {
212           throw new Error($mdUtil.supplant('mdColors: couldn\'t find \'{palette}\' in the palettes.', {palette: palette}));
213         }
214         palette = scheme.name;
215       }
216
217       return palette;
218     }
219
220     function extractHue(parts, theme) {
221       var themeColors = $mdTheming.THEMES[theme].colors;
222
223       if (parts[1] === 'hue') {
224         var hueNumber = parseInt(parts.splice(2, 1)[0], 10);
225
226         if (hueNumber < 1 || hueNumber > 3) {
227           throw new Error($mdUtil.supplant('mdColors: \'hue-{hueNumber}\' is not a valid hue, can be only \'hue-1\', \'hue-2\' and \'hue-3\'', {hueNumber: hueNumber}));
228         }
229         parts[1] = 'hue-' + hueNumber;
230
231         if (!(parts[0] in themeColors)) {
232           throw new Error($mdUtil.supplant('mdColors: \'hue-x\' can only be used with [{availableThemes}], but was used with \'{usedTheme}\'', {
233             availableThemes: Object.keys(themeColors).join(', '),
234             usedTheme: parts[0]
235           }));
236         }
237
238         return themeColors[parts[0]].hues[parts[1]];
239       }
240
241       return parts[1] || themeColors[parts[0] in themeColors ? parts[0] : 'primary'].hues['default'];
242     }
243   }
244
245   /**
246    * @ngdoc directive
247    * @name mdColors
248    * @module material.components.colors
249    *
250    * @restrict A
251    *
252    * @description
253    * `mdColors` directive will apply the theme-based color expression as RGBA CSS style values.
254    *
255    *   The format will be similar to our color defining in the scss files:
256    *
257    *   ## `[?theme]-[palette]-[?hue]-[?opacity]`
258    *   - [theme]    - default value is the default theme
259    *   - [palette]  - can be either palette name or primary/accent/warn/background
260    *   - [hue]      - default is 500 (hue-x can be used with primary/accent/warn/background)
261    *   - [opacity]  - default is 1
262    *
263    *   > `?` indicates optional parameter
264    *
265    * @usage
266    * <hljs lang="html">
267    *   <div md-colors="{background: 'myTheme-accent-900-0.43'}">
268    *     <div md-colors="{color: 'red-A100', 'border-color': 'primary-600'}">
269    *       <span>Color demo</span>
270    *     </div>
271    *   </div>
272    * </hljs>
273    *
274    * `mdColors` directive will automatically watch for changes in the expression if it recognizes an interpolation
275    * expression or a function. For performance options, you can use `::` prefix to the `md-colors` expression
276    * to indicate a one-time data binding.
277    * <hljs lang="html">
278    *   <md-card md-colors="::{background: '{{theme}}-primary-700'}">
279    *   </md-card>
280    * </hljs>
281    *
282    */
283   function MdColorsDirective($mdColors, $mdUtil, $log, $parse) {
284     return {
285       restrict: 'A',
286       require: ['^?mdTheme'],
287       compile: function (tElem, tAttrs) {
288         var shouldWatch = shouldColorsWatch();
289
290         return function (scope, element, attrs, ctrl) {
291           var mdThemeController = ctrl[0];
292
293           var lastColors = {};
294
295           var parseColors = function (theme) {
296             if (typeof theme !== 'string') {
297               theme = '';
298             }
299
300             if (!attrs.mdColors) {
301               attrs.mdColors = '{}';
302             }
303
304             /**
305              * Json.parse() does not work because the keys are not quoted;
306              * use $parse to convert to a hash map
307              */
308             var colors = $parse(attrs.mdColors)(scope);
309
310             /**
311              * If mdTheme is defined up the DOM tree
312              * we add mdTheme theme to colors who doesn't specified a theme
313              *
314              * # example
315              * <hljs lang="html">
316              *   <div md-theme="myTheme">
317              *     <div md-colors="{background: 'primary-600'}">
318              *       <span md-colors="{background: 'mySecondTheme-accent-200'}">Color demo</span>
319              *     </div>
320              *   </div>
321              * </hljs>
322              *
323              * 'primary-600' will be 'myTheme-primary-600',
324              * but 'mySecondTheme-accent-200' will stay the same cause it has a theme prefix
325              */
326             if (mdThemeController) {
327               Object.keys(colors).forEach(function (prop) {
328                 var color = colors[prop];
329                 if (!$mdColors.hasTheme(color)) {
330                   colors[prop] = (theme || mdThemeController.$mdTheme) + '-' + color;
331                 }
332               });
333             }
334
335             cleanElement(colors);
336
337             return colors;
338           };
339
340           var cleanElement = function (colors) {
341             if (!angular.equals(colors, lastColors)) {
342               var keys = Object.keys(lastColors);
343
344               if (lastColors.background && !keys.color) {
345                 keys.push('color');
346               }
347
348               keys.forEach(function (key) {
349                 element.css(key, '');
350               });
351             }
352
353             lastColors = colors;
354           };
355
356           /**
357            * Registering for mgTheme changes and asking mdTheme controller run our callback whenever a theme changes
358            */
359           var unregisterChanges = angular.noop;
360
361           if (mdThemeController) {
362             unregisterChanges = mdThemeController.registerChanges(function (theme) {
363               $mdColors.applyThemeColors(element, parseColors(theme));
364             });
365           }
366
367           scope.$on('$destroy', function () {
368             unregisterChanges();
369           });
370
371           try {
372             if (shouldWatch) {
373               scope.$watch(parseColors, angular.bind(this,
374                 $mdColors.applyThemeColors, element
375               ), true);
376             }
377             else {
378               $mdColors.applyThemeColors(element, parseColors());
379             }
380
381           }
382           catch (e) {
383             $log.error(e.message);
384           }
385
386         };
387
388         function shouldColorsWatch() {
389           // Simulate 1x binding and mark mdColorsWatch == false
390           var rawColorExpression = tAttrs.mdColors;
391           var bindOnce = rawColorExpression.indexOf('::') > -1;
392           var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);
393
394           // Remove it for the postLink...
395           tAttrs.mdColors = rawColorExpression.replace('::', '');
396
397           var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);
398
399           return (bindOnce || isStatic) ? false :
400             hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;
401         }
402       }
403     };
404
405   }
406
407
408 })();
409
410 ngmaterial.components.colors = angular.module("material.components.colors");