right-rails 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>");