license import { assert , assertCloseMatchesOpenTag , assertInAttributes , assertInPatch , assertNotInAttributes , assertNotInSkip , setInAttributes } from "./assertions" ; import { attributes , updateAttribute } from "./attributes" ; import { getArgsBuilder , getAttrsBuilder , close , open , text as coreText , currentElement } from "./core" ; import { DEBUG } from "./global" ; import { getData , NodeData } from "./node_data" ; import { AttrMutatorConfig , Key , NameOrCtorDef , Statics } from "./types" ; import { createMap , truncateArray } from "./util" ; import { calculateDiff } from "./diff" ; /**
 * The offset in the virtual element declaration where the attributes are
 * specified.
 */ const ATTRIBUTES_OFFSET = 3 ; /**
 * Used to keep track of the previous values when a 2-way diff is necessary.
 * This object is reused.
 * TODO(sparhamI) Scope this to a patch so you can call patch from an attribute
 * update.
 */ const prevAttrsMap = createMap ( ) ; param element param data param attrs function diffAttrs ( element , data , attrs ) { const attrsBuilder = getAttrsBuilder ( ) ; const prevAttrsArr = data . getAttrsArr ( attrsBuilder . length ) ; calculateDiff ( prevAttrsArr , attrsBuilder , element , updateAttribute , attrs , data . alwaysDiffAttributes ) ; truncateArray ( attrsBuilder , 0 ) ; } param node param data param statics param attrs function diffStatics ( node , data , statics , attrs ) { if ( data . staticsApplied ) { return ; } data . staticsApplied = true ; if ( ! statics || ! statics . length ) { return ; } if ( data . hasEmptyAttrsArr ( ) ) { for ( let i = 0 ; i < statics . length ; i += 2 ) { updateAttribute ( node , statics [ i ] as string , statics [ i + 1 ] , attrs ) ; } return ; } for ( let i = 0 ; i < statics . length ; i += 2 ) { prevAttrsMap [ statics [ i ] as string ] = i + 1 ; } const attrsArr = data . getAttrsArr ( 0 ) ; let j = 0 ; for ( let i = 0 ; i < attrsArr . length ; i += 2 ) { const name = attrsArr [ i ] ; const value = attrsArr [ i + 1 ] ; const staticsIndex = prevAttrsMap [ name ] ; if ( staticsIndex ) { if ( statics [ staticsIndex ] === value ) { delete prevAttrsMap [ name ] ; } continue ; } attrsArr [ j ] = name ; attrsArr [ j + 1 ] = value ; j += 2 ; } truncateArray ( attrsArr , j ) ; for ( const name in prevAttrsMap ) { updateAttribute ( node , name , statics [ prevAttrsMap [ name ] ] , attrs ) ; delete prevAttrsMap [ name ] ; } } param nameOrCtor param key param statics function elementOpenStart ( nameOrCtor , key ? , statics ? ) { const argsBuilder = getArgsBuilder ( ) ; if ( DEBUG ) { assertNotInAttributes ( "elementOpenStart" ) ; setInAttributes ( true ) ; } argsBuilder [ 0 ] = nameOrCtor ; argsBuilder [ 1 ] = key ; argsBuilder [ 2 ] = statics ; } param key function key ( key ) { const argsBuilder = getArgsBuilder ( ) ; if ( DEBUG ) { assertInAttributes ( "key" ) ; assert ( argsBuilder ) ; } argsBuilder [ 1 ] = key ; } param name param value function attr ( name , value ) { const attrsBuilder = getAttrsBuilder ( ) ; if ( DEBUG ) { assertInPatch ( "attr" ) ; } attrsBuilder . push ( name ) ; attrsBuilder . push ( value ) ; } return function getNonce ( ) { const argsBuilder = getArgsBuilder ( ) ; const statics = < Statics > argsBuilder [ 2 ] ; if ( statics ) { for ( let i = 0 ; i < statics . length ; i += 2 ) { if ( statics [ i ] === "nonce" ) { return statics [ i + 1 ] as string ; } } } return "" ; } return function elementOpenEnd ( ) { const argsBuilder = getArgsBuilder ( ) ; if ( DEBUG ) { assertInAttributes ( "elementOpenEnd" ) ; setInAttributes ( false ) ; } const node = open ( < NameOrCtorDef > argsBuilder [ 0 ] , < Key > argsBuilder [ 1 ] , getNonce ( ) ) ; const data = getData ( node ) ; diffStatics ( node , data , < Statics > argsBuilder [ 2 ] , attributes ) ; diffAttrs ( node , data , attributes ) ; truncateArray ( argsBuilder , 0 ) ; return node ; } param nameOrCtor param key param statics param varArgs return function elementOpen ( nameOrCtor , key ? , statics ? , ... varArgs ) { if ( DEBUG ) { assertNotInAttributes ( "elementOpen" ) ; assertNotInSkip ( "elementOpen" ) ; } elementOpenStart ( nameOrCtor , key , statics ) ; for ( let i = ATTRIBUTES_OFFSET ; i < arguments . length ; i += 2 ) { attr ( arguments [ i ] , arguments [ i + 1 ] ) ; } return elementOpenEnd ( ) ; } param attrs function applyAttrs ( attrs = attributes ) { const node = currentElement ( ) ; const data = getData ( node ) ; diffAttrs ( node , data , attrs ) ; } param statics param attrs function applyStatics ( statics , attrs = attributes ) { const node = currentElement ( ) ; const data = getData ( node ) ; diffStatics ( node , data , statics , attrs ) ; } param nameOrCtor return function elementClose ( nameOrCtor ) { if ( DEBUG ) { assertNotInAttributes ( "elementClose" ) ; } const node = close ( ) ; if ( DEBUG ) { assertCloseMatchesOpenTag ( getData ( node ) . nameOrCtor , nameOrCtor ) ; } return node ; } param nameOrCtor param key param statics param varArgs return function elementVoid ( nameOrCtor , key ? , statics ? , ... varArgs ) { elementOpen . apply ( null , arguments as any ) ; return elementClose ( nameOrCtor ) ; } param value param varArgs return function text ( value , ... varArgs ) { if ( DEBUG ) { assertNotInAttributes ( "text" ) ; assertNotInSkip ( "text" ) ; } const node = coreText ( ) ; const data = getData ( node ) ; if ( data . text !== value ) { data . text = value as string ; let formatted = value ; for ( let i = 1 ; i < arguments . length ; i += 1 ) { const fn = arguments [ i ] ; formatted = fn ( formatted ) ; } if ( node . data !== formatted ) { node . data = formatted as string ; } } return node ; } /** */ export { applyAttrs , applyStatics , elementOpenStart , elementOpenEnd , elementOpen , elementVoid , elementClose , text , attr , key } ;