/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const React = require("devtools/client/shared/vendor/react"); const ReactDOM = require("devtools/client/shared/vendor/react-dom"); const Draggable = React.createFactory(require("devtools/client/shared/components/splitter/draggable")); const { DOM: dom, PropTypes } = React; /** * This component represents a Splitter. The splitter supports vertical * as well as horizontal mode. */ const SplitBox = React.createClass({ displayName: "SplitBox", propTypes: { // Custom class name. You can use more names separated by a space. className: PropTypes.string, // Initial size of controlled panel. initialSize: PropTypes.number, // Left/top panel startPanel: PropTypes.any, // Min panel size. minSize: PropTypes.number, // Max panel size. maxSize: PropTypes.number, // Right/bottom panel endPanel: PropTypes.any, // True if the right/bottom panel should be controlled. endPanelControl: PropTypes.bool, // Size of the splitter handle bar. splitterSize: PropTypes.number, // True if the splitter bar is vertical (default is vertical). vert: PropTypes.bool }, getDefaultProps() { return { splitterSize: 5, vert: true, endPanelControl: false }; }, /** * The state stores the current orientation (vertical or horizontal) * and the current size (width/height). All these values can change * during the component's life time. */ getInitialState() { return { vert: this.props.vert, width: this.props.initialWidth || this.props.initialSize, height: this.props.initialHeight || this.props.initialSize }; }, // Dragging Events /** * Set 'resizing' cursor on entire document during splitter dragging. * This avoids cursor-flickering that happens when the mouse leaves * the splitter bar area (happens frequently). */ onStartMove() { const splitBox = ReactDOM.findDOMNode(this); const doc = splitBox.ownerDocument; let defaultCursor = doc.documentElement.style.cursor; doc.documentElement.style.cursor = (this.state.vert ? "ew-resize" : "ns-resize"); splitBox.classList.add("dragging"); this.setState({ defaultCursor: defaultCursor }); }, onStopMove() { const splitBox = ReactDOM.findDOMNode(this); const doc = splitBox.ownerDocument; doc.documentElement.style.cursor = this.state.defaultCursor; splitBox.classList.remove("dragging"); }, /** * Adjust size of the controlled panel. Depending on the current * orientation we either remember the width or height of * the splitter box. */ onMove(x, y) { const node = ReactDOM.findDOMNode(this); const doc = node.ownerDocument; const win = doc.defaultView; let size; let { endPanelControl } = this.props; if (this.state.vert) { // Switch the control flag in case of RTL. Note that RTL // has impact on vertical splitter only. let dir = win.getComputedStyle(doc.documentElement).direction; if (dir == "rtl") { endPanelControl = !endPanelControl; } size = endPanelControl ? (node.offsetLeft + node.offsetWidth) - x : x - node.offsetLeft; this.setState({ width: size }); } else { size = endPanelControl ? (node.offsetTop + node.offsetHeight) - y : y - node.offsetTop; this.setState({ height: size }); } }, // Rendering render() { const vert = this.state.vert; const { startPanel, endPanel, endPanelControl, minSize, maxSize, splitterSize } = this.props; let style = Object.assign({}, this.props.style); // Calculate class names list. let classNames = ["split-box"]; classNames.push(vert ? "vert" : "horz"); if (this.props.className) { classNames = classNames.concat(this.props.className.split(" ")); } let leftPanelStyle; let rightPanelStyle; // Set proper size for panels depending on the current state. if (vert) { leftPanelStyle = { maxWidth: endPanelControl ? null : maxSize, minWidth: endPanelControl ? null : minSize, width: endPanelControl ? null : this.state.width }; rightPanelStyle = { maxWidth: endPanelControl ? maxSize : null, minWidth: endPanelControl ? minSize : null, width: endPanelControl ? this.state.width : null }; } else { leftPanelStyle = { maxHeight: endPanelControl ? null : maxSize, minHeight: endPanelControl ? null : minSize, height: endPanelControl ? null : this.state.height }; rightPanelStyle = { maxHeight: endPanelControl ? maxSize : null, minHeight: endPanelControl ? minSize : null, height: endPanelControl ? this.state.height : null }; } // Calculate splitter size let splitterStyle = { flex: "0 0 " + splitterSize + "px" }; return ( dom.div({ className: classNames.join(" "), style: style }, startPanel ? dom.div({ className: endPanelControl ? "uncontrolled" : "controlled", style: leftPanelStyle}, startPanel ) : null, Draggable({ className: "splitter", style: splitterStyle, onStart: this.onStartMove, onStop: this.onStopMove, onMove: this.onMove }), endPanel ? dom.div({ className: endPanelControl ? "controlled" : "uncontrolled", style: rightPanelStyle}, endPanel ) : null ) ); } }); module.exports = SplitBox;