1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.Object} 34 * @param {!Element} element 35 */ 36 WebInspector.StatusBarItem = function(element) 37 { 38 this.element = element; 39 this._enabled = true; 40 } 41 42 WebInspector.StatusBarItem.prototype = { 43 /** 44 * @param {boolean} value 45 */ 46 setEnabled: function(value) 47 { 48 if (this._enabled === value) 49 return; 50 this._enabled = value; 51 this._applyEnabledState(); 52 }, 53 54 /** 55 * @protected 56 */ 57 _applyEnabledState: function() 58 { 59 this.element.disabled = !this._enabled; 60 }, 61 62 __proto__: WebInspector.Object.prototype 63 } 64 65 /** 66 * @constructor 67 * @extends {WebInspector.StatusBarItem} 68 * @param {string} text 69 * @param {string=} className 70 */ 71 WebInspector.StatusBarText = function(text, className) 72 { 73 WebInspector.StatusBarItem.call(this, document.createElement("span")); 74 this.element.className = "status-bar-item status-bar-text"; 75 if (className) 76 this.element.addStyleClass(className); 77 this.element.textContent = text; 78 } 79 80 WebInspector.StatusBarText.prototype = { 81 /** 82 * @param {string} text 83 */ 84 setText: function(text) 85 { 86 this.element.textContent = text; 87 }, 88 89 __proto__: WebInspector.StatusBarItem.prototype 90 } 91 92 93 /** 94 * @constructor 95 * @extends {WebInspector.StatusBarItem} 96 * @param {string} title 97 * @param {string} className 98 * @param {number=} states 99 */ 100 WebInspector.StatusBarButton = function(title, className, states) 101 { 102 WebInspector.StatusBarItem.call(this, document.createElement("button")); 103 this.element.className = className + " status-bar-item"; 104 this.element.addEventListener("click", this._clicked.bind(this), false); 105 106 this.glyph = document.createElement("div"); 107 this.glyph.className = "glyph"; 108 this.element.appendChild(this.glyph); 109 110 this.glyphShadow = document.createElement("div"); 111 this.glyphShadow.className = "glyph shadow"; 112 this.element.appendChild(this.glyphShadow); 113 114 this.states = states; 115 if (!states) 116 this.states = 2; 117 118 if (states == 2) 119 this._state = false; 120 else 121 this._state = 0; 122 123 this.title = title; 124 this.className = className; 125 this._visible = true; 126 } 127 128 WebInspector.StatusBarButton.prototype = { 129 _clicked: function() 130 { 131 this.dispatchEventToListeners("click"); 132 if (this._longClickInterval) 133 clearInterval(this._longClickInterval); 134 }, 135 136 /** 137 * @return {boolean} 138 */ 139 enabled: function() 140 { 141 return this._enabled; 142 }, 143 144 get title() 145 { 146 return this._title; 147 }, 148 149 set title(x) 150 { 151 if (this._title === x) 152 return; 153 this._title = x; 154 this.element.title = x; 155 }, 156 157 get state() 158 { 159 return this._state; 160 }, 161 162 set state(x) 163 { 164 if (this._state === x) 165 return; 166 167 if (this.states === 2) 168 this.element.enableStyleClass("toggled-on", x); 169 else { 170 this.element.removeStyleClass("toggled-" + this._state); 171 if (x !== 0) 172 this.element.addStyleClass("toggled-" + x); 173 } 174 this._state = x; 175 }, 176 177 get toggled() 178 { 179 if (this.states !== 2) 180 throw("Only used toggled when there are 2 states, otherwise, use state"); 181 return this.state; 182 }, 183 184 set toggled(x) 185 { 186 if (this.states !== 2) 187 throw("Only used toggled when there are 2 states, otherwise, use state"); 188 this.state = x; 189 }, 190 191 get visible() 192 { 193 return this._visible; 194 }, 195 196 set visible(x) 197 { 198 if (this._visible === x) 199 return; 200 201 this.element.enableStyleClass("hidden", !x); 202 this._visible = x; 203 }, 204 205 makeLongClickEnabled: function() 206 { 207 this.element.addEventListener("mousedown", mouseDown.bind(this), false); 208 this.element.addEventListener("mouseout", mouseUp.bind(this), false); 209 this.element.addEventListener("mouseup", mouseUp.bind(this), false); 210 211 var longClicks = 0; 212 213 function mouseDown(e) 214 { 215 if (e.which !== 1) 216 return; 217 longClicks = 0; 218 this._longClickInterval = setInterval(longClicked.bind(this), 200); 219 } 220 221 function mouseUp(e) 222 { 223 if (e.which !== 1) 224 return; 225 if (this._longClickInterval) 226 clearInterval(this._longClickInterval); 227 } 228 229 function longClicked() 230 { 231 ++longClicks; 232 this.dispatchEventToListeners(longClicks === 1 ? "longClickDown" : "longClickPress"); 233 } 234 }, 235 236 /** 237 * @param {function():Array.<WebInspector.StatusBarButton>} buttonsProvider 238 */ 239 makeLongClickOptionsEnabled: function(buttonsProvider) 240 { 241 this.makeLongClickEnabled(); 242 243 this.longClickGlyph = document.createElement("div"); 244 this.longClickGlyph.className = "fill long-click-glyph"; 245 this.element.appendChild(this.longClickGlyph); 246 247 this.longClickGlyphShadow = document.createElement("div"); 248 this.longClickGlyphShadow.className = "fill long-click-glyph shadow"; 249 this.element.appendChild(this.longClickGlyphShadow); 250 251 this.addEventListener("longClickDown", this._showOptions.bind(this, buttonsProvider), this); 252 }, 253 254 /** 255 * @param {function():Array.<WebInspector.StatusBarButton>} buttonsProvider 256 */ 257 _showOptions: function(buttonsProvider) 258 { 259 var buttons = buttonsProvider(); 260 var mainButtonClone = new WebInspector.StatusBarButton(this.title, this.className, this.states); 261 mainButtonClone.addEventListener("click", this._clicked, this); 262 mainButtonClone.state = this.state; 263 buttons.push(mainButtonClone); 264 265 var mouseUpListener = mouseUp.bind(this); 266 document.documentElement.addEventListener("mouseup", mouseUpListener, false); 267 268 var optionsGlassPane = new WebInspector.GlassPane(); 269 var optionsBarElement = optionsGlassPane.element.createChild("div", "alternate-status-bar-buttons-bar"); 270 const buttonHeight = 24; 271 optionsBarElement.style.height = (buttonHeight * buttons.length) + "px"; 272 optionsBarElement.style.left = (this.element.offsetLeft + 1) + "px"; 273 274 var boundMouseOver = mouseOver.bind(this); 275 var boundMouseOut = mouseOut.bind(this); 276 for (var i = 0; i < buttons.length; ++i) { 277 buttons[i].element.addEventListener("mousemove", boundMouseOver, false); 278 buttons[i].element.addEventListener("mouseout", boundMouseOut, false); 279 optionsBarElement.appendChild(buttons[i].element); 280 } 281 buttons[buttons.length - 1].element.addStyleClass("emulate-active"); 282 283 function mouseOver(e) 284 { 285 if (e.which !== 1) 286 return; 287 var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); 288 buttonElement.addStyleClass("emulate-active"); 289 } 290 291 function mouseOut(e) 292 { 293 if (e.which !== 1) 294 return; 295 var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); 296 buttonElement.removeStyleClass("emulate-active"); 297 } 298 299 function mouseUp(e) 300 { 301 if (e.which !== 1) 302 return; 303 optionsGlassPane.dispose(); 304 document.documentElement.removeEventListener("mouseup", mouseUpListener, false); 305 306 for (var i = 0; i < buttons.length; ++i) { 307 if (buttons[i].element.hasStyleClass("emulate-active")) { 308 buttons[i].element.removeStyleClass("emulate-active"); 309 buttons[i]._clicked(); 310 break; 311 } 312 } 313 } 314 }, 315 316 __proto__: WebInspector.StatusBarItem.prototype 317 } 318 319 /** 320 * @constructor 321 * @extends {WebInspector.StatusBarItem} 322 * @param {?function(Event)} changeHandler 323 * @param {string=} className 324 */ 325 WebInspector.StatusBarComboBox = function(changeHandler, className) 326 { 327 WebInspector.StatusBarItem.call(this, document.createElement("span")); 328 this.element.className = "status-bar-select-container"; 329 330 this._selectElement = this.element.createChild("select", "status-bar-item"); 331 this.element.createChild("div", "status-bar-select-arrow"); 332 if (changeHandler) 333 this._selectElement.addEventListener("change", changeHandler, false); 334 if (className) 335 this._selectElement.addStyleClass(className); 336 } 337 338 WebInspector.StatusBarComboBox.prototype = { 339 /** 340 * @return {number} 341 */ 342 size: function() 343 { 344 return this._selectElement.childElementCount; 345 }, 346 347 /** 348 * @param {!Element} option 349 */ 350 addOption: function(option) 351 { 352 this._selectElement.appendChild(option); 353 }, 354 355 /** 356 * @param {string} label 357 * @param {string=} title 358 * @param {string=} value 359 * @return {!Element} 360 */ 361 createOption: function(label, title, value) 362 { 363 var option = this._selectElement.createChild("option"); 364 option.text = label; 365 if (title) 366 option.title = title; 367 if (typeof value !== "undefined") 368 option.value = value; 369 return option; 370 }, 371 372 /** 373 * @override 374 */ 375 _applyEnabledState: function() 376 { 377 this._selectElement.disabled = !this._enabled; 378 }, 379 380 /** 381 * @param {!Element} option 382 */ 383 removeOption: function(option) 384 { 385 this._selectElement.removeChild(option); 386 }, 387 388 removeOptions: function() 389 { 390 this._selectElement.removeChildren(); 391 }, 392 393 /** 394 * @return {?Element} 395 */ 396 selectedOption: function() 397 { 398 if (this._selectElement.selectedIndex >= 0) 399 return this._selectElement[this._selectElement.selectedIndex]; 400 return null; 401 }, 402 403 /** 404 * @param {Element} option 405 */ 406 select: function(option) 407 { 408 this._selectElement.selectedIndex = Array.prototype.indexOf.call(this._selectElement, option); 409 }, 410 411 /** 412 * @param {number} index 413 */ 414 setSelectedIndex: function(index) 415 { 416 this._selectElement.selectedIndex = index; 417 }, 418 419 /** 420 * @return {number} 421 */ 422 selectedIndex: function() 423 { 424 return this._selectElement.selectedIndex; 425 }, 426 427 __proto__: WebInspector.StatusBarItem.prototype 428 } 429