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