interface ElementConstructor { new ( ... args ) : HTMLElement ; } /**
 * A very simplified CustomElementsRegistry to maintain tag to constructor
 * mapping
 * TODO: Implement `whenDefined`.
 */ class CustomElementsRegistry { private registry = new Map < string , ElementConstructor > ( ) ; private reverseRegistry = new Map < { } , string > ( ) ; define ( name , constructor ) { this . registry . set ( name , constructor ) ; this . reverseRegistry . set ( constructor . prototype , name ) ; } get ( name ) { return this . registry . get ( name ) ; } getName ( proto ) { return this . reverseRegistry . get ( proto ) ; } } enum MutationType { VALUE = 1 , ATTR = 2 , REMOVE_ATTR = 3 , REMOVE = 4 , MOVE = 5 , INSERT = 6 } interface DominoMutationEvent { type : MutationType ; target : HTMLElement & { [ k ] : Function | undefined ; } ; node ? : HTMLElement & { [ k ] : Function | undefined ; } ; attr ? : { data : string ; name : string ; } ; } function nextTick ( fn ) { Promise . resolve ( null ) . then ( fn ) ; } function callConnectedCallback ( node ) { if ( typeof ( node as any ) [ 'connectedCallback' ] === 'function' ) { nextTick ( ( ) => ( ( node as any ) [ 'connectedCallback' ] as Function ) . call ( node , node ) ) ; } } function callAttributeChangedCallback ( clss , target , attr , newValue ) { if ( ( clss as any ) [ 'observedAttributes' ] == null ) { return ; } if ( ( clss as any ) [ 'observedAttributes' ] . indexOf ( attr . name ) > - 1 && typeof ( target as any ) [ 'attributeChangedCallback' ] === 'function' ) { ( target as any ) [ 'attributeChangedCallback' ] ! . call ( target , attr . name , undefined , newValue ) ; } } function upgradeNode ( node ) { const doc = ( node . ownerDocument as any ) ; const customElements = doc . __ce__ ; const localName = node . localName ; const clss = localName != null ? customElements . get ( localName ) : undefined ; const name = customElements . getName ( Object . getPrototypeOf ( node ) ) ; let upgraded = false ; if ( name != null && ( node as any ) . __ceClass__ == null ) { const clss = customElements . get ( name ) ! ; ( node as any ) . __ceClass__ = clss ; ( node as any ) . localName = name ; ( node as any ) . tagName = name . toUpperCase ( ) ; const attrs = Array . from ( node . attributes ) ; for ( const attr of attrs ) { callAttributeChangedCallback ( clss , node , attr , node . getAttribute ( attr . name ) ! ) ; } upgraded = true ; } if ( localName != null && clss != null && ( node as any ) . __ceClass__ == null ) { const instance = new clss ( ) ; for ( const k in instance ) { if ( ! node . hasOwnProperty ( k ) ) { ( node as any ) [ k ] = ( instance as any ) [ k ] ; } } ( node as any ) . __ceClass__ = clss ; ( Object as any ) . setPrototypeOf ( node , clss . prototype ) ; const attrs = Array . from ( node . attributes ) ; for ( const attr of attrs ) { callAttributeChangedCallback ( clss , node , attr , node . getAttribute ( attr . name ) ! ) ; } upgraded = true ; } if ( upgraded ) { callConnectedCallback ( node ) ; } } function callDisconnectedCallback ( node ) { if ( typeof ( node as any ) [ 'disconnectedCallback' ] === 'function' ) { nextTick ( ( ) => ( node as any ) [ 'disconnectedCallback' ] . call ( node ) ) ; } } function recursivelyRoot ( node ) { upgradeNode ( node ) ; for ( let kid = node . firstChild ; kid !== null ; kid = kid . nextSibling ) { recursivelyRoot ( kid as HTMLElement ) ; } } function recursivelyUproot ( node ) { callDisconnectedCallback ( node ) ; for ( let kid = node . firstChild ; kid !== null ; kid = kid . nextSibling ) { recursivelyUproot ( kid as HTMLElement ) ; } } /**
 * Patch a Document object to support upgrading known custom elements when they
 * are created.
 */ export function patchDocument ( doc ) { if ( ( doc as any ) . __ce__ ) { return ; } ( doc as any ) . __ce__ = new CustomElementsRegistry ( ) ; const oldMutationHandler = ( doc as any ) . mutationHandler ; ( doc as any ) . _setMutationHandler ( ( event ) => { const target = event . target ; const node = event . node ! ; switch ( event . type ) { case MutationType . INSERT : recursivelyRoot ( node ) ; break ; case MutationType . REMOVE : recursivelyUproot ( node ) ; break ; case MutationType . ATTR : case MutationType . REMOVE_ATTR : const attr = event . attr ! ; const clss = target . __ceClass__ ; const newValue = event . type === MutationType . ATTR ? attr . data : undefined ; if ( clss ) { callAttributeChangedCallback ( clss , target , attr , newValue ) ; } break ; default : } if ( oldMutationHandler ) { oldMutationHandler ( event ) ; } } ) ; }