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