[ PHPXref.com ] [ Generated: Sun Jul 20 17:59:13 2008 ] [ GLPI 0.65 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/calendar/ -> calendar.js (source)

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


[ Powered by PHPXref - Served by Debian GNU/Linux ]