UNPKG

occaecatidicta

Version:
437 lines (350 loc) 13.5 kB
/* * Copyright (C) 2011 Brian Grinstead All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @constructor * @extends {WebInspector.Object} */ WebInspector.Spectrum = function() { this._popover = new WebInspector.Popover(); this._popover.setCanShrink(false); this._popover.element.addEventListener("mousedown", consumeEvent, false); this._containerElement = document.createElement('div'); this._containerElement.className = "spectrum-container"; this._containerElement.tabIndex = 0; this._containerElement.addEventListener("keydown", this._onKeyDown.bind(this), false); var topElement = this._containerElement.createChild("div", "spectrum-top"); topElement.createChild("div", "spectrum-fill"); var topInnerElement = topElement.createChild("div", "spectrum-top-inner fill"); this._draggerElement = topInnerElement.createChild("div", "spectrum-color"); this._dragHelperElement = this._draggerElement.createChild("div", "spectrum-sat fill").createChild("div", "spectrum-val fill").createChild("div", "spectrum-dragger"); this._sliderElement = topInnerElement.createChild("div", "spectrum-hue"); this.slideHelper = this._sliderElement.createChild("div", "spectrum-slider"); var rangeContainer = this._containerElement.createChild("div", "spectrum-range-container"); var alphaLabel = rangeContainer.createChild("label"); alphaLabel.textContent = WebInspector.UIString("\u03B1:"); this._alphaElement = rangeContainer.createChild("input", "spectrum-range"); this._alphaElement.setAttribute("type", "range"); this._alphaElement.setAttribute("min", "0"); this._alphaElement.setAttribute("max", "100"); this._alphaElement.addEventListener("change", alphaDrag.bind(this), false); var swatchElement = document.createElement("span"); swatchElement.className = "swatch"; this._swatchInnerElement = swatchElement.createChild("span", "swatch-inner"); var displayContainer = this._containerElement.createChild("div"); displayContainer.appendChild(swatchElement); this._displayElement = displayContainer.createChild("span", "source-code spectrum-display-value"); WebInspector.Spectrum.draggable(this._sliderElement, hueDrag.bind(this)); WebInspector.Spectrum.draggable(this._draggerElement, colorDrag.bind(this)); function hueDrag(element, dragX, dragY) { this.hsv[0] = (dragY / this.slideHeight); this._onchange(); } function colorDrag(element, dragX, dragY) { this.hsv[1] = dragX / this.dragWidth; this.hsv[2] = (this.dragHeight - dragY) / this.dragHeight; this._onchange(); } function alphaDrag() { this.hsv[3] = this._alphaElement.value / 100; this._onchange(); } this._hideProxy = this.hide.bind(this); }; WebInspector.Spectrum.Events = { ColorChanged: "ColorChanged", Hidden: "Hidden" }; WebInspector.Spectrum.hsvaToRGBA = function(h, s, v, a) { var r, g, b; var i = Math.floor(h * 6); var f = h * 6 - i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); switch(i % 6) { case 0: r = v, g = t, b = p; break; case 1: r = q, g = v, b = p; break; case 2: r = p, g = v, b = t; break; case 3: r = p, g = q, b = v; break; case 4: r = t, g = p, b = v; break; case 5: r = v, g = p, b = q; break; } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a]; }; WebInspector.Spectrum.rgbaToHSVA = function(r, g, b, a) { r = r / 255; g = g / 255; b = b / 255; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var h; var s; var v = max; var d = max - min; s = max ? d / max : 0; if(max === min) { // Achromatic. h = 0; } else { switch(max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return [h, s, v, a]; }; //FIXME: migrate to WebInspector.elementDragStart /** * @param {Function=} onmove * @param {Function=} onstart * @param {Function=} onstop */ WebInspector.Spectrum.draggable = function(element, onmove, onstart, onstop) { var doc = document; var dragging; var offset; var scrollOffset; var maxHeight; var maxWidth; function consume(e) { e.consume(true); } function move(e) { if (dragging) { var dragX = Math.max(0, Math.min(e.pageX - offset.left + scrollOffset.left, maxWidth)); var dragY = Math.max(0, Math.min(e.pageY - offset.top + scrollOffset.top, maxHeight)); if (onmove) onmove(element, dragX, dragY); } } function start(e) { var rightClick = e.which ? (e.which === 3) : (e.button === 2); if (!rightClick && !dragging) { if (onstart) onstart(element, e) dragging = true; maxHeight = element.clientHeight; maxWidth = element.clientWidth; scrollOffset = element.scrollOffset(); offset = element.totalOffset(); doc.addEventListener("selectstart", consume, false); doc.addEventListener("dragstart", consume, false); doc.addEventListener("mousemove", move, false); doc.addEventListener("mouseup", stop, false); move(e); consume(e); } } function stop(e) { if (dragging) { doc.removeEventListener("selectstart", consume, false); doc.removeEventListener("dragstart", consume, false); doc.removeEventListener("mousemove", move, false); doc.removeEventListener("mouseup", stop, false); if (onstop) onstop(element, e); } dragging = false; } element.addEventListener("mousedown", start, false); }; WebInspector.Spectrum.prototype = { set color(color) { var rgba = (color.rgba || color.rgb).slice(0); if (rgba.length === 3) rgba[3] = 1; this.hsv = WebInspector.Spectrum.rgbaToHSVA(rgba[0], rgba[1], rgba[2], rgba[3]); }, get color() { var rgba = WebInspector.Spectrum.hsvaToRGBA(this.hsv[0], this.hsv[1], this.hsv[2], this.hsv[3]); var color; if (rgba[3] === 1) color = WebInspector.Color.fromRGB(rgba[0], rgba[1], rgba[2]); else color = WebInspector.Color.fromRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); var colorValue = color.toString(this.outputColorFormat); if (!colorValue) colorValue = color.toString(); // this.outputColorFormat can be invalid for current color (e.g. "nickname"). return new WebInspector.Color(colorValue); }, get outputColorFormat() { var cf = WebInspector.StylesSidebarPane.ColorFormat; var format = this._originalFormat; if (this.hsv[3] === 1) { // Simplify transparent formats. if (format === cf.RGBA) format = cf.RGB; else if (format === cf.HSLA) format = cf.HSL; } else { // Everything except HSL(A) should be returned as RGBA if transparency is involved. if (format === cf.HSL || format === cf.HSLA) format = cf.HSLA; else format = cf.RGBA; } return format; }, get colorHueOnly() { var rgba = WebInspector.Spectrum.hsvaToRGBA(this.hsv[0], 1, 1, 1); return WebInspector.Color.fromRGBA(rgba[0], rgba[1], rgba[2], rgba[3]); }, set displayText(text) { this._displayElement.textContent = text; }, get visible() { return this._popover.visible; }, _onchange: function() { this._updateUI(); this.dispatchEventToListeners(WebInspector.Spectrum.Events.ColorChanged, this.color); }, _updateHelperLocations: function() { var h = this.hsv[0]; var s = this.hsv[1]; var v = this.hsv[2]; // Where to show the little circle that displays your current selected color. var dragX = s * this.dragWidth; var dragY = this.dragHeight - (v * this.dragHeight); dragX = Math.max(-this._dragHelperElementHeight, Math.min(this.dragWidth - this._dragHelperElementHeight, dragX - this._dragHelperElementHeight)); dragY = Math.max(-this._dragHelperElementHeight, Math.min(this.dragHeight - this._dragHelperElementHeight, dragY - this._dragHelperElementHeight)); this._dragHelperElement.positionAt(dragX, dragY); // Where to show the bar that displays your current selected hue. var slideY = (h * this.slideHeight) - this.slideHelperHeight; this.slideHelper.style.top = slideY + "px"; this._alphaElement.value = this.hsv[3] * 100; }, _updateUI: function() { this._updateHelperLocations(); var rgb = (this.color.rgba || this.color.rgb).slice(0); if (rgb.length === 3) rgb[3] = 1; var rgbHueOnly = this.colorHueOnly.rgb; var flatColor = "rgb(" + rgbHueOnly[0] + ", " + rgbHueOnly[1] + ", " + rgbHueOnly[2] + ")"; var fullColor = "rgba(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ", " + rgb[3] + ")"; this._draggerElement.style.backgroundColor = flatColor; this._swatchInnerElement.style.backgroundColor = fullColor; this._alphaElement.value = this.hsv[3] * 100; }, toggle: function(element, color, format) { if (this.visible) this.hide(); else this.show(element, color, format); return this.visible; }, show: function(element, color, format) { if (this.visible) { if (this.anchorElement === element) return false; // Reopen the picker for another anchor element. this.hide(); } this.reposition(element); this.anchorElement = element; document.addEventListener("mousedown", this._hideProxy, false); window.addEventListener("blur", this._hideProxy, false); this.slideHeight = this._sliderElement.offsetHeight; this.dragWidth = this._draggerElement.offsetWidth; this.dragHeight = this._draggerElement.offsetHeight; this._dragHelperElementHeight = this._dragHelperElement.offsetHeight / 2; this.slideHelperHeight = this.slideHelper.offsetHeight / 2; this.color = color; this._originalFormat = format || color.format; this._updateUI(); return true; }, reposition: function(element) { if (!this._previousFocusElement) this._previousFocusElement = WebInspector.currentFocusElement(); this._popover.show(this._containerElement, element); WebInspector.setCurrentFocusElement(this._containerElement); }, hide: function() { this._popover.hide(); document.removeEventListener("mousedown", this._hideProxy, false); window.removeEventListener("blur", this._hideProxy, false); this.dispatchEventToListeners(WebInspector.Spectrum.Events.Hidden); WebInspector.setCurrentFocusElement(this._previousFocusElement); delete this._previousFocusElement; delete this.anchorElement; }, _onKeyDown: function(event) { if (event.keyIdentifier === "Enter" || event.keyIdentifier === "U+001B") { // Escape key this.hide(); event.consume(true); } } } WebInspector.Spectrum.prototype.__proto__ = WebInspector.Object.prototype;