OSDN Git Service

git-svn-id: https://svn.sourceforge.jp/svnroot/nucleus-jp/plugin@1020 1ca29b6e-896d...
[nucleus-jp/nucleus-plugins.git] / NP_TrackBack / trunk / trackback / js / rico / ricoCalendar.js
1 //  By Matt Brown\r
2 //  June-October 2006\r
3 //  email: dowdybrown@yahoo.com\r
4 //  Implements a pop-up Gregorian calendar.\r
5 //  Dates of adoption of the Gregorian calendar vary by country - accurate as a US & British calendar from 14 Sept 1752 to present.\r
6 //  Mark special dates with calls to addHoliday()\r
7 //  Inspired by code originally written by Tan Ling Wee on 2 Dec 2001\r
8 \r
9 //  Requires prototype.js and ricoCommon.js\r
10 \r
11 Rico.CalendarControl = Class.create();\r
12 \r
13 Rico.CalendarControl.prototype = {\r
14 \r
15   initialize: function(id,options) {\r
16     this.id=id;\r
17     var today=new Date();\r
18     Object.extend(this, new Rico.Popup({ignoreClicks:true}));\r
19     Object.extend(this.options, {\r
20       startAt : 0,           // week starts with 0=sunday, 1=monday\r
21       showWeekNumber : 0,    // show week number in first column?\r
22       showToday : 1,         // show "Today is..." in footer?\r
23       cursorColor: '#FDD',   // color used to highlight dates as the user moves their mouse\r
24       repeatInterval : 100,  // when left/right arrow is pressed, repeat action every x milliseconds\r
25       dateFmt : 'ISO8601',   // default is ISO-8601, 'rico'=use format stored in ricoTranslate object\r
26       selectedDateBorder : "#666666",  // border to indicate currently selected date\r
27       minDate : new Date(today.getFullYear()-50,0,1),  // default to +-50 yrs from current date\r
28       maxDate : new Date(today.getFullYear()+50,11,31)\r
29     });\r
30     Object.extend(this.options, options || {});\r
31     this.close=this.closePopup;\r
32     this.bPageLoaded=false;\r
33     this.img=new Array();\r
34     this.Holidays={};\r
35     this.todayString=RicoTranslate.getPhrase("Today is ");\r
36     this.weekString=RicoTranslate.getPhrase("Wk");\r
37     if (this.options.dateFmt=='rico') this.options.dateFmt=RicoTranslate.dateFmt;\r
38     this.dateParts=new Array();\r
39     this.re=/^\s*(\w+)(\W)(\w+)(\W)(\w+)/i;\r
40     if (this.re.exec(this.options.dateFmt)) {\r
41       this.dateParts[RegExp.$1]=0;\r
42       this.dateParts[RegExp.$3]=1;\r
43       this.dateParts[RegExp.$5]=2;\r
44     }\r
45   },\r
46 \r
47 \r
48   // y=0 implies a repeating holiday\r
49   addHoliday : function(d, m, y, desc, bgColor, txtColor) {\r
50     this.Holidays[this.holidayKey(y,m-1,d)]={desc:desc, txtColor:txtColor, bgColor:bgColor || '#DDF'};\r
51   },\r
52   \r
53   holidayKey : function(y,m,d) {\r
54     return 'h'+y.toPaddedString(4)+m.toPaddedString(2)+d.toPaddedString(2);\r
55   },\r
56 \r
57   atLoad : function() {\r
58     this.container=document.createElement("div");\r
59     this.container.style.display="none"\r
60     this.container.id=this.id;\r
61     this.container.className='ricoCalContainer';\r
62 \r
63     this.maintab=document.createElement("table");\r
64     this.maintab.cellSpacing=0;\r
65     this.maintab.cellPadding=0;\r
66     this.maintab.border=0;\r
67     this.maintab.className='ricoCalTab';\r
68 \r
69     for (var i=0; i<7; i++) {\r
70       var r=this.maintab.insertRow(-1);\r
71       r.className='row'+i;\r
72       for (var c=0; c<8; c++)\r
73         r.insertCell(-1);\r
74     }\r
75     this.tbody=this.maintab.tBodies[0];\r
76     var r=this.tbody.rows[0];\r
77     r.className='ricoCalDayNames';\r
78     if (this.options.showWeekNumber) {\r
79       r.cells[0].innerHTML=this.weekString;\r
80       for (var i=0; i<7; i++)\r
81         this.tbody.rows[i].cells[0].className='ricoCalWeekNum';\r
82     }\r
83     this.styles=[];\r
84     for (var i=0; i<7; i++) {\r
85       var dow=(i+this.options.startAt) % 7;\r
86       r.cells[i+1].innerHTML=RicoTranslate.dayNames[dow].substring(0,3);\r
87       this.styles[i+1]='ricoCal'+dow;\r
88     }\r
89     \r
90     // table header (navigation controls)\r
91     this.thead=this.maintab.createTHead()\r
92     var r=this.thead.insertRow(-1);\r
93     var c=r.insertCell(-1);\r
94     c.colSpan=8;\r
95     var img=this.createNavArrow('decMonth','left');\r
96     c.appendChild(document.createElement("a")).appendChild(img);\r
97     this.titleMonth=document.createElement("a");\r
98     c.appendChild(this.titleMonth);\r
99     Event.observe(this.titleMonth,"click", this.popUpMonth.bindAsEventListener(this), false);\r
100     var img=this.createNavArrow('incMonth','right');\r
101     c.appendChild(document.createElement("a")).appendChild(img);\r
102     var s=document.createElement("span");\r
103     s.innerHTML='&nbsp;';\r
104     s.style.paddingLeft='3em';\r
105     c.appendChild(s);\r
106 \r
107     var img=this.createNavArrow('decYear','left');\r
108     c.appendChild(document.createElement("a")).appendChild(img);\r
109     this.titleYear=document.createElement("a");\r
110     Event.observe(this.titleYear,"click", this.popUpYear.bindAsEventListener(this), false);\r
111     c.appendChild(this.titleYear);\r
112     var img=this.createNavArrow('incYear','right');\r
113     c.appendChild(document.createElement("a")).appendChild(img);\r
114 \r
115     // table footer (today)\r
116     if (this.options.showToday) {\r
117       this.tfoot=this.maintab.createTFoot()\r
118       var r=this.tfoot.insertRow(-1);\r
119       this.todayCell=r.insertCell(-1);\r
120       this.todayCell.colSpan=8;\r
121       Event.observe(this.todayCell,"click", this.selectNow.bindAsEventListener(this), false);\r
122     }\r
123     \r
124 \r
125     this.container.appendChild(this.maintab);\r
126     \r
127     // close icon (upper right)\r
128     var img=document.createElement("img");\r
129     img.src=Rico.imgDir+'close.gif';\r
130     img.onclick=this.close.bind(this);\r
131     img.style.cursor='pointer';\r
132     img.style.position='absolute';\r
133     img.style.top='1px';   /* assumes a 1px border */\r
134     img.style.right='1px';\r
135     this.container.appendChild(img);\r
136     \r
137     // month selector\r
138     this.monthSelect=document.createElement("table");\r
139     this.monthSelect.className='ricoCalMenu';\r
140     this.monthSelect.cellPadding=2;\r
141     this.monthSelect.cellSpacing=0;\r
142     this.monthSelect.border=0;\r
143     for (var i=0; i<4; i++) {\r
144       var r=this.monthSelect.insertRow(-1);\r
145       for (var j=0; j<3; j++) {\r
146         var c=r.insertCell(-1);\r
147         var a=document.createElement("a");\r
148         a.innerHTML=RicoTranslate.monthNames[i*3+j].substring(0,3);\r
149         a.name=i*3+j;\r
150         c.appendChild(a);\r
151         Event.observe(a,"click", this.selectMonth.bindAsEventListener(this), false);\r
152       }\r
153     }\r
154     this.monthSelect.style.display='none';\r
155     this.container.appendChild(this.monthSelect);\r
156     \r
157     // fix anchors so they work in IE6\r
158     var a=this.container.getElementsByTagName('a');\r
159     for (var i=0; i<a.length; i++)\r
160       a[i].href='#';\r
161     \r
162     Event.observe(this.tbody,"click", this.saveAndClose.bindAsEventListener(this));\r
163     Event.observe(this.tbody,"mouseover", this.mouseOver.bindAsEventListener(this));
164     Event.observe(this.tbody,"mouseout",  this.mouseOut.bindAsEventListener(this));
165     document.getElementsByTagName("body")[0].appendChild(this.container);\r
166     this.setDiv(this.container);\r
167     this.close()\r
168     this.bPageLoaded=true\r
169   },\r
170   \r
171   selectNow : function() {\r
172     this.monthSelected=this.monthNow;\r
173     this.yearSelected=this.yearNow;\r
174     this.constructCalendar();\r
175   },\r
176   \r
177   createNavArrow: function(funcname,gifname) {\r
178     var img=document.createElement("img");\r
179     img.src=Rico.imgDir+gifname+'.gif';\r
180     img.name=funcname;\r
181     Event.observe(img,"click", this[funcname].bindAsEventListener(this), false);\r
182     Event.observe(img,"mousedown", this.mouseDown.bindAsEventListener(this), false);\r
183     Event.observe(img,"mouseup", this.mouseUp.bindAsEventListener(this), false);\r
184     Event.observe(img,"mouseout", this.mouseUp.bindAsEventListener(this), false);\r
185     return img\r
186   },\r
187 \r
188   mouseOver: function(e) {\r
189     var el=Event.element(e);\r
190     if (this.lastHighlight==el) return;\r
191     this.unhighlight();\r
192     var s=el.innerHTML.replace(/&nbsp;/g,'');\r
193     if (s=='' || el.className=='ricoCalWeekNum') return;\r
194     var day=parseInt(s);\r
195     if (isNaN(day)) return;\r
196     this.lastHighlight=el;\r
197     this.tmpColor=el.style.backgroundColor;\r
198     el.style.backgroundColor=this.options.cursorColor;\r
199   },\r
200   \r
201   unhighlight: function() {\r
202     if (!this.lastHighlight) return;\r
203     this.lastHighlight.style.backgroundColor=this.tmpColor;\r
204     this.lastHighlight=null;\r
205   },\r
206   \r
207   mouseOut: function(e) {\r
208     var el=Event.element(e);\r
209     if (el==this.lastHighlight) this.unhighlight();\r
210   },\r
211   \r
212   mouseDown: function(e) {\r
213     var el=Event.element(e);\r
214     this.repeatFunc=this[el.name].bind(this);\r
215     this.timeoutID=setTimeout(this.repeatStart.bind(this),500);\r
216   },\r
217   \r
218   mouseUp: function(e) {\r
219     clearTimeout(this.timeoutID);\r
220     clearInterval(this.intervalID)\r
221   },\r
222   \r
223   repeatStart : function() {\r
224     clearInterval(this.intervalID);\r
225     this.intervalID=setInterval(this.repeatFunc,this.options.repeatInterval);\r
226   },\r
227   \r
228   // is yr/mo within minDate/MaxDate?\r
229   isValidMonth : function(yr,mo) {\r
230     if (yr < this.options.minDate.getFullYear()) return false;\r
231     if (yr == this.options.minDate.getFullYear() && mo < this.options.minDate.getMonth()) return false;\r
232     if (yr > this.options.maxDate.getFullYear()) return false;\r
233     if (yr == this.options.maxDate.getFullYear() && mo > this.options.maxDate.getMonth()) return false;\r
234     return true;\r
235   },\r
236 \r
237   incMonth : function() {\r
238     var newMonth=this.monthSelected+1;\r
239     var newYear=this.yearSelected;\r
240     if (newMonth>11) {\r
241       newMonth=0;\r
242       newYear++;\r
243     }\r
244     if (!this.isValidMonth(newYear,newMonth)) return;\r
245     this.monthSelected=newMonth;\r
246     this.yearSelected=newYear;\r
247     this.constructCalendar()\r
248   },\r
249 \r
250   decMonth : function() {\r
251     var newMonth=this.monthSelected-1;\r
252     var newYear=this.yearSelected;\r
253     if (newMonth<0) {\r
254       newMonth=11;\r
255       newYear--;\r
256     }\r
257     if (!this.isValidMonth(newYear,newMonth)) return;\r
258     this.monthSelected=newMonth;\r
259     this.yearSelected=newYear;\r
260     this.constructCalendar()\r
261   },\r
262   \r
263   selectMonth : function(e) {\r
264     var el=Event.element(e);\r
265     this.monthSelected=parseInt(el.name);\r
266     this.constructCalendar();\r
267     Event.stop(e);\r
268   },\r
269 \r
270   popUpMonth : function() {\r
271     this.monthSelect.style.display=this.monthSelect.style.display=='none' ? 'block' : 'none';\r
272   },\r
273 \r
274   popDownMonth : function() {\r
275     this.monthSelect.style.display='none';\r
276   },\r
277 \r
278   /*** Year Pulldown ***/\r
279 \r
280   popUpYear : function() {\r
281     var newYear=prompt(RicoTranslate.getPhrase("Year ("+this.options.minDate.getFullYear()+"-"+this.options.maxDate.getFullYear()+")"),this.yearSelected);\r
282     if (newYear==null) return;\r
283     newYear=parseInt(newYear);\r
284     if (isNaN(newYear) || newYear<this.options.minDate.getFullYear() || newYear>this.options.maxDate.getFullYear()) {\r
285       alert(RicoTranslate.getPhrase("Invalid year"));\r
286     } else {\r
287       this.yearSelected=newYear;\r
288       this.constructCalendar();\r
289     }\r
290   },\r
291   \r
292   incYear : function() {\r
293     if (this.yearSelected>=this.options.maxDate.getFullYear()) return;\r
294     this.yearSelected++;\r
295     this.constructCalendar();\r
296   },\r
297 \r
298   decYear : function() {\r
299     if (this.yearSelected<=this.options.minDate.getFullYear()) return;\r
300     this.yearSelected--;\r
301     this.constructCalendar();\r
302   },\r
303 \r
304   // tried a number of different week number functions posted on the net\r
305   // this is the only one that produced consistent results when comparing week numbers for December and the following January\r
306   WeekNbr : function(year,month,day) {\r
307     var when = new Date(year,month,day);\r
308     var newYear = new Date(year,0,1);\r
309     var offset = 7 + 1 - newYear.getDay();\r
310     if (offset == 8) offset = 1;\r
311     var daynum = ((Date.UTC(year,when.getMonth(),when.getDate(),0,0,0) - Date.UTC(year,0,1,0,0,0)) /1000/60/60/24) + 1;\r
312     var weeknum = Math.floor((daynum-offset+7)/7);\r
313     if (weeknum == 0) {\r
314         year--;\r
315         var prevNewYear = new Date(year,0,1);\r
316         var prevOffset = 7 + 1 - prevNewYear.getDay();\r
317         if (prevOffset == 2 || prevOffset == 8) weeknum = 53; else weeknum = 52;\r
318     }\r
319     return weeknum;\r
320   },\r
321 \r
322   constructCalendar : function() {\r
323     var aNumDays = Array (31,0,31,30,31,30,31,31,30,31,30,31)\r
324     var startDate = new Date (this.yearSelected,this.monthSelected,1)\r
325     var endDate,numDaysInMonth\r
326 \r
327     if (typeof this.monthSelected!='number' || this.monthSelected>=12 || this.monthSelected<0) {\r
328       alert('ERROR in calendar: monthSelected='+this.monthSelected);\r
329       return;\r
330     }\r
331     var today = new Date();\r
332     this.dateNow  = today.getDate();\r
333     this.monthNow = today.getMonth();\r
334     this.yearNow  = today.getFullYear();\r
335 \r
336     if (this.monthSelected==1) {\r
337       endDate = new Date (this.yearSelected,this.monthSelected+1,1);\r
338       endDate = new Date (endDate - (24*60*60*1000));\r
339       numDaysInMonth = endDate.getDate()\r
340     } else {\r
341       numDaysInMonth = aNumDays[this.monthSelected];\r
342     }\r
343     var dayPointer = startDate.getDay() - this.options.startAt\r
344     if (dayPointer<0) dayPointer+=7;\r
345     this.popDownMonth();\r
346 \r
347     this.bgcolor=Element.getStyle(this.tbody,'background-color');\r
348     this.bgcolor=this.bgcolor.replace(/\"/g,'');\r
349     if (this.options.showWeekNumber) {\r
350       for (var i=1; i<7; i++)\r
351         this.tbody.rows[i].cells[0].innerHTML='&nbsp;';\r
352     }\r
353     for ( var i=1; i<=dayPointer; i++ )\r
354       this.resetCell(this.tbody.rows[1].cells[i]);\r
355 \r
356     for ( var datePointer=1,r=1; datePointer<=numDaysInMonth; datePointer++,dayPointer++ ) {\r
357       var colnum=dayPointer % 7 + 1;\r
358       if (this.options.showWeekNumber==1 && colnum==1)\r
359         this.tbody.rows[r].cells[0].innerHTML=this.WeekNbr(this.yearSelected,this.monthSelected,datePointer);\r
360       var dateClass=this.styles[colnum];\r
361       if ((datePointer==this.dateNow)&&(this.monthSelected==this.monthNow)&&(this.yearSelected==this.yearNow))\r
362         dateClass='ricoCalToday';\r
363       var c=this.tbody.rows[r].cells[colnum];\r
364       c.innerHTML="&nbsp;" + datePointer + "&nbsp;";\r
365       c.className=dateClass;\r
366       var bordercolor=(datePointer==this.odateSelected) && (this.monthSelected==this.omonthSelected) && (this.yearSelected==this.oyearSelected) ? this.options.selectedDateBorder : this.bgcolor;\r
367       c.style.border='1px solid '+bordercolor;\r
368       var h=this.Holidays[this.holidayKey(this.yearSelected,this.monthSelected,datePointer)];\r
369       if (!h)  h=this.Holidays[this.holidayKey(0,this.monthSelected,datePointer)];\r
370       c.style.color=h ? h.txtColor : '';\r
371       c.style.backgroundColor=h ? h.bgColor : '';\r
372       c.title=h ? h.desc : '';\r
373       if (colnum==7) r++;\r
374     }\r
375     while (dayPointer<42) {\r
376       var colnum=dayPointer % 7 + 1;\r
377       this.resetCell(this.tbody.rows[r].cells[colnum]);\r
378       dayPointer++;\r
379       if (colnum==7) r++;\r
380     }\r
381 \r
382     this.titleMonth.innerHTML = RicoTranslate.monthNames[this.monthSelected].substring(0,3);\r
383     this.titleYear.innerHTML = this.yearSelected;\r
384     if (this.options.showToday)\r
385       this.todayCell.innerHTML=this.todayString+'<span>'+this.dateNow + " " + RicoTranslate.monthNames[this.monthNow].substring(0,3) + " " + this.yearNow+'</span>';\r
386     this.monthSelect.style.top=this.thead.offsetHeight+'px';\r
387     this.monthSelect.style.left=this.titleMonth.offsetLeft+'px';\r
388   },\r
389   \r
390   resetCell: function(c) {\r
391     c.innerHTML="&nbsp;";\r
392     c.className='ricoCalEmpty';\r
393     c.style.border='1px solid '+this.bgcolor;\r
394     c.style.color='';\r
395     c.style.backgroundColor='';\r
396     c.title='';\r
397   },\r
398   \r
399   saveAndClose : function(e) {\r
400     Event.stop(e);\r
401     var el=Event.element(e);\r
402     var s=el.innerHTML.replace(/&nbsp;/g,'');\r
403     if (s=='' || el.className=='ricoCalWeekNum') return;\r
404     var day=parseInt(s);\r
405     if (isNaN(day)) return;\r
406     var d=new Date(this.yearSelected,this.monthSelected,day);\r
407     var dateStr=d.formatDate(this.options.dateFmt=='ISO8601' ? 'yyyy-mm-dd' : this.options.dateFmt);\r
408     if (this.returnValue) this.returnValue(dateStr);\r
409     this.close();\r
410   },\r
411 \r
412   open : function(curval) {\r
413     if (!this.bPageLoaded) return;\r
414     if (typeof curval=='object') {\r
415       this.dateSelected  = curval.getDate();\r
416       this.monthSelected = curval.getMonth();\r
417       this.yearSelected  = curval.getFullYear();\r
418     } else if (this.options.dateFmt=='ISO8601') {\r
419       var d=new Date;\r
420       d.setISO8601(curval);\r
421       this.dateSelected  = d.getDate();\r
422       this.monthSelected = d.getMonth();\r
423       this.yearSelected  = d.getFullYear();\r
424     } else if (this.re.exec(curval)) {\r
425       var aDate=new Array(RegExp.$1,RegExp.$3,RegExp.$5);\r
426       this.dateSelected  = parseInt(aDate[this.dateParts['dd']], 10);\r
427       this.monthSelected = parseInt(aDate[this.dateParts['mm']], 10) - 1;\r
428       this.yearSelected  = parseInt(aDate[this.dateParts['yyyy']], 10);\r
429     } else {\r
430       if (curval) alert('ERROR: invalid date passed to calendar ('+curval+')');\r
431       this.dateSelected  = this.dateNow\r
432       this.monthSelected = this.monthNow\r
433       this.yearSelected  = this.yearNow\r
434     }\r
435     this.odateSelected=this.dateSelected\r
436     this.omonthSelected=this.monthSelected\r
437     this.oyearSelected=this.yearSelected\r
438     this.constructCalendar();\r
439     this.openPopup();\r
440   }\r
441 }\r
442 \r
443 Rico.includeLoaded('ricoCalendar.js');