Clockworkgeek_CalendarView - Version 1.4.0

Version Notes

Switched to version 1.4 of CalendarView as forked here https://github.com/clockworkgeek/calendarview. Version numbers of this extension should now mirror the JS widget.

Localisation now follows the admin setting in System > Configuration > General > Locale Options. There is no need to edit the skin files any more. To add more locales see the file /js/calendarview/i18n.js

Download this release

Release Info

Developer Clockworkgeek
Extension Clockworkgeek_CalendarView
Version 1.4.0
Comparing to
See all releases


Code changes from version 0.3.0 to 1.4.0

app/code/community/Clockworkgeek/CalendarView/Block/Html/Date.php CHANGED
@@ -27,7 +27,22 @@ class Clockworkgeek_CalendarView_Block_Html_Date extends Mage_Core_Block_Html_Da
27
  $html .= 'title="' . $this->helper('core')->__('Select Date') . '" id="' . $this->getId() . '_trig" />';
28
 
29
  $helper = Mage::helper('calendarview');
30
- $script = "Calendar.setup({dateField: '{$this->getId()}', triggerElement: '{$this->getId()}_trig', dateFormat: '{$helper->getDateFieldsOrder()}'});";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  $html .= Mage::helper('core/js')->getScript($script);
32
 
33
  return $html;
27
  $html .= 'title="' . $this->helper('core')->__('Select Date') . '" id="' . $this->getId() . '_trig" />';
28
 
29
  $helper = Mage::helper('calendarview');
30
+ $firstDay = (int) Mage::getStoreConfig('general/locale/firstday');
31
+ $weekend = Mage::getStoreConfig('general/locale/weekend');
32
+ $yearStart = Mage::getSingleton('catalog/product_option_type_date')->getYearStart();
33
+ $yearEnd = Mage::getSingleton('catalog/product_option_type_date')->getYearEnd();
34
+
35
+ $script = "Calendar.language = '{$helper->getLocaleLanguageCode()}';
36
+ Calendar.firstDayOfWeek = {$firstDay};
37
+ Calendar.weekendDays = [{$weekend}];
38
+ new Calendar({
39
+ outputFields: ['{$this->getId()}'],
40
+ popupTriggerElement: '{$this->getId()}_trig',
41
+ dateFormat: '{$helper->getDateFieldsOrder()}',
42
+ hideOnClickElsewhere : true,
43
+ hideOnClickOnDay : true,
44
+ }).setRange({$yearStart}, {$yearEnd});";
45
+
46
  $html .= Mage::helper('core/js')->getScript($script);
47
 
48
  return $html;
app/code/community/Clockworkgeek/CalendarView/Helper/Data.php CHANGED
@@ -18,6 +18,14 @@
18
  class Clockworkgeek_CalendarView_Helper_Data extends Mage_Core_Helper_Data
19
  {
20
 
 
 
 
 
 
 
 
 
21
  public function getDateFieldsOrder()
22
  {
23
  $text = Mage::getStoreConfig('catalog/custom_options/date_fields_order');
18
  class Clockworkgeek_CalendarView_Helper_Data extends Mage_Core_Helper_Data
19
  {
20
 
21
+ /**
22
+ * Retrieve just the language part and not the country part
23
+ */
24
+ public function getLocaleLanguageCode()
25
+ {
26
+ return substr(Mage::app()->getLocale()->getLocaleCode(), 0, 2);
27
+ }
28
+
29
  public function getDateFieldsOrder()
30
  {
31
  $text = Mage::getStoreConfig('catalog/custom_options/date_fields_order');
app/code/community/Clockworkgeek/CalendarView/etc/config.xml CHANGED
@@ -19,7 +19,7 @@
19
 
20
  <modules>
21
  <Clockworkgeek_CalendarView>
22
- <version>0.3.0</version>
23
  </Clockworkgeek_CalendarView>
24
  </modules>
25
 
19
 
20
  <modules>
21
  <Clockworkgeek_CalendarView>
22
+ <version>1.4.0</version>
23
  </Clockworkgeek_CalendarView>
24
  </modules>
25
 
app/design/frontend/base/default/layout/calendarview.xml CHANGED
@@ -26,8 +26,9 @@
26
  <action method="removeItem"><type>js</type><name>calendar/calendar-setup.js</name></action>
27
 
28
  <!-- Insert new, pretty, streamlined date picker -->
29
- <action method="addItem"><type>skin_js</type><name>js/calendarview.js</name></action>
30
- <action method="addItem"><type>skin_css</type><name>css/calendarview.css</name></action>
 
31
  </reference>
32
  </catalog_product_view>
33
 
26
  <action method="removeItem"><type>js</type><name>calendar/calendar-setup.js</name></action>
27
 
28
  <!-- Insert new, pretty, streamlined date picker -->
29
+ <action method="addItem"><type>js</type><name>calendarview/calendarview.js</name></action>
30
+ <action method="addItem"><type>skin_css</type><name>css/calendarview/calendarview.css</name></action>
31
+ <action method="addItem"><type>skin_css</type><name>css/calendarview/calendarview-ie.css</name><params/><if>lt IE 8</if></action>
32
  </reference>
33
  </catalog_product_view>
34
 
js/calendarview/I18n.js ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Use this as a source for the declaration of Calendar.messagebundle in calendarview.js
2
+ Calendar.messagebundle = $H({'en' :
3
+ $H({
4
+ 'monday' : 'Monday',
5
+ 'tuesday' : 'Tuesday',
6
+ 'wednesday' : 'Wednesday',
7
+ 'thursday' : 'Thursday',
8
+ 'friday' : 'Friday',
9
+ 'saturday' : 'Saturday',
10
+ 'sunday' : 'Sunday',
11
+
12
+ 'monday_short' : 'M',
13
+ 'tuesday_short' : 'T',
14
+ 'wednesday_short' : 'W',
15
+ 'thursday_short' : 'T',
16
+ 'friday_short' : 'F',
17
+ 'saturday_short' : 'S',
18
+ 'sunday_short' : 'S',
19
+
20
+ 'january' : 'January',
21
+ 'february' : 'February',
22
+ 'march' : 'March',
23
+ 'april' : 'April',
24
+ 'may' : 'May',
25
+ 'june' : 'June',
26
+ 'july' : 'July',
27
+ 'august' : 'August',
28
+ 'september' : 'September',
29
+ 'october' : 'October',
30
+ 'november' : 'November',
31
+ 'december' : 'December',
32
+
33
+ 'january_short' : 'Jan',
34
+ 'february_short' : 'Feb',
35
+ 'march_short' : 'Mar',
36
+ 'april_short' : 'Apr',
37
+ 'may_short' : 'May',
38
+ 'june_short' : 'Jun',
39
+ 'july_short' : 'Jul',
40
+ 'august_short' : 'Aug',
41
+ 'september_short' : 'Sep',
42
+ 'october_short' : 'Oct',
43
+ 'november_short' : 'Nov',
44
+ 'december_short' : 'Dec',
45
+
46
+ 'today' : 'Today'
47
+ }),
48
+ 'fr' :
49
+ $H({
50
+ 'monday' : 'Lundi',
51
+ 'tuesday' : 'Mardi',
52
+ 'wednesday' : 'Mercredi',
53
+ 'thursday' : 'Jeudi',
54
+ 'friday' : 'Vendredi',
55
+ 'saturday' : 'Samedi',
56
+ 'sunday' : 'Dimanche',
57
+
58
+ 'monday_short' : 'Lu',
59
+ 'tuesday_short' : 'Ma',
60
+ 'wednesday_short' : 'Me',
61
+ 'thursday_short' : 'Je',
62
+ 'friday_short' : 'Ve',
63
+ 'saturday_short' : 'Sa',
64
+ 'sunday_short' : 'Di',
65
+
66
+ 'january' : 'janvier',
67
+ 'february' : 'février',
68
+ 'march' : 'mars',
69
+ 'april' : 'avril',
70
+ 'may' : 'mai',
71
+ 'june' : 'juin',
72
+ 'july' : 'juillet',
73
+ 'august' : 'août',
74
+ 'september' : 'septembre',
75
+ 'october' : 'octobre',
76
+ 'november' : 'novembre',
77
+ 'december' : 'décembre',
78
+
79
+ 'january_short' : 'jan',
80
+ 'february_short' : 'fév',
81
+ 'march_short' : 'mar',
82
+ 'april_short' : 'avr',
83
+ 'may_short' : 'mai',
84
+ 'june_short' : 'jun',
85
+ 'july_short' : 'jul',
86
+ 'august_short' : 'aoû',
87
+ 'september_short' : 'sep',
88
+ 'october_short' : 'oct',
89
+ 'november_short' : 'nov',
90
+ 'december_short' : 'dec',
91
+
92
+ 'today' : 'aujourd\'hui'
93
+ }),
94
+ 'pt' :
95
+ $H({
96
+ 'monday' : 'Segunda-feira',
97
+ 'tuesday' : 'Terça-feira',
98
+ 'wednesday' : 'Quarta-feira',
99
+ 'thursday' : 'Quinta-feira',
100
+ 'friday' : 'Sexta-feira',
101
+ 'saturday' : 'Sabado',
102
+ 'sunday' : 'Domingo',
103
+
104
+ 'monday_short' : 'Seg',
105
+ 'tuesday_short' : 'Ter',
106
+ 'wednesday_short' : 'Qua',
107
+ 'thursday_short' : 'Qui',
108
+ 'friday_short' : 'Sex',
109
+ 'saturday_short' : 'Sab',
110
+ 'sunday_short' : 'Dom',
111
+
112
+ 'january' : 'Janeiro',
113
+ 'february' : 'Fevereiro',
114
+ 'march' : 'Março',
115
+ 'april' : 'Abril',
116
+ 'may' : 'Maio',
117
+ 'june' : 'Junho',
118
+ 'july' : 'Julho',
119
+ 'august' : 'Agosto',
120
+ 'september' : 'Setembro',
121
+ 'october' : 'Outubro',
122
+ 'november' : 'Novembro',
123
+ 'december' : 'Dezembro',
124
+
125
+ 'january_short' : 'Jan',
126
+ 'february_short' : 'Fev',
127
+ 'march_short' : 'Mar',
128
+ 'april_short' : 'Abr',
129
+ 'may_short' : 'Mai',
130
+ 'june_short' : 'Jun',
131
+ 'july_short' : 'Jul',
132
+ 'august_short' : 'Ago',
133
+ 'september_short' : 'Set',
134
+ 'october_short' : 'Out',
135
+ 'november_short' : 'Nov',
136
+ 'december_short' : 'Dez',
137
+
138
+ 'today' : 'hoje'
139
+ }),
140
+ 'ru' :
141
+ $H({
142
+ 'monday' : 'Понедельник',
143
+ 'tuesday' : 'Вторник',
144
+ 'wednesday' : 'Среда',
145
+ 'thursday' : 'Четверг',
146
+ 'friday' : 'Пятница',
147
+ 'saturday' : 'Суббота',
148
+ 'sunday' : 'Воскресенье',
149
+
150
+ 'monday_short' : 'Пн',
151
+ 'tuesday_short' : 'Вт',
152
+ 'wednesday_short' : 'Ср',
153
+ 'thursday_short' : 'Чт',
154
+ 'friday_short' : 'Пт',
155
+ 'saturday_short' : 'Сб',
156
+ 'sunday_short' : 'Вс',
157
+
158
+ 'january' : 'январь',
159
+ 'february' : 'февраль',
160
+ 'march' : 'март',
161
+ 'april' : 'апрель',
162
+ 'may' : 'май',
163
+ 'june' : 'июнь',
164
+ 'july' : 'июль',
165
+ 'august' : 'август',
166
+ 'september' : 'сентябрь',
167
+ 'october' : 'октябрь',
168
+ 'november' : 'ноябрь',
169
+ 'december' : 'декабрь',
170
+
171
+ 'january_short' : 'янв',
172
+ 'february_short' : 'февр',
173
+ 'march_short' : 'март',
174
+ 'april_short' : 'апр',
175
+ 'may_short' : 'май',
176
+ 'june_short' : 'июнь',
177
+ 'july_short' : 'июль',
178
+ 'august_short' : 'авг',
179
+ 'september_short' : 'сен',
180
+ 'october_short' : 'окт',
181
+ 'november_short' : 'нояб',
182
+ 'december_short' : 'дек',
183
+
184
+ 'today' : 'сегодня'
185
+ }),
186
+
187
+ 'nl' :
188
+ $H({
189
+ 'monday' : 'maandag',
190
+ 'tuesday' : 'dinsdag',
191
+ 'wednesday' : 'woensdag',
192
+ 'thursday' : 'donderdag',
193
+ 'friday' : 'vrijdag',
194
+ 'saturday' : 'zaterdag',
195
+ 'sunday' : 'zondag',
196
+
197
+ 'monday_short' : 'Ma',
198
+ 'tuesday_short' : 'Di',
199
+ 'wednesday_short' : 'Wo',
200
+ 'thursday_short' : 'Do',
201
+ 'friday_short' : 'Vr',
202
+ 'saturday_short' : 'Za',
203
+ 'sunday_short' : 'Zo',
204
+
205
+ 'january' : 'januari',
206
+ 'february' : 'februari',
207
+ 'march' : 'maart',
208
+ 'april' : 'april',
209
+ 'may' : 'mei',
210
+ 'june' : 'juni',
211
+ 'july' : 'juli',
212
+ 'august' : 'augustus',
213
+ 'september' : 'september',
214
+ 'october' : 'oktober',
215
+ 'november' : 'november',
216
+ 'december' : 'december',
217
+
218
+ 'january_short' : 'jan',
219
+ 'february_short' : 'feb',
220
+ 'march_short' : 'mrt',
221
+ 'april_short' : 'apr',
222
+ 'may_short' : 'mei',
223
+ 'june_short' : 'jun',
224
+ 'july_short' : 'jul',
225
+ 'august_short' : 'aug',
226
+ 'september_short' : 'sep',
227
+ 'october_short' : 'okt',
228
+ 'november_short' : 'nov',
229
+ 'december_short' : 'dec',
230
+
231
+ 'today' : 'vandaag'
232
+ }),
233
+ 'de' :
234
+ $H({
235
+ 'monday' : 'Montag',
236
+ 'tuesday' : 'Dienstag',
237
+ 'wednesday' : 'Mittwoch',
238
+ 'thursday' : 'Donnerstag',
239
+ 'friday' : 'Freitag',
240
+ 'saturday' : 'Samstag',
241
+ 'sunday' : 'Sonntag',
242
+
243
+ 'monday_short' : 'Mo',
244
+ 'tuesday_short' : 'Di',
245
+ 'wednesday_short' : 'Mi',
246
+ 'thursday_short' : 'Do',
247
+ 'friday_short' : 'Fr',
248
+ 'saturday_short' : 'Sa',
249
+ 'sunday_short' : 'So',
250
+
251
+ 'january' : 'Januar',
252
+ 'february' : 'Februar',
253
+ 'march' : 'März',
254
+ 'april' : 'April',
255
+ 'may' : 'Mai',
256
+ 'june' : 'Juni',
257
+ 'july' : 'Juli',
258
+ 'august' : 'August',
259
+ 'september' : 'September',
260
+ 'october' : 'Oktober',
261
+ 'november' : 'November',
262
+ 'december' : 'Dezemer',
263
+
264
+ 'january_short' : 'Jan',
265
+ 'february_short' : 'Feb',
266
+ 'march_short' : 'Mär',
267
+ 'april_short' : 'Apr',
268
+ 'may_short' : 'Mai',
269
+ 'june_short' : 'Jun',
270
+ 'july_short' : 'Jul',
271
+ 'august_short' : 'Aug',
272
+ 'september_short' : 'Sep',
273
+ 'october_short' : 'Okt',
274
+ 'november_short' : 'Nov',
275
+ 'december_short' : 'Dez',
276
+
277
+ 'today' : 'Heute'
278
+ }),
279
+ 'sk' :
280
+ $H({
281
+ 'monday' : 'Pondelok',
282
+ 'tuesday' : 'Utorok',
283
+ 'wednesday' : 'Streda',
284
+ 'thursday' : 'Štvrtok',
285
+ 'friday' : 'Piatok',
286
+ 'saturday' : 'Sobota',
287
+ 'sunday' : 'Nedeľa',
288
+
289
+ 'monday_short' : 'Po',
290
+ 'tuesday_short' : 'Ut',
291
+ 'wednesday_short' : 'St',
292
+ 'thursday_short' : 'Št',
293
+ 'friday_short' : 'Pi',
294
+ 'saturday_short' : 'So',
295
+ 'sunday_short' : 'Ne',
296
+
297
+ 'january' : 'Január',
298
+ 'february' : 'Február',
299
+ 'march' : 'Marec',
300
+ 'april' : 'Apríl',
301
+ 'may' : 'Máj',
302
+ 'june' : 'Jún',
303
+ 'july' : 'Júl',
304
+ 'august' : 'August',
305
+ 'september' : 'September',
306
+ 'october' : 'Október',
307
+ 'november' : 'November',
308
+ 'december' : 'December',
309
+
310
+ 'january_short' : 'Jan',
311
+ 'february_short' : 'Feb',
312
+ 'march_short' : 'Mar',
313
+ 'april_short' : 'Apr',
314
+ 'may_short' : 'Máj',
315
+ 'june_short' : 'Jún',
316
+ 'july_short' : 'Júl',
317
+ 'august_short' : 'Aug',
318
+ 'september_short' : 'Sep',
319
+ 'october_short' : 'Okt',
320
+ 'november_short' : 'Nov',
321
+ 'december_short' : 'Dec',
322
+
323
+ 'today' : 'Dnes'
324
+ }),
325
+ 'cz' :
326
+ $H({
327
+ 'monday' : 'Pondělí',
328
+ 'tuesday' : 'Uterý',
329
+ 'wednesday' : 'Středa',
330
+ 'thursday' : 'Čtvrtek',
331
+ 'friday' : 'Pátek',
332
+ 'saturday' : 'Sobota',
333
+ 'sunday' : 'Neděle',
334
+
335
+ 'monday_short' : 'Po',
336
+ 'tuesday_short' : 'Ut',
337
+ 'wednesday_short' : 'St',
338
+ 'thursday_short' : 'Čt',
339
+ 'friday_short' : 'Pá',
340
+ 'saturday_short' : 'So',
341
+ 'sunday_short' : 'Ne',
342
+
343
+ 'january' : 'Leden',
344
+ 'february' : 'Únor',
345
+ 'march' : 'Březen',
346
+ 'april' : 'Duben',
347
+ 'may' : 'Květen',
348
+ 'june' : 'Červen',
349
+ 'july' : 'Červenec',
350
+ 'august' : 'Srpen',
351
+ 'september' : 'Září',
352
+ 'october' : 'Říjen',
353
+ 'november' : 'Listopad',
354
+ 'december' : 'Prosinec',
355
+
356
+ 'january_short' : 'Led',
357
+ 'february_short' : 'Úno',
358
+ 'march_short' : 'Bře',
359
+ 'april_short' : 'Dub',
360
+ 'may_short' : 'Kvě',
361
+ 'june_short' : 'Čen',
362
+ 'july_short' : 'Čec',
363
+ 'august_short' : 'Srp',
364
+ 'september_short' : 'Zář',
365
+ 'october_short' : 'Říj',
366
+ 'november_short' : 'Lis',
367
+ 'december_short' : 'Pro',
368
+
369
+ 'today' : 'Dnes'
370
+ }),
371
+
372
+ 'by' :
373
+ $H({
374
+ 'monday' : 'панядзелак',
375
+ 'tuesday' : 'аўторак',
376
+ 'wednesday' : 'серада',
377
+ 'thursday' : 'чацьвер',
378
+ 'friday' : 'пятніца',
379
+ 'saturday' : 'субота',
380
+ 'sunday' : 'нядзеля',
381
+
382
+ 'monday_short' : 'пн',
383
+ 'tuesday_short' : 'аў',
384
+ 'wednesday_short' : 'ср',
385
+ 'thursday_short' : 'чц',
386
+ 'friday_short' : 'пт',
387
+ 'saturday_short' : 'сб',
388
+ 'sunday_short' : 'ндз',
389
+
390
+ 'january' : 'студзень',
391
+ 'february' : 'люты',
392
+ 'march' : 'сакавiк',
393
+ 'april' : 'красавiк',
394
+ 'may' : 'травень',
395
+ 'june' : 'чэрвень',
396
+ 'july' : 'лiпень',
397
+ 'august' : 'жнiвень',
398
+ 'september' : 'верасень',
399
+ 'october' : 'кастрычнiк',
400
+ 'november' : 'лiстапад',
401
+ 'december' : 'cьнежань',
402
+ // god knows how it should really be :(
403
+ 'january_short' : 'ст',
404
+ 'february_short' : 'лют',
405
+ 'march_short' : 'сак',
406
+ 'april_short' : 'кр',
407
+ 'may_short' : 'тр',
408
+ 'june_short' : 'чэр',
409
+ 'july_short' : 'лiп',
410
+ 'august_short' : 'жн',
411
+ 'september_short' : 'вер',
412
+ 'october_short' : 'кас',
413
+ 'november_short' : 'лiс',
414
+ 'december_short' : 'cьн',
415
+
416
+ 'today' : 'сёньня'
417
+ })
418
+ });
js/calendarview/calendarview.js ADDED
@@ -0,0 +1,1222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
20
+
21
+ /* This fork by Yuri Leikind ( git://github.com/leikind/calendarview.git ) adds a number of features.
22
+
23
+ The differences from the original are
24
+
25
+ * Support for time in the form of two dropdowns for hours and minutes. Can be turned off/on.
26
+ * Draggable popup calendars (which introduces new dependancies: script.aculo.us effects.js and dragdrop.js)
27
+ * Close button
28
+ * Ability to unset the date by clicking on the active date
29
+ * Simple I18n support
30
+ * Removed all ambiguity in the API
31
+ * Two strategies in positioning of popup calendars: relative to the popup trigger element (original behavior),
32
+ and is relative to the mouse pointer (can be configured)
33
+ * Popup calendars are not created every time they pop up, on the contrary, they are created once just like
34
+ embedded calendars, and then shown or hidden.
35
+ * Possible to have many popup calendars on page. The behavior of the original calendarview when a popup
36
+ calendar is hidden when the user clicks elsewhere on the page is an option now.
37
+ * Refactoring and changes to the OO design like getting rid of Calendar.prototype in favor of class based
38
+ OO provided by OO, and getting rid of Calendar.setup({}) in favor of a simple object constructor new Calendar({}).
39
+
40
+ */
41
+
42
+ var Calendar = Class.create({
43
+
44
+ container: null,
45
+
46
+ minYear: 1900,
47
+ maxYear: 2100,
48
+
49
+ date: new Date(),
50
+ currentDateElement: null,
51
+
52
+ shouldClose: false,
53
+ isPopup: true,
54
+
55
+ initialize: function(params){
56
+
57
+ if (! Calendar.init_done){
58
+ Calendar.init();
59
+ }
60
+
61
+ embedAt = params.embedAt || null;
62
+ this.withTime = params.withTime || null;
63
+ this.dateFormat = params.dateFormat || null;
64
+ initialDate = params.initialDate || null;
65
+ popupTriggerElement = params.popupTriggerElement || null;
66
+ this.disableDateCallback = params.disableDateCallback || function(date, calendar){return false;};
67
+ this.onHideCallback = params.onHideCallback || function(date, calendar){};
68
+ this.onDateChangedCallback = params.onDateChangedCallback || function(date, calendar){};
69
+ this.minuteStep = params.minuteStep || 5;
70
+ this.hideOnClickOnDay = params.hideOnClickOnDay || false;
71
+ this.hideOnClickElsewhere = params.hideOnClickElsewhere || false;
72
+ this.outputFields = params.outputFields || $A();
73
+ this.popupPositioningStrategy = params.popupPositioningStrategy || 'trigger'; // or 'pointer'
74
+ this.x = params.x || 0;
75
+ this.y = params.y || 0.6;
76
+
77
+ this.outputFields = $A(this.outputFields).collect(function(f){
78
+ return $(f);
79
+ });
80
+
81
+ if (embedAt){
82
+ this.embedAt = $(embedAt);
83
+ this.embedAt._calendar = this;
84
+ }else{
85
+ this.embedAt = null;
86
+ }
87
+
88
+ if (!this.dateFormat){
89
+ if(this.withTime){
90
+ this.dateFormat = Calendar.defaultDateTimeFormat;
91
+ }else{
92
+ this.dateFormat = Calendar.defaultDateFormat;
93
+ }
94
+ }
95
+
96
+ this.dateFormatForHiddenField = params.dateFormatForHiddenField || this.dateFormat;
97
+
98
+
99
+ if (initialDate) {
100
+ this.date = this.parseDate(initialDate);
101
+ }
102
+
103
+ this.build();
104
+
105
+ if (this.isPopup) { //Popup Calendars
106
+ var popupTriggerElement = $(popupTriggerElement);
107
+ popupTriggerElement._calendar = this;
108
+
109
+ popupTriggerElement.observe('click', function(event){
110
+ this.showAtElement(event, popupTriggerElement);
111
+ }.bind(this) );
112
+
113
+ } else{ // In-Page Calendar
114
+ this.show();
115
+ }
116
+
117
+ if (params.updateOuterFieldsOnInit){
118
+ this.updateOuterFieldWithoutCallback(); // Just for the sake of localization and DatePicker
119
+ }
120
+ },
121
+
122
+ build: function(){
123
+ if (this.embedAt) {
124
+ var parentForCalendarTable = this.embedAt;
125
+ this.isPopup = false;
126
+ } else {
127
+ var parentForCalendarTable = document.getElementsByTagName('body')[0];
128
+ this.isPopup = true;
129
+ }
130
+
131
+
132
+ var table = new Element('table');
133
+
134
+ var thead = new Element('thead');
135
+ table.appendChild(thead);
136
+
137
+ var firstRow = new Element('tr');
138
+
139
+ if (this.isPopup){
140
+ var cell = new Element('td');
141
+ cell.addClassName('draggableHandler');
142
+ firstRow.appendChild(cell);
143
+
144
+ cell = new Element('td', { colSpan: 5 });
145
+ cell.addClassName('title' );
146
+ cell.addClassName('draggableHandler');
147
+ firstRow.appendChild(cell);
148
+
149
+ cell = new Element('td');
150
+ cell.addClassName('closeButton');
151
+ firstRow.appendChild(cell);
152
+ cell.update('x');
153
+
154
+ cell.observe('mousedown', function(){
155
+ this.hide();
156
+ }.bind(this));
157
+
158
+
159
+ }else{
160
+ var cell = new Element('td', { colSpan: 7 } );
161
+ firstRow.appendChild(cell);
162
+ }
163
+
164
+ cell.addClassName('title');
165
+
166
+ thead.appendChild(firstRow);
167
+
168
+ var row = new Element('tr')
169
+ this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR);
170
+ this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH);
171
+ this._drawButtonCell(row, Calendar.getMessageFor('today'), 3, Calendar.NAV_TODAY);
172
+ this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH);
173
+ this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR);
174
+ thead.appendChild(row)
175
+
176
+ // Day Names
177
+ row = new Element('tr');
178
+ for (var i = 0; i < 7; ++i) {
179
+ var day = (i+Calendar.firstDayOfWeek)%7;
180
+ cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[day]);
181
+ if (this.isWeekend(day)) {
182
+ cell.addClassName('weekend');
183
+ }
184
+ row.appendChild(cell);
185
+ }
186
+ thead.appendChild(row);
187
+
188
+ // Calendar Days
189
+ var tbody = table.appendChild(new Element('tbody'));
190
+ for (i = 6; i > 0; --i) {
191
+ row = tbody.appendChild(new Element('tr'));
192
+ row.addClassName('days');
193
+ for (var j = 7; j > 0; --j) {
194
+ cell = row.appendChild(new Element('td'));
195
+ cell.calendar = this;
196
+ }
197
+ }
198
+
199
+ // Time Placeholder
200
+ if (this.withTime){
201
+ var tfoot = table.appendChild(new Element('tfoot'));
202
+ row = tfoot.appendChild(new Element('tr'));
203
+ cell = row.appendChild(new Element('td', { colSpan: 7 }));
204
+ cell.addClassName('time');
205
+ var hourSelect = cell.appendChild(new Element('select', { name : 'hourSelect'}));
206
+ for (var i = 0; i < 24; i++) {
207
+ hourSelect.appendChild(new Element('option', {value : i}).update(i));
208
+ }
209
+ this.hourSelect = hourSelect;
210
+
211
+ cell.appendChild(new Element('span')).update(' : ');
212
+
213
+ var minuteSelect = cell.appendChild(new Element('select', { name : 'minuteSelect'}));
214
+ for (var i = 0; i < 60; i += this.minuteStep) {
215
+ minuteSelect.appendChild(new Element('option', {value : i}).update(i));
216
+ }
217
+ this.minuteSelect = minuteSelect;
218
+
219
+ hourSelect.observe('change', function(event){
220
+ if (! this.date) return;
221
+ var elem = event.element();
222
+ var selectedIndex = elem.selectedIndex;
223
+ if ((typeof selectedIndex != 'undefined') && selectedIndex != null){
224
+ this.date.setHours(elem.options[selectedIndex].value);
225
+ this.updateOuterField();
226
+ }
227
+ }.bind(this));
228
+
229
+ minuteSelect.observe('change', function(event){
230
+ if (! this.date) return;
231
+ var elem = event.element();
232
+ var selectedIndex = elem.selectedIndex;
233
+ if ((typeof selectedIndex != 'undefined') && selectedIndex != null){
234
+ this.date.setMinutes(elem.options[selectedIndex].value);
235
+ this.updateOuterField();
236
+ }
237
+ }.bind(this))
238
+ }
239
+
240
+ // Calendar Container (div)
241
+ this.container = new Element('div');
242
+ this.container.addClassName('calendar');
243
+ if (this.isPopup) {
244
+ this.container.setStyle({ position: 'absolute', display: 'none' });
245
+ this.container.addClassName('popup');
246
+ }
247
+ this.container.appendChild(table);
248
+
249
+ this.update(this.date);
250
+
251
+ Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent);
252
+
253
+ parentForCalendarTable.appendChild(this.container);
254
+
255
+ if (this.isPopup){
256
+ new Draggable(table, {handle : firstRow });
257
+ }
258
+ },
259
+
260
+ updateOuterFieldReal: function(element){
261
+ if (element.tagName == 'DIV' || element.tagName == 'SPAN') {
262
+ formatted = this.date ? this.date.print(this.dateFormat) : '';
263
+ element.update(formatted);
264
+ } else if (element.tagName == 'INPUT') {
265
+ formatted = this.date ? this.date.print(this.dateFormatForHiddenField) : '';
266
+ element.value = formatted;
267
+ }
268
+ },
269
+
270
+ updateOuterFieldWithoutCallback: function(){
271
+ this.outputFields.each(function(field){
272
+ this.updateOuterFieldReal(field);
273
+ }.bind(this));
274
+ },
275
+
276
+ updateOuterField: function(){
277
+ this.updateOuterFieldWithoutCallback();
278
+ this.onDateChangedCallback(this.date, this);
279
+ },
280
+
281
+ viewOutputFields: function(){
282
+ return this.outputFields.findAll(function(element){
283
+ if (element.tagName == 'DIV' || element.tagName == 'SPAN'){
284
+ return true;
285
+ }else{
286
+ return false;
287
+ }
288
+ });
289
+ },
290
+
291
+
292
+ //----------------------------------------------------------------------------
293
+ // Update Calendar
294
+ //----------------------------------------------------------------------------
295
+
296
+ update: function(date) {
297
+
298
+ var today = new Date();
299
+ var thisYear = today.getFullYear();
300
+ var thisMonth = today.getMonth();
301
+ var thisDay = today.getDate();
302
+ var month = date.getMonth();
303
+ var dayOfMonth = date.getDate();
304
+ var hour = date.getHours();
305
+ var minute = date.getMinutes();
306
+
307
+ // Ensure date is within the defined range
308
+ if (date.getFullYear() < this.minYear)
309
+ date.__setFullYear(this.minYear);
310
+ else if (date.getFullYear() > this.maxYear)
311
+ date.__setFullYear(this.maxYear);
312
+
313
+ if (this.isBackedUp()){
314
+ this.dateBackedUp = new Date(date);
315
+ }else{
316
+ this.date = new Date(date);
317
+ }
318
+
319
+ // Calculate the first day to display (including the previous month)
320
+ date.setDate(1)
321
+ date.setDate(-(date.getDay()) + 1 + Calendar.firstDayOfWeek)
322
+
323
+ // Fill in the days of the month
324
+ Element.getElementsBySelector(this.container, 'tbody tr').each(
325
+ function(row, i) {
326
+ var rowHasDays = false;
327
+ row.immediateDescendants().each(
328
+ function(cell, j) {
329
+ var day = date.getDate();
330
+ var dayOfWeek = date.getDay();
331
+ var isCurrentMonth = (date.getMonth() == month);
332
+
333
+ // Reset classes on the cell
334
+ cell.className = '';
335
+ cell.date = new Date(date);
336
+ cell.update(day);
337
+
338
+ // Account for days of the month other than the current month
339
+ if (!isCurrentMonth)
340
+ cell.addClassName('otherDay');
341
+ else
342
+ rowHasDays = true;
343
+
344
+ // Ensure the current day is selected
345
+ if ((! this.isBackedUp()) && isCurrentMonth && day == dayOfMonth) {
346
+ cell.addClassName('selected');
347
+ this.currentDateElement = cell;
348
+ }
349
+
350
+ // Today
351
+ if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
352
+ cell.addClassName('today');
353
+
354
+ // Weekend
355
+ if (this.isWeekend(dayOfWeek))
356
+ cell.addClassName('weekend');
357
+
358
+ if (isCurrentMonth && this.disableDateCallback(date, this)) {
359
+ cell.addClassName('disabled');
360
+ cell.navAction = 'disabled';
361
+ }
362
+
363
+ // Set the date to tommorrow
364
+ date.setDate(day + 1);
365
+ }.bind(this)
366
+ )
367
+ // Hide the extra row if it contains only days from another month
368
+ !rowHasDays ? row.hide() : row.show();
369
+ }.bind(this)
370
+ )
371
+
372
+ Element.getElementsBySelector(this.container, 'tfoot tr td select').each(
373
+ function(sel){
374
+ if(sel.name == 'hourSelect'){
375
+ sel.selectedIndex = hour;
376
+ }else if(sel.name == 'minuteSelect'){
377
+ if (this.minuteStep == 1){
378
+ sel.selectedIndex = minute;
379
+ }else{
380
+ sel.selectedIndex = this.findClosestMinute(minute);
381
+ }
382
+ }
383
+ }.bind(this)
384
+ )
385
+
386
+ this.container.getElementsBySelector('td.title')[0].update(
387
+ Calendar.MONTH_NAMES[month] + ' ' + this.dateOrDateBackedUp().getFullYear()
388
+ )
389
+
390
+ },
391
+
392
+
393
+ findClosestMinute: function(val){
394
+ if (val == 0){
395
+ return 0;
396
+ }
397
+ var lowest = ((val / this.minuteStep).floor() * this.minuteStep);
398
+ var distance = val % this.minuteStep;
399
+ var minuteValueToShow;
400
+
401
+ if (distance <= (this.minuteStep / 2)){
402
+ minuteValueToShow = lowest;
403
+ }else{
404
+ minuteValueToShow = lowest + this.minuteStep;
405
+ }
406
+
407
+ if (minuteValueToShow == 0){
408
+ return minuteValueToShow;
409
+ }else if(minuteValueToShow >= 60){
410
+ return (minuteValueToShow / this.minuteStep).floor() - 1;
411
+ }else{
412
+ return minuteValueToShow / this.minuteStep;
413
+ }
414
+ },
415
+
416
+ _drawButtonCell: function(parentForCell, text, colSpan, navAction) {
417
+ var cell = new Element('td');
418
+ if (colSpan > 1) cell.colSpan = colSpan;
419
+ cell.className = 'cvbutton';
420
+ cell.calendar = this;
421
+ cell.navAction = navAction;
422
+ cell.innerHTML = text;
423
+ cell.unselectable = 'on'; // IE
424
+ parentForCell.appendChild(cell);
425
+ return cell;
426
+ },
427
+
428
+
429
+ //------------------------------------------------------------------------------
430
+ // Calendar Display Functions
431
+ //------------------------------------------------------------------------------
432
+
433
+ show: function(){
434
+ this.container.show();
435
+ if (this.isPopup) {
436
+ if (this.hideOnClickElsewhere){
437
+ window._popupCalendar = this;
438
+ document.observe('mousedown', Calendar._checkCalendar);
439
+ }
440
+ }
441
+ },
442
+
443
+ showAt: function (x, y) {
444
+ this.container.setStyle({ left: x + 'px', top: y + 'px' });
445
+ this.show();
446
+ },
447
+
448
+
449
+ showAtElement: function(event, element) {
450
+ this.container.show();
451
+ var x, y;
452
+ if (this.popupPositioningStrategy == 'pointer'){ // follow the mouse pointer
453
+ var pos = Event.pointer(event);
454
+ var containerWidth = this.container.getWidth();
455
+ x = containerWidth * this.x + pos.x;
456
+ y = containerWidth * this.y + pos.y;
457
+ }else{ // 'container' - container of the trigger elements
458
+ var pos = Position.cumulativeOffset(element);
459
+ x = pos[0];
460
+ y = this.container.offsetHeight * 0.75 + pos[1];
461
+ }
462
+ this.showAt(x, y);
463
+ },
464
+
465
+ hide: function() {
466
+ if (this.isPopup){
467
+ Event.stopObserving(document, 'mousedown', Calendar._checkCalendar);
468
+ }
469
+ this.container.hide();
470
+ this.onHideCallback(this.date, this);
471
+ },
472
+
473
+
474
+ // Tries to identify the date represented in a string. If successful it also
475
+ // calls this.updateIfDateDifferent which moves the calendar to the given date.
476
+ parseDate: function(str, format){
477
+ if (!format){
478
+ format = this.dateFormat;
479
+ }
480
+ var res = Date.parseDate(str, format);
481
+ return res;
482
+ },
483
+
484
+
485
+ dateOrDateBackedUp: function(){
486
+ return this.date || this.dateBackedUp;
487
+ },
488
+
489
+ updateIfDateDifferent: function(date) {
490
+ if (!date.equalsTo(this.dateOrDateBackedUp())){
491
+ this.update(date);
492
+ }
493
+ },
494
+
495
+ backupDateAndCurrentElement: function(){
496
+ if (this.minuteSelect){
497
+ this.minuteSelect.disable();
498
+ }
499
+ if (this.hourSelect){
500
+ this.hourSelect.disable();
501
+ }
502
+
503
+ this.currentDateElementBackedUp = this.currentDateElement;
504
+ this.currentDateElement = null;
505
+
506
+ this.dateBackedUp = this.date;
507
+ this.date = null;
508
+ },
509
+
510
+ restoreDateAndCurrentElement: function(){
511
+ if (this.minuteSelect){
512
+ this.minuteSelect.enable();
513
+ }
514
+ if (this.hourSelect){
515
+ this.hourSelect.enable();
516
+ }
517
+
518
+ this.currentDateElement = this.currentDateElementBackedUp;
519
+ this.currentDateElementBackedUp = null;
520
+
521
+ this.date = this.dateBackedUp;
522
+ this.dateBackedUp = null;
523
+ },
524
+
525
+ isBackedUp: function(){
526
+ return ((this.date == null) && this.dateBackedUp);
527
+ },
528
+
529
+ dumpDates: function(){
530
+ console.log('date: ' + this.date);
531
+ console.log('dateBackedUp: ' + this.dateBackedUp);
532
+ },
533
+
534
+ isWeekend: function(day){
535
+ return Calendar.weekendDays.indexOf(day) != -1;
536
+ },
537
+
538
+ setRange: function(minYear, maxYear) {
539
+ this.minYear = minYear;
540
+ this.maxYear = maxYear;
541
+ }
542
+ });
543
+
544
+ // Delete or add new locales from I18n.js according to your needs
545
+ Calendar.messagebundle = $H({'en' :
546
+ $H({
547
+ 'monday' : 'Monday',
548
+ 'tuesday' : 'Tuesday',
549
+ 'wednesday' : 'Wednesday',
550
+ 'thursday' : 'Thursday',
551
+ 'friday' : 'Friday',
552
+ 'saturday' : 'Saturday',
553
+ 'sunday' : 'Sunday',
554
+
555
+ 'monday_short' : 'M',
556
+ 'tuesday_short' : 'T',
557
+ 'wednesday_short' : 'W',
558
+ 'thursday_short' : 'T',
559
+ 'friday_short' : 'F',
560
+ 'saturday_short' : 'S',
561
+ 'sunday_short' : 'S',
562
+
563
+ 'january' : 'January',
564
+ 'february' : 'February',
565
+ 'march' : 'March',
566
+ 'april' : 'April',
567
+ 'may' : 'May',
568
+ 'june' : 'June',
569
+ 'july' : 'July',
570
+ 'august' : 'August',
571
+ 'september' : 'September',
572
+ 'october' : 'October',
573
+ 'november' : 'November',
574
+ 'december' : 'December',
575
+
576
+ 'january_short' : 'Jan',
577
+ 'february_short' : 'Feb',
578
+ 'march_short' : 'Mar',
579
+ 'april_short' : 'Apr',
580
+ 'may_short' : 'May',
581
+ 'june_short' : 'Jun',
582
+ 'july_short' : 'Jul',
583
+ 'august_short' : 'Aug',
584
+ 'september_short' : 'Sep',
585
+ 'october_short' : 'Oct',
586
+ 'november_short' : 'Nov',
587
+ 'december_short' : 'Dec',
588
+
589
+ 'today' : 'Today'
590
+ }),
591
+ 'fr' :
592
+ $H({
593
+ 'monday' : 'Lundi',
594
+ 'tuesday' : 'Mardi',
595
+ 'wednesday' : 'Mercredi',
596
+ 'thursday' : 'Jeudi',
597
+ 'friday' : 'Vendredi',
598
+ 'saturday' : 'Samedi',
599
+ 'sunday' : 'Dimanche',
600
+
601
+ 'monday_short' : 'Lu',
602
+ 'tuesday_short' : 'Ma',
603
+ 'wednesday_short' : 'Me',
604
+ 'thursday_short' : 'Je',
605
+ 'friday_short' : 'Ve',
606
+ 'saturday_short' : 'Sa',
607
+ 'sunday_short' : 'Di',
608
+
609
+ 'january' : 'janvier',
610
+ 'february' : 'février',
611
+ 'march' : 'mars',
612
+ 'april' : 'avril',
613
+ 'may' : 'mai',
614
+ 'june' : 'juin',
615
+ 'july' : 'juillet',
616
+ 'august' : 'août',
617
+ 'september' : 'septembre',
618
+ 'october' : 'octobre',
619
+ 'november' : 'novembre',
620
+ 'december' : 'décembre',
621
+
622
+ 'january_short' : 'jan',
623
+ 'february_short' : 'fév',
624
+ 'march_short' : 'mar',
625
+ 'april_short' : 'avr',
626
+ 'may_short' : 'mai',
627
+ 'june_short' : 'jun',
628
+ 'july_short' : 'jul',
629
+ 'august_short' : 'aoû',
630
+ 'september_short' : 'sep',
631
+ 'october_short' : 'oct',
632
+ 'november_short' : 'nov',
633
+ 'december_short' : 'dec',
634
+
635
+ 'today' : 'aujourd\'hui'
636
+ }),
637
+ 'nl' :
638
+ $H({
639
+ 'monday' : 'maandag',
640
+ 'tuesday' : 'dinsdag',
641
+ 'wednesday' : 'woensdag',
642
+ 'thursday' : 'donderdag',
643
+ 'friday' : 'vrijdag',
644
+ 'saturday' : 'zaterdag',
645
+ 'sunday' : 'zondag',
646
+
647
+ 'monday_short' : 'Ma',
648
+ 'tuesday_short' : 'Di',
649
+ 'wednesday_short' : 'Wo',
650
+ 'thursday_short' : 'Do',
651
+ 'friday_short' : 'Vr',
652
+ 'saturday_short' : 'Za',
653
+ 'sunday_short' : 'Zo',
654
+
655
+ 'january' : 'januari',
656
+ 'february' : 'februari',
657
+ 'march' : 'maart',
658
+ 'april' : 'april',
659
+ 'may' : 'mei',
660
+ 'june' : 'juni',
661
+ 'july' : 'juli',
662
+ 'august' : 'augustus',
663
+ 'september' : 'september',
664
+ 'october' : 'oktober',
665
+ 'november' : 'november',
666
+ 'december' : 'december',
667
+
668
+ 'january_short' : 'jan',
669
+ 'february_short' : 'feb',
670
+ 'march_short' : 'mrt',
671
+ 'april_short' : 'apr',
672
+ 'may_short' : 'mei',
673
+ 'june_short' : 'jun',
674
+ 'july_short' : 'jul',
675
+ 'august_short' : 'aug',
676
+ 'september_short' : 'sep',
677
+ 'october_short' : 'okt',
678
+ 'november_short' : 'nov',
679
+ 'december_short' : 'dec',
680
+
681
+ 'today' : 'vandaag'
682
+ }),
683
+ 'de' :
684
+ $H({
685
+ 'monday' : 'Montag',
686
+ 'tuesday' : 'Dienstag',
687
+ 'wednesday' : 'Mittwoch',
688
+ 'thursday' : 'Donnerstag',
689
+ 'friday' : 'Freitag',
690
+ 'saturday' : 'Samstag',
691
+ 'sunday' : 'Sonntag',
692
+
693
+ 'monday_short' : 'Mo',
694
+ 'tuesday_short' : 'Di',
695
+ 'wednesday_short' : 'Mi',
696
+ 'thursday_short' : 'Do',
697
+ 'friday_short' : 'Fr',
698
+ 'saturday_short' : 'Sa',
699
+ 'sunday_short' : 'So',
700
+
701
+ 'january' : 'Januar',
702
+ 'february' : 'Februar',
703
+ 'march' : 'März',
704
+ 'april' : 'April',
705
+ 'may' : 'Mai',
706
+ 'june' : 'Juni',
707
+ 'july' : 'Juli',
708
+ 'august' : 'August',
709
+ 'september' : 'September',
710
+ 'october' : 'Oktober',
711
+ 'november' : 'November',
712
+ 'december' : 'Dezemer',
713
+
714
+ 'january_short' : 'Jan',
715
+ 'february_short' : 'Feb',
716
+ 'march_short' : 'Mär',
717
+ 'april_short' : 'Apr',
718
+ 'may_short' : 'Mai',
719
+ 'june_short' : 'Jun',
720
+ 'july_short' : 'Jul',
721
+ 'august_short' : 'Aug',
722
+ 'september_short' : 'Sep',
723
+ 'october_short' : 'Okt',
724
+ 'november_short' : 'Nov',
725
+ 'december_short' : 'Dez',
726
+
727
+ 'today' : 'Heute'
728
+ })
729
+ });
730
+
731
+
732
+ Calendar.getMessageFor = function(key){
733
+
734
+ var lang = Calendar.language || 'en';
735
+ if (! Calendar.messagebundle.get(lang)){
736
+ lang = 'en';
737
+ }
738
+ return Calendar.messagebundle.get(lang).get(key);
739
+ };
740
+
741
+ Calendar.VERSION = '1.4';
742
+
743
+ Calendar.defaultDateFormat = '%Y-%m-%d';
744
+ Calendar.defaultDateTimeFormat = '%Y-%m-%d %H:%M';
745
+ Calendar.firstDayOfWeek = 0;
746
+ Calendar.weekendDays = [0,6];
747
+
748
+ // we need to postpone the initialization of these structures to let the page define the language of the page
749
+ Calendar.init = function(){
750
+
751
+ Calendar.DAY_NAMES = new Array(
752
+ Calendar.getMessageFor('sunday'),
753
+ Calendar.getMessageFor('monday'),
754
+ Calendar.getMessageFor('tuesday'),
755
+ Calendar.getMessageFor('wednesday'),
756
+ Calendar.getMessageFor('thursday'),
757
+ Calendar.getMessageFor('friday'),
758
+ Calendar.getMessageFor('saturday')
759
+ );
760
+
761
+ Calendar.SHORT_DAY_NAMES = new Array(
762
+ Calendar.getMessageFor('sunday_short'),
763
+ Calendar.getMessageFor('monday_short'),
764
+ Calendar.getMessageFor('tuesday_short'),
765
+ Calendar.getMessageFor('wednesday_short'),
766
+ Calendar.getMessageFor('thursday_short'),
767
+ Calendar.getMessageFor('friday_short'),
768
+ Calendar.getMessageFor('saturday_short')
769
+ );
770
+
771
+ Calendar.MONTH_NAMES = new Array(
772
+ Calendar.getMessageFor('january'),
773
+ Calendar.getMessageFor('february'),
774
+ Calendar.getMessageFor('march'),
775
+ Calendar.getMessageFor('april'),
776
+ Calendar.getMessageFor('may'),
777
+ Calendar.getMessageFor('june'),
778
+ Calendar.getMessageFor('july'),
779
+ Calendar.getMessageFor('august'),
780
+ Calendar.getMessageFor('september'),
781
+ Calendar.getMessageFor('october'),
782
+ Calendar.getMessageFor('november'),
783
+ Calendar.getMessageFor('december')
784
+ );
785
+
786
+ Calendar.SHORT_MONTH_NAMES = new Array(
787
+ Calendar.getMessageFor('january_short'),
788
+ Calendar.getMessageFor('february_short'),
789
+ Calendar.getMessageFor('march_short'),
790
+ Calendar.getMessageFor('april_short'),
791
+ Calendar.getMessageFor('may_short'),
792
+ Calendar.getMessageFor('june_short'),
793
+ Calendar.getMessageFor('july_short'),
794
+ Calendar.getMessageFor('august_short'),
795
+ Calendar.getMessageFor('september_short'),
796
+ Calendar.getMessageFor('october_short'),
797
+ Calendar.getMessageFor('november_short'),
798
+ Calendar.getMessageFor('december_short')
799
+ );
800
+ Calendar.init_done = true;
801
+ };
802
+
803
+ Calendar.NAV_PREVIOUS_YEAR = -2;
804
+ Calendar.NAV_PREVIOUS_MONTH = -1;
805
+ Calendar.NAV_TODAY = 0;
806
+ Calendar.NAV_NEXT_MONTH = 1;
807
+ Calendar.NAV_NEXT_YEAR = 2;
808
+
809
+ //------------------------------------------------------------------------------
810
+ // Static Methods
811
+ //------------------------------------------------------------------------------
812
+
813
+ // This gets called when the user presses a mouse button anywhere in the
814
+ // document, if the calendar is shown. If the click was outside the open
815
+ // calendar this function closes it.
816
+ Calendar._checkCalendar = function(event) {
817
+ if (!window._popupCalendar){
818
+ return false;
819
+ }
820
+ if (Element.descendantOf(Event.element(event), window._popupCalendar.container)){
821
+ return;
822
+ }
823
+ Calendar.closeHandler(window._popupCalendar);
824
+ return Event.stop(event);
825
+ };
826
+
827
+ //------------------------------------------------------------------------------
828
+ // Event Handlers
829
+ //------------------------------------------------------------------------------
830
+
831
+ Calendar.handleMouseDownEvent = function(event){
832
+ if (event.element().type == 'select-one'){ // ignore select elements - not escaping this in Safari leaves select boxes non-functional
833
+ return true;
834
+ }
835
+ Event.observe(document, 'mouseup', Calendar.handleMouseUpEvent);
836
+ Event.stop(event)
837
+ };
838
+
839
+ Calendar.handleMouseUpEvent = function(event){
840
+ var el = Event.element(event);
841
+ var calendar = el.calendar;
842
+ var isNewDate = false;
843
+
844
+
845
+ // If the element that was clicked on does not have an associated Calendar
846
+ // object, return as we have nothing to do.
847
+ if (!calendar) return false;
848
+
849
+ // Clicked on a day
850
+ if (typeof el.navAction == 'undefined') {
851
+
852
+ var dateWasDefined = true;
853
+ if (calendar.date == null){
854
+ dateWasDefined = false;
855
+ calendar.restoreDateAndCurrentElement();
856
+ }
857
+
858
+
859
+ if (calendar.currentDateElement) {
860
+ Element.removeClassName(calendar.currentDateElement, 'selected');
861
+
862
+ if (dateWasDefined && el == calendar.currentDateElement){
863
+ calendar.backupDateAndCurrentElement();
864
+
865
+ calendar.updateOuterField();
866
+
867
+ Event.stopObserving(document, 'mouseup', Calendar.handleMouseUpEvent);
868
+ return Event.stop(event);
869
+ }
870
+
871
+ Element.addClassName(el, 'selected');
872
+
873
+ calendar.shouldClose = (calendar.currentDateElement == el);
874
+
875
+ if (!calendar.shouldClose) {
876
+
877
+ calendar.currentDateElement = el;
878
+ }
879
+ }
880
+ calendar.date.setDateOnly(el.date);
881
+ isNewDate = true;
882
+
883
+ calendar.shouldClose = !el.hasClassName('otherDay');
884
+
885
+
886
+ var isOtherMonth = !calendar.shouldClose;
887
+ if (isOtherMonth) {
888
+ calendar.update(calendar.date);
889
+ }
890
+
891
+ if (! calendar.hideOnClickOnDay){ // override closing if calendar.hideOnClickOnDay is false
892
+ calendar.shouldClose = false;
893
+ }
894
+
895
+ } else { // Clicked on an action button
896
+
897
+ var date = new Date(calendar.dateOrDateBackedUp());
898
+
899
+ if (el.navAction == Calendar.NAV_TODAY){
900
+ date.setDateOnly(new Date());
901
+ }
902
+
903
+ var year = date.getFullYear();
904
+ var mon = date.getMonth();
905
+
906
+ function setMonth(m) {
907
+ var day = date.getDate();
908
+ var max = date.getMonthDays(m);
909
+ if (day > max) date.setDate(max);
910
+ date.setMonth(m);
911
+ }
912
+
913
+ switch (el.navAction) {
914
+
915
+ // Previous Year
916
+ case Calendar.NAV_PREVIOUS_YEAR:
917
+ if (year > calendar.minYear)
918
+ date.__setFullYear(year - 1);
919
+ break;
920
+
921
+ // Previous Month
922
+ case Calendar.NAV_PREVIOUS_MONTH:
923
+ if (mon > 0) {
924
+ setMonth(mon - 1);
925
+ }
926
+ else if (year-- > calendar.minYear) {
927
+ date.__setFullYear(year);
928
+ setMonth(11);
929
+ }
930
+ break;
931
+
932
+ // Today
933
+ case Calendar.NAV_TODAY:
934
+ break;
935
+
936
+ // Next Month
937
+ case Calendar.NAV_NEXT_MONTH:
938
+ if (mon < 11) {
939
+ setMonth(mon + 1);
940
+ }else if (year < calendar.maxYear) {
941
+ date.__setFullYear(year + 1);
942
+ setMonth(0);
943
+ }
944
+ break;
945
+
946
+ // Next Year
947
+ case Calendar.NAV_NEXT_YEAR:
948
+ if (year < calendar.maxYear){
949
+ date.__setFullYear(year + 1);
950
+ }
951
+ break;
952
+ }
953
+
954
+ if (!date.equalsTo(calendar.dateOrDateBackedUp())) {
955
+ calendar.updateIfDateDifferent(date);
956
+ isNewDate = true;
957
+ } // else if (el.navAction == 0) {
958
+ // isNewDate = (calendar.shouldClose = true);
959
+ // } // Hm, what did I mean with this code?
960
+ }
961
+
962
+ if (isNewDate && event) {
963
+ Calendar.selectHandler(calendar);
964
+ }
965
+
966
+ if (calendar.shouldClose && event) {
967
+ Calendar.closeHandler(calendar);
968
+ }
969
+
970
+ Event.stopObserving(document, 'mouseup', Calendar.handleMouseUpEvent);
971
+ return Event.stop(event);
972
+ };
973
+
974
+ Calendar.selectHandler = function(calendar){
975
+
976
+ // Update dateField value
977
+ calendar.updateOuterField();
978
+
979
+
980
+ // Call the close handler, if necessary
981
+ if (calendar.shouldClose) {
982
+ Calendar.closeHandler(calendar);
983
+ }
984
+ };
985
+
986
+ Calendar.closeHandler = function(calendar){
987
+ calendar.hide();
988
+ calendar.shouldClose = false;
989
+ };
990
+
991
+
992
+
993
+ // global object that remembers the calendar
994
+ window._popupCalendar = null;
995
+
996
+
997
+ //==============================================================================
998
+ //
999
+ // Date Object Patches
1000
+ //
1001
+ // This is pretty much untouched from the original. I really would like to get
1002
+ // rid of these patches if at all possible and find a cleaner way of
1003
+ // accomplishing the same things. It's a shame Prototype doesn't extend Date at
1004
+ // all.
1005
+ //
1006
+ //==============================================================================
1007
+
1008
+ Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
1009
+ Date.SECOND = 1000 /* milliseconds */
1010
+ Date.MINUTE = 60 * Date.SECOND
1011
+ Date.HOUR = 60 * Date.MINUTE
1012
+ Date.DAY = 24 * Date.HOUR
1013
+ Date.WEEK = 7 * Date.DAY
1014
+
1015
+ // Parses Date
1016
+ Date.parseDate = function(str, fmt) {
1017
+ if (str){
1018
+ str = new String(str);
1019
+ }else{
1020
+ str = new String('');
1021
+ }
1022
+ str = str.strip();
1023
+
1024
+ var today = new Date();
1025
+ var y = 0;
1026
+ var m = -1;
1027
+ var d = 0;
1028
+ var a = str.split(/\W+/);
1029
+ var b = fmt.match(/%./g);
1030
+ var i = 0, j = 0;
1031
+ var hr = 0;
1032
+ var min = 0;
1033
+
1034
+ for (i = 0; i < a.length; ++i) {
1035
+ if (!a[i]) continue;
1036
+ switch (b[i]) {
1037
+ case "%d":
1038
+ case "%e":
1039
+ d = parseInt(a[i], 10);
1040
+ break;
1041
+ case "%m":
1042
+ m = parseInt(a[i], 10) - 1;
1043
+ break;
1044
+ case "%Y":
1045
+ case "%y":
1046
+ y = parseInt(a[i], 10);
1047
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
1048
+ break;
1049
+ case "%b":
1050
+ case "%B":
1051
+ for (j = 0; j < 12; ++j) {
1052
+ if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
1053
+ m = j;
1054
+ break;
1055
+ }
1056
+ }
1057
+ break;
1058
+ case "%H":
1059
+ case "%I":
1060
+ case "%k":
1061
+ case "%l":
1062
+ hr = parseInt(a[i], 10);
1063
+ break;
1064
+ case "%P":
1065
+ case "%p":
1066
+ if (/pm/i.test(a[i]) && hr < 12)
1067
+ hr += 12;
1068
+ else if (/am/i.test(a[i]) && hr >= 12)
1069
+ hr -= 12;
1070
+ break;
1071
+ case "%M":
1072
+ min = parseInt(a[i], 10);
1073
+ break;
1074
+ }
1075
+ }
1076
+ if (isNaN(y)) y = today.getFullYear();
1077
+ if (isNaN(m)) m = today.getMonth();
1078
+ if (isNaN(d)) d = today.getDate();
1079
+ if (isNaN(hr)) hr = today.getHours();
1080
+ if (isNaN(min)) min = today.getMinutes();
1081
+ if (y != 0 && m != -1 && d != 0)
1082
+ return new Date(y, m, d, hr, min, 0);
1083
+ y = 0; m = -1; d = 0;
1084
+ for (i = 0; i < a.length; ++i) {
1085
+ if (a[i].search(/[a-zA-Z]+/) != -1) {
1086
+ var t = -1;
1087
+ for (j = 0; j < 12; ++j) {
1088
+ if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
1089
+ }
1090
+ if (t != -1) {
1091
+ if (m != -1) {
1092
+ d = m+1;
1093
+ }
1094
+ m = t;
1095
+ }
1096
+ } else if (parseInt(a[i], 10) <= 12 && m == -1) {
1097
+ m = a[i]-1;
1098
+ } else if (parseInt(a[i], 10) > 31 && y == 0) {
1099
+ y = parseInt(a[i], 10);
1100
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
1101
+ } else if (d == 0) {
1102
+ d = a[i];
1103
+ }
1104
+ }
1105
+ if (y == 0)
1106
+ y = today.getFullYear();
1107
+ if (m != -1 && d != 0)
1108
+ return new Date(y, m, d, hr, min, 0);
1109
+ return today;
1110
+ };
1111
+
1112
+ // Returns the number of days in the current month
1113
+ Date.prototype.getMonthDays = function(month) {
1114
+ var year = this.getFullYear()
1115
+ if (typeof month == "undefined")
1116
+ month = this.getMonth()
1117
+ if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
1118
+ return 29
1119
+ else
1120
+ return Date.DAYS_IN_MONTH[month]
1121
+ };
1122
+
1123
+ // Returns the number of day in the year
1124
+ Date.prototype.getDayOfYear = function() {
1125
+ var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
1126
+ var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
1127
+ var time = now - then;
1128
+ return Math.floor(time / Date.DAY);
1129
+ };
1130
+
1131
+ /** Returns the number of the week in year, as defined in ISO 8601. */
1132
+ Date.prototype.getWeekNumber = function() {
1133
+ var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
1134
+ var DoW = d.getDay();
1135
+ d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
1136
+ var ms = d.valueOf(); // GMT
1137
+ d.setMonth(0);
1138
+ d.setDate(4); // Thu in Week 1
1139
+ return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
1140
+ };
1141
+
1142
+ /** Checks date and time equality */
1143
+ Date.prototype.equalsTo = function(date) {
1144
+ return ((this.getFullYear() == date.getFullYear()) &&
1145
+ (this.getMonth() == date.getMonth()) &&
1146
+ (this.getDate() == date.getDate()) &&
1147
+ (this.getHours() == date.getHours()) &&
1148
+ (this.getMinutes() == date.getMinutes()));
1149
+ };
1150
+
1151
+ /** Set only the year, month, date parts (keep existing time) */
1152
+ Date.prototype.setDateOnly = function(date) {
1153
+ var tmp = new Date(date);
1154
+ this.setDate(1);
1155
+ this.__setFullYear(tmp.getFullYear());
1156
+ this.setMonth(tmp.getMonth());
1157
+ this.setDate(tmp.getDate());
1158
+ };
1159
+
1160
+ /** Prints the date in a string according to the given format. */
1161
+ Date.prototype.print = function (str) {
1162
+ var m = this.getMonth();
1163
+ var d = this.getDate();
1164
+ var y = this.getFullYear();
1165
+ var wn = this.getWeekNumber();
1166
+ var w = this.getDay();
1167
+ var s = {};
1168
+ var hr = this.getHours();
1169
+ var pm = (hr >= 12);
1170
+ var ir = (pm) ? (hr - 12) : hr;
1171
+ var dy = this.getDayOfYear();
1172
+ if (ir == 0)
1173
+ ir = 12;
1174
+ var min = this.getMinutes();
1175
+ var sec = this.getSeconds();
1176
+ s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
1177
+ s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
1178
+ s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
1179
+ s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
1180
+ // FIXME: %c : preferred date and time representation for the current locale
1181
+ s["%C"] = 1 + Math.floor(y / 100); // the century number
1182
+ s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
1183
+ s["%e"] = d; // the day of the month (range 1 to 31)
1184
+ // FIXME: %D : american date style: %m/%d/%y
1185
+ // FIXME: %E, %F, %G, %g, %h (man strftime)
1186
+ s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
1187
+ s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
1188
+ s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
1189
+ s["%k"] = hr; // hour, range 0 to 23 (24h format)
1190
+ s["%l"] = ir; // hour, range 1 to 12 (12h format)
1191
+ s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
1192
+ s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
1193
+ s["%n"] = "\n"; // a newline character
1194
+ s["%p"] = pm ? "PM" : "AM";
1195
+ s["%P"] = pm ? "pm" : "am";
1196
+ // FIXME: %r : the time in am/pm notation %I:%M:%S %p
1197
+ // FIXME: %R : the time in 24-hour notation %H:%M
1198
+ s["%s"] = Math.floor(this.getTime() / 1000);
1199
+ s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
1200
+ s["%t"] = "\t"; // a tab character
1201
+ // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
1202
+ s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
1203
+ s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
1204
+ s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
1205
+ // FIXME: %x : preferred date representation for the current locale without the time
1206
+ // FIXME: %X : preferred time representation for the current locale without the date
1207
+ s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
1208
+ s["%Y"] = y; // year with the century
1209
+ s["%%"] = "%"; // a literal '%' character
1210
+
1211
+ return str.gsub(/%./, function(match) { return s[match] || match });
1212
+ };
1213
+
1214
+
1215
+ Date.prototype.__setFullYear = function(y) {
1216
+ var d = new Date(this);
1217
+ d.setFullYear(y);
1218
+ if (d.getMonth() != this.getMonth())
1219
+ this.setDate(28);
1220
+ this.setFullYear(y);
1221
+ };
1222
+
package.xml CHANGED
@@ -1,19 +1,22 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Clockworkgeek_CalendarView</name>
4
- <version>0.3.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Replace date picker with CalendarView</summary>
10
- <description>Replaces the default (and ugly) (and buggy) javascript date picker with a newer, lightweight one from http://calendarview.org/</description>
11
- <notes>Can be skinned entirely by modifying skin/frontend/base/defaultcss/calendarview.css&#xD;
12
- Translations are provided in skin/frontend/default/french/js/calendarview.js and .../german/js/calendarview.js</notes>
13
- <authors><author><name>Clockworkgeek</name><user>auto-converted</user><email>nonproffessional@clockworkgeek.com</email></author></authors>
14
- <date>2012-12-29</date>
15
- <time>15:58:22</time>
16
- <contents><target name="magecommunity"><dir name="Clockworkgeek"><dir name="CalendarView"><dir name="Block"><dir name="Html"><file name="Date.php" hash="f2f6bb07e6bf26cd9e8ec53dcfdd3ab2"/></dir></dir><dir name="Helper"><file name="Data.php" hash="ec59157ac0545fcfc4ca89d437ff789c"/></dir><dir name="etc"><file name="config.xml" hash="2c2ea3a27a93771132b02443e8215482"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Clockworkgeek_CalendarView.xml" hash="e15dbdb8dff966babc0afffb340e76d7"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="calendarview.xml" hash="c5124aae4d0f96a878f3bc6ae20106e6"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><file name="calendarview.css" hash="d70521aa7c6b49cd295231c64c192160"/></dir><dir name="js"><file name="calendarview.js" hash="cc2dc9484e911511d046f7e8e5d8c47d"/></dir></dir></dir><dir name="default"><dir name="french"><dir name="js"><file name="calendarview.js" hash="588635391ce80b3d5c2db62458c31f86"/></dir></dir><dir name="german"><dir name="js"><file name="calendarview.js" hash="d065b6a3bbdd08dbce531b7cfd5b935f"/></dir></dir></dir></dir></target></contents>
 
 
 
17
  <compatible/>
18
- <dependencies/>
19
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Clockworkgeek_CalendarView</name>
4
+ <version>1.4.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Replace date picker with CalendarView</summary>
10
+ <description>Replaces the default (and ugly) (and buggy) javascript date picker with a newer, lightweight one from http://calendarview.org/&#xD;
11
+ </description>
12
+ <notes>Switched to version 1.4 of CalendarView as forked here https://github.com/clockworkgeek/calendarview. Version numbers of this extension should now mirror the JS widget.&#xD;
13
+ &#xD;
14
+ Localisation now follows the admin setting in System &gt; Configuration &gt; General &gt; Locale Options. There is no need to edit the skin files any more. To add more locales see the file /js/calendarview/i18n.js&#xD;
15
+ </notes>
16
+ <authors><author><name>Clockworkgeek</name><user>nonproffessional</user><email>nonproffessional@clockworkgeek.com</email></author></authors>
17
+ <date>2014-07-13</date>
18
+ <time>20:07:13</time>
19
+ <contents><target name="magecommunity"><dir name="Clockworkgeek"><dir name="CalendarView"><dir name="Block"><dir name="Html"><file name="Date.php" hash="88033157b18467dea1ff7eaaef819314"/></dir></dir><dir name="Helper"><file name="Data.php" hash="796e1c34398f91401f459d5751461665"/></dir><dir name="etc"><file name="config.xml" hash="d903a3a245a791e72821f9a402b6e273"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Clockworkgeek_CalendarView.xml" hash="e15dbdb8dff966babc0afffb340e76d7"/></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="calendarview.xml" hash="63802012b673918deae096bc4a8c8f26"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><dir name="calendarview"><file name="calendarview.css" hash="72e1b36973450f6a7d35902d9103d93c"/><file name="calendarview_ie.css" hash="048fa59cd71dfa6206c718b09702f26d"/></dir></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><dir name="calendarview"><file name="I18n.js" hash="9973ea4834fa32e28e3185b77767c6f4"/><file name="calendarview.js" hash="1e1e00fa9d8c3706e9fedc53247a9345"/></dir></dir></target></contents>
20
  <compatible/>
21
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
22
  </package>
skin/frontend/base/default/css/{calendarview.css → calendarview/calendarview.css} RENAMED
@@ -3,7 +3,8 @@ div.calendar
3
  {
4
  font-size: smaller;
5
  color: #000;
6
- z-index: 100;
 
7
  }
8
 
9
  div.calendar.popup
@@ -52,14 +53,22 @@ div.calendar tr.days td {
52
  }
53
 
54
  div.calendar tr.days td:hover,
55
- div.calendar td.button:hover
56
  {
57
  background-color: #34ABFA;
58
  cursor: pointer;
59
  }
60
 
 
 
 
 
 
 
 
 
61
  div.calendar tr.days td:active
62
- div.calendar td.button:active
63
  {
64
  background-color: #cde;
65
  }
@@ -81,3 +90,28 @@ div.calendar tr.days td.otherDay
81
  {
82
  color: #bbb;
83
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  {
4
  font-size: smaller;
5
  color: #000;
6
+ z-index: 5;
7
+ width: 217px;
8
  }
9
 
10
  div.calendar.popup
53
  }
54
 
55
  div.calendar tr.days td:hover,
56
+ div.calendar td.cvbutton:hover
57
  {
58
  background-color: #34ABFA;
59
  cursor: pointer;
60
  }
61
 
62
+
63
+ div.calendar tr td.closeButton:hover
64
+ {
65
+ background-color: #34ABFA;
66
+ cursor: pointer;
67
+ }
68
+
69
+
70
  div.calendar tr.days td:active
71
+ div.calendar td.cvbutton:active
72
  {
73
  background-color: #cde;
74
  }
90
  {
91
  color: #bbb;
92
  }
93
+
94
+ div.calendar tr.days td.disabled,
95
+ div.calendar tr.days td.disabled:hover
96
+ {
97
+ background-color: initial;
98
+ color: #bbb;
99
+ cursor: default;
100
+ text-shadow: 1px 1px 0 white;
101
+ }
102
+
103
+ div.calendar .draggableHandler{
104
+ cursor: move;
105
+ }
106
+
107
+ /* styles for the date_picker Rails plugin */
108
+ span.date_picker a.date_label{
109
+ margin-left: 5px;
110
+ margin-right: 5px;
111
+ text-decoration: none;
112
+ }
113
+ span.date_picker a.date_label:hover{text-decoration: line-through;}
114
+
115
+ span.date_picker span.trigger:hover{
116
+ cursor: pointer;
117
+ }
skin/frontend/base/default/css/calendarview/calendarview_ie.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ div.calendar {
2
+ width: 200px;
3
+ }
skin/frontend/base/default/js/calendarview.js DELETED
@@ -1,839 +0,0 @@
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
-
20
- var Calendar = Class.create()
21
-
22
- //------------------------------------------------------------------------------
23
- // Constants
24
- //------------------------------------------------------------------------------
25
-
26
- Calendar.VERSION = '1.2'
27
-
28
- Calendar.DAY_NAMES = new Array(
29
- 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
30
- 'Sunday'
31
- )
32
-
33
- Calendar.SHORT_DAY_NAMES = new Array(
34
- 'S', 'M', 'T', 'W', 'T', 'F', 'S', 'S'
35
- )
36
-
37
- Calendar.MONTH_NAMES = new Array(
38
- 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
39
- 'September', 'October', 'November', 'December'
40
- )
41
-
42
- Calendar.SHORT_MONTH_NAMES = new Array(
43
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
44
- 'Dec'
45
- )
46
-
47
- Calendar.NAV_PREVIOUS_YEAR = -2
48
- Calendar.NAV_PREVIOUS_MONTH = -1
49
- Calendar.NAV_TODAY = 0
50
- Calendar.NAV_NEXT_MONTH = 1
51
- Calendar.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.
60
- Calendar._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
-
73
- Calendar.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!
81
- Calendar.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
-
181
- Calendar.defaultSelectHandler = function(calendar)
182
- {
183
- if (!calendar.dateField) return false
184
-
185
- // Update dateField value
186
- if (calendar.dateField.tagName == 'DIV')
187
- Element.update(calendar.dateField, calendar.date.print(calendar.dateFormat))
188
- else if (calendar.dateField.tagName == 'INPUT') {
189
- calendar.dateField.value = calendar.date.print(calendar.dateFormat) }
190
-
191
- // Trigger the onchange callback on the dateField, if one has been defined
192
- if (typeof calendar.dateField.onchange == 'function')
193
- calendar.dateField.onchange()
194
-
195
- // Call the close handler, if necessary
196
- if (calendar.shouldClose) calendar.callCloseHandler()
197
- }
198
-
199
- Calendar.defaultCloseHandler = function(calendar)
200
- {
201
- calendar.hide()
202
- }
203
-
204
-
205
- //------------------------------------------------------------------------------
206
- // Calendar Setup
207
- //------------------------------------------------------------------------------
208
-
209
- Calendar.setup = function(params)
210
- {
211
-
212
- function param_default(name, def) {
213
- if (!params[name]) params[name] = def
214
- }
215
-
216
- param_default('dateField', null)
217
- param_default('triggerElement', null)
218
- param_default('parentElement', null)
219
- param_default('selectHandler', null)
220
- param_default('closeHandler', null)
221
-
222
- // In-Page Calendar
223
- if (params.parentElement)
224
- {
225
- var calendar = new Calendar(params.parentElement)
226
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
227
- if (params.dateFormat)
228
- calendar.setDateFormat(params.dateFormat)
229
- if (params.dateField) {
230
- calendar.setDateField(params.dateField)
231
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
232
- }
233
- calendar.show()
234
- return calendar
235
- }
236
-
237
- // Popup Calendars
238
- //
239
- // XXX There is significant optimization to be had here by creating the
240
- // calendar and storing it on the page, but then you will have issues with
241
- // multiple calendars on the same page.
242
- else
243
- {
244
- var triggerElement = $(params.triggerElement || params.dateField)
245
- triggerElement.onclick = function() {
246
- var calendar = new Calendar()
247
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
248
- calendar.setCloseHandler(params.closeHandler || Calendar.defaultCloseHandler)
249
- if (params.dateFormat)
250
- calendar.setDateFormat(params.dateFormat)
251
- if (params.dateField) {
252
- calendar.setDateField(params.dateField)
253
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
254
- }
255
- if (params.dateField)
256
- Date.parseDate(calendar.dateField.value || calendar.dateField.innerHTML, calendar.dateFormat)
257
- calendar.showAtElement(triggerElement)
258
- return calendar
259
- }
260
- }
261
-
262
- }
263
-
264
-
265
-
266
- //------------------------------------------------------------------------------
267
- // Calendar Instance
268
- //------------------------------------------------------------------------------
269
-
270
- Calendar.prototype = {
271
-
272
- // The HTML Container Element
273
- container: null,
274
-
275
- // Callbacks
276
- selectHandler: null,
277
- closeHandler: null,
278
-
279
- // Configuration
280
- minYear: 1900,
281
- maxYear: 2100,
282
- dateFormat: '%Y-%m-%d',
283
-
284
- // Dates
285
- date: new Date(),
286
- currentDateElement: null,
287
-
288
- // Status
289
- shouldClose: false,
290
- isPopup: true,
291
-
292
- dateField: null,
293
-
294
-
295
- //----------------------------------------------------------------------------
296
- // Initialize
297
- //----------------------------------------------------------------------------
298
-
299
- initialize: function(parent)
300
- {
301
- if (parent)
302
- this.create($(parent))
303
- else
304
- this.create()
305
- },
306
-
307
-
308
-
309
- //----------------------------------------------------------------------------
310
- // Update / (Re)initialize Calendar
311
- //----------------------------------------------------------------------------
312
-
313
- update: function(date)
314
- {
315
- var calendar = this
316
- var today = new Date()
317
- var thisYear = today.getFullYear()
318
- var thisMonth = today.getMonth()
319
- var thisDay = today.getDate()
320
- var month = date.getMonth();
321
- var dayOfMonth = date.getDate();
322
-
323
- // Ensure date is within the defined range
324
- if (date.getFullYear() < this.minYear)
325
- date.setFullYear(this.minYear)
326
- else if (date.getFullYear() > this.maxYear)
327
- date.setFullYear(this.maxYear)
328
-
329
- this.date = new Date(date)
330
-
331
- // Calculate the first day to display (including the previous month)
332
- date.setDate(1)
333
- date.setDate(-(date.getDay()) + 1)
334
-
335
- // Fill in the days of the month
336
- Element.getElementsBySelector(this.container, 'tbody tr').each(
337
- function(row, i) {
338
- var rowHasDays = false
339
- row.immediateDescendants().each(
340
- function(cell, j) {
341
- var day = date.getDate()
342
- var dayOfWeek = date.getDay()
343
- var isCurrentMonth = (date.getMonth() == month)
344
-
345
- // Reset classes on the cell
346
- cell.className = ''
347
- cell.date = new Date(date)
348
- cell.update(day)
349
-
350
- // Account for days of the month other than the current month
351
- if (!isCurrentMonth)
352
- cell.addClassName('otherDay')
353
- else
354
- rowHasDays = true
355
-
356
- // Ensure the current day is selected
357
- if (isCurrentMonth && day == dayOfMonth) {
358
- cell.addClassName('selected')
359
- calendar.currentDateElement = cell
360
- }
361
-
362
- // Today
363
- if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
364
- cell.addClassName('today')
365
-
366
- // Weekend
367
- if ([0, 6].indexOf(dayOfWeek) != -1)
368
- cell.addClassName('weekend')
369
-
370
- // Set the date to tommorrow
371
- date.setDate(day + 1)
372
- }
373
- )
374
- // Hide the extra row if it contains only days from another month
375
- !rowHasDays ? row.hide() : row.show()
376
- }
377
- )
378
-
379
- this.container.getElementsBySelector('td.title')[0].update(
380
- Calendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear()
381
- )
382
- },
383
-
384
-
385
-
386
- //----------------------------------------------------------------------------
387
- // Create/Draw the Calendar HTML Elements
388
- //----------------------------------------------------------------------------
389
-
390
- create: function(parent)
391
- {
392
-
393
- // If no parent was specified, assume that we are creating a popup calendar.
394
- if (!parent) {
395
- parent = document.getElementsByTagName('body')[0]
396
- this.isPopup = true
397
- } else {
398
- this.isPopup = false
399
- }
400
-
401
- // Calendar Table
402
- var table = new Element('table')
403
-
404
- // Calendar Header
405
- var thead = new Element('thead')
406
- table.appendChild(thead)
407
-
408
- // Title Placeholder
409
- var row = new Element('tr')
410
- var cell = new Element('td', { colSpan: 7 } )
411
- cell.addClassName('title')
412
- row.appendChild(cell)
413
- thead.appendChild(row)
414
-
415
- // Calendar Navigation
416
- row = new Element('tr')
417
- this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR)
418
- this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH)
419
- this._drawButtonCell(row, 'Today', 3, Calendar.NAV_TODAY)
420
- this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH)
421
- this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR)
422
- thead.appendChild(row)
423
-
424
- // Day Names
425
- row = new Element('tr')
426
- for (var i = 0; i < 7; ++i) {
427
- cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[i])
428
- if (i == 0 || i == 6)
429
- cell.addClassName('weekend')
430
- row.appendChild(cell)
431
- }
432
- thead.appendChild(row)
433
-
434
- // Calendar Days
435
- var tbody = table.appendChild(new Element('tbody'))
436
- for (i = 6; i > 0; --i) {
437
- row = tbody.appendChild(new Element('tr'))
438
- row.addClassName('days')
439
- for (var j = 7; j > 0; --j) {
440
- cell = row.appendChild(new Element('td'))
441
- cell.calendar = this
442
- }
443
- }
444
-
445
- // Calendar Container (div)
446
- this.container = new Element('div')
447
- this.container.addClassName('calendar')
448
- if (this.isPopup) {
449
- this.container.setStyle({ position: 'absolute', display: 'none' })
450
- this.container.addClassName('popup')
451
- }
452
- this.container.appendChild(table)
453
-
454
- // Initialize Calendar
455
- this.update(this.date)
456
-
457
- // Observe the container for mousedown events
458
- Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent)
459
-
460
- // Append to parent element
461
- parent.appendChild(this.container)
462
-
463
- },
464
-
465
- _drawButtonCell: function(parent, text, colSpan, navAction)
466
- {
467
- var cell = new Element('td')
468
- if (colSpan > 1) cell.colSpan = colSpan
469
- cell.className = 'button'
470
- cell.calendar = this
471
- cell.navAction = navAction
472
- cell.innerHTML = text
473
- cell.unselectable = 'on' // IE
474
- parent.appendChild(cell)
475
- return cell
476
- },
477
-
478
-
479
-
480
- //------------------------------------------------------------------------------
481
- // Callbacks
482
- //------------------------------------------------------------------------------
483
-
484
- // Calls the Select Handler (if defined)
485
- callSelectHandler: function()
486
- {
487
- if (this.selectHandler)
488
- this.selectHandler(this, this.date.print(this.dateFormat))
489
- },
490
-
491
- // Calls the Close Handler (if defined)
492
- callCloseHandler: function()
493
- {
494
- if (this.closeHandler)
495
- this.closeHandler(this)
496
- },
497
-
498
-
499
-
500
- //------------------------------------------------------------------------------
501
- // Calendar Display Functions
502
- //------------------------------------------------------------------------------
503
-
504
- // Shows the Calendar
505
- show: function()
506
- {
507
- this.container.show()
508
- if (this.isPopup) {
509
- window._popupCalendar = this
510
- Event.observe(document, 'mousedown', Calendar._checkCalendar)
511
- }
512
- },
513
-
514
- // Shows the calendar at the given absolute position
515
- showAt: function (x, y)
516
- {
517
- this.container.setStyle({ left: x + 'px', top: y + 'px' })
518
- this.show()
519
- },
520
-
521
- // Shows the Calendar at the coordinates of the provided element
522
- showAtElement: function(element)
523
- {
524
- var pos = Position.cumulativeOffset(element)
525
- this.showAt(pos[0], pos[1])
526
- },
527
-
528
- // Hides the Calendar
529
- hide: function()
530
- {
531
- if (this.isPopup)
532
- Event.stopObserving(document, 'mousedown', Calendar._checkCalendar)
533
- this.container.hide()
534
- },
535
-
536
-
537
-
538
- //------------------------------------------------------------------------------
539
- // Miscellaneous
540
- //------------------------------------------------------------------------------
541
-
542
- // Tries to identify the date represented in a string. If successful it also
543
- // calls this.setDate which moves the calendar to the given date.
544
- parseDate: function(str, format)
545
- {
546
- if (!format)
547
- format = this.dateFormat
548
- this.setDate(Date.parseDate(str, format))
549
- },
550
-
551
-
552
-
553
- //------------------------------------------------------------------------------
554
- // Getters/Setters
555
- //------------------------------------------------------------------------------
556
-
557
- setSelectHandler: function(selectHandler)
558
- {
559
- this.selectHandler = selectHandler
560
- },
561
-
562
- setCloseHandler: function(closeHandler)
563
- {
564
- this.closeHandler = closeHandler
565
- },
566
-
567
- setDate: function(date)
568
- {
569
- if (!date.equalsTo(this.date))
570
- this.update(date)
571
- },
572
-
573
- setDateFormat: function(format)
574
- {
575
- this.dateFormat = format
576
- },
577
-
578
- setDateField: function(field)
579
- {
580
- this.dateField = $(field)
581
- },
582
-
583
- setRange: function(minYear, maxYear)
584
- {
585
- this.minYear = minYear
586
- this.maxYear = maxYear
587
- }
588
-
589
- }
590
-
591
- // global object that remembers the calendar
592
- window._popupCalendar = null
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
- //==============================================================================
623
- //
624
- // Date Object Patches
625
- //
626
- // This is pretty much untouched from the original. I really would like to get
627
- // rid of these patches if at all possible and find a cleaner way of
628
- // accomplishing the same things. It's a shame Prototype doesn't extend Date at
629
- // all.
630
- //
631
- //==============================================================================
632
-
633
- Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
634
- Date.SECOND = 1000 /* milliseconds */
635
- Date.MINUTE = 60 * Date.SECOND
636
- Date.HOUR = 60 * Date.MINUTE
637
- Date.DAY = 24 * Date.HOUR
638
- Date.WEEK = 7 * Date.DAY
639
-
640
- // Parses Date
641
- Date.parseDate = function(str, fmt) {
642
- var today = new Date();
643
- var y = 0;
644
- var m = -1;
645
- var d = 0;
646
- var a = str.split(/\W+/);
647
- var b = fmt.match(/%./g);
648
- var i = 0, j = 0;
649
- var hr = 0;
650
- var min = 0;
651
-
652
- for (i = 0; i < a.length; ++i) {
653
- if (!a[i]) continue;
654
- switch (b[i]) {
655
- case "%d":
656
- case "%e":
657
- d = parseInt(a[i], 10);
658
- break;
659
- case "%m":
660
- m = parseInt(a[i], 10) - 1;
661
- break;
662
- case "%Y":
663
- case "%y":
664
- y = parseInt(a[i], 10);
665
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
666
- break;
667
- case "%b":
668
- case "%B":
669
- for (j = 0; j < 12; ++j) {
670
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
671
- m = j;
672
- break;
673
- }
674
- }
675
- break;
676
- case "%H":
677
- case "%I":
678
- case "%k":
679
- case "%l":
680
- hr = parseInt(a[i], 10);
681
- break;
682
- case "%P":
683
- case "%p":
684
- if (/pm/i.test(a[i]) && hr < 12)
685
- hr += 12;
686
- else if (/am/i.test(a[i]) && hr >= 12)
687
- hr -= 12;
688
- break;
689
- case "%M":
690
- min = parseInt(a[i], 10);
691
- break;
692
- }
693
- }
694
- if (isNaN(y)) y = today.getFullYear();
695
- if (isNaN(m)) m = today.getMonth();
696
- if (isNaN(d)) d = today.getDate();
697
- if (isNaN(hr)) hr = today.getHours();
698
- if (isNaN(min)) min = today.getMinutes();
699
- if (y != 0 && m != -1 && d != 0)
700
- return new Date(y, m, d, hr, min, 0);
701
- y = 0; m = -1; d = 0;
702
- for (i = 0; i < a.length; ++i) {
703
- if (a[i].search(/[a-zA-Z]+/) != -1) {
704
- var t = -1;
705
- for (j = 0; j < 12; ++j) {
706
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
707
- }
708
- if (t != -1) {
709
- if (m != -1) {
710
- d = m+1;
711
- }
712
- m = t;
713
- }
714
- } else if (parseInt(a[i], 10) <= 12 && m == -1) {
715
- m = a[i]-1;
716
- } else if (parseInt(a[i], 10) > 31 && y == 0) {
717
- y = parseInt(a[i], 10);
718
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
719
- } else if (d == 0) {
720
- d = a[i];
721
- }
722
- }
723
- if (y == 0)
724
- y = today.getFullYear();
725
- if (m != -1 && d != 0)
726
- return new Date(y, m, d, hr, min, 0);
727
- return today;
728
- };
729
-
730
- // Returns the number of days in the current month
731
- Date.prototype.getMonthDays = function(month) {
732
- var year = this.getFullYear()
733
- if (typeof month == "undefined")
734
- month = this.getMonth()
735
- if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
736
- return 29
737
- else
738
- return Date.DAYS_IN_MONTH[month]
739
- };
740
-
741
- // Returns the number of day in the year
742
- Date.prototype.getDayOfYear = function() {
743
- var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
744
- var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
745
- var time = now - then;
746
- return Math.floor(time / Date.DAY);
747
- };
748
-
749
- /** Returns the number of the week in year, as defined in ISO 8601. */
750
- Date.prototype.getWeekNumber = function() {
751
- var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
752
- var DoW = d.getDay();
753
- d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
754
- var ms = d.valueOf(); // GMT
755
- d.setMonth(0);
756
- d.setDate(4); // Thu in Week 1
757
- return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
758
- };
759
-
760
- /** Checks date and time equality */
761
- Date.prototype.equalsTo = function(date) {
762
- return ((this.getFullYear() == date.getFullYear()) &&
763
- (this.getMonth() == date.getMonth()) &&
764
- (this.getDate() == date.getDate()) &&
765
- (this.getHours() == date.getHours()) &&
766
- (this.getMinutes() == date.getMinutes()));
767
- };
768
-
769
- /** Set only the year, month, date parts (keep existing time) */
770
- Date.prototype.setDateOnly = function(date) {
771
- var tmp = new Date(date);
772
- this.setDate(1);
773
- this.setFullYear(tmp.getFullYear());
774
- this.setMonth(tmp.getMonth());
775
- this.setDate(tmp.getDate());
776
- };
777
-
778
- /** Prints the date in a string according to the given format. */
779
- Date.prototype.print = function (str) {
780
- var m = this.getMonth();
781
- var d = this.getDate();
782
- var y = this.getFullYear();
783
- var wn = this.getWeekNumber();
784
- var w = this.getDay();
785
- var s = {};
786
- var hr = this.getHours();
787
- var pm = (hr >= 12);
788
- var ir = (pm) ? (hr - 12) : hr;
789
- var dy = this.getDayOfYear();
790
- if (ir == 0)
791
- ir = 12;
792
- var min = this.getMinutes();
793
- var sec = this.getSeconds();
794
- s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
795
- s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
796
- s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
797
- s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
798
- // FIXME: %c : preferred date and time representation for the current locale
799
- s["%C"] = 1 + Math.floor(y / 100); // the century number
800
- s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
801
- s["%e"] = d; // the day of the month (range 1 to 31)
802
- // FIXME: %D : american date style: %m/%d/%y
803
- // FIXME: %E, %F, %G, %g, %h (man strftime)
804
- s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
805
- s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
806
- s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
807
- s["%k"] = hr; // hour, range 0 to 23 (24h format)
808
- s["%l"] = ir; // hour, range 1 to 12 (12h format)
809
- s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
810
- s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
811
- s["%n"] = "\n"; // a newline character
812
- s["%p"] = pm ? "PM" : "AM";
813
- s["%P"] = pm ? "pm" : "am";
814
- // FIXME: %r : the time in am/pm notation %I:%M:%S %p
815
- // FIXME: %R : the time in 24-hour notation %H:%M
816
- s["%s"] = Math.floor(this.getTime() / 1000);
817
- s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
818
- s["%t"] = "\t"; // a tab character
819
- // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
820
- s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
821
- s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
822
- s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
823
- // FIXME: %x : preferred date representation for the current locale without the time
824
- // FIXME: %X : preferred time representation for the current locale without the date
825
- s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
826
- s["%Y"] = y; // year with the century
827
- s["%%"] = "%"; // a literal '%' character
828
-
829
- return str.gsub(/%./, function(match) { return s[match] || match });
830
- };
831
-
832
- Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
833
- Date.prototype.setFullYear = function(y) {
834
- var d = new Date(this);
835
- d.__msh_oldSetFullYear(y);
836
- if (d.getMonth() != this.getMonth())
837
- this.setDate(28);
838
- this.__msh_oldSetFullYear(y);
839
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
skin/frontend/default/french/js/calendarview.js DELETED
@@ -1,839 +0,0 @@
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
-
20
- var Calendar = Class.create()
21
-
22
- //------------------------------------------------------------------------------
23
- // Constants
24
- //------------------------------------------------------------------------------
25
-
26
- Calendar.VERSION = '1.2'
27
-
28
- Calendar.DAY_NAMES = new Array(
29
- 'Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi',
30
- 'Dimanche'
31
- )
32
-
33
- Calendar.SHORT_DAY_NAMES = new Array(
34
- 'D', 'L', 'M', 'M', 'J', 'V', 'S', 'D'
35
- )
36
-
37
- Calendar.MONTH_NAMES = new Array(
38
- 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil', 'Août',
39
- 'Septembre', 'Octobre', 'Novembre', 'Décembre'
40
- )
41
-
42
- Calendar.SHORT_MONTH_NAMES = new Array(
43
- 'Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov',
44
- 'Déc'
45
- )
46
-
47
- Calendar.NAV_PREVIOUS_YEAR = -2
48
- Calendar.NAV_PREVIOUS_MONTH = -1
49
- Calendar.NAV_TODAY = 0
50
- Calendar.NAV_NEXT_MONTH = 1
51
- Calendar.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.
60
- Calendar._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
-
73
- Calendar.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!
81
- Calendar.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
-
181
- Calendar.defaultSelectHandler = function(calendar)
182
- {
183
- if (!calendar.dateField) return false
184
-
185
- // Update dateField value
186
- if (calendar.dateField.tagName == 'DIV')
187
- Element.update(calendar.dateField, calendar.date.print(calendar.dateFormat))
188
- else if (calendar.dateField.tagName == 'INPUT') {
189
- calendar.dateField.value = calendar.date.print(calendar.dateFormat) }
190
-
191
- // Trigger the onchange callback on the dateField, if one has been defined
192
- if (typeof calendar.dateField.onchange == 'function')
193
- calendar.dateField.onchange()
194
-
195
- // Call the close handler, if necessary
196
- if (calendar.shouldClose) calendar.callCloseHandler()
197
- }
198
-
199
- Calendar.defaultCloseHandler = function(calendar)
200
- {
201
- calendar.hide()
202
- }
203
-
204
-
205
- //------------------------------------------------------------------------------
206
- // Calendar Setup
207
- //------------------------------------------------------------------------------
208
-
209
- Calendar.setup = function(params)
210
- {
211
-
212
- function param_default(name, def) {
213
- if (!params[name]) params[name] = def
214
- }
215
-
216
- param_default('dateField', null)
217
- param_default('triggerElement', null)
218
- param_default('parentElement', null)
219
- param_default('selectHandler', null)
220
- param_default('closeHandler', null)
221
-
222
- // In-Page Calendar
223
- if (params.parentElement)
224
- {
225
- var calendar = new Calendar(params.parentElement)
226
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
227
- if (params.dateFormat)
228
- calendar.setDateFormat(params.dateFormat)
229
- if (params.dateField) {
230
- calendar.setDateField(params.dateField)
231
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
232
- }
233
- calendar.show()
234
- return calendar
235
- }
236
-
237
- // Popup Calendars
238
- //
239
- // XXX There is significant optimization to be had here by creating the
240
- // calendar and storing it on the page, but then you will have issues with
241
- // multiple calendars on the same page.
242
- else
243
- {
244
- var triggerElement = $(params.triggerElement || params.dateField)
245
- triggerElement.onclick = function() {
246
- var calendar = new Calendar()
247
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
248
- calendar.setCloseHandler(params.closeHandler || Calendar.defaultCloseHandler)
249
- if (params.dateFormat)
250
- calendar.setDateFormat(params.dateFormat)
251
- if (params.dateField) {
252
- calendar.setDateField(params.dateField)
253
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
254
- }
255
- if (params.dateField)
256
- Date.parseDate(calendar.dateField.value || calendar.dateField.innerHTML, calendar.dateFormat)
257
- calendar.showAtElement(triggerElement)
258
- return calendar
259
- }
260
- }
261
-
262
- }
263
-
264
-
265
-
266
- //------------------------------------------------------------------------------
267
- // Calendar Instance
268
- //------------------------------------------------------------------------------
269
-
270
- Calendar.prototype = {
271
-
272
- // The HTML Container Element
273
- container: null,
274
-
275
- // Callbacks
276
- selectHandler: null,
277
- closeHandler: null,
278
-
279
- // Configuration
280
- minYear: 1900,
281
- maxYear: 2100,
282
- dateFormat: '%Y-%m-%d',
283
-
284
- // Dates
285
- date: new Date(),
286
- currentDateElement: null,
287
-
288
- // Status
289
- shouldClose: false,
290
- isPopup: true,
291
-
292
- dateField: null,
293
-
294
-
295
- //----------------------------------------------------------------------------
296
- // Initialize
297
- //----------------------------------------------------------------------------
298
-
299
- initialize: function(parent)
300
- {
301
- if (parent)
302
- this.create($(parent))
303
- else
304
- this.create()
305
- },
306
-
307
-
308
-
309
- //----------------------------------------------------------------------------
310
- // Update / (Re)initialize Calendar
311
- //----------------------------------------------------------------------------
312
-
313
- update: function(date)
314
- {
315
- var calendar = this
316
- var today = new Date()
317
- var thisYear = today.getFullYear()
318
- var thisMonth = today.getMonth()
319
- var thisDay = today.getDate()
320
- var month = date.getMonth();
321
- var dayOfMonth = date.getDate();
322
-
323
- // Ensure date is within the defined range
324
- if (date.getFullYear() < this.minYear)
325
- date.setFullYear(this.minYear)
326
- else if (date.getFullYear() > this.maxYear)
327
- date.setFullYear(this.maxYear)
328
-
329
- this.date = new Date(date)
330
-
331
- // Calculate the first day to display (including the previous month)
332
- date.setDate(1)
333
- date.setDate(-(date.getDay()) + 1)
334
-
335
- // Fill in the days of the month
336
- Element.getElementsBySelector(this.container, 'tbody tr').each(
337
- function(row, i) {
338
- var rowHasDays = false
339
- row.immediateDescendants().each(
340
- function(cell, j) {
341
- var day = date.getDate()
342
- var dayOfWeek = date.getDay()
343
- var isCurrentMonth = (date.getMonth() == month)
344
-
345
- // Reset classes on the cell
346
- cell.className = ''
347
- cell.date = new Date(date)
348
- cell.update(day)
349
-
350
- // Account for days of the month other than the current month
351
- if (!isCurrentMonth)
352
- cell.addClassName('otherDay')
353
- else
354
- rowHasDays = true
355
-
356
- // Ensure the current day is selected
357
- if (isCurrentMonth && day == dayOfMonth) {
358
- cell.addClassName('selected')
359
- calendar.currentDateElement = cell
360
- }
361
-
362
- // Today
363
- if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
364
- cell.addClassName('today')
365
-
366
- // Weekend
367
- if ([0, 6].indexOf(dayOfWeek) != -1)
368
- cell.addClassName('weekend')
369
-
370
- // Set the date to tommorrow
371
- date.setDate(day + 1)
372
- }
373
- )
374
- // Hide the extra row if it contains only days from another month
375
- !rowHasDays ? row.hide() : row.show()
376
- }
377
- )
378
-
379
- this.container.getElementsBySelector('td.title')[0].update(
380
- Calendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear()
381
- )
382
- },
383
-
384
-
385
-
386
- //----------------------------------------------------------------------------
387
- // Create/Draw the Calendar HTML Elements
388
- //----------------------------------------------------------------------------
389
-
390
- create: function(parent)
391
- {
392
-
393
- // If no parent was specified, assume that we are creating a popup calendar.
394
- if (!parent) {
395
- parent = document.getElementsByTagName('body')[0]
396
- this.isPopup = true
397
- } else {
398
- this.isPopup = false
399
- }
400
-
401
- // Calendar Table
402
- var table = new Element('table')
403
-
404
- // Calendar Header
405
- var thead = new Element('thead')
406
- table.appendChild(thead)
407
-
408
- // Title Placeholder
409
- var row = new Element('tr')
410
- var cell = new Element('td', { colSpan: 7 } )
411
- cell.addClassName('title')
412
- row.appendChild(cell)
413
- thead.appendChild(row)
414
-
415
- // Calendar Navigation
416
- row = new Element('tr')
417
- this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR)
418
- this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH)
419
- this._drawButtonCell(row, 'Aujourd\'hui', 3, Calendar.NAV_TODAY)
420
- this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH)
421
- this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR)
422
- thead.appendChild(row)
423
-
424
- // Day Names
425
- row = new Element('tr')
426
- for (var i = 0; i < 7; ++i) {
427
- cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[i])
428
- if (i == 0 || i == 6)
429
- cell.addClassName('weekend')
430
- row.appendChild(cell)
431
- }
432
- thead.appendChild(row)
433
-
434
- // Calendar Days
435
- var tbody = table.appendChild(new Element('tbody'))
436
- for (i = 6; i > 0; --i) {
437
- row = tbody.appendChild(new Element('tr'))
438
- row.addClassName('days')
439
- for (var j = 7; j > 0; --j) {
440
- cell = row.appendChild(new Element('td'))
441
- cell.calendar = this
442
- }
443
- }
444
-
445
- // Calendar Container (div)
446
- this.container = new Element('div')
447
- this.container.addClassName('calendar')
448
- if (this.isPopup) {
449
- this.container.setStyle({ position: 'absolute', display: 'none' })
450
- this.container.addClassName('popup')
451
- }
452
- this.container.appendChild(table)
453
-
454
- // Initialize Calendar
455
- this.update(this.date)
456
-
457
- // Observe the container for mousedown events
458
- Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent)
459
-
460
- // Append to parent element
461
- parent.appendChild(this.container)
462
-
463
- },
464
-
465
- _drawButtonCell: function(parent, text, colSpan, navAction)
466
- {
467
- var cell = new Element('td')
468
- if (colSpan > 1) cell.colSpan = colSpan
469
- cell.className = 'button'
470
- cell.calendar = this
471
- cell.navAction = navAction
472
- cell.innerHTML = text
473
- cell.unselectable = 'on' // IE
474
- parent.appendChild(cell)
475
- return cell
476
- },
477
-
478
-
479
-
480
- //------------------------------------------------------------------------------
481
- // Callbacks
482
- //------------------------------------------------------------------------------
483
-
484
- // Calls the Select Handler (if defined)
485
- callSelectHandler: function()
486
- {
487
- if (this.selectHandler)
488
- this.selectHandler(this, this.date.print(this.dateFormat))
489
- },
490
-
491
- // Calls the Close Handler (if defined)
492
- callCloseHandler: function()
493
- {
494
- if (this.closeHandler)
495
- this.closeHandler(this)
496
- },
497
-
498
-
499
-
500
- //------------------------------------------------------------------------------
501
- // Calendar Display Functions
502
- //------------------------------------------------------------------------------
503
-
504
- // Shows the Calendar
505
- show: function()
506
- {
507
- this.container.show()
508
- if (this.isPopup) {
509
- window._popupCalendar = this
510
- Event.observe(document, 'mousedown', Calendar._checkCalendar)
511
- }
512
- },
513
-
514
- // Shows the calendar at the given absolute position
515
- showAt: function (x, y)
516
- {
517
- this.container.setStyle({ left: x + 'px', top: y + 'px' })
518
- this.show()
519
- },
520
-
521
- // Shows the Calendar at the coordinates of the provided element
522
- showAtElement: function(element)
523
- {
524
- var pos = Position.cumulativeOffset(element)
525
- this.showAt(pos[0], pos[1])
526
- },
527
-
528
- // Hides the Calendar
529
- hide: function()
530
- {
531
- if (this.isPopup)
532
- Event.stopObserving(document, 'mousedown', Calendar._checkCalendar)
533
- this.container.hide()
534
- },
535
-
536
-
537
-
538
- //------------------------------------------------------------------------------
539
- // Miscellaneous
540
- //------------------------------------------------------------------------------
541
-
542
- // Tries to identify the date represented in a string. If successful it also
543
- // calls this.setDate which moves the calendar to the given date.
544
- parseDate: function(str, format)
545
- {
546
- if (!format)
547
- format = this.dateFormat
548
- this.setDate(Date.parseDate(str, format))
549
- },
550
-
551
-
552
-
553
- //------------------------------------------------------------------------------
554
- // Getters/Setters
555
- //------------------------------------------------------------------------------
556
-
557
- setSelectHandler: function(selectHandler)
558
- {
559
- this.selectHandler = selectHandler
560
- },
561
-
562
- setCloseHandler: function(closeHandler)
563
- {
564
- this.closeHandler = closeHandler
565
- },
566
-
567
- setDate: function(date)
568
- {
569
- if (!date.equalsTo(this.date))
570
- this.update(date)
571
- },
572
-
573
- setDateFormat: function(format)
574
- {
575
- this.dateFormat = format
576
- },
577
-
578
- setDateField: function(field)
579
- {
580
- this.dateField = $(field)
581
- },
582
-
583
- setRange: function(minYear, maxYear)
584
- {
585
- this.minYear = minYear
586
- this.maxYear = maxYear
587
- }
588
-
589
- }
590
-
591
- // global object that remembers the calendar
592
- window._popupCalendar = null
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
- //==============================================================================
623
- //
624
- // Date Object Patches
625
- //
626
- // This is pretty much untouched from the original. I really would like to get
627
- // rid of these patches if at all possible and find a cleaner way of
628
- // accomplishing the same things. It's a shame Prototype doesn't extend Date at
629
- // all.
630
- //
631
- //==============================================================================
632
-
633
- Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
634
- Date.SECOND = 1000 /* milliseconds */
635
- Date.MINUTE = 60 * Date.SECOND
636
- Date.HOUR = 60 * Date.MINUTE
637
- Date.DAY = 24 * Date.HOUR
638
- Date.WEEK = 7 * Date.DAY
639
-
640
- // Parses Date
641
- Date.parseDate = function(str, fmt) {
642
- var today = new Date();
643
- var y = 0;
644
- var m = -1;
645
- var d = 0;
646
- var a = str.split(/\W+/);
647
- var b = fmt.match(/%./g);
648
- var i = 0, j = 0;
649
- var hr = 0;
650
- var min = 0;
651
-
652
- for (i = 0; i < a.length; ++i) {
653
- if (!a[i]) continue;
654
- switch (b[i]) {
655
- case "%d":
656
- case "%e":
657
- d = parseInt(a[i], 10);
658
- break;
659
- case "%m":
660
- m = parseInt(a[i], 10) - 1;
661
- break;
662
- case "%Y":
663
- case "%y":
664
- y = parseInt(a[i], 10);
665
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
666
- break;
667
- case "%b":
668
- case "%B":
669
- for (j = 0; j < 12; ++j) {
670
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
671
- m = j;
672
- break;
673
- }
674
- }
675
- break;
676
- case "%H":
677
- case "%I":
678
- case "%k":
679
- case "%l":
680
- hr = parseInt(a[i], 10);
681
- break;
682
- case "%P":
683
- case "%p":
684
- if (/pm/i.test(a[i]) && hr < 12)
685
- hr += 12;
686
- else if (/am/i.test(a[i]) && hr >= 12)
687
- hr -= 12;
688
- break;
689
- case "%M":
690
- min = parseInt(a[i], 10);
691
- break;
692
- }
693
- }
694
- if (isNaN(y)) y = today.getFullYear();
695
- if (isNaN(m)) m = today.getMonth();
696
- if (isNaN(d)) d = today.getDate();
697
- if (isNaN(hr)) hr = today.getHours();
698
- if (isNaN(min)) min = today.getMinutes();
699
- if (y != 0 && m != -1 && d != 0)
700
- return new Date(y, m, d, hr, min, 0);
701
- y = 0; m = -1; d = 0;
702
- for (i = 0; i < a.length; ++i) {
703
- if (a[i].search(/[a-zA-Z]+/) != -1) {
704
- var t = -1;
705
- for (j = 0; j < 12; ++j) {
706
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
707
- }
708
- if (t != -1) {
709
- if (m != -1) {
710
- d = m+1;
711
- }
712
- m = t;
713
- }
714
- } else if (parseInt(a[i], 10) <= 12 && m == -1) {
715
- m = a[i]-1;
716
- } else if (parseInt(a[i], 10) > 31 && y == 0) {
717
- y = parseInt(a[i], 10);
718
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
719
- } else if (d == 0) {
720
- d = a[i];
721
- }
722
- }
723
- if (y == 0)
724
- y = today.getFullYear();
725
- if (m != -1 && d != 0)
726
- return new Date(y, m, d, hr, min, 0);
727
- return today;
728
- };
729
-
730
- // Returns the number of days in the current month
731
- Date.prototype.getMonthDays = function(month) {
732
- var year = this.getFullYear()
733
- if (typeof month == "undefined")
734
- month = this.getMonth()
735
- if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
736
- return 29
737
- else
738
- return Date.DAYS_IN_MONTH[month]
739
- };
740
-
741
- // Returns the number of day in the year
742
- Date.prototype.getDayOfYear = function() {
743
- var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
744
- var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
745
- var time = now - then;
746
- return Math.floor(time / Date.DAY);
747
- };
748
-
749
- /** Returns the number of the week in year, as defined in ISO 8601. */
750
- Date.prototype.getWeekNumber = function() {
751
- var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
752
- var DoW = d.getDay();
753
- d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
754
- var ms = d.valueOf(); // GMT
755
- d.setMonth(0);
756
- d.setDate(4); // Thu in Week 1
757
- return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
758
- };
759
-
760
- /** Checks date and time equality */
761
- Date.prototype.equalsTo = function(date) {
762
- return ((this.getFullYear() == date.getFullYear()) &&
763
- (this.getMonth() == date.getMonth()) &&
764
- (this.getDate() == date.getDate()) &&
765
- (this.getHours() == date.getHours()) &&
766
- (this.getMinutes() == date.getMinutes()));
767
- };
768
-
769
- /** Set only the year, month, date parts (keep existing time) */
770
- Date.prototype.setDateOnly = function(date) {
771
- var tmp = new Date(date);
772
- this.setDate(1);
773
- this.setFullYear(tmp.getFullYear());
774
- this.setMonth(tmp.getMonth());
775
- this.setDate(tmp.getDate());
776
- };
777
-
778
- /** Prints the date in a string according to the given format. */
779
- Date.prototype.print = function (str) {
780
- var m = this.getMonth();
781
- var d = this.getDate();
782
- var y = this.getFullYear();
783
- var wn = this.getWeekNumber();
784
- var w = this.getDay();
785
- var s = {};
786
- var hr = this.getHours();
787
- var pm = (hr >= 12);
788
- var ir = (pm) ? (hr - 12) : hr;
789
- var dy = this.getDayOfYear();
790
- if (ir == 0)
791
- ir = 12;
792
- var min = this.getMinutes();
793
- var sec = this.getSeconds();
794
- s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
795
- s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
796
- s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
797
- s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
798
- // FIXME: %c : preferred date and time representation for the current locale
799
- s["%C"] = 1 + Math.floor(y / 100); // the century number
800
- s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
801
- s["%e"] = d; // the day of the month (range 1 to 31)
802
- // FIXME: %D : american date style: %m/%d/%y
803
- // FIXME: %E, %F, %G, %g, %h (man strftime)
804
- s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
805
- s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
806
- s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
807
- s["%k"] = hr; // hour, range 0 to 23 (24h format)
808
- s["%l"] = ir; // hour, range 1 to 12 (12h format)
809
- s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
810
- s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
811
- s["%n"] = "\n"; // a newline character
812
- s["%p"] = pm ? "PM" : "AM";
813
- s["%P"] = pm ? "pm" : "am";
814
- // FIXME: %r : the time in am/pm notation %I:%M:%S %p
815
- // FIXME: %R : the time in 24-hour notation %H:%M
816
- s["%s"] = Math.floor(this.getTime() / 1000);
817
- s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
818
- s["%t"] = "\t"; // a tab character
819
- // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
820
- s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
821
- s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
822
- s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
823
- // FIXME: %x : preferred date representation for the current locale without the time
824
- // FIXME: %X : preferred time representation for the current locale without the date
825
- s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
826
- s["%Y"] = y; // year with the century
827
- s["%%"] = "%"; // a literal '%' character
828
-
829
- return str.gsub(/%./, function(match) { return s[match] || match });
830
- };
831
-
832
- Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
833
- Date.prototype.setFullYear = function(y) {
834
- var d = new Date(this);
835
- d.__msh_oldSetFullYear(y);
836
- if (d.getMonth() != this.getMonth())
837
- this.setDate(28);
838
- this.__msh_oldSetFullYear(y);
839
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
skin/frontend/default/german/js/calendarview.js DELETED
@@ -1,839 +0,0 @@
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
-
20
- var Calendar = Class.create()
21
-
22
- //------------------------------------------------------------------------------
23
- // Constants
24
- //------------------------------------------------------------------------------
25
-
26
- Calendar.VERSION = '1.2'
27
-
28
- Calendar.DAY_NAMES = new Array(
29
- 'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag',
30
- 'Sonntag'
31
- )
32
-
33
- Calendar.SHORT_DAY_NAMES = new Array(
34
- 'S', 'M', 'D', 'M', 'D', 'F', 'S', 'S'
35
- )
36
-
37
- Calendar.MONTH_NAMES = new Array(
38
- 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August',
39
- 'September', 'Oktober', 'November', 'Dezember'
40
- )
41
-
42
- Calendar.SHORT_MONTH_NAMES = new Array(
43
- 'Jan', 'Feb', 'März', 'Apr', 'Mai', 'Juni', 'Juli', 'Aug', 'Sep', 'Okt', 'Nov',
44
- 'Dez'
45
- )
46
-
47
- Calendar.NAV_PREVIOUS_YEAR = -2
48
- Calendar.NAV_PREVIOUS_MONTH = -1
49
- Calendar.NAV_TODAY = 0
50
- Calendar.NAV_NEXT_MONTH = 1
51
- Calendar.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.
60
- Calendar._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
-
73
- Calendar.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!
81
- Calendar.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
-
181
- Calendar.defaultSelectHandler = function(calendar)
182
- {
183
- if (!calendar.dateField) return false
184
-
185
- // Update dateField value
186
- if (calendar.dateField.tagName == 'DIV')
187
- Element.update(calendar.dateField, calendar.date.print(calendar.dateFormat))
188
- else if (calendar.dateField.tagName == 'INPUT') {
189
- calendar.dateField.value = calendar.date.print(calendar.dateFormat) }
190
-
191
- // Trigger the onchange callback on the dateField, if one has been defined
192
- if (typeof calendar.dateField.onchange == 'function')
193
- calendar.dateField.onchange()
194
-
195
- // Call the close handler, if necessary
196
- if (calendar.shouldClose) calendar.callCloseHandler()
197
- }
198
-
199
- Calendar.defaultCloseHandler = function(calendar)
200
- {
201
- calendar.hide()
202
- }
203
-
204
-
205
- //------------------------------------------------------------------------------
206
- // Calendar Setup
207
- //------------------------------------------------------------------------------
208
-
209
- Calendar.setup = function(params)
210
- {
211
-
212
- function param_default(name, def) {
213
- if (!params[name]) params[name] = def
214
- }
215
-
216
- param_default('dateField', null)
217
- param_default('triggerElement', null)
218
- param_default('parentElement', null)
219
- param_default('selectHandler', null)
220
- param_default('closeHandler', null)
221
-
222
- // In-Page Calendar
223
- if (params.parentElement)
224
- {
225
- var calendar = new Calendar(params.parentElement)
226
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
227
- if (params.dateFormat)
228
- calendar.setDateFormat(params.dateFormat)
229
- if (params.dateField) {
230
- calendar.setDateField(params.dateField)
231
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
232
- }
233
- calendar.show()
234
- return calendar
235
- }
236
-
237
- // Popup Calendars
238
- //
239
- // XXX There is significant optimization to be had here by creating the
240
- // calendar and storing it on the page, but then you will have issues with
241
- // multiple calendars on the same page.
242
- else
243
- {
244
- var triggerElement = $(params.triggerElement || params.dateField)
245
- triggerElement.onclick = function() {
246
- var calendar = new Calendar()
247
- calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
248
- calendar.setCloseHandler(params.closeHandler || Calendar.defaultCloseHandler)
249
- if (params.dateFormat)
250
- calendar.setDateFormat(params.dateFormat)
251
- if (params.dateField) {
252
- calendar.setDateField(params.dateField)
253
- calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
254
- }
255
- if (params.dateField)
256
- Date.parseDate(calendar.dateField.value || calendar.dateField.innerHTML, calendar.dateFormat)
257
- calendar.showAtElement(triggerElement)
258
- return calendar
259
- }
260
- }
261
-
262
- }
263
-
264
-
265
-
266
- //------------------------------------------------------------------------------
267
- // Calendar Instance
268
- //------------------------------------------------------------------------------
269
-
270
- Calendar.prototype = {
271
-
272
- // The HTML Container Element
273
- container: null,
274
-
275
- // Callbacks
276
- selectHandler: null,
277
- closeHandler: null,
278
-
279
- // Configuration
280
- minYear: 1900,
281
- maxYear: 2100,
282
- dateFormat: '%Y-%m-%d',
283
-
284
- // Dates
285
- date: new Date(),
286
- currentDateElement: null,
287
-
288
- // Status
289
- shouldClose: false,
290
- isPopup: true,
291
-
292
- dateField: null,
293
-
294
-
295
- //----------------------------------------------------------------------------
296
- // Initialize
297
- //----------------------------------------------------------------------------
298
-
299
- initialize: function(parent)
300
- {
301
- if (parent)
302
- this.create($(parent))
303
- else
304
- this.create()
305
- },
306
-
307
-
308
-
309
- //----------------------------------------------------------------------------
310
- // Update / (Re)initialize Calendar
311
- //----------------------------------------------------------------------------
312
-
313
- update: function(date)
314
- {
315
- var calendar = this
316
- var today = new Date()
317
- var thisYear = today.getFullYear()
318
- var thisMonth = today.getMonth()
319
- var thisDay = today.getDate()
320
- var month = date.getMonth();
321
- var dayOfMonth = date.getDate();
322
-
323
- // Ensure date is within the defined range
324
- if (date.getFullYear() < this.minYear)
325
- date.setFullYear(this.minYear)
326
- else if (date.getFullYear() > this.maxYear)
327
- date.setFullYear(this.maxYear)
328
-
329
- this.date = new Date(date)
330
-
331
- // Calculate the first day to display (including the previous month)
332
- date.setDate(1)
333
- date.setDate(-(date.getDay()) + 1)
334
-
335
- // Fill in the days of the month
336
- Element.getElementsBySelector(this.container, 'tbody tr').each(
337
- function(row, i) {
338
- var rowHasDays = false
339
- row.immediateDescendants().each(
340
- function(cell, j) {
341
- var day = date.getDate()
342
- var dayOfWeek = date.getDay()
343
- var isCurrentMonth = (date.getMonth() == month)
344
-
345
- // Reset classes on the cell
346
- cell.className = ''
347
- cell.date = new Date(date)
348
- cell.update(day)
349
-
350
- // Account for days of the month other than the current month
351
- if (!isCurrentMonth)
352
- cell.addClassName('otherDay')
353
- else
354
- rowHasDays = true
355
-
356
- // Ensure the current day is selected
357
- if (isCurrentMonth && day == dayOfMonth) {
358
- cell.addClassName('selected')
359
- calendar.currentDateElement = cell
360
- }
361
-
362
- // Today
363
- if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
364
- cell.addClassName('today')
365
-
366
- // Weekend
367
- if ([0, 6].indexOf(dayOfWeek) != -1)
368
- cell.addClassName('weekend')
369
-
370
- // Set the date to tommorrow
371
- date.setDate(day + 1)
372
- }
373
- )
374
- // Hide the extra row if it contains only days from another month
375
- !rowHasDays ? row.hide() : row.show()
376
- }
377
- )
378
-
379
- this.container.getElementsBySelector('td.title')[0].update(
380
- Calendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear()
381
- )
382
- },
383
-
384
-
385
-
386
- //----------------------------------------------------------------------------
387
- // Create/Draw the Calendar HTML Elements
388
- //----------------------------------------------------------------------------
389
-
390
- create: function(parent)
391
- {
392
-
393
- // If no parent was specified, assume that we are creating a popup calendar.
394
- if (!parent) {
395
- parent = document.getElementsByTagName('body')[0]
396
- this.isPopup = true
397
- } else {
398
- this.isPopup = false
399
- }
400
-
401
- // Calendar Table
402
- var table = new Element('table')
403
-
404
- // Calendar Header
405
- var thead = new Element('thead')
406
- table.appendChild(thead)
407
-
408
- // Title Placeholder
409
- var row = new Element('tr')
410
- var cell = new Element('td', { colSpan: 7 } )
411
- cell.addClassName('title')
412
- row.appendChild(cell)
413
- thead.appendChild(row)
414
-
415
- // Calendar Navigation
416
- row = new Element('tr')
417
- this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR)
418
- this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH)
419
- this._drawButtonCell(row, 'Heute', 3, Calendar.NAV_TODAY)
420
- this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH)
421
- this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR)
422
- thead.appendChild(row)
423
-
424
- // Day Names
425
- row = new Element('tr')
426
- for (var i = 0; i < 7; ++i) {
427
- cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[i])
428
- if (i == 0 || i == 6)
429
- cell.addClassName('weekend')
430
- row.appendChild(cell)
431
- }
432
- thead.appendChild(row)
433
-
434
- // Calendar Days
435
- var tbody = table.appendChild(new Element('tbody'))
436
- for (i = 6; i > 0; --i) {
437
- row = tbody.appendChild(new Element('tr'))
438
- row.addClassName('days')
439
- for (var j = 7; j > 0; --j) {
440
- cell = row.appendChild(new Element('td'))
441
- cell.calendar = this
442
- }
443
- }
444
-
445
- // Calendar Container (div)
446
- this.container = new Element('div')
447
- this.container.addClassName('calendar')
448
- if (this.isPopup) {
449
- this.container.setStyle({ position: 'absolute', display: 'none' })
450
- this.container.addClassName('popup')
451
- }
452
- this.container.appendChild(table)
453
-
454
- // Initialize Calendar
455
- this.update(this.date)
456
-
457
- // Observe the container for mousedown events
458
- Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent)
459
-
460
- // Append to parent element
461
- parent.appendChild(this.container)
462
-
463
- },
464
-
465
- _drawButtonCell: function(parent, text, colSpan, navAction)
466
- {
467
- var cell = new Element('td')
468
- if (colSpan > 1) cell.colSpan = colSpan
469
- cell.className = 'button'
470
- cell.calendar = this
471
- cell.navAction = navAction
472
- cell.innerHTML = text
473
- cell.unselectable = 'on' // IE
474
- parent.appendChild(cell)
475
- return cell
476
- },
477
-
478
-
479
-
480
- //------------------------------------------------------------------------------
481
- // Callbacks
482
- //------------------------------------------------------------------------------
483
-
484
- // Calls the Select Handler (if defined)
485
- callSelectHandler: function()
486
- {
487
- if (this.selectHandler)
488
- this.selectHandler(this, this.date.print(this.dateFormat))
489
- },
490
-
491
- // Calls the Close Handler (if defined)
492
- callCloseHandler: function()
493
- {
494
- if (this.closeHandler)
495
- this.closeHandler(this)
496
- },
497
-
498
-
499
-
500
- //------------------------------------------------------------------------------
501
- // Calendar Display Functions
502
- //------------------------------------------------------------------------------
503
-
504
- // Shows the Calendar
505
- show: function()
506
- {
507
- this.container.show()
508
- if (this.isPopup) {
509
- window._popupCalendar = this
510
- Event.observe(document, 'mousedown', Calendar._checkCalendar)
511
- }
512
- },
513
-
514
- // Shows the calendar at the given absolute position
515
- showAt: function (x, y)
516
- {
517
- this.container.setStyle({ left: x + 'px', top: y + 'px' })
518
- this.show()
519
- },
520
-
521
- // Shows the Calendar at the coordinates of the provided element
522
- showAtElement: function(element)
523
- {
524
- var pos = Position.cumulativeOffset(element)
525
- this.showAt(pos[0], pos[1])
526
- },
527
-
528
- // Hides the Calendar
529
- hide: function()
530
- {
531
- if (this.isPopup)
532
- Event.stopObserving(document, 'mousedown', Calendar._checkCalendar)
533
- this.container.hide()
534
- },
535
-
536
-
537
-
538
- //------------------------------------------------------------------------------
539
- // Miscellaneous
540
- //------------------------------------------------------------------------------
541
-
542
- // Tries to identify the date represented in a string. If successful it also
543
- // calls this.setDate which moves the calendar to the given date.
544
- parseDate: function(str, format)
545
- {
546
- if (!format)
547
- format = this.dateFormat
548
- this.setDate(Date.parseDate(str, format))
549
- },
550
-
551
-
552
-
553
- //------------------------------------------------------------------------------
554
- // Getters/Setters
555
- //------------------------------------------------------------------------------
556
-
557
- setSelectHandler: function(selectHandler)
558
- {
559
- this.selectHandler = selectHandler
560
- },
561
-
562
- setCloseHandler: function(closeHandler)
563
- {
564
- this.closeHandler = closeHandler
565
- },
566
-
567
- setDate: function(date)
568
- {
569
- if (!date.equalsTo(this.date))
570
- this.update(date)
571
- },
572
-
573
- setDateFormat: function(format)
574
- {
575
- this.dateFormat = format
576
- },
577
-
578
- setDateField: function(field)
579
- {
580
- this.dateField = $(field)
581
- },
582
-
583
- setRange: function(minYear, maxYear)
584
- {
585
- this.minYear = minYear
586
- this.maxYear = maxYear
587
- }
588
-
589
- }
590
-
591
- // global object that remembers the calendar
592
- window._popupCalendar = null
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
- //==============================================================================
623
- //
624
- // Date Object Patches
625
- //
626
- // This is pretty much untouched from the original. I really would like to get
627
- // rid of these patches if at all possible and find a cleaner way of
628
- // accomplishing the same things. It's a shame Prototype doesn't extend Date at
629
- // all.
630
- //
631
- //==============================================================================
632
-
633
- Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
634
- Date.SECOND = 1000 /* milliseconds */
635
- Date.MINUTE = 60 * Date.SECOND
636
- Date.HOUR = 60 * Date.MINUTE
637
- Date.DAY = 24 * Date.HOUR
638
- Date.WEEK = 7 * Date.DAY
639
-
640
- // Parses Date
641
- Date.parseDate = function(str, fmt) {
642
- var today = new Date();
643
- var y = 0;
644
- var m = -1;
645
- var d = 0;
646
- var a = str.split(/\W+/);
647
- var b = fmt.match(/%./g);
648
- var i = 0, j = 0;
649
- var hr = 0;
650
- var min = 0;
651
-
652
- for (i = 0; i < a.length; ++i) {
653
- if (!a[i]) continue;
654
- switch (b[i]) {
655
- case "%d":
656
- case "%e":
657
- d = parseInt(a[i], 10);
658
- break;
659
- case "%m":
660
- m = parseInt(a[i], 10) - 1;
661
- break;
662
- case "%Y":
663
- case "%y":
664
- y = parseInt(a[i], 10);
665
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
666
- break;
667
- case "%b":
668
- case "%B":
669
- for (j = 0; j < 12; ++j) {
670
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
671
- m = j;
672
- break;
673
- }
674
- }
675
- break;
676
- case "%H":
677
- case "%I":
678
- case "%k":
679
- case "%l":
680
- hr = parseInt(a[i], 10);
681
- break;
682
- case "%P":
683
- case "%p":
684
- if (/pm/i.test(a[i]) && hr < 12)
685
- hr += 12;
686
- else if (/am/i.test(a[i]) && hr >= 12)
687
- hr -= 12;
688
- break;
689
- case "%M":
690
- min = parseInt(a[i], 10);
691
- break;
692
- }
693
- }
694
- if (isNaN(y)) y = today.getFullYear();
695
- if (isNaN(m)) m = today.getMonth();
696
- if (isNaN(d)) d = today.getDate();
697
- if (isNaN(hr)) hr = today.getHours();
698
- if (isNaN(min)) min = today.getMinutes();
699
- if (y != 0 && m != -1 && d != 0)
700
- return new Date(y, m, d, hr, min, 0);
701
- y = 0; m = -1; d = 0;
702
- for (i = 0; i < a.length; ++i) {
703
- if (a[i].search(/[a-zA-Z]+/) != -1) {
704
- var t = -1;
705
- for (j = 0; j < 12; ++j) {
706
- if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
707
- }
708
- if (t != -1) {
709
- if (m != -1) {
710
- d = m+1;
711
- }
712
- m = t;
713
- }
714
- } else if (parseInt(a[i], 10) <= 12 && m == -1) {
715
- m = a[i]-1;
716
- } else if (parseInt(a[i], 10) > 31 && y == 0) {
717
- y = parseInt(a[i], 10);
718
- (y < 100) && (y += (y > 29) ? 1900 : 2000);
719
- } else if (d == 0) {
720
- d = a[i];
721
- }
722
- }
723
- if (y == 0)
724
- y = today.getFullYear();
725
- if (m != -1 && d != 0)
726
- return new Date(y, m, d, hr, min, 0);
727
- return today;
728
- };
729
-
730
- // Returns the number of days in the current month
731
- Date.prototype.getMonthDays = function(month) {
732
- var year = this.getFullYear()
733
- if (typeof month == "undefined")
734
- month = this.getMonth()
735
- if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
736
- return 29
737
- else
738
- return Date.DAYS_IN_MONTH[month]
739
- };
740
-
741
- // Returns the number of day in the year
742
- Date.prototype.getDayOfYear = function() {
743
- var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
744
- var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
745
- var time = now - then;
746
- return Math.floor(time / Date.DAY);
747
- };
748
-
749
- /** Returns the number of the week in year, as defined in ISO 8601. */
750
- Date.prototype.getWeekNumber = function() {
751
- var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
752
- var DoW = d.getDay();
753
- d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
754
- var ms = d.valueOf(); // GMT
755
- d.setMonth(0);
756
- d.setDate(4); // Thu in Week 1
757
- return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
758
- };
759
-
760
- /** Checks date and time equality */
761
- Date.prototype.equalsTo = function(date) {
762
- return ((this.getFullYear() == date.getFullYear()) &&
763
- (this.getMonth() == date.getMonth()) &&
764
- (this.getDate() == date.getDate()) &&
765
- (this.getHours() == date.getHours()) &&
766
- (this.getMinutes() == date.getMinutes()));
767
- };
768
-
769
- /** Set only the year, month, date parts (keep existing time) */
770
- Date.prototype.setDateOnly = function(date) {
771
- var tmp = new Date(date);
772
- this.setDate(1);
773
- this.setFullYear(tmp.getFullYear());
774
- this.setMonth(tmp.getMonth());
775
- this.setDate(tmp.getDate());
776
- };
777
-
778
- /** Prints the date in a string according to the given format. */
779
- Date.prototype.print = function (str) {
780
- var m = this.getMonth();
781
- var d = this.getDate();
782
- var y = this.getFullYear();
783
- var wn = this.getWeekNumber();
784
- var w = this.getDay();
785
- var s = {};
786
- var hr = this.getHours();
787
- var pm = (hr >= 12);
788
- var ir = (pm) ? (hr - 12) : hr;
789
- var dy = this.getDayOfYear();
790
- if (ir == 0)
791
- ir = 12;
792
- var min = this.getMinutes();
793
- var sec = this.getSeconds();
794
- s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
795
- s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
796
- s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
797
- s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
798
- // FIXME: %c : preferred date and time representation for the current locale
799
- s["%C"] = 1 + Math.floor(y / 100); // the century number
800
- s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
801
- s["%e"] = d; // the day of the month (range 1 to 31)
802
- // FIXME: %D : american date style: %m/%d/%y
803
- // FIXME: %E, %F, %G, %g, %h (man strftime)
804
- s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
805
- s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
806
- s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
807
- s["%k"] = hr; // hour, range 0 to 23 (24h format)
808
- s["%l"] = ir; // hour, range 1 to 12 (12h format)
809
- s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
810
- s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
811
- s["%n"] = "\n"; // a newline character
812
- s["%p"] = pm ? "PM" : "AM";
813
- s["%P"] = pm ? "pm" : "am";
814
- // FIXME: %r : the time in am/pm notation %I:%M:%S %p
815
- // FIXME: %R : the time in 24-hour notation %H:%M
816
- s["%s"] = Math.floor(this.getTime() / 1000);
817
- s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
818
- s["%t"] = "\t"; // a tab character
819
- // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
820
- s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
821
- s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
822
- s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
823
- // FIXME: %x : preferred date representation for the current locale without the time
824
- // FIXME: %X : preferred time representation for the current locale without the date
825
- s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
826
- s["%Y"] = y; // year with the century
827
- s["%%"] = "%"; // a literal '%' character
828
-
829
- return str.gsub(/%./, function(match) { return s[match] || match });
830
- };
831
-
832
- Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
833
- Date.prototype.setFullYear = function(y) {
834
- var d = new Date(this);
835
- d.__msh_oldSetFullYear(y);
836
- if (d.getMonth() != this.getMonth())
837
- this.setDate(28);
838
- this.__msh_oldSetFullYear(y);
839
- }