<!-- MxxCalendar.htm -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>梅雪香日期时间控件</title>
<style type="text/css">
.mxxCalendar{ behavior: url(MxxCalendar.htc);}
td{font-size:12px}
</style>
</head>
<body>
<table width="800" border="1" cellspacing="0" cellpadding="8" align="center">
<tr>
<td colspan="2" align="center"><h2>梅雪香日期时间控件</h2></td>
</tr>
<tr>
<td width="20%"><div align="right">控件名称:</div></td>
<td width="80%">梅雪香日期时间控件</td>
</tr>
<tr>
<td><div align="right">相关技术:</div></td>
<td>htc,popup</td>
</tr>
<tr>
<td><div align="right">版本:</div></td>
<td style="color:red">V1.01 修正了当页面有滚动条或者页面在frame中不能正常定位的问题</td>
</tr>
<tr>
<td><div align="right">功能说明:</div></td>
<td>选择日期和时间,支持动态显示,支持快捷键操作.</td>
</tr>
<tr>
<td><div align="right">修改须知:</div></td>
<td>该控件没有详细的帮助文档,需要自己摸索,参看不详尽的注释.</td>
</tr>
<tr>
<td><div align="right">调用方法:</div></td>
<td>参见htc文件头部说明,需要显示时间在控件源对象上添加代码: showtime="true"</td>
</tr>
<tr>
<td><div align="right">问题反馈:</div></td>
<td>如发现bug或者有改进意见请mail给我:wy_hd@163.com,想骂我mail同上</td>
</tr>
<tr>
<td><div align="right">示例:</div></td>
<td>
<input name="text" type="text" class="mxxCalendar" showtime="true" id="txtMxxCalendar" value="" size="20">
<input type="button" value="※" οnclick="document.getElementById('txtMxxCalendar').focus();">
</td>
</tr>
</table>
</body>
</html>
<!--
MxxCalendar.htc
作者 : 梅雪香(meixx)
时间 : 2005-11-11
描述 : mxxCalendar(htc) v1.0
调用方法:在<head></head>中添加
<style type="text/css">
.mxxCalendar{ behavior: url(MxxCalendar.htc);}
</style>
为需要菜单的对象添加 class="mxxCalendar"
e.g : <input type="text" id="txtMxxCalendar" size="15" class="mxxCalendar">
-->
<!--
接口定义
-->
<public:component>
<public:property name="description" value="mxxCalendar" />
<public:property name="version" value="1.0.0.0" />
<public:attach event="oncontentready" onevent="init()" />
<public:attach event="onfocus" onevent="showMxxCalendar()" />
<public:attach event="onclick" onevent="showMxxCalendar()" />
</public:component>
<!--
组件实现
-->
<script language="javascript">
var oPopup = null; //popup对象,作为载体
var step = 1 ; //动态显示时的记步器
function mxxCalendar(){
this.showTime = eval(element.showtime); //是否显示时间选择项,默认为不显示
this.style = "yy-mm-dd"; //显示时间的样式
this.year = 0; //当前年
this.month = 0; //当前月
this.day = 0; //当前月
this.left = 0; //控件位置x坐标
this.top = 0; //控件位置y坐标
this.width = 150; //控件宽度
this.height = 160; //控件高度
this.curClassName=""; //记录onmouseover时,日期td的className
this.minYear = 1970; //年区间最小值
this.maxYear = 2030; //年区间最大值
this.isDynamicShow = false; //是否动态显示控件
this.dynamicShow = "v"; //动态显示方向 h:水平 v:竖直
this.speed = 2; //动态显示时的速度
}
var mc = new mxxCalendar();
function init(){
element.readOnly = true;
element.style.cursor = "default";
oPopup= window.createPopup();
var oPopDoc = oPopup.document;
var oPopBody = oPopDoc.body;
oPopDoc.oncontextmenu = function (){ return false; };
oPopBody.onselectstart = function (){ return false; };
var strHTML=""
strHTML+='<table id="tbMxxCalendar" cellpadding="0">'
+ '<tr>'
+ '<td><input type="button" HIDEFOCUS="true" οnfοcus="this.blur()" value="<<" title="向前一年(Up or W)" class="button"></td>'
+ '<td><input type="button" HIDEFOCUS="true" οnfοcus="this.blur()" value="<" title="向前一月(Left or A)" class="button"></td>'
+ '<td colspan="2"></td><td colspan="2"></td>'
+ '<td><input type="button" HIDEFOCUS="true" οnfοcus="this.blur()" value=">" title="向后一月(Right or D)" class="button"></td>'
+ '<td><input type="button" HIDEFOCUS="true" οnfοcus="this.blur()" value=">>" title="向后一年(Down or S)" class="button"></td>'
+ '</tr><tr>';
for(i=0;i<8;i++)
strHTML += '<td width="10%">'+'周日一二三四五六'.charAt(i)+'</td>';
strHTML+='</tr>';
for(var i=0;i<5;i++){
strHTML+="<tr>";
for(var j=0;j<8;j++)
strHTML+="<td> </td>";
strHTML+="</tr>";
}
strHTML+='<tr><td> </td><td> </td><td> </td><td> </td>';
if(mc.showTime){
for(var i=0;i<3;i++)
strHTML += '<td title="'+"时分秒".charAt(i)+'" class="tdTime"></td>';
}
else strHTML += '<td> </td><td> </td><td> </td>';
strHTML += '<td><input type="button" hidefocus="true" οnfοcus="this.blur()" value="清" title="清楚文本框内容(Del)"/ class="button"></td>'
+ '</table>';
oPopBody.innerHTML=strHTML;
SetMxxCalendarStyle();
attachEventForTb();
}
function SetMxxCalendarStyle(){
var oPopDoc = oPopup.document;
var oStyleSheet=oPopDoc.createStyleSheet();
with(oStyleSheet){
addRule("td", "vertical-align:middle; text-align: center; border:1px solid; border-color: #D4D0C8 #FFFFFF #FFFFFF #D4D0C8");
addRule("#tbMxxCalendar", "border:solid 1px #6BBFD9; font-size:12px; width:100%; height:100%; cursor:default");
addRule(".button", "width:100%; height:100%;border: 0px solid #D4D0C8; padding-top: 1px; height: 18;color:#000080; background-color:#FFFFF1");
addRule(".firstrow", "color:#000080; background-color:#FFFFF1");
addRule(".secondrow", "color:blue; background-color:#FFFFF1");
addRule(".curMonth", "color:#000080; background-color:#DEEAF6");
addRule(".notCurMonth", "color:#DCDCDC; background-color:#DEEAF6");
addRule(".curDay", "color:red; background-color:#DEEAF6");
addRule(".tdTime", "color:#FF00FF; background-color:#FFFFF1");
addRule(".tdOver", "color:#FFFFF1; background-color:#6BBFD9");
addRule(".tdWeek", "color:#3399FF; background-color:#FFFFF1");
}
var tbRows = oPopup.document.getElementById("tbMxxCalendar").rows;
tbRows[0].className = "firstrow";
tbRows[1].className = "secondrow";
for(var i=2;i<8;i++){
tbRows[i].cells[0].className = "tdWeek";
}
}
//为表格设定事件
function attachEventForTb(){
var pDoc = oPopup.document;
var tbRows = pDoc.getElementById("tbMxxCalendar").rows;
var head= pDoc.getElementsByTagName("head").item(0);
with(tbRows[0]){
cells[0].childNodes[0].attachEvent("onclick",function(){chgDate("y",-1);});
cells[1].childNodes[0].attachEvent("onclick",function(){chgDate("m",-1);});
cells[4].childNodes[0].attachEvent("onclick",function(){chgDate("m",1);});
cells[5].childNodes[0].attachEvent("onclick",function(){chgDate("y",1);});
cells[2].attachEvent("onclick",function(){selectVal(tbRows[0].cells[2],0);});
cells[3].attachEvent("onclick",function(){selectVal(tbRows[0].cells[3],12);});
}
var script = pDoc.createElement('SCRIPT');
script.language = "javascript";
var strScript = '';
strScript += 'document.onkeydown = function(){'
+ ' var code = window.event.keyCode;'
+ ' var firstRow = document.getElementById("tbMxxCalendar").rows[0];'
+ ' if(event.ctrlKey){'
+ ' var td=null;'
+ ' switch(code){'
+ ' case 37: td = firstRow.cells[1].childNodes[0];td.click();td.click();td.click(); break;'
+ ' case 38: td = firstRow.cells[0].childNodes[0];td.click();td.click();td.click();td.click();td.click(); break;'
+ ' case 39: td = firstRow.cells[4].childNodes[0];td.click();td.click();td.click(); break;'
+ ' case 40: td = firstRow.cells[5].childNodes[0];td.click();td.click();td.click();td.click();td.click(); break;'
+ ' default: return;'
+ ' }'
+ ' }'
+ ' else{'
+ ' switch(code){'
+ ' case 32: case 13: var td = document.getElementById("curDay"); if(td) td.click(); break;'
+ ' case 65: case 37: firstRow.cells[1].childNodes[0].click(); break;'
+ ' case 87: case 38: firstRow.cells[0].childNodes[0].click(); break;'
+ ' case 68: case 39: firstRow.cells[4].childNodes[0].click(); break;'
+ ' case 83: case 40: firstRow.cells[5].childNodes[0].click(); break;'
+ ' case 46: document.getElementById("tbMxxCalendar").rows[7].cells[7].childNodes[0].click(); break;'
+ ' default: return;'
+ ' }'
+ ' }'
+ '}';
script.text = strScript;
head.appendChild(script);
for(var i=2;i<8;i++)
for(var j=1,k=(i==7?(mc.showTime?4:7):8);j<k;j++)
addEvent(tbRows[i].cells[j]);
with(tbRows[7]){
if(mc.showTime){
cells[4].attachEvent("onclick",function(){selectVal(cells[4],23);});
cells[5].attachEvent("onclick",function(){selectVal(cells[5],59);});
cells[6].attachEvent("onclick",function(){selectVal(cells[6],59);});
}
cells[7].childNodes[0].attachEvent("onclick",function(){element.value=""; oPopup.hide();});
}
}
//显示日期控件
function showMxxCalendar(){
var parObj = element;
mc.top = 0;
mc.left = 0;
while(parObj){
mc.left += parObj.offsetLeft;
mc.top += parObj.offsetTop;
if (!parObj.offsetParent)
{
mc.top -= parObj.ownerDocument.body.scrollTop;
mc.left -= parObj.ownerDocument.body.scrollLeft;
}
if(!parObj.offsetParent && parObj.ownerDocument.parentWindow.frameElement)
parObj = parObj.ownerDocument.parentWindow.frameElement;
else
parObj = parObj.offsetParent;
}
//没有考虑框架中也有滚动条的情况
mc.top += element.clientHeight+6;
mc.left += 4;
var date = element.value.createDate();
mc.year = date.getFullYear();
mc.month = date.getMonth();
mc.day = date.getDate();
writeCalendar(date);
if(mc.isDynamicShow) timer = setTimeout(dynamicShow,mc.speed);
else oPopup.show(mc.left, mc.top, mc.width,mc.height, document.body);
}
//动态显示控件
var timer = null;
function dynamicShow(){
if(step > 15) { step = 1; clearTimeout(timer); return ;}
else{
if(mc.dynamicShow == "v")
oPopup.show(mc.left, mc.top, mc.width,Math.floor(Math.sin(Math.PI*step/30)*mc.height), document.body);
else
oPopup.show(mc.left, mc.top, Math.floor(Math.sin(Math.PI*step/30)*mc.width),mc.height, document.body);
step ++;
timer = setTimeout(dynamicShow,mc.speed);
}
}
//根据日期来改变控件的显示
function writeCalendar(date){
//获得传入日期属性
var tbRows = oPopup.document.getElementById("tbMxxCalendar").rows;
var tdYear = tbRows[0].cells[2];
var tdMonth = tbRows[0].cells[3];
var year = date.getFullYear();
var month = date.getMonth();
if(mc.showTime){
tbRows[7].cells[4].innerText = date.getHours().toString().replace(/^(/d)$/,"0$1");
tbRows[7].cells[5].innerText = date.getMinutes().toString().replace(/^(/d)$/,"0$1");
tbRows[7].cells[6].innerText = date.getSeconds().toString().replace(/^(/d)$/,"0$1");
}
//判断是否合法的年份
//if(year > mc.maxYear || year <mc.minYear){ alert("超出设定的显示年份!"); return false;}
//写入年月
tdYear.innerText = year;
tdMonth.innerText = eval(month+1).toString().replace(/^(/d)$/,"0$1");
tdYear.title = "西元" +year + "年";
tdMonth.title = eval(month+1) + "月";
//返回当月1号日期
date = new Date(year,month,1);
//计算当前月1号的周数
var week = date.getWeekNum();
//计算该周第一天(周日)的日期
date = new Date(year,month,date.getDate()-date.getDay());
for(var i=2;i<8;i++){
tbRows[i].cells[0].innerText = week;
tbRows[i].cells[0].title = year + "年的第" + week++ + "周";
for(var j=1,k=(i==7?(mc.showTime?4:7):8);j<k;j++){
var tdTemp = tbRows[i].cells[j];
tdTemp.innerText = date.getDate();
tdTemp.id = "";
tdTemp.title =date.getFullYear() + "/" + eval(date.getMonth()+1)+"/" + tdTemp.innerText;
if(month != date.getMonth()) tdTemp.className = "notCurMonth";
else if(mc.year == date.getFullYear() && mc.month == date.getMonth() && mc.day == date.getDate()) {
tdTemp.id = "curDay";
tdTemp.title += "(Enter or Space)";
tdTemp.className = "curDay";
}
else tdTemp.className = "curMonth";
date = date.dateAfter();
}
}
}
//年月改变事件
function chgDate(flag,num){
var tbRows = oPopup.document.getElementById("tbMxxCalendar").rows;
var year = parseInt(tbRows[0].cells[2].innerText,10);
var month = parseInt(tbRows[0].cells[3].innerText,10)-1;
var hour =parseInt(tbRows[7].cells[4].innerText,10);
var minute =parseInt(tbRows[7].cells[5].innerText,10);
var second =parseInt(tbRows[7].cells[6].innerText,10);
var date =null;
if(flag == "y") date = new Date(year+num,month,1);
else if (flag == "m") date = new Date(year,month+num,1);
else date = new Date();
date.setHours(hour , minute, second);
writeCalendar(date);
}
function addEvent(td){
td.attachEvent("onmouseover",function(){ mc.curClassName = td.className; td.className = "tdOver"; });
td.attachEvent("onmouseout",function(){td.className = mc.curClassName;});
td.attachEvent("onclick",function(){
var tbRows = oPopup.document.getElementById("tbMxxCalendar").rows;
var style = mc.style;
var date = new Date(td.title);
if(mc.showTime){
var hour =parseInt(tbRows[7].cells[4].innerText,10);
var minute =parseInt(tbRows[7].cells[5].innerText,10);
var second =parseInt(tbRows[7].cells[6].innerText,10);
date.setHours(hour , minute, second)
style += " hh:mi:ss";
}
element.value = date.parseString(style);
oPopup.hide();
});
}
var pp=null;
function initpp(){
pp=oPopup.document.parentWindow.createPopup();
var ppDoc = pp.document;
var ppBody = pp.document.body;
ppDoc.oncontextmenu = function (){ return false; };
ppDoc.onselectstart = function (){ return false; };
ppBody.style.overflow = "auto";
var oStyleSheet=ppDoc.createStyleSheet();
oStyleSheet.addRule("body", "background-color:#DEEAF6; border:solid #6BBFD9 1px; scrollbar-arrow-color:#000080; scrollbar-shadow-color:#DEEAF6; scrollbar-base-color:#DEEAF6; scrollbar-highlight-color:#DEEAF6;");
oStyleSheet.addRule(".divNormal", "color:#000080; vertical-align:middle; font-size:12px; text-align: center; border:1px solid; border-color: #FFFFFF #D4D0C8 #D4D0C8 #FFFFFF ; width:100%; height:16; cursor:default;");
oStyleSheet.addRule(".divOver", "color:#FFFFF1; background-color:#6BBFD9; vertical-align:middle; font-size:12px; text-align: center; border:1px solid; border-color: #FFFFFF #D4D0C8 #D4D0C8 #FFFFFF ; width:100%; height:16; cursor:default;");
oStyleSheet.addRule(".divCurent", "color:#FF0000; background-color:#6BBFD9; vertical-align:middle; font-size:12px; text-align: center; border:1px solid; border-color: #FFFFFF #D4D0C8 #D4D0C8 #FFFFFF ; width:100%; height:16; cursor:default;");
}
function selectVal(obj,val){
var start =0;
var end = val;
if(val ==0){ start =mc.minYear; end = mc.maxYear;}
else if(val ==12){ start =1; end = 12;}
var txt = obj.innerText;
if(pp == null) initpp();
var ppDoc = pp.document;
var ppBody = pp.document.body;
ppBody.innerHTML="";
for(var i=start;i<=end;i++){
var newDiv = ppDoc.createElement('div');
newDiv.id = "div"+i;
newDiv.innerText = i;
newDiv.className = "divNormal";
divAttach(newDiv,obj,val);
ppBody.appendChild(newDiv);
}
pp.show(mc.width+1, 0, 50, mc.height, oPopup.document.body);
var divNow = ppDoc.getElementById("div"+parseInt(obj.innerText,10));
if(divNow){
divNow.scrollIntoView();
divNow.className = "divCurent";
}
}
function divAttach(newDiv,obj,val){
newDiv.attachEvent("onmouseover",function(){
newDiv.className = "divOver";
});
newDiv.attachEvent("onmouseout",function(){
newDiv.className = "divNormal";
});
newDiv.attachEvent("onclick",function(){
pp.hide();
obj.innerText = newDiv.innerText.trim().replace(/^(/d)$/,"0$1");
var data = parseInt(obj.innerText,10);
var date = null;
var tbRows = oPopup.document.getElementById("tbMxxCalendar").rows;
var hour =parseInt(tbRows[7].cells[4].innerText,10);
var minute =parseInt(tbRows[7].cells[5].innerText,10);
var second =parseInt(tbRows[7].cells[6].innerText,10);
if(val == 0){
var month = parseInt(tbRows[0].cells[3].innerText,10)-1;
date = new Date(data,month,1);
}
else if(val ==12){
var year = parseInt(tbRows[0].cells[2].innerText,10);
date = new Date(year,data-1,1);
}
else return false;
date.setHours(hour , minute, second, 0);
writeCalendar(date);
});
}
String.prototype.trim = function(){return this.replace(/(^/s*)|(/s*$)/g,"");}
/*用相对不规则的字符串来创建日期对象,不规则的含义为:顺序包含年月日三个或者年月日时分秒六个数值串,有间隔
*如果element.value非法,返回当前日期
*/
String.prototype.createDate = function(){
if(this == "") return new Date();
var regThree = /^/D*(/d{2,4})/D+(/d{1,2})/D+(/d{1,2})/D*$/;
var regSix = /^/D*(/d{2,4})/D+(/d{1,2})/D+(/d{1,2})/D+(/d{1,2})/D+(/d{1,2})/D+(/d{1,2})/D*$/;
var str = "";
var date = null;
if(regThree.test(this)){
str = this.replace(//s/g,"").replace(regThree,"$1/$2/$3");
date = new Date(str);
}
else if(regSix.test(this)){
str = this.match(regSix);
date = new Date(str[1],str[2]-1,str[3],str[4],str[5],str[6]);
}
else return new Date();
return date;
}
//根据日期返回该日期所在年的周数
Date.prototype.getWeekNum = function (){
var dat = new Date(this.getFullYear(),0,1);
var week = dat.getDay();
week = (week==0?7:week);
var days = this.calDateDistance(dat)+1;
return ((days + 6 - this.getDay() - 7 + week)/7);
}
/*功能:返回两日期之差
*参数:date Date对象
*/
Date.prototype.calDateDistance = function (date){
if(typeof(date) != "object" || !(/Date/.test(date.constructor)))
throw new Error(-1,"calDateDistance参数为Date类型.");
return num = (( this.valueOf()- date.valueOf())/86400000).fmtRtnVal(0);
}
//返回整数或者两位小数的浮点数
Number.prototype.fmtRtnVal = function (intOrFloat){
return (intOrFloat == 0 ? Math.floor(this) : parseInt(this*100)/100);
}
/* 功能 : 返回下一天的日期
* 返回 : 新的Date
*/
Date.prototype.dateAfter=function(){
return new Date(this.valueOf() + 86400000);
}
/*
* 功能:根据输入表达式返回日期字符串
* 参数:dateFmt:字符串,由以下结构组成
* yy:长写年,mm:数字月,dd:日,hh:时,mi:分,ss秒
*/
Date.prototype.parseString = function(dateFmt){
dateFmt = (dateFmt == null?"yy-mm-dd" : dateFmt);
if(typeof(dateFmt) != "string" )
throw (new Error(-1, 'parseString()方法需要字符串类型参数!'));
var str=dateFmt;
str = str.replace(/yy/g,this.getFullYear());
str = str.replace(/mm/g,(this.getMonth()+1));
str = str.replace(/dd/g,this.getDate());
str = str.replace(/hh/g,this.getHours());
str = str.replace(/mi/g,this.getMinutes());
str = str.replace(/ss/g,this.getSeconds());
str = str.replace(/(/D)(/d)(?=/D|$)/g, "$10$2");
return str;
}
</script>