import * as React from "react" ; import * as PropTypes from "prop-types" ; import AemComponent from "./AemComponent" ; import EditDialog from "./EditDialog" ; import { Sling } from "../store/Sling" ; import RootComponentRegistry from "../RootComponentRegistry" ; import ResourceUtils from "../ResourceUtils" ; import { ResourceInclude } from "../include" ; export interface Resource { "sling:resourceType" : string ; } export enum STATE { LOADING , LOADED , FAILED } export interface ResourceState { absolutePath : string ; resource ? : any ; state : STATE ; } export interface ResourceProps { path : string ; skipRenderDialog ? : boolean ; root ? : boolean ; wcmmode ? : string ; className ? : string ; } /**
 * Provides base functionality for components that are
 */ export abstract class ResourceComponent < C extends Resource , P extends ResourceProps , S extends ResourceState > extends AemComponent < P , S > { public static childContextTypes : any = { wcmmode : PropTypes . string , path : PropTypes . string , } ; public getChildContext ( ) { return { wcmmode : this . getWcmmode ( ) , path : this . getPath ( ) , } ; } public componentWillMount ( ) { this . initialize ( ) ; } public componentWillReceiveProps ( newProps , newContext ) { this . initialize ( ) ; } public initialize ( ) { let absolutePath ; if ( ResourceUtils . isAbsolutePath ( this . props . path ) ) { absolutePath = this . props . path ; } else { absolutePath = this . context . path + "/" + this . props . path ; } if ( absolutePath !== this . getPath ( ) ) { this . setState ( ( { absolutePath : absolutePath , state : STATE . LOADING } as S ) ) ; ( this . getAemContext ( ) . container . get ( "sling" ) as Sling ) . subscribe ( this , absolutePath , { depth : this . getDepth ( ) } ) ; } } public getWcmmode ( ) { return this . props . wcmmode || this . context . wcmmode ; } public getPath ( ) { if ( typeof this . state !== "undefined" && this . state !== null ) { return this . state . absolutePath ; } else { return null ; } } protected renderLoading ( ) { return ( < span > Loading < /span>); } public render ( ) { let child ; if ( this . state . state === STATE . LOADING ) { child = this . renderLoading ( ) ; } else if ( ! ! this . props . skipRenderDialog ) { return this . renderBody ( ) ; } else { child = this . renderBody ( ) ; } return ( < EditDialog path = { this . getPath ( ) } resourceType = { this . getResourceType ( ) } className = { this . props . className } > { child } < /EditDialog>); } public getRegistry ( ) { return this . context . aemContext . registry ; } public abstract renderBody ( ) ; public getResource ( ) { return ( this . state . resource as C ) ; } public getResourceType ( ) { return this . context . aemContext . registry . getResourceType ( this ) ; } public changedResource ( path , resource ) { this . setState ( ( { state : STATE . LOADED , resource : resource , absolutePath : path } ) as any ) ; } protected getDepth ( ) { return 0 ; } protected renderChildren ( path , childClassName ? , childElementName ? ) { if ( path && path . match ( /^\// ) ) { throw new Error ( "path must be relative. was " + path ) ; } let childrenResource = ! ! path ? ( this . getResource ( ) as any ) [ path ] : this . getResource ( ) ; let children = ResourceUtils . getChildren ( childrenResource ) ; let childComponents = [ ] ; let basePath = ! ! path ? path + "/" : "" ; Object . keys ( children ) . forEach ( ( nodeName , childIdx ) => { let resource = children [ nodeName ] ; let resourceType = resource [ "sling:resourceType" ] ; let actualPath = basePath + nodeName ; let componentType = this . getRegistry ( ) . getComponent ( resourceType ) ; if ( childElementName ) { if ( componentType ) { let props = { resource : resource , path : actualPath , reactKey : path , key : nodeName } ; childComponents . push ( React . createElement ( childElementName , { key : nodeName , className : childClassName } , React . createElement ( componentType , props ) ) ) ; } else { childComponents . push ( React . createElement ( childElementName , { key : nodeName , className : childClassName } , React . createElement ( ResourceInclude , { path : actualPath , key : nodeName , resourceType : resourceType } ) ) ) ; } } else { if ( componentType ) { let props = { resource : resource , path : basePath + nodeName , reactKey : path , key : nodeName , className : childClassName } ; childComponents . push ( React . createElement ( componentType , props ) ) ; } else { childComponents . push ( < ResourceInclude path = { actualPath } key = { nodeName } resourceType = { resourceType } > < /ResourceInclude>); } } } , this ) ; let newZone = null ; if ( this . isWcmEnabled ( ) ) { let parsysPath = path ? path + "/*" : "*" ; let resourceType = "foundation/components/parsys/new" ; newZone = < ResourceInclude key = "newZone" element = "div" path = { parsysPath } resourceType = { resourceType } > < /ResourceInclude>; childComponents . push ( newZone ) ; } return childComponents ; } }