/*
* This plugin can according to your specified options to help you create the right click menu in web.
* Thank you for another plug-in jQuery.contextMenu inspired me.
*
* Comment version: 1.0.0
* Author：Linkfly
* Sina:为你聚焦半世纪 |  Baidu:假如天空够深 | Email:silin6@live.com
* For documentation visit http://www.trendskitchens.co.nz/jquery/contextmenu/
* date：2013-12-2
* 
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/

(function ($) {
    //初始化函数基本数据，默认参数
    var defaults = {
        menuStyle: {
            listStyle: 'none',
            padding: '1px',
            margin: '0px',
            position: 'absolute',
            fontSize: '10pt',
            backgroundColor: 'WHITE',
            width: '120px',
            border: '1px solid #6fb4e7',
            boxShadow: '5px 4px 10px -6px #777777'
        },
        itemStyle: {
            margin: '0',
            color: '#000',
            display: 'block',
            cursor: 'default',
            padding: '3px 10px',
            border: '1px solid WHITE',
            backgroundColor: 'transparent',
            transition: 'all 0.1s ease-in-out 0s',
            position: 'relative'
        },
        itemHoverStyle: {
            cursor: 'pointer',
            border: '1px solid #6fb4e7',
            backgroundColor: '#6fb4e7',
            transition: 'all 0.1s ease-in-out 0s'
        },
        moreIcon: {
            borderStyle: 'solid',
            borderWidth: '5px',
            display: 'inline-block',
            borderColor: 'transparent transparent transparent #646464',
            position: 'absolute',
            top: '6px',
            right: '0px'
        },
        isCache: false, //缓存，状态保持选项
        eventPosX: 'pageX',
        eventPosY: 'pageY',
        onShowMenu: null, //onShowMenu(eventSource指向事件源):this指向menu,eventSource指向事件源
        onHideMenu: null, //onHideMenu(eventSource指向事件源):this指向menu,eventSource指向事件源
        animated: null
    };
    //菜单容器，事件源
    var menu, eventSource;
    $.fn.lightMenu = function (id, options) {
        /// <summary>
        ///     1: 在指定的Jquery对象上根据指定的选项生成右键菜单，具体参数配置请参考：
        ///     &#10;    1.1 - rightMenu(id,options) - 在指定的jQuery对象上根据指定的选项生成右键菜单
        /// </summary>
        /// <param name="id" type="String">
        ///     要创建的菜单对象ID
        /// </param>
        /// <param name="options" type="Json">
        ///     要创建的菜单对象参数
        ///     &#10;  items（必须:json）：选项内容，Json格式
        ///     &#10;  menuStyle（可选:String or Json）：菜单样式
        ///     &#10;  itemStyle（可选:String or Json）：选项样式，如果传入String则指定为class
        ///     &#10;  itemHoverStyle（可选:String or Json）：选项悬浮样式，如果传入String则指定为class（当itemStyle指定为String的时候该项必须也指定为字符串，涉及css样式表优先级）
        ///     &#10;  moreIcon（可选:String or Json）：当该选项存在子项菜单的时候该项后缀样式
        ///     &#10;  isCache（可选:Boolean）：是否"缓存（状态保持）"该菜单对象，默认不进行"缓存"。当该项为true，则不再动态创建DOM，而只是隐藏和显示DOM，能够尽可能少的对DOM动态改变，但是因为状态保持在某种精度要求比较高的用户交互上略有缺陷，具体请参阅项目源文档
        ///     &#10;  eventPosX（可选:Int）：菜单显示的x坐标方位
        ///     &#10;  eventPosY（可选:Int）：菜单显示的y坐标方位
        ///     &#10;  onShowMenu（可选:function）：菜单显示事件，该函数this指针引用当前菜单的DOM，而参数eventSource指向事件源
        ///     &#10;  onHideMenu（可选:function）：菜单隐藏事件，该函数this指针引用当前菜单的DOM，而参数eventSource指向事件源
        ///     &#10;  animated（可选:Json）： TODO 菜单显示动画，和jQuery.animated()中参数相同【尚未完善，请勿使用】
        /// </param>
        /// <returns type="Object" />
        var configure = {//合并参数项
            id: id,
            menuStyle: ((typeof options.menuStyle) == 'string' ? options.menuStyle : $.extend({}, defaults.menuStyle, options.menuStyle || {})),
            itemStyle: ((typeof options.itemStyle) == 'string' ? options.itemStyle : $.extend({}, defaults.itemStyle, options.itemStyle || {})),
            itemHoverStyle: ((typeof options.itemHoverStyle) == 'string' ? options.itemHoverStyle : $.extend({}, defaults.itemHoverStyle, options.itemHoverStyle || {})),
            moreIcon: ((typeof options.moreIcon) == 'string' ? options.moreIcon : $.extend({}, defaults.moreIcon, options.moreIcon || {})),
            isCache: defaults.isCache || options.isCache,
            onShowMenu: options.onShowMenu || defaults.onShowMenu,
            onHideMenu: options.onHideMenu || defaults.onHideMenu,
            eventPosX: options.eventPosX || defaults.eventPosX,
            eventPosY: options.eventPosY || defaults.eventPosY,
            animated: options.animated || null
        };
        $(this).bind('contextmenu', function (e) {
            eventSource = e.currentTarget;                             //取得事件源对象
            if (menu && configure.isCache) {                    //显示菜单，状态保持
                menu.children('ul').children('li').find('ul').hide(0);
                menu.css({ 'left': e[configure.eventPosX], 'top': e[configure.eventPosY] }).stop().show(0);
                $(document).one("click", function () {          //隐藏条件
                    hide(configure.isCache, configure.onHideMenu);
                });
            } else {                                            //创建菜单
                var items = options.items || {};
                createMenu(id, items, configure, e);            //创建菜单
            }
            if (configure.onShowMenu) {
                menu.showMenu = configure.onShowMenu;
                menu.showMenu(eventSource);
            }
            return false;
        });
        return this;
    }
    function createMenu(id, items, options, e) {
        /// <summary>
        ///     1: 创建菜单
        /// </summary>
        /// <param name="id" type="String">
        ///     菜单ID
        /// </param>
        /// <param name="items" type="Json">
        ///     菜单里面的子项
        /// </param>
        /// <param name="options" type="Json">
        ///     菜单配置
        /// </param>
        /// <param name="e" type="EventSource">
        ///     事件源
        /// </param>
        /// <returns type="void" />
        if ($("#" + 'ctId').length > 0) { $('#' + 'ctId').remove(); }     //如果存在则干掉
        menu = $('<div id="' + id + '"></div>').css({ position: 'absolute', zIndex: '500', fontFamily: "Microsoft YaHei" }).bind('click', function (e) {//第一层创建父菜单
            e.stopPropagation();                                //阻止事件冒泡
        }).bind('contextmenu', function () { return false; });
        createItemMenu(items, menu, options);
        menu.css({ 'left': e[options.eventPosX], 'top': e[options.eventPosY] }).appendTo('body');
        if (options.animated) menu.css('display', 'block').stop().animate(options.animated, 300);    // TODO 显示菜单，尚未完善，请勿使用
        else menu.stop().fadeIn(300);
        $(document).one('click', function () {                          //隐藏菜单事件
            hide(options.isCache, options.onHideMenu);
        });
        function createItemMenu(options, parent, configure) {
            /// <summary>
            ///     1: 创建菜单列表（选项）
            /// </summary>
            /// <param name="options" type="String">
            ///     菜单项
            /// </param>
            /// <param name="parent" type="Json">
            ///     菜单要追加到的父容器对象
            /// </param>
            /// <param name="configure" type="Json">
            ///     菜单配置
            /// </param>
            /// <returns type="void" />
            if (parent.children("ul").length > 0 && configure.isCache) {    //从"缓存区"读取
                parent.children("ul").stop().fadeIn(100);
                return;
            } else if (parent.children("ul").length > 0) {                  //对象已存在，并且不在"缓存区"
                return;
            }
            var menuContext = $('<ul style="display:none" ></ul>');
            menuContext.css(configure.menuStyle).css('position', 'absolute');
            $.each(options, function () {                                   //循环选项，并为选项绑定上样式和指定的事件
                var currObj = this;                                         //当前循环的json对象
                var itemObj;                                                //每个选项对象（DOM模型）
                if (currObj.id) itemObj = $('<li id=' + currObj.id + ' class="rMenu_Items"><span>' + currObj.text + '<span/></li>');
                else itemObj = $('<li class="rMenu_Items"><span>' + currObj.text + '</span></li>');
                if (currObj.children) {
                    var moreIcon = $('<label></label>');                     //包含子项的特殊样式
                    if (typeof configure.moreIcon != 'string') moreIcon.css(configure.moreIcon);
                    else moreIcon.addClass(configure.moreIcon);
                    itemObj.append(moreIcon);
                }
                if (currObj.click) itemObj.click(function (e) {             //单击事件
                    e.stopPropagation();
                    eventSource.itemsClick = currObj.click;
                    var isClose = eventSource.itemsClick(itemObj);          //开放this指针，同时将当前单击对象传出:this指向菜单事件源，e指向菜单被单击的菜单（选项）对象
                    if (isClose == undefined || isClose) {                  //根据执行函数返回的结果表示是否隐藏
                        hide(configure.isCache, configure.onHideMenu);
                    }
                });
                if (typeof configure.itemStyle != 'string') $(itemObj).css(configure.itemStyle).css('position', 'relative');
                else $(itemObj).addClass(configure.itemStyle).removeClass(configure.itemHoverStyle);
                itemObj.mouseenter(function () {                                                //鼠标悬浮
                    if (typeof configure.itemHoverStyle != 'string') $(this).css(configure.itemHoverStyle);
                    else $(this).addClass(configure.itemHoverStyle).removeClass(configure.itemStyle);
                    if (itemObj.siblings('.rMenu_HisItems').length > 0) {                       //将同级菜单选项的样式改变
                        var hitItems = itemObj.siblings('.rMenu_HisItems');
                        hitItems.removeClass('rMenu_HisItems');
                        if (typeof configure.itemStyle != 'string') hitItems.css(configure.itemStyle);
                        else hitItems.addClass(configure.itemStyle).removeClass(configure.itemHoverStyle);
                    }
                    if (itemObj.siblings().children("ul").length > 0 && configure.isCache) {    //保持状态的隐藏
                        itemObj.siblings().children("ul").stop().hide(0);
                    } else if (itemObj.siblings().children("ul").length) {
                        itemObj.siblings().children("ul").remove();
                    }
                    if (currObj.children) {                                                     //包含子项，递归创建子菜单（或显示菜单）
                        createItemMenu(currObj.children, itemObj, configure);
                    }
                    itemObj.addClass('rMenu_HisItems');
                });
                menuContext.append(itemObj);
            });                                                                                 //循环结束
            menuContext.css({ 'left': parent.width() + 23, 'top': -3 }).appendTo(parent);
            if (!configure.isCache)                                                              //显示菜单
            {
                if (configure.animated) menuContext.css('display', 'block').stop().animate(configure.animated, 300);    // TODO 尚未完善，请勿使用
                else menuContext.stop().fadeIn(300);
            } else
                menuContext.stop().show(0);

        }
    }
    function hide(isCache, onHideMenu) {
        /// <summary>
        ///     1: 隐藏菜单（所有菜单）
        /// </summary>
        /// <param name="isCache" type="Boolean">
        ///     是否缓存该菜单对象
        /// </param>
        /// <param name="onHideMenu" type="Function">
        ///     隐藏菜单需要执行的事件
        /// </param>
        /// <returns type="void" />
        if (onHideMenu) {
            menu.onHideMenu = onHideMenu;
            menu.onHideMenu(eventSource);
        }
        if (isCache) {//缓存对象
            menu.stop().fadeOut(100, function () {
                menu.children('ul').children('li').find('ul').hide(0);
            });
        } else {
            menu.stop().fadeOut(300, function () {
                $(this).remove();
            }); //手动释放
        }
        return false;
    }
})(jQuery);