diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx index a362af6c2c..7aef7ff4e5 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-item/component.jsx @@ -81,6 +81,9 @@ class UserListItem extends Component { this.state = { isActionsOpen: false, + dropdownOffset: 0, + dropdownDirection: 'top', + dropdownVisible: false, }; this.handleScroll = this.handleScroll.bind(this); @@ -134,21 +137,82 @@ class UserListItem extends Component { ]); } + + componentDidUpdate(prevProps, prevState) { + this.checkDropdownDirection(); + } + + /** + * Check if the dropdown is visible, if so, check if should be draw on top or bottom direction. + */ + checkDropdownDirection() { + if (this.isDropdownActivedByUser()) { + const dropdown = findDOMNode(this.refs.dropdown); + const dropdownTrigger = dropdown.children[0]; + const dropdownContent = dropdown.children[1]; + + const scrollContainer = dropdown.parentElement.parentElement; + + let nextState = { + dropdownVisible: true, + }; + + const isDropdownVisible = + this.checkIfDropdownIsVisible(dropdownContent.offsetTop, dropdownContent.offsetHeight); + + if (!isDropdownVisible) { + const offsetPageTop = + (dropdownTrigger.offsetTop + dropdownTrigger.offsetHeight - scrollContainer.scrollTop); + + nextState.dropdownOffset = window.innerHeight - offsetPageTop; + nextState.dropdownDirection = 'bottom'; + } + + this.setState(nextState); + } + } + + /** + * Check if the dropdown is visible and is opened by the user + * + * @return True if is visible and opened by the user. + */ + isDropdownActivedByUser() { + const { isActionsOpen, dropdownVisible } = this.state; + return isActionsOpen && !dropdownVisible; + } + + /** + * Return true if the content fit on the screen, false otherwise. + * + * @param {number} contentOffSetTop + * @param {number} contentOffsetHeight + * @return True if the content fit on the screen, false otherwise. + */ + checkIfDropdownIsVisible(contentOffSetTop, contentOffsetHeight) { + return (contentOffSetTop + contentOffsetHeight) < window.innerHeight; + } + + onActionsShow() { const dropdown = findDOMNode(this.refs.dropdown); + const scrollContainer = dropdown.parentElement.parentElement; + const dropdownTrigger = dropdown.children[0]; + this.setState({ - contentTop: `${dropdown.offsetTop - dropdown.parentElement.parentElement.scrollTop}px`, isActionsOpen: true, - active: true, + dropdownVisible: false, + dropdownOffset: dropdownTrigger.offsetTop - scrollContainer.scrollTop, + dropdownDirection: 'top', }); - findDOMNode(this).parentElement.addEventListener('scroll', this.handleScroll, false); + scrollContainer.addEventListener('scroll', this.handleScroll, false); } onActionsHide() { this.setState({ - active: false, isActionsOpen: false, + dropdownVisible: false, }); findDOMNode(this).parentElement.removeEventListener('scroll', this.handleScroll, false); @@ -161,7 +225,7 @@ class UserListItem extends Component { let userItemContentsStyle = {}; userItemContentsStyle[styles.userItemContentsCompact] = compact; - userItemContentsStyle[styles.active] = this.state.active; + userItemContentsStyle[styles.active] = this.state.isActionsOpen; return (
  • - + {this.renderUserName()} {this.renderUserIcons()} @@ -191,10 +255,12 @@ class UserListItem extends Component { return contents; } + const { dropdownOffset, dropdownDirection, dropdownVisible, } = this.state; + return ( @@ -203,10 +269,11 @@ class UserListItem extends Component { + placement={`right ${dropdownDirection}`}> { @@ -216,7 +283,7 @@ class UserListItem extends Component { key={_.uniqueId('action-header')} label={user.name} style={{ fontWeight: 600 }} - defaultMessage={user.name}/>), + defaultMessage={user.name} />), (), ].concat(actions) } @@ -295,16 +362,16 @@ class UserListItem extends Component { { user.isSharingWebcam ? - + : null } { audioChatIcon ? - - - - : null + + + + : null } );