mirror of https://github.com/vector-im/riot-web
				
				
				
			Merge branch 'experimental' into nadonomy/icons
						commit
						1d43712a8f
					
				|  | @ -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,32 +192,37 @@ $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 { | ||||
|     display: block; | ||||
|     margin: 9px; | ||||
|     box-sizing: border-box; | ||||
|     background-color: transparent; | ||||
|     color: $input-darker-fg-color; | ||||
|     border-radius: 4px; | ||||
|     border: 1px solid #c1c1c1; | ||||
| } | ||||
| .mx_MatrixChat { | ||||
| 
 | ||||
| .mx_textinput { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
| } | ||||
|     :not(.mx_textinput) > input[type=text], | ||||
|     :not(.mx_textinput) > input[type=search], | ||||
|     .mx_textinput { | ||||
|         display: block; | ||||
|         margin: 9px; | ||||
|         box-sizing: border-box; | ||||
|         background-color: transparent; | ||||
|         color: $input-darker-fg-color; | ||||
|         border-radius: 4px; | ||||
|         border: 1px solid #c1c1c1; | ||||
|         flex: 0 0 auto; | ||||
|     } | ||||
| 
 | ||||
| .mx_textinput > input[type=text], | ||||
| .mx_textinput > input[type=search] { | ||||
|     border: none; | ||||
|     flex: 1; | ||||
|     color: inherit; //from .mx_textinput | ||||
|     .mx_textinput { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
| 
 | ||||
|         > 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,21 +82,35 @@ export default class AutoHideScrollbar extends React.Component { | |||
|         this.containerRef.classList.add("mx_AutoHideScrollbar_underflow"); | ||||
|     } | ||||
| 
 | ||||
|     checkOverflow() { | ||||
|         if (!this._needsOverflowListener) { | ||||
|             return; | ||||
|         } | ||||
|         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; | ||||
|             const needsOverflowListener = | ||||
|                 document.body.classList.contains("mx_scrollbar_nooverlay"); | ||||
| 
 | ||||
|             if (needsOverflowListener) { | ||||
|                 this.containerRef.addEventListener("overflow", this.onOverflow); | ||||
|                 this.containerRef.addEventListener("underflow", this.onUnderflow); | ||||
|             } | ||||
|             if (ref.scrollHeight > ref.clientHeight) { | ||||
|                 this.onOverflow(); | ||||
|             } else { | ||||
|                 this.onUnderflow(); | ||||
|             } | ||||
|         } | ||||
|         if (this.props.wrappedRef) { | ||||
|             this.props.wrappedRef(ref); | ||||
|  | @ -103,14 +118,13 @@ export default class AutoHideScrollbar extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     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.props.onHeaderClick(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,11 +48,42 @@ 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") { | ||||
|             this.setState({ | ||||
|                 phase: payload.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, | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -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); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bruno Windels
						Bruno Windels