annotate public/javascripts/calendar/calendar.js @ 8:0c83d98252d9 yuya

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