diff --git a/src/components/structures/RoomSubList.js b/src/components/structures/RoomSubList.js index 852dddd063..676e0e6976 100644 --- a/src/components/structures/RoomSubList.js +++ b/src/components/structures/RoomSubList.js @@ -84,7 +84,7 @@ const RoomSubList = React.createClass({ // The dataset elements are added in the RoomList _initAndPositionStickyHeaders method isCollapsableOnClick: function() { const stuck = this.refs.header.dataset.stuck; - if (this.state.hidden || stuck === undefined || stuck === "none") { + if (!this.props.forceExpand && (this.state.hidden || stuck === undefined || stuck === "none")) { return true; } else { return false; @@ -238,7 +238,7 @@ const RoomSubList = React.createClass({ } }, - _getHeaderJsx: function() { + _getHeaderJsx: function(isCollapsed) { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const subListNotifications = this.roomNotificationCount(); const subListNotifCount = subListNotifications[0]; @@ -287,8 +287,8 @@ const RoomSubList = React.createClass({ if (len) { const chevronClasses = classNames({ 'mx_RoomSubList_chevron': true, - 'mx_RoomSubList_chevronRight': this.state.hidden, - 'mx_RoomSubList_chevronDown': !this.state.hidden, + 'mx_RoomSubList_chevronRight': isCollapsed, + 'mx_RoomSubList_chevronDown': !isCollapsed, }); chevron = (
); } @@ -321,21 +321,23 @@ const RoomSubList = React.createClass({ render: function() { const len = this.props.list.length + this.props.extraTiles.length; + const isCollapsed = this.state.hidden && !this.props.forceExpand; if (len) { const subListClasses = classNames({ "mx_RoomSubList": true, - "mx_RoomSubList_hidden": this.state.hidden, - "mx_RoomSubList_nonEmpty": len && !this.state.hidden, + "mx_RoomSubList_hidden": isCollapsed, + "mx_RoomSubList_nonEmpty": len && !isCollapsed, }); - if (this.state.hidden) { + + if (isCollapsed) { return
- {this._getHeaderJsx()} + {this._getHeaderJsx(isCollapsed)}
; } else { const tiles = this.makeRoomTiles(); tiles.push(...this.props.extraTiles); return
- {this._getHeaderJsx()} + {this._getHeaderJsx(isCollapsed)} { tiles } @@ -344,13 +346,13 @@ const RoomSubList = React.createClass({ } else { const Loader = sdk.getComponent("elements.Spinner"); let content; - if (this.props.showSpinner && !this.state.hidden) { + if (this.props.showSpinner && !isCollapsed) { content = ; } return (
- { this._getHeaderJsx() } + { this._getHeaderJsx(isCollapsed) } { content }
); diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 4f92d0cad6..44fb14476a 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -82,7 +82,11 @@ module.exports = React.createClass({ this.collapsedState = collapsedJson ? JSON.parse(collapsedJson) : {}; this._layoutSections = []; - this._layout = new Layout((key, size) => { + const unfilteredOptions = { + allowWhitespace: true, + handleHeight: 1, + }; + this._unfilteredlayout = new Layout((key, size) => { const subList = this._subListRefs[key]; if (subList) { subList.setHeight(size); @@ -95,7 +99,19 @@ module.exports = React.createClass({ window.localStorage.setItem("mx_roomlist_sizes", JSON.stringify(this.subListSizes)); } - }, this.subListSizes, this.collapsedState); + }, this.subListSizes, this.collapsedState, unfilteredOptions); + + this._filteredLayout = new Layout((key, size) => { + const subList = this._subListRefs[key]; + if (subList) { + subList.setHeight(size); + } + }, null, null, { + allowWhitespace: false, + handleHeight: 0, + }); + + this._layout = this._unfilteredlayout; return { isLoadingLeftRooms: false, @@ -187,15 +203,21 @@ module.exports = React.createClass({ }, componentDidUpdate: function(prevProps) { + let forceLayoutUpdate = false; this._repositionIncomingCallBox(undefined, false); - // if (this.props.searchFilter !== prevProps.searchFilter) { - // this._checkSubListsOverflow(); - // } + if (!this.props.searchFilter && prevProps.searchFilter) { + this._layout = this._unfilteredlayout; + forceLayoutUpdate = true; + } else if (this.props.searchFilter && !prevProps.searchFilter) { + this._layout = this._filteredLayout; + forceLayoutUpdate = true; + } this._layout.update( this._layoutSections, this.resizeContainer && this.resizeContainer.clientHeight, + forceLayoutUpdate, ); - // TODO: call layout.setAvailableHeight, window height was changed when bannerShown prop was changed + this._checkSubListsOverflow(); }, onAction: function(payload) { @@ -617,7 +639,7 @@ module.exports = React.createClass({ onHeaderClick(collapsed); } }; - const startAsHidden = props.startAsHidden || this.collapsedState[chosenKey]; + let startAsHidden = props.startAsHidden || this.collapsedState[chosenKey]; this._layoutSections.push({ id: chosenKey, count: len, @@ -625,6 +647,7 @@ module.exports = React.createClass({ let subList = ( max) return max; if (height < min) return min; @@ -26,7 +23,7 @@ function clamp(height, min, max) { } export class Layout { - constructor(applyHeight, initialSizes, collapsedState) { + constructor(applyHeight, initialSizes, collapsedState, options) { // callback to set height of section this._applyHeight = applyHeight; // list of {id, count} objects, @@ -41,6 +38,17 @@ export class Layout { this._sectionHeights = Object.assign({}, initialSizes); // in-progress heights, while dragging. Committed on mouse-up. this._heights = []; + // use while manually resizing to cancel + // the resize for a given mouse position + // when the previous resize made the layout + // constrained + this._clampedOffset = 0; + // used while manually resizing, to clear + // _clampedOffset when the direction of resizing changes + this._lastOffset = 0; + + this._allowWhitespace = options && options.allowWhitespace; + this._handleHeight = (options && options.handleHeight) || 0; } setAvailableHeight(newSize) { @@ -60,7 +68,7 @@ export class Layout { this._applyNewSize(); } - update(sections, availableHeight) { + update(sections, availableHeight, force = false) { let heightChanged = false; if (Number.isFinite(availableHeight) && availableHeight !== this._availableHeight) { @@ -75,7 +83,7 @@ export class Layout { return a.id !== b.id || a.count !== b.count; }); - if (!heightChanged && !sectionsChanged) { + if (!heightChanged && !sectionsChanged && !force) { return; } @@ -104,7 +112,7 @@ export class Layout { const collapsed = this._collapsedState[section.id]; return count + (collapsed ? 0 : 1); }, 0); - return this._availableHeight - ((nonCollapsedSectionCount - 1) * handleHeight); + return this._availableHeight - ((nonCollapsedSectionCount - 1) * this._handleHeight); } _applyNewSize() { @@ -130,9 +138,10 @@ export class Layout { if (collapsed) { return this._sectionHeight(0); + } else if (!this._allowWhitespace) { + return this._sectionHeight(section.count); } else { return 100000; - // return this._sectionHeight(section.count); } } @@ -268,6 +277,22 @@ export class Layout { this._sectionHeights[section.id] = this._heights[i]; }); } + + _setUncommittedSectionHeight(sectionIndex, offset) { + if (Math.sign(offset) != Math.sign(this._lastOffset)) { + this._clampedOffset = undefined; + } + if (this._clampedOffset !== undefined) { + if (offset < 0 && offset < this._clampedOffset) { + return; + } + if (offset > 0 && offset > this._clampedOffset) { + return; + } + } + this._clampedOffset = this._relayout(sectionIndex, offset); + this._lastOffset = offset; + } } class Handle { @@ -278,7 +303,10 @@ class Handle { } setHeight(height) { - this._layout._relayout(this._sectionIndex, height - this._initialHeight); + this._layout._setUncommittedSectionHeight( + this._sectionIndex, + height - this._initialHeight, + ); return this; }