﻿/*--
标题：常规函数封装
设计：王集鹄
博客：http://blog.csdn.net/zswang
日期：2008年10月19日
--*/

//2009年8月13日 王集鹄 完善 UBB兼容[url]xxx[/url]格式

/// <summary>
/// 公共对象
/// </summary>
var Common = {
	scripts: { // 目前装载的脚本，用于判断依赖关系
		"Common": "2009年1月20日"
	}
	, ie: !!(/(msie)\s*(\d+(\.\d+)?)/i).exec(navigator.userAgent) // ie浏览器
	, ie6: !!(/(msie)\s*(6(\.\d+)?)/i).exec(navigator.userAgent)
};

var soundStates = {};

/// <summary>
/// 查询IE元素
/// </summary>
/// <param name="id">元素id</param>
/// <returns>返回id对应的网页元素</returns>
function $(id) { return document.getElementById(id); }

/// <summary>
/// 获得指定范围的随机数
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
/// <returns>返回指定范围的随机数</returns>
function $random(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); }


/// <summary>
/// 设置Cookie值
/// </summary>
/// <param name="name">Cookie变量名</param>
/// <param name="value">Cookie值</param>
/// <param name="days">保存的天数</param>
function setCookie(name, value, days) {
	document.cookie = name + "=" + escape(value) + (days ? "; expires=" + new Date(new Date().getTime() + 
		days * 24 * 60 * 60 * 1000).toGMTString() : "");
}

/// <summary>获取Cookie值</summary>
/// <param name="name">Cookie变量名</param>
/// <returns>返回获取到的Cookie值</returns>
function getCookie(name) {
	var re = new RegExp("(^|;)\\s*(" + name + ")=([^;]*)(;|$)", "i");
	var res = re.exec(document.cookie);
	return res != null ? unescape(res[3]) : null;
}

/// <summary>获取Url参数值</summary>
/// <param name="url">url</param>
/// <param name="param">参数名</param>
/// <param name="def">默认值</param>
/// <returns>返回Url参数值</returns>
function getUrlParam(url, param, def) {
	var re = new RegExp("(\\?|&)\\s*(" + param + ")\=([^&]*)(&|$)");
	var res = re.exec(decodeURIComponent(url));
	return res != null ? unescape(res[3]) : def;
}

function getUrlRoot(url) {
	var math = /^(http:\/\/.*?\/)/.exec(url);
	if (math) return RegExp.$1;
	return "";
}

/// <summary>
/// 调用脚本
/// </summary>
/// <param name="url">脚本地址</param>
/// <param name="loaded">载入后调用的方法</param>
/// <param name="loaded">异常后调用的方法</param>
/// <param name="charset">脚本字节编码</param>
function callScript(url, loaded, error, charset) {
	var script = document.createElement("script");
	if (typeof charset == "string") script.charset = charset;
	script.onreadystatechange = function() {
		switch (this.readyState) {
			case "complete":
			case "loaded":
				if (typeof loaded == "function") loaded();
				if (script.parentNode) script.parentNode.removeChild(script);
				break;
		}
	}
	script.onload = function() {
		if (typeof loaded == "function") loaded();
		if (script.parentNode) script.parentNode.removeChild(script);
	}
	script.onerror = function() {
		if (typeof error == "function") error();
		if (script.parentNode) script.parentNode.removeChild(script);
	}

	script.type = "text/javascript";
	script.defer = "true";
	script.src = url;
	var parent = document.getElementsByTagName("HEAD")[0] || document.documentElement;
	if (parent && parent.insertBefore) parent.insertBefore(script, parent.firstChild);
}

/// <summary>
/// 执行http请求
/// </summary>
/// <param name="url">链接地址</param>
/// <param name="type">请求类型</param>
/// <param name="data">提交的数据</param>
/// <param name="loaded">载入后调用的方法</param>
/// <param name="error">错误时触发</param>
function requestHttp(url, type, data, loaded, error) {
	if (typeof loaded != "function") return;
	var xmlhttp = typeof XMLHttpRequest == "undefined" ?
		new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
	xmlhttp.onreadystatechange = function() {
		if (xmlhttp.readyState == 4)
			if (xmlhttp.status == 200)
				loaded(xmlhttp);
			else if (parseFloat(xmlhttp.status) > 300 && typeof error == "function")
				error(xmlhttp);
	}
	xmlhttp.open(typeof type == "string" ? type : "GET", url, true);
	if (typeof data == "string") {
		xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
		xmlhttp.setRequestHeader("Content-Length", data.length);
	}
	xmlhttp.send(data);
}

/// <summary>
/// 载入样式表
/// </summary>
/// <param name="url">样式表地址</param>
/// <param name="charset">样式表字符编码</param>
function loadCss(url, charset) {
	var css = document.createElement("link");
	css.type = "text/css";
	if (typeof charset == "string") css.charset = charset;
	css.rel = "Stylesheet";
	css.href = url;
	var parent = document.getElementsByTagName("HEAD")[0] || document.documentElement;
	if (parent && parent.insertBefore) parent.insertBefore(css, parent.firstChild);
}

/// <summary>
/// 设置元素的文本
/// </summary>
/// <param name="element">元素对象</param>
/// <param name="text">文本内容</param>
function setElementText(element, text) {
	if (typeof element == "undefined") return;
	element = typeof element == "string" ? $(element) : element;
	if (typeof element.textContent != "undefined")
		element.textContent = text;
	else (typeof element.innerText != "undefined")
		element.innerText = text;
}

/// <summary>
/// 获得元素的绝对坐标
/// </summary>
/// <param name="element">HTML元素</param>
function absolutePoint(element) {
	var result = { x: element.offsetLeft, y: element.offsetTop };
	element = element.offsetParent;
	while (element) {
		result.x += element.offsetLeft;
		result.y += element.offsetTop;
		element = element.offsetParent;
	}
	return result;
}

/// <summary>
/// 添加事件
/// </summary>
/// <param name="target">载体</param>
/// <param name="type">事件类型</param>
/// <param name="func">事件函数</param>
function addEventHandler(target, type, func) {
	if (target.addEventListener)
		target.addEventListener(type, func, false);
	else if (target.attachEvent)
		target.attachEvent("on" + type, func);
	else target["on" + type] = func;
}

/// <summary>
/// 移除事件
/// </summary>
/// <param name="target">载体</param>
/// <param name="type">事件类型</param>
/// <param name="func">事件函数</param>
function removeEventHandler(target, type, func) {
	if (target.removeEventListener)
		target.removeEventListener(type, func, false);
	else if (target.detachEvent)
		target.detachEvent("on" + type, func);
	else delete target["on" + type];
}

/// <summary>
/// 格式化日期时间
/// </summary>
/// <param name="date">时间</param>
/// <param name="separator">分割字符</param>
/// <returns>返回被格式化后的字符串</returns>
function dateFormat(date, separator){
	date = typeof date == "number" ? new Date(date) : 
		(typeof date == "string" ? new Date(Date.parse(date)) : date);
	separator = typeof separator == "string" ? separator : "$1年$2月$3日 $4时$5分$6秒";
	var str = "" + date.getFullYear() + "-" + (date.getMonth() + 101) + "-" + (date.getDate() + 100) + " " +
		(date.getHours() + 100) + ":" +(date.getMinutes() + 100) + ":" + (date.getSeconds() + 100);
	return str.replace(/^(\d+)-\d*(\d{2})-\d*(\d{2}) \d*(\d{2}):\d*(\d{2}):\d*(\d{2})$/g, separator);
}

/// <summary>获得日期标题</summary>
/// <param name="date">时间</param>
/// <returns>返回日期标题</returns>
function dateCaption(date) {
	date = typeof date == "number" ? new Date(date) : 
		(typeof date == "string" ? new Date(Date.parse(date.replace(/-/g, "/"))) : date);
	var now = new Date();
	var space = now.getTime() - date.getTime();
	var suffix = space > 0 ? "前" : "后";
	space = Math.abs(space);
	if (space < 60 * 1000) return Math.floor(space / 1000) + "秒" + suffix;
	if (space < 60 * 60 * 1000) return Math.floor(space / 60 / 1000) + "分钟" + suffix;
	if (space < 24 * 60 * 60 * 1000) return Math.floor(space / 60 / 60 / 1000) + "小时" + suffix;
	if (space < 7 * 24 * 60 * 60 * 1000) return Math.floor(space / 24 / 60 / 60 / 1000) + "天" + suffix;
	if (space < 30 * 24 * 60 * 60 * 1000) return Math.floor(space / 7 / 24 / 60 / 60 / 1000) + "周" + suffix;
	if (space < 365 * 24 * 60 * 60 * 1000) return Math.floor(space / 30 / 24 / 60 / 60 / 1000) + "月" + suffix;
	return Math.floor(space / 365 / 24 / 60 / 60 / 1000) + "年" + suffix;
}

/// <summary>
/// 格式化浮点数
/// </summary>
/// <param name="number">浮点数</param>
/// <param name="length">总长度</param>
/// <param name="digits">保留小数</param>
/// <returns>返回被格式化后的字符串</returns>
function floatFormat(number, length, digits) {
	number = typeof number != "number" ? parseFloat(number) : (isNaN(number) ? 0 : number);
	var text = number.toFixed(digits);
	while (text.length < length) text = " " + text;
	return text;
}

/// <summary>
/// 格式化颜色
/// </summary>
/// <param name="color">颜色数值</param>
/// <returns>返回格式化后的字符串</returns>
function colorFormat(color) {
	return "#" + /.{6}$/.exec("00000" + color.toString(16));
}

/// <summary>获得HTML元素当前的样式</summary>
/// <param name="element">HTML元素</param>
/// <returns>返回元素样式</returns>
function currentStyle(element) {
	return element.currentStyle || document.defaultView.getComputedStyle(element, null);
}

/// <summary>去掉字符串前后空白字符</summary>
/// <param name="str">字符串</param>
/// <returns>返回处理后的字符串</returns>
function strTrim(str) {
	return str.replace(/^\s+|\s+$/g, "");
}

/// <summary>给字符串前后加上引号</summary>
/// <param name="str">字符串</param>
/// <returns>返回处理后的字符串</returns>
function strQuoted(str) {
	return '"' + ('' + str).replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
}

/// <summary>将json转换成字符串</summary>
/// <param name="json">对象</param>
/// <returns>返回处理后的字符串</returns>
function json2Text(json) {
	if (typeof json == "undefined") return '""';
	var i;
	var result;
	if (json instanceof Array) {
		result = '';
		for (i = 0; i < json.length; i++)
			result += ',' + json2Text(json[i]);
		return "[" + result.substr(1) + ']';
	} else if (typeof json == 'object') {
		result = '';
		for (i in json)
			result += ',' + strQuoted(i) + ':' + json2Text(json[i]);
		return '{' + result.substr(1) + '}';
	} else return strQuoted(json);
}

/// <summary>将表单中的输入元素加入到对象中</summary>
/// <param name="form">表单元素</param>
/// <returns>返回处理后的对象</returns>
function form2Json(form) {
	if (!form) return null;
	var result = {};
	var inputs = form.getElementsByTagName('input');
	for (var i = 0; i < inputs.length; i++) {
		if (inputs[i].name)
			if ((/^text|hidden|password$/i).test(inputs[i].type))
				result[inputs[i].name] = inputs[i].value;
			else if ((/^checkbox$/i).test(inputs[i].type))
				result[inputs[i].name] = inputs[i].checked;
			else if ((/^radio/i).test(inputs[i].type) && inputs[i].checked)
				result[inputs[i].name] = inputs[i].checked;			
	}
	return result;
}

/// <summary>将字符串处理问对象</summary>
/// <param name="str">表单元素</param>
/// <returns>返回处理后的对象</returns>
function str2Object(str) {
	if (!str) return false;
	try {
		return eval('(' + str.replace(/^\s*(<[^>]*>)+\s*|\s*(<[^>]*>)+\s*$/, "") + ')');
	} catch (ex) {
		return false;
	}
}
		
/// <summary>翻译UBB文本</summary>
/// <param name="str">UBB字符串</param>
/// <returns>返回UBB表达的HTML内容</returns>
function ubb2Html(str) {
	str = text2Html(str);
	str = str.replace(/(\[code\])([\s\S]*?)(\[\/code\])/ig, function($0, $1, $2) {
		if (typeof Highlight == "undefined") return "<pre><code>" + $2 + "</code></pre>";
		return "<pre><code>" + Highlight.exportHtml(html2Text($2)).replace(/\[/g, "&#91;").replace(/\[/g, "&#93;") + "</code></pre>";
	});
	while ((/\[(i|u|s|sub|sup|small|big|left|center|right|img|url)\]\[\/\1\]/i).test(str))
		str = str.replace(/\[(i|u|s|sub|sup|small|big|left|center|right|img|url)\]\[\/\1\]/ig, ''); // 去掉无意义的
	str = str.replace(/\[size=(\d{1,2}(\.\d+)?(px|pt|in|cm|mm|pc|em|ex|%)+?)\](.*?)\[\/size\]/ig, '<font style="font-size:$1">$4</font>');
	str = str.replace(/\[b\](.*?)\[\/b\]/ig, '<strong>$1</strong>');
	while ((/\[(i|u|s|sub|sup|small|big)\](.*?)\[\/\1\]/i).test(str))
		str = str.replace(/\[(i|u|s|sub|sup|small|big)\](.*?)\[\/\1\]/ig, '<$1>$2</$1>');
	str = str.replace(/\[(left|center|right)\](.+)\[\/\1]/ig, '<p align="$1">$2</p>');
	str = str.replace(/\[color=\s*(#[a-f0-9]{6})\s*\](.*?)\[\/color\]/ig, '<font style="color:$1">$2</font>');
	str = str.replace(/\[em([0-9]|[1-8][0-9])\]/ig, '<img src="/Images/em/$1.gif" alt="&#91;em$1&#93;" />');
	str = str.replace(/\[ex(\d+)\]/ig, '<img src="/Images/ex/$1.gif" alt="&#91;ex$1&#93;" />');
	str = str.replace(/\[fl(\d+)\]/ig, '<img src="/Images/fl/$1.gif" alt="&#91;fl$1&#93;" />');
	str = str.replace(/\[ml(\d+)\]/ig, '<img src="/Images/ml/$1.gif" alt="&#91;ml$1&#93;" />');
	str = str.replace(/\[(date|time)(\d{4}(\/|-)\d{1,2}(\/|-)\d{1,2}(\s|&nbsp;)+\d{1,2}:\d{1,2}:\d{1,2})]/ig, function($0, $1, $2){
		return "<span title=\"" + $2 + "\">" + dateCaption($2.replace(/&nbsp;/g, " ")) + "</span>";
	});
	str = str.replace(/\[img=\s*((https?:\/)?\/.*?)\](.*?)\s*\[\/img\]/ig, '<img src="$1" title="$3" alt="$3"/>');
	str = str.replace(/\[img\]\s*((https?:\/)?\/.*?)\[\/img\]/ig, '<img src="$1" alt="img"/>');
	str = str.replace(/\[url=\s*((https?:\/)?\/.*?)\](.*?)\s*\[\/url\]/ig, '<a href="$1" target="_blank">$3</a>');
	str = str.replace(/\[url\]\s*((https?:\/)?\/.*?)\[\/url\]/ig, '<a href="$1" alt="url" target="_blank">$1</a>');
	str = str.replace(/\[(br|hr)\]/ig, '<$1/>');
	
	str = str.replace(/\[(rr1)\]/ig, '<img src="/Images/fl/$1.gif" alt="人肉玩家"/>');
	str = str.replace(/\[f\](.*?)\[\/f\]/ig, '<small><strong>$1</strong></small>');
	str = str.replace(/\[ml(\d+)=(\d+)\]/ig, '<img src="/Images/ml/$1.gif" alt="&#91;ml$1&#93;" /><sup><small>x$2</small></sup>');
	
	do {
		var length = str.length;
		str = str.replace(/\[quote=([\s\S]*?)\]([\s\S]*?)\[\/quote\]/ig, '<fieldset><legend>$1</legend>$2</fieldset>');
	}  while (str.length != length)
	return str;
}

/// <summary>压缩UBB文本</summary>
/// <param name="text">UBB文本</param>
/// <returns>返回压缩后的UBB文本</returns>
function compressUbb(text) {
	do {
		var l = text.length;
		text = text.replace(/(\[color=#[a-f\d]+\])(.*?)\[\/color\]\1(.*?)(\[\/color\])/ig, "$1$2$3$4");
	} while(l != text.length)
	return text;
}

/// <summary>安全显示文本</summary>
/// <param name="str">文本</param>
/// <returns>返回可显示的HTML内容</returns>
function text2Html(str) {
	return str.replace(/[&"<> \t\n]/g, function() {
		return ({
			"&": "&amp;"
			, "\"": "&quot;"
			, "<": "&lt;"
			, ">": "&gt;"
			, " ": "&nbsp;"
			, "\n": "<br/>"
			, "\t": new Array(5).join("&nbsp;")
		})[arguments[0]];
	});
}

/// <summary>还原HTML文本</summary>
/// <param name="html">HTML内容</param>
/// <returns>返回HTML原文</returns>
function html2Text(html) {
	html = html.replace(/&amp;/g, "&");
	html = html.replace(/&quot;/g, "\"");
	html = html.replace(/&lt;/g, "<");
	html = html.replace(/&gt;/g, ">");
	html = html.replace(/&nbsp;/g, " ");
	html = html.replace(/<br\s*\/>/g, "\n");
	return html;
}

/// <summary>翻译talk文本</summary>
/// <param name="str">talk字符串</param>
/// <returns>返回talk表达的HTML内容</returns>
function talk2Html(str) {
	str = text2Html(str);
	str = str.replace(/\[em([0-9]|[1-8][0-9])\]/ig, '<img src="/Images/em/$1.gif" alt="&#91;em$1&#93;" />');
	str = str.replace(/\[ex(\d+)\]/ig, '<img src="/Images/ex/$1.gif" alt="&#91;ex$1&#93;" />');
	str = str.replace(/\[fl(\d+)\]/ig, '<img src="/Images/fl/$1.gif" alt="&#91;fl$1&#93;" />');
	str = str.replace(/\[ml(\d+)\]/ig, '<img src="/Images/ml/$1.gif" alt="&#91;ml$1&#93;" />');
	return str;
}

/// <summary>翻译format文本</summary>
/// <param name="content">内容</param>
/// <param name="format">格式</param>
/// <returns>返回format表达的HTML内容</returns>
function format2Html(content, format) {
	switch (format) {
		case 'talk':
			return talk2Html(content);
		case 'ubb':
			return ubb2Html(content);
		case 'html':
			return content;
		default:
			return text2Html(content);
			break;
	}
}

/// <summary>格式化json数据</summary>
/// <param name="template">模板/param>
/// <param name="json">内容</param>
function jsonFormat(template, json) {
	if (!json) return template;
	return template.replace(/\$\{(.+?)\}/g, function() {
		return json[arguments[1]];
	});
}  

/// <summary>格式化字符串</summary>
/// <param name="template">模板/param>
/// <param name="...">扩展参数</param>
function strFormat(template/*, ...*/) {
	var arg = arguments;
	return template.replace(/\{(\d+)\}/g, function() {
		return arg[+arguments[1] + 1];
	});
}

/// <summary>设置编辑器选择的文本</summary>
/// <param name="editor">编辑器/param>
/// <param name="value">内容</param>
/// <param name="range">记忆的范围</param>
function setSelectText(editor, value, range) {
	if (!editor || !value) return;
	editor.focus();
	if (range && range.parentElement() == editor) {
		range.text = value;
		range.select();
		range = null;
	} else if (document.selection) {
		document.selection.createRange().text = value;
	} else if (typeof editor.selectionStart != "undefined") {
		var str = editor.value;
		var start = editor.selectionStart;
		var scroll = editor.scrollTop;
		editor.value = str.substr(0, start) + value +
			str.substring(editor.selectionEnd, str.length);
		editor.selectionStart = start + value.length;
		editor.selectionEnd = start + value.length;
		editor.scrollTop = scroll;
	}
}

/// <summary>获得编辑器选择的文本</summary>
/// <param name="editor">编辑器</param>
/// <param name="range">记忆的范围</param>
function getSelectText(editor, range) {
	editor.focus();
	if (range && range.parentElement() == editor)
		return range.text;
	else if (document.selection)
		return document.selection.createRange().text;
	else if (typeof editor.selectionStart != "undefined")
		return editor.value.substring(
			editor.selectionStart, editor.selectionEnd);
}

/// <summary>格式化时间</summary>
/// <param name="second">秒</param>
function formatTime(second) {
	return ("0" + Math.floor(second / 60)).replace(/^.*(\d{2})$/, "$1") + ":" +
		("0" + second % 60).replace(/^.*(\d{2})$/, "$1");
}

function hsl2color(hsl) {
	if (hsl.h > 360 || hsl.h < 0 || hsl.s > 100 || hsl.s < 0 || hsl.l > 100 || hsl.l < 0)
		return "#000000";
	var rgb = {r: 0, g: 0, b: 0};
	if (hsl.h <= 60) {
		rgb.r = 255;
		rgb.g = Math.floor(255 / 60 * hsl.h);
	} else if (hsl.h <= 120) {
		rgb.r = Math.floor(255 - (255 / 60) * (hsl.h - 60));
		rgb.g = 255;
	} else if (hsl.h <= 180) {
		rgb.g = 255;
		rgb.b = Math.floor((255 / 60) * (hsl.h - 120));
	} else if (hsl.h <= 240) {
		rgb.g = Math.floor(255 - (255 / 60) * (hsl.h - 180));
		rgb.b = 255;
	} else if (hsl.h <= 300) {
		rgb.r = Math.floor((255 / 60) * (hsl.h - 240));
		rgb.b = 255;
	} else if (hsl.h <= 360) {
		rgb.r = 255;
		rgb.b = Math.floor(255 - (255 / 60) * (hsl.h - 300));
	}
	var sat = Math.abs((hsl.s - 100) / 100);
	rgb.r = Math.floor(rgb.r - (rgb.r - 128) * sat);
	rgb.g = Math.floor(rgb.g - (rgb.g - 128) * sat);
	rgb.b = Math.floor(rgb.b - (rgb.b - 128) * sat);
	var lum = (hsl.l - 50) / 50;
	if (lum > 0) {
		rgb.r = Math.floor(rgb.r + (255 - rgb.r) * lum);
		rgb.g = Math.floor(rgb.g + (255 - rgb.g) * lum);
		rgb.b = Math.floor(rgb.b + (255 - rgb.b) * lum);
	} else if (lum < 0) {
		rgb.r = Math.floor(rgb.r + rgb.r * lum);
		rgb.g = Math.floor(rgb.g + rgb.g * lum);
		rgb.b = Math.floor(rgb.b + rgb.b * lum);
	}
	return "#" + ("00000" + (rgb.r * 256 * 256 + rgb.g * 256 + rgb.b).toString(16)).replace(/^.*(.{6}$)/g, "$1");
}

/// <summary>获得数值的符号</summary>
/// <param name="x">内容</param>
/// <returns>返回x的符号</returns>
function sign(x) {
	return x == 0 ? 0 : (x > 0 ? +1 : -1);
}

/// <summary>获得下一个焦点元素</summary>
/// <param name="element">当前元素，如果为空则返回第一个焦点元素</param>
/// <returns>返回下一个焦点元素</returns>
function nextFocus(element) {
	var elements = document.getElementsByTagName("*");
	var start = !element;
	var group = "";
	for (var i = 0; i < elements.length; i++) {
		if (start && /^(input|textarea|button|select)$/i.test(elements[i].tagName) && !element.disabled &&
			(!group || group != elements[i].name) && !(/^(hidden)$/i.test(elements[i].type)) &&
			currentStyle(element).display != "none" && currentStyle(element).visibility != "hidden")
			return elements[i];
		if (elements[i] == element) {
			start = true;
			group = element.name;
		}
	}
}

/// <summary>播放声音</summary>
/// <param name="name">声音名称</param>
function playSound(name) {
	if (window.soundState || !window.soundManager) return;
	if (window.soundStates[name]) return;
	window.soundManager.play(name);
}