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 */ 36WebInspector.StatusBarItem = function(element) 37{ 38 this.element = element; 39 this._enabled = true; 40} 41 42WebInspector.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} title 69 * @param {string} className 70 * @param {number=} states 71 */ 72WebInspector.StatusBarButton = function(title, className, states) 73{ 74 WebInspector.StatusBarItem.call(this, document.createElement("button")); 75 this.element.className = className + " status-bar-item"; 76 this.element.addEventListener("click", this._clicked.bind(this), false); 77 78 this.glyph = document.createElement("div"); 79 this.glyph.className = "glyph"; 80 this.element.appendChild(this.glyph); 81 82 this.glyphShadow = document.createElement("div"); 83 this.glyphShadow.className = "glyph shadow"; 84 this.element.appendChild(this.glyphShadow); 85 86 this.states = states; 87 if (!states) 88 this.states = 2; 89 90 if (states == 2) 91 this._state = false; 92 else 93 this._state = 0; 94 95 this.title = title; 96 this.className = className; 97 this._visible = true; 98} 99 100WebInspector.StatusBarButton.prototype = { 101 _clicked: function() 102 { 103 this.dispatchEventToListeners("click"); 104 if (this._showOptionsTimer) 105 clearTimeout(this._showOptionsTimer); 106 }, 107 108 /** 109 * @return {boolean} 110 */ 111 enabled: function() 112 { 113 return this._enabled; 114 }, 115 116 get title() 117 { 118 return this._title; 119 }, 120 121 set title(x) 122 { 123 if (this._title === x) 124 return; 125 this._title = x; 126 this.element.title = x; 127 }, 128 129 get state() 130 { 131 return this._state; 132 }, 133 134 set state(x) 135 { 136 if (this._state === x) 137 return; 138 139 if (this.states === 2) 140 this.element.enableStyleClass("toggled-on", x); 141 else { 142 this.element.removeStyleClass("toggled-" + this._state); 143 if (x !== 0) 144 this.element.addStyleClass("toggled-" + x); 145 } 146 this._state = x; 147 }, 148 149 get toggled() 150 { 151 if (this.states !== 2) 152 throw("Only used toggled when there are 2 states, otherwise, use state"); 153 return this.state; 154 }, 155 156 set toggled(x) 157 { 158 if (this.states !== 2) 159 throw("Only used toggled when there are 2 states, otherwise, use state"); 160 this.state = x; 161 }, 162 163 get visible() 164 { 165 return this._visible; 166 }, 167 168 set visible(x) 169 { 170 if (this._visible === x) 171 return; 172 173 this.element.enableStyleClass("hidden", !x); 174 this._visible = x; 175 }, 176 177 /** 178 * @param {function():Array.<WebInspector.StatusBarButton>} buttonsProvider 179 */ 180 makeLongClickEnabled: function(buttonsProvider) 181 { 182 this.longClickGlyph = document.createElement("div"); 183 this.longClickGlyph.className = "fill long-click-glyph"; 184 this.element.appendChild(this.longClickGlyph); 185 186 this.longClickGlyphShadow = document.createElement("div"); 187 this.longClickGlyphShadow.className = "fill long-click-glyph shadow"; 188 this.element.appendChild(this.longClickGlyphShadow); 189 190 this.element.addEventListener("mousedown", mouseDown.bind(this), false); 191 this.element.addEventListener("mouseout", mouseUp.bind(this), false); 192 this.element.addEventListener("mouseup", mouseUp.bind(this), false); 193 194 function mouseDown(e) 195 { 196 if (e.which !== 1) 197 return; 198 this._showOptionsTimer = setTimeout(this._showOptions.bind(this, buttonsProvider), 200); 199 } 200 201 function mouseUp(e) 202 { 203 if (e.which !== 1) 204 return; 205 if (this._showOptionsTimer) 206 clearTimeout(this._showOptionsTimer); 207 } 208 }, 209 210 /** 211 * @param {function():Array.<WebInspector.StatusBarButton>} buttonsProvider 212 */ 213 _showOptions: function(buttonsProvider) 214 { 215 var buttons = buttonsProvider(); 216 var mainButtonClone = new WebInspector.StatusBarButton(this.title, this.className, this.states); 217 mainButtonClone.addEventListener("click", this._clicked, this); 218 mainButtonClone.state = this.state; 219 buttons.push(mainButtonClone); 220 221 var mouseUpListener = mouseUp.bind(this); 222 document.documentElement.addEventListener("mouseup", mouseUpListener, false); 223 224 var optionsGlassPane = new WebInspector.GlassPane(); 225 var optionsBarElement = optionsGlassPane.element.createChild("div", "alternate-status-bar-buttons-bar"); 226 const buttonHeight = 24; 227 optionsBarElement.style.height = (buttonHeight * buttons.length) + "px"; 228 optionsBarElement.style.left = (this.element.offsetLeft + 1) + "px"; 229 230 var boundMouseOver = mouseOver.bind(this); 231 var boundMouseOut = mouseOut.bind(this); 232 for (var i = 0; i < buttons.length; ++i) { 233 buttons[i].element.addEventListener("mousemove", boundMouseOver, false); 234 buttons[i].element.addEventListener("mouseout", boundMouseOut, false); 235 optionsBarElement.appendChild(buttons[i].element); 236 } 237 buttons[buttons.length - 1].element.addStyleClass("emulate-active"); 238 239 function mouseOver(e) 240 { 241 if (e.which !== 1) 242 return; 243 var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); 244 buttonElement.addStyleClass("emulate-active"); 245 } 246 247 function mouseOut(e) 248 { 249 if (e.which !== 1) 250 return; 251 var buttonElement = e.target.enclosingNodeOrSelfWithClass("status-bar-item"); 252 buttonElement.removeStyleClass("emulate-active"); 253 } 254 255 function mouseUp(e) 256 { 257 if (e.which !== 1) 258 return; 259 optionsGlassPane.dispose(); 260 document.documentElement.removeEventListener("mouseup", mouseUpListener, false); 261 262 for (var i = 0; i < buttons.length; ++i) { 263 if (buttons[i].element.hasStyleClass("emulate-active")) 264 buttons[i]._clicked(); 265 } 266 } 267 }, 268 269 __proto__: WebInspector.StatusBarItem.prototype 270} 271 272/** 273 * @constructor 274 * @extends {WebInspector.StatusBarItem} 275 * @param {?function(Event)} changeHandler 276 * @param {string=} className 277 */ 278WebInspector.StatusBarComboBox = function(changeHandler, className) 279{ 280 WebInspector.StatusBarItem.call(this, document.createElement("span")); 281 this.element.className = "status-bar-select-container"; 282 283 this._selectElement = this.element.createChild("select", "status-bar-item"); 284 if (changeHandler) 285 this._selectElement.addEventListener("change", changeHandler, false); 286 if (className) 287 this._selectElement.addStyleClass(className); 288} 289 290WebInspector.StatusBarComboBox.prototype = { 291 /** 292 * @return {number} 293 */ 294 size: function() 295 { 296 return this._selectElement.childElementCount; 297 }, 298 299 /** 300 * @param {!Element} option 301 */ 302 addOption: function(option) 303 { 304 this._selectElement.appendChild(option); 305 }, 306 307 /** 308 * @param {string} label 309 * @param {string=} title 310 * @param {string=} value 311 * @return {!Element} 312 */ 313 createOption: function(label, title, value) 314 { 315 var option = this._selectElement.createChild("option"); 316 option.text = label; 317 if (title) 318 option.title = title; 319 if (typeof value !== "undefined") 320 option.value = value; 321 return option; 322 }, 323 324 /** 325 * @override 326 */ 327 _applyEnabledState: function() 328 { 329 this._selectElement.disabled = !this._enabled; 330 }, 331 332 /** 333 * @param {!Element} option 334 */ 335 removeOption: function(option) 336 { 337 this._selectElement.removeChild(option); 338 }, 339 340 removeOptions: function() 341 { 342 this._selectElement.removeChildren(); 343 }, 344 345 /** 346 * @return {?Element} 347 */ 348 selectedOption: function() 349 { 350 if (this._selectElement.selectedIndex >= 0) 351 return this._selectElement[this._selectElement.selectedIndex]; 352 return null; 353 }, 354 355 /** 356 * @param {Element} option 357 */ 358 select: function(option) 359 { 360 this._selectElement.selectedIndex = Array.prototype.indexOf.call(this._selectElement, option); 361 }, 362 363 __proto__: WebInspector.StatusBarItem.prototype 364} 365