Unreviewed build fix; remove unintentional semicolon.
[WebKit-https.git] / Source / WebCore / Resources / pagepopups / colorSuggestionPicker.js
1 "use strict";
2 /*
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  */
25
26 var global = {
27     argumentsReceived: false,
28     params: null
29 };
30
31 /**
32  * @param {Event} event
33  */
34 function handleMessage(event) {
35     initialize(JSON.parse(event.data));
36     global.argumentsReceived = true;
37 }
38
39 /**
40  * @param {!Object} args
41  */
42 function initialize(args) { 
43     global.params = args;
44     var main = $("main");
45     main.innerHTML = "";
46     var errorString = validateArguments(args);
47     if (errorString) {
48         main.textContent = "Internal error: " + errorString;
49         resizeWindow(main.offsetWidth, main.offsetHeight);
50     } else
51         new ColorPicker(main, args);
52 }
53
54 // The DefaultColorPalette is used when the list of values are empty. 
55 var DefaultColorPalette = ["#000000", "#404040", "#808080", "#c0c0c0",
56     "#ffffff", "#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff",
57     "#4a86e8", "#0000ff", "#9900ff", "#ff00ff"];
58
59 function handleArgumentsTimeout() {
60     if (global.argumentsReceived)
61         return;
62     var args = {
63         values : DefaultColorPalette,
64         otherColorLabel: "Other..."
65     };
66     initialize(args);
67 }
68
69 /**
70  * @param {!Object} args
71  * @return {?string} An error message, or null if the argument has no errors.
72  */
73 function validateArguments(args) {
74     if (!args.values)
75         return "No values.";
76     if (!args.otherColorLabel)
77         return "No otherColorLabel.";
78     return null;
79 }
80
81 function ColorPicker(element, config) {
82     Picker.call(this, element, config);
83     this._config = config;
84     if (this._config.values.length === 0)
85         this._config.values = DefaultColorPalette;
86     this._container = null;
87     this._layout();
88     document.body.addEventListener("keydown", this._handleKeyDown.bind(this));
89     this._element.addEventListener("mousemove", this._handleMouseMove.bind(this));
90     this._element.addEventListener("mousedown", this._handleMouseDown.bind(this));
91 }
92 ColorPicker.prototype = Object.create(Picker.prototype);
93
94 var SwatchBorderBoxWidth = 24; // keep in sync with CSS
95 var SwatchBorderBoxHeight = 24; // keep in sync with CSS
96 var SwatchesPerRow = 5;
97 var SwatchesMaxRow = 4;
98
99 ColorPicker.prototype._layout = function() {
100     var container = createElement("div", "color-swatch-container");
101     container.addEventListener("click", this._handleSwatchClick.bind(this), false);
102     for (var i = 0; i < this._config.values.length; ++i) {
103         var swatch = createElement("button", "color-swatch");
104         swatch.dataset.index = i;
105         swatch.dataset.value = this._config.values[i];
106         swatch.title = this._config.values[i];
107         swatch.style.backgroundColor = this._config.values[i];
108         container.appendChild(swatch);
109     }
110     var containerWidth = SwatchBorderBoxWidth * SwatchesPerRow;
111     if (this._config.values.length > SwatchesPerRow * SwatchesMaxRow)
112         containerWidth += getScrollbarWidth();
113     container.style.width = containerWidth + "px";
114     container.style.maxHeight = (SwatchBorderBoxHeight * SwatchesMaxRow) + "px";
115     this._element.appendChild(container);
116     var otherButton = createElement("button", "other-color", this._config.otherColorLabel);
117     otherButton.addEventListener("click", this.chooseOtherColor.bind(this), false);
118     this._element.appendChild(otherButton);
119     this._container = container;
120     this._otherButton = otherButton;
121     var elementWidth = this._element.offsetWidth;
122     var elementHeight = this._element.offsetHeight;
123     resizeWindow(elementWidth, elementHeight);
124 };
125
126 ColorPicker.prototype.selectColorAtIndex = function(index) {
127     index = Math.max(Math.min(this._container.childNodes.length - 1, index), 0);
128     this._container.childNodes[index].focus();
129 };
130
131 ColorPicker.prototype._handleMouseMove = function(event) {
132     if (event.target.classList.contains("color-swatch"))
133         event.target.focus();
134 };
135
136 ColorPicker.prototype._handleMouseDown = function(event) {
137     // Prevent blur.
138     if (event.target.classList.contains("color-swatch"))
139         event.preventDefault();
140 };
141
142 ColorPicker.prototype._handleKeyDown = function(event) {
143     var key = event.keyIdentifier;
144     if (key === "U+001B") // ESC
145         this.handleCancel();
146     else if (key == "Left" || key == "Up" || key == "Right" || key == "Down") {
147         var selectedElement = document.activeElement;
148         var index = 0;
149         if (selectedElement.classList.contains("other-color")) {
150             if (key != "Right" && key != "Up")
151                 return;
152             index = this._container.childNodes.length - 1;
153         } else if (selectedElement.classList.contains("color-swatch")) {
154             index = parseInt(selectedElement.dataset.index, 10);
155             switch (key) {
156             case "Left":
157                 index--;
158                 break;
159             case "Right":
160                 index++;
161                 break;
162             case "Up":
163                 index -= SwatchesPerRow;
164                 break;
165             case "Down":
166                 index += SwatchesPerRow;
167                 break;
168             }
169             if (index > this._container.childNodes.length - 1) {
170                 this._otherButton.focus();
171                 return;
172             }
173         }
174         this.selectColorAtIndex(index);
175     }
176     event.preventDefault();
177 };
178
179 ColorPicker.prototype._handleSwatchClick = function(event) {
180     if (event.target.classList.contains("color-swatch"))
181         this.submitValue(event.target.dataset.value);
182 };
183
184 if (window.dialogArguments) {
185     initialize(dialogArguments);
186 } else {
187     window.addEventListener("message", handleMessage, false);
188     window.setTimeout(handleArgumentsTimeout, 1000);
189 }