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/**
27 * @param {!string} id
28 */
29function $(id) {
30    return document.getElementById(id);
31}
32
33/**
34 * @param {!string} tagName
35 * @param {string=} opt_class
36 * @param {string=} opt_text
37 * @return {!Element}
38 */
39function createElement(tagName, opt_class, opt_text) {
40    var element = document.createElement(tagName);
41    if (opt_class)
42        element.setAttribute("class", opt_class);
43    if (opt_text)
44        element.appendChild(document.createTextNode(opt_text));
45    return element;
46}
47
48/**
49 * @constructor
50 * @param {!number|Rectangle|Object} xOrRect
51 * @param {!number} y
52 * @param {!number} width
53 * @param {!number} height
54 */
55function Rectangle(xOrRect, y, width, height) {
56    if (typeof xOrRect === "object") {
57        y = xOrRect.y;
58        width = xOrRect.width;
59        height = xOrRect.height;
60        xOrRect = xOrRect.x;
61    }
62    this.x = xOrRect;
63    this.y = y;
64    this.width = width;
65    this.height = height;
66}
67
68Rectangle.prototype = {
69    get maxX() { return this.x + this.width; },
70    get maxY() { return this.y + this.height; },
71    toString: function() { return "Rectangle(" + this.x + "," + this.y + "," + this.width + "," + this.height + ")"; }
72};
73
74/**
75 * @param {!Rectangle} rect1
76 * @param {!Rectangle} rect2
77 * @return {?Rectangle}
78 */
79Rectangle.intersection = function(rect1, rect2) {
80    var x = Math.max(rect1.x, rect2.x);
81    var maxX = Math.min(rect1.maxX, rect2.maxX);
82    var y = Math.max(rect1.y, rect2.y);
83    var maxY = Math.min(rect1.maxY, rect2.maxY);
84    var width = maxX - x;
85    var height = maxY - y;
86    if (width < 0 || height < 0)
87        return null;
88    return new Rectangle(x, y, width, height);
89};
90
91/**
92 * @param {!number} width
93 * @param {!number} height
94 */
95function resizeWindow(width, height) {
96    setWindowRect(adjustWindowRect(width, height, width, height));
97}
98
99/**
100 * @param {!number} width
101 * @param {!number} height
102 * @param {?number} minWidth
103 * @param {?number} minHeight
104 * @return {!Rectangle}
105 */
106function adjustWindowRect(width, height, minWidth, minHeight) {
107    if (typeof minWidth !== "number")
108        minWidth = 0;
109    if (typeof minHeight !== "number")
110        minHeight = 0;
111
112    var windowRect = new Rectangle(0, 0, width, height);
113
114    if (!global.params.anchorRectInScreen)
115        return windowRect;
116
117    var anchorRect = new Rectangle(global.params.anchorRectInScreen);
118    var availRect = new Rectangle(window.screen.availLeft, window.screen.availTop, window.screen.availWidth, window.screen.availHeight);
119
120    _adjustWindowRectVertically(windowRect, availRect, anchorRect, minHeight);
121    _adjustWindowRectHorizontally(windowRect, availRect, anchorRect, minWidth);
122
123    return windowRect;
124}
125
126function _adjustWindowRectVertically(windowRect, availRect, anchorRect, minHeight) {
127    var availableSpaceAbove = anchorRect.y - availRect.y;
128    availableSpaceAbove = Math.max(0, Math.min(availRect.height, availableSpaceAbove));
129
130    var availableSpaceBelow = availRect.maxY - anchorRect.maxY;
131    availableSpaceBelow = Math.max(0, Math.min(availRect.height, availableSpaceBelow));
132
133    if (windowRect.height > availableSpaceBelow && availableSpaceBelow < availableSpaceAbove) {
134        windowRect.height = Math.min(windowRect.height, availableSpaceAbove);
135        windowRect.height = Math.max(windowRect.height, minHeight);
136        windowRect.y = anchorRect.y - windowRect.height;
137    } else {
138        windowRect.height = Math.min(windowRect.height, availableSpaceBelow);
139        windowRect.height = Math.max(windowRect.height, minHeight);
140        windowRect.y = anchorRect.maxY;
141    }
142    windowRect.y = Math.min(windowRect.y, availRect.maxY - windowRect.height);
143    windowRect.y = Math.max(windowRect.y, availRect.y);
144}
145
146function _adjustWindowRectHorizontally(windowRect, availRect, anchorRect, minWidth) {
147    windowRect.width = Math.min(windowRect.width, availRect.width);
148    windowRect.width = Math.max(windowRect.width, minWidth);
149    windowRect.x = anchorRect.x;
150    if (global.params.isRTL)
151        windowRect.x += anchorRect.width - windowRect.width;
152    windowRect.x = Math.min(windowRect.x, availRect.maxX - windowRect.width);
153    windowRect.x = Math.max(windowRect.x, availRect.x);
154}
155
156/**
157 * @param {!Rectangle} rect
158 */
159function setWindowRect(rect) {
160    if (window.frameElement) {
161        window.frameElement.style.width = rect.width + "px";
162        window.frameElement.style.height = rect.height + "px";
163    } else {
164        if (isWindowHidden()) {
165            window.moveTo(rect.x, rect.y);
166            window.resizeTo(rect.width, rect.height);
167        } else {
168            window.resizeTo(rect.width, rect.height);
169            window.moveTo(rect.x, rect.y);
170        }
171    }
172}
173
174function hideWindow() {
175    resizeWindow(1, 1);
176}
177
178/**
179 * @return {!boolean}
180 */
181function isWindowHidden() {
182    return window.innerWidth === 1 && window.innerHeight === 1;
183}
184
185window.addEventListener("resize", function() {
186    if (isWindowHidden())
187        window.dispatchEvent(new CustomEvent("didHide"));
188    else
189        window.dispatchEvent(new CustomEvent("didOpenPicker"));
190}, false);
191
192/**
193 * @return {!number}
194 */
195function getScrollbarWidth() {
196    if (typeof window.scrollbarWidth === "undefined") {
197        var scrollDiv = document.createElement("div");
198        scrollDiv.style.opacity = "0";
199        scrollDiv.style.overflow = "scroll";
200        scrollDiv.style.width = "50px";
201        scrollDiv.style.height = "50px";
202        document.body.appendChild(scrollDiv);
203        window.scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
204        scrollDiv.parentNode.removeChild(scrollDiv);
205    }
206    return window.scrollbarWidth;
207}
208
209/**
210 * @param {!string} className
211 * @return {?Element}
212 */
213function enclosingNodeOrSelfWithClass(selfNode, className)
214{
215    for (var node = selfNode; node && node !== selfNode.ownerDocument; node = node.parentNode) {
216        if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains(className))
217            return node;
218    }
219    return null;
220}
221
222/**
223 * @constructor
224 * @param {!Element} element
225 * @param {!Object} config
226 */
227function Picker(element, config) {
228    this._element = element;
229    this._config = config;
230}
231
232/**
233 * @enum {number}
234 */
235Picker.Actions = {
236    SetValue: 0,
237    Cancel: -1,
238    ChooseOtherColor: -2
239};
240
241/**
242 * @param {!string} value
243 */
244Picker.prototype.submitValue = function(value) {
245    window.pagePopupController.setValue(value);
246    window.pagePopupController.closePopup();
247};
248
249Picker.prototype.handleCancel = function() {
250    window.pagePopupController.closePopup();
251};
252
253Picker.prototype.chooseOtherColor = function() {
254    window.pagePopupController.setValueAndClosePopup(Picker.Actions.ChooseOtherColor, "");
255};
256
257Picker.prototype.cleanup = function() {};
258