Drawer.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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. * @constructor
  31. */
  32. WebInspector.Drawer = function()
  33. {
  34. this.element = document.getElementById("drawer");
  35. this.element.style.height = 0;
  36. this._savedHeight = 200; // Default.
  37. this._mainElement = document.getElementById("main");
  38. this._toolbarElement = document.getElementById("toolbar");
  39. this._floatingStatusBarContainer = document.getElementById("floating-status-bar-container");
  40. WebInspector.installDragHandle(this._floatingStatusBarContainer, this._startStatusBarDragging.bind(this), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), "row-resize");
  41. this._drawerBodyElement = this.element.createChild("div");
  42. this._drawerBodyElement.id = "drawer-body";
  43. this._drawerContentsElement = this._drawerBodyElement.createChild("div");
  44. this._drawerContentsElement.id = "drawer-contents";
  45. this._footerElementContainer = this._drawerBodyElement.createChild("div", "status-bar hidden");
  46. this._footerElementContainer.id = "drawer-footer";
  47. this._viewStatusBar = document.createElement("div");
  48. this._viewStatusBar.style.opacity = 0;
  49. this._bottomStatusBar = document.getElementById("bottom-status-bar-container");
  50. var drawerIsOverlay = WebInspector.experimentsSettings.drawerOverlay.isEnabled();
  51. this._elementToAdjust = drawerIsOverlay ? this._floatingStatusBarContainer : this._mainElement;
  52. document.body.enableStyleClass("drawer-overlay", drawerIsOverlay);
  53. }
  54. WebInspector.Drawer.AnimationType = {
  55. Immediately: 0,
  56. Normal: 1,
  57. Slow: 2
  58. }
  59. WebInspector.Drawer.prototype = {
  60. get visible()
  61. {
  62. return !!this._view;
  63. },
  64. _constrainHeight: function(height)
  65. {
  66. return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
  67. },
  68. isHiding: function()
  69. {
  70. return this._isHiding;
  71. },
  72. show: function(view, animationType)
  73. {
  74. WebInspector.searchController.cancelSearch();
  75. this.immediatelyFinishAnimation();
  76. var drawerWasVisible = this.visible;
  77. if (this._view) {
  78. this._view.detach();
  79. this._drawerContentsElement.removeChildren();
  80. }
  81. this._view = view;
  82. var statusBarItems = this._view.statusBarItems || [];
  83. this._viewStatusBar.removeChildren();
  84. for (var i = 0; i < statusBarItems.length; ++i)
  85. this._viewStatusBar.appendChild(statusBarItems[i]);
  86. document.body.addStyleClass("drawer-visible");
  87. this._floatingStatusBarContainer.insertBefore(document.getElementById("panel-status-bar"), this._floatingStatusBarContainer.firstElementChild);
  88. this._bottomStatusBar.appendChild(this._viewStatusBar);
  89. this._view.detach();
  90. this._view.markAsRoot();
  91. this._view.show(this._drawerContentsElement);
  92. if (drawerWasVisible)
  93. return;
  94. var height = this._constrainHeight(this._savedHeight || this.element.offsetHeight);
  95. var animations = [
  96. {element: this.element, end: {height: height}},
  97. {element: this._floatingStatusBarContainer, start: {"padding-left": this._bottomStatusBar.offsetLeft}, end: {"padding-left": 0}},
  98. {element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}},
  99. {element: this._elementToAdjust, start: {bottom: 0}, end: {bottom: height}}
  100. ];
  101. function animationCallback(finished)
  102. {
  103. if (WebInspector.inspectorView.currentPanel())
  104. WebInspector.inspectorView.currentPanel().doResize();
  105. if (!finished)
  106. return;
  107. if (this._view && this._view.afterShow)
  108. this._view.afterShow();
  109. delete this._currentAnimation;
  110. }
  111. this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
  112. if (animationType === WebInspector.Drawer.AnimationType.Immediately)
  113. this._currentAnimation.forceComplete();
  114. },
  115. hide: function(animationType)
  116. {
  117. WebInspector.searchController.cancelSearch();
  118. this.immediatelyFinishAnimation();
  119. if (!this.visible)
  120. return;
  121. this._isHiding = true;
  122. this._savedHeight = this.element.offsetHeight;
  123. WebInspector.restoreFocusFromElement(this.element);
  124. // Temporarily set properties and classes to mimic the post-animation values so panels
  125. // like Elements in their updateStatusBarItems call will size things to fit the final location.
  126. document.body.removeStyleClass("drawer-visible");
  127. WebInspector.inspectorView.currentPanel().statusBarResized();
  128. document.body.addStyleClass("drawer-visible");
  129. var animations = [
  130. {element: this.element, end: {height: 0}},
  131. {element: this._floatingStatusBarContainer, start: {"padding-left": 0}, end: {"padding-left": this._bottomStatusBar.offsetLeft} },
  132. {element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}},
  133. {element: this._elementToAdjust, end: {bottom: 0}}
  134. ];
  135. function animationCallback(finished)
  136. {
  137. if (WebInspector.inspectorView.currentPanel())
  138. WebInspector.inspectorView.currentPanel().doResize();
  139. if (!finished)
  140. return;
  141. this._view.detach();
  142. delete this._view;
  143. this._bottomStatusBar.removeChildren();
  144. this._bottomStatusBar.appendChild(document.getElementById("panel-status-bar"));
  145. this._drawerContentsElement.removeChildren();
  146. document.body.removeStyleClass("drawer-visible");
  147. delete this._currentAnimation;
  148. this._elementToAdjust.style.bottom = 0;
  149. delete this._isHiding;
  150. }
  151. this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
  152. if (animationType === WebInspector.Drawer.AnimationType.Immediately)
  153. this._currentAnimation.forceComplete();
  154. },
  155. resize: function()
  156. {
  157. if (!this.visible)
  158. return;
  159. this._view.storeScrollPositions();
  160. var height = this._constrainHeight(parseInt(this.element.style.height, 10));
  161. this._elementToAdjust.style.bottom = height + "px";
  162. this.element.style.height = height + "px";
  163. this._view.doResize();
  164. },
  165. immediatelyFinishAnimation: function()
  166. {
  167. if (this._currentAnimation)
  168. this._currentAnimation.forceComplete();
  169. },
  170. _animationDuration: function(animationType)
  171. {
  172. switch (animationType) {
  173. case WebInspector.Drawer.AnimationType.Slow:
  174. return 2000;
  175. case WebInspector.Drawer.AnimationType.Normal:
  176. return 100;
  177. default:
  178. return 0;
  179. }
  180. },
  181. /**
  182. * @return {boolean}
  183. */
  184. _startStatusBarDragging: function(event)
  185. {
  186. if (!this.visible || event.target !== this._floatingStatusBarContainer)
  187. return false;
  188. this._view.storeScrollPositions();
  189. this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop();
  190. return true;
  191. },
  192. _statusBarDragging: function(event)
  193. {
  194. var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
  195. height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
  196. this._elementToAdjust.style.bottom = height + "px";
  197. this.element.style.height = height + "px";
  198. if (WebInspector.inspectorView.currentPanel())
  199. WebInspector.inspectorView.currentPanel().doResize();
  200. this._view.doResize();
  201. event.consume(true);
  202. },
  203. _endStatusBarDragging: function(event)
  204. {
  205. this._savedHeight = this.element.offsetHeight;
  206. delete this._statusBarDragOffset;
  207. event.consume();
  208. },
  209. /**
  210. * @param {Element} element
  211. */
  212. setFooterElement: function(element)
  213. {
  214. if (element) {
  215. this._footerElementContainer.removeStyleClass("hidden");
  216. this._footerElementContainer.appendChild(element);
  217. this._drawerContentsElement.style.bottom = this._footerElementContainer.offsetHeight + "px";
  218. } else {
  219. this._footerElementContainer.addStyleClass("hidden");
  220. this._footerElementContainer.removeChildren();
  221. this._drawerContentsElement.style.bottom = 0;
  222. }
  223. this._view.doResize();
  224. },
  225. /**
  226. * @returns {WebInspector.Searchable}
  227. */
  228. getSearchProvider: function()
  229. {
  230. if (this._view && this._view.performSearch)
  231. return this._view;
  232. return null;
  233. }
  234. }
  235. /**
  236. * @type {WebInspector.Drawer}
  237. */
  238. WebInspector.drawer = null;