@@ -606,20 +606,53 @@ function ThemingProvider($mdColorPalette, $$mdMetaProvider) {
606606 */
607607
608608 /* @ngInject */
609- function ThemingService ( $rootScope , $log ) {
609+ function ThemingService ( $rootScope , $mdUtil , $q , $ log) {
610610 // Allow us to be invoked via a linking function signature.
611611 var applyTheme = function ( scope , el ) {
612612 if ( el === undefined ) { el = scope ; scope = undefined ; }
613613 if ( scope === undefined ) { scope = $rootScope ; }
614614 applyTheme . inherit ( el , el ) ;
615615 } ;
616616
617- applyTheme . THEMES = angular . extend ( { } , THEMES ) ;
618- applyTheme . PALETTES = angular . extend ( { } , PALETTES ) ;
617+ Object . defineProperty ( applyTheme , 'THEMES' , {
618+ get : function ( ) {
619+ return angular . extend ( { } , THEMES ) ;
620+ }
621+ } ) ;
622+ Object . defineProperty ( applyTheme , 'PALETTES' , {
623+ get : function ( ) {
624+ return angular . extend ( { } , PALETTES ) ;
625+ }
626+ } ) ;
619627 applyTheme . inherit = inheritTheme ;
620628 applyTheme . registered = registered ;
621629 applyTheme . defaultTheme = function ( ) { return defaultTheme ; } ;
622630 applyTheme . generateTheme = function ( name ) { generateTheme ( THEMES [ name ] , name , themeConfig . nonce ) ; } ;
631+ applyTheme . defineTheme = function ( name , options ) {
632+ options = options || { } ;
633+
634+ var theme = registerTheme ( name ) ;
635+
636+ if ( options . primary ) {
637+ theme . primaryPalette ( options . primary ) ;
638+ }
639+ if ( options . accent ) {
640+ theme . accentPalette ( options . accent ) ;
641+ }
642+ if ( options . warn ) {
643+ theme . warnPalette ( options . warn ) ;
644+ }
645+ if ( options . background ) {
646+ theme . backgroundPalette ( options . background ) ;
647+ }
648+ if ( options . dark ) {
649+ theme . dark ( ) ;
650+ }
651+
652+ this . generateTheme ( name ) ;
653+
654+ return $q . resolve ( name ) ;
655+ } ;
623656 applyTheme . setBrowserColor = enableBrowserColor ;
624657
625658 return applyTheme ;
@@ -636,22 +669,31 @@ function ThemingProvider($mdColorPalette, $$mdMetaProvider) {
636669 * Get theme name for the element, then update with Theme CSS class
637670 */
638671 function inheritTheme ( el , parent ) {
639- var ctrl = parent . controller ( 'mdTheme' ) ;
640- var attrThemeValue = el . attr ( 'md-theme-watch' ) ;
641- var watchTheme = ( alwaysWatchTheme || angular . isDefined ( attrThemeValue ) ) && attrThemeValue != 'false' ;
672+ var ctrl = parent . controller ( 'mdTheme' ) || el . data ( '$mdThemeController' ) ;
642673
643674 updateThemeClass ( lookupThemeName ( ) ) ;
644675
645- if ( ( alwaysWatchTheme && ! registerChangeCallback ( ) ) || ( ! alwaysWatchTheme && watchTheme ) ) {
646- el . on ( '$destroy' , $rootScope . $watch ( lookupThemeName , updateThemeClass ) ) ;
676+ if ( ctrl ) {
677+ var watchTheme =
678+ alwaysWatchTheme || ctrl . $shouldWatch || $mdUtil . parseAttributeBoolean ( el . attr ( 'md-theme-watch' ) ) ;
679+
680+ var unwatch = ctrl . registerChanges ( function ( name ) {
681+ updateThemeClass ( name ) ;
682+
683+ if ( ! watchTheme ) {
684+ unwatch ( ) ;
685+ }
686+ else {
687+ el . on ( '$destroy' , unwatch ) ;
688+ }
689+ } ) ;
647690 }
648691
649692 /**
650693 * Find the theme name from the parent controller or element data
651694 */
652695 function lookupThemeName ( ) {
653696 // As a few components (dialog) add their controllers later, we should also watch for a controller init.
654- ctrl = parent . controller ( 'mdTheme' ) || el . data ( '$mdThemeController' ) ;
655697 return ctrl && ctrl . $mdTheme || ( defaultTheme == 'default' ? '' : defaultTheme ) ;
656698 }
657699
@@ -674,24 +716,12 @@ function ThemingProvider($mdColorPalette, $$mdMetaProvider) {
674716 el . data ( '$mdThemeController' , ctrl ) ;
675717 }
676718 }
677-
678- /**
679- * Register change callback with parent mdTheme controller
680- */
681- function registerChangeCallback ( ) {
682- var parentController = parent . controller ( 'mdTheme' ) ;
683- if ( ! parentController ) return false ;
684- el . on ( '$destroy' , parentController . registerChanges ( function ( ) {
685- updateThemeClass ( lookupThemeName ( ) ) ;
686- } ) ) ;
687- return true ;
688- }
689719 }
690720
691721 }
692722}
693723
694- function ThemingDirective ( $mdTheming , $interpolate , $log ) {
724+ function ThemingDirective ( $mdTheming , $interpolate , $parse , $mdUtil , $q , $ log) {
695725 return {
696726 priority : 100 ,
697727 link : {
@@ -717,16 +747,39 @@ function ThemingDirective($mdTheming, $interpolate, $log) {
717747 if ( ! $mdTheming . registered ( theme ) ) {
718748 $log . warn ( 'attempted to use unregistered theme \'' + theme + '\'' ) ;
719749 }
750+
751+
720752 ctrl . $mdTheme = theme ;
721753
722- registeredCallbacks . forEach ( function ( cb ) {
723- cb ( ) ;
754+ // Iterating backwards to support unregistering during iteration
755+ // http://stackoverflow.com/a/9882349/890293
756+ registeredCallbacks . reverse ( ) . forEach ( function ( cb ) {
757+ cb ( theme ) ;
724758 } ) ;
725- }
759+ } ,
760+ $shouldWatch : $mdUtil . parseAttributeBoolean ( el . attr ( 'md-theme-watch' ) )
726761 } ;
762+
727763 el . data ( '$mdThemeController' , ctrl ) ;
728- ctrl . $setTheme ( $interpolate ( attrs . mdTheme ) ( scope ) ) ;
729- attrs . $observe ( 'mdTheme' , ctrl . $setTheme ) ;
764+
765+ var getThemeInterpolation = function ( ) { return $interpolate ( attrs . mdTheme ) ( scope ) ; } ;
766+
767+ var setParsedTheme = function ( interpolation ) {
768+ var theme = $parse ( interpolation ) ( scope ) || interpolation ;
769+
770+ if ( typeof theme === 'string' ) {
771+ return ctrl . $setTheme ( theme ) ;
772+ }
773+
774+ $q . when ( ( typeof theme === 'function' ) ? theme ( ) : theme )
775+ . then ( function ( name ) {
776+ ctrl . $setTheme ( name )
777+ } ) ;
778+ } ;
779+
780+ setParsedTheme ( getThemeInterpolation ( ) ) ;
781+
782+ scope . $watch ( getThemeInterpolation , setParsedTheme ) ;
730783 }
731784 }
732785 } ;
0 commit comments