////////////////////////////////////////////////////////
// 公司：上海摩方信息科技有限公司[Mopha]
// 模块：活动Web表格
// 文件：ActiveTable.js
// 类型：通用模块,客户端执行
// 版本：1.6
// 描述：能通过鼠标改变表格的列宽，交换列位置
// 参考：CSDN 论坛上的例子，dragdrop.htc
// 作者：郁慧
// 日期：2003年7月29日
// 邮件：YuHui-dh@163.com
// 修改记录：
// 2003年7月29日	InitCells(.) 	添加 ：// 调整宽度 var oHeadRow = argTable.rows[0];
// 2003年7月30日 修正了对TFOOT的兼容处理,最后一列能艰难地移动。
// 2003年8月01日 修该了跟着鼠标移动的方框的样式，表格之间不再有串扰。
//               修正了首行过窄时会分行的问题。
//               支持百分比宽度自动转换。
// 2004年6月28日 修正了内容过宽时滚动条的偏移。
//               （修改了FindPos函数，增加了 document.body.scroll* 的修正）
////////////////////////////////////////////////////////


// 设置单元格文字样式的标签内容，可根据需要调整
var sDivTag = '<DIV style="OVERFLOW: hidden; HEIGHT: 18px; WORD-BREAK: break-all; LINE-HEIGHT: 18px;">'
// 其它全局变量
var onSizeDrag = 0;		// 列宽度拖放状态：0-无 1-拖放
var onSwapDrag = 0;		// 列交换拖放状态：0-无 1-开始拖放
var gblDragCell = null;	// 拖放的对象(必须为 HEAD 行的单元格)
var gblDragTable = null;// 被拖放单元格所在的表格对象(必须与上面保持一致)
var gblFlyItem = null;	// 列交换拖放时跟着鼠标移动的方框

//////////////////////////////////////////////////////////
// 主函数：调用了此函数就可以使表格“动”起来。
// 参  数：表格对象
// 调用格式：SetTableActive(表格对象)
/* 调用举例：

<HEAD> 部分
<script src="ActiveTable.js" language="javascript"></script>
</HEAD>

在 BODY 中，表格声明后
<script language="javascript">
	SetTableActive(document.all("tabResizeTest"))
</script>

*/
// 注意事项：
// 1. 表格各列的初始宽度由 <HEAD> </HEAD>行的相应单元格决定， 
//    应在设计时对 HEAD 行的单元格的宽度进行设置。
// 2. 其它行的单元格不设宽度
// 3. <TROOT>行不被处理(不管在那一行)。
// 3. 表格列的百分比宽度会被自动转换，表格总宽自动去除。
/////////////////////////////////////////////////////////////
function SetTableActive(argTable)
{
	with(argTable)
	{
		attachEvent('onmousedown', OnColDragStart)
		attachEvent('onmousemove', OnColDragging)
		attachEvent('onmouseup', OnColDragEnd)
	}
	InitCells(argTable);
}

// 初始化表格中的单元格，只执行一次
// 即为单元格中的文本套上可以设置样式的 <div> 标签
// 其宽度由 HEAD 行的相应单元格决定
function InitCells(argTable)
{
	// 注：表格的第0行为 HEAD，DIV 标签从第1行开始插入
	var r = 0, c = 0;
	// 设置单元格的 DIV 属性
	for(r = 1; r < argTable.rows.length; r++)
	{
		var oTabRow = argTable.rows[r];
		if(IsOnTableFoot(oTabRow))	// 如果是表格底行，则忽略
			continue;
		for(c = 0; c < oTabRow.cells.length; c++)
		{
			var oTabCell = oTabRow.cells[c];
			oTabCell.innerHTML = sDivTag + oTabCell.innerHTML + '</DIV>';
		}
	}
	// 根据<HEAD>行的单元格调整宽度
	var oHeadRow = argTable.rows[0];
	for(c = 1; c < oHeadRow.cells.length; c++)
	{
		oHeadCell = oHeadRow.cells[c];
		if(oHeadCell.width.indexOf("%"))	// 转换百分比宽度
			oHeadCell.width = oHeadCell.clientWidth;
		//Debug("# DEBUG : Col=" + c + ", oHeadCell.width=" + oHeadCell.width + ", " + oHeadCell.offsetWidth + ", " + oHeadCell.clientWidth);
		ResizeFollowingCells(argTable, oHeadCell);
	}
	// 去掉表格的总宽度
	//Debug("# DEBUG : (Before Process)argTable.width = " + argTable.width);
	argTable.width = "";
	// 为<HEAD>行的单元格加上DIV 标签并设置事件函数
	for(c = 0; c < oHeadRow.cells.length; c++)
	{
		var oHeadCell = oHeadRow.cells[c];
		oHeadCell.innerHTML = sDivTag + oHeadCell.innerHTML + '</DIV>';
		var oDivObject = oHeadCell.children[0];
		if(oDivObject.tagName == "DIV")
		{
			oDivObject.onmousedown = OnColDragStart;
			oDivObject.onmousemove = OnColDragging;
			oDivObject.onmouseup = OnColDragEnd;
		}
	}
}

// 开始拖放（调整列宽度或列位置）
function OnColDragStart()
{
	var srcObj = event.srcElement;			// 事件源对象,可能是单元格中的 DIV 对象
	var srcCell = GetParentCell(srcObj);	// 获取单元格对象
	if(srcCell == null)
	{
		return;
	}
	var srcTable = GetTableParent(srcCell);	// 获取表格对象
	// 保证是 HEAD 行(第零行)
	if(srcCell.parentElement.rowIndex != 0) return;
	
	// 单元格边界的左侧按下鼠标（调整列宽的鼠标位置）
	if(srcObj.offsetWidth - event.offsetX <=3/* && srcCell.cellIndex <= srcCell.parentElement.cells.length*/)
	{
		gblDragTable = srcTable;
		gblDragCell = srcTable.rows[srcCell.parentElement.rowIndex].cells[srcCell.cellIndex];
		onSizeDrag = 1;
	}
	// 单元格边界的右侧按下鼠标（调整列宽的鼠标位置）
	if(event.offsetX <= 3 && srcCell.cellIndex != 0)
	{
		gblDragTable = srcTable;
		gblDragCell = srcTable.rows[srcCell.parentElement.rowIndex].cells[srcCell.cellIndex - 1];
		onSizeDrag = 1;
	}
	// 在 HEAD 行单元格靠中间的位置按下鼠标（可能要交换列位置）
	if(onSizeDrag != 1 && event.offsetX >= 5 && event.offsetX <= srcObj.offsetWidth - 5)
	{
		gblDragCell = srcCell;	// care, need test ！！！
		gblDragTable = GetTableParent(gblDragCell);
		onSwapDrag = 1;
		// 创建跟着鼠标移动的元素,外观上与被拖动的单元格保持一致,以下设置了一些必要的属性。
		if(gblFlyItem)
		{
			gblFlyItem.removeNode(true);
			gblFlyItem = null;
		}

		gblFlyItem = document.createElement("DIV");
		gblFlyItem.innerHTML		= srcCell.innerHTML;
		gblFlyItem.style.height		= srcCell.currentStyle.height;
		gblFlyItem.style.width 		= srcCell.currentStyle.width;
		gblFlyItem.style.background	= srcCell.currentStyle.backgroundColor;
		gblFlyItem.style.fontColor	= srcCell.currentStyle.fontColor;
		gblFlyItem.selectIndex		= srcCell.selectIndex;
		gblFlyItem.cellIndex		= srcCell.cellIndex;
 		gblFlyItem.style.borderStyle= "dotted";
 		gblFlyItem.style.borderWidth= "1";
		// 这里暂时不显示，初始位置不重要
		gblFlyItem.style.display	= "none";
		gblFlyItem.style.position 	= "absolute";
		gblFlyItem.style.x = 0;
		gblFlyItem.style.y = 0;
		// 将该元素插入为表格中的子元素，便于接收事件	
		srcCell.insertBefore(gblFlyItem);
	}
}

// 正在拖放
function OnColDragging()
{
	var srcObj = event.srcElement;		// 事件源对象
	var srcCell = GetParentCell(srcObj);	// 获取单元格对象
	var srcTable = GetTableParent(srcObj);	// 获取表格对象

	if(onSwapDrag == 1 && gblFlyItem)
	{
		// 拖动方格效果
		var midWObj = gblFlyItem.style.posWidth / 2;
		var midHObj = 12;

		var intTop = event.clientY + document.body.scrollTop;
 		var intLeft = event.clientX + document.body.scrollLeft;

		var cx=0, cy=0;
		var curObj = gblFlyItem.offsetParent;
		while (curObj.offsetParent != null) {
			cx += curObj.offsetLeft;
			cy += curObj.offsetTop;
			curObj = curObj.offsetParent;
		}
		gblFlyItem.style.pixelTop  = intTop  - cy - midHObj;
		gblFlyItem.style.pixelLeft = intLeft - cx - midWObj;

		if(gblFlyItem.style.display == "none") gblFlyItem.style.display = "";
		// 设置鼠标
		SetCursor(srcCell, "hand");
		event.cancelBubble = true;
		event.returnValue = false;		
	}
	else if(onSizeDrag == 1)
	{
		// 根据鼠标位置更改单元格宽度
		if(!srcCell)
			return;
		var intPosX = (new FindPos(gblDragCell)).intX
		gblDragCell.style.pixelWidth = event.x - intPosX;
		// gblDragCell 肯定为 HEAD 行的单元格，
		// 接下来修改同一列其它行的 DIV 标签属性
		ResizeFollowingCells(gblDragTable, gblDragCell);
	}else{
		// 显示鼠标指针样式,条件次序可能要调整
		if(srcCell && srcCell.tagName == "TD" && srcCell.parentElement.rowIndex == 0 && (Math.abs(event.offsetX) <= 3 || Math.abs(srcCell.offsetWidth - event.offsetX)<=3) && srcCell.cellIndex != 0)
		{
			SetCursor(srcObj, "move");
		}
		else if(srcCell && srcCell.tagName == "TD" && srcCell.parentElement.rowIndex == 0 && event.offsetX >= 5 && event.offsetX <= srcCell.offsetWidth - 5)
		{
			SetCursor(srcObj, "hand");
		}
		else
		{
			SetCursor(srcObj, "auto");
		}
	}
}

// 拖放结束
function OnColDragEnd()
{
	// 事件源对象
	onSizeDrag=0;
	SetCursor(null, "auto");

	//交换列
	if(onSwapDrag != 1 && gblFlyItem == null) return;
	onSwapDrag = 0;

	var iSelected = gblFlyItem.selectIndex;
	gblFlyItem.removeNode(true);
	gblFlyItem = null;

	var nDstIndex = FindDragDest(gblDragTable, event);
	var nSrcIndex = gblDragCell.cellIndex;
	MoveColumn(gblDragTable, nSrcIndex, nDstIndex);

	// Reset our variables
	iSelected = 0;
}

// 这里返回 obj 的坐标位置(相对于整个文档)
// 注：直接引用CSDN 的帖子，工作正常
function FindPos(obj)
{
	var x = obj.offsetLeft
	var y = obj.offsetTop
	while(obj = obj.offsetParent)
	{
		x += obj.offsetLeft;
		y += obj.offsetTop;
	}
	this.intX = x;
	this.intY = y
	// 版本 1.6 更改的地方
	// 这里确信要考虑滚动条的滚动位置
	this.intX = this.intX - document.body.scrollLeft;
	this.intY = this.intY - document.body.scrollTop;
	//alert(document.body.scrollLeft);
	return this;
}

// 根据 argHeadCell 的宽度修改同一列其它行的 DIV 标签属性
// 注：如果 argHeadCell.style.pixelWidth 不为零，则下面的宽度以
//     argHeadCell.style.pixelWidth 为准，否则以 argHeadCell.width 为准.
function ResizeFollowingCells(argTabObejct, argHeadCell)
{
	if(argTabObejct == null || argTabObejct.tagName != "TABLE")
		return;
	var nNewWidth = 0;
	
	if(argHeadCell.style.pixelWidth != 0)
		nNewWidth = argHeadCell.style.pixelWidth;
	else
		nNewWidth = argHeadCell.width;
	
	var r = 0, c = argHeadCell.cellIndex;

	for(r = 0; r < argTabObejct.rows.length; r++)
	{
		var oTabRow = argTabObejct.rows[r];
		if(IsOnTableFoot(oTabRow))						// 处理TFOOT
			continue;
		var oTabCell = argTabObejct.rows[r].cells[c];
		if(!oTabCell || oTabCell.children.length == 0)	// 容错
			continue;
		// 假设"DIV"为 oTabCell 的第一个子元素(InitCells函数可以保证)
		var oDiv = oTabCell.children[0];
		if(oDiv.tagName == "DIV")						// 容错
		{
			oDiv.style.pixelWidth = nNewWidth;
		}
	}
}

// 返回单元格的表格对象
// 参数：单元格对象
function GetTableParent(argObject)
{
	if(!argObject)
		throw("# ERROR @ GetTableParent() : 参数 argObject 不是有效对象！");
	
	if(argObject.tagName != 'TD') return null;
	// 为了代码键壮性的考虑，从srcObj 开始搜索
	// parentElement,可能鼠标正好点在表格(行)对象上。
	var tblParent = argObject;
	while(tblParent.tagName != 'TABLE')
		tblParent=tblParent.parentElement;
	
	return tblParent;
}

// 返回对象所在的单元格
// 如果此对象不在单元格内，则返回 null
function GetParentCell(argObject)
{
	var oParentCell = argObject;
	while(oParentCell && oParentCell.tagName != 'TD')
		oParentCell = oParentCell.parentElement;
	return oParentCell;
}

// 在设置鼠标指针样式
function SetCursor(argObject, sCursor)
{
	try{
		if(argObject == null)
			document.body.style.cursor=sCursor;
		else
			argObject.document.body.style.cursor=sCursor;
	}
	catch(e)
	{
		alert("ERROR @ SetCursor : 在设置鼠标指针样式时发生一个错误！");
	}
}

// 找出被交换单元格放下处的HEAD行的列位置
// 若返回-1则无效
function FindDragDest(argTable, E)
{
	if(argTable == null)
		return -1;
	var oHeadRow  = argTable.rows[0];
	var nHeadLeft = FindPos(oHeadRow).intX
	var nHeadTop  = FindPos(oHeadRow).intY;
	var nHeadBottom = nHeadTop + oHeadRow.clientHeight;
	var nMousePosX = E.clientX + document.body.scrollLeft;
	var nMousePosY = E.clientY + document.body.scrollTop;
	// 是否在 HEAD 行上
	if(!(nHeadTop <= nMousePosY && nMousePosY <= nHeadBottom))
		return -1;
	// 在哪一个单元格上
	var c = 0;
	for(c = 0; c < oHeadRow.cells.length; c++)
	{
		var oHeadCell = oHeadRow.cells[c];
		var nCellLeft = nHeadLeft + oHeadCell.offsetLeft;
		var nCellRight = nCellLeft + oHeadCell.clientWidth;
		if(nCellLeft <= nMousePosX && nMousePosX <= nCellRight)
		{
			if(IsOnTableFoot(oHeadCell))
				return -1;
			else
				return oHeadCell.cellIndex;
		}
	}
	return -1;
}

// 移动表格列
function MoveColumn(argTable, argSrcIndex, argDstIndex)
{
	if(!argTable || argTable.tagName != "TABLE")
	{
		//alert("ERROR @ MoveColumn : argTable 不是表格！");
		return;
	}
	var nColLen = argTable.rows[0].cells.length;
	if(argSrcIndex < 0 || argSrcIndex >= nColLen)
	{
		//alert("ERROR @ MoveColumn : argSrcIndex 超出范围！");
		return;
	}
	if(argDstIndex < 0 || argDstIndex >= nColLen)
	{
		//alert("ERROR @ MoveColumn : argDestIndex 超出范围！");
		return;
	}
	if(argSrcIndex == argDstIndex)
		return;
	// 开始已动列（包括首行）
	if(argDstIndex > argSrcIndex)
		argDstIndex++;
	if(argDstIndex >= argTable.rows[0].cells.length)
		argDstIndex = -1;	// 插在最后
	for(var r = 0; r < argTable.rows.length; r++)
	{
		var oTableRow = argTable.rows[r];
		// 碰到 TFOOT 的 child 时不处理
		
		if(IsOnTableFoot(oTableRow))
			continue;
		try{
			var oOldCell = oTableRow.cells[argSrcIndex];
			var oNewCell = oTableRow.insertCell(argDstIndex);
			// 复制属性和innerHTML
			oNewCell.mergeAttributes(oOldCell, false);
			oNewCell.innerHTML = oOldCell.innerHTML;
			// 删除
			oTableRow.deleteCell(oOldCell.cellIndex);
		}
		catch(E)
		{
			//Debug("ERROR @ MoveColumn ::");
		}
	
	}
}

// 返回是否是<TFOOT>的单元格
function IsOnTableFoot(argObject)
{
	var oObject = argObject;
	while(oObject && oObject.tagName != "TFOOT")
	{
		oObject = oObject.parentElement;
	}
	if(oObject && oObject.tagName == "TFOOT")
		return true;
	else
		return false;	
}

//*
// 调试
function Debug(strDebug)
{
		txtareaDebug.value += "\r\n" + strDebug;
}//*/