Completed
Push — master ( dce25d...9db7be )
by Dimas
09:29 queued 12s
created

etc/server/dummyimage/js/colorpicker.js   F

Complexity

Total Complexity 106
Complexity/F 2

Size

Lines of Code 476
Function Count 53

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 381
dl 0
loc 476
c 0
b 0
f 0
rs 2
wmc 106
mnd 53
bc 53
fnc 53
bpm 1
cpm 2
noi 6

How to fix   Complexity   

Complexity

Complex classes like etc/server/dummyimage/js/colorpicker.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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 = {},
0 ignored issues
show
Unused Code introduced by
The variable ids seems to be never used. Consider removing it.
Loading history...
13
			inAction,
0 ignored issues
show
Unused Code introduced by
The variable inAction seems to be never used. Consider removing it.
Loading history...
14
			charMin = 65,
15
			visible,
0 ignored issues
show
Unused Code introduced by
The variable visible seems to be never used. Consider removing it.
Loading history...
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) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if cal.data("colorpicker").livePreview === true is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
68
					change.apply(this);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
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) {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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)