1/* 2 * Copyright (C) 2012 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 * @param {!Element} relativeToElement 34 * @param {!WebInspector.DialogDelegate} delegate 35 */ 36WebInspector.Dialog = function(relativeToElement, delegate) 37{ 38 this._delegate = delegate; 39 this._relativeToElement = relativeToElement; 40 41 this._glassPane = new WebInspector.GlassPane(); 42 // Install glass pane capturing events. 43 this._glassPane.element.tabIndex = 0; 44 this._glassPane.element.addEventListener("focus", this._onGlassPaneFocus.bind(this), false); 45 this._glassPane.element.addEventListener("keydown", this._onGlassPaneKeyDown.bind(this), false); 46 47 this._element = this._glassPane.element.createChild("div"); 48 this._element.tabIndex = 0; 49 this._element.addEventListener("focus", this._onFocus.bind(this), false); 50 this._element.addEventListener("keydown", this._onKeyDown.bind(this), false); 51 this._closeKeys = [ 52 WebInspector.KeyboardShortcut.Keys.Enter.code, 53 WebInspector.KeyboardShortcut.Keys.Esc.code, 54 ]; 55 56 delegate.show(this._element); 57 58 this._position(); 59 this._delegate.focus(); 60} 61 62/** 63 * @return {?WebInspector.Dialog} 64 */ 65WebInspector.Dialog.currentInstance = function() 66{ 67 return WebInspector.Dialog._instance; 68} 69 70/** 71 * @param {!Element} relativeToElement 72 * @param {!WebInspector.DialogDelegate} delegate 73 */ 74WebInspector.Dialog.show = function(relativeToElement, delegate) 75{ 76 if (WebInspector.Dialog._instance) 77 return; 78 WebInspector.Dialog._instance = new WebInspector.Dialog(relativeToElement, delegate); 79} 80 81WebInspector.Dialog.hide = function() 82{ 83 if (!WebInspector.Dialog._instance) 84 return; 85 WebInspector.Dialog._instance._hide(); 86} 87 88WebInspector.Dialog.prototype = { 89 _hide: function() 90 { 91 if (this._isHiding) 92 return; 93 this._isHiding = true; 94 95 this._delegate.willHide(); 96 97 delete WebInspector.Dialog._instance; 98 this._glassPane.dispose(); 99 }, 100 101 _onGlassPaneFocus: function(event) 102 { 103 this._hide(); 104 }, 105 106 /** 107 * @param {?Event} event 108 */ 109 _onGlassPaneKeyDown: function(event) 110 { 111 var actions = WebInspector.shortcutRegistry.applicableActions(WebInspector.KeyboardShortcut.makeKeyFromEvent(/** @type {?KeyboardEvent} */ (event))); 112 if (actions.length) 113 event.consume(true); 114 }, 115 116 _onFocus: function(event) 117 { 118 this._delegate.focus(); 119 }, 120 121 _position: function() 122 { 123 this._delegate.position(this._element, this._relativeToElement); 124 }, 125 126 _onKeyDown: function(event) 127 { 128 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) { 129 event.preventDefault(); 130 return; 131 } 132 133 if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code) 134 this._delegate.onEnter(); 135 136 if (this._closeKeys.indexOf(event.keyCode) >= 0) { 137 this._hide(); 138 event.consume(true); 139 } 140 } 141}; 142 143/** 144 * @constructor 145 * @extends {WebInspector.Object} 146 */ 147WebInspector.DialogDelegate = function() 148{ 149 /** @type {!Element} */ 150 this.element; 151} 152 153WebInspector.DialogDelegate.prototype = { 154 /** 155 * @param {!Element} element 156 */ 157 show: function(element) 158 { 159 element.appendChild(this.element); 160 this.element.classList.add("dialog-contents"); 161 element.classList.add("dialog"); 162 }, 163 164 /** 165 * @param {!Element} element 166 * @param {!Element} relativeToElement 167 */ 168 position: function(element, relativeToElement) 169 { 170 var container = WebInspector.Dialog._modalHostView.element; 171 var box = relativeToElement.boxInWindow(window).relativeToElement(container); 172 173 var positionX = box.x + (relativeToElement.offsetWidth - element.offsetWidth) / 2; 174 positionX = Number.constrain(positionX, 0, container.offsetWidth - element.offsetWidth); 175 176 var positionY = box.y + (relativeToElement.offsetHeight - element.offsetHeight) / 2; 177 positionY = Number.constrain(positionY, 0, container.offsetHeight - element.offsetHeight); 178 179 element.style.position = "absolute"; 180 element.positionAt(positionX, positionY, container); 181 }, 182 183 focus: function() { }, 184 185 onEnter: function() { }, 186 187 willHide: function() { }, 188 189 __proto__: WebInspector.Object.prototype 190} 191 192/** @type {?WebInspector.View} */ 193WebInspector.Dialog._modalHostView = null; 194 195/** 196 * @param {!WebInspector.View} view 197 */ 198WebInspector.Dialog.setModalHostView = function(view) 199{ 200 WebInspector.Dialog._modalHostView = view; 201}; 202 203/** 204 * FIXME: make utility method in Dialog, so clients use it instead of this getter. 205 * Method should be like Dialog.showModalElement(position params, reposition callback). 206 * @return {?WebInspector.View} 207 */ 208WebInspector.Dialog.modalHostView = function() 209{ 210 return WebInspector.Dialog._modalHostView; 211}; 212 213WebInspector.Dialog.modalHostRepositioned = function() 214{ 215 if (WebInspector.Dialog._instance) 216 WebInspector.Dialog._instance._position(); 217}; 218 219