| /* |
| * Copyright (C) 2012 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. |
| * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.View} |
| * @param {boolean} isVertical |
| * @param {string=} sidebarSizeSettingName |
| * @param {number=} defaultSidebarWidth |
| * @param {number=} defaultSidebarHeight |
| */ |
| WebInspector.SplitView = function(isVertical, sidebarSizeSettingName, defaultSidebarWidth, defaultSidebarHeight) |
| { |
| WebInspector.View.call(this); |
| |
| this.registerRequiredCSS("splitView.css"); |
| |
| this.element.className = "split-view"; |
| |
| this._firstElement = this.element.createChild("div", "split-view-contents scroll-target split-view-contents-first"); |
| this._secondElement = this.element.createChild("div", "split-view-contents scroll-target split-view-contents-second"); |
| |
| this._resizerElement = this.element.createChild("div", "split-view-resizer"); |
| this.installResizer(this._resizerElement); |
| this._resizable = true; |
| |
| this._savedSidebarWidth = defaultSidebarWidth || 200; |
| this._savedSidebarHeight = defaultSidebarHeight || this._savedSidebarWidth; |
| |
| if (0 < this._savedSidebarWidth && this._savedSidebarWidth < 1 && |
| 0 < this._savedSidebarHeight && this._savedSidebarHeight < 1) |
| this._useFraction = true; |
| |
| this._sidebarSizeSettingName = sidebarSizeSettingName; |
| |
| this.setSecondIsSidebar(true); |
| |
| this._innerSetVertical(isVertical); |
| } |
| |
| WebInspector.SplitView.prototype = { |
| /** |
| * @return {boolean} |
| */ |
| isVertical: function() |
| { |
| return this._isVertical; |
| }, |
| |
| /** |
| * @param {boolean} isVertical |
| */ |
| setVertical: function(isVertical) |
| { |
| if (this._isVertical === isVertical) |
| return; |
| |
| this._innerSetVertical(isVertical); |
| |
| if (this.isShowing()) |
| this._updateLayout(); |
| }, |
| |
| /** |
| * @param {boolean} isVertical |
| */ |
| _innerSetVertical: function(isVertical) |
| { |
| this.element.removeStyleClass(this._isVertical ? "split-view-vertical" : "split-view-horizontal"); |
| this._isVertical = isVertical; |
| this.element.addStyleClass(this._isVertical ? "split-view-vertical" : "split-view-horizontal"); |
| delete this._resizerElementSize; |
| this._sidebarSize = -1; |
| }, |
| |
| _updateLayout: function() |
| { |
| delete this._totalSize; // Lazy update. |
| this._innerSetSidebarSize(this._lastSidebarSize()); |
| }, |
| |
| /** |
| * @return {Element} |
| */ |
| firstElement: function() |
| { |
| return this._firstElement; |
| }, |
| |
| /** |
| * @return {Element} |
| */ |
| secondElement: function() |
| { |
| return this._secondElement; |
| }, |
| |
| /** |
| * @return {Element} |
| */ |
| get mainElement() |
| { |
| return this.isSidebarSecond() ? this.firstElement() : this.secondElement(); |
| }, |
| |
| /** |
| * @return {Element} |
| */ |
| get sidebarElement() |
| { |
| return this.isSidebarSecond() ? this.secondElement() : this.firstElement(); |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| isSidebarSecond: function() |
| { |
| return this._secondIsSidebar; |
| }, |
| |
| /** |
| * @param {boolean} secondIsSidebar |
| */ |
| setSecondIsSidebar: function(secondIsSidebar) |
| { |
| this.sidebarElement.removeStyleClass("split-view-sidebar"); |
| this._secondIsSidebar = secondIsSidebar; |
| this.sidebarElement.addStyleClass("split-view-sidebar"); |
| }, |
| |
| /** |
| * @return {Element} |
| */ |
| resizerElement: function() |
| { |
| return this._resizerElement; |
| }, |
| |
| showOnlyFirst: function() |
| { |
| this._showOnly(this._firstElement, this._secondElement); |
| }, |
| |
| showOnlySecond: function() |
| { |
| this._showOnly(this._secondElement, this._firstElement); |
| }, |
| |
| /** |
| * @param {Element} sideA |
| * @param {Element} sideB |
| */ |
| _showOnly: function(sideA, sideB) |
| { |
| sideA.removeStyleClass("hidden"); |
| sideA.addStyleClass("maximized"); |
| sideB.addStyleClass("hidden"); |
| sideB.removeStyleClass("maximized"); |
| this._removeAllLayoutProperties(); |
| |
| this._isShowingOne = true; |
| this._sidebarSize = -1; |
| this.setResizable(false); |
| this.doResize(); |
| }, |
| |
| _removeAllLayoutProperties: function() |
| { |
| this._firstElement.style.removeProperty("right"); |
| this._firstElement.style.removeProperty("bottom"); |
| this._firstElement.style.removeProperty("width"); |
| this._firstElement.style.removeProperty("height"); |
| |
| this._secondElement.style.removeProperty("left"); |
| this._secondElement.style.removeProperty("top"); |
| this._secondElement.style.removeProperty("width"); |
| this._secondElement.style.removeProperty("height"); |
| |
| this._resizerElement.style.removeProperty("left"); |
| this._resizerElement.style.removeProperty("right"); |
| this._resizerElement.style.removeProperty("top"); |
| this._resizerElement.style.removeProperty("bottom"); |
| |
| this._resizerElement.style.removeProperty("margin-left"); |
| this._resizerElement.style.removeProperty("margin-right"); |
| this._resizerElement.style.removeProperty("margin-top"); |
| this._resizerElement.style.removeProperty("margin-bottom"); |
| }, |
| |
| showBoth: function() |
| { |
| this._firstElement.removeStyleClass("hidden"); |
| this._firstElement.removeStyleClass("maximized"); |
| this._secondElement.removeStyleClass("hidden"); |
| this._secondElement.removeStyleClass("maximized"); |
| |
| this._isShowingOne = false; |
| this._sidebarSize = -1; |
| this.setResizable(true); |
| this.doResize(); |
| }, |
| |
| /** |
| * @param {boolean} resizable |
| */ |
| setResizable: function(resizable) |
| { |
| this._resizable = resizable; |
| this._resizerElement.enableStyleClass("hidden", !resizable); |
| }, |
| |
| /** |
| * @param {number} size |
| */ |
| setSidebarSize: function(size) |
| { |
| this._innerSetSidebarSize(size); |
| this._saveSidebarSize(); |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| sidebarSize: function() |
| { |
| return Math.max(0, this._sidebarSize); |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| totalSize: function() |
| { |
| if (!this._totalSize) |
| this._totalSize = this._isVertical ? this.element.offsetWidth : this.element.offsetHeight; |
| return this._totalSize; |
| }, |
| |
| /** |
| * @param {number} size |
| */ |
| _innerSetSidebarSize: function(size) |
| { |
| if (this._isShowingOne) { |
| this._sidebarSize = size; |
| return; |
| } |
| |
| size = this._applyConstraints(size); |
| if (this._sidebarSize === size) |
| return; |
| |
| if (size < 0) { |
| // Never apply bad values, fix it upon onResize instead. |
| return; |
| } |
| |
| this._removeAllLayoutProperties(); |
| |
| var sizeValue; |
| if (this._useFraction) |
| sizeValue = (size / this.totalSize()) * 100 + "%"; |
| else |
| sizeValue = size + "px"; |
| |
| if (!this._resizerElementSize) |
| this._resizerElementSize = this._isVertical ? this._resizerElement.offsetWidth : this._resizerElement.offsetHeight; |
| |
| if (this._isVertical) { |
| if (this._secondIsSidebar) { |
| this._firstElement.style.right = sizeValue; |
| this._secondElement.style.width = sizeValue; |
| this._resizerElement.style.right = sizeValue; |
| this._resizerElement.style.marginRight = -this._resizerElementSize / 2 + "px"; |
| } else { |
| this._firstElement.style.width = sizeValue; |
| this._secondElement.style.left = sizeValue; |
| this._resizerElement.style.left = sizeValue; |
| this._resizerElement.style.marginLeft = -this._resizerElementSize / 2 + "px"; |
| } |
| } else { |
| if (this._secondIsSidebar) { |
| this._firstElement.style.bottom = sizeValue; |
| this._secondElement.style.height = sizeValue; |
| this._resizerElement.style.bottom = sizeValue; |
| this._resizerElement.style.marginBottom = -this._resizerElementSize / 2 + "px"; |
| } else { |
| this._firstElement.style.height = sizeValue; |
| this._secondElement.style.top = sizeValue; |
| this._resizerElement.style.top = sizeValue; |
| this._resizerElement.style.marginTop = -this._resizerElementSize / 2 + "px"; |
| } |
| } |
| |
| this._sidebarSize = size; |
| |
| // No need to recalculate this._sidebarSize and this._totalSize again. |
| this._muteOnResize = true; |
| this.doResize(); |
| delete this._muteOnResize; |
| }, |
| |
| /** |
| * @param {number=} minWidth |
| * @param {number=} minHeight |
| */ |
| setSidebarElementConstraints: function(minWidth, minHeight) |
| { |
| if (typeof minWidth === "number") |
| this._minimumSidebarWidth = minWidth; |
| if (typeof minHeight === "number") |
| this._minimumSidebarHeight = minHeight; |
| }, |
| |
| /** |
| * @param {number=} minWidth |
| * @param {number=} minHeight |
| */ |
| setMainElementConstraints: function(minWidth, minHeight) |
| { |
| if (typeof minWidth === "number") |
| this._minimumMainWidth = minWidth; |
| if (typeof minHeight === "number") |
| this._minimumMainHeight = minHeight; |
| }, |
| |
| /** |
| * @param {number} sidebarSize |
| * @return {number} |
| */ |
| _applyConstraints: function(sidebarSize) |
| { |
| const minPadding = 20; |
| var totalSize = this.totalSize(); |
| var from = (this.isVertical() ? this._minimumSidebarWidth : this._minimumSidebarHeight) || 0; |
| var fromInPercents = false; |
| if (from && from < 1) { |
| fromInPercents = true; |
| from = Math.round(totalSize * from); |
| } |
| from = Math.max(from, minPadding); |
| |
| var minMainSize = (this.isVertical() ? this._minimumMainWidth : this._minimumMainHeight) || 0; |
| var toInPercents = false; |
| if (minMainSize && minMainSize < 1) { |
| toInPercents = true; |
| minMainSize = Math.round(totalSize * minMainSize); |
| } |
| minMainSize = Math.max(minMainSize, minPadding); |
| |
| var to = totalSize - minMainSize; |
| if (from <= to) |
| return Number.constrain(sidebarSize, from, to); |
| |
| // Respect fixed constraints over percents. This will, for example, shrink |
| // the sidebar to its minimum size when possible. |
| if (!fromInPercents && !toInPercents) |
| return -1; |
| if (toInPercents && sidebarSize >= from && from < totalSize) |
| return from; |
| if (fromInPercents && sidebarSize <= to && to < totalSize) |
| return to; |
| |
| return -1; |
| }, |
| |
| wasShown: function() |
| { |
| this._updateLayout(); |
| }, |
| |
| onResize: function() |
| { |
| if (this._muteOnResize) |
| return; |
| this._updateLayout(); |
| }, |
| |
| /** |
| * @param {Event} event |
| * @return {boolean} |
| */ |
| _startResizerDragging: function(event) |
| { |
| if (!this._resizable) |
| return false; |
| |
| this._saveSidebarSizeRecursively(); |
| this._dragOffset = (this._secondIsSidebar ? this.totalSize() - this._sidebarSize : this._sidebarSize) - (this._isVertical ? event.pageX : event.pageY); |
| return true; |
| }, |
| |
| /** |
| * @param {Event} event |
| */ |
| _resizerDragging: function(event) |
| { |
| var newOffset = (this._isVertical ? event.pageX : event.pageY) + this._dragOffset; |
| var newSize = (this._secondIsSidebar ? this.totalSize() - newOffset : newOffset); |
| this.setSidebarSize(newSize); |
| event.preventDefault(); |
| }, |
| |
| /** |
| * @param {Event} event |
| */ |
| _endResizerDragging: function(event) |
| { |
| delete this._dragOffset; |
| this._saveSidebarSizeRecursively(); |
| }, |
| |
| _saveSidebarSizeRecursively: function() |
| { |
| /** @this {WebInspector.View} */ |
| function doSaveSidebarSizeRecursively() |
| { |
| if (this._saveSidebarSize) |
| this._saveSidebarSize(); |
| this._callOnVisibleChildren(doSaveSidebarSizeRecursively); |
| } |
| this._saveSidebarSize(); |
| this._callOnVisibleChildren(doSaveSidebarSizeRecursively); |
| }, |
| |
| /** |
| * @param {Element} resizerElement |
| */ |
| installResizer: function(resizerElement) |
| { |
| resizerElement.addEventListener("mousedown", this._onDragStart.bind(this), false); |
| }, |
| |
| /** |
| * |
| * @param {Event} event |
| */ |
| _onDragStart: function(event) |
| { |
| WebInspector._elementDragStart(this._startResizerDragging.bind(this), this._resizerDragging.bind(this), this._endResizerDragging.bind(this), this._isVertical ? "ew-resize" : "ns-resize", event); |
| }, |
| |
| /** |
| * @return {WebInspector.Setting} |
| */ |
| _sizeSetting: function() |
| { |
| if (!this._sidebarSizeSettingName) |
| return null; |
| |
| var settingName = this._sidebarSizeSettingName + (this._isVertical ? "" : "H"); |
| if (!WebInspector.settings[settingName]) |
| WebInspector.settings[settingName] = WebInspector.settings.createSetting(settingName, undefined); |
| |
| return WebInspector.settings[settingName]; |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| _lastSidebarSize: function() |
| { |
| var sizeSetting = this._sizeSetting(); |
| var size = sizeSetting ? sizeSetting.get() : 0; |
| if (!size) |
| size = this._isVertical ? this._savedSidebarWidth : this._savedSidebarHeight; |
| if (this._useFraction) |
| size *= this.totalSize(); |
| return size; |
| }, |
| |
| _saveSidebarSize: function() |
| { |
| var size = this._sidebarSize; |
| if (size < 0) |
| return; |
| |
| if (this._useFraction) |
| size /= this.totalSize(); |
| |
| if (this._isVertical) |
| this._savedSidebarWidth = size; |
| else |
| this._savedSidebarHeight = size; |
| |
| var sizeSetting = this._sizeSetting(); |
| if (sizeSetting) |
| sizeSetting.set(size); |
| }, |
| |
| __proto__: WebInspector.View.prototype |
| } |