1/** 2 * jscolor, JavaScript Color Picker 3 * 4 * @version 1.4.1 5 * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html 6 * @author Jan Odvarko, http://odvarko.cz 7 * @created 2008-06-15 8 * @updated 2013-04-08 9 * @link http://jscolor.com 10 */ 11 12 13var jscolor = { 14 15 16 dir : '', // location of jscolor directory (leave empty to autodetect) 17 bindClass : 'color', // class name 18 binding : true, // automatic binding via <input class="..."> 19 preloading : true, // use image preloading? 20 21 22 install : function() { 23 jscolor.addEvent(window, 'load', jscolor.init); 24 }, 25 26 27 init : function() { 28 if(jscolor.binding) { 29 jscolor.bind(); 30 } 31 if(jscolor.preloading) { 32 jscolor.preload(); 33 } 34 }, 35 36 37 getDir : function() { 38 if(!jscolor.dir) { 39 var detected = jscolor.detectDir(); 40 jscolor.dir = detected!==false ? detected : 'jscolor/'; 41 } 42 return jscolor.dir; 43 }, 44 45 46 detectDir : function() { 47 var base = location.href; 48 49 var e = document.getElementsByTagName('base'); 50 for(var i=0; i<e.length; i+=1) { 51 if(e[i].href) { base = e[i].href; } 52 } 53 54 var e = document.getElementsByTagName('script'); 55 for(var i=0; i<e.length; i+=1) { 56 if(e[i].src && /(^|\/)jscolor\.js([?#].*)?$/i.test(e[i].src)) { 57 var src = new jscolor.URI(e[i].src); 58 var srcAbs = src.toAbsolute(base); 59 srcAbs.path = srcAbs.path.replace(/[^\/]+$/, ''); // remove filename 60 srcAbs.query = null; 61 srcAbs.fragment = null; 62 return srcAbs.toString(); 63 } 64 } 65 return false; 66 }, 67 68 69 bind : function() { 70 var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')\\s*(\\{[^}]*\\})?', 'i'); 71 var e = document.getElementsByTagName('input'); 72 for(var i=0; i<e.length; i+=1) { 73 var m; 74 if(!e[i].color && e[i].className && (m = e[i].className.match(matchClass))) { 75 var prop = {}; 76 if(m[3]) { 77 try { 78 prop = (new Function ('return (' + m[3] + ')'))(); 79 } catch(eInvalidProp) {} 80 } 81 e[i].color = new jscolor.color(e[i], prop); 82 } 83 } 84 }, 85 86 87 preload : function() { 88 for(var fn in jscolor.imgRequire) { 89 if(jscolor.imgRequire.hasOwnProperty(fn)) { 90 jscolor.loadImage(fn); 91 } 92 } 93 }, 94 95 96 images : { 97 pad : [ 181, 101 ], 98 sld : [ 16, 101 ], 99 cross : [ 15, 15 ], 100 arrow : [ 7, 11 ] 101 }, 102 103 104 imgRequire : {}, 105 imgLoaded : {}, 106 107 108 requireImage : function(filename) { 109 jscolor.imgRequire[filename] = true; 110 }, 111 112 113 loadImage : function(filename) { 114 if(!jscolor.imgLoaded[filename]) { 115 jscolor.imgLoaded[filename] = new Image(); 116 jscolor.imgLoaded[filename].src = jscolor.getDir()+filename; 117 } 118 }, 119 120 121 fetchElement : function(mixed) { 122 return typeof mixed === 'string' ? document.getElementById(mixed) : mixed; 123 }, 124 125 126 addEvent : function(el, evnt, func) { 127 if(el.addEventListener) { 128 el.addEventListener(evnt, func, false); 129 } else if(el.attachEvent) { 130 el.attachEvent('on'+evnt, func); 131 } 132 }, 133 134 135 fireEvent : function(el, evnt) { 136 if(!el) { 137 return; 138 } 139 if(document.createEvent) { 140 var ev = document.createEvent('HTMLEvents'); 141 ev.initEvent(evnt, true, true); 142 el.dispatchEvent(ev); 143 } else if(document.createEventObject) { 144 var ev = document.createEventObject(); 145 el.fireEvent('on'+evnt, ev); 146 } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5) 147 el['on'+evnt](); 148 } 149 }, 150 151 152 getElementPos : function(e) { 153 var e1=e, e2=e; 154 var x=0, y=0; 155 if(e1.offsetParent) { 156 do { 157 x += e1.offsetLeft; 158 y += e1.offsetTop; 159 } while(e1 = e1.offsetParent); 160 } 161 while((e2 = e2.parentNode) && e2.nodeName.toUpperCase() !== 'BODY') { 162 x -= e2.scrollLeft; 163 y -= e2.scrollTop; 164 } 165 return [x, y]; 166 }, 167 168 169 getElementSize : function(e) { 170 return [e.offsetWidth, e.offsetHeight]; 171 }, 172 173 174 getRelMousePos : function(e) { 175 var x = 0, y = 0; 176 if (!e) { e = window.event; } 177 if (typeof e.offsetX === 'number') { 178 x = e.offsetX; 179 y = e.offsetY; 180 } else if (typeof e.layerX === 'number') { 181 x = e.layerX; 182 y = e.layerY; 183 } 184 return { x: x, y: y }; 185 }, 186 187 188 getViewPos : function() { 189 if(typeof window.pageYOffset === 'number') { 190 return [window.pageXOffset, window.pageYOffset]; 191 } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) { 192 return [document.body.scrollLeft, document.body.scrollTop]; 193 } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) { 194 return [document.documentElement.scrollLeft, document.documentElement.scrollTop]; 195 } else { 196 return [0, 0]; 197 } 198 }, 199 200 201 getViewSize : function() { 202 if(typeof window.innerWidth === 'number') { 203 return [window.innerWidth, window.innerHeight]; 204 } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) { 205 return [document.body.clientWidth, document.body.clientHeight]; 206 } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { 207 return [document.documentElement.clientWidth, document.documentElement.clientHeight]; 208 } else { 209 return [0, 0]; 210 } 211 }, 212 213 214 URI : function(uri) { // See RFC3986 215 216 this.scheme = null; 217 this.authority = null; 218 this.path = ''; 219 this.query = null; 220 this.fragment = null; 221 222 this.parse = function(uri) { 223 var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/); 224 this.scheme = m[3] ? m[2] : null; 225 this.authority = m[5] ? m[6] : null; 226 this.path = m[7]; 227 this.query = m[9] ? m[10] : null; 228 this.fragment = m[12] ? m[13] : null; 229 return this; 230 }; 231 232 this.toString = function() { 233 var result = ''; 234 if(this.scheme !== null) { result = result + this.scheme + ':'; } 235 if(this.authority !== null) { result = result + '//' + this.authority; } 236 if(this.path !== null) { result = result + this.path; } 237 if(this.query !== null) { result = result + '?' + this.query; } 238 if(this.fragment !== null) { result = result + '#' + this.fragment; } 239 return result; 240 }; 241 242 this.toAbsolute = function(base) { 243 var base = new jscolor.URI(base); 244 var r = this; 245 var t = new jscolor.URI; 246 247 if(base.scheme === null) { return false; } 248 249 if(r.scheme !== null && r.scheme.toLowerCase() === base.scheme.toLowerCase()) { 250 r.scheme = null; 251 } 252 253 if(r.scheme !== null) { 254 t.scheme = r.scheme; 255 t.authority = r.authority; 256 t.path = removeDotSegments(r.path); 257 t.query = r.query; 258 } else { 259 if(r.authority !== null) { 260 t.authority = r.authority; 261 t.path = removeDotSegments(r.path); 262 t.query = r.query; 263 } else { 264 if(r.path === '') { 265 t.path = base.path; 266 if(r.query !== null) { 267 t.query = r.query; 268 } else { 269 t.query = base.query; 270 } 271 } else { 272 if(r.path.substr(0,1) === '/') { 273 t.path = removeDotSegments(r.path); 274 } else { 275 if(base.authority !== null && base.path === '') { 276 t.path = '/'+r.path; 277 } else { 278 t.path = base.path.replace(/[^\/]+$/,'')+r.path; 279 } 280 t.path = removeDotSegments(t.path); 281 } 282 t.query = r.query; 283 } 284 t.authority = base.authority; 285 } 286 t.scheme = base.scheme; 287 } 288 t.fragment = r.fragment; 289 290 return t; 291 }; 292 293 function removeDotSegments(path) { 294 var out = ''; 295 while(path) { 296 if(path.substr(0,3)==='../' || path.substr(0,2)==='./') { 297 path = path.replace(/^\.+/,'').substr(1); 298 } else if(path.substr(0,3)==='/./' || path==='/.') { 299 path = '/'+path.substr(3); 300 } else if(path.substr(0,4)==='/../' || path==='/..') { 301 path = '/'+path.substr(4); 302 out = out.replace(/\/?[^\/]*$/, ''); 303 } else if(path==='.' || path==='..') { 304 path = ''; 305 } else { 306 var rm = path.match(/^\/?[^\/]*/)[0]; 307 path = path.substr(rm.length); 308 out = out + rm; 309 } 310 } 311 return out; 312 } 313 314 if(uri) { 315 this.parse(uri); 316 } 317 318 }, 319 320 321 // 322 // Usage example: 323 // var myColor = new jscolor.color(myInputElement) 324 // 325 326 color : function(target, prop) { 327 328 329 this.required = true; // refuse empty values? 330 this.adjust = true; // adjust value to uniform notation? 331 this.hash = false; // prefix color with # symbol? 332 this.caps = true; // uppercase? 333 this.slider = true; // show the value/saturation slider? 334 this.valueElement = target; // value holder 335 this.styleElement = target; // where to reflect current color 336 this.onImmediateChange = null;
336 // onchange callback (can be either string or function) 337 this.hsv = [0, 0, 1]; // read-only 0-6, 0-1, 0-1 338 this.rgb = [1, 1, 1]; // read-only 0-1, 0-1, 0-1 339 this.minH = 0; // read-only 0-6 340 this.maxH = 6; // read-only 0-6 341 this.minS = 0; // read-only 0-1 342 this.maxS = 1; // read-only 0-1 343 this.minV = 0; // read-only 0-1 344 this.maxV = 1; // read-only 0-1 345 346 this.pickerOnfocus = true; // display picker on focus? 347 this.pickerMode = 'HSV'; // HSV | HVS 348 this.pickerPosition = 'bottom'; // left | right | top | bottom 349 this.pickerSmartPosition = true; // automatically adjust picker position when necessary 350 this.pickerButtonHeight = 20; // px 351 this.pickerClosable = false; 352 this.pickerCloseText = 'Close'; 353 this.pickerButtonColor = 'ButtonText'; // px 354 this.pickerFace = 10; // px 355 this.pickerFaceColor = 'ThreeDFace'; // CSS color 356 this.pickerBorder = 1; // px 357 this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight'; // CSS color 358 this.pickerInset = 1; // px 359 this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow'; // CSS color 360 this.pickerZIndex = 10000; 361 362 363 for(var p in prop) { 364 if(prop.hasOwnProperty(p)) { 365 this[p] = prop[p]; 366 } 367 } 368 369 370 this.hidePicker = function() { 371 if(isPickerOwner()) { 372 removePicker(); 373 } 374 }; 375 376 377 this.showPicker = function() { 378 if(!isPickerOwner()) { 379 var tp = jscolor.getElementPos(target); // target pos 380 var ts = jscolor.getElementSize(target); // target size 381 var vp = jscolor.getViewPos(); // view pos 382 var vs = jscolor.getViewSize(); // view size 383 var ps = getPickerDims(this); // picker size 384 var a, b, c; 385 switch(this.pickerPosition.toLowerCase()) { 386 case 'left': a=1; b=0; c=-1; break; 387 case 'right':a=1; b=0; c=1; break; 388 case 'top': a=0; b=1; c=-1; break; 389 default: a=0; b=1; c=1; break; 390 } 391 var l = (ts[b]+ps[b])/2; 392 393 // picker pos 394 if (!this.pickerSmartPosition) { 395 var pp = [ 396 tp[a], 397 tp[b]+ts[b]-l+l*c 398 ]; 399 } else { 400 var pp = [ 401 -vp[a]+tp[a]+ps[a] > vs[a] ? 402 (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : 403 tp[a], 404 -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ? 405 (-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) : 406 (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c) 407 ]; 408 } 409 drawPicker(pp[a], pp[b]); 410 } 411 }; 412 413 414 this.importColor = function() { 415 if(!valueElement) { 416 this.exportColor(); 417 } else { 418 if(!this.adjust) { 419 if(!this.fromString(valueElement.value, leaveValue)) { 420 styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; 421 styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; 422 styleElement.style.color = styleElement.jscStyle.color; 423 this.exportColor(leaveValue | leaveStyle); 424 } 425 } else if(!this.required && /^\s*$/.test(valueElement.value)) { 426 valueElement.value = ''; 427 styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage; 428 styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor; 429 styleElement.style.color = styleElement.jscStyle.color; 430 this.exportColor(leaveValue | leaveStyle); 431 432 } else if(this.fromString(valueElement.value)) { 433 // OK 434 } else { 435 this.exportColor(); 436 } 437 } 438 }; 439 440 441 this.exportColor = function(flags) { 442 if(!(flags & leaveValue) && valueElement) { 443 var value = this.toString(); 444 if(this.caps) { value = value.toUpperCase(); } 445 if(this.hash) { value = '#'+value; } 446 valueElement.value = value; 447 } 448 if(!(flags & leaveStyle) && styleElement) { 449 styleElement.style.backgroundImage = "none"; 450 styleElement.style.backgroundColor = 451 '#'+this.toString(); 452 styleElement.style.color = 453 0.213 * this.rgb[0] + 454 0.715 * this.rgb[1] + 455 0.072 * this.rgb[2] 456 < 0.5 ? '#FFF' : '#000'; 457 } 458 if(!(flags & leavePad) && isPickerOwner()) { 459 redrawPad(); 460 } 461 if(!(flags & leaveSld) && isPickerOwner()) { 462 redrawSld(); 463 } 464 }; 465 466 467 this.fromHSV = function(h, s, v, flags) { // null = don't change 468 if(h !== null) { h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h)); } 469 if(s !== null) { s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s)); } 470 if(v !== null) { v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v)); } 471 472 this.rgb = HSV_RGB( 473 h===null ? this.hsv[0] : (this.hsv[0]=h), 474 s===null ? this.hsv[1] : (this.hsv[1]=s), 475 v===null ? this.hsv[2] : (this.hsv[2]=v) 476 ); 477 478 this.exportColor(flags); 479 }; 480 481 482 this.fromRGB = function(r, g, b, flags) { // null = don't change 483 if(r !== null) { r = Math.max(0.0, Math.min(1.0, r)); } 484 if(g !== null) { g = Math.max(0.0, Math.min(1.0, g)); } 485 if(b !== null) { b = Math.max(0.0, Math.min(1.0, b)); } 486 487 var hsv = RGB_HSV( 488 r===null ? this.rgb[0] : r, 489 g===null ? this.rgb[1] : g, 490 b===null ? this.rgb[2] : b 491 ); 492 if(hsv[0] !== null) { 493 this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0])); 494 } 495 if(hsv[2] !== 0) { 496 this.hsv[1] = hsv[1]===null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1])); 497 } 498 this.hsv[2] = hsv[2]===null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2])); 499 500 // update RGB according to final HSV, as some values might be trimmed 501 var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]); 502 this.rgb[0] = rgb[0]; 503 this.rgb[1] = rgb[1]; 504 this.rgb[2] = rgb[2]; 505 506 this.exportColor(flags); 507 }; 508 509 510 this.fromString = function(hex, flags) { 511 var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i); 512 if(!m) { 513 return false; 514 } else { 515 if(m[1].length === 6) { // 6-char notation 516 this.fromRGB(
517 parseInt(m[1].substr(0,2),16) / 255, 518 parseInt(m[1].substr(2,2),16) / 255, 519 parseInt(m[1].substr(4,2),16) / 255, 520 flags 521 ); 522 } else { // 3-char notation 523 this.fromRGB( 524 parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255, 525 parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255, 526 parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255, 527 flags 528 ); 529 } 530 return true; 531 } 532 }; 533 534 535 this.toString = function() { 536 return ( 537 (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) + 538 (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) + 539 (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1) 540 ); 541 }; 542 543 544 function RGB_HSV(r, g, b) { 545 var n = Math.min(Math.min(r,g),b); 546 var v = Math.max(Math.max(r,g),b); 547 var m = v - n; 548 if(m === 0) { return [ null, 0, v ]; } 549 var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m); 550 return [ h===6?0:h, m/v, v ]; 551 } 552 553 554 function HSV_RGB(h, s, v) { 555 if(h === null) { return [ v, v, v ]; } 556 var i = Math.floor(h); 557 var f = i%2 ? h-i : 1-(h-i); 558 var m = v * (1 - s); 559 var n = v * (1 - s*f); 560 switch(i) { 561 case 6: 562 case 0: return [v,n,m]; 563 case 1: return [n,v,m]; 564 case 2: return [m,v,n]; 565 case 3: return [m,n,v]; 566 case 4: return [n,m,v]; 567 case 5: return [v,m,n]; 568 } 569 } 570 571 572 function removePicker() { 573 delete jscolor.picker.owner; 574 document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB); 575 } 576 577 578 function drawPicker(x, y) { 579 if(!jscolor.picker) { 580 jscolor.picker = { 581 box : document.createElement('div'), 582 boxB : document.createElement('div'), 583 pad : document.createElement('div'), 584 padB : document.createElement('div'), 585 padM : document.createElement('div'), 586 sld : document.createElement('div'), 587 sldB : document.createElement('div'), 588 sldM : document.createElement('div'), 589 btn : document.createElement('div'), 590 btnS : document.createElement('span'), 591 btnT : document.createTextNode(THIS.pickerCloseText) 592 }; 593 for(var i=0,segSize=4; i<jscolor.images.sld[1]; i+=segSize) { 594 var seg = document.createElement('div'); 595 seg.style.height = segSize+'px'; 596 seg.style.fontSize = '1px'; 597 seg.style.lineHeight = '0'; 598 jscolor.picker.sld.appendChild(seg); 599 } 600 jscolor.picker.sldB.appendChild(jscolor.picker.sld); 601 jscolor.picker.box.appendChild(jscolor.picker.sldB); 602 jscolor.picker.box.appendChild(jscolor.picker.sldM); 603 jscolor.picker.padB.appendChild(jscolor.picker.pad); 604 jscolor.picker.box.appendChild(jscolor.picker.padB); 605 jscolor.picker.box.appendChild(jscolor.picker.padM); 606 jscolor.picker.btnS.appendChild(jscolor.picker.btnT); 607 jscolor.picker.btn.appendChild(jscolor.picker.btnS); 608 jscolor.picker.box.appendChild(jscolor.picker.btn); 609 jscolor.picker.boxB.appendChild(jscolor.picker.box); 610 } 611 612 var p = jscolor.picker; 613 614 // controls interaction 615 p.box.onmouseup = 616 p.box.onmouseout = function() { target.focus(); }; 617 p.box.onmousedown = function() { abortBlur=true; }; 618 p.box.onmousemove = function(e) { 619 if (holdPad || holdSld) { 620 holdPad && setPad(e); 621 holdSld && setSld(e); 622 if (document.selection) { 623 document.selection.empty(); 624 } else if (window.getSelection) { 625 window.getSelection().removeAllRanges(); 626 } 627 dispatchImmediateChange(); 628 } 629 }; 630 if('ontouchstart' in window) { // if touch device 631 p.box.addEventListener('touchmove', function(e) { 632 var event={ 633 'offsetX': e.touches[0].pageX-touchOffset.X, 634 'offsetY': e.touches[0].pageY-touchOffset.Y 635 }; 636 if (holdPad || holdSld) { 637 holdPad && setPad(event); 638 holdSld && setSld(event); 639 dispatchImmediateChange(); 640 } 641 e.stopPropagation(); // prevent move "view" on broswer 642 e.preventDefault(); // prevent Default - Android Fix (else android generated only 1-2 touchmove events) 643 }, false); 644 } 645 p.padM.onmouseup = 646 p.padM.onmouseout = function() { if(holdPad) { holdPad=false; jscolor.fireEvent(valueElement,'change'); } }; 647 p.padM.onmousedown = function(e) { 648 // if the slider is at the bottom, move it up 649 switch(modeID) { 650 case 0: if (THIS.hsv[2] === 0) { THIS.fromHSV(null, null, 1.0); }; break; 651 case 1: if (THIS.hsv[1] === 0) { THIS.fromHSV(null, 1.0, null); }; break; 652 } 653 holdSld=false; 654 holdPad=true; 655 setPad(e); 656 dispatchImmediateChange(); 657 }; 658 if('ontouchstart' in window) { 659 p.padM.addEventListener('touchstart', function(e) { 660 touchOffset={ 661 'X': e.target.offsetParent.offsetLeft, 662 'Y': e.target.offsetParent.offsetTop 663 }; 664 this.onmousedown({ 665 'offsetX':e.touches[0].pageX-touchOffset.X, 666 'offsetY':e.touches[0].pageY-touchOffset.Y 667 });
668 }); 669 } 670 p.sldM.onmouseup = 671 p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change'); } }; 672 p.sldM.onmousedown = function(e) { 673 holdPad=false; 674 holdSld=true; 675 setSld(e); 676 dispatchImmediateChange(); 677 }; 678 if('ontouchstart' in window) { 679 p.sldM.addEventListener('touchstart', function(e) { 680 touchOffset={ 681 'X': e.target.offsetParent.offsetLeft, 682 'Y': e.target.offsetParent.offsetTop 683 }; 684 this.onmousedown({ 685 'offsetX':e.touches[0].pageX-touchOffset.X, 686 'offsetY':e.touches[0].pageY-touchOffset.Y 687 }); 688 }); 689 } 690 691 // picker 692 var dims = getPickerDims(THIS); 693 p.box.style.width = dims[0] + 'px'; 694 p.box.style.height = dims[1] + 'px'; 695 696 // picker border 697 p.boxB.style.position = 'absolute'; 698 p.boxB.style.clear = 'both'; 699 p.boxB.style.left = x+'px'; 700 p.boxB.style.top = y+'px'; 701 p.boxB.style.zIndex = THIS.pickerZIndex; 702 p.boxB.style.border = THIS.pickerBorder+'px solid'; 703 p.boxB.style.borderColor = THIS.pickerBorderColor; 704 p.boxB.style.background = THIS.pickerFaceColor; 705 706 // pad image 707 p.pad.style.width = jscolor.images.pad[0]+'px'; 708 p.pad.style.height = jscolor.images.pad[1]+'px'; 709 710 // pad border 711 p.padB.style.position = 'absolute'; 712 p.padB.style.left = THIS.pickerFace+'px'; 713 p.padB.style.top = THIS.pickerFace+'px'; 714 p.padB.style.border = THIS.pickerInset+'px solid'; 715 p.padB.style.borderColor = THIS.pickerInsetColor; 716 717 // pad mouse area 718 p.padM.style.position = 'absolute'; 719 p.padM.style.left = '0'; 720 p.padM.style.top = '0'; 721 p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px'; 722 p.padM.style.height = p.box.style.height; 723 p.padM.style.cursor = 'crosshair'; 724 725 // slider image 726 p.sld.style.overflow = 'hidden'; 727 p.sld.style.width = jscolor.images.sld[0]+'px'; 728 p.sld.style.height = jscolor.images.sld[1]+'px'; 729 730 // slider border 731 p.sldB.style.display = THIS.slider ? 'block' : 'none'; 732 p.sldB.style.position = 'absolute'; 733 p.sldB.style.right = THIS.pickerFace+'px'; 734 p.sldB.style.top = THIS.pickerFace+'px'; 735 p.sldB.style.border = THIS.pickerInset+'px solid'; 736 p.sldB.style.borderColor = THIS.pickerInsetColor; 737 738 // slider mouse area 739 p.sldM.style.display = THIS.slider ? 'block' : 'none'; 740 p.sldM.style.position = 'absolute'; 741 p.sldM.style.right = '0'; 742 p.sldM.style.top = '0'; 743 p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px'; 744 p.sldM.style.height = p.box.style.height; 745 try { 746 p.sldM.style.cursor = 'pointer'; 747 } catch(eOldIE) { 748 p.sldM.style.cursor = 'hand'; 749 } 750 751 // "close" button 752 function setBtnBorder() { 753 var insetColors = THIS.pickerInsetColor.split(/\s+/); 754 var pickerOutsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1]; 755 p.btn.style.borderColor = pickerOutsetColor; 756 } 757 p.btn.style.display = THIS.pickerClosable ? 'block' : 'none'; 758 p.btn.style.position = 'absolute'; 759 p.btn.style.left = THIS.pickerFace + 'px'; 760 p.btn.style.bottom = THIS.pickerFace + 'px'; 761 p.btn.style.padding = '0 15px'; 762 p.btn.style.height = '18px'; 763 p.btn.style.border = THIS.pickerInset + 'px solid'; 764 setBtnBorder(); 765 p.btn.style.color = THIS.pickerButtonColor; 766 p.btn.style.font = '12px sans-serif'; 767 p.btn.style.textAlign = 'center'; 768 try { 769 p.btn.style.cursor = 'pointer'; 770 } catch(eOldIE) { 771 p.btn.style.cursor = 'hand'; 772 } 773 p.btn.onmousedown = function () { 774 THIS.hidePicker(); 775 }; 776 p.btnS.style.lineHeight = p.btn.style.height; 777 778 // load images in optimal order 779 switch(modeID) { 780 case 0: var padImg = 'hs.png'; break; 781 case 1: var padImg = 'hv.png'; break; 782 } 783 p.padM.style.backgroundImage = "url('"+jscolor.getDir()+"cross.gif')"; 784 p.padM.style.backgroundRepeat = "no-repeat"; 785 p.sldM.style.backgroundImage = "url('"+jscolor.getDir()+"arrow.gif')"; 786 p.sldM.style.backgroundRepeat = "no-repeat"; 787 p.pad.style.backgroundImage = "url('"+jscolor.getDir()+padImg+"')"; 788 p.pad.style.backgroundRepeat = "no-repeat"; 789 p.pad.style.backgroundPosition = "0 0"; 790 791 // place pointers 792 redrawPad(); 793 redrawSld(); 794 795 jscolor.picker.owner = THIS; 796 document.getElementsByTagName('body')[0].appendChild(p.boxB); 797 } 798 799 800 function getPickerDims(o) { 801 var dims = [ 802 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[0] + 803 (o.slider ? 2*o.pickerInset + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] : 0), 804 o.pickerClosable ? 805 4*o.pickerInset + 3*o.pickerFace + jscolor.images.pad[1] + o.pickerButtonHeight : 806 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[1] 807 ]; 808 return dims; 809 } 810 811 812 function redrawPad() { 813 // redraw the pad pointer 814 switch(modeID) { 815 case 0: var yComponent = 1; break; 816 case 1: var yComponent = 2; break; 817 } 818 var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1)); 819 var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1)); 820 jscolor.picker.padM.style.backgroundPosition = 821 (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' + 822 (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px'; 823 824 // redraw the slider image 825 var seg = jscolor.picker.sld.childNodes; 826 827 switch(modeID) { 828 case 0: 829 var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1); 830 for(var i=0; i<seg.length; i+=1) { 831 seg[i].style.backgroundColor = 'rgb('+ 832 (rgb[0]*(1-i/seg.length)*100)+'%,'+ 833 (rgb[1]*(1-i/seg.length)*100)+'%,'+ 834 (rgb[2]*(1-i/seg.length)*100)+'%)'; 835 } 836 break; 837 case 1: 838 var rgb, s, c = [ THIS.hsv[2], 0, 0 ]; 839 var i = Math.floor(THIS.hsv[0]); 840 var f = i%2 ? THIS.hsv[0]-i : 1-(THIS.hsv[0]-i); 841 switch(i) { 842 case 6: 843 case 0: rgb=[0,1,2]; break; 844 case 1: rgb=[1,0,2]; break; 845 case 2: rgb=[2,0,1]; break; 846 case 3: rgb=[2,1,0]; break; 847 case 4: rgb=[1,2,0]; break; 848 case 5: rgb=[0,2,1]; break; 849 } 850 for(var i=0; i<seg.length; i+=1) { 851 s = 1 - 1/(seg.length-1)*i; 852 c[1] = c[0] * (1 - s*f); 853 c[2] = c[0] * (1 - s); 854 seg[i].style.backgroundColor = 'rgb('+ 855 (c[rgb[0]]*100)+'%,'+ 856 (c[rgb[1]]*100)+'%,'+ 857 (c[rgb[2]]*100)+'%)'; 858 } 859 break; 860 } 861 } 862 863 864 function redrawSld() { 865 // redraw the slider pointer 866 switch(modeID) { 867 case 0: var yComponent = 2; break; 868 case 1: var yComponent = 1; break; 869 } 870 var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.sld[1]-1)); 871 jscolor.picker.sldM.style.backgroundPosition = 872 '0 ' + (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.arrow[1]/2)) + 'px'; 873 } 874 875 876 function isPickerOwner() { 877 return jscolor.picker && jscolor.picker.owner === THIS; 878 } 879 880 881 function blurTarget() { 882 if(valueElement === target) { 883 THIS.importColor(); 884 } 885 if(THIS.pickerOnfocus) { 886 THIS.hidePicker(); 887 } 888 } 889 890 891 function blurValue() { 892 if(valueElement !== target) { 893 THIS.importColor(); 894 } 895 } 896 897 898 function setPad(e) { 899 var mpos = jscolor.getRelMousePos(e); 900 var x = mpos.x - THIS.pickerFace - THIS.pickerInset; 901 var y = mpos.y - THIS.pickerFace - THIS.pickerInset; 902 switch(modeID) { 903 case 0: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), 1 - y/(jscolor.images.pad[1]-1), null, leaveSld); break; 904 case 1: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), null, 1 - y/(jscolor.images.pad[1]-1), leaveSld); break; 905 } 906 } 907 908 909 function setSld(e) { 910 var mpos = jscolor.getRelMousePos(e); 911 var y = mpos.y - THIS.pickerFace - THIS.pickerInset; 912 switch(modeID) { 913 case 0: THIS.fromHSV(null, null, 1 - y/(jscolor.images.sld[1]-1), leavePad); break; 914 case 1: THIS.fromHSV(null, 1 - y/(jscolor.images.sld[1]-1), null, leavePad); break; 915 } 916 } 917 918 919 function dispatchImmediateChange() { 920 if (THIS.onImmediateChange) { 921 var callback; 922 if (typeof THIS.onImmediateChange === 'string') { 923 callback = new Function (THIS.onImmediateChange); 924 } else { 925 callback = THIS.onImmediateChange; 926 } 927 callback.call(THIS); 928 } 929 } 930 931 932 var THIS = this; 933 var modeID = this.pickerMode.toLowerCase()==='hvs' ? 1 : 0; 934 var abortBlur = false; 935 var 936 valueElement = jscolor.fetchElement(this.valueElement), 937 styleElement = jscolor.fetchElement(this.styleElement); 938 var 939 holdPad = false, 940 holdSld = false, 941 touchOffset = {}; 942 var 943 leaveValue = 1<<0, 944 leaveStyle = 1<<1, 945 leavePad = 1<<2, 946 leaveSld = 1<<3; 947 948 // target 949 jscolor.addEvent(target, 'focus', function() { 950 if(THIS.pickerOnfocus) { THIS.showPicker(); } 951 }); 952 jscolor.addEvent(target, 'blur', function() { 953 if(!abortBlur) { 954 window.setTimeout(function(){ abortBlur || blurTarget(); abortBlur=false; }, 0); 955 } else { 956 abortBlur = false; 957 } 958 }); 959 960 // valueElement 961 if(valueElement) { 962 var updateField = function() { 963 THIS.fromString(valueElement.value, leaveValue); 964 dispatchImmediateChange(); 965 }; 966 jscolor.addEvent(valueElement, 'keyup', updateField); 967 jscolor.addEvent(valueElement, 'input', updateField); 968 jscolor.addEvent(valueElement, 'blur', blurValue); 969 valueElement.setAttribute('autocomplete', 'off'); 970 } 971 972 // styleElement 973 if(styleElement) { 974 styleElement.jscStyle = { 975 backgroundImage : styleElement.style.backgroundImage, 976 backgroundColor : styleElement.style.backgroundColor, 977 color : styleElement.style.color 978 }; 979 } 980 981 // require images 982 switch(modeID) { 983 case 0: jscolor.requireImage('hs.png'); break; 984 case 1: jscolor.requireImage('hv.png'); break; 985 } 986 jscolor.requireImage('cross.gif'); 987 jscolor.requireImage('arrow.gif'); 988 989 this.importColor(); 990 } 991 992}; 993 994 995jscolor.install();
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.