5
* @license MIT-style license
6
* @author Djamil Legato (w00fz) - < w00fzIT [at] gmail.com >
7
* @infos http://moorainbow.woolly-sheep.net
10
* includes a fix for mootools 1.2 by Piotr Przybylski
13
var MooRainbow = new Class({
14
Implements: [Options, Events],
19
startColor: [255, 0, 0],
21
onComplete: Class.empty,
22
onChange: Class.empty,
26
initialize: function(el, options) {
27
this.element = $(el); if (!this.element) return;
28
this.setOptions(options);
31
this.pickerPos = {x: 0, y: 0};
32
this.backupColor = this.options.startColor;
33
this.currentColor = this.options.startColor;
39
this.pickerClick = this.sliderClick = false;
40
if (!this.layout) this.doLayout();
44
if (this.options.wheel) this.wheelEvents();
45
this.element.addEvent('click', function(e) { this.toggle(e); }.bind(this));
47
this.layout.overlay.setStyle('background-color', this.options.startColor.rgbToHex());
48
this.layout.backup.setStyle('background-color', this.backupColor.rgbToHex());
50
this.pickerPos.x = this.snippet('curPos').l + this.snippet('curSize', 'int').w;
51
this.pickerPos.y = this.snippet('curPos').t + this.snippet('curSize', 'int').h;
53
this.manualSet(this.options.startColor);
55
this.pickerPos.x = this.snippet('curPos').l + this.snippet('curSize', 'int').w;
56
this.pickerPos.y = this.snippet('curPos').t + this.snippet('curSize', 'int').h;
57
this.sliderPos = this.snippet('arrPos') - this.snippet('arrSize', 'int');
59
if (Browser.Engine.webkit) this.hide();
63
this[this.visible ? 'hide' : 'show']()
68
this.layout.setStyle('display', 'block');
73
this.layout.setStyles({'display': 'none'});
77
manualSet: function(color, type) {
78
if (!type || (type != 'hsb' && type != 'hex')) type = 'rgb';
81
if (type == 'rgb') { rgb = color; hsb = color.rgbToHsb(); hex = color.rgbToHex(); }
82
else if (type == 'hsb') { hsb = color; rgb = color.hsbToRgb(); hex = rgb.rgbToHex(); }
83
else { hex = color; rgb = color.hexToRgb(true); hsb = rgb.rgbToHsb(); }
85
this.setMooRainbow(rgb);
89
autoSet: function(hsb) {
90
var curH = this.snippet('curSize', 'int').h;
91
var curW = this.snippet('curSize', 'int').w;
92
var oveH = this.layout.overlay.height;
93
var oveW = this.layout.overlay.width;
94
var sliH = this.layout.slider.height;
95
var arwH = this.snippet('arrSize', 'int');
98
var posx = Math.round(((oveW * hsb[1]) / 100) - curW);
99
var posy = Math.round(- ((oveH * hsb[2]) / 100) + oveH - curH);
101
var c = Math.round(((sliH * hsb[0]) / 360)); c = (c == 360) ? 0 : c;
102
var position = sliH - c + this.snippet('slider') - arwH;
103
hue = [this.sets.hsb[0], 100, 100].hsbToRgb().rgbToHex();
105
this.layout.cursor.setStyles({'top': posy, 'left': posx});
106
this.layout.arrows.setStyle('top', position);
107
this.layout.overlay.setStyle('background-color', hue);
108
this.sliderPos = this.snippet('arrPos') - arwH;
109
this.pickerPos.x = this.snippet('curPos').l + curW;
110
this.pickerPos.y = this.snippet('curPos').t + curH;
113
setMooRainbow: function(color, type) {
114
if (!type || (type != 'hsb' && type != 'hex')) type = 'rgb';
117
if (type == 'rgb') { rgb = color; hsb = color.rgbToHsb(); hex = color.rgbToHex(); }
118
else if (type == 'hsb') { hsb = color; rgb = color.hsbToRgb(); hex = rgb.rgbToHex(); }
119
else { hex = color; rgb = color.hexToRgb(); hsb = rgb.rgbToHsb(); }
127
if (!$chk(this.pickerPos.x))
130
this.RedInput.value = rgb[0];
131
this.GreenInput.value = rgb[1];
132
this.BlueInput.value = rgb[2];
133
this.HueInput.value = hsb[0];
134
this.SatuInput.value = hsb[1];
135
this.BrighInput.value = hsb[2];
136
this.hexInput.value = hex;
138
this.currentColor = rgb;
140
this.chooseColor.setStyle('background-color', rgb.rgbToHex());
143
parseColors: function(x, y, z) {
144
var s = Math.round((x * 100) / this.layout.overlay.width);
145
var b = 100 - Math.round((y * 100) / this.layout.overlay.height);
146
var h = 360 - Math.round((z * 360) / this.layout.slider.height) + this.snippet('slider') - this.snippet('arrSize', 'int');
147
h -= this.snippet('arrSize', 'int');
148
h = (h >= 360) ? 0 : (h < 0) ? 0 : h;
149
s = (s > 100) ? 100 : (s < 0) ? 0 : s;
150
b = (b > 100) ? 100 : (b < 0) ? 0 : b;
155
OverlayEvents: function() {
156
var lim, curH, curW, inputs;
157
curH = this.snippet('curSize', 'int').h;
158
curW = this.snippet('curSize', 'int').w;
159
inputs = $A(this.arrRGB).concat(this.arrHSB, this.hexInput);
161
document.addEvent('click', function() {
162
if(this.visible) this.hide(this.layout);
165
inputs.each(function(el) {
167
el.addEvent('keydown', this.eventKeydown.bindWithEvent(this, el));
168
el.addEvent('keyup', this.eventKeyup.bindWithEvent(this, el));
171
[this.element, this.layout].each(function(el) {
173
'click': function(e) { new Event(e).stop();},
174
'keyup': function(e) {
176
if(e.key == 'esc' && this.visible) this.hide(this.layout);
182
x: [0 - curW, (this.layout.overlay.width - curW)],
183
y: [0 - curH, (this.layout.overlay.height - curH)]
186
this.layout.drag = new Drag(this.layout.cursor, {
188
onStart: this.overlayDrag.bind(this),
189
onDrag: this.overlayDrag.bind(this),
193
this.layout.overlay2.addEvent('mousedown', function(e){
195
this.layout.cursor.setStyles({
196
'top': e.page.y - this.layout.overlay.getPosition().y - curH,
197
'left': e.page.x - this.layout.overlay.getPosition().x - curW
200
this.layout.drag.start(e);
203
this.okButton.addEvent('click', function() {
204
if(this.currentColor == this.options.startColor) {
206
this.fireEvent('onComplete', [this.sets, this]);
209
this.backupColor = this.currentColor;
210
this.layout.backup.setStyle('background-color', this.backupColor.rgbToHex());
212
this.fireEvent('onComplete', [this.sets, this]);
217
overlayDrag: function() {
218
var curH = this.snippet('curSize', 'int').h;
219
var curW = this.snippet('curSize', 'int').w;
220
this.pickerPos.x = this.snippet('curPos').l + curW;
221
this.pickerPos.y = this.snippet('curPos').t + curH;
223
this.setMooRainbow(this.parseColors(this.pickerPos.x, this.pickerPos.y, this.sliderPos), 'hsb');
224
this.fireEvent('onChange', [this.sets, this]);
227
sliderEvents: function() {
228
var arwH = this.snippet('arrSize', 'int'), lim;
230
lim = [0 + this.snippet('slider') - arwH, this.layout.slider.height - arwH + this.snippet('slider')];
231
this.layout.sliderDrag = new Drag(this.layout.arrows, {
233
modifiers: {x: false},
234
onStart: this.sliderDrag.bind(this),
235
onDrag: this.sliderDrag.bind(this),
239
this.layout.slider.addEvent('mousedown', function(e){
242
this.layout.arrows.setStyle(
243
'top', e.page.y - this.layout.slider.getPosition().y + this.snippet('slider') - arwH
246
this.layout.sliderDrag.start(e);
250
sliderDrag: function() {
251
var arwH = this.snippet('arrSize', 'int'), hue;
253
this.sliderPos = this.snippet('arrPos') - arwH;
254
this.setMooRainbow(this.parseColors(this.pickerPos.x, this.pickerPos.y, this.sliderPos), 'hsb');
255
hue = [this.sets.hsb[0], 100, 100].hsbToRgb().rgbToHex();
256
this.layout.overlay.setStyle('background-color', hue);
257
this.fireEvent('onChange', [this.sets, this]);
260
backupEvent: function() {
261
this.layout.backup.addEvent('click', function() {
262
this.manualSet(this.backupColor);
263
this.fireEvent('onChange', [this.sets, this]);
267
wheelEvents: function() {
268
var arrColors = $A(this.arrRGB).extend(this.arrHSB);
270
arrColors.each(function(el) {
272
'mousewheel': this.eventKeys.bindWithEvent(this, el),
273
'keydown': this.eventKeys.bindWithEvent(this, el)
277
[this.layout.arrows, this.layout.slider].each(function(el) {
279
'mousewheel': this.eventKeys.bindWithEvent(this, [this.arrHSB[0], 'slider']),
280
'keydown': this.eventKeys.bindWithEvent(this, [this.arrHSB[0], 'slider'])
285
eventKeys: function(e, el, id) {
287
id = (!id) ? el.id : this.arrHSB[0];
289
if (e.type == 'keydown') {
290
if (e.key == 'up') wheel = 1;
291
else if (e.key == 'down') wheel = -1;
293
} else if (e.type == Element.Events.mousewheel.base) wheel = (e.wheel > 0) ? 1 : -1;
295
if (this.arrRGB.contains(el)) type = 'rgb';
296
else if (this.arrHSB.contains(el)) type = 'hsb';
300
var rgb = this.sets.rgb, hsb = this.sets.hsb, prefix = this.options.prefix, pass;
301
var value = (el.value.toInt() || 0) + wheel;
302
value = (value > 255) ? 255 : (value < 0) ? 0 : value;
304
switch(el.className) {
305
case prefix + 'rInput': pass = [value, rgb[1], rgb[2]]; break;
306
case prefix + 'gInput': pass = [rgb[0], value, rgb[2]]; break;
307
case prefix + 'bInput': pass = [rgb[0], rgb[1], value]; break;
308
default : pass = rgb;
310
this.manualSet(pass);
311
this.fireEvent('onChange', [this.sets, this]);
313
var rgb = this.sets.rgb, hsb = this.sets.hsb, prefix = this.options.prefix, pass;
314
var value = (el.value.toInt() || 0) + wheel;
316
if (el.className.test(/(HueInput)/)) value = (value > 359) ? 0 : (value < 0) ? 0 : value;
317
else value = (value > 100) ? 100 : (value < 0) ? 0 : value;
319
switch(el.className) {
320
case prefix + 'HueInput': pass = [value, hsb[1], hsb[2]]; break;
321
case prefix + 'SatuInput': pass = [hsb[0], value, hsb[2]]; break;
322
case prefix + 'BrighInput': pass = [hsb[0], hsb[1], value]; break;
323
default : pass = hsb;
326
this.manualSet(pass, 'hsb');
327
this.fireEvent('onChange', [this.sets, this]);
332
eventKeydown: function(e, el) {
333
var n = e.code, k = e.key;
335
if ((!el.className.test(/hexInput/) && !(n >= 48 && n <= 57)) &&
336
(k!='backspace' && k!='tab' && k !='delete' && k!='left' && k!='right'))
340
eventKeyup: function(e, el) {
341
var n = e.code, k = e.key, pass, prefix, chr = el.value.charAt(0);
343
if (!$chk(el.value)) return;
344
if (el.className.test(/hexInput/)) {
345
if (chr != "#" && el.value.length != 6) return;
346
if (chr == '#' && el.value.length != 7) return;
348
if (!(n >= 48 && n <= 57) && (!['backspace', 'tab', 'delete', 'left', 'right'].contains(k)) && el.value.length > 3) return;
351
prefix = this.options.prefix;
353
if (el.className.test(/(rInput|gInput|bInput)/)) {
354
if (el.value < 0 || el.value > 255) return;
355
switch(el.className){
356
case prefix + 'rInput': pass = [el.value, this.sets.rgb[1], this.sets.rgb[2]]; break;
357
case prefix + 'gInput': pass = [this.sets.rgb[0], el.value, this.sets.rgb[2]]; break;
358
case prefix + 'bInput': pass = [this.sets.rgb[0], this.sets.rgb[1], el.value]; break;
359
default : pass = this.sets.rgb;
361
this.manualSet(pass);
362
this.fireEvent('onChange', [this.sets, this]);
364
else if (!el.className.test(/hexInput/)) {
365
if (el.className.test(/HueInput/) && el.value < 0 || el.value > 360) return;
366
else if (el.className.test(/HueInput/) && el.value == 360) el.value = 0;
367
else if (el.className.test(/(SatuInput|BrighInput)/) && el.value < 0 || el.value > 100) return;
368
switch(el.className){
369
case prefix + 'HueInput': pass = [el.value, this.sets.hsb[1], this.sets.hsb[2]]; break;
370
case prefix + 'SatuInput': pass = [this.sets.hsb[0], el.value, this.sets.hsb[2]]; break;
371
case prefix + 'BrighInput': pass = [this.sets.hsb[0], this.sets.hsb[1], el.value]; break;
372
default : pass = this.sets.hsb;
374
this.manualSet(pass, 'hsb');
375
this.fireEvent('onChange', [this.sets, this]);
377
pass = el.value.hexToRgb(true);
378
if (isNaN(pass[0])||isNaN(pass[1])||isNaN(pass[2])) return;
381
this.manualSet(pass);
382
this.fireEvent('onChange', [this.sets, this]);
388
doLayout: function() {
389
var id = this.options.id, prefix = this.options.prefix;
390
var idPrefix = id + ' .' + prefix;
392
this.layout = new Element('div', {
393
'styles': {'display': 'block', 'position': 'absolute'},
395
}).inject(document.body);
397
var box = new Element('div', {
398
'styles': {'position': 'relative'},
399
'class': prefix + 'box'
400
}).inject(this.layout);
402
var div = new Element('div', {
403
'styles': {'position': 'absolute', 'overflow': 'hidden'},
404
'class': prefix + 'overlayBox'
407
var ar = new Element('div', {
408
'styles': {'position': 'absolute', 'zIndex': 1},
409
'class': prefix + 'arrows'
411
ar.width = ar.getStyle('width').toInt();
412
ar.height = ar.getStyle('height').toInt();
414
var ov = new Element('img', {
415
'styles': {'background-color': '#fff', 'position': 'relative', 'zIndex': 2},
416
'src': this.options.imgPath + 'moor_woverlay.png',
417
'class': prefix + 'overlay'
420
var ov2 = new Element('img', {
421
'styles': {'position': 'absolute', 'top': 0, 'left': 0, 'zIndex': 2},
422
'src': this.options.imgPath + 'moor_boverlay.png',
423
'class': prefix + 'overlay'
426
if (Browser.Engine.trident4) {
427
div.setStyle('overflow', '');
429
ov.src = this.options.imgPath + 'blank.gif';
430
ov.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizingMethod='scale')";
432
ov2.src = this.options.imgPath + 'blank.gif';
433
ov2.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "', sizingMethod='scale')";
435
ov.width = ov2.width = div.getStyle('width').toInt();
436
ov.height = ov2.height = div.getStyle('height').toInt();
438
var cr = new Element('div', {
439
'styles': {'overflow': 'hidden', 'position': 'absolute', 'zIndex': 2},
440
'class': prefix + 'cursor'
442
cr.width = cr.getStyle('width').toInt();
443
cr.height = cr.getStyle('height').toInt();
445
var sl = new Element('img', {
446
'styles': {'position': 'absolute', 'z-index': 2},
447
'src': this.options.imgPath + 'moor_slider.png',
448
'class': prefix + 'slider'
450
this.layout.slider = sl;
451
sl.width = sl.getStyle('width').toInt();
452
sl.height = sl.getStyle('height').toInt();
455
'styles': {'position': 'absolute'},
456
'class': prefix + 'colorBox'
460
'styles': {'zIndex': 2, 'position': 'absolute'},
461
'class': prefix + 'chooseColor'
464
this.layout.backup = new Element('div', {
465
'styles': {'zIndex': 2, 'position': 'absolute', 'cursor': 'pointer'},
466
'class': prefix + 'currentColor'
469
var R = new Element('label').inject(box).setStyle('position', 'absolute');
470
var G = R.clone().inject(box).addClass(prefix + 'gLabel').set('html', 'G: ');
471
var B = R.clone().inject(box).addClass(prefix + 'bLabel').set('html', 'B: ');
472
R.set('html', 'R: ').addClass(prefix + 'rLabel');
474
var inputR = new Element('input');
475
var inputG = inputR.clone().inject(G).addClass(prefix + 'gInput');
476
var inputB = inputR.clone().inject(B).addClass(prefix + 'bInput');
477
inputR.inject(R).addClass(prefix + 'rInput');
479
var HU = new Element('label').inject(box).setStyle('position', 'absolute');
480
var SA = HU.clone().inject(box).addClass(prefix + 'SatuLabel').set('html', 'S: ');
481
var BR = HU.clone().inject(box).addClass(prefix + 'BrighLabel').set('html', 'B: ');
482
HU.set('html', 'H: ').addClass(prefix + 'HueLabel');
484
var inputHU = new Element('input');
485
var inputSA = inputHU.clone().inject(SA).addClass(prefix + 'SatuInput');
486
var inputBR = inputHU.clone().inject(BR).addClass(prefix + 'BrighInput');
487
inputHU.inject(HU).addClass(prefix + 'HueInput');
488
SA.innerHTML += " %"; BR.innerHTML += " %";
489
SP = new Element('span', {'styles': {'position': 'absolute'}, 'class': prefix + 'ballino'})
490
SP.innerHTML = " °"
491
SP.inject(HU,'after');
493
var hex = new Element('label').inject(box).setStyle('position', 'absolute').addClass(prefix + 'hexLabel').set('html', '#hex: ').adopt(new Element('input').addClass(prefix + 'hexInput'));
495
var ok = new Element('input', {
496
'styles': {'position': 'absolute'},
498
'value': this.options.selectText,
499
'class': prefix + 'okButton'
504
var overlays = $$('#' + id + ' .' + prefix + 'overlay');
505
this.layout.overlay = overlays[0];
506
this.layout.overlay2 = overlays[1];
507
this.layout.cursor = cr;
508
this.layout.arrows = ar;
509
this.chooseColor = this.layout.getElement('.' + prefix + 'chooseColor');
510
this.RedInput = inputR;
511
this.GreenInput = inputG;
512
this.BlueInput = inputB;
513
this.HueInput = inputHU;
514
this.SatuInput = this.layout.getElement('.' + prefix + 'SatuInput');
515
this.BrighInput = this.layout.getElement('.' + prefix + 'BrighInput');
516
this.hexInput = this.layout.getElement('.' + prefix + 'hexInput');;
518
this.arrRGB = [this.RedInput, this.GreenInput, this.BlueInput];
519
this.arrHSB = [this.HueInput, this.SatuInput, this.BrighInput];
522
if (!Browser.Engine.webkit419) this.hide();
524
rePosition: function() {
525
var coords = this.element.getCoordinates();
526
this.layout.setStyles({
528
'top': coords.top + coords.height + 1
532
snippet: function(mode, type) {
533
var size; type = (type) ? type : 'none';
537
var t = this.layout.arrows.getStyle('top').toInt();
541
var h = this.layout.arrows.height;
542
h = (type == 'int') ? (h/2).toInt() : h;
546
var l = this.layout.cursor.getStyle('left').toInt();
547
var t = this.layout.cursor.getStyle('top').toInt();
548
size = {'l': l, 't': t};
551
var t = this.layout.slider.getStyle('marginTop').toInt();
555
var h = this.layout.cursor.height;
556
var w = this.layout.cursor.width;
557
h = (type == 'int') ? (h/2).toInt() : h;
558
w = (type == 'int') ? (w/2).toInt() : w;