/** * Created by rburson on 3/13/17. */ import * as React from 'react' import { CvState, CvProps, CvContext, CvEvent, CvEventRegistry, CvEventType, CvActionFiredResult, CvScopeContext, CvAction, CvActionBase, CvMessageType, CvBaseMixin, CvResultCallback, CvStateChangeType, CvStateChangeResult, CvNavigationResult, CvNavigationResultUtil, CvMessage } from './catreact-core' import { PaneContext, ViewDesc, ObjUtil, Try, FormContext, NavRequest, Either, AppContext } from 'catavolt-sdk' export interface CvViewDescProps extends CvProps { /** * Array of {@link CvListener}s that will be notified if a view is 'opened' */ actionListeners?:Array<(event:CvEvent)=>void> /** * Array of {@link CvListener> that will be notified of a state change for which they may need to refresh */ stateChangeListeners?:Array<(event:CvEvent)=>void>; /** * The sdk {ViewDesc} */ viewDesc?:ViewDesc; /** * Register to receive {@link CvEvent}s of type {@link CvNavigationResult} */ navigationListeners?:Array<(event:CvEvent)=>void> /** * Provide a target for any navigations that originate from this action. The navTarget should * correspond to the 'targetId' value of the coresident {@link CvNavigation} or {@link CvNavigator}. * This is useful for single page apps where components may be coresident. */ navTarget?:string; /** * The sdk {PaneContext} associated with this action. If not specified, the context chain will be upwardly * searched to find a component with a containing sdk {PaneContext} scopeObj */ paneContext?:PaneContext; /** * Render override function. It should accept the following params: * @param cvContext The current cvContext. The cvContext.cvScope.scopeObj will be the sdk {ViewDesc} object */ renderer?:(cvContext:CvContext, callback:CvViewDescCallback)=>{} /** * Name of the wrapping element (should be component name) * Defaults to 'span' from backward compatibility's sake */ wrapperElemName?:string; /** * Props for the wrapping element */ wrapperElemProps?:any; /** * Name of the wrapperElem property that fires the 'open viewDesc' action (i.e. onClick or onPress) * Defaults to 'onClick' */ wrapperEventHandlerName?:string; } interface CvViewDescState extends CvState{ } export interface CvViewDescCallback { openView(resultCallback?:CvResultCallback>):void; } export var CvViewDesc = React.createClass({ mixins: [CvBaseMixin], componentDidMount: function() { }, getChildContext: function () { const ctx = this.getDefaultChildContext(); ctx.cvContext.scopeCtx.scopeObj = this.viewDesc(); return ctx; }, getDefaultProps: function () { return { paneContext: null, actionListeners: [], stateChangeListeners: [], navigationListeners: [], navTarget: null, viewDesc: null, renderer: null, wrapperElemName: 'span', wrapperElemProps: {}, wrapperEventHandlerName: 'onClick', } }, openView: function(resultCallback?:CvResultCallback>) { (CvViewDesc as any).openView( this.viewDesc(), this.paneContext(), this.eventRegistry(), this.catavolt(), this.props.actionListeners, this.props.stateChangeListeners, this.props.navigationListeners, this.props.navTarget, resultCallback ); }, paneContext: function ():PaneContext { var paneContext:PaneContext = null; if (this.props.paneContext) { paneContext = this.props.paneContext; } else { paneContext = this.findPaneContext(); } return paneContext; }, render: function () { if(this.viewDesc()) { if (this.props.renderer) { return this.props.renderer(this.getChildContext().cvContext, this._getCallbackObj()) } else if (this.props.children) { const props = ObjUtil.addAllProps(this.props.wrapperElemProps, {}); props[this.props.wrapperEventHandlerName] = ()=>{this.openView()}; return React.createElement(this.props.wrapperElemName, props, this.props.children); } else { return null; } } else { return null; } }, viewDesc: function():ViewDesc { return this.props.viewDesc; }, _getCallbackObj: function ():CvViewDescCallback { return { openView: (resultCallback?:CvResultCallback>):void => { this.openView(resultCallback); } } }, statics : { publishStateChange: function (paneContext:PaneContext, eventRegistry:CvEventRegistry, stateChangeListeners?:Array<(event:CvEvent)=>void>) { if (paneContext) { const event:CvEvent = { type: CvEventType.STATE_CHANGE, resourceId: null, eventObj: {source: paneContext, type: CvStateChangeType.PANE_DEF_CHANGE} }; eventRegistry.publish(event, false) stateChangeListeners.forEach(listener=> { listener(event) }); } }, publishNavigation: function(navRequest:NavRequest, actionId:string, paneContext:PaneContext, catavolt:AppContext, eventRegistry:CvEventRegistry, navigationListeners:Array<(event:CvEvent)=>void>, navTarget:string) { const e:CvEvent = CvNavigationResultUtil.publishNavigation(catavolt, eventRegistry, navRequest, actionId, null, navTarget, navigationListeners, paneContext.isDestroyed, false); }, publishError: function(failure:any, eventRegistry:CvEventRegistry) { const event:CvEvent = {type:CvEventType.MESSAGE, eventObj:{message:'Change View Failed', messageObj:failure, type: CvMessageType.ERROR}} eventRegistry.publish(event, false); }, openView: function(viewDesc:ViewDesc, paneContext:PaneContext, eventRegistry:CvEventRegistry, catavolt:AppContext, actionListeners:Array<(event:CvEvent)=>void>, stateChangeListeners:Array<(event:CvEvent)=>void>, navigationListeners:Array<(event:CvEvent)=>void>, navTarget:string, resultCallback?:CvResultCallback>) { const actionId = '#viewChange'; CvActionBase._publishActionStarted(actionId, paneContext, false, actionListeners, eventRegistry); paneContext.openView(viewDesc).onComplete((openViewTry:Try>)=> { CvActionBase._publishActionFinished(actionId, paneContext, actionListeners, eventRegistry); if (openViewTry.isFailure) { if (resultCallback) resultCallback(null, openViewTry.failure); (CvViewDesc as any).publishError(openViewTry.failure, eventRegistry); } else { if (resultCallback) resultCallback(openViewTry.success); if(openViewTry.success.isLeft) { (CvViewDesc as any).publishStateChange(openViewTry.success.left, eventRegistry, stateChangeListeners); } else { (CvViewDesc as any).publishNavigation(openViewTry.success.right, actionId, paneContext, catavolt, eventRegistry, navigationListeners, navTarget); } } }); }, } });