PageSourceSearch

https://www.crystalseas.com/assets/public/csres-jotform-4/js/calendarview.js?v=1

js crystalseas.com collected 2026-10-08 22:14:11 UTC 26,289 bytes, 923 lines download raw bytes

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, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR);
481    this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH);
482    this._drawButtonCell(row, Calendar.TODAY,    3, Calendar.NAV_TODAY);
483    this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH);
484    this._drawButtonCell(row, '&#x00bb;', 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.