import { MdcComponent } from '@aurelia-mdc-web/base' ; import { MDCSliderAdapter , Thumb , cssClasses , TickMark , MDCSliderChangeEventDetail , events , attributes } from '@material/slider' ; import { bindable } from 'aurelia-typed-observable-plugin' ; import { inject , useView , PLATFORM , customElement } from 'aurelia-framework' ; import { MdcSliderFoundationAurelia } from './mdc-slider-foundation-aurelia' ; import { MdcRipple } from '@aurelia-mdc-web/ripple' ; import { EventType , SpecificEventListener } from '@material/base' ; events . INPUT = events . INPUT . toLowerCase ( ) ; events . CHANGE = events . CHANGE . toLowerCase ( ) ; interface IEventHandler { element : HTMLElement | Window ; evtType : EventType ; handler : SpecificEventListener < EventType > ; } @ inject ( Element ) @ useView ( PLATFORM . moduleName ( './mdc-slider.html' ) ) @ customElement ( 'mdc-slider' ) export class MdcSlider extends MdcComponent < MdcSliderFoundationAurelia > { constructor ( root ) { super ( root ) ; defineMdcSliderElementApis ( this . root ) ; } private startInput ? : HTMLInputElement ; private endInput : HTMLInputElement ; private startThumb ? : HTMLElement ; private endThumb : HTMLElement ; private startRipple ? : MdcRipple ; private endRipple : MdcRipple ; private trackActive : HTMLElement ; tickMarkStatuses : TickMark [ ] ; TickMark = TickMark ; eventHandlers : IEventHandler [ ] = [ ] ; @ bindable . booleanAttr discrete : boolean ; @ bindable . booleanAttr tickMarks : boolean ; @ bindable . booleanAttr range : boolean ; @ bindable . booleanAttr disabled : boolean ; async disabledChanged ( ) { await this . initialised ; this . foundation ?. setDisabled ( this . disabled ) ; } @ bindable . number min : number = 0 ; async minChanged ( ) { await this . initialised ; ( this . startInput ?? this . endInput ) ?. setAttribute ( attributes . INPUT_MIN , this . min . toString ( ) ) ; this . foundation ?. destroy ( ) ; this . cleanupEventHandlers ( ) ; if ( this . range && this . valueStart < this . min ) { this . valueStart = this . min ; this . emit ( events . CHANGE , { value : this . value , thumb : Thumb . START } , true ) ; } if ( this . value < this . min ) { this . value = this . min ; this . emit ( events . CHANGE , { value : this . value , thumb : Thumb . END } , true ) ; } this . foundation ?. init ( ) ; this . foundation ?. layout ( ) ; } @ bindable . number max : number = 100 ; async maxChanged ( ) { await this . initialised ; this . endInput ?. setAttribute ( attributes . INPUT_MAX , this . max . toString ( ) ) ; this . foundation ?. destroy ( ) ; this . cleanupEventHandlers ( ) ; if ( this . range && this . valueStart > this . max ) { this . valueStart = this . max ; this . emit ( events . CHANGE , { value : this . value , thumb : Thumb . START } , true ) ; } if ( this . value > this . max ) { this . value = this . max ; this . emit ( events . CHANGE , { value : this . value , thumb : Thumb . END } , true ) ; } this . foundation ?. init ( ) ; this . foundation ?. layout ( ) ; } @ bindable step : string = '1' ; async stepChanged ( ) { await this . initialised ; this . startInput ?. setAttribute ( attributes . INPUT_STEP , this . step ) ; this . endInput ?. setAttribute ( attributes . INPUT_STEP , this . step ) ; this . foundation ?. destroy ( ) ; this . cleanupEventHandlers ( ) ; this . foundation ?. init ( ) ; } @ bindable valueToAriaValueTextFn : ( ( value : number ) => string ) | null = null ; _value : number = 0 ; get value ( ) : number { if ( this . foundation ) { return this . foundation . getValue ( ) ; } else { return this . _value ; } } set value ( value ) { this . _value = value ; this . foundation ?. setValue ( value ) ; } _valueStart : number = 0 ; get valueStart ( ) : number { if ( this . foundation ) { return this . foundation . getValueStart ( ) ; } else { return this . _valueStart ; } } set valueStart ( value ) { this . _valueStart = value ; this . foundation ?. setValueStart ( value ) ; } bind ( ) { } async initialise ( ) { this . endInput . setAttribute ( attributes . INPUT_MIN , this . min . toString ( ) ) ; this . endInput . setAttribute ( attributes . INPUT_MAX , this . max . toString ( ) ) ; this . endInput . setAttribute ( attributes . INPUT_VALUE , this . value . toString ( ) ) ; this . endInput . setAttribute ( attributes . INPUT_STEP , this . step ) ; this . startInput ?. setAttribute ( attributes . INPUT_VALUE , this . valueStart . toString ( ) ) ; this . startInput ?. setAttribute ( attributes . INPUT_STEP , this . step ) ; } initialSyncWithDOM ( ) { this . value = this . _value ; if ( this . range ) { this . valueStart = this . _valueStart ; } this . foundation ?. layout ( ) ; this . disabledChanged ( ) ; } getDefaultFoundation ( ) { const adapter = { hasClass : ( className ) => this . root . classList . contains ( className ) , addClass : ( className ) => { this . root . classList . add ( className ) ; } , removeClass : ( className ) => { this . root . classList . remove ( className ) ; } , addThumbClass : ( className , thumb ) => { this . getThumbEl ( thumb ) ?. classList . add ( className ) ; } , removeThumbClass : ( className , thumb ) => { this . getThumbEl ( thumb ) ?. classList . remove ( className ) ; } , getAttribute : ( attribute ) => this . root . getAttribute ( attribute ) , getInputValue : ( thumb ) => this . getInput ( thumb ) ! . value , setInputValue : ( value , thumb ) => { this . getInput ( thumb ) ! . value = value ; } , getInputAttribute : ( attribute , thumb ) => this . getInput ( thumb ) ! . getAttribute ( attribute ) , setInputAttribute : ( attribute , value , thumb ) => { this . getInput ( thumb ) ! . setAttribute ( attribute , value ) ; } , removeInputAttribute : ( attribute , thumb ) => { this . getInput ( thumb ) ?. removeAttribute ( attribute ) ; } , focusInput : ( thumb ) => { this . getInput ( thumb ) ?. focus ( ) ; } , isInputFocused : ( thumb ) => this . getInput ( thumb ) === document . activeElement , getThumbKnobWidth : ( thumb ) => { return this . getThumbEl ( thumb ) ?. querySelector < HTMLElement > ( `.${ cssClasses . THUMB_KNOB }` ) ! . getBoundingClientRect ( ) . width ?? 0 ; } , getThumbBoundingClientRect : ( thumb ) => this . getThumbEl ( thumb ) ! . getBoundingClientRect ( ) , getBoundingClientRect : ( ) => this . root . getBoundingClientRect ( ) , isRTL : ( ) => getComputedStyle ( this . root ) . direction === 'rtl' , setThumbStyleProperty : ( propertyName , value , thumb ) => { this . getThumbEl ( thumb ) ?. style . setProperty ( propertyName , value ) ; } , removeThumbStyleProperty : ( propertyName , thumb ) => { this . getThumbEl ( thumb ) ?. style . removeProperty ( propertyName ) ; } , setTrackActiveStyleProperty : ( propertyName , value ) => { this . trackActive . style . setProperty ( propertyName , value ) ; } , removeTrackActiveStyleProperty : ( propertyName ) => { this . trackActive . style . removeProperty ( propertyName ) ; } , setValueIndicatorText : ( value , thumb ) => { const valueIndicatorEl = this . getThumbEl ( thumb ) ?. querySelector < HTMLElement > ( `.${ cssClasses . VALUE_INDICATOR_TEXT }` ) ; valueIndicatorEl ! . textContent = String ( value ) ; } , getValueToAriaValueTextFn : ( ) => this . valueToAriaValueTextFn , updateTickMarks : ( tickMarks ) => { this . tickMarkStatuses = tickMarks ; } , setPointerCapture : ( pointerId ) => { this . root . setPointerCapture ( pointerId ) ; } , emitChangeEvent : ( value , thumb ) => { this . emit < MDCSliderChangeEventDetail > ( events . CHANGE , { value , thumb } ) ; } , emitInputEvent : ( value , thumb ) => { this . emit < MDCSliderChangeEventDetail > ( events . INPUT , { value , thumb } ) ; } , emitDragStartEvent : ( _ , thumb ) => { this . getRipple ( thumb ) ?. activate ( ) ; } , emitDragEndEvent : ( _ , thumb ) => { this . getRipple ( thumb ) ?. deactivate ( ) ; } , registerEventHandler : ( evtType , handler ) => { this . listen ( evtType , handler ) ; this . addEventHandler ( this . root , evtType , handler ) ; } , deregisterEventHandler : ( evtType , handler ) => { this . unlisten ( evtType , handler ) ; this . removeEventHandler ( this . root , evtType , handler ) ; } , registerThumbEventHandler : ( thumb , evtType , handler ) => { const thumbEl = this . getThumbEl ( thumb ) ; if ( thumbEl ) { thumbEl . addEventListener ( evtType , handler ) ; this . addEventHandler ( thumbEl , evtType , handler ) ; } } , deregisterThumbEventHandler : ( thumb , evtType , handler ) => { const thumbEl = this . getThumbEl ( thumb ) ; if ( thumbEl ) { thumbEl . removeEventListener ( evtType , handler ) ; this . removeEventHandler ( thumbEl , evtType , handler ) ; } } , registerInputEventHandler : ( thumb , evtType , handler ) => { const thumbInput = this . getInput ( thumb ) ; if ( thumbInput ) { thumbInput . addEventListener ( evtType , handler ) ; this . addEventHandler ( thumbInput , evtType , handler ) ; } } , deregisterInputEventHandler : ( thumb , evtType , handler ) => { const thumbInput = this . getInput ( thumb ) ; if ( thumbInput ) { thumbInput . removeEventListener ( evtType , handler ) ; this . removeEventHandler ( thumbInput , evtType , handler ) ; } } , registerBodyEventHandler : ( evtType , handler ) => { document . body . addEventListener ( evtType , handler ) ; this . addEventHandler ( document . body , evtType , handler ) ; } , deregisterBodyEventHandler : ( evtType , handler ) => { document . body . removeEventListener ( evtType , handler ) ; this . removeEventHandler ( document . body , evtType , handler ) ; } , registerWindowEventHandler : ( evtType , handler ) => { window . addEventListener ( evtType , handler ) ; this . addEventHandler ( window , evtType , handler ) ; } , deregisterWindowEventHandler : ( evtType , handler ) => { window . removeEventListener ( evtType , handler ) ; this . removeEventHandler ( window , evtType , handler ) ; } , } ; return new MdcSliderFoundationAurelia ( adapter ) ; } addEventHandler ( element , evtType , handler ) { this . eventHandlers . push ( { element , evtType , handler } ) ; } removeEventHandler ( element , evtType , handler ) { const i = this . eventHandlers . findIndex ( x => x . element === element && x . evtType === evtType && x . handler === handler ) ; if ( i !== - 1 ) { this . eventHandlers . splice ( i , 1 ) ; } } cleanupEventHandlers ( ) { this . eventHandlers . forEach ( x => { x . element . removeEventListener ( x . evtType , x . handler ) ; } ) ; this . eventHandlers = [ ] ; } getThumbEl ( thumb ) { return thumb === Thumb . END ? this . endThumb : this . startThumb ; } private getInput ( thumb ) { return thumb === Thumb . END ? this . endInput : this . startInput ; } private getRipple ( thumb ) { return thumb === Thumb . END ? this . endRipple : this . startRipple ; } focus ( ) { this . root . focus ( ) ; } blur ( ) { this . root . blur ( ) ; } } hidden export interface IMdcSliderElement extends HTMLElement { value : number ; valuestart : number ; indeterminate : boolean ; au : { controller : { viewModel : MdcSlider ; } ; } ; } function defineMdcSliderElementApis ( element ) { Object . defineProperties ( element , { value : { get ( this ) { return this . au . controller . viewModel . value ; } , set ( this , value ) { this . au . controller . viewModel . value = value ; } , configurable : true } , valuestart : { get ( this ) { return this . au . controller . viewModel . valueStart ; } , set ( this , value ) { this . au . controller . viewModel . valueStart = value ; } , configurable : true } , focus : { value ( this ) { this . au . controller . viewModel . focus ( ) ; } , configurable : true } , blur : { value ( this ) { this . au . controller . viewModel . blur ( ) ; } , configurable : true } } ) ; }