PageRenderTime 41ms CodeModel.GetById 1ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 1ms

/colorpicker.js

http://java-templates.googlecode.com/
JavaScript | 484 lines | 475 code | 1 blank | 8 comment | 108 complexity | 96e6db8dd2c341f8aee73603eccea3b9 MD5 | raw file
  1/**
  2 *
  3 * Color picker
  4 * Author: Stefan Petre www.eyecon.ro
  5 * 
  6 * Dual licensed under the MIT and GPL licenses
  7 * 
  8 */
  9(function ($) {
 10	var ColorPicker = function () {
 11		var
 12			ids = {},
 13			inAction,
 14			charMin = 65,
 15			visible,
 16			tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',
 17			defaults = {
 18				eventName: 'click',
 19				onShow: function () {},
 20				onBeforeShow: function(){},
 21				onHide: function () {},
 22				onChange: function () {},
 23				onSubmit: function () {},
 24				color: 'ff0000',
 25				livePreview: true,
 26				flat: false
 27			},
 28			fillRGBFields = function  (hsb, cal) {
 29				var rgb = HSBToRGB(hsb);
 30				$(cal).data('colorpicker').fields
 31					.eq(1).val(rgb.r).end()
 32					.eq(2).val(rgb.g).end()
 33					.eq(3).val(rgb.b).end();
 34			},
 35			fillHSBFields = function  (hsb, cal) {
 36				$(cal).data('colorpicker').fields
 37					.eq(4).val(hsb.h).end()
 38					.eq(5).val(hsb.s).end()
 39					.eq(6).val(hsb.b).end();
 40			},
 41			fillHexFields = function (hsb, cal) {
 42				$(cal).data('colorpicker').fields
 43					.eq(0).val(HSBToHex(hsb)).end();
 44			},
 45			setSelector = function (hsb, cal) {
 46				$(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({h: hsb.h, s: 100, b: 100}));
 47				$(cal).data('colorpicker').selectorIndic.css({
 48					left: parseInt(150 * hsb.s/100, 10),
 49					top: parseInt(150 * (100-hsb.b)/100, 10)
 50				});
 51			},
 52			setHue = function (hsb, cal) {
 53				$(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h/360, 10));
 54			},
 55			setCurrentColor = function (hsb, cal) {
 56				$(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
 57			},
 58			setNewColor = function (hsb, cal) {
 59				$(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
 60			},
 61			keyDown = function (ev) {
 62				var pressedKey = ev.charCode || ev.keyCode || -1;
 63				if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
 64					return false;
 65				}
 66				var cal = $(this).parent().parent();
 67				if (cal.data('colorpicker').livePreview === true) {
 68					change.apply(this);
 69				}
 70			},
 71			change = function (ev) {
 72				var cal = $(this).parent().parent(), col;
 73				if (this.parentNode.className.indexOf('_hex') > 0) {
 74					cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
 75				} else if (this.parentNode.className.indexOf('_hsb') > 0) {
 76					cal.data('colorpicker').color = col = fixHSB({
 77						h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
 78						s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
 79						b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
 80					});
 81				} else {
 82					cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
 83						r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
 84						g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
 85						b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
 86					}));
 87				}
 88				if (ev) {
 89					fillRGBFields(col, cal.get(0));
 90					fillHexFields(col, cal.get(0));
 91					fillHSBFields(col, cal.get(0));
 92				}
 93				setSelector(col, cal.get(0));
 94				setHue(col, cal.get(0));
 95				setNewColor(col, cal.get(0));
 96				cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);
 97			},
 98			blur = function (ev) {
 99				var cal = $(this).parent().parent();
100				cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
101			},
102			focus = function () {
103				charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
104				$(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
105				$(this).parent().addClass('colorpicker_focus');
106			},
107			downIncrement = function (ev) {
108				var field = $(this).parent().find('input').focus();
109				var current = {
110					el: $(this).parent().addClass('colorpicker_slider'),
111					max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
112					y: ev.pageY,
113					field: field,
114					val: parseInt(field.val(), 10),
115					preview: $(this).parent().parent().data('colorpicker').livePreview					
116				};
117				$(document).bind('mouseup', current, upIncrement);
118				$(document).bind('mousemove', current, moveIncrement);
119			},
120			moveIncrement = function (ev) {
121				ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
122				if (ev.data.preview) {
123					change.apply(ev.data.field.get(0), [true]);
124				}
125				return false;
126			},
127			upIncrement = function (ev) {
128				change.apply(ev.data.field.get(0), [true]);
129				ev.data.el.removeClass('colorpicker_slider').find('input').focus();
130				$(document).unbind('mouseup', upIncrement);
131				$(document).unbind('mousemove', moveIncrement);
132				return false;
133			},
134			downHue = function (ev) {
135				var current = {
136					cal: $(this).parent(),
137					y: $(this).offset().top
138				};
139				current.preview = current.cal.data('colorpicker').livePreview;
140				$(document).bind('mouseup', current, upHue);
141				$(document).bind('mousemove', current, moveHue);
142			},
143			moveHue = function (ev) {
144				change.apply(
145					ev.data.cal.data('colorpicker')
146						.fields
147						.eq(4)
148						.val(parseInt(360*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.y))))/150, 10))
149						.get(0),
150					[ev.data.preview]
151				);
152				return false;
153			},
154			upHue = function (ev) {
155				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
156				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
157				$(document).unbind('mouseup', upHue);
158				$(document).unbind('mousemove', moveHue);
159				return false;
160			},
161			downSelector = function (ev) {
162				var current = {
163					cal: $(this).parent(),
164					pos: $(this).offset()
165				};
166				current.preview = current.cal.data('colorpicker').livePreview;
167				$(document).bind('mouseup', current, upSelector);
168				$(document).bind('mousemove', current, moveSelector);
169			},
170			moveSelector = function (ev) {
171				change.apply(
172					ev.data.cal.data('colorpicker')
173						.fields
174						.eq(6)
175						.val(parseInt(100*(150 - Math.max(0,Math.min(150,(ev.pageY - ev.data.pos.top))))/150, 10))
176						.end()
177						.eq(5)
178						.val(parseInt(100*(Math.max(0,Math.min(150,(ev.pageX - ev.data.pos.left))))/150, 10))
179						.get(0),
180					[ev.data.preview]
181				);
182				return false;
183			},
184			upSelector = function (ev) {
185				fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
186				fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
187				$(document).unbind('mouseup', upSelector);
188				$(document).unbind('mousemove', moveSelector);
189				return false;
190			},
191			enterSubmit = function (ev) {
192				$(this).addClass('colorpicker_focus');
193			},
194			leaveSubmit = function (ev) {
195				$(this).removeClass('colorpicker_focus');
196			},
197			clickSubmit = function (ev) {
198				var cal = $(this).parent();
199				var col = cal.data('colorpicker').color;
200				cal.data('colorpicker').origColor = col;
201				setCurrentColor(col, cal.get(0));
202				cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
203			},
204			show = function (ev) {
205				var cal = $('#' + $(this).data('colorpickerId'));
206				cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
207				var pos = $(this).offset();
208				var viewPort = getViewport();
209				var top = pos.top + this.offsetHeight;
210				var left = pos.left;
211				if (top + 176 > viewPort.t + viewPort.h) {
212					top -= this.offsetHeight + 176;
213				}
214				if (left + 356 > viewPort.l + viewPort.w) {
215					left -= 356;
216				}
217				cal.css({left: left + 'px', top: top + 'px'});
218				if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
219					cal.show();
220				}
221				$(document).bind('mousedown', {cal: cal}, hide);
222				return false;
223			},
224			hide = function (ev) {
225				if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
226					if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
227						ev.data.cal.hide();
228					}
229					$(document).unbind('mousedown', hide);
230				}
231			},
232			isChildOf = function(parentEl, el, container) {
233				if (parentEl == el) {
234					return true;
235				}
236				if (parentEl.contains) {
237					return parentEl.contains(el);
238				}
239				if ( parentEl.compareDocumentPosition ) {
240					return !!(parentEl.compareDocumentPosition(el) & 16);
241				}
242				var prEl = el.parentNode;
243				while(prEl && prEl != container) {
244					if (prEl == parentEl)
245						return true;
246					prEl = prEl.parentNode;
247				}
248				return false;
249			},
250			getViewport = function () {
251				var m = document.compatMode == 'CSS1Compat';
252				return {
253					l : window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
254					t : window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
255					w : window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
256					h : window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
257				};
258			},
259			fixHSB = function (hsb) {
260				return {
261					h: Math.min(360, Math.max(0, hsb.h)),
262					s: Math.min(100, Math.max(0, hsb.s)),
263					b: Math.min(100, Math.max(0, hsb.b))
264				};
265			}, 
266			fixRGB = function (rgb) {
267				return {
268					r: Math.min(255, Math.max(0, rgb.r)),
269					g: Math.min(255, Math.max(0, rgb.g)),
270					b: Math.min(255, Math.max(0, rgb.b))
271				};
272			},
273			fixHex = function (hex) {
274				var len = 6 - hex.length;
275				if (len > 0) {
276					var o = [];
277					for (var i=0; i<len; i++) {
278						o.push('0');
279					}
280					o.push(hex);
281					hex = o.join('');
282				}
283				return hex;
284			}, 
285			HexToRGB = function (hex) {
286				var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
287				return {r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF)};
288			},
289			HexToHSB = function (hex) {
290				return RGBToHSB(HexToRGB(hex));
291			},
292			RGBToHSB = function (rgb) {
293				var hsb = {
294					h: 0,
295					s: 0,
296					b: 0
297				};
298				var min = Math.min(rgb.r, rgb.g, rgb.b);
299				var max = Math.max(rgb.r, rgb.g, rgb.b);
300				var delta = max - min;
301				hsb.b = max;
302				if (max != 0) {
303					
304				}
305				hsb.s = max != 0 ? 255 * delta / max : 0;
306				if (hsb.s != 0) {
307					if (rgb.r == max) {
308						hsb.h = (rgb.g - rgb.b) / delta;
309					} else if (rgb.g == max) {
310						hsb.h = 2 + (rgb.b - rgb.r) / delta;
311					} else {
312						hsb.h = 4 + (rgb.r - rgb.g) / delta;
313					}
314				} else {
315					hsb.h = -1;
316				}
317				hsb.h *= 60;
318				if (hsb.h < 0) {
319					hsb.h += 360;
320				}
321				hsb.s *= 100/255;
322				hsb.b *= 100/255;
323				return hsb;
324			},
325			HSBToRGB = function (hsb) {
326				var rgb = {};
327				var h = Math.round(hsb.h);
328				var s = Math.round(hsb.s*255/100);
329				var v = Math.round(hsb.b*255/100);
330				if(s == 0) {
331					rgb.r = rgb.g = rgb.b = v;
332				} else {
333					var t1 = v;
334					var t2 = (255-s)*v/255;
335					var t3 = (t1-t2)*(h%60)/60;
336					if(h==360) h = 0;
337					if(h<60) {rgb.r=t1;	rgb.b=t2; rgb.g=t2+t3}
338					else if(h<120) {rgb.g=t1; rgb.b=t2;	rgb.r=t1-t3}
339					else if(h<180) {rgb.g=t1; rgb.r=t2;	rgb.b=t2+t3}
340					else if(h<240) {rgb.b=t1; rgb.r=t2;	rgb.g=t1-t3}
341					else if(h<300) {rgb.b=t1; rgb.g=t2;	rgb.r=t2+t3}
342					else if(h<360) {rgb.r=t1; rgb.g=t2;	rgb.b=t1-t3}
343					else {rgb.r=0; rgb.g=0;	rgb.b=0}
344				}
345				return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
346			},
347			RGBToHex = function (rgb) {
348				var hex = [
349					rgb.r.toString(16),
350					rgb.g.toString(16),
351					rgb.b.toString(16)
352				];
353				$.each(hex, function (nr, val) {
354					if (val.length == 1) {
355						hex[nr] = '0' + val;
356					}
357				});
358				return hex.join('');
359			},
360			HSBToHex = function (hsb) {
361				return RGBToHex(HSBToRGB(hsb));
362			},
363			restoreOriginal = function () {
364				var cal = $(this).parent();
365				var col = cal.data('colorpicker').origColor;
366				cal.data('colorpicker').color = col;
367				fillRGBFields(col, cal.get(0));
368				fillHexFields(col, cal.get(0));
369				fillHSBFields(col, cal.get(0));
370				setSelector(col, cal.get(0));
371				setHue(col, cal.get(0));
372				setNewColor(col, cal.get(0));
373			};
374		return {
375			init: function (opt) {
376				opt = $.extend({}, defaults, opt||{});
377				if (typeof opt.color == 'string') {
378					opt.color = HexToHSB(opt.color);
379				} else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
380					opt.color = RGBToHSB(opt.color);
381				} else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
382					opt.color = fixHSB(opt.color);
383				} else {
384					return this;
385				}
386				return this.each(function () {
387					if (!$(this).data('colorpickerId')) {
388						var options = $.extend({}, opt);
389						options.origColor = opt.color;
390						var id = 'collorpicker_' + parseInt(Math.random() * 1000);
391						$(this).data('colorpickerId', id);
392						var cal = $(tpl).attr('id', id);
393						if (options.flat) {
394							cal.appendTo(this).show();
395						} else {
396							cal.appendTo(document.body);
397						}
398						options.fields = cal
399											.find('input')
400												.bind('keyup', keyDown)
401												.bind('change', change)
402												.bind('blur', blur)
403												.bind('focus', focus);
404						cal
405							.find('span').bind('mousedown', downIncrement).end()
406							.find('>div.colorpicker_current_color').bind('click', restoreOriginal);
407						options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
408						options.selectorIndic = options.selector.find('div div');
409						options.el = this;
410						options.hue = cal.find('div.colorpicker_hue div');
411						cal.find('div.colorpicker_hue').bind('mousedown', downHue);
412						options.newColor = cal.find('div.colorpicker_new_color');
413						options.currentColor = cal.find('div.colorpicker_current_color');
414						cal.data('colorpicker', options);
415						cal.find('div.colorpicker_submit')
416							.bind('mouseenter', enterSubmit)
417							.bind('mouseleave', leaveSubmit)
418							.bind('click', clickSubmit);
419						fillRGBFields(options.color, cal.get(0));
420						fillHSBFields(options.color, cal.get(0));
421						fillHexFields(options.color, cal.get(0));
422						setHue(options.color, cal.get(0));
423						setSelector(options.color, cal.get(0));
424						setCurrentColor(options.color, cal.get(0));
425						setNewColor(options.color, cal.get(0));
426						if (options.flat) {
427							cal.css({
428								position: 'relative',
429								display: 'block'
430							});
431						} else {
432							$(this).bind(options.eventName, show);
433						}
434					}
435				});
436			},
437			showPicker: function() {
438				return this.each( function () {
439					if ($(this).data('colorpickerId')) {
440						show.apply(this);
441					}
442				});
443			},
444			hidePicker: function() {
445				return this.each( function () {
446					if ($(this).data('colorpickerId')) {
447						$('#' + $(this).data('colorpickerId')).hide();
448					}
449				});
450			},
451			setColor: function(col) {
452				if (typeof col == 'string') {
453					col = HexToHSB(col);
454				} else if (col.r != undefined && col.g != undefined && col.b != undefined) {
455					col = RGBToHSB(col);
456				} else if (col.h != undefined && col.s != undefined && col.b != undefined) {
457					col = fixHSB(col);
458				} else {
459					return this;
460				}
461				return this.each(function(){
462					if ($(this).data('colorpickerId')) {
463						var cal = $('#' + $(this).data('colorpickerId'));
464						cal.data('colorpicker').color = col;
465						cal.data('colorpicker').origColor = col;
466						fillRGBFields(col, cal.get(0));
467						fillHSBFields(col, cal.get(0));
468						fillHexFields(col, cal.get(0));
469						setHue(col, cal.get(0));
470						setSelector(col, cal.get(0));
471						setCurrentColor(col, cal.get(0));
472						setNewColor(col, cal.get(0));
473					}
474				});
475			}
476		};
477	}();
478	$.fn.extend({
479		ColorPicker: ColorPicker.init,
480		ColorPickerHide: ColorPicker.hidePicker,
481		ColorPickerShow: ColorPicker.showPicker,
482		ColorPickerSetColor: ColorPicker.setColor
483	});
484})(jQuery)