﻿/* 
** Aloe JavaScript framework, version 1.0.0
** (c) 2008-2009 www.vinnosoft.com
*/
/// <summary>
/// <para>[功能说明]</para>
/// <remark>[备注]</remark>
/// </summary>
/// <param name="[参数名]">[参数说明]</param>
/// <param name="[参数名]">[参数说明]</param>
/// <param name="[参数名]">[参数说明]</param>
/// <returns>[返回值说明]</returns>
/// <example>
/// [示例代码]
/// </example>

/***** ***** ***** ***** Start: aloe initialization ***** ***** ***** *****/

// LN 9-54 in prototype v1.6.1.
// 框架全局对象，目的是把所有全局方法集中在一个对象中，其中包括 Global 对象 全部属性和方法。
var aloe = {
    /// <summary>
    /// <para>框架版本号。</para>
    /// </summary>
    version: "1.0.0",
    /// <summary>
    /// <para>是否调试，在发布站点中应用时应改为 false。</para>
    /// </summary>
    isDebug: true,

    config: {
        // 绝对脚本目录（引用后应重新设置该值）。
        absoluteScriptDirectory: String.empty
    },
    /// <summary>
    /// <para>异常调试，提示异常信息。</para>
    /// </summary>
    /// <param name="description">异常状况描述。</param>
    /// <param name="funcName">发生异常的函数名。</param>
    debug: function(description, funcName) {
        if (this.isDebug) {
            if (this.isUndefined(funcName))
                funcName = this.debug.caller;

            alert(String.format("{0} 执行异常: \n\n {1}", funcName, description));
        }
    },
    // LN 239-241 in prototype v1.6.1.
    /// <summary>
    /// <para>判断 给定对象实例的类型 是否为数值。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例的类型为数值返回 true，否则返回 false。</returns>
    isNumber: function(obj) {
        // typeof 返回值有六种可能： "number," "string," "boolean," "object," "function," 和 "undefined."。
        // 恒等运算符 （===、!==）：除了不进行类型转换，并且类型必须相同以外，这些运算符与相等运算符的作用是一样的。      
        return typeof obj === "number";
    },
    // LN 235-237 in prototype v1.6.1.
    /// <summary>
    /// <para>判断 给定对象实例的类型 是否为字符串。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例的类型为字符串返回 true，否则返回 false。</returns>    
    isString: function(obj) {
        return typeof obj === "string";
    },
    /// <summary>
    /// <para>判断 给定对象实例的类型 是否为布尔值。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例的类型为布尔值返回 true，否则返回 false。</returns>
    isBoolean: function(obj) {
        return typeof obj === "boolean";
    },
    /// <summary>
    /// <para>判断 给定对象实例的类型 是否为对象。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例的类型为对象返回 true，否则返回 false。</returns>
    isObject: function(obj) {
        return typeof obj === "object";
    },
    // LN 231-233 in prototype v1.6.1.
    /// <summary>
    /// <para>判断 给定对象实例的类型 是否为函数。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例的类型为函数返回 true，否则返回 false。</returns>
    isFunction: function(obj) {
        // typeof 返回值有六种可能： "number," "string," "boolean," "object," "function," 和 "undefined."。
        // 恒等运算符 （===、!==）：除了不进行类型转换，并且类型必须相同以外，这些运算符与相等运算符的作用是一样的。    
        return typeof obj === "function";
    },
    // LN 243-245 in prototype v1.6.1.
    /// <summary>
    /// <para>判断 给定对象实例 是否未定义。</para>
    /// <remark>undefined(未定义): 在变量被创建之后和被赋给值之前分配给该变量的一个特殊值。</remark>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例未定义返回 true，否则返回 false。</returns>
    isUndefined: function(obj) {
        // typeof 返回值有六种可能： "number," "string," "boolean," "object," "function," 和 "undefined."。
        // 恒等运算符 （===、!==）：除了不进行类型转换，并且类型必须相同以外，这些运算符与相等运算符的作用是一样的。
        return typeof obj === "undefined";
    },
    /// <summary>
    /// <para>判断 给定对象实例 是否已定义。</para>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例已定义返回 true，否则返回 false。</returns>
    isDefined: function(obj) {
        return !this.isUndefined(obj);
    },
    /// <summary>
    /// <para>判断 给定对象实例 是否为空引用。</para>
    /// <remark>
    /// null(空引用): 在 Jscript 中数据类型 null 只有一个值：null。关键字 null 不能用作函数或变量的名称。
    /// 包含 null 的变量包含“无值”或“无对象”。换句话说，该变量没有保存有效的数、字符串、boolean、数组或对象。
    /// 可以通过给一个变量赋 null 值来清除变量的内容。
    /// 请注意，在 Jscript 中，null 与 0 不相等（与在 C 和 C++ 中不同）。
    /// 同时应该指出的是，Jscript中 typeof 运算符将报告 null 值为 Object 类型，而非类型 null。这点潜在的混淆是为了向下兼容。
    /// </remark>
    /// </summary>
    /// <param name="obj">给定的对象实例。</param>
    /// <returns>给定对象实例为空引用返回 true，否则返回 false。</returns>
    isNull: function(obj) {
        return obj === null;
    },
    isUndefinedOrNull: function(obj) {
        return this.isUndefined(obj) || this.isNull(obj);
    },

    /// <summary>
    /// <para>对 String 对象编码，以便它们能在所有计算机上可读。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="charString">必选项，要编码的任意 String 对象或文字。</param>
    /// <returns>
    /// 返回一个包含了 charstring 内容的字符串值（Unicode 格式）。
    /// 所有空格、标点、重音符号以及其他非 ASCII 字符都用 %xx 编码代替，其中 xx 等于表示该字符的十六进制数。
    /// 例如，空格返回的是 "%20" 。
    /// 字符值大于 255 的以 %uxxxx 格式存储。
    /// <remark>escape 方法不能够用来对统一资源标示码 (URI) 进行编码。对其编码应使用 encodeURI 和encodeURIComponent 方法。</remark>
    /// </returns>
    escape: function(charString) {
        return escape(charString);
    },
    /// <summary>
    /// <para>将用 escape 方法进行了编码的 String 对象进行解码。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="charString">必选项，要解码的 String 对象。</param>
    /// <returns>
    /// 返回一个包含 charstring 内容的字符串值。所有以 %xx 十六进制形式编码的字符都用 ASCII 字符集中等价的字符代替。 
    /// 以 %uxxxx 格式（Unicode 字符）编码的字符用十六进制编码 xxxx 的 Unicode 字符代替。
    /// <remark>unescape 方法不能用于解码统一资源标识码 (URI)。解该码可使用 decodeURI 和 decodeURIComponent 方法。</remark>
    /// </returns>
    unescape: function() {
        return unescape(charString);
    },

    /// <summary>
    /// <para>将文本字符串编码为一个有效的统一资源标识符 (URI)。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="URIString">必选项，待编码的 URI。</param>
    /// <returns>
    /// 返回一个编码的 URI。如果您将编码结果传递给 decodeURI，那么将返回初始的字符串。
    /// <remark>encodeURI 方法不会对下列字符进行编码：":"、"/"、";" 和 "?"。请使用 encodeURIComponent 方法对这些字符进行编码。</remark>
    /// </returns>
    encodeURI: function(URIString) {
        return encodeURI(URIString);
    },
    /// <summary>
    /// <para>返回一个已编码的统一资源标识符 (URI) 的非编码形式。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="URIString">必选项，已编码 URI 的值。</param>
    /// <returns>
    /// 返回一个字符串值。使用 decodeURI 方法代替已经过时的 unescape 方法。
    /// <remark>如果 URIString 无效，那么将产生一个 URIError。</remark>
    /// </returns>
    decodeURI: function(URIString) {
        return decodeURI(URIString);
    },

    /// <summary>
    /// <para>将文本字符串编码为一个统一资源标识符 (URI) 的一个有效组件。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="URIString">必选项，待编码的 URI。</param>
    /// <returns>
    /// 返回一个已编码的 URI。如果您将编码结果传递给 decodeURIComponent，那么将返回初始的字符串。
    /// 因为 encodeURIComponent 方法对所有的字符编码。
    /// <remark>
    /// 如果该字符串代表一个路径，例如 /folder1/folder2/default.html，
    /// 其中的斜杠也将被编码。这样一来，当该编码结果被作为请求发送到 web 服务器时将是无效的。
    /// 如果字符串中包含不止一个 URI 组件，请使用 encodeURI 方法进行编码。
    /// </remark>
    /// </returns>
    encodeURIComponent: function(URIString) {
        return encodeURIComponent(URIString);
    },
    /// <summary>
    /// <para>返回统一资源标识符 (URI) 的一个已编码组件的非编码形式。</para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="encodedURIComponent">必选项，已编码的 URI 组件。</param>
    /// <returns>
    /// URIComponent 是一个完整的 URI 的一部分，通常对查询参数进行 encodeURIComponent 编码处理，
    /// 然后调用 decodeURIComponent 进行解码。
    /// <remark>如果 encodedURIString 无效，将产生一个 URIError。</remark>
    /// </returns>
    decodeURIComponent: function(encodedURIComponent) {
        return decodeURIComponent(encodedURIComponent);
    },

    /// <summary>
    /// <para>
    /// 检查 JScript 代码并执行。
    /// eval 函数允许 JScript 源代码的动态执行。例如,下面的代码创建了一个包含 Date 对象的新变量 mydate：
    /// eval("var mydate = new Date();");
    /// 传递给 eval 方法的代码执行时的上下文和调用 eval 方法的一样。
    /// </para>
    /// <remark>Global 对象的方法。</remark>
    /// </summary>
    /// <param name="codeString">包含有效 JScript 代码的字符串值。这个字符串将由 JScript 分析器进行分析和执行。</param>
    /// <returns>若代码执行后存在返回值，则返回该值；否则返回 undefined。</returns>
    eval: function(codeString) {
        return eval(codeString);
    },
    /// <summary>
    /// <para>获取 对象实例的属性名数组。</para>
    /// </summary>
    /// <param name="obj">对象实例。</param>
    /// <returns>对象实例的属性名数组。</returns>
    getPropertyNames: function(obj) {
        var pNames = new Array();
        for (var p in obj) {
            if (obj[p] && !(obj[p] instanceof Function))
                pNames.push(p);
        }
        return pNames.sort();
    },
    /// <summary>
    /// <para>获取 对象实例的属性计数。</para>
    /// </summary>
    /// <param name="obj">对象实例。</param>
    /// <returns>对象实例的属性计数。</returns>
    propertyCount: function(obj) {
        return this.getPropertyNames(obj).length;
    },
    /// <summary>
    /// <para>获取 对象实例的方法名数组。</para>
    /// </summary>
    /// <param name="obj">对象实例。</param>
    /// <returns>对象实例的方法名数组。</returns>    
    getMethodNames: function(obj) {
        var mNames = new Array();
        for (var p in obj) {
            if (obj[p] && obj[p] instanceof Function)
                mNames.push(p);
        }
        return mNames.sort();
    },
    /// <summary>
    /// <para>获取 对象实例的方法计数。</para>
    /// </summary>
    /// <param name="obj">对象实例。</param>
    /// <returns>对象实例的方法计数。</returns>
    methodCount: function(obj) {
        return this.getMethodNames(obj).length;
    },
    /// <summary>
    /// <para>获取 类路径。</para>
    /// <remark>重写 Object 原型上的 getClassPath 方法。</remark>
    /// </summary>
    /// <returns>类路径。</returns>    
    getClassPath: function(obj) {
        if (obj == this)
            return "[Object aloe]";

        var reg = /^\nfunction (\w+)\(\) \{[\s\S]*$/gi;

        // this is a Class.
        if (this.isDefined(obj.prototype))
            return String.format("[{0}]", obj.toString().replace(reg, function($0, $1, $2) {
                return $1;
            }));
        else {
            if (this.isDefined(obj.constructor)) {
                // this is a prototype.
                var className = obj.constructor.toString().replace(reg, function($0, $1, $2) {
                    return $1;
                });

                return String.format("[{0} prototype]", className);
            }
            else
                return "[document]";
        }
    }
};

/***** ***** ***** ***** End: aloe initialization ***** ***** ***** *****/


/***** ***** ***** ***** Start: Object ***** ***** ***** *****/

// LN 152-156 in prototype v1.6.1.
/// <summary>
/// <para>为目标对象(destination)扩展源对象(source)上所有的属性及方法。</para>
/// <remark>Object 的静态方法。</remark>
/// </summary>
/// <param name="destination">目标对象。</param>
/// <param name="source">源对象。</param>
/// <param name="isOverride">是否覆盖同名成员对象。</param>
/// <returns>扩展后的目标对象。</returns>
Object.extend = function(destination, source, isOverride) {
    if (isOverride) {
        for (var property in source) {
            destination[property] = source[property];
        }
    }
    else {
        for (var property in source) {
            if (!(property in destination))
                destination[property] = source[property];
        }
    }
    return destination;
}

/***** ***** ***** ***** End: Object ***** ***** ***** *****/

/***** ***** ***** ***** Start: String ***** ***** ***** *****/

/// <summary>
/// <para>空字符串。</para>
/// </summary>
String.empty = "";
/// <summary>
/// <para>忽略大小写。</para>
/// </summary>
String.ignoreCase = true;
/// <summary>
/// <para>判断 给定对象实例 是否为 空引用 或 未定义 或 空字符串。</para>
/// </summary>
/// <returns>是空引用 或 未定义 或 空字符串，返回 true；否则返回 false。</returns>
String.isNullOrUndefinedOrEmpty = function(str) {
    return aloe.isNull(str) || aloe.isUndefined(str) || str == String.empty;
};
/// <summary>
/// <para>
/// 字符串格式化，将指定的 String 中的每个格式项（形如 {0}, {1}等）替换为
/// 相应对象的值的文本等效项。
/// </para>
/// <remark>需显示左大括号时，应输入双左大括号，即 "{{" 。</remark>
/// </summary>
/// <param name="fmtStr">格式字符串，包含零到多个格式项。</param>
/// <param name="paramsArray">包含若干填充项的数组 或 若干以逗号分隔的参数列表。</param>
/// <returns>格式化后的字符串，其中的格式项被替换为 paramsArray 中填充项的值的文本。</returns>
/// <example>
/// String.format("Hello, {0}, {1}!<br />keep {{{{2}}", "world", 123);
/// </example>
String.format = function(fmtStr, paramsArray) {
    var output = fmtStr;
    var re;
    var valueArray;

    if (paramsArray instanceof Array)
        valueArray = paramsArray
    else {
        valueArray = new Array();
        for (var i = 1; i < arguments.length; i++)
            valueArray.push(arguments[i]);
    }

    for (var i = 0; i < valueArray.length; i++) {
        re = new RegExp("(\\{)?\\{" + i + "}", "g");

        output = output.replace(re, function($0, $1) {
            return $1 ? $0 : valueArray[i];
        });
    }

    return output.replace(new RegExp("\\{\\{", "g"), "{");
};
/// <summary>
/// <para>将 给定字符串 转换为 html 实体。</para>
/// <remark>转换后的字符串可保存至 ANSI 编码格式的 html 文件中，并可在浏览器中正确显示，而无需再次解码。</remark>
/// </summary>
/// <param name="str">给定的字符串。</param>
/// <returns>转换后包含 html 实体的字符串。</returns>
String.convertToHtmlEntity = function(str) {
    var reg = /%([0-9A-F]{1,2})|%u([0-9A-F]{4})/gi;
    return aloe.escape(str).replace(reg, function($0, $1, $2) {
        return String.format("&#{0};", parseInt($1 || $2, 16));
    });
};
// 将给定的以十六进制表示的字符串(\uxxxx)转换为 Unicode 字符串。
String.convertToUnicode = function(hexStr) {
    // hexStr 形如: \uxxxx，例如：\u00e1\u00e2\u00e3\u00e4

    // 方法一
    //return unescape(hexStr.replace(/\\u/g, "%u"));

    // 方法二
    return eval("\"" + hexStr + "\"");
};

String.prototype.equals = function(comparisonStr, ignoreCase) {
    if (aloe.isUndefined(ignoreCase))
        ignoreCase = false;

    if (ignoreCase)
        return this.toLowerCase() == comparisonStr.toLowerCase();
    else
        return this == comparisonStr;
}
// LN 617-619 in prototype v1.6.1;
/// <summary>
/// <para>判断字符串是否为空字符串。</para>
/// </summary>
/// <returns>是空字符串，返回 true；否则返回 false。</returns>
String.prototype.isEmpty = function() {
    return this == String.empty;
};
/// <summary>
/// <para>清除字符串实例左右两侧的空格。</para>
/// </summary>
/// <returns>处理后的字符串。</returns>
String.prototype.trim = function() {
    return this.replace(/(^\s+)|(\s+$)/g, String.empty);
};
/// <summary>
/// <para>清除字符串实例左侧的空格。</para>
/// </summary>
/// <returns>处理后的字符串。</returns>
String.prototype.leftTrim = function() {
    return this.replace(/^\s+/g, String.empty);
};
/// <summary>
/// <para>清除字符串实例右侧的空格。</para>
/// </summary>
/// <returns>处理后的字符串。</returns>
String.prototype.rightTrim = function() {
    return this.replace(/\s+$/g, String.empty);
};
/// <summary>
/// <para>反转字符串。</para>
/// </summary>
/// <returns>反转后的字符串。</returns>
String.prototype.reverse = function() {
    return this.split(String.empty).reverse().join(String.empty);
};
/// <summary>
/// <para>获取 字符串的字节长度。</para>
/// </summary>
/// <returns>字符串的字节长度。</returns>
String.prototype.getByteLength = function() {
    return this.replace(/[^\x00-\xff]/g, "xx").length;
};

/***** ***** ***** ***** End: String ***** ***** ***** *****/


/***** ***** ***** ***** Start: Array ***** ***** ***** *****/

/// <summary>
/// <para>获取 给定元素 在数组中的索引值。</para>
/// </summary>
/// <param name="element">给定元素。</param>
/// <param name="startIndex">
/// 可选项，搜索的起始位置，缺省从头开始，即 0；若为负数，
/// 则从字符串末尾倒数的第 startIndex 位置开始搜索。
/// </param>
/// <returns>若找到返回相应索引值，否则返回 -1。</returns>
Array.prototype.indexOf = function(element, startIndex) {
    startIndex || (startIndex = 0);

    var length = this.length;

    if (startIndex < 0)
        startIndex += length;

    for (; startIndex < length; startIndex++) {
        if (this[startIndex] === element)
            return startIndex;
    }

    return -1;
};
/// <summary>
/// <para>判断 给定元素 是否包含在数组中</para>
/// </summary>
/// <param name="element">给定元素。</param>
/// <returns>若找到返回 true，否则返回 false。</returns>
Array.prototype.contains = function(element) {
    if (this.indexOf(element) != -1)
        return true;
    else
        return false;
};
/// <summary>
/// <para>判断 数组是否为空，即长度为 0。</para>
/// </summary>
/// <returns>若为空返回 true，否则返回 false。</returns>
Array.prototype.isEmpty = function() {
    return this.length == 0;
};

/***** ***** ***** ***** End: Array ***** ***** ***** *****/

/***** ***** ***** ***** Start: Date ***** ***** ***** *****/

/// <summary>
/// <para>将 给定的中文格式日期字符串（形如 2009-10-01） 解析为 日期实例。</para>
/// </summary>
/// <param name="dateStr">给定的日期字符串。</param>
/// <returns>相应的日期实例 或 null。</returns>
Date.parseCnFmtDate = function(dateStr) {
    var re = /^(\d{4})-(\d{1,2})-(\d{1,2})/g;
    if (re.test(dateStr)) {
        var r = dateStr.split('-');
        return new Date(Date.parse(dateStr.replace(re, function($0, $1, $2, $3) {
            return String.format("{0}/{1}/{2}", $2, $3, $1);
        })));
    } else
        return null;
};

/***** ***** ***** ***** End: Date ***** ***** ***** *****/


/***** ***** ***** ***** Start: Math ***** ***** ***** *****/

Math._floor = Math.floor;
// 向下取整，扩展为按小数位截取。
Math.floor = function(number, decimalLength) {
    if (arguments.length == 2) {
        var zoomIn = Math.pow(10, decimalLength);
        return Math._floor(number * zoomIn) / zoomIn;
    }
    else
        return Math._floor(number);
};

Math._ceil = Math.ceil;
// 向上取整，扩展为按小数位截取。
Math.ceil = function(number, decimalLength) {
    if (arguments.length == 2) {
        var zoomIn = Math.pow(10, decimalLength);
        return Math._ceil(number * zoomIn) / zoomIn;
    }
    else
        return Math._ceil(number);
};

Math._round = Math.round;
// 四舍五入取整，扩展为按小数位截取。
Math.round = function(number, decimalLength) {
    if (arguments.length == 2) {
        var zoomIn = Math.pow(10, decimalLength);
        return Math._round(number * zoomIn) / zoomIn;
    }
    else
        return Math._round(number);
};

/***** ***** ***** ***** End: Math ***** ***** ***** *****/


/***** ***** ***** ***** Start: aloe extension ***** ***** ***** *****/

aloe.showMemberList = function(objCommaArgs) {
    /// <summary>
    /// <para>显示成员对象列表。</para>
    /// </summary>
    /// <param name="objCommaArgs">以逗号分隔的对象参数列表。</param>
    if (arguments.length > 1) {
        for (var i = 0; i < arguments.length; i++) {
            this.showMemberList(arguments[i]);
        }
    }
    else if (this.isObject(objCommaArgs) || this.isFunction(objCommaArgs)) {

        var pNames = aloe.getPropertyNames(objCommaArgs);
        var mNames = aloe.getMethodNames(objCommaArgs);

        if (pNames.isEmpty() && mNames.isEmpty()) return;

        var classPath = aloe.getClassPath(objCommaArgs);
        var regArgs = /function\(([\w, ]*)\)[\s\S]*$/gi;

        var propertyListFmt = "<p style='padding-left: 80px;'><code>{0}</code></p>";

        //document.write("<hr />");

        document.write(String.format("<h3>{0}</h3>", classPath));

        if (!pNames.isEmpty()) {
            document.write(String.format("<h4 style='padding-left: 40px;'> property ({0}):</h4>", pNames.length));
            document.write(String.format(propertyListFmt, pNames.join("<br />")));
        }

        if (!mNames.isEmpty()) {
            document.write(String.format("<h4 style='padding-left: 40px;'> method ({0}):</h4>", mNames.length));

            document.write("<p style='padding-left: 80px;'>");

            for (var i = 0; i < mNames.length; i++) {
                objCommaArgs[mNames[i]].toString().match(regArgs);
                document.write(String.format("<code>{0}(<i>{1}</i>)</code><br />", mNames[i], RegExp.$1));
            }

            document.write("</p>");
        }

        if (this.isFunction(objCommaArgs))
            this.showMemberList(objCommaArgs.prototype);
    }
}

/***** ***** ***** ***** End: aloe extension ***** ***** ***** *****/


/***** ***** ***** ***** Start: document extension ***** ***** ***** *****/

document.isHtmlNode = function(targetNode, funcName, paramName) {
    /*
    ** document.isHtmlNode
    */
    if (targetNode && targetNode.nodeType)
        return true;
    else {
        if (aloe.isDebug) {
            if (aloe.isUndefined(funcName))
                funcName = document.isHtmlNode.caller;

            aloe.debug(String.format("{0} 不是 HTML 节点。", paramName), funcName);
        }
        else
            return false;
    }
};

document.isElement = function(targetNode) {
    if (document.isHtmlNode(targetNode) && targetNode.nodeType == 1)
        return true;
    else
        return false;
};

document.isTextNode = function(targetNode) {
    if (document.isHtmlNode(targetNode) && targetNode.nodeType == 3)
        return true;
    else
        return false;
};

// 获取给定节点的前一兄弟元素节点。
document.getPreviousSiblingElement = function(oNode) {
    if (document.isHtmlNode(oNode, "document.getPreviousSiblingElement", "oNode")) {
        do {
            if (oNode.previousSibling
                && document.isElement(oNode.previousSibling))
                return oNode.previousSibling;
            else
                oNode = oNode.previousSibling;
        } while (oNode);
    }
};
// 根据 标记名称 获取 给定节点的前一兄弟元素节点。
document.getPreviousSiblingElementByTagName = function(oNode, sTagName) {
    if (document.isHtmlNode(oNode, "document.getPreviousSiblingElementByTagName", "oNode")) {
        do {
            if (oNode.previousSibling
                && document.isElement(oNode.previousSibling)
                && oNode.previousSibling.tagName.equals(sTagName, String.ignoreCase))
                return oNode.previousSibling;
            else
                oNode = oNode.previousSibling;
        } while (oNode);
    }
};
// 获取给定节点的后一兄弟元素节点。
document.getNextSiblingElement = function(oNode) {
    if (document.isHtmlNode(oNode, "document.getNextSiblingElement", "oNode")) {
        do {
            if (oNode.nextSibling
                && document.isElement(oNode.nextSibling))
                return oNode.nextSibling;
            else
                oNode = oNode.nextSibling;
        } while (oNode);
    }
};
// 根据 标记名称 获取 给定节点的后一兄弟元素节点。
document.getNextSiblingElementByTagName = function(oNode, sTagName) {
    if (document.isHtmlNode(oNode, "document.getNextSiblingElementByTagName", "oNode")) {
        do {
            if (oNode.nextSibling
                && document.isElement(oNode.nextSibling)
                && oNode.nextSibling.tagName.equals(sTagName, String.ignoreCase))
                return oNode.nextSibling;
            else
                oNode = oNode.nextSibling;
        } while (oNode);
    }
};

// 获取 给定元素的子元素节点。
document.getChildElements = function(oParent) {
    if (document.isHtmlNode(oParent, "document.getChildElements", "oParent")) {
        var elements = new Array();
        for (var i = 0; i < oParent.childNodes.length; i++) {
            if (document.isElement(oParent.childNodes[i])) {
                elements.push(oParent.childNodes[i]);
            }
        }
        return elements;
    }
};
// 根据 标记名称 获取 给定元素的子元素节点。
document.getChildElementsByTagName = function(oParent, sTagName) {
    if (document.isHtmlNode(oParent, "document.getChildElementsByTagName", "oParent")) {
        var elements = new Array();
        for (var i = 0; i < oParent.childNodes.length; i++) {
            if (document.isElement(oParent.childNodes[i])
                && oParent.childNodes[i].tagName.equals(sTagName, String.ignoreCase)) {
                elements.push(oParent.childNodes[i]);
            }
        }
        return elements;
    }
};

// 获取 给定元素的首个子元素节点。
document.getFirstChildElement = function(oParent) {
    if (document.isHtmlNode(oParent, "document.getFirstChildElement", "oParent")) {
        for (var i = 0; i < oParent.childNodes.length; i++) {
            if (document.isElement(oParent.childNodes[i]))
                return oParent.childNodes[i];
        }
    }
};
// 根据 标记名称 获取 给定元素的首个子元素节点。
document.getFirstChildElementByTagName = function(oParent, sTagName) {
    if (document.isHtmlNode(oParent, "document.getFirstChildElementByTagName", "oParent")) {
        for (var i = 0; i < oParent.childNodes.length; i++) {
            if (document.isElement(oParent.childNodes[i])
                && oParent.childNodes[i].tagName.equals(sTagName, String.ignoreCase))
                return oParent.childNodes[i];
        }
    }
};

// 获取 给定元素的末尾子元素节点。
document.getLastChildElement = function(oParent) {
    if (document.isHtmlNode(oParent, "document.getLastChildElement", "oParent")) {
        for (var i = oParent.childNodes.length - 1; i >= 0; i--) {
            if (document.isElement(oParent.childNodes[i]))
                return oParent.childNodes[i];
        }
    }
};
// 根据 标记名称 获取 给定元素的末尾子元素节点。
document.getLastChildElementByTagName = function(oParent, sTagName) {
    if (document.isHtmlNode(oParent, "document.getLastChildElementByTagName", "oParent")) {
        for (var i = oParent.childNodes.length - 1; i >= 0; i--) {
            if (document.isElement(oParent.childNodes[i])
                && oParent.childNodes[i].tagName.equals(sTagName, String.ignoreCase))
                return oParent.childNodes[i];
        }
    }
};

/// <summary>
/// 显示 给定元素。
/// </summary>
/// <param name="element">给定元素。</param>
document.showElement = function(element) {
    if (aloe.isUndefined(element)) element = this;
    element.style.visibility = "visible";
};
/// <summary>
/// 隐藏 给定元素。
/// </summary>
/// <param name="element">给定元素。</param>
document.hideElement = function(element) {
    if (aloe.isUndefined(element)) element = this;
    element.style.visibility = "hidden";
};
/// <summary>
/// 创建 div 元素。
/// </summary>
/// <returns>对于新创建的 div 元素的引用。</returns>
document.createDiv = function() {
    return document.createElement('div');
};
/// <summary>
/// 为 给定元素 的 特定事件 附加 执行函数。
/// </summary>
/// <param name="element">给定元素。</param>
/// <param name="eventName">事件名称。</param>
/// <param name="funcPointer">函数指针，即函数名。</param>
document.appendEventHandler = function(element, eventName, funcPointer) {
    if (document.isElement(element)) {
        var _eventHandler = element[eventName];
        element[eventName] = function() {
            if (_eventHandler) _eventHandler();
            funcPointer();
        };
    }
};

/***** ***** ***** ***** End: document extension ***** ***** ***** *****/


/***** ***** ***** ***** Start: Utility ***** ***** ***** *****/

// LN 1709-1718 in prototype v1.6.1;
function $(elementIdCommaArgs) {
    if (arguments.length > 1) {
        for (var i = 0, elements = [], length = arguments.length; i < length; i++)
            elements.push($(arguments[i]));
        return elements;
    }

    if (aloe.isString(elementIdCommaArgs))
        elementIdCommaArgs = document.getElementById(elementIdCommaArgs);

    // [TODO] 研究 Element，及其 extend 方法。
    //return Element.extend(element);
    return elementIdCommaArgs;
}

// 浏览器。
aloe.browser = {
    /// <summary>
    /// 获取 浏览器窗口的宽度。
    /// Calculate the current window width.
    /// </summary>
    /// <returns>浏览器窗口的宽度。</returns>
    getWidth: function() {
        if (window.innerWidth)
            return window.innerWidth;
        else if (document.documentElement && document.documentElement.clientWidth)
            return document.documentElement.clientWidth;
        else if (document.body)
            return document.body.clientWidth;
        else
            return null;
    },
    /// <summary>
    /// 获取 浏览器窗口的高度。
    /// Calculate the current window height.
    /// </summary>
    /// <returns>浏览器窗口的高度。</returns>
    getHeight: function() {
        if (window.innerHeight)
            return window.innerHeight;
        else if (document.documentElement && document.documentElement.clientHeight)
            return document.documentElement.clientHeight;
        else if (document.body)
            return document.body.clientHeight;
        else
            return null;
    },
    /// <summary>
    /// 获取 浏览器窗口与最顶部之间的距离。
    /// Calculate the current window vertical offset from page top.
    /// </summary>
    /// <returns>浏览器窗口的与最顶部之间的距离。</returns>
    getScrollTop: function() {
        if (window.pageYOffset)
            return window.pageYOffset;
        else if (document.documentElement && document.documentElement.scrollTop)
            return document.documentElement.scrollTop;
        else if (document.body.scrollTop)
            return document.body.scrollTop;
        else
            return 0;
    },
    /// <summary>
    /// 获取 浏览器窗口的与最左侧之间的距离。
    /// Calculate the current window horizontal offset from page left..
    /// </summary>
    /// <returns>浏览器窗口的与最左侧之间的距离。</returns>
    getScrollLeft: function() {
        if (window.pageXOffset)
            return window.pageXOffset;
        else if (document.documentElement && document.documentElement.scrollLeft)
            return document.documentElement.scrollLeft;
        else if (document.body.scrollLeft)
            return document.body.scrollLeft;
        else
            return 0;
    },
    /*
    * 无提示关闭窗口。
    *
    * 适用于 IE 6-8。
    */
    closeQuietly: function() {
        // 用于 IE6。
        window.opener = null
        window.open("", "_self")
        window.close();
    },
    /*
    * 快速显示模式对话框。
    *
    * sUrl: 对话框页面地址。
    * vArguments: 传入参数。
    */
    showFullScreenModalDialog: function(sUrl, vArguments) {
        var sFeatures = "dialogHeight:" + screen.availHeight + "px;"
                   + "dialogWidth:" + screen.availWidth + "px;"
                   + "resizable:yes;center:yes;";

        window.showModalDialog(sUrl, vArguments, sFeatures);
    },
    // 刷新当前页面。
    refresh: function() {
        window.location.href = window.location.href;
    }
};

// 消息类型。
aloe.msgType = {
    // 成功。
    success: "success",
    // 警告。
    warning: "warning",
    // 错误。
    error: "error",
    // 确认。
    confirm: "confirm"
};

/***** ***** Start: MsgBox ***** *****/

// 消息框。
aloe.msgBox = document.createDiv();
aloe.msgBox.isInitialized = false;
aloe.msgBox.imagePath = "aloe/images/msgBox/";
aloe.msgBox.configImagePath = function() {
    this.imagePath = String.format("{0}{1}", aloe.config.absoluteScriptDirectory, this.imagePath);
};
// setInterval 执行间隔，单位 millisecond。
aloe.msgBox.interval = 5;
// 透明度增长速度，每次增加 10。
aloe.msgBox.speed = 10;

aloe.msgBox.initialize = function() {
    if (!this.isInitialized) {
        document.body.appendChild(this);

        // 页面遮罩。
        this.pageMask = document.body.appendChild(document.createDiv());

        this.header = this.appendChild(document.createDiv());
        this.header.titleBar = this.header.appendChild(document.createDiv());
        this.header.titleBar.setTitle = function(title) {
            this.innerHTML = title;
        };
        this.header.closeButton = this.header.appendChild(document.createDiv());
        //this.header.closeButton.setAttribute('onclick', 'function() { aloe.msgBox.fadeOut() }');
        this.header.closeButton.onclick = function() { aloe.msgBox.fadeOut() };

        this.body = this.appendChild(document.createDiv());
        this.body.setMessage = function(msg) {
            this.innerHTML = msg;
        };

        this.footer = this.appendChild(document.createElement("div"));
        this.footer.okButton = this.footer.appendChild(document.createElement('<input type="submit" value="确定" />'));
        this.footer.okButton.onclick = function() {
            aloe.msgBox.fadeOut();
            aloe.msgBox.triggerElement.onclick = null;
            aloe.msgBox.triggerElement.click();
            // 清理 trigger。
            aloe.msgBox.triggerElement = null;
        };

        this.footer.cancelButton = this.footer.appendChild(document.createElement('<input type="button" value="取消" />'));
        this.footer.cancelButton.onclick = function() {
            aloe.msgBox.fadeOut();
            aloe.msgBox.triggerElement = null;
        }

        this.appendShowHideMethod(this);
        this.appendShowHideMethod(this.pageMask);

        this.initializeStyle();

        this.isInitialized = true;
    }
};

aloe.msgBox.afterHide = function() {
    /// <summary>
    /// 消息框隐藏后执行的函数。
    /// <remark>缺省为空函数，应在使用时重新定义。<remark>
    /// </summary>
};
/// <summary>
/// 淡入淡出消息框。
/// Fade-in the message box.
/// </summary>
/// <param name="isShow">是否显示消息框。</param>
aloe.msgBox.fade = function(isShow) {
    if (aloe.isUndefined(isShow)) isShow = true;

    var value = isShow ? (this.alpha + this.speed) : (this.alpha - this.speed);

    this.alpha = value;
    //this.style.opacity = (value / 100);
    this.style.filter = 'alpha(opacity=' + value + ')';

    if (value >= 99) {
        clearInterval(this.timerId);
        this.timerId = null;
    } else if (value <= 1) {
        clearInterval(this.timerId);
        this.hide();
        this.pageMask.hide();
        this.afterHide();
    }
};
/// <summary>
/// 淡入（显示）消息框。
/// Fade-out the message box.
/// </summary>
aloe.msgBox.fadeIn = function() {
    if (this.isInitialized)
        this.fade(true);
};
/// <summary>
/// 淡出（隐藏）消息框。
/// Fade-out the message box.
/// </summary>
aloe.msgBox.fadeOut = function() {
    if (this.isInitialized) {
        clearInterval(this.timerId);
        this.timerId = setInterval("aloe.msgBox.fade(false)", this.interval);
    }
};
/// <summary>
/// 为 给定元素 递归添加 显示、隐藏方法。
/// </summary>
/// <param name="element">给定元素。</param>
aloe.msgBox.appendShowHideMethod = function(element) {
    if (document.isElement(element)) {
        element.show = document.showElement;
        element.hide = document.hideElement;

        var children = document.getChildElements(element);
        for (var i = 0; i < children.length; i++)
            this.appendShowHideMethod(children[i]);
    }
};
/// <summary>
/// 初始化 messageBox 各组成元素的样式。
/// <remark>将样式表内化，以便通过脚本灵活控制。</remark>
/// </summary>
aloe.msgBox.initializeStyle = function() {
    if (!this.isInitialized) {
        this.pageMask.style.cssText = "position:absolute; top:0; left:0; min-height:100%; width:100%; background:#ffffff; opacity:.75; filter:alpha(opacity=75); z-index:100; ";

        this.style.cssText = "position:absolute; width:425px; padding:10px; z-index:200; background:#ffffff; ";

        this.header.initialCssText = "display:block; position:relative; width:411px; padding:4px 6px 7px 6px; height:14px; font-size:14px; font-weight:bold; ";
        this.header.style.cssText = this.header.initialCssText;

        this.header.titleBar.style.cssText = "float:left; ";

        this.header.closeButton.style.cssText = String.format("float:right; cursor:pointer; margin:3px 3px 3px 3px; height:11px; width:11px; background:url({0}dialog_close.gif) no-repeat; ", this.imagePath);

        this.body.initialCssText = "display:block; height:160px; padding:6px; color:#666666; font-size:13px; ";
        this.body.style.cssText = this.body.initialCssText;

        // [NOTE] 缺省状态下隐藏页脚，仅在 confirm 时显示页脚及其按钮。
        this.footer.style.cssText = "margin-left: 70px; margin-top: -40px; visibility: hidden; ";

        var btnCssText = String.format("cursor:hand; height:24px; width:60px; line-height:24px; font-size:14px; font-weight:bold; "
                            + "background:url({0}prompt_header.gif) repeat-x; color:#355468; border:1px solid #4f6d81; ", this.imagePath);
        this.footer.okButton.style.cssText = btnCssText + "margin-right:10px; ";
        this.footer.cancelButton.style.cssText = btnCssText;
    }
};
/// <summary>
/// 根据类型名称为 messageBox 设置匹配的样式。
/// </summary>
/// <param name="typeName">消息框类型名称。</param>
aloe.msgBox.setStyle = function(typeName) {
    var newHeaderCssText, newBodyCssText;

    this.header.closeButton.show();
    this.footer.hide();

    switch (typeName) {
        // 成功提示。                                                   
        case aloe.msgType.success:
            newHeaderCssText = String.format("background:url({0}success_header.gif) repeat-x; color:#3c7f51; border:1px solid #60a174; border-bottom:none; ", this.imagePath);
            newBodyCssText = String.format("background:#fff url({0}success_bg.jpg) bottom right no-repeat; border:1px solid #60a174; border-top:none; ", this.imagePath);
            break;
        // 警告提示，如：未填写必填项等。                                                                          
        case aloe.msgType.warning:
            newHeaderCssText = String.format("background:url({0}warning_header.gif) repeat-x; color:#957c17; border:1px solid #c5a524; border-bottom:none; ", this.imagePath);
            newBodyCssText = String.format("background:#fff url({0}warning_bg.jpg) bottom right no-repeat; border:1px solid #c5a524; border-top:none; ", this.imagePath);
            break;
        // 错误提示，如：违反业务规则等。                                                                            
        case aloe.msgType.error:
            newHeaderCssText = String.format("background:url({0}error_header.gif) repeat-x; color:#6f2c2c; border:1px solid #924949; border-bottom:none; ", this.imagePath);
            newBodyCssText = String.format("background:#fff url({0}error_bg.jpg) bottom right no-repeat; border:1px solid #924949; border-top:none; ", this.imagePath);
            break;
        // 确认提示，如：提交确认等。                                                                            
        case aloe.msgType.confirm:
            newHeaderCssText = String.format("background:url({0}prompt_header.gif) repeat-x; color:#355468; border:1px solid #4f6d81; border-bottom:none; ", this.imagePath);
            newBodyCssText = String.format("background:#fff url({0}prompt_bg.jpg) bottom right no-repeat; border:1px solid #4f6d81; border-top:none; ", this.imagePath);

            this.header.closeButton.hide();

            this.footer.show();

            if (event) {
                // 记录 触发元素。
                this.triggerElement = event.srcElement;
                // 阻止 正常提交。
                event.returnValue = false;
            }
            break;
    }

    this.header.style.cssText = this.header.initialCssText + newHeaderCssText;
    this.body.style.cssText = this.body.initialCssText + newBodyCssText;
};
/// <summary>
/// 显示（构建）消息框。
/// <remark>私有方法，仅用于内部调用。</remark>
/// </summary>
/// <param name="title">标题。</param>
/// <param name="message">提示信息。</param>
/// <param name="typeName">消息框类型名称。</param>
/// <param name="autoHideAfterSeconds">在指定秒数后自动隐藏。</param>
/// <param name="funcPointerAfterHide">隐藏对话框时执行的函数指针，即函数名。</param>
aloe.msgBox.display = function(title, message, typeName, autoHideAfterSeconds, funcPointerAfterHide) {
    if (this.isInitialized) {
        this.pageMask.show();
        this.show();
    } else
        this.initialize();

    // 设置 页面遮罩的宽、高。
    this.pageMask.style.width = document.documentElement.scrollWidth + 'px';
    this.pageMask.style.height = document.documentElement.scrollHeight + 'px';

    this.alpha = 0;
    //this.style.opacity = .00;
    this.style.filter = 'alpha(opacity=0)';

    with (aloe.browser) {
        this.style.top = (getScrollTop() + (getHeight() - this.offsetHeight) / 2) + "px";
        this.style.left = (getScrollLeft() + (getWidth() - this.offsetWidth) / 2) + "px";
    }

    this.header.titleBar.setTitle(title);
    this.body.setMessage(message);

    this.setStyle(typeName);

    if (aloe.isDefined(funcPointerAfterHide))
        this.afterHide = funcPointerAfterHide;

    this.timerId = setInterval("aloe.msgBox.fadeIn()", this.interval);

    if (autoHideAfterSeconds) {
        this.header.closeButton.hide();
        window.setTimeout("aloe.msgBox.fadeOut()", (autoHideAfterSeconds * 1000));
    }
};

/// <summary>
/// 简单提示消息框（2 秒后自动隐藏，用于成功提示）。
/// </summary>
/// <param name="title">标题。</param>
/// <param name="message">提示信息。</param>
/// <param name="funcPointerAfterHide">隐藏对话框时执行的函数指针，即函数名。</param>
aloe.msgBox.alert = function(title, message, funcPointerAfterHide) {
    document.appendEventHandler(document.body, "onload", function() {
        aloe.msgBox.display(title, message, aloe.msgType.success, 2, funcPointerAfterHide);
    });

};
/// <summary>
/// 警告消息框（用于必填项校验提示）。
/// </summary>
/// <param name="title">标题。</param>
/// <param name="message">提示信息。</param>
/// <param name="funcPointerAfterHide">隐藏对话框时执行的函数指针，即函数名。</param>
aloe.msgBox.warn = function(title, message, funcPointerAfterHide) {
    document.appendEventHandler(document.body, "onload", function() {
        aloe.msgBox.display(title, message, aloe.msgType.warning, funcPointerAfterHide);
    });
};
/// <summary>
/// 错误消息框（用于违反业务规则提示）。
/// </summary>
/// <param name="title">标题。</param>
/// <param name="message">提示信息。</param>
/// <param name="funcPointerAfterHide">隐藏对话框时执行的函数指针，即函数名。</param>
aloe.msgBox.showError = function(title, message, funcPointerAfterHide) {
    document.appendEventHandler(document.body, "onload", function() {
        aloe.msgBox.display(title, message, aloe.msgType.error, funcPointerAfterHide);
    });
};
/// <summary>
/// 确认消息框（用于提交确认提示）。
/// </summary>
/// <param name="title">标题。</param>
/// <param name="message">提示信息。</param>
/// <param name="funcPointerAfterHide">隐藏对话框时执行的函数指针，即函数名。</param>
aloe.msgBox.confirm = function(title, message, funcPointerAfterHide) {
    this.display(title, message, aloe.msgType.confirm, funcPointerAfterHide);
};

/***** ***** End: MsgBox ***** *****/

/***** ***** Start: ASP.NET TreeView ***** *****/

aloe.aspNet = {};

aloe.aspNet.treeView = {
    // 将给定 树节点 与 CheckBox 选框 联合。
    associateCheckBox: function(tn) {
        tn.checkBox = document.getFirstChildElementByTagName(tn.rows(0).lastChild, "input");
        tn.checkBox.treeNode = tn;
    },
    // 获取 给定父树节点 的 子节点。
    getChildTreeNodes: function(parentTN) {
        var container = document.getNextSiblingElementByTagName(parentTN, "div");

        if (aloe.isUndefined(container)) return;

        parentTN.childTreeNodes = document.getChildElementsByTagName(container, "table");

        for (var i = 0; i < parentTN.childTreeNodes.length; i++) {
            parentTN.childTreeNodes[i].parentTreeNode = parentTN;
        }

        return parentTN.childTreeNodes;
    },
    // 根据 给定父树节点 设置 子节点状态。
    setCheckBox: function(parentTN, isSelected) {
        if (aloe.isUndefined(parentTN.childTreeNodes)) return;

        for (var i = 0; i < parentTN.childTreeNodes.length; i++) {

            parentTN.childTreeNodes[i].checkBox.checked = isSelected;

            this.setCheckBox(parentTN.childTreeNodes[i], isSelected);
        }
    },
    // 选中 给定树节点的 父树节点。
    selectParentTreeNode: function(tn) {
        if (aloe.isUndefined(tn.parentTreeNode)) return;

        if (tn.parentTreeNode.checkBox.checked) return;

        tn.parentTreeNode.checkBox.checked = true;

        this.selectParentTreeNode(tn.parentTreeNode);
    },
    // 清除选中 给定树节点的 父树节点。
    unselectParentTreeNode: function(tn) {
        if (aloe.isUndefined(tn.parentTreeNode)) return;

        for (var i = 0; i < tn.parentTreeNode.childTreeNodes.length; i++) {
            if (tn.parentTreeNode.childTreeNodes[i].checkBox.checked) return;
        }

        tn.parentTreeNode.checkBox.checked = false;

        this.unselectParentTreeNode(tn.parentTreeNode);
    },
    // 根据 给定的 TreeView 的 clientId 初始化树上所有的 CheckBox 选框。
    initializeCheckBox: function(clientId) {
        var container = $(clientId);
        if (container) {
            var setCheckboxOnclickEvent = function(nodes) {
                if (aloe.isUndefined(nodes)) return;

                var node, cbx;

                for (var i = 0; i < nodes.length; i++) {
                    node = nodes[i];
                    aloe.aspNet.treeView.associateCheckBox(node)
                    node.checkBox.onclick = function() {
                        // 递归 选中/清除 全部子节点。
                        aloe.aspNet.treeView.setCheckBox(this.treeNode, this.checked);

                        if (this.checked) {
                            // 递归选中直接父节点。
                            aloe.aspNet.treeView.selectParentTreeNode(this.treeNode);
                        } else {
                            // 递归检查，直接父节点若无选中子节点则清除，否则保持选中。
                            aloe.aspNet.treeView.unselectParentTreeNode(this.treeNode);
                        }
                    };

                    setCheckboxOnclickEvent(aloe.aspNet.treeView.getChildTreeNodes(node));
                }
            }
            // 深度为 0 的子节点。
            setCheckboxOnclickEvent(document.getChildElementsByTagName(container, "table"));
        }
        else
            aloe.debug(String.format("当前页面不存在 Id 为 {0} 的 TreeView 控件！"), "aloe.aspNet.treeView.initializeCheckBox");
    }
};

/***** ***** End: ASP.NET TreeView ***** *****/

/***** ***** ***** ***** End: Utility ***** ***** ***** *****/


/***** ***** ***** ***** Start: [ProjectName] Customize ***** ***** ***** *****/

//aloe.config.absoluteScriptDirectory = ;
//aloe.msgBox.configImagePath();

aloe.config.absoluteScriptDirectory = "/Public/Script/";
aloe.msgBox.configImagePath();

// 根据 给定参数 设置 CheckBox 列 选中状态。
// 
// sTableId: 目标表 ID。
// iColumnIndex: CheckBox 列表的列索引。
// bChecked: 是否选中，True/False。
function setAllCheckBoxes(sTableId, iColumnIndex, bChecked) {
    var table = $(sTableId);
    if (table) {
        var cell;
        for (var i = 0; i < table.rows.length; i++) {
            cell = table.rows[i].cells[iColumnIndex];

            if (cell.hasChildNodes()
                && cell.firstChild.nodeType == 1
                && cell.firstChild.tagName.toLowerCase() == "input"
                && cell.firstChild.type.toLowerCase() == "checkbox") {
                cell.firstChild.checked = bChecked;
            }
        }
    }
}

/*
* 选择上传文件后显示文件名。
*/
function showFileName(iptFile) {
    if (iptFile.value != String.empty) {
        document.getNextSiblingElement(document.getNextSiblingElement(iptFile)).innerHTML = iptFile.value.split("\\").pop();
    }
}

/*
* 上传按钮检查。
*/
function alertSelectFile(btnUpload) {
    if (document.getPreviousSiblingElement(btnUpload).value == String.empty) {
        aloe.msgBox.warn("未选择上传文件", "请点击[浏览]按钮选择需上传的文件。");
        return false;
    }
    else
        true;
}

//获取当前对象的上一个ElementNode对象的引用。
function getCalendarInput(obj) {
    return document.getPreviousSiblingElement(obj).firstChild;
}

/*
* 折叠或展开字段集。
*/
function collapseExpandFieldSet(div) {
    if (div == undefined)
        div = this;

    var fst = div.parentNode.parentNode;
    var isExpand = fst.style.height == String.empty;

    if (isExpand)
        div.firstChild.innerHTML = "+";
    else
        div.firstChild.innerHTML = "-";

    div.title = isExpand ? "展开" : "折叠";
    fst.childNodes[1].style.display = fst.childNodes[1].style.display == 'none' ? String.empty : 'none';
    fst.style.height = fst.style.height == String.empty ? '25px' : '';
}
/*
* 初始化 Div 标题。
*/
function initializeDivTitles() {
    var lgds = document.getElementsByTagName("legend");
    var div;
    for (var i = 0; i < lgds.length; i++) {
        if (lgds[i].getElementsByTagName("div").length > 0) {
            div = lgds[i].getElementsByTagName("div")[0];
            if (div.getElementsByTagName("span").length == 0) {

                div.signSpan = div.insertBefore(document.createElement('<span class="spaPlusSign"></span>'), div.firstChild);
                div.signSpan.innerHTML = "-";

                div.title = "折叠";
                div.style.cursor = "hand";
            }
            div.onclick = collapseExpandFieldSet;
        }
    }
}

/*
* 当评审窗口关闭时，执行父窗体搜索点击事件。
*/
function onEvalWinClose() {
    window.onunload = function() {
        if (window.dialogArguments) {
            var parentWin = window.dialogArguments[0];
            parentWin.document.getElementById(window.dialogArguments[1]).click();
        }
    };
}

/***** ***** ***** ***** End: [ProjectName] Customize ***** ***** ***** *****/


// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;
// LN - in prototype v1.6.1;