PageSourceSearch

https://www.ldorganisation.com/scriptsv3/calendar.js

js ldorganisation.com collected 2026-09-26 04:14:44 UTC 47,240 bytes, 1,715 lines download raw bytes

1/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
2 * ------------------------------------------------------------------
3 *
4 * The DHTML Calendar, version 0.9.6 "Keep cool but don't freeze"
5 *
6 * Details and latest version at:
7 * http://dynarch.com/mishoo/calendar.epl
8 *
9 * This script is distributed under the GNU Lesser General Public License.
10 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
11 */
12
13// $Id: calendar.js,v 1.34 2004/02/06 18:53:11 mishoo Exp $
14
15/** The Calendar object constructor. */
16Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
17	// member variables
18	this.activeDiv = null;
19	this.currentDateEl = null;
20	this.getDateStatus = null;
21	this.timeout = null;
22	this.onSelected = onSelected || null;
23	this.onClose = onClose || null;
24	this.dragging = false;
25	this.hidden = false;
26	this.minYear = 1970;
27	this.maxYear = 2050;
28	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
29	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
30	this.isPopup = true;
31	this.weekNumbers = true;
32	this.firstDayOfWeek = firstDayOfWeek; // 0 for Sunday, 1 for Monday, etc.
33	this.showsOtherMonths = false;
34	this.dateStr = dateStr;
35	this.ar_days = null;
36	this.showsTime = false;
37	this.time24 = true;
38	this.yearStep = 2;
39	// HTML elements
40	this.table = null;
41	this.element = null;
42	this.tbody = null;
43	this.firstdayname = null;
44	// Combo boxes
45	this.monthsCombo = null;
46	this.yearsCombo = null;
47	this.hilitedMonth = null;
48	this.activeMonth = null;
49	this.hilitedYear = null;
50	this.activeYear = null;
51	// Information
52	this.dateClicked = false;
53
54	// one-time initializations
55	if (typeof Calendar._SDN == "undefined") {
56		// table of short day names
57		if (typeof Calendar._SDN_len == "undefined")
58			Calendar._SDN_len = 3;
59		var ar = new Array();
60		for (var i = 8; i > 0;) {
61			ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
62		}
63		Calendar._SDN = ar;
64		// table of short month names
65		if (typeof Calendar._SMN_len == "undefined")
66			Calendar._SMN_len = 3;
67		ar = new Array();
68		for (var i = 12; i > 0;) {
69			ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
70		}
71		Calendar._SMN = ar;
72	}
73};
74
75// ** constants
76
77/// "static", needed for event handlers.
78Calendar._C = null;
79
80/// detect a special case of "web browser"
81Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
82		   !/opera/i.test(navigator.userAgent) );
83
84Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );
85
86/// detect Opera browser
87Calendar.is_opera = /opera/i.test(navigator.userAgent);
88
89/// detect KHTML-based browsers
90Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);
91
92// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
93//        library, at some point.
94
95Calendar.getAbsolutePos = function(el) {
96	var SL = 0, ST = 0;
97	var is_div = /^div$/i.test(el.tagName);
98	if (is_div && el.scrollLeft)
99		SL = el.scrollLeft;
100	if (is_div && el.scrollTop)
101		ST = el.scrollTop;
102	var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
103	if (el.offsetParent) {
104		var tmp = this.getAbsolutePos(el.offsetParent);
105		r.x += tmp.x;
106		r.y += tmp.y;
107	}
108	return r;
109};
110
111Calendar.isRelated = function (el, evt) {
112	var related = evt.relatedTarget;
113	if (!related) {
114		var type = evt.type;
115		if (type == "mouseover") {
116			related = evt.fromElement;
117		} else if (type == "mouseout") {
118			related = evt.toElement;
119		}
120	}
121	while (related) {
122		if (related == el) {
123			return true;
124		}
125		related = related.parentNode;
126	}
127	return false;
128};
129
130Calendar.removeClass = function(el, className) {
131	if (!(el && el.className)) {
132		return;
133	}
134	var cls = el.className.split(" ");
135	var ar = new Array();
136	for (var i = cls.length; i > 0;) {
137		if (cls[--i] != className) {
138			ar[ar.length] = cls[i];
139		}
140	}
141	el.className = ar.join(" ");
142};
143
144Calendar.addClass = function(el, className) {
145	Calendar.removeClass(el, className);
146	el.className += " " + className;
147};
148
149Calendar.getElement = function(ev) {
150	if (Calendar.is_ie) {
151		return window.event.srcElement;
152	} else {
153		return ev.currentTarget;
154	}
155};
156
157Calendar.getTargetElement = function(ev) {
158	if (Calendar.is_ie) {
159		return window.event.srcElement;
160	} else {
161		return ev.target;
162	}
163};
164
165Calendar.stopEvent = function(ev) {
166	ev || (ev = window.event);
167	if (Calendar.is_ie) {
168		ev.cancelBubble = true;
169		ev.returnValue = false;
170	} else {
171		ev.preventDefault();
172		ev.stopPropagation();
173	}
174	return false;
175};
176
177Calendar.addEvent = function(el, evname, func) {
178	if (el.attachEvent) { // IE
179		el.attachEvent("on" + evname, func);
180	} else if (el.addEventListener) { // Gecko / W3C
181		el.addEventListener(evname, func, true);
182	} else {
183		el["on" + evname] = func;
184	}
185};
186
187Calendar.removeEvent = function(el, evname, func) {
188	if (el.detachEvent) { // IE
189		el.detachEvent("on" + evname, func);
190	} else if (el.removeEventListener) { // Gecko / W3C
191		el.removeEventListener(evname, func, true);
192	} else {
193		el["on" + evname] = null;
194	}
195};
196
197Calendar.createElement = function(type, parent) {
198	var el = null;
199	if (document.createElementNS) {
200		// use the XHTML namespace; IE won't normally get here unless
201		// _they_ "fix" the DOM2 implementation.
202		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
203	} else {
204		el = document.createElement(type);
205	}
206	if (typeof parent != "undefined") {
207		parent.appendChild(el);
208	}
209	return el;
210};
211
212// END: UTILITY FUNCTIONS
213
214// BEGIN: CALENDAR STATIC FUNCTIONS
215
216/** Internal -- adds a set of events to make some element behave like a button. */
217Calendar._add_evs = function(el) {
218	with (Calendar) {
219		addEvent(el, "mouseover", dayMouseOver);
220		addEvent(el, "mousedown", dayMouseDown);
221		addEvent(el, "mouseout", dayMouseOut);
222		if (is_ie) {
223			addEvent(el, "dblclick", dayMouseDblClick);
224			el.setAttribute("unselectable", true);
225		}
226	}
227};
228
229Calendar.findMonth = function(el) {
230	if (typeof el.month != "undefined") {
231		return el;
232	} else if (typeof el.parentNode.month != "undefined") {
233		return el.parentNode;
234	}
235	return null;
236};
237
238Calendar.findYear = function(el) {
239	if (typeof el.year != "undefined") {
240		return el;
241	} else if (typeof el.parentNode.year != "undefined") {
242		return el.parentNode;
243	}
244	return null;
245};
246
247Calendar.showMonthsCombo = function () {
248	var cal = Calendar._C;
249	if (!cal) {
250		return false;
251	}
252	var cal = cal;
253	var cd = cal.activeDiv;
254	var mc = cal.monthsCombo;
255	if (cal.hilitedMonth) {
256		Calendar.removeClass(cal.hilitedMonth, "hilite");
257	}
258	if (cal.activeMonth) {
259		Calendar.removeClass(cal.activeMonth, "active");
260	}
261	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
262	Calendar.addClass(mon, "active");
263	cal.activeMonth = mon;
264	var s = mc.style;
265	s.display = "block";
266	if (cd.navtype < 0)
267		s.left = cd.offsetLeft + "px";
268	else {
269		var mcw = mc.offsetWidth;
270		if (typeof mcw == "undefined")
271			// Konqueror brain-dead techniques
272			mcw = 50;
273		s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
274	}
275	s.top = (cd.offsetTop + cd.offsetHeight) + "px";
276};
277
278Calendar.showYearsCombo = function (fwd) {
279	var cal = Calendar._C;
280	if (!cal) {
281		return false;
282	}
283	var cal = cal;
284	var cd = cal.activeDiv;
285	var yc = cal.yearsCombo;
286	if (cal.hilitedYear) {
287		Calendar.removeClass(cal.hilitedYear, "hilite");
288	}
289	if (cal.activeYear) {
290		Calendar.removeClass(cal.activeYear, "active");
291	}
292	cal.activeYear = null;
293	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
294	var yr = yc.firstChild;
295	var show = false;
296	for (var i = 12; i > 0; --i) {
297		if (Y >= cal.minYear && Y <= cal.maxYear) {
298			yr.firstChild.data = Y;
299			yr.year = Y;
300			yr.style.display = "block";
301			show = true;
302		} else {
303			yr.style.display = "none";
304		}
305		yr = yr.nextSibling;
306		Y += fwd ? cal.yearStep : -cal.yearStep;
307	}
308	if (show) {
309		var s = yc.style;
310		s.display = "block";
311		if (cd.navtype < 0)
312			s.left = cd.offsetLeft + "px";
313		else {
314			var ycw = yc.offsetWidth;
315			if (typeof ycw == "undefined")
316				// Konqueror brain-dead techniques
317				ycw = 50;
318			s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
319		}
320		s.top = (cd.offsetTop + cd.offsetHeight) + "px";
321	}
322};
323
324// event handlers
325
326Calendar.tableMouseUp = function(ev) {
327	var cal = Calendar._C;
328	if (!cal) {
329		return false;
330	}
331	if (cal.timeout) {
332		clearTimeout(cal.timeout);
333	}
334	var el = cal.activeDiv;
335	if (!el) {
336		return false;
337	}
338	var target = Calendar.getTargetElement(ev);
339	ev || (ev = window.event);
340	Calendar.removeClass(el, "active");
341	if (target == el || target.parentNode == el) {
342		Calendar.cellClick(el, ev);
343	}
344	var mon = Calendar.findMonth(target);
345	var date = null;
346	if (mon) {
347		date = new Date(cal.date);
348		if (mon.month != date.getMonth()) {
349			date.setMonth(mon.month);
350			cal.setDate(date);
351			cal.dateClicked = false;
352			cal.callHandler();
353		}
354	} else {
355		var year = Calendar.findYear(target);
356		if (year) {
357			date = new Date(cal.date);
358			if (year.year != date.getFullYear()) {
359				date.setFullYear(year.year);
360				cal.setDate(date);
361				cal.dateClicked = false;
362				cal.callHandler();
363			}
364		}
365	}
366	with (Calendar) {
367		removeEvent(document, "mouseup", tableMouseUp);
368		removeEvent(document, "mouseover", tableMouseOver);
369		removeEvent(document, "mousemove", tableMouseOver);
370		cal._hideCombos();
371		_C = null;
372		return stopEvent(ev);
373	}
374};
375
376Calendar.tableMouseOver = function (ev) {
377	var cal = Calendar._C;
378	if (!cal) {
379		return;
380	}
381	var el = cal.activeDiv;
382	var target = Calendar.getTargetElement(ev);
383	if (target == el || target.parentNode == el) {
384		Calendar.addClass(el, "hilite active");
385		Calendar.addClass(el.parentNode, "rowhilite");
386	} else {
387		if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
388			Calendar.removeClass(el, "active");
389		Calendar.removeClass(el, "hilite");
390		Calendar.removeClass(el.parentNode, "rowhilite");
391	}
392	ev || (ev = window.event);
393	if (el.navtype == 50 && target != el) {
394		var pos = Calendar.getAbsolutePos(el);
395		var w = el.offsetWidth;
396		var x = ev.clientX;
397		var dx;
398		var decrease = true;
399		if (x > pos.x + w) {
400			dx = x - pos.x - w;
401			decrease = false;
402		} else
403			dx = pos.x - x;
404
405		if (dx < 0) dx = 0;
406		var range = el._range;
407		var current = el._current;
408		var count = Math.floor(dx / 10) % range.length;
409		for (var i = range.length; --i >= 0;)
410			if (range[i] == current)
411				break;
412		while (count-- > 0)
413			if (decrease) {
414				if (--i < 0)
415					i = range.length - 1;
416			} else if ( ++i >= range.length )
417				i = 0;
418		var newval = range[i];
419		el.firstChild.data = newval;
420
421		cal.onUpdateTime();
422	}
423	var mon = Calendar.findMonth(target);
424	if (mon) {
425		if (mon.month != cal.date.getMonth()) {
426			if (cal.hilitedMonth) {
427				Calendar.removeClass(cal.hilitedMonth, "hilite");
428			}
429			Calendar.addClass(mon, "hilite");
430			cal.hilitedMonth = mon;
431		} else if (cal.hilitedMonth) {
432			Calendar.removeClass(cal.hilitedMonth, "hilite");
433		}
434	} else {
435		if (cal.hilitedMonth) {
436			Calendar.removeClass(cal.hilitedMonth, "hilite");
437		}
438		var year = Calendar.findYear(target);
439		if (year) {
440			if (year.year != cal.date.getFullYear()) {
441				if (cal.hilitedYear) {
442					Calendar.removeClass(cal.hilitedYear, "hilite");
443				}
444				Calendar.addClass(year, "hilite");
445				cal.hilitedYear = year;
446			} else if (cal.hilitedYear) {
447				Calendar.removeClass(cal.hilitedYear, "hilite");
448			}
449		} else if (cal.hilitedYear) {
450			Calendar.removeClass(cal.hilitedYear, "hilite");
451		}
452	}
453	return Calendar.stopEvent(ev);
454};
455
456Calendar.tableMouseDown = function (ev) {
457	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
458		return Calendar.stopEvent(ev);
459	}
460};
461
462Calendar.calDragIt = function (ev) {
463	var cal = Calendar._C;
464	if (!(cal && cal.dragging)) {
465		return false;
466	}
467	var posX;
468	var posY;
469	if (Calendar.is_ie) {
470		posY = window.event.clientY + document.body.scrollTop;
471		posX = window.event.clientX + document.body.scrollLeft;
472	} else {
473		posX = ev.pageX;
474		posY = ev.pageY;
475	}
476	cal.hideShowCovered();
477	var st = cal.element.style;
478	st.left = (posX - cal.xOffs) + "px";
479	st.top = (posY - cal.yOffs) + "px";
480	return Calendar.stopEvent(ev);
481};
482
483Calendar.calDragEnd = function (ev) {
484	var cal = Calendar._C;
485	if (!cal) {
486		return false;
487	}
488	cal.dragging = false;
489	with (Calendar) {
490		removeEvent(document, "mousemove", calDragIt);
491		removeEvent(document, "mouseup", calDragEnd);
492		tableMouseUp(ev);
493	}
494	cal.hideShowCovered();
495};
496
497Calendar.dayMouseDown = function(ev) {
498	var el = Calendar.getElement(ev);
499	if (el.disabled) {
500		return false;
501	}
502	var cal = el.calendar;
503	cal.activeDiv = el;
504	Calendar._C = cal;
505	if (el.navtype != 300) with (Calendar) {
506		if (el.navtype == 50) {
507			el._current = el.firstChild.data;
508			addEvent(document, "mousemove", tableMouseOver);
509		} else
510			addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
511		addClass(el, "hilite active");
512		addEvent(document, "mouseup", tableMouseUp);
513	} else if (cal.isPopup) {
514		cal._dragStart(ev);
515	}
516	if (el.navtype == -1 || el.navtype == 1) {
517		if (cal.timeout) clearTimeout(cal.timeout);
518		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
519	} else if (el.navtype == -2 || el.navtype == 2) {
520		if (cal.timeout) clearTimeout(cal.timeout);
521		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
522	} else {
523		cal.timeout = null;
524	}
525	return Calendar.stopEvent(ev);
526};
527
528Calendar.dayMouseDblClick = function(ev) {
529	Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
530	if (Calendar.is_ie) {
531		document.selection.empty();
532	}
533};
534
535Calendar.dayMouseOver = function(ev) {
536	var el = Calendar.getElement(ev);
537	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
538		return false;
539	}
540	if (el.ttip) {
541		if (el.ttip.substr(0, 1) == "_") {
542			el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
543		}
544		el.calendar.tooltips.firstChild.data = el.ttip;
545	}
546	if (el.navtype != 300) {
547		Calendar.addClass(el, "hilite");
548		if (el.caldate) {
549			Calendar.addClass(el.parentNode, "rowhilite");
550		}
551	}
552	return Calendar.stopEvent(ev);
553};
554
555Calendar.dayMouseOut = function(ev) {
556	with (Calendar) {
557		var el = getElement(ev);
558		if (isRelated(el, ev) || _C || el.disabled) {
559			return false;
560		}
561		removeClass(el, "hilite");
562		if (el.caldate) {
563			removeClass(el.parentNode, "rowhilite");
564		}
565		el.calendar.tooltips.firstChild.data = _TT["SEL_DATE"];
566		return stopEvent(ev);
567	}
568};
569
570/**
571 *  A generic "click" handler :) handles all types of buttons defined in this
572 *  calendar.
573 */
574Calendar.cellClick = function(el, ev) {
575	var cal = el.calendar;
576	var closing = false;
577	var newdate = false;
578	var date = null;
579	if (typeof el.navtype == "undefined") {
580		Calendar.removeClass(cal.currentDateEl, "selected");
581		Calendar.addClass(el, "selected");
582		closing = (cal.currentDateEl == el);
583		if (!closing) {
584			cal.currentDateEl = el;
585		}
586		cal.date = new Date(el.caldate);
587		date = cal.date;
588		newdate = true;
589		// a date was clicked
590		if (!(cal.dateClicked = !el.otherMonth))
591			cal._init(cal.firstDayOfWeek, date);
592	} else {
593		if (el.navtype == 200) {
594			Calendar.removeClass(el, "hilite");
595			cal.callCloseHandler();
596			return;
597		}
598		date = (el.navtype == 0) ? new Date() : new Date(cal.date);
599		// unless "today" was clicked, we assume no date was clicked so
600		// the selected handler will know not to close the calenar when
601		// in single-click mode.
602		// cal.dateClicked = (el.navtype == 0);
603		cal.dateClicked = false;
604		var year = date.getFullYear();
605		var mon = date.getMonth();
606		function setMonth(m) {
607			var day = date.getDate();
608			var max = date.getMonthDays(m);
609			if (day > max) {
610				date.setDate(max);
611			}
612			date.setMonth(m);
613		};
614		switch (el.navtype) {
615		    case 400:
616			Calendar.removeClass(el, "hilite");
617			var text = Calendar._TT["ABOUT"];
618			if (typeof text != "undefined") {
619				text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
620			} else {
621				// FIXME: this should be removed as soon as lang files get updated!
622				text = "Help and about box text is not translated into this language.\n" +
623					"If you know this language and you feel generous please update\n" +
624					"the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
625					"and send it back to <[email protected]> to get it into the distribution  ;-)\n\n" +
626					"Thank you!\n" +
627					"http://dynarch.com/mishoo/calendar.epl\n";
628			}
629			alert(text);
630			return;
631		    case -2:
632			if (year > cal.minYear) {
633				date.setFullYear(year - 1);
634			}
635			break;
636		    case -1:
637			if (mon > 0) {
638				setMonth(mon - 1);
639			} else if (year-- > cal.minYear) {
640				date.setFullYear(year);
641				setMonth(11);
642			}
643			break;
644		    case 1:
645			if (mon < 11) {
646				setMonth(mon + 1);
647			} else if (year < cal.maxYear) {
648				date.setFullYear(year + 1);
649				setMonth(0);
650			}
651			break;
652		    case 2:
653			if (year < cal.maxYear) {
654				date.setFullYear(year + 1);
655			}
656			break;
657		    case 100:
658			cal.setFirstDayOfWeek(el.fdow);
659			return;
660		    case 50:
661			var range = el._range;
662			var current = el.firstChild.data;
663			for (var i = range.length; --i >= 0;)
664				if (range[i] == current)
665					break;
666			if (ev && ev.shiftKey) {
667				if (--i < 0)
668					i = range.length - 1;
669			} else if ( ++i >= range.length )
670				i = 0;
671			var newval = range[i];
672			el.firstChild.data = newval;
673			cal.onUpdateTime();
674			return;
675		    case 0:
676			// TODAY will bring us here
677			if ((typeof cal.getDateStatus == "function") && cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
678				// remember, "date" was previously set to new
679				// Date() if TODAY was clicked; thus, it
680				// contains today date.
681				return false;
682			}
683			break;
684		}
685		if (!date.equalsTo(cal.date)) {
686			cal.setDate(date);
687			newdate = true;
688		}
689	}
690	if (newdate) {
691		cal.callHandler();
692	}
693	if (closing) {
694		Calendar.removeClass(el, "hilite");
695		cal.callCloseHandler();
696	}
697};
698
699// END: CALENDAR STATIC FUNCTIONS
700
701// BEGIN: CALENDAR OBJECT FUNCTIONS
702
703/**
704 *  This function creates the calendar inside the given parent.  If _par is
705 *  null than it creates a popup calendar inside the BODY element.  If _par is
706 *  an element, be it BODY, then it creates a non-popup calendar (still
707 *  hidden).  Some properties need to be set before calling this function.
708 */
709Calendar.prototype.create = function (_par) {
710	var parent = null;
711	if (! _par) {
712		// default parent is the document body, in which case we create
713		// a popup calendar.
714		parent = document.getElementsByTagName("body")[0];
715		this.isPopup = true;
716	} else {
717		parent = _par;
718		this.isPopup = false;
719	}
720	this.date = this.dateStr ? new Date(this.dateStr) : new Date();
721
722	var table = Calendar.createElement("table");
723	this.table = table;
724	table.cellSpacing = 0;
725	table.cellPadding = 0;
726	table.calendar = this;
727	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);
728
729	var div = Calendar.createElement("div");
730	this.element = div;
731	div.className = "calendar";
732	if (this.isPopup) {
733		div.style.position = "absolute";
734		div.style.display = "none";
735	}
736	div.appendChild(table);
737
738	var thead = Calendar.createElement("thead", table);
739	var cell = null;
740	var row = null;
741
742	var cal = this;
743	var hh = function (text, cs, navtype) {
744		cell = Calendar.createElement("td", row);
745		cell.colSpan = cs;
746		cell.className = "button";
747		if (navtype != 0 && Math.abs(navtype) <= 2)
748			cell.className += " nav";
749		Calendar._add_evs(cell);
750		cell.calendar = cal;
751		cell.navtype = navtype;
752		if (text.substr(0, 1) != "&") {
753			cell.appendChild(document.createTextNode(text));
754		}
755		else {
756			// FIXME: dirty hack for entities
757			cell.innerHTML = text;
758		}
759		return cell;
760	};
761
762	row = Calendar.createElement("tr", thead);
763	var title_length = 6;
764	(this.isPopup) && --title_length;
765	(this.weekNumbers) && ++title_length;
766
767	hh("?", 1, 400).ttip = Calendar._TT["INFO"];
768	this.title = hh("", title_length, 300);
769	this.title.className = "title";
770	if (this.isPopup) {
771		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
772		this.title.style.cursor = "move";
773		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
774	}
775
776	row = Calendar.createElement("tr", thead);
777	row.className = "headrow";
778
779	this._nav_py = hh("&#x00ab;", 1, -2);
780	this._nav_py.ttip = Calendar._TT["PREV_YEAR"];
781
782	this._nav_pm = hh("&#x2039;", 1, -1);
783	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];
784
785	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
786	this._nav_now.ttip = Calendar._TT["GO_TODAY"];
787
788	this._nav_nm = hh("&#x203a;", 1, 1);
789	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];
790
791	this._nav_ny = hh("&#x00bb;", 1, 2);
792	this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];
793
794	// day names
795	row = Calendar.createElement("tr", thead);
796	row.className = "daynames";
797	if (this.weekNumbers) {
798		cell = Calendar.createElement("td", row);
799		cell.className = "name wn";
800		cell.appendChild(document.createTextNode(Calendar._TT["WK"]));
801	}
802	for (var i = 7; i > 0; --i) {
803		cell = Calendar.createElement("td", row);
804		cell.appendChild(document.createTextNode(""));
805		if (!i) {
806			cell.navtype = 100;
807			cell.calendar = this;
808			Calendar._add_evs(cell);
809		}
810	}
811	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
812	this._displayWeekdays();
813
814	var tbody = Calendar.createElement("tbody", table);
815	this.tbody = tbody;
816
817	for (i = 6; i > 0; --i) {
818		row = Calendar.createElement("tr", tbody);
819		if (this.weekNumbers) {
820			cell = Calendar.createElement("td", row);
821			cell.appendChild(document.createTextNode(""));
822		}
823		for (var j = 7; j > 0; --j) {
824			cell = Calendar.createElement("td", row);
825			cell.appendChild(document.createTextNode(""));
826			cell.calendar = this;
827			Calendar._add_evs(cell);
828		}
829	}
830
831	if (this.showsTime) {
832		row = Calendar.createElement("tr", tbody);
833		row.className = "time";
834
835		cell = Calendar.createElement("td", row);
836		cell.className = "time";
837		cell.colSpan = 2;
838		cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";
839
840		cell = Calendar.createElement("td", row);
841		cell.className = "time";
842		cell.colSpan = this.weekNumbers ? 4 : 3;
843
844		(function(){
845			function makeTimePart(className, init, range_start, range_end) {
846				var part = Calendar.createElement("span", cell);
847				part.className = className;
848				part.appendChild(document.createTextNode(init));
849				part.calendar = cal;
850				part.ttip = Calendar._TT["TIME_PART"];
851				part.navtype = 50;
852				part._range = [];
853				if (typeof range_start != "number")
854					part._range = range_start;
855				else {
856					for (var i = range_start; i <= range_end; ++i) {
857						var txt;
858						if (i < 10 && range_end >= 10) txt = '0' + i;
859						else txt = '' + i;
860						part._range[part._range.length] = txt;
861					}
862				}
863				Calendar._add_evs(part);
864				return part;
865			};
866			var hrs = cal.date.getHours();
867			var mins = cal.date.getMinutes();
868			var t12 = !cal.time24;
869			var pm = (hrs > 12);
870			if (t12 && pm) hrs -= 12;
871			var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
872			var span = Calendar.createElement("span", cell);
873			span.appendChild(document.createTextNode(":"));
874			span.className = "colon";
875			var M = makeTimePart("minute", mins, 0, 59);
876			var AP = null;
877			cell = Calendar.createElement("td", row);
878			cell.className = "time";
879			cell.colSpan = 2;
880			if (t12)
881				AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
882			else
883				cell.innerHTML = "&nbsp;";
884
885			cal.onSetTime = function() {
886				var hrs = this.date.getHours();
887				var mins = this.date.getMinutes();
888				var pm = (hrs > 12);
889				if (pm && t12) hrs -= 12;
890				H.firstChild.data = (hrs < 10) ? ("0" + hrs) : hrs;
891				M.firstChild.data = (mins < 10) ? ("0" + mins) : mins;
892				if (t12)
893					AP.firstChild.data = pm ? "pm" : "am";
894			};
895
896			cal.onUpdateTime = function() {
897				var date = this.date;
898				var h = parseInt(H.firstChild.data, 10);
899				if (t12) {
900					if (/pm/i.test(AP.firstChild.data) && h < 12)
901						h += 12;
902					else if (/am/i.test(AP.firstChild.data) && h == 12)
903						h = 0;
904				}
905				var d = date.getDate();
906				var m = date.getMonth();
907				var y = date.getFullYear();
908				date.setHours(h);
909				date.setMinutes(parseInt(M.firstChild.data, 10));
910				date.setFullYear(y);
911				date.setMonth(m);
912				date.setDate(d);
913				this.dateClicked = false;
914				this.callHandler();
915			};
916		})();
917	} else {
918		this.onSetTime = this.onUpdateTime = function() {};
919	}
920
921	var tfoot = Calendar.createElement("tfoot", table);
922
923	row = Calendar.createElement("tr", tfoot);
924	row.className = "footrow";
925
926	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
927	cell.className = "ttip";
928	if (this.isPopup) {
929		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
930		cell.style.cursor = "move";
931	}
932	this.tooltips = cell;
933
934	div = Calendar.createElement("div", this.element);
935	this.monthsCombo = div;
936	div.className = "combo";
937	for (i = 0; i < Calendar._MN.length; ++i) {
938		var mn = Calendar.createElement("div");
939		mn.className = Calendar.is_ie ? "label-IEfix" : "label";
940		mn.month = i;
941		mn.appendChild(document.createTextNode(Calendar._SMN[i]));
942		div.appendChild(mn);
943	}
944
945	div = Calendar.createElement("div", this.element);
946	this.yearsCombo = div;
947	div.className = "combo";
948	for (i = 12; i > 0; --i) {
949		var yr = Calendar.createElement("div");
950		yr.className = Calendar.is_ie ? "label-IEfix" : "label";
951		yr.appendChild(document.createTextNode(""));
952		div.appendChild(yr);
953	}
954
955	this._init(this.firstDayOfWeek, this.date);
956	parent.appendChild(this.element);
957};
958
959/** keyboard navigation, only for popup calendars */
960Calendar._keyEvent = function(ev) {
961	if (!window.calendar) {
962		return false;
963	}
964	(Calendar.is_ie) && (ev = window.event);
965	var cal = window.calendar;
966	var act = (Calendar.is_ie || ev.type == "keypress");
967	if (ev.ctrlKey) {
968		switch (ev.keyCode) {
969		    case 37: // KEY left
970			act && Calendar.cellClick(cal._nav_pm);
971			break;
972		    case 38: // KEY up
973			act && Calendar.cellClick(cal._nav_py);
974			break;
975		    case 39: // KEY right
976			act && Calendar.cellClick(cal._nav_nm);
977			break;
978		    case 40: // KEY down
979			act && Calendar.cellClick(cal._nav_ny);
980			break;
981		    default:
982			return false;
983		}
984	} else switch (ev.keyCode) {
985	    case 32: // KEY space (now)
986		Calendar.cellClick(cal._nav_now);
987		break;
988	    case 27: // KEY esc
989		act && cal.callCloseHandler();
990		break;
991	    case 37: // KEY left
992	    case 38: // KEY up
993	    case 39: // KEY right
994	    case 40: // KEY down
995		if (act) {
996			var date = cal.date.getDate() - 1;
997			var el = cal.currentDateEl;
998			var ne = null;
999			var prev = (ev.keyCode == 37) || (ev.keyCode == 38);
1000			switch (ev.keyCode) {
1001			    case 37: // KEY left
1002				(--date >= 0) && (ne = cal.ar_days[date]);
1003				break;
1004			    case 38: // KEY up
1005				date -= 7;
1006				(date >= 0) && (ne = cal.ar_days[date]);
1007				break;
1008			    case 39: // KEY right
1009				(++date < cal.ar_days.length) && (ne = cal.ar_days[date]);
1010				break;
1011			    case 40: // KEY down
1012				date += 7;
1013				(date < cal.ar_days.length) && (ne = cal.ar_days[date]);
1014				break;
1015			}
1016			if (!ne) {
1017				if (prev) {
1018					Calendar.cellClick(cal._nav_pm);
1019				} else {
1020					Calendar.cellClick(cal._nav_nm);
1021				}
1022				date = (prev) ? cal.date.getMonthDays() : 1;
1023				el = cal.currentDateEl;
1024				ne = cal.ar_days[date - 1];
1025			}
1026			Calendar.removeClass(el, "selected");
1027			Calendar.addClass(ne, "selected");
1028			cal.date = new Date(ne.caldate);
1029			cal.callHandler();
1030			cal.currentDateEl = ne;
1031		}
1032		break;
1033	    case 13: // KEY enter
1034		if (act) {
1035			cal.callHandler();
1036			cal.hide();
1037		}
1038		break;
1039	    default:
1040		return false;
1041	}
1042	return Calendar.stopEvent(ev);
1043};
1044
1045/**
1046 *  (RE)Initializes the calendar to the given date and firstDayOfWeek
1047 */
1048Calendar.prototype._init = function (firstDayOfWeek, date) {
1049	var today = new Date();
1050	this.table.style.visibility = "hidden";
1051	var year = date.getFullYear();
1052	if (year < this.minYear) {
1053		year = this.minYear;
1054		date.setFullYear(year);
1055	} else if (year > this.maxYear) {
1056		year = this.maxYear;
1057		date.setFullYear(year);
1058	}
1059	this.firstDayOfWeek = firstDayOfWeek;
1060	this.date = new Date(date);
1061	var month = date.getMonth();
1062	var mday = date.getDate();
1063	var no_days = date.getMonthDays();
1064
1065	// calendar voodoo for computing the first day that would actually be
1066	// displayed in the calendar, even if it's from the previous month.
1067	// WARNING: this is magic. ;-)
1068	date.setDate(1);
1069	var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
1070	if (day1 < 0)
1071		day1 += 7;
1072	date.setDate(-day1);
1073	date.setDate(date.getDate() + 1);
1074
1075	var row = this.tbody.firstChild;
1076	var MN = Calendar._SMN[month];
1077	var ar_days = new Array();
1078	var weekend = Calendar._TT["WEEKEND"];
1079	for (var i = 0; i < 6; ++i, row = row.nextSibling) {
1080		var cell = row.firstChild;
1081		if (this.weekNumbers) {
1082			cell.className = "day wn";
1083			cell.firstChild.data = date.getWeekNumber();
1084			cell = cell.nextSibling;
1085		}
1086		row.className = "daysrow";
1087		var hasdays = false;
1088		for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(date.getDate() + 1)) {
1089			var iday = date.getDate();
1090			var wday = date.getDay();
1091			cell.className = "day";
1092			var current_month = (date.getMonth() == month);
1093			if (!current_month) {
1094				if (this.showsOtherMonths) {
1095					cell.className += " othermonth";
1096					cell.otherMonth = true;
1097				} else {
1098					cell.className = "emptycell";
1099					cell.innerHTML = "&nbsp;";
1100					cell.disabled = true;
1101					continue;
1102				}
1103			} else {
1104				cell.otherMonth = false;
1105				hasdays = true;
1106			}
1107			cell.disabled = false;
1108			cell.firstChild.data = iday;
1109			if (typeof this.getDateStatus == "function") {
1110				var status = this.getDateStatus(date, year, month, iday);
1111				if (status === true) {
1112					cell.className += " disabled";
1113					cell.disabled = true;
1114				} else {
1115					if (/disabled/i.test(status))
1116						cell.disabled = true;
1117					cell.className += " " + status;
1118				}
1119			}
1120			if (!cell.disabled) {
1121				ar_days[ar_days.length] = cell;
1122				cell.caldate = new Date(date);
1123				cell.ttip = "_";
1124				if (current_month && iday == mday) {
1125					cell.className += " selected";
1126					this.currentDateEl = cell;
1127				}
1128				if (date.getFullYear() == today.getFullYear() &&
1129				    date.getMonth() == today.getMonth() &&
1130				    iday == today.getDate()) {
1131					cell.className += " today";
1132					cell.ttip += Calendar._TT["PART_TODAY"];
1133				}
1134				if (weekend.indexOf(wday.toString()) != -1) {
1135					cell.className += cell.otherMonth ? " oweekend" : " weekend";
1136				}
1137			}
1138		}
1139		if (!(hasdays || this.showsOtherMonths))
1140			row.className = "emptyrow";
1141	}
1142	this.ar_days = ar_days;
1143	this.title.firstChild.data = Calendar._MN[month] + ", " + year;
1144	this.onSetTime();
1145	this.table.style.visibility = "visible";
1146	// PROFILE
1147	// this.tooltips.firstChild.data = "Generated in " + ((new Date()) - today) + " ms";
1148};
1149
1150/**
1151 *  Calls _init function above for going to a certain date (but only if the
1152 *  date is different than the currently selected one).
1153 */
1154Calendar.prototype.setDate = function (date) {
1155	if (!date.equalsTo(this.date)) {
1156		this._init(this.firstDayOfWeek, date);
1157	}
1158};
1159
1160/**
1161 *  Refreshes the calendar.  Useful if the "disabledHandler" function is
1162 *  dynamic, meaning that the list of disabled date can change at runtime.
1163 *  Just * call this function if you think that the list of disabled dates
1164 *  should * change.
1165 */
1166Calendar.prototype.refresh = function () {
1167	this._init(this.firstDayOfWeek, this.date);
1168};
1169
1170/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
1171Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
1172	this._init(firstDayOfWeek, this.date);
1173	this._displayWeekdays();
1174};
1175
1176/**
1177 *  Allows customization of what dates are enabled.  The "unaryFunction"
1178 *  parameter must be a function object that receives the date (as a JS Date
1179 *  object) and returns a boolean value.  If the returned value is true then
1180 *  the passed date will be marked as disabled.
1181 */
1182Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
1183	this.getDateStatus = unaryFunction;
1184};
1185
1186/** Customization of allowed year range for the calendar. */
1187Calendar.prototype.setRange = function (a, z) {
1188	this.minYear = a;
1189	this.maxYear = z;
1190};
1191
1192/** Calls the first user handler (selectedHandler). */
1193Calendar.prototype.callHandler = function () {
1194	if (this.onSelected) {
1195		this.onSelected(this, this.date.print(this.dateFormat));
1196	}
1197};
1198
1199/** Calls the second user handler (closeHandler). */
1200Calendar.prototype.callCloseHandler = function () {
1201	if (this.onClose) {
1202		this.onClose(this);
1203	}
1204	this.hideShowCovered();
1205};
1206
1207/** Removes the calendar object from the DOM tree and destroys it. */
1208Calendar.prototype.destroy = function () {
1209	var el = this.element.parentNode;
1210	el.removeChild(this.element);
1211	Calendar._C = null;
1212	window.calendar = null;
1213};
1214
1215/**
1216 *  Moves the calendar element to a different section in the DOM tree (changes
1217 *  its parent).
1218 */
1219Calendar.prototype.reparent = function (new_parent) {
1220	var el = this.element;
1221	el.parentNode.removeChild(el);
1222	new_parent.appendChild(el);
1223};
1224
1225// This gets called when the user presses a mouse button anywhere in the
1226// document, if the calendar is shown.  If the click was outside the open
1227// calendar this function closes it.
1228Calendar._checkCalendar = function(ev) {
1229	if (!window.calendar) {
1230		return false;
1231	}
1232	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
1233	for (; el != null && el != calendar.element; el = el.parentNode);
1234	if (el == null) {
1235		// calls closeHandler which should hide the calendar.
1236		window.calendar.callCloseHandler();
1237		return Calendar.stopEvent(ev);
1238	}
1239};
1240
1241/** Shows the calendar. */
1242Calendar.prototype.show = function () {
1243	var rows = this.table.getElementsByTagName("tr");
1244	for (var i = rows.length; i > 0;) {
1245		var row = rows[--i];
1246		Calendar.removeClass(row, "rowhilite");
1247		var cells = row.getElementsByTagName("td");
1248		for (var j = cells.length; j > 0;) {
1249			var cell = cells[--j];
1250			Calendar.removeClass(cell, "hilite");
1251			Calendar.removeClass(cell, "active");
1252		}
1253	}
1254	this.element.style.display = "block";
1255	this.hidden = false;
1256	if (this.isPopup) {
1257		window.calendar = this;
1258		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
1259		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
1260		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
1261	}
1262	this.hideShowCovered();
1263};
1264
1265/**
1266 *  Hides the calendar.  Also removes any "hilite" from the class of any TD
1267 *  element.
1268 */
1269Calendar.prototype.hide = function () {
1270	if (this.isPopup) {
1271		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
1272		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
1273		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
1274	}
1275	this.element.style.display = "none";
1276	this.hidden = true;
1277	this.hideShowCovered();
1278};
1279
1280/**
1281 *  Shows the calendar at a given absolute position (beware that, depending on
1282 *  the calendar element style -- position property -- this might be relative
1283 *  to the parent's containing rectangle).
1284 */
1285Calendar.prototype.showAt = function (x, y) {
1286	var s = this.element.style;
1287	s.left = x + "px";
1288	s.top = y + "px";
1289	this.show();
1290};
1291
1292/** Shows the calendar near a given element. */
1293Calendar.prototype.showAtElement = function (el, opts) {
1294	var self = this;
1295	var p = Calendar.getAbsolutePos(el);
1296	if (!opts || typeof opts != "string") {
1297		this.showAt(p.x, p.y + el.offsetHeight);
1298		return true;
1299	}
1300	function fixPosition(box) {
1301		if (box.x < 0)
1302			box.x = 0;
1303		if (box.y < 0)
1304			box.y = 0;
1305		var cp = document.createElement("div");
1306		var s = cp.style;
1307		s.position = "absolute";
1308		s.right = s.bottom = s.width = s.height = "0px";
1309		document.body.appendChild(cp);
1310		var br = Calendar.getAbsolutePos(cp);
1311		document.body.removeChild(cp);
1312		if (Calendar.is_ie) {
1313			br.y += document.body.scrollTop;
1314			br.x += document.body.scrollLeft;
1315		} else {
1316			br.y += window.scrollY;
1317			br.x += window.scrollX;
1318		}
1319		var tmp = box.x + box.width - br.x;
1320		if (tmp > 0) box.x -= tmp;
1321		tmp = box.y + box.height - br.y;
1322		if (tmp > 0) box.y -= tmp;
1323	};
1324	this.element.style.display = "block";
1325	Calendar.continuation_for_the_fucking_khtml_browser = function() {
1326		var w = self.element.offsetWidth;
1327		var h = self.element.offsetHeight;
1328		self.element.style.display = "none";
1329		var valign = opts.substr(0, 1);
1330		var halign = "l";
1331		if (opts.length > 1) {
1332			halign = opts.substr(1, 1);
1333		}
1334		// vertical alignment
1335		switch (valign) {
1336		    case "T": p.y -= h; break;
1337		    case "B": p.y += el.offsetHeight; break;
1338		    case "C": p.y += (el.offsetHeight - h) / 2; break;
1339		    case "t": p.y += el.offsetHeight - h; break;
1340		    case "b": break; // already there
1341		}
1342		// horizontal alignment
1343		switch (halign) {
1344		    case "L": p.x -= w; break;
1345		    case "R": p.x += el.offsetWidth; break;
1346		    case "C": p.x += (el.offsetWidth - w) / 2; break;
1347		    case "r": p.x += el.offsetWidth - w; break;
1348		    case "l": break; // already there
1349		}
1350		p.width = w;
1351		p.height = h + 40;
1352		self.monthsCombo.style.display = "none";
1353		fixPosition(p);
1354		self.showAt(p.x, p.y);
1355	};
1356	if (Calendar.is_khtml)
1357		setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
1358	else
1359		Calendar.continuation_for_the_fucking_khtml_browser();
1360};
1361
1362/** Customizes the date format. */
1363Calendar.prototype.setDateFormat = function (str) {
1364	this.dateFormat = str;
1365};
1366
1367/** Customizes the tooltip date format. */
1368Calendar.prototype.setTtDateFormat = function (str) {
1369	this.ttDateFormat = str;
1370};
1371
1372/**
1373 *  Tries to identify the date represented in a string.  If successful it also
1374 *  calls this.setDate which moves the calendar to the given date.
1375 */
1376Calendar.prototype.parseDate = function (str, fmt) {
1377	var y = 0;
1378	var m = -1;
1379	var d = 0;
1380	var a = str.split(/\W+/);
1381	if (!fmt) {
1382		fmt = this.dateFormat;
1383	}
1384	var b = fmt.match(/%./g);
1385	var i = 0, j = 0;
1386	var hr = 0;
1387	var min = 0;
1388	for (i = 0; i < a.length; ++i) {
1389		if (!a[i])
1390			continue;
1391		switch (b[i]) {
1392		    case "%d":
1393		    case "%e":
1394			d = parseInt(a[i], 10);
1395			break;
1396
1397		    case "%m":
1398			m = parseInt(a[i], 10) - 1;
1399			break;
1400
1401		    case "%Y":
1402		    case "%y":
1403			y = parseInt(a[i], 10);
1404			(y < 100) && (y += (y > 29) ? 1900 : 2000);
1405			break;
1406
1407		    case "%b":
1408		    case "%B":
1409			for (j = 0; j < 12; ++j) {
1410				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
1411			}
1412			break;
1413
1414		    case "%H":
1415		    case "%I":
1416		    case "%k":
1417		    case "%l":
1418			hr = parseInt(a[i], 10);
1419			break;
1420
1421		    case "%P":
1422		    case "%p":
1423			if (/pm/i.test(a[i]) && hr < 12)
1424				hr += 12;
1425			break;
1426
1427		    case "%M":
1428			min = parseInt(a[i], 10);
1429			break;
1430		}
1431	}
1432	if (y != 0 && m != -1 && d != 0) {
1433		this.setDate(new Date(y, m, d, hr, min, 0));
1434		return;
1435	}
1436	y = 0; m = -1; d = 0;
1437	for (i = 0; i < a.length; ++i) {
1438		if (a[i].search(/[a-zA-Z]+/) != -1) {
1439			var t = -1;
1440			for (j = 0; j < 12; ++j) {
1441				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
1442			}
1443			if (t != -1) {
1444				if (m != -1) {
1445					d = m+1;
1446				}
1447				m = t;
1448			}
1449		} else if (parseInt(a[i], 10) <= 12 && m == -1) {
1450			m = a[i]-1;
1451		} else if (parseInt(a[i], 10) > 31 && y == 0) {
1452			y = parseInt(a[i], 10);
1453			(y < 100) && (y += (y > 29) ? 1900 : 2000);
1454		} else if (d == 0) {
1455			d = a[i];
1456		}
1457	}
1458	if (y == 0) {
1459		var today = new Date();
1460		y = today.getFullYear();
1461	}
1462	if (m != -1 && d != 0) {
1463		this.setDate(new Date(y, m, d, hr, min, 0));
1464	}
1465};
1466
1467Calendar.prototype.hideShowCovered = function () {
1468	var self = this;
1469	Calendar.continuation_for_the_fucking_khtml_browser = function() {
1470		function getVisib(obj){
1471			var value = obj.style.visibility;
1472			if (!value) {
1473				if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
1474					if (!Calendar.is_khtml)
1475						value = document.defaultView.
1476							getComputedStyle(obj, "").getPropertyValue("visibility");
1477					else
1478						value = '';
1479				} else if (obj.currentStyle) { // IE
1480					value = obj.currentStyle.visibility;
1481				} else
1482					value = '';
1483			}
1484			return value;
1485		};
1486
1487		var tags = new Array("applet", "iframe", "select");
1488		var el = self.element;
1489
1490		var p = Calendar.getAbsolutePos(el);
1491		var EX1 = p.x;
1492		var EX2 = el.offsetWidth + EX1;
1493		var EY1 = p.y;
1494		var EY2 = el.offsetHeight + EY1;
1495
1496		for (var k = tags.length; k > 0; ) {
1497			var ar = document.getElementsByTagName(tags[--k]);
1498			var cc = null;
1499
1500			for (var i = ar.length; i > 0;) {
1501				cc = ar[--i];
1502
1503				p = Calendar.getAbsolutePos(cc);
1504				var CX1 = p.x;
1505				var CX2 = cc.offsetWidth + CX1;
1506				var CY1 = p.y;
1507				var CY2 = cc.offsetHeight + CY1;
1508
1509				if (self.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
1510					if (!cc.__msh_save_visibility) {
1511						cc.__msh_save_visibility = getVisib(cc);
1512					}
1513					cc.style.visibility = cc.__msh_save_visibility;
1514				} else {
1515					if (!cc.__msh_save_visibility) {
1516						cc.__msh_save_visibility = getVisib(cc);
1517					}
1518					cc.style.visibility = "hidden";
1519				}
1520			}
1521		}
1522	};
1523	if (Calendar.is_khtml)
1524		setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
1525	else
1526		Calendar.continuation_for_the_fucking_khtml_browser();
1527};
1528
1529/** Internal function; it displays the bar with the names of the weekday. */
1530Calendar.prototype._displayWeekdays = function () {
1531	var fdow = this.firstDayOfWeek;
1532	var cell = this.firstdayname;
1533	var weekend = Calendar._TT["WEEKEND"];
1534	for (var i = 0; i < 7; ++i) {
1535		cell.className = "day name";
1536		var realday = (i + fdow) % 7;
1537		if (i) {
1538			cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
1539			cell.navtype = 100;
1540			cell.calendar = this;
1541			cell.fdow = realday;
1542			Calendar._add_evs(cell);
1543		}
1544		if (weekend.indexOf(realday.toString()) != -1) {
1545			Calendar.addClass(cell, "weekend");
1546		}
1547		cell.firstChild.data = Calendar._SDN[(i + fdow) % 7];
1548		cell = cell.nextSibling;
1549	}
1550};
1551
1552/** Internal function.  Hides all combo boxes that might be displayed. */
1553Calendar.prototype._hideCombos = function () {
1554	this.monthsCombo.style.display = "none";
1555	this.yearsCombo.style.display = "none";
1556};
1557
1558/** Internal function.  Starts dragging the element. */
1559Calendar.prototype._dragStart = function (ev) {
1560	if (this.dragging) {
1561		return;
1562	}
1563	this.dragging = true;
1564	var posX;
1565	var posY;
1566	if (Calendar.is_ie) {
1567		posY = window.event.clientY + document.body.scrollTop;
1568		posX = window.event.clientX + document.body.scrollLeft;
1569	} else {
1570		posY = ev.clientY + window.scrollY;
1571		posX = ev.clientX + window.scrollX;
1572	}
1573	var st = this.element.style;
1574	this.xOffs = posX - parseInt(st.left);
1575	this.yOffs = posY - parseInt(st.top);
1576	with (Calendar) {
1577		addEvent(document, "mousemove", calDragIt);
1578		addEvent(document, "mouseup", calDragEnd);
1579	}
1580};
1581
1582// BEGIN: DATE OBJECT PATCHES
1583
1584/** Adds the number of days array to the Date object. */
1585Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
1586
1587/** Constants used for time computations */
1588Date.SECOND = 1000 /* milliseconds */;
1589Date.MINUTE = 60 * Date.SECOND;
1590Date.HOUR   = 60 * Date.MINUTE;
1591Date.DAY    = 24 * Date.HOUR;
1592Date.WEEK   =  7 * Date.DAY;
1593
1594/** Returns the number of days in the current month */
1595Date.prototype.getMonthDays = function(month) {
1596	var year = this.getFullYear();
1597	if (typeof month == "undefined") {
1598		month = this.getMonth();
1599	}
1600	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
1601		return 29;
1602	} else {
1603		return Date._MD[month];
1604	}
1605};
1606
1607/** Returns the number of day in the year. */
1608Date.prototype.getDayOfYear = function() {
1609	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
1610	var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
1611	var time = now - then;
1612	return Math.floor(time / Date.DAY);
1613};
1614
1615/** Returns the number of the week in year, as defined in ISO 8601. */
1616Date.prototype.getWeekNumber = function() {
1617	var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
1618	var DoW = d.getDay();
1619	d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
1620	var ms = d.valueOf(); // GMT
1621	d.setMonth(0);
1622	d.setDate(4); // Thu in Week 1
1623	return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
1624};
1625
1626/** Checks dates equality (ignores time) */
1627Date.prototype.equalsTo = function(date) {
1628	return ((this.getFullYear() == date.getFullYear()) &&
1629		(this.getMonth() == date.getMonth()) &&
1630		(this.getDate() == date.getDate()) &&
1631		(this.getHours() == date.getHours()) &&
1632		(this.getMinutes() == date.getMinutes()));
1633};
1634
1635/** Prints the date in a string according to the given format. */
1636Date.prototype.print = function (str) {
1637	var m = this.getMonth();
1638	var d = this.getDate();
1639	var y = this.getFullYear();
1640	var wn = this.getWeekNumber();
1641	var w = this.getDay();
1642	var s = {};
1643	var hr = this.getHours();
1644	var pm = (hr >= 12);
1645	var ir = (pm) ? (hr - 12) : hr;
1646	var dy = this.getDayOfYear();
1647	if (ir == 0)
1648		ir = 12;
1649	var min = this.getMinutes();
1650	var sec = this.getSeconds();
1651	s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
1652	s["%A"] = Calendar._DN[w]; // full weekday name
1653	s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
1654	s["%B"] = Calendar._MN[m]; // full month name
1655	// FIXME: %c : preferred date and time representation for the current locale
1656	s["%C"] = 1 + Math.floor(y / 100); // the century number
1657	s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
1658	s["%e"] = d; // the day of the month (range 1 to 31)
1659	// FIXME: %D : american date style: %m/%d/%y
1660	// FIXME: %E, %F, %G, %g, %h (man strftime)
1661	s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
1662	s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
1663	s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
1664	s["%k"] = hr;		// hour, range 0 to 23 (24h format)
1665	s["%l"] = ir;		// hour, range 1 to 12 (12h format)
1666	s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
1667	s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
1668	s["%n"] = "\n";		// a newline character
1669	s["%p"] = pm ? "PM" : "AM";
1670	s["%P"] = pm ? "pm" : "am";
1671	// FIXME: %r : the time in am/pm notation %I:%M:%S %p
1672	// FIXME: %R : the time in 24-hour notation %H:%M
1673	s["%s"] = Math.floor(this.getTime() / 1000);
1674	s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
1675	s["%t"] = "\t";		// a tab character
1676	// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
1677	s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
1678	s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
1679	s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
1680	// FIXME: %x : preferred date representation for the current locale without the time
1681	// FIXME: %X : preferred time representation for the current locale without the date
1682	s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
1683	s["%Y"] = y;		// year with the century
1684	s["%%"] = "%";		// a literal '%' character
1685
1686	var re = /%./g;
1687	if (!Calendar.is_ie5)
1688		return str.replace(re, function (par) { return s[par] || par; });
1689
1690	var a = str.match(re);
1691	for (var i = 0; i < a.length; i++) {
1692		var tmp = s[a[i]];
1693		if (tmp) {
1694			re = new RegExp(a[i], 'g');
1695			str = str.replace(re, tmp);
1696		}
1697	}
1698
1699	return str;
1700};
1701
1702Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
1703Date.prototype.setFullYear = function(y) {
1704	var d = new Date(this);
1705	d.__msh_oldSetFullYear(y);
1706	if (d.getMonth() != this.getMonth())
1707		this.setDate(28);
1708	this.__msh_oldSetFullYear(y);
1709};
1710
1711// END: DATE OBJECT PATCHES
1712
1713
1714// global object that remembers the calendar
1715window.calendar = null;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.