Move welcome page logic from jquery to react

This commit is contained in:
Ilya Daynatovich 2016-12-01 20:55:42 +02:00 committed by Lyubomir Marinov
parent 986f13ef1a
commit 984a6519fc
7 changed files with 398 additions and 154 deletions

View File

@ -84,7 +84,6 @@ form {
}
.leftwatermark {
display: none;
left: $defaultToolbarSize;
margin-left: 10px;
background-image: url($defaultWatermarkLink);
@ -92,13 +91,11 @@ form {
}
.rightwatermark {
display: none;
right: 15;
background-position: center right;
}
.poweredby {
display: none;
position: absolute;
left: 25;
bottom: 7;
@ -142,4 +139,4 @@ form {
#inviteLinkRef {
-webkit-user-select: text;
user-select: text;
}
}

View File

@ -50,7 +50,7 @@
float: left;
}
#domain_name
.domain-name
{
float: left;
height: 55px;
@ -61,37 +61,51 @@
color: $defaultDarkColor;
}
#enter_room_field {
font-size: 15px;
border: none;
-webkit-appearance: none;
width: 228px;
height: 55px;
line-height: 55px;
font-weight: 500;
box-shadow: none;
float: left;
background-color: #FFFFFF;
position: relative;
z-index: 2;
}
.enter-room {
&__field {
font-size: 15px;
border: none;
-webkit-appearance: none;
width: 228px;
height: 55px;
line-height: 55px;
font-weight: 500;
box-shadow: none;
float: left;
background-color: #FFFFFF;
position: relative;
z-index: 2;
}
#enter_room_button {
width: 73px;
height: 45px;
background-color: #21B9FC;
moz-border-radius: 1px;
-webkit-border-radius: 1px;
color: #ffffff;
font-weight: 600;
border: none;
margin-top: 5px;
font-size: 19px;
padding-top: 6px;
outline: none;
float:left;
position: relative;
z-index: 2;
&__reload {
display: block;
width: 30px;
color: #acacac;
font-size: 1.9em;
line-height: 55px;
z-index: 3;
float: left;
cursor: pointer;
text-align: center;
}
&__button {
width: 73px;
height: 45px;
background-color: #21B9FC;
moz-border-radius: 1px;
-webkit-border-radius: 1px;
color: #ffffff;
font-weight: 600;
border: none;
margin-top: 5px;
font-size: 19px;
padding-top: 6px;
outline: none;
float:left;
position: relative;
z-index: 2;
}
}
#enter_room_container {
@ -184,16 +198,3 @@
line-height: 22px;
font-weight: 200;
}
#reload_roomname
{
width: 30px;
color: #acacac;
font-size: 1.9em;
line-height: 55px;
z-index: 3;
float: left;
cursor: pointer;
text-align: center;
display: none;
}

View File

@ -1,73 +1,22 @@
/* global $, interfaceConfig, APP */
import {
generateRoomWithoutSeparator
} from '../../../react/features/base/util/roomnameGenerator';
import UIUtil from '../util/UIUtil';
var animateTimeout, updateTimeout;
/* global $ */
function enterRoom() {
const $enterRoomField = $("#enter_room_field");
var val = $enterRoomField.val();
if(!val) {
val = $enterRoomField.attr("room_name");
val = $enterRoomField.data("room-name");
}
if (val) {
window.location.pathname = "/" + val;
}
}
function animate(word) {
var currentVal = $("#enter_room_field").attr("placeholder");
$("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
animateTimeout = setTimeout(function() {
animate(word.substring(1, word.length));
}, 70);
}
function update_roomname() {
var word = generateRoomWithoutSeparator();
$("#enter_room_field").attr("room_name", word);
$("#enter_room_field").attr("placeholder", "");
clearTimeout(animateTimeout);
animate(word);
updateTimeout = setTimeout(update_roomname, 10000);
}
function setupWelcomePage() {
$("#videoconference_page").hide();
$("#domain_name").text(
window.location.protocol + "//" + window.location.host + "/");
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv =
$("#welcome_page_header div[class='watermark leftwatermark']");
if(leftWatermarkDiv && leftWatermarkDiv.length > 0) {
leftWatermarkDiv.css({display: 'block'});
UIUtil.setLinkHref(
leftWatermarkDiv.parent(),
interfaceConfig.JITSI_WATERMARK_LINK);
}
}
if (interfaceConfig.SHOW_BRAND_WATERMARK) {
var rightWatermarkDiv =
$("#welcome_page_header div[class='watermark rightwatermark']");
if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
rightWatermarkDiv.css({display: 'block'});
UIUtil.setLinkHref(
rightWatermarkDiv.parent(),
interfaceConfig.BRAND_WATERMARK_LINK);
rightWatermarkDiv.get(0).style.backgroundImage =
"url(images/rightwatermark.png)";
}
}
if (interfaceConfig.SHOW_POWERED_BY) {
$("#welcome_page_header>a[class='poweredby']")
.css({display: 'block'});
}
/*
* XXX: We left only going to conference page here because transitions via
* React Router isn't implemented yet.
*/
$("#enter_room_button").click(function() {
enterRoom();
@ -78,25 +27,6 @@ function setupWelcomePage() {
enterRoom();
}
});
if (interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE !== false) {
var selector = $("#reload_roomname");
selector.click(function () {
clearTimeout(updateTimeout);
clearTimeout(animateTimeout);
update_roomname();
});
selector.show();
update_roomname();
}
$("#disable_welcome").click(function () {
APP.settings.setWelcomePageEnabled(
!$("#disable_welcome").is(":checked")
);
});
}
module.exports = setupWelcomePage;

View File

@ -62,7 +62,7 @@ export default class Conference extends Component {
<div className = 'watermark rightwatermark' />
</a>
<a
className = 'poweredby'
className = 'poweredby hide'
href = 'http://jitsi.org'
target = '_new'>
<span data-i18n = 'poweredby' /> jitsi.org

View File

@ -4,6 +4,7 @@ import { appNavigate } from '../../app';
import { isRoomValid } from '../../base/conference';
import { VideoTrack } from '../../base/media';
import { getLocalVideoTrack } from '../../base/tracks';
import { generateRoomWithoutSeparator } from '../../base/util';
/**
* Base (abstract) class for container component rendering the welcome page.
@ -34,15 +35,32 @@ export class AbstractWelcomePage extends Component {
/**
* Save room name into component's local state.
*
* @type {{room: string}}
* @type {Object}
* @property {string} room - Room name.
* @property {string} roomPlaceholder - Room placeholder
* that's used as a placeholder for input.
* @property {string} generatedRoomname - Automatically generated
* room name.
* @property {number|null} animateTimeoutId - Identificator for
* letter animation timeout.
* @property {nubmer|null} updateTimeoutId - Identificator for
* updating generated room name.
*/
this.state = {
room: ''
room: '',
roomPlaceholder: '',
generatedRoomname: '',
animateTimeoutId: null,
updateTimeoutId: null
};
// Bind event handlers so they are only bound once for every instance.
this._onJoinClick = this._onJoinClick.bind(this);
const roomnameChanging = this._animateRoomnameChanging.bind(this);
this._onJoin = this._onJoin.bind(this);
this._onRoomChange = this._onRoomChange.bind(this);
this._updateRoomname = this._updateRoomname.bind(this);
this._animateRoomnameChanging = roomnameChanging.bind(this);
}
/**
@ -55,6 +73,26 @@ export class AbstractWelcomePage extends Component {
this.setState({ room: nextProps.room });
}
/**
* This method is executed when method will be unmounted from DOM.
*
* @inheritdoc
*/
componentWillUnmount() {
this._clearTimeouts();
}
/**
* Method that clears timeouts for animations and updates of room name.
*
* @private
* @returns {void}
*/
_clearTimeouts() {
clearTimeout(this.state.animateTimeoutId);
clearTimeout(this.state.updateTimeoutId);
}
/**
* Determines whether the 'Join' button is (to be) disabled i.e. there's no
* valid room name typed into the respective text input field.
@ -68,13 +106,64 @@ export class AbstractWelcomePage extends Component {
}
/**
* Handles click on 'Join' button.
* Method triggering generation of new room name and
* initiating animation of its changing.
*
* @protected
* @returns {void}
*/
_onJoinClick() {
this.props.dispatch(appNavigate(this.state.room));
_updateRoomname() {
const generatedRoomname = generateRoomWithoutSeparator();
const roomPlaceholder = '';
const updateTimeoutId = setTimeout(this._updateRoomname, 10000);
this._clearTimeouts();
this.setState({
updateTimeoutId,
generatedRoomname,
roomPlaceholder
}, () => this._animateRoomnameChanging(generatedRoomname));
}
/**
* Method animating changing room name.
*
* @param {string} word - The part of room name that should
* be added to placeholder.
* @private
* @returns {void}
*/
_animateRoomnameChanging(word) {
const roomPlaceholder = this.state.roomPlaceholder + word.substr(0, 1);
let animateTimeoutId = null;
if (word.length > 1) {
animateTimeoutId = setTimeout(() => {
this._animateRoomnameChanging(word.substring(1, word.length));
}, 70);
}
this.setState({
animateTimeoutId,
roomPlaceholder
});
}
/**
* Handles joining. Either by clicking on 'Join' button
* or by pressing 'Enter' in room name input field.
*
* @protected
* @returns {void}
*/
_onJoin() {
const { room, generatedRoomname } = this.state;
if (room && room.length) {
this.props.dispatch(appNavigate(room));
} else {
this.props.dispatch(appNavigate(generatedRoomname));
}
}
/**

View File

@ -107,7 +107,7 @@ class WelcomePage extends AbstractWelcomePage {
value = { this.state.room } />
<TouchableHighlight
disabled = { this._isJoinDisabled() }
onPress = { this._onJoinClick }
onPress = { this._onJoin }
style = { styles.button }
underlayColor = { ColorPalette.white }>
<Text style = { styles.buttonText }>JOIN</Text>

View File

@ -1,11 +1,112 @@
import React, { Component } from 'react';
/* global interfaceConfig, APP */
import React from 'react';
import { connect } from 'react-redux';
import {
AbstractWelcomePage,
mapStateToProps
} from './AbstractWelcomePage';
const RIGHT_WATERMARK_STYLES = {
backgroundImage: 'url(images/rightwatermark.png)'
};
import { Conference } from '../../conference';
/**
* The web container rendering the welcome page.
*/
export default class WelcomePage extends Component {
class WelcomePage extends AbstractWelcomePage {
/**
* Constructor function of WelcomePage.
*
* @param {Object} props - Props to be set.
**/
constructor(props) {
super(props);
this._initState();
// Bind event handlers so they are only bound once for every instance.
const onToggleDisableWelcome = this._onToggleDisableWelcomePage;
this._onRoomChange = this._onRoomChange.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._setInput = this._setInput.bind(this);
this._onUpdateRoomname = this._onUpdateRoomname.bind(this);
this._onToggleDisableWelcomePage = onToggleDisableWelcome.bind(this);
}
/**
* Method that initializes state of the component.
*
* @returns {void}
**/
_initState() {
const showPoweredBy = interfaceConfig.SHOW_POWERED_BY;
const generateRoomnames
= interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE;
const enableWelcomePage = true;
const showJitsiWatermark = interfaceConfig.SHOW_JITSI_WATERMARK;
const showBrandWatermark = interfaceConfig.SHOW_BRAND_WATERMARK;
let jitsiWatermarkLink = '';
let brandWatermarkLink = '';
if (showJitsiWatermark) {
jitsiWatermarkLink = interfaceConfig.JITSI_WATERMARK_LINK;
}
if (showBrandWatermark) {
brandWatermarkLink = interfaceConfig.BRAND_WATERMARK_LINK;
}
this.state = Object.assign({}, this.state, {
showPoweredBy,
generateRoomnames,
showJitsiWatermark,
showBrandWatermark,
jitsiWatermarkLink,
brandWatermarkLink,
enableWelcomePage
});
}
/**
* Returns the domain name.
*
* @private
* @returns {string} Domain name.
**/
_getDomain() {
return `${window.location.protocol}//${window.location.host}/`;
}
/**
* This method is executed when comonent is mounted.
*
* @inheritdoc
*/
componentDidMount() {
if (this.state.generateRoomnames) {
this._updateRoomname();
}
}
/**
* Handles toggling disable welcome page checkbox
*
* @returns {void}
**/
_onToggleDisableWelcomePage() {
const shouldEnable = this.state.enableWelcomePage;
this.setState({
enableWelcomePage: !shouldEnable
}, () => {
APP.settings.setWelcomePageEnabled(this.state.enableWelcomePage);
});
}
/**
* Implements React's {@link Component#render()}.
@ -35,6 +136,17 @@ export default class WelcomePage extends Component {
);
}
/**
* Sets input element as property of class.
*
* @param {HTMLInputElement} input - input element to be set.
* @returns {void}
* @private
**/
_setInput(input) {
this.roomNameInput = input;
}
/**
* Renders a feature with a specific index.
*
@ -93,41 +205,45 @@ export default class WelcomePage extends Component {
_renderHeader() {
return (
<div id = 'welcome_page_header'>
<a target = '_new'>
<div className = 'watermark leftwatermark' />
</a>
<a target = '_new'>
<div className = 'watermark rightwatermark' />
</a>
<a
className = 'poweredby'
href = 'http://jitsi.org'
target = '_new'>
<span data-i18n = 'poweredby' /> jitsi.org
</a>
{ this._renderJitsiWatermark() }
{ this._renderBrandWatermark() }
{ this._renderPoweredBy() }
<div id = 'enter_room_container'>
<div id = 'enter_room_form'>
<div id = 'domain_name' />
<div className = 'domain-name' >
{ this._getDomain() }
</div>
<div id = 'enter_room'>
<input
autoFocus = { true }
className = 'enter-room__field'
data-room-name =
{ this.state.generatedRoomname }
id = 'enter_room_field'
type = 'text' />
onChange = { this._onRoomChange }
onKeyDown = { this._onKeyDown }
placeholder = { this.state.roomPlaceholder }
ref = { this._setInput }
type = 'text'
value = { this.state.room } />
<div
className = 'icon-reload'
id = 'reload_roomname' />
<input
data-i18n = '[value]welcomepage.go'
className = 'icon-reload enter-room__reload'
onClick = { this._onUpdateRoomname } />
<button
className = 'enter-room__button'
data-i18n = 'welcomepage.go'
id = 'enter_room_button'
type = 'button'
value = 'GO' />
onClick = { this._onJoin }
type = 'button' />
</div>
</div>
</div>
<div id = 'brand_header' />
<input
checked = { !this.state.enableWelcomePage }
id = 'disable_welcome'
name = 'checkbox'
onChange = { this._onToggleDisableWelcomePage }
type = 'checkbox' />
<label
className = 'disable_welcome_position'
@ -138,6 +254,115 @@ export default class WelcomePage extends Component {
);
}
/**
* Method that returns brand watermark element if it is enabled.
*
* @returns {ReactElement|null} Watermark element or null.
**/
_renderBrandWatermark() {
if (this.state.showBrandWatermark) {
return (
<a
href = { this.state.brandWatermarkLink }
target = '_new'>
<div
className = 'watermark rightwatermark'
style = { RIGHT_WATERMARK_STYLES } />
</a>
);
}
return null;
}
/**
* Method that returns jitsi watermark element if it is enabled.
*
* @returns {ReactElement|null} Watermark element or null.
**/
_renderJitsiWatermark() {
if (this.state.showJitsiWatermark) {
return (
<a
href = { this.state.jitsiWatermarkLink }
target = '_new'>
<div className = 'watermark leftwatermark' />
</a>
);
}
return null;
}
/**
* Renders powered by block if it is enabled
*
* @returns {void}
* @private
**/
_renderPoweredBy() {
if (this.state.showPoweredBy) {
return (
<a
className = 'poweredby'
href = 'http://jitsi.org'
target = '_new'>
<span data-i18n = 'poweredby' /> jitsi.org
</a>
);
}
return null;
}
/**
* Handles updating roomname.
*
* @private
* @returns {void}
**/
_onUpdateRoomname() {
this._updateRoomname();
}
/**
* Event handler for changing room name input from web.
*
* @inheritdoc
* @override
* @protected
*/
_onRoomChange() {
super._onRoomChange(this.roomNameInput.value);
}
/**
* Handles 'keydown' event and initiate joining the room if 'return' button
* was pressed.
*
* @param {Event} event - Key down event object.
* @returns {void}
* @private
*/
_onKeyDown(event) {
const RETURN_BUTTON_CODE = 13;
if (event.keyCode === RETURN_BUTTON_CODE) {
this._onJoin();
}
}
/**
* We override this method for web app for not dispatching 'set room' action.
*
* @returns {null}
* @override
* @protected
**/
_onJoin() {
return null;
}
/**
* Renders the main part of this WelcomePage.
*
@ -159,3 +384,5 @@ export default class WelcomePage extends Component {
);
}
}
export default connect(mapStateToProps)(WelcomePage);