right-rails 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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>");