diff --git a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js index 2a6ee420161e1c22ad90c0ccdf296f3ab24ad67f..1fadd60a0a93ee47bfd576b0c3beee185a1d7f86 100755 --- a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js +++ b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js @@ -1,4 +1,3 @@ -import browser from 'browser-detect'; import BaseAudioBridge from './base'; import logger from '/imports/startup/client/logger'; import { @@ -19,6 +18,7 @@ import CallStateOptions from '/imports/api/voice-call-states/utils/callStates'; import Auth from '/imports/ui/services/auth'; import Settings from '/imports/ui/services/settings'; import Storage from '/imports/ui/services/storage/session'; +import browserInfo from '/imports/utils/browserInfo'; const MEDIA = Meteor.settings.public.media; const MEDIA_TAG = MEDIA.mediaTag; @@ -1084,7 +1084,9 @@ class SIPSession { const matchConstraints = this.filterSupportedConstraints(constraints); //Chromium bug - see: https://bugs.chromium.org/p/chromium/issues/detail?id=796964&q=applyConstraints&can=2 - if (browser().name === 'chrome') { + const { isChrome } = browserInfo; + + if (isChrome) { matchConstraints.deviceId = this.inputDeviceId; const stream = await navigator.mediaDevices.getUserMedia( diff --git a/bigbluebutton-html5/imports/startup/client/base.jsx b/bigbluebutton-html5/imports/startup/client/base.jsx index b83d3a5e58b9a06fec948c4d38a1fcd539ccee1c..db9afa1ea225770ed1dd0bdbd91fb7fadb375c7e 100755 --- a/bigbluebutton-html5/imports/startup/client/base.jsx +++ b/bigbluebutton-html5/imports/startup/client/base.jsx @@ -403,7 +403,7 @@ const BaseContainer = withTracker(() => { if (Session.equals('openPanel', undefined) || Session.equals('subscriptionsReady', true)) { if (!checkedUserSettings) { - if (getFromUserSettings('bbb_show_participants_on_login', Meteor.settings.public.layout.showParticipantsOnLogin) && !deviceInfo.type().isPhone) { + if (getFromUserSettings('bbb_show_participants_on_login', Meteor.settings.public.layout.showParticipantsOnLogin) && !deviceInfo.isPhone) { if (CHAT_ENABLED && getFromUserSettings('bbb_show_public_chat_on_login', !Meteor.settings.public.chat.startClosed)) { Session.set('openPanel', 'chat'); Session.set('idChatOpen', PUBLIC_CHAT_ID); diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx index bd336850491e17d239e62fe4cdc89e24ce7847ec..828cfcc83f2543812c5885427867ff2fb5c73f8e 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/create-breakout-room/component.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; import _ from 'lodash'; import cx from 'classnames'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; import Button from '/imports/ui/components/button/component'; import { Session } from 'meteor/session'; import Modal from '/imports/ui/components/modal/fullscreen/component'; @@ -807,8 +807,7 @@ class BreakoutRoom extends PureComponent { numberOfRoomsIsValid, } = this.state; - const BROWSER_RESULTS = browser(); - const isMobileBrowser = BROWSER_RESULTS.mobile || BROWSER_RESULTS.os.includes('Android'); + const { isMobile } = deviceInfo; return ( <Modal @@ -834,7 +833,7 @@ class BreakoutRoom extends PureComponent { > <div className={styles.content}> {isInvitation || this.renderTitle()} - {isMobileBrowser ? this.renderMobile() : this.renderDesktop()} + {isMobile ? this.renderMobile() : this.renderDesktop()} </div> </Modal> ); diff --git a/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx b/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx index 64dc749da3acd1d22649ee19fe1e38035063c73f..634a58adb28dca69b9b43cf3aecf7ab54e20c990 100755 --- a/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/actions-bar/screenshare/component.jsx @@ -1,7 +1,8 @@ import React, { memo } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; +import browserInfo from '/imports/utils/browserInfo'; import Button from '/imports/ui/components/button/component'; import logger from '/imports/startup/client/logger'; import { notify } from '/imports/ui/services/notification'; @@ -19,12 +20,8 @@ import { } from '/imports/ui/components/screenshare/service'; import { SCREENSHARING_ERRORS } from '/imports/api/screenshare/client/bridge/errors'; -const BROWSER_RESULTS = browser(); -const isMobileBrowser = (BROWSER_RESULTS ? BROWSER_RESULTS.mobile : false) - || (BROWSER_RESULTS && BROWSER_RESULTS.os - ? BROWSER_RESULTS.os.includes('Android') // mobile flag doesn't always work - : false); -const IS_SAFARI = BROWSER_RESULTS.name === 'safari'; +const { isMobile } = deviceInfo; +const { isSafari } = browserInfo; const propTypes = { intl: PropTypes.objectOf(Object).isRequired, @@ -174,7 +171,7 @@ const ScreenshareButton = ({ ? intlMessages.stopDesktopShareDesc : intlMessages.desktopShareDesc; const shouldAllowScreensharing = enabled - && !isMobileBrowser + && !isMobile && amIPresenter; return shouldAllowScreensharing @@ -193,7 +190,7 @@ const ScreenshareButton = ({ onClick={isVideoBroadcasting ? screenshareHasEnded : () => { - if (IS_SAFARI && !ScreenshareBridgeService.HAS_DISPLAY_MEDIA) { + if (isSafari && !ScreenshareBridgeService.HAS_DISPLAY_MEDIA) { renderScreenshareUnavailableModal(); } else { shareScreen(handleFailure); diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx index 890d75a857dcc36b44530afbbb3decbb6fd73132..3ddbaca3dbb920fd0c1d2bc33641e4c8a737725a 100755 --- a/bigbluebutton-html5/imports/ui/components/app/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx @@ -3,7 +3,8 @@ import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import { defineMessages, injectIntl } from 'react-intl'; import Modal from 'react-modal'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; +import deviceInfo from '/imports/utils/deviceInfo'; import PanelManager from '/imports/ui/components/panel-manager/component'; import PollingContainer from '/imports/ui/components/polling/container'; import logger from '/imports/startup/client/logger'; @@ -124,21 +125,18 @@ class App extends Component { const { locale, notify, intl, validIOSVersion, startBandwidthMonitoring, handleNetworkConnection, } = this.props; - const BROWSER_RESULTS = browser(); - const isMobileBrowser = BROWSER_RESULTS.mobile || BROWSER_RESULTS.os.includes('Android'); + const { browserName } = browserInfo; + const { isMobile, osName } = deviceInfo; MediaService.setSwapLayout(); Modal.setAppElement('#app'); document.getElementsByTagName('html')[0].lang = locale; - document.getElementsByTagName('html')[0].style.fontSize = isMobileBrowser ? MOBILE_FONT_SIZE : DESKTOP_FONT_SIZE; + document.getElementsByTagName('html')[0].style.fontSize = isMobile ? MOBILE_FONT_SIZE : DESKTOP_FONT_SIZE; const body = document.getElementsByTagName('body')[0]; - if (BROWSER_RESULTS && BROWSER_RESULTS.name) { - body.classList.add(`browser-${BROWSER_RESULTS.name}`); - } - if (BROWSER_RESULTS && BROWSER_RESULTS.os) { - body.classList.add(`os-${BROWSER_RESULTS.os.split(' ').shift().toLowerCase()}`); - } + + body.classList.add(`browser-${browserName.toLowerCase()}`); + body.classList.add(`os-${osName.split(' ').shift().toLowerCase()}`); if (!validIOSVersion()) { notify( @@ -160,7 +158,7 @@ class App extends Component { startBandwidthMonitoring(); } - if (isMobileBrowser) makeCall('setMobileUser'); + if (isMobile) makeCall('setMobileUser'); ConnectionStatusService.startRoundTripTime(); diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx index 71c0a129c6efbe4d92dc827f0acb1f1d53fee33d..5329a67fe801da17c9c5f2d1a2917a956169327f 100755 --- a/bigbluebutton-html5/imports/ui/components/app/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx @@ -115,7 +115,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) UserInfo, notify, validIOSVersion, - isPhone: deviceInfo.type().isPhone, + isPhone: deviceInfo.isPhone, isRTL: document.documentElement.getAttribute('dir') === 'rtl', meetingMuted: voiceProp.muteOnStart, currentUserEmoji: currentUserEmoji(currentUser), diff --git a/bigbluebutton-html5/imports/ui/components/app/service.js b/bigbluebutton-html5/imports/ui/components/app/service.js index d758bb7b8a517303f76cd7ffc9e916f5d7734016..1de523d006e453df94cc8a9dfbed6608db6fd38d 100644 --- a/bigbluebutton-html5/imports/ui/components/app/service.js +++ b/bigbluebutton-html5/imports/ui/components/app/service.js @@ -2,6 +2,7 @@ import Breakouts from '/imports/api/breakouts'; import Meetings from '/imports/api/meetings'; import Settings from '/imports/ui/services/settings'; import Auth from '/imports/ui/services/auth/index'; +import deviceInfo from '/imports/utils/deviceInfo'; const getFontSize = () => { const applicationSettings = Settings.application; @@ -17,12 +18,10 @@ function meetingIsBreakout() { } const validIOSVersion = () => { - const SUPPORTED_OS_VERSION = 12.2; - const iosMatch = navigator.userAgent.match(/OS (\d+)_(\d+)/); - if (iosMatch) { - const versionNumber = iosMatch[0].split(' ')[1].replace('_', '.'); - const isInvalid = parseFloat(versionNumber) < SUPPORTED_OS_VERSION; - if (isInvalid) return false; + const { isIos, isIosVersionSupported } = deviceInfo; + + if (isIos) { + return isIosVersionSupported(); } return true; }; diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx index 31504bffaf3df7ee194838a8fffe0d77547ae4af..8c40bf140b98bddf73366468fcff18b0522cc57d 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx @@ -1,8 +1,8 @@ import React, { PureComponent } from 'react'; -import { isMobile } from 'react-device-detect'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { defineMessages, injectIntl } from 'react-intl'; +import deviceInfo from '/imports/utils/deviceInfo'; import Button from '/imports/ui/components/button/component'; import getFromUserSettings from '/imports/ui/services/users-settings'; import withShortcutHelper from '/imports/ui/components/shortcut-help/service'; @@ -138,6 +138,8 @@ class AudioControls extends PureComponent { inAudio, } = this.props; + const { isMobile } = deviceInfo; + let { enableDynamicAudioDeviceSelection } = Meteor.settings.public.app; if (typeof enableDynamicAudioDeviceSelection === 'undefined') { diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx index 7c6e2c8f3bd0f5695e995ddcb07f4376f5353e8e..6002950a4e9595c63a4487caed28048dde1063db 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx @@ -1,7 +1,8 @@ import React from 'react'; import { withTracker } from 'meteor/react-meteor-data'; import { withModalMounter } from '/imports/ui/components/modal/service'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; +import browserInfo from '/imports/utils/browserInfo'; import getFromUserSettings from '/imports/ui/services/users-settings'; import AudioModal from './component'; import Meetings from '/imports/api/meetings'; @@ -56,6 +57,9 @@ export default lockContextContainer(withModalMounter(withTracker(({ userLocks }) const forceListenOnlyAttendee = forceListenOnly && !Service.isUserModerator(); + const { isIos } = deviceInfo; + const { isChrome, isEdge, isIe } = browserInfo; + return ({ joinedAudio, meetingIsBreakout, @@ -80,9 +84,9 @@ export default lockContextContainer(withModalMounter(withTracker(({ userLocks }) audioLocked: userLocks.userMic, joinFullAudioImmediately, forceListenOnlyAttendee, - isIOSChrome: browser().name === 'crios', + isIOSChrome: isIos && isChrome, isMobileNative: navigator.userAgent.toLowerCase().includes('bbbnative'), - isIEOrEdge: browser().name === 'edge' || browser().name === 'ie', + isIEOrEdge: isEdge || isIe, autoplayBlocked: Service.autoplayBlocked(), handleAllowAutoplay: () => Service.handleAllowAutoplay(), isRTL, diff --git a/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx index 152a71794e4411011ff2a01e411805916c7ca1c3..629cb2c39b3b031e9c5dfb388bccb2edc6e1e55c 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/device-selector/component.jsx @@ -3,7 +3,7 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import cx from 'classnames'; import logger from '/imports/startup/client/logger'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; import { styles } from '../audio-modal/styles'; const propTypes = { @@ -82,6 +82,7 @@ class DeviceSelector extends Component { } = this.props; const { options, value } = this.state; + const { isSafari } = browserInfo; return ( <select @@ -102,7 +103,7 @@ class DeviceSelector extends Component { </option> )) : ( - (kind === 'audiooutput' && browser().name === 'safari') + (kind === 'audiooutput' && isSafari) ? <option value="not-found">Default</option> : <option value="not-found">{`no ${kind} found`}</option> ) diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx index 662ebce99b7df10287ce8af3480d5af1725126cb..997f939c3656da07f1a5c331d4104e57332eea87 100755 --- a/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/component.jsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { defineMessages, injectIntl } from 'react-intl'; import cx from 'classnames'; import TextareaAutosize from 'react-autosize-textarea'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; import PropTypes from 'prop-types'; import _ from 'lodash'; import TypingIndicatorContainer from './typing-indicator/container'; @@ -80,8 +80,6 @@ class MessageForm extends PureComponent { hasErrors: false, }; - this.BROWSER_RESULTS = browser(); - this.handleMessageChange = this.handleMessageChange.bind(this); this.handleMessageKeyDown = this.handleMessageKeyDown.bind(this); this.handleSubmit = this.handleSubmit.bind(this); @@ -91,11 +89,11 @@ class MessageForm extends PureComponent { } componentDidMount() { - const { mobile } = this.BROWSER_RESULTS; + const { isMobile } = deviceInfo; this.setMessageState(); this.setMessageHint(); - if (!mobile) { + if (!isMobile) { if (this.textarea) this.textarea.focus(); } } @@ -108,9 +106,9 @@ class MessageForm extends PureComponent { partnerIsLoggedOut, } = this.props; const { message } = this.state; - const { mobile } = this.BROWSER_RESULTS; + const { isMobile } = deviceInfo; - if (prevProps.chatId !== chatId && !mobile) { + if (prevProps.chatId !== chatId && !isMobile) { if (this.textarea) this.textarea.focus(); } diff --git a/bigbluebutton-html5/imports/ui/components/chat/message-form/typing-indicator/component.jsx b/bigbluebutton-html5/imports/ui/components/chat/message-form/typing-indicator/component.jsx index b379f75af8054046c04c615b2ebfc0391047c809..08024cbaac08f00a7cb62392d17d0cd14a70d4f4 100644 --- a/bigbluebutton-html5/imports/ui/components/chat/message-form/typing-indicator/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/chat/message-form/typing-indicator/component.jsx @@ -2,7 +2,6 @@ import React, { PureComponent } from 'react'; import { defineMessages, injectIntl, FormattedMessage, } from 'react-intl'; -import browser from 'browser-detect'; import PropTypes from 'prop-types'; import cx from 'classnames'; import { styles } from '../styles.scss'; @@ -23,8 +22,6 @@ class TypingIndicator extends PureComponent { constructor(props) { super(props); - this.BROWSER_RESULTS = browser(); - this.renderTypingElement = this.renderTypingElement.bind(this); } diff --git a/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx index 2a1e908d28295849e628d12e03845b7c11f498a5..48498da0f54d9d28db401387d491f3b7d0f594f1 100644 --- a/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/dropdown/component.jsx @@ -1,10 +1,10 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; -import { isMobile, withOrientationChange } from 'react-device-detect'; import TetherComponent from 'react-tether'; import cx from 'classnames'; import { defineMessages, injectIntl } from 'react-intl'; +import deviceInfo from '/imports/utils/deviceInfo'; import Button from '/imports/ui/components/button/component'; import screenreaderTrap from 'makeup-screenreader-trap'; import { styles } from './styles'; @@ -78,7 +78,7 @@ const targetAttachments = { class Dropdown extends Component { constructor(props) { super(props); - this.state = { isOpen: false }; + this.state = { isOpen: false, isPortrait:deviceInfo.isPortrait() }; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); this.handleToggle = this.handleToggle.bind(this); @@ -129,6 +129,17 @@ class Dropdown extends Component { }); } + componentDidMount() { + window.addEventListener('resize', this.updateOrientation); + } + componentWillUnmount() { + window.removeEventListener('resize', this.updateOrientation); + } + + updateOrientation = () => { + this.setState({ isPortrait:deviceInfo.isPortrait() }); + }; + handleWindowClick(event) { const { keepOpen, onHide } = this.props; const { isOpen } = this.state; @@ -179,17 +190,13 @@ class Dropdown extends Component { tethered, placement, getContent, - isPortrait, ...otherProps } = this.props; - const { isOpen } = this.state; - - const MOBILE_MEDIA = 'only screen and (max-width: 40em)'; - const isSmall = window.matchMedia(MOBILE_MEDIA).matches; - + const { isOpen, isPortrait } = this.state; + const { isPhone } = deviceInfo; const placements = placement && placement.replace(' ', '-'); - const test = isMobile && isPortrait && isSmall ? { + const test = isPhone && isPortrait ? { width: '100%', height: '100%', transform: 'translateY(0)', @@ -245,11 +252,11 @@ class Dropdown extends Component { ...test, }} attachment={ - isMobile && isPortrait && isSmall ? 'middle center' + isPhone && isPortrait ? 'middle center' : attachments[placements] } targetAttachment={ - isMobile && isPortrait && isSmall ? 'auto auto' + isPhone && isPortrait ? 'auto auto' : targetAttachments[placements] } constraints={[ @@ -304,4 +311,4 @@ class Dropdown extends Component { Dropdown.propTypes = propTypes; Dropdown.defaultProps = defaultProps; -export default injectIntl(withOrientationChange(Dropdown), { forwardRef: true }); +export default injectIntl(Dropdown, { forwardRef: true }); diff --git a/bigbluebutton-html5/imports/ui/components/legacy/component.jsx b/bigbluebutton-html5/imports/ui/components/legacy/component.jsx index b859270bd6d4c88bf16b98e5fec0126d5cf2b665..f192ed59a4fda3090d35c27c5806ac549b61aa24 100755 --- a/bigbluebutton-html5/imports/ui/components/legacy/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/legacy/component.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; -import { IntlProvider, FormattedMessage, addLocaleData } from 'react-intl'; -import { browserName } from 'react-device-detect'; +import { IntlProvider, FormattedMessage } from 'react-intl'; +import browserInfo from '/imports/utils/browserInfo'; +import deviceInfo from '/imports/utils/deviceInfo'; import './styles.css'; @@ -68,7 +69,7 @@ import './styles.css'; const FETCHING = 'fetching'; const FALLBACK = 'fallback'; const READY = 'ready'; -const supportedBrowsers = ['chrome', 'firefox', 'safari', 'opera', 'edge', 'yandex']; +const supportedBrowsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'Microsoft Edge', 'Yandex Browser']; const DEFAULT_LANGUAGE = Meteor.settings.public.app.defaultSettings.application.fallbackLocale; export default class Legacy extends Component { @@ -148,9 +149,12 @@ export default class Legacy extends Component { } render() { + const { browserName, isChrome } = browserInfo; + const { isIos } = deviceInfo; + const { messages, normalizedLocale, viewState } = this.state; const isSupportedBrowser = supportedBrowsers.includes(browserName); - const isChromeIos = browserName === 'crios'; + const isChromeIos = isIos && isChrome; let messageId = isSupportedBrowser ? 'app.legacy.upgradeBrowser' : 'app.legacy.unsupportedBrowser'; if (isChromeIos) messageId = 'app.legacy.criosBrowser'; diff --git a/bigbluebutton-html5/imports/ui/components/media/component.jsx b/bigbluebutton-html5/imports/ui/components/media/component.jsx index e3dd38baf921d3234362dbc11323c7ae1229e6e2..32d86b03ab392b59d08228e3c7fb2289839f3880 100644 --- a/bigbluebutton-html5/imports/ui/components/media/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/media/component.jsx @@ -1,13 +1,13 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; +import deviceInfo from '/imports/utils/deviceInfo'; import Settings from '/imports/ui/services/settings'; -import { isMobile, isIPad13 } from 'react-device-detect'; import WebcamDraggable from './webcam-draggable-overlay/component'; import { styles } from './styles'; import Storage from '../../services/storage/session'; -const BROWSER_ISMOBILE = isMobile || isIPad13; +const { isMobile } = deviceInfo; const propTypes = { children: PropTypes.element.isRequired, @@ -91,7 +91,7 @@ export default class Media extends Component { ) ? '80%' : '100%', - minHeight: BROWSER_ISMOBILE && window.innerWidth > window.innerHeight ? '50%' : '20%', + minHeight: isMobile && window.innerWidth > window.innerHeight ? '50%' : '20%', maxWidth: usersVideo.length > 0 && ( webcamsPlacement !== 'top' diff --git a/bigbluebutton-html5/imports/ui/components/media/webcam-draggable-overlay/component.jsx b/bigbluebutton-html5/imports/ui/components/media/webcam-draggable-overlay/component.jsx index 4c9cf5a67b3915746a348d3e62737ccb0b79f445..e3b78e881f1938e4d59b14b797b9c106f6ee92b7 100644 --- a/bigbluebutton-html5/imports/ui/components/media/webcam-draggable-overlay/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/media/webcam-draggable-overlay/component.jsx @@ -3,7 +3,7 @@ import Draggable from 'react-draggable'; import cx from 'classnames'; import PropTypes from 'prop-types'; import Resizable from 're-resizable'; -import { isMobile, isIPad13 } from 'react-device-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; import { withDraggableConsumer } from './context'; import VideoProviderContainer from '/imports/ui/components/video-provider/container'; import { styles } from '../styles.scss'; @@ -11,8 +11,6 @@ import Storage from '../../../services/storage/session'; import { withLayoutConsumer } from '/imports/ui/components/layout/context'; import { WEBCAMSAREA_MIN_PERCENT, PRESENTATIONAREA_MIN_WIDTH } from '/imports/ui/components/layout/layout-manager'; -const BROWSER_ISMOBILE = isMobile || isIPad13; - const propTypes = { swapLayout: PropTypes.bool, hideOverlay: PropTypes.bool, @@ -286,6 +284,8 @@ class WebcamDraggable extends PureComponent { audioModalIsOpen, } = this.props; + const { isMobile } = deviceInfo; + const { resizing, webcamsAreaResizable, hideWebcams } = this.state; const { @@ -316,7 +316,7 @@ class WebcamDraggable extends PureComponent { }; } - if (swapLayout || isCameraFullscreen || BROWSER_ISMOBILE) { + if (swapLayout || isCameraFullscreen || isMobile) { position = { x: 0, y: 0, @@ -445,7 +445,7 @@ class WebcamDraggable extends PureComponent { onStart={this.handleWebcamDragStart} onStop={this.handleWebcamDragStop} onMouseDown={e => e.preventDefault()} - disabled={swapLayout || isCameraFullscreen || BROWSER_ISMOBILE || resizing} + disabled={swapLayout || isCameraFullscreen || isMobile || resizing} position={position} > <Resizable diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/container.jsx b/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/container.jsx index e21f0ccf0c8b305eddf49080ff6ccb0afb7c625b..6c7b282fad1e3b94e352945ff1b8e9037246b37f 100755 --- a/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/settings-dropdown/container.jsx @@ -1,14 +1,15 @@ import React from 'react'; import { withTracker } from 'meteor/react-meteor-data'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; +import browserInfo from '/imports/utils/browserInfo'; import SettingsDropdown from './component'; import FullscreenService from '../../fullscreen-button/service'; import { meetingIsBreakout } from '/imports/ui/components/app/service'; -const BROWSER_RESULTS = browser(); -const isSafari = BROWSER_RESULTS.name === 'safari'; -const isIphone = (navigator.userAgent.match(/iPhone/i)) ? true : false; -const noIOSFullscreen = ((isSafari && BROWSER_RESULTS.versionNumber < 12) || isIphone) ? true : false; +const { isIphone } = deviceInfo; +const { isSafari, isValidSafariVersion } = browserInfo; + +const noIOSFullscreen = !!(((isSafari && !isValidSafariVersion) || isIphone)); const SettingsDropdownContainer = props => ( <SettingsDropdown {...props} /> diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx index 473ec85b88e13e09fcf1fed2b239c7b19a8f43e7..11eeab3ec6d2fdbcda9f23184cd0ae5811c7c894 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-toolbar/component.jsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component'; import Button from '/imports/ui/components/button/component'; import { HUNDRED_PERCENT, MAX_PERCENT, STEP } from '/imports/utils/slideCalcUtils'; @@ -225,9 +225,7 @@ class PresentationToolbar extends PureComponent { currentSlide, } = this.props; - const BROWSER_RESULTS = browser(); - const isMobileBrowser = BROWSER_RESULTS.mobile - || BROWSER_RESULTS.os.includes('Android'); + const { isMobile } = deviceInfo; const startOfSlides = !(currentSlideNum > 1); const endOfSlides = !(currentSlideNum < numberOfSlides); @@ -314,7 +312,7 @@ class PresentationToolbar extends PureComponent { { <div className={styles.presentationZoomControls}> { - !isMobileBrowser + !isMobile ? ( <TooltipContainer> <ZoomTool diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx index 2c7053c0c406011f016d48b59447cb9a0f07d122..09b31515ac47b1282186dde0e5237872712f32e6 100755 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/component.jsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; import cx from 'classnames'; +import deviceInfo from '/imports/utils/deviceInfo'; import Button from '/imports/ui/components/button/component'; import Checkbox from '/imports/ui/components/checkbox/component'; import Icon from '/imports/ui/components/icon/component'; @@ -10,15 +11,10 @@ import update from 'immutability-helper'; import logger from '/imports/startup/client/logger'; import { notify } from '/imports/ui/services/notification'; import { toast } from 'react-toastify'; -import browser from 'browser-detect'; import _ from 'lodash'; import { styles } from './styles'; -const BROWSER_RESULTS = browser(); -const isMobileBrowser = (BROWSER_RESULTS ? BROWSER_RESULTS.mobile : false) - || (BROWSER_RESULTS && BROWSER_RESULTS.os - ? BROWSER_RESULTS.os.includes('Android') // mobile flag doesn't always work - : false); +const { isMobile } = deviceInfo; const propTypes = { intl: PropTypes.object.isRequired, @@ -968,7 +964,7 @@ class PresentationUploader extends Component { {`${intl.formatMessage(intlMessages.message)}`} </div> {this.renderPresentationList()} - {isMobileBrowser ? this.renderPicDropzone() : null} + {isMobile ? this.renderPicDropzone() : null} {this.renderDropzone()} </div> </div> diff --git a/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx b/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx index a55b0c8417c270abecebd39f97bce1065a73f05e..fa54f28de77071c313845ae75401a0d680cdf9bc 100644 --- a/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/shortcut-help/component.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl } from 'react-intl'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; +import deviceInfo from '/imports/utils/deviceInfo'; import Modal from '/imports/ui/components/modal/simple/component'; import _ from 'lodash'; import { styles } from './styles'; @@ -103,32 +104,32 @@ const CHAT_ENABLED = CHAT_CONFIG.enabled; const ShortcutHelpComponent = (props) => { const { intl, shortcuts } = props; - const { name, os } = browser(); + const { browserName } = browserInfo; + const { isIos, isMacos } = deviceInfo; let accessMod = null; // different browsers use different access modifier keys // on different systems when using accessKey property. // Overview how different browsers behave: https://www.w3schools.com/jsref/prop_html_accesskey.asp - switch (name) { - case 'chrome': - case 'edge': + switch (browserName) { + case 'Chrome': + case 'Microsoft Edge': accessMod = 'Alt'; break; - case 'firefox': + case 'Firefox': accessMod = 'Alt + Shift'; break; - case 'safari': - case 'crios': - case 'fxios': - accessMod = 'Control + Alt'; - break; default: break; } + // all Browsers on iOS are using Control + Alt as access modifier + if (isIos) { + accessMod = 'Control + Alt'; + } // all Browsers on MacOS are using Control + Option as access modifier - if (os.includes('OS X 10')) { + if (isMacos) { accessMod = 'Control + Option'; } diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/user-dropdown/theteredDropdown/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/user-dropdown/theteredDropdown/component.jsx index 542cb560af113c4e85b7b3521d30f261cf445404..4ec2b441eb35d382936b16bdfecef2e716e704e1 100644 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/user-dropdown/theteredDropdown/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-list-item/user-dropdown/theteredDropdown/component.jsx @@ -2,8 +2,8 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; import cx from 'classnames'; -import { isMobile } from 'react-device-detect'; import { defineMessages, injectIntl } from 'react-intl'; +import deviceInfo from '/imports/utils/deviceInfo'; import Button from '/imports/ui/components/button/component'; import screenreaderTrap from 'makeup-screenreader-trap'; import TetherComponent from 'react-tether'; @@ -180,6 +180,8 @@ class Dropdown extends Component { const { isOpen } = this.state; + const { isMobile } = deviceInfo; + let trigger = children.find(x => x.type === DropdownTrigger); let content = children.find(x => x.type === DropdownContent); diff --git a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx index fed89b40d6957a069acfb81d6c3a3a7236a5d0c7..cc57006b6925438a55a0be92d8d61e5204a7dc8b 100755 --- a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx @@ -4,10 +4,9 @@ import { defineMessages, injectIntl, FormattedMessage, } from 'react-intl'; import Button from '/imports/ui/components/button/component'; -// import { notify } from '/imports/ui/services/notification'; import logger from '/imports/startup/client/logger'; import Modal from '/imports/ui/components/modal/simple/component'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; import cx from 'classnames'; import Service from './service'; import VideoService from '../video-provider/service'; @@ -652,9 +651,11 @@ class VideoPreview extends Component { const shared = sharedDevices.includes(webcamDeviceId); + const { isEdge, isIe } = browserInfo; + return ( <div> - {browser().name === 'edge' || browser().name === 'ie' ? ( + {isEdge || isIe ? ( <p className={styles.browserWarning}> <FormattedMessage id="app.audioModal.unsupportedBrowserLabel" diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/service.js b/bigbluebutton-html5/imports/ui/components/video-provider/service.js index 05e0196d817ede7a0453919c9f7f54289e631200..40de0d01295a35034f0b69d2ac2b7c97624b4e84 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/service.js +++ b/bigbluebutton-html5/imports/ui/components/video-provider/service.js @@ -9,7 +9,8 @@ import UserListService from '/imports/ui/components/user-list/service'; import { makeCall } from '/imports/ui/services/api'; import { notify } from '/imports/ui/services/notification'; import { monitorVideoConnection } from '/imports/utils/stats'; -import browser from 'browser-detect'; +import deviceInfo from '/imports/utils/deviceInfo'; +import browserInfo from '/imports/utils/browserInfo'; import getFromUserSettings from '/imports/ui/services/users-settings'; import VideoPreviewService from '../video-preview/service'; import Storage from '/imports/ui/services/storage/session'; @@ -70,9 +71,9 @@ class VideoService { pageSize: 0, }); this.userParameterProfile = null; - const BROWSER_RESULTS = browser(); - this.isMobile = BROWSER_RESULTS.mobile || BROWSER_RESULTS.os.includes('Android'); - this.isSafari = BROWSER_RESULTS.name === 'safari'; + + this.isMobile = deviceInfo.isMobile; + this.isSafari = browserInfo.isSafari; this.numberOfDevices = 0; this.record = null; diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx index 21bb8333bdd9683277a297479f1ba7b4685cf3db..0c6d51e1908ce982fd325947f46eee6cb2ab166f 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/video-list/video-list-item/component.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; import { Meteor } from 'meteor/meteor'; import PropTypes from 'prop-types'; import _ from 'lodash'; @@ -12,7 +12,6 @@ import DropdownListTitle from '/imports/ui/components/dropdown/list/title/compon import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component'; import DropdownListItem from '/imports/ui/components/dropdown/list/item/component'; import Icon from '/imports/ui/components/icon/component'; -import logger from '/imports/startup/client/logger'; import FullscreenService from '/imports/ui/components/fullscreen-button/service'; import FullscreenButtonContainer from '/imports/ui/components/fullscreen-button/container'; import { styles } from '../styles'; @@ -44,7 +43,7 @@ class VideoListItem extends Component { this.onStreamStateChange = this.onStreamStateChange.bind(this); } - onStreamStateChange (e) { + onStreamStateChange(e) { const { streamState } = e.detail; const { isStreamHealthy } = this.state; @@ -173,26 +172,29 @@ class VideoListItem extends Component { numOfStreams, webcamDraggableState, swapLayout, - mirrored + mirrored, } = this.props; const availableActions = this.getAvailableActions(); const enableVideoMenu = Meteor.settings.public.kurento.enableVideoMenu || false; const shouldRenderReconnect = !isStreamHealthy && videoIsReady; - const result = browser(); - const isFirefox = (result && result.name) ? result.name.includes('firefox') : false; + const { isFirefox } = browserInfo; return ( - <div data-test={voiceUser.talking ? 'webcamItemTalkingUser' : 'webcamItem'} className={cx({ - [styles.content]: true, - [styles.talking]: voiceUser.talking, - })} + <div + data-test={voiceUser.talking ? 'webcamItemTalkingUser' : 'webcamItem'} + className={cx({ + [styles.content]: true, + [styles.talking]: voiceUser.talking, + })} > { - !videoIsReady && + !videoIsReady + && ( <div data-test="webcamConnecting" className={styles.connecting}> <span className={styles.loadingText}>{name}</span> </div> + ) } @@ -223,39 +225,41 @@ class VideoListItem extends Component { /> {videoIsReady && this.renderFullscreenButton()} </div> - { videoIsReady && + { videoIsReady + && ( <div className={styles.info}> - {enableVideoMenu && availableActions.length >= 3 - ? ( - <Dropdown className={isFirefox ? styles.dropdownFireFox : styles.dropdown}> - <DropdownTrigger className={styles.dropdownTrigger}> - <span>{name}</span> - </DropdownTrigger> - <DropdownContent placement="top left" className={styles.dropdownContent}> - <DropdownList className={styles.dropdownList}> - {availableActions} - </DropdownList> - </DropdownContent> - </Dropdown> - ) - : ( - <div className={isFirefox ? styles.dropdownFireFox - : styles.dropdown} - > - <span className={cx({ - [styles.userName]: true, - [styles.noMenu]: numOfStreams < 3, - })} + {enableVideoMenu && availableActions.length >= 3 + ? ( + <Dropdown className={isFirefox ? styles.dropdownFireFox : styles.dropdown}> + <DropdownTrigger className={styles.dropdownTrigger}> + <span>{name}</span> + </DropdownTrigger> + <DropdownContent placement="top left" className={styles.dropdownContent}> + <DropdownList className={styles.dropdownList}> + {availableActions} + </DropdownList> + </DropdownContent> + </Dropdown> + ) + : ( + <div className={isFirefox ? styles.dropdownFireFox + : styles.dropdown} > - {name} - </span> - </div> - ) + <span className={cx({ + [styles.userName]: true, + [styles.noMenu]: numOfStreams < 3, + })} + > + {name} + </span> + </div> + ) } - {voiceUser.muted && !voiceUser.listenOnly ? <Icon className={styles.muted} iconName="unmute_filled" /> : null} - {voiceUser.listenOnly ? <Icon className={styles.voice} iconName="listen" /> : null} - {voiceUser.joined && !voiceUser.muted ? <Icon className={styles.voice} iconName="unmute" /> : null} - </div> + {voiceUser.muted && !voiceUser.listenOnly ? <Icon className={styles.muted} iconName="unmute_filled" /> : null} + {voiceUser.listenOnly ? <Icon className={styles.voice} iconName="listen" /> : null} + {voiceUser.joined && !voiceUser.muted ? <Icon className={styles.voice} iconName="unmute" /> : null} + </div> + ) } </div> ); diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/component.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/component.jsx index f776cc807be11d89199614684374b80706406e4e..a5ce6bfb40e44f278da5562150810c645dc44296 100755 --- a/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/whiteboard/whiteboard-toolbar/component.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import cx from 'classnames'; import { HEXToINTColor, INTToHEXColor } from '/imports/utils/hexInt'; import { defineMessages, injectIntl } from 'react-intl'; -import browser from 'browser-detect'; +import browserInfo from '/imports/utils/browserInfo'; import { noop } from 'lodash'; import KEY_CODES from '/imports/utils/keyCodes'; import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component'; @@ -64,7 +64,7 @@ const intlMessages = defineMessages({ }, }); -const isEdge = browser().name === 'edge'; +const { isEdge } = browserInfo; const runExceptInEdge = fn => (isEdge ? noop : fn); class WhiteboardToolbar extends Component { diff --git a/bigbluebutton-html5/imports/utils/browserInfo.js b/bigbluebutton-html5/imports/utils/browserInfo.js new file mode 100755 index 0000000000000000000000000000000000000000..2459cb8af63b67b3125677298f2b2499fd3744db --- /dev/null +++ b/bigbluebutton-html5/imports/utils/browserInfo.js @@ -0,0 +1,29 @@ +import Bowser from 'bowser'; + +const BOWSER_RESULTS = Bowser.parse(window.navigator.userAgent); + +const isChrome = BOWSER_RESULTS.browser.name === 'Chrome'; +const isSafari = BOWSER_RESULTS.browser.name === 'Safari'; +const isEdge = BOWSER_RESULTS.browser.name === 'Microsoft Edge'; +const isIe = BOWSER_RESULTS.browser.name === 'Internet Explorer'; +const isFirefox = BOWSER_RESULTS.browser.name === 'Firefox'; + +const browserName = BOWSER_RESULTS.browser.name; +const versionNumber = BOWSER_RESULTS.browser.version; + +const isValidSafariVersion = Bowser.getParser(window.navigator.userAgent).satisfies({ + safari: '>12', +}); + +const browserInfo = { + isChrome, + isSafari, + isEdge, + isIe, + isFirefox, + browserName, + versionNumber, + isValidSafariVersion, +}; + +export default browserInfo; diff --git a/bigbluebutton-html5/imports/utils/deviceInfo.js b/bigbluebutton-html5/imports/utils/deviceInfo.js index a5dfb72da1d334e4b44f09e6cdaa0bbbdce5bb3a..9471862c58986673f3f5de47cfc84688b4538924 100755 --- a/bigbluebutton-html5/imports/utils/deviceInfo.js +++ b/bigbluebutton-html5/imports/utils/deviceInfo.js @@ -1,19 +1,34 @@ -const deviceInfo = { - type() { - // Listing of Device Viewport sizes, Updated : March 25th, 2018 - // http://mediag.com/news/popular-screen-resolutions-designing-for-all/ - const MAX_PHONE_SHORT_SIDE = 480; +import Bowser from 'bowser'; - const smallSide = window.screen.width < window.screen.height - ? window.screen.width - : window.screen.height; +const BOWSER_RESULTS = Bowser.parse(window.navigator.userAgent); - return { - isPhone: smallSide <= MAX_PHONE_SHORT_SIDE, - }; - }, - hasMediaDevices: !!navigator.mediaDevices, -}; +const isPhone = BOWSER_RESULTS.platform.type === 'mobile'; +// we need a 'hack' to correctly detect ipads with ios > 13 +const isTablet = BOWSER_RESULTS.platform.type === 'tablet' || (BOWSER_RESULTS.os.name === 'macOS' && window.navigator.maxTouchPoints > 0); +const isMobile = isPhone || isTablet; +const hasMediaDevices = !!navigator.mediaDevices; +const osName = BOWSER_RESULTS.os.name; +const osVersion = BOWSER_RESULTS.os.version; +const isIos = osName === 'iOS'; +const isMacos = osName === 'macOS'; +const isIphone = !!(window.navigator.userAgent.match(/iPhone/i)); + +const SUPPORTED_IOS_VERSION = 12.2; +const isIosVersionSupported = () => parseFloat(osVersion) >= SUPPORTED_IOS_VERSION; +const isPortrait = () => window.innerHeight > window.innerWidth; + +const deviceInfo = { + isTablet, + isPhone, + isMobile, + hasMediaDevices, + osName, + isPortrait, + isIos, + isMacos, + isIphone, + isIosVersionSupported, +}; export default deviceInfo; diff --git a/bigbluebutton-html5/package-lock.json b/bigbluebutton-html5/package-lock.json index af01ac900518db48e3fcb84f2f0b244e1c94ac9e..8762657cb4f97eec3812ec6d7a21eab2493360c0 100644 --- a/bigbluebutton-html5/package-lock.json +++ b/bigbluebutton-html5/package-lock.json @@ -2015,6 +2015,11 @@ "inherits": "~2.0.0" } }, + "bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2044,14 +2049,6 @@ "@browser-bunyan/levels": "^1.6.0" } }, - "browser-detect": { - "version": "0.2.28", - "resolved": "https://registry.npmjs.org/browser-detect/-/browser-detect-0.2.28.tgz", - "integrity": "sha512-KeWGHqYQmHDkCFG2dIiX/2wFUgqevbw/rd6wNi9N6rZbaSJFtG5kel0HtprRwCGp8sqpQP79LzDJXf/WCx4WAw==", - "requires": { - "core-js": "^2.5.7" - } - }, "browser-or-node": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.2.1.tgz", @@ -9283,14 +9280,6 @@ "tinycolor2": "^1.4.1" } }, - "react-device-detect": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-1.17.0.tgz", - "integrity": "sha512-bBblIStwpHmoS281JFIVqeimcN3LhpoP5YKDWzxQdBIUP8S2xPvHDgizLDhUq2ScguLfVPmwfF5y268EEQR60w==", - "requires": { - "ua-parser-js": "^0.7.24" - } - }, "react-dom": { "version": "16.14.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", @@ -11061,11 +11050,6 @@ "is-typedarray": "^1.0.0" } }, - "ua-parser-js": { - "version": "0.7.24", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.24.tgz", - "integrity": "sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==" - }, "unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", diff --git a/bigbluebutton-html5/package.json b/bigbluebutton-html5/package.json index 257e4063c26cc83f75cc3fbaba9bb24ad1f46868..4fb265608a5c87b607044588071492d538efbde2 100755 --- a/bigbluebutton-html5/package.json +++ b/bigbluebutton-html5/package.json @@ -35,8 +35,8 @@ "autoprefixer": "~9.3.1", "axios": "^0.21.1", "babel-runtime": "~6.26.0", + "bowser": "^2.11.0", "browser-bunyan": "^1.6.3", - "browser-detect": "^0.2.28", "classnames": "^2.2.6", "clipboard": "^2.0.8", "crypto-js": "^4.0.0", @@ -58,7 +58,6 @@ "react": "^16.14.0", "react-autosize-textarea": "^5.0.1", "react-color": "^2.19.3", - "react-device-detect": "^1.17.0", "react-dom": "^16.14.0", "react-draggable": "^3.3.2", "react-dropzone": "^7.0.1",