source: ether_2012/web/resources/js/calendarview-1.2/javascripts/calendarview.js @ 319

Last change on this file since 319 was 319, checked in by vmipsl, 12 years ago

Import du projet Ether pour le nouveau look 2012

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