import * as Backbone from 'backbone' ; const ElementProto = Element . prototype ; const matchesSelector = ElementProto . matches || ElementProto [ 'webkitMatchesSelector' ] || ElementProto [ 'mozMatchesSelector' ] || ElementProto [ 'msMatchesSelector' ] || ElementProto [ 'oMatchesSelector' ] || function matches ( selector ) : boolean { const matches = ( this . document || this . ownerDocument ) . querySelectorAll ( selector ) ; let i = matches . length ; while ( -- i >= 0 && matches . item ( i ) !== this ) { continue ; } return i > - 1 ; } ; interface IDOMEvent { eventName : string ; handler : any ; listener : any ; selector : string ; } export class NativeView < T extends Backbone . Model > extends Backbone . View < T > { _removeElement ( ) { this . undelegateEvents ( ) ; if ( this . el . parentNode ) { this . el . parentNode . removeChild ( this . el ) ; } } _setElement ( element ) { this . el = element ; } _setAttributes ( attrs ) { for ( const attr in attrs ) { attr in this . el ? ( ( this . el as any ) [ attr ] = attrs [ attr ] ) : this . el . setAttribute ( attr , attrs [ attr ] ) ; } } /**
     * Make an event delegation handler for the given `eventName` and `selector`
     * and attach it to `this.el`.
     * If selector is empty, the listener will be bound to `this.el`. If not, a
     * new handler that will recursively traverse up the event target's DOM
     * hierarchy looking for a node that matches the selector. If one is found,
     * the event's `delegateTarget` property is set to it and the return the
     * result of calling bound `listener` with the parameters given to the
     * handler.
     *
     * This does not properly handle selectors for things like focus and blur (see
     * https://github.com/jquery/jquery/blob/7d21f02b9ec9f655583e898350badf89165ed4d5/src/event.js#L442
     * for some similar exceptional cases).
     */ delegate ( eventName , listener ) ; delegate ( eventName , selector , listener ) ; delegate ( eventName , selector , listener ? ) { if ( typeof selector !== 'string' ) { listener = selector ; selector = null ! ; } if ( this . _domEvents === void 0 ) { this . _domEvents = [ ] ; } const root = this . el ; const handler = selector ? function ( e ) : any { let node = ( e . target as HTMLElement ) || ( e . srcElement as HTMLElement ) ; for ( ; node && node !== root ; node = node . parentNode as HTMLElement ) { if ( matchesSelector . call ( node , selector ) ) { ( e as any ) . delegateTarget = node ; if ( listener . handleEvent ) { return listener . handleEvent ( e ) ; } else { return listener ( e ) ; } } } } : listener ; this . el . addEventListener ( eventName , handler , false ) ; this . _domEvents . push ( { eventName , handler , listener , selector } ) ; return handler ; } undelegate ( eventName , selector ? , listener ? ) ; undelegate ( selector , listener ? ) ; undelegate ( eventName , selector ? , listener ? ) { if ( typeof selector === 'function' ) { listener = selector ; selector = null ! ; } if ( this . el && this . _domEvents ) { const handlers = this . _domEvents . slice ( ) ; let i = handlers . length ; while ( i -- ) { const item = handlers [ i ] ; const match = item . eventName === eventName && ( listener ? item . listener === listener : true ) && ( selector ? item . selector === selector : true ) ; if ( ! match ) { continue ; } this . el . removeEventListener ( item . eventName , item . handler , false ) ; this . _domEvents . splice ( i , 1 ) ; } } return this ; } undelegateEvents ( ) { if ( this . el && this . _domEvents ) { const len = this . _domEvents . length ; for ( let i = 0 ; i < len ; i ++ ) { const item = this . _domEvents [ i ] ; this . el . removeEventListener ( item . eventName , item . handler , false ) ; } this . _domEvents . length = 0 ; } return this ; } private _domEvents : IDOMEvent [ ] ; }