| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 | /* * 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}
 |