import { ESLBaseElement } from '../../../esl-base-element/core' ; import { EventUtils } from '../../../esl-utils/dom/events' ; import { bind } from '../../../esl-utils/decorators/bind' ; /** Interface for option definition */ export interface ESLSelectOption { /** Label text of the option */ text : string ; /** Value of the option */ value : string ; /** Disabled marker */ disabled : boolean ; /** Selected marker */ selected : boolean ; /** Initially selected marker */ defaultSelected : boolean ; } /** Interface to declare options source for select components */ export interface ESLSelectModel { /** Allow multiple items */ multiple : boolean ; /** Get list of options */ options : ESLSelectOption [ ] ; /** Get list of selected options */ selectedOptions : ESLSelectOption [ ] ; /** Toggle option with passed value to the state */ setSelected ( value , state ) : void ; /** Check selected state*/ isSelected ( value ) : boolean ; /** Has selected options */ hasSelected ( ) : boolean ; /** Check that all options are selected */ isAllSelected ( ) : boolean ; /** Toggle all options to the state */ setAllSelected ( state ) : void ; } /**
 * Base class for  HTMLSelectElement wrapper element, implements  ESLSelectModel options source
  export abstract class ESLSelectWrapper extends ESLBaseElement implements ESLSelectModel { protected static observationConfig : MutationObserverInit = { subtree : true , attributes : true , attributeFilter : [ 'value' , 'selected' , 'disabled' ] , childList : true , characterData : true } ; private _$select : HTMLSelectElement ; private _mutationObserver = new MutationObserver ( this . _onTargetMutation . bind ( this ) ) ; /** Native select that is wrapped */ public get $select ( ) : HTMLSelectElement { return this . _$select ; } public set $select ( select ) { const prev = this . _$select ; this . _$select = select ; this . _onTargetChange ( select , prev ) ; } protected connectedCallback ( ) { super . connectedCallback ( ) ; this . ownerDocument . addEventListener ( 'reset' , this . _onReset ) ; } protected disconnectedCallback ( ) { super . disconnectedCallback ( ) ; this . ownerDocument . removeEventListener ( 'reset' , this . _onReset ) ; this . _mutationObserver . disconnect ( ) ; this . _$select && this . _$select . removeEventListener ( 'change' , this . _onChange ) ; } protected _onChange ( event ? ) { } protected _onListChange ( ) { } protected _onTargetChange ( newTarget , oldTarget ) { if ( oldTarget ) oldTarget . removeEventListener ( 'change' , this . _onChange ) ; if ( newTarget ) newTarget . addEventListener ( 'change' , this . _onChange ) ; this . _mutationObserver . disconnect ( ) ; const type = ( this . constructor as typeof ESLSelectWrapper ) ; if ( newTarget ) this . _mutationObserver . observe ( newTarget , type . observationConfig ) ; } protected _onTargetMutation ( changes ) { const isListChange = ( change ) : boolean => change . addedNodes . length + change . removedNodes . length > 0 ; changes . some ( isListChange ) ? this . _onListChange ( ) : this . _onChange ( ) ; } @ bind protected _onReset ( event ) { if ( ! event . target || event . target !== this . form ) return ; setTimeout ( ( ) => this . _onChange ( event ) ) ; } public get multiple ( ) : boolean { return this . $select && this . $select . multiple ; } public get options ( ) : ESLSelectOption [ ] { return this . $select ? Array . from ( this . $select . options ) : [ ] ; } public get selectedOptions ( ) : ESLSelectOption [ ] { return this . options . filter ( ( item ) => item . selected ) ; } protected getOption ( value ) { return this . options . find ( ( item ) => item . value === value ) ; } public setSelected ( value , state ) { const option = this . getOption ( value ) ; option && ( option . selected = state ) ; EventUtils . dispatch ( this . $select , 'change' ) ; } public isSelected ( value ) { const opt = this . getOption ( value ) ; return ! ! opt && opt . selected ; } public hasSelected ( ) { return this . options . some ( ( item ) => item . selected ) ; } public isAllSelected ( ) { return this . options . every ( ( item ) => item . selected || item . disabled ) ; } public setAllSelected ( state ) { if ( ! this . multiple ) return ; this . options . forEach ( ( item ) => item . selected = ! item . disabled && state ) ; EventUtils . dispatch ( this . $select , 'change' ) ; } public get value ( ) : string | undefined { return this . $select ?. value ; } public get values ( ) : string [ ] { return this . selectedOptions . map ( ( item ) => item . value ) ; } public get form ( ) : HTMLFormElement | null { return this . $select ?. form ; } public get name ( ) : string { return this . $select ?. name ; } public set name ( name ) { this . $select && ( this . $select . name = name ) ; } public get required ( ) : boolean { return this . $select ?. required ; } public set required ( required ) { this . $select && ( this . $select . required = required ) ; } public get validity ( ) : ValidityState { return this . $select ?. validity ; } public get validationMessage ( ) : string { return this . $select ?. validationMessage ; } public get willValidate ( ) : boolean { return this . $select ?. willValidate ; } public checkValidity ( ) { return this . $select ?. checkValidity ( ) ; } public reportValidity ( ) { return this . $select ?. reportValidity ( ) ; } public setCustomValidity ( error ) { this . $select ?. setCustomValidity ( error ) ; } }