1// 2// CalendarView (for Prototype) 3// calendarview.org 4// 5// Maintained by Justin Mecham <[email protected]> 6// 7// Portions Copyright 2002-2005 Mihai Bazon 8// 9// This calendar is based very loosely on the Dynarch Calendar in that it was 10// used as a base, but completely gutted and more or less rewritten in place 11// to use the Prototype JavaScript library. 12// 13// As such, CalendarView is licensed under the terms of the GNU Lesser General 14// Public License (LGPL). More information on the Dynarch Calendar can be 15// found at: 16// 17// www.dynarch.com/projects/calendar 18// 19 20var Calendar = Class.create(); 21 22//------------------------------------------------------------------------------ 23// Constants 24//------------------------------------------------------------------------------ 25 26Calendar.VERSION = '1.2'; 27 28Calendar.DAY_NAMES = [ 29 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 30 'Sunday' 31]; 32 33Calendar.SHORT_DAY_NAMES = [ 34 'S', 'M', 'T', 'W', 'T', 'F', 'S', 'S' 35]; 36 37Calendar.MONTH_NAMES = [ 38 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 39 'September', 'October', 'November', 'December' 40]; 41 42Calendar.TODAY = "Today"; 43 44Calendar.SHORT_MONTH_NAMES = [ 45 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 46 'Dec' 47]; 48 49Calendar.NAV_PREVIOUS_YEAR = -2; 50Calendar.NAV_PREVIOUS_MONTH = -1; 51Calendar.NAV_TODAY = 0; 52Calendar.NAV_NEXT_MONTH = 1; 53Calendar.NAV_NEXT_YEAR = 2; 54 55//------------------------------------------------------------------------------ 56// Static Methods 57//------------------------------------------------------------------------------ 58 59// This gets called when the user presses a mouse button anywhere in the 60// document, if the calendar is shown. If the click was outside the open 61// calendar this function closes it. 62Calendar._checkCalendar = function(event) { 63 if (!window._popupCalendar){ 64 return false; 65 } 66 if (Element.descendantOf(Event.element(event), window._popupCalendar.container)){ 67 return; 68 } 69 window._popupCalendar.callCloseHandler(); 70 return Event.stop(event); 71}; 72 73//------------------------------------------------------------------------------ 74// Event Handlers 75//------------------------------------------------------------------------------ 76 77Calendar.handleMouseDownEvent = function(event) 78{ 79 Event.observe(document, 'mouseup', Calendar.handleMouseUpEvent); 80 Event.stop(event); 81}; 82 83// XXX I am not happy with how clicks of different actions are handled. Need to 84// clean this up! 85Calendar.handleMouseUpEvent = function(event) 86{ 87 var el = Event.element(event); 88 var calendar = el.calendar; 89 var isNewDate = false; 90 calendar.shouldClose = false; 91 92 // If the element that was clicked on does not have an associated Calendar 93 // object, return as we have nothing to do. 94 if (!calendar) { 95 return false; 96 } 97 98 // Clicked on a day 99 if (typeof el.navAction == 'undefined') 100 { 101 if (calendar.currentDateElement) { 102 Element.removeClassName(calendar.currentDateElement, 'selected'); 103 Element.addClassName(el, 'selected'); 104 calendar.shouldClose = (calendar.currentDateElement == el); 105 if (!calendar.shouldClose) { 106 calendar.currentDateElement = el; 107 } 108 } 109 calendar.date.setDateOnly(el.date); 110 isNewDate = true; 111 calendar.shouldClose = !el.hasClassName('otherDay'); 112 var isOtherMonth = !calendar.shouldClose; 113 if (isOtherMonth) { 114 calendar.update(calendar.date); 115 } 116 } 117 118 // Clicked on an action button 119 else 120 { 121 var date = new Date(calendar.date); 122 123 if (el.navAction == Calendar.NAV_TODAY){ 124 date.setDateOnly(new Date()); 125 } 126 127 var year = date.getFullYear(); 128 var mon = date.getMonth(); 129 function setMonth(m) { 130 var day = date.getDate(); 131 var max = date.getMonthDays(m); 132 if (day > max) { 133 date.setDate(max); 134 } 135 date.setMonth(m); 136 } 137 switch (el.navAction) { 138 139 // Previous Year 140 case Calendar.NAV_PREVIOUS_YEAR: 141 if (year > calendar.minYear){ 142 date.setFullYear(year - 1); 143 } 144 break; 145 146 // Previous Month 147 case Calendar.NAV_PREVIOUS_MONTH: 148 if (mon > 0) { 149 setMonth(mon - 1); 150 } 151 else if (year-- > calendar.minYear) { 152 date.setFullYear(year); 153 setMonth(11); 154 } 155 break; 156 157 // Today 158 case Calendar.NAV_TODAY: 159 break; 160 161 // Next Month 162 case Calendar.NAV_NEXT_MONTH: 163 if (mon < 11) { 164 setMonth(mon + 1); 165 } 166 else if (year < calendar.maxYear) { 167 date.setFullYear(year + 1); 168 setMonth(0); 169 } 170 break; 171 172 // Next Year 173 case Calendar.NAV_NEXT_YEAR: 174 if (year < calendar.maxYear){ 175 date.setFullYear(year + 1); 176 } 177 break; 178 179 } 180 181 if (!date.equalsTo(calendar.date)) { 182 calendar.setDate(date); 183 isNewDate = true; 184 } else if (el.navAction === 0) { 185 isNewDate = (calendar.shouldClose = true); 186 } 187 } 188 189 if (isNewDate) { 190 event && calendar.callSelectHandler(); 191 } 192 if (calendar.shouldClose) { 193 event && calendar.callCloseHandler(); 194 } 195 196 Event.stopObserving(document, 'mouseup', Calendar.handleMouseUpEvent); 197 198 return Event.stop(event); 199}; 200 201Calendar.defaultSelectHandler = function(calendar) 202{ 203 if (!calendar.dateField) { 204 return false;
205 } 206 207 // Update dateField value 208 if (calendar.dateField.tagName == 'DIV') { 209 Element.update(calendar.dateField, calendar.date.print(calendar.dateFormat)); 210 } else if (calendar.dateField.tagName == 'INPUT') { 211 calendar.dateField.value = calendar.date.print(calendar.dateFormat); 212 } 213 214 // Trigger the onchange callback on the dateField, if one has been defined 215 if (typeof calendar.dateField.onchange == 'function'){ 216 calendar.dateField.onchange(); 217 } 218 219 // Call the close handler, if necessary 220 if (calendar.shouldClose) { 221 calendar.callCloseHandler(); 222 } 223}; 224 225Calendar.defaultCloseHandler = function(calendar) 226{ 227 calendar.hide(); 228}; 229 230 231//------------------------------------------------------------------------------ 232// Calendar Setup 233//------------------------------------------------------------------------------ 234 235Calendar.setup = function(params) 236{ 237 238 Calendar.MONTH_NAMES = JotForm.calendarMonths || Calendar.MONTH_NAMES; 239 Calendar.DAY_NAMES = JotForm.calendarDays || Calendar.DAY_NAMES; 240 if(JotForm.calendarOther && JotForm.calendarOther.today) { 241 Calendar.TODAY = JotForm.calendarOther.today; 242 } 243 244 245 for(var i=0; i<=7; i++) { 246 Calendar.SHORT_DAY_NAMES[i] = Calendar.DAY_NAMES[i].substring(0,1).toUpperCase(); 247 } 248 249 function param_default(name, def) { 250 if (!params[name]) { 251 params[name] = def; 252 } 253 } 254 255 param_default('dateField', null); 256 param_default('triggerElement', null); 257 param_default('parentElement', null); 258 param_default('selectHandler', null); 259 param_default('closeHandler', null); 260 261 // In-Page Calendar 262 if (params.parentElement) 263 { 264 var calendar = new Calendar(params.parentElement); 265 calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler); 266 if (params.dateFormat){ 267 calendar.setDateFormat(params.dateFormat); 268 } 269 if (params.dateField) { 270 calendar.setDateField(params.dateField); 271 calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value); 272 } 273 calendar.show(); 274 return calendar; 275 } 276 277 // Popup Calendars 278 // 279 // XXX There is significant optimization to be had here by creating the 280 // calendar and storing it on the page, but then you will have issues with 281 // multiple calendars on the same page. 282 else 283 { 284 var triggerElement = $(params.triggerElement || params.dateField); 285 var calendar = new Calendar(); 286 calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler); 287 calendar.setCloseHandler(params.closeHandler || Calendar.defaultCloseHandler); 288 calendar.startOnMonday = params.startOnMonday; 289 if (params.dateFormat){ 290 calendar.setDateFormat(params.dateFormat); 291 } 292 if (params.dateField) { 293 calendar.setDateField(params.dateField); 294 calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value); 295 } 296 if (params.dateField){ 297 Date.parseDate(calendar.dateField.value || calendar.dateField.innerHTML, calendar.dateFormat); 298 } 299 triggerElement.onclick = function() { 300 calendar.showAtElement(triggerElement); 301 return calendar; 302 }; 303 if(calendar.startOnMonday) { 304 calendar.update(new Date()); 305 calendar.create(); 306 } 307 return calendar; 308 } 309 310}; 311 312 313 314//------------------------------------------------------------------------------ 315// Calendar Instance 316//------------------------------------------------------------------------------ 317 318Calendar.prototype = { 319 320 // The HTML Container Element 321 container: null, 322 323 // Callbacks 324 selectHandler: null, 325 closeHandler: null, 326 327 // Configuration 328 minYear: 1900, 329 maxYear: 2100, 330 dateFormat: '%Y-%m-%d', 331 332 // Dates 333 date: new Date(), 334 currentDateElement: null, 335 336 // Status 337 shouldClose: false, 338 isPopup: true, 339 340 dateField: null, 341 342 startOnMonday: false, 343 344 345 //---------------------------------------------------------------------------- 346 // Initialize 347 //---------------------------------------------------------------------------- 348 349 initialize: function(parent) 350 { 351 if (parent){ 352 this.create($(parent)); 353 } 354 else{ 355 this.create(); 356 } 357 }, 358 359 360 361 //---------------------------------------------------------------------------- 362 // Update / (Re)initialize Calendar 363 //---------------------------------------------------------------------------- 364 365 update: function(date) 366 { 367 var calendar = this; 368 var today = new Date(); 369 var thisYear = today.getFullYear(); 370 var thisMonth = today.getMonth(); 371 var thisDay = today.getDate(); 372 var month = date.getMonth(); 373 var dayOfMonth = date.getDate(); 374 375 // Ensure date is within the defined range 376 if (date.getFullYear() < this.minYear){ 377 date.setFullYear(this.minYear); 378 } 379 else if (date.getFullYear() > this.maxYear){ 380 date.setFullYear(this.maxYear); 381 } 382 383 this.date = new Date(date); 384 385 // Calculate the first day to display (including the previous month) 386 date.setDate(1); 387 if(calendar.startOnMonday) { 388 date.setDate(-(date.getDay()) - 5); 389 } else { 390 date.setDate(-(date.getDay()) + 1); 391 } 392 393 394 // Fill in the days of the month 395 Element.getElementsBySelector(this.container, 'tbody tr').each( 396 function(row, i) { 397 var rowHasDays = false;
398 row.immediateDescendants().each( 399 function(cell, j) { 400 var day = date.getDate(); 401 var dayOfWeek = date.getDay(); 402 var isCurrentMonth = (date.getMonth() == month); 403 404 // Reset classes on the cell 405 cell.className = ''; 406 cell.date = new Date(date); 407 cell.update(day); 408 409 // Account for days of the month other than the current month 410 if (!isCurrentMonth){ 411 cell.addClassName('otherDay'); 412 } 413 else{ 414 rowHasDays = true; 415 } 416 417 // Ensure the current day is selected 418 if (isCurrentMonth && day == dayOfMonth) { 419 cell.addClassName('selected'); 420 calendar.currentDateElement = cell; 421 } 422 423 // Today 424 if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay){ 425 cell.addClassName('today'); 426 } 427 428 // Weekend 429 if ([0, 6].indexOf(dayOfWeek) != -1){ 430 cell.addClassName('weekend'); 431 } 432 433 // Set the date to tommorrow 434 date.setDate(day + 1); 435 } 436 ); 437 // Hide the extra row if it contains only days from another month 438 rowHasDays ? row.show() : row.hide(); 439 } 440 ); 441 442 this.container.getElementsBySelector('td.title')[0].update( 443 Calendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear() 444 ); 445 }, 446 447 448 449 //---------------------------------------------------------------------------- 450 // Create/Draw the Calendar HTML Elements 451 //---------------------------------------------------------------------------- 452 453 create: function(parent) 454 { 455 456 // If no parent was specified, assume that we are creating a popup calendar. 457 if (!parent) { 458 parent = document.getElementsByTagName('body')[0]; 459 this.isPopup = true; 460 } else { 461 this.isPopup = false; 462 } 463 464 // Calendar Table 465 var table = new Element('table'); 466 467 // Calendar Header 468 var thead = new Element('thead'); 469 table.appendChild(thead); 470 471 // Title Placeholder 472 var row = new Element('tr'); 473 var cell = new Element('td', { colSpan: 7 } ); 474 cell.addClassName('title'); 475 row.appendChild(cell); 476 thead.appendChild(row); 477 478 // Calendar Navigation 479 row = new Element('tr'); 480 this._drawButtonCell(row, '«', 1, Calendar.NAV_PREVIOUS_YEAR); 481 this._drawButtonCell(row, '‹', 1, Calendar.NAV_PREVIOUS_MONTH); 482 this._drawButtonCell(row, Calendar.TODAY, 3, Calendar.NAV_TODAY); 483 this._drawButtonCell(row, '›', 1, Calendar.NAV_NEXT_MONTH); 484 this._drawButtonCell(row, '»', 1, Calendar.NAV_NEXT_YEAR); 485 thead.appendChild(row); 486 487 // Day Names
488 row = new Element('tr'); 489 490 var startDay = (this.startOnMonday)?1:0; 491 var endDay = (this.startOnMonday)?7:6; 492 493 for (var i = startDay; i <= endDay; ++i) { 494 cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[i]); 495 if (i === 0 || i == 6){ 496 cell.addClassName('weekend'); 497 } 498 row.appendChild(cell); 499 } 500 thead.appendChild(row); 501 502 // Calendar Days 503 var tbody = table.appendChild(new Element('tbody')); 504 for (i = 7; i > 0; --i) { 505 row = tbody.appendChild(new Element('tr')); 506 row.addClassName('days'); 507 for (var j = 7; j > 0; --j) { 508 cell = row.appendChild(new Element('td')); 509 cell.calendar = this; 510 } 511 } 512 513 // Calendar Container (div) 514 this.container = new Element('div'); 515 this.container.addClassName('calendar'); 516 if (this.isPopup) { 517 this.container.setStyle({ position: 'absolute', display: 'none' }); 518 this.container.addClassName('popup'); 519 } 520 this.container.appendChild(table); 521 522 // Initialize Calendar 523 this.update(this.date); 524 525 // Observe the container for mousedown events 526 Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent); 527 528 // Append to parent element 529 parent.appendChild(this.container); 530 531 }, 532 533 _drawButtonCell: function(parent, text, colSpan, navAction) 534 { 535 var cell = new Element('td'); 536 if (colSpan > 1) { 537 cell.colSpan = colSpan; 538 } 539 cell.className = 'button'; 540 cell.calendar = this; 541 cell.navAction = navAction; 542 cell.innerHTML = text; 543 cell.unselectable = 'on'; // IE 544 parent.appendChild(cell); 545 return cell; 546 }, 547 548 549 550 //------------------------------------------------------------------------------ 551 // Callbacks 552 //------------------------------------------------------------------------------ 553 554 // Calls the Select Handler (if defined) 555 callSelectHandler: function() 556 { 557 if (this.selectHandler){ 558 this.selectHandler(this, this.date.print(this.dateFormat)); 559 } 560 }, 561 562 // Calls the Close Handler (if defined) 563 callCloseHandler: function() 564 { 565 if (this.closeHandler){ 566 this.closeHandler(this); 567 } 568 }, 569 570 571 572 //------------------------------------------------------------------------------ 573 // Calendar Display Functions 574 //------------------------------------------------------------------------------ 575 576 // Shows the Calendar 577 show: function() 578 { 579 this.container.show(); 580 if (this.isPopup) { 581 window._popupCalendar = this; 582 Event.observe(document, 'mousedown', Calendar._checkCalendar); 583 } 584 }, 585 586 // Shows the calendar at the given absolute position 587 showAt: function (x, y) 588 { 589 this.container.setStyle({ left: x + 'px', top: y + 'px' }); 590 this.show(); 591 }, 592 593 // Shows the Calendar at the coordinates of the provided element 594 showAtElement: function(element) 595 { 596 var firstElement = element.up('div').down('input'); 597 598 if(firstElement.up('div').visible() === false){ 599 firstElement = element; 600 } 601 602 var firstPos = Position.cumulativeOffset(firstElement); 603 var x = firstPos[0] + 40; 604 var y = firstPos[1] + 100 + firstElement.getHeight(); 605 606 if(element.id.match(/_pick$/)) { 607 var elPos = Position.cumulativeOffset(element); 608 var elX = elPos[0] - 140; 609 if(elX > x) x = elX; 610 y = elPos[1] + 100 + element.getHeight(); 611 } 612 this.showAt(x, y); 613 }, 614 615 // Hides the Calendar 616 hide: function() 617 { 618 if (this.isPopup){ 619 Event.stopObserving(document, 'mousedown', Calendar._checkCalendar); 620 } 621 this.container.hide(); 622 }, 623 624 625 626 //------------------------------------------------------------------------------ 627 // Miscellaneous 628 //------------------------------------------------------------------------------ 629 630 // Tries to identify the date represented in a string. If successful it also 631 // calls this.setDate which moves the calendar to the given date. 632 parseDate: function(str, format) 633 { 634 if (!format){ 635 format = this.dateFormat; 636 } 637 this.setDate(Date.parseDate(str, format)); 638 }, 639 640 641 642 //------------------------------------------------------------------------------ 643 // Getters/Setters 644 //------------------------------------------------------------------------------ 645 646 setSelectHandler: function(selectHandler) 647 { 648 this.selectHandler = selectHandler; 649 }, 650 651 setCloseHandler: function(closeHandler) 652 { 653 this.closeHandler = closeHandler; 654 }, 655 656 setDate: function(date) 657 { 658 if (!date.equalsTo(this.date)){ 659 this.update(date); 660 } 661 }, 662 663 setDateFormat: function(format) 664 { 665 this.dateFormat = format; 666 }, 667 668 setDateField: function(field) 669 { 670 this.dateField = $(field); 671 }, 672 673 setRange: function(minYear, maxYear) 674 { 675 this.minYear = minYear; 676 this.maxYear = maxYear; 677 } 678 679}; 680 681// global object that remembers the calendar 682window._popupCalendar = null; 683 684//============================================================================== 685// 686// Date Object Patches 687// 688// This is pretty much untouched from the original. I really would like to get 689// rid of these patches if at all possible and find a cleaner way of 690// accomplishing the same things. It's a shame Prototype doesn't extend Date at 691// all. 692// 693//============================================================================== 694 695Date.DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 696Date.SECOND = 1000; /* milliseconds */ 697Date.MINUTE = 60 * Date.SECOND; 698Date.HOUR = 60 * Date.MINUTE; 699Date.DAY = 24 * Date.HOUR;
700Date.WEEK = 7 * Date.DAY; 701 702// Parses Date 703Date.parseDate = function(str, fmt) { 704 var today = new Date(); 705 var y = 0; 706 var m = -1; 707 var d = 0; 708 var a = str.split(/\W+/); 709 var b = fmt.match(/%./g); 710 var i = 0, j = 0; 711 var hr = 0; 712 var min = 0; 713 714 for (i = 0; i < a.length; ++i) { 715 if (!a[i]) { 716 continue; 717 } 718 switch (b[i]) { 719 case "%d": 720 case "%e": 721 d = parseInt(a[i], 10); 722 break; 723 case "%m": 724 m = parseInt(a[i], 10) - 1; 725 break; 726 case "%Y": 727 case "%y": 728 y = parseInt(a[i], 10); 729 (y < 100) && (y += (y > 29) ? 1900 : 2000); 730 break; 731 case "%b": 732 case "%B": 733 for (j = 0; j < 12; ++j) { 734 if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { 735 m = j; 736 break; 737 } 738 } 739 break; 740 case "%H": 741 case "%I": 742 case "%k": 743 case "%l": 744 hr = parseInt(a[i], 10); 745 break; 746 case "%P": 747 case "%p": 748 if (/pm/i.test(a[i]) && hr < 12){ 749 hr += 12; 750 } 751 else if (/am/i.test(a[i]) && hr >= 12){ 752 hr -= 12; 753 } 754 break; 755 case "%M": 756 min = parseInt(a[i], 10); 757 break; 758 } 759 } 760 if (isNaN(y)) { 761 y = today.getFullYear(); 762 } 763 if (isNaN(m)) { 764 m = today.getMonth(); 765 } 766 if (isNaN(d)) { 767 d = today.getDate(); 768 } 769 if (isNaN(hr)) { 770 hr = today.getHours(); 771 } 772 if (isNaN(min)) { 773 min = today.getMinutes(); 774 } 775 if (y != 0 && m != -1 && d != 0){ 776 return new Date(y, m, d, hr, min, 0); 777 } 778 y = 0; m = -1; d = 0; 779 for (i = 0; i < a.length; ++i) { 780 if (a[i].search(/[a-zA-Z]+/) != -1) { 781 var t = -1; 782 for (j = 0; j < 12; ++j) { 783 if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } 784 } 785 if (t != -1) { 786 if (m != -1) { 787 d = m+1; 788 } 789 m = t; 790 } 791 } else if (parseInt(a[i], 10) <= 12 && m == -1) { 792 m = a[i]-1; 793 } else if (parseInt(a[i], 10) > 31 && y == 0) { 794 y = parseInt(a[i], 10); 795 (y < 100) && (y += (y > 29) ? 1900 : 2000); 796 } else if (d == 0) { 797 d = a[i]; 798 } 799 } 800 if (y == 0){ 801 y = today.getFullYear(); 802 } 803 if (m != -1 && d != 0){ 804 return new Date(y, m, d, hr, min, 0); 805 } 806 return today; 807}; 808 809// Returns the number of days in the current month 810Date.prototype.getMonthDays = function(month) { 811 var year = this.getFullYear(); 812 if (typeof month == "undefined"){
813 month = this.getMonth(); 814 } 815 if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1){ 816 return 29; 817 } 818 else{ 819 return Date.DAYS_IN_MONTH[month]; 820 } 821}; 822 823// Returns the number of day in the year 824Date.prototype.getDayOfYear = function() { 825 var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); 826 var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); 827 var time = now - then; 828 return Math.floor(time / Date.DAY); 829}; 830 831/** Returns the number of the week in year, as defined in ISO 8601. */ 832Date.prototype.getWeekNumber = function() { 833 var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); 834 var DoW = d.getDay(); 835 d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu 836 var ms = d.valueOf(); // GMT 837 d.setMonth(0); 838 d.setDate(4); // Thu in Week 1 839 return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; 840}; 841 842/** Checks date and time equality */ 843Date.prototype.equalsTo = function(date) { 844 return ((this.getFullYear() == date.getFullYear()) && 845 (this.getMonth() == date.getMonth()) && 846 (this.getDate() == date.getDate()) && 847 (this.getHours() == date.getHours()) && 848 (this.getMinutes() == date.getMinutes())); 849}; 850 851/** Set only the year, month, date parts (keep existing time) */ 852Date.prototype.setDateOnly = function(date) { 853 var tmp = new Date(date); 854 this.setDate(1); 855 this.setFullYear(tmp.getFullYear()); 856 this.setMonth(tmp.getMonth()); 857 this.setDate(tmp.getDate()); 858}; 859 860/** Prints the date in a string according to the given format. */ 861Date.prototype.print = function (str) { 862 var m = this.getMonth(); 863 var d = this.getDate(); 864 var y = this.getFullYear(); 865 var wn = this.getWeekNumber(); 866 var w = this.getDay(); 867 var s = {}; 868 var hr = this.getHours(); 869 var pm = (hr >= 12); 870 var ir = (pm) ? (hr - 12) : hr; 871 var dy = this.getDayOfYear(); 872 if (ir == 0){ 873 ir = 12; 874 } 875 var min = this.getMinutes(); 876 var sec = this.getSeconds(); 877 s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N] 878 s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name 879 s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N] 880 s["%B"] = Calendar.MONTH_NAMES[m]; // full month name 881 // FIXME: %c : preferred date and time representation for the current locale 882 s["%C"] = 1 + Math.floor(y / 100); // the century number 883 s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) 884 s["%e"] = d; // the day of the month (range 1 to 31) 885 // FIXME: %D : american date style: %m/%d/%y 886 // FIXME: %E, %F, %G, %g, %h (man strftime) 887 s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) 888 s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) 889 s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) 890 s["%k"] = hr; // hour, range 0 to 23 (24h format) 891 s["%l"] = ir; // hour, range 1 to 12 (12h format) 892 s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 893 s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 894 s["%n"] = "\n"; // a newline character 895 s["%p"] = pm ? "PM" : "AM"; 896 s["%P"] = pm ? "pm" : "am"; 897 // FIXME: %r : the time in am/pm notation %I:%M:%S %p 898 // FIXME: %R : the time in 24-hour notation %H:%M 899 s["%s"] = Math.floor(this.getTime() / 1000); 900 s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 901 s["%t"] = "\t"; // a tab character 902 // FIXME: %T : the time in 24-hour notation (%H:%M:%S) 903 s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; 904 s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) 905 s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) 906 // FIXME: %x : preferred date representation for the current locale without the time 907 // FIXME: %X : preferred time representation for the current locale without the date 908 s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) 909 s["%Y"] = y; // year with the century 910 s["%%"] = "%"; // a literal '%' character 911 912 return str.gsub(/%./, function(match) { return s[match] || match; }); 913}; 914 915Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear; 916Date.prototype.setFullYear = function(y) { 917 var d = new Date(this); 918 d.__msh_oldSetFullYear(y); 919 if (d.getMonth() != this.getMonth()){ 920 this.setDate(28); 921 } 922 this.__msh_oldSetFullYear(y); 923};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.