right-rails 0.6.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.rdoc +71 -0
  3. data/Rakefile +144 -14
  4. data/generators/right_rails/right_rails_generator.rb +18 -21
  5. data/init.rb +11 -32
  6. data/lib/generators/right_rails/right_rails_generator.rb +27 -0
  7. data/lib/generators/right_rails/templates/iframed.html.erb +10 -0
  8. data/lib/right-rails.rb +1 -1
  9. data/lib/right_rails/config.rb +278 -0
  10. data/lib/right_rails/controller_extensions.rb +10 -5
  11. data/lib/right_rails/helpers/basic.rb +10 -66
  12. data/lib/right_rails/helpers/forms.rb +141 -139
  13. data/lib/right_rails/helpers/misc.rb +45 -67
  14. data/lib/right_rails/helpers/rails.rb +40 -105
  15. data/lib/right_rails/helpers.rb +364 -1
  16. data/lib/right_rails/java_script_generator.rb +34 -24
  17. data/lib/right_rails.rb +6 -1
  18. data/{images → public/images}/colorpicker.png +0 -0
  19. data/{images → public/images}/resizable.png +0 -0
  20. data/public/javascripts/right/autocompleter-src.js +612 -0
  21. data/public/javascripts/right/autocompleter.js +18 -0
  22. data/public/javascripts/right/calendar-src.js +1448 -0
  23. data/public/javascripts/right/calendar.js +36 -0
  24. data/public/javascripts/right/colorpicker-src.js +967 -0
  25. data/public/javascripts/right/colorpicker.js +26 -0
  26. data/{javascripts/right-dnd-src.js → public/javascripts/right/dnd-src.js} +86 -52
  27. data/public/javascripts/right/dnd.js +20 -0
  28. data/{javascripts/right-effects-src.js → public/javascripts/right/effects-src.js} +90 -45
  29. data/public/javascripts/right/effects.js +17 -0
  30. data/{javascripts/right-ui-i18n-de.js → public/javascripts/right/i18n/de.js} +7 -7
  31. data/{javascripts/right-ui-i18n-en-us.js → public/javascripts/right/i18n/en-us.js} +1 -1
  32. data/{javascripts/right-ui-i18n-es.js → public/javascripts/right/i18n/es.js} +7 -7
  33. data/{javascripts/right-ui-i18n-fr.js → public/javascripts/right/i18n/fr.js} +7 -7
  34. data/{javascripts/right-ui-i18n-hu.js → public/javascripts/right/i18n/hu.js} +7 -7
  35. data/{javascripts/right-ui-i18n-jp.js → public/javascripts/right/i18n/jp.js} +7 -7
  36. data/{javascripts/right-ui-i18n-nl.js → public/javascripts/right/i18n/nl.js} +7 -7
  37. data/{javascripts/right-ui-i18n-pt-br.js → public/javascripts/right/i18n/pt-br.js} +7 -7
  38. data/{javascripts/right-ui-i18n-ru.js → public/javascripts/right/i18n/ru.js} +7 -7
  39. data/{javascripts/right-ui-i18n-ua.js → public/javascripts/right/i18n/ua.js} +17 -12
  40. data/public/javascripts/right/in-edit-src.js +352 -0
  41. data/public/javascripts/right/in-edit.js +13 -0
  42. data/public/javascripts/right/json-src.js +160 -0
  43. data/public/javascripts/right/json.js +10 -0
  44. data/public/javascripts/right/lightbox-src.js +881 -0
  45. data/public/javascripts/right/lightbox.js +24 -0
  46. data/{javascripts/right-rails-src.js → public/javascripts/right/rails-src.js} +195 -171
  47. data/public/javascripts/right/rails.js +14 -0
  48. data/public/javascripts/right/rater-src.js +366 -0
  49. data/public/javascripts/right/rater.js +13 -0
  50. data/public/javascripts/right/resizable-src.js +420 -0
  51. data/public/javascripts/right/resizable.js +15 -0
  52. data/public/javascripts/right/selectable-src.js +687 -0
  53. data/public/javascripts/right/selectable.js +22 -0
  54. data/public/javascripts/right/slider-src.js +377 -0
  55. data/public/javascripts/right/slider.js +14 -0
  56. data/public/javascripts/right/sortable-src.js +392 -0
  57. data/public/javascripts/right/sortable.js +16 -0
  58. data/public/javascripts/right/tabs-src.js +1123 -0
  59. data/public/javascripts/right/tabs.js +29 -0
  60. data/public/javascripts/right/tooltip-src.js +307 -0
  61. data/public/javascripts/right/tooltip.js +12 -0
  62. data/public/javascripts/right/uploader-src.js +283 -0
  63. data/public/javascripts/right/uploader.js +13 -0
  64. data/{javascripts → public/javascripts}/right-olds-src.js +134 -186
  65. data/public/javascripts/right-olds.js +18 -0
  66. data/public/javascripts/right-safe-src.js +161 -0
  67. data/public/javascripts/right-safe.js +8 -0
  68. data/{javascripts → public/javascripts}/right-src.js +2558 -1750
  69. data/public/javascripts/right.js +92 -0
  70. data/spec/lib/right_rails/config_spec.rb +133 -0
  71. data/spec/lib/right_rails/controller_extensions_spec.rb +1 -1
  72. data/spec/lib/right_rails/helpers/basic_spec.rb +77 -66
  73. data/spec/lib/right_rails/helpers/forms_spec.rb +231 -33
  74. data/spec/lib/right_rails/helpers/misc_spec.rb +94 -26
  75. data/spec/lib/right_rails/helpers/rails_spec.rb +42 -7
  76. data/spec/lib/right_rails/helpers_spec.rb +125 -0
  77. data/spec/lib/right_rails/java_script_generator_spec.rb +30 -0
  78. data/spec/rcov.opts +3 -0
  79. data/spec/spec_helper.rb +12 -7
  80. metadata +70 -61
  81. data/README.textile +0 -69
  82. data/javascripts/right-autocompleter-src.js +0 -318
  83. data/javascripts/right-autocompleter.js +0 -9
  84. data/javascripts/right-behavior-src.js +0 -261
  85. data/javascripts/right-behavior.js +0 -8
  86. data/javascripts/right-calendar-src.js +0 -946
  87. data/javascripts/right-calendar.js +0 -9
  88. data/javascripts/right-colorpicker-src.js +0 -635
  89. data/javascripts/right-colorpicker.js +0 -9
  90. data/javascripts/right-dnd.js +0 -9
  91. data/javascripts/right-effects.js +0 -6
  92. data/javascripts/right-events-src.js +0 -321
  93. data/javascripts/right-events.js +0 -6
  94. data/javascripts/right-in-edit-src.js +0 -194
  95. data/javascripts/right-in-edit.js +0 -6
  96. data/javascripts/right-json-src.js +0 -141
  97. data/javascripts/right-json.js +0 -6
  98. data/javascripts/right-lightbox-src.js +0 -651
  99. data/javascripts/right-lightbox.js +0 -9
  100. data/javascripts/right-olds.js +0 -9
  101. data/javascripts/right-rails.js +0 -9
  102. data/javascripts/right-rater-src.js +0 -253
  103. data/javascripts/right-rater.js +0 -9
  104. data/javascripts/right-resizable-src.js +0 -336
  105. data/javascripts/right-resizable.js +0 -9
  106. data/javascripts/right-selectable-src.js +0 -565
  107. data/javascripts/right-selectable.js +0 -7
  108. data/javascripts/right-slider-src.js +0 -288
  109. data/javascripts/right-slider.js +0 -7
  110. data/javascripts/right-sortable-src.js +0 -225
  111. data/javascripts/right-sortable.js +0 -9
  112. data/javascripts/right-tabs-src.js +0 -937
  113. data/javascripts/right-tabs.js +0 -6
  114. data/javascripts/right-tooltips-src.js +0 -195
  115. data/javascripts/right-tooltips.js +0 -9
  116. data/javascripts/right-uploader-src.js +0 -167
  117. data/javascripts/right-uploader.js +0 -9
  118. data/javascripts/right.js +0 -7
@@ -0,0 +1,967 @@
1
+ /**
2
+ * RightJS UI Colorpicker widget
3
+ *
4
+ * See http://rightjs.org/ui/colorpicker
5
+ *
6
+ * Copyright (C) 2010 Nikolay Nemshilov
7
+ */
8
+ var Colorpicker = RightJS.Colorpicker = (function(document, Math, parseInt, RightJS) {
9
+ /**
10
+ * This module defines the basic widgets constructor
11
+ * it creates an abstract proxy with the common functionality
12
+ * which then we reuse and override in the actual widgets
13
+ *
14
+ * Copyright (C) 2010 Nikolay Nemshilov
15
+ */
16
+
17
+ /**
18
+ * The initialization files list
19
+ *
20
+ * Copyright (C) 2010 Nikolay Nemshilov
21
+ */
22
+
23
+ var R = RightJS,
24
+ $ = RightJS.$,
25
+ $w = RightJS.$w,
26
+ $$ = RightJS.$$,
27
+ $E = RightJS.$E,
28
+ $A = RightJS.$A,
29
+ isArray = RightJS.isArray,
30
+ Wrapper = RightJS.Wrapper,
31
+ Element = RightJS.Element,
32
+ Input = RightJS.Input;
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ /**
41
+ * The widget units constructor
42
+ *
43
+ * @param String tag-name or Object methods
44
+ * @param Object methods
45
+ * @return Widget wrapper
46
+ */
47
+ function Widget(tag_name, methods) {
48
+ if (!methods) {
49
+ methods = tag_name;
50
+ tag_name = 'DIV';
51
+ }
52
+
53
+ /**
54
+ * An Abstract Widget Unit
55
+ *
56
+ * Copyright (C) 2010 Nikolay Nemshilov
57
+ */
58
+ var AbstractWidget = new RightJS.Wrapper(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
59
+ /**
60
+ * The common constructor
61
+ *
62
+ * @param Object options
63
+ * @param String optional tag name
64
+ * @return void
65
+ */
66
+ initialize: function(key, options) {
67
+ this.key = key;
68
+ var args = [{'class': 'rui-' + key}];
69
+
70
+ // those two have different constructors
71
+ if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
72
+ args.unshift(tag_name);
73
+ }
74
+ this.$super.apply(this, args);
75
+
76
+ if (RightJS.isString(options)) {
77
+ options = RightJS.$(options);
78
+ }
79
+
80
+ // if the options is another element then
81
+ // try to dynamically rewrap it with our widget
82
+ if (options instanceof RightJS.Element) {
83
+ this._ = options._;
84
+ if ('$listeners' in options) {
85
+ options.$listeners = options.$listeners;
86
+ }
87
+ options = {};
88
+ }
89
+ this.setOptions(options, this);
90
+ return this;
91
+ },
92
+
93
+ // protected
94
+
95
+ /**
96
+ * Catches the options
97
+ *
98
+ * @param Object user-options
99
+ * @param Element element with contextual options
100
+ * @return void
101
+ */
102
+ setOptions: function(options, element) {
103
+ element = element || this;
104
+ RightJS.Options.setOptions.call(this,
105
+ RightJS.Object.merge(options, eval("("+(
106
+ element.get('data-'+ this.key) || '{}'
107
+ )+")"))
108
+ );
109
+ return this;
110
+ }
111
+ });
112
+
113
+ /**
114
+ * Creating the actual widget class
115
+ *
116
+ */
117
+ var Klass = new RightJS.Wrapper(AbstractWidget, methods);
118
+
119
+ // creating the widget related shortcuts
120
+ RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || []);
121
+
122
+ return Klass;
123
+ }
124
+
125
+
126
+ /**
127
+ * A shared button unit.
128
+ * NOTE: we use the DIV units instead of INPUTS
129
+ * so those buttons didn't interfere with
130
+ * the user's tab-index on his page
131
+ *
132
+ * Copyright (C) 2010 Nikolay Nemshilov
133
+ */
134
+ var Button = new RightJS.Wrapper(RightJS.Element, {
135
+ /**
136
+ * Constructor
137
+ *
138
+ * @param String caption
139
+ * @param Object options
140
+ * @return void
141
+ */
142
+ initialize: function(caption, options) {
143
+ this.$super('div', options);
144
+ this._.innerHTML = caption;
145
+ this.addClass('rui-button');
146
+ },
147
+
148
+ /**
149
+ * Disasbles the button
150
+ *
151
+ * @return Button this
152
+ */
153
+ disable: function() {
154
+ return this.addClass('rui-button-disabled');
155
+ },
156
+
157
+ /**
158
+ * Enables the button
159
+ *
160
+ * @return Button this
161
+ */
162
+ enable: function() {
163
+ return this.removeClass('rui-button-disabled');
164
+ },
165
+
166
+ /**
167
+ * Checks if the button is disabled
168
+ *
169
+ * @return Button this
170
+ */
171
+ disabled: function() {
172
+ return this.hasClass('rui-button-disabled');
173
+ },
174
+
175
+ /**
176
+ * Checks if the button is enabled
177
+ *
178
+ * @return Button this
179
+ */
180
+ enabled: function() {
181
+ return !this.disabled();
182
+ },
183
+
184
+ /**
185
+ * Overloading the method, so it fired the events
186
+ * only when the button is active
187
+ *
188
+ * @return Button this
189
+ */
190
+ fire: function() {
191
+ if (this.enabled()) {
192
+ this.$super.apply(this, arguments);
193
+ }
194
+ return this;
195
+ }
196
+ });
197
+
198
+ /**
199
+ * A shared module that toggles a widget visibility status
200
+ * in a uniformed way according to the options settings
201
+ *
202
+ * Copyright (C) 2010 Nikolay Nemshilov
203
+ */
204
+
205
+ /**
206
+ * The toggler's common functionality
207
+ *
208
+ * NOTE: this function getting called in the context
209
+ * of a widget
210
+ *
211
+ * @param Element the element to toggle
212
+ * @param event String 'show' or 'hide' the event name
213
+ * @param String an optional fx-name
214
+ * @param Object an optional fx-options hash
215
+ * @return void
216
+ */
217
+ function toggler(element, event, fx_name, fx_options) {
218
+ if (RightJS.Fx) {
219
+ if (fx_name === undefined) {
220
+ fx_name = this.options.fxName;
221
+
222
+ if (fx_options === undefined) {
223
+ fx_options = {
224
+ duration: this.options.fxDuration,
225
+ onFinish: RightJS(this.fire).bind(this, event)
226
+ };
227
+
228
+ // hide on double time
229
+ if (event === 'hide') {
230
+ fx_options.duration = (RightJS.Fx.Durations[fx_options.duration] ||
231
+ fx_options.duration) / 2;
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ RightJS.Element.prototype[event].call(element, fx_name, fx_options);
238
+
239
+ // manually trigger the event if no fx were specified
240
+ if (!RightJS.Fx || !fx_name) { this.fire(event); }
241
+
242
+ return this;
243
+ }
244
+
245
+ /**
246
+ * Relatively positions the current element
247
+ * against the specified one
248
+ *
249
+ * NOTE: this function is called in a context
250
+ * of another element
251
+ *
252
+ * @param Element the target element
253
+ * @param String position 'right' or 'bottom'
254
+ * @param Boolean if `true` then the element size will be adjusted
255
+ * @return void
256
+ */
257
+ function re_position(element, where, resize) {
258
+ var anchor = this.reAnchor || (this.reAnchor =
259
+ new RightJS.Element('div', {'class': 'rui-re-anchor'}))
260
+ .insert(this),
261
+
262
+ pos = anchor.insertTo(element, 'after').position(),
263
+ dims = element.dimensions(), target = this,
264
+
265
+ border_top = parseInt(element.getStyle('borderTopWidth')),
266
+ border_left = parseInt(element.getStyle('borderLeftWidth')),
267
+ border_right = parseInt(element.getStyle('borderRightWidth')),
268
+ border_bottom = parseInt(element.getStyle('borderBottomWidth')),
269
+
270
+ top = dims.top - pos.y + border_top,
271
+ left = dims.left - pos.x + border_left,
272
+ width = dims.width - border_left - border_right,
273
+ height = dims.height - border_top - border_bottom;
274
+
275
+ // making the element to appear so we could read it's sizes
276
+ target.setStyle('visibility:hidden').show(null);
277
+
278
+ if (where === 'right') {
279
+ left += width - target.size().x;
280
+ } else { // bottom
281
+ top += height;
282
+ }
283
+
284
+ target.moveTo(left, top);
285
+
286
+ if (resize) {
287
+ if (['left', 'right'].include(where)) {
288
+ target.setHeight(height);
289
+ } else {
290
+ target.setWidth(width);
291
+ }
292
+ }
293
+
294
+ // rolling the invisibility back
295
+ target.setStyle('visibility:visible').hide(null);
296
+ }
297
+
298
+ /**
299
+ * The actual shared module to be inserted in the widgets
300
+ *
301
+ * Copyright (C) 2010 Nikolay Nemshilov
302
+ */
303
+ var Toggler = {
304
+ /**
305
+ * Shows the element
306
+ *
307
+ * @param String fx-name
308
+ * @param Object fx-options
309
+ * @return Element this
310
+ */
311
+ show: function(fx_name, fx_options) {
312
+ this.constructor.current = this;
313
+ return toggler.call(this, this, 'show', fx_name, fx_options);
314
+ },
315
+
316
+ /**
317
+ * Hides the element
318
+ *
319
+ * @param String fx-name
320
+ * @param Object fx-options
321
+ * @return Element this
322
+ */
323
+ hide: function(fx_name, fx_options) {
324
+ this.constructor.current = null;
325
+ return toggler.call(this, this, 'hide', fx_name, fx_options);
326
+ },
327
+
328
+ /**
329
+ * Toggles the widget at the given element
330
+ *
331
+ * @param Element the related element
332
+ * @param String position right/bottom (bottom is the default)
333
+ * @param Boolean marker if the element should be resized to the element size
334
+ * @return Widget this
335
+ */
336
+ showAt: function(element, where, resize) {
337
+ this.hide(null).shownAt = element = RightJS.$(element);
338
+
339
+ // moves this element at the given one
340
+ re_position.call(this, element, where, resize);
341
+
342
+ return this.show();
343
+ },
344
+
345
+ /**
346
+ * Toggles the widget at the given element
347
+ *
348
+ * @param Element the related element
349
+ * @param String position top/left/right/bottom (bottom is the default)
350
+ * @param Boolean marker if the element should be resized to the element size
351
+ * @return Widget this
352
+ */
353
+ toggleAt: function(element, where, resize) {
354
+ return this.hidden() ? this.showAt(element, where, resize) : this.hide();
355
+ }
356
+ };
357
+
358
+ /**
359
+ * A shared module that provides for the widgets an ability
360
+ * to be assigned to an input element and work in pair with it
361
+ *
362
+ * NOTE: this module works in pair with the 'RePosition' module!
363
+ *
364
+ * Copyright (C) 2010 Nikolay Nemshilov
365
+ */
366
+ var Assignable = {
367
+ /**
368
+ * Assigns the widget to serve the given input element
369
+ *
370
+ * Basically it puts the references of the current widget
371
+ * to the input and trigger objects so they could be recognized
372
+ * later, and it also synchronizes the changes between the input
373
+ * element and the widget
374
+ *
375
+ * @param {Element} input field
376
+ * @param {Element} optional trigger
377
+ * @return Widget this
378
+ */
379
+ assignTo: function(input, trigger) {
380
+ input = RightJS.$(input);
381
+ trigger = RightJS.$(trigger);
382
+
383
+ if (trigger) {
384
+ trigger[this.key] = this;
385
+ trigger.assignedInput = input;
386
+ } else {
387
+ input[this.key] = this;
388
+ }
389
+
390
+ var on_change = RightJS(function() {
391
+ if (this.visible() && (!this.showAt || this.shownAt === input)) {
392
+ this.setValue(input.value());
393
+ }
394
+ }).bind(this);
395
+
396
+ input.on({
397
+ keyup: on_change,
398
+ change: on_change
399
+ });
400
+
401
+ this.onChange(function() {
402
+ if (!this.showAt || this.shownAt === input) {
403
+ input.setValue(this.getValue());
404
+ }
405
+ });
406
+
407
+ return this;
408
+ }
409
+ };
410
+
411
+ /**
412
+ * The basic file for Colorpicker
413
+ *
414
+ * Copyright (C) 2010 Nikolay Nemshilov
415
+ */
416
+ var Colorpicker = new Widget({
417
+ include: [Toggler, Assignable],
418
+
419
+ extend: {
420
+ version: '2.0.0',
421
+
422
+ EVENTS: $w('change show hide done'),
423
+
424
+ Options: {
425
+ format: 'hex', // hex or rgb
426
+
427
+ update: null, // an element to update with the color text
428
+ updateBg: null, // an element to update it's background color
429
+ trigger: null, // a trigger element for the popup
430
+
431
+ fxName: 'fade', // popup displaying fx
432
+ fxDuration: 'short',
433
+
434
+ cssRule: '*[data-colorpicker]'
435
+ },
436
+
437
+ i18n: {
438
+ Done: 'Done'
439
+ },
440
+
441
+ // hides all the popup colorpickers on the page
442
+ hideAll: function() {
443
+ $$('div.rui-colorpicker').each(function(picker) {
444
+ if (picker instanceof Colorpicker && !picker.inlined()) {
445
+ picker.hide();
446
+ }
447
+ });
448
+ }
449
+ },
450
+
451
+ /**
452
+ * basic constructor
453
+ *
454
+ * @param Object options
455
+ */
456
+ initialize: function(options) {
457
+ this
458
+ .$super('colorpicker', options)
459
+ .addClass('rui-panel')
460
+ .insert([
461
+ this.field = new Field(),
462
+ this.colors = new Colors(),
463
+ this.controls = new Controls()
464
+ ])
465
+ .on({
466
+ mousedown: this.startTrack,
467
+
468
+ keyup: this.recalc,
469
+ blur: this.update,
470
+ focus: this.cancelTimer,
471
+
472
+ done: this.done
473
+ });
474
+
475
+ // hooking up the elements to update
476
+ if (this.options.update) { this.assignTo(this.options.update, this.options.trigger); }
477
+ if (this.options.updateBg) { this.updateBg(this.options.updateBg); }
478
+
479
+ // setting up the initial values
480
+ this.tint = R([1, 0, 0]);
481
+ this.satur = 0;
482
+ this.bright = 1;
483
+ this.color = R([255, 255, 255]);
484
+
485
+ this.recalc().update();
486
+ },
487
+
488
+ /**
489
+ * Sets the color of the widget
490
+ *
491
+ * @param mixed value, Array or HEX or RGB value
492
+ * @return Colorpicker this
493
+ */
494
+ setValue: function(value) {
495
+ var color = isArray(value) ? value : this.toColor(value);
496
+ if (color && color.length === 3) {
497
+
498
+ // normalizing the data
499
+ color = color.map(function(value) {
500
+ return this.bound(parseInt(''+value), 0, 255);
501
+ }, this);
502
+
503
+ this.color = color;
504
+ this.color2tint().update();
505
+
506
+ // reupdating the popup-state a bit later when we have the sizes
507
+ if (!this.colors.size().y) {
508
+ this.update.bind(this).delay(20);
509
+ }
510
+ }
511
+ return this;
512
+ },
513
+
514
+ /**
515
+ * Returns the value of the widget
516
+ * formatted according to the options
517
+ *
518
+ * @param Boolean if you need a clean RGB values array
519
+ * @return mixed value
520
+ */
521
+ getValue: function(array) {
522
+ return array ? this.color : this[this.options.format === 'rgb' ? 'toRgb' : 'toHex']();
523
+ },
524
+
525
+ /**
526
+ * Assigns the colorpicer to automatically update
527
+ * given element's background on changes
528
+ *
529
+ * @param mixed element reference
530
+ * @return Colorpicker this
531
+ */
532
+ updateBg: function(element_ref) {
533
+ var element = $(element_ref);
534
+ if (element) {
535
+ this.onChange(R(function(color) {
536
+ element._.style.backgroundColor = this.toRgb();
537
+ }).bind(this));
538
+ }
539
+ return this;
540
+ },
541
+
542
+ /**
543
+ * Inlines the widget into the given element
544
+ *
545
+ * @param Element reference
546
+ * @param String optional position
547
+ * @return Colorpicker this
548
+ */
549
+ insertTo: function(element, position) {
550
+ return this
551
+ .$super(element, position)
552
+ .addClass('rui-colorpicker-inline');
553
+ },
554
+
555
+ /**
556
+ * Checks if that's an inlined version of the widget
557
+ *
558
+ * @return Boolean check result
559
+ */
560
+ inlined: function() {
561
+ return this.hasClass('rui-colorpicker-inline');
562
+ },
563
+
564
+ /**
565
+ * Finalizes the action
566
+ *
567
+ * @return Colorpicker this
568
+ */
569
+ done: function() {
570
+ if (!this.inlined()) {
571
+ this.hide();
572
+ }
573
+ return this;
574
+ },
575
+
576
+ // protected
577
+
578
+ // catching up the user options
579
+ setOptions: function(user_options) {
580
+ user_options = user_options || {};
581
+ this.$super(user_options, $(user_options.trigger || user_options.update));
582
+ },
583
+
584
+ // updates the preview and pointer positions
585
+ update: function() {
586
+ this.field._.style.backgroundColor = 'rgb('+ this.tint.map(function(c) { return Math.round(c*255); }) +')';
587
+
588
+ // updating the input fields
589
+ var color = this.color, controls = this.controls;
590
+
591
+ controls.preview._.style.backgroundColor = controls.display._.value = this.toHex();
592
+
593
+ controls.rDisplay._.value = color[0];
594
+ controls.gDisplay._.value = color[1];
595
+ controls.bDisplay._.value = color[2];
596
+
597
+ // adjusting the field pointer position
598
+ var pointer = this.field.pointer._.style,
599
+ field = this.field.size(),
600
+ top = field.y - this.bright * field.y - 2,
601
+ left = this.satur * field.x - 2;
602
+
603
+ pointer.top = this.bound(top, 0, field.y - 5) + 'px';
604
+ pointer.left = this.bound(left, 0, field.x - 5) + 'px';
605
+
606
+ // adjusting the ting pointer position
607
+ var tint = this.tint, position;
608
+ field = this.colors.size();
609
+
610
+ if (tint[1] == 0) { // the red-blue section
611
+ position = tint[0] == 1 ? tint[2] : (2 - tint[0]);
612
+ } else if (tint[0] == 0) { // the blue-green section
613
+ position = 2 + (tint[2] == 1 ? tint[1] : (2 - tint[2]));
614
+ } else { // the green-red section
615
+ position = 4 + (tint[1] == 1 ? tint[0] : (2 - tint[1]));
616
+ }
617
+
618
+ position = position / 6 * field.y;
619
+
620
+ this.colors.pointer._.style.top = this.bound(position, 0, field.y - 4) + 'px';
621
+
622
+ // tracking the color change events
623
+ if (this.prevColor !== ''+this.color) {
624
+ this.fire('change', this.color);
625
+ this.prevColor = ''+ this.color;
626
+ }
627
+
628
+ return this;
629
+ },
630
+
631
+ // recalculates the state after the input field changes
632
+ recalc: function(event) {
633
+ if (event) {
634
+ var field = event.target, value = field._.value, color = $A(this.color), changed=false;
635
+
636
+ if (field === this.controls.display && /#\w{6}/.test(value)) {
637
+ // using the hex values
638
+ changed = color = this.toColor(value);
639
+ } else if (/^\d+$/.test(value)) {
640
+ // using the rgb values
641
+ color[field._.cIndex] = value;
642
+ changed = true;
643
+ }
644
+
645
+ if (changed) { this.setValue(color); }
646
+
647
+ } else {
648
+ this.tint2color();
649
+ }
650
+
651
+ return this;
652
+ },
653
+
654
+ // starts the mousemoves tracking
655
+ startTrack: function(event) {
656
+ this.stopTrack();
657
+ this.cancelTimer();
658
+
659
+ if (event.target === this.field.pointer) {
660
+ event.target = this.field;
661
+ } else if (event.target === this.colors.pointer) {
662
+ event.target = this.colors;
663
+ }
664
+
665
+ if (event.target === this.field || event.target === this.colors) {
666
+ event.stop();
667
+ Colorpicker.tracking = this;
668
+ event.target.tracking = true;
669
+ this.trackMove(event); // jumping over there
670
+ }
671
+ },
672
+
673
+ // stops tracking the mousemoves
674
+ stopTrack: function() {
675
+ Colorpicker.tracking = false;
676
+ this.field.tracking = false;
677
+ this.colors.tracking = false;
678
+ },
679
+
680
+ // tracks the cursor moves over the fields
681
+ trackMove: function(event) {
682
+ var field, pos = event.position(), top, left;
683
+
684
+ if (this.field.tracking) {
685
+ field = this.field.dimensions();
686
+ } else if (this.colors.tracking) {
687
+ field = this.colors.dimensions();
688
+ }
689
+
690
+ if (field) {
691
+ top = this.bound(pos.y - field.top, 0, field.height);
692
+ left = this.bound(pos.x - field.left, 0, field.width);
693
+
694
+ if (this.field.tracking) {
695
+ this.satur = left / field.width;
696
+ this.bright = 1 - top / field.height;
697
+
698
+ } else if (this.colors.tracking) {
699
+ // preventing it from jumping to the top
700
+ if (top == field.height) { top = field.height - 0.1; }
701
+
702
+ var step = field.height / 6,
703
+ tint = this.tint = [0, 0, 0],
704
+ stright = top % step / step,
705
+ reverse = 1 - stright;
706
+
707
+ if (top < step) {
708
+ tint[0] = 1;
709
+ tint[2] = stright;
710
+ } else if (top < step * 2) {
711
+ tint[0] = reverse;
712
+ tint[2] = 1;
713
+ } else if (top < step * 3) {
714
+ tint[2] = 1;
715
+ tint[1] = stright;
716
+ } else if (top < step * 4) {
717
+ tint[2] = reverse;
718
+ tint[1] = 1;
719
+ } else if (top < step * 5) {
720
+ tint[1] = 1;
721
+ tint[0] = stright;
722
+ } else {
723
+ tint[1] = reverse;
724
+ tint[0] = 1;
725
+ }
726
+ }
727
+
728
+ this.recalc().update();
729
+ }
730
+ },
731
+
732
+ cancelTimer: function(event) {
733
+ R(function() { // IE has a lack of sync in here
734
+ if (this._hide_delay) {
735
+ this._hide_delay.cancel();
736
+ this._hide_delay = null;
737
+ }
738
+ }).bind(this).delay(10);
739
+ }
740
+ });
741
+
742
+ /**
743
+ * The colors field element
744
+ *
745
+ * Copyright (C) 2010
746
+ */
747
+ var Field = new Wrapper(Element, {
748
+ initialize: function(options) {
749
+ this.$super('div', {'class': 'field'});
750
+ this.insert(this.pointer = $E('div', {'class': 'pointer'}));
751
+ }
752
+ });
753
+
754
+ /**
755
+ * The tint picker block
756
+ *
757
+ * Copyright (C) 2010 Nikolay Nemshilov
758
+ */
759
+ var Colors = new Wrapper(Element, {
760
+ initialize: function() {
761
+ this.$super('div', {'class': 'colors'});
762
+ this.insert(this.pointer = $E('div', {'class': 'pointer'}));
763
+ }
764
+ });
765
+
766
+ /**
767
+ * The controls block unit
768
+ *
769
+ * Copyright (C) 2010 Nikolay Nemshilov
770
+ */
771
+ var Controls = new Wrapper(Element, {
772
+ initialize: function() {
773
+ this.$super('div', {'class': 'controls'});
774
+ this.insert([
775
+ this.preview = $E('div', {'class': 'preview', 'html': '&nbsp;'}),
776
+ this.display = $E('input', {'type': 'text', 'class': 'display', maxlength: 7}),
777
+ $E('div', {'class': 'rgb-display'}).insert([
778
+ $E('div').insert([$E('label', {html: 'R:'}), this.rDisplay = $E('input', {maxlength: 3, cIndex: 0})]),
779
+ $E('div').insert([$E('label', {html: 'G:'}), this.gDisplay = $E('input', {maxlength: 3, cIndex: 1})]),
780
+ $E('div').insert([$E('label', {html: 'B:'}), this.bDisplay = $E('input', {maxlength: 3, cIndex: 2})])
781
+ ]),
782
+ this.button = new Button(Colorpicker.i18n.Done).onClick('fire', 'done')
783
+ ]);
784
+ }
785
+ });
786
+
787
+ /**
788
+ * This module contains various caluculations logic for
789
+ * the Colorpicker widget
790
+ *
791
+ * Copyright (C) 2010 Nikolay Nemshilov
792
+ */
793
+ Colorpicker.include({
794
+ /**
795
+ * Converts the color to a RGB string value
796
+ *
797
+ * @param Array optional color
798
+ * @return String RGB value
799
+ */
800
+ toRgb: function(color) {
801
+ return 'rgb('+ this.color.join(',') +')';
802
+ },
803
+
804
+ /**
805
+ * Converts the color to a HEX string value
806
+ *
807
+ * @param Array optional color
808
+ * @return String HEX value
809
+ */
810
+ toHex: function(color) {
811
+ return '#'+ this.color.map(function(c) { return (c < 16 ? '0' : '') + c.toString(16); }).join('');
812
+ },
813
+
814
+ /**
815
+ * Converts a string value into an Array of color
816
+ *
817
+ * @param String value
818
+ * @return Array of color or null
819
+ */
820
+ toColor: function(in_value) {
821
+ var value = in_value.toLowerCase(), match;
822
+
823
+ if ((match = /rgb\((\d+),(\d+),(\d+)\)/.exec(value))) {
824
+ return [match[1], match[2], match[3]].map(parseInt);
825
+
826
+ } else if (/#[\da-f]+/.test(value)) {
827
+ // converting the shortified hex in to the full-length version
828
+ if ((match = /^#([\da-f])([\da-f])([\da-f])$/.exec(value))) {
829
+ value = '#'+match[1]+match[1]+match[2]+match[2]+match[3]+match[3];
830
+ }
831
+
832
+ if ((match = /#([\da-f]{2})([\da-f]{2})([\da-f]{2})/.exec(value))) {
833
+ return [match[1], match[2], match[3]].map(function(n) { return parseInt(n, 16); });
834
+ }
835
+ }
836
+ },
837
+
838
+ /**
839
+ * converts color into the tint, saturation and brightness values
840
+ *
841
+ * @return Colorpicker this
842
+ */
843
+ color2tint: function() {
844
+ var color = $A(this.color).sort(function(a,b) { return a-b; }),
845
+ min = color[0], max = color[2];
846
+
847
+ this.bright = max / 255;
848
+ this.satur = 1 - min / (max || 1);
849
+
850
+ this.tint.each(function(value, i) {
851
+ this.tint[i] = ((!min && !max) || min == max) ? i == 0 ? 1 : 0 :
852
+ (this.color[i] - min) / (max - min);
853
+ return this.tint[i];
854
+ }, this);
855
+
856
+ return this;
857
+ },
858
+
859
+ /**
860
+ * Converts tint, saturation and brightness into the actual RGB color
861
+ *
862
+ * @return Colorpicker this
863
+ */
864
+ tint2color: function() {
865
+ var tint = this.tint, color = this.color;
866
+
867
+ for (var i=0; i < 3; i++) {
868
+ color[i] = 1 + this.satur * (tint[i] - 1);
869
+ color[i] = Math.round(255 * color[i] * this.bright);
870
+ }
871
+
872
+ return this;
873
+ },
874
+
875
+ /**
876
+ * bounds the value to the given limits
877
+ *
878
+ * @param {Number} value
879
+ * @param {Number} min value
880
+ * @param {Number} max value
881
+ * @return {Number} the value in bounds
882
+ */
883
+ bound: function(in_value, min, max) {
884
+ var value = in_value;
885
+
886
+ if (min < max) {
887
+ value = value < min ? min : value > max ? max : value;
888
+ } else {
889
+ if (value > max) { value = max; }
890
+ if (value < min) { value = min; }
891
+ }
892
+
893
+ return value;
894
+ }
895
+ });
896
+
897
+ /**
898
+ * The document level hooks for colorpicker
899
+ *
900
+ * Copyright (C) 2010 Nikolay Nemshilov
901
+ */
902
+ $(document).on({
903
+ mouseup: function() {
904
+ if (Colorpicker.tracking) {
905
+ Colorpicker.tracking.stopTrack();
906
+ }
907
+ },
908
+
909
+ mousemove: function(event) {
910
+ if (Colorpicker.tracking) {
911
+ Colorpicker.tracking.trackMove(event);
912
+ }
913
+ },
914
+
915
+ focus: function(event) {
916
+ var target = event.target instanceof Input ? event.target : null;
917
+
918
+ Colorpicker.hideAll();
919
+
920
+ if (target && (target.colorpicker || target.match(Colorpicker.Options.cssRule))) {
921
+ (target.colorpicker || new Colorpicker({update: target}))
922
+ .setValue(target.value()).showAt(target);
923
+ }
924
+ },
925
+
926
+ blur: function(event) {
927
+ var target = event.target, colorpicker = target.colorpicker;
928
+
929
+ if (colorpicker) {
930
+ // we use the delay so it didn't get hidden when the user clicks the calendar itself
931
+ colorpicker._hide_delay = R(function() {
932
+ colorpicker.hide();
933
+ }).delay(200);
934
+ }
935
+ },
936
+
937
+ click: function(event) {
938
+ var target = (event.target instanceof Element) ? event.target : null;
939
+
940
+ if (target && (target.colorpicker || target.match(Colorpicker.Options.cssRule))) {
941
+ if (!(target instanceof Input)) {
942
+ event.stop();
943
+ (target.colorpicker || new Colorpicker({trigger: target}))
944
+ .hide(null).toggleAt(target.assignedInput);
945
+ }
946
+ } else if (!event.find('div.rui-colorpicker')){
947
+ Colorpicker.hideAll();
948
+ }
949
+ },
950
+
951
+ keydown: function(event) {
952
+ var colorpicker = Colorpicker.current, name = ({
953
+ 27: 'hide', // Escape
954
+ 13: 'done' // Enter
955
+ })[event.keyCode];
956
+
957
+ if (name && colorpicker && colorpicker.visible()) {
958
+ event.stop();
959
+ colorpicker[name]();
960
+ }
961
+ }
962
+ });
963
+
964
+ document.write("<style type=\"text/css\"> *.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}.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}div.rui-colorpicker .field,div.rui-colorpicker .field *,div.rui-colorpicker .colors,div.rui-colorpicker .colors *{border:none;background:none;width:auto;height:auto;position:static;float:none;top:none;left:none;right:none;bottom:none;margin:0;padding:0;display:block;font-weight:normal;vertical-align:center}div.rui-colorpicker div.field,div.rui-colorpicker div.field div.pointer,div.rui-colorpicker div.colors,div.rui-colorpicker div.colors div.pointer{background:url(/images/rightjs-ui/colorpicker.png) no-repeat 0 0}div.rui-colorpicker div.field,div.rui-colorpicker div.colors,div.rui-colorpicker div.controls{display:inline-block; *display:inline; *zoom:1;position:relative;vertical-align:top;height:150px}div.rui-colorpicker div.field div.pointer,div.rui-colorpicker div.colors div.pointer{position:absolute;top:0px;left:0;width:9px;height:9px}div.rui-colorpicker input.display,div.rui-colorpicker div.preview,div.rui-colorpicker div.rgb-display,div.rui-colorpicker input.rui-ui-button{font-size:100%;display:block;width:auto;padding:0 .2em}div.rui-colorpicker input.display,div.rui-colorpicker div.preview,div.rui-colorpicker div.rgb-display input,div.rui-colorpicker input.rui-ui-button{border:1px solid #AAA;-moz-border-radius:.2em;-webkit-border-radius:.2em}div.rui-colorpicker div.field{width:150px;background-color:red;cursor:crosshair;margin-right:1.2em}div.rui-colorpicker div.field div.pointer{background-position:-170px 0;margin-left:-2px;margin-top:-2px}div.rui-colorpicker div.colors{width:16px;background-position:-150px 0;border-color:#EEE;cursor:pointer;margin-right:.6em}div.rui-colorpicker div.colors div.pointer{cursor:default;background-position:-170px -20px;margin-left:-8px;margin-top:-3px}div.rui-colorpicker div.controls{width:5em}div.rui-colorpicker div.preview{height:2em;background:white;border-color:#BBB}div.rui-colorpicker input.display{margin-top:.5em;background:#FFF;width:4.5em}div.rui-colorpicker div.rgb-display{padding:0;text-align:right;margin-top:.5em}div.rui-colorpicker div.rgb-display label{display:inline}div.rui-colorpicker div.rgb-display label:after{content:none}div.rui-colorpicker div.rgb-display input{vertical-align:top;font-size:100%;width:2em;text-align:right;margin-left:.2em;padding:0 .2em;background:#FFF;margin-bottom:1px;display:inline}div.rui-colorpicker div.rui-button{cursor:pointer;position:absolute;bottom:0;right:0;width:4em}div.rui-colorpicker-inline{display:inline-block; *display:inline; *zoom:1;position:relative;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none;z-index:auto}</style>");
965
+
966
+ return Colorpicker;
967
+ })(document, Math, parseInt, RightJS);