Merge remote-tracking branch 'upstream/master' into compact-userlist

* upstream/master:
  add colour notification to caption tab when locale is switched
  Added "getBreakoutRoomInListen" method in Conference.as
  Switch moderator back to the main audio conference when close all breakout rooms button is clicked.
  HTML5 Dropdown - fixed warnings and added style
  Invite participants to existing breakout rooms.
This commit is contained in:
Gabriel Carvalho de Campes 2016-09-12 17:12:54 -03:00
commit ce04e64ee8
17 changed files with 231 additions and 54 deletions

View File

@ -649,6 +649,7 @@ bbb.users.settings.lockAll=Lock All Users
bbb.users.settings.lockAllExcept=Lock Users Except Presenter
bbb.users.settings.lockSettings=Lock Viewers ...
bbb.users.settings.breakoutRooms=Breakout Rooms ...
bbb.users.settings.sendBreakoutRoomsInvitations=Send Breakout Rooms Invitations ...
bbb.users.settings.unlockAll=Unlock All Viewers
bbb.users.settings.roomIsLocked=Locked by default
bbb.users.settings.roomIsMuted=Muted by default
@ -670,6 +671,7 @@ bbb.lockSettings.locked=Locked
bbb.lockSettings.lockOnJoin=Lock On Join
bbb.users.breakout.breakoutRooms = Breakout Rooms
bbb.users.breakout.updateBreakoutRooms = Update Breakout Rooms
bbb.users.breakout.remainingTimeBreakout = {0}: <b>{1} remaining</b>
bbb.users.breakout.remainingTimeParent = <b>{1} remaining</b>
bbb.users.breakout.calculatingRemainingTime = Calculating remaining time...
@ -683,6 +685,7 @@ bbb.users.breakout.record = Record
bbb.users.breakout.notAssigned = Not Assigned
bbb.users.breakout.dragAndDropToolTip = Tip: You can drag and drop users between rooms
bbb.users.breakout.start = Start
bbb.users.breakout.invite = Invite
bbb.users.breakout.close = Close
bbb.users.breakout.closeAllRooms = Close All Breakout Rooms
bbb.users.breakout.insufficientUsers = Insufficient users. You should place at least one user in one breakout room.

View File

@ -17,40 +17,44 @@
*
*/
package org.bigbluebutton.main.events {
import flash.events.Event;
public class BreakoutRoomEvent extends Event {
public static const OPEN_BREAKOUT_ROOMS_PANEL:String = "OPEN_BREAKOUT_ROOMS_PANEL";
public static const CREATE_BREAKOUT_ROOMS:String = "CREATE_BREAKOUT_ROOMS";
public static const REQUEST_BREAKOUT_JOIN_URL:String = "REQUEST_BREAKOUT_JOIN_URL";
public static const BREAKOUT_JOIN_URL:String = "BREAKOUT_JOIN_URL";
public static const LISTEN_IN:String = "LISTEN_IN";
public static const END_ALL_BREAKOUT_ROOMS:String = "END_ALL_BREAKOUT_ROOMS";
public static const UPDATE_REMAINING_TIME_PARENT:String = "UPDATE_REMAINING_TIME_PARENT";
public static const UPDATE_REMAINING_TIME_BREAKOUT:String = "UPDATE_REMAINING_TIME_BREAKOUT";
public var meetingId:String;
public var breakoutId:String;
public var rooms:Array;
public var durationInMinutes:int;
public var record:Boolean;
public var joinURL:String;
public var listen:Boolean;
public var joinMode:String;
public var userId:String;
public function BreakoutRoomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
}

View File

@ -389,6 +389,7 @@ package org.bigbluebutton.main.model.users
n.disableMyMic = user.disableMyMic;
n.disableMyPrivateChat = user.disableMyPrivateChat;
n.disableMyPublicChat = user.disableMyPublicChat;
n.breakoutRooms = user.breakoutRooms.concat(); // concatenate an array with nothing to deliver a new array.
return n;
}

View File

@ -633,6 +633,16 @@ package org.bigbluebutton.main.model.users {
}
}
}
public function getBreakoutRoomInListen() : BreakoutRoom {
for (var i:int = 0; i < breakoutRooms.length; i++) {
var br:BreakoutRoom = BreakoutRoom(breakoutRooms.getItemAt(i));
if (br.listenStatus == BreakoutRoom.SELF) {
return br;
}
}
return null;
}
public function resetBreakoutRooms():void {
for (var i:int = 0; i < breakoutRooms.length; i++) {

View File

@ -210,7 +210,7 @@ package org.bigbluebutton.main.model.users
}
public function requestBreakoutJoinUrl(e:BreakoutRoomEvent):void{
sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, _conferenceParameters.userid);
sender.requestBreakoutJoinUrl(_conferenceParameters.meetingID, e.breakoutId, e.userId);
}
public function listenInOnBreakout(e:BreakoutRoomEvent):void {

View File

@ -624,9 +624,10 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
ls.y = point1.y - (ls.height/2);
}
private function openBreakoutRoomsWindow(e:Event = null):void {
private function openBreakoutRoomsWindow(e:BreakoutRoomEvent):void {
var popUp:IFlexDisplayObject = PopUpManager.createPopUp(mdiCanvas, BreakoutRoomSettings, true);
PopUpManager.centerPopUp(popUp);
BreakoutRoomSettings(popUp).initCreateBreakoutRooms(e.joinMode);
}
private function onFooterLinkClicked(e:TextEvent):void{

View File

@ -40,6 +40,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import mx.binding.utils.ChangeWatcher;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.Button;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
@ -161,6 +162,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (!captionTabs.contains(textTab)) {
addTextTab();
}
var tab:Button = captionTabs.getTabAt(0);
if (tab != null) {
tab.setStyle("fillColors", new Array(0xFFAE00, 0xD3800A));
}
}
private function onTranscriptOwnerIDChange(o:Object):void {
@ -194,6 +200,11 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
captionTabs.addChildAt(textTab, 0);
}
private function onTabChange():void {
var tab:Button = captionTabs.getTabAt(captionTabs.selectedIndex);
tab.setStyle("fillColors", new Array(0xFFFFFF, 0xCCCCCC));
}
private function localeChanged(e:Event):void{
resourcesChanged();
}
@ -228,6 +239,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Box width="100%" height="100%" horizontalAlign="left">
<containers:SuperTabNavigator id="captionTabs"
width="100%" height="100%" minTabWidth="20"
dragEnabled="false" popUpButtonPolicy="off" />
dragEnabled="false" popUpButtonPolicy="off"
change="onTabChange()"/>
</mx:Box>
</CustomMdiWindow>

View File

@ -28,6 +28,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.DragEvent;
import org.bigbluebutton.main.model.users.BBBUser;
[Bindable]
public var roomName:String
@ -37,9 +40,21 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
[Bindable]
public var notAssignedUsers:Boolean;
[Bindable]
public var mode:String;
protected function startDragHandler(event:DragEvent):void {
var selectedNode:BBBUser = usersList.selectedItem as BBBUser;
if (mode == "invite" && selectedNode.breakoutRooms.length > 0) {
event.stopImmediatePropagation();
}
}
]]>
</fx:Script>
<mx:Label text="{roomName}" width="100%" fontWeight="{notAssignedUsers ? 'normal' : 'bold'}" />
<mx:List width="100%" height="100%" dataProvider="{users}" labelField="name"
dragEnabled="true" dragMoveEnabled="true" dropEnabled="true"/>
<mx:List id="usersList" width="100%" height="100%" dataProvider="{users}" labelField="name"
dragEnabled="true" dragMoveEnabled="true" dropEnabled="true"
itemRenderer="org.bigbluebutton.modules.users.views.UserItemRenderer"
dragStart="startDragHandler(event)" />
</mx:VBox>

View File

@ -26,7 +26,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
xmlns:mate="http://mate.asfusion.com/"
width="630" height="650"
close="onCloseClicked()"
creationComplete="creationCompleteHandler(event)"
visible="false"
showCloseButton="false">
<fx:Script>
@ -35,7 +35,6 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
import org.bigbluebutton.core.managers.UserManager;
@ -47,15 +46,17 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private var roomsProvider:Array;
private var dispatcher:Dispatcher;
[Bindable]
private var mode:String;
private function onCloseClicked():void {
PopUpManager.removePopUp(this);
}
/**
* Dispatches a BreakoutRoomEvent to start creating breakout rooms
*/
private function onStartClicked():void {
private function createBreakoutRooms():void {
// Will be used to check that all the new breakout room contains at least one users
var totalUsers:int;
var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.CREATE_BREAKOUT_ROOMS);
@ -67,7 +68,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
var room:Object = new Object();
room.users = new Array();
room.name =
UserManager.getInstance().getConference().meetingName + " (" +
UserManager.getInstance().getConference().meetingName + " (" +
ResourceUtil.getInstance().getString('bbb.users.breakout.room')
+ " - " + (i + 1).toString() + ")";;
for (var j:int = 0; j < users.length; j++) {
@ -78,16 +79,41 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (totalUsers > 0) {
event.durationInMinutes = durationStepper.value;
event.record = recordCheckbox.selected;
dispatcher.dispatchEvent(event);
PopUpManager.removePopUp(this);
} else {
Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers'));
}
}
protected function assignUsers():void {
dispatcher = new Dispatcher();
/**
* Dispatches a BreakoutRoomEvent to send breakout rooms join URL invitations
*/
private function inviteUsersToBreakoutRooms():void {
var list:BreakoutList;
var user:BBBUser;
var usersInvited:Boolean = false;
for (var i:int; i < roomsContainer.numChildren - 1; i++) {
list = roomsContainer.getChildAt(i) as BreakoutList;
for (var u:int = 0; u < list.users.length; u++) {
user = list.users.getItemAt(u) as BBBUser;
if (user.breakoutRooms.length == 0) {
usersInvited ||= true;
var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.REQUEST_BREAKOUT_JOIN_URL);
event.userId = user.userID;
event.breakoutId = UserManager.getInstance().getConference().internalMeetingID + "-" + (i + 1);
dispatcher.dispatchEvent(event);
}
}
}
if (usersInvited) {
PopUpManager.removePopUp(this);
} else {
Alert.show(ResourceUtil.getInstance().getString('bbb.users.breakout.insufficientUsers'));
}
}
protected function assignUsersForCreation():void {
var originalUsers:ArrayCollection = UserManager.getInstance().getConference().users;
var users:ArrayCollection = new ArrayCollection();
var me:BBBUser;
@ -121,19 +147,64 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
unassignedList.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.notAssigned');
unassignedList.notAssignedUsers = true;
startButton.enabled = true;
}
protected function creationCompleteHandler(event:FlexEvent):void
{
}
protected function assignUsersForInvitation():void {
var originalUsers:ArrayCollection = UserManager.getInstance().getConference().users;
var users:ArrayCollection = new ArrayCollection();
// Copy users to avoid removing the references from the original ArrayCollection
for (var l:int = 0; l < originalUsers.length; l++) {
users.addItem(BBBUser.copy(originalUsers[l]));
}
// Create breakout rooms lists
var rooms:int = UserManager.getInstance().getConference().breakoutRooms.length;
var user:BBBUser;
roomsContainer.removeAllChildren();
for (var r:int = 0; r < rooms; r++) {
var list:BreakoutList = roomsContainer.addChild(new BreakoutList()) as BreakoutList;
list.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.room') + " " + (r + 1).toString()
list.users = new ArrayCollection();
list.mode = mode;
}
var unassignedUsers:ArrayCollection = new ArrayCollection();
for (var j:int = 0; j < users.length; j++) {
user = users[j] as BBBUser;
if (user.breakoutRooms.length > 0) {
for (var b:int = 0; b < user.breakoutRooms.length; b++) {
BreakoutList(roomsContainer.getChildAt(user.breakoutRooms[b] - 1)).users.addItem(user as BBBUser);
}
} else {
unassignedUsers.addItem(user);
}
}
var unassignedList:BreakoutList = roomsContainer.addChild(new BreakoutList()) as BreakoutList;
unassignedList.users = unassignedUsers;
unassignedList.roomName = ResourceUtil.getInstance().getString('bbb.users.breakout.notAssigned');
unassignedList.notAssignedUsers = true;
startButton.enabled = true;
}
public function initCreateBreakoutRooms(mode:String):void {
dispatcher = new Dispatcher();
roomsProvider = new Array();
for (var i: int=2; i <=5; i++){
roomsProvider.push(i.toString() + " " + ResourceUtil.getInstance().getString('bbb.users.breakout.rooms'));
this.mode = mode;
for (var i:int = 2; i <= 5; i++) {
roomsProvider.push(i.toString() + " " + ResourceUtil.getInstance().getString('bbb.users.breakout.rooms'));
}
roomsCombo.selectedIndex = 0;
assignUsers();
if (this.mode == "create") {
startButton.label = ResourceUtil.getInstance().getString('bbb.users.breakout.start');
textArea.text = ResourceUtil.getInstance().getString('bbb.users.breakout.breakoutRooms');
assignUsersForCreation();
visible = true;
} else {
startButton.label = ResourceUtil.getInstance().getString('bbb.users.breakout.invite');
roomsBox.visible = durationBox.visible = recordBox.visible =
roomsBox.includeInLayout = durationBox.includeInLayout = recordBox.includeInLayout = false;
textArea.text = ResourceUtil.getInstance().getString('bbb.users.breakout.updateBreakoutRooms');
assignUsersForInvitation();
visible = true;
}
}
]]>
</fx:Script>
@ -149,26 +220,27 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:HBox id="roomsBox" paddingTop="20" width="100%">
<mx:HBox width="50%" height="100%" horizontalAlign="left" verticalAlign="middle">
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.rooms')}" />
<mx:ComboBox id="roomsCombo" width="80%" change="{assignUsers()}" dataProvider="{roomsProvider}"/>
<mx:ComboBox id="roomsCombo" width="80%" change="{assignUsersForCreation()}" dataProvider="{roomsProvider}"/>
</mx:HBox>
<!-- <mx:Button paddingLeft="20" width="50%" id="randomAssignBtn"
label="{ResourceUtil.getInstance().getString('bbb.users.breakout.randomAssign')}" click="assignUsers()"/> -->
</mx:HBox>
<mx:HBox width="100%" paddingTop="12">
<mx:HBox id="durationBox" width="100%" paddingTop="12">
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.timeLimit')}" />
<mx:NumericStepper id="durationStepper" value="15" minimum="1" maximum="600"/>
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.minutes')}"/>
</mx:HBox>
<mx:HBox width="100%" paddingTop="12">
<mx:HBox id="recordBox" width="100%" paddingTop="12">
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.users.breakout.record')}" visible="false" />
<mx:CheckBox id="recordCheckbox" visible="false" />
</mx:HBox>
<mx:Tile id="roomsContainer" styleName="roomsContainer" width="100%" height="100%"/>
<mx:HBox width="100%" horizontalAlign="right" verticalGap="15">
<mx:Button id="startButton" label="{ResourceUtil.getInstance().getString('bbb.users.breakout.start')}" click="onStartClicked()"/>
<mx:Button id="startButton"
click="this.mode == 'create' ? createBreakoutRooms() : inviteUsersToBreakoutRooms()"/>
<mx:Button label="{ResourceUtil.getInstance().getString('bbb.users.breakout.close')}" click="onCloseClicked()"/>
</mx:HBox>
</mx:VBox>

View File

@ -45,6 +45,7 @@
protected function requestBreakoutJoinUrl(event:MouseEvent):void {
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.REQUEST_BREAKOUT_JOIN_URL);
e.breakoutId = data.breakoutId as String;
e.userId = UserManager.getInstance().getConference().getMyUserId();
globalDispatch.dispatchEvent(e);
}
]]>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
BigBlueButton open source conferencing system - http://www.bigbluebutton.org
Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
BigBlueButton is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2.1 of the License, or (at your option) any later
version.
BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
$Id: $
-->
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml"
verticalScrollPolicy="off"
horizontalScrollPolicy="off">
<mx:Label id="nameLabel"
text="{data.name}"
color="{data.breakoutRooms.length > 0 ? 0xcccccc : 0x000000}"
toolTip="{data.name}" />
</mx:Box>

View File

@ -71,6 +71,7 @@
import org.bigbluebutton.main.events.BreakoutRoomEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.main.model.users.BreakoutRoom;
import org.bigbluebutton.main.model.users.events.EmojiStatusEvent;
import org.bigbluebutton.main.model.users.events.KickUserEvent;
import org.bigbluebutton.main.model.users.events.RoleChangeEvent;
@ -268,8 +269,12 @@
paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.unmuteAll'), icon: images.audio, handler: muteAll});
paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.lockSettings'), icon: images.lock_open, handler: lockSettings});
if (partOptions.enableBreakoutRooms && breakoutRoomsList.length == 0 && amIModerator && !UserManager.getInstance().getConference().isBreakout) {
paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.breakoutRooms'), handler: breakoutRooms});
if (partOptions.enableBreakoutRooms && amIModerator && !UserManager.getInstance().getConference().isBreakout) {
if (breakoutRoomsList.length == 0) {
paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.breakoutRooms'), handler: breakoutRooms});
} else {
paramsMenuData.push({label: ResourceUtil.getInstance().getString('bbb.users.settings.sendBreakoutRoomsInvitations'), handler: sendBreakoutRoomsInvitations});
}
}
// make sure the previous menu is closed before opening a new one
@ -309,11 +314,18 @@
var event:LockControlEvent = new LockControlEvent(LockControlEvent.OPEN_LOCK_SETTINGS);
dispatcher.dispatchEvent(event);
}
private function breakoutRooms():void {
dispatcher.dispatchEvent(new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL));
var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL);
event.joinMode = "create";
dispatcher.dispatchEvent(event);
}
private function sendBreakoutRoomsInvitations():void {
var event:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.OPEN_BREAKOUT_ROOMS_PANEL);
event.joinMode = "invite";
dispatcher.dispatchEvent(event);
}
private function handleRemainingTimeUpdate(event:BreakoutRoomEvent):void {
TimerUtil.setCountDownTimer(breakoutTimeLabel, event.durationInMinutes);
}
@ -496,11 +508,19 @@
}
}
}
private function endAllBreakoutRoomsHandler(event:MouseEvent):void {
// We need to switch the use back to the main audio confrence if he is in a breakout audio conference
var br:BreakoutRoom = UserManager.getInstance().getConference().getBreakoutRoomInListen();
if (br != null) {
var e:BreakoutRoomEvent = new BreakoutRoomEvent(BreakoutRoomEvent.LISTEN_IN);
e.breakoutId = br.breakoutId;
e.listen = false;
dispatcher.dispatchEvent(e);
}
dispatcher.dispatchEvent(new BreakoutRoomEvent(BreakoutRoomEvent.END_ALL_BREAKOUT_ROOMS));
}
private function focusWindow(e:ShortcutEvent):void {
focusManager.setFocus(titleBarOverlay);
}

View File

@ -47,7 +47,7 @@ class LeaveConfirmation extends Component {
<Modal
title={intl.formatMessage(intlMessages.title)}
confirm={{
callback: this.handleLeave,
callback: this.handleLeaveConfirmation,
label: intl.formatMessage(intlMessages.confirmLabel),
description: intl.formatMessage(intlMessages.confirmDesc),
}}

View File

@ -2,7 +2,7 @@ import React, { Component, PropTyes } from 'react';
import { FormattedMessage } from 'react-intl';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import styles from './styles';
import styles from '../styles';
import { showModal } from '/imports/ui/components/app/service';
import LogoutConfirmation from '/imports/ui/components/logout-confirmation/component';
@ -63,6 +63,7 @@ export default class SettingsDropdown extends Component {
ghost={true}
circle={true}
hideLabel={true}
className={styles.settingBtn}
// FIXME: Without onClick react proptypes keep warning
// even after the DropdownTrigger inject an onClick handler

View File

@ -1 +0,0 @@
@import "../../../stylesheets/variables/_all";

View File

@ -60,3 +60,11 @@
height:1px;
overflow:hidden;
}
.settingBtn {
transform: rotate(90deg);
span {
border: none;
box-shadow: none;
}
}

View File

@ -77,7 +77,7 @@ class Auth {
let logoutURL = this.logoutURL;
callServer('userLogout');
clearCredentials(() => {
this.clearCredentials(() => {
document.location.href = logoutURL;
});
};