import { Optional } from 'aurelia-dependency-injection' ; import { TaskQueue } from 'aurelia-task-queue' ; import { ValidationController } from './validation-controller' ; import { validateTrigger } from './validate-trigger' ; import { getTargetDOMElement } from './get-target-dom-element' ; import { getPropertyInfo } from './property-info' ; import { Expression } from 'aurelia-binding' ; /**
 * Binding behavior. Indicates the bound property should be validated.
 */ export abstract class ValidateBindingBehaviorBase { constructor ( private taskQueue ) { } protected abstract getValidateTrigger ( controller ) ; public bind ( binding , source , rulesOrController ? , rules ? ) { const target = getTargetDOMElement ( binding , source ) ; let controller ; if ( rulesOrController instanceof ValidationController ) { controller = rulesOrController ; } else { controller = source . container . get ( Optional . of ( ValidationController ) ) ; rules = rulesOrController ; } if ( controller === null ) { throw new Error ( `A ValidationController has not been registered.` ) ; } controller . registerBinding ( binding , target , rules ) ; binding . validationController = controller ; const trigger = this . getValidateTrigger ( controller ) ; const event = ( trigger & validateTrigger . blur ) === validateTrigger . blur ? 'blur' : ( trigger & validateTrigger . focusout ) === validateTrigger . focusout ? 'focusout' : null ; const hasChangeTrigger = ( trigger & validateTrigger . change ) === validateTrigger . change ; binding . isDirty = ! hasChangeTrigger ; binding . validatedOnce = hasChangeTrigger && event === null ; if ( hasChangeTrigger ) { binding . vbbUpdateSource = binding . updateSource ; binding . updateSource = function ( value ) { this . vbbUpdateSource ( value ) ; this . isDirty = true ; if ( this . validatedOnce ) { this . validationController . validateBinding ( this ) ; } } ; } if ( event !== null ) { binding . focusLossHandler = ( ) => { this . taskQueue . queueMicroTask ( ( ) => { if ( binding . isDirty ) { controller . validateBinding ( binding ) ; binding . validatedOnce = true ; } } ) ; } ; binding . validationTriggerEvent = event ; binding . validateTarget = target ; target . addEventListener ( event , binding . focusLossHandler ) ; if ( hasChangeTrigger ) { const { propertyName } = getPropertyInfo ( binding . sourceExpression as Expression , binding . source ) ! ; binding . validationSubscription = controller . subscribe ( ( event ) => { if ( ! binding . validatedOnce && event . type === 'validate' ) { binding . validatedOnce = event . errors . findIndex ( ( e ) => e . propertyName === propertyName ) > - 1 ; } } ) ; } } if ( trigger !== validateTrigger . manual ) { binding . standardUpdateTarget = binding . updateTarget ; binding . updateTarget = function ( value ) { this . standardUpdateTarget ( value ) ; this . validationController . resetBinding ( this ) ; } ; } } public unbind ( binding ) { if ( binding . vbbUpdateSource ) { binding . updateSource = binding . vbbUpdateSource ; binding . vbbUpdateSource = null ; } if ( binding . standardUpdateTarget ) { binding . updateTarget = binding . standardUpdateTarget ; binding . standardUpdateTarget = null ; } if ( binding . focusLossHandler ) { binding . validateTarget . removeEventListener ( binding . validationTriggerEvent , binding . focusLossHandler ) ; binding . focusLossHandler = null ; binding . validateTarget = null ; } if ( binding . validationSubscription ) { binding . validationSubscription . dispose ( ) ; binding . validationSubscription = null ; } binding . validationController . unregisterBinding ( binding ) ; binding . validationController = null ; binding . isDirty = null ; binding . validatedOnce = null ; } }