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.
- data/MIT-LICENSE +20 -0
- data/README.textile +50 -0
- data/Rakefile +23 -0
- data/generators/right_rails/right_rails_generator.rb +41 -0
- data/generators/right_rails/templates/iframed.html.erb +10 -0
- data/generators/right_scaffold/right_scaffold_generator.rb +53 -0
- data/generators/right_scaffold/templates/controller.rb +99 -0
- data/generators/right_scaffold/templates/helper.rb +2 -0
- data/generators/right_scaffold/templates/layout.html.erb +18 -0
- data/generators/right_scaffold/templates/style.css +54 -0
- data/generators/right_scaffold/templates/view__form.html.erb +16 -0
- data/generators/right_scaffold/templates/view__item.html.erb +13 -0
- data/generators/right_scaffold/templates/view_edit.html.erb +6 -0
- data/generators/right_scaffold/templates/view_index.html.erb +9 -0
- data/generators/right_scaffold/templates/view_new.html.erb +5 -0
- data/generators/right_scaffold/templates/view_show.html.erb +10 -0
- data/init.rb +12 -0
- data/javascripts/right-autocompleter-src.js +303 -0
- data/javascripts/right-autocompleter.js +9 -0
- data/javascripts/right-behavior-src.js +240 -0
- data/javascripts/right-behavior.js +8 -0
- data/javascripts/right-calendar-src.js +855 -0
- data/javascripts/right-calendar.js +9 -0
- data/javascripts/right-dnd-src.js +555 -0
- data/javascripts/right-dnd.js +9 -0
- data/javascripts/right-effects-src.js +425 -0
- data/javascripts/right-effects.js +6 -0
- data/javascripts/right-events-src.js +369 -0
- data/javascripts/right-events.js +6 -0
- data/javascripts/right-json-src.js +176 -0
- data/javascripts/right-json.js +6 -0
- data/javascripts/right-lightbox-src.js +597 -0
- data/javascripts/right-lightbox.js +9 -0
- data/javascripts/right-rails-src.js +269 -0
- data/javascripts/right-rails.js +9 -0
- data/javascripts/right-rater-src.js +248 -0
- data/javascripts/right-rater.js +9 -0
- data/javascripts/right-selectable-src.js +507 -0
- data/javascripts/right-selectable.js +7 -0
- data/javascripts/right-slider-src.js +291 -0
- data/javascripts/right-slider.js +7 -0
- data/javascripts/right-sortable-src.js +221 -0
- data/javascripts/right-sortable.js +9 -0
- data/javascripts/right-src.js +4939 -0
- data/javascripts/right-tabs-src.js +776 -0
- data/javascripts/right-tabs.js +6 -0
- data/javascripts/right-tooltips-src.js +130 -0
- data/javascripts/right-tooltips.js +9 -0
- data/javascripts/right-ui-i18n-de.js +29 -0
- data/javascripts/right-ui-i18n-en-us.js +11 -0
- data/javascripts/right-ui-i18n-es.js +29 -0
- data/javascripts/right-ui-i18n-fr.js +29 -0
- data/javascripts/right-ui-i18n-jp.js +33 -0
- data/javascripts/right-ui-i18n-ru.js +29 -0
- data/javascripts/right-ui-i18n-uk.js +29 -0
- data/javascripts/right.js +10 -0
- data/lib/right-rails.rb +11 -0
- data/lib/right_rails/controller_extensions.rb +85 -0
- data/lib/right_rails/helpers/basic.rb +111 -0
- data/lib/right_rails/helpers/forms.rb +239 -0
- data/lib/right_rails/helpers/misc.rb +164 -0
- data/lib/right_rails/helpers/rails.rb +166 -0
- data/lib/right_rails/helpers.rb +5 -0
- data/lib/right_rails/java_script_generator.rb +313 -0
- data/lib/right_rails.rb +6 -0
- data/spec/lib/right_rails/controller_extensions_spec.rb +60 -0
- data/spec/lib/right_rails/helpers/basic_spec.rb +74 -0
- data/spec/lib/right_rails/helpers/forms_spec.rb +51 -0
- data/spec/lib/right_rails/helpers/misc_spec.rb +120 -0
- data/spec/lib/right_rails/helpers/rails_spec.rb +149 -0
- data/spec/lib/right_rails/java_script_generator_spec.rb +317 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +15 -0
- 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: '‹', title: i18n.Prev}).insertTo(this.element);
|
366
|
+
this.nextButton = $E('div', {'class': 'right-ui-button right-calendar-next-button',
|
367
|
+
html: '›', 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: '«', title: i18n.PrevYear}).insertTo(this.prevButton, 'after');
|
372
|
+
this.nextYearButton = $E('div', {'class': 'right-ui-button right-calendar-next-year-button',
|
373
|
+
html: '»', 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>");
|