import { Ajax } from "../extend/Ajax" ; import { ControllerModel } from "../model/ControllerModel" ; import { ComponentModel } from "../model/ComponentModel" ; import { ComponentPoolItem } from "../model/ComponentPoolItem" ; import { ComponentConfiguration } from "../model/ComponentConfiguration" ; import { UkuleleUtil } from "../util/UkuleleUtil" ; import { IUkulele } from "./IUkulele" ; export class DefinitionManager { private uku : IUkulele ; constructor ( _uku ) { this . uku = _uku ; } private controllersDefinition : Object = { } ; private componentsDefinition : Object = { } ; private componentsPool : Object = { } ; private copyControllers : Object = { } ; private dependentScriptsCache : Object = { } ; private ajax : Ajax = new Ajax ( ) ; getComponentsDefinition ( ) { return this . componentsDefinition ; } getComponentsPool ( ) { return this . componentsPool ; } setComponentsPool ( pool ) { this . componentsPool = pool ; } setComponentsDefinition ( value ) { this . componentsDefinition = value ; } getComponentDefinition ( tagName ) { return this . componentsDefinition [ tagName ] as ComponentModel ; } getControllerDefinition ( instanceName ) { return this . controllersDefinition [ instanceName ] as ControllerModel ; } getControllersDefinition ( ) { return this . controllersDefinition ; } getComponent ( tagName ) { return this . componentsPool [ tagName ] ; } getCopyControllers ( ) { return this . copyControllers ; } addControllerDefinition ( instanceName , controllerInst ) { let controllerModel = new ControllerModel ( instanceName , controllerInst ) ; controllerInst . _alias = instanceName ; this . controllersDefinition [ instanceName ] = controllerModel ; } getControllerInstByDomId ( domId ) { for ( let alias in this . controllersDefinition ) { let controllerModel = this . controllersDefinition [ alias ] ; let controller = controllerModel . controllerInstance ; if ( controller . _dom && controller . _dom . id === domId ) { return controller ; } } return undefined ; } addComponentDefinition ( tag , templateUrl , preload ) { return new Promise < void > ( ( resolve , reject ) => { if ( ! preload ) { this . componentsPool [ tag ] = new ComponentPoolItem ( tag , templateUrl , true ) ; resolve ( ) ; } else { this . componentsPool [ tag ] = new ComponentPoolItem ( tag , templateUrl , false ) ; return this . ajax . get ( templateUrl ) . then ( ( result ) => { let componentConfig = UkuleleUtil . getComponentConfiguration ( result ) ; return this . analyizeComponent ( tag , componentConfig ) ; } ) ; } } ) ; } addLazyComponentDefinition ( tag , templateUrl ) { return new Promise < void > ( ( resolve , reject ) => { return this . ajax . get ( templateUrl ) . then ( ( result ) => { let componentConfig = UkuleleUtil . getComponentConfiguration ( result ) ; return this . analyizeComponent ( tag , componentConfig ) . then ( ( ) => { this . componentsPool [ tag ] = { 'tagName' : tag , 'templateUrl' : templateUrl , 'lazy' : false } ; resolve ( ) ; } ) ; } ) ; } ) ; } getBoundAttributeValue ( attr , ... additionalArgu ) { let controllerModels = this . getControllerModelByName ( attr ) ; let controllers = [ ] ; controllerModels . forEach ( controllerModel => { controllers . push ( controllerModel . controllerInstance ) ; } ) ; let parameters = [ this . uku , controllers , attr ] ; parameters = parameters . concat ( additionalArgu ) ; let result = UkuleleUtil . getFinalValue . apply ( null , parameters ) ; return result ; } ; getControllerModelByName ( expression ) { let arr = [ ] ; let normalReg = /\$\w+\./g ; let normals = expression . match ( normalReg ) ; if ( normals ) { normals . forEach ( matchAlias => { matchAlias = matchAlias . substr ( 0 , matchAlias . length - 1 ) ; let controllerModel = this . controllersDefinition [ matchAlias ] ; arr . push ( controllerModel ) ; } ) ; } let ccReg = /cc\_\w*\./g ; let ccs = expression . match ( ccReg ) ; if ( ccs ) { ccs . forEach ( ccAlias => { ccAlias = ccAlias . substr ( 0 , ccAlias . length - 1 ) ; let controllerModel = this . controllersDefinition [ ccAlias ] ; arr . push ( controllerModel ) ; } ) ; } let repeatReg = /repeatItem\_\w*\$/g ; let repeats = expression . match ( repeatReg ) ; if ( repeats ) { repeats . forEach ( repeatAlias => { let controllerModel = this . controllersDefinition [ repeatAlias ] ; arr . push ( controllerModel ) ; } ) ; } return arr ; } ; getFinalValueByExpression ( expression ) { let controllerModels = this . getControllerModelByName ( expression ) ; let controllers = [ ] ; controllerModels . forEach ( controllerModel => { controllers . push ( controllerModel . controllerInstance ) ; } ) ; return UkuleleUtil . getFinalValue ( controllers , expression ) ; } ; private async analyizeComponent ( tag , config ) { let deps = config . dependentScripts ; let self = this ; if ( deps && deps . length > 0 ) { let tmpAMD ; if ( typeof window [ 'define' ] === 'function' && window [ 'define' ] . amd ) { tmpAMD = window [ 'define' ] ; window [ 'define' ] = undefined ; } if ( ! config . componentControllerScript ) { let ccsExternal = deps [ deps . length - 1 ] ; config . componentControllerScript = await this . ajax . get ( ccsExternal ) ; deps . pop ( ) ; } for ( let i = 0 ; i < deps . length ; i ++ ) { let dep = deps [ i ] ; await loadDependentScript ( dep ) ; } if ( tmpAMD ) { window [ 'define' ] = tmpAMD ; } this . buildeComponentModel ( tag , config . template , config . componentControllerScript , config . stylesheet ) ; return ; } else { this . buildeComponentModel ( tag , config . template , config . componentControllerScript , config . stylesheet ) ; return ; } function loadDependentScript ( src ) { return new Promise < void > ( ( resolve , reject ) => { if ( ! self . dependentScriptsCache [ src ] ) { let head = document . getElementsByTagName ( 'HEAD' ) [ 0 ] ; let script = document . createElement ( 'script' ) ; script . type = 'text/javascript' ; script . charset = 'utf-8' ; script . async = true ; script . src = src ; script . onload = ( e ) => { self . dependentScriptsCache [ e . target [ 'src' ] ] = true ; resolve ( ) ; } ; head . appendChild ( script ) ; } else { resolve ( ) ; } } ) ; } } private buildeComponentModel ( tag , template , script , style ) { let debugComment = "//# sourceURL=" + tag + ".js" ; try { let controllerClazz ; if ( script ) { script = UkuleleUtil . wrapScriptInComponent ( script ) ; script += debugComment ; controllerClazz = eval ( script ) ; } let newComp = new ComponentModel ( tag , template , controllerClazz ) ; this . componentsDefinition [ tag ] = newComp ; if ( style ) { dealWithShadowStyle ( tag , style ) ; } } catch ( e ) { console . error ( e ) ; } function dealWithShadowStyle ( tagName , stylesheet ) { let head = document . getElementsByTagName ( 'HEAD' ) [ 0 ] ; let style = document . createElement ( 'style' ) ; style . type = 'text/css' ; var styleArray = stylesheet . split ( "}" ) ; var newArray = [ ] ; styleArray . forEach ( ( value , index ) => { var newValue = value . replace ( /^\s*/ , "" ) ; if ( newValue ) { newArray . push ( newValue ) ; } } ) ; stylesheet = newArray . join ( "}\n" + "." + tagName + " " ) ; stylesheet = "." + tagName + " " + stylesheet + "}" ; style . innerHTML = stylesheet ; head . appendChild ( style ) ; } } }