Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 077769b

Browse files
EladBezalelThomasBurleson
authored andcommitted
feat(colors): mdTheme integration
- If `md-theme` directive is somewhere up the DOM tree we inject the theme before each color value ### example ```html <div md-theme="myTheme"> <div md-colors="{background: 'primary-600'}"> <span md-colors="{background: 'mySecondTheme-accent-200'}">Color demo</span> </div> </div> ``` `'primary-600'` will be `'myTheme-primary-600'`, but `'mySecondTheme-accent-200'` will stay the same cause it has a theme prefix fixes #8407 Closes #8507
1 parent 44140ce commit 077769b

File tree

3 files changed

+148
-21
lines changed

3 files changed

+148
-21
lines changed

src/components/colors/colors.js

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
// Publish service instance
4646
return {
4747
applyThemeColors: applyThemeColors,
48-
getThemeColor: getThemeColor
48+
getThemeColor: getThemeColor,
49+
hasTheme: hasTheme
4950
};
5051

5152
// ********************************************
@@ -80,7 +81,7 @@
8081
try {
8182
// Assign the calculate RGBA color values directly as inline CSS
8283
element.css(interpolateColors(colorExpression));
83-
} catch( e ) {
84+
} catch (e) {
8485
$log.error(e.message);
8586
}
8687

@@ -154,6 +155,16 @@
154155
return rgbColors;
155156
}
156157

158+
/**
159+
* Check if expression has defined theme
160+
* e.g.
161+
* 'myTheme-primary' => true
162+
* 'red-800' => false
163+
*/
164+
function hasTheme(expression) {
165+
return angular.isDefined($mdTheming.THEMES[expression.split('-')[0]]);
166+
}
167+
157168
/**
158169
* For the evaluated expression, extract the color parts into a hash map
159170
*/
@@ -198,7 +209,7 @@
198209
var themeColors = $mdTheming.THEMES[theme].colors;
199210

200211
if (parts[1] === 'hue') {
201-
var hueNumber = parseInt(parts.splice(2, 1)[0],10);
212+
var hueNumber = parseInt(parts.splice(2, 1)[0], 10);
202213

203214
if (hueNumber < 1 || hueNumber > 3) {
204215
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}));
@@ -260,24 +271,71 @@
260271
function MdColorsDirective($mdColors, $mdUtil, $log, $parse) {
261272
return {
262273
restrict: 'A',
274+
require: ['^?mdTheme'],
263275
compile: function (tElem, tAttrs) {
264276
var shouldWatch = shouldColorsWatch();
265277

266-
return function (scope, element, attrs) {
267-
var colorExpression = function () {
268-
// Json.parse() does not work because the keys are not quoted;
269-
// use $parse to convert to a hash map
270-
return $parse(attrs.mdColors)(scope);
278+
return function (scope, element, attrs, ctrl) {
279+
var mdThemeController = ctrl[0];
280+
281+
var parseColors = function (theme) {
282+
/**
283+
* Json.parse() does not work because the keys are not quoted;
284+
* use $parse to convert to a hash map
285+
*/
286+
var colors = $parse(attrs.mdColors)(scope);
287+
288+
/**
289+
* If mdTheme is defined up the DOM tree
290+
* we add mdTheme theme to colors who doesn't specified a theme
291+
*
292+
* # example
293+
* <hljs lang="html">
294+
* <div md-theme="myTheme">
295+
* <div md-colors="{background: 'primary-600'}">
296+
* <span md-colors="{background: 'mySecondTheme-accent-200'}">Color demo</span>
297+
* </div>
298+
* </div>
299+
* </hljs>
300+
*
301+
* 'primary-600' will be 'myTheme-primary-600',
302+
* but 'mySecondTheme-accent-200' will stay the same cause it has a theme prefix
303+
*/
304+
if (mdThemeController) {
305+
Object.keys(colors).forEach(function (prop) {
306+
var color = colors[prop];
307+
if (!$mdColors.hasTheme(color)) {
308+
colors[prop] = (theme || mdThemeController.$mdTheme) + '-' + color;
309+
}
310+
});
311+
}
312+
313+
return colors;
271314
};
272315

316+
/**
317+
* Registering for mgTheme changes and asking mdTheme controller run our callback whenever a theme changes
318+
*/
319+
var unregisterChanges = angular.noop;
320+
321+
if (mdThemeController) {
322+
unregisterChanges = mdThemeController.registerChanges(function (theme) {
323+
$mdColors.applyThemeColors(element, parseColors(theme));
324+
});
325+
}
326+
327+
scope.$on('destroy', function () {
328+
unregisterChanges();
329+
});
330+
273331
try {
274332
if (shouldWatch) {
275-
scope.$watch(colorExpression, angular.bind(this,
333+
scope.$watch(parseColors, angular.bind(this,
276334
$mdColors.applyThemeColors, element
277335
), true);
278336
}
279337
else {
280-
$mdColors.applyThemeColors(element, colorExpression());
338+
$mdColors.applyThemeColors(element, parseColors());
281339
}
282340

283341
}
@@ -288,19 +346,19 @@
288346
};
289347

290348
function shouldColorsWatch() {
291-
// Simulate 1x binding and mark mdColorsWatch == false
292-
var rawColorExpression = tAttrs.mdColors;
293-
var bindOnce = rawColorExpression.indexOf('::') > -1;
294-
var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);
349+
// Simulate 1x binding and mark mdColorsWatch == false
350+
var rawColorExpression = tAttrs.mdColors;
351+
var bindOnce = rawColorExpression.indexOf('::') > -1;
352+
var isStatic = bindOnce ? true : STATIC_COLOR_EXPRESSION.test(tAttrs.mdColors);
295353

296-
// Remove it for the postLink...
297-
tAttrs.mdColors = rawColorExpression.replace('::','');
354+
// Remove it for the postLink...
355+
tAttrs.mdColors = rawColorExpression.replace('::', '');
298356

299-
var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);
357+
var hasWatchAttr = angular.isDefined(tAttrs.mdColorsWatch);
300358

301-
return (bindOnce || isStatic) ? false :
302-
hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;
303-
}
359+
return (bindOnce || isStatic) ? false :
360+
hasWatchAttr ? $mdUtil.parseAttributeBoolean(tAttrs.mdColorsWatch) : true;
361+
}
304362
}
305363
};
306364

src/components/colors/colors.spec.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,55 @@ describe('md-colors', function () {
264264
expect(element[0].style.background).toContain( expectedRGB );
265265
});
266266
});
267+
268+
describe('mdColors integration', function () {
269+
/**
270+
* <div md-theme="myTheme">
271+
* <div md-colors="{background: 'primary'}" >
272+
* </div>
273+
*/
274+
it('should automatically inject myTheme as the theme prefix', function () {
275+
276+
var type = 'primary';
277+
var paletteName = $mdTheming.THEMES['myTheme'].colors[type].name;
278+
var color = $mdColorPalette[paletteName]['500'].value;
279+
var expectedRGB = supplant('rgb({0}, {1}, {2})', [color[0], color[1], color[2]]);
280+
281+
282+
var markup = '<div md-theme="myTheme"><div md-colors="{background: \'primary\'}" ></div></div>';
283+
var element = $compile( markup )(scope);
284+
285+
expect(element.children()[0].style.background).toContain( expectedRGB );
286+
});
287+
288+
/**
289+
* <div md-theme="{{theme}}">
290+
* <div md-colors="{background: 'primary'}" >
291+
* </div>
292+
*/
293+
it('should register for theme changes and inject myTheme as the theme prefix', function () {
294+
295+
var type = 'primary';
296+
var paletteName = $mdTheming.THEMES['myTheme'].colors[type].name;
297+
var color = $mdColorPalette[paletteName]['500'].value;
298+
var expectedRGB = supplant('rgb({0}, {1}, {2})', [color[0], color[1], color[2]]);
299+
300+
scope.theme = 'myTheme';
301+
var markup = '<div md-theme="{{theme}}"><div md-colors="{background: \'primary\'}" ></div></div>';
302+
var element = $compile( markup )(scope);
303+
304+
expect(element.children()[0].style.background).toContain( expectedRGB );
305+
306+
paletteName = $mdTheming.THEMES['default'].colors[type].name;
307+
color = $mdColorPalette[paletteName]['500'].value;
308+
expectedRGB = supplant('rgb({0}, {1}, {2})', [color[0], color[1], color[2]]);
309+
310+
scope.theme = 'default';
311+
scope.$apply();
312+
313+
expect(element.children()[0].style.background).toContain( expectedRGB );
314+
});
315+
})
267316
});
268317

269318
describe('watched values', function () {

src/core/services/theming/theming.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,32 @@ function ThemingDirective($mdTheming, $interpolate, $log) {
419419
priority: 100,
420420
link: {
421421
pre: function(scope, el, attrs) {
422+
var registeredCallbacks = [];
422423
var ctrl = {
423-
$setTheme: function(theme) {
424+
registerChanges: function (cb, context) {
425+
if (context) {
426+
cb = angular.bind(context, cb);
427+
}
428+
429+
registeredCallbacks.push(cb);
430+
431+
return function () {
432+
var index = registeredCallbacks.indexOf(cb);
433+
434+
if (index > -1) {
435+
registeredCallbacks.splice(index, 1);
436+
}
437+
}
438+
},
439+
$setTheme: function (theme) {
424440
if (!$mdTheming.registered(theme)) {
425441
$log.warn('attempted to use unregistered theme \'' + theme + '\'');
426442
}
427443
ctrl.$mdTheme = theme;
444+
445+
registeredCallbacks.forEach(function (cb) {
446+
cb();
447+
})
428448
}
429449
};
430450
el.data('$mdThemeController', ctrl);

0 commit comments

Comments
 (0)