var ColorInput = Class.create(JSControl, { initialize: function($super, element, params){ $super(element); this.mode_ = this.element.getAttribute("mode"); this.currentValueDisplay = Element.down(this.element, this.mode === "compact" ? "span.Color" : "td.CurrentValue span"); this.params_ = params || {}; if (this.mode_ === "compact"){ this.input_ = this.element; Event.observe(this.input_, "change", this.change.bindAsEventListener(this)); this.display_ = params ? params.display : null; this.button_ = params ? params.button : null; if (params && params.button && params.attrs){ var awnd = AControl.GetParentWindow(this.element); this.opener_ = new SIPopupOpener(params.button, { "html": function(){ var types = []; if (awnd) types = AXML.SelectNodes(awnd.XML().documentElement, "st:types[@from]", {"st": STURI}).invoke("getAttribute", "from"); return JSControl.TransformElementAndUnwrap(params.attrs, types); }, "tablimit": 16, "align-id": this.display_ ? this.display_.getAttribute("id") : this.ID() }); SubscribeOnEvent("CHANGE", "document", this.onCHANGE, this); Event.observe(params.button, "SI:SHOW", function(event){ if (event.memo != this.opener_) return; var elem = document.getElementById(this.widgetID()); if (elem && elem.JSControl) elem.JSControl.SetValue(this.Value()); }.bindAsEventListener(this)); } }else{ this.jscontrols = Element.descendants(this.element).findAll(function(element){ return element.JSControl; }); this.spinners = {}; ["R", "G", "B", "H", "S", "V"].each(function(component_type){ this.spinners[component_type] = Element.down(this.element, "#" + this.ID() + "-" + component_type).JSControl; }, this); this.spinners_rgb = ["R", "G", "B"].collect(this.getSpinner, this); this.spinners_hsv = ["H", "S", "V"].collect(this.getSpinner, this); this.htmlvalue_input = document.getElementById(this.ID() + "-HTMLValue").JSControl; var awindow = AControl.GetParentWindow(this.ID()); if (awindow) awindow.Subscribe("CHANGE", this.onCHANGE, this); else SubscribeOnEvent("CHANGE", "document", this.onCHANGE, this) } var vis = this.element.getAttribute("visibility") || ""; if (ColorInput.visibility_modes.indexOf(vis) == -1) vis = "yes"; this.SetAttribute("visibility", vis); }, change: function(event){ if (this.display_ && this.input_) Element.setStyle(this.display_, {"backgroundColor": this.css_color(this.input_.value)}); this.onchange(); }, getSpinner: function(key){ return this.spinners[key]; }, setValueAndCallOnchange: function(color){ if (this.setValue(color)) this.onchange(); }, getSpinnerValues: function(spinners){ return spinners.invoke("Value").invoke("Value").collect(function(num){ return Number(num || 0); }); }, widgetID: function(){ var attrs = this.params_.attrs; if (attrs && "htmlid" in attrs) return attrs["htmlid"]; else return ""; }, onCHANGE: function(aevent){ var emitter = aevent.Emitter(); if (this.mode_ === "compact"){ var emitter = aevent.Emitter(); if (emitter.ID() === this.widgetID()){ this.SetValue(emitter.Value()); this.onchange(); } }else{ if (this.spinners_rgb.include(emitter)) this.setValueAndCallOnchange((new Color()).FromRGB(this.getSpinnerValues(this.spinners_rgb))); else if (this.spinners_hsv.include(emitter)) this.setValueAndCallOnchange((new Color()).FromHSV(this.getSpinnerValues(this.spinners_hsv))); else if (this.htmlvalue_input == emitter){ var val = this.htmlvalue_input.Value(); this.setValueAndCallOnchange(val.IsNull() ? "" : String(val.Value())); }else return; aevent.Stop(); } }, onclick: function(event){ var element = Event.findElement(event, "span"); if (!element || !Element.descendantOf(element, this.element) || // !Element.hasClassName(element, "ColorSample")) return; if (!element.color || !(element.color instanceof Color)) element.color = new Color(element.getAttribute("value")); this.setValueAndCallOnchange(element.color); }, CLICK: function(event){ new AEvent("CLICK", {}, this); }, value: "", setColor: function(color){ if (!(color instanceof Color)) color = new Color(color); if (this.value == color.Value()) return false; this.setAuxValue(color); var rgb = color.GetRGB(); var coefs = [0.2989, 0.5870, 0.1140]; var bri = 0; for (var iii = 0; iii < Math.min(rgb.length, coefs.length); ++iii) bri += rgb[iii] * coefs[iii]; Element.setStyle(this.currentValueDisplay, { "backgroundColor": this.css_color(color), "borderColor": color.IsValidColor() && bri < 128 ? "white" : "", "color": color.IsValidColor() && bri < 128 ? "white" : "" }); this.htmlvalue_input.SetValue(color.Value()); this.value = color.Value(); return true; }, setAuxValue: function(color){ if (!this.aux_) return; var val = color && color.Value ? String(color.Value()) : ""; for (var child = this.aux_.firstChild; child;){ var ref = child.nextSibling; if (child.nodeType == Node.TEXT_NODE) child.parentNode.removeChild(child); child = ref; } if (val) this.aux_.appendChild(document.createTextNode(val)); }, css_color: function(val){ val = this.unwrap_optional(val); if (!val) return ""; if (!(val instanceof Color)) val = new Color(val); if (val.IsValidColor()) return val.Value(); else return ""; }, setSpinnerValues: function(spinners, vals){ spinners.each(function(spinner, iii){ spinner.SetValue(Object.isUndefined(vals[iii]) ? null : int(vals[iii])); }); }, setRGB: function(rgb){ this.setSpinnerValues(this.spinners_rgb, rgb); }, setHSV: function(hsv){ this.setSpinnerValues(this.spinners_hsv, hsv); }, get_callbacks: function(vis){ switch (vis){ case "yes": var cont = Element.down(this.element, "td.PredefinedColors"); if (cont) return [[cont, "click", this.onclick.bindAsEventListener(this)]]; break; case "link": var callbacks = []; var elems = [this.aux_, this.display_]; for (var iii = 0; iii < elems.length; ++iii) if (elems[iii]) callbacks.push([elems[iii], "click", this.CLICK.bindAsEventListener(this)]); return callbacks.length > 0 ? callbacks : null; break; } return null; }, SetAttribute: function($super, nam, val){ switch (nam){ case "visibility": if (ColorInput.visibility_modes.indexOf(val) === -1) break; if (this.visibility_ === val) break; if (["yes", "ro"].indexOf(val) !== -1){ if (this.mode_ === "compact"){ if (this.input_) this.input_.disabled = "yes" !== val; }else{ var jscontrols = this.spinners_rgb.concat(this.spinners_hsv); jscontrols.push(this.htmlvalue_input); jscontrols.invoke("SetAttribute", nam, val); } Element["yes" == val ? "removeClassName" : "addClassName"](this.element, "Disabled"); } if (this.mode_ === "compact"){ if (this.button_) Element.setStyle(this.button_, {"display": "yes" === val ? "" : "none"}); if (this.display_){ Element.setStyle(this.display_, {"display": "no" === val ? "none" : ""}); Element[["yes", "ro"].indexOf(val) !== -1 ? "addClassName" : "removeClassName"](this.display_, "Large"); } } Element.setStyle(this.element, {"display": ["yes", "ro"].indexOf(val) === -1 ? "none" : ""}); if (["yes", "ro", "no"].indexOf(val) === -1){ if (!this.aux_){ this.aux_ = new Element("span", {"class": "Auxiliary"}); this.setAuxValue(this.Value()); } if (!this.display_){ this.display_ = new Element("span", {"class": "ColorDisplay"}); Element.setStyle(this.display_, {"backgroundColor": this.css_color(this.Value())}); } Element["link" == val ? "addClassName" : "removeClassName"](this.aux_, "Link"); if (!this.aux_.parentNode) this.element.parentNode.insertBefore(this.aux_, this.element); if (!this.display_.parentNode) this.aux_.parentNode.insertBefore(this.display_, this.aux_); }else{ if (this.aux_ && this.aux_.parentNode) this.aux_.parentNode.removeChild(this.aux_); if (this.mode_ !== "compact" && this.display_ && this.display_.parentNode) this.display_.parentNode.removeChild(this.display_); } if (this.callbacks_){ JSControl.remove_callbacks(this.callbacks_); delete this.callbacks_; } this.callbacks_ = this.get_callbacks(val); if (this.callbacks_) JSControl.add_callbacks(this.callbacks_); this.visibility_ = val; break; case "title": break; default: $super(nam, val); } }, setValue: function(color){ if (!(color instanceof Color)) color = new Color(color); this.setRGB(color.GetRGB()); this.setHSV(color.GetHSV()); return this.setColor(color); }, unwrap_optional: function(val){ while (val instanceof Optional) val = val.Value(); return val; }, SetValue: function(color){ if (this.mode_ === "compact"){ var val = this.unwrap_optional(color); if (val instanceof Color) val = val.Value(); this.input_.value = val || ""; if (this.display_) Element.setStyle(this.display_, {"backgroundColor": this.css_color(val)}); if (this.aux_) this.setAuxValue(val); }else{ if (color instanceof Optional && color.IsNull()) return; this.setValue(String(color)); if (this.display_) Element.setStyle(this.display_, {"backgroundColor": this.css_color(color)}); } }, Value: function(){ if (this.mode_ === "compact"){ if (!this.input_) return optional(); var val = new Color(this.input_.value); if (val.IsValidColor()) return optional(val.Value()); else return optional(); }else return this.value; }, SetTabOrder: function(tabbase){ if (this.mode_ === "compact"){ this.element.tabIndex = tabbase++; if (this.button_) this.button_.tabIndex = tabbase++; if (this.opener_) return this.opener_.SetTabOrder(tabbase); }else this.jscontrols.each(function(element){ if (element.JSControl && Object.isFunction(element.JSControl.SetTabOrder)) tabbase = element.JSControl.SetTabOrder(tabbase); }); return tabbase; } }); ColorInput.visibility_modes = ["yes", "ro", "vo", "link", "no"]; var Color = Class.create({ initialize: function(str){ this.str = String(str || ""); }, Value: function(){ return this.str; }, GetRGB: function(){ return this.IsValidColor() ? this.rgb : []; }, GetHSV: function(){ if (!this.IsValidColor()) return []; if (Object.isUndefined(this.hsv)) this.hsv = Color.RGB2HSV(this.rgb); return this.hsv; }, HTML: function(){ if (!this.IsValidColor()) return null; return "#" + this.GetRGB().invoke("toPaddedString", 2, 16).join(""); }, IsValidColor: function(){ if (!this.is_parsed) this.parse(); return this.is_valid; }, is_parsed: false, parse: function(){ var named_color = Color.named_colors[this.str.toLowerCase()]; var str = Object.isUndefined(named_color) ? this.str : named_color; var format = Color.formats.find(function(format){ return Object.isFunction(format.Test) ? format.Test(str) : format["test"].test(str); }); this.is_parsed = true; this.is_valid = !Object.isUndefined(format); if (this.is_valid) this.rgb = format.GetRGB(str); }, FromRGB: function(rgb){ this.rgb = rgb; this.str = Color.RGB2Color(this.rgb); delete this.hsv; this.is_parsed = this.is_valid = true; return this; }, FromHSV: function(hsv){ this.hsv = hsv; this.rgb = Color.HSV2RGB(hsv); this.str = Color.RGB2Color(this.rgb); this.is_parsed = this.is_valid = true; return this; }, toString: function(){ return this.str; } }); Color.formats = [{ "name": "hex", "test": /^\s*#?(?:[a-fA-F0-9]{3}){1,2}\s*$/, "GetRGB": function(str){ str = str.strip(); if (str.startsWith("#")) str = str.substr(1); if (str.length == "3") str = str.split("").invoke("times", 2).join(""); return [parseInt(str.substr(0, 2), 16), parseInt(str.substr(2, 2), 16), parseInt(str.substr(4), 16)]; } }, { "name": "rgb", "test": /^\s*rgb\(\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*(\d+%?)\s*\)\s*$/, "GetRGB": function(str){ var mtch = str.match(this.test); if (!mtch) return []; mtch.shift(); return mtch.collect(function(str){ return str.endsWith("%") ? parseInt(str, 10) * 2.55 : Math.min(parseInt(str, 10), 255); }).collect(Math.round); } }]; Color.RGB2HSV = function(rgb){ var r = rgb[0] / 255; var g = rgb[1] / 255; var b = rgb[2] / 255; var max = Math.max(r, g, b); var min = Math.min(r, g, b); var h = 0; if (max > min){ if (max == r) h = (g - b) / (max - min) + (g < b) * 6; else if (max == g) h = (b - r) / (max - min) + 2; else h = (r - g) / (max - min) + 4; h *= 60; } return [h, 100 * (max == 0 ? 0 : 1 - min / max), 100 * max].collect(Math.round); } Color.RGB2Color = function(rgb){ if (!Object.isArray(rgb) || rgb.length != 3) return ""; return "#" + rgb.invoke("toColorPart").join("").toUpperCase(); } Color.HSV2RGB_aux = function(hsv){ var h = hsv[0]; var s = hsv[1] / 100; var v = hsv[2] / 100; var f = h / 60 - Math.floor(h / 60); var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); switch(Math.floor(h / 60) % 6){ case 0: return [v, t, p]; case 1: return [q, v, p]; case 2: return [p, v, t]; case 3: return [p, q, v]; case 4: return [t, p, v]; case 5: return [v, p, q]; } } Color.HSV2RGB = function(hsv){ return Color.HSV2RGB_aux(hsv).collect(function(num){ return Math.round(num * 255); }); } Color.named_colors = { "AliceBlue": "#F0F8FF", "AntiqueWhite": "#FAEBD7", "Aqua": "#00FFFF", "Aquamarine": "#7FFFD4", "Azure": "#F0FFFF", "Beige": "#F5F5DC", "Bisque": "#FFE4C4", "Black": "#000000", "BlanchedAlmond": "#FFEBCD", "Blue": "#0000FF", "BlueViolet": "#8A2BE2", "Brown": "#A52A2A", "BurlyWood": "#DEB887", "CadetBlue": "#5F9EA0", "Chartreuse": "#7FFF00", "Chocolate": "#D2691E", "Coral": "#FF7F50", "CornflowerBlue": "#6495ED", "Cornsilk": "#FFF8DC", "Crimson": "#DC143C", "Cyan": "#00FFFF", "DarkBlue": "#00008B", "DarkCyan": "#008B8B", "DarkGoldenRod": "#B8860B", "DarkGray": "#A9A9A9", "DarkGreen": "#006400", "DarkKhaki": "#BDB76B", "DarkMagenta": "#8B008B", "DarkOliveGreen": "#556B2F", "Darkorange": "#FF8C00", "DarkOrchid": "#9932CC", "DarkRed": "#8B0000", "DarkSalmon": "#E9967A", "DarkSeaGreen": "#8FBC8F", "DarkSlateBlue": "#483D8B", "DarkSlateGray": "#2F4F4F", "DarkTurquoise": "#00CED1", "DarkViolet": "#9400D3", "DeepPink": "#FF1493", "DeepSkyBlue": "#00BFFF", "DimGray": "#696969", "DodgerBlue": "#1E90FF", "FireBrick": "#B22222", "FloralWhite": "#FFFAF0", "ForestGreen": "#228B22", "Fuchsia": "#FF00FF", "Gainsboro": "#DCDCDC", "GhostWhite": "#F8F8FF", "Gold": "#FFD700", "GoldenRod": "#DAA520", "Gray": "#808080", "Green": "#008000", "GreenYellow": "#ADFF2F", "HoneyDew": "#F0FFF0", "HotPink": "#FF69B4", "IndianRed": "#CD5C5C", "Indigo": "#4B0082", "Ivory": "#FFFFF0", "Khaki": "#F0E68C", "Lavender": "#E6E6FA", "LavenderBlush": "#FFF0F5", "LawnGreen": "#7CFC00", "LemonChiffon": "#FFFACD", "LightBlue": "#ADD8E6", "LightCoral": "#F08080", "LightCyan": "#E0FFFF", "LightGoldenRodYellow": "#FAFAD2", "LightGrey": "#D3D3D3", "LightGreen": "#90EE90", "LightPink": "#FFB6C1", "LightSalmon": "#FFA07A", "LightSeaGreen": "#20B2AA", "LightSkyBlue": "#87CEFA", "LightSlateGray": "#778899", "LightSteelBlue": "#B0C4DE", "LightYellow": "#FFFFE0", "Lime": "#00FF00", "LimeGreen": "#32CD32", "Linen": "#FAF0E6", "Magenta": "#FF00FF", "Maroon": "#800000", "MediumAquaMarine": "#66CDAA", "MediumBlue": "#0000CD", "MediumOrchid": "#BA55D3", "MediumPurple": "#9370D8", "MediumSeaGreen": "#3CB371", "MediumSlateBlue": "#7B68EE", "MediumSpringGreen": "#00FA9A", "MediumTurquoise": "#48D1CC", "MediumVioletRed": "#C71585", "MidnightBlue": "#191970", "MintCream": "#F5FFFA", "MistyRose": "#FFE4E1", "Moccasin": "#FFE4B5", "NavajoWhite": "#FFDEAD", "Navy": "#000080", "OldLace": "#FDF5E6", "Olive": "#808000", "OliveDrab": "#6B8E23", "Orange": "#FFA500", "OrangeRed": "#FF4500", "Orchid": "#DA70D6", "PaleGoldenRod": "#EEE8AA", "PaleGreen": "#98FB98", "PaleTurquoise": "#AFEEEE", "PaleVioletRed": "#D87093", "PapayaWhip": "#FFEFD5", "PeachPuff": "#FFDAB9", "Peru": "#CD853F", "Pink": "#FFC0CB", "Plum": "#DDA0DD", "PowderBlue": "#B0E0E6", "Purple": "#800080", "Red": "#FF0000", "RosyBrown": "#BC8F8F", "RoyalBlue": "#4169E1", "SaddleBrown": "#8B4513", "Salmon": "#FA8072", "SandyBrown": "#F4A460", "SeaGreen": "#2E8B57", "SeaShell": "#FFF5EE", "Sienna": "#A0522D", "Silver": "#C0C0C0", "SkyBlue": "#87CEEB", "SlateBlue": "#6A5ACD", "SlateGray": "#708090", "Snow": "#FFFAFA", "SpringGreen": "#00FF7F", "SteelBlue": "#4682B4", "Tan": "#D2B48C", "Teal": "#008080", "Thistle": "#D8BFD8", "Tomato": "#FF6347", "Turquoise": "#40E0D0", "Violet": "#EE82EE", "Wheat": "#F5DEB3", "White": "#FFFFFF", "WhiteSmoke": "#F5F5F5", "Yellow": "#FFFF00", "YellowGreen": "#9ACD32" } for (var key in Color.named_colors){ var key_lc = key.toLowerCase(); if (key_lc != key) Color.named_colors[key_lc] = Color.named_colors[key]; }