import { CustomPropertyHandler , WidgetResolveResult } from "../providers/property-handler-provider" ; import * as parseXml from '../parser/types' ; import { WidgetModel , PropertyModel , AttributeInfo } from '../models/models' ; import { makeTabs } from "../utils" ; import { PropertyResolver } from "../resolvers/property-resolver" ; interface IfModel { condition : any ; childWidget : WidgetModel [ ] ; } export class IfElementHandler extends CustomPropertyHandler { isElement = true ; elementAttributes : AttributeInfo [ ] = [ { name : 'value' } ] ; valueSnippet = 'value="${0:condition}"' ; constructor ( private readonly propertyResolver ) { super ( ) ; } canResolvePropertyElement ( ) { return true ; } resolvePropertyElement ( ifElement , widgetResolveResult , parent , parentChildren , resolveWidget ) { const ifChains = [ ] ; const wrappers = [ ] ; const multipleChild = widgetResolveResult . widget instanceof Array ; const ifBoundResult = this . propertyResolver . pipeValueResolver . resolve ( ifElement , 'value' , widgetResolveResult . propertyElementProperties . filter ( a => a . name === 'value' ) [ 0 ] . value , widgetResolveResult . widget ) ; if ( ifBoundResult . wrapperWidget && multipleChild ) { throw new Error ( "::You can't use behavior or stream pipe on <if> element that has more than one child. Instead wrap the children with Column or Row." ) ; } const ifConditionValue = ifBoundResult . value ; const childWidget = multipleChild ? ( widgetResolveResult . widget as any ) : [ widgetResolveResult . widget ] ; wrappers . push ( ifBoundResult . wrapperWidget as any ) ; ifChains . push ( { condition : ifConditionValue , childWidget : [ ... childWidget ] } ) ; let elseWidget = null ; const ifChildIndex = parentChildren . indexOf ( ifElement ) ; const children = [ ... parentChildren . filter ( ( a , i ) => i >= ifChildIndex && a . type === 'element' ) . map ( a => a as parseXml . Element ) ] ; let handleChild = false ; for ( const child of children ) { if ( handleChild ) { if ( child . name === 'elseIf' || child . name === 'else' ) { const childrenWidgets = this . resolveWidgets ( child . children . filter ( a => a . type === 'element' ) as parseXml . Element [ ] , parent , resolveWidget ) ; const i = parentChildren . indexOf ( child ) ; parentChildren . splice ( i , 1 ) ; if ( child . name === 'else' ) { elseWidget = childrenWidgets ; break ; } else { const elseIfBoundResult = this . propertyResolver . pipeValueResolver . resolve ( child , 'value' , child . attributes [ 'value' ] , widgetResolveResult . widget ) ; const elseIfConditionValue = elseIfBoundResult . value ; wrappers . push ( elseIfBoundResult . wrapperWidget as any ) ; ifChains . push ( { condition : elseIfConditionValue , childWidget : childrenWidgets } ) ; } } else { break ; } } else if ( child === ifElement ) { handleChild = true ; } } const ifElementWidget = { controllers : [ ] , vars : [ ] , formControls : [ ] , properties : [ ] , type : 'if' , tempData : { ifChains , elseWidget } , wrappedWidgets : [ ] , onResolved : [ ] , isCustom : true } ; let wrapperWidget = this . createWrapperWidget ( ifChains , wrappers , ifElementWidget ) ; ifChains . forEach ( a => ifElementWidget . wrappedWidgets . push ( ... a . childWidget ) ) ; return wrapperWidget || ifElementWidget ; } private resolveWidgets ( elements , parent , resolveWidget ) { const results = [ ] ; for ( const el of elements ) { results . push ( resolveWidget ( el , parent ) . widget ) ; } return results ; } private createWrapperWidget ( ifChains , wrappers , ifElementWidget ) { const ifChainWidgets = [ ] ; ifChains . forEach ( a => ifChainWidgets . push ( ... a . childWidget ) ) ; const findIfChainWidget = ( w ) => ifChainWidgets . filter ( a => a === w ) . length === 1 ; const getIfWidgetAndItsParent = ( w ) : WidgetModel => { if ( w . wrappedWidgets && w . wrappedWidgets [ 0 ] ) { if ( ! findIfChainWidget ( w ) && findIfChainWidget ( w . wrappedWidgets [ 0 ] ) ) { return w ; } else { return getIfWidgetAndItsParent ( w . wrappedWidgets [ 0 ] ) ; } } return null as any ; } ; let wrapperWidget = null ; let lastIfChainWidget = null as any ; const reversedWrappers = wrappers . filter ( a => ! ! a ) . reverse ( ) ; for ( const wrapper of reversedWrappers ) { const ifChainParentWidget = getIfWidgetAndItsParent ( wrapper ) ; if ( wrapperWidget ) { lastIfChainWidget . wrappedWidgets = ifChainParentWidget . wrappedWidgets ; ifChainParentWidget . wrappedWidgets = [ wrapperWidget ] ; } else { ifElementWidget . wrappedWidgets = ifChainParentWidget . wrappedWidgets ; ifChainParentWidget . wrappedWidgets = [ ifElementWidget ] ; lastIfChainWidget = ifElementWidget ; } wrapperWidget = ifChainParentWidget ; } return wrapperWidget ; } canGenerate ( widget ) { return true ; } generate ( widget , tabsLevel , generateChildWidgetCode , generatePropertyCode ) { const tabs = makeTabs ( tabsLevel ) ; const itemTabs = tabs + '      ' ; const elseItemsTabs = tabs + '  ' ; const ifChains = widget . tempData . ifChains ; const hasMultipleChild = ifChains . filter ( a => a . childWidget . length > 1 ) . length > 0 || widget . tempData . elseWidget && widget . tempData . elseWidget . length > 1 ; const elseWidget = widget . tempData . elseWidget ; const defaultElseWidget = 'null' ; const elseCode = elseWidget ? elseWidget . map ( c => generateChildWidgetCode ( c , tabsLevel + 1 + ( hasMultipleChild ? 1 : 0 ) ) ) . join ( `,\n${ elseItemsTabs }  ` ) : defaultElseWidget ; let code = `${ hasMultipleChild ? '...' : '' }WidgetHelpers.ifElseChain${ hasMultipleChild ? 'MultiChild' : '' }([\n${ tabs }    ` ; code += ifChains . map ( a => { return `SwitchCase${ hasMultipleChild ? 'MultiChild' : '' }(
${ tabs }      ${ a . condition },
${ tabs }      () => ${ hasMultipleChild ? `[\n${ itemTabs }  ` : '' }${ a . childWidget . map ( c => generateChildWidgetCode ( c , tabsLevel + 3 + ( hasMultipleChild ? 1 : 0 ) ) ) . join ( `,\n${ itemTabs }  ` ) || 'null' }${ hasMultipleChild ? `\n${ itemTabs }]` : '' }
${ tabs }    ),` ; } ) . join ( `\n${ tabs }    ` ) ; code += `
${ tabs }  ],
${ tabs }  () => ${ hasMultipleChild ? `[\n${ elseItemsTabs }  ` : '' }${ elseCode || 'null' }${ hasMultipleChild ? `\n${ elseItemsTabs }]` : '' }
${ tabs })` ; return code ; } }