1 /** 2 * @fileoverview 3 * 128 x 128 HSV Picker. 4 * @requires APE.dom, APE.EventPublisher, APE.color.ColorRGB 5 * @author Garrett Smith 6 7 * @namespace APE.widget 8 */ 9 APE.namespace("APE.widget"); 10 11 /** 12 * @constructor 13 */ 14 APE.widget.HsvPicker = function(id) { 15 16 var Draggable = APE.drag.Draggable; 17 this.id = id; 18 19 var hueSelectorEl = document.getElementById(this.id + "-hue-slider"); 20 var bgSelectorEl = document.getElementById(this.id + "-saturation-value-selector"); 21 22 this.hueSlider = Draggable.getByNode(hueSelectorEl, APE.drag.Draggable.constraints.VERT); 23 24 this.hueSlider.keepInContainer = true; 25 26 this.bgSelector = Draggable.getByNode(bgSelectorEl); 27 28 var bg = bgSelectorEl.parentNode.parentNode; 29 bg.onselectstart=function(){return false;}; 30 this.bg = bg; 31 this.bgSelector.container = bg; 32 33 this.bgSelector.keepInContainer = true; 34 35 this.textInput = document.getElementById(this.id + "-color-input"); 36 this.displayStyle = document.getElementById(this.id + "-color-preview").style; 37 38 // TODO: bgSelectorEl.parentNode.offsetTop/2 39 this.bgClipTop = 12/2; 40 this.bgClipLeft = 12/2; 41 42 this.enabled = true; 43 44 this.prevValue = this.textInput.value; 45 }; 46 47 APE.widget.HsvPicker.getById = APE.getById; 48 49 (function(){ 50 51 var HsvPicker = APE.widget.HsvPicker; 52 53 APE.mixin(HsvPicker, { 54 hueSlid : hueSlid, 55 grabHueSlider : grabHueSlider, 56 bgSelectorDrag : bgSelectorDrag, 57 textInputBlur : textInputBlur, 58 checkEnabled : checkEnabled, 59 textInputKeyDown : textInputKeyDown, 60 backgroundMousedown : backgroundMousedown, 61 saveValue : saveValue, 62 transparentClicked : transparentClicked 63 }); 64 65 function hueSlid(e) { 66 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 67 if(!hsvPicker.enabled) return; 68 hsvPicker.onbeforechange(); 69 hsvPicker.h = 360 * hsvPicker.hueSlider.el.offsetTop/128; 70 71 hsvPicker.bg.style.background = hsvPicker.rgbForHue(hsvPicker.h); 72 hsvPicker.updateDisplay(); 73 hsvPicker.onchange(e); 74 } 75 76 function grabHueSlider(e) { 77 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 78 if(!hsvPicker.enabled) return; 79 hsvPicker.hueSlider.grab(e); 80 hsvPicker.updateDisplay(); 81 hsvPicker.onchange(e); 82 hsvPicker.onchangecomplete(e); 83 } 84 85 function textInputBlur(e) { 86 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 87 if(!hsvPicker.enabled) return; 88 return hsvPicker.trySetValue(this.value, e||event); 89 } 90 91 function checkEnabled() { 92 return HsvPicker.getById(this.id.split("-")[0]).enabled; 93 } 94 95 // Must use keyDown for IE. 96 function textInputKeyDown(e) { 97 e = e||window.event; 98 var isTabKey = e.keyCode == 9; 99 var isEnterKey = e.keyCode == 13; 100 if(isTabKey || isEnterKey) { 101 HsvPicker.getById(this.id.split("-")[0]).trySetValue(this.value, e||event); 102 } 103 if(isEnterKey) 104 this.focus(); 105 } 106 107 function backgroundMousedown(e) { 108 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 109 if(!hsvPicker.enabled) return; 110 hsvPicker.onbeforechange(); 111 hsvPicker.bgSelector.grab(e); 112 hsvPicker.bg.style.background = hsvPicker.rgbForHue(hsvPicker.h); 113 hsvPicker.updateDisplay(); 114 hsvPicker.onchange(e); 115 hsvPicker.onchangecomplete(e); 116 } 117 118 function bgSelectorDrag(e) { 119 120 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 121 122 if(!hsvPicker.enabled) return; 123 124 hsvPicker.v = (127 - (this.el.offsetTop + hsvPicker.bgClipTop))/127; 125 hsvPicker.s = (this.el.offsetLeft + hsvPicker.bgClipLeft)/127; 126 //document.title = 'v=' + hsvPicker.v + ", s=" + hsvPicker.s; 127 hsvPicker.updateDisplay(); 128 hsvPicker.onchange(e); 129 } 130 131 function saveValue() { 132 if(this.textInput.value) 133 this.prevValue = this.textInput.value; 134 } 135 136 function transparentClicked(e) { 137 var hsvPicker = HsvPicker.getById(this.id.split("-")[0]); 138 hsvPicker.onbeforechange(); 139 if(this.checked) { 140 hsvPicker.prevValue = hsvPicker.textInput.value; 141 hsvPicker.setEnabled(false); 142 hsvPicker.setValue("transparent"); 143 } 144 else { 145 hsvPicker.setValue(hsvPicker.prevValue||new APE.color.ColorRGB(255,255,255).toString()); 146 hsvPicker.prevValue = ""; 147 hsvPicker.setEnabled(true); 148 149 // We have to update the position of the hueSlider and 150 // bgSelector, so we just feign ondrag by direct invocation. 151 // This seems potentially dangerous. 152 hsvPicker.hueSlider.ondrag(e); 153 hsvPicker.bgSelector.ondrag(e); 154 } 155 hsvPicker.onchange(e); 156 hsvPicker.onchangecomplete(e); 157 } 158 159 })(); 160 161 APE.widget.HsvPicker.prototype = { 162 163 rgbForHue : APE.color.ColorHSV.rgbForHue, 164 rgbFromString : APE.color.ColorRGB.fromString, 165 166 init : function() { 167 if(this.textInput.value) 168 this.setValue(this.textInput.value); 169 else 170 this.setValue("#ff0000"); 171 172 var HsvPicker = APE.widget.HsvPicker; 173 174 this.bgSelector.onbeforedragstart = HsvPicker.bgSelectorDrag; 175 this.bgSelector.ondrag = HsvPicker.bgSelectorDrag; 176 this.bgSelector.onglide = HsvPicker.bgSelectorDrag; 177 this.hueSlider.onbeforedragstart = HsvPicker.hueSlid; 178 this.hueSlider.ondrag = HsvPicker.hueSlid; 179 this.hueSlider.onglide = HsvPicker.hueSlid; 180 this.hueSlider.container.onmousedown = HsvPicker.grabHueSlider; 181 this.bgSelector.onglide = HsvPicker.bgSelectorDrag; 182 183 this.bgSelector.onfocus = HsvPicker.checkEnabled; 184 this.hueSlider.onfocus = HsvPicker.checkEnabled; 185 186 var EventPublisher = APE.EventPublisher; 187 188 EventPublisher.add(this.textInput, "onblur", HsvPicker.textInputBlur); 189 EventPublisher.add(this, "onbeforechange", HsvPicker.saveValue); 190 EventPublisher.add(this.bgSelector.el.parentNode, "onmousedown", HsvPicker.backgroundMousedown); 191 EventPublisher.add(this.bgSelector, "ondragend", function(e) { this.onchangecomplete(e); }, this); 192 EventPublisher.add(this.hueSlider, "ondragend", function(e) { this.onchangecomplete(e); }, this); 193 194 var tpCheckbox = document.getElementById(this.id + "-transparent-checkbox"); 195 EventPublisher.add(tpCheckbox, "onclick", HsvPicker.transparentClicked); 196 197 // This handles initialization when transparent checkbox is checked at load time. 198 if(tpCheckbox.checked) 199 HsvPicker.transparentClicked.call(document.getElementById(this.id + "-transparent-checkbox")); 200 }, 201 202 getHexValue : function() { 203 if(this.textInput.value == "") return ""; 204 return new APE.color.ColorHSV(this.h, this.s, this.v).toRGB().toHexString(); 205 }, 206 207 /**@event*/ 208 onbeforechange : function() { }, 209 /**@event*/ 210 onchange : function(e) { }, 211 /**@event*/ 212 onchangecomplete : function(e) { }, 213 214 setEnabled : function(bEnable) { 215 this.enabled = bEnable; 216 }, 217 218 setValue : function(hexOrRGB) { 219 220 if(hexOrRGB == "transparent") { 221 this.displayStyle.background = "transparent"; 222 this.hueSlider.el.parentNode.style.background = "transparent"; 223 this.bgSelector.el.parentNode.style.visibility = "hidden"; 224 this.bgSelector.el.parentNode.previousSibling.style.visibility = "inherit"; 225 this.setEnabled(false); 226 this.bg.style.backgroundColor = "transparent"; 227 this.textInput.value = ""; 228 document.getElementById(this.id + "-transparent-checkbox").checked = true; 229 return; 230 } 231 else { 232 this.displayStyle.background = "transparent"; 233 // this kills the background image in IE7. 234 // this.hueSlider.el.parentNode.style.background = ""; 235 this.bgSelector.el.parentNode.style.visibility = "inherit"; 236 this.bgSelector.el.parentNode.previousSibling.style.visibility = "hidden"; 237 this.setEnabled(true); 238 document.getElementById(this.id + "-transparent-checkbox").checked = false; 239 } 240 241 var rgb = this.rgbFromString(hexOrRGB); 242 var isInputValid = rgb.isValid(); 243 if(!isInputValid) { 244 rgb = this.rgbForHue(this.h = 0, this.s = 1, this.v = 1); 245 } 246 247 var hsv = rgb.toHSV(); 248 this.h = hsv.h; 249 this.s = hsv.s; 250 this.v = hsv.v; 251 252 this.hueSlider.el.style.top = (hsv.h/360*128) + "px"; 253 this.bgSelector.moveToX( (hsv.s * 127) - this.bgClipLeft); 254 this.bgSelector.moveToY( 127 - (hsv.v * 127) - this.bgClipTop ); 255 this.bg.style.backgroundColor = this.rgbForHue(hsv.h, 1, 1).toHexString(); 256 this.updateDisplay(rgb, isInputValid); 257 }, 258 259 updateDisplay : function(rgb, isInputValid) { 260 var color = rgb||new APE.color.ColorHSV(this.h, this.s, this.v).toRGB(); 261 if(color.isValid() && !(isInputValid == false)) 262 this.displayStyle.backgroundColor = this.textInput.value = color.toHexString(); 263 else 264 this.textInput.value = ""; 265 }, 266 267 trySetValue : function( value, e) { 268 if(this.rgbFromString(value).isValid()) { 269 this.setValue(value); 270 this.onchange(e); 271 this.onchangecomplete(e); 272 return true; 273 } 274 else { 275 alert("Please enter a valid color value."); 276 return false; 277 } 278 } 279 };