/** * Created by rburson on 3/11/16. */ import * as React from 'react' import {CvState, CvBaseMixin, CvContext, CvActionBase, CvActionBaseProps} from './catreact-core' import {MenuDef, ObjUtil, EditorContext} from 'catavolt-sdk' import {CvActionBaseState} from "./CvAction"; export var CvMenuItemBase = { getChildContext: function () { const ctx = this.getDefaultChildContext(); ctx.cvContext.scopeCtx.scopeObj = this.menuDef(); return ctx; }, }; export interface CvMenuItemState extends CvActionBaseState { } export interface CvMenuItemProps extends CvActionBaseProps { /** * If no menuDef property and no actionId property is provided, the render method will * render all child MenuDefs of the given parentMenuItem (or attempt to find it in scope) */ parentMenuItem?:MenuDef; /** * If provided, each 'child' sdk {MenuDef} of the current MenuDef is passed to the function, which should return a a component * to be rendered. The function should accept 2 params: * * @param cvContext The current {@link CvContext}. The cvContext.cvScope.scopeObj will be the current sdk {MenuDef} * @param menuItem A child sdk {MenuDef} of the current MenuDef */ subMenuItemRenderer?:(cvContext:CvContext, menuItem:MenuDef)=>{} } /* *************************************************** * Render a Menu *************************************************** */ /** * There are several ways to use CvMenuItem * * 1. Simple wrapper - Provide an actionId OR menuItem and (optionally) a wrapperElem and wrapperElemProps. * This will render your child tags wrapped in wrapperElem with an onClick that fires 'this' action * 1. Function for submenus - Provide an actionId OR menuItem and a subMenuItemRenderer * see {@link CvMenuItemProps.subMenuItemRenderer}. * Providing this function will allow you to render all 'child' MenuDefs (but not 'this' MenuDef). * The result will be wrapped in wrapperElem (if provided) * 1. Recursive rendering of child menus - Omit both an actionId and menuItem and (optionally) specify a parentMenuItem * The render method will render each child of the parentMenuItem (provided or found in scope) passing along all * additional properties to new child {@link CvMenuItem}s */ export var CvMenuItem = React.createClass({ mixins: [CvBaseMixin, CvActionBase, CvMenuItemBase], componentDidMount: function() { this._componentDidMount(); }, componentWillReceiveProps: function(nextProps) { this._componentWillReceiveProps(nextProps); }, getDefaultProps: function () { return { actionId: null, fireOnLoad:null, paneContext: null, navTarget: null, menuDef: null, actionListeners: [], navigationListeners: [], stateChangeListeners:[], parentMenuItem: null, subMenuItemRenderer: null, selectionProvider: null, renderer:null, wrapperElemName:'span', wrapperElemProps:{}, wrapperEventHandlerName:'onClick', actionHandler:null } }, getInitialState: function() { return this._getInitialState(); }, parentMenuDef: function() { return this.props.parentMenuItem || this.firstInScope(MenuDef); }, render: function() { const menuDef = this.menuDef(); if(menuDef) { /* render me (this.menuDef) */ /* showOnMenu and displayMode values apply here */ if(this.props.renderer) { return this._shouldRender(menuDef) ? this.props.renderer(this.getChildContext().cvContext, this._getCallbackObj()) : null; /* render me - the markup with a 'click' wrapper */ /* showOnMenu and displayMode values apply here */ } else if(React.Children.count(this.props.children) > 0) { if(this._shouldRender(menuDef)) { const props = ObjUtil.addAllProps(this.props.wrapperElemProps, {}); props[this.props.wrapperEventHandlerName] = ()=>{this.performAction()}; return React.createElement(this.props.wrapperElemName, props, this.props.children); } else { return null; } /* render child menuDefs (this.menuDef.menuDefs) */ } else if (this.props.subMenuItemRenderer) { let newChildren = []; menuDef.menuDefs.forEach((md:MenuDef, i:number)=> { newChildren.push(React.cloneElement(this.props.subMenuItemRenderer(this.getChildContext().cvContext, md), {key:md.name + i})); }); return React.createElement(this.props.wrapperElemName, this.props.wrapperElemProps, newChildren); } else { return null; } //render all menuDefs of my parent (i.e. wildcard) }else if(!this.props.actionId && this.props.renderer) { const parentMenuDef:MenuDef = this.parentMenuDef(); if(parentMenuDef && parentMenuDef.menuDefs && parentMenuDef.menuDefs.length > 0) { let newChildren = []; parentMenuDef.menuDefs.forEach((md:MenuDef, i:number)=> { newChildren.push(); }); return React.createElement(this.props.wrapperElemName, this.props.wrapperElemProps, newChildren); } else { return null; } } else { return null; } }, _shouldRender: function(menuDef:MenuDef):boolean { if(!menuDef.showOnMenu) { return false; } const paneContext = this.paneContext(); if(paneContext && paneContext instanceof EditorContext) { if(menuDef.isRead && menuDef.isWrite) { return true; } else if(menuDef.isRead) { return (paneContext as EditorContext).isReadMode; } else if(menuDef.isWrite){ return (paneContext as EditorContext).isWriteMode; } else { return false; } } else { return true; } } });