import { Tools } from 'babylonjs/Misc/tools' ; import { ViewerConfiguration } from './configuration' ; import { kebabToCamel } from '../helper/' ; /**
 * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
 */ export interface IMapper { map ( rawSource ) : ViewerConfiguration ; } /**
 * This is a simple HTML mapper.
 * This mapper parses a single HTML element and returns the configuration from its attributes.
 * it parses numbers and boolean values to the corresponding variable types.
 * The following HTML element:
 *  <div test="1" random-flag="true" a.string.object="test"> will result in the following configuration:
 *
 *  {
 *      test: 1, //a number!
 *      randomFlag: boolean, //camelCase and boolean
 *      a: {
 *          string: {
 *              object: "test" //dot-separated object levels
 *          }
 *      }
 *  }
 */ class HTMLMapper implements IMapper { param element map ( element ) { let config = { } ; for ( let attrIdx = 0 ; attrIdx < element . attributes . length ; ++ attrIdx ) { let attr = element . attributes . item ( attrIdx ) ; if ( ! attr ) { continue ; } let split = attr . nodeName . split ( '.' ) ; split . reduce ( ( currentConfig , key , idx ) => { let camelKey = kebabToCamel ( key ) ; if ( idx === split . length - 1 ) { let val = attr ! . nodeValue ; if ( val === "true" ) { val = true ; } else if ( val === "false" ) { val = false ; } else if ( val === "undefined" ) { val = undefined ; } else if ( val === "null" ) { val = null ; } else { var isnum = ! isNaN ( parseFloat ( val ) ) && isFinite ( val ) ; if ( isnum ) { let number = parseFloat ( val ) ; if ( ! isNaN ( number ) ) { val = number ; } } } currentConfig [ camelKey ] = val ; } else { currentConfig [ camelKey ] = currentConfig [ camelKey ] || { } ; } return currentConfig [ camelKey ] ; } , config ) ; } return config ; } } /**
 * A simple string-to-JSON mapper.
 * This is the main mapper, used to analyze downloaded JSON-Configuration or JSON payload
 */ class JSONMapper implements IMapper { map ( rawSource ) { return JSON . parse ( rawSource ) ; } } /**
 * The DOM Mapper will traverse an entire DOM Tree and will load the configuration from the
 * DOM elements and attributes.
 */ class DOMMapper implements IMapper { param baseElement returns map ( baseElement ) { let htmlMapper = new HTMLMapper ( ) ; let config = htmlMapper . map ( baseElement ) ; let traverseChildren = function ( element , partConfig ) { let children = element . children ; if ( children . length ) { for ( let i = 0 ; i < children . length ; ++ i ) { let item = < HTMLElement > children . item ( i ) ; let configMapped = htmlMapper . map ( item ) ; let key = kebabToCamel ( item . nodeName . toLowerCase ( ) ) ; if ( item . attributes . getNamedItem ( 'array' ) && item . attributes . getNamedItem ( 'array' ) ! . nodeValue === 'true' ) { partConfig [ key ] = [ ] ; } else { if ( element . attributes . getNamedItem ( 'array' ) && element . attributes . getNamedItem ( 'array' ) ! . nodeValue === 'true' ) { partConfig . push ( configMapped ) ; } else if ( partConfig [ key ] ) { element . setAttribute ( 'array' , 'true' ) ; let oldItem = partConfig [ key ] ; partConfig = [ oldItem , configMapped ] ; } else { partConfig [ key ] = configMapped ; } } traverseChildren ( item , partConfig [ key ] || configMapped ) ; } } return partConfig ; } ; traverseChildren ( baseElement , config ) ; return config ; } } /**
 * The MapperManager manages the different implemented mappers.
 * It allows the user to register new mappers as well and use them to parse their own configuration data
 */ export class MapperManager { private _mappers : { [ key ] : IMapper ; } ; /**
     * The default mapper is the JSON mapper.
     */ public static DefaultMapper = 'json' ; constructor ( ) { this . _mappers = { "html" : new HTMLMapper ( ) , "json" : new JSONMapper ( ) , "dom" : new DOMMapper ( ) } ; } param type public getMapper ( type ) { if ( ! this . _mappers [ type ] ) { Tools . Error ( "No mapper defined for " + type ) ; } return this . _mappers [ type ] ; } param type param mapper public registerMapper ( type , mapper ) { this . _mappers [ type ] = mapper ; } /**
     * Dispose the mapper manager and all of its mappers.
     */ public dispose ( ) { this . _mappers = { } ; } } /**
 * mapperManager is a singleton of the type MapperManager.
 * The mapperManager can be disposed directly with calling mapperManager.dispose()
 * or indirectly with using BabylonViewer.disposeAll()
 */ export let mapperManager = new MapperManager ( ) ;