Massive change. Changed to react-scripts (webpack) for building. Changed to material-ui where applicable. Changed to CSS-in-JS.
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import FullScreen from '../FullScreen';
|
||||
import FullScreenIcon from '@material-ui/icons/Fullscreen';
|
||||
import FullScreenExitIcon from '@material-ui/icons/FullscreenExit';
|
||||
|
||||
const styles = () =>
|
||||
({
|
||||
root :
|
||||
{
|
||||
position : 'absolute',
|
||||
top : 0,
|
||||
left : 0,
|
||||
height : '100%',
|
||||
width : '100%',
|
||||
zIndex : 20000
|
||||
},
|
||||
controls :
|
||||
{
|
||||
position : 'absolute',
|
||||
zIndex : 20020,
|
||||
right : 0,
|
||||
top : 0,
|
||||
display : 'flex',
|
||||
flexDirection : 'row',
|
||||
justifyContent : 'flex-start',
|
||||
alignItems : 'center',
|
||||
padding : '0.4vmin'
|
||||
},
|
||||
button :
|
||||
{
|
||||
flex : '0 0 auto',
|
||||
margin : '0.2vmin',
|
||||
borderRadius : 2,
|
||||
backgroundColor : 'rgba(255, 255, 255, 0.7)',
|
||||
cursor : 'pointer',
|
||||
transitionProperty : 'opacity, background-color',
|
||||
transitionDuration : '0.15s',
|
||||
width : '5vmin',
|
||||
height : '5vmin'
|
||||
},
|
||||
icon :
|
||||
{
|
||||
fontSize : '5vmin'
|
||||
},
|
||||
incompatibleVideo :
|
||||
{
|
||||
position : 'absolute',
|
||||
zIndex : 20010,
|
||||
top : 0,
|
||||
bottom : 0,
|
||||
left : 0,
|
||||
right : 0,
|
||||
display : 'flex',
|
||||
flexDirection : 'column',
|
||||
justifyContent : 'center',
|
||||
alignItems : 'center',
|
||||
'& p' :
|
||||
{
|
||||
padding : '6px 12px',
|
||||
borderRadius : 6,
|
||||
userSelect : 'none',
|
||||
pointerEvents : 'none',
|
||||
fontSize : 15,
|
||||
color : 'rgba(255, 255, 255, 0.55)'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
class NewWindow extends React.PureComponent
|
||||
{
|
||||
static defaultProps =
|
||||
{
|
||||
url : '',
|
||||
name : 'Multiparty Meeting',
|
||||
title : 'Multiparty Meeting',
|
||||
features : { width: '800px', height: '600px' },
|
||||
onBlock : null,
|
||||
onUnload : null,
|
||||
center : 'parent',
|
||||
copyStyles : true
|
||||
};
|
||||
|
||||
handleToggleFullscreen = () =>
|
||||
{
|
||||
if (this.fullscreen.fullscreenElement)
|
||||
{
|
||||
this.fullscreen.exitFullscreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fullscreen.requestFullscreen(this.window.document.documentElement);
|
||||
}
|
||||
};
|
||||
|
||||
handleFullscreenChange = () =>
|
||||
{
|
||||
this.setState({
|
||||
fullscreen : this.fullscreen.fullscreenElement !== null
|
||||
});
|
||||
};
|
||||
|
||||
constructor(props)
|
||||
{
|
||||
super(props);
|
||||
|
||||
this.container = document.createElement('div');
|
||||
this.window = null;
|
||||
this.windowCheckerInterval = null;
|
||||
this.released = false;
|
||||
this.fullscreen = null;
|
||||
|
||||
this.state = {
|
||||
mounted : false,
|
||||
fullscreen : false
|
||||
};
|
||||
}
|
||||
|
||||
render()
|
||||
{
|
||||
const {
|
||||
classes
|
||||
} = this.props;
|
||||
|
||||
if (!this.state.mounted)
|
||||
return null;
|
||||
|
||||
return ReactDOM.createPortal([
|
||||
<div key='newwindow' className={classes.root}>
|
||||
<div className={classes.controls}>
|
||||
{this.fullscreen.fullscreenEnabled && (
|
||||
<div
|
||||
className={classes.button}
|
||||
onClick={this.handleToggleFullscreen}
|
||||
data-tip='Fullscreen'
|
||||
data-place='right'
|
||||
data-type='dark'
|
||||
>
|
||||
{ this.state.fullscreen ?
|
||||
<FullScreenExitIcon className={classes.icon} />
|
||||
:
|
||||
<FullScreenIcon className={classes.icon} />
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
], this.container);
|
||||
}
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
this.openChild();
|
||||
// eslint-disable-next-line react/no-did-mount-set-state
|
||||
this.setState({ mounted: true });
|
||||
|
||||
this.fullscreen = new FullScreen(this.window.document);
|
||||
|
||||
if (this.fullscreen.fullscreenEnabled)
|
||||
{
|
||||
this.fullscreen.addEventListener('fullscreenchange', this.handleFullscreenChange);
|
||||
}
|
||||
}
|
||||
|
||||
openChild()
|
||||
{
|
||||
const {
|
||||
url,
|
||||
title,
|
||||
name,
|
||||
features,
|
||||
onBlock,
|
||||
center
|
||||
} = this.props;
|
||||
|
||||
if (center === 'parent')
|
||||
{
|
||||
features.left =
|
||||
(window.top.outerWidth / 2) + window.top.screenX - (features.width / 2);
|
||||
features.top =
|
||||
(window.top.outerHeight / 2) + window.top.screenY - (features.height / 2);
|
||||
}
|
||||
else if (center === 'screen')
|
||||
{
|
||||
const screenLeft =
|
||||
window.screenLeft !== undefined ? window.screenLeft : window.screen.left;
|
||||
const screenTop =
|
||||
window.screenTop !== undefined ? window.screenTop : window.screen.top;
|
||||
|
||||
const width = window.innerWidth
|
||||
? window.innerWidth
|
||||
: document.documentElement.clientWidth
|
||||
? document.documentElement.clientWidth
|
||||
: window.screen.width;
|
||||
const height = window.innerHeight
|
||||
? window.innerHeight
|
||||
: document.documentElement.clientHeight
|
||||
? document.documentElement.clientHeight
|
||||
: window.screen.height;
|
||||
|
||||
features.left = (width / 2) - (features.width / 2) + screenLeft;
|
||||
features.top = (height / 2) - (features.height / 2) + screenTop;
|
||||
}
|
||||
|
||||
this.window = window.open(url, name, toWindowFeatures(features));
|
||||
|
||||
this.windowCheckerInterval = setInterval(() =>
|
||||
{
|
||||
if (!this.window || this.window.closed)
|
||||
{
|
||||
this.release();
|
||||
}
|
||||
}, 50);
|
||||
|
||||
if (this.window)
|
||||
{
|
||||
this.window.document.title = title;
|
||||
this.window.document.body.appendChild(this.container);
|
||||
|
||||
if (this.props.copyStyles)
|
||||
{
|
||||
setTimeout(() => copyStyles(document, this.window.document), 0);
|
||||
}
|
||||
|
||||
this.window.addEventListener('beforeunload', () => this.release());
|
||||
}
|
||||
else if (typeof onBlock === 'function')
|
||||
{
|
||||
onBlock(null);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
if (this.window)
|
||||
{
|
||||
if (this.fullscreen && this.fullscreen.fullscreenEnabled)
|
||||
{
|
||||
this.fullscreen.removeEventListener('fullscreenchange', this.handleFullscreenChange);
|
||||
}
|
||||
|
||||
this.window.close();
|
||||
}
|
||||
}
|
||||
|
||||
release()
|
||||
{
|
||||
if (this.released)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.released = true;
|
||||
|
||||
clearInterval(this.windowCheckerInterval);
|
||||
|
||||
const { onUnload } = this.props;
|
||||
|
||||
if (typeof onUnload === 'function')
|
||||
{
|
||||
onUnload(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NewWindow.propTypes = {
|
||||
children : PropTypes.node,
|
||||
url : PropTypes.string,
|
||||
name : PropTypes.string,
|
||||
title : PropTypes.string,
|
||||
features : PropTypes.object,
|
||||
onUnload : PropTypes.func,
|
||||
onBlock : PropTypes.func,
|
||||
center : PropTypes.oneOf([ 'parent', 'screen' ]),
|
||||
copyStyles : PropTypes.bool,
|
||||
classes : PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
function copyStyles(source, target)
|
||||
{
|
||||
Array.from(source.styleSheets).forEach((styleSheet) =>
|
||||
{
|
||||
let rules;
|
||||
|
||||
try
|
||||
{
|
||||
rules = styleSheet.cssRules;
|
||||
}
|
||||
catch (err) {}
|
||||
|
||||
if (rules)
|
||||
{
|
||||
const newStyleEl = source.createElement('style');
|
||||
|
||||
Array.from(styleSheet.cssRules).forEach((cssRule) =>
|
||||
{
|
||||
const { cssText, type } = cssRule;
|
||||
|
||||
let returnText = cssText;
|
||||
|
||||
if ([ 3, 5 ].includes(type))
|
||||
{
|
||||
returnText = cssText
|
||||
.split('url(')
|
||||
.map((line) =>
|
||||
{
|
||||
if (line[1] === '/')
|
||||
{
|
||||
return `${line.slice(0, 1)}${
|
||||
window.location.origin
|
||||
}${line.slice(1)}`;
|
||||
}
|
||||
|
||||
return line;
|
||||
})
|
||||
.join('url(');
|
||||
}
|
||||
|
||||
newStyleEl.appendChild(source.createTextNode(returnText));
|
||||
});
|
||||
|
||||
target.head.appendChild(newStyleEl);
|
||||
}
|
||||
else if (styleSheet.href)
|
||||
{
|
||||
const newLinkEl = source.createElement('link');
|
||||
|
||||
newLinkEl.rel = 'stylesheet';
|
||||
newLinkEl.href = styleSheet.href;
|
||||
target.head.appendChild(newLinkEl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toWindowFeatures(obj)
|
||||
{
|
||||
return Object.keys(obj)
|
||||
.reduce((features, name) =>
|
||||
{
|
||||
const value = obj[name];
|
||||
|
||||
if (typeof value === 'boolean')
|
||||
{
|
||||
features.push(`${name}=${value ? 'yes' : 'no'}`);
|
||||
}
|
||||
else
|
||||
{
|
||||
features.push(`${name}=${value}`);
|
||||
}
|
||||
|
||||
return features;
|
||||
}, [])
|
||||
.join(',');
|
||||
}
|
||||
|
||||
export default withStyles(styles)(NewWindow);
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import NewWindow from './NewWindow';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as appPropTypes from '../appPropTypes';
|
||||
import * as stateActions from '../../actions/stateActions';
|
||||
import FullView from '../VideoContainers/FullView';
|
||||
|
||||
const VideoWindow = (props) =>
|
||||
{
|
||||
const {
|
||||
advancedMode,
|
||||
consumer,
|
||||
toggleConsumerWindow
|
||||
} = props;
|
||||
|
||||
if (!consumer)
|
||||
return null;
|
||||
|
||||
const consumerVisible = (
|
||||
Boolean(consumer) &&
|
||||
!consumer.locallyPaused &&
|
||||
!consumer.remotelyPaused
|
||||
);
|
||||
|
||||
let consumerProfile;
|
||||
|
||||
if (consumer)
|
||||
consumerProfile = consumer.profile;
|
||||
|
||||
return (
|
||||
<NewWindow onUnload={toggleConsumerWindow}>
|
||||
<FullView
|
||||
advancedMode={advancedMode}
|
||||
videoTrack={consumer ? consumer.track : null}
|
||||
videoVisible={consumerVisible}
|
||||
videoProfile={consumerProfile}
|
||||
/>
|
||||
</NewWindow>
|
||||
);
|
||||
};
|
||||
|
||||
VideoWindow.propTypes =
|
||||
{
|
||||
advancedMode : PropTypes.bool,
|
||||
consumer : appPropTypes.Consumer,
|
||||
toggleConsumerWindow : PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) =>
|
||||
{
|
||||
return {
|
||||
consumer : state.consumers[state.room.windowConsumer]
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) =>
|
||||
{
|
||||
return {
|
||||
toggleConsumerWindow : () =>
|
||||
{
|
||||
dispatch(stateActions.toggleConsumerWindow());
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const VideoWindowContainer = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(VideoWindow);
|
||||
|
||||
export default VideoWindowContainer;
|
||||
Reference in New Issue
Block a user