You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Conference.web.js 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /* global APP, $, interfaceConfig */
  2. import React, { Component } from 'react';
  3. import { connect as reactReduxConnect } from 'react-redux';
  4. import {
  5. connect,
  6. disconnect
  7. } from '../../base/connection';
  8. /**
  9. * For legacy reasons, inline style for display none.
  10. * @type {{display: string}}
  11. */
  12. const DISPLAY_NONE_STYLE = {
  13. display: 'none'
  14. };
  15. /**
  16. * Implements a React Component which renders initial conference layout
  17. */
  18. class Conference extends Component {
  19. /**
  20. * Until we don't rewrite UI using react components
  21. * we use UI.start from old app. Also method translates
  22. * component right after it has been mounted.
  23. *
  24. * @inheritdoc
  25. */
  26. componentDidMount() {
  27. APP.UI.start();
  28. // XXX Temporary solution until we add React translation.
  29. APP.translation.translateElement($('#videoconference_page'));
  30. this.props.dispatch(connect());
  31. }
  32. /**
  33. * Disconnect from the conference when component will be
  34. * unmounted.
  35. *
  36. * @inheritdoc
  37. */
  38. componentWillUnmount() {
  39. this.props.dispatch(disconnect());
  40. }
  41. /**
  42. * Conference component's property types.
  43. *
  44. * @static
  45. */
  46. static propTypes = {
  47. dispatch: React.PropTypes.func
  48. };
  49. /**
  50. * Initializes Conference component instance.
  51. *
  52. * @param {Object} props - The read-only properties with which the new
  53. * instance is to be initialized.
  54. */
  55. constructor(props) {
  56. super(props);
  57. const showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
  58. const showJitsiWatermark = interfaceConfig.SHOW_JITSI_WATERMARK;
  59. const showJitsiWatermarkForGuest
  60. = interfaceConfig.SHOW_WATERMARK_FOR_GUESTS;
  61. this.state = {
  62. ...this.state,
  63. showBrandWatermark,
  64. showJitsiWatermark,
  65. showJitsiWatermarkForGuest,
  66. brandWatermarkLink:
  67. showBrandWatermark ? interfaceConfig.BRAND_WATERMARK_LINK : '',
  68. jitsiWatermarkLink:
  69. showJitsiWatermark || showJitsiWatermarkForGuest
  70. ? interfaceConfig.JITSI_WATERMARK_LINK : '',
  71. showPoweredBy: interfaceConfig.SHOW_POWERED_BY
  72. };
  73. }
  74. /**
  75. * Implements React's {@link Component#render()}.
  76. *
  77. * @inheritdoc
  78. * @returns {ReactElement}
  79. */
  80. render() {
  81. return (
  82. <div id = 'videoconference_page'>
  83. <div id = 'mainToolbarContainer'>
  84. <div
  85. className = 'notice'
  86. id = 'notice'
  87. style = { DISPLAY_NONE_STYLE }>
  88. <span
  89. className = 'noticeText'
  90. id = 'noticeText' />
  91. </div>
  92. <div
  93. className = 'toolbar'
  94. id = 'mainToolbar' />
  95. </div>
  96. <div
  97. className = 'hide'
  98. id = 'subject' />
  99. <div
  100. className = 'toolbar'
  101. id = 'extendedToolbar'>
  102. <div id = 'extendedToolbarButtons' />
  103. <a
  104. className = 'button icon-feedback'
  105. id = 'feedbackButton' />
  106. <div id = 'sideToolbarContainer' />
  107. </div>
  108. <div id = 'videospace'>
  109. <div
  110. className = 'videocontainer'
  111. id = 'largeVideoContainer'>
  112. <div id = 'sharedVideo'>
  113. <div id = 'sharedVideoIFrame' />
  114. </div>
  115. <div id = 'etherpad' />
  116. {
  117. this._renderJitsiWatermark()
  118. }
  119. {
  120. this._renderBrandWatermark()
  121. }
  122. {
  123. this._renderPoweredBy()
  124. }
  125. <div id = 'dominantSpeaker'>
  126. <div className = 'dynamic-shadow' />
  127. <img
  128. id = 'dominantSpeakerAvatar'
  129. src = '' />
  130. </div>
  131. <span id = 'remoteConnectionMessage' />
  132. <div id = 'largeVideoWrapper'>
  133. <video
  134. autoPlay = { true }
  135. id = 'largeVideo'
  136. muted = 'true' />
  137. </div>
  138. <span id = 'localConnectionMessage' />
  139. <span
  140. className = 'video-state-indicator moveToCorner'
  141. id = 'videoResolutionLabel'>HD</span>
  142. <span
  143. className
  144. = 'video-state-indicator centeredVideoLabel'
  145. id = 'recordingLabel'>
  146. <span id = 'recordingLabelText' />
  147. <img
  148. className = 'recordingSpinner'
  149. id = 'recordingSpinner'
  150. src = 'images/spin.svg' />
  151. </span>
  152. </div>
  153. <div className = 'filmstrip'>
  154. <div
  155. className = 'filmstrip__videos'
  156. id = 'remoteVideos'>
  157. <span
  158. className = 'videocontainer'
  159. id = 'localVideoContainer'>
  160. <div
  161. className = 'videocontainer__background' />
  162. <span id = 'localVideoWrapper' />
  163. <audio
  164. autoPlay = { true }
  165. id = 'localAudio'
  166. muted = { true } />
  167. <div className = 'videocontainer__toolbar' />
  168. <div
  169. className = 'videocontainer__toptoolbar' />
  170. <div
  171. className
  172. = 'videocontainer__hoverOverlay' />
  173. </span>
  174. <audio
  175. id = 'userJoined'
  176. preload = 'auto'
  177. src = 'sounds/joined.wav' />
  178. <audio
  179. id = 'userLeft'
  180. preload = 'auto'
  181. src = 'sounds/left.wav' />
  182. </div>
  183. </div>
  184. </div>
  185. </div>
  186. );
  187. }
  188. /**
  189. * Method that returns brand watermark element if it is enabled.
  190. *
  191. * @returns {ReactElement|null}
  192. * @private
  193. */
  194. _renderBrandWatermark() {
  195. if (this.state.showBrandWatermark) {
  196. return (
  197. <a
  198. href = { this.state.brandWatermarkLink }
  199. target = '_new'>
  200. <div className = 'watermark rightwatermark' />
  201. </a>
  202. );
  203. }
  204. return null;
  205. }
  206. /**
  207. * Method that returns jitsi watermark element if it is enabled.
  208. *
  209. * @returns {ReactElement|null}
  210. * @private
  211. */
  212. _renderJitsiWatermark() {
  213. if (this.state.showJitsiWatermark
  214. || (APP.tokenData.isGuest
  215. && this.state.showJitsiWatermarkForGuest)) {
  216. return (
  217. <a
  218. href = { this.state.jitsiWatermarkLink }
  219. target = '_new'>
  220. <div className = 'watermark leftwatermark' />
  221. </a>
  222. );
  223. }
  224. return null;
  225. }
  226. /**
  227. * Renders powered by block if it is enabled.
  228. *
  229. * @returns {ReactElement|null}
  230. * @private
  231. */
  232. _renderPoweredBy() {
  233. if (this.state.showPoweredBy) {
  234. return (
  235. <a
  236. className = 'poweredby hide'
  237. href = 'http://jitsi.org'
  238. target = '_new'>
  239. <span data-i18n = 'poweredby' /> jitsi.org
  240. </a>
  241. );
  242. }
  243. return null;
  244. }
  245. }
  246. export default reactReduxConnect()(Conference);