right-rails 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +50 -0
  3. data/Rakefile +23 -0
  4. data/generators/right_rails/right_rails_generator.rb +41 -0
  5. data/generators/right_rails/templates/iframed.html.erb +10 -0
  6. data/generators/right_scaffold/right_scaffold_generator.rb +53 -0
  7. data/generators/right_scaffold/templates/controller.rb +99 -0
  8. data/generators/right_scaffold/templates/helper.rb +2 -0
  9. data/generators/right_scaffold/templates/layout.html.erb +18 -0
  10. data/generators/right_scaffold/templates/style.css +54 -0
  11. data/generators/right_scaffold/templates/view__form.html.erb +16 -0
  12. data/generators/right_scaffold/templates/view__item.html.erb +13 -0
  13. data/generators/right_scaffold/templates/view_edit.html.erb +6 -0
  14. data/generators/right_scaffold/templates/view_index.html.erb +9 -0
  15. data/generators/right_scaffold/templates/view_new.html.erb +5 -0
  16. data/generators/right_scaffold/templates/view_show.html.erb +10 -0
  17. data/init.rb +12 -0
  18. data/javascripts/right-autocompleter-src.js +303 -0
  19. data/javascripts/right-autocompleter.js +9 -0
  20. data/javascripts/right-behavior-src.js +240 -0
  21. data/javascripts/right-behavior.js +8 -0
  22. data/javascripts/right-calendar-src.js +855 -0
  23. data/javascripts/right-calendar.js +9 -0
  24. data/javascripts/right-dnd-src.js +555 -0
  25. data/javascripts/right-dnd.js +9 -0
  26. data/javascripts/right-effects-src.js +425 -0
  27. data/javascripts/right-effects.js +6 -0
  28. data/javascripts/right-events-src.js +369 -0
  29. data/javascripts/right-events.js +6 -0
  30. data/javascripts/right-json-src.js +176 -0
  31. data/javascripts/right-json.js +6 -0
  32. data/javascripts/right-lightbox-src.js +597 -0
  33. data/javascripts/right-lightbox.js +9 -0
  34. data/javascripts/right-rails-src.js +269 -0
  35. data/javascripts/right-rails.js +9 -0
  36. data/javascripts/right-rater-src.js +248 -0
  37. data/javascripts/right-rater.js +9 -0
  38. data/javascripts/right-selectable-src.js +507 -0
  39. data/javascripts/right-selectable.js +7 -0
  40. data/javascripts/right-slider-src.js +291 -0
  41. data/javascripts/right-slider.js +7 -0
  42. data/javascripts/right-sortable-src.js +221 -0
  43. data/javascripts/right-sortable.js +9 -0
  44. data/javascripts/right-src.js +4939 -0
  45. data/javascripts/right-tabs-src.js +776 -0
  46. data/javascripts/right-tabs.js +6 -0
  47. data/javascripts/right-tooltips-src.js +130 -0
  48. data/javascripts/right-tooltips.js +9 -0
  49. data/javascripts/right-ui-i18n-de.js +29 -0
  50. data/javascripts/right-ui-i18n-en-us.js +11 -0
  51. data/javascripts/right-ui-i18n-es.js +29 -0
  52. data/javascripts/right-ui-i18n-fr.js +29 -0
  53. data/javascripts/right-ui-i18n-jp.js +33 -0
  54. data/javascripts/right-ui-i18n-ru.js +29 -0
  55. data/javascripts/right-ui-i18n-uk.js +29 -0
  56. data/javascripts/right.js +10 -0
  57. data/lib/right-rails.rb +11 -0
  58. data/lib/right_rails/controller_extensions.rb +85 -0
  59. data/lib/right_rails/helpers/basic.rb +111 -0
  60. data/lib/right_rails/helpers/forms.rb +239 -0
  61. data/lib/right_rails/helpers/misc.rb +164 -0
  62. data/lib/right_rails/helpers/rails.rb +166 -0
  63. data/lib/right_rails/helpers.rb +5 -0
  64. data/lib/right_rails/java_script_generator.rb +313 -0
  65. data/lib/right_rails.rb +6 -0
  66. data/spec/lib/right_rails/controller_extensions_spec.rb +60 -0
  67. data/spec/lib/right_rails/helpers/basic_spec.rb +74 -0
  68. data/spec/lib/right_rails/helpers/forms_spec.rb +51 -0
  69. data/spec/lib/right_rails/helpers/misc_spec.rb +120 -0
  70. data/spec/lib/right_rails/helpers/rails_spec.rb +149 -0
  71. data/spec/lib/right_rails/java_script_generator_spec.rb +317 -0
  72. data/spec/spec.opts +5 -0
  73. data/spec/spec_helper.rb +15 -0
  74. metadata +128 -0
@@ -0,0 +1,855 @@
1
+ /**
2
+ * The calendar widget implemented with RightJS
3
+ *
4
+ * Home page: http://rightjs.org/ui/calendar
5
+ *
6
+ * @copyright (C) 2009 Nikolay V. Nemshilov aka St.
7
+ */
8
+ if (!RightJS) { throw "Gimme RightJS. Please." };
9
+
10
+ /**
11
+ * The calendar widget for RightJS
12
+ *
13
+ *
14
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
15
+ */
16
+ var Calendar = new Class(Observer, {
17
+ extend: {
18
+ EVENTS: $w('show hide select done'),
19
+
20
+ Options: {
21
+ format: 'ISO', // a key out of the predefined formats or a format string
22
+ showTime: null, // null for automatic, or true|false to enforce
23
+ showButtons: false,
24
+ minDate: null,
25
+ maxDate: null,
26
+ firstDay: 1, // 1 for Monday, 0 for Sunday
27
+ fxName: 'fade', // set to null if you don't wanna any fx
28
+ fxDuration: 200,
29
+ numberOfMonths: 1, // a number or [x, y] greed definition
30
+ timePeriod: 1, // the timepicker minimal periods (in minutes, might be bigger than 60)
31
+ checkTags: '*',
32
+ relName: 'calendar',
33
+ twentyFourHour: null, // null for automatic, or true|false to enforce
34
+ listYears: false // show/hide the years listing buttons
35
+ },
36
+
37
+ Formats: {
38
+ ISO: '%Y-%m-%d',
39
+ POSIX: '%Y/%m/%d',
40
+ EUR: '%d-%m-%Y',
41
+ US: '%m/%d/%Y'
42
+ },
43
+
44
+ i18n: {
45
+ Done: 'Done',
46
+ Now: 'Now',
47
+ Next: 'Next Month',
48
+ Prev: 'Previous Month',
49
+ NextYear: 'Next Year',
50
+ PrevYear: 'Prev Year',
51
+
52
+ dayNames: $w('Sunday Monday Tuesday Wednesday Thursday Friday Saturday'),
53
+ dayNamesShort: $w('Sun Mon Tue Wed Thu Fri Sat'),
54
+ dayNamesMin: $w('Su Mo Tu We Th Fr Sa'),
55
+ monthNames: $w('January February March April May June July August September October November December'),
56
+ monthNamesShort: $w('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec')
57
+ },
58
+
59
+ // scans for the auto-discoverable calendar inputs
60
+ rescan: function() {
61
+ var key = Calendar.Options.relName;
62
+ var rel_id_re = new RegExp(key+'\\[(.+?)\\]');
63
+
64
+ $$(Calendar.Options.checkTags+'[rel*='+key+']').each(function(element) {
65
+ var data = element.get('data-'+key+'-options');
66
+ var calendar = new Calendar(eval('('+data+')') || {});
67
+
68
+ var rel_id = element.get('rel').match(rel_id_re);
69
+ if (rel_id) {
70
+ var input = $(rel_id[1]);
71
+ if (input) {
72
+ calendar.assignTo(input, element);
73
+ }
74
+ } else {
75
+ calendar.assignTo(element);
76
+ }
77
+ });
78
+ }
79
+ },
80
+
81
+ /**
82
+ * Basic constructor
83
+ *
84
+ * @param Object options
85
+ */
86
+ initialize: function(options) {
87
+ this.$super(options);
88
+
89
+ this.element = $E('div', {'class': 'right-calendar'});
90
+ this.build().connectEvents().setDate(new Date());
91
+ },
92
+
93
+ /**
94
+ * additional options processing
95
+ *
96
+ * @param Object options
97
+ * @return Calendar this
98
+ */
99
+ setOptions: function(user_options) {
100
+ this.$super(user_options);
101
+
102
+ var klass = this.constructor;
103
+ var options = this.options;
104
+
105
+ with (this.options) {
106
+ // merging the i18n tables
107
+ options.i18n = {};
108
+
109
+ for (var key in klass.i18n) {
110
+ i18n[key] = isArray(klass.i18n[key]) ? klass.i18n[key].clone() : klass.i18n[key];
111
+ }
112
+ $ext(i18n, (user_options || {}).i18n);
113
+
114
+ // defining the current days sequence
115
+ options.dayNames = i18n.dayNamesMin;
116
+ if (firstDay) {
117
+ dayNames.push(dayNames.shift());
118
+ }
119
+
120
+ // the monthes table cleaning up
121
+ if (!isArray(numberOfMonths)) {
122
+ numberOfMonths = [numberOfMonths, 1];
123
+ }
124
+
125
+ // min/max dates preprocessing
126
+ if (minDate) minDate = this.parse(minDate);
127
+ if (maxDate) {
128
+ maxDate = this.parse(maxDate);
129
+ maxDate.setDate(maxDate.getDate() + 1);
130
+ }
131
+
132
+ // format catching up
133
+ format = (klass.Formats[format] || format).trim();
134
+
135
+ // setting up the showTime option
136
+ if (showTime === null) {
137
+ showTime = format.search(/%[HkIl]/) > -1;
138
+ }
139
+
140
+ // setting up the 24-hours format
141
+ if (twentyFourHour === null) {
142
+ twentyFourHour = format.search(/%[Il]/) < 0;
143
+ }
144
+
145
+ // enforcing the 24 hours format if the time threshold is some weird number
146
+ if (timePeriod > 60 && 12 % (timePeriod/60).ceil()) {
147
+ twentyFourHour = true;
148
+ }
149
+ }
150
+
151
+ return this;
152
+ },
153
+
154
+ /**
155
+ * Sets the date on the calendar
156
+ *
157
+ * @param Date date or String date
158
+ * @return Calendar this
159
+ */
160
+ setDate: function(date) {
161
+ this.date = this.prevDate = this.parse(date);
162
+ return this.update();
163
+ },
164
+
165
+ /**
166
+ * Returns the current date on the calendar
167
+ *
168
+ * @return Date currently selected date on the calendar
169
+ */
170
+ getDate: function() {
171
+ return this.date;
172
+ },
173
+
174
+ /**
175
+ * Hides the calendar
176
+ *
177
+ * @return Calendar this
178
+ */
179
+ hide: function() {
180
+ this.element.hide(this.options.fxName, {duration: this.options.fxDuration});
181
+ Calendar.current = null;
182
+ return this;
183
+ },
184
+
185
+ /**
186
+ * Shows the calendar
187
+ *
188
+ * @param Object {x,y} optional position
189
+ * @return Calendar this
190
+ */
191
+ show: function(position) {
192
+ this.element.show(this.options.fxName, {duration: this.options.fxDuration});
193
+ Calendar.current = this;
194
+ return this;
195
+ },
196
+
197
+ /**
198
+ * Inserts the calendar into the element making it inlined
199
+ *
200
+ * @param Element element or String element id
201
+ * @param String optional position top/bottom/before/after/instead, 'bottom' is default
202
+ * @return Calendar this
203
+ */
204
+ insertTo: function(element, position) {
205
+ this.element.addClass('right-calendar-inline').insertTo(element, position);
206
+ return this;
207
+ }
208
+ });
209
+
210
+ /**
211
+ * This module handles the calendar elemnts building/updating processes
212
+ *
213
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
214
+ */
215
+ Calendar.include({
216
+
217
+ // protected
218
+
219
+ // updates the calendar view
220
+ update: function(date) {
221
+ var date = new Date(date || this.date), options = this.options;
222
+
223
+ var monthes = this.element.select('div.right-calendar-month');
224
+ var monthes_num = monthes.length;
225
+
226
+ for (var i=-(monthes_num - monthes_num/2).ceil()+1; i < (monthes_num - monthes_num/2).floor()+1; i++) {
227
+ var month_date = new Date(date);
228
+ month_date.setMonth(date.getMonth() + i);
229
+
230
+ this.updateMonth(monthes.shift(), month_date);
231
+ }
232
+
233
+ this.updateNextPrevMonthButtons(date, monthes_num);
234
+
235
+ if (options.showTime) {
236
+ this.hours.value = options.timePeriod < 60 ? date.getHours() :
237
+ (date.getHours()/(options.timePeriod/60)).round() * (options.timePeriod/60);
238
+
239
+ this.minutes.value = (date.getMinutes() / (options.timePeriod % 60)).round() * options.timePeriod;
240
+ }
241
+
242
+ return this;
243
+ },
244
+
245
+ // updates a single month-block with the given date
246
+ updateMonth: function(element, date) {
247
+ // getting the number of days in the month
248
+ date.setDate(32);
249
+ var days_number = 32 - date.getDate();
250
+ date.setMonth(date.getMonth()-1);
251
+
252
+ var cur_day = (this.date.getTime() / 86400000).ceil();
253
+
254
+ // collecting the elements to update
255
+ var rows = element.select('tbody tr');
256
+ var cells = rows.shift().select('td');
257
+ element.select('tbody td').each(function(td) {
258
+ td.innerHTML = '';
259
+ td.className = 'right-calendar-day-blank';
260
+ });
261
+
262
+ var options = this.options;
263
+
264
+ for (var i=1; i <= days_number; i++) {
265
+ date.setDate(i);
266
+ var day_num = date.getDay();
267
+
268
+ if (this.options.firstDay) {
269
+ day_num = day_num ? day_num-1 : 6;
270
+ }
271
+
272
+ cells[day_num].innerHTML = ''+i;
273
+ cells[day_num].className = cur_day == (date.getTime() / 86400000).ceil() ? 'right-calendar-day-selected' : '';
274
+
275
+ if ((options.minDate && options.minDate > date) || (options.maxDate && options.maxDate < date))
276
+ cells[day_num].className = 'right-calendar-day-disabled';
277
+
278
+ cells[day_num].date = new Date(date);
279
+
280
+ if (day_num == 6) {
281
+ cells = rows.shift().select('td');
282
+ }
283
+ }
284
+
285
+ var caption = (options.listYears ? options.i18n.monthNamesShort[date.getMonth()] + ',' :
286
+ options.i18n.monthNames[date.getMonth()])+' '+date.getFullYear();
287
+
288
+ element.first('div.right-calendar-month-caption').update(caption);
289
+ },
290
+
291
+ updateNextPrevMonthButtons: function(date, monthes_num) {
292
+ var options = this.options;
293
+ if (options.minDate) {
294
+ var beginning = new Date(date.getFullYear(),0,1,0,0,0);
295
+ var min_date = new Date(options.minDate.getFullYear(),0,1,0,0,0);
296
+
297
+ this.hasPrevYear = beginning > min_date;
298
+
299
+ beginning.setMonth(date.getMonth() - (monthes_num - monthes_num/2).ceil());
300
+ min_date.setMonth(options.minDate.getMonth());
301
+
302
+ this.hasPrevMonth = beginning >= min_date;
303
+ } else {
304
+ this.hasPrevMonth = this.hasPrevYear = true;
305
+ }
306
+
307
+ if (options.maxDate) {
308
+ var end = new Date(date);
309
+ var max_date = new Date(options.maxDate);
310
+ [end, max_date].each(function(date) {
311
+ date.setDate(32);
312
+ date.setMonth(date.getMonth() - 1);
313
+ date.setDate(32 - date.getDate());
314
+ date.setHours(0);
315
+ date.setMinutes(0);
316
+ date.setSeconds(0);
317
+ date.setMilliseconds(0);
318
+ });
319
+
320
+ this.hasNextMonth = end < max_date;
321
+
322
+ // checking the next year
323
+ [end, max_date].each('setMonth', 0);
324
+ this.hasNextYear = end < max_date;
325
+ } else {
326
+ this.hasNextMonth = this.hasNextYear = true;
327
+ }
328
+
329
+ this.nextButton[this.hasNextMonth ? 'removeClass':'addClass']('right-ui-button-disabled');
330
+ this.prevButton[this.hasPrevMonth ? 'removeClass':'addClass']('right-ui-button-disabled');
331
+
332
+ if (this.nextYearButton) {
333
+ this.nextYearButton[this.hasNextYear ? 'removeClass':'addClass']('right-ui-button-disabled');
334
+ this.prevYearButton[this.hasPrevYear ? 'removeClass':'addClass']('right-ui-button-disabled');
335
+ }
336
+ },
337
+
338
+ // builds the calendar
339
+ build: function() {
340
+ this.buildSwaps();
341
+
342
+ // building the calendars greed
343
+ var greed = tbody = $E('table', {'class': 'right-calendar-greed'}).insertTo(this.element);
344
+ var options = this.options;
345
+ if (Browser.OLD) tbody = $E('tbody').insertTo(greed);
346
+
347
+ for (var y=0; y < options.numberOfMonths[1]; y++) {
348
+ var row = $E('tr').insertTo(tbody);
349
+ for (var x=0; x < options.numberOfMonths[0]; x++) {
350
+ $E('td').insertTo(row).insert(this.buildMonth());
351
+ }
352
+ }
353
+
354
+ if (options.showTime) this.buildTime();
355
+ this.buildButtons();
356
+
357
+ return this;
358
+ },
359
+
360
+ // builds the monthes swapping buttons
361
+ buildSwaps: function() {
362
+ var i18n = this.options.i18n;
363
+
364
+ this.prevButton = $E('div', {'class': 'right-ui-button right-calendar-prev-button',
365
+ html: '&lsaquo;', title: i18n.Prev}).insertTo(this.element);
366
+ this.nextButton = $E('div', {'class': 'right-ui-button right-calendar-next-button',
367
+ html: '&rsaquo;', title: i18n.Next}).insertTo(this.element);
368
+
369
+ if (this.options.listYears) {
370
+ this.prevYearButton = $E('div', {'class': 'right-ui-button right-calendar-prev-year-button',
371
+ html: '&laquo;', title: i18n.PrevYear}).insertTo(this.prevButton, 'after');
372
+ this.nextYearButton = $E('div', {'class': 'right-ui-button right-calendar-next-year-button',
373
+ html: '&raquo;', title: i18n.NextYear}).insertTo(this.nextButton, 'before');
374
+ }
375
+ },
376
+
377
+ // builds a month block
378
+ buildMonth: function() {
379
+ return $E('div', {'class': 'right-calendar-month'}).insert(
380
+ '<div class="right-calendar-month-caption"></div>'+
381
+ '<table><thead><tr>'+
382
+ this.options.dayNames.map(function(name) {return '<th>'+name+'</th>';}).join('')+
383
+ '</tr></thead><tbody>'+
384
+ '123456'.split('').map(function() {return '<tr><td><td><td><td><td><td><td></tr>'}).join('')+
385
+ '</tbody></table>'
386
+ );
387
+ },
388
+
389
+ // builds the time selection block
390
+ buildTime: function() {
391
+ var options = this.options;
392
+ var time_picker = $E('div', {'class': 'right-calendar-time', html: ':'}).insertTo(this.element);
393
+
394
+ this.hours = $E('select').insertTo(time_picker, 'top');
395
+ this.minutes = $E('select').insertTo(time_picker);
396
+
397
+ var minutes_threshold = options.timePeriod < 60 ? options.timePeriod : 60;
398
+ var hours_threshold = options.timePeriod < 60 ? 1 : (options.timePeriod / 60).ceil();
399
+
400
+ (60).times(function(i) {
401
+ var caption = (i < 10 ? '0' : '') + i;
402
+
403
+ if (i < 24 && i % hours_threshold == 0) {
404
+ if (options.twentyFourHour)
405
+ this.hours.insert($E('option', {value: i, html: caption}));
406
+ else if (i < 12) {
407
+ this.hours.insert($E('option', {value: i, html: i == 0 ? 12 : i}));
408
+ }
409
+ }
410
+
411
+ if (i % minutes_threshold == 0) {
412
+ this.minutes.insert($E('option', {value: i, html: caption}));
413
+ }
414
+ }, this);
415
+
416
+ // adding the meridian picker if it's a 12 am|pm picker
417
+ if (!options.twentyFourHour) {
418
+ this.meridian = $E('select').insertTo(time_picker);
419
+
420
+ (options.format.includes(/%P/) ? ['am', 'pm'] : ['AM', 'PM']).each(function(value) {
421
+ this.meridian.insert($E('option', {value: value.toLowerCase(), html: value}));
422
+ }, this);
423
+ }
424
+ },
425
+
426
+ // builds the bottom buttons block
427
+ buildButtons: function() {
428
+ if (!this.options.showButtons) return;
429
+
430
+ this.nowButton = $E('div', {'class': 'right-ui-button right-calendar-now-button', html: this.options.i18n.Now});
431
+ this.doneButton = $E('div', {'class': 'right-ui-button right-calendar-done-button', html: this.options.i18n.Done});
432
+
433
+ $E('div', {'class': 'right-ui-buttons right-calendar-buttons'})
434
+ .insert([this.doneButton, this.nowButton]).insertTo(this.element);
435
+ }
436
+
437
+ });
438
+
439
+ /**
440
+ * This module handles the events connection
441
+ *
442
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
443
+ */
444
+
445
+ // the document keybindings hookup
446
+ document.onKeydown(function(event) {
447
+ if (Calendar.current) {
448
+ var name;
449
+
450
+ switch(event.keyCode) {
451
+ case 27: name = 'hide'; break;
452
+ case 37: name = 'prevDay'; break;
453
+ case 39: name = 'nextDay'; break;
454
+ case 38: name = 'prevWeek'; break;
455
+ case 40: name = 'nextWeek'; break;
456
+ case 34: name = 'nextMonth'; break;
457
+ case 33: name = 'prevMonth'; break;
458
+ case 13:
459
+ Calendar.current.select(Calendar.current.date);
460
+ name = 'done';
461
+ break;
462
+ }
463
+
464
+ if (name) {
465
+ Calendar.current[name]();
466
+ event.stop();
467
+ }
468
+ }
469
+ });
470
+
471
+ Calendar.include({
472
+ /**
473
+ * Initiates the 'select' event on the object
474
+ *
475
+ * @param Date date
476
+ * @return Calendar this
477
+ */
478
+ select: function(date) {
479
+ this.date = date;
480
+ return this.fire('select', date);
481
+ },
482
+
483
+ /**
484
+ * Covers the 'done' event fire
485
+ *
486
+ * @return Calendar this
487
+ */
488
+ done: function() {
489
+ if (!this.element.hasClass('right-calendar-inline'))
490
+ this.hide();
491
+ return this.fire('done', this.date);
492
+ },
493
+
494
+ nextDay: function() {
495
+ return this.changeDate({'Date': 1});
496
+ },
497
+
498
+ prevDay: function() {
499
+ return this.changeDate({'Date': -1});
500
+ },
501
+
502
+ nextWeek: function() {
503
+ return this.changeDate({'Date': 7});
504
+ },
505
+
506
+ prevWeek: function() {
507
+ return this.changeDate({'Date': -7});
508
+ },
509
+
510
+ nextMonth: function() {
511
+ return this.changeDate({Month: 1});
512
+ },
513
+
514
+ prevMonth: function() {
515
+ return this.changeDate({Month: -1});
516
+ },
517
+
518
+ nextYear: function() {
519
+ return this.changeDate({FullYear: 1});
520
+ },
521
+
522
+ prevYear: function() {
523
+ return this.changeDate({FullYear: -1});
524
+ },
525
+
526
+ // protected
527
+
528
+ // changes the current date according to the hash
529
+ changeDate: function(hash) {
530
+ var date = new Date(this.date);
531
+
532
+ for (var key in hash) {
533
+ date['set'+key](date['get'+key]() + hash[key]);
534
+ }
535
+
536
+ // checking the date range constrains
537
+ if (!(
538
+ (this.options.minDate && this.options.minDate > date) ||
539
+ (this.options.maxDate && this.options.maxDate < date)
540
+ )) this.date = date;
541
+
542
+ return this.update(this.date);
543
+ },
544
+
545
+ connectEvents: function() {
546
+ // connecting the monthes swapping
547
+ this.prevButton.onClick(this.prevMonth.bind(this));
548
+ this.nextButton.onClick(this.nextMonth.bind(this));
549
+ if (this.nextYearButton) {
550
+ this.prevYearButton.onClick(this.prevYear.bind(this));
551
+ this.nextYearButton.onClick(this.nextYear.bind(this));
552
+ }
553
+
554
+ // connecting the calendar day-cells
555
+ this.element.select('div.right-calendar-month table tbody td').each(function(cell) {
556
+ cell.onClick(function() {
557
+ if (cell.innerHTML != '') {
558
+ var prev = this.element.first('.right-calendar-day-selected');
559
+ if (prev) prev.removeClass('right-calendar-day-selected');
560
+ cell.addClass('right-calendar-day-selected');
561
+ this.setTime(cell.date);
562
+ }
563
+ }.bind(this));
564
+ }, this);
565
+
566
+ // connecting the time picker events
567
+ if (this.hours) {
568
+ this.hours.on('change', this.setTime.bind(this));
569
+ this.minutes.on('change', this.setTime.bind(this));
570
+ if (!this.options.twentyFourHour) {
571
+ this.meridian.on('change', this.setTime.bind(this));
572
+ }
573
+ }
574
+
575
+ // connecting the bottom buttons
576
+ if (this.nowButton) {
577
+ this.nowButton.onClick(this.setDate.bind(this, new Date()));
578
+ this.doneButton.onClick(this.done.bind(this));
579
+ }
580
+
581
+ // blocking all the events from the element
582
+ this.element.onClick(function(e) {e.stop();});
583
+
584
+ return this;
585
+ },
586
+
587
+ // sets the date without nucking the time
588
+ setTime: function(date) {
589
+ // from clicking a day in a month table
590
+ if (date instanceof Date) {
591
+ this.date.setYear(date.getFullYear());
592
+ this.date.setMonth(date.getMonth());
593
+ this.date.setDate(date.getDate());
594
+ }
595
+
596
+ if (this.hours) {
597
+ this.date.setHours(this.hours.value.toInt() + (!this.options.twentyFourHour && this.meridian.value == 'pm' ? 12 : 0));
598
+ this.date.setMinutes(this.minutes.value);
599
+ }
600
+
601
+ return this.select(this.date);
602
+ }
603
+
604
+ });
605
+
606
+ /**
607
+ * This module handles the calendar assignment to an input field
608
+ *
609
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
610
+ */
611
+ Calendar.include({
612
+ /**
613
+ * Assigns the calendar to serve the given input element
614
+ *
615
+ * If no trigger element specified, then the calendar will
616
+ * appear and disappear with the element haveing its focus
617
+ *
618
+ * If a trigger element is specified, then the calendar will
619
+ * appear/disappear only by clicking on the trigger element
620
+ *
621
+ * @param Element input field
622
+ * @param Element optional trigger
623
+ * @return Calendar this
624
+ */
625
+ assignTo: function(input, trigger) {
626
+ var input = $(input), trigger = $(trigger);
627
+
628
+ if (trigger) {
629
+ trigger.onClick(function(e) {
630
+ e.stop();
631
+ this.showAt(input.focus());
632
+ }.bind(this));
633
+ } else {
634
+ input.on({
635
+ focus: this.showAt.bind(this, input),
636
+ click: function(e) { e.stop(); if (this.element.hidden()) this.showAt(input); }.bind(this),
637
+ keyDown: function(e) {
638
+ if (e.keyCode == 9 && this.element.visible())
639
+ this.hide();
640
+ }.bind(this)
641
+ });
642
+ }
643
+
644
+ document.onClick(this.hide.bind(this));
645
+
646
+ return this;
647
+ },
648
+
649
+ /**
650
+ * Shows the calendar at the given element left-bottom corner
651
+ *
652
+ * @param Element element or String element id
653
+ * @return Calendar this
654
+ */
655
+ showAt: function(element) {
656
+ var element = $(element), dims = element.dimensions();
657
+ this.setDate(this.parse(element.value));
658
+
659
+ this.element.setStyle({
660
+ position: 'absolute',
661
+ margin: '0',
662
+ left: (dims.left)+'px',
663
+ top: (dims.top + dims.height)+'px'
664
+ }).insertTo(document.body);
665
+
666
+ this.stopObserving('select').stopObserving('done');
667
+ this.on(this.doneButton ? 'done' : 'select', function() {
668
+ element.value = this.format();
669
+ }.bind(this));
670
+
671
+ return this.hideOthers().show();
672
+ },
673
+
674
+ /**
675
+ * Toggles the calendar state at the associated element position
676
+ *
677
+ * @param Element input
678
+ * @return Calendar this
679
+ */
680
+ toggleAt: function(input) {
681
+ if (this.element.parentNode && this.element.visible()) {
682
+ this.hide();
683
+ } else {
684
+ this.showAt(input);
685
+ }
686
+ return this;
687
+ },
688
+
689
+ // protected
690
+
691
+ // hides all the other calendars on the page
692
+ hideOthers: function() {
693
+ $$('div.right-calendar').each(function(element) {
694
+ if (!element.hasClass('right-calendar-inline')) {
695
+ if (element != this.element) {
696
+ element.hide();
697
+ }
698
+ }
699
+ });
700
+
701
+ return this;
702
+ }
703
+ });
704
+
705
+ /**
706
+ * This module handles the dates parsing/formatting processes
707
+ *
708
+ * To format dates and times this scripts use the GNU (C/Python/Ruby) strftime
709
+ * function formatting principles
710
+ *
711
+ * %a - The abbreviated weekday name (``Sun'')
712
+ * %A - The full weekday name (``Sunday'')
713
+ * %b - The abbreviated month name (``Jan'')
714
+ * %B - The full month name (``January'')
715
+ * %d - Day of the month (01..31)
716
+ * %e - Day of the month without leading zero (1..31)
717
+ * %m - Month of the year (01..12)
718
+ * %y - Year without a century (00..99)
719
+ * %Y - Year with century
720
+ * %H - Hour of the day, 24-hour clock (00..23)
721
+ * %k - Hour of the day, 24-hour clock without leading zero (0..23)
722
+ * %I - Hour of the day, 12-hour clock (01..12)
723
+ * %l - Hour of the day, 12-hour clock without leading zer (0..12)
724
+ * %p - Meridian indicator (``AM'' or ``PM'')
725
+ * %P - Meridian indicator (``pm'' or ``pm'')
726
+ * %M - Minute of the hour (00..59)
727
+ * %S - Second of the minute (00..60)
728
+ * %% - Literal ``%'' character
729
+ *
730
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
731
+ */
732
+ Calendar.include({
733
+
734
+ /**
735
+ * Parses out the given string based on the current date formatting
736
+ *
737
+ * @param String string date
738
+ * @return Date parsed date or null if it wasn't parsed
739
+ */
740
+ parse: function(string) {
741
+ var date;
742
+
743
+ if (string instanceof Date || Date.parse(string)) {
744
+ date = new Date(string);
745
+
746
+ } else if (isString(string) && string) {
747
+ var tpl = RegExp.escape(this.options.format);
748
+ var holders = tpl.match(/%[a-z]/ig).map('match', /[a-z]$/i).map('first').without('%');
749
+ var re = new RegExp('^'+tpl.replace(/%p/i, '(pm|PM|am|AM)').replace(/(%[a-z])/ig, '(.+?)')+'$');
750
+
751
+ var match = string.trim().match(re);
752
+
753
+ if (match) {
754
+ match.shift();
755
+
756
+ var year = null, month = null, date = null, hour = null, minute = null, second = null, meridian;
757
+
758
+ while (match.length) {
759
+ var value = match.shift();
760
+ var key = holders.shift();
761
+
762
+ if (key.toLowerCase() == 'b') {
763
+ month = this.options.i18n[key=='b' ? 'monthNamesShort' : 'monthNames'].indexOf(value);
764
+ } else if (key.toLowerCase() == 'p') {
765
+ meridian = value.toLowerCase();
766
+ } else {
767
+ value = value.toInt();
768
+ switch(key) {
769
+ case 'd':
770
+ case 'e': date = value; break;
771
+ case 'm': month = value-1; break;
772
+ case 'y':
773
+ case 'Y': year = value; break;
774
+ case 'H':
775
+ case 'k':
776
+ case 'I':
777
+ case 'l': hour = value; break;
778
+ case 'M': minute = value; break;
779
+ case 'S': second = value; break;
780
+ }
781
+ }
782
+ }
783
+
784
+ // converting 1..12am|pm into 0..23 hours marker
785
+ if (meridian) {
786
+ hour = hour == 12 ? 0 : hour;
787
+ hour = (meridian == 'pm' ? hour + 12 : hour);
788
+ }
789
+
790
+ date = new Date(year, month, date, hour, minute, second);
791
+ }
792
+ } else {
793
+ date = new Date();
794
+ }
795
+
796
+ return date;
797
+ },
798
+
799
+ /**
800
+ * Formats the current date into a string depend on the current or given format
801
+ *
802
+ * @param String optional format
803
+ * @return String formatted data
804
+ */
805
+ format: function(format) {
806
+ var i18n = this.options.i18n;
807
+ var day = this.date.getDay();
808
+ var month = this.date.getMonth();
809
+ var date = this.date.getDate();
810
+ var year = this.date.getFullYear();
811
+ var hour = this.date.getHours();
812
+ var minute = this.date.getMinutes();
813
+ var second = this.date.getSeconds();
814
+
815
+ var hour_ampm = (hour == 0 ? 12 : hour < 13 ? hour : hour - 12);
816
+
817
+ var values = {
818
+ a: i18n.dayNamesShort[day],
819
+ A: i18n.dayNames[day],
820
+ b: i18n.monthNamesShort[month],
821
+ B: i18n.monthNames[month],
822
+ d: (date < 10 ? '0' : '') + date,
823
+ e: ''+date,
824
+ m: (month < 9 ? '0' : '') + (month+1),
825
+ y: (''+year).substring(2,4),
826
+ Y: ''+year,
827
+ H: (hour < 10 ? '0' : '')+ hour,
828
+ k: '' + hour,
829
+ I: (hour > 0 && (hour < 10 || (hour > 12 && hour < 22)) ? '0' : '') + hour_ampm,
830
+ l: '' + hour_ampm,
831
+ p: hour < 12 ? 'AM' : 'PM',
832
+ P: hour < 12 ? 'am' : 'pm',
833
+ M: (minute < 10 ? '0':'')+minute,
834
+ S: (second < 10 ? '0':'')+second,
835
+ '%': '%'
836
+ };
837
+
838
+ var result = format || this.options.format;
839
+ for (var key in values) {
840
+ result = result.replace('%'+key, values[key]);
841
+ }
842
+
843
+ return result;
844
+ }
845
+ });
846
+
847
+ /**
848
+ * Calendar fields autodiscovery via the rel="calendar" attribute
849
+ *
850
+ * Copyright (C) 2009 Nikolay V. Nemshilov aka St.
851
+ */
852
+ document.onReady(Calendar.rescan);
853
+
854
+
855
+ document.write("<style type=\"text/css\">*.right-ui-button{display:inline-block;*display:inline;*zoom:1;height:1em;line-height:1em;padding:.2em .5em;text-align:center;border:1px solid #CCC;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;cursor:pointer;color:#555;background-color:#FFF}*.right-ui-button:hover{color:#222;border-color:#999;background-color:#CCC}*.right-ui-button-disabled,*.right-ui-button-disabled:hover{color:#888;background:#EEE;border-color:#CCC;cursor:default}*.right-ui-buttons{margin-top:.5em}div.right-calendar{position:absolute;height:auto;border:1px solid #BBB;position:relative;padding:.5em;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;cursor:default;background-color:#EEE;-moz-box-shadow:.2em .4em .8em #666;-webkit-box-shadow:.2em .4em .8em #666}div.right-calendar-inline{position:relative;display:inline-block;vertical-align:top;*display:inline;*zoom:1;-moz-box-shadow:none;-webkit-box-shadow:none}div.right-calendar-prev-button,div.right-calendar-next-button,div.right-calendar-prev-year-button,div.right-calendar-next-year-button{position:absolute;float:left;width:1em;padding:.15em .4em}div.right-calendar-next-button{right:.5em}div.right-calendar-prev-year-button{left:2.55em}div.right-calendar-next-year-button{right:2.55em}div.right-calendar-month-caption{text-align:center;height:1.2em;line-height:1.2em}table.right-calendar-greed{border-spacing:0px;border:none;background:none;width:auto}table.right-calendar-greed td{vertical-align:top;border:none;background:none;margin:0;padding:0;padding-right:.4em}table.right-calendar-greed td:last-child{padding:0}div.right-calendar-month table{margin:0;padding:0;border:none;width:auto;margin-top:.2em;border-spacing:1px;border-collapse:separate;border:none;background:none}div.right-calendar-month table th{color:#777;text-align:center;border:none;background:none;padding:0;margin:0}div.right-calendar-month table td,div.right-calendar-month table td:last-child{text-align:right;padding:.1em .3em;background-color:#FFF;border:1px solid #CCC;cursor:pointer;color:#555;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em}div.right-calendar-month table td:hover{background-color:#CCC;border-color:#AAA;color:#000}div.right-calendar-month table td.right-calendar-day-blank{background:transparent;cursor:default;border:none}div.right-calendar-month table td.right-calendar-day-selected{background-color:#BBB;border-color:#AAA;color:#222;font-weight:bold;padding:.1em .2em}div.right-calendar-month table td.right-calendar-day-disabled{color:#888;background:#EEE;border-color:#CCC;cursor:default}div.right-calendar-time{border-top:1px solid #ccc;margin-top:.3em;padding-top:.5em;text-align:center}div.right-calendar-time select{margin:0 .4em}div.right-calendar-buttons div.right-ui-button{width:3.2em}div.right-calendar-done-button{position:absolute;right:.5em}</style>");