• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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