source: branches/2.2/phpgwapi/js/jscalendar/calendar.js @ 3740

Revision 3740, 49.6 KB checked in by niltonneto, 13 years ago (diff)

Ticket #1531 - Corrigido problema ao selecionar data no mini-calendário.

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