3 * Copyright (C) 2012 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 argumentsReceived: false,
35 return document.getElementById(id);
38 function bind(func, context) {
40 return func.apply(context, arguments);
44 function getScrollbarWidth() {
45 if (gloabal.scrollbarWidth === null) {
46 var scrollDiv = document.createElement("div");
47 scrollDiv.style.opacity = "0";
48 scrollDiv.style.overflow = "scroll";
49 scrollDiv.style.width = "50px";
50 scrollDiv.style.height = "50px";
51 document.body.appendChild(scrollDiv);
52 gloabal.scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
53 scrollDiv.parentNode.removeChild(scrollDiv);
55 return gloabal.scrollbarWidth;
59 * @param {!string} tagName
60 * @param {string=} opt_class
61 * @param {string=} opt_text
64 function createElement(tagName, opt_class, opt_text) {
65 var element = document.createElement(tagName);
67 element.setAttribute("class", opt_class);
69 element.appendChild(document.createTextNode(opt_text));
74 * @param {Event} event
76 function handleMessage(event) {
77 initialize(JSON.parse(event.data));
78 global.argumentsReceived = true;
82 * @param {!Object} args
84 function initialize(args) {
87 var errorString = validateArguments(args);
89 main.textContent = "Internal error: " + errorString;
91 new ColorPicker(main, args);
94 // The DefaultColorPalette is used when the list of values are empty.
95 var DefaultColorPalette = ["#000000", "#404040", "#808080", "#c0c0c0",
96 "#ffffff", "#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff",
97 "#4a86e8", "#0000ff", "#9900ff", "#ff00ff"];
99 function handleArgumentsTimeout() {
100 if (global.argumentsReceived)
103 values : DefaultColorPalette,
104 otherColorLabel: "Other..."
110 * @param {!Object} args
111 * @return {?string} An error message, or null if the argument has no errors.
113 function validateArguments(args) {
116 if (!args.otherColorLabel)
117 return "No otherColorLabel.";
122 ChooseOtherColor: -2,
128 * @param {string} value
130 function submitValue(value) {
131 window.pagePopupController.setValueAndClosePopup(Actions.SetValue, value);
134 function handleCancel() {
135 window.pagePopupController.setValueAndClosePopup(Actions.Cancel, "");
138 function chooseOtherColor() {
139 window.pagePopupController.setValueAndClosePopup(Actions.ChooseOtherColor, "");
142 function ColorPicker(element, config) {
143 this._element = element;
144 this._config = config;
145 if (this._config.values.length === 0)
146 this._config.values = DefaultColorPalette;
150 var SwatchBorderBoxWidth = 24; // keep in sync with CSS
151 var SwatchBorderBoxHeight = 24; // keep in sync with CSS
152 var SwatchesPerRow = 5;
153 var SwatchesMaxRow = 4;
155 ColorPicker.prototype._layout = function() {
156 var container = createElement("div", "color-swatch-container");
157 container.addEventListener("click", bind(this._handleSwatchClick, this), false);
158 for (var i = 0; i < this._config.values.length; ++i) {
159 var swatch = createElement("div", "color-swatch");
160 swatch.dataset.value = this._config.values[i];
161 swatch.title = this._config.values[i];
162 swatch.style.backgroundColor = this._config.values[i];
163 container.appendChild(swatch);
165 var containerWidth = SwatchBorderBoxWidth * SwatchesPerRow;
166 if (this._config.values.length > SwatchesPerRow * SwatchesMaxRow)
167 containerWidth += getScrollbarWidth();
168 container.style.width = containerWidth + "px";
169 container.style.maxHeight = (SwatchBorderBoxHeight * SwatchesMaxRow) + "px";
170 this._element.appendChild(container);
171 var otherButton = createElement("button", "other-color", this._config.otherColorLabel);
172 otherButton.addEventListener("click", chooseOtherColor, false);
173 this._element.appendChild(otherButton);
174 if (window.frameElement) {
175 window.frameElement.style.width = this._element.offsetWidth + "px";
176 window.frameElement.style.height = this._element.offsetHeight + "px";
178 window.resizeTo(this._element.offsetWidth, this._element.offsetHeight);
182 ColorPicker.prototype._handleSwatchClick = function(event) {
183 if (event.target.classList.contains("color-swatch"))
184 submitValue(event.target.dataset.value);
187 if (window.dialogArguments) {
188 initialize(dialogArguments);
190 window.addEventListener("message", handleMessage, false);
191 window.setTimeout(handleArgumentsTimeout, 1000);