# src/menu/Menu.js File

    import React,{PropTypes} from 'react';
    import Component from '../utils/Component';
    import classnames from 'classnames';
    import {setPhoenixPrefix, closest} from '../utils/Tool';

    import MenuHeader from './MenuHeader';
    import MenuBody from './MenuBody';
    import MenuNav from './MenuNav';
    import MenuList from './MenuList';
    import MenuItem from './MenuItem';

    /**
     * <h5>菜单组件，主要包括组件:</h5>
     * <strong><a href='../classes/Menu.html'>Menu 菜单</a></strong><br/>
     * <strong><a href='../classes/MenuHeader.html'>MenuHeader 菜单头部</a></strong><br>
     * <strong><a href='../classes/MenuBody.html'>MenuBody 菜单主体</a></strong><br>
     * <strong><a href='../classes/MenuNav.html'>MenuNav 菜单导航</a></strong><br>
     * <strong><a href='../classes/MenuList.html'>MenuList 菜单导航列表</a></strong><br>
     * <strong><a href='../classes/MenuItem.html'>MenuItem 菜单导航列表项</a></strong><br>
     * <h6>点击以上链接或者左侧导航栏的组件名称链接进行查看</h6>
     * @module 菜单组件
     * @main 菜单组件
     * @static
     */
    /**
     * 菜单组件<br/>
     - 可通过visible设置菜单初始是否可见，默认不可见。
     - 不设置scrollCeiling时默认菜单不吸顶，设置scrollCeiling为具体数值时表示从当前距离开始吸顶，设置0表示至始至终吸顶。
     - 可通过onMenuChange函数设置菜单打开收起的回调函数。
     *
     * 主要属性和接口：
     * - visible:初始展开或收起的状态, 默认false收起。
     * - scrollCeiling:设置吸顶的距离, 默认不吸顶, 设置0表示始终吸顶。
     * - onMenuChange:菜单打开关闭时的回调函数。 <br/>
     * 如：
     * ```code
     *     <Menu scrollCeiling={100} visible={true} onMenuChange={(visible)=>{console.log(visible);}}>
     *         <Menu.Header>
     *             标题一
     *         </Menu.Header>
     *         <Menu.Body>
     *             ...
     *         </Menu.Body>
     *     </Menu>
     * ```
     *
     * @class Menu
     * @module 菜单组件
     * @extends Component
     * @constructor
     * @since 1.3.0
     * @demo menu|menu.js {展示}
     * @show true
     * */

    class Menu extends Component{

        static propTypes = {
            /**
             * 样式前缀
             * @property classPrefix
             * @type String
             * @default 'menu'
             * */
            classPrefix: PropTypes.string,
            /**
             * 标签tagName
             * @property componentTag
             * @type String
             * */
            componentTag:PropTypes.string,
            /**
             * 是否可见标识
             * @property visible
             * @type Boolean
             * @default false
             * */
            visible: PropTypes.bool,
            /**
             * 点击收起展开的回调函数
             * @method onMenuChange
             * @type Function
             * */
            onMenuChange: PropTypes.func,
            /**
             * 是否滚动吸顶, 默认不吸顶(false); 设置确定的数字从当前距离开始吸顶
             * @property scrollCeiling
             * @type Number
             * @default 不设置
             * */
            scrollCeiling: PropTypes.number
        };

        static defaultProps = {
            visible: false,
            classPrefix:'menu',
            componentTag:'div',
            classMapping : {}
        };

        constructor(props, context) {
            super(props, context);

            this.handleDocumentClick = this.handleDocumentClick.bind(this);
            this.handleWindowScroll = this.handleWindowScroll.bind(this);

            this.state = {
                visible: props.visible,
                ceiling: !(props.scrollCeiling === undefined || props.scrollCeiling > 0),
                headerHeight: 0
            };

            document.addEventListener('click', this.handleDocumentClick, false);

            // 是否滚动吸顶
            if(props.scrollCeiling === undefined || props.scrollCeiling === 0) return;

            window.addEventListener('scroll', this.handleWindowScroll, false);
        }

        handleDocumentClick(event){
            if(!this.state.visible) return;
            let el = event.target;

            if(!closest(el,'.ph-menu')){
                this.setState({
                    visible: false
                }, ()=>{
                    if(this.props.onMenuChange) this.props.onMenuChange(this.state.visible);
                });
            }

            return false;
        }

        handleWindowScroll(){
            if(document.body.scrollTop >= this.props.scrollCeiling){
                if(!this.state.ceiling) this.setState({ceiling: true});
            }else{
                if(this.state.ceiling) this.setState({ceiling: false});
            }
        }

        componentDidMount(){
            setTimeout(()=>{
                this.menuPlaceholder.style.height = this.menuCeiling.offsetHeight +'px';
                this.setState({headerHeight: this.menuCeiling.offsetHeight})
            },0);
        }

        // componentWillReceiveProps(nextProps){
        //     if(this.state.visible != nextProps.visible){
        //         this.setState({
        //             visible: nextProps.visible
        //         }, ()=>{
        //         if(this.props.onMenuChange) this.props.onMenuChange(nextProps.visible);
        //     });
        //     }
        // }

        changeVisible(){
            this.setState({
                visible: !this.state.visible
            }, ()=>{
                if(this.props.onMenuChange) this.props.onMenuChange(this.state.visible);
            });
        }

        renderChildren(){
            let _this = this;
            let newChildren = [];

            React.Children.forEach(this.props.children, function(child, index){
                newChildren.push(React.cloneElement(child, {
                    key: index,
                    visible: _this.state.visible,
                    changeVisible: _this.changeVisible.bind(_this),
                    headerHeight: _this.state.headerHeight
                }));
            });

            return newChildren;
        }

        componentWillUnmount(){
            document.removeEventListener('click', this.handleDocumentClick, false);
            window.removeEventListener('scroll', this.handleWindowScroll, false);
        }

        render(){
            let {componentTag:Component, className} = this.props;

            return (
                <Component {...this.props} className={classnames(
                    this.getProperty(true),
                    setPhoenixPrefix('menu-placeholder'),
                    className
                )} ref={(menuPlaceholder)=>{this.menuPlaceholder=menuPlaceholder}}>
                    <div className={this.state.ceiling? setPhoenixPrefix('menu-ceiling'):''} ref={(menuCeiling)=>{this.menuCeiling=menuCeiling}}>
                        {this.renderChildren()}
                    </div>
                </Component>
            );
        }
    }

    Menu.Header = MenuHeader;
    Menu.Body = MenuBody;
    Menu.Nav = MenuNav;
    Menu.List = MenuList;
    Menu.Item = MenuItem;

    export default Menu;