﻿//----------------------------------------------------------------------//
//                                                                      //
//                          钱文田  2007-12-17                          //
//                                                                      //
//              对用户信息提示、错误提示和正在加载进行显示              //
//                                                                      //
//                  需要外面调用页面引用 Common.js文件                  //
//                                                                      //
//----------------------------------------------------------------------//

///// <summary>
///// 自定义提示框类
///// </summary>
var MessageBox = 
{
    /// <summary>
    /// 是否正在加载
    /// </summary>
    loading : false,

    /// <summary>
    /// 显示提示消息框
    /// </summary>
    /// <param name="type">提示框类型 (info: 提醒; error: 错误; load: 正在加载 )</param>
    /// <param name="html">提示框显示的HTML内容</param>
    /// <param name="detail">提示框需要显示的详细内容</param>
    /// <param name="callback">提示框关闭后需要执行的函数</param>
    /// <param name="defultbutton">默认选中的按钮</param>
    /// <param name="buttons">用户自定义按钮组</param>
    show : function (type, html, detail, callback, defultbutton, buttons)
    {
        if (MessageBox.loading)
        {
            //window.status += "exec_";
            setTimeout(function(){MessageBox.show(type, html, detail, callback, buttons)}, 50);
            return;
        }
        MessageBox.loading = true;
        MessageBox.hideDetail();
        if ($("dialog_messagebox", top) && $("dialog_messagebox", top).style.display != "none")
        {
            // 如果调用 MessageBox.show 后, 没有调用 MessageBox.hide , 
            // 再一次调用 MessageBox.show, 需要调用上次show后结束的方法
            MessageBox.hide();
        }

        //MessageBox.notifyCallBack("");
        top.dialog.callbackStack.push(callback);

        // createDialog 返回 true  表示最新创建, onloadEvent 函数由 iframe.load 事件自动调用
        // createDialog 返回 false 表示没有创建, onloadEvent 需要手工调用
        if (!createDialog("dialog_messagebox", top.ApplicationPath + "/Js/MessageBox.aspx", "398px", "188px", "DialogMessageBox", onloadEvent))
        {
            onloadEvent();
        }

        // 由于firefox, opera 对 iframe 没有 readyState, onreadystatechange 支持
        // 在这里通过 iframe.onload 来通知框架页面加载完成 
        function onloadEvent()
        {
            type = type.toLowerCase();
            // 根据提示框类型, 设置显示的按钮
            switch (type)
            {
                case "info":
                case "error":
                    buttons = [{ value : "确 定", ok : true, cancel : true }];
                    break;
                case "load":
                    buttons = [];
                    break;
                case "okcancel":
                    // 如果用户没有指定按钮类型, 设置默认 "确 定"、"取 消" 两个按钮
                    if (!buttons) 
                        buttons = [ { value : "确 定", ok : true }, { value : "取 消", cancel : true }];
                    break;
                case "yesno":
                    // 如果用户没有指定按钮类型, 设置默认 "是"、"否" 两个按钮
                    if (!buttons) 
                        buttons = [{ value : "是", ok : true }, { value : "否", cancel : true }];
                    break;
                default:
                    throw new Error("提示框类型错误, 目前支持: [ info, error, load, okcancel, yesno ]");
            }

            // 设置提示图片
            $S($("img_info", top.dialog.currentDialogWin), type == "info");
            $S($("img_error", top.dialog.currentDialogWin), type == "error");
            $S($("img_load", top.dialog.currentDialogWin), type == "load");
            $S($("img_ask", top.dialog.currentDialogWin), type == "okcancel" || type == "yesno");

            // 设置提示信息
            $("MsgTxt", top.dialog.currentDialogWin).innerHTML = html;
            // 设置详细信息
            var msgDetail =  $("MsgDetail", top.dialog.currentDialogWin);
            if (!detail)
            {
                $S(msgDetail, false);
            }
            else
            {
                $S(msgDetail, true);
                msgDetail.href = "javascript:top.dialog.currentWindow.MessageBox.showDetail('" + detail.toJSString() + "');";
            }
            var Footer = $("Footer", top.dialog.currentDialogWin);

            // 根据按钮数组, 创建按钮集
            // 此处先用变量并串, 因为每次用 Footer.innerHTML 都会导致重新生成 childNodes
            var buttonHTML = "";
            for(var i = 0; i <= buttons.length - 1; i++)
            {
                if (buttonHTML == "")
                {
                    buttonHTML += '<input type="button" value="' + buttons[i].value + '" class="Button' + (buttons[i].value.dataLength() < 8 ? '' : '4') + '" onclick="top.dialog.currentWindow.MessageBox.hide(this);">';
                }
                else
                {
                    buttonHTML += '\r\n<input type="button" value="' + buttons[i].value + '" class="Button' + (buttons[i].value.dataLength() < 8 ? '' : '4') + '" onclick="top.dialog.currentWindow.MessageBox.hide(this);">';
                }
            }
            Footer.innerHTML = buttonHTML;

            // 附加按钮焦点事件, 此处循环必须独立出来, 因为 innerHTML 会改变 childNodes
            for(var i = 0; i <= buttons.length - 1; i++)
            {
                addEvent(Footer.childNodes[i * 2], "focus", MessageBox.buttonfocus);

                // 设置 回车 按钮
                if (buttons[i].ok == true) top.dialog.currentDialogWin.ok = Footer.childNodes[i * 2];

                // 设置 ESC 键按钮
                if (buttons[i].cancel == true) top.dialog.currentDialogWin.cancel = Footer.childNodes[i * 2];

                // 设置默认选中按钮
                if (buttons[i].value == defultbutton) top.dialog.currentDialogWin.focusButton = Footer.childNodes[i * 2];
            }
            
            // 根据提示框类型, 设置是否显示确定按钮、关闭图片
            $S(Footer, type != "load");
            $S($("div_no_move", top.dialog.currentDialogWin), type != "load");

            // 提示框设置事件
            addEvent(top.dialog.currentDialogWin.document, "keydown", MessageBox.keydown);
            addEvent(top.dialog.currentDialogWin.document, "mousedown", MessageBox.mousedown);
            addEvent(top.dialog.maskObj, "mousedown", MessageBox.mousedown);

            // 提示框页面初始化完成, 显示框架
            showDialog();

            // 设置默认按钮得到焦点
            MessageBox.setFocusButton();
            
            // 加载完成
            MessageBox.loading = false;
        }
    },
    
    ///// <summary>
    ///// 隐藏提示消息框
    ///// </summary>
    hide : function(button, callback)
    {
        // 如果消息框还没有加载完成, 请等待
        if (MessageBox.loading)
        {
            setTimeout(function(){MessageBox.hide(button)}, 50);
            return;
        }

        MessageBox.hideDetail();

        // 执行回调函数
        MessageBox.notifyCallBack(button ? button.value : (top.dialog.currentDialogWin.cancel ? top.dialog.currentDialogWin.cancel.value : ""));

        // 去除按钮焦点事件
        var Footer = $("Footer", top.dialog.currentDialogWin);
        for(var i = 0; i <= (Footer.childNodes.length - 1) / 2; i++)
        {
            addEvent(Footer.childNodes[i * 2], "focus", MessageBox.buttonfocus, true);
        }

        addEvent(top.dialog.currentDialogWin.document, "keydown", MessageBox.keydown, true);
        addEvent(top.dialog.currentDialogWin.document, "mousedown", MessageBox.mousedown, true);
        addEvent(top.dialog.maskObj, "mousedown", MessageBox.mousedown, true);

        top.dialog.currentDialogWin.ok = null;
        top.dialog.currentDialogWin.cancel = null;
        top.dialog.currentDialogWin.focusButton = null;

        // 必须在最后调用, 因为此函数中会把top.dialog对象里面很多对象设置为NULL
        closeDialog();
        
        if (typeof(callback) == "function")
            callback();
    },

    ///// <summary>
    ///// 执行回调函数
    ///// </summary>
    ///// <param name="result">返回值</param>
    notifyCallBack : function(result)
    {
        var callback = top.dialog.callbackStack.pop();
        if (callback)
        {
            try
            {
                callback(result);
            }
            catch(e)
            {
                // 由于第一次显示是有 iframe.load 事件调用, 而 firefox 对于异步调用代码触发的异常不能够被捕获
                // 所以此处针对调试阶段的时候, firefox 弹不出错误信息提示框, 需要在 ie 中调试错误, 
                // 但是如果不是调试阶段, 不影响发布时候使用
                if (top.__debug) throw e;
            }
        }
    },

    ///// <summary>
    ///// 显示详细信息
    ///// </summary>
    ///// <param name="detail">详细信息</param>
    showDetail : function(detail)
    {
        var detailObj = $("dialog_messagebox_detail", top);
        if (!detailObj)
        {
            detailObj = createPanel(top, "dialog_messagebox_detail", "", onloadEvent);
            detailObj.className = "DialogHint";
            // 必须输出body, 在 ie 中 iframe 没有指定 url, document.body 为空, firefox 中不为空
            if (gIsIE) $F("dialog_messagebox_detail", top).document.write('<body></body>');
            // 如果是 firefox, 等待页面 load 事件调用
            if (gIsNS) return;
        }

        onloadEvent();
        
        // 当 iframe 没有指定 src 的时候, ie 不触发 load 事件, 所以可以直接操作 document 对象, 
        // 但 firefox 触发 load 事件, 之前操作 document 对象在事件触发后就没了, 所以要在 load 事件中进行处理
        function onloadEvent()
        {
            var detailWin = $F("dialog_messagebox_detail", top);
            var bd = detailWin.document.body;
            // 查看 DIV 节点是否已经存在, 不存在创建
            if (bd.childNodes.length == 0)
            {
                bd.style.margin = "0px 0px 0px 0px";
                bd.innerHTML = '<div style="FONT-SIZE: 12px; color:#333333; padding: 8px 8px 8px 8px; LINE-HEIGHT: 18px; BORDER: #E3E3E3 solid 1px; BACKGROUND: #FFFFEE; WIDTH: 240px;"></div>';
            }
            // 把需要显示的内容填充到DIV中
            bd.childNodes[0].innerHTML = detail.replace(/\r/g, "<br>");
            // 只有先把框架显示出来, 才能访问 document.body.scrollHeight 属性
            $S(detailObj, true);
            var MsgDetail = $("MsgDetail", top.dialog.currentDialogWin);
            var pt = getPosition(MsgDetail);
            detailObj.style.top = parseInt(top.dialog.currentDialogObj.style.top) + pt.top + 15;
            detailObj.style.left = parseInt(top.dialog.currentDialogObj.style.left) + pt.left;
            // 由于 ie 中 body.srcollWidth 无效, 所以这里固定跟div一样的宽度
            detailObj.style.width = 240;
            detailObj.style.height = bd.scrollHeight;
        }
    },

    ///// <summary>
    ///// 隐藏详细信息
    ///// </summary>
    hideDetail : function()
    {
        $S($("dialog_messagebox_detail", top), false);
    },
    
    ///// <summary>
    ///// 提示最后焦点按钮获得焦点
    ///// </summary>
    setFocusButton : function()
    {
        if (top.dialog.currentDialogWin.focusButton && top.dialog.currentDialogWin.focusButton.focus)
        {
            setTimeout(function(){top.dialog.currentDialogWin.focusButton.focus();}, 0);
        }
        else if (top.dialog.currentDialogWin.ok && top.dialog.currentDialogWin.ok.focus)
        {
            setTimeout(function(){top.dialog.currentDialogWin.ok.focus();}, 0);
        }
    },
    
    ///// <summary>
    ///// 提示框按钮获得焦点
    ///// </summary>
    ///// <param name="e">消息参数</param>
    buttonfocus : function(e)
    {
        // 把最后获得焦点按钮保存下来
        top.dialog.currentDialogWin.focusButton = (e.target ? e.target : e.srcElement);
    },

    ///// <summary>
    ///// 鼠标按下
    ///// </summary>
    ///// <param name="e">消息参数</param>
    mousedown : function(e)
    {
        MessageBox.hideDetail();
        MessageBox.setFocusButton();
    },

    ///// <summary>
    ///// 提示框键盘消息处理
    ///// </summary>
    ///// <param name="e">消息参数</param>
    keydown : function(e)
    {
        var e = e ? e : event;
        switch(e.keyCode)
        {
            // ESC 键
            case 27:
                MessageBox.hide();
                break;
            // ←
            case 37:
            // ↑
            case 38:
                changeFocusButton(-1);
                break;
            // →
            case 39:
            // ↓
            case 40:
                changeFocusButton(1);
                break;
        }

        ///// <summary>
        ///// 查找当前焦点按钮的索引位置
        ///// </summary>
        ///// <param name="step">步长</return>
        ///// <return>索引位置</return>
        function changeFocusButton(step)
        {
            var Footer = $("Footer", top.dialog.currentDialogWin);

            if (Footer.childNodes.length == 0)
                return;

            if (Footer.childNodes.length == 1)
            {
                Footer.childNodes[0].focus();
            }
            else
            {
                var buttoncount = (Footer.childNodes.length + 1) / 2;
                var index = getCurrentButtonIndex() + step;
                if (index < 0)
                {
                    // 只有 索引位置为 -1, 并且 步长为 -1, 所以设置索引为最后一个按钮
                    index = buttoncount - 1;
                }
                else if (index >= buttoncount)
                {
                    index -= buttoncount;
                }
                Footer.childNodes[index * 2].focus();
            }

            ///// <summary>
            ///// 查找当前焦点按钮的索引位置
            ///// </summary>
            ///// <return>索引位置</return>
            function getCurrentButtonIndex()
            {
                for(var i = 0; i < buttoncount; i++)
                {
                    if (top.dialog.currentDialogWin.focusButton == Footer.childNodes[i * 2])
                        return i;
                }
                return -1;
            }
        }
    }
}
