You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-04 11:51:45 +03:00 
			
		
		
		
	Merge branch 'experimental' into nadonomy/icons
This commit is contained in:
		@@ -19,14 +19,14 @@ limitations under the License.
 | 
			
		||||
   each with a flex-shrink difference of 4 order of magnitude,
 | 
			
		||||
   so they ideally wouldn't affect each other.
 | 
			
		||||
   lowest category: .mx_RoomSubList
 | 
			
		||||
        flex:-shrink: 10000000
 | 
			
		||||
        flex-shrink: 10000000
 | 
			
		||||
        distribute size of items within the same categery by their size
 | 
			
		||||
   middle category: .mx_RoomSubList.resized-sized
 | 
			
		||||
        flex:-shrink: 1000
 | 
			
		||||
        flex-shrink: 1000
 | 
			
		||||
        applied when using the resizer, will have a max-height set to it,
 | 
			
		||||
        to limit the size
 | 
			
		||||
   highest category: .mx_RoomSubList.resized-all
 | 
			
		||||
        flex:-shrink: 1
 | 
			
		||||
        flex-shrink: 1
 | 
			
		||||
        small flex-shrink value (1), is only added if you can drag the resizer so far
 | 
			
		||||
        so in practice you can only assign this category if there is enough space.
 | 
			
		||||
*/
 | 
			
		||||
@@ -39,7 +39,7 @@ limitations under the License.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_RoomSubList_nonEmpty {
 | 
			
		||||
    min-height: 76px;
 | 
			
		||||
    min-height: 70px;
 | 
			
		||||
 | 
			
		||||
    .mx_AutoHideScrollbar_offset {
 | 
			
		||||
        padding-bottom: 4px;
 | 
			
		||||
@@ -154,7 +154,7 @@ limitations under the License.
 | 
			
		||||
        position: sticky;
 | 
			
		||||
        left: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        height: 40px;
 | 
			
		||||
        height: 30px;
 | 
			
		||||
        content: "";
 | 
			
		||||
        display: block;
 | 
			
		||||
        z-index: 100;
 | 
			
		||||
@@ -162,10 +162,10 @@ limitations under the License.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.mx_IndicatorScrollbar_topOverflow > .mx_AutoHideScrollbar_offset {
 | 
			
		||||
        margin-top: -40px;
 | 
			
		||||
        margin-top: -30px;
 | 
			
		||||
    }
 | 
			
		||||
    &.mx_IndicatorScrollbar_bottomOverflow > .mx_AutoHideScrollbar_offset {
 | 
			
		||||
        margin-bottom: -40px;
 | 
			
		||||
        margin-bottom: -30px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.mx_IndicatorScrollbar_topOverflow::before {
 | 
			
		||||
 
 | 
			
		||||
@@ -192,9 +192,11 @@ $progressbar-color: #000;
 | 
			
		||||
// it has the appearance of a text box so the controls
 | 
			
		||||
// appear to be part of the input
 | 
			
		||||
 | 
			
		||||
:not(.mx_textinput) > input[type=text],
 | 
			
		||||
:not(.mx_textinput) > input[type=search],
 | 
			
		||||
.mx_textinput {
 | 
			
		||||
.mx_MatrixChat {
 | 
			
		||||
 | 
			
		||||
    :not(.mx_textinput) > input[type=text],
 | 
			
		||||
    :not(.mx_textinput) > input[type=search],
 | 
			
		||||
    .mx_textinput {
 | 
			
		||||
        display: block;
 | 
			
		||||
        margin: 9px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
@@ -202,22 +204,25 @@ $progressbar-color: #000;
 | 
			
		||||
        color: $input-darker-fg-color;
 | 
			
		||||
        border-radius: 4px;
 | 
			
		||||
        border: 1px solid #c1c1c1;
 | 
			
		||||
}
 | 
			
		||||
        flex: 0 0 auto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
.mx_textinput {
 | 
			
		||||
    .mx_textinput {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.mx_textinput > input[type=text],
 | 
			
		||||
.mx_textinput > input[type=search] {
 | 
			
		||||
        > input[type=text],
 | 
			
		||||
        > input[type=search] {
 | 
			
		||||
            border: none;
 | 
			
		||||
            flex: 1;
 | 
			
		||||
            color: inherit; //from .mx_textinput
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input[type=text],
 | 
			
		||||
input[type=search] {
 | 
			
		||||
input[type=search],
 | 
			
		||||
input[type=password] {
 | 
			
		||||
    padding: 9px;
 | 
			
		||||
    font-family: $font-family;
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ export default class AutoHideScrollbar extends React.Component {
 | 
			
		||||
        this.onOverflow = this.onOverflow.bind(this);
 | 
			
		||||
        this.onUnderflow = this.onUnderflow.bind(this);
 | 
			
		||||
        this._collectContainerRef = this._collectContainerRef.bind(this);
 | 
			
		||||
        this._needsOverflowListener = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onOverflow() {
 | 
			
		||||
@@ -81,36 +82,49 @@ export default class AutoHideScrollbar extends React.Component {
 | 
			
		||||
        this.containerRef.classList.add("mx_AutoHideScrollbar_underflow");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _collectContainerRef(ref) {
 | 
			
		||||
        if (ref && !this.containerRef) {
 | 
			
		||||
            this.containerRef = ref;
 | 
			
		||||
            const needsOverflowListener =
 | 
			
		||||
                document.body.classList.contains("mx_scrollbar_nooverlay");
 | 
			
		||||
 | 
			
		||||
            if (needsOverflowListener) {
 | 
			
		||||
                this.containerRef.addEventListener("overflow", this.onOverflow);
 | 
			
		||||
                this.containerRef.addEventListener("underflow", this.onUnderflow);
 | 
			
		||||
    checkOverflow() {
 | 
			
		||||
        if (!this._needsOverflowListener) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
            if (ref.scrollHeight > ref.clientHeight) {
 | 
			
		||||
        if (this.containerRef.scrollHeight > this.containerRef.clientHeight) {
 | 
			
		||||
            this.onOverflow();
 | 
			
		||||
        } else {
 | 
			
		||||
            this.onUnderflow();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidUpdate() {
 | 
			
		||||
        this.checkOverflow();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        installBodyClassesIfNeeded();
 | 
			
		||||
        this._needsOverflowListener =
 | 
			
		||||
            document.body.classList.contains("mx_scrollbar_nooverlay");
 | 
			
		||||
        if (this._needsOverflowListener) {
 | 
			
		||||
            this.containerRef.addEventListener("overflow", this.onOverflow);
 | 
			
		||||
            this.containerRef.addEventListener("underflow", this.onUnderflow);
 | 
			
		||||
        }
 | 
			
		||||
        this.checkOverflow();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _collectContainerRef(ref) {
 | 
			
		||||
        if (ref && !this.containerRef) {
 | 
			
		||||
            this.containerRef = ref;
 | 
			
		||||
        }
 | 
			
		||||
        if (this.props.wrappedRef) {
 | 
			
		||||
            this.props.wrappedRef(ref);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        if (this.containerRef) {
 | 
			
		||||
        if (this._needsOverflowListener && this.containerRef) {
 | 
			
		||||
            this.containerRef.removeEventListener("overflow", this.onOverflow);
 | 
			
		||||
            this.containerRef.removeEventListener("underflow", this.onUnderflow);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        installBodyClassesIfNeeded();
 | 
			
		||||
        return (<div
 | 
			
		||||
                    ref={this._collectContainerRef}
 | 
			
		||||
                    className={["mx_AutoHideScrollbar", this.props.className].join(" ")}
 | 
			
		||||
 
 | 
			
		||||
@@ -1272,15 +1272,6 @@ export default React.createClass({
 | 
			
		||||
                        <TintableSvg src="img/icons-share.svg" width="16" height="16" />
 | 
			
		||||
                    </AccessibleButton>,
 | 
			
		||||
                );
 | 
			
		||||
                if (this.props.collapsedRhs) {
 | 
			
		||||
                    rightButtons.push(
 | 
			
		||||
                        <AccessibleButton className="mx_GroupHeader_button"
 | 
			
		||||
                            onClick={this._onShowRhsClick} title={_t('Show panel')} key="_maximiseButton"
 | 
			
		||||
                        >
 | 
			
		||||
                            <TintableSvg src="img/maximise.svg" width="10" height="16" />
 | 
			
		||||
                        </AccessibleButton>,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const rightPanel = !this.props.collapsedRhs ? <RightPanel groupId={this.props.groupId} /> : undefined;
 | 
			
		||||
@@ -1311,7 +1302,7 @@ export default React.createClass({
 | 
			
		||||
                        <div className="mx_GroupView_header_rightCol">
 | 
			
		||||
                            { rightButtons }
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <GroupHeaderButtons />
 | 
			
		||||
                        <GroupHeaderButtons collapsedRhs={this.props.collapsedRhs} />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <MainSplit collapsedRhs={this.props.collapsedRhs} panel={rightPanel}>
 | 
			
		||||
                        <GeminiScrollbarWrapper className="mx_GroupView_body">
 | 
			
		||||
 
 | 
			
		||||
@@ -21,41 +21,52 @@ export default class IndicatorScrollbar extends React.Component {
 | 
			
		||||
    constructor(props) {
 | 
			
		||||
        super(props);
 | 
			
		||||
        this._collectScroller = this._collectScroller.bind(this);
 | 
			
		||||
        this._collectScrollerComponent = this._collectScrollerComponent.bind(this);
 | 
			
		||||
        this.checkOverflow = this.checkOverflow.bind(this);
 | 
			
		||||
        this._scrollElement = null;
 | 
			
		||||
        this._autoHideScrollbar = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _collectScroller(scroller) {
 | 
			
		||||
        if (scroller && !this._scroller) {
 | 
			
		||||
            this._scroller = scroller;
 | 
			
		||||
            this._scroller.addEventListener("scroll", this.checkOverflow);
 | 
			
		||||
        if (scroller && !this._scrollElement) {
 | 
			
		||||
            this._scrollElement = scroller;
 | 
			
		||||
            this._scrollElement.addEventListener("scroll", this.checkOverflow);
 | 
			
		||||
            this.checkOverflow();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _collectScrollerComponent(autoHideScrollbar) {
 | 
			
		||||
        this._autoHideScrollbar = autoHideScrollbar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    checkOverflow() {
 | 
			
		||||
        const hasTopOverflow = this._scroller.scrollTop > 0;
 | 
			
		||||
        const hasBottomOverflow = this._scroller.scrollHeight >
 | 
			
		||||
            (this._scroller.scrollTop + this._scroller.clientHeight);
 | 
			
		||||
        const hasTopOverflow = this._scrollElement.scrollTop > 0;
 | 
			
		||||
        const hasBottomOverflow = this._scrollElement.scrollHeight >
 | 
			
		||||
            (this._scrollElement.scrollTop + this._scrollElement.clientHeight);
 | 
			
		||||
        if (hasTopOverflow) {
 | 
			
		||||
            this._scroller.classList.add("mx_IndicatorScrollbar_topOverflow");
 | 
			
		||||
            this._scrollElement.classList.add("mx_IndicatorScrollbar_topOverflow");
 | 
			
		||||
        } else {
 | 
			
		||||
            this._scroller.classList.remove("mx_IndicatorScrollbar_topOverflow");
 | 
			
		||||
            this._scrollElement.classList.remove("mx_IndicatorScrollbar_topOverflow");
 | 
			
		||||
        }
 | 
			
		||||
        if (hasBottomOverflow) {
 | 
			
		||||
            this._scroller.classList.add("mx_IndicatorScrollbar_bottomOverflow");
 | 
			
		||||
            this._scrollElement.classList.add("mx_IndicatorScrollbar_bottomOverflow");
 | 
			
		||||
        } else {
 | 
			
		||||
            this._scroller.classList.remove("mx_IndicatorScrollbar_bottomOverflow");
 | 
			
		||||
            this._scrollElement.classList.remove("mx_IndicatorScrollbar_bottomOverflow");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._autoHideScrollbar) {
 | 
			
		||||
            this._autoHideScrollbar.checkOverflow();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentWillUnmount() {
 | 
			
		||||
        if (this._scroller) {
 | 
			
		||||
            this._scroller.removeEventListener("scroll", this.checkOverflow);
 | 
			
		||||
        if (this._scrollElement) {
 | 
			
		||||
            this._scrollElement.removeEventListener("scroll", this.checkOverflow);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        return (<AutoHideScrollbar wrappedRef={this._collectScroller} {... this.props}>
 | 
			
		||||
        return (<AutoHideScrollbar ref={this._collectScrollerComponent} wrappedRef={this._collectScroller} {... this.props}>
 | 
			
		||||
            { this.props.children }
 | 
			
		||||
        </AutoHideScrollbar>);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ const LoggedInView = React.createClass({
 | 
			
		||||
        // Called with the credentials of a registered user (if they were a ROU that
 | 
			
		||||
        // transitioned to PWLU)
 | 
			
		||||
        onRegistered: PropTypes.func,
 | 
			
		||||
 | 
			
		||||
        collapsedRhs: PropTypes.bool,
 | 
			
		||||
        teamToken: PropTypes.string,
 | 
			
		||||
 | 
			
		||||
        // Used by the RoomView to handle joining rooms
 | 
			
		||||
@@ -438,7 +438,7 @@ const LoggedInView = React.createClass({
 | 
			
		||||
                        eventPixelOffset={this.props.initialEventPixelOffset}
 | 
			
		||||
                        key={this.props.currentRoomId || 'roomview'}
 | 
			
		||||
                        disabled={this.props.middleDisabled}
 | 
			
		||||
                        collapsedRhs={this.props.collapseRhs}
 | 
			
		||||
                        collapsedRhs={this.props.collapsedRhs}
 | 
			
		||||
                        ConferenceHandler={this.props.ConferenceHandler}
 | 
			
		||||
                    />;
 | 
			
		||||
                break;
 | 
			
		||||
@@ -488,7 +488,7 @@ const LoggedInView = React.createClass({
 | 
			
		||||
                page_element = <GroupView
 | 
			
		||||
                    groupId={this.props.currentGroupId}
 | 
			
		||||
                    isNew={this.props.currentGroupIsNew}
 | 
			
		||||
                    collapsedRhs={this.props.collapseRhs}
 | 
			
		||||
                    collapsedRhs={this.props.collapsedRhs}
 | 
			
		||||
                />;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -41,10 +41,13 @@ export default class MainSplit extends React.Component {
 | 
			
		||||
            {onResized: this._onResized},
 | 
			
		||||
        );
 | 
			
		||||
        resizer.setClassNames(classNames);
 | 
			
		||||
        const rhsSize = window.localStorage.getItem("mx_rhs_size");
 | 
			
		||||
        let rhsSize = window.localStorage.getItem("mx_rhs_size");
 | 
			
		||||
        if (rhsSize !== null) {
 | 
			
		||||
            resizer.forHandleAt(0).resize(parseInt(rhsSize, 10));
 | 
			
		||||
            rhsSize = parseInt(rhsSize, 10);
 | 
			
		||||
        } else {
 | 
			
		||||
            rhsSize = 350;
 | 
			
		||||
        }
 | 
			
		||||
        resizer.forHandleAt(0).resize(rhsSize);
 | 
			
		||||
 | 
			
		||||
        resizer.attach();
 | 
			
		||||
        this.resizer = resizer;
 | 
			
		||||
@@ -55,7 +58,7 @@ export default class MainSplit extends React.Component {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    componentDidMount() {
 | 
			
		||||
        if (this.props.panel && !this.collapsedRhs) {
 | 
			
		||||
        if (this.props.panel && !this.props.collapsedRhs) {
 | 
			
		||||
            this._createResizer();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ export default React.createClass({
 | 
			
		||||
            viewUserId: null,
 | 
			
		||||
 | 
			
		||||
            collapseLhs: false,
 | 
			
		||||
            collapseRhs: false,
 | 
			
		||||
            collapsedRhs: window.localStorage.getItem("mx_rhs_collapsed") === "true",
 | 
			
		||||
            leftDisabled: false,
 | 
			
		||||
            middleDisabled: false,
 | 
			
		||||
            rightDisabled: false,
 | 
			
		||||
@@ -555,7 +555,7 @@ export default React.createClass({
 | 
			
		||||
                break;
 | 
			
		||||
            case 'view_user':
 | 
			
		||||
                // FIXME: ugly hack to expand the RightPanel and then re-dispatch.
 | 
			
		||||
                if (this.state.collapseRhs) {
 | 
			
		||||
                if (this.state.collapsedRhs) {
 | 
			
		||||
                    setTimeout(()=>{
 | 
			
		||||
                        dis.dispatch({
 | 
			
		||||
                            action: 'show_right_panel',
 | 
			
		||||
@@ -656,13 +656,15 @@ export default React.createClass({
 | 
			
		||||
                });
 | 
			
		||||
                break;
 | 
			
		||||
            case 'hide_right_panel':
 | 
			
		||||
                window.localStorage.setItem("mx_rhs_collapsed", true);
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    collapseRhs: true,
 | 
			
		||||
                    collapsedRhs: true,
 | 
			
		||||
                });
 | 
			
		||||
                break;
 | 
			
		||||
            case 'show_right_panel':
 | 
			
		||||
                window.localStorage.setItem("mx_rhs_collapsed", false);
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    collapseRhs: false,
 | 
			
		||||
                    collapsedRhs: false,
 | 
			
		||||
                });
 | 
			
		||||
                break;
 | 
			
		||||
            case 'panel_disable': {
 | 
			
		||||
@@ -1217,7 +1219,7 @@ export default React.createClass({
 | 
			
		||||
            view: VIEWS.LOGIN,
 | 
			
		||||
            ready: false,
 | 
			
		||||
            collapseLhs: false,
 | 
			
		||||
            collapseRhs: false,
 | 
			
		||||
            collapsedRhs: false,
 | 
			
		||||
            currentRoomId: null,
 | 
			
		||||
            page_type: PageTypes.RoomDirectory,
 | 
			
		||||
        });
 | 
			
		||||
 
 | 
			
		||||
@@ -110,8 +110,9 @@ const RoomSubList = React.createClass({
 | 
			
		||||
        if (this.isCollapsableOnClick()) {
 | 
			
		||||
            // The header isCollapsable, so the click is to be interpreted as collapse and truncation logic
 | 
			
		||||
            const isHidden = !this.state.hidden;
 | 
			
		||||
            this.setState({hidden: isHidden});
 | 
			
		||||
            this.setState({hidden: isHidden}, () => {
 | 
			
		||||
                this.props.onHeaderClick(isHidden);
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // The header is stuck, so the click is to be interpreted as a scroll to the header
 | 
			
		||||
            this.props.onHeaderClick(this.state.hidden, this.refs.header.dataset.originalPosition);
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,6 @@ module.exports = React.createClass({
 | 
			
		||||
            case 'focus_room_filter':
 | 
			
		||||
                if (this.refs.search) {
 | 
			
		||||
                    this.refs.search.focus();
 | 
			
		||||
                    this.refs.search.select();
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -83,6 +82,10 @@ module.exports = React.createClass({
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onFocus: function(ev) {
 | 
			
		||||
        ev.target.select();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearSearch: function(source) {
 | 
			
		||||
        this.refs.search.value = "";
 | 
			
		||||
        this.onChange();
 | 
			
		||||
@@ -108,6 +111,7 @@ module.exports = React.createClass({
 | 
			
		||||
                    ref="search"
 | 
			
		||||
                    className="mx_textinput_icon mx_textinput_search"
 | 
			
		||||
                    value={ this.state.searchTerm }
 | 
			
		||||
                    onFocus={ this._onFocus }
 | 
			
		||||
                    onChange={ this.onChange }
 | 
			
		||||
                    onKeyDown={ this._onKeyDown }
 | 
			
		||||
                    placeholder={ _t('Filter room names') }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ const ResizeHandle = (props) => {
 | 
			
		||||
ResizeHandle.propTypes = {
 | 
			
		||||
    vertical: PropTypes.bool,
 | 
			
		||||
    reverse: PropTypes.bool,
 | 
			
		||||
    id: PropTypes.string,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default ResizeHandle;
 | 
			
		||||
 
 | 
			
		||||
@@ -55,23 +55,23 @@ export default class GroupHeaderButtons extends HeaderButtons {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderButtons() {
 | 
			
		||||
        const isPhaseGroup = [
 | 
			
		||||
        const groupPhases = [
 | 
			
		||||
            RightPanel.Phase.GroupMemberInfo,
 | 
			
		||||
            RightPanel.Phase.GroupMemberList,
 | 
			
		||||
        ].includes(this.state.phase);
 | 
			
		||||
        const isPhaseRoom = [
 | 
			
		||||
        ];
 | 
			
		||||
        const roomPhases = [
 | 
			
		||||
            RightPanel.Phase.GroupRoomList,
 | 
			
		||||
            RightPanel.Phase.GroupRoomInfo,
 | 
			
		||||
        ].includes(this.state.phase);
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            <HeaderButton key="_groupMembersButton" title={_t('Members')} iconSrc="img/icons-people.svg"
 | 
			
		||||
                isHighlighted={isPhaseGroup}
 | 
			
		||||
                isHighlighted={this.isPhase(groupPhases)}
 | 
			
		||||
                clickPhase={RightPanel.Phase.GroupMemberList}
 | 
			
		||||
                analytics={['Right Panel', 'Group Member List Button', 'click']}
 | 
			
		||||
            />,
 | 
			
		||||
            <HeaderButton key="_roomsButton" title={_t('Rooms')} iconSrc="img/icons-room-nobg.svg"
 | 
			
		||||
                isHighlighted={isPhaseRoom}
 | 
			
		||||
                isHighlighted={this.isPhase(roomPhases)}
 | 
			
		||||
                clickPhase={RightPanel.Phase.GroupRoomList}
 | 
			
		||||
                analytics={['Right Panel', 'Group Room List Button', 'click']}
 | 
			
		||||
            />,
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@ export default class HeaderButton extends React.Component {
 | 
			
		||||
        dis.dispatch({
 | 
			
		||||
            action: 'view_right_panel_phase',
 | 
			
		||||
            phase: this.props.clickPhase,
 | 
			
		||||
            fromHeader: true,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import dis from '../../../dispatcher';
 | 
			
		||||
 | 
			
		||||
export default class HeaderButtons extends React.Component {
 | 
			
		||||
@@ -25,7 +26,7 @@ export default class HeaderButtons extends React.Component {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            phase: initialPhase,
 | 
			
		||||
            phase: props.collapsedRhs ? null : initialPhase,
 | 
			
		||||
            isUserPrivilegedInGroup: null,
 | 
			
		||||
        };
 | 
			
		||||
        this.onAction = this.onAction.bind(this);
 | 
			
		||||
@@ -47,13 +48,44 @@ export default class HeaderButtons extends React.Component {
 | 
			
		||||
        }, extras));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isPhase(phases) {
 | 
			
		||||
        if (this.props.collapsedRhs) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (Array.isArray(phases)) {
 | 
			
		||||
            return phases.includes(this.state.phase);
 | 
			
		||||
        } else {
 | 
			
		||||
            return phases === this.state.phase;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onAction(payload) {
 | 
			
		||||
        if (payload.action === "view_right_panel_phase") {
 | 
			
		||||
            // only actions coming from header buttons should collapse the right panel
 | 
			
		||||
            if (this.state.phase === payload.phase && payload.fromHeader) {
 | 
			
		||||
                dis.dispatch({
 | 
			
		||||
                    action: 'hide_right_panel',
 | 
			
		||||
                });
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    phase: null,
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                if (this.props.collapsedRhs && payload.fromHeader) {
 | 
			
		||||
                    dis.dispatch({
 | 
			
		||||
                        action: 'show_right_panel',
 | 
			
		||||
                    });
 | 
			
		||||
                    // emit payload again as the RightPanel didn't exist up
 | 
			
		||||
                    // till show_right_panel, just without the fromHeader flag
 | 
			
		||||
                    // as that would hide the right panel again
 | 
			
		||||
                    dis.dispatch(Object.assign({}, payload, {fromHeader: false}));
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                this.setState({
 | 
			
		||||
                    phase: payload.phase,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        // inline style as this will be swapped around in future commits
 | 
			
		||||
@@ -62,3 +94,7 @@ export default class HeaderButtons extends React.Component {
 | 
			
		||||
        </div>;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HeaderButtons.propTypes = {
 | 
			
		||||
    collapsedRhs: PropTypes.bool,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -46,24 +46,24 @@ export default class RoomHeaderButtons extends HeaderButtons {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderButtons() {
 | 
			
		||||
        const isMembersPhase = [
 | 
			
		||||
        const membersPhases = [
 | 
			
		||||
            RightPanel.Phase.RoomMemberList,
 | 
			
		||||
            RightPanel.Phase.RoomMemberInfo,
 | 
			
		||||
        ].includes(this.state.phase);
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            <HeaderButton key="_membersButton" title={_t('Members')} iconSrc="img/feather-icons/user.svg"
 | 
			
		||||
                isHighlighted={isMembersPhase}
 | 
			
		||||
                isHighlighted={this.isPhase(membersPhases)}
 | 
			
		||||
                clickPhase={RightPanel.Phase.RoomMemberList}
 | 
			
		||||
                analytics={['Right Panel', 'Member List Button', 'click']}
 | 
			
		||||
            />,
 | 
			
		||||
            <HeaderButton key="_filesButton" title={_t('Files')} iconSrc="img/feather-icons/files.svg"
 | 
			
		||||
                isHighlighted={this.state.phase === RightPanel.Phase.FilePanel}
 | 
			
		||||
                isHighlighted={this.isPhase(RightPanel.Phase.FilePanel)}
 | 
			
		||||
                clickPhase={RightPanel.Phase.FilePanel}
 | 
			
		||||
                analytics={['Right Panel', 'File List Button', 'click']}
 | 
			
		||||
            />,
 | 
			
		||||
            <HeaderButton key="_notifsButton" title={_t('Notifications')} iconSrc="img/feather-icons/notifications.svg"
 | 
			
		||||
                isHighlighted={this.state.phase === RightPanel.Phase.NotificationPanel}
 | 
			
		||||
                isHighlighted={this.isPhase(RightPanel.Phase.NotificationPanel)}
 | 
			
		||||
                clickPhase={RightPanel.Phase.NotificationPanel}
 | 
			
		||||
                analytics={['Right Panel', 'Notification List Button', 'click']}
 | 
			
		||||
            />,
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ import sdk from '../../../index';
 | 
			
		||||
import { _t } from '../../../languageHandler';
 | 
			
		||||
import MatrixClientPeg from '../../../MatrixClientPeg';
 | 
			
		||||
import Modal from "../../../Modal";
 | 
			
		||||
import dis from "../../../dispatcher";
 | 
			
		||||
import RateLimitedFunc from '../../../ratelimitedfunc';
 | 
			
		||||
 | 
			
		||||
import * as linkify from 'linkifyjs';
 | 
			
		||||
@@ -146,10 +145,6 @@ module.exports = React.createClass({
 | 
			
		||||
        MatrixClientPeg.get().sendStateEvent(this.props.room.roomId, 'm.room.avatar', {url: null}, '');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onShowRhsClick: function(ev) {
 | 
			
		||||
        dis.dispatch({ action: 'show_right_panel' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onShareRoomClick: function(ev) {
 | 
			
		||||
        const ShareDialog = sdk.getComponent("dialogs.ShareDialog");
 | 
			
		||||
        Modal.createTrackedDialog('share room dialog', '', ShareDialog, {
 | 
			
		||||
@@ -394,14 +389,6 @@ module.exports = React.createClass({
 | 
			
		||||
                </AccessibleButton>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let rightPanelButtons;
 | 
			
		||||
        if (this.props.collapsedRhs) {
 | 
			
		||||
            rightPanelButtons =
 | 
			
		||||
                <AccessibleButton className="mx_RoomHeader_button mx_RoomHeader_showPanel" onClick={this.onShowRhsClick} title={_t('Show panel')}>
 | 
			
		||||
                    <TintableSvg src="img/maximise.svg" width="10" height="16" />
 | 
			
		||||
                </AccessibleButton>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let rightRow;
 | 
			
		||||
        let manageIntegsButton;
 | 
			
		||||
        if (this.props.room && this.props.room.roomId && this.props.inRoom) {
 | 
			
		||||
@@ -419,7 +406,6 @@ module.exports = React.createClass({
 | 
			
		||||
                    { manageIntegsButton }
 | 
			
		||||
                    { forgetButton }
 | 
			
		||||
                    { searchButton }
 | 
			
		||||
                    { rightPanelButtons }
 | 
			
		||||
                </div>;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -433,7 +419,7 @@ module.exports = React.createClass({
 | 
			
		||||
                    { saveButton }
 | 
			
		||||
                    { cancelButton }
 | 
			
		||||
                    { rightRow }
 | 
			
		||||
                    <RoomHeaderButtons />
 | 
			
		||||
                    <RoomHeaderButtons collapsedRhs={this.props.collapsedRhs} />
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
 
 | 
			
		||||
@@ -152,6 +152,8 @@ module.exports = React.createClass({
 | 
			
		||||
        }
 | 
			
		||||
        this.subListSizes[id] = newSize;
 | 
			
		||||
        window.localStorage.setItem("mx_roomlist_sizes", JSON.stringify(this.subListSizes));
 | 
			
		||||
        // update overflow indicators
 | 
			
		||||
        this._checkSubListsOverflow();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    componentDidMount: function() {
 | 
			
		||||
@@ -167,12 +169,10 @@ module.exports = React.createClass({
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // load stored sizes
 | 
			
		||||
        Object.entries(this.subListSizes).forEach(([id, size]) => {
 | 
			
		||||
            const handle = this.resizer.forHandleWithId(id);
 | 
			
		||||
            if (handle) {
 | 
			
		||||
                handle.resize(size);
 | 
			
		||||
            }
 | 
			
		||||
        Object.keys(this.subListSizes).forEach((key) => {
 | 
			
		||||
            this._restoreSubListSize(key);
 | 
			
		||||
        });
 | 
			
		||||
        this._checkSubListsOverflow();
 | 
			
		||||
 | 
			
		||||
        this.resizer.attach();
 | 
			
		||||
        this.mounted = true;
 | 
			
		||||
@@ -181,7 +181,11 @@ module.exports = React.createClass({
 | 
			
		||||
    componentDidUpdate: function(prevProps) {
 | 
			
		||||
        this._repositionIncomingCallBox(undefined, false);
 | 
			
		||||
        if (this.props.searchFilter !== prevProps.searchFilter) {
 | 
			
		||||
             Object.values(this._subListRefs).forEach(l => l.checkOverflow());
 | 
			
		||||
            // restore sizes
 | 
			
		||||
            Object.keys(this.subListSizes).forEach((key) => {
 | 
			
		||||
                this._restoreSubListSize(key);
 | 
			
		||||
            });
 | 
			
		||||
            this._checkSubListsOverflow();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -354,6 +358,11 @@ module.exports = React.createClass({
 | 
			
		||||
            // Do this here so as to not render every time the selected tags
 | 
			
		||||
            // themselves change.
 | 
			
		||||
            selectedTags: TagOrderStore.getSelectedTags(),
 | 
			
		||||
        }, () => {
 | 
			
		||||
            // we don't need to restore any size here, do we?
 | 
			
		||||
            // i guess we could have triggered a new group to appear
 | 
			
		||||
            // that already an explicit size the last time it appeared ...
 | 
			
		||||
            this._checkSubListsOverflow();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // this._lastRefreshRoomListTs = Date.now();
 | 
			
		||||
@@ -485,9 +494,30 @@ module.exports = React.createClass({
 | 
			
		||||
            (filter[0] === '#' && room.getAliases().some((alias) => alias.toLowerCase().startsWith(lcFilter))));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _persistCollapsedState: function(key, collapsed) {
 | 
			
		||||
    _handleCollapsedState: function(key, collapsed) {
 | 
			
		||||
        // persist collapsed state
 | 
			
		||||
        this.collapsedState[key] = collapsed;
 | 
			
		||||
        window.localStorage.setItem("mx_roomlist_collapsed", JSON.stringify(this.collapsedState));
 | 
			
		||||
        // load the persisted size configuration of the expanded sub list
 | 
			
		||||
        if (!collapsed) {
 | 
			
		||||
            this._restoreSubListSize(key);
 | 
			
		||||
        }
 | 
			
		||||
        // check overflow, as sub lists sizes have changed
 | 
			
		||||
        // important this happens after calling resize above
 | 
			
		||||
        this._checkSubListsOverflow();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _restoreSubListSize(key) {
 | 
			
		||||
        const size = this.subListSizes[key];
 | 
			
		||||
        const handle = this.resizer.forHandleWithId(key);
 | 
			
		||||
        if (handle) {
 | 
			
		||||
            handle.resize(size);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // check overflow for scroll indicator gradient
 | 
			
		||||
    _checkSubListsOverflow() {
 | 
			
		||||
        Object.values(this._subListRefs).forEach(l => l.checkOverflow());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _subListRef: function(key, ref) {
 | 
			
		||||
@@ -520,7 +550,7 @@ module.exports = React.createClass({
 | 
			
		||||
            const {key, label, onHeaderClick, ... otherProps} = props;
 | 
			
		||||
            const chosenKey = key || label;
 | 
			
		||||
            const onSubListHeaderClick = (collapsed) => {
 | 
			
		||||
                this._persistCollapsedState(chosenKey, collapsed);
 | 
			
		||||
                this._handleCollapsedState(chosenKey, collapsed);
 | 
			
		||||
                if (onHeaderClick) {
 | 
			
		||||
                    onHeaderClick(collapsed);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -84,8 +84,10 @@ export class Resizer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _onMouseDown(event) {
 | 
			
		||||
        const target = event.target;
 | 
			
		||||
        if (!this._isResizeHandle(target) || target.parentElement !== this.container) {
 | 
			
		||||
        // use closest in case the resize handle contains
 | 
			
		||||
        // child dom nodes that can be the target
 | 
			
		||||
        const resizeHandle = event.target && event.target.closest(`.${this.classNames.handle}`);
 | 
			
		||||
        if (!resizeHandle || resizeHandle.parentElement !== this.container) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // prevent starting a drag operation
 | 
			
		||||
@@ -96,7 +98,7 @@ export class Resizer {
 | 
			
		||||
            this.container.classList.add(this.classNames.resizing);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const {sizer, distributor} = this._createSizerAndDistributor(target);
 | 
			
		||||
        const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle);
 | 
			
		||||
 | 
			
		||||
        const onMouseMove = (event) => {
 | 
			
		||||
            const offset = sizer.offsetFromEvent(event);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user