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