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 */ 29 function $(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 */ 39 function 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 */ 55 function 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 68 Rectangle.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 */ 79 Rectangle.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 */ 95 function 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 */ 106 function 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 126 function _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 146 function _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 */ 159 function 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 174 function hideWindow() { 175 resizeWindow(1, 1); 176 } 177 178 /** 179 * @return {!boolean} 180 */ 181 function isWindowHidden() { 182 return window.innerWidth === 1 && window.innerHeight === 1; 183 } 184 185 window.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 */ 195 function 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 */ 213 function 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 */ 227 function Picker(element, config) { 228 this._element = element; 229 this._config = config; 230 } 231 232 /** 233 * @enum {number} 234 */ 235 Picker.Actions = { 236 SetValue: 0, 237 Cancel: -1, 238 ChooseOtherColor: -2 239 }; 240 241 /** 242 * @param {!string} value 243 */ 244 Picker.prototype.submitValue = function(value) { 245 window.pagePopupController.setValue(value); 246 window.pagePopupController.closePopup(); 247 } 248 249 Picker.prototype.handleCancel = function() { 250 window.pagePopupController.closePopup(); 251 } 252 253 Picker.prototype.chooseOtherColor = function() { 254 window.pagePopupController.setValueAndClosePopup(Picker.Actions.ChooseOtherColor, ""); 255 } 256 257 Picker.prototype.cleanup = function() {}; 258