import { assign } from './utils' ; import { WidgetModel , WidgetView , DOMWidgetView } from './widget' ; /**
 * Three functions to deal with some CSS attributes
 * to make them easier to use.
 */ export class StyleModel extends WidgetModel { defaults ( ) { const Derived = this . constructor as typeof StyleModel ; return assign ( super . defaults ( ) , { _model_name : 'StyleModel' , _view_name : 'StyleView' , } , Object . keys ( Derived . styleProperties ) . reduce ( ( obj , key ) => { obj [ key ] = Derived . styleProperties [ key ] . default ; return obj ; } , { } ) ) ; } public static styleProperties : { [ s ] : IStyleProperty ; } = { } ; } interface IStyleProperty { attribute : string ; selector : string ; default : string ; } export class StyleView extends WidgetView { /**
     * Public constructor
     */ initialize ( parameters ) { this . _traitNames = [ ] ; super . initialize ( parameters ) ; const ModelType = this . model . constructor as typeof StyleModel ; for ( const key of Object . keys ( ModelType . styleProperties ) ) { this . registerTrait ( key ) ; } this . style ( ) ; } param trait registerTrait ( trait ) { this . _traitNames . push ( trait ) ; this . listenTo ( this . model , 'change:' + trait , ( model , value ) => { this . handleChange ( trait , value ) ; } ) ; } /**
     * Handles when a trait value changes
     */ handleChange ( trait , value ) { const parent = this . options . parent as DOMWidgetView ; if ( parent ) { const ModelType = this . model . constructor as typeof StyleModel ; const styleProperties = ModelType . styleProperties ; const attribute = styleProperties [ trait ] . attribute ; const selector = styleProperties [ trait ] . selector ; const elements = selector ? parent . el . querySelectorAll < HTMLElement > ( selector ) : [ parent . el ] ; if ( value === null ) { for ( let i = 0 ; i !== elements . length ; ++ i ) { elements [ i ] . style . removeProperty ( attribute ) ; } } else { for ( let i = 0 ; i !== elements . length ; ++ i ) { elements [ i ] . style . setProperty ( attribute , value ) ; } } } else { console . warn ( 'Style not applied because a parent view does not exist' ) ; } } /**
     * Apply styles for all registered traits
     */ style ( ) { for ( const trait of this . _traitNames ) { this . handleChange ( trait , this . model . get ( trait ) ) ; } } /**
     * Remove the styling from the parent view.
     */ unstyle ( ) { const parent = this . options . parent as DOMWidgetView ; const ModelType = this . model . constructor as typeof StyleModel ; const styleProperties = ModelType . styleProperties ; this . _traitNames . forEach ( ( trait ) => { if ( parent ) { const attribute = styleProperties [ trait ] . attribute ; const selector = styleProperties [ trait ] . selector ; const elements = selector ? parent . el . querySelectorAll < HTMLElement > ( selector ) : [ parent . el ] ; for ( let i = 0 ; i !== elements . length ; ++ i ) { elements [ i ] . style . removeProperty ( attribute ) ; } } else { console . warn ( 'Style not removed because a parent view does not exist' ) ; } } , this ) ; } private _traitNames : string [ ] ; }