Merge branch 'master' into unify-users-and-listeners

Conflicts:
	bigbluebutton-client/build.xml
This commit is contained in:
Richard Alam 2013-02-19 21:31:56 +00:00
commit c24cf55d9c
154 changed files with 6433 additions and 334 deletions

View File

@ -0,0 +1,8 @@
package org.bigbluebutton.conference.service.poll;
import java.util.ArrayList;
import org.bigbluebutton.conference.service.poll.Poll;
public interface IPollRoomListener {
public String getName();
public void savePoll(Poll poll );
}

View File

@ -0,0 +1,116 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import net.jcip.annotations.ThreadSafe;
import java.util.concurrent.ConcurrentHashMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@ThreadSafe
public class Poll{
// Poll URL http://142.204.133.24/bigbluebutton/polls.jsp?poll={webKey}
/* KEY PLACES TO UPDATE, WHEN ADDING NEW FIELDS TO THE HASH:
* PollService.java, getPoll()
* PollInvoker.java, invoke()
* PollRecorder.java, record()
* Don't forget the client side as well (key locations found in PollObject.as)
*/
private static Logger log = Red5LoggerFactory.getLogger( Poll.class, "bigbluebutton" );
private String LOGNAME = "[Poll]";
// IMPORTANT: For every field you add to the hash, add one to the value of otherFields.
// The value MUST always reflect how many fields are in the hash, except for answers and votes.
private static int otherFields = 10;
public final String title; // 1
public final String room; // 2
public final Boolean isMultiple; // 3
public final String question; // 4
public ArrayList <String> answers; // --
public ArrayList <Integer> votes; // --
public String time; // 5
public int totalVotes; // 6
public Boolean status; // 7
public int didNotVote; // 8
public Boolean publishToWeb; // 9
public String webKey; // 10
@SuppressWarnings("unchecked")
public Poll (ArrayList otherPoll){
title = otherPoll.get(0).toString();
room = otherPoll.get(1).toString();
isMultiple = (Boolean)otherPoll.get(2);
question = otherPoll.get(3).toString();
answers = (ArrayList)otherPoll.get(4);
votes = (ArrayList)otherPoll.get(5);
time = otherPoll.get(6).toString();
totalVotes = Integer.parseInt(otherPoll.get(7).toString());
status = (Boolean)otherPoll.get(8);
didNotVote = Integer.parseInt(otherPoll.get(9).toString());
publishToWeb = (Boolean)otherPoll.get(10);
if (publishToWeb && webKey != null){
webKey = otherPoll.get(11).toString();
}
else{
webKey = "";
}
}
public String getRoom() {
return room;
}
public void checkObject(){
// This just loops through the Poll and does a bunch of log.debug messages to verify the contents.
if (this != null){
log.debug(LOGNAME + "Running CheckObject on the poll with title " + title);
log.debug(LOGNAME + "Room is: " + room);
log.debug(LOGNAME + "isMultiple is: " + isMultiple.toString());
log.debug(LOGNAME + "Question is: " + question);
log.debug(LOGNAME + "Answers are: " + answers);
log.debug(LOGNAME + "Votes are: " + votes);
log.debug(LOGNAME + "Time is: " + time);
log.debug(LOGNAME + "TotalVotes is: " + totalVotes);
log.debug(LOGNAME + "Status is: " + status.toString());
log.debug(LOGNAME + "DidNotVote is: " + didNotVote);
log.debug(LOGNAME + "PublishToWeb is: " + publishToWeb.toString());
log.debug(LOGNAME + "WebKey is: " + webKey);
}else{
log.error(LOGNAME + "This Poll is NULL.");
}
}
public static int getOtherFields(){
return otherFields;
}
}

View File

@ -0,0 +1,230 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import java.net.*;
import java.util.List;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import java.util.ArrayList;
import java.io.*;
import java.util.Scanner;
import org.bigbluebutton.conference.service.poll.PollRoomsManager;
import org.bigbluebutton.conference.service.poll.PollRoom;
import org.bigbluebutton.conference.service.poll.IPollRoomListener;
import org.bigbluebutton.conference.service.recorder.polling.PollRecorder;
import org.bigbluebutton.conference.service.recorder.polling.PollInvoker;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class PollApplication {
private static Logger log = Red5LoggerFactory.getLogger( PollApplication.class, "bigbluebutton" );
private static final String APP = "Poll";
private PollRoomsManager roomsManager;
private String CURRENTKEY = "bbb-polling-webID";
private Integer MAX_WEBKEYS = 9999;
private Integer MIN_WEBKEYS = 1000;
private static String BBB_FILE = "/var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties";
private static String BBB_SERVER_FIELD = "bigbluebutton.web.serverURL";
public PollHandler handler;
public boolean createRoom(String name) {
roomsManager.addRoom(new PollRoom(name));
return true;
}
public boolean destroyRoom(String name) {
if (roomsManager.hasRoom(name))
roomsManager.removeRoom(name);
destroyPolls(name);
return true;
}
public void destroyPolls(String name){
// Destroy polls that were created in the room
Jedis jedis = dbConnect();
ArrayList polls = titleList();
for (int i = 0; i < polls.size(); i++){
String pollKey = name + "-" + polls.get(i).toString();
Poll doomedPoll = getPoll(pollKey);
if (doomedPoll.publishToWeb){
cutOffWebPoll(pollKey);
}
try{
jedis.del(pollKey);
}
catch (Exception e){
log.error("Poll deletion failed.");
}
}
}
public void cutOffWebPoll(String pollKey){
Jedis jedis = dbConnect();
String webKey = jedis.hget(pollKey, "webKey");
try{
jedis.del(webKey);
}
catch (Exception e){
log.error("Error in deleting web key " + webKey);
}
}
public boolean hasRoom(String name) {
return roomsManager.hasRoom(name);
}
public boolean addRoomListener(String room, IPollRoomListener listener) {
if (roomsManager.hasRoom(room)){
roomsManager.addRoomListener(room, listener);
return true;
}
log.error("Adding listener to a non-existant room " + room);
return false;
}
public void setRoomsManager(PollRoomsManager r) {
log.debug("Setting room manager");
roomsManager = r;
}
public void savePoll(Poll poll) {
PollRecorder pollRecorder = new PollRecorder();
pollRecorder.record(poll);
}
public Poll getPoll(String pollKey)
{
PollInvoker pollInvoker = new PollInvoker();
return pollInvoker.invoke(pollKey);
}
// AnswerIDs comes in as an array of each answer the user voted for
// If they voted for answers 3 and 5, the array could be [0] = 3, [1] = 5 or the other way around, shouldn't matter
public void vote(String pollKey, Object[] answerIDs, Boolean webVote){
PollRecorder recorder = new PollRecorder();
Poll poll = getPoll(pollKey);
recorder.vote(pollKey, poll, answerIDs, webVote);
}
public ArrayList titleList()
{
PollInvoker pollInvoker = new PollInvoker();
ArrayList titles = pollInvoker.titleList();
return titles;
}
public void setStatus(String pollKey, Boolean status){
PollRecorder pollRecorder = new PollRecorder();
pollRecorder.setStatus(pollKey, status);
}
public ArrayList generate(String pollKey){
Jedis jedis = dbConnect();
if (!jedis.exists(CURRENTKEY)){
Integer base = MIN_WEBKEYS -1;
jedis.set(CURRENTKEY, base.toString());
}
// The value stored in the bbb-polling-webID key represents the next available web-friendly poll ID
ArrayList webInfo = new ArrayList();
String nextWebKey = webKeyIncrement(Integer.parseInt(jedis.get(CURRENTKEY)), jedis);
jedis.del(nextWebKey);
jedis.set(nextWebKey, pollKey);
// Save the webKey that is being used as part of the poll key, for quick reference later
jedis.hset(pollKey, "webKey", nextWebKey);
// Replace the value stored in bbb-polling-webID
jedis.set(CURRENTKEY, nextWebKey);
webInfo.add(nextWebKey);
String hostname = getLocalIP();
webInfo.add(hostname);
return webInfo;
}
private String webKeyIncrement(Integer index, Jedis jedis){
String nextIndex;
if (++index <= MAX_WEBKEYS){
nextIndex = index.toString();
}else{
nextIndex = MIN_WEBKEYS.toString();
}
return nextIndex;
}
public static Jedis dbConnect(){
String serverIP = "127.0.0.1";
//String serverIP = getLocalIP();
//serverIP = serverIP.substring(7);
JedisPool redisPool = new JedisPool(serverIP, 6379);
try{
return redisPool.getResource();
}
catch (Exception e){
log.error("Error in PollApplication.dbConnect():");
log.error(e.toString());
}
log.error("Returning NULL from dbConnect()");
return null;
}
private static String getLocalIP()
{
File parseFile = new File(BBB_FILE);
try{
Scanner scanner = new Scanner(new FileReader(parseFile));
Boolean found = false;
String serverAddress = "";
while (!found && scanner.hasNextLine()){
serverAddress = processLine(scanner.nextLine());
if (!serverAddress.equals("")){
found = true;
}
}
scanner.close();
return serverAddress;
}
catch (Exception e){
log.error("Error in scanning " + BBB_FILE + " to find server address.");
}
return null;
}
private static String processLine(String line){
//use a second Scanner to parse the content of each line
Scanner scanner = new Scanner(line);
scanner.useDelimiter("=");
if ( scanner.hasNext() ){
String name = scanner.next();
if (name.equals(BBB_SERVER_FIELD)){
String value = scanner.next();
return value;
}
}
return "";
}
}

View File

@ -0,0 +1,139 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import org.red5.server.adapter.IApplication;
import org.red5.server.api.IClient;
import org.red5.server.api.IConnection;
import org.red5.server.api.scope.IScope;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.so.ISharedObject;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.Red5;
import org.bigbluebutton.conference.BigBlueButtonSession;
import org.bigbluebutton.conference.Constants;
import org.bigbluebutton.conference.service.recorder.RecorderApplication;
//import org.bigbluebutton.conference.service.recorder.poll.PollEventRecorder;
public class PollHandler extends ApplicationAdapter implements IApplication{
private static Logger log = Red5LoggerFactory.getLogger( PollHandler.class, "bigbluebutton" );
private static final String POLL = "POLL";
private static final String POLL_SO = "pollSO";
private static final String APP = "POLL";
private RecorderApplication recorderApplication;
private PollApplication pollApplication;
private IScope scope;
@Override
public boolean appConnect(IConnection conn, Object[] params) {
log.debug(APP + "appConnect");
return true;
}
@Override
public void appDisconnect(IConnection conn) {
log.debug(APP + "appDisconnect");
}
@Override
public boolean appJoin(IClient client, IScope scope) {
log.debug(APP + "appJoin: " + scope.getName());
return true;
}
@Override
public void appLeave(IClient client, IScope scope) {
log.debug(APP + "appLeave: " + scope.getName());
}
@Override
public boolean appStart(IScope scope) {
this.scope = scope;
log.debug(APP + "appStart: " + scope.getName());
return true;
}
@Override
public void appStop(IScope scope) {
log.debug(APP + "appStop: " + scope.getName());
}
@Override
public boolean roomConnect(IConnection connection, Object[] params) {
log.debug("roomConnect");
log.debug(APP + "Setting up recorder");
log.debug(APP + "adding event recorder to " + connection.getScope().getName());
log.debug(APP + "Adding room listener");
log.debug(APP + "Done setting up recorder and listener");
return true;
}
@Override
public void roomDisconnect(IConnection connection) {
log.debug(APP + "roomDisconnect");
}
@Override
public boolean roomJoin(IClient client, IScope scope) {
log.debug(APP + "roomJoin " + scope.getName(), scope.getParent().getName());
return true;
}
@Override
public void roomLeave(IClient client, IScope scope) {
log.debug(APP + "roomLeave: " + scope.getName());
}
@Override
public boolean roomStart(IScope scope) {
log.debug(APP + " roomStart " + scope.getName());
pollApplication.createRoom(scope.getName());
log.debug(APP + " inside roomStart startin room");
return true;
}
@Override
public void roomStop(IScope scope) {
log.debug(APP +"roomStop ", scope.getName());
pollApplication.destroyRoom(scope.getName());
}
public void setPollApplication(PollApplication a) {
log.debug("Setting chat application");
pollApplication = a;
pollApplication.handler = this;
}
public void setRecorderApplication(RecorderApplication a) {
log.debug(APP + " Setting poll archive application");
recorderApplication = a;
}
private BigBlueButtonSession getBbbSession() {
return (BigBlueButtonSession) Red5.getConnectionLocal().getAttribute(Constants.SESSION);
}
}

View File

@ -0,0 +1,67 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import net.jcip.annotations.ThreadSafe;
import java.util.concurrent.ConcurrentHashMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/* Contains information about a PollRoom.
*/
@ThreadSafe
public class PollRoom {
private static Logger log = Red5LoggerFactory.getLogger( PollRoom.class, "bigbluebutton" );
private final String name;
private final Map<String, IPollRoomListener> listeners;
ArrayList<String> messages;
public PollRoom(String name) {
this.name = name;
listeners = new ConcurrentHashMap<String, IPollRoomListener>();
this.messages = new ArrayList<String>();
}
public String getName() {
return name;
}
public void addRoomListener(IPollRoomListener listener) {
if (! listeners.containsKey(listener.getName())) {
listeners.put(listener.getName(), listener);
}
}
public void removeRoomListener(IPollRoomListener listener) {
listeners.remove(listener);
}
@SuppressWarnings("unchecked")
public void savePoll(Poll poll){
for (Iterator iter = listeners.values().iterator(); iter.hasNext();) {
IPollRoomListener listener = (IPollRoomListener) iter.next();
listener.savePoll(poll);
}
}
}

View File

@ -0,0 +1,81 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import net.jcip.annotations.ThreadSafe;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* This encapsulates access to PollRoom and messages. This class must be threadsafe.
*/
@ThreadSafe
public class PollRoomsManager {
private static Logger log = Red5LoggerFactory.getLogger( PollRoomsManager.class, "bigbluebutton" );
private final Map <String, PollRoom> rooms;
public PollRoomsManager() {
rooms = new ConcurrentHashMap<String, PollRoom>();
}
public void addRoom(PollRoom room) {
rooms.put(room.getName(), room);
}
public void removeRoom(String name) {
rooms.remove(name);
}
public boolean hasRoom(String name) {
return rooms.containsKey(name);
}
/**
* Keeping getRoom private so that all access to PollRoom goes through here.
*/
private PollRoom getRoom(String name) {
return rooms.get(name);
}
public void savePoll(Poll poll) {
String room = poll.room;
PollRoom r = getRoom(room);
if (r != null) {
r.savePoll(poll);
} else {
log.warn("Sending message to a non-existing room " + poll.room);
}
}
public void addRoomListener(String roomName, IPollRoomListener listener) {
PollRoom r = getRoom(roomName);
if (r != null) {
r.addRoomListener(listener);
return;
}
log.warn("Adding listener to a non-existing room " + roomName);
}
}

View File

@ -0,0 +1,106 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.poll;
import org.apache.commons.lang.time.DateFormatUtils;
import org.bigbluebutton.conference.service.poll.PollApplication;
import org.bigbluebutton.conference.service.poll.Poll;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.so.ISharedObject;
import org.red5.server.api.Red5;
import redis.clients.jedis.Jedis;
public class PollService {
private static Logger log = Red5LoggerFactory.getLogger( PollService.class, "bigbluebutton" );
private PollApplication application;
private String LOGNAME = "[PollService]";
private Poll poll;
public void savePoll(ArrayList clientSidePoll){
String pollTime = DateFormatUtils.formatUTC(System.currentTimeMillis(), "MM/dd/yy HH:mm");
clientSidePoll.set(6, pollTime);
poll = new Poll(clientSidePoll);
application.savePoll(poll);
}
public ArrayList publish(ArrayList clientSidePoll, String pollKey){
savePoll(clientSidePoll);
return getPoll(pollKey);
}
public void setPollApplication(PollApplication a) {
log.debug(LOGNAME + "Setting Poll Applications");
application = a;
}
public ArrayList getPoll(String pollKey)
{
Poll poll = application.getPoll(pollKey);
ArrayList values = new ArrayList();
values.add(poll.title);
values.add(poll.room);
values.add(poll.isMultiple);
values.add(poll.question);
values.add(poll.answers);
values.add(poll.votes);
values.add(poll.time);
values.add(poll.totalVotes);
values.add(poll.status);
values.add(poll.didNotVote);
values.add(poll.publishToWeb);
values.add(poll.webKey);
return values;
}
public ArrayList vote(String pollKey, ArrayList answerIDs, Boolean webVote)
{
application.vote(pollKey, answerIDs.toArray(), webVote);
return getPoll(pollKey);
}
public ArrayList titleList()
{
return application.titleList();
}
public void setStatus(String pollKey, Boolean status){
application.setStatus(pollKey, status);
}
public ArrayList generate(String pollKey){
ArrayList webInfo = new ArrayList();
webInfo = application.generate(pollKey);
return webInfo;
}
public void cutOffWebPoll(String pollKey){
application.cutOffWebPoll(pollKey);
}
}

View File

@ -0,0 +1,128 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.recorder.polling;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Array;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Scanner;
import javax.servlet.ServletRequest;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.Red5;
import org.slf4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import org.apache.commons.lang.time.DateFormatUtils;
import org.bigbluebutton.conference.service.poll.Poll;
import org.bigbluebutton.conference.service.poll.PollApplication;
public class PollInvoker {
private String BBB_FILE = "/var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties";
private String BBB_SERVER_FIELD = "bigbluebutton.web.serverURL";
private static Logger log = Red5LoggerFactory.getLogger( PollInvoker.class, "bigbluebutton");
JedisPool redisPool;
public PollInvoker(){
super();
}
public JedisPool getRedisPool() {
return redisPool;
}
public void setRedisPool(JedisPool pool) {
this.redisPool = pool;
}
// The invoke method is called after already determining which poll is going to be used
// (ie, the presenter has chosen this poll from a list and decided to use it, or it is being used immediately after creation)
public Poll invoke(String pollKey){
Jedis jedis = PollApplication.dbConnect();
if (jedis.exists(pollKey))
{
// Get Boolean values from string-based Redis hash
boolean pMultiple = false;
boolean pStatus = false;
boolean pWebPublish = false;
if (jedis.hget(pollKey, "multiple").compareTo("true") == 0)
pMultiple = true;
if (jedis.hget(pollKey, "status").compareTo("true") == 0)
pStatus = true;
if (jedis.hget(pollKey, "publishToWeb").compareTo("true") == 0)
pWebPublish = true;
// ANSWER EXTRACTION
long pollSize = jedis.hlen(pollKey);
// otherFields is defined in Poll.java as the number of fields the hash has which are not answers or votes.
long numAnswers = (pollSize-Poll.getOtherFields())/2;
// Create an ArrayList of Strings for answers, and one of ints for answer votes
ArrayList <String> pAnswers = new ArrayList <String>();
ArrayList <Integer> pVotes = new ArrayList <Integer>();
for (int j = 1; j <= numAnswers; j++)
{
pAnswers.add(jedis.hget(pollKey, "answer"+j+"text"));
pVotes.add(Integer.parseInt(jedis.hget(pollKey, "answer"+j)));
}
ArrayList retrievedPoll = new ArrayList();
retrievedPoll.add(jedis.hget(pollKey, "title"));
retrievedPoll.add(jedis.hget(pollKey, "room"));
retrievedPoll.add(pMultiple);
retrievedPoll.add(jedis.hget(pollKey, "question"));
retrievedPoll.add(pAnswers);
retrievedPoll.add(pVotes);
retrievedPoll.add(jedis.hget(pollKey, "time"));
retrievedPoll.add(jedis.hget(pollKey, "totalVotes"));
retrievedPoll.add(pStatus);
retrievedPoll.add(jedis.hget(pollKey, "didNotVote"));
retrievedPoll.add(pWebPublish);
retrievedPoll.add(jedis.hget(pollKey, "webKey"));
Poll poll = new Poll(retrievedPoll);
return poll;
}
log.error("[ERROR] A poll is being invoked that does not exist. Null exception will be thrown.");
return null;
}
// Gets the ID of the current room, and returns a list of all available polls.
public ArrayList <String> titleList()
{
Jedis jedis = PollApplication.dbConnect();
String roomName = Red5.getConnectionLocal().getScope().getName();
ArrayList <String> pollTitleList = new ArrayList <String>();
for (String s : jedis.keys(roomName+"*"))
{
pollTitleList.add(jedis.hget(s, "title"));
}
return pollTitleList;
}
}

View File

@ -0,0 +1,110 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.conference.service.recorder.polling;
import java.net.InetAddress;
import javax.servlet.ServletRequest;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.util.ArrayList;
import org.apache.commons.lang.time.DateFormatUtils;
import org.bigbluebutton.conference.service.poll.Poll;
import org.bigbluebutton.conference.service.poll.PollApplication;
public class PollRecorder {
private static Logger log = Red5LoggerFactory.getLogger( PollRecorder.class, "bigbluebutton");
JedisPool redisPool;
public PollRecorder() {
super();
}
public JedisPool getRedisPool() {
return redisPool;
}
public void setRedisPool(JedisPool pool) {
this.redisPool = pool;
}
public void record(Poll poll) {
Jedis jedis = PollApplication.dbConnect();
// Merges the poll title, room into a single string seperated by a hyphen
String pollKey = poll.room + "-" + poll.title;
// Saves all relevant information about the poll as fields in a hash
jedis.hset(pollKey, "title", poll.title);
jedis.hset(pollKey, "question", poll.question);
jedis.hset(pollKey, "multiple", poll.isMultiple.toString());
jedis.hset(pollKey, "room", poll.room);
jedis.hset(pollKey, "time", poll.time);
// Dynamically creates enough fields in the hash to store all of the answers and their corresponding votes.
// If the poll is freshly created and has no votes yet, the votes are initialized at zero;
// otherwise it fetches the previous number of votes.
for (int i = 1; i <= poll.answers.size(); i++)
{
jedis.hset(pollKey, "answer"+i+"text", poll.answers.toArray()[i-1].toString());
if (poll.votes == null){
jedis.hset(pollKey, "answer"+i, "0");
}else{
jedis.hset(pollKey, "answer"+i, poll.votes.toArray()[i-1].toString());
}
}
Integer tv = poll.totalVotes;
String totalVotesStr = tv.toString();
Integer dnv = poll.didNotVote;
String didNotVoteStr = dnv.toString();
if (totalVotesStr == null){
jedis.hset(pollKey, "totalVotes", "0");
}else{
jedis.hset(pollKey, "totalVotes", totalVotesStr);
}
jedis.hset(pollKey, "status", poll.status.toString());
jedis.hset(pollKey, "didNotVote", didNotVoteStr);
jedis.hset(pollKey, "publishToWeb", poll.publishToWeb.toString());
jedis.hset(pollKey, "webKey", poll.webKey);
}
public void setStatus(String pollKey, Boolean status){
Jedis jedis = PollApplication.dbConnect();
jedis.hset(pollKey, "status", status.toString());
}
public void vote(String pollKey, Poll poll, Object[] answerIDs, Boolean webVote){
Jedis jedis = PollApplication.dbConnect();
for (int i = 0; i < answerIDs.length; i++){
// Extract the index value stored at element i of answerIDs
Integer index = Integer.parseInt(answerIDs[i].toString()) + 1;
// Increment the votes for answer
jedis.hincrBy(pollKey, "answer"+index, 1);
}
if (answerIDs.length > 0){
if (!webVote)
jedis.hincrBy(pollKey, "didNotVote", -1);
jedis.hincrBy(pollKey, "totalVotes", 1);
}
}
}

View File

@ -188,4 +188,37 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<!-- END RECORDER AND MESSAGING -->
<!-- START Polling -->
<bean id="pollHandler"
class="org.bigbluebutton.conference.service.poll.PollHandler">
<property name="pollApplication">
<ref local="pollApplication"/>
</property>
<property name="recorderApplication">
<ref local="recorderApplication"/>
</property>
</bean>
<bean id="pollApplication" class="org.bigbluebutton.conference.service.poll.PollApplication">
<property name="roomsManager">
<ref local="pollRoomsManager"/>
</property>
</bean>
<bean id="poll.service"
class="org.bigbluebutton.conference.service.poll.PollService">
<property name="pollApplication">
<ref local="pollApplication"/>
</property>
</bean>
<bean id="pollRoomsManager"
class="org.bigbluebutton.conference.service.poll.PollRoomsManager"/>
<bean id="pollRecorder"
class="org.bigbluebutton.conference.service.recorder.polling.PollRecorder">
<property name="redisPool">
<ref local="redisPool" />
</property>
</bean>
</beans>

View File

@ -378,7 +378,7 @@ DataGrid {
.micSettingsWindowCancelButtonStyle {
fillAlphas: 1, 1, 1, 1;
fillColors: #ff0000, #ff0000, #ffffff, #eeeeee;
fillColors: #ffffff, #eeeeee, #ffffff, #eeeeee;
rollOverColor: #eeeeee;
color: #5e5f63;
textRollOverColor: #5e5f63;
@ -627,5 +627,5 @@ MDIWindow {
.cameraDisplaySettingsWindowStartBtn
{
icon: Embed('assets/images/play-blue.png');
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

View File

@ -33,6 +33,7 @@
<property name="VIDEO" value="VideoconfModule" />
<property name="WHITEBOARD" value="WhiteboardModule" />
<property name="VIDEO_DOCK" value="VideodockModule" />
<property name="POLLING" value="PollingModule" />
<property name="LAYOUT" value="LayoutModule" />
<property name="PARTICIPANTS" value="ParticipantsModule" />
@ -178,6 +179,10 @@
<build-module src="${SRC_DIR}" target="${NOTES}" />
</target>
<target name="build-polling" description="Compile Polling Module">
<build-module src="${SRC_DIR}" target="${POLLING}" />
</target>
<target name="build-viewers" description="Compile Viewers Module">
<build-module src="${SRC_DIR}" target="${VIEWERS}" />
</target>
@ -476,5 +481,5 @@
description="Build BBB client without locales"/>
<target name="cleanandmake" depends="clean-build-all" description="Build BBB client including locales"/>
<target name="build-custom" depends="init-ant-contrib, build-participants" description="Build a custom defined module only, to save time as each build takes several minutes" />
<target name="build-poll" depends="init-ant-contrib, build-polling" description="Build only the polling module." />
</project>

View File

@ -168,3 +168,46 @@ bbb.settings.noissues = Keine ausstehenden Verbesserungen wurden entdeckt.
bbb.settings.instructions = Akzeptieren Sie die Flash-Abfrage welche nach dem Kamerazugriff fragt. Wenn Sie sich selber sehen und hören können, dann wurde ihr Browser richtig konfiguriert. Andere mögliche Ursachen sind unten angezeigt. Klicken Sie auf jede dieser Ursachen um eine mögliche Lösung zu finden.
bbb.videodock.title = Video Sammelfenster
bbb.zzzzz.yyyy =
bbb.polling.createPoll=Neue Umfrage erstellen
bbb.polling.createPoll.moreThanOneResponse=Mehrfachwahl von Antworten f\u00fcr Nutzer erlauben
bbb.polling.createPoll.hint=Tip: Beginnen Sie jede Antwort mit einer neuen Zeile
bbb.polling.createPoll.answers=Antworten:
bbb.polling.createPoll.question=Frage:
bbb.polling.createPoll.title=Titel:
bbb.polling.createPoll.publishToWeb=Webumfragen aktivieren
bbb.polling.pollPreview=Umfrage Vorschau
bbb.polling.pollPreview.modify=\u00c4ndern
bbb.polling.pollPreview.publish=Ver\u00f6ffentlichen
bbb.polling.pollPreview.preview=Vorschau
bbb.polling.pollPreview.save=Speichern
bbb.polling.pollPreview.cancel=Abbrechen
bbb.polling.pollPreview.modify=\u00c4ndern
bbb.polling.pollPreview.hereIsYourPoll=Hier ist Ihre Umfrage:
bbb.polling.pollPreview.ifYouWantChanges=Wenn Sie \u00c4nderungen vornehmen m\u00f6chten, klicken Sie bitte auf \"\u00c4ndern\"
bbb.polling.pollPreview.checkAll=(Zutreffendes bitte anhaken)
bbb.polling.pollPreview.pollWillPublishOnline=Diese Umfrage wird f\u00fcr eine Webabstimmung verf\u00fcgbar sein.
bbb.polling.validation.toolongAnswer=Ihre Antwort ist zu lang. Die maximale L\u00e4nge ist
bbb.polling.validation.toolongQuestion=Ihre Frage ist zu lang. Maximale Anzahl Zeichen:
bbb.polling.validation.toolongTitle=Der Titel ist zu lang. Max:
bbb.polling.validation.noQuestion=Bitte stellen Sie eine Frage
bbb.polling.validation.noTitle=Bitte geben Sie einen Titel ein
bbb.polling.validation.toomuchAnswers=Sie haben zu viele Antworten markiert. Maximal erlaubte Anzahl:
bbb.polling.validation.eachNewLine=Bitte geben Sie mindestens 2 Antworten ein. Beginnen Sie jede mit einer neuen Zeile
bbb.polling.validation.answerUnique=Jede Antwort sollte einzigartig sein.
bbb.polling.validation.atLeast2Answers=Bitte nennen Sie mindestens 2 Antworten
bbb.polling.validation.duplicateTitle=Diese Umfrage existiert bereits
bbb.polling.pollView.vote=Senden
bbb.polling.toolbar.toolTip=Stimmenabgabe
bbb.polling.stats.repost=Erneute Eingabe
bbb.polling.stats.close=Schlie\u00dfen
bbb.polling.stats.didNotVote=Nicht abgestimmt
bbb.polling.stats.refresh=Aktualisieren
bbb.polling.stats.stopPoll=Umfrage stoppen
bbb.polling.stats.title=Umfragestatistiken
bbb.polling.view.title=Umfrage
bbb.polling.stats.webPollURL=Diese Umfrage ist verf\u00fcgbar unter:
bbb.polling.stats.votes=Stimmen
bbb.polling.webPollClosed=Webumfrage wurde geschlossen.
bbb.polling.pollClosed=Die Umfrage wurde beendet! Die Ergebnisse sind:
bbb.polling.vote.error.radio=Bitte w\u00e4hlen Sie eine Option oder schlie\u00dfen Sie das Fenster um nichts zu w\u00e4hlen.
bbb.polling.vote.error.check=Bitte w\u00e4hlen Sie mindestens eine Optionen oder schlie\u00dfen Sie das Fenster um nichts zu w\u00e4hlen.

View File

@ -27,9 +27,9 @@ bbb.viewers.viewersGrid.nameItemRenderer = Name
bbb.viewers.viewersGrid.nameItemRenderer.nameLabel.toolTip = You are logged in as this user.
bbb.viewers.viewersGrid.roleItemRenderer = Role
bbb.viewers.viewersGrid.statusItemRenderer = Status
bbb.viewers.viewersGrid.statusItemRenderer.raiseHand.toolTip = Hand Raised on {0}
bbb.viewers.viewersGrid.statusItemRenderer.streamIcon.toolTip = Click to view.
bbb.viewers.viewersGrid.statusItemRenderer.presIcon.toolTip = Presenter
bbb.viewers.viewersGrid.statusItemRenderer.raiseHand.toolTip = Hand Raised.
bbb.viewers.viewersGrid.statusItemRenderer.streamIcon.toolTip = Sharing webcam.
bbb.viewers.viewersGrid.statusItemRenderer.presIcon.toolTip = Is Presenter.
bbb.viewers.presentBtn.toolTip = Select web participant to be presenter.
bbb.viewers.raiseHandBtn.toolTip = Click to raise hand.
bbb.viewers.presentBtn.label = Switch Presenter
@ -263,6 +263,57 @@ bbb.shortcutkey.chat.chatbox.gofirst = control+shift+32
bbb.shortcutkey.chat.chatbox.gofirst.function = Go to first message
bbb.shortcutkey.chat.chatbox.goread = control+shift+82
bbb.shortcutkey.chat.chatbox.goread.function = Go to the most recent message you have read
bbb.shortcutkey.glossary.open = control+shift+191
bbb.shortcutkey.glossary.open.function = Open shortcut glossary window
bbb.polling.createPoll = Create New Poll
bbb.polling.createPoll.moreThanOneResponse = Allow users to choose more than one response
bbb.polling.createPoll.hint = Hint: Start every answer with a new line
bbb.polling.createPoll.answers = Answers:
bbb.polling.createPoll.question = Question:
bbb.polling.createPoll.title = Title:
bbb.polling.createPoll.publishToWeb = Enable web polling
bbb.polling.pollPreview = Poll Preview
bbb.polling.pollPreview.modify = Modify
bbb.polling.pollPreview.publish = Publish
bbb.polling.pollPreview.preview = Preview
bbb.polling.pollPreview.save = Save
bbb.polling.pollPreview.cancel = Cancel
bbb.polling.pollPreview.modify = Modify
bbb.polling.pollPreview.hereIsYourPoll = Here is your poll:
bbb.polling.pollPreview.ifYouWantChanges = if you want to make any changes click 'Modify' button
bbb.polling.pollPreview.checkAll = (check all that may apply)
bbb.polling.pollPreview.pollWillPublishOnline = This poll will be available for web polling.
bbb.polling.validation.toolongAnswer = Your answers are too long. Max length is
bbb.polling.validation.toolongQuestion = Question is too long. Maximum chars:
bbb.polling.validation.toolongTitle = Title is too long, Max:
bbb.polling.validation.noQuestion = Please provide a Question
bbb.polling.validation.noTitle = Please provide a Title
bbb.polling.validation.toomuchAnswers = You have too many answers. Max, answers allowed:
bbb.polling.validation.eachNewLine = Please provide at least 2 Answers start each with new line
bbb.polling.validation.answerUnique = Every answer should be unique
bbb.polling.validation.atLeast2Answers = Please provide at least 2 Answers
bbb.polling.validation.duplicateTitle = This poll already exists
bbb.polling.pollView.vote = Submit
bbb.polling.toolbar.toolTip = Polling
bbb.polling.stats.repost = Repost
bbb.polling.stats.close = Close
bbb.polling.stats.didNotVote = Did Not Vote
bbb.polling.stats.refresh = Refresh
bbb.polling.stats.stopPoll = Stop Poll
bbb.polling.stats.title = Poll Statistics
bbb.polling.view.title = Poll
bbb.polling.stats.webPollURL = This poll is available at:
bbb.polling.stats.votes = votes
bbb.polling.webPollClosed = Web polling has been closed.
bbb.polling.pollClosed = Polling has been closed! The results are:
bbb.polling.vote.error.radio = Please select an option, or close this window to not vote.
bbb.polling.vote.error.check = Please select one or more options, or close this window to not vote.
bbb.publishVideo.startPublishBtn.labelText = Start Sharing
bbb.publishVideo.changeCameraBtn.labelText = Change Camera Settings
bbb.publishVideo.changeCameraBtn.labelText = Change Camera Settings

View File

@ -169,3 +169,46 @@ bbb.settings.instructions = Acepte la solicitud de Flash que le pide permisos pa
bbb.videodock.title = Área de video
bbb.zzzzz.yyyy =
=
bbb.polling.createPoll=Crear nueva encuesta
bbb.polling.createPoll.moreThanOneResponse=Permitir a los usuarios elegir m\u00e1s de una opci\u00f3n
bbb.polling.createPoll.hint=Pista: Introduzca cada posible opci\u00f3n en una linea
bbb.polling.createPoll.answers=Opciones:
bbb.polling.createPoll.question=Pregunta:
bbb.polling.createPoll.title=T\u00edtulo:
bbb.polling.createPoll.publishToWeb=Activar votaci\u00f3n web
bbb.polling.pollPreview=Previsualizaci\u00f3n de la encuesta
bbb.polling.pollPreview.modify=Modificar
bbb.polling.pollPreview.publish=Publicar
bbb.polling.pollPreview.preview=Previsualizaci\u00f3n
bbb.polling.pollPreview.save=Guardar
bbb.polling.pollPreview.cancel=Cancelar
bbb.polling.pollPreview.modify=Modificar
bbb.polling.pollPreview.hereIsYourPoll=Esta es su encuesta:
bbb.polling.pollPreview.ifYouWantChanges=Si quiere hacer cambios, pulse el bot\u00f3n \'Modificar\'
bbb.polling.pollPreview.checkAll=(marque todas las que considere correctas)
bbb.polling.pollPreview.pollWillPublishOnline=La encuesta estar\u00e1 disponible para votaci\u00f3n web
bbb.polling.validation.toolongAnswer=Las opciones son demasiado largas. Longitud m\u00e1xima:
bbb.polling.validation.toolongQuestion=Pregunta demasiado larga. Longitud m\u00e1xima:
bbb.polling.validation.toolongTitle=T\u00edtulo demasiado largo. M\u00e1ximo:
bbb.polling.validation.noQuestion=Introduzca una pregunta
bbb.polling.validation.noTitle=Por favor, indique un Titulo
bbb.polling.validation.toomuchAnswers=Demasiadas opciones. M\u00e1ximas admitidas:
bbb.polling.validation.eachNewLine=Proporcione al menos 2 opciones, empezando cada una en una linea nueva
bbb.polling.validation.answerUnique=Las respuestas deben ser \u00fanicas
bbb.polling.validation.atLeast2Answers=Introduzca al menos 2 opciones
bbb.polling.validation.duplicateTitle=La encuesta ya existe
bbb.polling.pollView.vote=Enviar
bbb.polling.toolbar.toolTip=Encuestando
bbb.polling.stats.repost=Publicar de nuevo
bbb.polling.stats.close=Cerrar
bbb.polling.stats.didNotVote=No ha votado
bbb.polling.stats.refresh=Actualizar
bbb.polling.stats.stopPoll=Detener encuesta
bbb.polling.stats.title=Estad\u00edsticas de la encuesta
bbb.polling.view.title=Encuesta
bbb.polling.stats.webPollURL=Esta encuesta est\u00e1 disponible en:
bbb.polling.stats.votes=votos
bbb.polling.webPollClosed=La encuesta web ha sido cerrada.
bbb.polling.pollClosed=\u00a1La encuesta ha sido cerrada! Resultados:
bbb.polling.vote.error.radio=Por favor, seleccione una opci\u00f3n, o cierre esta ventana para no votar
bbb.polling.vote.error.check=Por favor, seleccione una o varias opciones, o cierre esta ventana para no votar

View File

@ -169,3 +169,46 @@ bbb.settings.instructions = درخواست فلش مبنی بر اجازه بر
bbb.videodock.title = داک تصویر
bbb.zzzzz.yyyy =
=
bbb.polling.createPoll=\u0627\u064a\u062c\u0627\u062f \u064a\u06a9 \u0646\u0638\u0631\u0633\u0646\u062c\u064a \u062c\u062f\u064a\u062f
bbb.polling.createPoll.moreThanOneResponse=\u0628\u0647 \u06a9\u0627\u0631\u0628\u0631\u0627\u0646 \u0627\u062c\u0627\u0632\u0647 \u0627\u0646\u062a\u062e\u0627\u0628 \u0628\u06cc\u0634 \u0627\u0632 \u06cc\u06a9 \u06af\u0632\u06cc\u0646\u0647 \u0631\u0627 \u0628\u062f\u0647
bbb.polling.createPoll.hint=\u0646\u06a9\u062a\u0647: \u0647\u0631 \u067e\u0627\u0633\u062e \u0631\u0627 \u062f\u0631 \u062e\u0637 \u062c\u062f\u064a\u062f \u0628\u0646\u0648\u064a\u0633\u064a\u062f
bbb.polling.createPoll.answers=\u067e\u0627\u0633\u062e \u0647\u0627:
bbb.polling.createPoll.question=\u067e\u0631\u0633\u0634:
bbb.polling.createPoll.title=\u0639\u0646\u0648\u0627\u0646:
bbb.polling.createPoll.publishToWeb=\u0641\u0639\u0627\u0644 \u0633\u0627\u0632\u064a \u0646\u0638\u0631\u0633\u0646\u062c\u064a
bbb.polling.pollPreview=\u067e\u064a\u0634 \u0646\u0645\u0627\u064a\u0634 \u0646\u0638\u0631\u0633\u0646\u062c\u06cc
bbb.polling.pollPreview.modify=\u0648\u06cc\u0631\u0627\u06cc\u0634
bbb.polling.pollPreview.publish=\u0627\u0646\u062a\u0634\u0627\u0631
bbb.polling.pollPreview.preview=\u067e\u064a\u0634 \u0646\u0645\u0627\u064a\u0634
bbb.polling.pollPreview.save=\u0630\u062e\u06cc\u0631\u0647
bbb.polling.pollPreview.cancel=\u0627\u0646\u0635\u0631\u0627\u0641
bbb.polling.pollPreview.modify=\u0648\u06cc\u0631\u0627\u06cc\u0634
bbb.polling.pollPreview.hereIsYourPoll=\u0646\u0638\u0631 \u0633\u0646\u062c\u06cc \u0634\u0645\u0627 \u0622\u0645\u0627\u062f\u0647 \u0627\u0633\u062a:
bbb.polling.pollPreview.ifYouWantChanges=\u0628\u0631\u0627\u064a \u0627\u064a\u062c\u0627\u062f \u0647\u0631 \u062a\u063a\u064a\u064a\u0631\u064a \u0628\u0631 \u0631\u0648\u064a \u062f\u06a9\u0645\u0647 \"\u0648\u064a\u0631\u0627\u064a\u0634\" \u06a9\u0644\u064a\u06a9 \u06a9\u0646\u064a\u062f.
bbb.polling.pollPreview.checkAll=(\u0645\u0648\u0627\u0631\u062f\u064a \u06a9\u0647 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u06a9\u0627\u0631 \u0628\u0631\u0648\u0646\u062f \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u064a\u062f)
bbb.polling.pollPreview.pollWillPublishOnline=\u0627\u06cc\u0646 \u0646\u0638\u0631\u0633\u0646\u062c\u06cc \u0628\u0647 \u0635\u0648\u0631\u062a \u0622\u0646\u0644\u0627\u064a\u0646 \u062f\u0631 \u062f\u0633\u062a\u0631\u0633 \u062e\u0648\u0627\u0647\u062f \u0628\u0648\u062f.
bbb.polling.validation.toolongAnswer=\u067e\u0627\u0633\u062e\u200c\u0647\u0627\u064a \u0634\u0645\u0627 \u0628\u0633\u064a\u0627\u0631 \u0637\u0648\u0644\u0627\u0646\u064a \u0627\u0633\u062a\u060c \u062d\u062f\u0627\u06a9\u062b\u0631 \u0637\u0648\u0644 \u067e\u0627\u0633\u062e \u0628\u0631\u0627\u0628\u0631 \u0627\u0633\u062a \u0628\u0627:
bbb.polling.validation.toolongQuestion=\u067e\u0631\u0633\u0634 \u0634\u0645\u0627 \u0628\u0633\u064a\u0627\u0631 \u0637\u0648\u0644\u0627\u0646\u064a \u0627\u0633\u062a\u060c \u062d\u062f\u0627\u06a9\u062b\u0631 \u06a9\u0627\u0631\u0627\u06a9\u062a\u0631 \u0628\u0631\u0627\u0628\u0631 \u0627\u0633\u062a \u0628\u0627:
bbb.polling.validation.toolongTitle=\u0639\u0646\u0648\u0627\u0646 \u0637\u0648\u0644\u0627\u0646\u064a \u0627\u0633\u062a. \u0628\u064a\u0634\u062a\u0631\u064a\u0646 \u062a\u0639\u062f\u0627\u062f \u0645\u062c\u0627\u0632:
bbb.polling.validation.noQuestion=\u0644\u0637\u0641\u0627 \u064a\u06a9 \u0633\u0648\u0627\u0644 \u0627\u064a\u062c\u0627\u062f \u06a9\u0646\u064a\u062f
bbb.polling.validation.noTitle=\u0644\u0637\u0641\u0627 \u0639\u0646\u0648\u0627\u0646 \u0631\u0627 \u0648\u0627\u0631\u062f \u0646\u0645\u0627\u06cc\u06cc\u062f
bbb.polling.validation.toomuchAnswers=\u062a\u0639\u062f\u0627\u062f \u067e\u0627\u0633\u062e \u0647\u0627 \u0632\u064a\u0627\u062f \u0627\u0633\u062a. \u0628\u06cc\u0634\u062a\u0631\u06cc\u0646 \u062a\u0639\u062f\u0627\u062f \u0645\u062c\u0627\u0632
bbb.polling.validation.eachNewLine=\u0644\u0637\u0641\u0627 \u062d\u062f \u0627\u0642\u0644 2 \u067e\u0627\u0633\u062e \u0648\u0627\u0631\u062f \u0646\u0645\u0627\u064a\u064a\u062f\u060c \u0647\u0631 \u067e\u0627\u0633\u062e \u062f\u0631 \u06cc\u06a9 \u0633\u0637\u0631 \u062c\u062f\u06cc\u062f
bbb.polling.validation.answerUnique=\u0647\u0631 \u067e\u0627\u0633\u062e\u06cc \u0628\u0627\u06cc\u062f \u0645\u0646\u062d\u0635\u0631 \u0628\u0647 \u0641\u0631\u062f \u0628\u0627\u0634\u062f
bbb.polling.validation.atLeast2Answers=\u0644\u0637\u0641\u0627 \u062d\u062f\u0627\u0642\u0644 2 \u067e\u0627\u0633\u062e \u0627\u0631\u0627\u0626\u0647 \u062f\u0647\u064a\u062f
bbb.polling.validation.duplicateTitle=\u0627\u06cc\u0646 \u0646\u0638\u0631\u0633\u0646\u062c\u06cc \u0645\u0648\u062c\u0648\u062f \u0627\u0633\u062a
bbb.polling.pollView.vote=\u0627\u0631\u0633\u0627\u0644
bbb.polling.toolbar.toolTip=\u0646\u0638\u0631\u0633\u0646\u062c\u064a
bbb.polling.stats.repost=\u0627\u0631\u0633\u0627\u0644 \u0645\u062c\u062f\u062f
bbb.polling.stats.close=\u0628\u0633\u062a\u0646
bbb.polling.stats.didNotVote=\u062f\u0631 \u0646\u0638\u0631\u0633\u0646\u062c\u064a \u0634\u0631\u06a9\u062a \u06a9\u0631\u062f\u0647 \u0627\u064a\u062f
bbb.polling.stats.refresh=\u0646\u0648\u0633\u0627\u0632\u06cc
bbb.polling.stats.stopPoll=\u062a\u0648\u0642\u0641 \u0646\u0638\u0631\u0633\u0646\u062c\u064a
bbb.polling.stats.title=\u06af\u0632\u0627\u0631\u0634 \u0646\u0638\u0631\u0633\u0646\u062c\u064a
bbb.polling.view.title=\u0646\u0638\u0631\u0633\u0646\u062c\u06cc
bbb.polling.stats.webPollURL=\u062f\u0633\u062a\u0631\u0633\u064a \u0628\u0647 \u0646\u0638\u0631\u0633\u0646\u062c\u064a \u062f\u0631:
bbb.polling.stats.votes=\u0646\u0638\u0631 \u0633\u0646\u062c\u064a \u0647\u0627
bbb.polling.webPollClosed=\u0646\u0638\u0631\u0633\u0646\u062c\u064a \u0622\u0646\u0644\u0627\u064a\u0646 \u062a\u0645\u0627\u0645 \u0634\u062f.
bbb.polling.pollClosed=\u0646\u0638\u0631\u0633\u0646\u062c\u064a \u062a\u0645\u0627\u0645 \u0634\u062f! \u0646\u062a\u0627\u06cc\u062c \u0628\u062f\u06cc\u0646 \u0634\u0631\u062d \u0627\u0633\u062a:
bbb.polling.vote.error.radio=\u0644\u0637\u0641\u0627 \u064a\u06a9 \u06af\u0632\u064a\u0646\u0647 \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u064a\u062f \u0648 \u064a\u0627 \u0628\u0631\u0627\u064a \u0634\u0631\u06a9\u062a \u0646\u06a9\u0631\u062f\u0646 \u062f\u0631 \u0646\u0638\u0631\u0633\u0646\u062c\u064a \u067e\u0646\u062c\u0631\u0647 \u0631\u0627 \u0628\u0628\u0646\u062f\u064a\u062f.
bbb.polling.vote.error.check=\u0644\u0637\u0641\u0627 \u064a\u06a9 \u064a\u0627 \u0686\u0646\u062f \u06af\u0632\u064a\u0646\u0647 \u0631\u0627 \u0627\u0646\u062a\u062e\u0627\u0628 \u06a9\u0646\u064a\u062f \u0648 \u064a\u0627 \u0628\u0631\u0627\u064a \u0634\u0631\u06a9\u062a \u0646\u06a9\u0631\u062f\u0646 \u062f\u0631 \u0646\u0638\u0631\u0633\u0646\u062c\u064a \u067e\u0646\u062c\u0631\u0647 \u0631\u0627 \u0628\u0628\u0646\u062f\u064a\u062f.

View File

@ -142,3 +142,46 @@ bbb.presentation.uploadwindow.presentationfile = Presentasjonsfil
bbb.viewers.raiseHandBtn.toolTip = Klikk for håndsopprekking
bbb.presentation.error.convert.format = Feil: Vennligst sjekk at dokumenttypen er korrekt.
bbb.desktopPublish.fullscreen.label = Hele skjermen
bbb.polling.createPoll=Opprett ny avstemming
bbb.polling.createPoll.moreThanOneResponse=Tillat brukere \u00e5 velge mer enn ett svar
bbb.polling.createPoll.hint=Hint: Start hvert svar p\u00e5 en ny linje
bbb.polling.createPoll.answers=Svar:
bbb.polling.createPoll.question=Sp\u00f8rsm\u00e5l:
bbb.polling.createPoll.title=Tittel:
bbb.polling.createPoll.publishToWeb=Aktiver web avstemming
bbb.polling.pollPreview=Forh\u00e5ndsvisning av avstemmingen
bbb.polling.pollPreview.modify=Endre
bbb.polling.pollPreview.publish=Publiser
bbb.polling.pollPreview.preview=Forh\u00e5ndsvisning
bbb.polling.pollPreview.save=Lagre
bbb.polling.pollPreview.cancel=Avbryt
bbb.polling.pollPreview.modify=Endre
bbb.polling.pollPreview.hereIsYourPoll=Her er din avstemming:
bbb.polling.pollPreview.ifYouWantChanges=Dersom du \u00f8nsker \u00e5 endre noe, klikk \'Endre\' knappen
bbb.polling.pollPreview.checkAll=(sjekk alt som m\u00e5 v\u00e6re med)
bbb.polling.pollPreview.pollWillPublishOnline=Denne avstemmingen vil bli tilgjengelig for web avstemming.
bbb.polling.validation.toolongAnswer=Ditt svar er for langt, maks lengde er
bbb.polling.validation.toolongQuestion=Sp\u00f8rsm\u00e5let er for langt, Maks antall tegn er :
bbb.polling.validation.toolongTitle=For lang tittel, maks:
bbb.polling.validation.noQuestion=Vennligst oppgi et Sp\u00f8rsm\u00e5l
bbb.polling.validation.noTitle=Vennligst oppgi en tittel
bbb.polling.validation.toomuchAnswers=Du har for mange svar, Maks tillatte svar:
bbb.polling.validation.eachNewLine=Vennligst avgi minst 2 svar, start hvert svar med ny linje
bbb.polling.validation.answerUnique=Hvert svar m\u00e5 v\u00e6re unikt
bbb.polling.validation.atLeast2Answers=Vennligst oppgi minst 2 svar
bbb.polling.validation.duplicateTitle=Avstemmingen er allerede opprettet
bbb.polling.pollView.vote=Send
bbb.polling.toolbar.toolTip=Det stemmes
bbb.polling.stats.repost=Send igjen
bbb.polling.stats.close=Lukk
bbb.polling.stats.didNotVote=Har ikke stemt
bbb.polling.stats.refresh=Oppdater
bbb.polling.stats.stopPoll=Avslutt avstemming
bbb.polling.stats.title=Stemme statistikk
bbb.polling.view.title=Avstemming
bbb.polling.stats.webPollURL=Denne avstemmingen er tilgjengelig p\u00e5:
bbb.polling.stats.votes=stemmer
bbb.polling.webPollClosed=Web avstemming er stengt.
bbb.polling.pollClosed=Avstemmingen er stengt! Resultatet er:
bbb.polling.vote.error.radio=Vennligst oppgi et valg, eller steng dette vinduet for \u00e5 ikke avgi stemme.
bbb.polling.vote.error.check=Velg et eller flere alternativ, eller steng dette vinduet for \u00e5 ikke stemme.

View File

@ -169,3 +169,46 @@ bbb.settings.instructions = Tillat at Flash vil bruke ditt kamera. Hvis du kan s
bbb.videodock.title = Video dokk
bbb.zzzzz.yyyy =
=
bbb.polling.createPoll=Lag en ny unders\u00f8kelse
bbb.polling.createPoll.moreThanOneResponse=Tillat brukere \u00e5 avgi flere svar
bbb.polling.createPoll.hint=Hint: Start hvert svar med en ny linje
bbb.polling.createPoll.answers=Svar:
bbb.polling.createPoll.question=Sp\u00f8rsm\u00e5l:
bbb.polling.createPoll.title=Tittel:
bbb.polling.createPoll.publishToWeb=Aktiver web sp\u00f8rreunders\u00f8kelse
bbb.polling.pollPreview=Avstemmings forh\u00e5ndsvisning
bbb.polling.pollPreview.modify=Endre
bbb.polling.pollPreview.publish=Publiser
bbb.polling.pollPreview.preview=Forh\u00e5ndsvisning
bbb.polling.pollPreview.save=Lagre
bbb.polling.pollPreview.cancel=Avbryt
bbb.polling.pollPreview.modify=Endre
bbb.polling.pollPreview.hereIsYourPoll=Her er din avstemming:
bbb.polling.pollPreview.ifYouWantChanges=Dersom du vil gj\u00f8re endringer, klikk \'Endre\' knappen
bbb.polling.pollPreview.checkAll=(sjekk alt som det ang\u00e5r)
bbb.polling.pollPreview.pollWillPublishOnline=Denne unders\u00f8kelsen er vil bli tilgjengelig som web-avstemming.
bbb.polling.validation.toolongAnswer=Ditt svar er for langt. Maks lengde er
bbb.polling.validation.toolongQuestion=Sp\u00f8rsm\u00e5let er for langt. Maks antall tegn er:
bbb.polling.validation.toolongTitle=Tittel for lang, maks:
bbb.polling.validation.noQuestion=Vennligst skriv inn sp\u00f8rsm\u00e5let
bbb.polling.validation.noTitle=Vennligst oppgi tittel
bbb.polling.validation.toomuchAnswers=For mange svar, Maks antall svar tillatt er:
bbb.polling.validation.eachNewLine=Vennligst oppgi minst 2 svar, start hvert svar med ny linje
bbb.polling.validation.answerUnique=Hvert svar burde v\u00e6re unikt
bbb.polling.validation.atLeast2Answers=Vennligst oppgi minst to svar
bbb.polling.validation.duplicateTitle=Denne avstemmingen er allerede opprettet
bbb.polling.pollView.vote=Send
bbb.polling.toolbar.toolTip=Avstemming
bbb.polling.stats.repost=Send igjen
bbb.polling.stats.close=Lukk
bbb.polling.stats.didNotVote=Har ikke stemt
bbb.polling.stats.refresh=Oppfrisk
bbb.polling.stats.stopPoll=Stopp avstemming
bbb.polling.stats.title=Svarstatistikk
bbb.polling.view.title=Avstemming
bbb.polling.stats.webPollURL=Denne avstemmingen er tilgjelgelig p\u00e5:
bbb.polling.stats.votes=stemmer
bbb.polling.webPollClosed=Web-avstemmingen er stengt.
bbb.polling.pollClosed=Avstemmingen er stengt! Resultatet er:
bbb.polling.vote.error.radio=Vennligst velg et alternativ, eller lukk dette vinduet for \u00e5 ikke avgi stemme.
bbb.polling.vote.error.check=Vennligst velg ett eller flere alternativ. Lukk vindu dersom du ikke vil stemme.

View File

@ -169,3 +169,46 @@ bbb.settings.instructions = Aceite a notificação do Flash quando ele pedir per
bbb.videodock.title = Janela de vídeos
bbb.zzzzz.yyyy =
=
bbb.polling.createPoll=Criar Nova Enquete
bbb.polling.createPoll.moreThanOneResponse=Permitir aos usu\u00e1rios escolher mais de uma resposta
bbb.polling.createPoll.hint=Dica: Inicie cada pergunta com nova linha
bbb.polling.createPoll.answers=Respostas:
bbb.polling.createPoll.question=Pergunta:
bbb.polling.createPoll.title=T\u00edtulo:
bbb.polling.createPoll.publishToWeb=Habilitar web enquete
bbb.polling.pollPreview=Pr\u00e9-visualiza\u00e7\u00e3o da enquete
bbb.polling.pollPreview.modify=Modificar
bbb.polling.pollPreview.publish=Publicar
bbb.polling.pollPreview.preview=Pr\u00e9-visualizar
bbb.polling.pollPreview.save=Salvar
bbb.polling.pollPreview.cancel=Cancelar
bbb.polling.pollPreview.modify=Modificar
bbb.polling.pollPreview.hereIsYourPoll=Aqui est\u00e1 sua enquete
bbb.polling.pollPreview.ifYouWantChanges=Se voc\u00ea deseja fazer alguma mudan\u00e7a, clique no bot\u00e3o \"Modificar\"
bbb.polling.pollPreview.checkAll=(marque todas que se aplicam)
bbb.polling.pollPreview.pollWillPublishOnline=Esta enquete estar\u00e1 dispon\u00edvel na web.
bbb.polling.validation.toolongAnswer=Suas respostas est\u00e3o muito longas. O limite \u00e9
bbb.polling.validation.toolongQuestion=Pergunta muito longa. Limite de caracteres:
bbb.polling.validation.toolongTitle=T\u00edtulo muito longo. Limite:
bbb.polling.validation.noQuestion=Por favor, escreva a Pergunta
bbb.polling.validation.noTitle=Por favor, escreva o T\u00edtulo
bbb.polling.validation.toomuchAnswers=Voc\u00ea inseriu perguntas em excesso. Limite de perguntas permitido:
bbb.polling.validation.eachNewLine=Por favor escreva no m\u00ednimo 2 Respostas. Inicie cada uma com uma nova linha
bbb.polling.validation.answerUnique=Cada resposta deve ser \u00fanica.
bbb.polling.validation.atLeast2Answers=Por favor escreva no m\u00ednimo 2 Respostas
bbb.polling.validation.duplicateTitle=Esta enquete j\u00e1 existe
bbb.polling.pollView.vote=Enviar
bbb.polling.toolbar.toolTip=Enquete
bbb.polling.stats.repost=Reenviar
bbb.polling.stats.close=Fechar
bbb.polling.stats.didNotVote=N\u00e3o votou
bbb.polling.stats.refresh=Atualizar
bbb.polling.stats.stopPoll=Parar Enquete
bbb.polling.stats.title=Resultados da Enquete
bbb.polling.view.title=Enquete
bbb.polling.stats.webPollURL=Esta enquete est\u00e1 dispon\u00edvel em:
bbb.polling.stats.votes=votos
bbb.polling.webPollClosed=Web enquete foi encerrada.
bbb.polling.pollClosed=A enquete foi encerrada! Os resultados s\u00e3o:
bbb.polling.vote.error.radio=Por favot selecione uma op\u00e7\u00e3o, ou feche esta janela para n\u00e3o votar.
bbb.polling.vote.error.check=Por favor selecione uma ou mais op\u00e7\u00f5es, ou feche a janela para n\u00e3o votar.

View File

@ -169,3 +169,46 @@ bbb.settings.instructions = Разрешите Flash Player обращаться
bbb.videodock.title = Видеотрансляции
bbb.zzzzz.yyyy =
=
bbb.polling.createPoll=\u00d0\u00a1\u00d0\u00be\u00d0\u00b7\u00d0\u00b4\u00d0\u00b0\u00d1\u0082\u00d1\u008c \u00d0\u009d\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00b5 \u00d0\u0093\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d0\u00b5
bbb.polling.createPoll.moreThanOneResponse=\u00d0\u00a0\u00d0\u00b0\u00d0\u00b7\u00d1\u0080\u00d0\u00b5\u00d1\u0088\u00d0\u00b8\u00d1\u0082\u00d1\u008c \u00d0\u00bf\u00d0\u00be\u00d0\u00bb\u00d1\u008c\u00d0\u00b7\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d1\u0082\u00d0\u00b5\u00d0\u00bb\u00d1\u008f\u00d0\u00bc \u00d0\u00b2\u00d1\u008b\u00d0\u00b1\u00d0\u00b8\u00d1\u0080\u00d0\u00b0\u00d1\u0082\u00d1\u008c \u00d0\u00b1\u00d0\u00be\u00d0\u00bb\u00d1\u008c\u00d1\u0088\u00d0\u00b5 \u00d0\u00be\u00d0\u00b4\u00d0\u00bd\u00d0\u00be\u00d0\u00b3\u00d0\u00be \u00d0\u00be\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082\u00d0\u00b0
bbb.polling.createPoll.hint=\u00d0\u009f\u00d0\u00be\u00d0\u00b4\u00d1\u0081\u00d0\u00ba\u00d0\u00b0\u00d0\u00b7\u00d0\u00ba\u00d0\u00b0: \u00d0\u009a\u00d0\u00b0\u00d0\u00b6\u00d0\u00b4\u00d1\u008b\u00d0\u00b9 \u00d0\u00be\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082 \u00d0\u00bd\u00d0\u00b0\u00d1\u0087\u00d0\u00b8\u00d0\u00bd\u00d0\u00b0\u00d0\u00b5\u00d1\u0082\u00d1\u0081\u00d1\u008f \u00d1\u0081 \u00d0\u00bd\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00b9 \u00d1\u0081\u00d1\u0082\u00d1\u0080\u00d0\u00be\u00d0\u00ba\u00d0\u00b8
bbb.polling.createPoll.answers=\u00d0\u009e\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082\u00d1\u008b:
bbb.polling.createPoll.question=\u00d0\u0092\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081:
bbb.polling.createPoll.title=\u00d0\u0097\u00d0\u00b0\u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00ba:
bbb.polling.createPoll.publishToWeb=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u043f\u0440\u043e\u0441
bbb.polling.pollPreview=\u00d0\u009f\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d0\u00bc\u00d0\u00be\u00d1\u0082\u00d1\u0080 \u00d0\u0093\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d1\u008f
bbb.polling.pollPreview.modify=\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.pollPreview.publish=\u00d0\u009e\u00d0\u00bf\u00d1\u0083\u00d0\u00b1\u00d0\u00bb\u00d0\u00b8\u00d0\u00ba\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d1\u0082\u00d1\u008c
bbb.polling.pollPreview.preview=\u00d0\u009f\u00d1\u0080\u00d0\u00b5\u00d0\u00b4\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d0\u00bc\u00d0\u00be\u00d1\u0082\u00d1\u0080
bbb.polling.pollPreview.save=\u00d0\u00a1\u00d0\u00be\u00d1\u0085\u00d1\u0080\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.pollPreview.cancel=\u00d0\u009e\u00d1\u0082\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.pollPreview.modify=\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.pollPreview.hereIsYourPoll=\u00d0\u00a2\u00d0\u00b0\u00d0\u00ba \u00d0\u00b2\u00d1\u008b\u00d0\u00b3\u00d0\u00bb\u00d1\u008f\u00d0\u00b4\u00d0\u00b8\u00d1\u0082 \u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d1\u0081\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d0\u00b5:
bbb.polling.pollPreview.ifYouWantChanges=\u00d0\u0095\u00d1\u0081\u00d0\u00bb\u00d0\u00b8 \u00d0\u00b2\u00d1\u008b \u00d1\u0085\u00d0\u00be\u00d1\u0082\u00d0\u00b8\u00d1\u0082\u00d0\u00b5 \u00d1\u0081\u00d0\u00b4\u00d0\u00b5\u00d0\u00bb\u00d0\u00b0\u00d1\u0082\u00d1\u008c \u00d0\u00b8\u00d0\u00bc\u00d0\u00b7\u00d0\u00b5\u00d0\u00bd\u00d0\u00b5\u00d0\u00bd\u00d0\u00b8\u00d1\u008f \u00d0\u00bd\u00d0\u00b0\u00d0\u00b6\u00d0\u00bc\u00d0\u00b8\u00d0\u00bd\u00d0\u00b5 \u00d0\u00ba\u00d0\u00bd\u00d0\u00be\u00d0\u00bf\u00d0\u00ba\u00d1\u0083 \'\u00d0\u0098\u00d0\u00b7\u00d0\u00bc\u00d0\u00b5\u00d0\u00bd\u00d1\u0082\u00d1\u008c\'
bbb.polling.pollPreview.checkAll=(\u00d0\u00bc\u00d0\u00be\u00d0\u00b6\u00d0\u00bd\u00d0\u00be \u00d0\u00be\u00d1\u0082\u00d0\u00bc\u00d0\u00b5\u00d1\u0082\u00d0\u00b8\u00d1\u0082\u00d1\u008c \u00d0\u00b1\u00d0\u00be\u00d0\u00bb\u00d1\u008c\u00d1\u0088\u00d0\u00b5 \u00d0\u00be\u00d0\u00b4\u00d0\u00bd\u00d0\u00be\u00d0\u00b3\u00d0\u00be \u00d0\u00b2\u00d0\u00b0\u00d1\u0080\u00d0\u00b8\u00d0\u00b0\u00d0\u00bd\u00d1\u0082)
bbb.polling.pollPreview.pollWillPublishOnline=\u042d\u0442\u043e\u0442 \u043e\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0432\u0435\u0431-\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043d\u0438\u044f.
bbb.polling.validation.toolongAnswer=\u00d0\u0092\u00d0\u00b0\u00d1\u0088\u00d0\u00b8 \u00d0\u00be\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082\u00d1\u008b \u00d1\u0081\u00d0\u00bb\u00d0\u00b8\u00d1\u0088\u00d0\u00ba\u00d0\u00be\u00d0\u00bc \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00bd\u00d1\u008b\u00d0\u00b5. \u00d0\u009c\u00d0\u00b0\u00d0\u00ba\u00d1\u0081\u00d0\u00b8\u00d0\u00bc\u00d0\u00b0\u00d0\u00bb\u00d1\u008c\u00d0\u00bd\u00d0\u00b0\u00d1\u008f \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00b0 \u00d0\u00be\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082\u00d0\u00b0:
bbb.polling.validation.toolongQuestion=\u00d0\u0092\u00d0\u00b0\u00d1\u0088 \u00d0\u00b2\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081 \u00d1\u0081\u00d0\u00bb\u00d0\u00b8\u00d1\u0088\u00d0\u00ba\u00d0\u00be\u00d0\u00bc \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00bd\u00d1\u008b\u00d0\u00b9. \u00d0\u009c\u00d0\u00b0\u00d0\u00ba\u00d1\u0081\u00d0\u00b8\u00d0\u00bc\u00d0\u00b0\u00d0\u00bb\u00d1\u008c\u00d0\u00bd\u00d0\u00b0\u00d1\u008f \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00b0 \u00d0\u00b2\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d0\u00b0:
bbb.polling.validation.toolongTitle=\u00d0\u0092\u00d0\u00b0\u00d1\u0088 \u00d0\u00b7\u00d0\u00b0\u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00ba \u00d1\u0081\u00d0\u00bb\u00d0\u00b8\u00d1\u0088\u00d0\u00ba\u00d0\u00be\u00d0\u00bc \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00bd\u00d1\u008b\u00d0\u00b9. \u00d0\u009c\u00d0\u00b0\u00d0\u00ba\u00d1\u0081\u00d0\u00b8\u00d0\u00bc\u00d0\u00b0\u00d0\u00bb\u00d1\u008c\u00d0\u00bd\u00d0\u00b0\u00d1\u008f \u00d0\u00b4\u00d0\u00bb\u00d0\u00b8\u00d0\u00bd\u00d0\u00b0 \u00d0\u00b7\u00d0\u00b0\u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d0\u00b2\u00d0\u00ba\u00d0\u00b0:
bbb.polling.validation.noQuestion=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441
bbb.polling.validation.noTitle=\u00d0\u0097\u00d0\u00b0\u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00ba \u00d0\u00bd\u00d0\u00b5 \u00d0\u00bc\u00d0\u00be\u00d0\u00b6\u00d0\u00b5\u00d1\u0082 \u00d0\u00b1\u00d1\u008b\u00d1\u0082\u00d1\u008c \u00d0\u00bf\u00d1\u0083\u00d1\u0081\u00d1\u0082\u00d1\u008b\u00d0\u00bc
bbb.polling.validation.toomuchAnswers=\u00d0\u00a3 \u00d0\u00b2\u00d0\u00b0\u00d1\u0081 \u00d1\u0081\u00d0\u00bb\u00d0\u00b8\u00d1\u0088\u00d0\u00ba\u00d0\u00be\u00d0\u00bc \u00d0\u00bc\u00d0\u00bd\u00d0\u00be\u00d0\u00b3\u00d0\u00be \u00d0\u00b2\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2. \u00d0\u009c\u00d0\u00b0\u00d0\u00ba\u00d1\u0081. \u00d0\u00ba\u00d0\u00be\u00d0\u00bb\u00d0\u00b8\u00d1\u0087\u00d0\u00b5\u00d1\u0081\u00d1\u0082\u00d0\u00b2\u00d0\u00be \u00d0\u00b2\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2:
bbb.polling.validation.eachNewLine=\u00d0\u009f\u00d0\u00be\u00d0\u00b6\u00d0\u00b0\u00d0\u00bb\u00d1\u0083\u00d0\u00b9\u00d1\u0081\u00d1\u0082\u00d0\u00b0 \u00d0\u00b2\u00d0\u00b2\u00d0\u00b5\u00d0\u00b4\u00d0\u00b8\u00d1\u0082\u00d0\u00b5 \u00d0\u00bc\u00d0\u00b8\u00d0\u00bd\u00d0\u00b8\u00d0\u00bc\u00d1\u0083\u00d0\u00bc 2 \u00d0\u00be\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0082\u00d0\u00b0, \u00d0\u00ba\u00d0\u00b0\u00d0\u00b6\u00d0\u00b4\u00d1\u008b\u00d0\u00b9 \u00d1\u0081 \u00d0\u00bd\u00d0\u00be\u00d0\u00b2\u00d0\u00be\u00d0\u00b9 \u00d1\u0081\u00d1\u0082\u00d1\u0080\u00d0\u00be\u00d0\u00ba\u00d0\u00b8
bbb.polling.validation.answerUnique=\u00d0\u0092\u00d0\u00be\u00d0\u00bf\u00d1\u0080\u00d0\u00be\u00d1\u0081\u00d1\u008b \u00d0\u00bd\u00d0\u00b5 \u00d0\u00b4\u00d0\u00be\u00d0\u00bb\u00d0\u00b6\u00d0\u00bd\u00d1\u008b \u00d0\u00bf\u00d0\u00be\u00d0\u00b2\u00d1\u0082\u00d0\u00be\u00d1\u0080\u00d1\u008f\u00d1\u0082\u00d1\u008c\u00d1\u0081\u00d1\u008f
bbb.polling.validation.atLeast2Answers=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, 2 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430
bbb.polling.validation.duplicateTitle=\u042d\u0442\u043e\u0442 \u043e\u043f\u0440\u043e\u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
bbb.polling.pollView.vote=\u00d0\u009f\u00d0\u00be\u00d0\u00b4\u00d1\u0082\u00d0\u00b2\u00d0\u00b5\u00d1\u0080\u00d0\u00b4\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.toolbar.toolTip=\u041e\u043f\u0440\u043e\u0441
bbb.polling.stats.repost=\u00d0\u009e\u00d0\u00bf\u00d1\u0083\u00d0\u00b1\u00d0\u00bb\u00d0\u00b8\u00d0\u00ba\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d1\u0082\u00d1\u008c
bbb.polling.stats.close=\u0417\u0430\u043a\u0440\u044b\u0442\u044c
bbb.polling.stats.didNotVote=\u00d0\u009d\u00d0\u00b5 \u00d0\u00b3\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bb\u00d0\u00b8
bbb.polling.stats.refresh=\u00d0\u009e\u00d0\u00b1\u00d0\u00bd\u00d0\u00be\u00d0\u00b2\u00d0\u00b8\u00d1\u0082\u00d1\u008c
bbb.polling.stats.stopPoll=\u00d0\u009e\u00d1\u0081\u00d1\u0082\u00d0\u00b0\u00d0\u00bd\u00d0\u00be\u00d0\u00b2\u00d0\u00b8\u00d1\u0082\u00d1\u008c \u00d0\u009f\u00d0\u00be\u00d0\u00bb\u00d0\u00bb
bbb.polling.stats.title=\u00d0\u00a1\u00d1\u0082\u00d0\u00b0\u00d1\u0082\u00d0\u00b8\u00d1\u0081\u00d1\u0082\u00d0\u00b8\u00d0\u00ba\u00d0\u00b0
bbb.polling.view.title=\u00d0\u0093\u00d0\u00be\u00d0\u00bb\u00d0\u00be\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d0\u00b5
bbb.polling.stats.webPollURL=\u041e\u043f\u0440\u043e\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432:
bbb.polling.stats.votes=\u0433\u043e\u043b\u043e\u0441\u0430
bbb.polling.webPollClosed=\u042d\u0442\u043e\u0442 \u043e\u043f\u0440\u043e\u0441 \u0431\u044b\u043b \u0437\u0430\u043a\u0440\u044b\u0442.
bbb.polling.pollClosed=\u041e\u043f\u0440\u043e\u0441 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d! \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:
bbb.polling.vote.error.radio=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0434\u043d\u0443 \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043e\u043f\u0446\u0438\u0439 \u0438\u043b\u0438 \u0437\u0430\u043a\u0440\u043e\u0439\u0442\u0435 \u043e\u043a\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u0442\u044c.
bbb.polling.vote.error.check=\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0434\u043d\u0443 \u0438\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u043e\u043f\u0446\u0438\u0439 \u0438\u043b\u0438 \u0437\u0430\u043a\u0440\u043e\u0439\u043d\u0435 \u043e\u043a\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u0442\u044c.

View File

@ -84,7 +84,14 @@
uri="rtmp://HOST/bigbluebutton"
dependsOn="PresentModule"
/>
<!--
<module name="PollingModule" url="http://HOST/client/PollingModule.swf?v=VERSION"
uri="rtmp://HOST/bigbluebutton"
dependsOn="PresentModule"
/>
-->
<module name="PresentModule" url="http://HOST/client/PresentModule.swf?v=VERSION"
uri="rtmp://HOST/bigbluebutton"
host="http://HOST"

View File

@ -201,3 +201,28 @@ var sendPrivateChat = function () {
var message = "ECHO: " + bbbEvent.message;
BBB.sendPrivateChatMessage(bbbEvent.fromColor, bbbEvent.fromLang, message, bbbEvent.fromUserID);
}
var webcamViewStandaloneAppReady = function() {
console.log("WebcamViewStandalone App is ready.");
BBB.getPresenterUserID(function(puid) {
if (puid == "") {
console.log("There is no presenter in the meeting");
} else {
console.log("The presenter user id is [" + puid + "]");
// Is presenter sharing webcam? If so, get the webcam stream and display.
}
});
}
var webcamPreviewStandaloneAppReady = function() {
console.log("WebcamPreviewStandalone App is ready.");
BBB.getPresenterUserID(function(puid) {
if (puid == "") {
console.log("There is no presenter in the meeting");
} else {
console.log("The presenter user id is [" + puid + "]");
}
});
// Am I presenter? If so, am I publishing my camera? If so, display my camera.
}

View File

@ -1,3 +1,19 @@
/**
This file contains the BigBlueButton client APIs that will allow 3rd-party applications
to embed the Flash client and interact with it through Javascript.
HOW TO USE:
Some APIs allow synchronous and asynchronous calls. When using asynchronous, the 3rd-party
JS should register as listener for events listed at the bottom of this file. For synchronous,
3rd-party JS should pass in a callback function when calling the API.
For an example on how to use these APIs, see:
https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/resources/prod/lib/3rd-party.js
https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/resources/prod/3rd-party.html
*/
(function(window, undefined) {
var BBB = {};
@ -13,7 +29,14 @@
}
/**
* Get info if user is sharing webcam.
* Query if the current user is sharing webcam.
*
* Param:
* callback - function to return the result
*
* If you want to instead receive an event with the result, register a listener
* for AM_I_SHARING_CAM_RESP (see below).
*
*/
BBB.amISharingWebcam = function(callback) {
var swfObj = getSwfObj();
@ -29,7 +52,13 @@
}
/**
* Get my user info.
* Query if another user is sharing her camera.
*
* Param:
* userID : the id of the user that may be sharing the camera
* callback: function if you want to be informed synchronously. Don't pass a function
* if you want to be informed through an event. You have to register for
* IS_USER_PUBLISHING_CAM_RESP (see below).
*/
BBB.isUserSharingWebcam = function(userID, callback) {
var swfObj = getSwfObj();
@ -44,6 +73,16 @@
}
}
/**
* Issue a switch presenter command.
*
* Param:
* newPresenterUserID - the user id of the new presenter
*
* 3rd-party JS must listen for SWITCHED_PRESENTER (see below) to get notified
* of switch presenter events.
*
*/
BBB.switchPresenter = function(newPresenterUserID) {
var swfObj = getSwfObj();
if (swfObj) {
@ -53,10 +92,11 @@
}
/**
* Query the Flash client if user is presenter.
* Query if current user is presenter.
*
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for the response as an event.
* for AM_I_PRESENTER_RESP (see below).
*/
BBB.amIPresenter = function(callback) {
var swfObj = getSwfObj();
@ -70,12 +110,27 @@
}
}
}
/**
* Query who is presenter.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getPresenterUserID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
if (typeof callback === 'function') {
callback(swfObj.getPresenterUserID());
}
}
}
/**
* Query the Flash client for the user's role.
* Query the current user's role.
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for the response as an event.
* for GET_MY_ROLE_RESP (see below).
*/
BBB.getMyRole = function(callback) {
var swfObj = getSwfObj();
@ -91,8 +146,11 @@
}
/**
* Get external userID.
*/
* Query the current user's id.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getMyUserID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
@ -103,9 +161,12 @@
}
}
/**
* Get my user info.
*/
/**
* Query the current user's role.
* Params:
* callback - function if you want a callback as response. Otherwise, you need to listen
* for GET_MY_ROLE_RESP (see below).
*/
BBB.getMyUserInfo = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
@ -120,8 +181,11 @@
}
/**
* Get external meetingID.
*/
* Query the meeting id.
*
* Params:
* callback - function that gets executed for the response.
*/
BBB.getMeetingID = function(callback) {
var swfObj = getSwfObj();
if (swfObj) {
@ -143,6 +207,9 @@
}
}
/**
* Leave the voice conference.
*/
BBB.leaveVoiceConference = function() {
var swfObj = getSwfObj();
if (swfObj) {
@ -153,6 +220,9 @@
/**
* Share user's webcam.
*
* Params:
* publishInClient : (DO NOT USE - Unimplemented)
*/
BBB.shareVideoCamera = function(publishInClient) {
var swfObj = getSwfObj();
@ -165,34 +235,54 @@
}
}
/**
* Stop share user's webcam.
*
*/
BBB.stopSharingCamera = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.stopShareCameraRequest();
}
}
/**
* Mute the current user.
*
*/
BBB.muteMe = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.muteMeRequest();
}
}
/**
* Unmute the current user.
*
*/
BBB.unmuteMe = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.unmuteMeRequest();
}
}
/**
* Mute all the users.
*
*/
BBB.muteAll = function() {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.muteAllUsersRequest();
}
}
/**
* Unmute all the users.
*
*/
BBB.unmuteAll = function() {
var swfObj = getSwfObj();
if (swfObj) {
@ -200,13 +290,26 @@
}
}
/**
* Switch to a new layout.
*
* Param:
* newLayout : name of the layout as defined in layout.xml (found in /var/www/bigbluebutton/client/conf/layout.xml)
*
*/
BBB.switchLayout = function(newLayout) {
var swfObj = getSwfObj();
if (swfObj) {
swfObj.switchLayout(newLayout);
}
}
/**
* Lock the layout.
*
* Locking the layout means that users will have the same layout with the moderator that issued the lock command.
* Other users won't be able to move or resize the different windows.
*/
BBB.lockLayout = function(lock) {
var swfObj = getSwfObj();
if (swfObj) {
@ -242,17 +345,21 @@
swfObj.sendPrivateChatRequest(fontColor, localeLang, message, toUserID);
}
}
// Third-party JS apps should use this to query if the BBB SWF file is ready to handle calls.
BBB.isSwfClientReady = function() {
return swfReady;
}
/* ***********************************************************************************
* Broadcasting of events to 3rd-party apps.
*************************************************************************************/
/** Stores the event listeners ***/
/** Stores the 3rd-party app event listeners ***/
var listeners = {};
/**
* Register to listen for events.
* 3rd-party apps should user this method to register to listen for events.
*/
BBB.listen = function(eventName, handler) {
if (typeof listeners[eventName] === 'undefined')
@ -262,7 +369,7 @@
};
/**
* Unregister listener for event.
* 3rd-party app should use this method to unregister listener for a given event.
*/
BBB.unlisten = function(eventName, handler) {
if (!listeners[eventName])
@ -277,7 +384,7 @@
};
/**
* Private function to broadcast received event from Flash client to
* Private function to broadcast received event from the BigBlueButton Flash client to
* 3rd-parties.
*/
function broadcast(bbbEvent) {
@ -293,12 +400,51 @@
};
/**
* Function called by the Flash client to inform 3rd-parties of internal events.
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*
* DO NOT CALL THIS METHOD FROM YOUR JS CODE.
*
* This is called by the BigBlueButton Flash client to inform 3rd-parties of internal events.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
BBB.handleFlashClientBroadcastEvent = function (bbbEvent) {
console.log("Received [" + bbbEvent.eventName + "]");
broadcast(bbbEvent);
}
// Flag to indicate that the SWF file has been loaded and ready to handle calls.
var swfReady = false;
/**
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*
* DO NOT CALL THIS METHOD FROM YOUR JS CODE.
*
* This is called by the BigBlueButton Flash client to inform 3rd-parties that it is ready.
*
* WARNING:
* Doesn't actually work as intended. The Flash client calls this function when it's loaded.
* However, the client as to query the BBB server to get the status of the meeting.
* We're working on the proper way to determining that the client is TRULY ready.
*
* !!! As a workaround, 3rd-party JS on init should call getUserInfo until it return NOT NULL.
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*/
BBB.swfClientIsReady = function () {
console.log("BigBlueButton SWF is ready.");
swfReady = true;
}
/* ********************************************************************* */
@ -306,17 +452,6 @@
callback;
}
// Flag to indicate that the SWF file has been loaded and ready to handle calls.
var swfReady = false;
BBB.swfClientIsReady = function () {
console.log("BigBlueButton SWF is ready.");
swfReady = true;
}
// Third-party JS apps should use this to query if the BBB SWF file is ready to handle calls.
BBB.isSwfClientReady = function() {
return swfReady;
}
/************************************************
* EVENT NAME CONSTANTS
@ -324,27 +459,30 @@
* See https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/src/org/bigbluebutton/core/EventConstants.as
*
************************************************/
var GET_MY_ROLE_RESP = 'GetMyRoleResponse';
var AM_I_PRESENTER_RESP = 'AmIPresenterQueryResponse';
var AM_I_SHARING_CAM_RESP = 'AmISharingCamQueryResponse';
var BROADCASTING_CAM_STARTED = 'BroadcastingCameraStartedEvent';
var BROADCASTING_CAM_STOPPED = 'BroadcastingCameraStoppedEvent';
var I_AM_SHARING_CAM = 'IAmSharingCamEvent';
var CAM_STREAM_SHARED = 'CamStreamSharedEvent';
var USER_JOINED = 'UserJoinedEvent';
var USER_LEFT = 'UserLeftEvent';
var SWITCHED_PRESENTER = 'SwitchedPresenterEvent';
var NEW_PRIVATE_CHAT = 'NewPrivateChatEvent';
var NEW_PUBLIC_CHAT = 'NewPublicChatEvent';
var SWITCHED_LAYOUT = 'SwitchedLayoutEvent';
var REMOTE_LOCKED_LAYOUT = 'RemoteLockedLayoutEvent';
var REMOTE_UNLOCKED_LAYOUT = 'RemoteUnlockedLayoutEvent';
var USER_JOINED_VOICE = 'UserJoinedVoiceEvent';
var USER_LEFT_VOICE = 'UserLeftVoiceEvent';
var USER_MUTED_VOICE = 'UserVoiceMutedEvent';
var USER_TALKING = 'UserTalkingEvent';
var USER_LOCKED_VOICE = 'UserLockedVoiceEvent';
var START_PRIVATE_CHAT = 'StartPrivateChatEvent';
var GET_MY_ROLE_RESP = 'GetMyRoleResponse';
var AM_I_PRESENTER_RESP = 'AmIPresenterQueryResponse';
var AM_I_SHARING_CAM_RESP = 'AmISharingCamQueryResponse';
var BROADCASTING_CAM_STARTED = 'BroadcastingCameraStartedEvent';
var BROADCASTING_CAM_STOPPED = 'BroadcastingCameraStoppedEvent';
var I_AM_SHARING_CAM = 'IAmSharingCamEvent';
var CAM_STREAM_SHARED = 'CamStreamSharedEvent';
var USER_JOINED = 'UserJoinedEvent';
var USER_LEFT = 'UserLeftEvent';
var SWITCHED_PRESENTER = 'SwitchedPresenterEvent';
var NEW_ROLE = 'NewRoleEvent';
var NEW_PRIVATE_CHAT = 'NewPrivateChatEvent';
var NEW_PUBLIC_CHAT = 'NewPublicChatEvent';
var SWITCHED_LAYOUT = 'SwitchedLayoutEvent';
var REMOTE_LOCKED_LAYOUT = 'RemoteLockedLayoutEvent';
var REMOTE_UNLOCKED_LAYOUT = 'RemoteUnlockedLayoutEvent';
var USER_JOINED_VOICE = 'UserJoinedVoiceEvent';
var USER_LEFT_VOICE = 'UserLeftVoiceEvent';
var USER_MUTED_VOICE = 'UserVoiceMutedEvent';
var USER_TALKING = 'UserTalkingEvent';
var USER_LOCKED_VOICE = 'UserLockedVoiceEvent';
var START_PRIVATE_CHAT = "StartPrivateChatEvent";
var GET_MY_USER_INFO_REP = "GetMyUserInfoResponse";
var IS_USER_PUBLISHING_CAM_RESP = "IsUserPublishingCamResponse";
window.BBB = BBB;
})(this);

View File

@ -128,11 +128,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
{
var keyPress:String = (e.ctrlKey ? "control+" : "") + (e.shiftKey ? "shift+" : "") +
(e.altKey ? "alt+" : "") + e.keyCode;
//LogUtil.debug("Chad keypress " + keyPress);
if (keyCombos[keyPress])
{
trace("Chad keypress " + keyPress);
globalDispatcher.dispatchEvent(new ShortcutEvent(keyCombos[keyPress]));
}
}

View File

@ -38,8 +38,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import mx.containers.Canvas;
import mx.controls.Button;
import mx.controls.Image;
import mx.core.UIComponent;
import mx.controls.Label;
import mx.core.UIComponent;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.modules.deskshare.events.AppletStartedEvent;
import org.bigbluebutton.modules.deskshare.events.CursorEvent;
@ -102,52 +102,59 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
navigateToURL(url, '_self');
}
private function onDeskshareConnectionEvent(event:ConnectionEvent):void {
private function onDeskshareConnectionEvent(event:ConnectionEvent):void {
var warningText:String;
switch(event.status) {
case ConnectionEvent.SUCCESS:
progressLabel.text = "Connecting to server successful.";
warningText = "Connecting to server successful.";
break;
case ConnectionEvent.FAILED:
progressLabel.text = "Connecting to server failed.";
warningText = "Connecting to server failed.";
break;
case ConnectionEvent.CLOSED:
progressLabel.text = "Connection to server closed.";
warningText = "Connection to server closed.";
break;
case ConnectionEvent.REJECTED:
progressLabel.text = "Connection to server rejected.";
warningText = "Connection to server rejected.";
break;
case ConnectionEvent.INVALIDAPP:
progressLabel.text = "Connecting to server failed. Invalid application.";
warningText = "Connecting to server failed. Invalid application.";
break;
case ConnectionEvent.APPSHUTDOWN:
progressLabel.text = "Connection to server failed. Server shutting down.";
warningText = "Connection to server failed. Server shutting down.";
break;
case ConnectionEvent.SECURITYERROR:
progressLabel.text = "Connecting to server failed. Security error.";
warningText = "Connecting to server failed. Security error.";
break;
case ConnectionEvent.DISCONNECTED:
progressLabel.text = "Connection to server disconnected.";
warningText = "Connection to server disconnected.";
break;
case ConnectionEvent.CONNECTING:
progressLabel.text = "Connecting to server.";
warningText = "Connecting to server...";
break;
case ConnectionEvent.CONNECTING_RETRY:
progressLabel.text = "Connecting to server. Retry [" + event.retryAttempts + "]";
warningText = "Connecting to server failed. Retry [" + event.retryAttempts + "]";
break;
case ConnectionEvent.CONNECTING_MAX_RETRY:
progressLabel.text = "Connecting to server. Max retry reached.";
warningText = "Connecting to server failed. Max retry reached. Giving up.";
break;
case ConnectionEvent.CHECK_FOR_DESKSHARE_STREAM:
warningText = "Loading...";
break;
case ConnectionEvent.FAIL_CHECK_FOR_DESKSHARE_STREAM:
warningText = "Loading shared desktop failed.";
break;
case ConnectionEvent.NO_DESKSHARE_STREAM:
warningText = "Desktop is not shared.";
break;
}
trace("DeskshareSA::Connecting to server.");
showStatusText(warningText, true, "0x000000");
trace("CONNECT STATUS EVENT [" + event.status + "]");
}
private function onConnectingToServerRetry(event:ConnectionEvent):void {
progressLabel.text = "Connecting to server timedout. Retrying.";
trace("DeskshareSA::Connecting to server timedout. Retrying.");
}
private function startVideo(connection:NetConnection, stream:String, videoWidth:Number, videoHeight:Number):void{
ns = new NetStream(connection);
ns.addEventListener( NetStatusEvent.NET_STATUS, onNetStatus );
@ -166,18 +173,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
trace("DeskshareSA::Determine how to display video = [" + videoWidth + "x" + videoHeight + "] display=[" + this.width + "x" + this.height + "]");
determineHowToDisplayVideo();
// calculateDisplayDimensions(video, videoHolder);
// videoHolder.addChild(video);
// videoHolder.addChild(cursor);
// videoHolder.addChild(cursorImg);
// centerVideo();
ns.play(stream);
this.stream = stream;
// vbox.addChild(videoHolder);
}
private function onMetaData(info:Object):void {
@ -194,16 +192,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
}
private function onUpdateCursorEvent(event:CursorEvent):void {
private function onUpdateCursorEvent(event:CursorEvent):void {
if (cursor == null) return;
// cursor.x = ((event.x/video.videoWidth)) * videoHolder.width;
// cursor.y = ((event.y/video.videoHeight)) * videoHolder.height;
cursor.x = videoHolder.x + (event.x * (videoHolder.width / videoWidth));
cursor.y = videoHolder.y + (event.y * (videoHolder.height / videoHeight));
// cursor.visible = true;
cursorImg.visible = true;
// DO NOT compute the x and y coordinate and assign directly to the cursorImg
@ -222,16 +216,26 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function onNetStatus(e:NetStatusEvent):void{
switch(e.info.code){
case "NetStream.Play.Start":
trace("DeskshareSA::NetStream.Publish.Start for broadcast stream " + stream);
trace("DeskshareSA::Dispatching start viewing event");
service.sendStartedViewingNotification();
break;
case "NetStream.Play.UnpublishNotify":
trace("DeskshareSA::NetStream.Play.UnpublishNotify for broadcast stream " + stream);
stopViewing();
break;
}
case "NetStream.Play.Start":
trace("DeskshareSA::NetStream.Publish.Start for broadcast stream " + stream);
trace("DeskshareSA::Dispatching start viewing event");
service.sendStartedViewingNotification();
break;
case "NetStream.Play.UnpublishNotify":
trace("DeskshareSA::NetStream.Play.UnpublishNotify for broadcast stream " + stream);
stopViewing();
break;
case "NetStream.DRM.UpdateNeeded":
case "NetStream.Play.Failed":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
case "NetStream.Play.StreamNotFound":
// case "NetStream.Play.Reset":
showStatusText(e.info.code, true, "0x000000");
break;
}
trace("NET STATUS EVENT [" + e.info.code + "]");
}
//----------------------------
@ -240,10 +244,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
videoHolder.height = video.height = videoHeight;
videoHolder.x = video.x = (this.width - video.width) / 4;
videoHolder.y = video.y = (this.height - video.height) / 4;
// videoHolder.x = video.x = 0;
// videoHolder.y = video.y = 0;
trace("DeskshareSA::Center video = [" + video.width + "x" + video.height
+ "] display=[" + this.width + "x" + this.height + "]"
+ "loc=[" + videoHolder.x + "," + videoHolder.y + "]");
@ -252,7 +253,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
videoHolder.addChild(cursor);
videoHolder.addChild(cursorImg);
addChild(videoHolder);
showVideoHolder();
}
private function fitVideoToWindow():void {
@ -283,7 +284,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
videoHolder.addChild(cursor);
videoHolder.addChild(cursorImg);
addChild(videoHolder);
showVideoHolder();
}
private function fitToHeightAndAdjustWidthToMaintainAspectRatio():void {
@ -308,9 +309,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
videoHolder.addChild(cursor);
videoHolder.addChild(cursorImg);
addChild(videoHolder);
showVideoHolder();
}
private function showVideoHolder():void {
addChild(videoHolder);
}
private function determineHowToDisplayVideo():void {
// if (videoIsSmallerThanWindow()) {
// trace("Video is smaller than window. Centering.");
@ -319,13 +324,35 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
// trace("Video is greater than window. Scaling.");
// fitVideoToWindow();
// }
}
private var hideStatusTextTimer:Timer = null;
private function showStatusText(statusText:String, autoHide:Boolean=false, color:String="0xFF0000"):void {
if (hideStatusTextTimer != null)
hideStatusTextTimer.stop();
if (autoHide) {
hideStatusTextTimer = new Timer(3000, 1);
hideStatusTextTimer.addEventListener(TimerEvent.TIMER, hideStatusText);
hideStatusTextTimer.start();
}
// bring the label to front
setChildIndex(statusTextDisplay, getChildren().length - 1);
statusTextDisplay.text = statusText;
statusTextDisplay.setStyle("color", color);
statusTextDisplay.visible = true;
}
private function hideStatusText(e:TimerEvent):void {
statusTextDisplay.visible = false;
}
]]>
</mx:Script>
<mx:Image id="cursorImg" visible="false" source="@Embed('org/bigbluebutton/modules/deskshare/assets/images/cursor4.png')"/>
<!--
<mx:Canvas id="vbox" width="100%" height="100%" backgroundColor="blue"/>
-->
<mx:Label id="progressLabel" text="FOOOOOOO!!!!!" width="100%" height="30" x="100" y="100" color="red"/>
<mx:Fade id="dissolveOut" duration="1000" alphaFrom="1.0" alphaTo="0.0"/>
<mx:Fade id="dissolveIn" duration="1000" alphaFrom="0.0" alphaTo="1.0"/>
<mx:Text id="statusTextDisplay" width="100%" fontSize="14" fontWeight="bold" textAlign="center" y="{(this.height - statusTextDisplay.height) / 2}"
visible="false" selectable="false" hideEffect="{dissolveOut}" showEffect="{dissolveIn}"/>
</mx:Application>

View File

@ -0,0 +1,124 @@
<?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:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
implements="org.bigbluebutton.common.IBigBlueButtonModule"
xmlns:polling="org.bigbluebutton.modules.polling.*"
xmlns:maps="org.bigbluebutton.modules.polling.maps.*"
creationComplete="onCreationComplete()">
<maps:PollingEventMap id="eventMap"/>
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import com.asfusion.mate.events.Dispatcher;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.modules.polling.events.ModuleEvent;
import org.bigbluebutton.modules.polling.views.PollingViewWindow;
import org.bigbluebutton.modules.polling.managers.PollingManager;
import org.bigbluebutton.modules.polling.maps.PollingEventMap;
private var _moduleName:String = "Polling";
private var _attributes:Object;
public var globalDispatcher:Dispatcher = new Dispatcher();
public static const LOGNAME:String = "[PollingModule] ";
private function onCreationComplete():void {
LogUtil.debug(LOGNAME + "initialized");
}
public function get moduleName():String {
return _moduleName;
}
public function get uri():String{
if (_attributes.mode == "PLAYBACK")
return _attributes.uri + "/" + _attributes.playbackRoom;
return _attributes.uri + "/" + _attributes.room;
}
public function get username():String {
return _attributes.username;
}
public function get connection():NetConnection {
return _attributes.connection;
}
public function getRoom():String{
return _attributes.room;
}
public function get userid():Number {
return _attributes.userid as Number;
}
public function get role():String {
return _attributes.userrole as String;
}
public function start(attributes:Object):void {
LogUtil.debug(LOGNAME +" started [Username: " + attributes.username + " Role: " +attributes.userrole + " Room:" +attributes.room+ "]" );
_attributes = attributes;
//eventMap.module = this;
LogUtil.debug(LOGNAME + "inside start() dispatching ModuleEvent");
var startEvent:ModuleEvent = new ModuleEvent(ModuleEvent.START);
startEvent.module = this;
globalDispatcher.dispatchEvent(startEvent);
}
public function stop():void {
LogUtil.debug(LOGNAME + "STOPPING Polling MODULE");
}
public function getMeetingInfo():String{
return getMeetingInfo();
}
]]>
</mx:Script>
</mx:Module>

View File

@ -58,7 +58,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
trace("WebcamPreviewSA:: Security.allowDomain(" + determineHTMLURL() + ");");
initExternalInterface();
// displayCamera("0", 30, 10, 0, 90);
callWebcamPreviewStandaloneReady();
}
private function determineHTMLURL():String {
@ -84,6 +84,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
}
private function callWebcamPreviewStandaloneReady():void {
if (ExternalInterface.available) {
ExternalInterface.call("webcamPreviewStandaloneAppReady");
}
}
private function handleStartPreviewCameraRequest(camIndex:String, camWidth:int, camHeight:int,
camKeyFrameInterval:int, camModeFps:Number,
camQualityBandwidth:int, camQualityPicture:int):void {

View File

@ -67,6 +67,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
trace("WebcamViewSA:: Security.allowDomain(" + determineHTMLURL() + ");");
initExternalInterface();
callWebcamViewStandaloneReady();
}
private function determineHTMLURL():String {
@ -92,6 +93,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
}
private function callWebcamViewStandaloneReady():void {
if (ExternalInterface.available) {
ExternalInterface.call("webcamViewStandaloneAppReady");
}
}
private function connect(url:String):void {
nc = new NetConnection();
nc.client = this;

View File

@ -248,7 +248,9 @@ package org.bigbluebutton.common
public var arrow_in:Class;
[Embed(source="assets/images/shape_handles.png")]
public var shape_handles:Class;
public var shape_handles:Class;
[Embed(source="assets/images/poll_icon.png")]
public var pollIcon:Class;
[Embed(source="assets/images/disk.png")]
public var disk:Class;

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

View File

@ -28,6 +28,15 @@ package org.bigbluebutton.core
public class UsersUtil
{
public static function getPresenterUserID():String {
var presenter:BBBUser = UserManager.getInstance().getConference().getPresenter();
if (presenter != null) {
return presenter.userID;
}
return "";
}
public static function amIPublishing():CameraSettingsVO {
return UserManager.getInstance().getConference().amIPublishing();
}

View File

@ -19,6 +19,7 @@
package org.bigbluebutton.core.managers {
import mx.collections.ArrayCollection;
import org.bigbluebutton.main.model.users.Conference;
import org.bigbluebutton.main.model.users.BBBUser;
/**
* The UserManager allows you to interact with the user data of those currently logged in to the conference.
@ -57,8 +58,7 @@ package org.bigbluebutton.core.managers {
public function getConference():Conference{
return this.conference;
}
}
}
class SingletonEnforcer{}
class SingletonEnforcer{}

View File

@ -56,6 +56,7 @@ package org.bigbluebutton.main.api
ExternalInterface.addCallback("switchPresenterRequest", handleSwitchPresenterRequest);
ExternalInterface.addCallback("getMyUserInfoSync", handleGetMyUserInfoSynch);
ExternalInterface.addCallback("getMyUserInfoAsync", handleGetMyUserInfoAsynch);
ExternalInterface.addCallback("getPresenterUserID", handleGetPresenterUserID);
ExternalInterface.addCallback("getMyUserID", handleGetMyUserID);
ExternalInterface.addCallback("getExternalMeetingID", handleGetExternalMeetingID);
ExternalInterface.addCallback("joinVoiceRequest", handleJoinVoiceRequest);
@ -179,6 +180,15 @@ package org.bigbluebutton.main.api
return UsersUtil.internalUserIDToExternalUserID(UsersUtil.getMyUserID());
}
private function handleGetPresenterUserID():String {
var presUserID:String = UsersUtil.getPresenterUserID();
if (presUserID != "") {
return UsersUtil.internalUserIDToExternalUserID(presUserID);
}
// return an empty string. Meeting has no presenter.
return "";
}
private function handleGetExternalMeetingID():String {
return UserManager.getInstance().getConference().externalMeetingID;
}
@ -303,9 +313,8 @@ package org.bigbluebutton.main.api
private function handleJoinVoiceRequest():void {
trace("handleJoinVoiceRequest");
var joinEvent:BBBEvent = new BBBEvent("JOIN_VOICE_CONFERENCE_EVENT");
joinEvent.payload['useMicrophone'] = true;
_dispatcher.dispatchEvent(joinEvent);
var showMicEvent:BBBEvent = new BBBEvent("SHOW_MIC_SETTINGS");
_dispatcher.dispatchEvent(showMicEvent);
}
private function handleLeaveVoiceRequest():void {

View File

@ -174,7 +174,7 @@ package org.bigbluebutton.main.api
public function handleGetMyRoleResponse(event:CoreEvent):void {
var payload:Object = new Object();
payload.eventName = EventConstants.GET_MY_ROLE_RESP;
payload.myRole = event.message.myRole;
payload.myRole = UserManager.getInstance().getConference().whatsMyRole();
broadcastEvent(payload);
}

View File

@ -23,6 +23,7 @@ package org.bigbluebutton.main.model.users
import mx.collections.ArrayCollection;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.common.Role;
import org.bigbluebutton.main.model.users.events.StreamStartedEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
@ -106,6 +107,7 @@ package org.bigbluebutton.main.model.users
}
[Bindable] public var voiceLocked:Boolean = false;
[Bindable] public var status:String = "";
/*
* This variable is for accessibility for the Participants Window. It can't be manually set
@ -150,15 +152,20 @@ package org.bigbluebutton.main.model.users
}
private var _status:StatusCollection = new StatusCollection();
public function get status():ArrayCollection {
return _status.getAll();
}
public function set status(s:ArrayCollection):void {
_status.status = s;
}
public function buildStatus():void{
var showingWebcam:String = "";
var isPresenter:String = "";
var handRaised:String = "";
if (hasStream)
showingWebcam = ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.streamIcon.toolTip');
if (presenter)
isPresenter = ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.presIcon.toolTip');
if (raiseHand)
handRaised = ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.raiseHand.toolTip');
status = showingWebcam + isPresenter + handRaised;
}
public function addStatus(status:Status):void {
_status.addStatus(status);
}
@ -195,6 +202,7 @@ package org.bigbluebutton.main.model.users
raiseHand = status.value as Boolean;
break;
}
buildStatus();
}
public function removeStatus(name:String):void {

View File

@ -107,6 +107,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private var receivedConfigLocaleVer:Boolean = false;
private var receivedResourceLocaleVer:Boolean = false;
private var glossaryOpen:Boolean = false;
public function get mode():String {
return _mode;
@ -207,11 +208,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (scWindow == null) {
scWindow = new ShortcutHelpWindow();
}
mdiCanvas.windowManager.add(scWindow);
mdiCanvas.windowManager.absPos(scWindow, mdiCanvas.width/2 - 150, mdiCanvas.height/2 - 150);
scWindow.width = 300;
scWindow.height = 300;
scWindow.focusCategories();
if (!glossaryOpen){
mdiCanvas.windowManager.add(scWindow);
mdiCanvas.windowManager.absPos(scWindow, mdiCanvas.width/2 - 150, mdiCanvas.height/2 - 150);
scWindow.width = 300;
scWindow.height = 300;
scWindow.focusCategories();
}
else
mdiCanvas.windowManager.remove(scWindow);
glossaryOpen = !glossaryOpen;
}
private function toggleFullScreen():void{

View File

@ -51,21 +51,20 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private var shownKeys:ArrayCollection;
private function onCreationComplete():void {
LogUtil.debug("WATERFALL: Shortcut window has been opened");
reloadKeys();
ResourceUtil.getInstance().addEventListener(Event.CHANGE, reloadKeys); // Listen for locale changing
}
private function reloadKeys(e:Event = null):void {
LogUtil.debug("Chad start of function");
// LogUtil.debug("Chad start of function");
genKeys = loadKeys(genResource);
LogUtil.debug("CHAD loaded" + genKeys);
// LogUtil.debug("CHAD loaded" + genKeys);
presKeys = loadKeys(presResource);
LogUtil.debug("CHAD loaded" + presKeys.length);
// LogUtil.debug("CHAD loaded" + presKeys.length);
chatKeys = loadKeys(chatResource);
LogUtil.debug("CHAD loaded" + chatKeys.length);
// LogUtil.debug("CHAD loaded" + chatKeys.length);
audKeys = loadKeys(audResource);
LogUtil.debug("CHAD loaded" + audKeys.length);
// LogUtil.debug("CHAD loaded" + audKeys.length);
changeArray();
}
@ -118,9 +117,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
return keyList;
}
public function focusCategories():void {
focusManager.setFocus(categories);
categories.drawFocus(true);
public function focusCategories():void { //actually focuses the datagrid instead
focusManager.setFocus(keyList);
keyList.drawFocus(true);
}
]]>
</mx:Script>

View File

@ -47,6 +47,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function init():void{
users = UserManager.getInstance().getConference().users;
}
public function accessibleClick(event:KeyboardEvent):void{
if (event.keyCode == 32){
openPrivateChat(event);
}
}
protected function openPrivateChat(event:Event):void{
if (usersList.selectedIndex == -1) return;

View File

@ -343,11 +343,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
}
public function handleKeyDown(e:KeyboardEvent) :void {
// LogUtil.debug("WATERFALL: Entering handleKeyDown");
var keyPress:String = (e.ctrlKey ? "control+" : "") + (e.shiftKey ? "shift+" : "") + (e.altKey ? "alt+" : "") + e.keyCode;
// LogUtil.debug("WATERFALL keypress: " + keyPress);
var keyPress:String = (e.ctrlKey ? "control+" : "") + (e.shiftKey ? "shift+" : "") + (e.altKey ? "alt+" : "") + e.keyCode;
if (keyCombos[keyPress]) {
// LogUtil.debug("WATERFALL keypress matched something in keyCombos: " + keyCombos[keyPress]);
var event:ShortcutEvent = new ShortcutEvent(keyCombos[keyPress]);
event.otherUserID = chatWithUserID;
globalDispatcher.dispatchEvent(event);

View File

@ -274,6 +274,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
tabBox.label = TAB_BOX_ID;
tabBox.name = TAB_BOX_ID;
tabBox.chatOptions = chatOptions;
tabBox.addEventListener(KeyboardEvent.KEY_DOWN, tabBox.accessibleClick);
chatTabs.addChild(tabBox);
return tabBox;

View File

@ -16,29 +16,29 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.modules.deskshare.services
{
import com.asfusion.mate.events.Dispatcher;
import flash.net.NetConnection;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.deskshare.services.red5.Connection;
/**
* The DeskShareProxy communicates with the Red5 deskShare server application
* @author Snap
*
*/
public class DeskshareService
{
private var conn:Connection;
package org.bigbluebutton.modules.deskshare.services
{
import com.asfusion.mate.events.Dispatcher;
import flash.net.NetConnection;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.deskshare.services.red5.Connection;
/**
* The DeskShareProxy communicates with the Red5 deskShare server application
* @author Snap
*
*/
public class DeskshareService
{
private var conn:Connection;
private var module:DeskShareModule;
private var dispatcher:Dispatcher;
private var uri:String;
private var room:String;
public function DeskshareService() {
this.dispatcher = new Dispatcher();
}
@ -52,28 +52,28 @@ package org.bigbluebutton.modules.deskshare.services
public function connect(uri:String, room:String):void {
this.uri = uri;
this.room = room;
trace("Deskshare Service connecting to " + uri);
conn = new Connection(room);
conn.setURI(uri);
conn.connect();
}
trace("Deskshare Service connecting to " + uri);
conn = new Connection(room);
conn.setURI(uri);
conn.connect();
}
public function getConnection():NetConnection{
return conn.getConnection();
}
public function disconnect():void{
conn.disconnect();
}
}
public function sendStartViewingNotification(captureWidth:Number, captureHeight:Number):void{
conn.sendStartViewingNotification(captureWidth, captureHeight);
}
}
public function sendStartedViewingNotification():void{
conn.sendStartedViewingNotification();
}
}
}
}
}

View File

@ -20,20 +20,23 @@
package org.bigbluebutton.modules.deskshare.services.red5
{
import com.asfusion.mate.events.Dispatcher;
import flash.net.Responder;
import flash.net.SharedObject;
import flash.events.EventDispatcher;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.TimerEvent;
import flash.net.NetConnection;
import flash.net.ObjectEncoding;
import flash.net.Responder;
import flash.net.SharedObject;
import flash.utils.Timer;
import org.bigbluebutton.modules.deskshare.events.AppletStartedEvent;
import org.bigbluebutton.modules.deskshare.events.CursorEvent;
import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
import mx.events.MetadataEvent;
import mx.events.MetadataEvent;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.deskshare.events.AppletStartedEvent;
import org.bigbluebutton.modules.deskshare.events.CursorEvent;
import org.bigbluebutton.modules.deskshare.events.ViewStreamEvent;
public class Connection {
@ -67,9 +70,15 @@ package org.bigbluebutton.modules.deskshare.services.red5
dispatcher.dispatchEvent(event);
} else {
trace("No deskshare stream being published");
var connEvent:ConnectionEvent = new ConnectionEvent();
connEvent.status = ConnectionEvent.NO_DESKSHARE_STREAM;
dispatcher.dispatchEvent(connEvent);
}
},
function(status:Object):void{
var checkFailedEvent:ConnectionEvent = new ConnectionEvent();
checkFailedEvent.status = ConnectionEvent.FAIL_CHECK_FOR_DESKSHARE_STREAM;
dispatcher.dispatchEvent(checkFailedEvent);
trace("Error while trying to call remote mathod on server");
}
);
@ -233,8 +242,12 @@ package org.bigbluebutton.modules.deskshare.services.red5
* This method is useful for clients which have joined a room where somebody is already publishing
*
*/
private function checkIfStreamIsPublishing(room:String):void{
private function checkIfStreamIsPublishing(room: String):void{
trace("checking if desk share stream is publishing");
var event:ConnectionEvent = new ConnectionEvent();
event.status = ConnectionEvent.CHECK_FOR_DESKSHARE_STREAM;
dispatcher.dispatchEvent(event);
nc.call("deskshare.checkIfStreamIsPublishing", responder, room);
}

View File

@ -35,6 +35,9 @@ package org.bigbluebutton.modules.deskshare.services.red5
public static const CONNECTING:String = "connection connecting";
public static const CONNECTING_RETRY:String = "connection retry";
public static const CONNECTING_MAX_RETRY:String = "connection max retry";
public static const CHECK_FOR_DESKSHARE_STREAM:String = "connection check deskshare publishing";
public static const NO_DESKSHARE_STREAM:String = "connection deskshare publishing";
public static const FAIL_CHECK_FOR_DESKSHARE_STREAM:String = "connection failed check deskshare publishing";
public var status:String = "";

View File

@ -224,9 +224,8 @@ package org.bigbluebutton.modules.listeners.business
}
}
public function userTalk(userId:Number, talk:Boolean) : void
{
trace("User talking event");
public function userTalk(userId:Number, talk:Boolean):void {
trace("ListenersSOService:: User talking event userID=[" + userId + "] talking=[" + talk + "]");
var l:Listener = _listeners.getListener(userId);
if (l != null) {
l.talking = talk;
@ -242,19 +241,20 @@ package org.bigbluebutton.modules.listeners.business
}
}
public function userLeft(userId:Number):void
{
_listeners.removeListener(userId);
public function userLeft(userID:Number):void {
// Set the user to not talking. This will update UIs that depend on the user talking state.
userTalk(userID, false);
/**
* Let's store the voice userid so we can do push to talk.
*/
if (UserManager.getInstance().getConference().amIThisVoiceUser(userId)) {
if (UserManager.getInstance().getConference().amIThisVoiceUser(userID)) {
UserManager.getInstance().getConference().setMyVoiceJoined(false);
UserManager.getInstance().getConference().setMyVoiceUserId(0);
UserManager.getInstance().getConference().setMyVoiceJoined(false);
}
var bu:BBBUser = UsersUtil.getVoiceUser(userId)
var bu:BBBUser = UsersUtil.getVoiceUser(userID)
if (bu != null) {
bu.voiceUserid = 0;
bu.voiceMuted = false;
@ -264,6 +264,8 @@ package org.bigbluebutton.modules.listeners.business
bbbEvent.payload.userID = bu.userID;
globalDispatcher.dispatchEvent(bbbEvent);
}
_listeners.removeListener(userID);
}
public function ping(message:String):void {
@ -486,4 +488,4 @@ package org.bigbluebutton.modules.listeners.business
_soErrors.push(error);
}
}
}
}

View File

@ -0,0 +1,42 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class GenerateWebKeyEvent extends Event
{
public static const GENERATE:String = "GENERATE_WEB_KEY";
public static const RETURN:String = "RETURN_TO_INSTRUCTIONS_WINDOW";
public var repost:Boolean;
public var pollKey:String;
public var poll:PollObject;
public var webHostIP:String;
public var webHostPort:String;
public function GenerateWebKeyEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,39 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.common.IBigBlueButtonModule;
public class ModuleEvent extends Event
{
public static const START:String = "Polling Module Start Event";
public static const STOP:String = "Polling Module Stop Event";
public var module:IBigBlueButtonModule;
public function ModuleEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
this.module = module;
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class OpenSavedPollEvent extends Event
{
public static const OPEN:String = "OPEN_POLL_SAVED_POLL";
public var pollKey:String;
public var poll:PollObject;
public function OpenSavedPollEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,39 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollGetPollEvent extends Event
{
public static const INIT:String = "INIT_GET_POLL";
public static const GET:String = "GET_GET_POLL";
public static const RETURN:String = "RETURN_GET_POLL";
public var pollKey:String;
public var poll:PollObject;
public function PollGetPollEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject()
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollGetStatusEvent extends Event
{
public static const UPDATE:String = "UPDATE_GET_STATUS";
public var statusList:Array;
public function PollGetStatusEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollGetTitlesEvent extends Event
{
public static const INIT:String = "INIT_GET_TITLES";
public static const UPDATE:String = "UPDATE_GET_TITLES";
public static const CHECK:String = "GET_TITLES_CHECK";
public static const RETURN:String = "GET_TITLES_RETURN";
public var titleList:Array;
public function PollGetTitlesEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,38 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollRefreshEvent extends Event
{
public static const REFRESH:String = "REFRESH_REFRESH";
public static const GET:String = "GET_REFRESH";
public var pollKey:String;
public var poll:PollObject
public function PollRefreshEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollReturnStatusEvent extends Event
{
public static const UPDATE:String = "UPDATE_RETURN_STATUS";
public var statusList:Array;
public function PollReturnStatusEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollReturnTitlesEvent extends Event
{
public static const UPDATE:String = "UPDATE_RETURN_TITLES";
public var titleList:Array;
public function PollReturnTitlesEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollingInstructionsWindowEvent extends Event
{
public static const OPEN:String = "OPEN_POLLING_INSTRUCTIONS_WINDOW";
public static const CLOSE:String = "CLOSE_POLLING_INSTRUCTIONS_WINDOW";
public function PollingInstructionsWindowEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,38 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollingStatsWindowEvent extends Event
{
public static const OPEN:String = "OPEN_POLLING_STATS_WINDOW";
public static const CLOSE:String = "CLOSE_POLLING_STATS_WINDOW";
public var poll:PollObject;
public function PollingStatsWindowEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class PollingStatusCheckEvent extends Event
{
public static const CHECK:String = "CHECK_STATUS_CHECK";
public var allowed:Boolean;
public function PollingStatusCheckEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,38 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollingViewWindowEvent extends Event
{
public static const OPEN:String = "OPEN_POLLING_VIEW_WINDOW";
public static const CLOSE:String = "CLOSE_POLLING_VIEW_WINDOW";
public var poll:PollObject;
public function PollingViewWindowEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PublishPollEvent extends Event
{
public static const PUBLISH:String = "PUBLISH_POLL_PUBLISH";
public static const REPOST:String = "REPOST_POLL_PUBLISH";
public var poll:PollObject;
public function PublishPollEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class ReviewResultsEvent extends Event
{
public static const REVIEW:String = "REVIEW_RESULTS_REVIEW";
public var pollKey:String;
public var poll:PollObject;
public function ReviewResultsEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,36 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class SavePollEvent extends Event
{
public static const SAVE:String = "SAVE_POLL";
public var poll:PollObject;
public function SavePollEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,33 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class StartPollingEvent extends Event
{
public static const START:String = "START_POLL";
public function StartPollingEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,37 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
import org.bigbluebutton.modules.polling.model.PollObject;
public class StopPollEvent extends Event
{
public static const STOP_POLL:String = "STOP_POLL";
public var pollKey : String;
public var poll:PollObject;
public function StopPollEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
poll = new PollObject();
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,36 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.events
{
import flash.events.Event;
public class VoteEvent extends Event
{
public static const START:String = "VOTE_START";
public var answerID : Array;
public var pollKey : String;
public var title : String;
public function VoteEvent(type: String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}

View File

@ -0,0 +1,257 @@
package org.bigbluebutton.modules.polling.managers
{
import com.asfusion.mate.events.Dispatcher;
import mx.collections.ArrayCollection;
import org.bigbluebutton.modules.polling.views.PollingInstructionsWindow;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.IBbbModuleWindow;
import org.bigbluebutton.modules.polling.events.*;
import org.bigbluebutton.modules.polling.service.PollingService;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.model.users.Conference
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.common.Role;
public class PollingManager
{
public static const LOGNAME:String = "[PollingManager] ";
public var toolbarButtonManager:ToolbarButtonManager;
private var module:PollingModule;
private var globalDispatcher:Dispatcher;
private var service:PollingService;
private var viewWindowManager:PollingWindowManager;
private var isPolling:Boolean = false;
public var pollKey:String;
public var participants:int;
private var conference:Conference;
public function PollingManager()
{
LogUtil.debug(LOGNAME +" Building PollingManager");
service = new PollingService();
toolbarButtonManager = new ToolbarButtonManager();
globalDispatcher = new Dispatcher();
viewWindowManager = new PollingWindowManager(service);
}
//Starting Module
public function handleStartModuleEvent(module:PollingModule):void {
LogUtil.debug(LOGNAME + "Polling Module starting");
this.module = module;
service.handleStartModuleEvent(module);
}
// Acting on Events when user SWITCH TO/FROM PRESENTER-VIEWER
//#####################################################################################
public function handleMadePresenterEvent(e:MadePresenterEvent):void{
LogUtil.debug(LOGNAME +" Adding Polling Menu");
toolbarButtonManager.addToolbarButton();
}
public function handleMadeViewerEvent(e:MadePresenterEvent):void{
toolbarButtonManager.removeToolbarButton();
}
//######################################################################################
// Handling Window Events
//#####################################################################################
//Sharing Polling Window
public function handleStartPollingEvent(e:StartPollingEvent):void{
toolbarButtonManager.enableToolbarButton();
}
//##################################################################################
// Closing Instructions Window
public function handleClosePollingInstructionsWindowEvent(e:PollingInstructionsWindowEvent):void {
viewWindowManager.handleClosePollingInstructionsWindow(e);
toolbarButtonManager.enableToolbarButton();
}
//Opening Instructions Window
public function handleOpenPollingInstructionsWindowEvent(e:PollingInstructionsWindowEvent):void {
if (toolbarButtonManager.appFM == null)
LogUtil.debug("WATERFALL In Polling Manager, TBM's appFM is null");
viewWindowManager.appFM = toolbarButtonManager.appFM;
viewWindowManager.handleOpenPollingInstructionsWindow(e);
}
// Checking the polling status to prevent a presenter from publishing two polls at a time
public function handleCheckStatusEvent(e:PollingStatusCheckEvent):void{
viewWindowManager.handleCheckStatusEvent(e);
}
//##################################################################################
// Opening PollingViewWindow
public function handleOpenPollingViewWindow(e:PollingViewWindowEvent):void{
if(isPolling) return;
LogUtil.debug("WATERFALL: PollingManager sending voting signal");
viewWindowManager.handleOpenPollingViewWindow(e);
toolbarButtonManager.disableToolbarButton();
}
// Closing PollingViewWindow
public function handleClosePollingViewWindow(e:PollingViewWindowEvent):void{
viewWindowManager.handleClosePollingViewWindow(e);
toolbarButtonManager.enableToolbarButton();
}
// Stop polling, close all viewer's poll windows, and delete the web key if the poll in question has been published to the web
public function handleStopPolling(e:StopPollEvent):void{
if (e.poll.publishToWeb){
service.cutOffWebPoll(e.poll);
}
viewWindowManager.handleStopPolling(e);
service.closeAllPollingWindows();
}
//##################################################################################
public function handleSavePollEvent(e:SavePollEvent):void
{
e.poll.room = module.getRoom();
service.savePoll(e.poll);
}
public function handlePublishPollEvent(e:PublishPollEvent):void
{
if (!service.getPollingStatus() && (e.poll.title != null)){
e.poll.room = module.getRoom();
service.publish(e.poll);
}
}
public function handleRepostPollEvent(e:PublishPollEvent):void
{
for (var v:int = 0; v < e.poll.votes.length; v++){
e.poll.votes[v] = 0;
}
e.poll.totalVotes = 0;
participants = 0;
var p:BBBUser;
conference = UserManager.getInstance().getConference();
for (var i:int = 0; i < conference.users.length; i++) {
p = conference.users.getItemAt(i) as BBBUser;
if (p.role != Role.MODERATOR) {
participants++;
}
}
e.poll.didNotVote = participants;
e.poll.room = module.getRoom();
service.publish(e.poll);
}
public function handleVoteEvent(e:VoteEvent):void
{
e.pollKey = module.getRoom() +"-"+ e.title;
service.vote(e.pollKey, e.answerID);
}
public function handleGenerateWebKeyEvent(e:GenerateWebKeyEvent):void
{
e.poll.room = module.getRoom();
e.pollKey = e.poll.room +"-"+ e.poll.title;
service.generate(e);
}
public function handleReturnWebKeyEvent(e:GenerateWebKeyEvent):void
{
viewWindowManager.handleReturnWebKeyEvent(e);
}
//##################################################################################
// Opening PollingStatsWindow
public function handleOpenPollingStatsWindow(e:PollingStatsWindowEvent):void{
e.poll.room = module.getRoom();
viewWindowManager.handleOpenPollingStatsWindow(e);
}
// Closing PollingStatsWindow
public function handleClosePollingStatsWindow(e:PollingStatsWindowEvent):void{
viewWindowManager.handleClosePollingStatsWindow(e);
}
// Refreshing PollingStatsWindow
public function handleRefreshPollingStatsWindow(e:PollRefreshEvent):void{
viewWindowManager.handleRefreshPollingStatsWindow(e);
}
public function handleGetPollingStats(e:PollRefreshEvent):void{
e.poll.room = module.getRoom();
e.pollKey = e.poll.room +"-"+ e.poll.title ;
service.getPoll(e.pollKey, "refresh");
}
//##################################################################################
// Make a call to the service to update the list of titles and statuses for the Polling Menu
public function handleInitializePollMenuEvent(e:PollGetTitlesEvent):void{
toolbarButtonManager.button.roomID = module.getRoom();
service.initializePollingMenu(module.getRoom());
}
public function handleUpdateTitlesEvent(e:PollGetTitlesEvent):void{
toolbarButtonManager.button.roomID = module.getRoom();
service.updateTitles();
}
public function handleReturnTitlesEvent(e:PollReturnTitlesEvent):void{
toolbarButtonManager.button.titleList = e.titleList;
}
public function handleGetPollEvent(e:PollGetPollEvent):void{
service.getPoll(e.pollKey, "menu");
}
public function handlePopulateMenuEvent(e:PollGetPollEvent):void{
toolbarButtonManager.button.pollList.addItem(e.poll);
}
public function handleReturnPollEvent(e:PollGetPollEvent):void{
var unique:Boolean = true;
if (toolbarButtonManager.button.pollList.length != null){
for (var i:int = 0; i < toolbarButtonManager.button.pollList.length; i++){
var listKey:String = toolbarButtonManager.button.pollList.getItemAt(i).room+"-"+toolbarButtonManager.button.pollList.getItemAt(i).title;
if (e.pollKey == listKey){
unique = false;
// Delete and replace the offending poll
toolbarButtonManager.button.pollList.setItemAt(e.poll, i);
} // _compare pollKeys
} // _for-loop
} // _if pollList is null
if (unique){
toolbarButtonManager.button.pollList.addItem(e.poll);
}
}
public function handleCheckTitlesEvent(e:PollGetTitlesEvent):void{
if (e.type == PollGetTitlesEvent.CHECK){
service.checkTitles();
}
else if (e.type == PollGetTitlesEvent.RETURN){
viewWindowManager.handleCheckTitlesInInstructions(e);
}
}
//##################################################################################
public function handleOpenSavedPollEvent(e:OpenSavedPollEvent):void{
viewWindowManager.handleOpenPollingInstructionsWindowWithExistingPoll(e);
}
public function handleReviewResultsEvent(e:ReviewResultsEvent):void{
viewWindowManager.handleReviewResultsEvent(e);
}
//##################################################################################
}
}

View File

@ -0,0 +1,225 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.managers
{
import com.asfusion.mate.events.Dispatcher;
import mx.collections.ArrayCollection;
import org.bigbluebutton.common.IBbbModuleWindow;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.common.events.CloseWindowEvent;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.modules.polling.service.PollingService;
import org.bigbluebutton.modules.polling.views.PollingViewWindow;
import org.bigbluebutton.modules.polling.views.PollingStatsWindow;
import org.bigbluebutton.modules.polling.views.PollingInstructionsWindow;
import org.bigbluebutton.modules.polling.events.PollingViewWindowEvent;
import org.bigbluebutton.modules.polling.events.PollingInstructionsWindowEvent;
import org.bigbluebutton.modules.polling.events.PollingStatsWindowEvent;
import org.bigbluebutton.modules.polling.events.PollRefreshEvent;
import org.bigbluebutton.modules.polling.events.StopPollEvent;
import org.bigbluebutton.modules.polling.events.PollingStatusCheckEvent;
import org.bigbluebutton.modules.polling.events.PollGetTitlesEvent;
import org.bigbluebutton.modules.polling.events.OpenSavedPollEvent;
import org.bigbluebutton.modules.polling.events.ReviewResultsEvent;
import org.bigbluebutton.modules.polling.events.GenerateWebKeyEvent;
import mx.managers.IFocusManager;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.FocusEvent;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollingWindowManager {
private var pollingWindow:PollingViewWindow;
private var statsWindow:PollingStatsWindow;
private var instructionsWindow:PollingInstructionsWindow;
private var service:PollingService;
private var isViewing:Boolean = false;
private var globalDispatcher:Dispatcher;
private var votingOpen:Boolean = false;
public var appFM:IFocusManager;
private var instructionsFocusTimer:Timer = new Timer(250);
private var statsFocusTimer:Timer = new Timer(250);
public static const LOGNAME:String = "[Polling::PollingWindowManager] ";
public function PollingWindowManager(service:PollingService) {
LogUtil.debug(LOGNAME +" Built PollingWindowManager");
this.service = service;
globalDispatcher = new Dispatcher();
}
//PollingInstructionsWindow.mxml Window Event Handlerscx
//##########################################################################
public function handleOpenPollingInstructionsWindow(e:PollingInstructionsWindowEvent):void{
instructionsWindow = new PollingInstructionsWindow();
// Use the PollGetTitlesEvent to fetch a list of already-used titles
var getTitlesEvent:PollGetTitlesEvent = new PollGetTitlesEvent(PollGetTitlesEvent.CHECK);
globalDispatcher.dispatchEvent(getTitlesEvent);
openWindow(instructionsWindow);
instructionsFocusTimer.addEventListener(TimerEvent.TIMER, moveInstructionsFocus);
instructionsFocusTimer.start();
}
private function moveInstructionsFocus(event:TimerEvent):void{
appFM.setFocus(instructionsWindow.pollTitle);
instructionsFocusTimer.stop();
}
public function handleOpenPollingInstructionsWindowWithExistingPoll(e:OpenSavedPollEvent):void{
instructionsWindow = new PollingInstructionsWindow();
// Use the PollGetTitlesEvent to fetch a list of already-used titles
var getTitlesEvent:PollGetTitlesEvent = new PollGetTitlesEvent(PollGetTitlesEvent.CHECK);
globalDispatcher.dispatchEvent(getTitlesEvent);
if (e.poll != null){
instructionsWindow.incomingPoll = new PollObject();
instructionsWindow.incomingPoll = e.poll;
instructionsWindow.editing = true;
}
openWindow(instructionsWindow);
instructionsFocusTimer.addEventListener(TimerEvent.TIMER, moveInstructionsFocus);
instructionsFocusTimer.start();
}
public function handleClosePollingInstructionsWindow(e:PollingInstructionsWindowEvent):void{
closeWindow(instructionsWindow);
}
// Checking the polling status to prevent a presenter from publishing two polls at a time
public function handleCheckStatusEvent(e:PollingStatusCheckEvent):void{
e.allowed = !service.getPollingStatus();
instructionsWindow.publishingAllowed = e.allowed;
}
public function handleCheckTitlesInInstructions(e:PollGetTitlesEvent):void{
instructionsWindow.invalidTitles = e.titleList;
}
public function handleReturnWebKeyEvent(e:GenerateWebKeyEvent):void
{
var transferURL:String = e.webHostIP + "/p/" + e.poll.webKey;
LogUtil.debug("Returning poll URL to Statistics window: " + transferURL);
statsWindow.webPollUrl = transferURL;
statsWindow.setUrlBoxText();
if (!e.repost){
instructionsWindow._webKey = e.poll.webKey;
} else{
statsWindow.trackingPoll.webKey = e.poll.webKey;
}
}
// Action makers (function that actually act on the windows )
//#############################################################################
private function openWindow(window:IBbbModuleWindow):void{
var windowEvent:OpenWindowEvent = new OpenWindowEvent(OpenWindowEvent.OPEN_WINDOW_EVENT);
windowEvent.window = window;
if (windowEvent.window != null)
globalDispatcher.dispatchEvent(windowEvent);
}
private function closeWindow(window:IBbbModuleWindow):void{
var windowEvent:CloseWindowEvent = new CloseWindowEvent(CloseWindowEvent.CLOSE_WINDOW_EVENT);
windowEvent.window = window;
globalDispatcher.dispatchEvent(windowEvent);
}
//#################################################################################
// PollingViewWindow.mxml Window Handlers
//#########################################################################
public function handleOpenPollingViewWindow(e:PollingViewWindowEvent):void{
if (!votingOpen){
votingOpen = true;
pollingWindow = new PollingViewWindow();
pollingWindow.title = e.poll.title;
pollingWindow.question = e.poll.question;
pollingWindow.isMultiple = e.poll.isMultiple;
pollingWindow.answers = e.poll.answers;
openWindow(pollingWindow);
}
}
public function handleClosePollingViewWindow(e:PollingViewWindowEvent):void{
votingOpen = false;
closeWindow(pollingWindow);
}
public function handleStopPolling(e:StopPollEvent):void{
service.setPolling(false);
}
//##########################################################################
// PollingStatsWindow.mxml Window Handlers
//#########################################################################
public function handleOpenPollingStatsWindow(e:PollingStatsWindowEvent):void{
statsWindow = new PollingStatsWindow();
statsWindow.trackingPoll = e.poll;
openWindow(statsWindow);
service.setPolling(true);
if (statsWindow.webPollText.visible)
statsFocusTimer.addEventListener(TimerEvent.TIMER, focusStatsWebPoll);
else
statsFocusTimer.addEventListener(TimerEvent.TIMER, focusStatsRefresh);
statsFocusTimer.start();
}
private function focusStatsWebPoll(event:TimerEvent):void{
statsWindow.focusManager.setFocus(statsWindow.webPollURLBox);
statsFocusTimer.stop();
}
private function focusStatsRefresh(event:TimerEvent):void{
statsWindow.focusManager.setFocus(statsWindow.btnRefreshResults);
statsFocusTimer.stop();
}
public function handleClosePollingStatsWindow(e:PollingStatsWindowEvent):void{
closeWindow(statsWindow);
}
public function handleRefreshPollingStatsWindow(e:PollRefreshEvent):void{
statsWindow.refreshWindow(e.poll.votes, e.poll.totalVotes, e.poll.didNotVote);
}
public function handleReviewResultsEvent(e:ReviewResultsEvent):void{
statsWindow = new PollingStatsWindow();
statsWindow.trackingPoll = e.poll;
statsWindow.viewingClosedPoll = true;
statsWindow.reviewing = true;
openWindow(statsWindow);
}
//##########################################################################
}
}

View File

@ -0,0 +1,80 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.managers
{
import com.asfusion.mate.events.Dispatcher;
import org.bigbluebutton.common.IBbbModuleWindow;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.common.events.ToolbarButtonEvent;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.polling.views.ToolbarButton;
import mx.managers.IFocusManager;
import flash.display.DisplayObjectContainer;
public class ToolbarButtonManager {
public var button:ToolbarButton;
private var globalDispatcher:Dispatcher;
private var buttonShownOnToolbar:Boolean = false;
public var appFM:IFocusManager;
public static const LOGNAME:String = "[Polling :: ToolBarButtonManager] ";
public function ToolbarButtonManager() {
LogUtil.debug(LOGNAME + " initialized ")
globalDispatcher = new Dispatcher();
button = new ToolbarButton();
}
// Button
public function addToolbarButton():void {
if ((button != null) && (!buttonShownOnToolbar)) {
button = new ToolbarButton();
var event:ToolbarButtonEvent = new ToolbarButtonEvent(ToolbarButtonEvent.ADD);
event.button = button;
globalDispatcher.dispatchEvent(event);
buttonShownOnToolbar = true;
button.enabled = true;
appFM = button.focusManager;
}
}
public function removeToolbarButton():void {
if (buttonShownOnToolbar) {
var event:ToolbarButtonEvent = new ToolbarButtonEvent(ToolbarButtonEvent.REMOVE);
event.button = button;
globalDispatcher.dispatchEvent(event);
buttonShownOnToolbar = false;
}
}
public function enableToolbarButton():void {
button.enabled = true;
}
public function disableToolbarButton():void {
appFM.setFocus(button.focusManager.getNextFocusManagerComponent());
button.enabled = false;
}
// _Button
}
}

View File

@ -0,0 +1,167 @@
<!--
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: $
-->
<EventMap xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="http://mate.asfusion.com/">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.BBBEvent;
import org.bigbluebutton.modules.polling.managers.PollingManager;
import org.bigbluebutton.modules.polling.events.*;
]]>
</mx:Script>
<EventHandlers type="{FlexEvent.PREINITIALIZE}">
<ObjectBuilder generator="{PollingManager}"/>
</EventHandlers>
<!-- Module Events -->
<EventHandlers type="{ModuleEvent.START}">
<MethodInvoker generator="{PollingManager}" method="handleStartModuleEvent" arguments="{event.module}"/>
</EventHandlers>
<EventHandlers type="{ModuleEvent.STOP}">
</EventHandlers>
<!-- PollingInstructionsWindow Events -->
<EventHandlers type="{PollingInstructionsWindowEvent.OPEN}">
<MethodInvoker generator="{PollingManager}" method="handleOpenPollingInstructionsWindowEvent" arguments="{event}" />
</EventHandlers>
<EventHandlers type="{PollingInstructionsWindowEvent.CLOSE}">
<MethodInvoker generator="{PollingManager}" method="handleClosePollingInstructionsWindowEvent" arguments="{event}"/>
</EventHandlers>
<!-- PollingViewWindow Events -->
<EventHandlers type="{PollingViewWindowEvent.OPEN}">
<MethodInvoker generator="{PollingManager}" method="handleOpenPollingViewWindow" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollingViewWindowEvent.CLOSE}">
<MethodInvoker generator="{PollingManager}" method="handleClosePollingViewWindow" arguments="{event}"/>
</EventHandlers>
<!-- Start Polling Event - Sharing Polling View Window -->
<EventHandlers type="{StartPollingEvent.START}">
<MethodInvoker generator="{PollingManager}" method="handleStartPollingEvent" arguments="{event}"/>
</EventHandlers>
<!-- Events on the switch between Presenter and Viewer -->
<EventHandlers type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}">
<MethodInvoker generator="{PollingManager}" method="handleMadePresenterEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{MadePresenterEvent.SWITCH_TO_VIEWER_MODE}">
<MethodInvoker generator="{PollingManager}" method="handleMadeViewerEvent" arguments="{event}"/>
</EventHandlers>
<!-- Event to save Poll to db -->
<EventHandlers type="{SavePollEvent.SAVE}">
<MethodInvoker generator="{PollingManager}" method="handleSavePollEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PublishPollEvent.PUBLISH}">
<MethodInvoker generator="{PollingManager}" method="handlePublishPollEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PublishPollEvent.REPOST}">
<MethodInvoker generator="{PollingManager}" method="handleRepostPollEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{VoteEvent.START}">
<MethodInvoker generator="{PollingManager}" method="handleVoteEvent" arguments="{event}"/>
</EventHandlers>
<!-- PollingStatsWindow Events -->
<EventHandlers type="{PollingStatsWindowEvent.OPEN}">
<MethodInvoker generator="{PollingManager}" method="handleOpenPollingStatsWindow" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollingStatsWindowEvent.CLOSE}">
<MethodInvoker generator="{PollingManager}" method="handleClosePollingStatsWindow" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollRefreshEvent.REFRESH}">
<MethodInvoker generator="{PollingManager}" method="handleRefreshPollingStatsWindow" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollRefreshEvent.GET}">
<MethodInvoker generator="{PollingManager}" method="handleGetPollingStats" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{StopPollEvent.STOP_POLL}">
<MethodInvoker generator="{PollingManager}" method="handleStopPolling" arguments="{event}"/>
</EventHandlers>
<!-- Event to check if a poll is already open before allowing presenter to publish a second poll -->
<EventHandlers type="{PollingStatusCheckEvent.CHECK}">
<MethodInvoker generator="{PollingManager}" method="handleCheckStatusEvent" arguments="{event}"/>
</EventHandlers>
<!-- Events to update the list of poll titles and statuses to display in the Polling Menu -->
<EventHandlers type="{PollGetTitlesEvent.INIT}">
<MethodInvoker generator="{PollingManager}" method="handleInitializePollMenuEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollGetTitlesEvent.UPDATE}">
<MethodInvoker generator="{PollingManager}" method="handleUpdateTitlesEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollReturnTitlesEvent.UPDATE}">
<MethodInvoker generator="{PollingManager}" method="handleReturnTitlesEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollGetPollEvent.INIT}">
<MethodInvoker generator="{PollingManager}" method="handlePopulateMenuEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollGetPollEvent.RETURN}">
<MethodInvoker generator="{PollingManager}" method="handleReturnPollEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollGetTitlesEvent.CHECK}">
<MethodInvoker generator="{PollingManager}" method="handleCheckTitlesEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{PollGetTitlesEvent.RETURN}">
<MethodInvoker generator="{PollingManager}" method="handleCheckTitlesEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{OpenSavedPollEvent.OPEN}">
<MethodInvoker generator="{PollingManager}" method="handleOpenSavedPollEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{ReviewResultsEvent.REVIEW}">
<MethodInvoker generator="{PollingManager}" method="handleReviewResultsEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{GenerateWebKeyEvent.GENERATE}">
<MethodInvoker generator="{PollingManager}" method="handleGenerateWebKeyEvent" arguments="{event}"/>
</EventHandlers>
<EventHandlers type="{GenerateWebKeyEvent.RETURN}">
<MethodInvoker generator="{PollingManager}" method="handleReturnWebKeyEvent" arguments="{event}"/>
</EventHandlers>
</EventMap>

View File

@ -0,0 +1,13 @@
package org.bigbluebutton.modules.polling.model
{
import mx.collections.ArrayCollection;
import org.bigbluebutton.common.LogUtil;
[Bindable]
public class AnswerObject
{
public var answer:String;
public var votes:String;
public var percent:String;
}
}

View File

@ -0,0 +1,109 @@
package org.bigbluebutton.modules.polling.model
{
import mx.collections.ArrayCollection;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.polling.model.PollStatLineObject;
/*
* This class has been setted his attributes to public, for serialize with the model of the bigbluebutton-apps, in order
* to enable the communication. This class is used for send public and private.
**/
[Bindable]
[RemoteClass(alias="org.bigbluebutton.conference.service.poll.Poll")]
public class PollObject
{
public static const LOGNAME:String = "[PollingObject] ";
/*
########################################################################################
# KEY PLACES TO UPDATE, WHEN ADDING NEW FIELDS TO THE HASH: #
# PollingService.as, buildServerPoll() #
# PollingService.as, extractPoll() #
# PollingInstructionsWindow.mxml, buildPoll() #
# - Only necessary when the new field is involved with poll creation #
# Don't forget to update the server side as well (key locations found in Poll.java) #
########################################################################################
*/
public var title:String;
public var room:String;
public var isMultiple:Boolean;
public var question:String;
public var answers:Array;
public var votes:Array;
public var time:String;
public var totalVotes:int;
public var status:Boolean;
public var didNotVote:int;
public var publishToWeb:Boolean;
public var webKey:String = new String;
// For developer use, this method outputs all fields of a poll into the debug log for examination.
// Please remember to add lines for any new fields that may be added.
public function checkObject():void{
if (this != null){
LogUtil.debug(LOGNAME + "Running CheckObject on the poll with title " + title);
LogUtil.debug(LOGNAME + "Room is: " + room);
LogUtil.debug(LOGNAME + "isMultiple is: " + isMultiple.toString());
LogUtil.debug(LOGNAME + "Question is: " + question);
LogUtil.debug(LOGNAME + "Answers are: " + answers);
LogUtil.debug(LOGNAME + "Votes are: " + votes);
LogUtil.debug(LOGNAME + "Time is: " + time);
LogUtil.debug(LOGNAME + "TotalVotes is: " + totalVotes);
LogUtil.debug(LOGNAME + "Status is: " + status.toString());
LogUtil.debug(LOGNAME + "DidNotVote is: " + didNotVote);
LogUtil.debug(LOGNAME + "PublishToWeb is: " + publishToWeb.toString());
LogUtil.debug(LOGNAME + "WebKey is: " + webKey);
LogUtil.debug(LOGNAME + "--------------");
}else{
LogUtil.error(LOGNAME + "This PollObject is NULL.");
}
}
public function generateStats():ArrayCollection{
var returnCollection:ArrayCollection = new ArrayCollection;
for (var i:int = 0; i < answers.length; i++){
var pso:PollStatLineObject = new PollStatLineObject;
pso.answer = answers[i].toString();
pso.votes = votes[i].toString();
//pso.percentage =
if (totalVotes == 0){
pso.percentage = "";
}
else{
pso.percentage = Math.round(100*(votes[i]/totalVotes)) + "%";
}
returnCollection.addItem(pso);
}
return returnCollection;
}
public function generateTestStats():ArrayCollection{
var ds:String = "TEST STATS: ";
var returnCollection:ArrayCollection = new ArrayCollection;
for (var i:int = 0; i < 6; i++){
var pso:PollStatLineObject = new PollStatLineObject;
pso.answer = "Test answer " + i;
pso.votes = "Test votes " + i;
pso.percentage = "Test percent " + i;
returnCollection.addItem(pso);
LogUtil.debug(ds + pso.debug());
}
return returnCollection;
}
public function generateOneLine():ArrayCollection{
var ds:String = "TEST LINE: ";
var returnCollection:ArrayCollection = new ArrayCollection;
var pso:PollStatLineObject = new PollStatLineObject;
pso.answer = "ANSWER CELL";
pso.votes = "VOTEs CELL";
pso.percentage = "PERCENTAGE CELL";
returnCollection.addItem(pso);
LogUtil.debug(ds + pso.debug());
return returnCollection;
}
}
}

View File

@ -0,0 +1,16 @@
package org.bigbluebutton.modules.polling.model
{
import mx.collections.ArrayCollection;
import org.bigbluebutton.common.LogUtil;
[Bindable]
public class PollStatLineObject
{
public var answer:String;
public var votes:String;
public var percentage:String;
public function debug():String{
return answer + " " + votes + " " + percentage;
}
}
}

View File

@ -0,0 +1,20 @@
package org.bigbluebutton.modules.polling.model
{
import org.bigbluebutton.modules.polling.model.PollObject;
[Bindable]
public class ValueObject
{
public var id:String;
public var label:String;
public var icon:String;
public var poll:PollObject;
public function ValueObject(id:String, label:String, icon:String=null)
{
poll = new PollObject();
this.id = id;
this.label = label;
this.icon = icon;
}
}
}

View File

@ -0,0 +1,442 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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/>.
*
*/
package org.bigbluebutton.modules.polling.service
{
import com.asfusion.mate.events.Dispatcher;
import flash.events.AsyncErrorEvent;
import flash.events.IEventDispatcher;
import flash.events.NetStatusEvent;
import flash.events.SyncEvent;
import flash.net.NetConnection;
import flash.net.SharedObject;
import flash.net.Responder;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.polling.events.PollingViewWindowEvent;
import org.bigbluebutton.modules.polling.events.PollingStatsWindowEvent;
import org.bigbluebutton.modules.polling.events.PollRefreshEvent;
import org.bigbluebutton.modules.polling.events.PollGetTitlesEvent;
import org.bigbluebutton.modules.polling.events.PollReturnTitlesEvent;
import org.bigbluebutton.modules.polling.events.PollGetPollEvent;
import org.bigbluebutton.modules.polling.events.GenerateWebKeyEvent;
import org.bigbluebutton.modules.polling.views.PollingViewWindow;
import org.bigbluebutton.modules.polling.views.PollingInstructionsWindow;
import org.bigbluebutton.modules.polling.managers.PollingWindowManager;
import org.bigbluebutton.common.events.OpenWindowEvent;
import org.bigbluebutton.common.IBbbModuleWindow;
import org.bigbluebutton.modules.polling.model.PollObject;
public class PollingService
{
public static const LOGNAME:String = "[PollingService] ";
private var pollingSO:SharedObject;
private var nc:NetConnection;
private var uri:String;
private var module:PollingModule;
private var dispatcher:Dispatcher;
private var attributes:Object;
private var windowManager: PollingWindowManager;
public var pollGlobal:PollObject;
public var test:String;
private static const SHARED_OBJECT:String = "pollingSO";
private var isPolling:Boolean = false;
private var isConnected:Boolean = false;
private var viewWindow:PollingViewWindow;
public function PollingService()
{
LogUtil.debug(LOGNAME + " Building PollingService");
dispatcher = new Dispatcher();
}
public function handleStartModuleEvent(module:PollingModule):void {
this.module = module;
nc = module.connection
uri = module.uri;
connect();
}
// CONNECTION
/*###################################################*/
public function connect():void {
pollingSO = SharedObject.getRemote(SHARED_OBJECT, uri, false);
pollingSO.addEventListener(SyncEvent.SYNC, sharedObjectSyncHandler);
pollingSO.addEventListener(NetStatusEvent.NET_STATUS, handleResult);
pollingSO.client = this;
pollingSO.connect(nc);
}
public function getConnection():NetConnection{
return module.connection;
}
// Dealing with PollingViewWindow
/*#######################################################*/
public function sharePollingWindow(poll:PollObject):void{
if (isConnected = true ) {
pollingSO.send("openPollingWindow", buildServerPoll(poll));
}
}
public function openPollingWindow(serverPoll:Array):void{
var username:String = module.username;
var poll:PollObject = extractPoll(serverPoll, serverPoll[1]+"-"+serverPoll[0]);
if (!UserManager.getInstance().getConference().amIModerator()){
var e:PollingViewWindowEvent = new PollingViewWindowEvent(PollingViewWindowEvent.OPEN);
e.poll = poll;
dispatcher.dispatchEvent(e);
}
else{
var stats:PollingStatsWindowEvent = new PollingStatsWindowEvent(PollingStatsWindowEvent.OPEN);
stats.poll = poll;
stats.poll.status = false;
dispatcher.dispatchEvent(stats);
}
}
public function closeAllPollingWindows():void{
if (isConnected = true ) {
pollingSO.send("closePollingWindow");
}
}
public function closePollingWindow():void{
var e:PollingViewWindowEvent = new PollingViewWindowEvent(PollingViewWindowEvent.CLOSE);
dispatcher.dispatchEvent(e);
}
//Event Handlers
/*######################################################*/
public function setPolling(polling:Boolean):void{
isPolling = polling;
}
public function setStatus(pollKey:String, status:Boolean):void{
if (status){
openPoll(pollKey);
}else{
closePoll(pollKey);
}
}
public function getPollingStatus():Boolean{
return isPolling;
}
public function disconnect():void{
if (module.connection != null) module.connection.close();
}
public function onBWDone():void{
//called from asc
trace("onBandwithDone");
}
public function handleResult(e:NetStatusEvent):void {
var statusCode : String = e.info.code;
switch (statusCode){
case "NetConnection.Connect.Success":
isConnected = true;
break;
case "NetConnection.Connect.Failed":
break;
case "NetConnection.Connect.Rejected":
break;
default:
break;
}
}
private function sharedObjectSyncHandler(e:SyncEvent) : void{}
public function savePoll(poll:PollObject):void
{
var serverPoll:Array = buildServerPoll(poll);
nc.call("poll.savePoll", new Responder(success, failure), serverPoll);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{}
function failure(obj:Object):void{
LogUtil.error(LOGNAME + "Responder object failure in SAVEPOLL NC.CALL");
}
//--------------------------------------//
}
public function getPoll(pollKey:String, option:String):void{
nc.call("poll.getPoll", new Responder(success, failure), pollKey);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{
var itemArray:Array = obj as Array;
extractPoll(itemArray, pollKey, option);
}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in GETPOLL NC.CALL");
}
//--------------------------------------//
}
public function publish(poll:PollObject):void{
var pollKey:String = poll.room + "-" + poll.title;
var webKey:String = poll.webKey;
var serverPoll:Array = buildServerPoll(poll);
nc.call("poll.publish", new Responder(success, failure), serverPoll, pollKey);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{
var itemArray:Array = obj as Array;
if (webKey != null){
itemArray[11] = webKey;
}
extractPoll(itemArray, pollKey, "publish");
}
function failure(obj:Object):void{
LogUtil.error(LOGNAME + "Responder object failure in PUBLISH NC.CALL");
}
//--------------------------------------//
}
public function vote(pollKey:String, answerIDs:Array, webVote:Boolean = false):void{
// answerIDs will indicate by integer which option(s) the user voted for
// i.e., they voted for 3 and 5 on multiple choice, answerIDs will hold [0] = 3, [1] = 5
// It works the same regardless of if AnswerIDs holds {3,5} or {5,3}
nc.call("poll.vote", new Responder(success, failure), pollKey, answerIDs, webVote);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{}
function failure(obj:Object):void{
LogUtil.error(LOGNAME + "Responder object failure in VOTE NC.CALL");
}
//--------------------------------------//
}
public function refreshResults(poll:PollObject):void{
var refreshEvent:PollRefreshEvent = new PollRefreshEvent(PollRefreshEvent.REFRESH);
refreshEvent.poll = poll;
dispatcher.dispatchEvent(refreshEvent);
}
public function cutOffWebPoll(poll:PollObject):void{
var pollKey:String = poll.room+"-"+poll.title;
nc.call("poll.cutOffWebPoll", new Responder(success, failure), pollKey);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{}
function failure(obj:Object):void{
LogUtil.error(LOGNAME + "Responder object failure in CUT OFF WEB POLL NC.CALL");
}
//--------------------------------------//
}
//#################################################//
// POLLOBJECT-TO-ARRAY AND ARRAY-TO-POLLOBJECT TRANSFORMATION
// Reminder: When adding new fields to the Redis hash, include them here.
private function buildServerPoll(poll:PollObject):Array{
var builtPoll:Array = new Array(poll.title,
poll.room,
poll.isMultiple,
poll.question,
poll.answers,
poll.votes,
poll.time,
poll.totalVotes,
poll.status,
poll.didNotVote,
poll.publishToWeb,
poll.webKey);
return builtPoll;
}
public function extractPoll(values:Array, pollKey:String, option:String = "extract"):PollObject {
var poll:PollObject = new PollObject();
poll.title = values[0] as String;
poll.room = values[1] as String;
poll.isMultiple = values[2] as Boolean;
poll.question = values[3] as String;
poll.answers = values[4] as Array;
poll.votes = values[5] as Array;
poll.time = values[6] as String;
poll.totalVotes = values[7] as int;
poll.status = values[8] as Boolean;
poll.didNotVote = values[9] as int;
poll.publishToWeb = values[10] as Boolean;
poll.webKey = values[11] as String;
switch (option)
{
case "publish":
sharePollingWindow(poll);
break;
case "refresh":
refreshResults(poll);
break;
case "menu":
var pollReturn:PollGetPollEvent = new PollGetPollEvent(PollGetPollEvent.RETURN);
pollReturn.poll = poll;
pollReturn.pollKey = pollKey;
dispatcher.dispatchEvent(pollReturn);
break;
case "initialize":
var pollInitialize:PollGetPollEvent = new PollGetPollEvent(PollGetPollEvent.INIT);
pollInitialize.poll = poll;
pollInitialize.pollKey = pollKey;
dispatcher.dispatchEvent(pollInitialize);
break;
case "extract":
break;
default:
LogUtil.error(LOGNAME+"Error in extractPoll: unknown option ["+option+"]");
break;
}
return poll;
}
// END OF POLLOBJECT-TO-ARRAY AND ARRAY-TO-POLLOBJECT TRANSFORMATION
//#################################################//
// TOOLBAR/POLLING MENU
// Initialize the Polling Menu on the toolbar button
public function initializePollingMenu(roomID:String):void{
nc.call("poll.titleList", new Responder(titleSuccess, titleFailure));
//--------------------------------------//
// Responder functions
function titleSuccess(obj:Object):void{
LogUtil.debug("LISTINIT: Entering NC CALL SUCCESS section");
var event:PollReturnTitlesEvent = new PollReturnTitlesEvent(PollReturnTitlesEvent.UPDATE);
event.titleList = obj as Array;
// Append roomID to each item in titleList, call getPoll on that key, add the result to pollList back in ToolBarButton
for (var i:int = 0; i < event.titleList.length; i++){
var pollKey:String = roomID +"-"+ event.titleList[i];
getPoll(pollKey, "initialize");
}
// This dispatch populates the titleList back in the Menu; the pollList is populated one item at a time in the for-loop
dispatcher.dispatchEvent(event);
}
function titleFailure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in INITALIZE POLLING MENU NC.CALL");
LogUtil.error("Failure object tostring is: " + obj.toString());
}
//--------------------------------------//
}
public function updateTitles():void{
nc.call("poll.titleList", new Responder(success, failure));
//--------------------------------------//
// Responder functions
function success(obj:Object):void{
var event:PollReturnTitlesEvent = new PollReturnTitlesEvent(PollReturnTitlesEvent.UPDATE);
event.titleList = obj as Array;
dispatcher.dispatchEvent(event);
}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in UPDATE_TITLES NC.CALL");
}
//--------------------------------------//
}
public function checkTitles():void{
nc.call("poll.titleList", new Responder(success, failure));
//--------------------------------------//
// Responder functions
function success(obj:Object):void{
var event:PollGetTitlesEvent = new PollGetTitlesEvent(PollGetTitlesEvent.RETURN);
event.titleList = obj as Array;
dispatcher.dispatchEvent(event);
}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in CHECK_TITLES NC.CALL");
}
//--------------------------------------//
}
// END OF TOOLBAR/POLLING MENU
//#################################################//
// OTHER POLL METHODS
public function openPoll(pollKey:String):void{
nc.call("poll.setStatus", new Responder(success, failure), pollKey, true);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in OPENPOLL NC.CALL");
}
//--------------------------------------//
}
public function closePoll(pollKey:String):void{
nc.call("poll.setStatus", new Responder(success, failure), pollKey, false);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in CLOSEPOLL NC.CALL");
}
//--------------------------------------//
}
public function generate(generateEvent:GenerateWebKeyEvent):void{
nc.call("poll.generate", new Responder(success, failure), generateEvent.pollKey);
//--------------------------------------//
// Responder functions
function success(obj:Object):void{
var webInfo:Array = obj as Array;
var webKey:String = webInfo[0];
var webHostIP:String = webInfo[1];
var webHostPort:String = webInfo[2];
var webKeyReturnEvent:GenerateWebKeyEvent = new GenerateWebKeyEvent(GenerateWebKeyEvent.RETURN);
webKeyReturnEvent.poll = generateEvent.poll
webKeyReturnEvent.poll.webKey = webKey;
webKeyReturnEvent.webHostIP = webHostIP;
webKeyReturnEvent.webHostPort = webHostPort;
dispatcher.dispatchEvent(webKeyReturnEvent);
}
function failure(obj:Object):void{
LogUtil.error(LOGNAME+"Responder object failure in GENERATE NC.CALL");
}
//--------------------------------------//
}
}
}

View File

@ -0,0 +1,32 @@
<?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:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import org.bigbluebutton.util.i18n.ResourceUtil;
// {data.answer}
]]>
</mx:Script>
<mx:Label id="answerRenderLabel" textAlign="left" text="ANSWER"/>
</mx:HBox>

View File

@ -0,0 +1,32 @@
<?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:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import org.bigbluebutton.util.i18n.ResourceUtil;
// {data.percentage}
]]>
</mx:Script>
<mx:Label id="percentRenderLabel" textAlign="left" text="PERCENT"/>
</mx:HBox>

View File

@ -0,0 +1,591 @@
<?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: $
-->
<!--
Notes.mxml is the main view of the SharedNotes application
-->
<MDIWindow xmlns="flexlib.mdi.containers.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
width="510" height="600"
xmlns:mate="http://mate.asfusion.com/"
implements="org.bigbluebutton.common.IBbbModuleWindow"
creationComplete="onCreationComplete()"
label="Create Poll" layout="absolute"
title="{ResourceUtil.getInstance().getString('bbb.polling.createPoll')}">
<!-- Pre Defined Validation -->
<mx:Script>
<![CDATA[
import flexlib.mdi.events.MDIWindowEvent;
import org.bigbluebutton.main.views.MainCanvas;
import mx.controls.Alert;
import org.bigbluebutton.common.LogUtil;
import mx.validators.Validator;
import mx.utils.ObjectUtil;
import mx.utils.StringUtil;
import mx.collections.ArrayCollection;
import mx.core.IUIComponent;
import mx.containers.HBox;
import mx.controls.CheckBox;
import mx.controls.RadioButton;
import org.bigbluebutton.modules.polling.events.SavePollEvent;
import org.bigbluebutton.modules.polling.events.PublishPollEvent;
import org.bigbluebutton.modules.polling.managers.PollingManager;
import org.bigbluebutton.modules.polling.events.PollingInstructionsWindowEvent;
import org.bigbluebutton.modules.polling.events.StartPollingEvent;
import org.bigbluebutton.modules.polling.events.PollingStatusCheckEvent;
import org.bigbluebutton.modules.polling.events.PollGetTitlesEvent;
import org.bigbluebutton.modules.polling.events.GenerateWebKeyEvent;
import org.bigbluebutton.modules.polling.model.PollObject;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.model.users.Conference
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.common.Role;
import org.bigbluebutton.util.i18n.ResourceUtil;
public static const LOGNAME:String = "[PollingInstructionsWindow] ";
public var moduleAttributes:Object = new Object();
private var userName:String;
private var module:PollingModule;
private var published:Boolean;
[Bindable] public var participants:int;
// Bindable is set to allow data to change when You hit Back and change something, this change will appear in review
private var conference:Conference;
[Bindable]private var _title:String;
[Bindable]private var _question:String;
[Bindable]private var _answers:ArrayCollection;
[Bindable]private var _isMultiple:Boolean =false;
[Bindable] public var _publishToWeb:Boolean;
public var _webKey:String;
private var _answersArray:Array;
public var publishingAllowed:Boolean = true;
private var manager:PollingManager = new PollingManager();
[Bindable] public var invalidTitles:Array;
[Bindable] public var incomingPoll:PollObject;
[Bindable] public var editing:Boolean;
// LENGTH CONSTRAINTS ( CHANGE IF YOU NEED)
//################################################
[Bindable]private var _MAX_QUESTION_LENGTH:uint = 200;
[Bindable]private var _MAX_TITLE_LENGTH:uint=50;
[Bindable]private var _MAX_ANSWER_LENGTH:uint = 100;
[Bindable]private var _MAX_ANSWERS_AMOUNT:uint = 10;
[Bindable]private var _ANSWER_CHARS_PER_LINE:uint=28; // made to avoid scrollbars (can be changed )
//###############################################
public function getPrefferedPosition():String{
return MainCanvas.POPUP;
}
private function onCreationComplete():void{
published = false;
/*pollTitle.editable = false;
focusManager.setFocus(pollTitle);
pollTitle.editable = true;
focusManager.setFocus(pollTitle);*/
if (incomingPoll != null){
LogUtil.debug("EDITING POLL");
pollTitle.text = incomingPoll.title;
pollQuestion.text = incomingPoll.question;
for (var i:int = 0; i < incomingPoll.answers.length; i++){
pollAnswers.text += incomingPoll.answers[i];
if (i < incomingPoll.answers.length-1){
pollAnswers.text += "\n";
}
}
multiple_response.selected = incomingPoll.isMultiple;
publishToWeb_response.selected = incomingPoll.publishToWeb;
isMultiple();
publishToWeb();
}else{
editing = false;
}
userName = moduleAttributes.username;
this.module = module;
}
// Overwritting close to use custom function
override public function close(event:MouseEvent = null):void {
closeInstructionsWindow();
}
// function invoked when close window
private function closeInstructionsWindow():void {
dispatchEvent(new PollingInstructionsWindowEvent(PollingInstructionsWindowEvent.CLOSE));
}
// function invoked when checkbox is checked
private function isMultiple():void{
if(multiple_response.selected == true)
_isMultiple= true;
else
_isMultiple= false;
}
private function publishToWeb():void{
if(publishToWeb_response.selected == true)
_publishToWeb= true;
else
_publishToWeb= false;
}
//TESTING
private function reviewChanges():void{
LogUtil.debug(LOGNAME + "WHAT WE HAVE:");
LogUtil.debug(LOGNAME + "Title: "+_title);
LogUtil.debug(LOGNAME + "Question: "+_question);
LogUtil.debug(LOGNAME + "Answers: "+_answers);
if(_isMultiple) LogUtil.debug(LOGNAME + "Multiple answers allowed");
}
// END TESTING
// DATA VALIDATION
//##################################################################################
private function validateAndSubmit():void {
var valid:Boolean = true;
// Gathering Error Messages
titleErrMsg.text = titleError();
qErrMsg.text = questionError();
aErrMsg.text = answerError();
// Making Error messages Visible if there is an Error
if (titleErrMsg.text != "VALID"){ // checking if function returned any error string
titleErrMsg.visible=true;
valid = false; // setting flag to false in case of error
}else
titleErrMsg.visible=false;
if(qErrMsg.text != "VALID"){
qErrMsg.visible=true;
valid = false;
} else
qErrMsg.visible=false;
if (aErrMsg.text != "VALID") {
aErrMsg.visible=true;
valid = false;
}else
aErrMsg.visible=false;
if(valid){
formatAndReview();
}else{
LogUtil.error(LOGNAME + "Error occurred in poll validation");
}
allowPublishing();
publishButton.enabled = publishingAllowed;
}
// GENERATING ERROR MESSAGES
//################################
//TITLE VALIDATION
private function titleError():String{
var errMsg:String = "VALID";
// If the presenter is creating a new poll, the module will not permit duplicate titles.
// If the presenter is editing an existing poll, the module will ignore duplicate titles long enough to save it again.
if (!editing){
for (var i:int = 0; i < invalidTitles.length; i++){
if (invalidTitles[i] != null){
var checkTitle:String = invalidTitles[i];
if (StringUtil.trim(pollTitle.text.toUpperCase()) == StringUtil.trim(checkTitle.toUpperCase())){
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.duplicateTitle');
}
}
}
}
if (pollTitle.length == 0 ){
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.noTitle');
}
else if (pollTitle.length > _MAX_TITLE_LENGTH ){
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.toolongTitle')+" " +_MAX_TITLE_LENGTH;
}
else{
_title = StringUtil.trim(pollTitle.text);
}
return errMsg;
} // _TITLE VALIDATION
//QUESTION VALIDATION
private function questionError():String{
var errMsg:String = "VALID";
if (pollQuestion.length == 0 )
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.noQuestion');
else if (pollQuestion.length > _MAX_QUESTION_LENGTH )
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.toolongQuestion') + " "+ _MAX_QUESTION_LENGTH;
else
_question=pollQuestion.text;
return errMsg;
}
// ANSWER VALIDATION
private function answerError():String{
var errMsg:String = "VALID";
var answersArray:Array;
var valid:Boolean=true;
answersArray = pollAnswers.text.split("\r");
// splitting by '*' and new line, thus user can type '*' anywhere except the newline
//answersArray[0] = answersArray[0].split('*').join('');
// As after split '*' is not displayed we need to take off from first element which is not splitted
answersArray = makeAnswersPretty(answersArray);
// ALL THE MESSAGES NEED TO BE LOCALISED!!!!!
if (pollAnswers.length == 0 )
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.atLeast2Answers');
else if (isDuplicateAnswers(answersArray))
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.answerUnique');
else if(answersArray.length < 2)
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.eachNewLine');
else if(answersArray.length > _MAX_ANSWERS_AMOUNT)
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.toomuchAnswers') +" "+_MAX_ANSWERS_AMOUNT;
else {
for (var i:int=0; i< answersArray.length; i++){
if(i != 0 && (answersArray[i] == null || answersArray[i] == "")){
answersArray.splice(i,1);
}else if(answersArray[i].length > _MAX_ANSWER_LENGTH){
errMsg = ResourceUtil.getInstance().getString('bbb.polling.validation.toolongAnswer') +" "+_MAX_ANSWER_LENGTH;
valid=false;
}
// if last character of the array element is return (new line) or space, we it to have accurate string and than checking for duplicates again
if(valid && !isDuplicateAnswers(answersArray)){
_answers = new ArrayCollection(answersArray); // This will be displayed in Preview
_answersArray= answersArray; // this will be sent to server
}
}
}
return errMsg;
}
//#####################################################################################################
public function goBack():void{
back.visible=false;
publishButton.visible=false;
options.removeAllChildren();
}
private function isDuplicateAnswers(arr:Array):Boolean{
var x:uint;
var y:uint;
for (x = 0; x < arr.length ; x++){
for (y = x + 1; y < arr.length; y++){
if (arr[x] === arr[y]){
return true;
}
}
}
return false;
}
//trimming return and whitespaces at the end of each array element
private function makeAnswersPretty(arr:Array):Array{
var i:uint;
var trim:RegExp = /^\s+|\s+$/g;
for (i = 0; i < arr.length; i++){
arr[i] = arr[i].replace(trim, "");
if(!arr[i]) //if user puts just return or space and return - this array elements will be deleted
arr.splice(i,1);
}
return arr;
}
private function formatAndReview():void{
// Change maind window and buttons to Review
mainArea.selectedChild=review;
buttons.selectedChild=reviewButtons;
//REFRESHING CANVAS
invalidateDisplayList();
validateNow();
// Make Back button visible
back.visible=true;
publishButton.visible=true;
checkInstructions.visible = _isMultiple;
// Make Title and Question string first letter Upper case
_title = upperFirstLetter(_title);
_question = upperFirstLetter(_question);
createButtons(_answers.length,_answers);
focusManager.setFocus(back);
}
private function upperFirstLetter(str:String) : String {
return str.substr(0, 1).toUpperCase() + str.substr(1, str.length);
}
// function receives Array.length and ArrayCollectionvar p:BBBUser;
private function createButtons(amount:uint, content:ArrayCollection):void{
var _cb:CheckBox;
var _rb:RadioButton;
var _tx: Text;
var _hb: HBox;
// creating buttons one by one
for (var i:int = 0; i < amount; i++) {
_tx = new Text();
_hb = new HBox();
_tx.name = "option" +i;
_tx.width = 200;
// assigning array element to text field
_tx.text =content.getItemAt(i).toString();
options.addChild(_hb);
// if global var _isMultiple is true it means user wants checkboxes,
//otherwise radiobutton (if multiple choices are allowed)
if(_isMultiple){
_cb= new CheckBox();
// giving button a name of array elelment to process it easier later
_cb.name=content.getItemAt(i).toString();
// gap between the buttons
_cb.y=i*20;
// adding buttons to the Horizontal Box
_hb.addChild(_cb);
}else{
_rb = new RadioButton();
_rb.name = content.getItemAt(i).toString(); // giving button a name of array elelment to process it easier later
_rb.groupName = "answers";
_rb.label =" ";
_hb.addChild(_rb);
}
_hb.addChild(_tx); // adding text near button
} // end of loop
} // end of function
private function buildPoll():PollObject{
var builtPoll:PollObject = new PollObject();
builtPoll.title = _title;
builtPoll.isMultiple = _isMultiple;
builtPoll.question = _question;
builtPoll.answers = _answersArray;
builtPoll.didNotVote = participants;
builtPoll.publishToWeb = _publishToWeb;
if (_publishToWeb && _webKey != null)
builtPoll.webKey = _webKey;
return builtPoll;
}
private function savePoll(callingFromPublish:Boolean = false):void {
participants = 0;
var p:BBBUser;
conference = UserManager.getInstance().getConference();
for (var i:int = 0; i < conference.users.length; i++) {
p = conference.users.getItemAt(i) as BBBUser;
if (p.role != Role.MODERATOR) {
participants++;
}
}
var savePollEvent: SavePollEvent = new SavePollEvent(SavePollEvent.SAVE);
savePollEvent.poll = buildPoll();
savePollEvent.poll.status = !callingFromPublish;
dispatchEvent(savePollEvent);
if(!callingFromPublish)
closeInstructionsWindow();
}
private function publish():void {
published = true;
savePoll(true);
var publishPollEvent: PublishPollEvent = new PublishPollEvent(PublishPollEvent.PUBLISH);
publishPollEvent.poll = buildPoll();
publishPollEvent.poll.webKey = _webKey;
dispatchEvent(publishPollEvent);
dispatchEvent(new StartPollingEvent(StartPollingEvent.START));
closeInstructionsWindow();
}
private function allowPublishing():void {
dispatchEvent(new PollingStatusCheckEvent(PollingStatusCheckEvent.CHECK));
}
]]>
</mx:Script>
<mx:ViewStack id="mainArea" width="100%">
<!-- ################### MAIN AREA ##############-->
<!-- Instructions Window with Form-->
<mx:Canvas id="instrMain" width="90%" height="90%" focusEnabled="true">
<mx:VBox width="90%" height="90%" focusEnabled="true">
<mx:Form width="100%" id="instructionsForm" paddingTop="30" paddingBottom="10" paddingLeft="30" focusEnabled="true">
<mx:FormItem fontWeight="bold"
label="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.title')}"
paddingLeft="35"
id="titleFormItem"
focusEnabled="true">
<mx:TextInput id="pollTitle" focusEnabled="true" accessibilityDescription="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.title')}"/>
<mx:Label id="titleErrMsg"
text=""
visible="false"
width="100%"
color="red"
fontSize="9"
fontWeight="normal"/>
</mx:FormItem>
<mx:FormItem fontWeight="bold"
label="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.question')}"
paddingLeft="35"
paddingTop="20" >
<mx:TextArea id="pollQuestion"
width="200"
height="100"
accessibilityDescription="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.question')}"/>
<mx:Label id="qErrMsg"
text=""
visible="false"
width="100%"
color="red"
fontSize="9"
fontWeight="normal" />
</mx:FormItem>
<mx:FormItem fontWeight="bold"
label="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.answers')}"
paddingLeft="35"
paddingTop="30" >
<mx:TextArea id="pollAnswers"
width="200"
height="100"
accessibilityDescription="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.answers')}"/>
<mx:Label id="answerHint"
text="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.hint')}"
visible="true"
width="100%"
fontSize="9"
fontWeight="normal" />
</mx:FormItem>
<mx:FormItem fontWeight="bold"
paddingLeft="20"
paddingTop="5" >
<mx:Label id="aErrMsg"
text=""
visible="false"
width="100%"
color="red"
fontSize="9"
fontWeight="normal" />
</mx:FormItem>
<mx:FormItem paddingLeft="10"
paddingTop="5" >
<mx:CheckBox id="multiple_response"
label="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.moreThanOneResponse')}"
click="isMultiple()" />
<mx:CheckBox id="publishToWeb_response"
label="{ResourceUtil.getInstance().getString('bbb.polling.createPoll.publishToWeb')}"
click="publishToWeb()" />
</mx:FormItem>
</mx:Form>
</mx:VBox>
</mx:Canvas>
<!-- Review Window that is invoked when Next button is clicked -->
<mx:Canvas id="review">
<mx:VBox width="90%" height="90%" paddingLeft="40">
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.hereIsYourPoll')}"
fontSize="11"
fontWeight="bold"
width ="100%"
paddingTop="30"
paddingLeft="20"
paddingBottom="5"/>
<mx:Label text="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.pollWillPublishOnline')}"
fontSize="11"
fontWeight="bold"
width ="100%"
color="red"
paddingTop="10"
paddingLeft="20"
paddingBottom="15"
visible="{_publishToWeb}"/>
<mx:Panel id="titleShow"
title="{_title}"
width="90%" >
<mx:VBox paddingLeft="40"
paddingBottom="40">
<mx:Text text="{_question}"
fontSize="10"
fontWeight="bold"
paddingBottom="5"
paddingTop="20"
width="{_MAX_QUESTION_LENGTH}"/>
<mx:Text id="checkInstructions"
text="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.checkAll')}"/>
<mx:Box id="options" />
</mx:VBox>
</mx:Panel>
<mx:Label text=" {ResourceUtil.getInstance().getString('bbb.polling.pollPreview.ifYouWantChanges')}"
fontSize="11"
fontWeight="normal"
width ="100%"
paddingLeft="20"
paddingBottom="20"
paddingTop="20"/>
</mx:VBox>
</mx:Canvas>
</mx:ViewStack>
<!-- ###################BUTTONS##############-->
<!-- area where buttons are located -->
<mx:ControlBar>
<!-- Back Button is not visible while instructions and visible while preView -->
<mx:Button id="back"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.modify')}"
click="{mainArea.selectedChild=instrMain} {buttons.selectedChild=instrButtons} goBack()"
width="100"
height="30"
visible="false"/>
<mx:Button id="publishButton"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.publish')}"
click="publish();"
width="100"
height="30"
visible="false"/>
<mx:ViewStack id="buttons">
<!--buttons that appear when Instructions is displayed -->
<mx:Canvas id="instrButtons">
<mx:Button id="next"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.preview')}"
click="validateAndSubmit()"
width="100"
height="30"/>
</mx:Canvas>
<!-- buttons that appear on Review -->
<mx:Canvas id="reviewButtons">
<mx:Button id="SavePoll"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.save')}"
click="savePoll()"
width="100"
height="30"/>
</mx:Canvas>
</mx:ViewStack>
<!-- Cancel button appear everywhere -->
<mx:Button id="Cancel"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.cancel')}"
click="closeInstructionsWindow()"
width="100"
height="30"/>
</mx:ControlBar>
</MDIWindow>

View File

@ -0,0 +1,399 @@
<?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: $
-->
<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml"
height="150"
width="410"
xmlns:mate="http://mate.asfusion.com/"
implements="org.bigbluebutton.common.IBbbModuleWindow"
initialize="init();"
creationComplete="onCreationComplete()"
label="{ResourceUtil.getInstance().getString('bbb.polling.toolbar.toolTip')}"
title="{ResourceUtil.getInstance().getString('bbb.polling.toolbar.toolTip')}"
layout="absolute"
>
<mx:Script>
<![CDATA[
import flexlib.mdi.events.MDIWindowEvent;
import org.bigbluebutton.main.views.MainCanvas;
import mx.controls.Alert;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.polling.events.StartPollingEvent;
import org.bigbluebutton.modules.polling.managers.PollingManager;
import org.bigbluebutton.modules.polling.events.VoteEvent;
import org.bigbluebutton.modules.polling.events.PollingStatsWindowEvent;
import org.bigbluebutton.modules.polling.events.PollRefreshEvent;
import org.bigbluebutton.modules.polling.events.StopPollEvent;
import org.bigbluebutton.modules.polling.events.SavePollEvent;
import org.bigbluebutton.modules.polling.events.PublishPollEvent;
import org.bigbluebutton.modules.polling.events.GenerateWebKeyEvent;
import org.bigbluebutton.modules.chat.events.SendPublicChatMessageEvent;
import org.bigbluebutton.modules.polling.model.PollObject;
import org.bigbluebutton.modules.polling.model.PollStatLineObject;
import org.bigbluebutton.modules.polling.model.AnswerObject;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.model.users.Conference
import org.bigbluebutton.main.model.users.BBBUser;
import org.bigbluebutton.common.Role;
import mx.validators.Validator;
import mx.utils.ObjectUtil;
import org.bigbluebutton.util.i18n.ResourceUtil;
import mx.collections.ArrayCollection;
import mx.core.IUIComponent;
import mx.controls.Text;
import mx.controls.TextArea;
import mx.containers.*;
import mx.controls.*;
import flash.utils.Timer;
import flash.events.TimerEvent;
public static const LOGNAME:String = "[PollingStatsWindow] ";
[Bindable] public var question:String;
[Bindable] public var answers:Array;
[Bindable] public var trackingPoll:PollObject;
[Bindable] public var webPollUrl:String;
public var viewingClosedPoll:Boolean = false;
public var moduleAttributes:Object;
private var _userid:Number;
private var window:PollingStatsWindow;
private var conference:Conference;
[Bindable]public var reviewing:Boolean = false;
private var POLL_URL_COLOUR:String = "35071";
private var webClosed:Boolean;
private var notified:Boolean;
private var refreshTimer:Timer = new Timer(1000);
private var answersAC:ArrayCollection = new ArrayCollection();
private function init():void{
conference = UserManager.getInstance().getConference();
webPollText.visible = (conference.amIPresenter() && (!reviewing && trackingPoll.publishToWeb));
btnClosePoll.visible = conference.amIPresenter();
webPollBox.visible = webPollText.visible;
if (webPollText.visible){
webClosed = false;
var generate: GenerateWebKeyEvent = new GenerateWebKeyEvent(GenerateWebKeyEvent.GENERATE);
generate.poll = trackingPoll;
dispatchEvent(generate);
}
refreshTimer.addEventListener(TimerEvent.TIMER, autoRefresh);
refreshTimer.start();
answersAC = trackingPoll.generateStats();
notified = false;
}
private function autoRefresh(event:TimerEvent):void{
refreshPoll();
}
private function onCreationComplete():void{
//conference.amIPresenter()
// If the statistics window is being opened to view a poll that has been published and closed, the interface will
// immediately appear with only the option to close the window.
if(viewingClosedPoll)
stopPoll();
if (conference.amIPresenter()){
messageForRecording("A poll is open for voting.");
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.createPoll.title') + " " + trackingPoll.title);
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.createPoll.question') + " " + trackingPoll.question);
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.createPoll.answers'));
for (var i:int = 0; i < trackingPoll.answers.length; i++){
messageForRecording("- " + trackingPoll.answers[i]);
}
}
if (webPollText.visible){
LogUtil.debug("webPollURL is : " + webPollUrl);
LogUtil.debug("webkey is : " + trackingPoll);
LogUtil.debug("webPollURLBox.Text is : " + webPollURLBox.text);
}
answers = trackingPoll.answers;
question = trackingPoll.question;
var lines:int = (question.length / 28) + 1;
for(var s:String in answers){
lines = lines + ((s.length / 28) + 1);
}
height = height + ((lines+1) * 45);
createResultsTable(answers.length, answers);
}
public function setUrlBoxText():void{
webPollURLBox.text = webPollUrl;
LogUtil.debug("webPollURLBox.Text is : " + webPollURLBox.text);
if (conference.amIPresenter())
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.stats.webPollURL') + " " + webPollUrl);
}
private function messageForRecording(message:String):void{
/*if (!viewingClosedPoll){
var chatMessage:SendPublicChatMessageEvent = new SendPublicChatMessageEvent(SendPublicChatMessageEvent.SEND_PUBLIC_CHAT_MESSAGE_EVENT);
chatMessage.message = message;
chatMessage.time = "";
chatMessage.color = POLL_URL_COLOUR.toString();
chatMessage.language = ResourceUtil.getInstance().getCurrentLanguageCode().split("_")[0];
dispatchEvent(chatMessage);
}*/
}
public function getPrefferedPosition():String{
return MainCanvas.POPUP;
}
private function refreshPoll():void{
var e:PollRefreshEvent = new PollRefreshEvent(PollRefreshEvent.GET);
e.poll.title = trackingPoll.title;
dispatchEvent(e);
} // end of function refreshResults
private function closeWindow():void{
dispatchEvent(new PollingStatsWindowEvent(PollingStatsWindowEvent.CLOSE));
}
public function refreshWindow(newVotes:Array, totalVotes:int, noVoteYet:int):void{
trackingPoll.votes = newVotes;
trackingPoll.totalVotes = totalVotes;
trackingPoll.didNotVote = noVoteYet;
createResultsTable(trackingPoll.answers.length, trackingPoll.answers);
invalidateDisplayList();
validateNow();
}
private function stopPoll():void{
refreshPoll();
refreshTimer.stop();
btnRefreshResults.visible = conference.amIPresenter();
btnRefreshResults.label = ResourceUtil.getInstance().getString('bbb.polling.stats.repost');
btnRefreshResults.removeEventListener(MouseEvent.CLICK, refreshWindow);
btnRefreshResults.addEventListener(MouseEvent.CLICK, publishPollAgain);
btnClosePoll.label = ResourceUtil.getInstance().getString('bbb.polling.stats.close');
btnClosePoll.removeEventListener(MouseEvent.CLICK, closeWindow);
btnClosePoll.addEventListener(MouseEvent.CLICK, closeButtonClick);
trackingPoll.status = false;
if (webPollText.visible && !webClosed){
webClosed = true;
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.webPollClosed'));
}
if (!notified){
var percentage:int;
var totalVotes:int = 0;
for (var n:int = 0; n < trackingPoll.votes.length; n++){
totalVotes+= int(trackingPoll.votes[n]);
}
messageForRecording(ResourceUtil.getInstance().getString('bbb.polling.pollClosed'));
for (var i:int = 0; i < trackingPoll.answers.length; i++){
if (totalVotes > 0){
percentage = Math.round(100*(trackingPoll.votes[i]/totalVotes));
}
else{
percentage = 0;
}
// Example of how this message will appear:
// "Answer one - 3 votes/73%"
messageForRecording(trackingPoll.answers[i] + " - " + trackingPoll.votes[i] + " " + ResourceUtil.getInstance().getString('bbb.polling.stats.votes') + "/" + percentage + "%");
}
notified = true;
}
stopViewersPolls();
}
private function publishPollAgain(e:Event):void{
var event:PublishPollEvent = new PublishPollEvent(PublishPollEvent.REPOST);
event.poll = trackingPoll;
dispatchEvent(event);
closeWindow();
}
private function closeButtonClick(e:Event):void{
closeWindow();
}
private function stopViewersPolls():void{
var stopPollEvent:StopPollEvent = new StopPollEvent(StopPollEvent.STOP_POLL);
stopPollEvent.poll = trackingPoll;
dispatchEvent(stopPollEvent);
}
// function receives Array.length and ArrayCollection
private function createResultsTable(amount:uint, content:Array):void{
var _tx: Text;
var _votes: Text;
var _percent: Text;
var _hb: HBox;
var _line: HRule;
var totalVotes:int = 0;
for (var n:int = 0; n < trackingPoll.votes.length; n++){
totalVotes+= int(trackingPoll.votes[n]);
}
// delete existing rows
resultBox.removeAllChildren();
// creating rows one by one
for (var i:int = 0; i < amount; i++) {
_tx = new Text();
_votes= new Text;
_percent= new Text();
_hb = new HBox();
_line = new HRule();
_line.width = 290;
_tx.name = "option" +i;
_tx.width = 200;
_tx.text =content[i].toString();
_votes.name = "votes" +i;
_votes.width = 30;
_votes.text = trackingPoll.votes[i];
_percent.name = "percent" +i;
_percent.width = 50;
// Percentage is in terms of how many votes each option has in terms of total votes
if (totalVotes > 0){
_percent.text = Math.round(100*(trackingPoll.votes[i]/totalVotes)) + "%";
}else{
// Prevents percentages from displaying misleading results before any votes come in, and from dividing by zero
_percent.text = " ";
}
resultBox.addChild(_hb);
_hb.addChild(_tx);
_hb.addChild(_votes);
_hb.addChild(_percent);
resultBox.addChild(_line);
} // end of loop
didNotVote();
invalidateDisplayList();
resultBox.validateNow();
} // end of function createResultsTable
private function didNotVote():void{
var _tx:Text = new Text();
var _votes:Text= new Text;
var _hb:HBox = new HBox();
_tx.name = "optionNull";
_tx.width = 200;
_tx.text = ResourceUtil.getInstance().getString('bbb.polling.stats.didNotVote');
_votes.name = "voteNull";
_votes.width = 30;
_votes.text = trackingPoll.didNotVote.toString();
resultBox.addChild(_hb);
_hb.addChild(_tx);
_hb.addChild(_votes);
}
]]>
</mx:Script>
<!-- Prototype of Polling Statistics View Design -->
<mx:VBox width="100%"
height="75%"
horizontalAlign="center"
paddingLeft="10"
paddingRight="10"
focusEnabled="true"
accessibilityDescription="Alpha">
<mx:HBox width="90%"
paddingTop="10"
focusEnabled="true"
accessibilityDescription="Bravo">
<mx:Text id="webPollText"
text="{ResourceUtil.getInstance().getString('bbb.polling.stats.webPollURL')}"
width="140"/>
</mx:HBox>
<mx:HBox id="webPollBox"
width="90%"
accessibilityDescription="Charlie">
<mx:TextArea id="webPollURLBox"
editable="false"
text=""
height="25"
width="95%"
/>
</mx:HBox>
<mx:Text width="200"
paddingTop="15" paddingBottom="10"
fontWeight="bold" textAlign="center"
text="{question}"/>
<mx:Box id="resultBox"
width="90%"
height="90%" />
<!-- Viewer's grid used as an example -->
<!--mx:DataGrid id="viewersGrid" dataProvider="{UserManager.getInstance().getConference().users}" editable="false"
>>>>>>> poll-access
dragEnabled="false" width="90%" height="100%" accessibilityName="Users list.">
<mx:columns>
<mx:DataGridColumn dataField="role"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.roleItemRenderer')}"
dataTipField="Role"
editable="false"
width="35"
itemRenderer="org.bigbluebutton.modules.viewers.views.RoleItemRenderer"
sortable="false"
id="roleField"/>
<mx:DataGridColumn dataField="name"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.nameItemRenderer')}"
editable="true"
width="100"
sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.NameItemRenderer"/>
<mx:DataGridColumn dataField="status"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer')}"
dataTipField="Status"
id="statusField"
sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.StatusItemRenderer"/>
</mx:columns>
</mx:DataGrid-->
</mx:VBox>
<mx:ControlBar width="100%" height="10%">
<mx:Spacer width="100%"/>
<mx:Button id="btnRefreshResults"
label="{ResourceUtil.getInstance().getString('bbb.polling.stats.refresh')}"
click="refreshPoll()"
width="100"
height="30"
visible = "true"
/>
<mx:Button id="btnClosePoll"
label="{ResourceUtil.getInstance().getString('bbb.polling.stats.stopPoll')}"
click="stopPoll()"
width="100"
height="30"
visible = "true"/>
<mx:Spacer width="100%"/>
</mx:ControlBar>
</MDIWindow>

View File

@ -0,0 +1,218 @@
<?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: $
-->
<MDIWindow xmlns="flexlib.mdi.containers.*" xmlns:mx="http://www.adobe.com/2006/mxml"
width="410" height="150"
xmlns:mate="http://mate.asfusion.com/"
implements="org.bigbluebutton.common.IBbbModuleWindow"
creationComplete="onCreationComplete()"
label="{ResourceUtil.getInstance().getString('bbb.polling.toolbar.toolTip')}"
title="{ResourceUtil.getInstance().getString('bbb.polling.toolbar.toolTip')}"
layout="absolute">
<mx:Script>
<![CDATA[
import flexlib.mdi.events.MDIWindowEvent;
import org.bigbluebutton.main.views.MainCanvas;
import mx.controls.Alert;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.modules.polling.events.StartPollingEvent;
import org.bigbluebutton.modules.polling.events.PollingViewWindowEvent;
import org.bigbluebutton.modules.polling.managers.PollingManager;
import org.bigbluebutton.modules.polling.events.VoteEvent;
import org.bigbluebutton.main.model.users.Conference;
import mx.validators.Validator;
import mx.utils.ObjectUtil;
import org.bigbluebutton.util.i18n.ResourceUtil;
import mx.collections.ArrayCollection;
import mx.core.IUIComponent;
import mx.controls.CheckBox;
import mx.controls.RadioButton;
import mx.controls.Text;
import mx.containers.*;
import mx.controls.*;
public static const LOGNAME:String = "[PollingViewWindow] ";
public var isMultiple:Boolean;
[Bindable] public var question:String;
[Bindable] public var answers:Array;
public var votes:Array;
public var time:String;
public var moduleAttributes:Object;
private var _userid:Number;
private var window:PollingViewWindow;
private var submissionAllowed:Boolean=false;
public var cbSelected:Array = new Array(); // variable that receives either CheckBox or RadioButton info and sends it to VoteEvent
public function getPrefferedPosition():String{
return MainCanvas.POPUP;
}
private function closeWindow():void{
dispatchEvent(new PollingViewWindowEvent(PollingViewWindowEvent.CLOSE));
}
private function onCreationComplete():void{
if (isMultiple)
errorMessage.text = ResourceUtil.getInstance().getString('bbb.polling.vote.error.check');
else
errorMessage.text = ResourceUtil.getInstance().getString('bbb.polling.vote.error.radio');
checkInstructions.visible = isMultiple;
createButtons(answers.length,answers);
invalidateDisplayList();
validateNow();
var lines:int = (question.length / 28) + 1;
for(var s:String in answers){
lines = lines + ((s.length / 28) + 1);
}
height = height + (lines * 50);
//questionBox.
}
// This function will receive information and generate radiobuttons on fly
// function receives Array.length and ArrayCollection
private function createButtons(amount:uint, content:Array):void{
var _cb:CheckBox;
var _rb:RadioButton;
var _tx: Text;
var _hb: HBox;
var _rb_group:RadioButtonGroup = new RadioButtonGroup();
// creating buttons one by one
for (var i:int = 0; i < amount; i++) {
_tx = new Text();
_hb = new HBox();
_tx.name = "option" +i;
_tx.width = 200;
// assigning array element to text field
_tx.text =content[i].toString();
answerBox.addChild(_hb);
// if global var isMultiple is true it means user wants checkboxes,
//otherwise radiobutton (if multiple choices are allowed)
if(isMultiple){
_cb= new CheckBox();
_cb.id = "answers"+i;
_cb.addEventListener(MouseEvent.CLICK, checkBoxClick);
// gap between the buttons
_cb.y=i*20;
// adding buttons to the Horizontal Box
_hb.addChild(_cb);
}else{
_rb = new RadioButton();
_rb.groupName = "answersGroup";
_rb.name = content[i].toString(); // giving button a name of array elelment to process it easier later
_rb.id = "answers"+i;
_rb.addEventListener(MouseEvent.CLICK, radioClick);
_hb.addChild(_rb);
}
_hb.addChild(_tx); // adding text near button
} // end of loop
answerBox.validateNow();
} // end of function createButtons
private function Vote():void{
if (submissionAllowed){
var voteEvent: VoteEvent = new VoteEvent(VoteEvent.START);
if (isMultiple){
// Checkboxes
voteEvent.answerID = cbSelected;
}else{
// Radio Buttons
cbSelected[0]= answersGroup.selection.toString().substr(-1,1); // answergroup... is answerID index
// [0] index because RadioButtons could have only one element
voteEvent.answerID = cbSelected;
}
voteEvent.title = title;
dispatchEvent(voteEvent);
closeWindow();
}
else
errorMessage.visible = true;
} // _vote
// As the user clicks CheckBoxes, this function keeps a running tally of which boxes are and are not selected
private function checkBoxClick(e:Event):void{
var boxID:String = e.currentTarget.toString();
var match:Boolean = false;
var target:int;
// Goes through each element of the array, looks for a match to boxID
for (var i:int = 0; i < cbSelected.length; i++){
if (cbSelected[i] == boxID.charAt(boxID.length-1)){
match = true;
target = i;
}
}
// If a match is found, delete that element. If no match is found, add boxID to the array
if (match){
cbSelected.splice(target, 1);
}else{
cbSelected.push(boxID.charAt(boxID.length-1));
}
submissionAllowed = (cbSelected.length > 0);
}
public function radioClick(e:Event):void{
submissionAllowed = true;
}
]]>
</mx:Script>
<mx:RadioButtonGroup id="answersGroup"/>
<!-- Prototype of Polling Module Design -->
<mx:VBox accessibilityDescription="The question will go into the V BOX"
width="100%"
height="75%"
horizontalAlign="center"
paddingLeft="10"
paddingRight="10"
focusEnabled="true">
<mx:HBox accessibilityDescription="The question will go into the H BOX"/>
<mx:Text width="200"
paddingTop="30"
paddingBottom="10"
fontWeight="bold"
textAlign="center"
text="{question}"
accessibilityDescription="The question will go into the m x TEXT"
/>
<mx:Text id="checkInstructions"
text="{ResourceUtil.getInstance().getString('bbb.polling.pollPreview.checkAll')}"/>
<mx:Box id="answerBox"
width="90%"
height="90%" />
<mx:Text id="errorMessage"
color="red"
visible="false"/>
</mx:VBox>
<mx:ControlBar width="100%"
horizontalAlign="center">
<mx:Button id="btnAcceptPoll"
label="{ResourceUtil.getInstance().getString('bbb.polling.pollView.vote')}"
click="Vote()"
width="100"
height="30"/>
</mx:ControlBar>
</MDIWindow>

View File

@ -0,0 +1,165 @@
<?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:Button xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:mate="http://mate.asfusion.com/"
toolTip="{ResourceUtil.getInstance().getString('bbb.polling.toolbar.toolTip')}"
implements="org.bigbluebutton.common.IBbbToolbarComponent"
initialize="init();"
click="createAndShow();"
icon="{pollIcon}"
>
<mx:Script>
<![CDATA[
import com.asfusion.mate.events.Dispatcher;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.main.views.MainToolbar;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.modules.polling.events.PollingInstructionsWindowEvent;
import org.bigbluebutton.modules.polling.events.PollGetTitlesEvent;
import org.bigbluebutton.modules.polling.events.PollGetPollEvent;
import org.bigbluebutton.modules.polling.events.OpenSavedPollEvent;
import org.bigbluebutton.modules.polling.events.ReviewResultsEvent;
import org.bigbluebutton.modules.polling.model.ValueObject;
import org.bigbluebutton.modules.polling.model.PollObject;
import mx.collections.ArrayCollection;
import mx.controls.Menu;
import mx.events.MenuEvent;
import flash.events.FocusEvent;
import org.bigbluebutton.modules.polling.model.PollObject;
private var images:Images = new Images();
[Bindable] private var myMenuData:ArrayCollection;
[Bindable]
[Embed(source="../../../common/assets/images/poll_icon.png")]
public var pollIcon:Class;
public static const LOGNAME:String = "[Polling (views) : ToolbarButton] ";
[Bindable] public var roomID:String;
[Bindable] public var titleList:Array;
[Bindable] public var pollList:ArrayCollection;
// #################################################################
public function init():void {
LogUtil.debug("Initializing Polling toolbar button.");
myMenuData = new ArrayCollection();
pollList = new ArrayCollection();
listInitialize();
renderMenu();
this.addEventListener(FocusEvent.FOCUS_IN, updateMenuByEvent);
}
private function createAndShow():void{
renderMenu();
var myMenu:Menu = Menu.createMenu(null, myMenuData, false);
myMenu.iconField="icon";
myMenu.show(this.x + 10, this.y + this.height + 10);
myMenu.addEventListener(MenuEvent.ITEM_CLICK, menuClick);
}
// #################################################################
public function listInitialize():void{
titleList = new Array();
myMenuData.removeAll();
pollList.removeAll();
var pevent:PollGetTitlesEvent = new PollGetTitlesEvent(PollGetTitlesEvent.INIT);
try{
dispatchEvent(pevent);
}
catch (e:*){
LogUtil.debug("Bleh.");
}
}
private function renderMenu():void{
myMenuData.removeAll();
myMenuData.addItem(new ValueObject("create", ResourceUtil.getInstance().getString('bbb.polling.createPoll')));
for (var i:int = 0; i < pollList.length; i++){
if (pollList[i] != null){
var keyString:String = pollList[i].room +"-"+ pollList[i].title;
var menuEntry:ValueObject = new ValueObject(keyString, pollList[i].title);
menuEntry.poll = pollList[i];
if (!pollList[i].status){
menuEntry.label = "X-" + menuEntry.label;
}else{
menuEntry.icon = "pollIcon";
}
myMenuData.addItem(menuEntry);
}
}
}
private function updateMenuByEvent(e:FocusEvent):void{
updateMenu();
}
private function updateMenu():void{
listInitialize();
}
private function menuClick(event:MenuEvent):void {
/*LogUtil.debug("WATERFALL At the start of menuclick, focus is set to: " + focusManager.getFocus());
focusManager.setFocus(this);
focusManager.setFocus(focusManager.getNextFocusManagerComponent());
LogUtil.debug("WATERFALL focus is now set to: " + focusManager.getFocus());*/
if(event.index == 0){
openPollingInstructions();
}else{
var poll:PollObject = myMenuData.getItemAt(event.index).poll;
if (poll.status){
// Poll has not been used yet, open instructions window
var openPollEvent:OpenSavedPollEvent = new OpenSavedPollEvent(OpenSavedPollEvent.OPEN);
openPollEvent.poll = poll;
dispatchEvent(openPollEvent);
}else{
// Poll has been closed, show results
var reviewEvent:ReviewResultsEvent = new ReviewResultsEvent(ReviewResultsEvent.REVIEW);
reviewEvent.poll = poll;
dispatchEvent(reviewEvent);
}
}
}
public function getAlignment():String{
return MainToolbar.ALIGN_RIGHT;
}
private function openPollingInstructions():void {
dispatchEvent(new PollingInstructionsWindowEvent(PollingInstructionsWindowEvent.OPEN));
this.enabled=false;
}
]]>
</mx:Script>
</mx:Button>

View File

@ -0,0 +1,32 @@
<?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:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
<mx:Script>
<![CDATA[
import org.bigbluebutton.util.i18n.ResourceUtil;
// {data.votes}
]]>
</mx:Script>
<mx:Label id="votesRenderLabel" textAlign="left" text="VOTES"/>
</mx:HBox>

View File

@ -48,6 +48,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
import org.bigbluebutton.modules.viewers.events.ViewCameraEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.main.model.users.BBBUser;
private var images:Images = new Images();
[Bindable] public var kickIcon:Class = images.cancel;
@ -96,20 +98,33 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
dispatchEvent(new KickUserEvent(data.userID));
}
}
private function handRaised():Boolean{
var rvalue:Boolean = false;
return rvalue;
}
[Bindable] private var webcamIcon:Class = images.webcam;
[Bindable] private var handIcon:Class = images.raisehand;
[Bindable] private var presenterIcon:Object = images.presenter;
// toolTip="{CASE ? TRUE : FALSE}"
// toolTip="{data.role == Role.MODERATOR ? 'moderator' : 'viewer'}"
// toolTip="{UserManager.getInstance().getConference().isUserPresenter(data.userid) ? 'presenter' : 'ordinary'}"
]]>
</mx:Script>
<mx:Button id="raiseHand" visible="{data.raiseHand}" click="lowerHand()"
icon="{handIcon}" width="18" height="18"
toolTip="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.raiseHand.toolTip'),
[new Date()]}"/>
toolTip="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.raiseHand.toolTip')}"/>
<mx:Button id="streamIcon" visible="{data.hasStream}" click="viewCamera()" icon="{webcamIcon}"
width="18" height="18" enabled="false"
toolTip="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.streamIcon.toolTip')}"/>
<mx:Image id="presIcon" visible="{data.presenter}" source="{presenterIcon}" toolTip="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer.presIcon.toolTip')}"/>
<mx:Image id="presIcon" visible="{data.presenter}" source="{presenterIcon}"
toolTip="{UserManager.getInstance().getConference().isUserPresenter(data.userid) ? 'presenter' : 'ordinary'}"
accessibilityDescription="{UserManager.getInstance().getConference().isUserPresenter(data.userid) ? 'presenter' : 'ordinary'}"/>
<mx:Button id="kickUserBtn" icon="{kickIcon}"
width="20" height="20" visible="false"

View File

@ -62,7 +62,9 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
[Bindable] public var participants:ArrayCollection = new ArrayCollection();
private var conference:Conference;
[Bindable] public var isModerator:Boolean = false;
//private var isPresenter:Boolean = false;
private var handRaised:Boolean = false;
//private var showingWebcam:Boolean = false;
public var images:Images = new Images();
[Bindable] public var presenterIcon : Class = images.presenter;
@ -76,6 +78,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
conference = UserManager.getInstance().getConference();
participants = conference.users;
this.isModerator = UserManager.getInstance().getConference().amIModerator();
//this.isPresenter = UserManager.getInstance().getConference().amIPresenter();
BindingUtils.bindSetter(updateNumberOfViewers, participants, "length");
dispatcher = new Dispatcher();
@ -166,14 +169,36 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:DataGrid id="viewersGrid" dataProvider="{participants}" editable="false"
dragEnabled="false" itemClick="viewerSelectEvent(event);" width="100%" height="100%"
itemRollOver="onItemRollOver(event)"
itemRollOut="onItemRollOut(event)">
itemRollOut="onItemRollOut(event)"
accessibilityName="Users list.">
<mx:columns>
<mx:DataGridColumn dataField="role" headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.roleItemRenderer')}" dataTipField="Role" editable="false" width="35"
itemRenderer="org.bigbluebutton.modules.viewers.views.RoleItemRenderer" sortable="false" id="roleField"/>
<mx:DataGridColumn dataField="name" headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.nameItemRenderer')}" editable="true" width="100" sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.NameItemRenderer"/>
<mx:DataGridColumn dataField="status" headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer')}" sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.StatusItemRenderer"/>
<mx:DataGridColumn dataField="role"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.roleItemRenderer')}"
dataTipField="Role"
editable="false"
width="35"
itemRenderer="org.bigbluebutton.modules.viewers.views.RoleItemRenderer"
sortable="false"
id="roleField"/>
<mx:DataGridColumn dataField="name"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.nameItemRenderer')}"
editable="true"
width="100"
sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.NameItemRenderer"/>
<!--mx:DataGridColumn dataField="status"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer')}"
dataTipField="Status"
editable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.StatusItemRenderer"
sortable="false"
id="statusField"/-->
<mx:DataGridColumn dataField="status"
headerText="{ResourceUtil.getInstance().getString('bbb.viewers.viewersGrid.statusItemRenderer')}"
dataTipField="Status"
id="statusField"
sortable="false"
itemRenderer="org.bigbluebutton.modules.viewers.views.StatusItemRenderer"/>
</mx:columns>
</mx:DataGrid>

View File

@ -25,6 +25,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
xmlns:view="org.bigbluebutton.modules.whiteboard.views.*"
xmlns:wbBtns="org.bigbluebutton.modules.whiteboard.views.buttons.*"
xmlns:mate="http://mate.asfusion.com/" creationComplete="onCreationComplete()"
initialize="init()"
visible="{showWhiteboardToolbar}" styleName="whiteboardToolbarStyle">
<mate:Listener type="{MadePresenterEvent.SWITCH_TO_PRESENTER_MODE}" method="presenterMode" />
@ -57,28 +58,32 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<mx:Script>
<![CDATA[
import flash.ui.Keyboard;
import mx.events.MoveEvent;
import mx.events.ResizeEvent;
import mx.managers.CursorManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.modules.present.events.PresentationEvent;
import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.GraphicObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.TextObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.WhiteboardConstants;
import org.bigbluebutton.modules.whiteboard.events.GraphicObjectFocusEvent;
import org.bigbluebutton.modules.whiteboard.events.StopWhiteboardModuleEvent;
import org.bigbluebutton.modules.whiteboard.events.ToggleGridEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardPresenterEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardSettingResetEvent;
import org.bigbluebutton.util.i18n.ResourceUtil;
import org.bigbluebutton.common.LogUtil;
import mx.events.MoveEvent;
import mx.events.ResizeEvent;
import mx.managers.CursorManager;
import org.bigbluebutton.common.Images;
import org.bigbluebutton.common.LogUtil;
import org.bigbluebutton.core.UsersUtil;
import org.bigbluebutton.core.managers.UserManager;
import org.bigbluebutton.main.events.MadePresenterEvent;
import org.bigbluebutton.main.events.ShortcutEvent;
import org.bigbluebutton.modules.present.events.PresentationEvent;
import org.bigbluebutton.modules.present.ui.views.PresentationWindow;
import org.bigbluebutton.modules.whiteboard.business.shapes.DrawObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.GraphicObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.TextObject;
import org.bigbluebutton.modules.whiteboard.business.shapes.WhiteboardConstants;
import org.bigbluebutton.modules.whiteboard.events.GraphicObjectFocusEvent;
import org.bigbluebutton.modules.whiteboard.events.StopWhiteboardModuleEvent;
import org.bigbluebutton.modules.whiteboard.events.ToggleGridEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardButtonEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardDrawEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardPresenterEvent;
import org.bigbluebutton.modules.whiteboard.events.WhiteboardSettingResetEvent;
import org.bigbluebutton.modules.whiteboard.views.models.WhiteboardOptions;
import org.bigbluebutton.util.i18n.ResourceUtil;
private var images:Images = new Images();
[Bindable] private var hand_icon:Class = images.hand_icon;
@ -100,13 +105,19 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
[Bindable] private var select_icon:Class = images.select_icon;
[Bindable] private var grid_icon:Class = images.grid_icon;
[Bindable] private var showWhiteboardToolbar:Boolean = true;
private var wbOptions:WhiteboardOptions;
[Bindable] private var showWhiteboardToolbar:Boolean = false;
public var canvas:WhiteboardCanvas;
private var presentationWindow:PresentationWindow;
[Bindable] private var colorPickerColours:Array = ['0x000000', '0xFFFFFF' , '0xFF0000', '0xFF8800',
'0xCCFF00', '0x00FF00', '0x00FF88', '0x00FFFF', '0x0088FF', '0x0000FF', '0x8800FF', '0xFF00FF', '0xC0C0C0'];
private function init():void {
wbOptions = new WhiteboardOptions();
}
private function onCreationComplete():void {
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
@ -181,14 +192,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
if (canvas == null) return;
canvas.makeTextObjectsEditable(e);
hideOrDisplayToolbar();
setToolType(WhiteboardConstants.TYPE_ZOOM, null);
}
private function viewerMode(e:MadePresenterEvent):void {
canvas.makeTextObjectsUneditable(e);
hideOrDisplayToolbar();
}
canvas.makeTextObjectsUneditable(e);
if (!toolbarAllowed()) hideToolbar();
}
private function undoShortcut(e:ShortcutEvent):void{
LogUtil.debug("Ctrl-Z got into undoShortcut");
@ -204,19 +214,22 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
public function positionToolbar(window:PresentationWindow):void {
trace("Positioning whiteboard toolbar");
presentationWindow = window;
presentationWindow.addEventListener(MoveEvent.MOVE, setPositionAndDepth);
presentationWindow.addEventListener(ResizeEvent.RESIZE, setPositionAndDepth);
presentationWindow.addEventListener(MouseEvent.CLICK, setPositionAndDepth);
this.x = presentationWindow.x + presentationWindow.width + 3;
this.y = presentationWindow.y + 30;
hideOrDisplayToolbar();
parent.setChildIndex(this, parent.numChildren - 1);
//presentationWindow.addEventListener(MoveEvent.MOVE, setPositionAndDepth);
//presentationWindow.addEventListener(ResizeEvent.RESIZE, setPositionAndDepth);
//presentationWindow.addEventListener(MouseEvent.CLICK, setPositionAndDepth);
presentationWindow.addEventListener(MouseEvent.ROLL_OVER, showToolbar);
presentationWindow.addEventListener(MouseEvent.ROLL_OUT, hideToolbar);
this.addEventListener(MouseEvent.ROLL_OVER, showToolbar);
this.addEventListener(MouseEvent.ROLL_OUT, hideToolbar);
//this.x = presentationWindow.x + presentationWindow.width - 43;
//this.y = presentationWindow.y + 30;
//parent.setChildIndex(this, parent.numChildren - 1);
}
private function setPositionAndDepth(e:Event = null):void {
this.x = presentationWindow.x + presentationWindow.width + 3;
this.x = presentationWindow.x + presentationWindow.width - 43;
this.y = presentationWindow.y + 30;
hideOrDisplayToolbar();
parent.setChildIndex(this, parent.numChildren - 1);
}
@ -224,15 +237,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
parent.removeChild(this);
}
private function hideOrDisplayToolbar():void {
if (presentationWindow != null && presentationWindow.visible && ! presentationWindow.minimized) {
trace("Positioning whiteboard toolbar: showing");
showWhiteboardToolbar = true;
} else {
trace("Positioning whiteboard toolbar: not showing");
showWhiteboardToolbar = false;
private function showToolbar(e:MouseEvent):void {
if (toolbarAllowed()) {
setPositionAndDepth();
showWhiteboardToolbar = true;
}
}
private function hideToolbar(e:MouseEvent = null):void {
showWhiteboardToolbar = false;
}
private function graphicObjSelected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
@ -241,7 +255,30 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
private function graphicObjDeselected(event:GraphicObjectFocusEvent):void {
var gobj:GraphicObject = event.data;
}
private function toolbarAllowed():Boolean {
if (wbOptions) {
if (wbOptions.whiteboardAccess == "presenter")
return isPresenter;
else if (wbOptions.whiteboardAccess == "moderator")
return isModerator || isPresenter;
else if (wbOptions.whiteboardAccess == "all")
return true;
else
return false;
} else
return false;
}
/** Helper method to test whether this user is the presenter */
private function get isPresenter():Boolean {
return UsersUtil.amIPresenter();
}
private function get isModerator():Boolean {
return UsersUtil.amIModerator();
}
]]>
</mx:Script>

View File

@ -0,0 +1,21 @@
package org.bigbluebutton.modules.whiteboard.views.models
{
import org.bigbluebutton.core.BBB;
import org.bigbluebutton.common.LogUtil;
public class WhiteboardOptions
{
[Bindable] public var whiteboardAccess:String;
public function WhiteboardOptions() {
var vxml:XML = BBB.getConfigForModule("WhiteboardModule");
if (vxml != null) {
if (vxml.@whiteboardAccess != undefined) {
whiteboardAccess = vxml.@whiteboardAccess;
}
else{
whiteboardAccess = "presenter";
}
}
}
}
}

View File

@ -44,6 +44,7 @@
# 2012-01-14 FFD Tsting the development environment for 0.8
# 2012-02-22 FFD Updates to development environment
# 2012-04-27 FFD Added sum of version numbers in --check
# 2013-02-03 FFD Updated for changes to parameters for 0.81 in bigbluebutton-sip.properties
#set -x
#set -e
@ -949,7 +950,7 @@ check_configuration() {
FREESWITCH_ESL_IP=$(sudo cat /opt/freeswitch/conf/autoload_configs/event_socket.conf.xml | grep 'name="listen-ip"' | cut -d\" -f4 | awk '{print $1}')
check_no_value event_socket /opt/freeswitch/conf/autoload_configs/event_socket.conf.xml $FREESWITCH_ESL_IP
ESL_HOST=$(cat /usr/share/red5/webapps/bigbluebutton/WEB-INF/bigbluebutton.properties | grep esl.host | sed 's/esl.host=//g')
ESL_HOST=$(cat /usr/share/red5/webapps/bigbluebutton/WEB-INF/bigbluebutton.properties | grep esl.host | sed 's/freeswitch.esl.host=//g')
check_no_value esl.host /usr/share/red5/webapps/bigbluebutton/WEB-INF/bigbluebutton.properties $ESL_HOST
if [ "$FREESWITCH_ESL_IP" != "$ESL_HOST" ]; then
@ -1361,21 +1362,23 @@ check_state() {
echo
fi
SIP_SERVER_HOST=$(cat /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties | sed -n '/^sip.server.host=/{s/.*=//;s/;//;p}')
if [ $SIP_SERVER_HOST != "127.0.0.1" ]; then
if [ $SIP_SERVER_HOST != $IP ]; then
echo "# Error: The setting of ($SIP_SERVER_HOST) for sip.server.host in"
BBB_SIP_APP_IP=$(cat /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties | sed -n '/^bbb.sip.app.ip=/{s/.*=//;s/;//;p}')
if [ $BBB_SIP_APP_IP != "127.0.0.1" ]; then
if [ $BBB_SIP_APP_IP != $IP ]; then
echo "# Warning: The setting of ($BBB_SIP_APP_IP) for bbb.sip.app.ip in"
echo "#"
echo "# /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties"
echo "#"
echo "# does not match the local IP address ($IP)."
echo "# (This is OK if you've manually changed the values to an external "
echo "# FreeSWITCH server.)"
echo
fi
SIP_IP=$(netstat -ant | grep 5060 | head -n1 | awk -F" " '{print $4}' | cut -d: -f1)
if [ $SIP_SERVER_HOST != $SIP_IP ]; then
if [ $BBB_SIP_APP_IP != $SIP_IP ]; then
echo "# Error: FreeSWITCH is listening on IP address $SIP_IP for SIP calls, but "
echo "# The IP address ($SIP_SERVER_HOST) set for sip.server.host."
echo "# The IP address ($BBB_SIP_APP_IP) set bbb.sip.app.ip."
echo "#"
echo "# If your audio is not working (users click the headset icon "
echo "# and don't appear in the Listeners window, ensure FreeSWITCH uses"
@ -1392,41 +1395,6 @@ check_state() {
echo
fi
#
# We've not done extensive testing of asterisk in BigBlueButton 0.8
#
if dpkg -l | grep -q bbb-voice-conference; then
if [ "$VOICE_CONFERENCE" == "bbb-voice-freeswitch.xml" ]; then
echo "# You have asterisk installed, but the current voice conference set"
echo "# to freeswitch. To switch to asterisk, enter"
echo "#"
echo "# sudo bbb-conf --conference konference"
echo
fi
SIP_SERVER_HOST=$(cat /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties | sed -n '/sip.server.host=/{s/.*=//;s/;//;p}')
if [ $SIP_SERVER_HOST != "127.0.0.1" ]; then
echo "# The IP address ($SIP_SERVER_HOST) set for sip.server.host in"
echo "#"
echo "# /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties"
echo "#"
echo "# should be 127.0.0.1 for Asterisk."
echo
fi
fi
if [ -f /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml ]; then
PLAYBACK_IP=$(cat /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml | sed -n '/playback_host/{s/.*:[ ]*//;s/;//;p}')
if [ $PLAYBACK_IP != $IP ]; then
echo "# Warning: The value ($PLAYBACK_IP) for playback_host in"
echo "#"
echo "# /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml"
echo "#"
echo "# does not match the local IP address ($IP)."
echo
fi
fi
if [ -d ${SERVLET_DIR}/lti ]; then
if test ${SERVLET_DIR}/lti.war -nt ${SERVLET_DIR}/lti; then
echo "# Error: The updated lti.war did not deploy. To manually deploy:"
@ -1603,11 +1571,6 @@ if [ $CHECK ]; then
echo " playback host: $PLAYBACK_IP"
fi
#SIP_SERVER_HOST=$(cat /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties | sed -n '/sip.server.host=/{s/.*=//;s/;//;p}')
#echo
#echo "/usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties"
#echo " SIP server host: $SIP_SERVER_HOST"
check_state
echo ""
@ -1972,7 +1935,7 @@ if [ $CONFERENCE ]; then
sudo update-rc.d -f freeswitch remove >/dev/null
fi
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties sip.server.host 127.0.0.1
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties bbb.sip.server.ip 127.0.0.1
sudo update-rc.d asterisk defaults 21 > /dev/null
@ -2022,7 +1985,7 @@ if [ $CONFERENCE ]; then
/usr/share/red5/webapps/bigbluebutton/WEB-INF/red5-web.xml
fi
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties sip.server.host 127.0.0.1
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties bbb.sip.server.ip 127.0.0.1
echo "Switching to $CONFERENCE ... "
if [ -f $FREESWITCH_INIT_D ]; then
@ -2052,7 +2015,7 @@ if [ $CONFERENCE ]; then
/usr/share/red5/webapps/bigbluebutton/WEB-INF/red5-web.xml
fi
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties sip.server.host 127.0.0.1
change_var_ip /usr/share/red5/webapps/sip/WEB-INF/bigbluebutton-sip.properties bbb.sip.server.ip 127.0.0.1
echo "Switching to $CONFERENCE ... "
if [ -f /etc/init.d/asterisk ]; then

View File

@ -286,8 +286,8 @@ class ApiController {
respondWithErrors(errors)
return;
}
String webVoice = StringUtils.isEmpty(params.webVoiceConf) ? meeting.getTelVoice() : params.webVoiceConf
String webVoice = StringUtils.isEmpty(params.webVoiceConf) ? meeting.getTelVoice() : params.webVoiceConf
boolean redirectImm = parseBoolean(params.redirectImmediately)
@ -297,6 +297,12 @@ class ApiController {
if (StringUtils.isEmpty(externUserID)) {
externUserID = internalUserID
}
//Return a Map with the user custom data
Map<String,String> userCustomData = paramsProcessorUtil.getUserCustomData(params);
//Currently, it's associated with the externalUserID
if(userCustomData.size()>0)
meetingService.addUserCustomData(meeting.getInternalId(),externUserID,userCustomData);
UserSession us = new UserSession();
us.internalUserId = internalUserID
@ -1201,6 +1207,7 @@ class ApiController {
meetingID(meeting.getExternalId())
createTime(meeting.getCreateTime())
voiceBridge(meeting.getTelVoice())
dialNumber(meeting.getDialNumber())
attendeePW(meeting.getViewerPassword())
moderatorPW(meeting.getModeratorPassword())
running(meeting.isRunning() ? "true" : "false")
@ -1217,6 +1224,11 @@ class ApiController {
userID("${att.externalUserId}")
fullName("${att.fullname}")
role("${att.role}")
customdata(){
meeting.getUserCustomData(att.externalUserId).each{ k,v ->
"$k"("$v")
}
}
}
}
}

View File

@ -226,6 +226,13 @@ public class MeetingService {
log.debug("endMeeting - meeting doesn't exist: " + meetingId);
}
}
public void addUserCustomData(String meetingId, String userID, Map<String,String> userCustomData){
Meeting m = getMeeting(meetingId);
if(m != null){
m.addUserCustomData(userID,userCustomData);
}
}
public void setDefaultMeetingCreateJoinDuration(int expiration) {
this.defaultMeetingCreateJoinDuration = expiration;

View File

@ -542,4 +542,20 @@ public class ParamsProcessorUtil {
}
return internalMeetingIds;
}
public Map<String,String> getUserCustomData(Map<String,String> params){
Map<String,String> resp = new HashMap<String, String>();
for (String key: params.keySet()) {
if (key.contains("userdata")&&key.indexOf("userdata")==0){
String[] userdata = key.split("-");
if(userdata.length == 2){
log.debug("Got user custom data {} = {}", key, params.get(key));
resp.put(userdata[1], params.get(key));
}
}
}
return resp;
}
}

View File

@ -21,6 +21,7 @@ package org.bigbluebutton.api.domain;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -47,7 +48,8 @@ public class Meeting {
private String dialNumber;
private String defaultAvatarURL;
private Map<String, String> metadata;
private Map<String, String> metadata;
private Map<String, Object> userCustomData;
private final ConcurrentMap<String, User> users;
public Meeting(Builder builder) {
@ -67,6 +69,7 @@ public class Meeting {
dialNumber = builder.dialNumber;
metadata = builder.metadata;
createdTime = builder.createdTime;
userCustomData = new HashMap<String, Object>();
users = new ConcurrentHashMap<String, User>();
}
@ -235,6 +238,14 @@ public class Meeting {
return (System.currentTimeMillis() - endTime > (expiry * MILLIS_IN_A_MINUTE));
}
public void addUserCustomData(String userID, Map<String, String> data) {
userCustomData.put(userID, data);
}
public Map getUserCustomData(String userID){
return (Map) userCustomData.get(userID);
}
/***
* Meeting Builder
*

View File

@ -18,9 +18,13 @@
*/
package org.bigbluebutton.deskshare.client;
import javax.imageio.ImageIO;
import javax.swing.JApplet;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import java.io.IOException;
import java.net.URL;
import java.security.*;
import java.awt.Image;
@ -73,7 +77,11 @@ public class DeskShareApplet extends JApplet implements ClientListener {
String tunnel = getParameter("HTTP_TUNNEL");
if (tunnel != null) tunnelValue = Boolean.parseBoolean(tunnel);
icon = getImage(getCodeBase(), "bbb.gif");
try {
URL url = new URL(getCodeBase(), "bbb.gif");
icon = ImageIO.read(url);
} catch (IOException e) {
}
}
@Override
@ -83,7 +91,7 @@ public class DeskShareApplet extends JApplet implements ClientListener {
client = new DeskshareClient.NewBuilder().host(hostValue).port(portValue)
.room(roomValue).captureWidth(cWidthValue)
.captureHeight(cHeightValue).scaleWidth(sWidthValue).scaleHeight(sHeightValue)
.quality(qualityValue)
.quality(qualityValue).autoScale(0.8)
.x(xValue).y(yValue).fullScreen(fullScreenValue).useSVC2(useSVC2Value)
.httpTunnel(tunnelValue).trayIcon(icon).enableTrayIconActions(false).build();
client.addClientListener(this);

View File

@ -33,10 +33,12 @@ module BigBlueButton
events_xml = "#{archive_dir}/events.xml"
audio_events = BigBlueButton::AudioEvents.process_events(audio_dir, events_xml)
audio_files = []
first_no_silence = audio_events.select { |e| !e.padding }.first
sampling_rate = first_no_silence.nil? ? 16000 : FFMPEG::Movie.new(first_no_silence.file).audio_sample_rate
audio_events.each do |ae|
if ae.padding
ae.file = "#{audio_dir}/#{ae.length_of_gap}.wav"
BigBlueButton::AudioEvents.generate_silence(ae.length_of_gap, ae.file, 16000)
BigBlueButton::AudioEvents.generate_silence(ae.length_of_gap, ae.file, sampling_rate)
else
# Substitute the original file location with the archive location
ae.file = ae.file.sub(/.+\//, "#{audio_dir}/")
@ -50,4 +52,4 @@ module BigBlueButton
BigBlueButton::AudioEvents.wav_to_ogg(wav_file, ogg_file)
end
end
end
end

View File

@ -923,7 +923,7 @@
* to bypass a known webkit bug that causes loadedmetadata to be triggered
* before the duration is available
*/
var t = window.setInterval(function() {
if (acorn.$self[0].readyState > 0) {
updateSeek();
@ -949,7 +949,6 @@
*/
acorn.$container.addClass('audio-player');
}
}();
};

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 349 B

After

Width:  |  Height:  |  Size: 349 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 368 B

After

Width:  |  Height:  |  Size: 368 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 354 B

Some files were not shown because too many files have changed in this diff Show More