Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2009 Joseph Pecoraro
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /**
     31  * @constructor
     32  */
     33 WebInspector.Drawer = function()
     34 {
     35     this.element = document.getElementById("drawer");
     36     this.element.style.height = 0;
     37 
     38     this._savedHeight = 200; // Default.
     39     this._mainElement = document.getElementById("main");
     40     this._toolbarElement = document.getElementById("toolbar");
     41 
     42     this._floatingStatusBarContainer = document.getElementById("floating-status-bar-container");
     43     WebInspector.installDragHandle(this._floatingStatusBarContainer, this._startStatusBarDragging.bind(this), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), "row-resize");
     44 
     45     this._drawerBodyElement = this.element.createChild("div");
     46     this._drawerBodyElement.id = "drawer-body";
     47 
     48     this._drawerContentsElement = this._drawerBodyElement.createChild("div");
     49     this._drawerContentsElement.id = "drawer-contents";
     50 
     51     this._footerElementContainer = this._drawerBodyElement.createChild("div", "status-bar hidden");
     52     this._footerElementContainer.id = "drawer-footer";
     53 
     54     this._viewStatusBar = document.createElement("div");
     55     this._viewStatusBar.style.opacity = 0;
     56     this._bottomStatusBar = document.getElementById("bottom-status-bar-container");
     57 
     58     var drawerIsOverlay = WebInspector.experimentsSettings.drawerOverlay.isEnabled();
     59     this._elementToAdjust = drawerIsOverlay ? this._floatingStatusBarContainer : this._mainElement;
     60 
     61     document.body.enableStyleClass("drawer-overlay", drawerIsOverlay);
     62 }
     63 
     64 WebInspector.Drawer.AnimationType = {
     65     Immediately: 0,
     66     Normal: 1,
     67     Slow: 2
     68 }
     69 
     70 WebInspector.Drawer.prototype = {
     71     get visible()
     72     {
     73         return !!this._view;
     74     },
     75 
     76     _constrainHeight: function(height)
     77     {
     78         return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
     79     },
     80 
     81     show: function(view, animationType)
     82     {
     83         WebInspector.searchController.cancelSearch();
     84         this.immediatelyFinishAnimation();
     85 
     86         var drawerWasVisible = this.visible;
     87 
     88         if (this._view) {
     89             this._view.detach();
     90             this._drawerContentsElement.removeChildren();
     91         }
     92 
     93         this._view = view;
     94 
     95         var statusBarItems = this._view.statusBarItems || [];
     96         this._viewStatusBar.removeChildren();
     97         for (var i = 0; i < statusBarItems.length; ++i)
     98             this._viewStatusBar.appendChild(statusBarItems[i]);
     99 
    100         document.body.addStyleClass("drawer-visible");
    101         this._floatingStatusBarContainer.insertBefore(document.getElementById("panel-status-bar"), this._floatingStatusBarContainer.firstElementChild);
    102         this._bottomStatusBar.appendChild(this._viewStatusBar);
    103         this._view.detach();
    104         this._view.markAsRoot();
    105         this._view.show(this._drawerContentsElement);
    106 
    107         if (drawerWasVisible)
    108             return;
    109 
    110         var height = this._constrainHeight(this._savedHeight || this.element.offsetHeight);
    111         var animations = [
    112             {element: this.element, end: {height: height}},
    113             {element: this._floatingStatusBarContainer, start: {"padding-left": this._bottomStatusBar.offsetLeft}, end: {"padding-left": 0}},
    114             {element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}},
    115             {element: this._elementToAdjust, start: {bottom: 0}, end: {bottom: height}}
    116         ];
    117 
    118         function animationCallback(finished)
    119         {
    120             if (WebInspector.inspectorView.currentPanel())
    121                 WebInspector.inspectorView.currentPanel().doResize();
    122             if (!finished)
    123                 return;
    124             if (this._view && this._view.afterShow)
    125                 this._view.afterShow();
    126             delete this._currentAnimation;
    127         }
    128 
    129         this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
    130 
    131         if (animationType === WebInspector.Drawer.AnimationType.Immediately)
    132             this._currentAnimation.forceComplete();
    133     },
    134 
    135     hide: function(animationType)
    136     {
    137         WebInspector.searchController.cancelSearch();
    138         this.immediatelyFinishAnimation();
    139         if (!this.visible)
    140             return;
    141 
    142         this._savedHeight = this.element.offsetHeight;
    143 
    144         WebInspector.restoreFocusFromElement(this.element);
    145 
    146         // Temporarily set properties and classes to mimic the post-animation values so panels
    147         // like Elements in their updateStatusBarItems call will size things to fit the final location.
    148         document.body.removeStyleClass("drawer-visible");
    149         WebInspector.inspectorView.currentPanel().statusBarResized();
    150         document.body.addStyleClass("drawer-visible");
    151 
    152         var animations = [
    153             {element: this.element, end: {height: 0}},
    154             {element: this._floatingStatusBarContainer, start: {"padding-left": 0}, end: {"padding-left": this._bottomStatusBar.offsetLeft} },
    155             {element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}},
    156             {element: this._elementToAdjust, end: {bottom: 0}}
    157         ];
    158 
    159         function animationCallback(finished)
    160         {
    161             if (WebInspector.inspectorView.currentPanel())
    162                 WebInspector.inspectorView.currentPanel().doResize();
    163             if (!finished)
    164                 return;
    165             this._view.detach();
    166             delete this._view;
    167             this._bottomStatusBar.removeChildren();
    168             this._bottomStatusBar.appendChild(document.getElementById("panel-status-bar"));
    169             this._drawerContentsElement.removeChildren();
    170             document.body.removeStyleClass("drawer-visible");
    171             delete this._currentAnimation;
    172             this._elementToAdjust.style.bottom = 0;
    173         }
    174 
    175         this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
    176 
    177         if (animationType === WebInspector.Drawer.AnimationType.Immediately)
    178             this._currentAnimation.forceComplete();
    179     },
    180 
    181     resize: function()
    182     {
    183         if (!this.visible)
    184             return;
    185 
    186         this._view.storeScrollPositions();
    187         var height = this._constrainHeight(parseInt(this.element.style.height, 10));
    188         this._elementToAdjust.style.bottom = height + "px";
    189         this.element.style.height = height + "px";
    190         this._view.doResize();
    191     },
    192 
    193     immediatelyFinishAnimation: function()
    194     {
    195         if (this._currentAnimation)
    196             this._currentAnimation.forceComplete();
    197     },
    198 
    199     _animationDuration: function(animationType)
    200     {
    201         switch (animationType) {
    202         case WebInspector.Drawer.AnimationType.Slow:
    203             return 2000;
    204         case WebInspector.Drawer.AnimationType.Normal:
    205             return 100;
    206         default:
    207             return 0;
    208         }
    209     },
    210 
    211     /**
    212      * @return {boolean}
    213      */
    214     _startStatusBarDragging: function(event)
    215     {
    216         if (!this.visible || event.target !== this._floatingStatusBarContainer)
    217             return false;
    218 
    219         this._view.storeScrollPositions();
    220         this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop();
    221         return true;
    222     },
    223 
    224     _statusBarDragging: function(event)
    225     {
    226         var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
    227         height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
    228 
    229         this._elementToAdjust.style.bottom = height + "px";
    230         this.element.style.height = height + "px";
    231         if (WebInspector.inspectorView.currentPanel())
    232             WebInspector.inspectorView.currentPanel().doResize();
    233         this._view.doResize();
    234 
    235         event.consume(true);
    236     },
    237 
    238     _endStatusBarDragging: function(event)
    239     {
    240         this._savedHeight = this.element.offsetHeight;
    241         delete this._statusBarDragOffset;
    242 
    243         event.consume();
    244     },
    245 
    246     /**
    247      * @param {Element} element
    248      */
    249     setFooterElement: function(element)
    250     {
    251         if (element) {
    252             this._footerElementContainer.removeStyleClass("hidden");
    253             this._footerElementContainer.appendChild(element);
    254             this._drawerContentsElement.style.bottom = this._footerElementContainer.offsetHeight + "px";
    255         } else {
    256             this._footerElementContainer.addStyleClass("hidden");
    257             this._footerElementContainer.removeChildren();
    258             this._drawerContentsElement.style.bottom = 0;
    259         }
    260         this._view.doResize();
    261     },
    262 
    263     /**
    264      * @returns {WebInspector.Searchable}
    265      */
    266     getSearchProvider: function()
    267     {
    268         if (this._view && this._view.performSearch)
    269             return this._view;
    270 
    271         return null;
    272     }
    273 }
    274 
    275 /**
    276  * @type {WebInspector.Drawer}
    277  */
    278 WebInspector.drawer = null;
    279