PageSourceSearch

https://space-india.com/wp-content/themes/Kidko/assets/js/jscolor.js?ver=1790157281

js space-india.com collected 2026-09-24 10:19:17 UTC 58,236 bytes, 1,988 lines download raw bytes

1/**
2 * jscolor - JavaScript Color Picker
3 *
4 * @link    http://jscolor.com
5 * @license For open source use: GPLv3
6 *          For commercial use: JSColor Commercial License
7 * @author  Jan Odvarko
8 * @version 2.1.1
9 *
10 * See usage examples at http://jscolor.com/examples/
11 */
12
13
14"use strict";
15
16
17if (!window.jscolor) {
18
19window.jscolor = (function () { // BEGIN window.jscolor
20
21var jsc = {
22
23
24	register : function () {
25		jsc.attachDOMReadyEvent(jsc.jscolor.init);
26		jsc.attachEvent(document, 'mousedown', jsc.onDocumentMouseDown);
27		jsc.attachEvent(document, 'touchstart', jsc.onDocumentTouchStart);
28		jsc.attachEvent(document, 'keyup', jsc.onDocumentKeyUp);
29		jsc.attachEvent(window, 'resize', jsc.onWindowResize);
30	},
31
32
33	tryInstallOnElements : function (elms, className) {
34		var matchClass = new RegExp('(^|\\s)(' + className + ')(\\s*(\\{[^}]*\\})|\\s|$)', 'i');
35
36		for (var i = 0; i < elms.length; i += 1) {
37			if (elms[i].type !== undefined && elms[i].type.toLowerCase() == 'color') {
38				if (jsc.isColorAttrSupported) {
39					// skip inputs of type 'color' if supported by the browser
40					continue;
41				}
42			}
43
44			if (elms[i].jscolor) {
45				// jscolor is already installed on this element
46				continue;
47			}
48
49			var m, dataOpts;
50
51			if (
52				(dataOpts = jsc.getDataAttr(elms[i], 'jscolor')) !== null ||
53				(elms[i].className && (m = elms[i].className.match(matchClass)))
54			) {
55				var targetElm = elms[i];
56				var optsStr = null;
57
58				if (dataOpts !== null) {
59					optsStr = dataOpts;
60				} else if (m && m[4]) {
61					optsStr = m[4];
62				}
63
64				var opts = {};
65				if (optsStr) {
66					try {
67						opts = (new Function ('return (' + optsStr + ')'))();
68					} catch(eParseError) {
69						jsc.warn('Error parsing jscolor options: ' + eParseError + ':\n' + optsStr);
70					}
71				}
72				targetElm.jscolor = new jsc.jscolor(targetElm, opts);
73			}
74		}
75	},
76
77
78	isColorAttrSupported : (function () {
79		var elm = document.createElement('input');
80		if (elm.setAttribute) {
81			elm.setAttribute('type', 'color');
82			if (elm.type.toLowerCase() == 'color') {
83				return true;
84			}
85		}
86		return false;
87	})(),
88
89
90	isCanvasSupported : (function () {
91		var elm = document.createElement('canvas');
92		return !!(elm.getContext && elm.getContext('2d'));
93	})(),
94
95
96	fetchElement : function (mixed) {
97		return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
98	},
99
100
101	isElementType : function (elm, type) {
102		return elm.nodeName.toLowerCase() === type.toLowerCase();
103	},
104
105
106	getDataAttr : function (el, name) {
107		var attrName = 'data-' + name;
108		var attrValue = el.getAttribute(attrName);
109		if (attrValue !== null) {
110			return attrValue;
111		}
112		return null;
113	},
114
115
116	attachEvent : function (el, evnt, func) {
117		if (el.addEventListener) {
118			el.addEventListener(evnt, func, false);
119		} else if (el.attachEvent) {
120			el.attachEvent('on' + evnt, func);
121		}
122	},
123
124
125	detachEvent : function (el, evnt, func) {
126		if (el.removeEventListener) {
127			el.removeEventListener(evnt, func, false);
128		} else if (el.detachEvent) {
129			el.detachEvent('on' + evnt, func);
130		}
131	},
132
133
134	_attachedGroupEvents : {},
135
136
137	attachGroupEvent : function (groupName, el, evnt, func) {
138		if (!jsc._attachedGroupEvents.hasOwnProperty(groupName)) {
139			jsc._attachedGroupEvents[groupName] = [];
140		}
141		jsc._attachedGroupEvents[groupName].push([el, evnt, func]);
142		jsc.attachEvent(el, evnt, func);
143	},
144
145
146	detachGroupEvents : function (groupName) {
147		if (jsc._attachedGroupEvents.hasOwnProperty(groupName)) {
148			for (var i = 0; i < jsc._attachedGroupEvents[groupName].length; i += 1) {
149				var evt = jsc._attachedGroupEvents[groupName][i];
150				jsc.detachEvent(evt[0], evt[1], evt[2]);
151			}
152			delete jsc._attachedGroupEvents[groupName];
153		}
154	},
155
156
157	attachDOMReadyEvent : function (func) {
158		var fired = false;
159		var fireOnce = function () {
160			if (!fired) {
161				fired = true;
162				func();
163			}
164		};
165
166		if (document.readyState === 'complete') {
167			setTimeout(fireOnce, 1); // async
168			return;
169		}
170
171		if (document.addEventListener) {
172			document.addEventListener('DOMContentLoaded', fireOnce, false);
173
174			// Fallback
175			window.addEventListener('load', fireOnce, false);
176
177		} else if (document.attachEvent) {
178			// IE
179			document.attachEvent('onreadystatechange', function () {
180				if (document.readyState === 'complete') {
181					document.detachEvent('onreadystatechange', arguments.callee);
182					fireOnce();
183				}
184			})
185
186			// Fallback
187			window.attachEvent('onload', fireOnce);
188
189			// IE7/8
190			if (document.documentElement.doScroll && window == window.top) {
191				var tryScroll = function () {
192					if (!document.body) { return; }
193					try {
194						document.documentElement.doScroll('left');
195						fireOnce();
196					} catch (e) {
197						setTimeout(tryScroll, 1);
198					}
199				};
200				tryScroll();
201			}
202		}
203	},
204
205
206	warn : function (msg) {
207		if (window.console && window.console.warn) {
208			window.console.warn(msg);
209		}
210	},
211
212
213	preventDefault : function (e) {
214		if (e.preventDefault) { e.preventDefault(); }
215		e.returnValue = false;
216	},
217
218
219	captureTarget : function (target) {
220		// IE
221		if (target.setCapture) {
222			jsc._capturedTarget = target;
223			jsc._capturedTarget.setCapture();
224		}
225	},
226
227
228	releaseTarget : function () {
229		// IE
230		if (jsc._capturedTarget) {
231			jsc._capturedTarget.releaseCapture();
232			jsc._capturedTarget = null;
233		}
234	},
235
236
237	fireEvent : function (el, evnt) {
238		if (!el) {
239			return;
240		}
241		if (document.createEvent) {
242			var ev = document.createEvent('HTMLEvents');
243			ev.initEvent(evnt, true, true);
244			el.dispatchEvent(ev);
245		} else if (document.createEventObject) {
246			var ev = document.createEventObject();
247			el.fireEvent('on' + evnt, ev);
248		} else if (el['on' + evnt]) { // alternatively use the traditional event model
249			el['on' + evnt]();
250		}
251	},
252
253
254	classNameToList : function (className) {
255		return className.replace(/^\s+|\s+$/g, '').split(/\s+/);
256	},
257
258
259	// The className parameter (str) can only contain a single class name
260	hasClass : function (elm, className) {
261		if (!className) {
262			return false;
263		}
264		return -1 != (' ' + elm.className.replace(/\s+/g, ' ') + ' ').indexOf(' ' + className + ' ');
265	},
266
267
268	// The className parameter (str) can contain multiple class names separated by whitespace
269	setClass : function (elm, className) {
270		var classList = jsc.classNameToList(className);
271		for (var i = 0; i < classList.length; i += 1) {
272			if (!jsc.hasClass(elm, classList[i])) {
273				elm.className += (elm.className ? ' ' : '') + classList[i];
274			}
275		}
276	},
277
278
279	// The className parameter (str) can contain multiple class names separated by whitespace
280	unsetClass : function (elm, className) {
281		var classList = jsc.classNameToList(className);
282		for (var i = 0; i < classList.length; i += 1) {
283			var repl = new RegExp(
284				'^\\s*' + classList[i] + '\\s*|' +
285				'\\s*' + classList[i] + '\\s*$|' +
286				'\\s+' + classList[i] + '(\\s+)',
287				'g'
288			);
289			elm.className = elm.className.replace(repl, '$1');
290		}
291	},
292
293
294	getStyle : function (elm) {
295		return window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle;
296	},
297
298
299	setStyle : (function () {
300		var helper = document.createElement('div');
301		var getSupportedProp = function (names) {
302			for (var i = 0; i < names.length; i += 1) {
303				if (names[i] in helper.style) {
304					return names[i];
305				}
306			}
307		};
308		var props = {
309			borderRadius: getSupportedProp(['borderRadius', 'MozBorderRadius', 'webkitBorderRadius']),
310			boxShadow: getSupportedProp(['boxShadow', 'MozBoxShadow', 'webkitBoxShadow'])
311		};
312		return function (elm, prop, value) {
313			switch (prop.toLowerCase()) {
314			case 'opacity':
315				var alphaOpacity = Math.round(parseFloat(value) * 100);
316				elm.style.opacity = value;
317				elm.style.filter = 'alpha(opacity=' + alphaOpacity + ')';
318				break;
319			default:
320				elm.style[props[prop]] = value;
321				break;
322			}
323		};
324	})(),
325
326
327	setBorderRadius : function (elm, value) {
328		jsc.setStyle(elm, 'borderRadius', value || '0');
329	},
330
331
332	setBoxShadow : function (elm, value) {
333		jsc.setStyle(elm, 'boxShadow', value || 'none');
334	},
335
336
337	getElementPos : function (e, relativeToViewport) {
338		var x=0, y=0;
339		var rect = e.getBoundingClientRect();
340		x = rect.left;
341		y = rect.top;
342		if (!relativeToViewport) {
343			var viewPos = jsc.getViewPos();
344			x += viewPos[0];
345			y += viewPos[1];
346		}
347		return [x, y];
348	},
349
350
351	getElementSize : function (e) {
352		return [e.offsetWidth, e.offsetHeight];
353	},
354
355
356	// get pointer's X/Y coordinates relative to viewport
357	getAbsPointerPos : function (e) {
358		if (!e) { e = window.event; }
359		var x = 0, y = 0;
360		if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) {
361			// touch devices
362			x = e.changedTouches[0].clientX;
363			y = e.changedTouches[0].clientY;
364		} else if (typeof e.clientX === 'number') {
365			x = e.clientX;
366			y = e.clientY;
367		}
368		return { x: x, y: y };
369	},
370
371
372	// get pointer's X/Y coordinates relative to target element
373	getRelPointerPos : function (e) {
374		if (!e) { e = window.event; }
375		var target = e.target || e.srcElement;
376		var targetRect = target.getBoundingClientRect();
377
378		var x = 0, y = 0;
379
380		var clientX = 0, clientY = 0;
381		if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) {
382			// touch devices
383			clientX = e.changedTouches[0].clientX;
384			clientY = e.changedTouches[0].clientY;
385		} else if (typeof e.clientX === 'number') {
386			clientX = e.clientX;
387			clientY = e.clientY;
388		}
389
390		x = clientX - targetRect.left;
391		y = clientY - targetRect.top;
392		return { x: x, y: y };
393	},
394
395
396	getViewPos : function () {
397		var doc = document.documentElement;
398		return [
399			(window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0),
400			(window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
401		];
402	},
403
404
405	getViewSize : function () {
406		var doc = document.documentElement;
407		return [
408			(window.innerWidth || doc.clientWidth),
409			(window.innerHeight || doc.clientHeight),
410		];
411	},
412
413
414	setOption : function (option, value) {
415		if (typeof this[option] === 'undefined') {
416			jsc.warn('Unrecognized option \'' + option + '\'');
417			return false;
418		}
419		this[option] = value;
420	},
421
422
423	redrawPosition : function () {
424
425		if (jsc.picker && jsc.picker.owner) {
426			var thisObj = jsc.picker.owner;
427
428			var tp, vp;
429
430			if (thisObj.fixed) {
431				// Fixed elements are positioned relative to viewport,
432				// therefore we can ignore the scroll offset
433				tp = jsc.getElementPos(thisObj.targetElement, true); // target pos
434				vp = [0, 0]; // view pos
435			} else {
436				tp = jsc.getElementPos(thisObj.targetElement); // target pos
437				vp = jsc.getViewPos(); // view pos
438			}
439
440			var ts = jsc.getElementSize(thisObj.targetElement); // target size
441			var vs = jsc.getViewSize(); // view size
442			var ps = jsc.getPickerOuterDims(thisObj); // picker size
443			var a, b, c;
444			switch (thisObj.position.toLowerCase()) {
445				case 'left': a=1; b=0; c=-1; break;
446				case 'right':a=1; b=0; c=1; break;
447				case 'top':  a=0; b=1; c=-1; break;
448				default:     a=0; b=1; c=1; break;
449			}
450			var l = (ts[b]+ps[b])/2;
451
452			// compute picker position
453			if (!thisObj.smartPosition) {
454				var pp = [
455					tp[a],
456					tp[b]+ts[b]-l+l*c
457				];
458			} else {
459				var pp = [
460					-vp[a]+tp[a]+ps[a] > vs[a] ?
461						(-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >
461= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
462						tp[a],
463					-vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
464						(-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
465						(tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
466				];
467			}
468
469			var x = pp[a];
470			var y = pp[b];
471			var positionValue = thisObj.fixed ? 'fixed' : 'absolute';
472			var contractShadow =
473				(pp[0] + ps[0] > tp[0] || pp[0] < tp[0] + ts[0]) &&
474				(pp[1] + ps[1] < tp[1] + ts[1]);
475
476			jsc._drawPosition(thisObj, x, y, positionValue, contractShadow);
477		}
478	},
479
480
481	_drawPosition : function (thisObj, x, y, positionValue, contractShadow) {
482		var vShadow = contractShadow ? 0 : thisObj.shadowBlur; // px
483
484		jsc.picker.wrap.style.position = positionValue;
485		jsc.picker.wrap.style.left = x + 'px';
486		jsc.picker.wrap.style.top = y + 'px';
487
488		jsc.setBoxShadow(
489			jsc.picker.boxS,
490			thisObj.shadow ?
491				new jsc.BoxShadow(0, vShadow, thisObj.shadowBlur, 0, thisObj.shadowColor) :
492				null);
493	},
494
495
496	getPickerDims : function (thisObj) {
497		var displaySlider = !!jsc.getSliderComponent(thisObj);
498		var dims = [
499			2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.width +
500				(displaySlider ? 2 * thisObj.insetWidth + jsc.getPadToSliderPadding(thisObj) + thisObj.sliderSize : 0),
501			2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.height +
502				(thisObj.closable ? 2 * thisObj.insetWidth + thisObj.padding + thisObj.buttonHeight : 0)
503		];
504		return dims;
505	},
506
507
508	getPickerOuterDims : function (thisObj) {
509		var dims = jsc.getPickerDims(thisObj);
510		return [
511			dims[0] + 2 * thisObj.borderWidth,
512			dims[1] + 2 * thisObj.borderWidth
513		];
514	},
515
516
517	getPadToSliderPadding : function (thisObj) {
518		return Math.max(thisObj.padding, 1.5 * (2 * thisObj.pointerBorderWidth + thisObj.pointerThickness));
519	},
520
521
522	getPadYComponent : function (thisObj) {
523		switch (thisObj.mode.charAt(1).toLowerCase()) {
524			case 'v': return 'v'; break;
525		}
526		return 's';
527	},
528
529
530	getSliderComponent : function (thisObj) {
531		if (thisObj.mode.length > 2) {
532			switch (thisObj.mode.charAt(2).toLowerCase()) {
533				case 's': return 's'; break;
534				case 'v': return 'v'; break;
535			}
536		}
537		return null;
538	},
539
540
541	onDocumentMouseDown : function (e) {
542		if (!e) { e = window.event; }
543		var target = e.target || e.srcElement;
544
545		if (target._jscLinkedInstance) {
546			if (target._jscLinkedInstance.showOnClick) {
547				target._jscLinkedInstance.show();
548			}
549		} else if (target._jscControlName) {
550			jsc.onControlPointerStart(e, target, target._jscControlName, 'mouse');
551		} else {
552			// Mouse is outside the picker controls -> hide the color picker!
553			if (jsc.picker && jsc.picker.owner) {
554				jsc.picker.owner.hide();
555			}
556		}
557	},
558
559
560	onDocumentTouchStart : function (e) {
561		if (!e) { e = window.event; }
562		var target = e.target || e.srcElement;
563
564		if (target._jscLinkedInstance) {
565			if (target._jscLinkedInstance.showOnClick) {
566				target._jscLinkedInstance.show();
567			}
568		} else if (target._jscControlName) {
569			jsc.onControlPointerStart(e, target, target._jscControlName, 'touch');
570		} else {
571			if (jsc.picker && jsc.picker.owner) {
572				jsc.picker.owner.hide();
573			}
574		}
575	},
576
577
578	onDocumentKeyUp : function (e) {
579		if (!e) { e = window.event; }
580
581		if (
582			(e.code && e.code === 'Enter' || e.keyCode === 13) ||
583			(e.code && e.code === 'Escape' || e.keyCode === 27)
584		) {
585			if (jsc.picker && jsc.picker.owner) {
586				jsc.picker.owner.hide();
587			}
588		}
589	},
590
591
592	onWindowResize : function (e) {
593		jsc.redrawPosition();
594	},
595
596
597	onParentScroll : function (e) {
598		// hide the picker when one of the parent elements is scrolled
599		if (jsc.picker && jsc.picker.owner) {
600			jsc.picker.owner.hide();
601		}
602	},
603
604
605	_pointerMoveEvent : {
606		mouse: 'mousemove',
607		touch: 'touchmove'
608	},
609	_pointerEndEvent : {
610		mouse: 'mouseup',
611		touch: 'touchend'
612	},
613
614
615	_pointerOrigin : null,
616	_capturedTarget : null,
617
618
619	onControlPointerStart : function (e, target, controlName, pointerType) {
620		var thisObj = target._jscInstance;
621
622		jsc.preventDefault(e);
623		jsc.captureTarget(target);
624
625		var registerDragEvents = function (doc, offset) {
626			jsc.attachGroupEvent('drag', doc, jsc._pointerMoveEvent[pointerType],
627				jsc.onDocumentPointerMove(e, target, controlName, pointerType, offset));
628			jsc.attachGroupEvent('drag', doc, jsc._pointerEndEvent[pointerType],
629				jsc.onDocumentPointerEnd(e, target, controlName, pointerType));
630		};
631
632		registerDragEvents(document, [0, 0]);
633
634		if (window.parent && window.frameElement) {
635			var rect = window.frameElement.getBoundingClientRect();
636			var ofs = [-rect.left, -rect.top];
637			registerDragEvents(window.parent.window.document, ofs);
638		}
639
640		var abs = jsc.getAbsPointerPos(e);
641		var rel = jsc.getRelPointerPos(e);
642		jsc._pointerOrigin = {
643			x: abs.x - rel.x,
644			y: abs.y - rel.y
645		};
646
647		switch (controlName) {
648		case 'pad':
649			// if the slider is at the bottom, move it up
650			switch (jsc.getSliderComponent(thisObj)) {
651			case 's': if (thisObj.hsv[1] === 0) { thisObj.fromHSV(null, 100, null); }; break;
652			case 'v': if (thisObj.hsv[2] === 0) { thisObj.fromHSV(null, null, 100); }; break;
653			}
654			jsc.setPad(thisObj, e, 0, 0);
655			break;
656
657		case 'sld':
658			jsc.setSld(thisObj, e, 0);
659			break;
660		}
661
662		jsc.dispatchFineChange(thisObj);
663	},
664
665
666	onDocumentPointerMove : function (e, target, controlName, pointerType, offset) {
667		return function (e) {
668			var thisObj = target._jscInstance;
669			switch (controlName) {
670			case 'pad':
671				if (!e) { e = window.event; }
672				jsc.setPad(thisObj, e, offset[0], offset[1]);
673				jsc.dispatchFineChange(thisObj);
674				break;
675
676			case 'sld':
677				if (!e) { e = window.event; }
678				jsc.setSld(thisObj, e, offset[1]);
679				jsc.dispatchFineChange(thisObj);
680				break;
681			}
682		}
683	},
684
685
686	onDocumentPointerEnd : function (e, target, controlName, pointerType) {
687		return function (e) {
688			var thisObj = target._jscInstance;
689			jsc.detachGroupEvents('drag');
690			jsc.releaseTarget();
691			// Always dispatch changes after detaching outstanding mouse handlers,
692			// in case some user interaction will occur in user's onchange callback
693			// that would intrude with current mouse events
694			jsc.dispatchChange(thisObj);
695		};
696	},
697
698
699	dispatchChange : function (thisObj) {
700		if (thisObj.valueElement) {
701			if (jsc.isElementType(thisObj.valueElement, 'input')) {
702				jsc.fireEvent(thisObj.valueElement, 'change');
703			}
704		}
705	},
706
707
708	dispatchFineChange : function (thisObj) {
709		if (thisObj.onFineChange) {
710			var callback;
711			if (typeof thisObj.onFineChange === 'string') {
712				callback = new Function (thisObj.onFineChange);
713			} else {
714				callback = thisObj.onFineChange;
715			}
716			callback.call(thisObj);
717		}
718	},
719
720
721	setPad : function (thisObj, e, ofsX, ofsY) {
722		var pointerAbs = jsc.getAbsPointerPos(e);
723		var x = ofsX + pointerAbs.x - jsc._pointerOrigin.x - thisObj.padding - thisObj.insetWidth;
724		var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth;
725
726		var xVal = x * (360 / (thisObj.width - 1));
727		var yVal = 100 - (y * (100 / (thisObj.height - 1)));
728
729		switch (jsc.getPadYComponent(thisObj)) {
730		case 's': thisObj.fromHSV(xVal, yVal, null, jsc.leaveSld); break;
731		case 'v': thisObj.fromHSV(xVal, null, yVal, jsc.leaveSld); break;
732		}
733	},
734
735
736	setSld : function (thisObj, e, ofsY) {
737		var pointerAbs = jsc.getAbsPointerPos(e);
738		var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth;
739
740		var yVal = 100 - (y * (100 / (thisObj.height - 1)));
741
742		switch (jsc.getSliderComponent(thisObj)) {
743		case 's': thisObj.fromHSV(null, yVal, null, jsc.leavePad); break;
744		case 'v': thisObj.fromHSV(null, null, yVal, jsc.leavePad); break;
745		}
746	},
747
748
749	_vmlNS : 'jsc_vml_',
750	_vmlCSS : 'jsc_vml_css_',
751	_vmlReady : false,
752
753
754	initVML : function () {
755		if (!jsc._vmlReady) {
756			// init VML namespace
757			var doc = document;
758			if (!doc.namespaces[jsc._vmlNS]) {
759				doc.namespaces.add(jsc._vmlNS, 'urn:schemas-microsoft-com:vml');
760			}
761			if (!doc.styleSheets[jsc._vmlCSS]) {
762				var tags = ['shape', 'shapetype', 'group', 'background', 'path', 'formulas', 'handles', 'fill', 'stroke', 'shadow', 'textbox', 'textpath', 'imagedata', 'line', 'polyline', 'curve', 'rect', 'roundrect', 'oval', 'arc', 'image'];
763				var ss = doc.createStyleSheet();
764				ss.owningElement.id = jsc._vmlCSS;
765				for (var i = 0; i < tags.length; i += 1) {
766					ss.addRule(jsc._vmlNS + '\\:' + tags[i], 'behavior:url(#default#VML);');
767				}
768			}
769			jsc._vmlReady = true;
770		}
771	},
772
773
774	createPalette : function () {
775
776		var paletteObj = {
777			elm: null,
778			draw: null
779		};
780
781		if (jsc.isCanvasSupported) {
782			// Canvas implementation for modern browsers
783
784			var canvas = document.createElement('canvas');
785			var ctx = canvas.getContext('2d');
786
787			var drawFunc = function (width, height, type) {
788				canvas.width = width;
789				canvas.height = height;
790
791				ctx.clearRect(0, 0, canvas.width, canvas.height);
792
793				var hGrad = ctx.createLinearGradient(0, 0, canvas.width, 0);
794				hGrad.addColorStop(0 / 6, '#F00');
795				hGrad.addColorStop(1 / 6, '#FF0');
796				hGrad.addColorStop(2 / 6, '#0F0');
797				hGrad.addColorStop(3 / 6, '#0FF');
798				hGrad.addColorStop(4 / 6, '#00F');
799				hGrad.addColorStop(5 / 6, '#F0F');
800				hGrad.addColorStop(6 / 6, '#F00');
801
802				ctx.fillStyle = hGrad;
803				ctx.fillRect(0, 0, canvas.width, canvas.height);
804
805				var vGrad = ctx.createLinearGradient(0, 0, 0, canvas.height);
806				switch (type.toLowerCase()) {
807				case 's':
808					vGrad.addColorStop(0, 'rgba(255,255,255,0)');
809					vGrad.addColorStop(1, 'rgba(255,255,255,1)');
810					break;
811				case 'v':
812					vGrad.addColorStop(0, 'rgba(0,0,0,0)');
813					vGrad.addColorStop(1, 'rgba(0,0,0,1)');
814					break;
815				}
816				ctx.fillStyle = vGrad;
817				ctx.fillRect(0, 0, canvas.width, canvas.height);
818			};
819
820			paletteObj.elm = canvas;
821			paletteObj.draw = drawFunc;
822
823		} else {
824			// VML fallback for IE 7 and 8
825
826			jsc.initVML();
827
828			var vmlContainer = document.createElement('div');
829			vmlContainer.style.position = 'relative';
830			vmlContainer.style.overflow = 'hidden';
831
832			var hGrad = document.createElement(jsc._vmlNS + ':fill');
833			hGrad.type = 'gradient';
834			hGrad.method = 'linear';
835			hGrad.angle = '90';
836			hGrad.colors = '16.67% #F0F, 33.33% #00F, 50% #0FF, 66.67% #0F0, 83.33% #FF0'
837
838			var hRect = document.createElement(jsc._vmlNS + ':rect');
839			hRect.style.position = 'absolute';
840			hRect.style.left = -1 + 'px';
841			hRect.style.top = -1 + 'px';
842			hRect.stroked = false;
843			hRect.appendChild(hGrad);
844			vmlContainer.appendChild(hRect);
845
846			var vGrad = document.createElement(jsc._vmlNS + ':fill');
847			vGrad.type = 'gradient';
848			vGrad.method = 'linear';
849			vGrad.angle = '180';
850			vGrad.opacity = '0';
851
852			var vRect = document.createElement(jsc._vmlNS + ':rect');
853			vRect.style.position = 'absolute';
854			vRect.style.left = -1 + 'px';
855			vRect.style.top = -1 + 'px';
856			vRect.stroked = false;
857			vRect.appendChild(vGrad);
858			vmlContainer.appendChild(vRect);
859
860			var drawFunc = function (width, height, type) {
861				vmlContainer.style.width = width + 'px';
862				vmlContainer.style.height = height + 'px';
863
864				hRect.style.width =
865				vRect.style.width =
866					(width + 1) + 'px';
867				hRect.style.height =
868				vRect.style.height =
869					(height + 1) + 'px';
870
871				// Colors must be specified during every redraw, otherwise IE won't display
872				// a full gradient during a subsequential redraw
873				hGrad.color = '#F00';
874				hGrad.color2 = '#F00';
875
876				switch (type.toLowerCase()) {
877				case 's':
878					vGrad.color = vGrad.color2 = '#FFF';
879					break;
880				case 'v':
881					vGrad.color = vGrad.color2 = '#000';
882					break;
883				}
884			};
885			
886			paletteObj.elm = vmlContainer;
887			paletteObj.draw = drawFunc;
888		}
889
890		return paletteObj;
891	},
892
893
894	createSliderGradient : function () {
895
896		var sliderObj = {
897			elm: null,
898			draw: null
899		};
900
901		if (jsc.isCanvasSupported) {
902			// Canvas implementation for modern browsers
903
904			var canvas = document.createElement('canvas');
905			var ctx = canvas.getContext('2d');
906
907			var drawFunc = function (width, height, color1, color2) {
908				canvas.width = width;
909				canvas.height = height;
910
911				ctx.clearRect(0, 0, canvas.width, canvas.height);
912
913				var grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
914				grad.addColorStop(0, color1);
915				grad.addColorStop(1, color2);
916
917				ctx.fillStyle = grad;
918				ctx.fillRect(0, 0, canvas.width, canvas.height);
919			};
920
921			sliderObj.elm = canvas;
922			sliderObj.draw = drawFunc;
923
924		} else {
925			// VML fallback for IE 7 and 8
926
927			jsc.initVML();
928
929			var vmlContainer = document.createElement('div');
930			vmlContainer.style.position = 'relative';
931			vmlContainer.style.overflow = 'hidden';
932
933			var grad = document.createElement(jsc._vmlNS + ':fill');
934			grad.type = 'gradient';
935			grad.method = 'linear';
936			grad.angle = '180';
937
938			var rect = document.createElement(jsc._vmlNS + ':rect');
939			rect.style.position = 'absolute';
940			rect.style.left = -1 + 'px';
941			rect.style.top = -1 + 'px';
942			rect.stroked = false;
943			rect.appendChild(grad);
944			vmlContainer.appendChild(rect);
945
946			var drawFunc = function (width, height, color1, color2) {
947				vmlContainer.style.width = width + 'px';
948				vmlContainer.style.height = height + 'px';
949
950				rect.style.width = (width + 1) + 'px';
951				rect.style.height = (height + 1) + 'px';
952
953				grad.color = color1;
954				grad.color2 = color2;
955			};
956			
957			sliderObj.elm = vmlContainer;
958			sliderObj.draw = drawFunc;
959		}
960
961		return sliderObj;
962	},
963
964
965	leaveValue : 1<<0,
966	leaveStyle : 1<<1,
967	leavePad : 1<<2,
968	leaveSld : 1<<3,
969
970
971	BoxShadow : (function () {
972		var BoxShadow = function (hShadow, vShadow, blur, spread, color, inset) {
973			this.hShadow = hShadow;
974			this.vShadow = vShadow;
975			this.blur = blur;
976			this.spread = spread;
977			this.color = color;
978			this.inset = !!inset;
979		};
980
981		BoxShadow.prototype.toString = function () {
982			var vals = [
983				Math.round(this.hShadow) + 'px',
984				Math.round(this.vShadow) + 'px',
985				Math.round(this.blur) + 'px',
986				Math.round(this.spread) + 'px',
987				this.color
988			];
989			if (this.inset) {
990				vals.push('inset');
991			}
992			return vals.join(' ');
993		};
994
995		return BoxShadow;
996	})(),
997
998
999	//
1000	// Usage:
1001	// var myColor = new jscolor(<targetElement> [, <options>])
1002	//
1003	// (you can use both 'new jscolor' and 'new JSColor')
1004	//
1005
1006	jscolor : function (targetElement, opts) {
1007
1008		// General options
1009		//
1010		this.value = null; // initial HEX color. To change it later, use methods fromString(), fromHSV() and fromRGB()
1011		this.valueElement = targetElement; // element that will be used to display and input the color code
1012		this.styleElement = targetElement; // element that will preview the picked color using CSS backgroundColor
1013		this.required = true; // whether the associated text <input> can be left empty
1014		this.refine = true; // whether to refine the entered color code (e.g. uppercase it and remove whitespace)
1015		this.hash = false; // whether to prefix the HEX color code with # symbol
1016		this.uppercase = true; // whether to show the color code in upper case
1017		this.onFineChange = null; // called instantly every time the color changes (value can be either a function or a string with javascript code)
1018		this.activeClass = 'jscolor-active'; // class to be set to the target element when a picker window is open on it
1019		this.overwriteImportant = false; // whether to overwrite colors of styleElement using !important
1020		this.minS = 0; // min allowed saturation (0 - 100)
1021		this.maxS = 100; // max allowed saturation (0 - 100)
1022		this.minV = 0; // min allowed value (brightness) (0 - 100)
1023		this.maxV = 100; // max allowed value (brightness) (0 - 100)
1024
1025		// Accessing the picked color
1026		//
1027		this.hsv = [0, 0, 100]; // read-only  [0-360, 0-100, 0-100]
1028		this.rgb = [255, 255, 255]; // read-only  [0-255, 0-255, 0-255]
1029
1030		// Color Picker options
1031		//
1032		this.width = 181; // width of color palette (in px)
1033		this.height = 101; // height of color palette (in px)
1034		this.showOnClick = true; // whether to display the color picker when user clicks on its target element
1035		this.mode = 'HSV'; // HSV | HVS | HS | HV - layout of the color picker controls
1036		this.position = 'bottom'; // left | right | top | bottom - position relative to the target element
1037		this.smartPosition = true; // automatically change picker position when there is not enough space for it
1038		this.sliderSize = 16; // px
1039		this.crossSize = 8; // px
1040		this.closable = false; // whether to display the Close button
1041		this.closeText = 'Close';
1042		this.buttonColor = '#000000'; // CSS color
1043		this.buttonHeight = 18; // px
1044		this.padding = 12; // px
1045		this.backgroundColor = '#FFFFFF'; // CSS color
1046		this.borderWidth = 1; // px
1047		this.borderColor = '#BBBBBB'; // CSS color
1048		this.borderRadius = 8; // px
1049		this.insetWidth = 1; // px
1050		this.insetColor = '#BBBBBB'; // CSS color
1051		this.shadow = true; // whether to display shadow
1052		this.shadowBlur = 15; // px
1053		this.shadowColor = 'rgba(0,0,0,0.2)'; // CSS color
1054		this.pointerColor = '#4C4C4C'; // px
1055		this.pointerBorderColor = '#FFFFFF'; // CSS color
1056		this.pointerBorderWidth = 1; // px
1057		this.pointerThickness = 2; // px
1058		this.zIndex = 1000;
1059		this.container = null; // where to append the color picker (BODY element by default)
1060
1061
1062		// let's process the DEPRECATED jscolor.options property (this will be later removed)
1063		if (jsc.jscolor.options) {
1064			// let's set custom default options, if specified
1065			for (var opt in jsc.jscolor.options) {
1066				if (jsc.jscolor.options.hasOwnProperty(opt)) {
1067					jsc.setOption.call(this, opt, jsc.jscolor.options[opt]);
1068				}
1069			}
1070		}
1071
1072
1073		// let's apply configuration presets
1074		//
1075		var presetsArr = [];
1076
1077		if (opts.preset) {
1078			if (typeof opts.preset === 'string') {
1079				presetsArr = opts.preset.split(/\s+/);
1080			} else if (Array.isArray(opts.preset)) {
1081				presetsArr = opts.preset.slice(); // to clone
1082			} else {
1083				jsc.warn('Unrecognized preset value');
1084			}
1085		}
1086
1087		// always use the 'default' preset as a baseline
1088		presetsArr.push('default');
1089
1090		// let's apply the presets in reverse order, so that should there be any overlapping options,
1091		// then the formerly listed preset overrides the latter
1092		for (var i = presetsArr.length - 1; i >= 0; i -= 1) {
1093			var pres = presetsArr[i];
1094			if (!pres) {
1095				continue; // preset is empty string
1096			}
1097			if (!jsc.jscolor.presets.hasOwnProperty(pres)) {
1098				jsc.warn('Unknown preset \'' + pres + '\'');
1099				continue;
1100			}
1101			for (var opt in jsc.jscolor.presets[pres]) {
1102				if (jsc.jscolor.presets[pres].hasOwnProperty(opt)) {
1103					jsc.setOption.call(this, opt, jsc.jscolor.presets[pres][opt]);
1104				}
1105			}
1106		}
1107
1108
1109		// let's set specific options for this color picker
1110		var nonProperties = ['preset']; // these options won't be set as instance properties
1111		for (var opt in opts) {
1112			if (opts.hasOwnProperty(opt)) {
1113				if (nonProperties.indexOf(opt) === -1) {
1114					jsc.setOption.call(this, opt, opts[opt]);
1115				}
1116			}
1117		}
1118
1119
1120		this.hide = function () {
1121			if (isPickerOwner()) {
1122				detachPicker();
1123			}
1124		};
1125
1126
1127		this.show = function () {
1128			drawPicker();
1129		};
1130
1131
1132		this.redraw = function () {
1133			if (isPickerOwner()) {
1134				drawPicker();
1135			}
1136		};
1137
1138
1139		this.importColor = function () {
1140			if (!this.valueElement) {
1141				this.exportColor();
1142			} else {
1143				if (jsc.isElementType(this.valueElement, 'input')) {
1144					if (!this.refine) {
1145						if (!this.fromString(this.valueElement.value, jsc.leaveValue)) {
1146							if (this.styleElement) {
1147								this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage;
1148								this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor;
1149								this.styleElement.style.color = this.styleElement._jscOrigStyle.color;
1150							}
1151							this.exportColor(jsc.leaveValue | jsc.leaveStyle);
1152						}
1153					} else if (!this.required && /^\s*$/.test(this.valueElement.value)) {
1154						this.valueElement.value = '';
1155						if (this.styleElement) {
1156							this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage;
1157							this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor;
1158							this.styleElement.style.color = this.styleElement._jscOrigStyle.color;
1159						}
1160						this.exportColor(jsc.leaveValue | jsc.leaveStyle);
1161
1162					} else if (this.fromString(this.valueElement.value)) {
1163						// managed to import color successfully from the value -> OK, don't do anything
1164					} else {
1165						this.exportColor();
1166					}
1167				} else {
1168					// not an input element -> doesn't have any value
1169					this.exportColor();
1170				}
1171			}
1172		};
1173
1174
1175		this.exportColor = function (flags) {
1176			if (!(flags & jsc.leaveValue) && this.valueElement) {
1177				var value = this.toString();
1178				if (this.uppercase) { value = value.toUpperCase(); }
1179				if (this.hash) { value = '#' + value; }
1180
1181				if (jsc.isElementType(this.valueElement, 'input')) {
1182					if (this.valueElement.value !== value) {
1183						this.valueElement.value = value;
1184					}
1185				} else {
1186					this.valueElement.innerHTML = value;
1187				}
1188			}
1189			if (!(flags & jsc.leaveStyle)) {
1190				if (this.styleElement) {
1191					var bgColor = '#' + this.toString();
1192					var fgColor = this.isLight() ? '#000' : '#FFF';
1193
1194					this.styleElement.style.backgroundImage = 'none';
1195					this.styleElement.style.backgroundColor = bgColor;
1196					this.styleElement.style.color = fgColor;
1197
1198					if (this.overwriteImportant) {
1199						this.styleElement.setAttribute('style',
1200							'background: ' + bgColor + ' !important; ' +
1201							'color: ' + fgColor + ' !important;'
1202						);
1203					}
1204				}
1205			}
1206			if (!(flags & jsc.leavePad) && isPickerOwner()) {
1207				redrawPad();
1208			}
1209			if (!(flags & jsc.leaveSld) && isPickerOwner()) {
1210				redrawSld();
1211			}
1212		};
1213
1214
1215		// h: 0-360
1216		// s: 0-100
1217		// v: 0-100
1218		//
1219		this.fromHSV = function (h, s, v, flags) { // null = don't change
1220			if (h !== null) {
1221				if (isNaN(h)) { return false; }
1222				h = Math.max(0, Math.min(360, h));
1223			}
1224			if (s !== null) {
1225				if (isNaN(s)) { return false; }
1226				s = Math.max(0, Math.min(100, this.maxS, s), this.minS);
1227			}
1228			if (v !== null) {
1229				if (isNaN(v)) { return false; }
1230				v = Math.max(0, Math.min(100, this.maxV, v), this.minV);
1231			}
1232
1233			this.rgb = HSV_RGB(
1234				h===null ? this.hsv[0] : (this.hsv[0]=h),
1235				s===null ? this.hsv[1] : (this.hsv[1]=s),
1236				v===null ? this.hsv[2] : (this.hsv[2]=v)
1237			);
1238
1239			this.exportColor(flags);
1240		};
1241
1242
1243		// r: 0-255
1244		// g: 0-255
1245		// b: 0-255
1246		//
1247		this.fromRGB = function (r, g, b, flags) { // null = don't change
1248			if (r !== null) {
1249				if (isNaN(r)) { return false; }
1250				r = Math.max(0, Math.min(255, r));
1251			}
1252			if (g !== null) {
1253				if (isNaN(g)) { return false; }
1254				g = Math.max(0, Math.min(255, g));
1255			}
1256			if (b !== null) {
1257				if (isNaN(b)) { return false; }
1258				b = Math.max(0, Math.min(255, b));
1259			}
1260
1261			var hsv = RGB_HSV(
1262				r===null ? this.rgb[0] : r,
1263				g===null ? this.rgb[1] : g,
1264				b===null ? this.rgb[2] : b
1265			);
1266			if (hsv[0] !== null) {
1267				this.hsv[0] = Math.max(0, Math.min(360, hsv[0]));
1268			}
1269			if (hsv[2] !== 0) {
1270				this.hsv[1] = hsv[1]===null ? null : Math.max(0, this.minS, Math.min(100, this.maxS, hsv[1]));
1271			}
1272			this.hsv[2] = hsv[2]===null ? null : Math.max(0, this.minV, Math.min(100, this.maxV, hsv[2]));
1273
1274			// update RGB according to final HSV, as some values might be trimmed
1275			var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]);
1276			this.rgb[0] = rgb[0];
1277			this.rgb[1] = rgb[1];
1278			this.rgb[2] = rgb[2];
1279
1280			this.exportColor(flags);
1281		};
1282
1283
1284		this.fromString = function (str, flags) {
1285			var m;
1286			if (m = str.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i)) {
1287				// HEX notation
1288				//
1289
1290				if (m[1].length === 6) {
1291					// 6-char notation
1292					this.fromRGB(
1293						parseInt(m[1].substr(0,2),16),
1294						parseInt(m[1].substr(2,2),16),
1295						parseInt(m[1].substr(4,2),16),
1296						flags
1297					);
1298				} else {
1299					// 3-char notation
1300					this.fromRGB(
1301						parseInt(m[1].charAt(0) + m[1].charAt(0),16),
1302						parseInt(m[1].charAt(1) + m[1].charAt(1),16),
1303						parseInt(m[1].charAt(2) + m[1].charAt(2),16),
1304						flags
1305					);
1306				}
1307				return true;
1308
1309			} else if (m = str.match(/^\W*rgba?\(([^)]*)\)\W*$/i)) {
1310				var params = m[1].split(',');
1311				var re = /^\s*(\d*)(\.\d+)?\s*$/;
1312				var mR, mG, mB;
1313				if (
1314					params.length >= 3 &&
1315					(mR = params[0].match(re)) &&
1316					(mG = params[1].match(re)) &&
1317					(mB = params[2].match(re))
1318				) {
1319					var r = parseFloat((mR[1] || '0') + (mR[2] || ''));
1320					var g = parseFloat((mG[1] || '0') + (mG[2] || ''));
1321					var b = parseFloat((mB[1] || '0') + (mB[2] || ''));
1322					this.fromRGB(r, g, b, flags);
1323					return true;
1324				}
1325			}
1326			return false;
1327		};
1328
1329
1330		this.toString = function () {
1331			return (
1332				(0x100 | Math.round(this.rgb[0])).toString(16).substr(1) +
1333				(0x100 | Math.round(this.rgb[1])).toString(16).substr(1) +
1334				(0x100 | Math.round(this.rgb[2])).toString(16).substr(1)
1335			);
1336		};
1337
1338
1339		this.toHEXString = function () {
1340			return '#' + this.toString().toUpperCase();
1341		};
1342
1343
1344		this.toRGBString = function () {
1345			return ('rgb(' +
1346				Math.round(this.rgb[0]) + ',' +
1347				Math.round(this.rgb[1]) + ',' +
1348				Math.round(this.rgb[2]) + ')'
1349			);
1350		};
1351
1352
1353		this.toGrayscale = function () {
1354			return (
1355				0.213 * this.rgb[0] +
1356				0.715 * this.rgb[1] +
1357				0.072 * this.rgb[2]
1358			);
1359		};
1360
1361
1362		this.isLight = function () {
1363			return this.toGrayscale() > 255 / 2;
1364		};
1365
1366
1367		this._processParentElementsInDOM = function () {
1368			if (this._linkedElementsProcessed) { return; }
1369			this._linkedElementsProcessed = true;
1370
1371			var elm = this.targetElement;
1372			do {
1373				// If the target element or one of its parent nodes has fixed position,
1374				// then use fixed positioning instead
1375				//
1376				// Note: In Firefox, getComputedStyle returns null in a hidden iframe,
1377				// that's why we need to check if the returned style object is non-empty
1378				var currStyle = jsc.getStyle(elm);
1379				if (currStyle && currStyle.position.toLowerCase() === 'fixed') {
1380					this.fixed = true;
1381				}
1382
1383				if (elm !== this.targetElement) {
1384					// Ensure to attach onParentScroll only once to each parent element
1385					// (multiple targetElements can share the same parent nodes)
1386					//
1387					// Note: It's not just offsetParents that can be scrollable,
1388					// that's why we loop through all parent nodes
1389					if (!elm._jscEventsAttached) {
1390						jsc.attachEvent(elm, 'scroll', jsc.onParentScroll);
1391						elm._jscEventsAttached = true;
1392					}
1393				}
1394			} while ((elm = elm.parentNode) && !jsc.isElementType(elm, 'body'));
1395		};
1396
1397
1398		// r: 0-255
1399		// g: 0-255
1400		// b: 0-255
1401		//
1402		// returns: [ 0-360, 0-100, 0-100 ]
1403		//
1404		function RGB_HSV (r, g, b) {
1405			r /= 255;
1406			g /= 255;
1407			b /= 255;
1408			var n = Math.min(Math.min(r,g),b);
1409			var v = Math.max(Math.max(r,g),b);
1410			var m = v - n;
1411			if (m === 0) { return [ null, 0, 100 * v ]; }
1412			var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
1413			return [
1414				60 * (h===6?0:h),
1415				100 * (m/v),
1416				100 * v
1417			];
1418		}
1419
1420
1421		// h: 0-360
1422		// s: 0-100
1423		// v: 0-100
1424		//
1425		// returns: [ 0-255, 0-255, 0-255 ]
1426		//
1427		function HSV_RGB (h, s, v) {
1428			var u = 255 * (v / 100);
1429
1430			if (h === null) {
1431				return [ u, u, u ];
1432			}
1433
1434			h /= 60;
1435			s /= 100;
1436
1437			var i = Math.floor(h);
1438			var f = i%2 ? h-i : 1-(h-i);
1439			var m = u * (1 - s);
1440			var n = u * (1 - s * f);
1441			switch (i) {
1442				case 6:
1443				case 0: return [u,n,m];
1444				case 1: return [n,u,m];
1445				case 2: return [m,u,n];
1446				case 3: return [m,n,u];
1447				case 4: return [n,m,u];
1448				case 5: return [u,m,n];
1449			}
1450		}
1451
1452
1453		function detachPicker () {
1454			jsc.unsetClass(THIS.targetElement, THIS.activeClass);
1455			jsc.picker.wrap.parentNode.removeChild(jsc.picker.wrap);
1456			delete jsc.picker.owner;
1457		}
1458
1459
1460		function drawPicker () {
1461
1462			// At this point, when drawing the picker, we know what the parent elements are
1463			// and we can do all related DOM operations, such as registering events on them
1464			// or checking their positioning
1465			THIS._processParentElementsInDOM();
1466
1467			if (!jsc.picker) {
1468				jsc.picker = {
1469					owner: null,
1470					wrap : document.createElement('div'),
1471					box : document.createElement('div'),
1472					boxS : document.createElement('div'), // shadow area
1473					boxB : document.createElement('div'), // border
1474					pad : document.createElement('div'),
1475					padB : document.createElement('div'), // border
1476					padM : document.createElement('div'), // mouse/touch area
1477					padPal : jsc.createPalette(),
1478					cross : document.createElement('div'),
1479					crossBY : document.createElement('div'), // border Y
1480					crossBX : document.createElement('div'), // border X
1481					crossLY : document.createElement('div'), // line Y
1482					crossLX : document.createElement('div'), // line X
1483					sld : document.createElement('div'),
1484					sldB : document.createElement('div'), // border
1485					sldM : document.createElement('div'), // mouse/touch area
1486					sldGrad : jsc.createSliderGradient(),
1487					sldPtrS : document.createElement('div'), // slider pointer spacer
1488					sldPtrIB : document.createElement('div'), // slider pointer inner border
1489					sldPtrMB : document.createElement('div'), // slider pointer middle border
1490					sldPtrOB : document.createElement('div'), // slider pointer outer border
1491					btn : document.createElement('div'),
1492					btnT : document.createElement('span') // text
1493				};
1494
1495				jsc.picker.pad.appendChild(jsc.picker.padPal.elm);
1496				jsc.picker.padB.appendChild(jsc.picker.pad);
1497				jsc.picker.cross.appendChild(jsc.picker.crossBY);
1498				jsc.picker.cross.appendChild(jsc.picker.crossBX);
1499				jsc.picker.cross.appendChild(jsc.picker.crossLY);
1500				jsc.picker.cross.appendChild(jsc.picker.crossLX);
1501				jsc.picker.padB.appendChild(jsc.picker.cross);
1502				jsc.picker.box.appendChild(jsc.picker.padB);
1503				jsc.picker.box.appendChild(jsc.picker.padM);
1504
1505				jsc.picker.sld.appendChild(jsc.picker.sldGrad.elm);
1506				jsc.picker.sldB.appendChild(jsc.picker.sld);
1507				jsc.picker.sldB.appendChild(jsc.picker.sldPtrOB);
1508				jsc.picker.sldPtrOB.appendChild(jsc.picker.sldPtrMB);
1509				jsc.picker.sldPtrMB.appendChild(jsc.picker.sldPtrIB);
1510				jsc.picker.sldPtrIB.appendChild(jsc.picker.sldPtrS);
1511				jsc.picker.box.appendChild(jsc.picker.sldB);
1512				jsc.picker.box.appendChild(jsc.picker.sldM);
1513
1514				jsc.picker.btn.appendChild(jsc.picker.btnT);
1515				jsc.picker.box.appendChild(jsc.picker.btn);
1516
1517				jsc.picker.boxB.appendChild(jsc.picker.box);
1518				jsc.picker.wrap.appendChild(jsc.picker.boxS);
1519				jsc.picker.wrap.appendChild(jsc.picker.boxB);
1520			}
1521
1522			var p = jsc.picker;
1523
1524			var displaySlider = !!jsc.getSliderComponent(THIS);
1525			var dims = jsc.getPickerDims(THIS);
1526			var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize);
1527			var padToSliderPadding = jsc.getPadToSliderPadding(THIS);
1528			var borderRadius = Math.min(
1529				THIS.borderRadius,
1530				Math.round(THIS.padding * Math.PI)); // px
1531			var padCursor = 'crosshair';
1532
1533			// wrap
1534			p.wrap.className = 'jscolor-picker-wrap';
1535			p.wrap.style.clear = 'both';
1536			p.wrap.style.width = (dims[0] + 2 * THIS.borderWidth) + 'px';
1537			p.wrap.style.height = (dims[1] + 2 * THIS.borderWidth) + 'px';
1538			p.wrap.style.zIndex = THIS.zIndex;
1539
1540			// picker
1541			p.box.className = 'jscolor-picker';
1542			p.box.style.width = dims[0] + 'px';
1543			p.box.style.height = dims[1] + 'px';
1544
1545			// picker shadow
1546			p.boxS.className = 'jscolor-picker-shadow';
1547			p.boxS.style.position = 'absolute';
1548			p.boxS.style.left = '0';
1549			p.boxS.style.top = '0';
1550			p.boxS.style.width = '100%';
1551			p.boxS.style.height = '100%';
1552			jsc.setBorderRadius(p.boxS, borderRadius + 'px');
1553
1554			// picker border
1555			p.boxB.className = 'jscolor-picker-border';
1556			p.boxB.style.position = 'relative';
1557			p.boxB.style.border = THIS.borderWidth + 'px solid';
1558			p.boxB.style.borderColor = THIS.borderColor;
1559			p.boxB.style.background = THIS.backgroundColor;
1560			jsc.setBorderRadius(p.boxB, borderRadius + 'px');
1561
1562			// IE hack:
1563			// If the element is transparent, IE will trigger the event on the elements under it,
1564			// e.g. on Canvas or on elements with border
1565			p.padM.style.background =
1566			p.sldM.style.background =
1567				'#FFF';
1568			jsc.setStyle(p.padM, 'opacity', '0');
1569			jsc.setStyle(p.sldM, 'opacity', '0');
1570
1571			// pad
1572			p.pad.style.position = 'relative';
1573			p.pad.style.width = THIS.width + 'px';
1574			p.pad.style.height = THIS.height + 'px';
1575
1576			// pad palettes (HSV and HVS)
1577			p.padPal.draw(THIS.width, THIS.height, jsc.getPadYComponent(THIS));
1578
1579			// pad border
1580			p.padB.style.position = 'absolute';
1581			p.padB.style.left = THIS.padding + 'px';
1582			p.padB.style.top = THIS.padding + 'px';
1583			p.padB.style.border = THIS.insetWidth + 'px solid';
1584			p.padB.style.borderColor = THIS.insetColor;
1585
1586			// pad mouse area
1587			p.padM._jscInstance = THIS;
1588			p.padM._jscControlName = 'pad';
1589			p.padM.style.position = 'absolute';
1590			p.padM.style.left = '0';
1591			p.padM.style.top = '0';
1592			p.padM.style.width = (THIS.padding + 2 * THIS.insetWidth + THIS.width + padToSliderPadding / 2) + 'px';
1593			p.padM.style.height = dims[1] + 'px';
1594			p.padM.style.cursor = padCursor;
1595
1596			// pad cross
1597			p.cross.style.position = 'absolute';
1598			p.cross.style.left =
1599			p.cross.style.top =
1600				'0';
1601			p.cross.style.width =
1602			p.cross.style.height =
1603				crossOuterSize + 'px';
1604
1605			// pad cross border Y and X
1606			p.crossBY.style.position =
1607			p.crossBX.style.position =
1608				'absolute';
1609			p.crossBY.style.background =
1610			p.crossBX.style.background =
1611				THIS.pointerBorderColor;
1612			p.crossBY.style.width =
1613			p.crossBX.style.height =
1614				(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px';
1615			p.crossBY.style.height =
1616			p.crossBX.style.width =
1617				crossOuterSize + 'px';
1618			p.crossBY.style.left =
1619			p.crossBX.style.top =
1620				(Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2) - THIS.pointerBorderWidth) + 'px';
1621			p.crossBY.style.top =
1622			p.crossBX.style.left =
1623				'0';
1624
1625			// pad cross line Y and X
1626			p.crossLY.style.position =
1627			p.crossLX.style.position =
1628				'absolute';
1629			p.crossLY.style.background =
1630			p.crossLX.style.background =
1631				THIS.pointerColor;
1632			p.crossLY.style.height =
1633			p.crossLX.style.width =
1634				(crossOuterSize - 2 * THIS.pointerBorderWidth) + 'px';
1635			p.crossLY.style.width =
1636			p.crossLX.style.height =
1637				THIS.pointerThickness + 'px';
1638			p.crossLY.style.left =
1639			p.crossLX.style.top =
1640				(Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2)) + 'px';
1641			p.crossLY.style.top =
1642			p.crossLX.style.left =
1643				THIS.pointerBorderWidth + 'px';
1644
1645			// slider
1646			p.sld.style.overflow = 'hidden';
1647			p.sld.style.width = THIS.sliderSize + 'px';
1648			p.sld.style.height = THIS.height + 'px';
1649
1650			// slider gradient
1651			p.sldGrad.draw(THIS.sliderSize, THIS.height, '#000', '#000');
1652
1653			// slider border
1654			p.sldB.style.display = displaySlider ? 'block' : 'none';
1655			p.sldB.style.position = 'absolute';
1656			p.sldB.style.right = THIS.padding + 'px';
1657			p.sldB.style.top = THIS.padding + 'px';
1658			p.sldB.style.border = THIS.insetWidth + 'px solid';
1659			p.sldB.style.borderColor = THIS.insetColor;
1660
1661			// slider mouse area
1662			p.sldM._jscInstance = THIS;
1663			p.sldM._jscControlName = 'sld';
1664			p.sldM.style.display = displaySlider ? 'block' : 'none';
1665			p.sldM.style.position = 'absolute';
1666			p.sldM.style.right = '0';
1667			p.sldM.style.top = '0';
1668			p.sldM.style.width = (THIS.sliderSize + padToSliderPadding / 2 + THIS.padding + 2 * THIS.insetWidth) + 'px';
1669			p.sldM.style.height = dims[1] + 'px';
1670			p.sldM.style.cursor = 'default';
1671
1672			// slider pointer inner and outer border
1673			p.sldPtrIB.style.border =
1674			p.sldPtrOB.style.border =
1675				THIS.pointerBorderWidth + 'px solid ' + THIS.pointerBorderColor;
1676
1677			// slider pointer outer border
1678			p.sldPtrOB.style.position = 'absolute';
1679			p.sldPtrOB.style.left = -(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px';
1680			p.sldPtrOB.style.top = '0';
1681
1682			// slider pointer middle border
1683			p.sldPtrMB.style.border = THIS.pointerThickness + 'px solid ' + THIS.pointerColor;
1684
1685			// slider pointer spacer
1686			p.sldPtrS.style.width = THIS.sliderSize + 'px';
1687			p.sldPtrS.style.height = sliderPtrSpace + 'px';
1688
1689			// the Close button
1690			function setBtnBorder () {
1691				var insetColors = THIS.insetColor.split(/\s+/);
1692				var outsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1];
1693				p.btn.style.borderColor = outsetColor;
1694			}
1695			p.btn.className = 'jscolor-btn-close';
1696			p.btn.style.display = THIS.closable ? 'block' : 'none';
1697			p.btn.style.position = 'absolute';
1698			p.btn.style.left = THIS.padding + 'px';
1699			p.btn.style.bottom = THIS.padding + 'px';
1700			p.btn.style.padding = '0 15px';
1701			p.btn.style.height = THIS.buttonHeight + 'px';
1702			p.btn.style.border = THIS.insetWidth + 'px solid';
1703			setBtnBorder();
1704			p.btn.style.color = THIS.buttonColor;
1705			p.btn.style.font = '12px sans-serif';
1706			p.btn.style.textAlign = 'center';
1707			try {
1708				p.btn.style.cursor = 'pointer';
1709			} catch(eOldIE) {
1710				p.btn.style.cursor = 'hand';
1711			}
1712			p.btn.onmousedown = function () {
1713				THIS.hide();
1714			};
1715			p.btnT.style.lineHeight = THIS.buttonHeight + 'px';
1716			p.btnT.innerHTML = '';
1717			p.btnT.appendChild(document.createTextNode(THIS.closeText));
1718
1719			// place pointers
1720			redrawPad();
1721			redrawSld();
1722
1723			// If we are changing the owner without first closing the picker,
1724			// make sure to first deal with the old owner
1725			if (jsc.picker.owner && jsc.picker.owner !== THIS) {
1726				jsc.unsetClass(jsc.picker.owner.targetElement, THIS.activeClass);
1727			}
1728
1729			// Set the new picker owner
1730			jsc.picker.owner = THIS;
1731
1732			// The redrawPosition() method needs picker.owner to be set, that's why we call it here,
1733			// after setting the owner
1734			if (jsc.isElementType(container, 'body')) {
1735				jsc.redrawPosition();
1736			} else {
1737				jsc._drawPosition(THIS, 0, 0, 'relative', false);
1738			}
1739
1740			if (p.wrap.parentNode != container) {
1741				container.appendChild(p.wrap);
1742			}
1743
1744			jsc.setClass(THIS.targetElement, THIS.activeClass);
1745		}
1746
1747
1748		function redrawPad () {
1749			// redraw the pad pointer
1750			switch (jsc.getPadYComponent(THIS)) {
1751			case 's': var yComponent = 1; break;
1752			case 'v': var yComponent = 2; break;
1753			}
1754			var x = Math.round((THIS.hsv[0] / 360) * (THIS.width - 1));
1755			var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1));
1756			var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize);
1757			var ofs = -Math.floor(crossOuterSize / 2);
1758			jsc.picker.cross.style.left = (x + ofs) + 'px';
1759			jsc.picker.cross.style.top = (y + ofs) + 'px';
1760
1761			// redraw the slider
1762			switch (jsc.getSliderComponent(THIS)) {
1763			case 's':
1764				var rgb1 = HSV_RGB(THIS.hsv[0], 100, THIS.hsv[2]);
1765				var rgb2 = HSV_RGB(THIS.hsv[0], 0, THIS.hsv[2]);
1766				var color1 = 'rgb(' +
1767					Math.round(rgb1[0]) + ',' +
1768					Math.round(rgb1[1]) + ',' +
1769					Math.round(rgb1[2]) + ')';
1770				var color2 = 'rgb(' +
1771					Math.round(rgb2[0]) + ',' +
1772					Math.round(rgb2[1]) + ',' +
1773					Math.round(rgb2[2]) + ')';
1774				jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2);
1775				break;
1776			case 'v':
1777				var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 100);
1778				var color1 = 'rgb(' +
1779					Math.round(rgb[0]) + ',' +
1780					Math.round(rgb[1]) + ',' +
1781					Math.round(rgb[2]) + ')';
1782				var color2 = '#000';
1783				jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2);
1784				break;
1785			}
1786		}
1787
1788
1789		function redrawSld () {
1790			var sldComponent = jsc.getSliderComponent(THIS);
1791			if (sldComponent) {
1792				// redraw the slider pointer
1793				switch (sldComponent) {
1794				case 's': var yComponent = 1; break;
1795				case 'v': var yComponent = 2; break;
1796				}
1797				var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1));
1798				jsc.picker.sldPtrOB.style.top = (y - (2 * THIS.pointerBorderWidth + THIS.pointerThickness) - Math.floor(sliderPtrSpace / 2)) + 'px';
1799			}
1800		}
1801
1802
1803		function isPickerOwner () {
1804			return jsc.picker && jsc.picker.owner === THIS;
1805		}
1806
1807
1808		function handleValueBlur () {
1809			THIS.importColor();
1810		}
1811
1812
1813		// Find the target element
1814		if (typeof targetElement === 'string') {
1815			var id = targetElement;
1816			var elm = document.getElementById(id);
1817			if (elm) {
1818				this.targetElement = elm;
1819			} else {
1820				jsc.warn('Could not find target element with ID \'' + id + '\'');
1821			}
1822		} else if (targetElement) {
1823			this.targetElement = targetElement;
1824		} else {
1825			jsc.warn('Invalid target element: \'' + targetElement + '\'');
1826		}
1827
1828		if (this.targetElement._jscLinkedInstance) {
1829			jsc.warn('Cannot link jscolor twice to the same element. Skipping.');
1830			return;
1831		}
1832		this.targetElement._jscLinkedInstance = this;
1833
1834		// Find the value element
1835		this.valueElement = jsc.fetchElement(this.valueElement);
1836		// Find the style element
1837		this.styleElement = jsc.fetchElement(this.styleElement);
1838
1839		var THIS = this;
1840		var container =
1841			this.container ?
1842			jsc.fetchElement(this.container) :
1843			document.getElementsByTagName('body')[0];
1844		var sliderPtrSpace = 3; // px
1845
1846		// For BUTTON elements it's important to stop them from sending the form when clicked
1847		// (e.g. in Safari)
1848		if (jsc.isElementType(this.targetElement, 'button')) {
1849			if (this.targetElement.onclick) {
1850				var origCallback = this.targetElement.onclick;
1851				this.targetElement.onclick = function (evt) {
1852					origCallback.call(this, evt);
1853					return false;
1854				};
1855			} else {
1856				this.targetElement.onclick = function () { return false; };
1857			}
1858		}
1859
1860		/*
1861		var elm = this.targetElement;
1862		do {
1863			// If the target element or one of its offsetParents has fixed position,
1864			// then use fixed positioning instead
1865			//
1866			// Note: In Firefox, getComputedStyle returns null in a hidden iframe,
1867			// that's why we need to check if the returned style object is non-empty
1868			var currStyle = jsc.getStyle(elm);
1869			if (currStyle && currStyle.position.toLowerCase() === 'fixed') {
1870				this.fixed = true;
1871			}
1872
1873			if (elm !== this.targetElement) {
1874				// attach onParentScroll so that we can recompute the picker position
1875				// when one of the offsetParents is scrolled
1876				if (!elm._jscEventsAttached) {
1877					jsc.attachEvent(elm, 'scroll', jsc.onParentScroll);
1878					elm._jscEventsAttached = true;
1879				}
1880			}
1881		} while ((elm = elm.offsetParent) && !jsc.isElementType(elm, 'body'));
1882		*/
1883
1884		// valueElement
1885		if (this.valueElement) {
1886			if (jsc.isElementType(this.valueElement, 'input')) {
1887				var handleValueInput = function () {
1888					THIS.fromString(THIS.valueElement.value, jsc.leaveValue);
1889					jsc.dispatchFineChange(THIS);
1890				};
1891				jsc.attachEvent(this.valueElement, 'keyup', handleValueInput);
1892				jsc.attachEvent(this.valueElement, 'input', handleValueInput);
1893				jsc.attachEvent(this.valueElement, 'blur', handleValueBlur);
1894				this.valueElement.setAttribute('autocomplete', 'off');
1895			}
1896		}
1897
1898		// styleElement
1899		if (this.styleElement) {
1900			this.styleElement._jscOrigStyle = {
1901				backgroundImage : this.styleElement.style.backgroundImage,
1902				backgroundColor : this.styleElement.style.backgroundColor,
1903				color : this.styleElement.style.color
1904			};
1905		}
1906
1907		if (this.value) {
1908			// Try to set the color from the .value option and if unsuccessful,
1909			// export the current color
1910			this.fromString(this.value) || this.exportColor();
1911		} else {
1912			this.importColor();
1913		}
1914	}
1915
1916};
1917
1918
1919//================================
1920// Public properties and methods
1921//================================
1922//
1923// These will be publicly available via jscolor.<name> and JSColor.<name>
1924//
1925
1926
1927// Initializes jscolor on current DOM tree
1928jsc.jscolor.init = function () {
1929	if (jsc.jscolor.lookupClass) {
1930		jsc.jscolor.installByClassName(jsc.jscolor.lookupClass);
1931	}
1932};
1933
1934
1935jsc.jscolor.presets = {};
1936
1937jsc.jscolor.presets['default'] = {}; // baseline for customization
1938
1939jsc.jscolor.presets['light'] = { backgroundColor:'#FFFFFF', insetColor:'#BBBBBB' }; // default color scheme
1940jsc.jscolor.presets['dark'] = { backgroundColor:'#333333', insetColor:'#999999' };
1941
1942jsc.jscolor.presets['small'] = { width:101, height:101 };
1943jsc.jscolor.presets['medium'] = { width:181, height:101 }; // default size
1944jsc.jscolor.presets['large'] = { width:271, height:151 };
1945
1946jsc.jscolor.presets['thin'] = { borderWidth:1, insetWidth:1, pointerBorderWidth:1 }; // default thickness
1947jsc.jscolor.presets['thick'] = { borderWidth:2, insetWidth:2, pointerBorderWidth:2 };
1948
1949
1950// DEPRECATED. Use jscolor.presets.default instead.
1951//
1952// Custom default options for all color pickers, e.g. { hash: true, width: 300 }
1953jsc.jscolor.options = {};
1954
1955
1956// DEPRECATED. Use data-jscolor attribute instead, which installs jscolor on given element.
1957//
1958// By default, we'll search for all elements with class="jscolor" and install a color picker on them.
1959//
1960// You can change what class name will be looked for by setting the property jscolor.lookupClass
1961// anywhere in your HTML document. To completely disable the automatic lookup, set it to null.
1962//
1963jsc.jscolor.lookupClass = 'jscolor';
1964
1965
1966// DEPRECATED. Use data-jscolor attribute instead, which installs jscolor on given element.
1967//
1968// Install jscolor on all elements that have the specified class name
1969jsc.jscolor.installByClassName = function (className) {
1970	var inputElms = document.getElementsByTagName('input');
1971	var buttonElms = document.getElementsByTagName('button');
1972
1973	jsc.tryInstallOnElements(inputElms, className);
1974	jsc.tryInstallOnElements(buttonElms, className);
1975};
1976
1977
1978jsc.register();
1979
1980
1981return jsc.jscolor;
1982
1983
1984})(); // END window.jscolor
1985
1986window.JSColor = window.jscolor; // 'JSColor' is an alias to 'jscolor'
1987
1988} // endif

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.