right-rails 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/CHANGELOG +4 -0
  2. data/README.rdoc +10 -18
  3. data/Rakefile +2 -2
  4. data/init.rb +9 -2
  5. data/lib/right_rails.rb +1 -1
  6. data/vendor/assets/images/rightjs-ui/colorpicker.png +0 -0
  7. data/vendor/assets/images/rightjs-ui/resizable.png +0 -0
  8. data/vendor/assets/images/rightjs-ui/rte.png +0 -0
  9. data/vendor/assets/javascripts/right-olds-src.js +652 -0
  10. data/vendor/assets/javascripts/right-olds.js +9 -0
  11. data/vendor/assets/javascripts/right-safe-src.js +68 -0
  12. data/vendor/assets/javascripts/right-safe.js +7 -0
  13. data/vendor/assets/javascripts/right-src.js +6014 -0
  14. data/vendor/assets/javascripts/right.js +7 -0
  15. data/vendor/assets/javascripts/right/autocompleter-src.js +625 -0
  16. data/vendor/assets/javascripts/right/autocompleter.js +7 -0
  17. data/vendor/assets/javascripts/right/billboard-src.js +564 -0
  18. data/vendor/assets/javascripts/right/billboard.js +7 -0
  19. data/vendor/assets/javascripts/right/calendar-src.js +1464 -0
  20. data/vendor/assets/javascripts/right/calendar.js +7 -0
  21. data/vendor/assets/javascripts/right/casting-src.js +183 -0
  22. data/vendor/assets/javascripts/right/casting.js +7 -0
  23. data/vendor/assets/javascripts/right/colorpicker-src.js +981 -0
  24. data/vendor/assets/javascripts/right/colorpicker.js +7 -0
  25. data/vendor/assets/javascripts/right/dialog-src.js +768 -0
  26. data/vendor/assets/javascripts/right/dialog.js +7 -0
  27. data/vendor/assets/javascripts/right/dnd-src.js +591 -0
  28. data/vendor/assets/javascripts/right/dnd.js +7 -0
  29. data/vendor/assets/javascripts/right/effects-src.js +508 -0
  30. data/vendor/assets/javascripts/right/effects.js +7 -0
  31. data/vendor/assets/javascripts/right/i18n/de.js +95 -0
  32. data/vendor/assets/javascripts/right/i18n/en-us.js +11 -0
  33. data/vendor/assets/javascripts/right/i18n/es.js +95 -0
  34. data/vendor/assets/javascripts/right/i18n/fi.js +96 -0
  35. data/vendor/assets/javascripts/right/i18n/fr.js +95 -0
  36. data/vendor/assets/javascripts/right/i18n/hu.js +100 -0
  37. data/vendor/assets/javascripts/right/i18n/it.js +95 -0
  38. data/vendor/assets/javascripts/right/i18n/jp.js +99 -0
  39. data/vendor/assets/javascripts/right/i18n/nl.js +95 -0
  40. data/vendor/assets/javascripts/right/i18n/pt-br.js +95 -0
  41. data/vendor/assets/javascripts/right/i18n/ru.js +95 -0
  42. data/vendor/assets/javascripts/right/i18n/ua.js +99 -0
  43. data/vendor/assets/javascripts/right/in-edit-src.js +373 -0
  44. data/vendor/assets/javascripts/right/in-edit.js +7 -0
  45. data/vendor/assets/javascripts/right/jquerysh-src.js +362 -0
  46. data/vendor/assets/javascripts/right/jquerysh.js +7 -0
  47. data/vendor/assets/javascripts/right/json-src.js +147 -0
  48. data/vendor/assets/javascripts/right/json.js +7 -0
  49. data/vendor/assets/javascripts/right/keys-src.js +87 -0
  50. data/vendor/assets/javascripts/right/keys.js +7 -0
  51. data/vendor/assets/javascripts/right/lightbox-src.js +931 -0
  52. data/vendor/assets/javascripts/right/lightbox.js +7 -0
  53. data/vendor/assets/javascripts/right/rails-src.js +402 -0
  54. data/vendor/assets/javascripts/right/rails.js +7 -0
  55. data/vendor/assets/javascripts/right/rater-src.js +384 -0
  56. data/vendor/assets/javascripts/right/rater.js +7 -0
  57. data/vendor/assets/javascripts/right/resizable-src.js +465 -0
  58. data/vendor/assets/javascripts/right/resizable.js +7 -0
  59. data/vendor/assets/javascripts/right/rte-src.js +2685 -0
  60. data/vendor/assets/javascripts/right/rte.js +7 -0
  61. data/vendor/assets/javascripts/right/selectable-src.js +725 -0
  62. data/vendor/assets/javascripts/right/selectable.js +7 -0
  63. data/vendor/assets/javascripts/right/sizzle-src.js +1132 -0
  64. data/vendor/assets/javascripts/right/sizzle.js +7 -0
  65. data/vendor/assets/javascripts/right/slider-src.js +395 -0
  66. data/vendor/assets/javascripts/right/slider.js +7 -0
  67. data/vendor/assets/javascripts/right/sortable-src.js +430 -0
  68. data/vendor/assets/javascripts/right/sortable.js +7 -0
  69. data/vendor/assets/javascripts/right/table-src.js +176 -0
  70. data/vendor/assets/javascripts/right/table.js +7 -0
  71. data/vendor/assets/javascripts/right/tabs-src.js +1157 -0
  72. data/vendor/assets/javascripts/right/tabs.js +7 -0
  73. data/vendor/assets/javascripts/right/tags-src.js +745 -0
  74. data/vendor/assets/javascripts/right/tags.js +7 -0
  75. data/vendor/assets/javascripts/right/tooltips-src.js +331 -0
  76. data/vendor/assets/javascripts/right/tooltips.js +7 -0
  77. data/vendor/assets/javascripts/right/uploader-src.js +302 -0
  78. data/vendor/assets/javascripts/right/uploader.js +7 -0
  79. metadata +78 -14
@@ -0,0 +1,7 @@
1
+ /**
2
+ * RightJS-UI Billboard v2.2.0
3
+ * http://rightjs.org/ui/billboard
4
+ *
5
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
6
+ */
7
+ var Billboard=RightJS.Billboard=function(a){function b(b,c){c||(c=b,b="DIV");var d=new a.Class(a.Element.Wrappers[b]||a.Element,{initialize:function(c,d){this.key=c;var e=[{"class":"rui-"+c}];this instanceof a.Input||this instanceof a.Form||e.unshift(b),this.$super.apply(this,e),a.isString(d)&&(d=a.$(d)),d instanceof a.Element&&(this._=d._,"$listeners"in d&&(d.$listeners=d.$listeners),d={}),this.setOptions(d,this);return a.Wrapper.Cache[a.$uid(this._)]=this},setOptions:function(b,c){c&&(b=a.Object.merge(b,(new Function("return "+(c.get("data-"+this.key)||"{}")))())),b&&a.Options.setOptions.call(this,a.Object.merge(this.options,b));return this}}),e=new a.Class(d,c);a.Observer.createShortcuts(e.prototype,e.EVENTS||a([]));return e}var c=a,d=a.$,e=a.$$,f=a.$w,g=a.$E,h=a.Fx,i=a.Class,j=a.Object,k=new b("UL",{extend:{version:"2.2.0",EVENTS:f("change first last"),Options:{fxName:"stripe",fxDuration:"long",autostart:!0,delay:4e3,loop:!0,showButtons:!0,prevButton:"native",nextButton:"native",stripes:10,cssRule:"*.rui-billboard"}},initialize:function(a){this.$super("billboard",a),this.options.showButtons&&(this.prevButton=this.options.prevButton!=="native"?d(this.options.prevButton):g("div",{"class":"rui-billboard-button-prev",html:"&lsaquo;"}).insertTo(this),this.nextButton=this.options.nextButton!=="native"?d(this.options.nextButton):g("div",{"class":"rui-billboard-button-next",html:"&rsaquo;"}).insertTo(this),this.prevButton.onClick(c(function(a){a.stop(),this.showPrev()}).bind(this)),this.nextButton.onClick(c(function(a){a.stop(),this.showNext()}).bind(this))),this.onChange(function(a){a.item===this.items().first()?this.fire("first"):a.item===this.items().last()&&this.fire("last")}),this.on({mouseover:function(){this.stop()},mouseout:function(a){this.options.autostart&&!a.find(".rui-billboard")&&this.start()}}),this.options.autostart&&this.start()},items:function(){return this.children().without(this.prevButton,this.nextButton)},showNext:function(){var a=this.items(),b=a.indexOf(this.current())+1;b==a.length&&this.options.loop&&(b=0);return this.current(b)},showPrev:function(){var a=this.items(),b=a.indexOf(this.current())-1;b<0&&this.options.loop&&(b=a.length-1);return this.current(b)},current:function(a){var b=this.items();if(arguments.length)a instanceof Element&&(a=b.indexOf(a)),this.runFx(b[a]);else return b.length?b.first("hasClass","rui-billboard-current")||b.first().addClass("rui-billboard-current"):null;return this},start:function(){this.timer=c(this.showNext).bind(this).periodical(this.options.delay)},stop:function(){this.timer&&this.timer.stop()},fire:function(a,b){return this.$super(a,j.merge({index:this.items().indexOf(this.current()),item:this.current()},b))},runFx:function(a){if(a&&!this._running){var b=k.Fx[c(this.options.fxName||"").capitalize()];b?(new b(this)).start(this.current(),a):(this.current().removeClass("rui-billboard-current"),a.addClass("rui-billboard-current"))}}});k.Fx=new i(h,{initialize:function(a){this.container=g("div",{"class":"rui-billboard-fx-container"}),this.$super(a,{duration:a.options.fxDuration,onStart:function(){a._running=!0,a.insert(this.container)},onFinish:function(){this.container.remove(),a._running=!1,a.fire("change")}})},prepare:function(a,b){a.removeClass("rui-billboard-current"),b.addClass("rui-billboard-current"),this.clone=a.clone(),this.container.update(this.clone)}}),k.Fx.Fade=new i(k.Fx,{prepare:function(a,b){this.$super(a,b)},render:function(a){this.container.setStyle({opacity:1-a})}}),k.Fx.Slide=new i(k.Fx,{prepare:function(a,b){this._width=this.element.current().size().x,this._direction=a.nextSiblings().include(b)?-1:1,this.$super(a,b),this.clone.setStyle({width:this._width+"px"})},render:function(a){this.clone._.style.left=this._direction*this._width*a+"px"}}),k.Fx.Stripe=new i(k.Fx,{directions:["down","up","left","right"],prepare:function(a,b){this.$super(a,b);var d=this.element.options.stripes,e=this.element.items()[0].size().x/d,f=100,h=this.directions.shift();this.directions.push(h),this.container.clean();for(var i=0;i<d;i++){var j=g("div",{"class":"rui-billboard-stripe",style:{width:e+1+"px",left:i*e+"px"}}).insert(a.clone().setStyle({width:e*d+"px",left:-i*e+"px"}));this.container.append(j);var k={duration:this.options.duration};if(h!=="right"&&i===d-1||h==="right"&&i===0)k.onFinish=c(this.finish).bind(this,!0);switch(h){case"up":c(function(a,b){a.setHeight(a.size().y),a.morph({height:"0px"},b)}).bind(this,j,k).delay(i*f);break;case"down":j.setStyle("top: auto; bottom: 0px"),c(function(a,b){a.setHeight(a.size().y),a.morph({height:"0px"},b)}).bind(this,j,k).delay(i*f);break;case"left":c(function(a,b){a.morph({width:"0px"},b)}).bind(this,j,k).delay(i*f);break;case"right":c(function(a,b){a.morph({width:"0px"},b)}).bind(this,j,k).delay((d-i-1)*f);break;default:this.finish(!0)}}},finish:function(a){a&&this.$super();return this}}),d(document).onReady(function(){e(k.Options.cssRule).each(function(a){a instanceof k||(a=new k(a))})});var l=document.createElement("style"),m=document.createTextNode("*.rui-billboard, *.rui-billboard> *{margin:0;padding:0;list-style:none} *.rui-billboard{display:inline-block; *display:inline; *zoom:1;position:relative} *.rui-billboard> *{display:none;width:100%;height:100%} *.rui-billboard> *:first-child, *.rui-billboard> *.rui-billboard-current:first-child{display:block;position:relative} *.rui-billboard> *>img{margin:0;padding:0} *.rui-billboard-current{position:absolute;left:0;top:0;display:block;z-index:999} *.rui-billboard-button-prev, *.rui-billboard-button-next{position:absolute;z-index:99999;left:.25em;top:auto;bottom:.25em;display:block;width:.5em;height:auto;text-align:center;font-size:200%;font-family:Arial;font-weight:bold;padding:0em .5em .2em .5em;background:white;opacity:0;filter:alpha(opacity:0);cursor:pointer;border:.12em solid #888;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;user-select:none;-moz-user-select:none;-webkit-user-select:none;transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out} *.rui-billboard-button-next{left:auto;right:.25em;text-align:right} *.rui-billboard-button-prev:active{text-indent:-.1em} *.rui-billboard-button-next:active{text-indent:.2em} *.rui-billboard:hover *.rui-billboard-button-prev, *.rui-billboard:hover *.rui-billboard-button-next{opacity:0.4;filter:alpha(opacity:40)} *.rui-billboard:hover *.rui-billboard-button-prev:hover, *.rui-billboard:hover *.rui-billboard-button-next:hover{opacity:0.7;filter:alpha(opacity:70)}.rui-billboard-fx-container{position:absolute;left:0;top:0;display:block;z-index:9999;overflow:hidden}.rui-billboard-fx-container> *{position:absolute;left:0;top:0}.rui-billboard-stripe{overflow:hidden}.rui-billboard-stripe> *{position:relative}");l.type="text/css",document.getElementsByTagName("head")[0].appendChild(l),l.styleSheet?l.styleSheet.cssText=m.nodeValue:l.appendChild(m);return k}(RightJS)
@@ -0,0 +1,1464 @@
1
+ /**
2
+ * RightJS-UI Calendar v2.2.0
3
+ * http://rightjs.org/ui/calendar
4
+ *
5
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
6
+ */
7
+ var Calendar = RightJS.Calendar = (function(document, parseInt, RightJS) {
8
+ /**
9
+ * This module defines the basic widgets constructor
10
+ * it creates an abstract proxy with the common functionality
11
+ * which then we reuse and override in the actual widgets
12
+ *
13
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
14
+ */
15
+
16
+ /**
17
+ * The widget units constructor
18
+ *
19
+ * @param String tag-name or Object methods
20
+ * @param Object methods
21
+ * @return Widget wrapper
22
+ */
23
+ function Widget(tag_name, methods) {
24
+ if (!methods) {
25
+ methods = tag_name;
26
+ tag_name = 'DIV';
27
+ }
28
+
29
+ /**
30
+ * An Abstract Widget Unit
31
+ *
32
+ * Copyright (C) 2010 Nikolay Nemshilov
33
+ */
34
+ var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
35
+ /**
36
+ * The common constructor
37
+ *
38
+ * @param Object options
39
+ * @param String optional tag name
40
+ * @return void
41
+ */
42
+ initialize: function(key, options) {
43
+ this.key = key;
44
+ var args = [{'class': 'rui-' + key}];
45
+
46
+ // those two have different constructors
47
+ if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
48
+ args.unshift(tag_name);
49
+ }
50
+ this.$super.apply(this, args);
51
+
52
+ if (RightJS.isString(options)) {
53
+ options = RightJS.$(options);
54
+ }
55
+
56
+ // if the options is another element then
57
+ // try to dynamically rewrap it with our widget
58
+ if (options instanceof RightJS.Element) {
59
+ this._ = options._;
60
+ if ('$listeners' in options) {
61
+ options.$listeners = options.$listeners;
62
+ }
63
+ options = {};
64
+ }
65
+ this.setOptions(options, this);
66
+
67
+ return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
68
+ },
69
+
70
+ // protected
71
+
72
+ /**
73
+ * Catches the options
74
+ *
75
+ * @param Object user-options
76
+ * @param Element element with contextual options
77
+ * @return void
78
+ */
79
+ setOptions: function(options, element) {
80
+ if (element) {
81
+ options = RightJS.Object.merge(options, new Function("return "+(
82
+ element.get('data-'+ this.key) || '{}'
83
+ ))());
84
+ }
85
+
86
+ if (options) {
87
+ RightJS.Options.setOptions.call(this, RightJS.Object.merge(this.options, options));
88
+ }
89
+
90
+ return this;
91
+ }
92
+ });
93
+
94
+ /**
95
+ * Creating the actual widget class
96
+ *
97
+ */
98
+ var Klass = new RightJS.Class(AbstractWidget, methods);
99
+
100
+ // creating the widget related shortcuts
101
+ RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || RightJS([]));
102
+
103
+ return Klass;
104
+ }
105
+
106
+
107
+ /**
108
+ * A shared button unit.
109
+ * NOTE: we use the DIV units instead of INPUTS
110
+ * so those buttons didn't interfere with
111
+ * the user's tab-index on his page
112
+ *
113
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
114
+ */
115
+ var Button = new RightJS.Class(RightJS.Element, {
116
+ /**
117
+ * Constructor
118
+ *
119
+ * @param String caption
120
+ * @param Object options
121
+ * @return void
122
+ */
123
+ initialize: function(caption, options) {
124
+ this.$super('div', options);
125
+ this._.innerHTML = caption;
126
+ this.addClass('rui-button');
127
+ this.on('selectstart', 'stopEvent');
128
+ },
129
+
130
+ /**
131
+ * Disasbles the button
132
+ *
133
+ * @return Button this
134
+ */
135
+ disable: function() {
136
+ return this.addClass('rui-button-disabled');
137
+ },
138
+
139
+ /**
140
+ * Enables the button
141
+ *
142
+ * @return Button this
143
+ */
144
+ enable: function() {
145
+ return this.removeClass('rui-button-disabled');
146
+ },
147
+
148
+ /**
149
+ * Checks if the button is disabled
150
+ *
151
+ * @return Button this
152
+ */
153
+ disabled: function() {
154
+ return this.hasClass('rui-button-disabled');
155
+ },
156
+
157
+ /**
158
+ * Checks if the button is enabled
159
+ *
160
+ * @return Button this
161
+ */
162
+ enabled: function() {
163
+ return !this.disabled();
164
+ },
165
+
166
+ /**
167
+ * Overloading the method, so it fired the events
168
+ * only when the button is active
169
+ *
170
+ * @return Button this
171
+ */
172
+ fire: function() {
173
+ if (this.enabled()) {
174
+ this.$super.apply(this, arguments);
175
+ }
176
+ return this;
177
+ }
178
+ });
179
+
180
+
181
+ /**
182
+ * A shared module that toggles a widget visibility status
183
+ * in a uniformed way according to the options settings
184
+ *
185
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
186
+ */
187
+ var Toggler = {
188
+ /**
189
+ * Shows the element
190
+ *
191
+ * @param String fx-name
192
+ * @param Object fx-options
193
+ * @return Element this
194
+ */
195
+ show: function(fx_name, fx_options) {
196
+ this.constructor.current = this;
197
+ return Toggler_toggle(this, 'show', fx_name, fx_options);
198
+ },
199
+
200
+ /**
201
+ * Hides the element
202
+ *
203
+ * @param String fx-name
204
+ * @param Object fx-options
205
+ * @return Element this
206
+ */
207
+ hide: function(fx_name, fx_options) {
208
+ this.constructor.current = null;
209
+ return Toggler_toggle(this, 'show', fx_name, fx_options);
210
+ },
211
+
212
+ /**
213
+ * Toggles the widget at the given element
214
+ *
215
+ * @param Element the related element
216
+ * @param String position right/bottom (bottom is the default)
217
+ * @param Boolean marker if the element should be resized to the element size
218
+ * @return Widget this
219
+ */
220
+ showAt: function(element, where, resize) {
221
+ this.hide(null).shownAt = element = RightJS.$(element);
222
+
223
+ // moves this element at the given one
224
+ Toggler_re_position.call(this, element, where, resize);
225
+
226
+ return this.show();
227
+ },
228
+
229
+ /**
230
+ * Toggles the widget at the given element
231
+ *
232
+ * @param Element the related element
233
+ * @param String position top/left/right/bottom (bottom is the default)
234
+ * @param Boolean marker if the element should be resized to the element size
235
+ * @return Widget this
236
+ */
237
+ toggleAt: function(element, where, resize) {
238
+ return this.hidden() ? this.showAt(element, where, resize) : this.hide();
239
+ }
240
+ };
241
+
242
+
243
+ /**
244
+ * toggles the element's state according to the current settings
245
+ *
246
+ * @param event String 'show' or 'hide' the event name
247
+ * @param String an optional fx-name
248
+ * @param Object an optional fx-options hash
249
+ * @return void
250
+ */
251
+ function Toggler_toggle(element, event, fx_name, fx_options) {
252
+ if (RightJS.Fx) {
253
+ if (fx_name === undefined) {
254
+ fx_name = element.options.fxName;
255
+
256
+ if (fx_options === undefined) {
257
+ fx_options = {
258
+ duration: element.options.fxDuration,
259
+ onFinish: RightJS(element.fire).bind(element, event)
260
+ };
261
+
262
+ // hide on double time
263
+ if (event === 'hide') {
264
+ fx_options.duration = (RightJS.Fx.Durations[fx_options.duration] ||
265
+ fx_options.duration) / 2;
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ // manually trigger the event if no fx were specified
272
+ if (!RightJS.Fx || !fx_name) { element.fire(event); }
273
+
274
+ return element.$super(fx_name, fx_options);
275
+ }
276
+
277
+ /**
278
+ * Relatively positions the current element
279
+ * against the specified one
280
+ *
281
+ * NOTE: this function is called in a context
282
+ * of another element
283
+ *
284
+ * @param Element the target element
285
+ * @param String position 'right' or 'bottom'
286
+ * @param Boolean if `true` then the element size will be adjusted
287
+ * @return void
288
+ */
289
+ function Toggler_re_position(element, where, resize) {
290
+ var anchor = this.reAnchor || (this.reAnchor =
291
+ new RightJS.Element('div', {'class': 'rui-re-anchor'}))
292
+ .insert(this),
293
+
294
+ pos = anchor.insertTo(element, 'after').position(),
295
+ dims = element.dimensions(), target = this,
296
+
297
+ border_top = parseInt(element.getStyle('borderTopWidth')),
298
+ border_left = parseInt(element.getStyle('borderLeftWidth')),
299
+ border_right = parseInt(element.getStyle('borderRightWidth')),
300
+ border_bottom = parseInt(element.getStyle('borderBottomWidth')),
301
+
302
+ top = dims.top - pos.y + border_top,
303
+ left = dims.left - pos.x + border_left,
304
+ width = dims.width - border_left - border_right,
305
+ height = dims.height - border_top - border_bottom;
306
+
307
+ // making the element to appear so we could read it's sizes
308
+ target.setStyle('visibility:hidden').show(null);
309
+
310
+ if (where === 'right') {
311
+ left += width - target.size().x;
312
+ } else { // bottom
313
+ top += height;
314
+ }
315
+
316
+ target.moveTo(left, top);
317
+
318
+ if (resize) {
319
+ if (where === 'left' || where === 'right') {
320
+ target.setHeight(height);
321
+ } else {
322
+ target.setWidth(width);
323
+ }
324
+ }
325
+
326
+ // rolling the invisibility back
327
+ target.setStyle('visibility:visible').hide(null);
328
+ }
329
+
330
+ /**
331
+ * A shared module that provides for the widgets an ability
332
+ * to be assigned to an input element and work in pair with it
333
+ *
334
+ * NOTE: this module works in pair with the 'RePosition' module!
335
+ *
336
+ * Copyright (C) 2010 Nikolay Nemshilov
337
+ */
338
+ var Assignable = {
339
+ /**
340
+ * Assigns the widget to serve the given input element
341
+ *
342
+ * Basically it puts the references of the current widget
343
+ * to the input and trigger objects so they could be recognized
344
+ * later, and it also synchronizes the changes between the input
345
+ * element and the widget
346
+ *
347
+ * @param {Element} input field
348
+ * @param {Element} optional trigger
349
+ * @return Widget this
350
+ */
351
+ assignTo: function(input, trigger) {
352
+ input = RightJS.$(input);
353
+ trigger = RightJS.$(trigger);
354
+
355
+ if (trigger) {
356
+ trigger[this.key] = this;
357
+ trigger.assignedInput = input;
358
+ } else {
359
+ input[this.key] = this;
360
+ }
361
+
362
+ var on_change = RightJS(function() {
363
+ if (this.visible() && (!this.showAt || this.shownAt === input)) {
364
+ this.setValue(input.value());
365
+ }
366
+ }).bind(this);
367
+
368
+ input.on({
369
+ keyup: on_change,
370
+ change: on_change
371
+ });
372
+
373
+ this.onChange(function() {
374
+ if (!this.showAt || this.shownAt === input) {
375
+ input.setValue(this.getValue());
376
+ }
377
+ });
378
+
379
+ return this;
380
+ }
381
+ };
382
+
383
+
384
+ /**
385
+ * Converts a number into a string with leading zeros
386
+ *
387
+ * @param Number number
388
+ * @return String with zeros
389
+ */
390
+ function zerofy(number) {
391
+ return (number < 10 ? '0' : '') + number;
392
+ }
393
+
394
+
395
+ /**
396
+ * The filenames to include
397
+ *
398
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
399
+ */
400
+
401
+ var R = RightJS,
402
+ $ = RightJS.$,
403
+ $$ = RightJS.$$,
404
+ $w = RightJS.$w,
405
+ $ext = RightJS.$ext,
406
+ $uid = RightJS.$uid,
407
+ isString = RightJS.isString,
408
+ isArray = RightJS.isArray,
409
+ isFunction = RightJS.isFunction,
410
+ Class = RightJS.Class,
411
+ Element = RightJS.Element,
412
+ Input = RightJS.Input,
413
+ RegExp = RightJS.RegExp,
414
+ Browser = RightJS.Browser;
415
+
416
+
417
+
418
+
419
+
420
+
421
+
422
+
423
+
424
+ /**
425
+ * The calendar widget for RightJS
426
+ *
427
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
428
+ */
429
+ var Calendar = new Widget({
430
+ include: [Toggler, Assignable],
431
+
432
+ extend: {
433
+ version: '2.2.0',
434
+
435
+ EVENTS: $w('show hide change done'),
436
+
437
+ Options: {
438
+ format: 'ISO', // a key out of the predefined formats or a format string
439
+
440
+ showTime: null, // null for automatic, or true|false to enforce
441
+ showButtons: false, // show the bottom buttons
442
+
443
+ minDate: false, // the minimal date available
444
+ maxDate: false, // the maximal date available
445
+
446
+ fxName: 'fade', // set to null if you don't wanna any fx
447
+ fxDuration: 'short', // the fx-duration
448
+
449
+ firstDay: 1, // 1 for Monday, 0 for Sunday
450
+ numberOfMonths: 1, // a number or [x, y] greed definition
451
+ timePeriod: 1, // the timepicker minimal periods (in minutes, might be bigger than 60)
452
+
453
+ twentyFourHour: null, // null for automatic, or true|false to enforce
454
+ listYears: false, // show/hide the years listing buttons
455
+
456
+ hideOnPick: false, // hides the popup when the user changes a day
457
+
458
+ update: null, // a reference to an input element to assign to
459
+ trigger: null, // a reference to a trigger element that would be paired too
460
+
461
+ cssRule: '*[data-calendar]' // css rule for calendar related elements
462
+ },
463
+
464
+ Formats: {
465
+ ISO: '%Y-%m-%d',
466
+ POSIX: '%Y/%m/%d',
467
+ EUR: '%d-%m-%Y',
468
+ US: '%m/%d/%Y'
469
+ },
470
+
471
+ i18n: {
472
+ Done: 'Done',
473
+ Now: 'Now',
474
+ NextMonth: 'Next Month',
475
+ PrevMonth: 'Previous Month',
476
+ NextYear: 'Next Year',
477
+ PrevYear: 'Previous Year',
478
+
479
+ dayNames: $w('Sunday Monday Tuesday Wednesday Thursday Friday Saturday'),
480
+ dayNamesShort: $w('Sun Mon Tue Wed Thu Fri Sat'),
481
+ dayNamesMin: $w('Su Mo Tu We Th Fr Sa'),
482
+ monthNames: $w('January February March April May June July August September October November December'),
483
+ monthNamesShort: $w('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec')
484
+ },
485
+
486
+ current: null,
487
+
488
+ // hides all the popup calendars
489
+ hideAll: function(that_one) {
490
+ $$('div.rui-calendar').each(function(element) {
491
+ if (element instanceof Calendar && element !== that_one && element.visible() && !element.inlined()) {
492
+ element.hide();
493
+ }
494
+ });
495
+ }
496
+ },
497
+
498
+ /**
499
+ * Basic constructor
500
+ *
501
+ * @param Object options
502
+ */
503
+ initialize: function(options) {
504
+ this.$super('calendar', options);
505
+ this.addClass('rui-panel');
506
+
507
+ options = this.options;
508
+
509
+ this.insert([
510
+ this.swaps = new Swaps(options),
511
+ this.greed = new Greed(options)
512
+ ]);
513
+
514
+ if (options.showTime) {
515
+ this.insert(this.timepicker = new Timepicker(options));
516
+ }
517
+
518
+ if (options.showButtons) {
519
+ this.insert(this.buttons = new Buttons(options));
520
+ }
521
+
522
+ this.setDate(new Date()).initEvents();
523
+ },
524
+
525
+ /**
526
+ * Sets the date on the calendar
527
+ *
528
+ * NOTE: if it's `true` then it will change the date but
529
+ * won't shift the months greed (used in the days picking)
530
+ *
531
+ * @param Date date or String date
532
+ * @param Boolean no-shifting mode
533
+ * @return Calendar this
534
+ */
535
+ setDate: function(date, no_shift) {
536
+ if ((date = this.parse(date))) {
537
+ var options = this.options;
538
+
539
+ // checking the date range constrains
540
+ if (options.minDate && options.minDate > date) {
541
+ date = new Date(options.minDate);
542
+ }
543
+ if (options.maxDate && options.maxDate < date) {
544
+ date = new Date(options.maxDate);
545
+ date.setDate(date.getDate() - 1);
546
+ }
547
+
548
+ // setting the dates greed
549
+ this._date = no_shift ? new Date(this._date || this.date) : null;
550
+ this.greed.setDate(this._date || date, date);
551
+
552
+ // updating the shifters state
553
+ if (options.minDate || options.maxDate) {
554
+ this.swaps.setDate(date);
555
+ }
556
+
557
+ // updating the time-picker
558
+ if (this.timepicker && !no_shift) {
559
+ this.timepicker.setDate(date);
560
+ }
561
+
562
+ if (date != this.date) {
563
+ this.fire('change', {date: this.date = date});
564
+ }
565
+ }
566
+
567
+ return this;
568
+ },
569
+
570
+ /**
571
+ * Returns the current date on the calendar
572
+ *
573
+ * @return Date currently selected date on the calendar
574
+ */
575
+ getDate: function() {
576
+ return this.date;
577
+ },
578
+
579
+ /**
580
+ * Sets the value as a string
581
+ *
582
+ * @param String value
583
+ * @return Calendar this
584
+ */
585
+ setValue: function(value) {
586
+ return this.setDate(value);
587
+ },
588
+
589
+ /**
590
+ * Returns the value as a string
591
+ *
592
+ * @param String optional format
593
+ * @return String formatted date
594
+ */
595
+ getValue: function(format) {
596
+ return this.format(format);
597
+ },
598
+
599
+ /**
600
+ * Inserts the calendar into the element making it inlined
601
+ *
602
+ * @param Element element or String element id
603
+ * @param String optional position top/bottom/before/after/instead, 'bottom' is default
604
+ * @return Calendar this
605
+ */
606
+ insertTo: function(element, position) {
607
+ this.addClass('rui-calendar-inline');
608
+ return this.$super(element, position);
609
+ },
610
+
611
+ /**
612
+ * Marks it done
613
+ *
614
+ * @return Calendar this
615
+ */
616
+ done: function() {
617
+ if (!this.inlined()) {
618
+ this.hide();
619
+ }
620
+
621
+ this.fire('done', {date: this.date});
622
+ },
623
+
624
+ /**
625
+ * Checks if the calendar is inlined
626
+ *
627
+ * @return boolean check
628
+ */
629
+ inlined: function() {
630
+ return this.hasClass('rui-calendar-inline');
631
+ },
632
+
633
+ // protected
634
+
635
+ /**
636
+ * additional options processing
637
+ *
638
+ * @param Object options
639
+ * @return Calendar this
640
+ */
641
+ setOptions: function(user_options) {
642
+ user_options = user_options || {};
643
+ this.$super(user_options, $(user_options.trigger || user_options.update));
644
+
645
+ var klass = this.constructor, options = this.options;
646
+
647
+ // merging the i18n tables
648
+ options.i18n = {};
649
+
650
+ for (var key in klass.i18n) {
651
+ options.i18n[key] = isArray(klass.i18n[key]) ? klass.i18n[key].clone() : klass.i18n[key];
652
+ }
653
+ $ext(options.i18n, user_options.i18n);
654
+
655
+ // defining the current days sequence
656
+ options.dayNames = options.i18n.dayNamesMin;
657
+ if (options.firstDay) {
658
+ options.dayNames.push(options.dayNames.shift());
659
+ }
660
+
661
+ // the monthes table cleaning up
662
+ if (!isArray(options.numberOfMonths)) {
663
+ options.numberOfMonths = [options.numberOfMonths, 1];
664
+ }
665
+
666
+ // min/max dates preprocessing
667
+ if (options.minDate) {
668
+ options.minDate = this.parse(options.minDate);
669
+ }
670
+ if (options.maxDate) {
671
+ options.maxDate = this.parse(options.maxDate);
672
+ options.maxDate.setDate(options.maxDate.getDate() + 1);
673
+ }
674
+
675
+ // format catching up
676
+ options.format = R(klass.Formats[options.format] || options.format).trim();
677
+
678
+ // setting up the showTime option
679
+ if (options.showTime === null) {
680
+ options.showTime = options.format.search(/%[HkIl]/) > -1;
681
+ }
682
+
683
+ // setting up the 24-hours format
684
+ if (options.twentyFourHour === null) {
685
+ options.twentyFourHour = options.format.search(/%[Il]/) < 0;
686
+ }
687
+
688
+ // enforcing the 24 hours format if the time threshold is some weird number
689
+ if (options.timePeriod > 60 && 12 % Math.ceil(options.timePeriod/60)) {
690
+ options.twentyFourHour = true;
691
+ }
692
+
693
+ if (options.update) {
694
+ this.assignTo(options.update, options.trigger);
695
+ }
696
+
697
+ return this;
698
+ },
699
+
700
+ /**
701
+ * hides all the other calendars on the page
702
+ *
703
+ * @return Calendar this
704
+ */
705
+ hideOthers: function() {
706
+ Calendar.hideAll(this);
707
+ return this;
708
+ }
709
+ });
710
+
711
+
712
+ /**
713
+ * The calendar month/year swapping buttons block
714
+ *
715
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
716
+ */
717
+ var Swaps = new Class(Element, {
718
+ /**
719
+ * Constructor
720
+ *
721
+ * @param Object options
722
+ * @return void
723
+ */
724
+ initialize: function(options) {
725
+ this.$super('div', {'class': 'swaps'});
726
+ this.options = options;
727
+
728
+ var i18n = options.i18n;
729
+
730
+ this.insert([
731
+ this.prevMonth = new Button('&lsaquo;', {title: i18n.PrevMonth, 'class': 'prev-month'}),
732
+ this.nextMonth = new Button('&rsaquo;', {title: i18n.NextMonth, 'class': 'next-month'})
733
+ ]);
734
+
735
+ if (options.listYears) {
736
+ this.insert([
737
+ this.prevYear = new Button('&laquo;', {title: i18n.PrevYear, 'class': 'prev-year'}),
738
+ this.nextYear = new Button('&raquo;', {title: i18n.NextYear, 'class': 'next-year'})
739
+ ]);
740
+ }
741
+
742
+ this.buttons = R([this.prevMonth, this.nextMonth, this.prevYear, this.nextYear]).compact();
743
+
744
+ this.onClick(this.clicked);
745
+ },
746
+
747
+ /**
748
+ * Changes the swapping buttons state depending on the options and the current date
749
+ *
750
+ * @param Date date
751
+ * @return void
752
+ */
753
+ setDate: function(date) {
754
+ var options = this.options, months_num = options.numberOfMonths[0] * options.numberOfMonths[1],
755
+ has_prev_year = true, has_next_year = true, has_prev_month = true, has_next_month = true;
756
+
757
+ if (options.minDate) {
758
+ var beginning = new Date(date.getFullYear(),0,1,0,0,0);
759
+ var min_date = new Date(options.minDate.getFullYear(),0,1,0,0,0);
760
+
761
+ has_prev_year = beginning > min_date;
762
+
763
+ beginning.setMonth(date.getMonth() - Math.ceil(months_num - months_num/2));
764
+ min_date.setMonth(options.minDate.getMonth());
765
+
766
+ has_prev_month = beginning >= min_date;
767
+ }
768
+
769
+ if (options.maxDate) {
770
+ var end = new Date(date);
771
+ var max_date = new Date(options.maxDate);
772
+ var dates = R([end, max_date]);
773
+ dates.each(function(date) {
774
+ date.setDate(32);
775
+ date.setMonth(date.getMonth() - 1);
776
+ date.setDate(32 - date.getDate());
777
+ date.setHours(0);
778
+ date.setMinutes(0);
779
+ date.setSeconds(0);
780
+ date.setMilliseconds(0);
781
+ });
782
+
783
+ has_next_month = end < max_date;
784
+
785
+ // checking the next year
786
+ dates.each('setMonth', 0);
787
+ has_next_year = end < max_date;
788
+ }
789
+
790
+ this.nextMonth[has_next_month ? 'enable':'disable']();
791
+ this.prevMonth[has_prev_month ? 'enable':'disable']();
792
+
793
+ if (this.nextYear) {
794
+ this.nextYear[has_next_year ? 'enable':'disable']();
795
+ this.prevYear[has_prev_year ? 'enable':'disable']();
796
+ }
797
+ },
798
+
799
+ // protected
800
+
801
+ // handles the clicks on the
802
+ clicked: function(event) {
803
+ var target = event.target;
804
+ if (target && this.buttons.include(target)) {
805
+ if (target.enabled()) {
806
+ this.fire(target.get('className').split(/\s+/)[0]);
807
+ }
808
+ }
809
+ }
810
+ });
811
+
812
+
813
+ /**
814
+ * Represents a single month block
815
+ *
816
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
817
+ */
818
+ var Month = new Class(Element, {
819
+ /**
820
+ * Constructor
821
+ *
822
+ * @param Object options
823
+ * @return void
824
+ */
825
+ initialize: function(options) {
826
+ this.$super('table', {'class': 'month'});
827
+ this.options = options;
828
+
829
+ // the caption (for the month name)
830
+ this.insert(this.caption = new Element('caption'));
831
+
832
+ // the headline for the day-names
833
+ this.insert('<thead><tr>'+
834
+ options.dayNames.map(function(name) {return '<th>'+ name +'</th>';}).join('') +
835
+ '</tr></thead>');
836
+
837
+ // the body with the day-cells
838
+ this.days = [];
839
+
840
+ var tbody = new Element('tbody').insertTo(this), x, y, row;
841
+
842
+ for (y=0; y < 6; y++) {
843
+ row = new Element('tr').insertTo(tbody);
844
+ for (x=0; x < 7; x++) {
845
+ this.days.push(new Element('td').insertTo(row));
846
+ }
847
+ }
848
+
849
+ this.onClick(this.clicked);
850
+ },
851
+
852
+ /**
853
+ * Initializes the month values by the date
854
+ *
855
+ * @param Date date
856
+ * @return void
857
+ */
858
+ setDate: function(date, current_date) {
859
+ // getting the number of days in the month
860
+ date.setDate(32);
861
+ var days_number = 32 - date.getDate();
862
+ date.setMonth(date.getMonth()-1);
863
+
864
+ var cur_day = Math.ceil(current_date.getTime() / 86400000),
865
+ options = this.options, i18n = options.i18n, days = this.days;
866
+
867
+ // resetting the first and last two weeks cells
868
+ // because there will be some empty cells over there
869
+ for (var i=0, len = days.length-1, one, two, tre; i < 7; i++) {
870
+ one = days[i]._;
871
+ two = days[len - i]._;
872
+ tre = days[len - i - 7]._;
873
+
874
+ one.innerHTML = two.innerHTML = tre.innerHTML = '';
875
+ one.className = two.className = tre.className = 'blank';
876
+ }
877
+
878
+ // putting the actual day numbers in place
879
+ for (var i=1, row=0, week, cell; i <= days_number; i++) {
880
+ date.setDate(i);
881
+ var day_num = date.getDay();
882
+
883
+ if (options.firstDay === 1) { day_num = day_num > 0 ? day_num-1 : 6; }
884
+ if (i === 1 || day_num === 0) {
885
+ week = days.slice(row*7, row*7 + 7); row ++;
886
+ }
887
+
888
+ cell = week[day_num]._;
889
+
890
+ if (Browser.OLD) { // IE6 has a nasty glitch with that
891
+ cell.innerHTML = '';
892
+ cell.appendChild(document.createTextNode(i));
893
+ } else {
894
+ cell.innerHTML = ''+i;
895
+ }
896
+
897
+ cell.className = cur_day === Math.ceil(date.getTime() / 86400000) ? 'selected' : '';
898
+
899
+ if ((options.minDate && options.minDate > date) || (options.maxDate && options.maxDate < date)) {
900
+ cell.className = 'disabled';
901
+ }
902
+
903
+ week[day_num].date = new Date(date);
904
+ }
905
+
906
+ // setting up the caption with the month name
907
+ var caption = (options.listYears ?
908
+ i18n.monthNamesShort[date.getMonth()] + ',' :
909
+ i18n.monthNames[date.getMonth()])+
910
+ ' '+date.getFullYear(),
911
+ element = this.caption._;
912
+
913
+ if (Browser.OLD) {
914
+ element.innerHTML = '';
915
+ element.appendChild(document.createTextNode(caption));
916
+ } else {
917
+ element.innerHTML = caption;
918
+ }
919
+ },
920
+
921
+ // protected
922
+
923
+ /**
924
+ * Handles clicks on the day-cells
925
+ *
926
+ * @param Event click event
927
+ * @return void
928
+ */
929
+ clicked: function(event) {
930
+ var target = event.target, date = target.date;
931
+
932
+ if (target && date && !target.hasClass('disabled') && !target.hasClass('blank')) {
933
+ target.addClass('selected');
934
+
935
+ this.fire('date-set', {
936
+ date: date.getDate(),
937
+ month: date.getMonth(),
938
+ year: date.getFullYear()
939
+ });
940
+ }
941
+ }
942
+ });
943
+
944
+
945
+ /**
946
+ * The calendar months greed unit
947
+ *
948
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
949
+ */
950
+ var Greed = new Class(Element, {
951
+ /**
952
+ * Constructor
953
+ *
954
+ * @param Object options
955
+ * @return void
956
+ */
957
+ initialize: function(options) {
958
+ this.$super('table', {'class': 'greed'});
959
+
960
+ this.months = [];
961
+
962
+ var tbody = new Element('tbody').insertTo(this), month;
963
+
964
+ for (var y=0; y < options.numberOfMonths[1]; y++) {
965
+ var row = new Element('tr').insertTo(tbody);
966
+ for (var x=0; x < options.numberOfMonths[0]; x++) {
967
+ this.months.push(month = new Month(options));
968
+ new Element('td').insertTo(row).insert(month);
969
+ }
970
+ }
971
+ },
972
+
973
+ /**
974
+ * Sets the months to the date
975
+ *
976
+ * @param Date date in the middle of the greed
977
+ * @param the current date (might be different)
978
+ * @return void
979
+ */
980
+ setDate: function(date, current_date) {
981
+ var months = this.months, months_num = months.length;
982
+
983
+ current_date = current_date || date;
984
+
985
+ for (var i=-Math.ceil(months_num - months_num/2)+1,j=0; i < Math.floor(months_num - months_num/2)+1; i++,j++) {
986
+ var month_date = new Date(date);
987
+ month_date.setMonth(date.getMonth() + i);
988
+ months[j].setDate(month_date, current_date);
989
+ }
990
+ }
991
+ });
992
+
993
+
994
+ /**
995
+ * The time-picker block unit
996
+ *
997
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
998
+ */
999
+ var Timepicker = new Class(Element, {
1000
+ /**
1001
+ * Constructor
1002
+ *
1003
+ * @param Object options
1004
+ * @return void
1005
+ */
1006
+ initialize: function(options) {
1007
+ this.$super('div', {'class': 'timepicker'});
1008
+ this.options = options;
1009
+
1010
+ var on_change = R(this.timeChanged).bind(this);
1011
+
1012
+ this.insert([
1013
+ this.hours = new Element('select').onChange(on_change),
1014
+ this.minutes = new Element('select').onChange(on_change)
1015
+ ]);
1016
+
1017
+ var minutes_threshold = options.timePeriod < 60 ? options.timePeriod : 60;
1018
+ var hours_threshold = options.timePeriod < 60 ? 1 : Math.ceil(options.timePeriod / 60);
1019
+
1020
+ for (var i=0; i < 60; i++) {
1021
+ var caption = zerofy(i);
1022
+
1023
+ if (i < 24 && i % hours_threshold == 0) {
1024
+ if (options.twentyFourHour) {
1025
+ this.hours.insert(new Element('option', {value: i, html: caption}));
1026
+ } else if (i < 12) {
1027
+ this.hours.insert(new Element('option', {value: i, html: i == 0 ? 12 : i}));
1028
+ }
1029
+ }
1030
+
1031
+ if (i % minutes_threshold == 0) {
1032
+ this.minutes.insert(new Element('option', {value: i, html: caption}));
1033
+ }
1034
+ }
1035
+
1036
+
1037
+ // adding the meridian picker if it's a 12 am|pm picker
1038
+ if (!options.twentyFourHour) {
1039
+ this.meridian = new Element('select').onChange(on_change).insertTo(this);
1040
+
1041
+ R(R(options.format).includes(/%P/) ? ['am', 'pm'] : ['AM', 'PM']).each(function(value) {
1042
+ this.meridian.insert(new Element('option', {value: value.toLowerCase(), html: value}));
1043
+ }, this);
1044
+ }
1045
+ },
1046
+
1047
+ /**
1048
+ * Sets the time-picker values by the data
1049
+ *
1050
+ * @param Date date
1051
+ * @return void
1052
+ */
1053
+ setDate: function(date) {
1054
+ var options = this.options;
1055
+ var hour = options.timePeriod < 60 ? date.getHours() :
1056
+ Math.round(date.getHours()/(options.timePeriod/60)) * (options.timePeriod/60);
1057
+ var minute = Math.round(date.getMinutes() / (options.timePeriod % 60)) * options.timePeriod;
1058
+
1059
+ if (this.meridian) {
1060
+ this.meridian.setValue(hour < 12 ? 'am' : 'pm');
1061
+ hour = (hour == 0 || hour == 12) ? 12 : hour > 12 ? (hour - 12) : hour;
1062
+ }
1063
+
1064
+ this.hours.setValue(hour);
1065
+ this.minutes.setValue(minute);
1066
+ },
1067
+
1068
+ // protected
1069
+
1070
+ /**
1071
+ * Handles the time-picking events
1072
+ *
1073
+ * @return void
1074
+ */
1075
+ timeChanged: function(event) {
1076
+ event.stopPropagation();
1077
+
1078
+ var hours = parseInt(this.hours.value());
1079
+ var minutes = parseInt(this.minutes.value());
1080
+
1081
+ if (this.meridian) {
1082
+ if (hours == 12) {
1083
+ hours = 0;
1084
+ }
1085
+ if (this.meridian.value() == 'pm') {
1086
+ hours += 12;
1087
+ }
1088
+ }
1089
+
1090
+ this.fire('time-set', {hours: hours, minutes: minutes});
1091
+ }
1092
+ });
1093
+
1094
+
1095
+ /**
1096
+ * The bottom-buttons block unit
1097
+ *
1098
+ * Copyright (C) 2010 Nikolay Nemshilov
1099
+ */
1100
+ var Buttons = new Class(Element, {
1101
+ /**
1102
+ * Constructor
1103
+ *
1104
+ * @param Object options
1105
+ * @return void
1106
+ */
1107
+ initialize: function(options) {
1108
+ this.$super('div', {'class': 'buttons'});
1109
+
1110
+ this.insert([
1111
+ new Button(options.i18n.Now, {'class': 'now'}).onClick('fire', 'now-clicked'),
1112
+ new Button(options.i18n.Done, {'class': 'done'}).onClick('fire', 'done-clicked')
1113
+ ]);
1114
+ }
1115
+ });
1116
+
1117
+
1118
+ /**
1119
+ * This module handles the dates parsing/formatting processes
1120
+ *
1121
+ * To format dates and times this scripts use the GNU (C/Python/Ruby) strftime
1122
+ * function formatting principles
1123
+ *
1124
+ * %a - The abbreviated weekday name (``Sun'')
1125
+ * %A - The full weekday name (``Sunday'')
1126
+ * %b - The abbreviated month name (``Jan'')
1127
+ * %B - The full month name (``January'')
1128
+ * %d - Day of the month (01..31)
1129
+ * %e - Day of the month without leading zero (1..31)
1130
+ * %m - Month of the year (01..12)
1131
+ * %y - Year without a century (00..99)
1132
+ * %Y - Year with century
1133
+ * %H - Hour of the day, 24-hour clock (00..23)
1134
+ * %k - Hour of the day, 24-hour clock without leading zero (0..23)
1135
+ * %I - Hour of the day, 12-hour clock (01..12)
1136
+ * %l - Hour of the day, 12-hour clock without leading zer (0..12)
1137
+ * %p - Meridian indicator (``AM'' or ``PM'')
1138
+ * %P - Meridian indicator (``pm'' or ``pm'')
1139
+ * %M - Minute of the hour (00..59)
1140
+ * %S - Second of the minute (00..60)
1141
+ * %% - Literal ``%'' character
1142
+ *
1143
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
1144
+ */
1145
+ Calendar.include({
1146
+
1147
+ /**
1148
+ * Parses out the given string based on the current date formatting
1149
+ *
1150
+ * @param String string date
1151
+ * @return Date parsed date or null if it wasn't parsed
1152
+ */
1153
+ parse: function(string) {
1154
+ var date;
1155
+
1156
+ if (isString(string) && string) {
1157
+ var tpl = RegExp.escape(this.options.format);
1158
+ var holders = R(tpl.match(/%[a-z]/ig)).map('match', /[a-z]$/i).map('first').without('%');
1159
+ var re = new RegExp('^'+tpl.replace(/%p/i, '(pm|PM|am|AM)').replace(/(%[a-z])/ig, '(.+?)')+'$');
1160
+
1161
+ var match = R(string).trim().match(re);
1162
+
1163
+ if (match) {
1164
+ match.shift();
1165
+
1166
+ var year = null, month = null, hour = null, minute = null, second = null, meridian;
1167
+
1168
+ while (match.length) {
1169
+ var value = match.shift();
1170
+ var key = holders.shift();
1171
+
1172
+ if (key.toLowerCase() == 'b') {
1173
+ month = this.options.i18n[key=='b' ? 'monthNamesShort' : 'monthNames'].indexOf(value);
1174
+ } else if (key.toLowerCase() == 'p') {
1175
+ meridian = value.toLowerCase();
1176
+ } else {
1177
+ value = parseInt(value, 10);
1178
+ switch(key) {
1179
+ case 'd':
1180
+ case 'e': date = value; break;
1181
+ case 'm': month = value-1; break;
1182
+ case 'y':
1183
+ case 'Y': year = value; break;
1184
+ case 'H':
1185
+ case 'k':
1186
+ case 'I':
1187
+ case 'l': hour = value; break;
1188
+ case 'M': minute = value; break;
1189
+ case 'S': second = value; break;
1190
+ }
1191
+ }
1192
+ }
1193
+
1194
+ // converting 1..12am|pm into 0..23 hours marker
1195
+ if (meridian) {
1196
+ hour = hour == 12 ? 0 : hour;
1197
+ hour = (meridian == 'pm' ? hour + 12 : hour);
1198
+ }
1199
+
1200
+ date = new Date(year, month, date, hour, minute, second);
1201
+ }
1202
+ } else if (string instanceof Date || Date.parse(string)) {
1203
+ date = new Date(string);
1204
+ }
1205
+
1206
+ return (!date || isNaN(date.getTime())) ? null : date;
1207
+ },
1208
+
1209
+ /**
1210
+ * Formats the current date into a string depend on the current or given format
1211
+ *
1212
+ * @param String optional format
1213
+ * @return String formatted data
1214
+ */
1215
+ format: function(format) {
1216
+ var i18n = this.options.i18n;
1217
+ var day = this.date.getDay();
1218
+ var month = this.date.getMonth();
1219
+ var date = this.date.getDate();
1220
+ var year = this.date.getFullYear();
1221
+ var hour = this.date.getHours();
1222
+ var minute = this.date.getMinutes();
1223
+ var second = this.date.getSeconds();
1224
+
1225
+ var hour_ampm = (hour == 0 ? 12 : hour < 13 ? hour : hour - 12);
1226
+
1227
+ var values = {
1228
+ a: i18n.dayNamesShort[day],
1229
+ A: i18n.dayNames[day],
1230
+ b: i18n.monthNamesShort[month],
1231
+ B: i18n.monthNames[month],
1232
+ d: zerofy(date),
1233
+ e: ''+date,
1234
+ m: (month < 9 ? '0' : '') + (month+1),
1235
+ y: (''+year).substring(2,4),
1236
+ Y: ''+year,
1237
+ H: zerofy(hour),
1238
+ k: '' + hour,
1239
+ I: (hour > 0 && (hour < 10 || (hour > 12 && hour < 22)) ? '0' : '') + hour_ampm,
1240
+ l: '' + hour_ampm,
1241
+ p: hour < 12 ? 'AM' : 'PM',
1242
+ P: hour < 12 ? 'am' : 'pm',
1243
+ M: zerofy(minute),
1244
+ S: zerofy(second),
1245
+ '%': '%'
1246
+ };
1247
+
1248
+ var result = format || this.options.format;
1249
+ for (var key in values) {
1250
+ result = result.replace('%'+key, values[key]);
1251
+ }
1252
+
1253
+ return result;
1254
+ }
1255
+ });
1256
+
1257
+
1258
+ /**
1259
+ * This module handles the events connection
1260
+ *
1261
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
1262
+ */
1263
+ Calendar.include({
1264
+
1265
+ // protected
1266
+
1267
+ // connects the events with handlers
1268
+ initEvents: function() {
1269
+ var shift = '_shiftDate', terminate = this._terminate;
1270
+
1271
+ this.on({
1272
+ // the dates/months/etc listing events
1273
+ 'prev-day': [shift, {Date: -1}],
1274
+ 'next-day': [shift, {Date: 1}],
1275
+ 'prev-week': [shift, {Date: -7}],
1276
+ 'next-week': [shift, {Date: 7}],
1277
+ 'prev-month': [shift, {Month: -1}],
1278
+ 'next-month': [shift, {Month: 1}],
1279
+ 'prev-year': [shift, {FullYear: -1}],
1280
+ 'next-year': [shift, {FullYear: 1}],
1281
+
1282
+ // the date/time picking events
1283
+ 'date-set': this._changeDate,
1284
+ 'time-set': this._changeTime,
1285
+
1286
+ // the bottom buttons events
1287
+ 'now-clicked': this._setNow,
1288
+ 'done-clicked': this.done,
1289
+
1290
+ // handling the clicks
1291
+ 'click': terminate,
1292
+ 'mousedown': terminate,
1293
+ 'focus': terminate,
1294
+ 'blur': terminate
1295
+ });
1296
+ },
1297
+
1298
+ // shifts the date according to the params
1299
+ _shiftDate: function(params) {
1300
+ var date = new Date(this.date), options = this.options;
1301
+
1302
+ // shifting the date according to the params
1303
+ for (var key in params) {
1304
+ date['set'+key](date['get'+key]() + params[key]);
1305
+ }
1306
+
1307
+ this.setDate(date);
1308
+ },
1309
+
1310
+ // changes the current date (not the time)
1311
+ _changeDate: function(event) {
1312
+ var date = new Date(this.date);
1313
+
1314
+ date.setDate(event.date);
1315
+ date.setMonth(event.month);
1316
+ date.setFullYear(event.year);
1317
+
1318
+ this.setDate(date, true); // <- `true` means just change the date without shifting the list
1319
+
1320
+ if (this.options.hideOnPick) {
1321
+ this.done();
1322
+ }
1323
+ },
1324
+
1325
+ // changes the current time (not the date)
1326
+ _changeTime: function(event) {
1327
+ var date = new Date(this.date);
1328
+
1329
+ date.setHours(event.hours);
1330
+ date.setMinutes(event.minutes);
1331
+
1332
+ this.setDate(date);
1333
+ },
1334
+
1335
+ // resets the calendar to the current time
1336
+ _setNow: function() {
1337
+ this.setDate(new Date());
1338
+ },
1339
+
1340
+ /** simply stops the event so we didn't bother the things outside of the object
1341
+ *
1342
+ * @param {Event} event
1343
+ * @return void
1344
+ * @private
1345
+ */
1346
+ _terminate: function(event) {
1347
+ event.stopPropagation(); // don't let the clicks go anywere out of the clanedar
1348
+
1349
+ if (this._hide_delay) {
1350
+ this._hide_delay.cancel();
1351
+ this._hide_delay = null;
1352
+ }
1353
+ }
1354
+ });
1355
+
1356
+
1357
+ /**
1358
+ * Document level event listeners for navigation and lazy initialization
1359
+ *
1360
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
1361
+ */
1362
+ $(document).on({
1363
+ /**
1364
+ * Watches the focus events and dispalys the calendar
1365
+ * popups when there is a related input element
1366
+ *
1367
+ * @param Event focus-event
1368
+ * @return void
1369
+ */
1370
+ focus: function(event) {
1371
+ var target = event.target instanceof Input && event.target.get('type') == 'text' ? event.target : null;
1372
+
1373
+ Calendar.hideAll();
1374
+
1375
+ if (target && (target.calendar || target.match(Calendar.Options.cssRule))) {
1376
+ (target.calendar || new Calendar({update: target}))
1377
+ .setValue(target.value()).showAt(target);
1378
+ }
1379
+ },
1380
+
1381
+ /**
1382
+ * Watches the input elements blur events
1383
+ * and hides shown popups
1384
+ *
1385
+ * @param Event blur-event
1386
+ * @return void
1387
+ */
1388
+ blur: function(event) {
1389
+ var target = event.target, calendar = target.calendar;
1390
+
1391
+ if (calendar) {
1392
+ // we use the delay so it didn't get hidden when the user clicks the calendar itself
1393
+ calendar._hide_delay = R(function() {
1394
+ calendar.hide();
1395
+ }).delay(200);
1396
+ }
1397
+ },
1398
+
1399
+ /**
1400
+ * Catches clicks on trigger elements
1401
+ *
1402
+ * @param Event click
1403
+ * @return void
1404
+ */
1405
+ click: function(event) {
1406
+ var target = (event.target instanceof Element) ? event.target : null;
1407
+
1408
+ if (target && (target.calendar || target.match(Calendar.Options.cssRule))) {
1409
+ if (!(target instanceof Input) || target.get('type') != 'text') {
1410
+ event.stop();
1411
+ (target.calendar || new Calendar({trigger: target}))
1412
+ .hide(null).toggleAt(target.assignedInput);
1413
+ }
1414
+ } else if (!event.find('div.rui-calendar')){
1415
+ Calendar.hideAll();
1416
+ }
1417
+ },
1418
+
1419
+ /**
1420
+ * Catching the key-downs to navigate in the currently
1421
+ * opened Calendar hover
1422
+ *
1423
+ * @param Event event
1424
+ * @return void
1425
+ */
1426
+ keydown: function(event) {
1427
+ var calendar = Calendar.current, name = ({
1428
+ 27: 'hide', // Escape
1429
+ 37: 'prev-day', // Left Arrow
1430
+ 39: 'next-day', // Right Arrow
1431
+ 38: 'prev-week', // Up Arrow
1432
+ 40: 'next-week', // Down Arrow
1433
+ 33: 'prev-month', // Page Up
1434
+ 34: 'next-month', // Page Down
1435
+ 13: 'done' // Enter
1436
+ })[event.keyCode];
1437
+
1438
+ if (name && calendar && calendar.visible()) {
1439
+ event.stop();
1440
+ if (isFunction(calendar[name])) {
1441
+ calendar[name]();
1442
+ } else {
1443
+ calendar.fire(name);
1444
+ }
1445
+ }
1446
+ }
1447
+ });
1448
+
1449
+
1450
+ var embed_style = document.createElement('style'),
1451
+ embed_rules = document.createTextNode(".rui-panel{margin:0;padding:.5em;position:relative;background-color:#EEE;border:1px solid #BBB;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;box-shadow:.15em .3em .5em #BBB;-moz-box-shadow:.15em .3em .5em #BBB;-webkit-box-shadow:.15em .3em .5em #BBB;cursor:default} *.rui-button{display:inline-block; *display:inline; *zoom:1;height:1em;line-height:1em;margin:0;padding:.2em .5em;text-align:center;border:1px solid #CCC;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;cursor:pointer;color:#333;background-color:#FFF;user-select:none;-moz-user-select:none;-webkit-user-select:none} *.rui-button:hover{color:#111;border-color:#999;background-color:#DDD;box-shadow:#888 0 0 .1em;-moz-box-shadow:#888 0 0 .1em;-webkit-box-shadow:#888 0 0 .1em} *.rui-button:active{color:#000;border-color:#777;text-indent:1px;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none} *.rui-button-disabled, *.rui-button-disabled:hover, *.rui-button-disabled:active{color:#888;background:#DDD;border-color:#CCC;cursor:default;text-indent:0;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none}div.rui-re-anchor{margin:0;padding:0;background:none;border:none;float:none;display:inline;position:absolute;z-index:9999}div.rui-calendar .swaps,div.rui-calendar .greed,div.rui-calendar .timepicker,div.rui-calendar .buttons,div.rui-calendar table,div.rui-calendar table tr,div.rui-calendar table th,div.rui-calendar table td,div.rui-calendar table tbody,div.rui-calendar table thead,div.rui-calendar table caption{background:none;border:none;width:auto;height:auto;margin:0;padding:0}div.rui-calendar-inline{position:relative;display:inline-block; *display:inline; *zoom:1;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none}div.rui-calendar .swaps{position:relative}div.rui-calendar .swaps .rui-button{position:absolute;float:left;width:1em;padding:.15em .4em}div.rui-calendar .swaps .next-month{right:0em;_right:.5em}div.rui-calendar .swaps .prev-year{left:2.05em}div.rui-calendar .swaps .next-year{right:2.05em;_right:2.52em}div.rui-calendar .greed{border-spacing:0px;border-collapse:collapse;border-size:0}div.rui-calendar .greed td{vertical-align:top;padding-left:.4em}div.rui-calendar .greed>tbody>tr>td:first-child{padding:0}div.rui-calendar .month{margin-top:.2em;border-spacing:1px;border-collapse:separate}div.rui-calendar .month caption{text-align:center}div.rui-calendar .month th{color:#666;text-align:center}div.rui-calendar .month td{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.rui-calendar .month td:hover{background-color:#CCC;border-color:#AAA;color:#000}div.rui-calendar .month td.blank{background:transparent;cursor:default;border:none}div.rui-calendar .month td.selected{background-color:#BBB;border-color:#AAA;color:#222;font-weight:bold;padding:.1em .2em}div.rui-calendar .month td.disabled{color:#888;background:#EEE;border-color:#CCC;cursor:default}div.rui-calendar .timepicker{border-top:1px solid #ccc;margin-top:.3em;padding-top:.5em;text-align:center}div.rui-calendar .timepicker select{margin:0 .4em}div.rui-calendar .buttons{position:relative;margin-top:.5em}div.rui-calendar .buttons div.rui-button{width:4em;padding:.25em .5em}div.rui-calendar .buttons .done{position:absolute;right:0em;top:0}");
1452
+
1453
+ embed_style.type = 'text/css';
1454
+ document.getElementsByTagName('head')[0].appendChild(embed_style);
1455
+
1456
+ if(embed_style.styleSheet) {
1457
+ embed_style.styleSheet.cssText = embed_rules.nodeValue;
1458
+ } else {
1459
+ embed_style.appendChild(embed_rules);
1460
+ }
1461
+
1462
+
1463
+ return Calendar;
1464
+ })(document, parseInt, RightJS);