Merge pull request #5528 from KDSBrowne/xx.add.Edge-support-html5
Add support for HTML5 client in Edge
This commit is contained in:
commit
fb66e9420a
@ -5,7 +5,7 @@ import { defineMessages, injectIntl, intlShape } from 'react-intl';
|
||||
import Modal from 'react-modal';
|
||||
import cx from 'classnames';
|
||||
import Resizable from 're-resizable';
|
||||
|
||||
import browser from 'browser-detect';
|
||||
import ToastContainer from '../toast/container';
|
||||
import ModalContainer from '../modal/container';
|
||||
import NotificationsBarContainer from '../notifications-bar/container';
|
||||
@ -79,6 +79,11 @@ class App extends Component {
|
||||
document.getElementsByTagName('html')[0].lang = locale;
|
||||
document.getElementsByTagName('html')[0].style.fontSize = this.props.fontSize;
|
||||
|
||||
const BROWSER_RESULTS = browser();
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
body.classList.add(`browser-${BROWSER_RESULTS.name}`);
|
||||
body.classList.add(`os-${BROWSER_RESULTS.os.split(' ').shift().toLowerCase()}`);
|
||||
|
||||
this.handleWindowResize();
|
||||
window.addEventListener('resize', this.handleWindowResize, false);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ModalBase from '/imports/ui/components/modal/base/component';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import { defineMessages, injectIntl, intlShape } from 'react-intl';
|
||||
import { styles } from './styles';
|
||||
import PermissionsOverlay from '../permissions-overlay/component';
|
||||
@ -10,7 +9,6 @@ import AudioSettings from '../audio-settings/component';
|
||||
import EchoTest from '../echo-test/component';
|
||||
import Help from '../help/component';
|
||||
|
||||
|
||||
const propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
closeModal: PropTypes.func.isRequired,
|
||||
@ -307,11 +305,12 @@ class AudioModal extends Component {
|
||||
const {
|
||||
isEchoTest,
|
||||
intl,
|
||||
isIOSChrome,
|
||||
} = this.props;
|
||||
|
||||
const { content } = this.state;
|
||||
|
||||
if (deviceInfo.osType().isIOSChrome) {
|
||||
if (isIOSChrome) {
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.warning}>!</div>
|
||||
@ -381,6 +380,7 @@ class AudioModal extends Component {
|
||||
const {
|
||||
intl,
|
||||
showPermissionsOvelay,
|
||||
isIOSChrome,
|
||||
} = this.props;
|
||||
|
||||
const { content } = this.state;
|
||||
@ -399,16 +399,13 @@ class AudioModal extends Component {
|
||||
data-test="audioModalHeader"
|
||||
className={styles.header}
|
||||
>{
|
||||
(!deviceInfo.osType().isIOSChrome ?
|
||||
isIOSChrome ? null :
|
||||
<h3 className={styles.title}>
|
||||
{content ?
|
||||
this.contents[content].title :
|
||||
intl.formatMessage(intlMessages.audioChoiceLabel)}
|
||||
</h3> : <h3 className={styles.title} />
|
||||
)
|
||||
</h3>
|
||||
}
|
||||
|
||||
|
||||
<Button
|
||||
data-test="modalBaseCloseButton"
|
||||
className={styles.closeBtn}
|
||||
|
@ -1,6 +1,7 @@
|
||||
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 AudioModal from './component';
|
||||
import Service from '../service';
|
||||
|
||||
@ -24,7 +25,7 @@ export default withModalMounter(withTracker(({ mountModal }) =>
|
||||
}
|
||||
reject(() => {
|
||||
Service.exitAudio();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
return call.then(() => {
|
||||
@ -55,4 +56,5 @@ export default withModalMounter(withTracker(({ mountModal }) =>
|
||||
joinFullAudioImmediately: !listenOnlyMode && skipCheck,
|
||||
joinFullAudioEchoTest: !listenOnlyMode && !skipCheck,
|
||||
forceListenOnlyAttendee: listenOnlyMode && forceListenOnly && !Service.isUserModerator(),
|
||||
isIOSChrome: browser().name === 'crios',
|
||||
}))(AudioModalContainer));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
import { injectIntl, intlShape, defineMessages } from 'react-intl';
|
||||
import { styles } from './styles';
|
||||
|
||||
@ -17,52 +17,16 @@ const intlMessages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
class PermissionsOverlay extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const broswerStyles = {
|
||||
Chrome: {
|
||||
top: '145px',
|
||||
left: '380px',
|
||||
},
|
||||
Firefox: {
|
||||
top: '210px',
|
||||
left: '605px',
|
||||
},
|
||||
Safari: {
|
||||
top: '100px',
|
||||
left: '100px',
|
||||
},
|
||||
};
|
||||
|
||||
const browser = window.bowser.name;
|
||||
|
||||
this.state = {
|
||||
styles: {
|
||||
top: broswerStyles[browser].top,
|
||||
left: broswerStyles[browser].left,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
intl,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={styles.overlay}>
|
||||
<div style={this.state.styles} className={styles.hint}>
|
||||
{ intl.formatMessage(intlMessages.title) }
|
||||
<small>
|
||||
{ intl.formatMessage(intlMessages.hint) }
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
const PermissionsOverlay = ({ intl }) => (
|
||||
<div className={styles.overlay}>
|
||||
<div className={styles.hint}>
|
||||
{ intl.formatMessage(intlMessages.title) }
|
||||
<small>
|
||||
{ intl.formatMessage(intlMessages.hint) }
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
PermissionsOverlay.propTypes = propTypes;
|
||||
|
||||
|
@ -1,3 +1,44 @@
|
||||
@mixin arrowIconStyle() {
|
||||
&:after {
|
||||
top: -50px;
|
||||
left: -20px;
|
||||
font-size: 20px;
|
||||
-webkit-animation: bounce 2s infinite;
|
||||
animation: bounce 2s infinite;
|
||||
display: block;
|
||||
font-family: 'bbb-icons';
|
||||
content: "\E906";
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:global(.browser-edge) &:after {
|
||||
top: -50px;
|
||||
left: -15.5em;
|
||||
font-size: 20px;
|
||||
-webkit-animation: bounceRotate 2s infinite;
|
||||
animation: bounceRotate 2s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin positionHint() {
|
||||
:global(.browser-edge) & {
|
||||
left: 50%;
|
||||
bottom: 10%;
|
||||
}
|
||||
:global(.browser-firefox) & {
|
||||
top: 210px;
|
||||
left: 605px;
|
||||
}
|
||||
:global(.browser-chrome) & {
|
||||
top: 145px;
|
||||
left: 380px;
|
||||
}
|
||||
:global(.browser-safari) & {
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 1002;
|
||||
@ -10,6 +51,8 @@
|
||||
}
|
||||
|
||||
.hint {
|
||||
@include positionHint();
|
||||
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
@ -25,17 +68,7 @@
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
font-family: 'bbb-icons';
|
||||
content: "\E906";
|
||||
position: relative;
|
||||
top: -50px;
|
||||
left: -20px;
|
||||
font-size: 20px;
|
||||
-webkit-animation: bounce 2s infinite;
|
||||
animation: bounce 2s infinite;
|
||||
}
|
||||
@include arrowIconStyle();
|
||||
}
|
||||
|
||||
@-webkit-keyframes bounce {
|
||||
@ -80,6 +113,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounceRotate {
|
||||
0%, 20%, 50%, 80%, 100% {
|
||||
-ms-transform: translateY(0) rotate(180deg);
|
||||
transform: translateY(0) rotate(180deg);
|
||||
}
|
||||
40% {
|
||||
-ms-transform: translateY(10px) rotate(180deg);
|
||||
transform: translateY(10px) rotate(180deg);
|
||||
}
|
||||
60% {
|
||||
-ms-transform: translateY(5px) rotate(180deg);
|
||||
transform: translateY(5px) rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import browser from 'browser-detect';
|
||||
import Modal from '/imports/ui/components/modal/simple/component';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import _ from 'lodash';
|
||||
import { styles } from './styles';
|
||||
|
||||
@ -77,23 +77,24 @@ const SHORTCUTS_CONFIG = Meteor.settings.public.app.shortcuts;
|
||||
class ShortcutHelpComponent extends Component {
|
||||
render() {
|
||||
const { intl } = this.props;
|
||||
const { isWindows, isLinux, isMac } = deviceInfo.osType();
|
||||
const { isFirefox, isChrome, isIE } = deviceInfo.browserType();
|
||||
const shortcuts = Object.values(SHORTCUTS_CONFIG);
|
||||
const { name } = browser();
|
||||
|
||||
let accessMod = null;
|
||||
|
||||
if (isMac) {
|
||||
accessMod = 'Control + Alt';
|
||||
}
|
||||
|
||||
if (isWindows) {
|
||||
accessMod = isIE ? 'Alt' : accessMod;
|
||||
}
|
||||
|
||||
if (isWindows || isLinux) {
|
||||
accessMod = isFirefox ? 'Alt + Shift' : accessMod;
|
||||
accessMod = isChrome ? 'Alt' : accessMod;
|
||||
switch (name) {
|
||||
case 'chrome':
|
||||
case 'edge':
|
||||
accessMod = 'Alt';
|
||||
break;
|
||||
case 'firefox':
|
||||
accessMod = 'Alt + Shift';
|
||||
break;
|
||||
case 'safari':
|
||||
case 'crios':
|
||||
case 'fxios':
|
||||
accessMod = 'Control + Alt';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,12 +1,12 @@
|
||||
@import "/imports/ui/stylesheets/variables/palette";
|
||||
@import "/imports/ui/stylesheets/variables/general";
|
||||
@import "/imports/ui/stylesheets/mixins/_indicators";
|
||||
|
||||
/* Variables
|
||||
* ==========
|
||||
*/
|
||||
$user-avatar-border: $color-gray-light;
|
||||
$user-avatar-text: $color-white;
|
||||
$user-indicators-offset: -5px;
|
||||
$user-indicator-presenter-bg: $color-primary;
|
||||
$user-indicator-voice-bg: $color-success;
|
||||
$user-indicator-muted-bg: $color-danger;
|
||||
$user-list-bg: $color-off-white;
|
||||
@ -72,24 +72,14 @@ $user-color: currentColor; //picks the current color reference in the class
|
||||
.presenter {
|
||||
&:before {
|
||||
content: "\00a0\e90b\00a0";
|
||||
opacity: 1;
|
||||
top: $user-indicators-offset;
|
||||
left: $user-indicators-offset;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
border-radius: 5px;
|
||||
background-color: $user-indicator-presenter-bg;
|
||||
padding: .425rem;
|
||||
}
|
||||
@include presenterIndicator();
|
||||
}
|
||||
|
||||
.voice {
|
||||
&:after {
|
||||
content: "\00a0\e931\00a0";
|
||||
background-color: $user-indicator-voice-bg;
|
||||
opacity: 1;
|
||||
width: 1.375rem;
|
||||
height: 1.375rem;
|
||||
top: 1.375rem;
|
||||
left: 1.375rem;
|
||||
}
|
||||
@ -99,18 +89,19 @@ $user-color: currentColor; //picks the current color reference in the class
|
||||
&:after {
|
||||
content: "\00a0\e932\00a0";
|
||||
background-color: $user-indicator-muted-bg;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.listenOnly {
|
||||
&:after {
|
||||
content: "\00a0\e90c\00a0";
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.listenOnly, .muted, .voice {
|
||||
@include indicatorStyles();
|
||||
}
|
||||
|
||||
.content {
|
||||
color: $user-avatar-text;
|
||||
top: 50%;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RenderInBrowser from 'react-render-in-browser';
|
||||
import AnnotationHelpers from '../helpers';
|
||||
|
||||
const DRAW_END = Meteor.settings.public.whiteboard.annotations.status.end;
|
||||
@ -138,20 +139,19 @@ export default class TextDrawComponent extends Component {
|
||||
|
||||
renderViewerTextShape(results) {
|
||||
const styles = TextDrawComponent.getViewerStyles(results);
|
||||
const { isChrome, isEdge } = this.props.browserType;
|
||||
|
||||
return (
|
||||
<g>
|
||||
{ isChrome || isEdge ? null :
|
||||
<clipPath id={this.props.annotation.id}>
|
||||
<rect
|
||||
x={results.x}
|
||||
y={results.y}
|
||||
width={results.width}
|
||||
height={results.height}
|
||||
/>
|
||||
</clipPath>
|
||||
}
|
||||
<RenderInBrowser only firefox>
|
||||
<clipPath id={this.props.annotation.id}>
|
||||
<rect
|
||||
x={results.x}
|
||||
y={results.y}
|
||||
width={results.width}
|
||||
height={results.height}
|
||||
/>
|
||||
</clipPath>
|
||||
</RenderInBrowser>
|
||||
<foreignObject
|
||||
clipPath={`url(#${this.props.annotation.id})`}
|
||||
x={results.x}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import TextShapeService from './service';
|
||||
import TextDrawComponent from './component';
|
||||
|
||||
@ -21,6 +20,5 @@ export default withTracker((params) => {
|
||||
isActive,
|
||||
setTextShapeValue: TextShapeService.setTextShapeValue,
|
||||
resetTextShapeActiveId: TextShapeService.resetTextShapeActiveId,
|
||||
browserType: deviceInfo.browserType(),
|
||||
};
|
||||
})(TextDrawContainer);
|
||||
|
@ -3,6 +3,9 @@ import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
import { HEXToINTColor, INTToHEXColor } from '/imports/utils/hexInt';
|
||||
import { defineMessages, injectIntl, intlShape } from 'react-intl';
|
||||
import RenderInBrowser from 'react-render-in-browser';
|
||||
import browser from 'browser-detect';
|
||||
import { noop } from 'lodash';
|
||||
import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component';
|
||||
import { styles } from './styles.scss';
|
||||
import ToolbarMenuItem from './toolbar-menu-item/component';
|
||||
@ -58,6 +61,8 @@ const intlMessages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
const runExceptInEdge = fn => (browser().name === 'edge' ? noop : fn);
|
||||
|
||||
class WhiteboardToolbar extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
@ -97,6 +102,8 @@ class WhiteboardToolbar extends Component {
|
||||
this.handleColorChange = this.handleColorChange.bind(this);
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||
this.componentDidMount = runExceptInEdge(this.componentDidMount);
|
||||
this.componentDidUpdate = runExceptInEdge(this.componentDidUpdate);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
@ -174,7 +181,6 @@ class WhiteboardToolbar extends Component {
|
||||
* 3. Switch from the Text tool to any other - trigger color and radius for thickness
|
||||
* 4. Trigger initial animation for the icons
|
||||
*/
|
||||
|
||||
// 1st case
|
||||
if (this.state.colorSelected.value !== prevState.colorSelected.value) {
|
||||
// 1st case b)
|
||||
@ -186,13 +192,12 @@ class WhiteboardToolbar extends Component {
|
||||
// 2nd case
|
||||
} else if (this.state.thicknessSelected.value !== prevState.thicknessSelected.value) {
|
||||
this.thicknessListIconRadius.beginElement();
|
||||
// 3rd case
|
||||
// 3rd case
|
||||
} else if (this.state.annotationSelected.value !== 'text' &&
|
||||
prevState.annotationSelected.value === 'text') {
|
||||
prevState.annotationSelected.value === 'text') {
|
||||
this.thicknessListIconRadius.beginElement();
|
||||
this.thicknessListIconColor.beginElement();
|
||||
}
|
||||
|
||||
// 4th case, initial animation is triggered in componentDidMount
|
||||
}
|
||||
|
||||
@ -406,36 +411,41 @@ class WhiteboardToolbar extends Component {
|
||||
renderThicknessItemIcon() {
|
||||
return (
|
||||
<svg className={styles.customSvgIcon} shapeRendering="geometricPrecision">
|
||||
<circle
|
||||
shapeRendering="geometricPrecision"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
stroke="black"
|
||||
strokeWidth="1"
|
||||
>
|
||||
<animate
|
||||
ref={(ref) => { this.thicknessListIconColor = ref; }}
|
||||
attributeName="fill"
|
||||
attributeType="XML"
|
||||
from={this.state.prevColorSelected.value}
|
||||
to={this.state.colorSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
<animate
|
||||
ref={(ref) => { this.thicknessListIconRadius = ref; }}
|
||||
attributeName="r"
|
||||
attributeType="XML"
|
||||
from={this.state.prevThicknessSelected.value}
|
||||
to={this.state.thicknessSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
</circle>
|
||||
<RenderInBrowser only edge>
|
||||
<circle cx="50%" cy="50%" r={this.state.thicknessSelected.value} stroke="black" strokeWidth="1" fill={this.state.colorSelected.value} />
|
||||
</RenderInBrowser>
|
||||
<RenderInBrowser except edge>
|
||||
<circle
|
||||
shapeRendering="geometricPrecision"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
stroke="black"
|
||||
strokeWidth="1"
|
||||
>
|
||||
<animate
|
||||
ref={(ref) => { this.thicknessListIconColor = ref; }}
|
||||
attributeName="fill"
|
||||
attributeType="XML"
|
||||
from={this.state.prevColorSelected.value}
|
||||
to={this.state.colorSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
<animate
|
||||
ref={(ref) => { this.thicknessListIconRadius = ref; }}
|
||||
attributeName="r"
|
||||
attributeType="XML"
|
||||
from={this.state.prevThicknessSelected.value}
|
||||
to={this.state.thicknessSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
</circle>
|
||||
</RenderInBrowser>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@ -474,19 +484,24 @@ class WhiteboardToolbar extends Component {
|
||||
renderColorItemIcon() {
|
||||
return (
|
||||
<svg className={styles.customSvgIcon}>
|
||||
<rect x="25%" y="25%" width="50%" height="50%" stroke="black" strokeWidth="1">
|
||||
<animate
|
||||
ref={(ref) => { this.colorListIconColor = ref; }}
|
||||
attributeName="fill"
|
||||
attributeType="XML"
|
||||
from={this.state.prevColorSelected.value}
|
||||
to={this.state.colorSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
</rect>
|
||||
<RenderInBrowser only edge>
|
||||
<rect x="25%" y="25%" width="50%" height="50%" stroke="black" strokeWidth="1" fill={this.state.colorSelected.value} />
|
||||
</RenderInBrowser>
|
||||
<RenderInBrowser except edge>
|
||||
<rect x="25%" y="25%" width="50%" height="50%" stroke="black" strokeWidth="1">
|
||||
<animate
|
||||
ref={(ref) => { this.colorListIconColor = ref; }}
|
||||
attributeName="fill"
|
||||
attributeType="XML"
|
||||
from={this.state.prevColorSelected.value}
|
||||
to={this.state.colorSelected.value}
|
||||
begin="indefinite"
|
||||
dur={TRANSITION_DURATION}
|
||||
repeatCount="0"
|
||||
fill="freeze"
|
||||
/>
|
||||
</rect>
|
||||
</RenderInBrowser>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
@import "/imports/ui/stylesheets/variables/palette";
|
||||
@import "/imports/ui/stylesheets/variables/general";
|
||||
|
||||
@mixin presenterIndicator() {
|
||||
&:before {
|
||||
opacity: 1;
|
||||
top: $user-indicators-offset;
|
||||
left: $user-indicators-offset;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
border-radius: 5px;
|
||||
background-color: $color-primary;
|
||||
}
|
||||
|
||||
:global(.browser-chrome) &:before,
|
||||
:global(.browser-firefox) &:before {
|
||||
padding: .45rem;
|
||||
}
|
||||
|
||||
:global(.browser-edge) &:before {
|
||||
padding-top: $indicator-padding-top;
|
||||
padding-left: $indicator-padding-left;
|
||||
padding-right: $indicator-padding-right;
|
||||
padding-bottom: $indicator-padding-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin indicatorStyles() {
|
||||
&:after {
|
||||
opacity: 1;
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
}
|
||||
|
||||
:global(.browser-edge) &:after {
|
||||
padding-top: $indicator-padding-top;
|
||||
padding-left: $indicator-padding-left;
|
||||
padding-right: $indicator-padding-right;
|
||||
padding-bottom: $indicator-padding-bottom;
|
||||
}
|
||||
}
|
@ -14,3 +14,14 @@ $lg-padding-y: 0.6rem;
|
||||
|
||||
$jumbo-padding-x: 3.025rem;
|
||||
$jumbo-padding-y: 1.5rem;
|
||||
|
||||
//used to center presenter indicator icon in Chrome / Firefox
|
||||
$indicator-padding: .425rem;
|
||||
|
||||
//used to center indicator icons in Edge
|
||||
$indicator-padding-right: 1.2em;
|
||||
$indicator-padding-left: 0.175em;
|
||||
$indicator-padding-top: 0.7em;
|
||||
$indicator-padding-bottom: 0.7em;
|
||||
|
||||
$user-indicators-offset: -5px;
|
||||
|
@ -12,25 +12,6 @@ const deviceInfo = {
|
||||
isPhone: smallSide <= MAX_PHONE_SHORT_SIDE,
|
||||
};
|
||||
},
|
||||
browserType() {
|
||||
return {
|
||||
// Uses features to determine browser
|
||||
isChrome: !!window.chrome && !!window.chrome.webstore,
|
||||
isFirefox: typeof InstallTrigger !== 'undefined',
|
||||
isIE: 'ActiveXObject' in window,
|
||||
isEdge: !document.documentMode && window.StyleMedia,
|
||||
};
|
||||
},
|
||||
osType() {
|
||||
return {
|
||||
// Uses userAgent to determine operating system
|
||||
isWindows: window.navigator.userAgent.indexOf('Windows') !== -1,
|
||||
isMac: window.navigator.userAgent.indexOf('Mac') !== -1,
|
||||
isLinux: window.navigator.userAgent.indexOf('Linux') !== -1,
|
||||
isIOSChrome: navigator.userAgent.match('CriOS'),
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
25
bigbluebutton-html5/package-lock.json
generated
25
bigbluebutton-html5/package-lock.json
generated
@ -401,6 +401,21 @@
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"browser-detect": {
|
||||
"version": "0.2.27",
|
||||
"resolved": "https://registry.npmjs.org/browser-detect/-/browser-detect-0.2.27.tgz",
|
||||
"integrity": "sha512-qjOSrFROblMbGhFbS1U7DkszptdRxAH7O9I3zZPT6oIbZKjhrudj+ZRuiQkuVtXs1/HEgMv+2zJuxZIsn/bLhQ==",
|
||||
"requires": {
|
||||
"core-js": "2.5.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "2.11.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz",
|
||||
@ -4660,6 +4675,16 @@
|
||||
"prop-types": "15.6.0"
|
||||
}
|
||||
},
|
||||
"react-render-in-browser": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-render-in-browser/-/react-render-in-browser-1.0.0.tgz",
|
||||
"integrity": "sha512-DnOYcGVfjcu13Em8Z/sNbgYSrL26NjCQhZNzOEMV3BJiZ5WfvWFqvI9P/MW2K8guAkuf+hBouQyZysJdqrVhKA==",
|
||||
"requires": {
|
||||
"prop-types": "15.6.0",
|
||||
"react": "16.0.0",
|
||||
"react-dom": "16.0.0"
|
||||
}
|
||||
},
|
||||
"react-router": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-3.0.5.tgz",
|
||||
|
@ -29,6 +29,7 @@
|
||||
"need to investigate"
|
||||
],
|
||||
"babel-runtime": "~6.26.0",
|
||||
"browser-detect": "^0.2.27",
|
||||
"classnames": "~2.2.5",
|
||||
"clipboard": "~1.7.1",
|
||||
"core-js": "~2.5.3",
|
||||
@ -52,6 +53,7 @@
|
||||
"react-dropzone": "~4.2.1",
|
||||
"react-intl": "~2.4.0",
|
||||
"react-modal": "~3.0.4",
|
||||
"react-render-in-browser": "^1.0.0",
|
||||
"react-router": "~3.0.2",
|
||||
"react-tabs": "~2.1.0",
|
||||
"react-toastify": "~2.1.2",
|
||||
|
Loading…
Reference in New Issue
Block a user