PageSourceSearch

http://www.avezzanoinforma.it/js/jsCalendar/calendar.js

js avezzanoinforma.it collected 2026-10-02 21:57:44 UTC 59,857 bytes, 1,844 lines download raw bytes

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