right-rails 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/README.textile +7 -3
  2. data/Rakefile +19 -0
  3. data/generators/right_rails/right_rails_generator.rb +8 -0
  4. data/images/colorpicker.png +0 -0
  5. data/images/resizable.png +0 -0
  6. data/javascripts/right-autocompleter-src.js +1 -4
  7. data/javascripts/right-calendar-src.js +0 -3
  8. data/javascripts/right-colorpicker-src.js +635 -0
  9. data/javascripts/right-colorpicker.js +9 -0
  10. data/javascripts/right-in-edit-src.js +1 -4
  11. data/javascripts/right-lightbox-src.js +2 -5
  12. data/javascripts/right-lightbox.js +1 -1
  13. data/javascripts/right-rails-src.js +29 -5
  14. data/javascripts/right-rails.js +1 -1
  15. data/javascripts/right-rater-src.js +1 -4
  16. data/javascripts/right-resizable-src.js +336 -0
  17. data/javascripts/right-resizable.js +9 -0
  18. data/javascripts/right-selectable-src.js +13 -11
  19. data/javascripts/right-selectable.js +1 -1
  20. data/javascripts/right-slider-src.js +1 -4
  21. data/javascripts/right-sortable-src.js +0 -1
  22. data/javascripts/right-tabs-src.js +2 -5
  23. data/javascripts/right-tooltips-src.js +19 -11
  24. data/javascripts/right-tooltips.js +1 -1
  25. data/javascripts/right-ui-i18n-de.js +8 -2
  26. data/javascripts/right-ui-i18n-es.js +7 -1
  27. data/javascripts/right-ui-i18n-fr.js +7 -1
  28. data/javascripts/right-ui-i18n-hu.js +6 -1
  29. data/javascripts/right-ui-i18n-jp.js +8 -1
  30. data/javascripts/right-ui-i18n-nl.js +8 -1
  31. data/javascripts/right-ui-i18n-pt-br.js +43 -0
  32. data/javascripts/right-ui-i18n-ru.js +8 -1
  33. data/javascripts/right-ui-i18n-ua.js +8 -1
  34. data/javascripts/right-uploader-src.js +1 -4
  35. data/lib/right_rails/helpers/basic.rb +7 -0
  36. data/lib/right_rails/helpers/forms.rb +44 -3
  37. data/lib/right_rails/helpers/misc.rb +55 -16
  38. data/lib/right_rails/java_script_generator.rb +4 -4
  39. data/spec/lib/right_rails/helpers/basic_spec.rb +4 -1
  40. data/spec/lib/right_rails/helpers/forms_spec.rb +10 -0
  41. data/spec/lib/right_rails/helpers/misc_spec.rb +39 -8
  42. metadata +11 -4
data/README.textile CHANGED
@@ -37,15 +37,19 @@ h3. Usage
37
37
 
38
38
  Install the plugin to your rails application
39
39
 
40
- @script/plugin install git://github.com/MadRabbit/right-rails.git@
40
+ <pre>script/plugin install git://github.com/MadRabbit/right-rails.git</pre>
41
41
 
42
42
  After that run the @right_rails@ generator, which will put all the JavaScripts in place
43
43
 
44
- @script/generate right_rails@
44
+ <pre>script/generate right_rails</pre>
45
+
46
+ And add the following helper to your application layout, this will include all the necessary scripts on your page
47
+
48
+ <pre><%= rightjs_scripts %></pre>
45
49
 
46
50
  You also will have an ajax-friendly scaffold generator
47
51
 
48
- @script/generate right_scaffold Zing@
52
+ <pre>script/generate right_scaffold Zing</pre>
49
53
 
50
54
  h4. Ruby Gem
51
55
 
data/Rakefile CHANGED
@@ -21,3 +21,22 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
21
21
  rdoc.rdoc_files.include('README')
22
22
  rdoc.rdoc_files.include('lib/**/*.rb')
23
23
  end
24
+
25
+
26
+ namespace :rjs do
27
+ desc 'Patches the JavaScript UI modules for new images location'
28
+ task :patch_ui do
29
+ FileList['javascripts/*.js'].each do |filename|
30
+ old_content = File.read(filename)
31
+ new_content = old_content.gsub('url(../../img/', "url(/images/rightjs-ui/")
32
+ new_content = new_content.gsub(/([^\s])no-repeat/, '\1 no-repeat') # front-compiler CSS compressor bug fix
33
+
34
+ if old_content != new_content
35
+ puts "Patching: #{filename}"
36
+ File.open(filename, "w") do |f|
37
+ f.write new_content
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -30,6 +30,14 @@ class RightRailsGenerator < Rails::Generator::Base
30
30
  # creating the iframed uploads layout
31
31
  m.directory "app/views/layouts"
32
32
  m.file "/../generators/right_rails/templates/iframed.html.erb", "app/views/layouts/iframed.html.erb"
33
+
34
+ # copying the images in place
35
+ m.directory "public/images/rightjs-ui"
36
+ Dir.open("#{File.dirname(__FILE__)}/../../images").each do |filename|
37
+ unless ['.', '..'].include?(filename)
38
+ m.file "/../images/#{filename}", "public/images/rightjs-ui/#{filename}"
39
+ end
40
+ end
33
41
  end
34
42
  end
35
43
 
Binary file
Binary file
@@ -6,7 +6,6 @@
6
6
  * @copyright (C) 2009-2010 Nikolay V. Nemshilov
7
7
  */
8
8
  if (!RightJS) { throw "Gimme RightJS. Please." };
9
-
10
9
  /**
11
10
  * The RightJS UI Autocompleter unit base class
12
11
  *
@@ -316,6 +315,4 @@ document.on({
316
315
  Autocompleter.find(event);
317
316
  }
318
317
  }
319
- });
320
-
321
- document.write("<style type=\"text/css\">div.right-autocompleter,div.autocompleter,div.autocompleter ul,div.autocompleter ul li,div.autocompleter-spinner,div.autocompleter-spinner div{border:none;background:none;margin:0;padding:0;list-style:none;font-weight:normal}div.right-autocompleter{position:absolute;display:inline}div.autocompleter{display:none;position:absolute;z-index:9999999;background:white;-moz-box-shadow:#BBB .2em .2em .4em;-webkit-box-shadow:#BBB .2em .2em .4em;overflow:hidden}div.autocompleter ul{*border-bottom:1px solid #CCC}div.autocompleter ul li{padding:.2em .4em;border:1px solid #CCC;border-top:none;border-bottom:none;cursor:pointer}div.autocompleter ul li:first-child{border-top:1px solid #CCC}div.autocompleter ul li:last-child{border-bottom:1px solid #CCC;*border-bottom:none}div.autocompleter ul li.current{background:#DDD}div.autocompleter-spinner{position:absolute;z-index:100000000;text-align:center;font-size:140%;font-family:Georgia;background:#DDD;color:#666;display:none;width:1em}div.autocompleter-spinner div.dot-1{margin-left:-4px}div.autocompleter-spinner div.dot-2{}div.autocompleter-spinner div.dot-3{margin-left:4px}</style>");
318
+ });document.write("<style type=\"text/css\">div.right-autocompleter,div.autocompleter,div.autocompleter ul,div.autocompleter ul li,div.autocompleter-spinner,div.autocompleter-spinner div{border:none;background:none;margin:0;padding:0;list-style:none;font-weight:normal}div.right-autocompleter{position:absolute;display:inline}div.autocompleter{display:none;position:absolute;z-index:9999999;background:white;-moz-box-shadow:#BBB .2em .2em .4em;-webkit-box-shadow:#BBB .2em .2em .4em;overflow:hidden}div.autocompleter ul{*border-bottom:1px solid #CCC}div.autocompleter ul li{padding:.2em .4em;border:1px solid #CCC;border-top:none;border-bottom:none;cursor:pointer}div.autocompleter ul li:first-child{border-top:1px solid #CCC}div.autocompleter ul li:last-child{border-bottom:1px solid #CCC;*border-bottom:none}div.autocompleter ul li.current{background:#DDD}div.autocompleter-spinner{position:absolute;z-index:100000000;text-align:center;font-size:140%;font-family:Georgia;background:#DDD;color:#666;display:none;width:1em}div.autocompleter-spinner div.dot-1{margin-left:-4px}div.autocompleter-spinner div.dot-2{}div.autocompleter-spinner div.dot-3{margin-left:4px}</style>");
@@ -6,7 +6,6 @@
6
6
  * @copyright (C) 2009-2010 Nikolay V. Nemshilov
7
7
  */
8
8
  if (!RightJS) { throw "Gimme RightJS. Please." };
9
-
10
9
  /**
11
10
  * The calendar widget for RightJS
12
11
  *
@@ -944,6 +943,4 @@ Calendar.include({
944
943
  })();
945
944
 
946
945
 
947
-
948
-
949
946
  document.write("<style type=\"text/css\">div.right-calendar,div.right-calendar table,div.right-calendar table tr,div.right-calendar table th,div.right-calendar table td,div.right-calendar table tbody,div.right-calendar table thead{background:none;border:none;width:auto;height:auto;margin:0;padding:0}*.right-ui-button{display:inline-block;*display:inline;*zoom:1;height:1em;line-height:1em;padding:.2em .5em;text-align:center;border:1px solid #CCC;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;cursor:pointer;color:#555;background-color:#FFF}*.right-ui-button:hover{color:#222;border-color:#999;background-color:#CCC}*.right-ui-button-disabled,*.right-ui-button-disabled:hover{color:#888;background:#EEE;border-color:#CCC;cursor:default}*.right-ui-buttons{margin-top:.5em}div.right-calendar{position:absolute;height:auto;border:1px solid #BBB;position:relative;padding:.5em;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;cursor:default;background-color:#EEE;-moz-box-shadow:.2em .4em .8em #666;-webkit-box-shadow:.2em .4em .8em #666}div.right-calendar-inline{position:relative;display:inline-block;vertical-align:top;*display:inline;*zoom:1;-moz-box-shadow:none;-webkit-box-shadow:none}div.right-calendar-prev-button,div.right-calendar-next-button,div.right-calendar-prev-year-button,div.right-calendar-next-year-button{position:absolute;float:left;width:1em;padding:.15em .4em}div.right-calendar-next-button{right:.5em}div.right-calendar-prev-year-button{left:2.55em}div.right-calendar-next-year-button{right:2.55em}div.right-calendar-month-caption{text-align:center;height:1.2em;line-height:1.2em}table.right-calendar-greed{border-spacing:0px}table.right-calendar-greed td{vertical-align:top;padding-right:.4em}table.right-calendar-greed>tbody>td:last-child{padding:0}div.right-calendar-month table{margin-top:.2em;border-spacing:1px;border-collapse:separate}div.right-calendar-month table th{color:#777;text-align:center}div.right-calendar-month table 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.right-calendar-month table td:hover{background-color:#CCC;border-color:#AAA;color:#000}div.right-calendar-month table td.right-calendar-day-blank{background:transparent;cursor:default;border:none}div.right-calendar-month table td.right-calendar-day-selected{background-color:#BBB;border-color:#AAA;color:#222;font-weight:bold;padding:.1em .2em}div.right-calendar-month table td.right-calendar-day-disabled{color:#888;background:#EEE;border-color:#CCC;cursor:default}div.right-calendar-time{border-top:1px solid #ccc;margin-top:.3em;padding-top:.5em;text-align:center}div.right-calendar-time select{margin:0 .4em}div.right-calendar-buttons div.right-ui-button{width:3.2em}div.right-calendar-done-button{position:absolute;right:.5em}</style>");
@@ -0,0 +1,635 @@
1
+ /**
2
+ * RightJS UI Colorpicker widget
3
+ *
4
+ * See http://rightjs.org/ui/colorpicker
5
+ *
6
+ * Copyright (C) 2010 Nikolay Nemshilov
7
+ */
8
+ if (!self.RightJS) throw "Gimme RightJS";
9
+ /**
10
+ * The basic file for Colorpicker
11
+ *
12
+ * Copyright (C) 2010 Nikolay Nemshilov
13
+ */
14
+ var Colorpicker = new Class(Observer, {
15
+ extend: {
16
+ EVENTS: $w('change show hide done'),
17
+
18
+ Options: {
19
+ format: 'hex', // hex or rgb
20
+
21
+ update: null, // an element to update with the color text
22
+ updateBg: null, // an element to update it's background color
23
+
24
+ fxName: 'fade', // popup displaying fx
25
+ fxDuration: 'short',
26
+
27
+ cssRule: '*[rel^=colorpicker]'
28
+ },
29
+
30
+ i18n: {
31
+ Done: 'Done'
32
+ },
33
+
34
+ // builds or finds a colorpicker for the target element
35
+ find: function(element) {
36
+ var uid = $uid(element), instances = Colorpicker.instances;
37
+
38
+ if (!instances[uid]) {
39
+ var pick = instances[uid] = new Colorpicker(eval('('+ element.get('data-colorpicker-options') +')'));
40
+
41
+ if (element.tagName == 'INPUT')
42
+ pick.assignTo(element);
43
+ else {
44
+ var attr = Colorpicker.Options.cssRule.split('[').last().split('^=').first(),
45
+ match = /\[(.+?)\]/.exec(element.get(attr)), input;
46
+
47
+ if (match && (input = $(match[1]))) {
48
+ pick.assignTo(input, element);
49
+ }
50
+ }
51
+ }
52
+
53
+ return instances[uid];
54
+ },
55
+
56
+ instances: []
57
+ },
58
+
59
+ /**
60
+ * basic constructor
61
+ *
62
+ * @param Object options
63
+ */
64
+ initialize: function(options) {
65
+ this.$super(options);
66
+ this.init();
67
+ },
68
+
69
+ /**
70
+ * Sets the color of the widget
71
+ *
72
+ * @param mixed value, Array or HEX or RGB value
73
+ * @return Colorpicker this
74
+ */
75
+ setValue: function(value) {
76
+ var color = isArray(value) ? value : this.toColor(value);
77
+ if (color && color.length == 3) {
78
+
79
+ // normalizing the data
80
+ color = color.map(function(value) {
81
+ return this.bound((''+value).toInt(), 0, 255);
82
+ }, this);
83
+
84
+ this.color = color;
85
+ this.color2tint().update();
86
+ }
87
+ return this;
88
+ },
89
+
90
+ /**
91
+ * Returns the value of the widget
92
+ * formatted according to the options
93
+ *
94
+ * @param Boolean if you need a clean RGB values array
95
+ * @return mixed value
96
+ */
97
+ getValue: function(array) {
98
+ return array ? this.color : this[this.options.format === 'rgb' ? 'toRgb' : 'toHex']();
99
+ },
100
+
101
+ /**
102
+ * Inlines the widget into the given element
103
+ *
104
+ * @param Element reference
105
+ * @param String optional position
106
+ * @return Colorpicker this
107
+ */
108
+ insertTo: function(element, position) {
109
+ this.element
110
+ .addClass('right-colorpicker-inline')
111
+ .insertTo(element, position);
112
+
113
+ return this;
114
+ },
115
+
116
+ // protected
117
+
118
+ // initializes the widget
119
+ init: function() {
120
+ this.build();
121
+
122
+ // attaching the mouse-events to the fields
123
+ [this.field, this.colors].each(function(element) {
124
+ element.onMousedown(this.startTrack.bind(this));
125
+ }, this);
126
+
127
+ // tracking the changes on the input fields
128
+ [this.display, this.rDisplay, this.gDisplay, this.bDisplay].each('on', {
129
+ keyup: this.recalc.bind(this),
130
+ blur: this.update.bind(this),
131
+ focus: this.cancelTimer.bind(this)
132
+ });
133
+
134
+ // attaching the done button
135
+ this.button.onClick(this.fire.bind(this, 'done'));
136
+
137
+ // preventing the general body clicks
138
+ this.element.onMousedown(function(event) {
139
+ if (event.target.tagName !== 'INPUT') {
140
+ event.stop();
141
+ this.cancelTimer();
142
+ }
143
+ }.bind(this));
144
+
145
+ // attaching the picker own events
146
+ this
147
+ .onDone('hide')
148
+ .onChange(function(color) {
149
+ if (this.target) {
150
+ this.target[this.target.tagName == 'INPUT' ? 'value' : 'innerHTML'] =
151
+ this[this.options.format == 'rgb' ? 'toRgb' : 'toHex']();
152
+ }
153
+ }.bind(this));
154
+
155
+ // hooking up the elements to update
156
+ if (this.options.update) this.assignTo(this.options.update);
157
+ if (this.options.updateBg) this.updateBg(this.options.updateBg);
158
+
159
+ // setting up the initial value
160
+ // NOTE: to speed the things up a bit we use params
161
+ // for tint, saturation and brightness and
162
+ // normal RGB value to keep the current color
163
+ this.tint = [1, 0, 0];
164
+ this.satur = 0;
165
+ this.bright = 1;
166
+ this.color = [255, 255, 255];
167
+
168
+ this.recalc().update();
169
+ },
170
+
171
+ // builds the widget
172
+ build: function() {
173
+ var base = this.element = $E('div', {'class': 'right-colorpicker right-ui-panel'});
174
+
175
+ // the field block
176
+ this.field = $E('div', {'class': 'field'}).insertTo(base);
177
+ this.fieldPointer = $E('div', {'class': 'field-pointer'}).insertTo(this.field);
178
+
179
+ // the tint block
180
+ this.colors = $E('div', {'class': 'colors'}).insertTo(base);
181
+ this.colorsPointer = $E('div', {'class': 'colors-pointer'}).insertTo(this.colors);
182
+
183
+ // the controls block
184
+ $E('div', {'class': 'controls'}).insert([
185
+ this.preview = $E('div', {'class': 'preview', 'html': '&nbsp;'}).insertTo(base),
186
+ this.display = $E('input', {'type': 'text', 'class': 'display', maxlength: 7}).insertTo(base),
187
+ $E('div', {'class': 'rgb-display'}).insert([
188
+ $E('div').insert([$E('label', {html: 'R:'}), this.rDisplay = $E('input', {maxlength: 3, cIndex: 0})]),
189
+ $E('div').insert([$E('label', {html: 'G:'}), this.gDisplay = $E('input', {maxlength: 3, cIndex: 1})]),
190
+ $E('div').insert([$E('label', {html: 'B:'}), this.bDisplay = $E('input', {maxlength: 3, cIndex: 2})])
191
+ ]),
192
+ this.button = $E('input', {'type': 'button', 'class': 'right-ui-button', value: Colorpicker.i18n.Done})
193
+ ]).insertTo(base);
194
+ },
195
+
196
+ // updates the preview and pointer positions
197
+ update: function() {
198
+ this.field.style.backgroundColor = 'rgb('+ this.tint.map(function(c) { return (c*255).round(); }) +')';
199
+ this.preview.style.backgroundColor = this.display.value = this.toHex();
200
+
201
+ // updating the input fields
202
+ var color = this.color;
203
+ this.rDisplay.value = color[0];
204
+ this.gDisplay.value = color[1];
205
+ this.bDisplay.value = color[2];
206
+
207
+ // adjusting the field pointer position
208
+ var pointer = this.fieldPointer.style,
209
+ field = this.field.sizes(),
210
+ top = field.y - this.bright * field.y - 2,
211
+ left = this.satur * field.x - 2;
212
+
213
+ pointer.top = this.bound(top, 0, field.y - 5) + 'px';
214
+ pointer.left = this.bound(left, 0, field.x - 5) + 'px';
215
+
216
+ // adjusting the ting pointer position
217
+ var field = this.colors.sizes(), tint = this.tint, position;
218
+
219
+ if (tint[1] == 0) { // the red-blue section
220
+ position = tint[0] == 1 ? tint[2] : (2 - tint[0]);
221
+ } else if (tint[0] == 0) { // the blue-green section
222
+ position = 2 + (tint[2] == 1 ? tint[1] : (2 - tint[2]));
223
+ } else { // the green-red section
224
+ position = 4 + (tint[1] == 1 ? tint[0] : (2 - tint[1]));
225
+ }
226
+
227
+ position = position / 6 * field.y;
228
+
229
+ this.colorsPointer.style.top = this.bound(position, 0, field.y - 4) + 'px';
230
+
231
+ // tracking the color change events
232
+ if (this.prevColor !== ''+this.color) {
233
+ this.fire('change', this.color);
234
+ this.prevColor = ''+ this.color;
235
+ }
236
+
237
+ return this;
238
+ },
239
+
240
+ // recalculates the state after the input field changes
241
+ recalc: function(event) {
242
+ if (event) {
243
+ var field = event.target, value = field.value, color = this.color.clone(), changed=false;
244
+
245
+ if (field == this.display && /#\w{6}/.test(value)) {
246
+ // using the hex values
247
+ changed = color = this.toColor(value);
248
+ } else if (/^\d+$/.test(value)) {
249
+ // using the rgb values
250
+ color[field.cIndex] = value;
251
+ changed = true;
252
+ }
253
+
254
+ if (changed) this.setValue(color);
255
+
256
+ } else {
257
+ this.tint2color();
258
+ }
259
+
260
+ return this;
261
+ },
262
+
263
+ // starts the mousemoves tracking
264
+ startTrack: function(event) {
265
+ event.stop();
266
+ this.stopTrack();
267
+ this.cancelTimer();
268
+ Colorpicker.tracking = this;
269
+ event.target.tracking = true;
270
+ this.trackMove(event); // jumping over there
271
+ },
272
+
273
+ // stops tracking the mousemoves
274
+ stopTrack: function() {
275
+ Colorpicker.tracking = false;
276
+ this.field.tracking = false;
277
+ this.colors.tracking = false;
278
+ },
279
+
280
+ // tracks the cursor moves over the fields
281
+ trackMove: function(event) {
282
+ var field, pos = event.position(), top, left;
283
+
284
+ if (this.field.tracking) {
285
+ field = this.field.dimensions();
286
+ } else if (this.colors.tracking) {
287
+ field = this.colors.dimensions();
288
+ }
289
+
290
+ if (field) {
291
+ top = this.bound(pos.y - field.top, 0, field.height);
292
+ left = this.bound(pos.x - field.left, 0, field.width);
293
+
294
+ if (this.field.tracking) {
295
+ this.satur = left / field.width;
296
+ this.bright = 1 - top / field.height;
297
+
298
+ } else if (this.colors.tracking) {
299
+ // preventing it from jumping to the top
300
+ if (top == field.height) top = field.height - 0.1;
301
+
302
+ var step = field.height / 6,
303
+ tint = this.tint = [0, 0, 0],
304
+ stright = top % step / step,
305
+ reverse = 1 - stright;
306
+
307
+ if (top < step) {
308
+ tint[0] = 1;
309
+ tint[2] = stright;
310
+ } else if (top < step * 2) {
311
+ tint[0] = reverse;
312
+ tint[2] = 1;
313
+ } else if (top < step * 3) {
314
+ tint[2] = 1;
315
+ tint[1] = stright;
316
+ } else if (top < step * 4) {
317
+ tint[2] = reverse;
318
+ tint[1] = 1;
319
+ } else if (top < step * 5) {
320
+ tint[1] = 1;
321
+ tint[0] = stright;
322
+ } else {
323
+ tint[1] = reverse;
324
+ tint[0] = 1;
325
+ }
326
+ }
327
+
328
+ this.recalc().update();
329
+ }
330
+ }
331
+ });
332
+
333
+ /**
334
+ * This module contains various caluculations logic for
335
+ * the Colorpicker widget
336
+ *
337
+ * Copyright (C) 2010 Nikolay Nemshilov
338
+ */
339
+ Colorpicker.include({
340
+ /**
341
+ * Converts the color to a RGB string value
342
+ *
343
+ * @param Array optional color
344
+ * @return String RGB value
345
+ */
346
+ toRgb: function(color) {
347
+ return 'rgb('+ this.color.join(',') +')';
348
+ },
349
+
350
+ /**
351
+ * Converts the color to a HEX string value
352
+ *
353
+ * @param Array optional color
354
+ * @return String HEX value
355
+ */
356
+ toHex: function(color) {
357
+ return '#'+ this.color.map(function(c) { return (c < 16 ? '0' : '') + c.toString(16); }).join('');
358
+ },
359
+
360
+ /**
361
+ * Converts a string value into an Array of color
362
+ *
363
+ * @param String value
364
+ * @return Array of color or null
365
+ */
366
+ toColor: function(in_value) {
367
+ var value = in_value.toLowerCase(), match;
368
+
369
+ if (match = /rgb\((\d+),(\d+),(\d+)\)/.exec(value)) {
370
+ return [match[1], match[2], match[3]].map('toInt');
371
+
372
+ } else if (/#[\da-f]+/.test(value)) {
373
+ // converting the shortified hex in to the full-length version
374
+ if (match = /^#([\da-f])([\da-f])([\da-f])$/.exec(value))
375
+ value = '#'+match[1]+match[1]+match[2]+match[2]+match[3]+match[3];
376
+
377
+ if (match = /#([\da-f]{2})([\da-f]{2})([\da-f]{2})/.exec(value)) {
378
+ return [match[1], match[2], match[3]].map('toInt', 16);
379
+ }
380
+ }
381
+ },
382
+
383
+ /**
384
+ * converts color into the tint, saturation and brightness values
385
+ *
386
+ * @return Colorpicker this
387
+ */
388
+ color2tint: function() {
389
+ var color = this.color.clone().sort(function(a,b) { return a-b; }),
390
+ min = color[0], max = color[2];
391
+
392
+ this.bright = max / 255;
393
+ this.satur = 1 - min / (max || 1);
394
+
395
+ this.tint.each(function(value, i) {
396
+ return this.tint[i] = ((!min && !max) || min == max) ? i == 0 ? 1 : 0 :
397
+ (this.color[i] - min) / (max - min);
398
+ }, this);
399
+
400
+ return this;
401
+ },
402
+
403
+ /**
404
+ * Converts tint, saturation and brightness into the actual RGB color
405
+ *
406
+ * @return Colorpicker this
407
+ */
408
+ tint2color: function() {
409
+ var tint = this.tint, color = this.color;
410
+
411
+ for (var i=0; i < 3; i++) {
412
+ color[i] = 1 + this.satur * (tint[i] - 1);
413
+ color[i] = (255 * color[i] * this.bright).round();
414
+ }
415
+
416
+ return this;
417
+ },
418
+
419
+ /**
420
+ * bounds the value to the given limits
421
+ *
422
+ * @param Number value
423
+ * @param Number min value
424
+ * @param Number max value
425
+ * @return Number the value in bounds
426
+ */
427
+ bound: function(in_value, min, max) {
428
+ var value = in_value;
429
+
430
+ if (min < max) {
431
+ value = value < min ? min : value > max ? max : value;
432
+ } else {
433
+ if (value > max) value = max;
434
+ if (value < min) value = min;
435
+ }
436
+
437
+ return value;
438
+ }
439
+ });
440
+
441
+ /**
442
+ * This module handles the colorpicker assignments
443
+ * to input fields
444
+ *
445
+ * Copyright (C) 2010 Nikolay Nemshilov
446
+ */
447
+ Colorpicker.include({
448
+ /**
449
+ * Hides the pop up element
450
+ *
451
+ * @return Colorpicker this
452
+ */
453
+ hide: function() {
454
+ if (!this.element.hasClass('right-colorpicker-inline')) {
455
+ this.target = null;
456
+ Colorpicker.current = null;
457
+ this.element.hide(this.options.fxName, {
458
+ duration: this.options.fxDuration
459
+ });
460
+
461
+ this.fire('hide');
462
+ }
463
+
464
+ return this;
465
+ },
466
+
467
+ /**
468
+ * Shows the element as a popup
469
+ *
470
+ * @param Element where to show the popup
471
+ * @return Colorpicker this
472
+ */
473
+ show: function(target) {
474
+ // moving into the target position
475
+ if (target) {
476
+ var element = $(target).dimensions(), style = this.element.style;
477
+
478
+ if (element) {
479
+ style.left = element.left + 'px';
480
+ style.top = element.top + element.height + 'px';
481
+
482
+ this.target = $(target);
483
+ }
484
+ }
485
+
486
+ // hide the others
487
+ if (Colorpicker.current && Colorpicker.current !== this) {
488
+ Colorpicker.current.element.hide();
489
+ }
490
+
491
+ this.element.insertTo(document.body);
492
+
493
+ if (!this.element.visible()) {
494
+ this.element.show(this.options.fxName, {
495
+ duration: this.options.fxDuration
496
+ });
497
+
498
+ this.fire('show');
499
+ }
500
+
501
+ if (this.target) {
502
+ this.setValue(this.target.value);
503
+ }
504
+
505
+ return Colorpicker.current = this;
506
+ },
507
+
508
+ /**
509
+ * Toggles the visibility status
510
+ *
511
+ * @param Element target
512
+ * @return Colorpicker this
513
+ */
514
+ toggle: function(target) {
515
+ return this[this.element.visible() ? 'hide' : 'show'](target);
516
+ },
517
+
518
+ /**
519
+ * Assigns the colorpicer to work in pair with an input of a content element
520
+ *
521
+ * @param Element reference
522
+ * @param Element optional trigger element
523
+ * @return Colorpicker this
524
+ */
525
+ assignTo: function(input, trigger) {
526
+ var input = $(input), trigger = $(trigger);
527
+
528
+ if (trigger) {
529
+ trigger.onClick(function(e) {
530
+ e.stop();
531
+ this.toggle(input.focus());
532
+ }.bind(this));
533
+ } else {
534
+ input.onFocus(this.show.bind(this, input));
535
+ }
536
+
537
+ input.on({
538
+ blur: function() {
539
+ this.timer = (function() {
540
+ this.hide();
541
+ }).bind(this).delay(100);
542
+ }.bind(this),
543
+
544
+ keyUp: function() {
545
+ this.setValue(input.value);
546
+ }.bind(this)
547
+ });
548
+
549
+ this.element.hide();
550
+
551
+ return this;
552
+ },
553
+
554
+ /**
555
+ * Assigns the colorpicer to automatically update
556
+ * given element's background on changes
557
+ *
558
+ * @param mixed element reference
559
+ * @return Colorpicker this
560
+ */
561
+ updateBg: function(element_ref) {
562
+ var element = $(element_ref);
563
+ if (element) {
564
+ this.onChange(function(color) {
565
+ element.style.backgroundColor = this.toRgb();
566
+ }.bind(this));
567
+ }
568
+ return this;
569
+ },
570
+
571
+ // protected
572
+
573
+ cancelTimer: function() {
574
+ (function() { // IE has a lack of sync in here
575
+ if (this.timer) {
576
+ this.timer.cancel();
577
+ this.timer = null;
578
+ }
579
+ }).bind(this).delay(10);
580
+ }
581
+ });
582
+
583
+ /**
584
+ * The document level hooks for colorpicker
585
+ *
586
+ * Copyright (C) 2010 Nikolay Nemshilov
587
+ */
588
+ document.on({
589
+ mouseup: function() {
590
+ if (Colorpicker.tracking) {
591
+ Colorpicker.tracking.stopTrack();
592
+ }
593
+ },
594
+
595
+ mousemove: function(event) {
596
+ if (Colorpicker.tracking) {
597
+ Colorpicker.tracking.trackMove(event);
598
+ }
599
+ },
600
+
601
+ mousedown: function(event) {
602
+ var picker = Colorpicker.current, target = event.target;
603
+
604
+ if (picker && target != picker.target && ![target].concat(target.parents()).include(picker.element)) {
605
+ picker.hide();
606
+ }
607
+ }
608
+ });
609
+
610
+ window.on('blur', function() {
611
+ if (Colorpicker.tracking) {
612
+ Colorpicker.tracking.stopTrack();
613
+ }
614
+ });
615
+
616
+ // colorpickers autodiscovery feature
617
+ Colorpicker.Options.cssRule.on({
618
+ focus: function(event) {
619
+ if (this.tagName == 'INPUT') {
620
+ Colorpicker.find(this).show(this);
621
+ }
622
+ },
623
+
624
+ click: function(event) {
625
+ var attr = Colorpicker.Options.cssRule.split('[').last().split('^=').first(),
626
+ match = /\[(.+?)\]/.exec(this.get(attr)), input;
627
+
628
+ if (match && (input = $(match[1]))) {
629
+ event.stop();
630
+
631
+ Colorpicker.find(this).show(input);
632
+ }
633
+ }
634
+ });
635
+ document.write("<style type=\"text/css\">div.right-colorpicker,div.right-colorpicker*{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.right-colorpicker{position:absolute;padding:.6em;background:#EEE;border:1px solid #CCC;-moz-border-radius:.2em;-webkit-border-radius:.2em;-moz-box-shadow:#AAA .3em .3em .4em;-webkit-box-shadow:#AAA .3em .3em .4em;z-index:9999}div.right-colorpicker div.field,div.right-colorpicker div.field-pointer,div.right-colorpicker div.colors,div.right-colorpicker div.colors-pointer{background:url(/images/rightjs-ui/colorpicker.png) no-repeat 0 0}div.right-colorpicker div.field,div.right-colorpicker div.colors,div.right-colorpicker div.controls{display:inline-block;*display:inline;*zoom:1;position:relative;vertical-align:top;height:150px}div.right-colorpicker div.field-pointer,div.right-colorpicker div.colors-pointer{position:absolute;top:0px;left:0;width:9px;height:9px}div.right-colorpicker input.display,div.right-colorpicker div.preview,div.right-colorpicker div.rgb-display,div.right-colorpicker input.right-ui-button{font-size:100%;display:block;width:auto;padding:0 .2em}div.right-colorpicker input.display,div.right-colorpicker div.preview,div.right-colorpicker div.rgb-display input,div.right-colorpicker input.right-ui-button{border:1px solid #AAA;-moz-border-radius:.2em;-webkit-border-radius:.2em}div.right-colorpicker div.field{width:150px;background-color:red;cursor:crosshair;margin-right:1.2em}div.right-colorpicker div.field-pointer{background-position:-170px 0;margin-left:-2px;margin-top:-2px}div.right-colorpicker div.colors{width:16px;background-position:-150px 0;border-color:#EEE;cursor:pointer;margin-right:.6em}div.right-colorpicker div.colors-pointer{cursor:default;background-position:-170px -20px;margin-left:-8px;margin-top:-3px}div.right-colorpicker div.controls{width:5em}div.right-colorpicker div.preview{height:2em;background:white;border-color:#BBB}div.right-colorpicker input.display{margin-top:.5em;background:#FFF;width:4.5em}div.right-colorpicker div.rgb-display{padding:0;text-align:right;margin-top:.5em}div.right-colorpicker div.rgb-display label{display:inline}div.right-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.right-colorpicker input.right-ui-button{cursor:pointer;position:absolute;bottom:0;width:5em;background:#CCC}div.right-colorpicker-inline{display:inline-block;*display:inline;*zoom:1;position:relative;-moz-box-shadow:none;-webkit-box-shadow:none;z-index:auto}</style>");